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 2006 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 * Data-Link Services Module 30 */ 31 32 #include <sys/types.h> 33 #include <sys/stream.h> 34 #include <sys/strsun.h> 35 #include <sys/sysmacros.h> 36 #include <sys/atomic.h> 37 #include <sys/dlpi.h> 38 #include <sys/vlan.h> 39 #include <sys/ethernet.h> 40 #include <sys/byteorder.h> 41 #include <sys/mac.h> 42 43 #include <sys/dls.h> 44 #include <sys/dls_impl.h> 45 #include <sys/dls_soft_ring.h> 46 47 static kmem_cache_t *i_dls_impl_cachep; 48 static uint32_t i_dls_impl_count; 49 50 static kstat_t *dls_ksp = (kstat_t *)NULL; 51 struct dls_kstats dls_kstat = 52 { 53 { "soft_ring_pkt_drop", KSTAT_DATA_UINT32 }, 54 }; 55 56 57 /* 58 * Private functions. 59 */ 60 61 /*ARGSUSED*/ 62 static int 63 i_dls_constructor(void *buf, void *arg, int kmflag) 64 { 65 dls_impl_t *dip = buf; 66 67 bzero(buf, sizeof (dls_impl_t)); 68 69 rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL); 70 return (0); 71 } 72 73 /*ARGSUSED*/ 74 static void 75 i_dls_destructor(void *buf, void *arg) 76 { 77 dls_impl_t *dip = buf; 78 79 ASSERT(dip->di_dvp == NULL); 80 ASSERT(dip->di_mnh == NULL); 81 ASSERT(dip->di_dmap == NULL); 82 ASSERT(!dip->di_bound); 83 ASSERT(dip->di_rx == NULL); 84 ASSERT(dip->di_txinfo == NULL); 85 86 rw_destroy(&(dip->di_lock)); 87 } 88 89 static void 90 i_dls_notify(void *arg, mac_notify_type_t type) 91 { 92 dls_impl_t *dip = arg; 93 94 switch (type) { 95 case MAC_NOTE_UNICST: 96 mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 97 break; 98 99 case MAC_NOTE_PROMISC: 100 /* 101 * Every time the MAC interface changes promiscuity we 102 * need to reset our transmit information. 103 */ 104 dip->di_txinfo = mac_tx_get(dip->di_mh); 105 break; 106 } 107 } 108 109 static void 110 dls_stat_init() 111 { 112 if ((dls_ksp = kstat_create("dls", 0, "dls_stat", 113 "net", KSTAT_TYPE_NAMED, 114 sizeof (dls_kstat) / sizeof (kstat_named_t), 115 KSTAT_FLAG_VIRTUAL)) == NULL) { 116 cmn_err(CE_WARN, 117 "DLS: failed to create kstat structure for dls stats"); 118 return; 119 } 120 dls_ksp->ks_data = (void *)&dls_kstat; 121 kstat_install(dls_ksp); 122 } 123 124 static void 125 dls_stat_destroy() 126 { 127 kstat_delete(dls_ksp); 128 } 129 130 /* 131 * Module initialization functions. 132 */ 133 134 void 135 dls_init(void) 136 { 137 /* 138 * Create a kmem_cache of dls_impl_t. 139 */ 140 i_dls_impl_cachep = kmem_cache_create("dls_cache", 141 sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL, 142 NULL, NULL, 0); 143 ASSERT(i_dls_impl_cachep != NULL); 144 soft_ring_init(); 145 dls_stat_init(); 146 } 147 148 int 149 dls_fini(void) 150 { 151 /* 152 * If there are any dls_impl_t in use then return EBUSY. 153 */ 154 if (i_dls_impl_count != 0) 155 return (EBUSY); 156 157 /* 158 * Destroy the kmem_cache. 159 */ 160 kmem_cache_destroy(i_dls_impl_cachep); 161 dls_stat_destroy(); 162 return (0); 163 } 164 165 /* 166 * Client function. 167 */ 168 169 int 170 dls_create(const char *linkname, const char *macname, uint_t ddi_instance) 171 { 172 return (dls_vlan_create(linkname, macname, ddi_instance, 0)); 173 } 174 175 int 176 dls_destroy(const char *name) 177 { 178 return (dls_vlan_destroy(name)); 179 } 180 181 int 182 dls_open(const char *name, dls_channel_t *dcp) 183 { 184 dls_impl_t *dip; 185 dls_vlan_t *dvp; 186 dls_link_t *dlp; 187 int err; 188 189 /* 190 * Get a reference to the named dls_vlan_t. 191 * Tagged vlans get created automatically. 192 */ 193 if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) 194 return (err); 195 196 /* 197 * Allocate a new dls_impl_t. 198 */ 199 dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP); 200 dip->di_dvp = dvp; 201 202 /* 203 * Cache a copy of the MAC interface handle, a pointer to the 204 * immutable MAC info and a copy of the current MAC address. 205 */ 206 dlp = dvp->dv_dlp; 207 dip->di_mh = dlp->dl_mh; 208 dip->di_mip = dlp->dl_mip; 209 210 mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 211 212 /* 213 * Set the MAC transmit information. 214 */ 215 dip->di_txinfo = mac_tx_get(dip->di_mh); 216 217 /* 218 * Add a notification function so that we get updates from the MAC. 219 */ 220 dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip); 221 222 /* 223 * Bump the kmem_cache count to make sure it is not prematurely 224 * destroyed. 225 */ 226 atomic_add_32(&i_dls_impl_count, 1); 227 228 /* 229 * Hand back a reference to the dls_impl_t. 230 */ 231 *dcp = (dls_channel_t)dip; 232 return (0); 233 } 234 235 void 236 dls_close(dls_channel_t dc) 237 { 238 dls_impl_t *dip = (dls_impl_t *)dc; 239 dls_vlan_t *dvp; 240 dls_link_t *dlp; 241 dls_multicst_addr_t *p; 242 dls_multicst_addr_t *nextp; 243 244 dls_active_clear(dc); 245 246 rw_enter(&(dip->di_lock), RW_WRITER); 247 248 /* 249 * Remove the notify function. 250 */ 251 mac_notify_remove(dip->di_mh, dip->di_mnh); 252 dip->di_mnh = NULL; 253 254 /* 255 * If the dls_impl_t is bound then unbind it. 256 */ 257 dvp = dip->di_dvp; 258 dlp = dvp->dv_dlp; 259 260 if (dip->di_bound) { 261 rw_exit(&(dip->di_lock)); 262 dls_link_remove(dlp, dip); 263 rw_enter(&(dip->di_lock), RW_WRITER); 264 dip->di_bound = B_FALSE; 265 } 266 267 dip->di_rx = NULL; 268 dip->di_rx_arg = NULL; 269 270 /* 271 * Walk the list of multicast addresses, disabling each at the MAC. 272 */ 273 for (p = dip->di_dmap; p != NULL; p = nextp) { 274 (void) mac_multicst_remove(dip->di_mh, p->dma_addr); 275 nextp = p->dma_nextp; 276 kmem_free(p, sizeof (dls_multicst_addr_t)); 277 } 278 dip->di_dmap = NULL; 279 280 rw_exit(&(dip->di_lock)); 281 282 /* 283 * If the MAC has been set in promiscuous mode then disable it. 284 */ 285 (void) dls_promisc(dc, 0); 286 287 /* 288 * Free the dls_impl_t back to the cache. 289 */ 290 dip->di_dvp = NULL; 291 dip->di_txinfo = NULL; 292 293 if (dip->di_soft_ring_list != NULL) { 294 soft_ring_set_destroy(dip->di_soft_ring_list, 295 dip->di_soft_ring_size); 296 dip->di_soft_ring_list = NULL; 297 } 298 dip->di_soft_ring_size = 0; 299 300 kmem_cache_free(i_dls_impl_cachep, dip); 301 302 /* 303 * Decrement the reference count to allow the cache to be destroyed 304 * if there are no more dls_impl_t. 305 */ 306 atomic_add_32(&i_dls_impl_count, -1); 307 308 /* 309 * Release our reference to the dls_vlan_t allowing that to be 310 * destroyed if there are no more dls_impl_t. An unreferenced tagged 311 * vlan gets destroyed automatically. 312 */ 313 dls_vlan_rele(dvp); 314 } 315 316 mac_handle_t 317 dls_mac(dls_channel_t dc) 318 { 319 return (((dls_impl_t *)dc)->di_mh); 320 } 321 322 uint16_t 323 dls_vid(dls_channel_t dc) 324 { 325 return (((dls_impl_t *)dc)->di_dvp->dv_id); 326 } 327 328 int 329 dls_bind(dls_channel_t dc, uint32_t sap) 330 { 331 dls_impl_t *dip = (dls_impl_t *)dc; 332 dls_link_t *dlp; 333 uint32_t dls_sap; 334 335 /* 336 * Check to see the value is legal for the media type. 337 */ 338 if (!mac_sap_verify(dip->di_mh, sap, &dls_sap)) 339 return (EINVAL); 340 if (dip->di_promisc & DLS_PROMISC_SAP) 341 dls_sap = DLS_SAP_PROMISC; 342 343 /* 344 * Set up the dls_impl_t to mark it as able to receive packets. 345 */ 346 rw_enter(&(dip->di_lock), RW_WRITER); 347 ASSERT(!dip->di_bound); 348 dip->di_sap = sap; 349 dip->di_bound = B_TRUE; 350 rw_exit(&(dip->di_lock)); 351 352 /* 353 * Now bind the dls_impl_t by adding it into the hash table in the 354 * dls_link_t. 355 * 356 * NOTE: This must be done without the dls_impl_t lock being held 357 * otherwise deadlock may ensue. 358 */ 359 dlp = dip->di_dvp->dv_dlp; 360 dls_link_add(dlp, dls_sap, dip); 361 362 return (0); 363 } 364 365 void 366 dls_unbind(dls_channel_t dc) 367 { 368 dls_impl_t *dip = (dls_impl_t *)dc; 369 dls_link_t *dlp; 370 371 /* 372 * Unbind the dls_impl_t by removing it from the hash table in the 373 * dls_link_t. 374 * 375 * NOTE: This must be done without the dls_impl_t lock being held 376 * otherise deadlock may enuse. 377 */ 378 dlp = dip->di_dvp->dv_dlp; 379 dls_link_remove(dlp, dip); 380 381 /* 382 * Mark the dls_impl_t as unable to receive packets This will make 383 * sure that 'receives in flight' will not come our way. 384 */ 385 dip->di_bound = B_FALSE; 386 } 387 388 int 389 dls_promisc(dls_channel_t dc, uint32_t flags) 390 { 391 dls_impl_t *dip = (dls_impl_t *)dc; 392 dls_link_t *dlp; 393 int err = 0; 394 395 ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 396 DLS_PROMISC_PHYS))); 397 398 /* 399 * Check if we need to turn on 'all sap' mode. 400 */ 401 rw_enter(&(dip->di_lock), RW_WRITER); 402 dlp = dip->di_dvp->dv_dlp; 403 if ((flags & DLS_PROMISC_SAP) && 404 !(dip->di_promisc & DLS_PROMISC_SAP)) { 405 dip->di_promisc |= DLS_PROMISC_SAP; 406 if (!dip->di_bound) 407 goto multi; 408 409 rw_exit(&(dip->di_lock)); 410 dls_link_remove(dlp, dip); 411 dls_link_add(dlp, DLS_SAP_PROMISC, dip); 412 rw_enter(&(dip->di_lock), RW_WRITER); 413 goto multi; 414 } 415 416 /* 417 * Check if we need to turn off 'all sap' mode. 418 */ 419 if (!(flags & DLS_PROMISC_SAP) && 420 (dip->di_promisc & DLS_PROMISC_SAP)) { 421 uint32_t dls_sap; 422 423 dip->di_promisc &= ~DLS_PROMISC_SAP; 424 if (!dip->di_bound) 425 goto multi; 426 427 rw_exit(&(dip->di_lock)); 428 dls_link_remove(dlp, dip); 429 (void) mac_sap_verify(dip->di_mh, dip->di_sap, &dls_sap); 430 dls_link_add(dlp, dls_sap, dip); 431 rw_enter(&(dip->di_lock), RW_WRITER); 432 } 433 434 multi: 435 /* 436 * It's easiest to add the txloop handler up-front; if promiscuous 437 * mode cannot be enabled, then we'll remove it before returning. 438 * Use dl_promisc_lock to prevent racing with another thread also 439 * manipulating the promiscuous state on another dls_impl_t associated 440 * with the same dls_link_t. 441 */ 442 mutex_enter(&dlp->dl_promisc_lock); 443 if (dlp->dl_npromisc == 0 && 444 (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) { 445 ASSERT(dlp->dl_mth == NULL); 446 dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_txloop, dlp); 447 } 448 449 /* 450 * Turn on or off 'all multicast' mode, if necessary. 451 */ 452 if (flags & DLS_PROMISC_MULTI) { 453 if (!(dip->di_promisc & DLS_PROMISC_MULTI)) { 454 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 455 if (err != 0) 456 goto done; 457 dip->di_promisc |= DLS_PROMISC_MULTI; 458 dlp->dl_npromisc++; 459 } 460 } else { 461 if (dip->di_promisc & DLS_PROMISC_MULTI) { 462 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 463 if (err != 0) 464 goto done; 465 dip->di_promisc &= ~DLS_PROMISC_MULTI; 466 dlp->dl_npromisc--; 467 } 468 } 469 470 /* 471 * Turn on or off 'all physical' mode, if necessary. 472 */ 473 if (flags & DLS_PROMISC_PHYS) { 474 if (!(dip->di_promisc & DLS_PROMISC_PHYS)) { 475 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 476 if (err != 0) 477 goto done; 478 dip->di_promisc |= DLS_PROMISC_PHYS; 479 dlp->dl_npromisc++; 480 } 481 } else { 482 if (dip->di_promisc & DLS_PROMISC_PHYS) { 483 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 484 if (err != 0) 485 goto done; 486 dip->di_promisc &= ~DLS_PROMISC_PHYS; 487 dlp->dl_npromisc--; 488 } 489 } 490 491 done: 492 if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 493 mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 494 dlp->dl_mth = NULL; 495 } 496 497 ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 498 mutex_exit(&dlp->dl_promisc_lock); 499 500 rw_exit(&(dip->di_lock)); 501 return (err); 502 } 503 504 int 505 dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 506 { 507 dls_impl_t *dip = (dls_impl_t *)dc; 508 int err; 509 dls_multicst_addr_t **pp; 510 dls_multicst_addr_t *p; 511 uint_t addr_length; 512 513 /* 514 * Check whether the address is in the list of enabled addresses for 515 * this dls_impl_t. 516 */ 517 rw_enter(&(dip->di_lock), RW_WRITER); 518 addr_length = dip->di_mip->mi_addr_length; 519 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 520 if (bcmp(addr, p->dma_addr, addr_length) == 0) { 521 /* 522 * It is there so there's nothing to do. 523 */ 524 err = 0; 525 goto done; 526 } 527 } 528 529 /* 530 * Allocate a new list item. 531 */ 532 if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 533 KM_NOSLEEP)) == NULL) { 534 err = ENOMEM; 535 goto done; 536 } 537 538 /* 539 * Enable the address at the MAC. 540 */ 541 if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 542 kmem_free(p, sizeof (dls_multicst_addr_t)); 543 goto done; 544 } 545 546 /* 547 * The address is now enabled at the MAC so add it to the list. 548 */ 549 bcopy(addr, p->dma_addr, addr_length); 550 *pp = p; 551 552 done: 553 rw_exit(&(dip->di_lock)); 554 return (err); 555 } 556 557 int 558 dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 559 { 560 dls_impl_t *dip = (dls_impl_t *)dc; 561 int err; 562 dls_multicst_addr_t **pp; 563 dls_multicst_addr_t *p; 564 uint_t addr_length; 565 566 /* 567 * Find the address in the list of enabled addresses for this 568 * dls_impl_t. 569 */ 570 rw_enter(&(dip->di_lock), RW_WRITER); 571 addr_length = dip->di_mip->mi_addr_length; 572 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 573 if (bcmp(addr, p->dma_addr, addr_length) == 0) 574 break; 575 } 576 577 /* 578 * If we walked to the end of the list then the given address is 579 * not currently enabled for this dls_impl_t. 580 */ 581 if (p == NULL) { 582 err = ENOENT; 583 goto done; 584 } 585 586 /* 587 * Disable the address at the MAC. 588 */ 589 if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 590 goto done; 591 592 /* 593 * Remove the address from the list. 594 */ 595 *pp = p->dma_nextp; 596 kmem_free(p, sizeof (dls_multicst_addr_t)); 597 598 done: 599 rw_exit(&(dip->di_lock)); 600 return (err); 601 } 602 603 mblk_t * 604 dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri, 605 mblk_t **payloadp) 606 { 607 dls_impl_t *dip = (dls_impl_t *)dc; 608 uint16_t vid; 609 size_t extra_len; 610 uint16_t mac_sap; 611 mblk_t *mp, *payload; 612 boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER); 613 struct ether_vlan_header *evhp; 614 615 vid = dip->di_dvp->dv_id; 616 payload = (payloadp == NULL) ? NULL : (*payloadp); 617 618 /* 619 * If the following conditions are satisfied: 620 * - This is not a ETHERTYPE_VLAN listener; and 621 * - This is either a VLAN stream or this is a physical stream 622 * but the priority is not 0. 623 * 624 * then we know ahead of time that we'll need to fill in additional 625 * VLAN information in the link-layer header. We will tell the MAC 626 * layer to pre-allocate some space at the end of the Ethernet 627 * header for us. 628 */ 629 if (is_ethernet && sap != ETHERTYPE_VLAN && 630 (vid != VLAN_ID_NONE || pri != 0)) { 631 extra_len = sizeof (struct ether_vlan_header) - 632 sizeof (struct ether_header); 633 mac_sap = ETHERTYPE_VLAN; 634 } else { 635 extra_len = 0; 636 mac_sap = sap; 637 } 638 639 mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len); 640 if (mp == NULL) 641 return (NULL); 642 643 if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet) 644 return (mp); 645 646 /* 647 * Fill in the tag information. 648 */ 649 ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 650 if (extra_len != 0) { 651 mp->b_wptr += extra_len; 652 evhp = (struct ether_vlan_header *)mp->b_rptr; 653 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 654 evhp->ether_type = htons(sap); 655 } else { 656 /* 657 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 658 * in the payload. Update the priority. 659 */ 660 struct ether_vlan_extinfo *extinfo; 661 size_t len = sizeof (struct ether_vlan_extinfo); 662 663 ASSERT(sap == ETHERTYPE_VLAN); 664 ASSERT(payload != NULL); 665 666 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 667 mblk_t *newmp; 668 669 /* 670 * Because some DLS consumers only check the db_ref 671 * count of the first mblk, we pullup 'payload' into 672 * a single mblk. 673 */ 674 newmp = msgpullup(payload, -1); 675 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 676 freemsg(newmp); 677 freemsg(mp); 678 return (NULL); 679 } else { 680 freemsg(payload); 681 *payloadp = payload = newmp; 682 } 683 } 684 685 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 686 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 687 VLAN_ID(ntohs(extinfo->ether_tci)))); 688 } 689 return (mp); 690 } 691 692 int 693 dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip) 694 { 695 return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp, 696 mp, mhip)); 697 } 698 699 void 700 dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 701 { 702 dls_impl_t *dip = (dls_impl_t *)dc; 703 704 rw_enter(&(dip->di_lock), RW_WRITER); 705 dip->di_rx = rx; 706 dip->di_rx_arg = arg; 707 rw_exit(&(dip->di_lock)); 708 } 709 710 mblk_t * 711 dls_tx(dls_channel_t dc, mblk_t *mp) 712 { 713 const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo; 714 715 return (mtp->mt_fn(mtp->mt_arg, mp)); 716 } 717 718 boolean_t 719 dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 720 void **di_rx_arg) 721 { 722 dls_multicst_addr_t *dmap; 723 size_t addr_length = dip->di_mip->mi_addr_length; 724 725 /* 726 * We must not accept packets if the dls_impl_t is not marked as bound 727 * or is being removed. 728 */ 729 rw_enter(&(dip->di_lock), RW_READER); 730 if (!dip->di_bound || dip->di_removing) 731 goto refuse; 732 733 /* 734 * If the dls_impl_t is in 'all physical' mode then always accept. 735 */ 736 if (dip->di_promisc & DLS_PROMISC_PHYS) 737 goto accept; 738 739 switch (mhip->mhi_dsttype) { 740 case MAC_ADDRTYPE_UNICAST: 741 /* 742 * Check to see if the destination address matches the 743 * dls_impl_t unicast address. 744 */ 745 if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) == 746 0) { 747 goto accept; 748 } 749 break; 750 case MAC_ADDRTYPE_MULTICAST: 751 /* 752 * Check the address against the list of addresses enabled 753 * for this dls_impl_t or accept it unconditionally if the 754 * dls_impl_t is in 'all multicast' mode. 755 */ 756 if (dip->di_promisc & DLS_PROMISC_MULTI) 757 goto accept; 758 for (dmap = dip->di_dmap; dmap != NULL; 759 dmap = dmap->dma_nextp) { 760 if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 761 addr_length) == 0) { 762 goto accept; 763 } 764 } 765 break; 766 case MAC_ADDRTYPE_BROADCAST: 767 /* 768 * If the address is broadcast then the dls_impl_t will 769 * always accept it. 770 */ 771 goto accept; 772 } 773 774 refuse: 775 rw_exit(&(dip->di_lock)); 776 return (B_FALSE); 777 778 accept: 779 /* 780 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 781 * always be in sync. 782 */ 783 *di_rx = dip->di_rx; 784 *di_rx_arg = dip->di_rx_arg; 785 rw_exit(&(dip->di_lock)); 786 return (B_TRUE); 787 } 788 789 /* ARGSUSED */ 790 boolean_t 791 dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 792 void **di_rx_arg) 793 { 794 /* 795 * We must not accept packets if the dls_impl_t is not marked as bound 796 * or is being removed. 797 */ 798 rw_enter(&(dip->di_lock), RW_READER); 799 if (!dip->di_bound || dip->di_removing) 800 goto refuse; 801 802 /* 803 * A dls_impl_t should only accept loopback packets if it is in 804 * 'all physical' mode. 805 */ 806 if (dip->di_promisc & DLS_PROMISC_PHYS) 807 goto accept; 808 809 refuse: 810 rw_exit(&(dip->di_lock)); 811 return (B_FALSE); 812 813 accept: 814 /* 815 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 816 * always be in sync. 817 */ 818 *di_rx = dip->di_rx; 819 *di_rx_arg = dip->di_rx_arg; 820 rw_exit(&(dip->di_lock)); 821 return (B_TRUE); 822 } 823 824 boolean_t 825 dls_active_set(dls_channel_t dc) 826 { 827 dls_impl_t *dip = (dls_impl_t *)dc; 828 dls_link_t *dlp = dip->di_dvp->dv_dlp; 829 830 rw_enter(&dip->di_lock, RW_WRITER); 831 832 /* If we're already active, then there's nothing more to do. */ 833 if (dip->di_active) { 834 rw_exit(&dip->di_lock); 835 return (B_TRUE); 836 } 837 838 /* 839 * If this is the first active client on this link, notify 840 * the mac that we're becoming an active client. 841 */ 842 if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) { 843 rw_exit(&dip->di_lock); 844 return (B_FALSE); 845 } 846 dip->di_active = B_TRUE; 847 mutex_enter(&dlp->dl_lock); 848 dlp->dl_nactive++; 849 mutex_exit(&dlp->dl_lock); 850 rw_exit(&dip->di_lock); 851 return (B_TRUE); 852 } 853 854 void 855 dls_active_clear(dls_channel_t dc) 856 { 857 dls_impl_t *dip = (dls_impl_t *)dc; 858 dls_link_t *dlp = dip->di_dvp->dv_dlp; 859 860 rw_enter(&dip->di_lock, RW_WRITER); 861 862 if (!dip->di_active) 863 goto out; 864 dip->di_active = B_FALSE; 865 866 mutex_enter(&dlp->dl_lock); 867 if (--dlp->dl_nactive == 0) 868 mac_active_clear(dip->di_mh); 869 mutex_exit(&dlp->dl_lock); 870 out: 871 rw_exit(&dip->di_lock); 872 } 873