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