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