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