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