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 * MAC Services Module 31 */ 32 33 #include <sys/types.h> 34 #include <sys/conf.h> 35 #include <sys/stat.h> 36 #include <sys/stream.h> 37 #include <sys/strsun.h> 38 #include <sys/strsubr.h> 39 #include <sys/dlpi.h> 40 #include <sys/mac.h> 41 #include <sys/mac_impl.h> 42 #include <sys/dld_impl.h> 43 44 #define IMPL_HASHSZ 67 /* prime */ 45 46 static kmem_cache_t *i_mac_impl_cachep; 47 static ght_t i_mac_impl_hash; 48 49 /* 50 * Private functions. 51 */ 52 53 /*ARGSUSED*/ 54 static boolean_t 55 i_mac_ether_unicst_verify(mac_impl_t *mip, const uint8_t *addr) 56 { 57 /* 58 * Check the address is not a group address. 59 */ 60 if (addr[0] & 0x01) 61 return (B_FALSE); 62 63 return (B_TRUE); 64 } 65 66 static boolean_t 67 i_mac_ether_multicst_verify(mac_impl_t *mip, const uint8_t *addr) 68 { 69 mac_t *mp = mip->mi_mp; 70 71 /* 72 * Check the address is a group address. 73 */ 74 if (!(addr[0] & 0x01)) 75 return (B_FALSE); 76 77 /* 78 * Check the address is not the media broadcast address. 79 */ 80 if (bcmp(addr, mp->m_info.mi_brdcst_addr, mip->mi_addr_length) == 0) 81 return (B_FALSE); 82 83 return (B_TRUE); 84 } 85 86 /*ARGSUSED*/ 87 static int 88 i_mac_constructor(void *buf, void *arg, int kmflag) 89 { 90 mac_impl_t *mip = buf; 91 92 bzero(buf, sizeof (mac_impl_t)); 93 94 mip->mi_link = LINK_STATE_UNKNOWN; 95 96 rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 97 rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 98 rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 99 rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 100 rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 101 rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 102 mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 103 return (0); 104 } 105 106 /*ARGSUSED*/ 107 static void 108 i_mac_destructor(void *buf, void *arg) 109 { 110 mac_impl_t *mip = buf; 111 112 ASSERT(mip->mi_mp == NULL); 113 ASSERT(mip->mi_hte == NULL); 114 ASSERT(mip->mi_ref == 0); 115 ASSERT(mip->mi_active == 0); 116 ASSERT(mip->mi_link == LINK_STATE_UNKNOWN); 117 ASSERT(mip->mi_devpromisc == 0); 118 ASSERT(mip->mi_promisc == 0); 119 ASSERT(mip->mi_mmap == NULL); 120 ASSERT(mip->mi_mnfp == NULL); 121 ASSERT(mip->mi_resource_add == NULL); 122 ASSERT(mip->mi_ksp == NULL); 123 124 rw_destroy(&mip->mi_state_lock); 125 rw_destroy(&mip->mi_data_lock); 126 rw_destroy(&mip->mi_notify_lock); 127 rw_destroy(&mip->mi_rx_lock); 128 rw_destroy(&mip->mi_txloop_lock); 129 rw_destroy(&mip->mi_resource_lock); 130 mutex_destroy(&mip->mi_activelink_lock); 131 } 132 133 int 134 i_mac_create(mac_t *mp) 135 { 136 dev_info_t *dip; 137 mac_impl_t *mip; 138 int err; 139 ghte_t hte; 140 141 dip = mp->m_dip; 142 ASSERT(dip != NULL); 143 ASSERT(ddi_get_instance(dip) >= 0); 144 145 /* 146 * Allocate a new mac_impl_t. 147 */ 148 mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 149 150 /* 151 * Construct a name. 152 */ 153 (void) snprintf(mip->mi_dev, MAXNAMELEN - 1, "%s%d", 154 ddi_driver_name(dip), ddi_get_instance(dip)); 155 mip->mi_port = mp->m_port; 156 157 MAC_NAME(mip->mi_name, mip->mi_dev, mip->mi_port); 158 159 /* 160 * Set the mac_t/mac_impl_t cross-references. 161 */ 162 mip->mi_mp = mp; 163 mp->m_impl = (void *)mip; 164 165 /* 166 * Allocate a hash table entry. 167 */ 168 hte = ght_alloc(i_mac_impl_hash, KM_SLEEP); 169 170 GHT_KEY(hte) = GHT_PTR_TO_KEY(mip->mi_name); 171 GHT_VAL(hte) = GHT_PTR_TO_VAL(mip); 172 173 /* 174 * Insert the hash table entry. 175 */ 176 ght_lock(i_mac_impl_hash, GHT_WRITE); 177 if ((err = ght_insert(hte)) != 0) { 178 ght_free(hte); 179 kmem_cache_free(i_mac_impl_cachep, mip); 180 goto done; 181 } 182 183 mip->mi_hte = hte; 184 185 /* 186 * Copy the fixed 'factory' MAC address from the immutable info. 187 * This is taken to be the MAC address currently in use. 188 */ 189 mip->mi_addr_length = mp->m_info.mi_addr_length; 190 bcopy(mp->m_info.mi_unicst_addr, mip->mi_addr, mip->mi_addr_length); 191 192 /* 193 * Set up the address verification functions. 194 */ 195 ASSERT(mp->m_info.mi_media == DL_ETHER); 196 mip->mi_unicst_verify = i_mac_ether_unicst_verify; 197 mip->mi_multicst_verify = i_mac_ether_multicst_verify; 198 199 /* 200 * Initialize the kstats for this device. 201 */ 202 mac_stat_create(mip); 203 204 done: 205 ght_unlock(i_mac_impl_hash); 206 return (err); 207 } 208 209 static void 210 i_mac_destroy(mac_t *mp) 211 { 212 mac_impl_t *mip = mp->m_impl; 213 ghte_t hte; 214 mac_multicst_addr_t *p, *nextp; 215 216 ght_lock(i_mac_impl_hash, GHT_WRITE); 217 218 ASSERT(mip->mi_ref == 0); 219 ASSERT(!mip->mi_activelink); 220 221 /* 222 * Destroy the kstats. 223 */ 224 mac_stat_destroy(mip); 225 226 /* 227 * Remove and destroy the hash table entry. 228 */ 229 hte = mip->mi_hte; 230 ght_remove(hte); 231 ght_free(hte); 232 mip->mi_hte = NULL; 233 234 /* 235 * Free the list of multicast addresses. 236 */ 237 for (p = mip->mi_mmap; p != NULL; p = nextp) { 238 nextp = p->mma_nextp; 239 kmem_free(p, sizeof (mac_multicst_addr_t)); 240 } 241 mip->mi_mmap = NULL; 242 243 /* 244 * Clean up the mac_impl_t ready to go back into the cache. 245 */ 246 mp->m_impl = NULL; 247 mip->mi_mp = NULL; 248 mip->mi_link = LINK_STATE_UNKNOWN; 249 mip->mi_destroying = B_FALSE; 250 251 /* 252 * Free the structure back to the cache. 253 */ 254 kmem_cache_free(i_mac_impl_cachep, mip); 255 256 ght_unlock(i_mac_impl_hash); 257 } 258 259 static void 260 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 261 { 262 mac_notify_fn_t *mnfp; 263 mac_notify_t notify; 264 void *arg; 265 266 /* 267 * Walk the list of notifications. 268 */ 269 rw_enter(&(mip->mi_notify_lock), RW_READER); 270 for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 271 notify = mnfp->mnf_fn; 272 arg = mnfp->mnf_arg; 273 274 ASSERT(notify != NULL); 275 notify(arg, type); 276 } 277 rw_exit(&(mip->mi_notify_lock)); 278 } 279 280 /* 281 * Module initialization functions. 282 */ 283 284 void 285 mac_init(void) 286 { 287 int err; 288 289 i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 290 sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, NULL, 291 NULL, NULL, 0); 292 ASSERT(i_mac_impl_cachep != NULL); 293 294 err = ght_str_create("mac_impl_hash", IMPL_HASHSZ, &i_mac_impl_hash); 295 ASSERT(err == 0); 296 } 297 298 int 299 mac_fini(void) 300 { 301 int err; 302 303 if ((err = ght_destroy(i_mac_impl_hash)) != 0) 304 return (err); 305 306 kmem_cache_destroy(i_mac_impl_cachep); 307 return (0); 308 } 309 310 /* 311 * Client functions. 312 */ 313 314 int 315 mac_open(const char *dev, uint_t port, mac_handle_t *mhp) 316 { 317 char name[MAXNAMELEN]; 318 char driver[MAXNAMELEN]; 319 uint_t instance; 320 major_t major; 321 dev_info_t *dip; 322 mac_impl_t *mip; 323 ghte_t hte; 324 int err; 325 326 /* 327 * Check the device name length to make sure it won't overflow our 328 * buffer. 329 */ 330 if (strlen(dev) >= MAXNAMELEN) 331 return (EINVAL); 332 333 /* 334 * Split the device name into driver and instance components. 335 */ 336 if (ddi_parse(dev, driver, &instance) != DDI_SUCCESS) 337 return (EINVAL); 338 339 /* 340 * Get the major number of the driver. 341 */ 342 if ((major = ddi_name_to_major(driver)) == (major_t)-1) 343 return (EINVAL); 344 345 /* 346 * Hold the given instance to prevent it from being detached. 347 * (This will also attach it if it is not currently attached). 348 */ 349 if ((dip = ddi_hold_devi_by_instance(major, instance, 0)) == NULL) 350 return (EINVAL); 351 352 /* 353 * Construct the name of the MAC interface. 354 */ 355 MAC_NAME(name, dev, port); 356 357 /* 358 * Look up its entry in the global hash table. 359 */ 360 again: 361 ght_lock(i_mac_impl_hash, GHT_WRITE); 362 if ((err = ght_find(i_mac_impl_hash, GHT_PTR_TO_KEY(name), &hte)) != 0) 363 goto failed; 364 365 mip = (mac_impl_t *)GHT_VAL(hte); 366 ASSERT(mip->mi_mp->m_dip == dip); 367 368 if (mip->mi_destroying) { 369 ght_unlock(i_mac_impl_hash); 370 goto again; 371 } 372 373 mip->mi_ref++; 374 ght_unlock(i_mac_impl_hash); 375 376 *mhp = (mac_handle_t)mip; 377 return (0); 378 379 failed: 380 ght_unlock(i_mac_impl_hash); 381 ddi_release_devi(dip); 382 return (err); 383 } 384 385 void 386 mac_close(mac_handle_t mh) 387 { 388 mac_impl_t *mip = (mac_impl_t *)mh; 389 dev_info_t *dip = mip->mi_mp->m_dip; 390 391 ght_lock(i_mac_impl_hash, GHT_WRITE); 392 393 ASSERT(mip->mi_ref != 0); 394 if (--mip->mi_ref == 0) { 395 ASSERT(!mip->mi_activelink); 396 } 397 ddi_release_devi(dip); 398 ght_unlock(i_mac_impl_hash); 399 } 400 401 const mac_info_t * 402 mac_info(mac_handle_t mh) 403 { 404 mac_impl_t *mip = (mac_impl_t *)mh; 405 mac_t *mp = mip->mi_mp; 406 407 /* 408 * Return a pointer to the mac_info_t embedded in the mac_t. 409 */ 410 return (&(mp->m_info)); 411 } 412 413 uint64_t 414 mac_stat_get(mac_handle_t mh, enum mac_stat stat) 415 { 416 mac_impl_t *mip = (mac_impl_t *)mh; 417 mac_t *mp = mip->mi_mp; 418 419 ASSERT(mp->m_info.mi_stat[stat]); 420 ASSERT(mp->m_stat != NULL); 421 422 /* 423 * Call the driver to get the given statistic. 424 */ 425 return (mp->m_stat(mp->m_driver, stat)); 426 } 427 428 int 429 mac_start(mac_handle_t mh) 430 { 431 mac_impl_t *mip = (mac_impl_t *)mh; 432 mac_t *mp = mip->mi_mp; 433 int err; 434 435 ASSERT(mp->m_start != NULL); 436 437 rw_enter(&(mip->mi_state_lock), RW_WRITER); 438 439 /* 440 * Check whether the device is already started. 441 */ 442 if (mip->mi_active++ != 0) { 443 /* 444 * It's already started so there's nothing more to do. 445 */ 446 err = 0; 447 goto done; 448 } 449 450 /* 451 * Start the device. 452 */ 453 if ((err = mp->m_start(mp->m_driver)) != 0) 454 --mip->mi_active; 455 456 done: 457 rw_exit(&(mip->mi_state_lock)); 458 return (err); 459 } 460 461 void 462 mac_stop(mac_handle_t mh) 463 { 464 mac_impl_t *mip = (mac_impl_t *)mh; 465 mac_t *mp = mip->mi_mp; 466 467 ASSERT(mp->m_stop != NULL); 468 469 rw_enter(&(mip->mi_state_lock), RW_WRITER); 470 471 /* 472 * Check whether the device is still needed. 473 */ 474 ASSERT(mip->mi_active != 0); 475 if (--mip->mi_active != 0) { 476 /* 477 * It's still needed so there's nothing more to do. 478 */ 479 goto done; 480 } 481 482 /* 483 * Stop the device. 484 */ 485 mp->m_stop(mp->m_driver); 486 487 done: 488 rw_exit(&(mip->mi_state_lock)); 489 } 490 491 int 492 mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 493 { 494 mac_impl_t *mip = (mac_impl_t *)mh; 495 mac_t *mp = mip->mi_mp; 496 mac_multicst_addr_t **pp; 497 mac_multicst_addr_t *p; 498 int err; 499 500 ASSERT(mp->m_multicst != NULL); 501 502 /* 503 * Verify the address. 504 */ 505 if (!(mip->mi_multicst_verify(mip, addr))) 506 return (EINVAL); 507 508 /* 509 * Check whether the given address is already enabled. 510 */ 511 rw_enter(&(mip->mi_data_lock), RW_WRITER); 512 for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 513 if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) { 514 /* 515 * The address is already enabled so just bump the 516 * reference count. 517 */ 518 p->mma_ref++; 519 err = 0; 520 goto done; 521 } 522 } 523 524 /* 525 * Allocate a new list entry. 526 */ 527 if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 528 KM_NOSLEEP)) == NULL) { 529 err = ENOMEM; 530 goto done; 531 } 532 533 /* 534 * Enable a new multicast address. 535 */ 536 if ((err = mp->m_multicst(mp->m_driver, B_TRUE, addr)) != 0) { 537 kmem_free(p, sizeof (mac_multicst_addr_t)); 538 goto done; 539 } 540 541 /* 542 * Add the address to the list of enabled addresses. 543 */ 544 bcopy(addr, p->mma_addr, mip->mi_addr_length); 545 p->mma_ref++; 546 *pp = p; 547 548 done: 549 rw_exit(&(mip->mi_data_lock)); 550 return (err); 551 } 552 553 int 554 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 555 { 556 mac_impl_t *mip = (mac_impl_t *)mh; 557 mac_t *mp = mip->mi_mp; 558 mac_multicst_addr_t **pp; 559 mac_multicst_addr_t *p; 560 int err; 561 562 ASSERT(mp->m_multicst != NULL); 563 564 /* 565 * Find the entry in the list for the given address. 566 */ 567 rw_enter(&(mip->mi_data_lock), RW_WRITER); 568 for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 569 if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) { 570 if (--p->mma_ref == 0) 571 break; 572 573 /* 574 * There is still a reference to this address so 575 * there's nothing more to do. 576 */ 577 err = 0; 578 goto done; 579 } 580 } 581 582 /* 583 * We did not find an entry for the given address so it is not 584 * currently enabled. 585 */ 586 if (p == NULL) { 587 err = ENOENT; 588 goto done; 589 } 590 ASSERT(p->mma_ref == 0); 591 592 /* 593 * Disable the multicast address. 594 */ 595 if ((err = mp->m_multicst(mp->m_driver, B_FALSE, addr)) != 0) { 596 p->mma_ref++; 597 goto done; 598 } 599 600 /* 601 * Remove it from the list. 602 */ 603 *pp = p->mma_nextp; 604 kmem_free(p, sizeof (mac_multicst_addr_t)); 605 606 done: 607 rw_exit(&(mip->mi_data_lock)); 608 return (err); 609 } 610 611 int 612 mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 613 { 614 mac_impl_t *mip = (mac_impl_t *)mh; 615 mac_t *mp = mip->mi_mp; 616 int err; 617 boolean_t notify = B_FALSE; 618 619 ASSERT(mp->m_unicst != NULL); 620 621 /* 622 * Verify the address. 623 */ 624 if (!(mip->mi_unicst_verify(mip, addr))) 625 return (EINVAL); 626 627 /* 628 * Program the new unicast address. 629 */ 630 rw_enter(&(mip->mi_data_lock), RW_WRITER); 631 632 /* 633 * If address doesn't change, do nothing. 634 * This check is necessary otherwise it may call into mac_unicst_set 635 * recursively. 636 */ 637 if (bcmp(addr, mip->mi_addr, mip->mi_addr_length) == 0) { 638 err = 0; 639 goto done; 640 } 641 642 if ((err = mp->m_unicst(mp->m_driver, addr)) != 0) 643 goto done; 644 645 /* 646 * Save the address and flag that we need to send a notification. 647 */ 648 bcopy(addr, mip->mi_addr, mip->mi_addr_length); 649 notify = B_TRUE; 650 651 done: 652 rw_exit(&(mip->mi_data_lock)); 653 654 if (notify) 655 i_mac_notify(mip, MAC_NOTE_UNICST); 656 657 return (err); 658 } 659 660 void 661 mac_unicst_get(mac_handle_t mh, uint8_t *addr) 662 { 663 mac_impl_t *mip = (mac_impl_t *)mh; 664 665 /* 666 * Copy out the current unicast address. 667 */ 668 rw_enter(&(mip->mi_data_lock), RW_READER); 669 bcopy(mip->mi_addr, addr, mip->mi_addr_length); 670 rw_exit(&(mip->mi_data_lock)); 671 } 672 673 int 674 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 675 { 676 mac_impl_t *mip = (mac_impl_t *)mh; 677 mac_t *mp = mip->mi_mp; 678 int err = 0; 679 680 ASSERT(mp->m_promisc != NULL); 681 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 682 683 /* 684 * Determine whether we should enable or disable promiscuous mode. 685 * For details on the distinction between "device promiscuous mode" 686 * and "MAC promiscuous mode", see PSARC/2005/289. 687 */ 688 rw_enter(&(mip->mi_data_lock), RW_WRITER); 689 if (on) { 690 /* 691 * Enable promiscuous mode on the device if not yet enabled. 692 */ 693 if (mip->mi_devpromisc++ == 0) { 694 if ((err = mp->m_promisc(mp->m_driver, B_TRUE)) != 0) { 695 mip->mi_devpromisc--; 696 goto done; 697 } 698 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 699 } 700 701 /* 702 * Enable promiscuous mode on the MAC if not yet enabled. 703 */ 704 if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 705 i_mac_notify(mip, MAC_NOTE_PROMISC); 706 } else { 707 if (mip->mi_devpromisc == 0) { 708 err = EPROTO; 709 goto done; 710 } 711 712 /* 713 * Disable promiscuous mode on the device if this is the last 714 * enabling. 715 */ 716 if (--mip->mi_devpromisc == 0) { 717 if ((err = mp->m_promisc(mp->m_driver, B_FALSE)) != 0) { 718 mip->mi_devpromisc++; 719 goto done; 720 } 721 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 722 } 723 724 /* 725 * Disable promiscuous mode on the MAC if this is the last 726 * enabling. 727 */ 728 if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 729 i_mac_notify(mip, MAC_NOTE_PROMISC); 730 } 731 732 done: 733 rw_exit(&(mip->mi_data_lock)); 734 return (err); 735 } 736 737 boolean_t 738 mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 739 { 740 mac_impl_t *mip = (mac_impl_t *)mh; 741 742 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 743 744 /* 745 * Return the current promiscuity. 746 */ 747 if (ptype == MAC_DEVPROMISC) 748 return (mip->mi_devpromisc != 0); 749 else 750 return (mip->mi_promisc != 0); 751 } 752 753 void 754 mac_resources(mac_handle_t mh) 755 { 756 mac_impl_t *mip = (mac_impl_t *)mh; 757 mac_t *mp = mip->mi_mp; 758 759 ASSERT(mp->m_resources != NULL); 760 761 /* 762 * Call the driver to register its resources. 763 */ 764 mp->m_resources(mp->m_driver); 765 } 766 767 void 768 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 769 { 770 mac_impl_t *mip = (mac_impl_t *)mh; 771 mac_t *mp = mip->mi_mp; 772 773 ASSERT(mp->m_ioctl != NULL); 774 775 /* 776 * Call the driver to handle the ioctl. 777 */ 778 mp->m_ioctl(mp->m_driver, wq, bp); 779 } 780 781 void 782 mac_tx_get(mac_handle_t mh, mac_tx_t *txp, void **argp) 783 { 784 mac_impl_t *mip = (mac_impl_t *)mh; 785 mac_t *mp = mip->mi_mp; 786 787 ASSERT(mp->m_tx != NULL); 788 789 *txp = mp->m_tx; 790 *argp = mp->m_driver; 791 } 792 793 link_state_t 794 mac_link_get(mac_handle_t mh) 795 { 796 mac_impl_t *mip = (mac_impl_t *)mh; 797 798 /* 799 * Return the current link state. 800 */ 801 return (mip->mi_link); 802 } 803 804 mac_notify_handle_t 805 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 806 { 807 mac_impl_t *mip = (mac_impl_t *)mh; 808 mac_notify_fn_t *mnfp; 809 810 mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 811 mnfp->mnf_fn = notify; 812 mnfp->mnf_arg = arg; 813 814 /* 815 * Add it to the head of the 'notify' callback list. 816 */ 817 rw_enter(&(mip->mi_notify_lock), RW_WRITER); 818 mnfp->mnf_nextp = mip->mi_mnfp; 819 mip->mi_mnfp = mnfp; 820 rw_exit(&(mip->mi_notify_lock)); 821 822 return ((mac_notify_handle_t)mnfp); 823 } 824 825 void 826 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 827 { 828 mac_impl_t *mip = (mac_impl_t *)mh; 829 mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 830 mac_notify_fn_t **pp; 831 mac_notify_fn_t *p; 832 833 /* 834 * Search the 'notify' callback list for the function closure. 835 */ 836 rw_enter(&(mip->mi_notify_lock), RW_WRITER); 837 for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 838 pp = &(p->mnf_nextp)) { 839 if (p == mnfp) 840 break; 841 } 842 ASSERT(p != NULL); 843 844 /* 845 * Remove it from the list. 846 */ 847 *pp = p->mnf_nextp; 848 rw_exit(&(mip->mi_notify_lock)); 849 850 /* 851 * Free it. 852 */ 853 kmem_free(mnfp, sizeof (mac_notify_fn_t)); 854 } 855 856 void 857 mac_notify(mac_handle_t mh) 858 { 859 mac_impl_t *mip = (mac_impl_t *)mh; 860 mac_notify_type_t type; 861 862 for (type = 0; type < MAC_NNOTE; type++) 863 i_mac_notify(mip, type); 864 } 865 866 mac_rx_handle_t 867 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 868 { 869 mac_impl_t *mip = (mac_impl_t *)mh; 870 mac_rx_fn_t *mrfp; 871 872 mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 873 mrfp->mrf_fn = rx; 874 mrfp->mrf_arg = arg; 875 876 /* 877 * Add it to the head of the 'rx' callback list. 878 */ 879 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 880 mrfp->mrf_nextp = mip->mi_mrfp; 881 mip->mi_mrfp = mrfp; 882 rw_exit(&(mip->mi_rx_lock)); 883 884 return ((mac_rx_handle_t)mrfp); 885 } 886 887 /* 888 * Unregister a receive function for this mac. This removes the function 889 * from the list of receive functions for this mac. 890 */ 891 void 892 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 893 { 894 mac_impl_t *mip = (mac_impl_t *)mh; 895 mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 896 mac_rx_fn_t **pp; 897 mac_rx_fn_t *p; 898 899 /* 900 * Search the 'rx' callback list for the function closure. 901 */ 902 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 903 for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 904 if (p == mrfp) 905 break; 906 } 907 ASSERT(p != NULL); 908 909 /* Remove it from the list. */ 910 *pp = p->mrf_nextp; 911 kmem_free(mrfp, sizeof (mac_rx_fn_t)); 912 rw_exit(&(mip->mi_rx_lock)); 913 } 914 915 mac_txloop_handle_t 916 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 917 { 918 mac_impl_t *mip = (mac_impl_t *)mh; 919 mac_txloop_fn_t *mtfp; 920 921 mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 922 mtfp->mtf_fn = tx; 923 mtfp->mtf_arg = arg; 924 925 /* 926 * Add it to the head of the 'tx' callback list. 927 */ 928 rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 929 mtfp->mtf_nextp = mip->mi_mtfp; 930 mip->mi_mtfp = mtfp; 931 rw_exit(&(mip->mi_txloop_lock)); 932 933 return ((mac_txloop_handle_t)mtfp); 934 } 935 936 /* 937 * Unregister a transmit function for this mac. This removes the function 938 * from the list of transmit functions for this mac. 939 */ 940 void 941 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 942 { 943 mac_impl_t *mip = (mac_impl_t *)mh; 944 mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 945 mac_txloop_fn_t **pp; 946 mac_txloop_fn_t *p; 947 948 /* 949 * Search the 'tx' callback list for the function. 950 */ 951 rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 952 for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 953 if (p == mtfp) 954 break; 955 } 956 ASSERT(p != NULL); 957 958 /* Remove it from the list. */ 959 *pp = p->mtf_nextp; 960 kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 961 rw_exit(&(mip->mi_txloop_lock)); 962 } 963 964 void 965 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 966 { 967 mac_impl_t *mip = (mac_impl_t *)mh; 968 969 /* 970 * Update the 'resource_add' callbacks. 971 */ 972 rw_enter(&(mip->mi_resource_lock), RW_WRITER); 973 mip->mi_resource_add = add; 974 mip->mi_resource_add_arg = arg; 975 rw_exit(&(mip->mi_resource_lock)); 976 } 977 978 /* 979 * Driver support functions. 980 */ 981 982 int 983 mac_register(mac_t *mp) 984 { 985 int err; 986 char name[MAXNAMELEN], aggr_name[MAXNAMELEN]; 987 struct devnames *dnp; 988 989 #ifdef DEBUG 990 if (strcmp(mp->m_ident, MAC_IDENT) != 0) 991 cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch", 992 ddi_driver_name(mp->m_dip), 993 ddi_get_instance(mp->m_dip), 994 mp->m_port); 995 #endif /* DEBUG */ 996 997 ASSERT(!(mp->m_info.mi_addr_length & 1)); 998 999 /* 1000 * Create a new mac_impl_t to pair with the mac_t. 1001 */ 1002 if ((err = i_mac_create(mp)) != 0) 1003 return (err); 1004 1005 /* 1006 * Create a DDI_NT_MAC minor node such that libdevinfo(3lib) can be 1007 * used to search for mac interfaces. 1008 */ 1009 (void) sprintf(name, "%d", mp->m_port); 1010 if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, mp->m_port, 1011 DDI_NT_MAC, 0) != DDI_SUCCESS) { 1012 i_mac_destroy(mp); 1013 return (EEXIST); 1014 } 1015 1016 /* 1017 * Right now only the "aggr" driver creates nodes at mac_register 1018 * time, but it is expected that in the future with some 1019 * enhancement of devfs, all the drivers can create nodes here. 1020 */ 1021 if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) { 1022 (void) snprintf(aggr_name, MAXNAMELEN, "aggr%u", mp->m_port); 1023 err = dld_ppa_create(aggr_name, AGGR_DEV, mp->m_port, 0); 1024 if (err != 0) { 1025 ASSERT(err != EEXIST); 1026 ddi_remove_minor_node(mp->m_dip, name); 1027 i_mac_destroy(mp); 1028 return (err); 1029 } 1030 } 1031 1032 /* set the gldv3 flag in dn_flags */ 1033 dnp = &devnamesp[ddi_driver_major(mp->m_dip)]; 1034 LOCK_DEV_OPS(&dnp->dn_lock); 1035 dnp->dn_flags |= DN_GLDV3_DRIVER; 1036 UNLOCK_DEV_OPS(&dnp->dn_lock); 1037 1038 cmn_err(CE_NOTE, "!%s%d/%d registered", 1039 ddi_driver_name(mp->m_dip), 1040 ddi_get_instance(mp->m_dip), 1041 mp->m_port); 1042 1043 return (0); 1044 } 1045 1046 int 1047 mac_unregister(mac_t *mp) 1048 { 1049 int err; 1050 char name[MAXNAMELEN]; 1051 mac_impl_t *mip = mp->m_impl; 1052 1053 /* 1054 * See if there are any other references to this mac_t (e.g., VLAN's). 1055 * If not, set mi_destroying to prevent any new VLAN's from being 1056 * created before we can perform the i_mac_destroy() below. 1057 */ 1058 ght_lock(i_mac_impl_hash, GHT_WRITE); 1059 if (mip->mi_ref > 0) { 1060 ght_unlock(i_mac_impl_hash); 1061 return (EBUSY); 1062 } 1063 mip->mi_destroying = B_TRUE; 1064 ght_unlock(i_mac_impl_hash); 1065 1066 if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) { 1067 (void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port); 1068 if ((err = dld_ppa_destroy(name)) != 0) 1069 return (err); 1070 } 1071 1072 /* 1073 * Destroy the mac_impl_t. 1074 */ 1075 i_mac_destroy(mp); 1076 1077 /* 1078 * Remove the minor node. 1079 */ 1080 (void) sprintf(name, "%d", mp->m_port); 1081 ddi_remove_minor_node(mp->m_dip, name); 1082 1083 cmn_err(CE_NOTE, "!%s%d/%d unregistered", 1084 ddi_driver_name(mp->m_dip), 1085 ddi_get_instance(mp->m_dip), 1086 mp->m_port); 1087 1088 return (0); 1089 } 1090 1091 void 1092 mac_rx(mac_t *mp, mac_resource_handle_t mrh, mblk_t *bp) 1093 { 1094 mac_impl_t *mip = mp->m_impl; 1095 mac_rx_fn_t *mrfp; 1096 1097 /* 1098 * Call all registered receive functions. 1099 */ 1100 rw_enter(&mip->mi_rx_lock, RW_READER); 1101 mrfp = mip->mi_mrfp; 1102 if (mrfp == NULL) { 1103 /* There are no registered receive functions. */ 1104 freemsgchain(bp); 1105 rw_exit(&mip->mi_rx_lock); 1106 return; 1107 } 1108 do { 1109 mblk_t *recv_bp; 1110 1111 if (mrfp->mrf_nextp != NULL) { 1112 /* XXX Do we bump a counter if copymsgchain() fails? */ 1113 recv_bp = copymsgchain(bp); 1114 } else { 1115 recv_bp = bp; 1116 } 1117 if (recv_bp != NULL) 1118 mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 1119 mrfp = mrfp->mrf_nextp; 1120 } while (mrfp != NULL); 1121 rw_exit(&mip->mi_rx_lock); 1122 } 1123 1124 /* 1125 * Transmit function -- ONLY used when there are registered loopback listeners. 1126 */ 1127 mblk_t * 1128 mac_txloop(void *arg, mblk_t *bp) 1129 { 1130 mac_impl_t *mip = arg; 1131 mac_t *mp = mip->mi_mp; 1132 mac_txloop_fn_t *mtfp; 1133 mblk_t *loop_bp, *resid_bp, *next_bp; 1134 1135 while (bp != NULL) { 1136 next_bp = bp->b_next; 1137 bp->b_next = NULL; 1138 1139 if ((loop_bp = copymsg(bp)) == NULL) 1140 goto noresources; 1141 1142 if ((resid_bp = mp->m_tx(mp->m_driver, bp)) != NULL) { 1143 ASSERT(resid_bp == bp); 1144 freemsg(loop_bp); 1145 goto noresources; 1146 } 1147 1148 rw_enter(&mip->mi_txloop_lock, RW_READER); 1149 1150 mtfp = mip->mi_mtfp; 1151 for (; mtfp != NULL; mtfp = mtfp->mtf_nextp) { 1152 bp = loop_bp; 1153 if (mtfp->mtf_nextp != NULL) { 1154 loop_bp = copymsg(bp); 1155 /* XXX counter bump if copymsg() fails? */ 1156 } 1157 1158 mtfp->mtf_fn(mtfp->mtf_arg, bp); 1159 if (loop_bp == NULL) 1160 break; 1161 } 1162 1163 rw_exit(&mip->mi_txloop_lock); 1164 bp = next_bp; 1165 } 1166 1167 return (NULL); 1168 1169 noresources: 1170 bp->b_next = next_bp; 1171 return (bp); 1172 } 1173 1174 void 1175 mac_link_update(mac_t *mp, link_state_t link) 1176 { 1177 mac_impl_t *mip = mp->m_impl; 1178 1179 ASSERT(mip->mi_mp == mp); 1180 1181 /* 1182 * Save the link state. 1183 */ 1184 mip->mi_link = link; 1185 1186 /* 1187 * Send a MAC_NOTE_LINK notification. 1188 */ 1189 i_mac_notify(mip, MAC_NOTE_LINK); 1190 } 1191 1192 void 1193 mac_unicst_update(mac_t *mp, const uint8_t *addr) 1194 { 1195 mac_impl_t *mip = mp->m_impl; 1196 1197 ASSERT(mip->mi_mp == mp); 1198 1199 /* 1200 * Save the address. 1201 */ 1202 bcopy(addr, mip->mi_addr, mip->mi_addr_length); 1203 1204 /* 1205 * Send a MAC_NOTE_UNICST notification. 1206 */ 1207 i_mac_notify(mip, MAC_NOTE_UNICST); 1208 } 1209 1210 void 1211 mac_tx_update(mac_t *mp) 1212 { 1213 mac_impl_t *mip = mp->m_impl; 1214 1215 ASSERT(mip->mi_mp == mp); 1216 1217 /* 1218 * Send a MAC_NOTE_TX notification. 1219 */ 1220 i_mac_notify(mip, MAC_NOTE_TX); 1221 } 1222 1223 void 1224 mac_resource_update(mac_t *mp) 1225 { 1226 mac_impl_t *mip = mp->m_impl; 1227 1228 ASSERT(mip->mi_mp == mp); 1229 1230 /* 1231 * Send a MAC_NOTE_RESOURCE notification. 1232 */ 1233 i_mac_notify(mip, MAC_NOTE_RESOURCE); 1234 } 1235 1236 mac_resource_handle_t 1237 mac_resource_add(mac_t *mp, mac_resource_t *mrp) 1238 { 1239 mac_impl_t *mip = mp->m_impl; 1240 mac_resource_handle_t mrh; 1241 mac_resource_add_t add; 1242 void *arg; 1243 1244 rw_enter(&mip->mi_resource_lock, RW_READER); 1245 add = mip->mi_resource_add; 1246 arg = mip->mi_resource_add_arg; 1247 1248 mrh = add(arg, mrp); 1249 rw_exit(&mip->mi_resource_lock); 1250 1251 return (mrh); 1252 } 1253 1254 void 1255 mac_multicst_refresh(mac_t *mp, mac_multicst_t refresh, void *arg, 1256 boolean_t add) 1257 { 1258 mac_impl_t *mip = mp->m_impl; 1259 mac_multicst_addr_t *p; 1260 1261 /* 1262 * If no specific refresh function was given then default to the 1263 * driver's m_multicst entry point. 1264 */ 1265 if (refresh == NULL) { 1266 refresh = mp->m_multicst; 1267 arg = mp->m_driver; 1268 } 1269 ASSERT(refresh != NULL); 1270 1271 /* 1272 * Walk the multicast address list and call the refresh function for 1273 * each address. 1274 */ 1275 rw_enter(&(mip->mi_data_lock), RW_READER); 1276 for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 1277 refresh(arg, add, p->mma_addr); 1278 rw_exit(&(mip->mi_data_lock)); 1279 } 1280 1281 void 1282 mac_unicst_refresh(mac_t *mp, mac_unicst_t refresh, void *arg) 1283 { 1284 mac_impl_t *mip = mp->m_impl; 1285 /* 1286 * If no specific refresh function was given then default to the 1287 * driver's m_unicst entry point. 1288 */ 1289 if (refresh == NULL) { 1290 refresh = mp->m_unicst; 1291 arg = mp->m_driver; 1292 } 1293 ASSERT(refresh != NULL); 1294 1295 /* 1296 * Call the refresh function with the current unicast address. 1297 */ 1298 refresh(arg, mip->mi_addr); 1299 } 1300 1301 void 1302 mac_promisc_refresh(mac_t *mp, mac_promisc_t refresh, void *arg) 1303 { 1304 mac_impl_t *mip = mp->m_impl; 1305 1306 /* 1307 * If no specific refresh function was given then default to the 1308 * driver's m_promisc entry point. 1309 */ 1310 if (refresh == NULL) { 1311 refresh = mp->m_promisc; 1312 arg = mp->m_driver; 1313 } 1314 ASSERT(refresh != NULL); 1315 1316 /* 1317 * Call the refresh function with the current promiscuity. 1318 */ 1319 refresh(arg, (mip->mi_devpromisc != 0)); 1320 } 1321 1322 boolean_t 1323 mac_active_set(mac_handle_t mh) 1324 { 1325 mac_impl_t *mip = (mac_impl_t *)mh; 1326 1327 mutex_enter(&mip->mi_activelink_lock); 1328 if (mip->mi_activelink) { 1329 mutex_exit(&mip->mi_activelink_lock); 1330 return (B_FALSE); 1331 } 1332 mip->mi_activelink = B_TRUE; 1333 mutex_exit(&mip->mi_activelink_lock); 1334 return (B_TRUE); 1335 } 1336 1337 void 1338 mac_active_clear(mac_handle_t mh) 1339 { 1340 mac_impl_t *mip = (mac_impl_t *)mh; 1341 1342 mutex_enter(&mip->mi_activelink_lock); 1343 ASSERT(mip->mi_activelink); 1344 mip->mi_activelink = B_FALSE; 1345 mutex_exit(&mip->mi_activelink_lock); 1346 } 1347