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