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