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