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