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) 172 { 173 return (dls_vlan_create(linkname, macname, 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 if (dip->di_soft_ring_list != NULL) { 312 soft_ring_set_destroy(dip->di_soft_ring_list, 313 dip->di_soft_ring_size); 314 dip->di_soft_ring_list = NULL; 315 } 316 dip->di_soft_ring_size = 0; 317 318 kmem_cache_free(i_dls_impl_cachep, dip); 319 320 /* 321 * Decrement the reference count to allow the cache to be destroyed 322 * if there are no more dls_impl_t. 323 */ 324 atomic_add_32(&i_dls_impl_count, -1); 325 326 /* 327 * Release our reference to the dls_vlan_t allowing that to be 328 * destroyed if there are no more dls_impl_t. An unreferenced tagged 329 * vlan gets destroyed automatically. 330 */ 331 dls_vlan_rele(dvp); 332 } 333 334 mac_handle_t 335 dls_mac(dls_channel_t dc) 336 { 337 return (((dls_impl_t *)dc)->di_mh); 338 } 339 340 uint16_t 341 dls_vid(dls_channel_t dc) 342 { 343 return (((dls_impl_t *)dc)->di_dvp->dv_id); 344 } 345 346 int 347 dls_bind(dls_channel_t dc, uint32_t sap) 348 { 349 dls_impl_t *dip = (dls_impl_t *)dc; 350 dls_link_t *dlp; 351 uint32_t dls_sap; 352 353 /* 354 * Check to see the value is legal for the media type. 355 */ 356 if (!mac_sap_verify(dip->di_mh, sap, &dls_sap)) 357 return (EINVAL); 358 if (dip->di_promisc & DLS_PROMISC_SAP) 359 dls_sap = DLS_SAP_PROMISC; 360 361 /* 362 * Set up the dls_impl_t to mark it as able to receive packets. 363 */ 364 rw_enter(&(dip->di_lock), RW_WRITER); 365 ASSERT(!dip->di_bound); 366 dip->di_sap = sap; 367 dip->di_bound = B_TRUE; 368 rw_exit(&(dip->di_lock)); 369 370 /* 371 * Now bind the dls_impl_t by adding it into the hash table in the 372 * dls_link_t. 373 * 374 * NOTE: This must be done without the dls_impl_t lock being held 375 * otherwise deadlock may ensue. 376 */ 377 dlp = dip->di_dvp->dv_dlp; 378 dls_link_add(dlp, dls_sap, dip); 379 380 return (0); 381 } 382 383 void 384 dls_unbind(dls_channel_t dc) 385 { 386 dls_impl_t *dip = (dls_impl_t *)dc; 387 dls_link_t *dlp; 388 389 /* 390 * Unbind the dls_impl_t by removing it from the hash table in the 391 * dls_link_t. 392 * 393 * NOTE: This must be done without the dls_impl_t lock being held 394 * otherise deadlock may enuse. 395 */ 396 dlp = dip->di_dvp->dv_dlp; 397 dls_link_remove(dlp, dip); 398 399 /* 400 * Mark the dls_impl_t as unable to receive packets This will make 401 * sure that 'receives in flight' will not come our way. 402 */ 403 dip->di_bound = B_FALSE; 404 } 405 406 int 407 dls_promisc(dls_channel_t dc, uint32_t flags) 408 { 409 dls_impl_t *dip = (dls_impl_t *)dc; 410 dls_link_t *dlp; 411 int err = 0; 412 413 ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 414 DLS_PROMISC_PHYS))); 415 416 /* 417 * Check if we need to turn on 'all sap' mode. 418 */ 419 rw_enter(&(dip->di_lock), RW_WRITER); 420 dlp = dip->di_dvp->dv_dlp; 421 if ((flags & DLS_PROMISC_SAP) && 422 !(dip->di_promisc & DLS_PROMISC_SAP)) { 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 dls_link_add(dlp, DLS_SAP_PROMISC, dip); 430 rw_enter(&(dip->di_lock), RW_WRITER); 431 goto multi; 432 } 433 434 /* 435 * Check if we need to turn off 'all sap' mode. 436 */ 437 if (!(flags & DLS_PROMISC_SAP) && 438 (dip->di_promisc & DLS_PROMISC_SAP)) { 439 uint32_t dls_sap; 440 441 dip->di_promisc &= ~DLS_PROMISC_SAP; 442 if (!dip->di_bound) 443 goto multi; 444 445 rw_exit(&(dip->di_lock)); 446 dls_link_remove(dlp, dip); 447 (void) mac_sap_verify(dip->di_mh, dip->di_sap, &dls_sap); 448 dls_link_add(dlp, dls_sap, dip); 449 rw_enter(&(dip->di_lock), RW_WRITER); 450 } 451 452 multi: 453 /* 454 * It's easiest to add the txloop callback up-front; if promiscuous 455 * mode cannot be enabled, then we'll remove it before returning. 456 * Use dl_promisc_lock to prevent racing with another thread also 457 * manipulating the promiscuous state on another dls_impl_t associated 458 * with the same dls_link_t. 459 */ 460 mutex_enter(&dlp->dl_promisc_lock); 461 if ((dlp->dl_npromisc == 0) && (flags & DLS_PROMISC_PHYS)) { 462 ASSERT(dlp->dl_mth == NULL); 463 dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dls_link_txloop, dlp); 464 } 465 466 /* 467 * Turn on or off 'all multicast' mode, if necessary. 468 */ 469 if (flags & DLS_PROMISC_MULTI) { 470 if (!(dip->di_promisc & DLS_PROMISC_MULTI)) { 471 if ((err = mac_promisc_set(dip->di_mh, B_TRUE, 472 MAC_DEVPROMISC)) != 0) { 473 goto done; 474 } 475 dip->di_promisc |= DLS_PROMISC_MULTI; 476 } 477 } else { 478 if (dip->di_promisc & DLS_PROMISC_MULTI) { 479 if ((err = mac_promisc_set(dip->di_mh, B_FALSE, 480 MAC_DEVPROMISC)) != 0) { 481 goto done; 482 } 483 dip->di_promisc &= ~DLS_PROMISC_MULTI; 484 } 485 } 486 487 /* 488 * Turn on or off 'all physical' mode, if necessary. 489 */ 490 if (flags & DLS_PROMISC_PHYS) { 491 if (!(dip->di_promisc & DLS_PROMISC_PHYS)) { 492 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 493 if (err != 0) 494 goto done; 495 dip->di_promisc |= DLS_PROMISC_PHYS; 496 dlp->dl_npromisc++; 497 } 498 } else { 499 if (dip->di_promisc & DLS_PROMISC_PHYS) { 500 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 501 if (err != 0) 502 goto done; 503 dip->di_promisc &= ~DLS_PROMISC_PHYS; 504 dlp->dl_npromisc--; 505 } 506 } 507 508 done: 509 if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 510 mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 511 dlp->dl_mth = NULL; 512 } 513 514 ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 515 mutex_exit(&dlp->dl_promisc_lock); 516 517 rw_exit(&(dip->di_lock)); 518 return (err); 519 } 520 521 int 522 dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 523 { 524 dls_impl_t *dip = (dls_impl_t *)dc; 525 int err; 526 dls_multicst_addr_t **pp; 527 dls_multicst_addr_t *p; 528 uint_t addr_length; 529 530 /* 531 * Check whether the address is in the list of enabled addresses for 532 * this dls_impl_t. 533 */ 534 rw_enter(&(dip->di_lock), RW_WRITER); 535 addr_length = dip->di_mip->mi_addr_length; 536 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 537 if (bcmp(addr, p->dma_addr, addr_length) == 0) { 538 /* 539 * It is there so there's nothing to do. 540 */ 541 err = 0; 542 goto done; 543 } 544 } 545 546 /* 547 * Allocate a new list item. 548 */ 549 if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 550 KM_NOSLEEP)) == NULL) { 551 err = ENOMEM; 552 goto done; 553 } 554 555 /* 556 * Enable the address at the MAC. 557 */ 558 if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 559 kmem_free(p, sizeof (dls_multicst_addr_t)); 560 goto done; 561 } 562 563 /* 564 * The address is now enabled at the MAC so add it to the list. 565 */ 566 bcopy(addr, p->dma_addr, addr_length); 567 *pp = p; 568 569 done: 570 rw_exit(&(dip->di_lock)); 571 return (err); 572 } 573 574 int 575 dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 576 { 577 dls_impl_t *dip = (dls_impl_t *)dc; 578 int err; 579 dls_multicst_addr_t **pp; 580 dls_multicst_addr_t *p; 581 uint_t addr_length; 582 583 /* 584 * Find the address in the list of enabled addresses for this 585 * dls_impl_t. 586 */ 587 rw_enter(&(dip->di_lock), RW_WRITER); 588 addr_length = dip->di_mip->mi_addr_length; 589 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 590 if (bcmp(addr, p->dma_addr, addr_length) == 0) 591 break; 592 } 593 594 /* 595 * If we walked to the end of the list then the given address is 596 * not currently enabled for this dls_impl_t. 597 */ 598 if (p == NULL) { 599 err = ENOENT; 600 goto done; 601 } 602 603 /* 604 * Disable the address at the MAC. 605 */ 606 if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 607 goto done; 608 609 /* 610 * Remove the address from the list. 611 */ 612 *pp = p->dma_nextp; 613 kmem_free(p, sizeof (dls_multicst_addr_t)); 614 615 done: 616 rw_exit(&(dip->di_lock)); 617 return (err); 618 } 619 620 mblk_t * 621 dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri, 622 mblk_t **payloadp) 623 { 624 dls_impl_t *dip = (dls_impl_t *)dc; 625 uint16_t vid; 626 size_t extra_len; 627 uint16_t mac_sap; 628 mblk_t *mp, *payload; 629 boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER); 630 struct ether_vlan_header *evhp; 631 632 vid = dip->di_dvp->dv_id; 633 payload = (payloadp == NULL) ? NULL : (*payloadp); 634 635 /* 636 * If the following conditions are satisfied: 637 * - This is not a ETHERTYPE_VLAN listener; and 638 * - This is either a VLAN stream or this is a physical stream 639 * but the priority is not 0. 640 * 641 * then we know ahead of time that we'll need to fill in additional 642 * VLAN information in the link-layer header. We will tell the MAC 643 * layer to pre-allocate some space at the end of the Ethernet 644 * header for us. 645 */ 646 if (is_ethernet && sap != ETHERTYPE_VLAN && 647 (vid != VLAN_ID_NONE || pri != 0)) { 648 extra_len = sizeof (struct ether_vlan_header) - 649 sizeof (struct ether_header); 650 mac_sap = ETHERTYPE_VLAN; 651 } else { 652 extra_len = 0; 653 mac_sap = sap; 654 } 655 656 mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len); 657 if (mp == NULL) 658 return (NULL); 659 660 if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet) 661 return (mp); 662 663 /* 664 * Fill in the tag information. 665 */ 666 ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 667 if (extra_len != 0) { 668 mp->b_wptr += extra_len; 669 evhp = (struct ether_vlan_header *)mp->b_rptr; 670 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 671 evhp->ether_type = htons(sap); 672 } else { 673 /* 674 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 675 * in the payload. Update the priority. 676 */ 677 struct ether_vlan_extinfo *extinfo; 678 size_t len = sizeof (struct ether_vlan_extinfo); 679 680 ASSERT(sap == ETHERTYPE_VLAN); 681 ASSERT(payload != NULL); 682 683 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 684 mblk_t *newmp; 685 686 /* 687 * Because some DLS consumers only check the db_ref 688 * count of the first mblk, we pullup 'payload' into 689 * a single mblk. 690 */ 691 newmp = msgpullup(payload, -1); 692 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 693 freemsg(newmp); 694 freemsg(mp); 695 return (NULL); 696 } else { 697 freemsg(payload); 698 *payloadp = payload = newmp; 699 } 700 } 701 702 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 703 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 704 VLAN_ID(ntohs(extinfo->ether_tci)))); 705 } 706 return (mp); 707 } 708 709 int 710 dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip) 711 { 712 return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp, 713 mp, mhip)); 714 } 715 716 void 717 dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 718 { 719 dls_impl_t *dip = (dls_impl_t *)dc; 720 721 rw_enter(&(dip->di_lock), RW_WRITER); 722 dip->di_rx = rx; 723 dip->di_rx_arg = arg; 724 rw_exit(&(dip->di_lock)); 725 } 726 727 mblk_t * 728 dls_tx(dls_channel_t dc, mblk_t *mp) 729 { 730 const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo; 731 732 return (mtp->mt_fn(mtp->mt_arg, mp)); 733 } 734 735 boolean_t 736 dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 737 void **di_rx_arg) 738 { 739 dls_multicst_addr_t *dmap; 740 size_t addr_length = dip->di_mip->mi_addr_length; 741 742 /* 743 * We must not accept packets if the dls_impl_t is not marked as bound 744 * or is being removed. 745 */ 746 rw_enter(&(dip->di_lock), RW_READER); 747 if (!dip->di_bound || dip->di_removing) 748 goto refuse; 749 750 /* 751 * If the dls_impl_t is in 'all physical' mode then always accept. 752 */ 753 if (dip->di_promisc & DLS_PROMISC_PHYS) 754 goto accept; 755 756 switch (mhip->mhi_dsttype) { 757 case MAC_ADDRTYPE_UNICAST: 758 /* 759 * Check to see if the destination address matches the 760 * dls_impl_t unicast address. 761 */ 762 if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) == 763 0) { 764 goto accept; 765 } 766 break; 767 case MAC_ADDRTYPE_MULTICAST: 768 /* 769 * Check the address against the list of addresses enabled 770 * for this dls_impl_t or accept it unconditionally if the 771 * dls_impl_t is in 'all multicast' mode. 772 */ 773 if (dip->di_promisc & DLS_PROMISC_MULTI) 774 goto accept; 775 for (dmap = dip->di_dmap; dmap != NULL; 776 dmap = dmap->dma_nextp) { 777 if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 778 addr_length) == 0) { 779 goto accept; 780 } 781 } 782 break; 783 case MAC_ADDRTYPE_BROADCAST: 784 /* 785 * If the address is broadcast then the dls_impl_t will 786 * always accept it. 787 */ 788 goto accept; 789 } 790 791 refuse: 792 rw_exit(&(dip->di_lock)); 793 return (B_FALSE); 794 795 accept: 796 /* 797 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 798 * always be in sync. 799 */ 800 *di_rx = dip->di_rx; 801 *di_rx_arg = dip->di_rx_arg; 802 rw_exit(&(dip->di_lock)); 803 return (B_TRUE); 804 } 805 806 /* ARGSUSED */ 807 boolean_t 808 dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 809 void **di_rx_arg) 810 { 811 /* 812 * We must not accept packets if the dls_impl_t is not marked as bound 813 * or is being removed. 814 */ 815 rw_enter(&(dip->di_lock), RW_READER); 816 if (!dip->di_bound || dip->di_removing) 817 goto refuse; 818 819 /* 820 * A dls_impl_t should only accept loopback packets if it is in 821 * 'all physical' mode. 822 */ 823 if (dip->di_promisc & DLS_PROMISC_PHYS) 824 goto accept; 825 826 refuse: 827 rw_exit(&(dip->di_lock)); 828 return (B_FALSE); 829 830 accept: 831 /* 832 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 833 * always be in sync. 834 */ 835 *di_rx = dip->di_rx; 836 *di_rx_arg = dip->di_rx_arg; 837 rw_exit(&(dip->di_lock)); 838 return (B_TRUE); 839 } 840 841 boolean_t 842 dls_active_set(dls_channel_t dc) 843 { 844 dls_impl_t *dip = (dls_impl_t *)dc; 845 dls_link_t *dlp = dip->di_dvp->dv_dlp; 846 847 rw_enter(&dip->di_lock, RW_WRITER); 848 849 /* If we're already active, then there's nothing more to do. */ 850 if (dip->di_active) { 851 rw_exit(&dip->di_lock); 852 return (B_TRUE); 853 } 854 855 /* 856 * If this is the first active client on this link, notify 857 * the mac that we're becoming an active client. 858 */ 859 if (dlp->dl_nactive == 0 && !mac_active_shareable_set(dlp->dl_mh)) { 860 rw_exit(&dip->di_lock); 861 return (B_FALSE); 862 } 863 dip->di_active = B_TRUE; 864 mutex_enter(&dlp->dl_lock); 865 dlp->dl_nactive++; 866 mutex_exit(&dlp->dl_lock); 867 rw_exit(&dip->di_lock); 868 return (B_TRUE); 869 } 870 871 void 872 dls_active_clear(dls_channel_t dc) 873 { 874 dls_impl_t *dip = (dls_impl_t *)dc; 875 dls_link_t *dlp = dip->di_dvp->dv_dlp; 876 877 rw_enter(&dip->di_lock, RW_WRITER); 878 879 if (!dip->di_active) 880 goto out; 881 dip->di_active = B_FALSE; 882 883 mutex_enter(&dlp->dl_lock); 884 if (--dlp->dl_nactive == 0) 885 mac_active_clear(dip->di_mh); 886 mutex_exit(&dlp->dl_lock); 887 out: 888 rw_exit(&dip->di_lock); 889 } 890 891 dev_info_t * 892 dls_finddevinfo(dev_t dev) 893 { 894 return (dls_vlan_finddevinfo(dev)); 895 } 896 897 int 898 dls_ppa_from_minor(minor_t minor, t_uscalar_t *ppa) 899 { 900 return (dls_vlan_ppa_from_minor(minor, ppa)); 901 } 902