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