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