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 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 handler 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 && 462 (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) { 463 ASSERT(dlp->dl_mth == NULL); 464 dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_txloop, dlp); 465 } 466 467 /* 468 * Turn on or off 'all multicast' mode, if necessary. 469 */ 470 if (flags & DLS_PROMISC_MULTI) { 471 if (!(dip->di_promisc & DLS_PROMISC_MULTI)) { 472 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 473 if (err != 0) 474 goto done; 475 dip->di_promisc |= DLS_PROMISC_MULTI; 476 dlp->dl_npromisc++; 477 } 478 } else { 479 if (dip->di_promisc & DLS_PROMISC_MULTI) { 480 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 481 if (err != 0) 482 goto done; 483 dip->di_promisc &= ~DLS_PROMISC_MULTI; 484 dlp->dl_npromisc--; 485 } 486 } 487 488 /* 489 * Turn on or off 'all physical' mode, if necessary. 490 */ 491 if (flags & DLS_PROMISC_PHYS) { 492 if (!(dip->di_promisc & DLS_PROMISC_PHYS)) { 493 err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 494 if (err != 0) 495 goto done; 496 dip->di_promisc |= DLS_PROMISC_PHYS; 497 dlp->dl_npromisc++; 498 } 499 } else { 500 if (dip->di_promisc & DLS_PROMISC_PHYS) { 501 err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 502 if (err != 0) 503 goto done; 504 dip->di_promisc &= ~DLS_PROMISC_PHYS; 505 dlp->dl_npromisc--; 506 } 507 } 508 509 done: 510 if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 511 mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 512 dlp->dl_mth = NULL; 513 } 514 515 ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 516 mutex_exit(&dlp->dl_promisc_lock); 517 518 rw_exit(&(dip->di_lock)); 519 return (err); 520 } 521 522 int 523 dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 524 { 525 dls_impl_t *dip = (dls_impl_t *)dc; 526 int err; 527 dls_multicst_addr_t **pp; 528 dls_multicst_addr_t *p; 529 uint_t addr_length; 530 531 /* 532 * Check whether the address is in the list of enabled addresses for 533 * this dls_impl_t. 534 */ 535 rw_enter(&(dip->di_lock), RW_WRITER); 536 addr_length = dip->di_mip->mi_addr_length; 537 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 538 if (bcmp(addr, p->dma_addr, addr_length) == 0) { 539 /* 540 * It is there so there's nothing to do. 541 */ 542 err = 0; 543 goto done; 544 } 545 } 546 547 /* 548 * Allocate a new list item. 549 */ 550 if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 551 KM_NOSLEEP)) == NULL) { 552 err = ENOMEM; 553 goto done; 554 } 555 556 /* 557 * Enable the address at the MAC. 558 */ 559 if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 560 kmem_free(p, sizeof (dls_multicst_addr_t)); 561 goto done; 562 } 563 564 /* 565 * The address is now enabled at the MAC so add it to the list. 566 */ 567 bcopy(addr, p->dma_addr, addr_length); 568 *pp = p; 569 570 done: 571 rw_exit(&(dip->di_lock)); 572 return (err); 573 } 574 575 int 576 dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 577 { 578 dls_impl_t *dip = (dls_impl_t *)dc; 579 int err; 580 dls_multicst_addr_t **pp; 581 dls_multicst_addr_t *p; 582 uint_t addr_length; 583 584 /* 585 * Find the address in the list of enabled addresses for this 586 * dls_impl_t. 587 */ 588 rw_enter(&(dip->di_lock), RW_WRITER); 589 addr_length = dip->di_mip->mi_addr_length; 590 for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 591 if (bcmp(addr, p->dma_addr, addr_length) == 0) 592 break; 593 } 594 595 /* 596 * If we walked to the end of the list then the given address is 597 * not currently enabled for this dls_impl_t. 598 */ 599 if (p == NULL) { 600 err = ENOENT; 601 goto done; 602 } 603 604 /* 605 * Disable the address at the MAC. 606 */ 607 if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 608 goto done; 609 610 /* 611 * Remove the address from the list. 612 */ 613 *pp = p->dma_nextp; 614 kmem_free(p, sizeof (dls_multicst_addr_t)); 615 616 done: 617 rw_exit(&(dip->di_lock)); 618 return (err); 619 } 620 621 mblk_t * 622 dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri, 623 mblk_t **payloadp) 624 { 625 dls_impl_t *dip = (dls_impl_t *)dc; 626 uint16_t vid; 627 size_t extra_len; 628 uint16_t mac_sap; 629 mblk_t *mp, *payload; 630 boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER); 631 struct ether_vlan_header *evhp; 632 633 vid = dip->di_dvp->dv_id; 634 payload = (payloadp == NULL) ? NULL : (*payloadp); 635 636 /* 637 * If the following conditions are satisfied: 638 * - This is not a ETHERTYPE_VLAN listener; and 639 * - This is either a VLAN stream or this is a physical stream 640 * but the priority is not 0. 641 * 642 * then we know ahead of time that we'll need to fill in additional 643 * VLAN information in the link-layer header. We will tell the MAC 644 * layer to pre-allocate some space at the end of the Ethernet 645 * header for us. 646 */ 647 if (is_ethernet && sap != ETHERTYPE_VLAN && 648 (vid != VLAN_ID_NONE || pri != 0)) { 649 extra_len = sizeof (struct ether_vlan_header) - 650 sizeof (struct ether_header); 651 mac_sap = ETHERTYPE_VLAN; 652 } else { 653 extra_len = 0; 654 mac_sap = sap; 655 } 656 657 mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len); 658 if (mp == NULL) 659 return (NULL); 660 661 if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet) 662 return (mp); 663 664 /* 665 * Fill in the tag information. 666 */ 667 ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 668 if (extra_len != 0) { 669 mp->b_wptr += extra_len; 670 evhp = (struct ether_vlan_header *)mp->b_rptr; 671 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 672 evhp->ether_type = htons(sap); 673 } else { 674 /* 675 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 676 * in the payload. Update the priority. 677 */ 678 struct ether_vlan_extinfo *extinfo; 679 size_t len = sizeof (struct ether_vlan_extinfo); 680 681 ASSERT(sap == ETHERTYPE_VLAN); 682 ASSERT(payload != NULL); 683 684 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 685 mblk_t *newmp; 686 687 /* 688 * Because some DLS consumers only check the db_ref 689 * count of the first mblk, we pullup 'payload' into 690 * a single mblk. 691 */ 692 newmp = msgpullup(payload, -1); 693 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 694 freemsg(newmp); 695 freemsg(mp); 696 return (NULL); 697 } else { 698 freemsg(payload); 699 *payloadp = payload = newmp; 700 } 701 } 702 703 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 704 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 705 VLAN_ID(ntohs(extinfo->ether_tci)))); 706 } 707 return (mp); 708 } 709 710 int 711 dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip) 712 { 713 return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp, 714 mp, mhip)); 715 } 716 717 void 718 dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 719 { 720 dls_impl_t *dip = (dls_impl_t *)dc; 721 722 rw_enter(&(dip->di_lock), RW_WRITER); 723 dip->di_rx = rx; 724 dip->di_rx_arg = arg; 725 rw_exit(&(dip->di_lock)); 726 } 727 728 mblk_t * 729 dls_tx(dls_channel_t dc, mblk_t *mp) 730 { 731 const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo; 732 733 return (mtp->mt_fn(mtp->mt_arg, mp)); 734 } 735 736 boolean_t 737 dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 738 void **di_rx_arg) 739 { 740 dls_multicst_addr_t *dmap; 741 size_t addr_length = dip->di_mip->mi_addr_length; 742 743 /* 744 * We must not accept packets if the dls_impl_t is not marked as bound 745 * or is being removed. 746 */ 747 rw_enter(&(dip->di_lock), RW_READER); 748 if (!dip->di_bound || dip->di_removing) 749 goto refuse; 750 751 /* 752 * If the dls_impl_t is in 'all physical' mode then always accept. 753 */ 754 if (dip->di_promisc & DLS_PROMISC_PHYS) 755 goto accept; 756 757 switch (mhip->mhi_dsttype) { 758 case MAC_ADDRTYPE_UNICAST: 759 /* 760 * Check to see if the destination address matches the 761 * dls_impl_t unicast address. 762 */ 763 if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) == 764 0) { 765 goto accept; 766 } 767 break; 768 case MAC_ADDRTYPE_MULTICAST: 769 /* 770 * Check the address against the list of addresses enabled 771 * for this dls_impl_t or accept it unconditionally if the 772 * dls_impl_t is in 'all multicast' mode. 773 */ 774 if (dip->di_promisc & DLS_PROMISC_MULTI) 775 goto accept; 776 for (dmap = dip->di_dmap; dmap != NULL; 777 dmap = dmap->dma_nextp) { 778 if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 779 addr_length) == 0) { 780 goto accept; 781 } 782 } 783 break; 784 case MAC_ADDRTYPE_BROADCAST: 785 /* 786 * If the address is broadcast then the dls_impl_t will 787 * always accept it. 788 */ 789 goto accept; 790 } 791 792 refuse: 793 rw_exit(&(dip->di_lock)); 794 return (B_FALSE); 795 796 accept: 797 /* 798 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 799 * always be in sync. 800 */ 801 *di_rx = dip->di_rx; 802 *di_rx_arg = dip->di_rx_arg; 803 rw_exit(&(dip->di_lock)); 804 return (B_TRUE); 805 } 806 807 /* ARGSUSED */ 808 boolean_t 809 dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 810 void **di_rx_arg) 811 { 812 /* 813 * We must not accept packets if the dls_impl_t is not marked as bound 814 * or is being removed. 815 */ 816 rw_enter(&(dip->di_lock), RW_READER); 817 if (!dip->di_bound || dip->di_removing) 818 goto refuse; 819 820 /* 821 * A dls_impl_t should only accept loopback packets if it is in 822 * 'all physical' mode. 823 */ 824 if (dip->di_promisc & DLS_PROMISC_PHYS) 825 goto accept; 826 827 refuse: 828 rw_exit(&(dip->di_lock)); 829 return (B_FALSE); 830 831 accept: 832 /* 833 * Since we hold di_lock here, the returned di_rx and di_rx_arg will 834 * always be in sync. 835 */ 836 *di_rx = dip->di_rx; 837 *di_rx_arg = dip->di_rx_arg; 838 rw_exit(&(dip->di_lock)); 839 return (B_TRUE); 840 } 841 842 boolean_t 843 dls_active_set(dls_channel_t dc) 844 { 845 dls_impl_t *dip = (dls_impl_t *)dc; 846 dls_link_t *dlp = dip->di_dvp->dv_dlp; 847 848 rw_enter(&dip->di_lock, RW_WRITER); 849 850 /* If we're already active, then there's nothing more to do. */ 851 if (dip->di_active) { 852 rw_exit(&dip->di_lock); 853 return (B_TRUE); 854 } 855 856 /* 857 * If this is the first active client on this link, notify 858 * the mac that we're becoming an active client. 859 */ 860 if (dlp->dl_nactive == 0 && !mac_active_shareable_set(dlp->dl_mh)) { 861 rw_exit(&dip->di_lock); 862 return (B_FALSE); 863 } 864 dip->di_active = B_TRUE; 865 mutex_enter(&dlp->dl_lock); 866 dlp->dl_nactive++; 867 mutex_exit(&dlp->dl_lock); 868 rw_exit(&dip->di_lock); 869 return (B_TRUE); 870 } 871 872 void 873 dls_active_clear(dls_channel_t dc) 874 { 875 dls_impl_t *dip = (dls_impl_t *)dc; 876 dls_link_t *dlp = dip->di_dvp->dv_dlp; 877 878 rw_enter(&dip->di_lock, RW_WRITER); 879 880 if (!dip->di_active) 881 goto out; 882 dip->di_active = B_FALSE; 883 884 mutex_enter(&dlp->dl_lock); 885 if (--dlp->dl_nactive == 0) 886 mac_active_clear(dip->di_mh); 887 mutex_exit(&dlp->dl_lock); 888 out: 889 rw_exit(&dip->di_lock); 890 } 891 892 dev_info_t * 893 dls_finddevinfo(dev_t dev) 894 { 895 return (dls_vlan_finddevinfo(dev)); 896 } 897 898 int 899 dls_ppa_from_minor(minor_t minor, t_uscalar_t *ppa) 900 { 901 return (dls_vlan_ppa_from_minor(minor, ppa)); 902 } 903