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