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