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