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