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 2008 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/sunndi.h> 48 #include <sys/modhash.h> 49 #include <sys/stropts.h> 50 #include <sys/sysmacros.h> 51 #include <sys/vlan.h> 52 #include <sys/softmac_impl.h> 53 #include <sys/softmac.h> 54 #include <sys/dls.h> 55 56 /* 57 * Softmac hash table including softmacs for both style-2 and style-1 devices. 58 */ 59 static krwlock_t softmac_hash_lock; 60 static mod_hash_t *softmac_hash; 61 62 #define SOFTMAC_HASHSZ 64 63 64 static void softmac_create_task(void *); 65 static void softmac_mac_register(softmac_t *); 66 static int softmac_create_datalink(softmac_t *); 67 static int softmac_m_start(void *); 68 static void softmac_m_stop(void *); 69 static int softmac_m_open(void *); 70 static void softmac_m_close(void *); 71 static boolean_t softmac_m_getcapab(void *, mac_capab_t, void *); 72 73 #define SOFTMAC_M_CALLBACK_FLAGS \ 74 (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_OPEN | MC_CLOSE) 75 76 static mac_callbacks_t softmac_m_callbacks = { 77 SOFTMAC_M_CALLBACK_FLAGS, 78 softmac_m_stat, 79 softmac_m_start, 80 softmac_m_stop, 81 softmac_m_promisc, 82 softmac_m_multicst, 83 softmac_m_unicst, 84 softmac_m_tx, 85 softmac_m_resources, 86 softmac_m_ioctl, 87 softmac_m_getcapab, 88 softmac_m_open, 89 softmac_m_close 90 }; 91 92 void 93 softmac_init() 94 { 95 softmac_hash = mod_hash_create_extended("softmac_hash", 96 SOFTMAC_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 97 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 98 99 rw_init(&softmac_hash_lock, NULL, RW_DEFAULT, NULL); 100 } 101 102 void 103 softmac_fini() 104 { 105 rw_destroy(&softmac_hash_lock); 106 mod_hash_destroy_hash(softmac_hash); 107 } 108 109 /* ARGSUSED */ 110 static uint_t 111 softmac_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 112 { 113 boolean_t *pexist = arg; 114 115 *pexist = B_TRUE; 116 return (MH_WALK_TERMINATE); 117 } 118 119 boolean_t 120 softmac_busy() 121 { 122 boolean_t exist = B_FALSE; 123 124 rw_enter(&softmac_hash_lock, RW_READER); 125 mod_hash_walk(softmac_hash, softmac_exist, &exist); 126 rw_exit(&softmac_hash_lock); 127 return (exist); 128 } 129 130 /* 131 * This function is called for each minor node during the post-attach of 132 * each DDI_NT_NET device instance. Note that it is possible that a device 133 * instance has two minor nodes (DLPI style-1 and style-2), so that for that 134 * specific device, softmac_create() could be called twice. 135 * 136 * A softmac_t is used to track each DDI_NT_NET device, and a softmac_dev_t 137 * is created to track each minor node. 138 * 139 * For each minor node of a legacy device, a taskq is started to finish 140 * softmac_mac_register(), which will finish the rest of work (see comments 141 * above softmac_mac_register()). 142 */ 143 int 144 softmac_create(dev_info_t *dip, dev_t dev) 145 { 146 char devname[MAXNAMELEN]; 147 softmac_t *softmac; 148 softmac_dev_t *softmac_dev = NULL; 149 int index; 150 int ppa, err = 0; 151 152 /* 153 * Force the softmac driver to be attached. 154 */ 155 if (i_ddi_attach_pseudo_node(SOFTMAC_DEV_NAME) == NULL) { 156 cmn_err(CE_WARN, "softmac_create:softmac attach fails"); 157 return (ENXIO); 158 } 159 160 ppa = ddi_get_instance(dip); 161 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 162 163 /* 164 * We expect legacy devices have at most two minor nodes - one style-1 165 * and one style-2. 166 */ 167 if (!GLDV3_DRV(ddi_driver_major(dip)) && 168 i_ddi_minor_node_count(dip, DDI_NT_NET) > 2) { 169 cmn_err(CE_WARN, "%s has more than 2 minor nodes; unsupported", 170 devname); 171 return (ENOTSUP); 172 } 173 174 /* 175 * Check whether the softmac for the specified device already exists 176 */ 177 rw_enter(&softmac_hash_lock, RW_WRITER); 178 if ((err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 179 (mod_hash_val_t *)&softmac)) != 0) { 180 181 softmac = kmem_zalloc(sizeof (softmac_t), KM_SLEEP); 182 mutex_init(&softmac->smac_mutex, NULL, MUTEX_DRIVER, NULL); 183 cv_init(&softmac->smac_cv, NULL, CV_DRIVER, NULL); 184 rw_init(&softmac->smac_lock, NULL, RW_DRIVER, NULL); 185 (void) strlcpy(softmac->smac_devname, devname, MAXNAMELEN); 186 187 /* 188 * Insert the softmac into the hash table. 189 */ 190 err = mod_hash_insert(softmac_hash, 191 (mod_hash_key_t)softmac->smac_devname, 192 (mod_hash_val_t)softmac); 193 ASSERT(err == 0); 194 } 195 196 mutex_enter(&softmac->smac_mutex); 197 if (softmac->smac_attachok_cnt == 0) { 198 /* 199 * Initialize the softmac if this is the post-attach of the 200 * first minor node. 201 */ 202 softmac->smac_flags = 0; 203 softmac->smac_umajor = ddi_driver_major(dip); 204 softmac->smac_uppa = ppa; 205 206 /* 207 * Note that for GLDv3 devices, we create devfs minor nodes 208 * for VLANs as well. Assume a GLDv3 driver on which only 209 * a VLAN is created. During the detachment of this device 210 * instance, the following would happen: 211 * a. the pre-detach callback softmac_destroy() succeeds. 212 * Because the physical link itself is not in use, 213 * softmac_destroy() succeeds and destroys softmac_t; 214 * b. the device detach fails in mac_unregister() because 215 * this MAC is still used by a VLAN. 216 * c. the post-attach callback is then called which leads 217 * us here. Note that ddi_minor_node_count() returns 3 218 * (including the minior node of the VLAN). In that case, 219 * we must correct the minor node count to 2 as that is 220 * the count of minor nodes that go through post-attach. 221 */ 222 if (GLDV3_DRV(ddi_driver_major(dip))) { 223 softmac->smac_flags |= SOFTMAC_GLDV3; 224 softmac->smac_cnt = 2; 225 } else { 226 softmac->smac_cnt = 227 i_ddi_minor_node_count(dip, DDI_NT_NET); 228 } 229 } 230 231 index = (getmajor(dev) == ddi_name_to_major("clone")); 232 if (softmac->smac_softmac[index] != NULL) { 233 /* 234 * This is possible if the post_attach() is called: 235 * 236 * a. after pre_detach() fails. 237 * 238 * b. for a new round of reattachment. Note that DACF will not 239 * call pre_detach() for successfully post_attached minor 240 * nodes even when the post-attach failed after all. 241 * 242 * Both seem to be defects in the DACF framework. To work 243 * around it and only clear the SOFTMAC_ATTACH_DONE flag for 244 * the b case, a smac_attached_left field is used to tell 245 * the two cases apart. 246 */ 247 ASSERT(softmac->smac_attachok_cnt != 0); 248 249 if (softmac->smac_attached_left != 0) 250 /* case a */ 251 softmac->smac_attached_left--; 252 else if (softmac->smac_attachok_cnt != softmac->smac_cnt) { 253 /* case b */ 254 softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE; 255 } 256 mutex_exit(&softmac->smac_mutex); 257 rw_exit(&softmac_hash_lock); 258 return (0); 259 } 260 mutex_exit(&softmac->smac_mutex); 261 rw_exit(&softmac_hash_lock); 262 263 /* 264 * No lock is needed for access this softmac pointer, as pre-detach and 265 * post-attach won't happen at the same time. 266 */ 267 mutex_enter(&softmac->smac_mutex); 268 269 softmac_dev = kmem_zalloc(sizeof (softmac_dev_t), KM_SLEEP); 270 softmac_dev->sd_dev = dev; 271 softmac->smac_softmac[index] = softmac_dev; 272 273 /* 274 * Continue to register the mac and create the datalink only when all 275 * the minor nodes are attached. 276 */ 277 if (++softmac->smac_attachok_cnt != softmac->smac_cnt) { 278 mutex_exit(&softmac->smac_mutex); 279 return (0); 280 } 281 282 /* 283 * All of the minor nodes have been attached; start a taskq 284 * to do the rest of the work. We use a taskq instead of of 285 * doing the work here because: 286 * 287 * - We could be called as a result of an open() system call 288 * where spec_open() already SLOCKED the snode. Using a taskq 289 * sidesteps the risk that our ldi_open_by_dev() call would 290 * deadlock trying to set SLOCKED on the snode again. 291 * 292 * - The devfs design requires no interruptible function calls 293 * in the device post-attach routine, but we need to make an 294 * (interruptible) upcall. Using a taskq to make the upcall 295 * sidesteps this. 296 */ 297 ASSERT(softmac->smac_taskq == NULL); 298 softmac->smac_taskq = taskq_dispatch(system_taskq, 299 softmac_create_task, softmac, TQ_SLEEP); 300 mutex_exit(&softmac->smac_mutex); 301 return (0); 302 } 303 304 static boolean_t 305 softmac_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 306 { 307 softmac_t *softmac = arg; 308 309 if (!(softmac->smac_capab_flags & cap)) 310 return (B_FALSE); 311 312 switch (cap) { 313 case MAC_CAPAB_HCKSUM: { 314 uint32_t *txflags = cap_data; 315 316 *txflags = softmac->smac_hcksum_txflags; 317 break; 318 } 319 case MAC_CAPAB_LEGACY: { 320 mac_capab_legacy_t *legacy = cap_data; 321 322 legacy->ml_unsup_note = ~softmac->smac_notifications & 323 (DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN | DL_NOTE_SPEED); 324 legacy->ml_dev = makedevice(softmac->smac_umajor, 325 softmac->smac_uppa + 1); 326 break; 327 } 328 329 /* 330 * For the capabilities below, there's nothing for us to fill in; 331 * simply return B_TRUE if we support it. 332 */ 333 case MAC_CAPAB_NO_ZCOPY: 334 case MAC_CAPAB_POLL: 335 case MAC_CAPAB_NO_NATIVEVLAN: 336 default: 337 break; 338 } 339 return (B_TRUE); 340 } 341 342 static int 343 softmac_update_info(softmac_t *softmac, datalink_id_t *linkidp) 344 { 345 datalink_id_t linkid = DATALINK_INVALID_LINKID; 346 uint32_t media; 347 int err; 348 349 if ((err = dls_mgmt_update(softmac->smac_devname, softmac->smac_media, 350 softmac->smac_flags & SOFTMAC_NOSUPP, &media, &linkid)) == 0) { 351 *linkidp = linkid; 352 } 353 354 if (err == EEXIST) { 355 /* 356 * There is a link name conflict. Either: 357 * 358 * - An existing link with the same device name with a 359 * different media type from of the given type. 360 * Mark this link back to persistent only; or 361 * 362 * - We cannot assign the "suggested" name because 363 * GLDv3 and therefore vanity naming is not supported 364 * for this link type. Delete this link's <link name, 365 * linkid> mapping. 366 */ 367 if (media != softmac->smac_media) { 368 cmn_err(CE_WARN, "%s device %s conflicts with " 369 "existing %s device %s.", 370 dl_mactypestr(softmac->smac_media), 371 softmac->smac_devname, dl_mactypestr(media), 372 softmac->smac_devname); 373 (void) dls_mgmt_destroy(linkid, B_FALSE); 374 } else { 375 cmn_err(CE_WARN, "link name %s is already in-use.", 376 softmac->smac_devname); 377 (void) dls_mgmt_destroy(linkid, B_TRUE); 378 } 379 380 cmn_err(CE_WARN, "%s device might not be available " 381 "for use.", softmac->smac_devname); 382 cmn_err(CE_WARN, "See dladm(1M) for more information."); 383 } 384 385 return (err); 386 } 387 388 /* 389 * This function: 390 * 1. provides the link's media type to dlmgmtd. 391 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 392 */ 393 static int 394 softmac_create_datalink(softmac_t *softmac) 395 { 396 datalink_id_t linkid = DATALINK_INVALID_LINKID; 397 int err; 398 399 ASSERT(MUTEX_HELD(&softmac->smac_mutex)); 400 401 /* 402 * Inform dlmgmtd of this link so that softmac_hold_device() is able 403 * to know the existence of this link. If this failed with EBADF, 404 * it might be because dlmgmtd was not started in time (e.g., 405 * diskless boot); ignore the failure and continue to create 406 * the GLDv3 datalink if needed. 407 */ 408 err = dls_mgmt_create(softmac->smac_devname, 409 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 410 DATALINK_CLASS_PHYS, DL_OTHER, B_TRUE, &linkid); 411 if (err != 0 && err != EBADF) 412 return (err); 413 414 /* 415 * Provide the media type of the physical link to dlmgmtd. 416 */ 417 if ((err != EBADF) && 418 ((err = softmac_update_info(softmac, &linkid)) != 0)) { 419 return (err); 420 } 421 422 /* 423 * Create the GLDv3 datalink. 424 */ 425 if ((!(softmac->smac_flags & SOFTMAC_NOSUPP)) && 426 ((err = dls_devnet_create(softmac->smac_mh, linkid)) != 0)) { 427 cmn_err(CE_WARN, "dls_devnet_create failed for %s", 428 softmac->smac_devname); 429 return (err); 430 } 431 432 if (linkid == DATALINK_INVALID_LINKID) 433 softmac->smac_flags |= SOFTMAC_NEED_RECREATE; 434 435 return (0); 436 } 437 438 static void 439 softmac_create_task(void *arg) 440 { 441 softmac_t *softmac = arg; 442 mac_handle_t mh; 443 int err; 444 445 if (!GLDV3_DRV(softmac->smac_umajor)) { 446 softmac_mac_register(softmac); 447 return; 448 } 449 450 if ((err = mac_open(softmac->smac_devname, &mh)) != 0) 451 goto done; 452 453 mutex_enter(&softmac->smac_mutex); 454 softmac->smac_media = (mac_info(mh))->mi_nativemedia; 455 softmac->smac_mh = mh; 456 457 /* 458 * We can safely release the reference on the mac because 459 * this mac will only be unregistered and destroyed when 460 * the device detaches, and the softmac will be destroyed 461 * before then (in the pre-detach routine of the device). 462 */ 463 mac_close(mh); 464 465 /* 466 * Create the GLDv3 datalink for this mac. 467 */ 468 err = softmac_create_datalink(softmac); 469 470 done: 471 ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); 472 softmac->smac_flags |= SOFTMAC_ATTACH_DONE; 473 softmac->smac_attacherr = err; 474 softmac->smac_taskq = NULL; 475 cv_broadcast(&softmac->smac_cv); 476 mutex_exit(&softmac->smac_mutex); 477 } 478 479 /* 480 * This function is only called for legacy devices. It: 481 * 1. registers the MAC for the legacy devices whose media type is supported 482 * by the GLDv3 framework. 483 * 2. creates the GLDv3 datalink if the media type is supported by GLDv3. 484 */ 485 static void 486 softmac_mac_register(softmac_t *softmac) 487 { 488 softmac_dev_t *softmac_dev; 489 dev_t dev; 490 ldi_handle_t lh = NULL; 491 ldi_ident_t li = NULL; 492 int index; 493 boolean_t native_vlan = B_FALSE; 494 int err; 495 496 /* 497 * Note that we do not need any locks to access this softmac pointer, 498 * as softmac_destroy() will wait until this function is called. 499 */ 500 ASSERT(softmac != NULL); 501 502 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) { 503 mutex_enter(&softmac->smac_mutex); 504 goto done; 505 } 506 507 /* 508 * Determine whether this legacy device support VLANs by opening 509 * the style-2 device node (if it exists) and attaching to a VLAN 510 * PPA (1000 + ppa). 511 */ 512 dev = makedevice(ddi_name_to_major("clone"), softmac->smac_umajor); 513 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 514 if (err == 0) { 515 if (dl_attach(lh, softmac->smac_uppa + 1 * 1000, NULL) == 0) 516 native_vlan = B_TRUE; 517 (void) ldi_close(lh, FREAD|FWRITE, kcred); 518 } 519 520 err = EINVAL; 521 for (index = 0; index < 2; index++) { 522 dl_info_ack_t dlia; 523 dl_error_ack_t dlea; 524 uint32_t notes; 525 struct strioctl iocb; 526 uint32_t margin; 527 int rval; 528 529 if ((softmac_dev = softmac->smac_softmac[index]) == NULL) 530 continue; 531 532 softmac->smac_dev = dev = softmac_dev->sd_dev; 533 if (ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, 534 li) != 0) { 535 continue; 536 } 537 538 /* 539 * Pop all the intermediate modules in order to negotiate 540 * capabilities correctly. 541 */ 542 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 543 ; 544 545 /* DLPI style-1 or DLPI style-2? */ 546 if ((rval = dl_info(lh, &dlia, NULL, NULL, &dlea)) != 0) { 547 if (rval == ENOTSUP) { 548 cmn_err(CE_NOTE, "softmac: received " 549 "DL_ERROR_ACK to DL_INFO_ACK; " 550 "DLPI errno 0x%x, UNIX errno %d", 551 dlea.dl_errno, dlea.dl_unix_errno); 552 } 553 (void) ldi_close(lh, FREAD|FWRITE, kcred); 554 continue; 555 } 556 557 /* 558 * Currently only DL_ETHER has GLDv3 mac plugin support. 559 * For media types that GLDv3 does not support, create a 560 * link id for it. 561 */ 562 if ((softmac->smac_media = dlia.dl_mac_type) != DL_ETHER) { 563 (void) ldi_close(lh, FREAD|FWRITE, kcred); 564 err = 0; 565 break; 566 } 567 568 if ((dlia.dl_provider_style == DL_STYLE2) && 569 (dl_attach(lh, softmac->smac_uppa, NULL) != 0)) { 570 (void) ldi_close(lh, FREAD|FWRITE, kcred); 571 continue; 572 } 573 574 if ((rval = dl_bind(lh, 0, NULL)) != 0) { 575 if (rval == ENOTSUP) { 576 cmn_err(CE_NOTE, "softmac: received " 577 "DL_ERROR_ACK to DL_BIND_ACK; " 578 "DLPI errno 0x%x, UNIX errno %d", 579 dlea.dl_errno, dlea.dl_unix_errno); 580 } 581 (void) ldi_close(lh, FREAD|FWRITE, kcred); 582 continue; 583 } 584 585 /* 586 * Call dl_info() after dl_bind() because some drivers only 587 * provide correct information (e.g. MAC address) once bound. 588 */ 589 softmac->smac_addrlen = sizeof (softmac->smac_unicst_addr); 590 if ((rval = dl_info(lh, &dlia, softmac->smac_unicst_addr, 591 &softmac->smac_addrlen, &dlea)) != 0) { 592 if (rval == ENOTSUP) { 593 cmn_err(CE_NOTE, "softmac: received " 594 "DL_ERROR_ACK to DL_INFO_ACK; " 595 "DLPI errno 0x%x, UNIX errno %d", 596 dlea.dl_errno, dlea.dl_unix_errno); 597 } 598 (void) ldi_close(lh, FREAD|FWRITE, kcred); 599 continue; 600 } 601 602 softmac->smac_style = dlia.dl_provider_style; 603 softmac->smac_saplen = ABS(dlia.dl_sap_length); 604 softmac->smac_min_sdu = dlia.dl_min_sdu; 605 softmac->smac_max_sdu = dlia.dl_max_sdu; 606 607 if ((softmac->smac_saplen != sizeof (uint16_t)) || 608 (softmac->smac_addrlen != ETHERADDRL) || 609 (dlia.dl_brdcst_addr_length != ETHERADDRL) || 610 (dlia.dl_brdcst_addr_offset == 0)) { 611 (void) ldi_close(lh, FREAD|FWRITE, kcred); 612 continue; 613 } 614 615 /* 616 * Check other DLPI capabilities. Note that this must be after 617 * dl_bind() because some drivers return DL_ERROR_ACK if the 618 * stream is not bound. It is also before mac_register(), so 619 * we don't need any lock protection here. 620 * 621 * Softmac always supports POLL. 622 */ 623 softmac->smac_capab_flags = 624 (MAC_CAPAB_POLL | MAC_CAPAB_NO_ZCOPY | MAC_CAPAB_LEGACY); 625 626 softmac->smac_no_capability_req = B_FALSE; 627 if (softmac_fill_capab(lh, softmac) != 0) 628 softmac->smac_no_capability_req = B_TRUE; 629 630 /* 631 * Check the margin of the underlying driver. 632 */ 633 margin = 0; 634 iocb.ic_cmd = DLIOCMARGININFO; 635 iocb.ic_timout = INFTIM; 636 iocb.ic_len = sizeof (margin); 637 iocb.ic_dp = (char *)&margin; 638 softmac->smac_margin = 0; 639 640 if (ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, 641 &rval) == 0) { 642 softmac->smac_margin = margin; 643 } 644 645 /* 646 * If the legacy driver doesn't support DLIOCMARGININFO, but 647 * it can support native VLAN, correct its margin value to 4. 648 */ 649 if (native_vlan) { 650 if (softmac->smac_margin == 0) 651 softmac->smac_margin = VLAN_TAGSZ; 652 } else { 653 softmac->smac_capab_flags |= MAC_CAPAB_NO_NATIVEVLAN; 654 } 655 656 /* 657 * Not all drivers support DL_NOTIFY_REQ, so ignore ENOTSUP. 658 */ 659 softmac->smac_notifications = 0; 660 notes = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN; 661 switch (dl_notify(lh, ¬es, NULL)) { 662 case 0: 663 softmac->smac_notifications = notes; 664 break; 665 case ENOTSUP: 666 break; 667 default: 668 (void) ldi_close(lh, FREAD|FWRITE, kcred); 669 continue; 670 } 671 672 (void) ldi_close(lh, FREAD|FWRITE, kcred); 673 err = 0; 674 break; 675 } 676 ldi_ident_release(li); 677 678 mutex_enter(&softmac->smac_mutex); 679 680 if (err != 0) 681 goto done; 682 683 if (softmac->smac_media != DL_ETHER) 684 softmac->smac_flags |= SOFTMAC_NOSUPP; 685 686 /* 687 * Finally, we're ready to register ourselves with the MAC layer 688 * interface; if this succeeds, we're all ready to start() 689 */ 690 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 691 mac_register_t *macp; 692 693 if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 694 err = ENOMEM; 695 goto done; 696 } 697 698 macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 699 macp->m_driver = softmac; 700 macp->m_dip = softmac_dip; 701 702 macp->m_margin = softmac->smac_margin; 703 macp->m_src_addr = softmac->smac_unicst_addr; 704 macp->m_min_sdu = softmac->smac_min_sdu; 705 macp->m_max_sdu = softmac->smac_max_sdu; 706 macp->m_callbacks = &softmac_m_callbacks; 707 macp->m_instance = (uint_t)-1; 708 709 err = mac_register(macp, &softmac->smac_mh); 710 mac_free(macp); 711 if (err != 0) { 712 cmn_err(CE_WARN, "mac_register failed for %s", 713 softmac->smac_devname); 714 goto done; 715 } 716 } 717 718 /* 719 * Try to create the datalink for this softmac. 720 */ 721 if ((err = softmac_create_datalink(softmac)) != 0) { 722 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 723 (void) mac_unregister(softmac->smac_mh); 724 softmac->smac_mh = NULL; 725 } 726 } 727 728 done: 729 ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); 730 softmac->smac_flags |= SOFTMAC_ATTACH_DONE; 731 softmac->smac_attacherr = err; 732 softmac->smac_taskq = NULL; 733 cv_broadcast(&softmac->smac_cv); 734 mutex_exit(&softmac->smac_mutex); 735 } 736 737 int 738 softmac_destroy(dev_info_t *dip, dev_t dev) 739 { 740 char devname[MAXNAMELEN]; 741 softmac_t *softmac; 742 softmac_dev_t *softmac_dev; 743 int index; 744 int ppa, err; 745 datalink_id_t linkid; 746 747 ppa = ddi_get_instance(dip); 748 (void) snprintf(devname, MAXNAMELEN, "%s%d", ddi_driver_name(dip), ppa); 749 750 rw_enter(&softmac_hash_lock, RW_WRITER); 751 err = mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 752 (mod_hash_val_t *)&softmac); 753 ASSERT(err == 0); 754 755 mutex_enter(&softmac->smac_mutex); 756 757 /* 758 * Fail the predetach routine if this softmac is in-use. 759 */ 760 if (softmac->smac_hold_cnt != 0) { 761 softmac->smac_attached_left = softmac->smac_attachok_cnt; 762 mutex_exit(&softmac->smac_mutex); 763 rw_exit(&softmac_hash_lock); 764 return (EBUSY); 765 } 766 767 /* 768 * Even if the predetach of one minor node has already failed 769 * (smac_attached_left is not 0), the DACF framework will continue 770 * to call the predetach routines of the other minor nodes, 771 * so we fail these calls here. 772 */ 773 if (softmac->smac_attached_left != 0) { 774 mutex_exit(&softmac->smac_mutex); 775 rw_exit(&softmac_hash_lock); 776 return (EBUSY); 777 } 778 779 if (softmac->smac_attachok_cnt != softmac->smac_cnt) 780 goto done; 781 782 /* 783 * This is the detach for the first minor node. Wait until all the 784 * minor nodes are attached. 785 */ 786 while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)) 787 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 788 789 if (softmac->smac_mh != NULL) { 790 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 791 if ((err = dls_devnet_destroy(softmac->smac_mh, 792 &linkid)) != 0) { 793 goto done; 794 } 795 } 796 /* 797 * If softmac_mac_register() succeeds in registering the mac 798 * of the legacy device, unregister it. 799 */ 800 if (!(softmac->smac_flags & (SOFTMAC_GLDV3 | SOFTMAC_NOSUPP))) { 801 if ((err = mac_unregister(softmac->smac_mh)) != 0) { 802 (void) dls_devnet_create(softmac->smac_mh, 803 linkid); 804 goto done; 805 } 806 } 807 softmac->smac_mh = NULL; 808 } 809 softmac->smac_flags &= ~SOFTMAC_ATTACH_DONE; 810 811 done: 812 if (err == 0) { 813 /* 814 * Free softmac_dev 815 */ 816 index = (getmajor(dev) == ddi_name_to_major("clone")); 817 softmac_dev = softmac->smac_softmac[index]; 818 ASSERT(softmac_dev != NULL); 819 softmac->smac_softmac[index] = NULL; 820 kmem_free(softmac_dev, sizeof (softmac_dev_t)); 821 822 if (--softmac->smac_attachok_cnt == 0) { 823 mod_hash_val_t hashval; 824 825 err = mod_hash_remove(softmac_hash, 826 (mod_hash_key_t)devname, 827 (mod_hash_val_t *)&hashval); 828 ASSERT(err == 0); 829 830 mutex_exit(&softmac->smac_mutex); 831 rw_exit(&softmac_hash_lock); 832 833 ASSERT(softmac->smac_taskq == NULL); 834 ASSERT(!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)); 835 mutex_destroy(&softmac->smac_mutex); 836 cv_destroy(&softmac->smac_cv); 837 rw_destroy(&softmac->smac_lock); 838 kmem_free(softmac, sizeof (softmac_t)); 839 return (0); 840 } 841 } else { 842 softmac->smac_attached_left = softmac->smac_attachok_cnt; 843 } 844 845 mutex_exit(&softmac->smac_mutex); 846 rw_exit(&softmac_hash_lock); 847 return (err); 848 } 849 850 /* 851 * This function is called as the result of a newly started dlmgmtd daemon. 852 * 853 * We walk through every softmac that was created but failed to notify 854 * dlmgmtd about it (whose SOFTMAC_NEED_RECREATE flag is set). This occurs 855 * when softmacs are created before dlmgmtd is ready. For example, during 856 * diskless boot, a network device is used (and therefore attached) before 857 * the datalink-management service starts dlmgmtd. 858 */ 859 /* ARGSUSED */ 860 static uint_t 861 softmac_mac_recreate(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 862 { 863 softmac_t *softmac = (softmac_t *)val; 864 datalink_id_t linkid; 865 int err; 866 867 ASSERT(RW_READ_HELD(&softmac_hash_lock)); 868 869 /* 870 * Wait for softmac_create() and softmac_mac_register() to exit. 871 */ 872 mutex_enter(&softmac->smac_mutex); 873 while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)) 874 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 875 876 if ((softmac->smac_attacherr != 0) || 877 !(softmac->smac_flags & SOFTMAC_NEED_RECREATE)) { 878 mutex_exit(&softmac->smac_mutex); 879 return (MH_WALK_CONTINUE); 880 } 881 882 if (dls_mgmt_create(softmac->smac_devname, 883 makedevice(softmac->smac_umajor, softmac->smac_uppa + 1), 884 DATALINK_CLASS_PHYS, softmac->smac_media, B_TRUE, &linkid) != 0) { 885 mutex_exit(&softmac->smac_mutex); 886 return (MH_WALK_CONTINUE); 887 } 888 889 if ((err = softmac_update_info(softmac, &linkid)) != 0) { 890 cmn_err(CE_WARN, "softmac: softmac_update_info() for %s " 891 "failed (%d)", softmac->smac_devname, err); 892 mutex_exit(&softmac->smac_mutex); 893 return (MH_WALK_CONTINUE); 894 } 895 896 /* 897 * Create a link for this MAC. The link name will be the same 898 * as the MAC name. 899 */ 900 if (!(softmac->smac_flags & SOFTMAC_NOSUPP)) { 901 err = dls_devnet_recreate(softmac->smac_mh, linkid); 902 if (err != 0) { 903 cmn_err(CE_WARN, "softmac: dls_devnet_recreate() for " 904 "%s (linkid %d) failed (%d)", 905 softmac->smac_devname, linkid, err); 906 } 907 } 908 909 softmac->smac_flags &= ~SOFTMAC_NEED_RECREATE; 910 mutex_exit(&softmac->smac_mutex); 911 912 return (MH_WALK_CONTINUE); 913 } 914 915 /* 916 * See comments above softmac_mac_recreate(). 917 */ 918 void 919 softmac_recreate() 920 { 921 /* 922 * Walk through the softmac_hash table. Request to create the 923 * [link name, linkid] mapping if we failed to do so. 924 */ 925 rw_enter(&softmac_hash_lock, RW_READER); 926 mod_hash_walk(softmac_hash, softmac_mac_recreate, NULL); 927 rw_exit(&softmac_hash_lock); 928 } 929 930 /* ARGSUSED */ 931 static int 932 softmac_m_start(void *arg) 933 { 934 return (0); 935 } 936 937 /* ARGSUSED */ 938 static void 939 softmac_m_stop(void *arg) 940 { 941 } 942 943 /* 944 * Set up the lower stream above the legacy device which is shared by 945 * GLDv3 MAC clients. Put the lower stream into DLIOCRAW mode to send 946 * and receive the raw data. Further, put the lower stream into 947 * DL_PROMISC_SAP mode to receive all packets of interest. 948 */ 949 static int 950 softmac_lower_setup(softmac_t *softmac, softmac_lower_t **slpp) 951 { 952 ldi_ident_t li; 953 dev_t dev; 954 ldi_handle_t lh = NULL; 955 softmac_lower_t *slp = NULL; 956 smac_ioc_start_t start_arg; 957 struct strioctl strioc; 958 uint32_t notifications; 959 int err, rval; 960 961 if ((err = ldi_ident_from_dip(softmac_dip, &li)) != 0) 962 return (err); 963 964 dev = softmac->smac_dev; 965 err = ldi_open_by_dev(&dev, OTYP_CHR, FREAD|FWRITE, kcred, &lh, li); 966 ldi_ident_release(li); 967 if (err != 0) 968 goto done; 969 970 /* 971 * Pop all the intermediate modules. The autopushed modules will 972 * be pushed when the softmac node is opened. 973 */ 974 while (ldi_ioctl(lh, I_POP, 0, FKIOCTL, kcred, &rval) == 0) 975 ; 976 977 if ((softmac->smac_style == DL_STYLE2) && 978 ((err = dl_attach(lh, softmac->smac_uppa, NULL)) != 0)) { 979 goto done; 980 } 981 982 /* 983 * Put the lower stream into DLIOCRAW mode to send/receive raw data. 984 */ 985 if ((err = ldi_ioctl(lh, DLIOCRAW, 0, FKIOCTL, kcred, &rval)) != 0) 986 goto done; 987 988 /* 989 * Then push the softmac shim layer atop the lower stream. 990 */ 991 if ((err = ldi_ioctl(lh, I_PUSH, (intptr_t)SOFTMAC_DEV_NAME, FKIOCTL, 992 kcred, &rval)) != 0) { 993 goto done; 994 } 995 996 /* 997 * Send the ioctl to get the slp pointer. 998 */ 999 strioc.ic_cmd = SMAC_IOC_START; 1000 strioc.ic_timout = INFTIM; 1001 strioc.ic_len = sizeof (start_arg); 1002 strioc.ic_dp = (char *)&start_arg; 1003 1004 if ((err = ldi_ioctl(lh, I_STR, (intptr_t)&strioc, FKIOCTL, 1005 kcred, &rval)) != 0) { 1006 goto done; 1007 } 1008 slp = start_arg.si_slp; 1009 slp->sl_lh = lh; 1010 slp->sl_softmac = softmac; 1011 *slpp = slp; 1012 1013 /* 1014 * Bind to SAP 2 on token ring, 0 on other interface types. 1015 * (SAP 0 has special significance on token ring). 1016 * Note that the receive-side packets could come anytime after bind. 1017 */ 1018 if (softmac->smac_media == DL_TPR) 1019 err = softmac_send_bind_req(slp, 2); 1020 else 1021 err = softmac_send_bind_req(slp, 0); 1022 if (err != 0) 1023 goto done; 1024 1025 /* 1026 * Put the lower stream into DL_PROMISC_SAP mode to receive all 1027 * packets of interest. 1028 * 1029 * Some drivers (e.g. the old legacy eri driver) incorrectly pass up 1030 * packets to DL_PROMISC_SAP stream when the lower stream is not bound, 1031 * so we send DL_PROMISON_REQ after DL_BIND_REQ. 1032 */ 1033 if ((err = softmac_send_promisc_req(slp, DL_PROMISC_SAP, B_TRUE)) != 0) 1034 goto done; 1035 1036 /* 1037 * Enable the capabilities the underlying driver claims to support. 1038 * Some drivers require this to be called after the stream is bound. 1039 */ 1040 if ((err = softmac_capab_enable(slp)) != 0) 1041 goto done; 1042 1043 /* 1044 * Send the DL_NOTIFY_REQ to enable certain DL_NOTIFY_IND. 1045 * We don't have to wait for the ack. 1046 */ 1047 notifications = DL_NOTE_PHYS_ADDR | DL_NOTE_LINK_UP | 1048 DL_NOTE_LINK_DOWN | DL_NOTE_PROMISC_ON_PHYS | 1049 DL_NOTE_PROMISC_OFF_PHYS; 1050 1051 (void) softmac_send_notify_req(slp, 1052 (notifications & softmac->smac_notifications)); 1053 1054 done: 1055 if (err != 0) 1056 (void) ldi_close(lh, FREAD|FWRITE, kcred); 1057 return (err); 1058 } 1059 1060 static int 1061 softmac_m_open(void *arg) 1062 { 1063 softmac_t *softmac = arg; 1064 softmac_lower_t *slp; 1065 int err; 1066 1067 rw_enter(&softmac->smac_lock, RW_READER); 1068 if (softmac->smac_state == SOFTMAC_READY) 1069 goto done; 1070 rw_exit(&softmac->smac_lock); 1071 1072 if ((err = softmac_lower_setup(softmac, &slp)) != 0) 1073 return (err); 1074 1075 rw_enter(&softmac->smac_lock, RW_WRITER); 1076 ASSERT(softmac->smac_state == SOFTMAC_INITIALIZED); 1077 softmac->smac_lower = slp; 1078 softmac->smac_state = SOFTMAC_READY; 1079 done: 1080 rw_exit(&softmac->smac_lock); 1081 return (0); 1082 } 1083 1084 static void 1085 softmac_m_close(void *arg) 1086 { 1087 softmac_t *softmac = arg; 1088 softmac_lower_t *slp; 1089 1090 rw_enter(&softmac->smac_lock, RW_WRITER); 1091 slp = softmac->smac_lower; 1092 ASSERT(slp != NULL); 1093 1094 /* 1095 * Note that slp is destroyed when lh is closed. 1096 */ 1097 (void) ldi_close(slp->sl_lh, FREAD|FWRITE, kcred); 1098 softmac->smac_state = SOFTMAC_INITIALIZED; 1099 softmac->smac_lower = NULL; 1100 rw_exit(&softmac->smac_lock); 1101 } 1102 1103 int 1104 softmac_hold_device(dev_t dev, dls_dev_handle_t *ddhp) 1105 { 1106 dev_info_t *dip; 1107 const char *drvname; 1108 char devname[MAXNAMELEN]; 1109 softmac_t *softmac; 1110 int ppa, err; 1111 1112 if ((ppa = getminor(dev) - 1) > 1000) 1113 return (ENOENT); 1114 1115 /* 1116 * First try to hold this device instance to force the MAC 1117 * to be registered. 1118 */ 1119 if ((dip = ddi_hold_devi_by_instance(getmajor(dev), ppa, 0)) == NULL) 1120 return (ENOENT); 1121 1122 drvname = ddi_driver_name(dip); 1123 1124 /* 1125 * Exclude non-physical network device instances, for example, aggr0. 1126 */ 1127 if ((ddi_driver_major(dip) != getmajor(dev)) || 1128 !NETWORK_DRV(getmajor(dev)) || (strcmp(drvname, "aggr") == 0) || 1129 (strcmp(drvname, "vnic") == 0)) { 1130 ddi_release_devi(dip); 1131 return (ENOENT); 1132 } 1133 1134 /* 1135 * This is a network device; wait for its softmac to be registered. 1136 */ 1137 (void) snprintf(devname, MAXNAMELEN, "%s%d", drvname, ppa); 1138 again: 1139 rw_enter(&softmac_hash_lock, RW_READER); 1140 1141 if (mod_hash_find(softmac_hash, (mod_hash_key_t)devname, 1142 (mod_hash_val_t *)&softmac) != 0) { 1143 /* 1144 * This is rare but possible. It could happen when pre-detach 1145 * routine of the device succeeds. But the softmac will then 1146 * be recreated when device fails to detach (as this device 1147 * is held). 1148 */ 1149 rw_exit(&softmac_hash_lock); 1150 goto again; 1151 } 1152 1153 /* 1154 * Bump smac_hold_cnt to prevent device detach. 1155 */ 1156 mutex_enter(&softmac->smac_mutex); 1157 softmac->smac_hold_cnt++; 1158 mutex_exit(&softmac->smac_mutex); 1159 1160 rw_exit(&softmac_hash_lock); 1161 1162 /* 1163 * Wait till the device is fully attached. 1164 */ 1165 mutex_enter(&softmac->smac_mutex); 1166 while (!(softmac->smac_flags & SOFTMAC_ATTACH_DONE)) 1167 cv_wait(&softmac->smac_cv, &softmac->smac_mutex); 1168 1169 if ((err = softmac->smac_attacherr) != 0) 1170 softmac->smac_hold_cnt--; 1171 else 1172 *ddhp = (dls_dev_handle_t)softmac; 1173 mutex_exit(&softmac->smac_mutex); 1174 1175 ddi_release_devi(dip); 1176 return (err); 1177 } 1178 1179 void 1180 softmac_rele_device(dls_dev_handle_t ddh) 1181 { 1182 softmac_t *softmac; 1183 1184 if (ddh == NULL) 1185 return; 1186 1187 softmac = (softmac_t *)ddh; 1188 mutex_enter(&softmac->smac_mutex); 1189 softmac->smac_hold_cnt--; 1190 mutex_exit(&softmac->smac_mutex); 1191 } 1192