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