1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * The softmac driver is used to "unify" non-GLDv3 drivers to the GLDv3 28 * framework. It also creates the kernel datalink structure for each 29 * physical network device. 30 * 31 * Specifically, a softmac will be created for each physical network device 32 * (dip) during the device's post-attach process. When this softmac is 33 * created, the following will also be done: 34 * - create the device's <link name, linkid> mapping; 35 * - register the mac if this is a non-GLDv3 device and the media type is 36 * supported by the GLDv3 framework; 37 * - create the kernel data-link structure for this physical device; 38 * 39 * This softmac will be destroyed during the device's pre-detach process, 40 * and all the above will be undone. 41 */ 42 43 #include <sys/types.h> 44 #include <sys/file.h> 45 #include <sys/cred.h> 46 #include <sys/dlpi.h> 47 #include <sys/mac_provider.h> 48 #include <sys/disp.h> 49 #include <sys/sunndi.h> 50 #include <sys/modhash.h> 51 #include <sys/stropts.h> 52 #include <sys/sysmacros.h> 53 #include <sys/vlan.h> 54 #include <sys/softmac_impl.h> 55 #include <sys/softmac.h> 56 #include <sys/dls.h> 57 58 /* Used as a parameter to the mod hash walk of softmac structures */ 59 typedef struct { 60 softmac_t *smw_softmac; 61 boolean_t smw_retry; 62 } softmac_walk_t; 63 64 /* 65 * Softmac hash table including softmacs for both style-2 and style-1 devices. 66 */ 67 static krwlock_t softmac_hash_lock; 68 static mod_hash_t *softmac_hash; 69 static kmutex_t smac_global_lock; 70 static kcondvar_t smac_global_cv; 71 72 static kmem_cache_t *softmac_cachep; 73 74 #define SOFTMAC_HASHSZ 64 75 76 static void softmac_create_task(void *); 77 static void softmac_mac_register(softmac_t *); 78 static int softmac_create_datalink(softmac_t *); 79 static int softmac_m_start(void *); 80 static void softmac_m_stop(void *); 81 static int softmac_m_open(void *); 82 static void softmac_m_close(void *); 83 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *); 84 static int softmac_m_setprop(void *, const char *, mac_prop_id_t, 85 uint_t, const void *); 86 static int softmac_m_getprop(void *, const char *, mac_prop_id_t, 87 uint_t, uint_t, void *, uint_t *); 88 89 90 #define SOFTMAC_M_CALLBACK_FLAGS \ 91 (MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE | MC_SETPROP | MC_GETPROP) 92 93 static mac_callbacks_t softmac_m_callbacks = { 94 SOFTMAC_M_CALLBACK_FLAGS, 95 softmac_m_stat, 96 softmac_m_start, 97 softmac_m_stop, 98 softmac_m_promisc, 99 softmac_m_multicst, 100 softmac_m_unicst, 101 softmac_m_tx, 102 softmac_m_ioctl, 103 softmac_m_getcapab, 104 softmac_m_open, 105 softmac_m_close, 106 softmac_m_setprop, 107 softmac_m_getprop 108 }; 109 110 /*ARGSUSED*/ 111 static int 112 softmac_constructor(void *buf, void *arg, int kmflag) 113 { 114 softmac_t *softmac = buf; 115 116 bzero(buf, sizeof (softmac_t)); 117 mutex_init(&softmac->smac_mutex, NULL, MUTEX_DEFAULT, NULL); 118 mutex_init(&softmac->smac_active_mutex, NULL, MUTEX_DEFAULT, NULL); 119 mutex_init(&softmac->smac_fp_mutex, NULL, MUTEX_DEFAULT, NULL); 120 cv_init(&softmac->smac_cv, NULL, CV_DEFAULT, NULL); 121 cv_init(&softmac->smac_fp_cv, NULL, CV_DEFAULT, NULL); 122 list_create(&softmac->smac_sup_list, sizeof (softmac_upper_t), 123 offsetof(softmac_upper_t, su_list_node)); 124 return (0); 125 } 126 127 /*ARGSUSED*/ 128 static void 129 softmac_destructor(void *buf, void *arg) 130 { 131 softmac_t *softmac = buf; 132 133 ASSERT(softmac->smac_fp_disable_clients == 0); 134 ASSERT(!softmac->smac_fastpath_admin_disabled); 135 136 ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); 137 ASSERT(softmac->smac_hold_cnt == 0); 138 ASSERT(softmac->smac_attachok_cnt == 0); 139 ASSERT(softmac->smac_mh == NULL); 140 ASSERT(softmac->smac_softmac[0] == NULL && 141 softmac->smac_softmac[1] == NULL); 142 ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED); 143 ASSERT(softmac->smac_lower == NULL); 144 ASSERT(softmac->smac_active == B_FALSE); 145 ASSERT(softmac->smac_nactive == 0); 146 ASSERT(list_is_empty(&softmac->smac_sup_list)); 147 148 list_destroy(&softmac->smac_sup_list); 149 mutex_destroy(&softmac->smac_mutex); 150 mutex_destroy(&softmac->smac_active_mutex); 151 mutex_destroy(&softmac->smac_fp_mutex); 152 cv_destroy(&softmac->smac_cv); 153 cv_destroy(&softmac->smac_fp_cv); 154 } 155 156 void 157 softmac_init() 158 { 159 softmac_hash = mod_hash_create_extended("softmac_hash", 160 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 161 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 162 163 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL); 164 mutex_init(&smac_global_lock, NULL, MUTEX_DRIVER, NULL); 165 cv_init(&smac_global_cv, NULL, CV_DRIVER, NULL); 166 167 softmac_cachep = kmem_cache_create("softmac_cache", 168 sizeof (softmac_t), 0, softmac_constructor, 169 softmac_destructor, NULL, NULL, NULL, 0); 170 ASSERT(softmac_cachep != NULL); 171 softmac_fp_init(); 172 } 173 174 void 175 softmac_fini() 176 { 177 softmac_fp_fini(); 178 kmem_cache_destroy(softmac_cachep); 179 rw_destroy(&softmac_hash_lock); 180 mod_hash_destroy_hash(softmac_hash); 181 mutex_destroy(&smac_global_lock); 182 cv_destroy(&smac_global_cv); 183 } 184 185 /* ARGSUSED */ 186 static uint_t 187 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 188 { 189 boolean_t *pexist = arg; 190 191 *pexist = B_TRUE; 192 return (MH_WALK_TERMINATE); 193 } 194 195 boolean_t 196 softmac_busy() 197 { 198 boolean_t exist = B_FALSE; 199 200 rw_enter(&softmac_hash_lock, RW_READER); 201 mod_hash_walk(softmac_hash, softmac_exist, &exist); 202 rw_exit(&softmac_hash_lock); 203 return (exist); 204 } 205 206 /* 207 * 208 * softmac_create() is called for each minor node during the post-attach of 209 * each DDI_NT_NET device instance. Note that it is possible that a device 210 * instance has two minor nodes (DLPI style-1 and style-2), so that for that 211 * specific device, softmac_create() could be called twice. 212 * 213 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t 214 * is created to track each minor node. 215 * 216 * For each minor node of a legacy device, a taskq is started to finish 217 * softmac_mac_register(), which will finish the rest of work (see comments 218 * above softmac_mac_register()). 219 * 220 * softmac state machine 221 * -------------------------------------------------------------------------- 222 * OLD STATE EVENT NEW STATE 223 * -------------------------------------------------------------------------- 224 * UNINIT attach of 1st minor node ATTACH_INPROG 225 * okcnt = 0 net_postattach -> softmac_create okcnt = 1 226 * 227 * ATTACH_INPROG attach of 2nd minor node (GLDv3) ATTACH_DONE 228 * okcnt = 1 net_postattach -> softmac_create okcnt = 2 229 * 230 * ATTACH_INPROG attach of 2nd minor node (legacy) ATTACH_INPROG 231 * okcnt = 1 net_postattach -> softmac_create okcnt = 2 232 * schedule softmac_mac_register 233 * 234 * ATTACH_INPROG legacy device node ATTACH_DONE 235 * okcnt = 2 softmac_mac_register okcnt = 2 236 * 237 * ATTACH_DONE detach of 1st minor node DETACH_INPROG 238 * okcnt = 2 (success) okcnt = 1 239 * 240 * DETACH_INPROG detach of 2nd minor node UNINIT (or free) 241 * okcnt = 1 (success) okcnt = 0 242 * 243 * ATTACH_DONE detach failure state unchanged 244 * DETACH_INPROG left = okcnt 245 * 246 * DETACH_INPROG reattach ATTACH_INPROG 247 * okcnt = 0,1 net_postattach -> softmac_create 248 * 249 * ATTACH_DONE reattach ATTACH_DONE 250 * left != 0 net_postattach -> softmac_create left = 0 251 * 252 * Abbreviation notes: 253 * states have SOFTMAC_ prefix, 254 * okcnt - softmac_attach_okcnt, 255 * left - softmac_attached_left 256 */ 257 258 #ifdef DEBUG 259 void 260 softmac_state_verify(softmac_t *softmac) 261 { 262 ASSERT(MUTEX_HELD(&softmac->smac_mutex)); 263 264 /* 265 * There are at most 2 minor nodes, one per DLPI style 266 */ 267 ASSERT(softmac->smac_cnt <= 2 && softmac->smac_attachok_cnt <= 2); 268 269 /* 270 * The smac_attachok_cnt represents the number of attaches i.e. the 271 * number of times net_postattach -> softmac_create() has been called 272 * for a device instance. 273 */ 274 ASSERT(softmac->smac_attachok_cnt == SMAC_NONZERO_NODECNT(softmac)); 275 276 /* 277 * softmac_create (or softmac_mac_register) -> softmac_create_datalink 278 * happens only after all minor nodes have been attached 279 */ 280 ASSERT(softmac->smac_state != SOFTMAC_ATTACH_DONE || 281 softmac->smac_attachok_cnt == softmac->smac_cnt); 282 283 if (softmac->smac_attachok_cnt == 0) { 284 ASSERT(softmac->smac_state == SOFTMAC_UNINIT); 285 ASSERT(softmac->smac_mh == NULL); 286 } else if (softmac->smac_attachok_cnt < softmac->smac_cnt) { 287 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG || 288 softmac->smac_state == SOFTMAC_DETACH_INPROG); 289 ASSERT(softmac->smac_mh == NULL); 290 } else { 291 /* 292 * In the stable condition the state whould be 293 * SOFTMAC_ATTACH_DONE. But there is a small transient window 294 * in softmac_destroy where we change the state to 295 * SOFTMAC_DETACH_INPROG and drop the lock before doing 296 * the link destroy 297 */ 298 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 299 ASSERT(softmac->smac_state != SOFTMAC_UNINIT); 300 } 301 if (softmac->smac_mh != NULL) 302 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 303 } 304 #endif 305 306 #ifdef DEBUG 307 #define SOFTMAC_STATE_VERIFY(softmac) softmac_state_verify(softmac) 308 #else 309 #define SOFTMAC_STATE_VERIFY(softmac) 310 #endif 311 312 int 313 softmac_create(dev_info_t *dip, dev_t dev) 314 { 315 char devname[MAXNAMELEN]; 316 softmac_t *softmac; 317 softmac_dev_t *softmac_dev = NULL; 318 int index; 319 int ppa, err = 0; 320 321 /* 322 * Force the softmac driver to be attached. 323 */ 324 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) { 325 cmn_err(CE_WARN, "softmac_create:softmac attach fails"); 326 return (ENXIO); 327 } 328 329 if (GLDV3_DRV(ddi_driver_major(dip))) { 330 minor_t minor = getminor(dev); 331 /* 332 * For GLDv3, we don't care about the DLPI style 2 333 * compatibility node. (We know that all such devices 334 * have style 1 nodes.) 335 */ 336 if ((strcmp(ddi_driver_name(dip), "clone") == 0) || 337 (getmajor(dev) == ddi_name_to_major("clone")) || 338 (minor == 0)) { 339 return (0); 340 } 341 342 /* 343 * Likewise, we know that the minor number for DLPI style 1 344 * nodes is constrained to a maximum value. 345 */ 346 if (minor >= DLS_MAX_MINOR) { 347 return (ENOTSUP); 348 } 349 /* 350 * Otherwise we can decode the instance from the minor number, 351 * which allows for situations with multiple mac instances 352 * for a single dev_info_t. 353 */ 354 ppa = DLS_MINOR2INST(minor); 355 } else { 356 /* 357 * For legacy drivers, we just have to limit them to 358 * two minor nodes, one style 1 and one style 2, and 359 * we assume the ddi_get_instance() is the PPA. 360 * Drivers that need more flexibility should be ported 361 * to GLDv3. 362 */ 363 ppa = ddi_get_instance(dip); 364 if (i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { 365 cmn_err(CE_WARN, "%s has more than 2 minor nodes; " 366 "unsupported", devname); 367 return (ENOTSUP); 368 } 369 } 370 371 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 372 373 /* 374 * Check whether the softmac for the specified device already exists 375 */ 376 rw_enter(&softmac_hash_lock, RW_WRITER); 377 if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 378 (mod_hash_val_t *)&softmac)) != 0) { 379 380 softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP); 381 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); 382 383 err = mod_hash_insert(softmac_hash, 384 (mod_hash_key_t)softmac->smac_devname, 385 (mod_hash_val_t)softmac); 386 ASSERT(err == 0); 387 mutex_enter(&smac_global_lock); 388 cv_broadcast(&smac_global_cv); 389 mutex_exit(&smac_global_lock); 390 } 391 392 mutex_enter(&softmac->smac_mutex); 393 SOFTMAC_STATE_VERIFY(softmac); 394 if (softmac->smac_state != SOFTMAC_ATTACH_DONE) 395 softmac->smac_state = SOFTMAC_ATTACH_INPROG; 396 if (softmac->smac_attachok_cnt == 0) { 397 /* 398 * Initialize the softmac if this is the post-attach of the 399 * first minor node. 400 */ 401 softmac->smac_flags = 0; 402 softmac->smac_umajor = ddi_driver_major(dip); 403 softmac->smac_uppa = ppa; 404 405 /* 406 * For GLDv3, we ignore the style 2 node (see the logic 407 * above on that), and we should have exactly one attach 408 * per MAC instance (possibly more than one per dev_info_t). 409 */ 410 if (GLDV3_DRV(ddi_driver_major(dip))) { 411 softmac->smac_flags |= SOFTMAC_GLDV3; 412 softmac->smac_cnt = 1; 413 } else { 414 softmac->smac_cnt = 415 i_ddi_minor_node_count(dip, DDI_NT_NET); 416 } 417 } 418 419 index = (getmajor(dev) == ddi_name_to_major("clone")); 420 if (softmac->smac_softmac[index] != NULL) { 421 /* 422 * This is possible if the post_attach() is called after 423 * pre_detach() fails. This seems to be a defect of the DACF 424 * framework. We work around it by using a smac_attached_left 425 * field that tracks this 426 */ 427 ASSERT(softmac->smac_attached_left != 0); 428 softmac->smac_attached_left--; 429 mutex_exit(&softmac->smac_mutex); 430 rw_exit(&softmac_hash_lock); 431 return (0); 432 433 } 434 mutex_exit(&softmac->smac_mutex); 435 rw_exit(&softmac_hash_lock); 436 437 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); 438 softmac_dev->sd_dev = dev; 439 440 mutex_enter(&softmac->smac_mutex); 441 softmac->smac_softmac[index] = softmac_dev; 442 /* 443 * Continue to register the mac and create the datalink only when all 444 * the minor nodes are attached. 445 */ 446 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { 447 mutex_exit(&softmac->smac_mutex); 448 return (0); 449 } 450 451 /* 452 * All of the minor nodes have been attached; start a taskq 453 * to do the rest of the work. We use a taskq instead of 454 * doing the work here because: 455 * 456 * We could be called as a result of a open() system call 457 * where spec_open() already SLOCKED the snode. Using a taskq 458 * sidesteps the risk that our ldi_open_by_dev() call would 459 * deadlock trying to set SLOCKED on the snode again. 460 * 461 * The devfs design requires that the downcalls don't use any 462 * interruptible cv_wait which happens when we do door upcalls. 463 * Otherwise the downcalls which may be holding devfs resources 464 * may cause a deadlock if the thread is stopped. Also we need to make 465 * sure these downcalls into softmac_create or softmac_destroy 466 * don't cv_wait on any devfs related condition. Thus softmac_destroy 467 * returns EBUSY if the asynchronous threads started in softmac_create 468 * haven't finished. 469 */ 470 (void) taskq_dispatch(system_taskq, softmac_create_task, 471 softmac, TQ_SLEEP); 472 mutex_exit(&softmac->smac_mutex); 473 return (0); 474 } 475 476 static boolean_t 477 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 478 { 479 softmac_t *softmac = arg; 480 481 if (!(softmac->smac_capab_flags & cap)) 482 return (B_FALSE); 483 484 switch (cap) { 485 case MAC_CAPAB_HCKSUM: { 486 uint32_t *txflags = cap_data; 487 488 *txflags = softmac->smac_hcksum_txflags; 489 break; 490 } 491 case MAC_CAPAB_LEGACY: { 492 mac_capab_legacy_t *legacy = cap_data; 493 494 /* 495 * The caller is not interested in the details. 496 */ 497 if (legacy == NULL) 498 break; 499 500 legacy->ml_unsup_note = ~softmac->smac_notifications & 501 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 502 legacy->ml_active_set = softmac_active_set; 503 legacy->ml_active_clear = softmac_active_clear; 504 legacy->ml_fastpath_disable = softmac_fastpath_disable; 505 legacy->ml_fastpath_enable = softmac_fastpath_enable; 506 legacy->ml_dev = makedevice(softmac->smac_umajor, 507 softmac->smac_uppa + 1); 508 break; 509 } 510 511 /* 512 * For the capabilities below, there's nothing for us to fill in; 513 * simply return B_TRUE if we support it. 514 */ 515 case MAC_CAPAB_NO_ZCOPY: 516 case MAC_CAPAB_NO_NATIVEVLAN: 517 default: 518 break; 519 } 520 return (B_TRUE); 521 } 522 523 static int 524 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 525 { 526 datalink_id_t linkid = DATALINK_INVALID_LINKID; 527 uint32_t media; 528 int err; 529 530 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 531 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 532 *linkidp = linkid; 533 } 534 535 if (err == EEXIST) { 536 /* 537 * There is a link name conflict. Either: 538 * 539 * - An existing link with the same device name with a 540 * different media type from of the given type. 541 * Mark this link back to persistent only; or 542 * 543 * - We cannot assign the "suggested" name because 544 * GLDv3 and therefore vanity naming is not supported 545 * for this link type. Delete this link's <link name, 546 * linkid> mapping. 547 */ 548 if (media != softmac->smac_media) { 549 cmn_err(CE_WARN, "%s device %s conflicts with " 550 "existing %s device %s.", 551 dl_mactypestr(softmac->smac_media), 552 softmac->smac_devname, dl_mactypestr(media), 553 softmac->smac_devname); 554 (void) dls_mgmt_destroy(linkid, B_FALSE); 555 } else { 556 cmn_err(CE_WARN, "link name %s is already in-use.", 557 softmac->smac_devname); 558 (void) dls_mgmt_destroy(linkid, B_TRUE); 559 } 560 561 cmn_err(CE_WARN, "%s device might not be available " 562 "for use.", softmac->smac_devname); 563 cmn_err(CE_WARN, "See dladm(1M) for more information."); 564 } 565 566 return (err); 567 } 568 569 /* 570 * This function: 571 * 1. provides the link's media type to dlmgmtd. 572 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 573 */ 574 static int 575 softmac_create_datalink(softmac_t *softmac) 576 { 577 datalink_id_t linkid = DATALINK_INVALID_LINKID; 578 int err; 579 580 /* 581 * Inform dlmgmtd of this link so that softmac_hold_device() is able 582 * to know the existence of this link. If this failed with EBADF, 583 * it might be because dlmgmtd was not started in time (e.g., 584 * diskless boot); ignore the failure and continue to create 585 * the GLDv3 datalink if needed. 586 */ 587 err = dls_mgmt_create(softmac->smac_devname, 588 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 589 DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 590 if (err != 0 && err != EBADF) 591 return (err); 592 593 /* 594 * Provide the media type of the physical link to dlmgmtd. 595 */ 596 if ((err != EBADF) && 597 ((err = softmac_update_info(softmac, &linkid)) != 0)) { 598 return (err); 599 } 600 601 /* 602 * Create the GLDv3 datalink. 603 */ 604 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 605 err = dls_devnet_create(softmac->smac_mh, linkid, 606 crgetzoneid(CRED())); 607 if (err != 0) { 608 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 609 softmac->smac_devname); 610 return (err); 611 } 612 } 613 614 if (linkid == DATALINK_INVALID_LINKID) { 615 mutex_enter(&softmac->smac_mutex); 616 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 617 mutex_exit(&softmac->smac_mutex); 618 } 619 620 return (0); 621 } 622 623 static void 624 softmac_create_task(void *arg) 625 { 626 softmac_t *softmac = arg; 627 mac_handle_t mh; 628 int err; 629 630 if (!GLDV3_DRV(softmac->smac_umajor)) { 631 softmac_mac_register(softmac); 632 return; 633 } 634 635 if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 636 goto done; 637 638 mutex_enter(&softmac->smac_mutex); 639 softmac->smac_media = (mac_info(mh))->mi_nativemedia; 640 softmac->smac_mh = mh; 641 mutex_exit(&softmac->smac_mutex); 642 643 /* 644 * We can safely release the reference on the mac because 645 * this mac will only be unregistered and destroyed when 646 * the device detaches, and the softmac will be destroyed 647 * before then (in the pre-detach routine of the device). 648 */ 649 mac_close(mh); 650 651 /* 652 * Create the GLDv3 datalink for this mac. 653 */ 654 err = softmac_create_datalink(softmac); 655 656 done: 657 mutex_enter(&softmac->smac_mutex); 658 if (err != 0) 659 softmac->smac_mh = NULL; 660 softmac->smac_attacherr = err; 661 softmac->smac_state = SOFTMAC_ATTACH_DONE; 662 cv_broadcast(&softmac->smac_cv); 663 mutex_exit(&softmac->smac_mutex); 664 } 665 666 /* 667 * This function is only called for legacy devices. It: 668 * 1. registers the MAC for the legacy devices whose media type is supported 669 * by the GLDv3 framework. 670 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 671 */ 672 static void 673 softmac_mac_register(softmac_t *softmac) 674 { 675 softmac_dev_t *softmac_dev; 676 dev_t dev; 677 ldi_handle_t lh = NULL; 678 ldi_ident_t li = NULL; 679 int index; 680 boolean_t native_vlan = B_FALSE; 681 int err; 682 683 /* 684 * Note that we do not need any locks to access this softmac pointer, 685 * as softmac_destroy() will wait until this function is called. 686 */ 687 ASSERT(softmac != NULL); 688 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 689 softmac->smac_attachok_cnt == softmac->smac_cnt); 690 691 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 692 mutex_enter(&softmac->smac_mutex); 693 goto done; 694 } 695 696 /* 697 * Determine whether this legacy device support VLANs by opening 698 * the style-2 device node (if it exists) and attaching to a VLAN 699 * PPA (1000 + ppa). 700 */ 701 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 702 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 703 if (err == 0) { 704 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 705 native_vlan = B_TRUE; 706 (void) ldi_close(lh, FREAD|FWRITE, kcred); 707 } 708 709 err = EINVAL; 710 for (index = 0; index < 2; index++) { 711 dl_info_ack_t dlia; 712 dl_error_ack_t dlea; 713 uint32_t notes; 714 struct strioctl iocb; 715 uint32_t margin; 716 int rval; 717 718 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 719 continue; 720 721 softmac->smac_dev = dev = softmac_dev->sd_dev; 722 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 723 li) != 0) { 724 continue; 725 } 726 727 /* 728 * Pop all the intermediate modules in order to negotiate 729 * capabilities correctly. 730 */ 731 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 732 ; 733 734 /* DLPI style-1 or DLPI style-2? */ 735 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 736 if (rval == ENOTSUP) { 737 cmn_err(CE_NOTE, "softmac: received " 738 "DL_ERROR_ACK to DL_INFO_ACK; " 739 "DLPI errno 0x%x, UNIX errno %d", 740 dlea.dl_errno, dlea.dl_unix_errno); 741 } 742 (void) ldi_close(lh, FREAD|FWRITE, kcred); 743 continue; 744 } 745 746 /* 747 * Currently only DL_ETHER has GLDv3 mac plugin support. 748 * For media types that GLDv3 does not support, create a 749 * link id for it. 750 */ 751 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 752 (void) ldi_close(lh, FREAD|FWRITE, kcred); 753 err = 0; 754 break; 755 } 756 757 if ((dlia.dl_provider_style == DL_STYLE2) && 758 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 759 (void) ldi_close(lh, FREAD|FWRITE, kcred); 760 continue; 761 } 762 763 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 764 if (rval == ENOTSUP) { 765 cmn_err(CE_NOTE, "softmac: received " 766 "DL_ERROR_ACK to DL_BIND_ACK; " 767 "DLPI errno 0x%x, UNIX errno %d", 768 dlea.dl_errno, dlea.dl_unix_errno); 769 } 770 (void) ldi_close(lh, FREAD|FWRITE, kcred); 771 continue; 772 } 773 774 /* 775 * Call dl_info() after dl_bind() because some drivers only 776 * provide correct information (e.g. MAC address) once bound. 777 */ 778 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 779 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 780 &softmac->smac_addrlen, &dlea)) != 0) { 781 if (rval == ENOTSUP) { 782 cmn_err(CE_NOTE, "softmac: received " 783 "DL_ERROR_ACK to DL_INFO_ACK; " 784 "DLPI errno 0x%x, UNIX errno %d", 785 dlea.dl_errno, dlea.dl_unix_errno); 786 } 787 (void) ldi_close(lh, FREAD|FWRITE, kcred); 788 continue; 789 } 790 791 softmac->smac_style = dlia.dl_provider_style; 792 softmac->smac_saplen = ABS(dlia.dl_sap_length); 793 softmac->smac_min_sdu = dlia.dl_min_sdu; 794 softmac->smac_max_sdu = dlia.dl_max_sdu; 795 796 if ((softmac->smac_saplen != sizeof (uint16_t)) || 797 (softmac->smac_addrlen != ETHERADDRL) || 798 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 799 (dlia.dl_brdcst_addr_offset == 0)) { 800 (void) ldi_close(lh, FREAD|FWRITE, kcred); 801 continue; 802 } 803 804 /* 805 * Check other DLPI capabilities. Note that this must be after 806 * dl_bind() because some drivers return DL_ERROR_ACK if the 807 * stream is not bound. It is also before mac_register(), so 808 * we don't need any lock protection here. 809 */ 810 softmac->smac_capab_flags = 811 (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 812 813 softmac->smac_no_capability_req = B_FALSE; 814 if (softmac_fill_capab(lh, softmac) != 0) 815 softmac->smac_no_capability_req = B_TRUE; 816 817 /* 818 * Check the margin of the underlying driver. 819 */ 820 margin = 0; 821 iocb.ic_cmd = DLIOCMARGININFO; 822 iocb.ic_timout = INFTIM; 823 iocb.ic_len = sizeof (margin); 824 iocb.ic_dp = (char *)&margin; 825 softmac->smac_margin = 0; 826 827 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 828 &rval) == 0) { 829 softmac->smac_margin = margin; 830 } 831 832 /* 833 * If the legacy driver doesn't support DLIOCMARGININFO, but 834 * it can support native VLAN, correct its margin value to 4. 835 */ 836 if (native_vlan) { 837 if (softmac->smac_margin == 0) 838 softmac->smac_margin = VLAN_TAGSZ; 839 } else { 840 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 841 } 842 843 /* 844 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 845 */ 846 softmac->smac_notifications = 0; 847 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 848 switch (dl_notify(lh, ¬es, NULL)) { 849 case 0: 850 softmac->smac_notifications = notes; 851 break; 852 case ENOTSUP: 853 break; 854 default: 855 (void) ldi_close(lh, FREAD|FWRITE, kcred); 856 continue; 857 } 858 859 (void) ldi_close(lh, FREAD|FWRITE, kcred); 860 err = 0; 861 break; 862 } 863 ldi_ident_release(li); 864 865 mutex_enter(&softmac->smac_mutex); 866 867 if (err != 0) 868 goto done; 869 870 if (softmac->smac_media != DL_ETHER) 871 softmac->smac_flags |= SOFTMAC_NOSUPP; 872 873 /* 874 * Finally, we're ready to register ourselves with the MAC layer 875 * interface; if this succeeds, we're all ready to start() 876 */ 877 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 878 mac_register_t *macp; 879 880 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 881 err = ENOMEM; 882 goto done; 883 } 884 885 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 886 macp->m_driver = softmac; 887 macp->m_dip = softmac_dip; 888 889 macp->m_margin = softmac->smac_margin; 890 macp->m_src_addr = softmac->smac_unicst_addr; 891 macp->m_min_sdu = softmac->smac_min_sdu; 892 macp->m_max_sdu = softmac->smac_max_sdu; 893 macp->m_callbacks = &softmac_m_callbacks; 894 macp->m_instance = (uint_t)-1; 895 896 err = mac_register(macp, &softmac->smac_mh); 897 mac_free(macp); 898 if (err != 0) { 899 cmn_err(CE_WARN, "mac_register failed for %s", 900 softmac->smac_devname); 901 goto done; 902 } 903 } 904 mutex_exit(&softmac->smac_mutex); 905 906 /* 907 * Try to create the datalink for this softmac. 908 */ 909 if ((err = softmac_create_datalink(softmac)) != 0) { 910 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) 911 (void) mac_unregister(softmac->smac_mh); 912 mutex_enter(&softmac->smac_mutex); 913 softmac->smac_mh = NULL; 914 goto done; 915 } 916 /* 917 * If succeed, create the thread which handles the DL_NOTIFY_IND from 918 * the lower stream. 919 */ 920 mutex_enter(&softmac->smac_mutex); 921 if (softmac->smac_mh != NULL) { 922 softmac->smac_notify_thread = thread_create(NULL, 0, 923 softmac_notify_thread, softmac, 0, &p0, 924 TS_RUN, minclsyspri); 925 } 926 927 done: 928 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 929 softmac->smac_attachok_cnt == softmac->smac_cnt); 930 softmac->smac_state = SOFTMAC_ATTACH_DONE; 931 softmac->smac_attacherr = err; 932 cv_broadcast(&softmac->smac_cv); 933 mutex_exit(&softmac->smac_mutex); 934 } 935 936 int 937 softmac_destroy(dev_info_t *dip, dev_t dev) 938 { 939 char devname[MAXNAMELEN]; 940 softmac_t *softmac; 941 softmac_dev_t *softmac_dev; 942 int index; 943 int ppa, err; 944 datalink_id_t linkid; 945 mac_handle_t smac_mh; 946 uint32_t smac_flags; 947 948 if (GLDV3_DRV(ddi_driver_major(dip))) { 949 minor_t minor = getminor(dev); 950 /* 951 * For an explanation of this logic, see the 952 * equivalent code in softmac_create. 953 */ 954 if ((strcmp(ddi_driver_name(dip), "clone") == 0) || 955 (getmajor(dev) == ddi_name_to_major("clone")) || 956 (minor == 0)) { 957 return (0); 958 } 959 if (minor >= DLS_MAX_MINOR) { 960 return (ENOTSUP); 961 } 962 ppa = DLS_MINOR2INST(minor); 963 } else { 964 ppa = ddi_get_instance(dip); 965 } 966 967 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 968 969 /* 970 * We are called only from the predetach entry point. The DACF 971 * framework ensures there can't be a concurrent postattach call 972 * for the same softmac. The softmac found out from the modhash 973 * below can't vanish beneath us since this is the only place where 974 * it is deleted. 975 */ 976 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 977 (mod_hash_val_t *)&softmac); 978 ASSERT(err == 0); 979 980 mutex_enter(&softmac->smac_mutex); 981 SOFTMAC_STATE_VERIFY(softmac); 982 983 /* 984 * Fail the predetach routine if this softmac is in-use. 985 * Make sure these downcalls into softmac_create or softmac_destroy 986 * don't cv_wait on any devfs related condition. Thus softmac_destroy 987 * returns EBUSY if the asynchronous thread started in softmac_create 988 * hasn't finished 989 */ 990 if ((softmac->smac_hold_cnt != 0) || 991 (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) { 992 softmac->smac_attached_left = softmac->smac_attachok_cnt; 993 mutex_exit(&softmac->smac_mutex); 994 return (EBUSY); 995 } 996 997 /* 998 * Even if the predetach of one minor node has already failed 999 * (smac_attached_left is not 0), the DACF framework will continue 1000 * to call the predetach routines of the other minor nodes, 1001 * so we fail these calls here. 1002 */ 1003 if (softmac->smac_attached_left != 0) { 1004 mutex_exit(&softmac->smac_mutex); 1005 return (EBUSY); 1006 } 1007 1008 smac_mh = softmac->smac_mh; 1009 smac_flags = softmac->smac_flags; 1010 softmac->smac_state = SOFTMAC_DETACH_INPROG; 1011 mutex_exit(&softmac->smac_mutex); 1012 1013 if (smac_mh != NULL) { 1014 /* 1015 * This is the first minor node that is being detached for this 1016 * softmac. 1017 */ 1018 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 1019 if (!(smac_flags & SOFTMAC_NOSUPP)) { 1020 if ((err = dls_devnet_destroy(smac_mh, &linkid, 1021 B_FALSE)) != 0) { 1022 goto error; 1023 } 1024 } 1025 /* 1026 * If softmac_mac_register() succeeds in registering the mac 1027 * of the legacy device, unregister it. 1028 */ 1029 if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 1030 if ((err = mac_disable_nowait(smac_mh)) != 0) { 1031 (void) dls_devnet_create(smac_mh, linkid, 1032 crgetzoneid(CRED())); 1033 goto error; 1034 } 1035 /* 1036 * Ask softmac_notify_thread to quit, and wait for 1037 * that to be done. 1038 */ 1039 mutex_enter(&softmac->smac_mutex); 1040 softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT; 1041 cv_broadcast(&softmac->smac_cv); 1042 while (softmac->smac_notify_thread != NULL) { 1043 cv_wait(&softmac->smac_cv, 1044 &softmac->smac_mutex); 1045 } 1046 mutex_exit(&softmac->smac_mutex); 1047 VERIFY(mac_unregister(smac_mh) == 0); 1048 } 1049 softmac->smac_mh = NULL; 1050 } 1051 1052 /* 1053 * Free softmac_dev 1054 */ 1055 rw_enter(&softmac_hash_lock, RW_WRITER); 1056 mutex_enter(&softmac->smac_mutex); 1057 1058 ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG && 1059 softmac->smac_attachok_cnt != 0); 1060 softmac->smac_mh = NULL; 1061 index = (getmajor(dev) == ddi_name_to_major("clone")); 1062 softmac_dev = softmac->smac_softmac[index]; 1063 ASSERT(softmac_dev != NULL); 1064 softmac->smac_softmac[index] = NULL; 1065 kmem_free(softmac_dev, sizeof (softmac_dev_t)); 1066 1067 if (--softmac->smac_attachok_cnt == 0) { 1068 mod_hash_val_t hashval; 1069 1070 softmac->smac_state = SOFTMAC_UNINIT; 1071 if (softmac->smac_hold_cnt != 0) { 1072 /* 1073 * Someone did a softmac_hold_device while we dropped 1074 * the locks. Leave the softmac itself intact which 1075 * will be reused by the reattach 1076 */ 1077 mutex_exit(&softmac->smac_mutex); 1078 rw_exit(&softmac_hash_lock); 1079 return (0); 1080 } 1081 err = mod_hash_remove(softmac_hash, 1082 (mod_hash_key_t)devname, 1083 (mod_hash_val_t *)&hashval); 1084 ASSERT(err == 0); 1085 1086 mutex_exit(&softmac->smac_mutex); 1087 rw_exit(&softmac_hash_lock); 1088 ASSERT(softmac->smac_fp_disable_clients == 0); 1089 softmac->smac_fastpath_admin_disabled = B_FALSE; 1090 kmem_cache_free(softmac_cachep, softmac); 1091 return (0); 1092 } 1093 mutex_exit(&softmac->smac_mutex); 1094 rw_exit(&softmac_hash_lock); 1095 return (0); 1096 1097 error: 1098 mutex_enter(&softmac->smac_mutex); 1099 softmac->smac_attached_left = softmac->smac_attachok_cnt; 1100 softmac->smac_state = SOFTMAC_ATTACH_DONE; 1101 cv_broadcast(&softmac->smac_cv); 1102 mutex_exit(&softmac->smac_mutex); 1103 return (err); 1104 } 1105 1106 /* 1107 * This function is called as the result of a newly started dlmgmtd daemon. 1108 * 1109 * We walk through every softmac that was created but failed to notify 1110 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 1111 * when softmacs are created before dlmgmtd is ready. For example, during 1112 * diskless boot, a network device is used (and therefore attached) before 1113 * the datalink-management service starts dlmgmtd. 1114 */ 1115 /* ARGSUSED */ 1116 static uint_t 1117 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1118 { 1119 softmac_t *softmac = (softmac_t *)val; 1120 datalink_id_t linkid; 1121 int err; 1122 softmac_walk_t *smwp = arg; 1123 1124 /* 1125 * The framework itself must not hold any locks across calls to the 1126 * mac perimeter. Thus this function does not call any framework 1127 * function that needs to grab the mac perimeter. 1128 */ 1129 ASSERT(RW_READ_HELD(&softmac_hash_lock)); 1130 1131 smwp->smw_retry = B_FALSE; 1132 mutex_enter(&softmac->smac_mutex); 1133 SOFTMAC_STATE_VERIFY(softmac); 1134 if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) { 1135 /* 1136 * Wait till softmac_create or softmac_mac_register finishes 1137 * Hold the softmac to ensure it stays around. The wait itself 1138 * is done in the caller, since we need to drop all locks 1139 * including the mod hash's internal lock before calling 1140 * cv_wait. 1141 */ 1142 smwp->smw_retry = B_TRUE; 1143 smwp->smw_softmac = softmac; 1144 softmac->smac_hold_cnt++; 1145 return (MH_WALK_TERMINATE); 1146 } 1147 1148 if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) || 1149 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 1150 mutex_exit(&softmac->smac_mutex); 1151 return (MH_WALK_CONTINUE); 1152 } 1153 1154 /* 1155 * Bumping up the smac_hold_cnt allows us to drop the lock. It also 1156 * makes softmac_destroy() return failure on an attempted device detach. 1157 * We don't want to hold the lock across calls to other subsystems 1158 * like kstats, which will happen in the call to dls_devnet_recreate 1159 */ 1160 softmac->smac_hold_cnt++; 1161 mutex_exit(&softmac->smac_mutex); 1162 1163 if (dls_mgmt_create(softmac->smac_devname, 1164 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 1165 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 1166 softmac_rele_device((dls_dev_handle_t)softmac); 1167 return (MH_WALK_CONTINUE); 1168 } 1169 1170 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 1171 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 1172 "failed (%d)", softmac->smac_devname, err); 1173 softmac_rele_device((dls_dev_handle_t)softmac); 1174 return (MH_WALK_CONTINUE); 1175 } 1176 1177 /* 1178 * Create a link for this MAC. The link name will be the same 1179 * as the MAC name. 1180 */ 1181 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 1182 err = dls_devnet_recreate(softmac->smac_mh, linkid); 1183 if (err != 0) { 1184 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 1185 "%s (linkid %d) failed (%d)", 1186 softmac->smac_devname, linkid, err); 1187 } 1188 } 1189 1190 mutex_enter(&softmac->smac_mutex); 1191 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 1192 ASSERT(softmac->smac_hold_cnt != 0); 1193 softmac->smac_hold_cnt--; 1194 mutex_exit(&softmac->smac_mutex); 1195 1196 return (MH_WALK_CONTINUE); 1197 } 1198 1199 /* 1200 * See comments above softmac_mac_recreate(). 1201 */ 1202 void 1203 softmac_recreate() 1204 { 1205 softmac_walk_t smw; 1206 softmac_t *softmac; 1207 1208 /* 1209 * Walk through the softmac_hash table. Request to create the 1210 * [link name, linkid] mapping if we failed to do so. 1211 */ 1212 do { 1213 smw.smw_retry = B_FALSE; 1214 rw_enter(&softmac_hash_lock, RW_READER); 1215 mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw); 1216 rw_exit(&softmac_hash_lock); 1217 if (smw.smw_retry) { 1218 /* 1219 * softmac_create or softmac_mac_register hasn't yet 1220 * finished and the softmac is not yet in the 1221 * SOFTMAC_ATTACH_DONE state. 1222 */ 1223 softmac = smw.smw_softmac; 1224 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1225 softmac->smac_hold_cnt--; 1226 mutex_exit(&softmac->smac_mutex); 1227 } 1228 } while (smw.smw_retry); 1229 } 1230 1231 static int 1232 softmac_m_start(void *arg) 1233 { 1234 softmac_t *softmac = arg; 1235 softmac_lower_t *slp = softmac->smac_lower; 1236 int err; 1237 1238 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1239 /* 1240 * Bind to SAP 2 on token ring, 0 on other interface types. 1241 * (SAP 0 has special significance on token ring). 1242 * Note that the receive-side packets could come anytime after bind. 1243 */ 1244 err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0); 1245 if (err != 0) 1246 return (err); 1247 1248 /* 1249 * Put the lower stream to the DL_PROMISC_SAP mode in order to receive 1250 * all packets of interest. 1251 * 1252 * some driver (e.g. the old legacy eri driver) incorrectly passes up 1253 * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 1254 * so that we send DL_PROMISON_REQ after DL_BIND_REQ. 1255 */ 1256 err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE); 1257 if (err != 0) { 1258 (void) softmac_send_unbind_req(slp); 1259 return (err); 1260 } 1261 1262 /* 1263 * Enable capabilities the underlying driver claims to support. 1264 * Some driver requires this being called after the stream is bound. 1265 */ 1266 if ((err = softmac_capab_enable(slp)) != 0) { 1267 (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE); 1268 (void) softmac_send_unbind_req(slp); 1269 } 1270 1271 return (err); 1272 } 1273 1274 /* ARGSUSED */ 1275 static void 1276 softmac_m_stop(void *arg) 1277 { 1278 softmac_t *softmac = arg; 1279 softmac_lower_t *slp = softmac->smac_lower; 1280 1281 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1282 1283 /* 1284 * It is not needed to reset zerocopy, MDT or HCKSUM capabilities. 1285 */ 1286 (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE); 1287 (void) softmac_send_unbind_req(slp); 1288 } 1289 1290 /* 1291 * Set up the lower stream above the legacy device. There are two different 1292 * type of lower streams: 1293 * 1294 * - Shared lower-stream 1295 * 1296 * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW 1297 * mode to send and receive the raw data. Further, put the lower stream into 1298 * DL_PROMISC_SAP mode to receive all packets of interest. 1299 * 1300 * - Dedicated lower-stream 1301 * 1302 * The lower-stream which is dedicated to upper IP/ARP stream. This is used 1303 * as fast-path for IP. In this case, the second argument is the pointer to 1304 * the softmac upper-stream. 1305 */ 1306 int 1307 softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup, 1308 softmac_lower_t **slpp) 1309 { 1310 ldi_ident_t li; 1311 dev_t dev; 1312 ldi_handle_t lh = NULL; 1313 softmac_lower_t *slp = NULL; 1314 smac_ioc_start_t start_arg; 1315 struct strioctl strioc; 1316 uint32_t notifications; 1317 int err, rval; 1318 1319 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 1320 return (err); 1321 1322 /* 1323 * The GLDv3 framework makes sure that mac_unregister(), mac_open(), 1324 * and mac_close() cannot be called at the same time. So we don't 1325 * need any protection to access softmac here. 1326 */ 1327 dev = softmac->smac_dev; 1328 1329 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 1330 ldi_ident_release(li); 1331 if (err != 0) 1332 goto done; 1333 1334 /* 1335 * Pop all the intermediate modules. The autopushed modules will 1336 * be pushed when the softmac node is opened. 1337 */ 1338 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 1339 ; 1340 1341 if ((softmac->smac_style == DL_STYLE2) && 1342 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 1343 goto done; 1344 } 1345 1346 /* 1347 * If this is the shared-lower-stream, put the lower stream to 1348 * the DLIOCRAW mode to send/receive raw data. 1349 */ 1350 if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, 1351 kcred, &rval)) != 0) { 1352 goto done; 1353 } 1354 1355 /* 1356 * Then push the softmac shim layer atop the lower stream. 1357 */ 1358 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 1359 kcred, &rval)) != 0) { 1360 goto done; 1361 } 1362 1363 /* 1364 * Send the ioctl to get the slp pointer. 1365 */ 1366 strioc.ic_cmd = SMAC_IOC_START; 1367 strioc.ic_timout = INFTIM; 1368 strioc.ic_len = sizeof (start_arg); 1369 strioc.ic_dp = (char *)&start_arg; 1370 1371 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 1372 kcred, &rval)) != 0) { 1373 goto done; 1374 } 1375 slp = start_arg.si_slp; 1376 slp->sl_sup = sup; 1377 slp->sl_lh = lh; 1378 slp->sl_softmac = softmac; 1379 *slpp = slp; 1380 1381 if (sup != NULL) { 1382 slp->sl_rxinfo = &sup->su_rxinfo; 1383 } else { 1384 /* 1385 * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 1386 * We don't have to wait for the ack. 1387 */ 1388 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 1389 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 1390 DL_NOTE_PROMISC_OFF_PHYS; 1391 1392 (void) softmac_send_notify_req(slp, 1393 (notifications & softmac->smac_notifications)); 1394 } 1395 1396 done: 1397 if (err != 0) 1398 (void) ldi_close(lh, FREAD|FWRITE, kcred); 1399 return (err); 1400 } 1401 1402 static int 1403 softmac_m_open(void *arg) 1404 { 1405 softmac_t *softmac = arg; 1406 softmac_lower_t *slp; 1407 int err; 1408 1409 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1410 1411 if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0) 1412 return (err); 1413 1414 softmac->smac_lower = slp; 1415 return (0); 1416 } 1417 1418 static void 1419 softmac_m_close(void *arg) 1420 { 1421 softmac_t *softmac = arg; 1422 softmac_lower_t *slp; 1423 1424 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1425 slp = softmac->smac_lower; 1426 ASSERT(slp != NULL); 1427 1428 /* 1429 * Note that slp is destroyed when lh is closed. 1430 */ 1431 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1432 softmac->smac_lower = NULL; 1433 } 1434 1435 /* 1436 * Softmac supports two priviate link properteis: 1437 * 1438 * - "_fastpath" 1439 * 1440 * This is a read-only link property which points out the current data-path 1441 * model of the given legacy link. The possible values are "disabled" and 1442 * "enabled". 1443 * 1444 * - "_disable_fastpath" 1445 * 1446 * This is a read-write link property which can be used to disable or enable 1447 * the fast-path of the given legacy link. The possible values are "true" 1448 * and "false". Note that even when "_disable_fastpath" is set to be 1449 * "false", the fast-path may still not be enabled since there may be 1450 * other mac cleints that request the fast-path to be disabled. 1451 */ 1452 /* ARGSUSED */ 1453 static int 1454 softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id, 1455 uint_t valsize, const void *val) 1456 { 1457 softmac_t *softmac = arg; 1458 1459 if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0) 1460 return (ENOTSUP); 1461 1462 if (strcmp(val, "true") == 0) 1463 return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE)); 1464 else if (strcmp(val, "false") == 0) 1465 return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE)); 1466 else 1467 return (EINVAL); 1468 } 1469 1470 static int 1471 softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t flags, 1472 uint_t valsize, void *val, uint_t *perm) 1473 { 1474 softmac_t *softmac = arg; 1475 char *fpstr; 1476 1477 if (id != MAC_PROP_PRIVATE) 1478 return (ENOTSUP); 1479 1480 if (strcmp(name, "_fastpath") == 0) { 1481 if ((flags & MAC_PROP_DEFAULT) != 0) 1482 return (ENOTSUP); 1483 1484 *perm = MAC_PROP_PERM_READ; 1485 mutex_enter(&softmac->smac_fp_mutex); 1486 fpstr = (DATAPATH_MODE(softmac) == SOFTMAC_SLOWPATH) ? 1487 "disabled" : "enabled"; 1488 mutex_exit(&softmac->smac_fp_mutex); 1489 } else if (strcmp(name, "_disable_fastpath") == 0) { 1490 *perm = MAC_PROP_PERM_RW; 1491 fpstr = ((flags & MAC_PROP_DEFAULT) != 0) ? "false" : 1492 (softmac->smac_fastpath_admin_disabled ? "true" : "false"); 1493 } else { 1494 return (ENOTSUP); 1495 } 1496 1497 return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0); 1498 } 1499 1500 int 1501 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 1502 { 1503 dev_info_t *dip; 1504 const char *drvname; 1505 char devname[MAXNAMELEN]; 1506 softmac_t *softmac; 1507 int ppa, err, inst; 1508 1509 drvname = ddi_major_to_name(getmajor(dev)); 1510 1511 /* 1512 * Exclude non-physical network device instances, for example, aggr0. 1513 */ 1514 if (!NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 1515 (strcmp(drvname, "vnic") == 0)) { 1516 return (ENOENT); 1517 } 1518 1519 /* 1520 * We have to lookup the device instance using getinfo(9e). 1521 */ 1522 inst = dev_to_instance(dev); 1523 if (inst < 0) 1524 return (ENOENT); 1525 1526 if ((ppa = getminor(dev) - 1) > 1000) 1527 return (ENOENT); 1528 1529 /* 1530 * First try to hold this device instance to force the MAC 1531 * to be registered. 1532 */ 1533 if ((dip = ddi_hold_devi_by_instance(getmajor(dev), inst, 0)) == NULL) 1534 return (ENOENT); 1535 1536 /* 1537 * This is a network device; wait for its softmac to be registered. 1538 */ 1539 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 1540 again: 1541 rw_enter(&softmac_hash_lock, RW_READER); 1542 1543 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 1544 (mod_hash_val_t *)&softmac) != 0) { 1545 /* 1546 * This is rare but possible. It could happen when pre-detach 1547 * routine of the device succeeds. But the softmac will then 1548 * be recreated when device fails to detach (as this device 1549 * is held). 1550 */ 1551 mutex_enter(&smac_global_lock); 1552 rw_exit(&softmac_hash_lock); 1553 cv_wait(&smac_global_cv, &smac_global_lock); 1554 mutex_exit(&smac_global_lock); 1555 goto again; 1556 } 1557 1558 /* 1559 * Bump smac_hold_cnt to prevent device detach. 1560 */ 1561 mutex_enter(&softmac->smac_mutex); 1562 softmac->smac_hold_cnt++; 1563 rw_exit(&softmac_hash_lock); 1564 1565 /* 1566 * Wait till the device is fully attached. 1567 */ 1568 while (softmac->smac_state != SOFTMAC_ATTACH_DONE) 1569 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1570 1571 SOFTMAC_STATE_VERIFY(softmac); 1572 1573 if ((err = softmac->smac_attacherr) != 0) 1574 softmac->smac_hold_cnt--; 1575 else 1576 *ddhp = (dls_dev_handle_t)softmac; 1577 mutex_exit(&softmac->smac_mutex); 1578 1579 ddi_release_devi(dip); 1580 return (err); 1581 } 1582 1583 void 1584 softmac_rele_device(dls_dev_handle_t ddh) 1585 { 1586 if (ddh != NULL) 1587 softmac_rele((softmac_t *)ddh); 1588 } 1589 1590 int 1591 softmac_hold(dev_t dev, softmac_t **softmacp) 1592 { 1593 softmac_t *softmac; 1594 char *drv; 1595 mac_handle_t mh; 1596 char mac[MAXNAMELEN]; 1597 int err; 1598 1599 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL) 1600 return (EINVAL); 1601 1602 (void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1); 1603 if ((err = mac_open(mac, &mh)) != 0) 1604 return (err); 1605 1606 softmac = (softmac_t *)mac_driver(mh); 1607 1608 mutex_enter(&softmac->smac_mutex); 1609 softmac->smac_hold_cnt++; 1610 mutex_exit(&softmac->smac_mutex); 1611 mac_close(mh); 1612 *softmacp = softmac; 1613 return (0); 1614 } 1615 1616 void 1617 softmac_rele(softmac_t *softmac) 1618 { 1619 mutex_enter(&softmac->smac_mutex); 1620 softmac->smac_hold_cnt--; 1621 mutex_exit(&softmac->smac_mutex); 1622 } 1623