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