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