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