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 ppa = ddi_get_instance(dip); 330 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 331 332 /* 333 * We expect legacy devices have at most two minor nodes - one style-1 334 * and one style-2. 335 */ 336 if (!GLDV3_DRV(ddi_driver_major(dip)) && 337 i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { 338 cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported", 339 devname); 340 return (ENOTSUP); 341 } 342 343 /* 344 * Check whether the softmac for the specified device already exists 345 */ 346 rw_enter(&softmac_hash_lock, RW_WRITER); 347 if ((mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 348 (mod_hash_val_t *)&softmac)) != 0) { 349 350 softmac = kmem_cache_alloc(softmac_cachep, KM_SLEEP); 351 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); 352 353 err = mod_hash_insert(softmac_hash, 354 (mod_hash_key_t)softmac->smac_devname, 355 (mod_hash_val_t)softmac); 356 ASSERT(err == 0); 357 mutex_enter(&smac_global_lock); 358 cv_broadcast(&smac_global_cv); 359 mutex_exit(&smac_global_lock); 360 } 361 362 mutex_enter(&softmac->smac_mutex); 363 SOFTMAC_STATE_VERIFY(softmac); 364 if (softmac->smac_state != SOFTMAC_ATTACH_DONE) 365 softmac->smac_state = SOFTMAC_ATTACH_INPROG; 366 if (softmac->smac_attachok_cnt == 0) { 367 /* 368 * Initialize the softmac if this is the post-attach of the 369 * first minor node. 370 */ 371 softmac->smac_flags = 0; 372 softmac->smac_umajor = ddi_driver_major(dip); 373 softmac->smac_uppa = ppa; 374 375 /* 376 * Note that for GLDv3 devices, we create devfs minor nodes 377 * for VLANs as well. Assume a GLDv3 driver on which only 378 * a VLAN is created. During the detachment of this device 379 * instance, the following would happen: 380 * a. the pre-detach callback softmac_destroy() succeeds. 381 * Because the physical link itself is not in use, 382 * softmac_destroy() succeeds and destroys softmac_t; 383 * b. the device detach fails in mac_unregister() because 384 * this MAC is still used by a VLAN. 385 * c. the post-attach callback is then called which leads 386 * us here. Note that ddi_minor_node_count() returns 3 387 * (including the minior node of the VLAN). In that case, 388 * we must correct the minor node count to 2 as that is 389 * the count of minor nodes that go through post-attach. 390 */ 391 if (GLDV3_DRV(ddi_driver_major(dip))) { 392 softmac->smac_flags |= SOFTMAC_GLDV3; 393 softmac->smac_cnt = 2; 394 } else { 395 softmac->smac_cnt = 396 i_ddi_minor_node_count(dip, DDI_NT_NET); 397 } 398 } 399 400 index = (getmajor(dev) == ddi_name_to_major("clone")); 401 if (softmac->smac_softmac[index] != NULL) { 402 /* 403 * This is possible if the post_attach() is called after 404 * pre_detach() fails. This seems to be a defect of the DACF 405 * framework. We work around it by using a smac_attached_left 406 * field that tracks this 407 */ 408 ASSERT(softmac->smac_attached_left != 0); 409 softmac->smac_attached_left--; 410 mutex_exit(&softmac->smac_mutex); 411 rw_exit(&softmac_hash_lock); 412 return (0); 413 414 } 415 mutex_exit(&softmac->smac_mutex); 416 rw_exit(&softmac_hash_lock); 417 418 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); 419 softmac_dev->sd_dev = dev; 420 421 mutex_enter(&softmac->smac_mutex); 422 softmac->smac_softmac[index] = softmac_dev; 423 /* 424 * Continue to register the mac and create the datalink only when all 425 * the minor nodes are attached. 426 */ 427 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { 428 mutex_exit(&softmac->smac_mutex); 429 return (0); 430 } 431 432 /* 433 * All of the minor nodes have been attached; start a taskq 434 * to do the rest of the work. We use a taskq instead of 435 * doing the work here because: 436 * 437 * We could be called as a result of a open() system call 438 * where spec_open() already SLOCKED the snode. Using a taskq 439 * sidesteps the risk that our ldi_open_by_dev() call would 440 * deadlock trying to set SLOCKED on the snode again. 441 * 442 * The devfs design requires that the downcalls don't use any 443 * interruptible cv_wait which happens when we do door upcalls. 444 * Otherwise the downcalls which may be holding devfs resources 445 * may cause a deadlock if the thread is stopped. Also we need to make 446 * sure these downcalls into softmac_create or softmac_destroy 447 * don't cv_wait on any devfs related condition. Thus softmac_destroy 448 * returns EBUSY if the asynchronous threads started in softmac_create 449 * haven't finished. 450 */ 451 (void) taskq_dispatch(system_taskq, softmac_create_task, 452 softmac, TQ_SLEEP); 453 mutex_exit(&softmac->smac_mutex); 454 return (0); 455 } 456 457 static boolean_t 458 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 459 { 460 softmac_t *softmac = arg; 461 462 if (!(softmac->smac_capab_flags & cap)) 463 return (B_FALSE); 464 465 switch (cap) { 466 case MAC_CAPAB_HCKSUM: { 467 uint32_t *txflags = cap_data; 468 469 *txflags = softmac->smac_hcksum_txflags; 470 break; 471 } 472 case MAC_CAPAB_LEGACY: { 473 mac_capab_legacy_t *legacy = cap_data; 474 475 /* 476 * The caller is not interested in the details. 477 */ 478 if (legacy == NULL) 479 break; 480 481 legacy->ml_unsup_note = ~softmac->smac_notifications & 482 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 483 legacy->ml_active_set = softmac_active_set; 484 legacy->ml_active_clear = softmac_active_clear; 485 legacy->ml_fastpath_disable = softmac_fastpath_disable; 486 legacy->ml_fastpath_enable = softmac_fastpath_enable; 487 legacy->ml_dev = makedevice(softmac->smac_umajor, 488 softmac->smac_uppa + 1); 489 break; 490 } 491 492 /* 493 * For the capabilities below, there's nothing for us to fill in; 494 * simply return B_TRUE if we support it. 495 */ 496 case MAC_CAPAB_NO_ZCOPY: 497 case MAC_CAPAB_NO_NATIVEVLAN: 498 default: 499 break; 500 } 501 return (B_TRUE); 502 } 503 504 static int 505 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 506 { 507 datalink_id_t linkid = DATALINK_INVALID_LINKID; 508 uint32_t media; 509 int err; 510 511 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 512 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 513 *linkidp = linkid; 514 } 515 516 if (err == EEXIST) { 517 /* 518 * There is a link name conflict. Either: 519 * 520 * - An existing link with the same device name with a 521 * different media type from of the given type. 522 * Mark this link back to persistent only; or 523 * 524 * - We cannot assign the "suggested" name because 525 * GLDv3 and therefore vanity naming is not supported 526 * for this link type. Delete this link's <link name, 527 * linkid> mapping. 528 */ 529 if (media != softmac->smac_media) { 530 cmn_err(CE_WARN, "%s device %s conflicts with " 531 "existing %s device %s.", 532 dl_mactypestr(softmac->smac_media), 533 softmac->smac_devname, dl_mactypestr(media), 534 softmac->smac_devname); 535 (void) dls_mgmt_destroy(linkid, B_FALSE); 536 } else { 537 cmn_err(CE_WARN, "link name %s is already in-use.", 538 softmac->smac_devname); 539 (void) dls_mgmt_destroy(linkid, B_TRUE); 540 } 541 542 cmn_err(CE_WARN, "%s device might not be available " 543 "for use.", softmac->smac_devname); 544 cmn_err(CE_WARN, "See dladm(1M) for more information."); 545 } 546 547 return (err); 548 } 549 550 /* 551 * This function: 552 * 1. provides the link's media type to dlmgmtd. 553 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 554 */ 555 static int 556 softmac_create_datalink(softmac_t *softmac) 557 { 558 datalink_id_t linkid = DATALINK_INVALID_LINKID; 559 int err; 560 561 /* 562 * Inform dlmgmtd of this link so that softmac_hold_device() is able 563 * to know the existence of this link. If this failed with EBADF, 564 * it might be because dlmgmtd was not started in time (e.g., 565 * diskless boot); ignore the failure and continue to create 566 * the GLDv3 datalink if needed. 567 */ 568 err = dls_mgmt_create(softmac->smac_devname, 569 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 570 DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 571 if (err != 0 && err != EBADF) 572 return (err); 573 574 /* 575 * Provide the media type of the physical link to dlmgmtd. 576 */ 577 if ((err != EBADF) && 578 ((err = softmac_update_info(softmac, &linkid)) != 0)) { 579 return (err); 580 } 581 582 /* 583 * Create the GLDv3 datalink. 584 */ 585 if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) && 586 ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) { 587 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 588 softmac->smac_devname); 589 return (err); 590 } 591 592 if (linkid == DATALINK_INVALID_LINKID) { 593 mutex_enter(&softmac->smac_mutex); 594 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 595 mutex_exit(&softmac->smac_mutex); 596 } 597 598 return (0); 599 } 600 601 static void 602 softmac_create_task(void *arg) 603 { 604 softmac_t *softmac = arg; 605 mac_handle_t mh; 606 int err; 607 608 if (!GLDV3_DRV(softmac->smac_umajor)) { 609 softmac_mac_register(softmac); 610 return; 611 } 612 613 if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 614 goto done; 615 616 mutex_enter(&softmac->smac_mutex); 617 softmac->smac_media = (mac_info(mh))->mi_nativemedia; 618 softmac->smac_mh = mh; 619 mutex_exit(&softmac->smac_mutex); 620 621 /* 622 * We can safely release the reference on the mac because 623 * this mac will only be unregistered and destroyed when 624 * the device detaches, and the softmac will be destroyed 625 * before then (in the pre-detach routine of the device). 626 */ 627 mac_close(mh); 628 629 /* 630 * Create the GLDv3 datalink for this mac. 631 */ 632 err = softmac_create_datalink(softmac); 633 634 done: 635 mutex_enter(&softmac->smac_mutex); 636 if (err != 0) 637 softmac->smac_mh = NULL; 638 softmac->smac_attacherr = err; 639 softmac->smac_state = SOFTMAC_ATTACH_DONE; 640 cv_broadcast(&softmac->smac_cv); 641 mutex_exit(&softmac->smac_mutex); 642 } 643 644 /* 645 * This function is only called for legacy devices. It: 646 * 1. registers the MAC for the legacy devices whose media type is supported 647 * by the GLDv3 framework. 648 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 649 */ 650 static void 651 softmac_mac_register(softmac_t *softmac) 652 { 653 softmac_dev_t *softmac_dev; 654 dev_t dev; 655 ldi_handle_t lh = NULL; 656 ldi_ident_t li = NULL; 657 int index; 658 boolean_t native_vlan = B_FALSE; 659 int err; 660 661 /* 662 * Note that we do not need any locks to access this softmac pointer, 663 * as softmac_destroy() will wait until this function is called. 664 */ 665 ASSERT(softmac != NULL); 666 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 667 softmac->smac_attachok_cnt == softmac->smac_cnt); 668 669 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 670 mutex_enter(&softmac->smac_mutex); 671 goto done; 672 } 673 674 /* 675 * Determine whether this legacy device support VLANs by opening 676 * the style-2 device node (if it exists) and attaching to a VLAN 677 * PPA (1000 + ppa). 678 */ 679 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 680 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 681 if (err == 0) { 682 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 683 native_vlan = B_TRUE; 684 (void) ldi_close(lh, FREAD|FWRITE, kcred); 685 } 686 687 err = EINVAL; 688 for (index = 0; index < 2; index++) { 689 dl_info_ack_t dlia; 690 dl_error_ack_t dlea; 691 uint32_t notes; 692 struct strioctl iocb; 693 uint32_t margin; 694 int rval; 695 696 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 697 continue; 698 699 softmac->smac_dev = dev = softmac_dev->sd_dev; 700 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 701 li) != 0) { 702 continue; 703 } 704 705 /* 706 * Pop all the intermediate modules in order to negotiate 707 * capabilities correctly. 708 */ 709 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 710 ; 711 712 /* DLPI style-1 or DLPI style-2? */ 713 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 714 if (rval == ENOTSUP) { 715 cmn_err(CE_NOTE, "softmac: received " 716 "DL_ERROR_ACK to DL_INFO_ACK; " 717 "DLPI errno 0x%x, UNIX errno %d", 718 dlea.dl_errno, dlea.dl_unix_errno); 719 } 720 (void) ldi_close(lh, FREAD|FWRITE, kcred); 721 continue; 722 } 723 724 /* 725 * Currently only DL_ETHER has GLDv3 mac plugin support. 726 * For media types that GLDv3 does not support, create a 727 * link id for it. 728 */ 729 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 730 (void) ldi_close(lh, FREAD|FWRITE, kcred); 731 err = 0; 732 break; 733 } 734 735 if ((dlia.dl_provider_style == DL_STYLE2) && 736 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 737 (void) ldi_close(lh, FREAD|FWRITE, kcred); 738 continue; 739 } 740 741 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 742 if (rval == ENOTSUP) { 743 cmn_err(CE_NOTE, "softmac: received " 744 "DL_ERROR_ACK to DL_BIND_ACK; " 745 "DLPI errno 0x%x, UNIX errno %d", 746 dlea.dl_errno, dlea.dl_unix_errno); 747 } 748 (void) ldi_close(lh, FREAD|FWRITE, kcred); 749 continue; 750 } 751 752 /* 753 * Call dl_info() after dl_bind() because some drivers only 754 * provide correct information (e.g. MAC address) once bound. 755 */ 756 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 757 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 758 &softmac->smac_addrlen, &dlea)) != 0) { 759 if (rval == ENOTSUP) { 760 cmn_err(CE_NOTE, "softmac: received " 761 "DL_ERROR_ACK to DL_INFO_ACK; " 762 "DLPI errno 0x%x, UNIX errno %d", 763 dlea.dl_errno, dlea.dl_unix_errno); 764 } 765 (void) ldi_close(lh, FREAD|FWRITE, kcred); 766 continue; 767 } 768 769 softmac->smac_style = dlia.dl_provider_style; 770 softmac->smac_saplen = ABS(dlia.dl_sap_length); 771 softmac->smac_min_sdu = dlia.dl_min_sdu; 772 softmac->smac_max_sdu = dlia.dl_max_sdu; 773 774 if ((softmac->smac_saplen != sizeof (uint16_t)) || 775 (softmac->smac_addrlen != ETHERADDRL) || 776 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 777 (dlia.dl_brdcst_addr_offset == 0)) { 778 (void) ldi_close(lh, FREAD|FWRITE, kcred); 779 continue; 780 } 781 782 /* 783 * Check other DLPI capabilities. Note that this must be after 784 * dl_bind() because some drivers return DL_ERROR_ACK if the 785 * stream is not bound. It is also before mac_register(), so 786 * we don't need any lock protection here. 787 */ 788 softmac->smac_capab_flags = 789 (MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 790 791 softmac->smac_no_capability_req = B_FALSE; 792 if (softmac_fill_capab(lh, softmac) != 0) 793 softmac->smac_no_capability_req = B_TRUE; 794 795 /* 796 * Check the margin of the underlying driver. 797 */ 798 margin = 0; 799 iocb.ic_cmd = DLIOCMARGININFO; 800 iocb.ic_timout = INFTIM; 801 iocb.ic_len = sizeof (margin); 802 iocb.ic_dp = (char *)&margin; 803 softmac->smac_margin = 0; 804 805 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 806 &rval) == 0) { 807 softmac->smac_margin = margin; 808 } 809 810 /* 811 * If the legacy driver doesn't support DLIOCMARGININFO, but 812 * it can support native VLAN, correct its margin value to 4. 813 */ 814 if (native_vlan) { 815 if (softmac->smac_margin == 0) 816 softmac->smac_margin = VLAN_TAGSZ; 817 } else { 818 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 819 } 820 821 /* 822 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 823 */ 824 softmac->smac_notifications = 0; 825 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 826 switch (dl_notify(lh, ¬es, NULL)) { 827 case 0: 828 softmac->smac_notifications = notes; 829 break; 830 case ENOTSUP: 831 break; 832 default: 833 (void) ldi_close(lh, FREAD|FWRITE, kcred); 834 continue; 835 } 836 837 (void) ldi_close(lh, FREAD|FWRITE, kcred); 838 err = 0; 839 break; 840 } 841 ldi_ident_release(li); 842 843 mutex_enter(&softmac->smac_mutex); 844 845 if (err != 0) 846 goto done; 847 848 if (softmac->smac_media != DL_ETHER) 849 softmac->smac_flags |= SOFTMAC_NOSUPP; 850 851 /* 852 * Finally, we're ready to register ourselves with the MAC layer 853 * interface; if this succeeds, we're all ready to start() 854 */ 855 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 856 mac_register_t *macp; 857 858 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 859 err = ENOMEM; 860 goto done; 861 } 862 863 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 864 macp->m_driver = softmac; 865 macp->m_dip = softmac_dip; 866 867 macp->m_margin = softmac->smac_margin; 868 macp->m_src_addr = softmac->smac_unicst_addr; 869 macp->m_min_sdu = softmac->smac_min_sdu; 870 macp->m_max_sdu = softmac->smac_max_sdu; 871 macp->m_callbacks = &softmac_m_callbacks; 872 macp->m_instance = (uint_t)-1; 873 874 err = mac_register(macp, &softmac->smac_mh); 875 mac_free(macp); 876 if (err != 0) { 877 cmn_err(CE_WARN, "mac_register failed for %s", 878 softmac->smac_devname); 879 goto done; 880 } 881 } 882 mutex_exit(&softmac->smac_mutex); 883 884 /* 885 * Try to create the datalink for this softmac. 886 */ 887 if ((err = softmac_create_datalink(softmac)) != 0) { 888 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) 889 (void) mac_unregister(softmac->smac_mh); 890 mutex_enter(&softmac->smac_mutex); 891 softmac->smac_mh = NULL; 892 goto done; 893 } 894 /* 895 * If succeed, create the thread which handles the DL_NOTIFY_IND from 896 * the lower stream. 897 */ 898 mutex_enter(&softmac->smac_mutex); 899 if (softmac->smac_mh != NULL) { 900 softmac->smac_notify_thread = thread_create(NULL, 0, 901 softmac_notify_thread, softmac, 0, &p0, 902 TS_RUN, minclsyspri); 903 } 904 905 done: 906 ASSERT(softmac->smac_state == SOFTMAC_ATTACH_INPROG && 907 softmac->smac_attachok_cnt == softmac->smac_cnt); 908 softmac->smac_state = SOFTMAC_ATTACH_DONE; 909 softmac->smac_attacherr = err; 910 cv_broadcast(&softmac->smac_cv); 911 mutex_exit(&softmac->smac_mutex); 912 } 913 914 int 915 softmac_destroy(dev_info_t *dip, dev_t dev) 916 { 917 char devname[MAXNAMELEN]; 918 softmac_t *softmac; 919 softmac_dev_t *softmac_dev; 920 int index; 921 int ppa, err; 922 datalink_id_t linkid; 923 mac_handle_t smac_mh; 924 uint32_t smac_flags; 925 926 ppa = ddi_get_instance(dip); 927 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 928 929 /* 930 * We are called only from the predetach entry point. The DACF 931 * framework ensures there can't be a concurrent postattach call 932 * for the same softmac. The softmac found out from the modhash 933 * below can't vanish beneath us since this is the only place where 934 * it is deleted. 935 */ 936 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 937 (mod_hash_val_t *)&softmac); 938 ASSERT(err == 0); 939 940 mutex_enter(&softmac->smac_mutex); 941 SOFTMAC_STATE_VERIFY(softmac); 942 943 /* 944 * Fail the predetach routine if this softmac is in-use. 945 * Make sure these downcalls into softmac_create or softmac_destroy 946 * don't cv_wait on any devfs related condition. Thus softmac_destroy 947 * returns EBUSY if the asynchronous thread started in softmac_create 948 * hasn't finished 949 */ 950 if ((softmac->smac_hold_cnt != 0) || 951 (softmac->smac_state == SOFTMAC_ATTACH_INPROG)) { 952 softmac->smac_attached_left = softmac->smac_attachok_cnt; 953 mutex_exit(&softmac->smac_mutex); 954 return (EBUSY); 955 } 956 957 /* 958 * Even if the predetach of one minor node has already failed 959 * (smac_attached_left is not 0), the DACF framework will continue 960 * to call the predetach routines of the other minor nodes, 961 * so we fail these calls here. 962 */ 963 if (softmac->smac_attached_left != 0) { 964 mutex_exit(&softmac->smac_mutex); 965 return (EBUSY); 966 } 967 968 smac_mh = softmac->smac_mh; 969 smac_flags = softmac->smac_flags; 970 softmac->smac_state = SOFTMAC_DETACH_INPROG; 971 mutex_exit(&softmac->smac_mutex); 972 973 if (smac_mh != NULL) { 974 /* 975 * This is the first minor node that is being detached for this 976 * softmac. 977 */ 978 ASSERT(softmac->smac_attachok_cnt == softmac->smac_cnt); 979 if (!(smac_flags & SOFTMAC_NOSUPP)) { 980 if ((err = dls_devnet_destroy(smac_mh, &linkid, 981 B_FALSE)) != 0) { 982 goto error; 983 } 984 } 985 /* 986 * If softmac_mac_register() succeeds in registering the mac 987 * of the legacy device, unregister it. 988 */ 989 if (!(smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 990 if ((err = mac_disable_nowait(smac_mh)) != 0) { 991 (void) dls_devnet_create(smac_mh, linkid); 992 goto error; 993 } 994 /* 995 * Ask softmac_notify_thread to quit, and wait for 996 * that to be done. 997 */ 998 mutex_enter(&softmac->smac_mutex); 999 softmac->smac_flags |= SOFTMAC_NOTIFY_QUIT; 1000 cv_broadcast(&softmac->smac_cv); 1001 while (softmac->smac_notify_thread != NULL) { 1002 cv_wait(&softmac->smac_cv, 1003 &softmac->smac_mutex); 1004 } 1005 mutex_exit(&softmac->smac_mutex); 1006 VERIFY(mac_unregister(smac_mh) == 0); 1007 } 1008 softmac->smac_mh = NULL; 1009 } 1010 1011 /* 1012 * Free softmac_dev 1013 */ 1014 rw_enter(&softmac_hash_lock, RW_WRITER); 1015 mutex_enter(&softmac->smac_mutex); 1016 1017 ASSERT(softmac->smac_state == SOFTMAC_DETACH_INPROG && 1018 softmac->smac_attachok_cnt != 0); 1019 softmac->smac_mh = NULL; 1020 index = (getmajor(dev) == ddi_name_to_major("clone")); 1021 softmac_dev = softmac->smac_softmac[index]; 1022 ASSERT(softmac_dev != NULL); 1023 softmac->smac_softmac[index] = NULL; 1024 kmem_free(softmac_dev, sizeof (softmac_dev_t)); 1025 1026 if (--softmac->smac_attachok_cnt == 0) { 1027 mod_hash_val_t hashval; 1028 1029 softmac->smac_state = SOFTMAC_UNINIT; 1030 if (softmac->smac_hold_cnt != 0) { 1031 /* 1032 * Someone did a softmac_hold_device while we dropped 1033 * the locks. Leave the softmac itself intact which 1034 * will be reused by the reattach 1035 */ 1036 mutex_exit(&softmac->smac_mutex); 1037 rw_exit(&softmac_hash_lock); 1038 return (0); 1039 } 1040 err = mod_hash_remove(softmac_hash, 1041 (mod_hash_key_t)devname, 1042 (mod_hash_val_t *)&hashval); 1043 ASSERT(err == 0); 1044 1045 mutex_exit(&softmac->smac_mutex); 1046 rw_exit(&softmac_hash_lock); 1047 ASSERT(softmac->smac_fp_disable_clients == 0); 1048 softmac->smac_fastpath_admin_disabled = B_FALSE; 1049 kmem_cache_free(softmac_cachep, softmac); 1050 return (0); 1051 } 1052 mutex_exit(&softmac->smac_mutex); 1053 rw_exit(&softmac_hash_lock); 1054 return (0); 1055 1056 error: 1057 mutex_enter(&softmac->smac_mutex); 1058 softmac->smac_attached_left = softmac->smac_attachok_cnt; 1059 softmac->smac_state = SOFTMAC_ATTACH_DONE; 1060 cv_broadcast(&softmac->smac_cv); 1061 mutex_exit(&softmac->smac_mutex); 1062 return (err); 1063 } 1064 1065 /* 1066 * This function is called as the result of a newly started dlmgmtd daemon. 1067 * 1068 * We walk through every softmac that was created but failed to notify 1069 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 1070 * when softmacs are created before dlmgmtd is ready. For example, during 1071 * diskless boot, a network device is used (and therefore attached) before 1072 * the datalink-management service starts dlmgmtd. 1073 */ 1074 /* ARGSUSED */ 1075 static uint_t 1076 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1077 { 1078 softmac_t *softmac = (softmac_t *)val; 1079 datalink_id_t linkid; 1080 int err; 1081 softmac_walk_t *smwp = arg; 1082 1083 /* 1084 * The framework itself must not hold any locks across calls to the 1085 * mac perimeter. Thus this function does not call any framework 1086 * function that needs to grab the mac perimeter. 1087 */ 1088 ASSERT(RW_READ_HELD(&softmac_hash_lock)); 1089 1090 smwp->smw_retry = B_FALSE; 1091 mutex_enter(&softmac->smac_mutex); 1092 SOFTMAC_STATE_VERIFY(softmac); 1093 if (softmac->smac_state == SOFTMAC_ATTACH_INPROG) { 1094 /* 1095 * Wait till softmac_create or softmac_mac_register finishes 1096 * Hold the softmac to ensure it stays around. The wait itself 1097 * is done in the caller, since we need to drop all locks 1098 * including the mod hash's internal lock before calling 1099 * cv_wait. 1100 */ 1101 smwp->smw_retry = B_TRUE; 1102 smwp->smw_softmac = softmac; 1103 softmac->smac_hold_cnt++; 1104 return (MH_WALK_TERMINATE); 1105 } 1106 1107 if ((softmac->smac_state != SOFTMAC_ATTACH_DONE) || 1108 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 1109 mutex_exit(&softmac->smac_mutex); 1110 return (MH_WALK_CONTINUE); 1111 } 1112 1113 /* 1114 * Bumping up the smac_hold_cnt allows us to drop the lock. It also 1115 * makes softmac_destroy() return failure on an attempted device detach. 1116 * We don't want to hold the lock across calls to other subsystems 1117 * like kstats, which will happen in the call to dls_devnet_recreate 1118 */ 1119 softmac->smac_hold_cnt++; 1120 mutex_exit(&softmac->smac_mutex); 1121 1122 if (dls_mgmt_create(softmac->smac_devname, 1123 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 1124 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 1125 softmac_rele_device((dls_dev_handle_t)softmac); 1126 return (MH_WALK_CONTINUE); 1127 } 1128 1129 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 1130 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 1131 "failed (%d)", softmac->smac_devname, err); 1132 softmac_rele_device((dls_dev_handle_t)softmac); 1133 return (MH_WALK_CONTINUE); 1134 } 1135 1136 /* 1137 * Create a link for this MAC. The link name will be the same 1138 * as the MAC name. 1139 */ 1140 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 1141 err = dls_devnet_recreate(softmac->smac_mh, linkid); 1142 if (err != 0) { 1143 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 1144 "%s (linkid %d) failed (%d)", 1145 softmac->smac_devname, linkid, err); 1146 } 1147 } 1148 1149 mutex_enter(&softmac->smac_mutex); 1150 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 1151 ASSERT(softmac->smac_hold_cnt != 0); 1152 softmac->smac_hold_cnt--; 1153 mutex_exit(&softmac->smac_mutex); 1154 1155 return (MH_WALK_CONTINUE); 1156 } 1157 1158 /* 1159 * See comments above softmac_mac_recreate(). 1160 */ 1161 void 1162 softmac_recreate() 1163 { 1164 softmac_walk_t smw; 1165 softmac_t *softmac; 1166 1167 /* 1168 * Walk through the softmac_hash table. Request to create the 1169 * [link name, linkid] mapping if we failed to do so. 1170 */ 1171 do { 1172 smw.smw_retry = B_FALSE; 1173 rw_enter(&softmac_hash_lock, RW_READER); 1174 mod_hash_walk(softmac_hash, softmac_mac_recreate, &smw); 1175 rw_exit(&softmac_hash_lock); 1176 if (smw.smw_retry) { 1177 /* 1178 * softmac_create or softmac_mac_register hasn't yet 1179 * finished and the softmac is not yet in the 1180 * SOFTMAC_ATTACH_DONE state. 1181 */ 1182 softmac = smw.smw_softmac; 1183 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1184 softmac->smac_hold_cnt--; 1185 mutex_exit(&softmac->smac_mutex); 1186 } 1187 } while (smw.smw_retry); 1188 } 1189 1190 static int 1191 softmac_m_start(void *arg) 1192 { 1193 softmac_t *softmac = arg; 1194 softmac_lower_t *slp = softmac->smac_lower; 1195 int err; 1196 1197 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1198 /* 1199 * Bind to SAP 2 on token ring, 0 on other interface types. 1200 * (SAP 0 has special significance on token ring). 1201 * Note that the receive-side packets could come anytime after bind. 1202 */ 1203 err = softmac_send_bind_req(slp, softmac->smac_media == DL_TPR ? 2 : 0); 1204 if (err != 0) 1205 return (err); 1206 1207 /* 1208 * Put the lower stream to the DL_PROMISC_SAP mode in order to receive 1209 * all packets of interest. 1210 * 1211 * some driver (e.g. the old legacy eri driver) incorrectly passes up 1212 * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 1213 * so that we send DL_PROMISON_REQ after DL_BIND_REQ. 1214 */ 1215 err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE); 1216 if (err != 0) { 1217 (void) softmac_send_unbind_req(slp); 1218 return (err); 1219 } 1220 1221 /* 1222 * Enable capabilities the underlying driver claims to support. 1223 * Some driver requires this being called after the stream is bound. 1224 */ 1225 if ((err = softmac_capab_enable(slp)) != 0) { 1226 (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE); 1227 (void) softmac_send_unbind_req(slp); 1228 } 1229 1230 return (err); 1231 } 1232 1233 /* ARGSUSED */ 1234 static void 1235 softmac_m_stop(void *arg) 1236 { 1237 softmac_t *softmac = arg; 1238 softmac_lower_t *slp = softmac->smac_lower; 1239 1240 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1241 1242 /* 1243 * It is not needed to reset zerocopy, MDT or HCKSUM capabilities. 1244 */ 1245 (void) softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_FALSE); 1246 (void) softmac_send_unbind_req(slp); 1247 } 1248 1249 /* 1250 * Set up the lower stream above the legacy device. There are two different 1251 * type of lower streams: 1252 * 1253 * - Shared lower-stream 1254 * 1255 * Shared by all GLDv3 MAC clients. Put the lower stream to the DLIOCRAW 1256 * mode to send and receive the raw data. Further, put the lower stream into 1257 * DL_PROMISC_SAP mode to receive all packets of interest. 1258 * 1259 * - Dedicated lower-stream 1260 * 1261 * The lower-stream which is dedicated to upper IP/ARP stream. This is used 1262 * as fast-path for IP. In this case, the second argument is the pointer to 1263 * the softmac upper-stream. 1264 */ 1265 int 1266 softmac_lower_setup(softmac_t *softmac, softmac_upper_t *sup, 1267 softmac_lower_t **slpp) 1268 { 1269 ldi_ident_t li; 1270 dev_t dev; 1271 ldi_handle_t lh = NULL; 1272 softmac_lower_t *slp = NULL; 1273 smac_ioc_start_t start_arg; 1274 struct strioctl strioc; 1275 uint32_t notifications; 1276 int err, rval; 1277 1278 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 1279 return (err); 1280 1281 /* 1282 * The GLDv3 framework makes sure that mac_unregister(), mac_open(), 1283 * and mac_close() cannot be called at the same time. So we don't 1284 * need any protection to access softmac here. 1285 */ 1286 dev = softmac->smac_dev; 1287 1288 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 1289 ldi_ident_release(li); 1290 if (err != 0) 1291 goto done; 1292 1293 /* 1294 * Pop all the intermediate modules. The autopushed modules will 1295 * be pushed when the softmac node is opened. 1296 */ 1297 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 1298 ; 1299 1300 if ((softmac->smac_style == DL_STYLE2) && 1301 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 1302 goto done; 1303 } 1304 1305 /* 1306 * If this is the shared-lower-stream, put the lower stream to 1307 * the DLIOCRAW mode to send/receive raw data. 1308 */ 1309 if ((sup == NULL) && (err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, 1310 kcred, &rval)) != 0) { 1311 goto done; 1312 } 1313 1314 /* 1315 * Then push the softmac shim layer atop the lower stream. 1316 */ 1317 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 1318 kcred, &rval)) != 0) { 1319 goto done; 1320 } 1321 1322 /* 1323 * Send the ioctl to get the slp pointer. 1324 */ 1325 strioc.ic_cmd = SMAC_IOC_START; 1326 strioc.ic_timout = INFTIM; 1327 strioc.ic_len = sizeof (start_arg); 1328 strioc.ic_dp = (char *)&start_arg; 1329 1330 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 1331 kcred, &rval)) != 0) { 1332 goto done; 1333 } 1334 slp = start_arg.si_slp; 1335 slp->sl_sup = sup; 1336 slp->sl_lh = lh; 1337 slp->sl_softmac = softmac; 1338 *slpp = slp; 1339 1340 if (sup != NULL) { 1341 slp->sl_rxinfo = &sup->su_rxinfo; 1342 } else { 1343 /* 1344 * Send DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 1345 * We don't have to wait for the ack. 1346 */ 1347 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 1348 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 1349 DL_NOTE_PROMISC_OFF_PHYS; 1350 1351 (void) softmac_send_notify_req(slp, 1352 (notifications & softmac->smac_notifications)); 1353 } 1354 1355 done: 1356 if (err != 0) 1357 (void) ldi_close(lh, FREAD|FWRITE, kcred); 1358 return (err); 1359 } 1360 1361 static int 1362 softmac_m_open(void *arg) 1363 { 1364 softmac_t *softmac = arg; 1365 softmac_lower_t *slp; 1366 int err; 1367 1368 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1369 1370 if ((err = softmac_lower_setup(softmac, NULL, &slp)) != 0) 1371 return (err); 1372 1373 softmac->smac_lower = slp; 1374 return (0); 1375 } 1376 1377 static void 1378 softmac_m_close(void *arg) 1379 { 1380 softmac_t *softmac = arg; 1381 softmac_lower_t *slp; 1382 1383 ASSERT(MAC_PERIM_HELD(softmac->smac_mh)); 1384 slp = softmac->smac_lower; 1385 ASSERT(slp != NULL); 1386 1387 /* 1388 * Note that slp is destroyed when lh is closed. 1389 */ 1390 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1391 softmac->smac_lower = NULL; 1392 } 1393 1394 /* 1395 * Softmac supports two priviate link properteis: 1396 * 1397 * - "_fastpath" 1398 * 1399 * This is a read-only link property which points out the current data-path 1400 * model of the given legacy link. The possible values are "disabled" and 1401 * "enabled". 1402 * 1403 * - "_disable_fastpath" 1404 * 1405 * This is a read-write link property which can be used to disable or enable 1406 * the fast-path of the given legacy link. The possible values are "true" 1407 * and "false". Note that even when "_disable_fastpath" is set to be 1408 * "false", the fast-path may still not be enabled since there may be 1409 * other mac cleints that request the fast-path to be disabled. 1410 */ 1411 /* ARGSUSED */ 1412 static int 1413 softmac_m_setprop(void *arg, const char *name, mac_prop_id_t id, 1414 uint_t valsize, const void *val) 1415 { 1416 softmac_t *softmac = arg; 1417 1418 if (id != MAC_PROP_PRIVATE || strcmp(name, "_disable_fastpath") != 0) 1419 return (ENOTSUP); 1420 1421 if (strcmp(val, "true") == 0) 1422 return (softmac_datapath_switch(softmac, B_TRUE, B_TRUE)); 1423 else if (strcmp(val, "false") == 0) 1424 return (softmac_datapath_switch(softmac, B_FALSE, B_TRUE)); 1425 else 1426 return (EINVAL); 1427 } 1428 1429 static int 1430 softmac_m_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t flags, 1431 uint_t valsize, void *val, uint_t *perm) 1432 { 1433 softmac_t *softmac = arg; 1434 char *fpstr; 1435 1436 if (id != MAC_PROP_PRIVATE) 1437 return (ENOTSUP); 1438 1439 if (strcmp(name, "_fastpath") == 0) { 1440 if ((flags & MAC_PROP_DEFAULT) != 0) 1441 return (ENOTSUP); 1442 1443 *perm = MAC_PROP_PERM_READ; 1444 mutex_enter(&softmac->smac_fp_mutex); 1445 fpstr = (DATAPATH_MODE(softmac) == SOFTMAC_SLOWPATH) ? 1446 "disabled" : "enabled"; 1447 mutex_exit(&softmac->smac_fp_mutex); 1448 } else if (strcmp(name, "_disable_fastpath") == 0) { 1449 *perm = MAC_PROP_PERM_RW; 1450 fpstr = ((flags & MAC_PROP_DEFAULT) != 0) ? "false" : 1451 (softmac->smac_fastpath_admin_disabled ? "true" : "false"); 1452 } else { 1453 return (ENOTSUP); 1454 } 1455 1456 return (strlcpy(val, fpstr, valsize) >= valsize ? EINVAL : 0); 1457 } 1458 1459 int 1460 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 1461 { 1462 dev_info_t *dip; 1463 const char *drvname; 1464 char devname[MAXNAMELEN]; 1465 softmac_t *softmac; 1466 int ppa, err; 1467 1468 if ((ppa = getminor(dev) - 1) > 1000) 1469 return (ENOENT); 1470 1471 /* 1472 * First try to hold this device instance to force the MAC 1473 * to be registered. 1474 */ 1475 if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL) 1476 return (ENOENT); 1477 1478 drvname = ddi_driver_name(dip); 1479 1480 /* 1481 * Exclude non-physical network device instances, for example, aggr0. 1482 */ 1483 if ((ddi_driver_major(dip) != getmajor(dev)) || 1484 !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 1485 (strcmp(drvname, "vnic") == 0)) { 1486 ddi_release_devi(dip); 1487 return (ENOENT); 1488 } 1489 1490 /* 1491 * This is a network device; wait for its softmac to be registered. 1492 */ 1493 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 1494 again: 1495 rw_enter(&softmac_hash_lock, RW_READER); 1496 1497 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 1498 (mod_hash_val_t *)&softmac) != 0) { 1499 /* 1500 * This is rare but possible. It could happen when pre-detach 1501 * routine of the device succeeds. But the softmac will then 1502 * be recreated when device fails to detach (as this device 1503 * is held). 1504 */ 1505 mutex_enter(&smac_global_lock); 1506 rw_exit(&softmac_hash_lock); 1507 cv_wait(&smac_global_cv, &smac_global_lock); 1508 mutex_exit(&smac_global_lock); 1509 goto again; 1510 } 1511 1512 /* 1513 * Bump smac_hold_cnt to prevent device detach. 1514 */ 1515 mutex_enter(&softmac->smac_mutex); 1516 softmac->smac_hold_cnt++; 1517 rw_exit(&softmac_hash_lock); 1518 1519 /* 1520 * Wait till the device is fully attached. 1521 */ 1522 while (softmac->smac_state != SOFTMAC_ATTACH_DONE) 1523 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1524 1525 SOFTMAC_STATE_VERIFY(softmac); 1526 1527 if ((err = softmac->smac_attacherr) != 0) 1528 softmac->smac_hold_cnt--; 1529 else 1530 *ddhp = (dls_dev_handle_t)softmac; 1531 mutex_exit(&softmac->smac_mutex); 1532 1533 ddi_release_devi(dip); 1534 return (err); 1535 } 1536 1537 void 1538 softmac_rele_device(dls_dev_handle_t ddh) 1539 { 1540 if (ddh != NULL) 1541 softmac_rele((softmac_t *)ddh); 1542 } 1543 1544 int 1545 softmac_hold(dev_t dev, softmac_t **softmacp) 1546 { 1547 softmac_t *softmac; 1548 char *drv; 1549 mac_handle_t mh; 1550 char mac[MAXNAMELEN]; 1551 int err; 1552 1553 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL) 1554 return (EINVAL); 1555 1556 (void) snprintf(mac, MAXNAMELEN, "%s%d", drv, getminor(dev) - 1); 1557 if ((err = mac_open(mac, &mh)) != 0) 1558 return (err); 1559 1560 softmac = (softmac_t *)mac_driver(mh); 1561 1562 mutex_enter(&softmac->smac_mutex); 1563 softmac->smac_hold_cnt++; 1564 mutex_exit(&softmac->smac_mutex); 1565 mac_close(mh); 1566 *softmacp = softmac; 1567 return (0); 1568 } 1569 1570 void 1571 softmac_rele(softmac_t *softmac) 1572 { 1573 mutex_enter(&softmac->smac_mutex); 1574 softmac->smac_hold_cnt--; 1575 mutex_exit(&softmac->smac_mutex); 1576 } 1577