1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Data-Link Services Module 28 */ 29 30 #include <sys/strsun.h> 31 #include <sys/vlan.h> 32 #include <sys/dld_impl.h> 33 #include <sys/mac_client_priv.h> 34 35 int 36 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp) 37 { 38 zoneid_t zid = getzoneid(); 39 boolean_t local; 40 int err; 41 42 /* 43 * Check whether this client belongs to the zone of this dlp. Note that 44 * a global zone client is allowed to open a local zone dlp. 45 */ 46 if (zid != GLOBAL_ZONEID && dlp->dl_zid != zid) 47 return (ENOENT); 48 49 /* 50 * mac_start() is required for non-legacy MACs to show accurate 51 * kstats even before the interface is brought up. For legacy 52 * drivers, this is not needed. Further, calling mac_start() for 53 * legacy drivers would make the shared-lower-stream to stay in 54 * the DL_IDLE state, which in turn causes performance regression. 55 */ 56 if (!mac_capab_get(dlp->dl_mh, MAC_CAPAB_LEGACY, NULL) && 57 ((err = mac_start(dlp->dl_mh)) != 0)) { 58 return (err); 59 } 60 61 local = (zid == dlp->dl_zid); 62 dlp->dl_zone_ref += (local ? 1 : 0); 63 64 /* 65 * Cache a copy of the MAC interface handle, a pointer to the 66 * immutable MAC info. 67 */ 68 dsp->ds_dlp = dlp; 69 dsp->ds_mh = dlp->dl_mh; 70 dsp->ds_mch = dlp->dl_mch; 71 dsp->ds_mip = dlp->dl_mip; 72 dsp->ds_ddh = ddh; 73 dsp->ds_local = local; 74 75 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 76 return (0); 77 } 78 79 void 80 dls_close(dld_str_t *dsp) 81 { 82 dls_link_t *dlp = dsp->ds_dlp; 83 dls_multicst_addr_t *p; 84 dls_multicst_addr_t *nextp; 85 uint32_t old_flags; 86 87 ASSERT(dsp->ds_datathr_cnt == 0); 88 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 89 90 if (dsp->ds_local) 91 dlp->dl_zone_ref--; 92 dsp->ds_local = B_FALSE; 93 94 /* 95 * Walk the list of multicast addresses, disabling each at the MAC. 96 * Note that we must remove multicast address before 97 * mac_unicast_remove() (called by dls_active_clear()) because 98 * mac_multicast_remove() relies on the unicast flows on the mac 99 * client. 100 */ 101 for (p = dsp->ds_dmap; p != NULL; p = nextp) { 102 (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr); 103 nextp = p->dma_nextp; 104 kmem_free(p, sizeof (dls_multicst_addr_t)); 105 } 106 dsp->ds_dmap = NULL; 107 108 dls_active_clear(dsp, B_TRUE); 109 110 /* 111 * If the dld_str_t is bound then unbind it. 112 */ 113 if (dsp->ds_dlstate == DL_IDLE) { 114 dls_unbind(dsp); 115 dsp->ds_dlstate = DL_UNBOUND; 116 } 117 118 /* 119 * If the MAC has been set in promiscuous mode then disable it. 120 * This needs to be done before resetting ds_rx. 121 */ 122 old_flags = dsp->ds_promisc; 123 dsp->ds_promisc = 0; 124 (void) dls_promisc(dsp, old_flags); 125 126 /* 127 * At this point we have cutoff inbound packet flow from the mac 128 * for this 'dsp'. The dls_link_remove above cut off packets meant 129 * for us and waited for upcalls to finish. Similarly the dls_promisc 130 * reset above waited for promisc callbacks to finish. Now we can 131 * safely reset ds_rx to NULL 132 */ 133 dsp->ds_rx = NULL; 134 dsp->ds_rx_arg = NULL; 135 136 dsp->ds_dlp = NULL; 137 138 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL)) 139 mac_stop(dsp->ds_mh); 140 141 /* 142 * Release our reference to the dls_link_t allowing that to be 143 * destroyed if there are no more dls_impl_t. 144 */ 145 dls_link_rele(dlp); 146 } 147 148 int 149 dls_bind(dld_str_t *dsp, uint32_t sap) 150 { 151 uint32_t dls_sap; 152 153 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 154 155 /* 156 * Check to see the value is legal for the media type. 157 */ 158 if (!mac_sap_verify(dsp->ds_mh, sap, &dls_sap)) 159 return (EINVAL); 160 161 if (dsp->ds_promisc & DLS_PROMISC_SAP) 162 dls_sap = DLS_SAP_PROMISC; 163 164 /* 165 * Set up the dld_str_t to mark it as able to receive packets. 166 */ 167 dsp->ds_sap = sap; 168 169 /* 170 * The MAC layer does the VLAN demultiplexing and will only pass up 171 * untagged packets to non-promiscuous primary MAC clients. In order to 172 * support the binding to the VLAN SAP which is required by DLPI, dls 173 * needs to get a copy of all tagged packets when the client binds to 174 * the VLAN SAP. We do this by registering a separate promiscuous 175 * callback for each dls client binding to that SAP. 176 * 177 * Note: even though there are two promiscuous handles in dld_str_t, 178 * ds_mph is for the regular promiscuous mode, ds_vlan_mph is the handle 179 * to receive VLAN pkt when promiscuous mode is not on. Only one of 180 * them can be non-NULL at the same time, to avoid receiving dup copies 181 * of pkts. 182 */ 183 if (sap == ETHERTYPE_VLAN && dsp->ds_promisc == 0) { 184 int err; 185 186 if (dsp->ds_vlan_mph != NULL) 187 return (EINVAL); 188 err = mac_promisc_add(dsp->ds_mch, 189 MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp, 190 &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS); 191 192 if (err == 0 && dsp->ds_nonip && 193 dsp->ds_dlp->dl_nonip_cnt++ == 0) 194 mac_rx_bypass_disable(dsp->ds_mch); 195 196 return (err); 197 } 198 199 /* 200 * Now bind the dld_str_t by adding it into the hash table in the 201 * dls_link_t. 202 */ 203 dls_link_add(dsp->ds_dlp, dls_sap, dsp); 204 if (dsp->ds_nonip && dsp->ds_dlp->dl_nonip_cnt++ == 0) 205 mac_rx_bypass_disable(dsp->ds_mch); 206 207 return (0); 208 } 209 210 void 211 dls_unbind(dld_str_t *dsp) 212 { 213 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 214 215 if (dsp->ds_nonip && --dsp->ds_dlp->dl_nonip_cnt == 0) 216 mac_rx_bypass_enable(dsp->ds_mch); 217 218 /* 219 * For VLAN SAP, there was a promisc handle registered when dls_bind. 220 * When unbind this dls link, we need to remove the promisc handle. 221 * See comments in dls_bind(). 222 */ 223 if (dsp->ds_vlan_mph != NULL) { 224 mac_promisc_remove(dsp->ds_vlan_mph); 225 dsp->ds_vlan_mph = NULL; 226 return; 227 } 228 229 /* 230 * Unbind the dld_str_t by removing it from the hash table in the 231 * dls_link_t. 232 */ 233 dls_link_remove(dsp->ds_dlp, dsp); 234 dsp->ds_sap = 0; 235 } 236 237 int 238 dls_promisc(dld_str_t *dsp, uint32_t old_flags) 239 { 240 int err = 0; 241 242 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 243 ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 244 DLS_PROMISC_PHYS))); 245 246 if (old_flags == 0 && dsp->ds_promisc != 0) { 247 /* 248 * If only DLS_PROMISC_SAP, we don't turn on the 249 * physical promisc mode 250 */ 251 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL, 252 dls_rx_promisc, dsp, &dsp->ds_mph, 253 (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 : 254 MAC_PROMISC_FLAGS_NO_PHYS); 255 if (err != 0) 256 return (err); 257 258 /* Remove vlan promisc handle to avoid sending dup copy up */ 259 if (dsp->ds_vlan_mph != NULL) { 260 mac_promisc_remove(dsp->ds_vlan_mph); 261 dsp->ds_vlan_mph = NULL; 262 } 263 } else if (old_flags != 0 && dsp->ds_promisc == 0) { 264 ASSERT(dsp->ds_mph != NULL); 265 266 mac_promisc_remove(dsp->ds_mph); 267 dsp->ds_mph = NULL; 268 269 if (dsp->ds_sap == ETHERTYPE_VLAN && 270 dsp->ds_dlstate != DL_UNBOUND) { 271 int err; 272 273 if (dsp->ds_vlan_mph != NULL) 274 return (EINVAL); 275 err = mac_promisc_add(dsp->ds_mch, 276 MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp, 277 &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS); 278 return (err); 279 } 280 } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 && 281 dsp->ds_promisc != old_flags) { 282 /* 283 * If the old flag is PROMISC_SAP, but the current flag has 284 * changed to some new non-zero value, we need to turn the 285 * physical promiscuous mode. 286 */ 287 ASSERT(dsp->ds_mph != NULL); 288 mac_promisc_remove(dsp->ds_mph); 289 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL, 290 dls_rx_promisc, dsp, &dsp->ds_mph, 0); 291 } 292 293 return (err); 294 } 295 296 int 297 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr) 298 { 299 int err; 300 dls_multicst_addr_t **pp; 301 dls_multicst_addr_t *p; 302 uint_t addr_length; 303 304 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 305 306 /* 307 * Check whether the address is in the list of enabled addresses for 308 * this dld_str_t. 309 */ 310 addr_length = dsp->ds_mip->mi_addr_length; 311 312 /* 313 * Protect against concurrent access of ds_dmap by data threads using 314 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and 315 * remove operations. Dropping the ds_rw_lock across mac calls is thus 316 * ok and is also required by the locking protocol. 317 */ 318 rw_enter(&dsp->ds_rw_lock, RW_WRITER); 319 for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 320 if (bcmp(addr, p->dma_addr, addr_length) == 0) { 321 /* 322 * It is there so there's nothing to do. 323 */ 324 err = 0; 325 goto done; 326 } 327 } 328 329 /* 330 * Allocate a new list item and add it to the list. 331 */ 332 p = kmem_zalloc(sizeof (dls_multicst_addr_t), KM_SLEEP); 333 bcopy(addr, p->dma_addr, addr_length); 334 *pp = p; 335 rw_exit(&dsp->ds_rw_lock); 336 337 /* 338 * Enable the address at the MAC. 339 */ 340 err = mac_multicast_add(dsp->ds_mch, addr); 341 if (err == 0) 342 return (0); 343 344 /* Undo the operation as it has failed */ 345 rw_enter(&dsp->ds_rw_lock, RW_WRITER); 346 ASSERT(*pp == p && p->dma_nextp == NULL); 347 *pp = NULL; 348 kmem_free(p, sizeof (dls_multicst_addr_t)); 349 done: 350 rw_exit(&dsp->ds_rw_lock); 351 return (err); 352 } 353 354 int 355 dls_multicst_remove(dld_str_t *dsp, const uint8_t *addr) 356 { 357 dls_multicst_addr_t **pp; 358 dls_multicst_addr_t *p; 359 uint_t addr_length; 360 361 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 362 363 /* 364 * Find the address in the list of enabled addresses for this 365 * dld_str_t. 366 */ 367 addr_length = dsp->ds_mip->mi_addr_length; 368 369 /* 370 * Protect against concurrent access to ds_dmap by data threads using 371 * ds_rw_lock. The mac perimeter serializes the dls_multicst_add and 372 * remove operations. Dropping the ds_rw_lock across mac calls is thus 373 * ok and is also required by the locking protocol. 374 */ 375 rw_enter(&dsp->ds_rw_lock, RW_WRITER); 376 for (pp = &(dsp->ds_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 377 if (bcmp(addr, p->dma_addr, addr_length) == 0) 378 break; 379 } 380 381 /* 382 * If we walked to the end of the list then the given address is 383 * not currently enabled for this dld_str_t. 384 */ 385 if (p == NULL) { 386 rw_exit(&dsp->ds_rw_lock); 387 return (ENOENT); 388 } 389 390 /* 391 * Remove the address from the list. 392 */ 393 *pp = p->dma_nextp; 394 rw_exit(&dsp->ds_rw_lock); 395 396 /* 397 * Disable the address at the MAC. 398 */ 399 mac_multicast_remove(dsp->ds_mch, addr); 400 kmem_free(p, sizeof (dls_multicst_addr_t)); 401 return (0); 402 } 403 404 mblk_t * 405 dls_header(dld_str_t *dsp, const uint8_t *addr, uint16_t sap, uint_t pri, 406 mblk_t **payloadp) 407 { 408 uint16_t vid; 409 size_t extra_len; 410 uint16_t mac_sap; 411 mblk_t *mp, *payload; 412 boolean_t is_ethernet = (dsp->ds_mip->mi_media == DL_ETHER); 413 struct ether_vlan_header *evhp; 414 415 vid = mac_client_vid(dsp->ds_mch); 416 payload = (payloadp == NULL) ? NULL : (*payloadp); 417 418 /* 419 * In the case of Ethernet, we need to tell mac_header() if we need 420 * extra room beyond the Ethernet header for a VLAN header. We'll 421 * need to add a VLAN header if this isn't an ETHERTYPE_VLAN listener 422 * (because such streams will be handling VLAN headers on their own) 423 * and one of the following conditions is satisfied: 424 * 425 * - This is a VLAN stream 426 * - This is a physical stream, the priority is not 0, and user 427 * priority tagging is allowed. 428 */ 429 if (is_ethernet && sap != ETHERTYPE_VLAN && 430 (vid != VLAN_ID_NONE || 431 (pri != 0 && dsp->ds_dlp->dl_tagmode != LINK_TAGMODE_VLANONLY))) { 432 extra_len = sizeof (struct ether_vlan_header) - 433 sizeof (struct ether_header); 434 mac_sap = ETHERTYPE_VLAN; 435 } else { 436 extra_len = 0; 437 mac_sap = sap; 438 } 439 440 mp = mac_header(dsp->ds_mh, addr, mac_sap, payload, extra_len); 441 if (mp == NULL) 442 return (NULL); 443 444 if ((vid == VLAN_ID_NONE && (pri == 0 || 445 dsp->ds_dlp->dl_tagmode == LINK_TAGMODE_VLANONLY)) || !is_ethernet) 446 return (mp); 447 448 /* 449 * Fill in the tag information. 450 */ 451 ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 452 if (extra_len != 0) { 453 mp->b_wptr += extra_len; 454 evhp = (struct ether_vlan_header *)mp->b_rptr; 455 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 456 evhp->ether_type = htons(sap); 457 } else { 458 /* 459 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 460 * in the payload. Update the priority. 461 */ 462 struct ether_vlan_extinfo *extinfo; 463 size_t len = sizeof (struct ether_vlan_extinfo); 464 465 ASSERT(sap == ETHERTYPE_VLAN); 466 ASSERT(payload != NULL); 467 468 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 469 mblk_t *newmp; 470 471 /* 472 * Because some DLS consumers only check the db_ref 473 * count of the first mblk, we pullup 'payload' into 474 * a single mblk. 475 */ 476 newmp = msgpullup(payload, -1); 477 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 478 freemsg(newmp); 479 freemsg(mp); 480 return (NULL); 481 } else { 482 freemsg(payload); 483 *payloadp = payload = newmp; 484 } 485 } 486 487 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 488 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 489 VLAN_ID(ntohs(extinfo->ether_tci)))); 490 } 491 return (mp); 492 } 493 494 void 495 dls_rx_set(dld_str_t *dsp, dls_rx_t rx, void *arg) 496 { 497 mutex_enter(&dsp->ds_lock); 498 dsp->ds_rx = rx; 499 dsp->ds_rx_arg = arg; 500 mutex_exit(&dsp->ds_lock); 501 } 502 503 static boolean_t 504 dls_accept_common(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 505 void **ds_rx_arg, boolean_t promisc, boolean_t promisc_loopback) 506 { 507 dls_multicst_addr_t *dmap; 508 size_t addr_length = dsp->ds_mip->mi_addr_length; 509 510 /* 511 * We must not accept packets if the dld_str_t is not marked as bound 512 * or is being removed. 513 */ 514 if (dsp->ds_dlstate != DL_IDLE) 515 goto refuse; 516 517 if (dsp->ds_promisc != 0) { 518 /* 519 * Filter out packets that arrived from the data path 520 * (i_dls_link_rx) when promisc mode is on. 521 */ 522 if (!promisc) 523 goto refuse; 524 /* 525 * If the dls_impl_t is in 'all physical' mode then 526 * always accept. 527 */ 528 if (dsp->ds_promisc & DLS_PROMISC_PHYS) 529 goto accept; 530 531 /* 532 * Loopback packets i.e. packets sent out by DLS on a given 533 * mac end point, will be accepted back by DLS on loopback 534 * from the mac, only in the 'all physical' mode which has been 535 * covered by the previous check above 536 */ 537 if (promisc_loopback) 538 goto refuse; 539 } 540 541 switch (mhip->mhi_dsttype) { 542 case MAC_ADDRTYPE_UNICAST: 543 case MAC_ADDRTYPE_BROADCAST: 544 /* 545 * We can accept unicast and broadcast packets because 546 * filtering is already done by the mac layer. 547 */ 548 goto accept; 549 case MAC_ADDRTYPE_MULTICAST: 550 /* 551 * Additional filtering is needed for multicast addresses 552 * because different streams may be interested in different 553 * addresses. 554 */ 555 if (dsp->ds_promisc & DLS_PROMISC_MULTI) 556 goto accept; 557 558 rw_enter(&dsp->ds_rw_lock, RW_READER); 559 for (dmap = dsp->ds_dmap; dmap != NULL; 560 dmap = dmap->dma_nextp) { 561 if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 562 addr_length) == 0) { 563 rw_exit(&dsp->ds_rw_lock); 564 goto accept; 565 } 566 } 567 rw_exit(&dsp->ds_rw_lock); 568 break; 569 } 570 571 refuse: 572 return (B_FALSE); 573 574 accept: 575 /* 576 * the returned ds_rx and ds_rx_arg will always be in sync. 577 */ 578 mutex_enter(&dsp->ds_lock); 579 *ds_rx = dsp->ds_rx; 580 *ds_rx_arg = dsp->ds_rx_arg; 581 mutex_exit(&dsp->ds_lock); 582 583 return (B_TRUE); 584 } 585 586 /* ARGSUSED */ 587 boolean_t 588 dls_accept(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 589 void **ds_rx_arg) 590 { 591 return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_FALSE, 592 B_FALSE)); 593 } 594 595 boolean_t 596 dls_accept_promisc(dld_str_t *dsp, mac_header_info_t *mhip, dls_rx_t *ds_rx, 597 void **ds_rx_arg, boolean_t loopback) 598 { 599 return (dls_accept_common(dsp, mhip, ds_rx, ds_rx_arg, B_TRUE, 600 loopback)); 601 } 602 603 int 604 dls_mac_active_set(dls_link_t *dlp) 605 { 606 int err = 0; 607 608 /* 609 * First client; add the primary unicast address. 610 */ 611 if (dlp->dl_nactive == 0) { 612 /* 613 * First client; add the primary unicast address. 614 */ 615 mac_diag_t diag; 616 617 /* request the primary MAC address */ 618 if ((err = mac_unicast_add(dlp->dl_mch, NULL, 619 MAC_UNICAST_PRIMARY | MAC_UNICAST_TAG_DISABLE | 620 MAC_UNICAST_DISABLE_TX_VID_CHECK, &dlp->dl_mah, 0, 621 &diag)) != 0) { 622 return (err); 623 } 624 625 /* 626 * Set the function to start receiving packets. 627 */ 628 mac_rx_set(dlp->dl_mch, i_dls_link_rx, dlp); 629 } 630 dlp->dl_nactive++; 631 return (0); 632 } 633 634 void 635 dls_mac_active_clear(dls_link_t *dlp) 636 { 637 if (--dlp->dl_nactive == 0) { 638 ASSERT(dlp->dl_mah != NULL); 639 (void) mac_unicast_remove(dlp->dl_mch, dlp->dl_mah); 640 dlp->dl_mah = NULL; 641 mac_rx_clear(dlp->dl_mch); 642 } 643 } 644 645 int 646 dls_active_set(dld_str_t *dsp) 647 { 648 int err = 0; 649 650 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 651 652 if (dsp->ds_passivestate == DLD_PASSIVE) 653 return (0); 654 655 /* If we're already active, then there's nothing more to do. */ 656 if ((dsp->ds_nactive == 0) && 657 ((err = dls_mac_active_set(dsp->ds_dlp)) != 0)) { 658 /* except for ENXIO all other errors are mapped to EBUSY */ 659 if (err != ENXIO) 660 return (EBUSY); 661 return (err); 662 } 663 664 dsp->ds_passivestate = DLD_ACTIVE; 665 dsp->ds_nactive++; 666 return (0); 667 } 668 669 /* 670 * Note that dls_active_set() is called whenever an active operation 671 * (DL_BIND_REQ, DL_ENABMULTI_REQ ...) is processed and 672 * dls_active_clear(dsp, B_FALSE) is called whenever the active operation 673 * is being undone (DL_UNBIND_REQ, DL_DISABMULTI_REQ ...). In some cases, 674 * a stream is closed without every active operation being undone and we 675 * need to clear all the "active" states by calling 676 * dls_active_clear(dsp, B_TRUE). 677 */ 678 void 679 dls_active_clear(dld_str_t *dsp, boolean_t all) 680 { 681 ASSERT(MAC_PERIM_HELD(dsp->ds_mh)); 682 683 if (dsp->ds_passivestate == DLD_PASSIVE) 684 return; 685 686 if (all && dsp->ds_nactive == 0) 687 return; 688 689 ASSERT(dsp->ds_nactive > 0); 690 691 dsp->ds_nactive -= (all ? dsp->ds_nactive : 1); 692 if (dsp->ds_nactive != 0) 693 return; 694 695 ASSERT(dsp->ds_passivestate == DLD_ACTIVE); 696 dls_mac_active_clear(dsp->ds_dlp); 697 dsp->ds_passivestate = DLD_UNINITIALIZED; 698 } 699