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 #include <sys/modctl.h> 45 #include <sys/atomic.h> 46 47 #define IMPL_HASHSZ 67 /* prime */ 48 49 static kmem_cache_t *i_mac_impl_cachep; 50 static mod_hash_t *i_mac_impl_hash; 51 krwlock_t i_mac_impl_lock; 52 uint_t i_mac_impl_count; 53 54 #define MACTYPE_KMODDIR "mac" 55 #define MACTYPE_HASHSZ 67 56 static mod_hash_t *i_mactype_hash; 57 /* 58 * i_mactype_lock synchronizes threads that obtain references to mactype_t 59 * structures through i_mactype_getplugin(). 60 */ 61 static kmutex_t i_mactype_lock; 62 63 static void i_mac_notify_task(void *); 64 65 /* 66 * Private functions. 67 */ 68 69 /*ARGSUSED*/ 70 static int 71 i_mac_constructor(void *buf, void *arg, int kmflag) 72 { 73 mac_impl_t *mip = buf; 74 75 bzero(buf, sizeof (mac_impl_t)); 76 77 mip->mi_linkstate = LINK_STATE_UNKNOWN; 78 79 rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 80 rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 81 rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 82 rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 83 rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 84 rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 85 mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 86 mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL); 87 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 88 return (0); 89 } 90 91 /*ARGSUSED*/ 92 static void 93 i_mac_destructor(void *buf, void *arg) 94 { 95 mac_impl_t *mip = buf; 96 97 ASSERT(mip->mi_ref == 0); 98 ASSERT(mip->mi_active == 0); 99 ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 100 ASSERT(mip->mi_devpromisc == 0); 101 ASSERT(mip->mi_promisc == 0); 102 ASSERT(mip->mi_mmap == NULL); 103 ASSERT(mip->mi_mnfp == NULL); 104 ASSERT(mip->mi_resource_add == NULL); 105 ASSERT(mip->mi_ksp == NULL); 106 ASSERT(mip->mi_kstat_count == 0); 107 108 rw_destroy(&mip->mi_state_lock); 109 rw_destroy(&mip->mi_data_lock); 110 rw_destroy(&mip->mi_notify_lock); 111 rw_destroy(&mip->mi_rx_lock); 112 rw_destroy(&mip->mi_txloop_lock); 113 rw_destroy(&mip->mi_resource_lock); 114 mutex_destroy(&mip->mi_activelink_lock); 115 mutex_destroy(&mip->mi_notify_ref_lock); 116 cv_destroy(&mip->mi_notify_cv); 117 } 118 119 static void 120 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 121 { 122 mac_notify_task_arg_t *mnta; 123 124 rw_enter(&i_mac_impl_lock, RW_READER); 125 if (mip->mi_disabled) 126 goto exit; 127 128 if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) { 129 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory " 130 "allocation failed", mip->mi_name, type); 131 goto exit; 132 } 133 134 mnta->mnt_mip = mip; 135 mnta->mnt_type = type; 136 137 mutex_enter(&mip->mi_notify_ref_lock); 138 mip->mi_notify_ref++; 139 mutex_exit(&mip->mi_notify_ref_lock); 140 141 rw_exit(&i_mac_impl_lock); 142 143 if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta, 144 TQ_NOSLEEP) == NULL) { 145 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch " 146 "failed", mip->mi_name, type); 147 148 mutex_enter(&mip->mi_notify_ref_lock); 149 if (--mip->mi_notify_ref == 0) 150 cv_signal(&mip->mi_notify_cv); 151 mutex_exit(&mip->mi_notify_ref_lock); 152 153 kmem_free(mnta, sizeof (*mnta)); 154 } 155 return; 156 157 exit: 158 rw_exit(&i_mac_impl_lock); 159 } 160 161 static void 162 i_mac_notify_task(void *notify_arg) 163 { 164 mac_notify_task_arg_t *mnta = (mac_notify_task_arg_t *)notify_arg; 165 mac_impl_t *mip; 166 mac_notify_type_t type; 167 mac_notify_fn_t *mnfp; 168 mac_notify_t notify; 169 void *arg; 170 171 mip = mnta->mnt_mip; 172 type = mnta->mnt_type; 173 kmem_free(mnta, sizeof (*mnta)); 174 175 /* 176 * Walk the list of notifications. 177 */ 178 rw_enter(&mip->mi_notify_lock, RW_READER); 179 for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 180 notify = mnfp->mnf_fn; 181 arg = mnfp->mnf_arg; 182 183 ASSERT(notify != NULL); 184 notify(arg, type); 185 } 186 rw_exit(&mip->mi_notify_lock); 187 mutex_enter(&mip->mi_notify_ref_lock); 188 if (--mip->mi_notify_ref == 0) 189 cv_signal(&mip->mi_notify_cv); 190 mutex_exit(&mip->mi_notify_ref_lock); 191 } 192 193 static mactype_t * 194 i_mactype_getplugin(const char *pname) 195 { 196 mactype_t *mtype = NULL; 197 boolean_t tried_modload = B_FALSE; 198 199 mutex_enter(&i_mactype_lock); 200 201 find_registered_mactype: 202 if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname, 203 (mod_hash_val_t *)&mtype) != 0) { 204 if (!tried_modload) { 205 /* 206 * If the plugin has not yet been loaded, then 207 * attempt to load it now. If modload() succeeds, 208 * the plugin should have registered using 209 * mactype_register(), in which case we can go back 210 * and attempt to find it again. 211 */ 212 if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) { 213 tried_modload = B_TRUE; 214 goto find_registered_mactype; 215 } 216 } 217 } else { 218 /* 219 * Note that there's no danger that the plugin we've loaded 220 * could be unloaded between the modload() step and the 221 * reference count bump here, as we're holding 222 * i_mactype_lock, which mactype_unregister() also holds. 223 */ 224 atomic_inc_32(&mtype->mt_ref); 225 } 226 227 mutex_exit(&i_mactype_lock); 228 return (mtype); 229 } 230 231 /* 232 * Module initialization functions. 233 */ 234 235 void 236 mac_init(void) 237 { 238 i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 239 sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 240 NULL, NULL, NULL, 0); 241 ASSERT(i_mac_impl_cachep != NULL); 242 243 i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 244 IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 245 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 246 rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 247 i_mac_impl_count = 0; 248 249 i_mactype_hash = mod_hash_create_extended("mactype_hash", 250 MACTYPE_HASHSZ, 251 mod_hash_null_keydtor, mod_hash_null_valdtor, 252 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 253 } 254 255 int 256 mac_fini(void) 257 { 258 if (i_mac_impl_count > 0) 259 return (EBUSY); 260 261 mod_hash_destroy_hash(i_mac_impl_hash); 262 rw_destroy(&i_mac_impl_lock); 263 264 kmem_cache_destroy(i_mac_impl_cachep); 265 266 mod_hash_destroy_hash(i_mactype_hash); 267 return (0); 268 } 269 270 /* 271 * Client functions. 272 */ 273 274 int 275 mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp) 276 { 277 char driver[MAXNAMELEN]; 278 uint_t instance; 279 major_t major; 280 dev_info_t *dip; 281 mac_impl_t *mip; 282 int err; 283 284 /* 285 * Check the device name length to make sure it won't overflow our 286 * buffer. 287 */ 288 if (strlen(macname) >= MAXNAMELEN) 289 return (EINVAL); 290 291 /* 292 * Split the device name into driver and instance components. 293 */ 294 if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS) 295 return (EINVAL); 296 297 /* 298 * Get the major number of the driver. 299 */ 300 if ((major = ddi_name_to_major(driver)) == (major_t)-1) 301 return (EINVAL); 302 303 /* 304 * Hold the given instance to prevent it from being detached. 305 * This will also attach the instance if it is not currently attached. 306 * Currently we ensure that mac_register() (called by the driver's 307 * attach entry point) and all code paths under it cannot possibly 308 * call mac_open() because this would lead to a recursive attach 309 * panic. 310 */ 311 if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL) 312 return (EINVAL); 313 314 /* 315 * Look up its entry in the global hash table. 316 */ 317 again: 318 rw_enter(&i_mac_impl_lock, RW_WRITER); 319 err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 320 (mod_hash_val_t *)&mip); 321 if (err != 0) { 322 err = ENOENT; 323 goto failed; 324 } 325 326 if (mip->mi_disabled) { 327 rw_exit(&i_mac_impl_lock); 328 goto again; 329 } 330 331 mip->mi_ref++; 332 rw_exit(&i_mac_impl_lock); 333 334 *mhp = (mac_handle_t)mip; 335 return (0); 336 337 failed: 338 rw_exit(&i_mac_impl_lock); 339 ddi_release_devi(dip); 340 return (err); 341 } 342 343 void 344 mac_close(mac_handle_t mh) 345 { 346 mac_impl_t *mip = (mac_impl_t *)mh; 347 dev_info_t *dip = mip->mi_dip; 348 349 rw_enter(&i_mac_impl_lock, RW_WRITER); 350 351 ASSERT(mip->mi_ref != 0); 352 if (--mip->mi_ref == 0) { 353 ASSERT(!mip->mi_activelink); 354 } 355 ddi_release_devi(dip); 356 rw_exit(&i_mac_impl_lock); 357 } 358 359 const mac_info_t * 360 mac_info(mac_handle_t mh) 361 { 362 return (&((mac_impl_t *)mh)->mi_info); 363 } 364 365 dev_info_t * 366 mac_devinfo_get(mac_handle_t mh) 367 { 368 return (((mac_impl_t *)mh)->mi_dip); 369 } 370 371 uint64_t 372 mac_stat_get(mac_handle_t mh, uint_t stat) 373 { 374 mac_impl_t *mip = (mac_impl_t *)mh; 375 uint64_t val; 376 int ret; 377 378 /* 379 * The range of stat determines where it is maintained. Stat 380 * values from 0 up to (but not including) MAC_STAT_MIN are 381 * mainteined by the mac module itself. Everything else is 382 * maintained by the driver. 383 */ 384 if (stat < MAC_STAT_MIN) { 385 /* These stats are maintained by the mac module itself. */ 386 switch (stat) { 387 case MAC_STAT_LINK_STATE: 388 return (mip->mi_linkstate); 389 case MAC_STAT_LINK_UP: 390 return (mip->mi_linkstate == LINK_STATE_UP); 391 case MAC_STAT_PROMISC: 392 return (mip->mi_devpromisc != 0); 393 default: 394 ASSERT(B_FALSE); 395 } 396 } 397 398 /* 399 * Call the driver to get the given statistic. 400 */ 401 ret = mip->mi_getstat(mip->mi_driver, stat, &val); 402 if (ret != 0) { 403 /* 404 * The driver doesn't support this statistic. Get the 405 * statistic's default value. 406 */ 407 val = mac_stat_default(mip, stat); 408 } 409 return (val); 410 } 411 412 int 413 mac_start(mac_handle_t mh) 414 { 415 mac_impl_t *mip = (mac_impl_t *)mh; 416 int err; 417 418 ASSERT(mip->mi_start != NULL); 419 420 rw_enter(&(mip->mi_state_lock), RW_WRITER); 421 422 /* 423 * Check whether the device is already started. 424 */ 425 if (mip->mi_active++ != 0) { 426 /* 427 * It's already started so there's nothing more to do. 428 */ 429 err = 0; 430 goto done; 431 } 432 433 /* 434 * Start the device. 435 */ 436 if ((err = mip->mi_start(mip->mi_driver)) != 0) 437 --mip->mi_active; 438 439 done: 440 rw_exit(&(mip->mi_state_lock)); 441 return (err); 442 } 443 444 void 445 mac_stop(mac_handle_t mh) 446 { 447 mac_impl_t *mip = (mac_impl_t *)mh; 448 449 ASSERT(mip->mi_stop != NULL); 450 451 rw_enter(&(mip->mi_state_lock), RW_WRITER); 452 453 /* 454 * Check whether the device is still needed. 455 */ 456 ASSERT(mip->mi_active != 0); 457 if (--mip->mi_active != 0) { 458 /* 459 * It's still needed so there's nothing more to do. 460 */ 461 goto done; 462 } 463 464 /* 465 * Stop the device. 466 */ 467 mip->mi_stop(mip->mi_driver); 468 469 done: 470 rw_exit(&(mip->mi_state_lock)); 471 } 472 473 int 474 mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 475 { 476 mac_impl_t *mip = (mac_impl_t *)mh; 477 mac_multicst_addr_t **pp; 478 mac_multicst_addr_t *p; 479 int err; 480 481 ASSERT(mip->mi_multicst != NULL); 482 483 /* 484 * Verify the address. 485 */ 486 if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 487 mip->mi_pdata)) != 0) { 488 return (err); 489 } 490 491 /* 492 * Check whether the given address is already enabled. 493 */ 494 rw_enter(&(mip->mi_data_lock), RW_WRITER); 495 for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 496 if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 497 0) { 498 /* 499 * The address is already enabled so just bump the 500 * reference count. 501 */ 502 p->mma_ref++; 503 err = 0; 504 goto done; 505 } 506 } 507 508 /* 509 * Allocate a new list entry. 510 */ 511 if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 512 KM_NOSLEEP)) == NULL) { 513 err = ENOMEM; 514 goto done; 515 } 516 517 /* 518 * Enable a new multicast address. 519 */ 520 if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 521 kmem_free(p, sizeof (mac_multicst_addr_t)); 522 goto done; 523 } 524 525 /* 526 * Add the address to the list of enabled addresses. 527 */ 528 bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 529 p->mma_ref++; 530 *pp = p; 531 532 done: 533 rw_exit(&(mip->mi_data_lock)); 534 return (err); 535 } 536 537 int 538 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 539 { 540 mac_impl_t *mip = (mac_impl_t *)mh; 541 mac_multicst_addr_t **pp; 542 mac_multicst_addr_t *p; 543 int err; 544 545 ASSERT(mip->mi_multicst != NULL); 546 547 /* 548 * Find the entry in the list for the given address. 549 */ 550 rw_enter(&(mip->mi_data_lock), RW_WRITER); 551 for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 552 if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 553 0) { 554 if (--p->mma_ref == 0) 555 break; 556 557 /* 558 * There is still a reference to this address so 559 * there's nothing more to do. 560 */ 561 err = 0; 562 goto done; 563 } 564 } 565 566 /* 567 * We did not find an entry for the given address so it is not 568 * currently enabled. 569 */ 570 if (p == NULL) { 571 err = ENOENT; 572 goto done; 573 } 574 ASSERT(p->mma_ref == 0); 575 576 /* 577 * Disable the multicast address. 578 */ 579 if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 580 p->mma_ref++; 581 goto done; 582 } 583 584 /* 585 * Remove it from the list. 586 */ 587 *pp = p->mma_nextp; 588 kmem_free(p, sizeof (mac_multicst_addr_t)); 589 590 done: 591 rw_exit(&(mip->mi_data_lock)); 592 return (err); 593 } 594 595 /* 596 * mac_unicst_verify: Verifies the passed address. It fails 597 * if the passed address is a group address or has incorrect length. 598 */ 599 boolean_t 600 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 601 { 602 mac_impl_t *mip = (mac_impl_t *)mh; 603 604 /* 605 * Verify the address. 606 */ 607 if ((len != mip->mi_type->mt_addr_length) || 608 (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 609 mip->mi_pdata)) != 0) { 610 return (B_FALSE); 611 } else { 612 return (B_TRUE); 613 } 614 } 615 616 int 617 mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 618 { 619 mac_impl_t *mip = (mac_impl_t *)mh; 620 int err; 621 boolean_t notify = B_FALSE; 622 623 ASSERT(mip->mi_unicst != NULL); 624 625 /* 626 * Verify the address. 627 */ 628 if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 629 mip->mi_pdata)) != 0) { 630 return (err); 631 } 632 633 /* 634 * Program the new unicast address. 635 */ 636 rw_enter(&(mip->mi_data_lock), RW_WRITER); 637 638 /* 639 * If address doesn't change, do nothing. 640 * This check is necessary otherwise it may call into mac_unicst_set 641 * recursively. 642 */ 643 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 644 err = 0; 645 goto done; 646 } 647 648 if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 649 goto done; 650 651 /* 652 * Save the address and flag that we need to send a notification. 653 */ 654 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 655 notify = B_TRUE; 656 657 done: 658 rw_exit(&(mip->mi_data_lock)); 659 660 if (notify) 661 i_mac_notify(mip, MAC_NOTE_UNICST); 662 663 return (err); 664 } 665 666 void 667 mac_unicst_get(mac_handle_t mh, uint8_t *addr) 668 { 669 mac_impl_t *mip = (mac_impl_t *)mh; 670 671 /* 672 * Copy out the current unicast source address. 673 */ 674 rw_enter(&(mip->mi_data_lock), RW_READER); 675 bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 676 rw_exit(&(mip->mi_data_lock)); 677 } 678 679 void 680 mac_dest_get(mac_handle_t mh, uint8_t *addr) 681 { 682 mac_impl_t *mip = (mac_impl_t *)mh; 683 684 /* 685 * Copy out the current destination address. 686 */ 687 rw_enter(&(mip->mi_data_lock), RW_READER); 688 bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 689 rw_exit(&(mip->mi_data_lock)); 690 } 691 692 int 693 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 694 { 695 mac_impl_t *mip = (mac_impl_t *)mh; 696 int err = 0; 697 698 ASSERT(mip->mi_setpromisc != NULL); 699 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 700 701 /* 702 * Determine whether we should enable or disable promiscuous mode. 703 * For details on the distinction between "device promiscuous mode" 704 * and "MAC promiscuous mode", see PSARC/2005/289. 705 */ 706 rw_enter(&(mip->mi_data_lock), RW_WRITER); 707 if (on) { 708 /* 709 * Enable promiscuous mode on the device if not yet enabled. 710 */ 711 if (mip->mi_devpromisc++ == 0) { 712 err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 713 if (err != 0) { 714 mip->mi_devpromisc--; 715 goto done; 716 } 717 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 718 } 719 720 /* 721 * Enable promiscuous mode on the MAC if not yet enabled. 722 */ 723 if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 724 i_mac_notify(mip, MAC_NOTE_PROMISC); 725 } else { 726 if (mip->mi_devpromisc == 0) { 727 err = EPROTO; 728 goto done; 729 } 730 731 /* 732 * Disable promiscuous mode on the device if this is the last 733 * enabling. 734 */ 735 if (--mip->mi_devpromisc == 0) { 736 err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 737 if (err != 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 778 /* 779 * If the driver supports resource registration, call the driver to 780 * ask it to register its resources. 781 */ 782 if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 783 mip->mi_resources(mip->mi_driver); 784 } 785 786 void 787 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 788 { 789 mac_impl_t *mip = (mac_impl_t *)mh; 790 791 /* 792 * Call the driver to handle the ioctl. The driver may not support 793 * any ioctls, in which case we reply with a NAK on its behalf. 794 */ 795 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 796 mip->mi_ioctl(mip->mi_driver, wq, bp); 797 else 798 miocnak(wq, bp, 0, EINVAL); 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 rw_exit(&mip->mi_txloop_lock); 828 return (mtp); 829 } 830 831 link_state_t 832 mac_link_get(mac_handle_t mh) 833 { 834 return (((mac_impl_t *)mh)->mi_linkstate); 835 } 836 837 mac_notify_handle_t 838 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 839 { 840 mac_impl_t *mip = (mac_impl_t *)mh; 841 mac_notify_fn_t *mnfp; 842 843 mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 844 mnfp->mnf_fn = notify; 845 mnfp->mnf_arg = arg; 846 847 /* 848 * Add it to the head of the 'notify' callback list. 849 */ 850 rw_enter(&mip->mi_notify_lock, RW_WRITER); 851 mnfp->mnf_nextp = mip->mi_mnfp; 852 mip->mi_mnfp = mnfp; 853 rw_exit(&mip->mi_notify_lock); 854 855 return ((mac_notify_handle_t)mnfp); 856 } 857 858 void 859 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 860 { 861 mac_impl_t *mip = (mac_impl_t *)mh; 862 mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 863 mac_notify_fn_t **pp; 864 mac_notify_fn_t *p; 865 866 /* 867 * Search the 'notify' callback list for the function closure. 868 */ 869 rw_enter(&mip->mi_notify_lock, RW_WRITER); 870 for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 871 pp = &(p->mnf_nextp)) { 872 if (p == mnfp) 873 break; 874 } 875 ASSERT(p != NULL); 876 877 /* 878 * Remove it from the list. 879 */ 880 *pp = p->mnf_nextp; 881 rw_exit(&mip->mi_notify_lock); 882 883 /* 884 * Free it. 885 */ 886 kmem_free(mnfp, sizeof (mac_notify_fn_t)); 887 } 888 889 void 890 mac_notify(mac_handle_t mh) 891 { 892 mac_impl_t *mip = (mac_impl_t *)mh; 893 mac_notify_type_t type; 894 895 for (type = 0; type < MAC_NNOTE; type++) 896 i_mac_notify(mip, type); 897 } 898 899 mac_rx_handle_t 900 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 901 { 902 mac_impl_t *mip = (mac_impl_t *)mh; 903 mac_rx_fn_t *mrfp; 904 905 mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 906 mrfp->mrf_fn = rx; 907 mrfp->mrf_arg = arg; 908 909 /* 910 * Add it to the head of the 'rx' callback list. 911 */ 912 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 913 mrfp->mrf_nextp = mip->mi_mrfp; 914 mip->mi_mrfp = mrfp; 915 rw_exit(&(mip->mi_rx_lock)); 916 917 return ((mac_rx_handle_t)mrfp); 918 } 919 920 /* 921 * Unregister a receive function for this mac. This removes the function 922 * from the list of receive functions for this mac. 923 */ 924 void 925 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 926 { 927 mac_impl_t *mip = (mac_impl_t *)mh; 928 mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 929 mac_rx_fn_t **pp; 930 mac_rx_fn_t *p; 931 932 /* 933 * Search the 'rx' callback list for the function closure. 934 */ 935 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 936 for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 937 if (p == mrfp) 938 break; 939 } 940 ASSERT(p != NULL); 941 942 /* Remove it from the list. */ 943 *pp = p->mrf_nextp; 944 kmem_free(mrfp, sizeof (mac_rx_fn_t)); 945 rw_exit(&(mip->mi_rx_lock)); 946 } 947 948 mac_txloop_handle_t 949 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 950 { 951 mac_impl_t *mip = (mac_impl_t *)mh; 952 mac_txloop_fn_t *mtfp; 953 954 mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 955 mtfp->mtf_fn = tx; 956 mtfp->mtf_arg = arg; 957 958 /* 959 * Add it to the head of the 'tx' callback list. 960 */ 961 rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 962 mtfp->mtf_nextp = mip->mi_mtfp; 963 mip->mi_mtfp = mtfp; 964 rw_exit(&(mip->mi_txloop_lock)); 965 966 return ((mac_txloop_handle_t)mtfp); 967 } 968 969 /* 970 * Unregister a transmit function for this mac. This removes the function 971 * from the list of transmit functions for this mac. 972 */ 973 void 974 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 975 { 976 mac_impl_t *mip = (mac_impl_t *)mh; 977 mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 978 mac_txloop_fn_t **pp; 979 mac_txloop_fn_t *p; 980 981 /* 982 * Search the 'tx' callback list for the function. 983 */ 984 rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 985 for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 986 if (p == mtfp) 987 break; 988 } 989 ASSERT(p != NULL); 990 991 /* Remove it from the list. */ 992 *pp = p->mtf_nextp; 993 kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 994 rw_exit(&(mip->mi_txloop_lock)); 995 } 996 997 void 998 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 999 { 1000 mac_impl_t *mip = (mac_impl_t *)mh; 1001 1002 /* 1003 * Update the 'resource_add' callbacks. 1004 */ 1005 rw_enter(&(mip->mi_resource_lock), RW_WRITER); 1006 mip->mi_resource_add = add; 1007 mip->mi_resource_add_arg = arg; 1008 rw_exit(&(mip->mi_resource_lock)); 1009 } 1010 1011 /* 1012 * Driver support functions. 1013 */ 1014 1015 mac_register_t * 1016 mac_alloc(uint_t mac_version) 1017 { 1018 mac_register_t *mregp; 1019 1020 /* 1021 * Make sure there isn't a version mismatch between the driver and 1022 * the framework. In the future, if multiple versions are 1023 * supported, this check could become more sophisticated. 1024 */ 1025 if (mac_version != MAC_VERSION) 1026 return (NULL); 1027 1028 mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 1029 mregp->m_version = mac_version; 1030 return (mregp); 1031 } 1032 1033 void 1034 mac_free(mac_register_t *mregp) 1035 { 1036 kmem_free(mregp, sizeof (mac_register_t)); 1037 } 1038 1039 /* 1040 * mac_register() is how drivers register new MACs with the GLDv3 1041 * framework. The mregp argument is allocated by drivers using the 1042 * mac_alloc() function, and can be freed using mac_free() immediately upon 1043 * return from mac_register(). Upon success (0 return value), the mhp 1044 * opaque pointer becomes the driver's handle to its MAC interface, and is 1045 * the argument to all other mac module entry points. 1046 */ 1047 int 1048 mac_register(mac_register_t *mregp, mac_handle_t *mhp) 1049 { 1050 mac_impl_t *mip; 1051 mactype_t *mtype; 1052 int err; 1053 struct devnames *dnp; 1054 minor_t minor; 1055 mod_hash_val_t val; 1056 boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 1057 1058 /* Find the required MAC-Type plugin. */ 1059 if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 1060 return (EINVAL); 1061 1062 /* Create a mac_impl_t to represent this MAC. */ 1063 mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 1064 1065 /* 1066 * The mac is not ready for open yet. 1067 */ 1068 mip->mi_disabled = B_TRUE; 1069 1070 mip->mi_drvname = ddi_driver_name(mregp->m_dip); 1071 /* 1072 * Some drivers such as aggr need to register multiple MACs. Such 1073 * drivers must supply a non-zero "instance" argument so that each 1074 * MAC can be assigned a unique MAC name and can have unique 1075 * kstats. 1076 */ 1077 mip->mi_instance = ((mregp->m_instance == 0) ? 1078 ddi_get_instance(mregp->m_dip) : mregp->m_instance); 1079 1080 /* Construct the MAC name as <drvname><instance> */ 1081 (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 1082 mip->mi_drvname, mip->mi_instance); 1083 1084 rw_enter(&i_mac_impl_lock, RW_WRITER); 1085 if (mod_hash_insert(i_mac_impl_hash, 1086 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 1087 kmem_cache_free(i_mac_impl_cachep, mip); 1088 rw_exit(&i_mac_impl_lock); 1089 return (EEXIST); 1090 } 1091 atomic_inc_32(&i_mac_impl_count); 1092 1093 mip->mi_driver = mregp->m_driver; 1094 1095 mip->mi_type = mtype; 1096 mip->mi_info.mi_media = mtype->mt_type; 1097 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 1098 mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 1099 if (mregp->m_max_sdu <= mregp->m_min_sdu) { 1100 err = EINVAL; 1101 goto fail; 1102 } 1103 mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 1104 mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 1105 /* 1106 * If the media supports a broadcast address, cache a pointer to it 1107 * in the mac_info_t so that upper layers can use it. 1108 */ 1109 mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1110 1111 /* 1112 * Copy the unicast source address into the mac_info_t, but only if 1113 * the MAC-Type defines a non-zero address length. We need to 1114 * handle MAC-Types that have an address length of 0 1115 * (point-to-point protocol MACs for example). 1116 */ 1117 if (mip->mi_type->mt_addr_length > 0) { 1118 if (mregp->m_src_addr == NULL) { 1119 err = EINVAL; 1120 goto fail; 1121 } 1122 mip->mi_info.mi_unicst_addr = 1123 kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 1124 bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 1125 mip->mi_type->mt_addr_length); 1126 1127 /* 1128 * Copy the fixed 'factory' MAC address from the immutable 1129 * info. This is taken to be the MAC address currently in 1130 * use. 1131 */ 1132 bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 1133 mip->mi_type->mt_addr_length); 1134 /* Copy the destination address if one is provided. */ 1135 if (mregp->m_dst_addr != NULL) { 1136 bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 1137 mip->mi_type->mt_addr_length); 1138 } 1139 } else if (mregp->m_src_addr != NULL) { 1140 err = EINVAL; 1141 goto fail; 1142 } 1143 1144 /* 1145 * The format of the m_pdata is specific to the plugin. It is 1146 * passed in as an argument to all of the plugin callbacks. The 1147 * driver can update this information by calling 1148 * mac_pdata_update(). 1149 */ 1150 if (mregp->m_pdata != NULL) { 1151 /* 1152 * Verify that the plugin supports MAC plugin data and that 1153 * the supplied data is valid. 1154 */ 1155 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 1156 err = EINVAL; 1157 goto fail; 1158 } 1159 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 1160 mregp->m_pdata_size)) { 1161 err = EINVAL; 1162 goto fail; 1163 } 1164 mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 1165 bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 1166 mip->mi_pdata_size = mregp->m_pdata_size; 1167 } 1168 1169 /* 1170 * Stash the driver callbacks into the mac_impl_t, but first sanity 1171 * check to make sure all mandatory callbacks are set. 1172 */ 1173 if (mregp->m_callbacks->mc_getstat == NULL || 1174 mregp->m_callbacks->mc_start == NULL || 1175 mregp->m_callbacks->mc_stop == NULL || 1176 mregp->m_callbacks->mc_setpromisc == NULL || 1177 mregp->m_callbacks->mc_multicst == NULL || 1178 mregp->m_callbacks->mc_unicst == NULL || 1179 mregp->m_callbacks->mc_tx == NULL) { 1180 err = EINVAL; 1181 goto fail; 1182 } 1183 mip->mi_callbacks = mregp->m_callbacks; 1184 1185 mip->mi_dip = mregp->m_dip; 1186 1187 /* 1188 * Set up the two possible transmit routines. 1189 */ 1190 mip->mi_txinfo.mt_fn = mip->mi_tx; 1191 mip->mi_txinfo.mt_arg = mip->mi_driver; 1192 mip->mi_txloopinfo.mt_fn = mac_txloop; 1193 mip->mi_txloopinfo.mt_arg = mip; 1194 1195 /* 1196 * Initialize the kstats for this device. 1197 */ 1198 mac_stat_create(mip); 1199 1200 err = EEXIST; 1201 /* Create a style-2 DLPI device */ 1202 if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 1203 S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 1204 goto fail; 1205 style2_created = B_TRUE; 1206 1207 /* Create a style-1 DLPI device */ 1208 minor = (minor_t)mip->mi_instance + 1; 1209 if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 1210 DDI_NT_NET, 0) != DDI_SUCCESS) 1211 goto fail; 1212 style1_created = B_TRUE; 1213 1214 /* 1215 * Create a link for this MAC. The link name will be the same as 1216 * the MAC name. 1217 */ 1218 err = dls_create(mip->mi_name, mip->mi_name, 1219 ddi_get_instance(mip->mi_dip)); 1220 if (err != 0) 1221 goto fail; 1222 1223 /* set the gldv3 flag in dn_flags */ 1224 dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 1225 LOCK_DEV_OPS(&dnp->dn_lock); 1226 dnp->dn_flags |= DN_GLDV3_DRIVER; 1227 UNLOCK_DEV_OPS(&dnp->dn_lock); 1228 1229 /* 1230 * Mark the MAC to be ready for open. 1231 */ 1232 mip->mi_disabled = B_FALSE; 1233 1234 cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 1235 rw_exit(&i_mac_impl_lock); 1236 *mhp = (mac_handle_t)mip; 1237 return (0); 1238 1239 fail: 1240 (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1241 &val); 1242 ASSERT(mip == (mac_impl_t *)val); 1243 atomic_dec_32(&i_mac_impl_count); 1244 1245 if (mip->mi_info.mi_unicst_addr != NULL) { 1246 kmem_free(mip->mi_info.mi_unicst_addr, 1247 mip->mi_type->mt_addr_length); 1248 mip->mi_info.mi_unicst_addr = NULL; 1249 } 1250 if (style1_created) 1251 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1252 if (style2_created) 1253 ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1254 1255 mac_stat_destroy(mip); 1256 1257 if (mip->mi_type != NULL) { 1258 atomic_dec_32(&mip->mi_type->mt_ref); 1259 mip->mi_type = NULL; 1260 } 1261 1262 if (mip->mi_pdata != NULL) { 1263 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1264 mip->mi_pdata = NULL; 1265 mip->mi_pdata_size = 0; 1266 } 1267 1268 kmem_cache_free(i_mac_impl_cachep, mip); 1269 rw_exit(&i_mac_impl_lock); 1270 return (err); 1271 } 1272 1273 int 1274 mac_unregister(mac_handle_t mh) 1275 { 1276 int err; 1277 mac_impl_t *mip = (mac_impl_t *)mh; 1278 mod_hash_val_t val; 1279 mac_multicst_addr_t *p, *nextp; 1280 1281 /* 1282 * See if there are any other references to this mac_t (e.g., VLAN's). 1283 * If not, set mi_disabled to prevent any new VLAN's from being 1284 * created while we're destroying this mac. 1285 */ 1286 rw_enter(&i_mac_impl_lock, RW_WRITER); 1287 if (mip->mi_ref > 0) { 1288 rw_exit(&i_mac_impl_lock); 1289 return (EBUSY); 1290 } 1291 mip->mi_disabled = B_TRUE; 1292 rw_exit(&i_mac_impl_lock); 1293 1294 /* 1295 * Wait for all taskqs which process the mac notifications to finish. 1296 */ 1297 mutex_enter(&mip->mi_notify_ref_lock); 1298 while (mip->mi_notify_ref != 0) 1299 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 1300 mutex_exit(&mip->mi_notify_ref_lock); 1301 1302 if ((err = dls_destroy(mip->mi_name)) != 0) { 1303 rw_enter(&i_mac_impl_lock, RW_WRITER); 1304 mip->mi_disabled = B_FALSE; 1305 rw_exit(&i_mac_impl_lock); 1306 return (err); 1307 } 1308 1309 /* 1310 * Remove both style 1 and style 2 minor nodes 1311 */ 1312 ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1313 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1314 1315 ASSERT(!mip->mi_activelink); 1316 1317 mac_stat_destroy(mip); 1318 1319 (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1320 &val); 1321 ASSERT(mip == (mac_impl_t *)val); 1322 1323 ASSERT(i_mac_impl_count > 0); 1324 atomic_dec_32(&i_mac_impl_count); 1325 1326 if (mip->mi_pdata != NULL) 1327 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1328 mip->mi_pdata = NULL; 1329 mip->mi_pdata_size = 0; 1330 1331 /* 1332 * Free the list of multicast addresses. 1333 */ 1334 for (p = mip->mi_mmap; p != NULL; p = nextp) { 1335 nextp = p->mma_nextp; 1336 kmem_free(p, sizeof (mac_multicst_addr_t)); 1337 } 1338 mip->mi_mmap = NULL; 1339 1340 mip->mi_linkstate = LINK_STATE_UNKNOWN; 1341 kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 1342 mip->mi_info.mi_unicst_addr = NULL; 1343 1344 atomic_dec_32(&mip->mi_type->mt_ref); 1345 mip->mi_type = NULL; 1346 1347 cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 1348 1349 kmem_cache_free(i_mac_impl_cachep, mip); 1350 1351 return (0); 1352 } 1353 1354 void 1355 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 1356 { 1357 mac_impl_t *mip = (mac_impl_t *)mh; 1358 mac_rx_fn_t *mrfp; 1359 1360 /* 1361 * Call all registered receive functions. 1362 */ 1363 rw_enter(&mip->mi_rx_lock, RW_READER); 1364 mrfp = mip->mi_mrfp; 1365 if (mrfp == NULL) { 1366 /* There are no registered receive functions. */ 1367 freemsgchain(bp); 1368 rw_exit(&mip->mi_rx_lock); 1369 return; 1370 } 1371 do { 1372 mblk_t *recv_bp; 1373 1374 if (mrfp->mrf_nextp != NULL) { 1375 /* XXX Do we bump a counter if copymsgchain() fails? */ 1376 recv_bp = copymsgchain(bp); 1377 } else { 1378 recv_bp = bp; 1379 } 1380 if (recv_bp != NULL) 1381 mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 1382 mrfp = mrfp->mrf_nextp; 1383 } while (mrfp != NULL); 1384 rw_exit(&mip->mi_rx_lock); 1385 } 1386 1387 /* 1388 * Transmit function -- ONLY used when there are registered loopback listeners. 1389 */ 1390 mblk_t * 1391 mac_txloop(void *arg, mblk_t *bp) 1392 { 1393 mac_impl_t *mip = arg; 1394 mac_txloop_fn_t *mtfp; 1395 mblk_t *loop_bp, *resid_bp, *next_bp; 1396 1397 while (bp != NULL) { 1398 next_bp = bp->b_next; 1399 bp->b_next = NULL; 1400 1401 if ((loop_bp = copymsg(bp)) == NULL) 1402 goto noresources; 1403 1404 if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 1405 ASSERT(resid_bp == bp); 1406 freemsg(loop_bp); 1407 goto noresources; 1408 } 1409 1410 rw_enter(&mip->mi_txloop_lock, RW_READER); 1411 mtfp = mip->mi_mtfp; 1412 while (mtfp != NULL && loop_bp != NULL) { 1413 bp = loop_bp; 1414 1415 /* XXX counter bump if copymsg() fails? */ 1416 if (mtfp->mtf_nextp != NULL) 1417 loop_bp = copymsg(bp); 1418 else 1419 loop_bp = NULL; 1420 1421 mtfp->mtf_fn(mtfp->mtf_arg, bp); 1422 mtfp = mtfp->mtf_nextp; 1423 } 1424 rw_exit(&mip->mi_txloop_lock); 1425 1426 /* 1427 * It's possible we've raced with the disabling of promiscuous 1428 * mode, in which case we can discard our copy. 1429 */ 1430 if (loop_bp != NULL) 1431 freemsg(loop_bp); 1432 1433 bp = next_bp; 1434 } 1435 1436 return (NULL); 1437 1438 noresources: 1439 bp->b_next = next_bp; 1440 return (bp); 1441 } 1442 1443 void 1444 mac_link_update(mac_handle_t mh, link_state_t link) 1445 { 1446 mac_impl_t *mip = (mac_impl_t *)mh; 1447 1448 /* 1449 * Save the link state. 1450 */ 1451 mip->mi_linkstate = link; 1452 1453 /* 1454 * Send a MAC_NOTE_LINK notification. 1455 */ 1456 i_mac_notify(mip, MAC_NOTE_LINK); 1457 } 1458 1459 void 1460 mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 1461 { 1462 mac_impl_t *mip = (mac_impl_t *)mh; 1463 1464 if (mip->mi_type->mt_addr_length == 0) 1465 return; 1466 1467 /* 1468 * Save the address. 1469 */ 1470 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 1471 1472 /* 1473 * Send a MAC_NOTE_UNICST notification. 1474 */ 1475 i_mac_notify(mip, MAC_NOTE_UNICST); 1476 } 1477 1478 void 1479 mac_tx_update(mac_handle_t mh) 1480 { 1481 /* 1482 * Send a MAC_NOTE_TX notification. 1483 */ 1484 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 1485 } 1486 1487 void 1488 mac_resource_update(mac_handle_t mh) 1489 { 1490 /* 1491 * Send a MAC_NOTE_RESOURCE notification. 1492 */ 1493 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 1494 } 1495 1496 mac_resource_handle_t 1497 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 1498 { 1499 mac_impl_t *mip = (mac_impl_t *)mh; 1500 mac_resource_handle_t mrh; 1501 mac_resource_add_t add; 1502 void *arg; 1503 1504 rw_enter(&mip->mi_resource_lock, RW_READER); 1505 add = mip->mi_resource_add; 1506 arg = mip->mi_resource_add_arg; 1507 1508 if (add != NULL) 1509 mrh = add(arg, mrp); 1510 else 1511 mrh = NULL; 1512 rw_exit(&mip->mi_resource_lock); 1513 1514 return (mrh); 1515 } 1516 1517 int 1518 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 1519 { 1520 mac_impl_t *mip = (mac_impl_t *)mh; 1521 1522 /* 1523 * Verify that the plugin supports MAC plugin data and that the 1524 * supplied data is valid. 1525 */ 1526 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 1527 return (EINVAL); 1528 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 1529 return (EINVAL); 1530 1531 if (mip->mi_pdata != NULL) 1532 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1533 1534 mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 1535 bcopy(mac_pdata, mip->mi_pdata, dsize); 1536 mip->mi_pdata_size = dsize; 1537 1538 /* 1539 * Since the MAC plugin data is used to construct MAC headers that 1540 * were cached in fast-path headers, we need to flush fast-path 1541 * information for links associated with this mac. 1542 */ 1543 i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 1544 return (0); 1545 } 1546 1547 void 1548 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 1549 boolean_t add) 1550 { 1551 mac_impl_t *mip = (mac_impl_t *)mh; 1552 mac_multicst_addr_t *p; 1553 1554 /* 1555 * If no specific refresh function was given then default to the 1556 * driver's m_multicst entry point. 1557 */ 1558 if (refresh == NULL) { 1559 refresh = mip->mi_multicst; 1560 arg = mip->mi_driver; 1561 } 1562 ASSERT(refresh != NULL); 1563 1564 /* 1565 * Walk the multicast address list and call the refresh function for 1566 * each address. 1567 */ 1568 rw_enter(&(mip->mi_data_lock), RW_READER); 1569 for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 1570 refresh(arg, add, p->mma_addr); 1571 rw_exit(&(mip->mi_data_lock)); 1572 } 1573 1574 void 1575 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 1576 { 1577 mac_impl_t *mip = (mac_impl_t *)mh; 1578 /* 1579 * If no specific refresh function was given then default to the 1580 * driver's mi_unicst entry point. 1581 */ 1582 if (refresh == NULL) { 1583 refresh = mip->mi_unicst; 1584 arg = mip->mi_driver; 1585 } 1586 ASSERT(refresh != NULL); 1587 1588 /* 1589 * Call the refresh function with the current unicast address. 1590 */ 1591 refresh(arg, mip->mi_addr); 1592 } 1593 1594 void 1595 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 1596 { 1597 mac_impl_t *mip = (mac_impl_t *)mh; 1598 1599 /* 1600 * If no specific refresh function was given then default to the 1601 * driver's m_promisc entry point. 1602 */ 1603 if (refresh == NULL) { 1604 refresh = mip->mi_setpromisc; 1605 arg = mip->mi_driver; 1606 } 1607 ASSERT(refresh != NULL); 1608 1609 /* 1610 * Call the refresh function with the current promiscuity. 1611 */ 1612 refresh(arg, (mip->mi_devpromisc != 0)); 1613 } 1614 1615 boolean_t 1616 mac_active_set(mac_handle_t mh) 1617 { 1618 mac_impl_t *mip = (mac_impl_t *)mh; 1619 1620 mutex_enter(&mip->mi_activelink_lock); 1621 if (mip->mi_activelink) { 1622 mutex_exit(&mip->mi_activelink_lock); 1623 return (B_FALSE); 1624 } 1625 mip->mi_activelink = B_TRUE; 1626 mutex_exit(&mip->mi_activelink_lock); 1627 return (B_TRUE); 1628 } 1629 1630 void 1631 mac_active_clear(mac_handle_t mh) 1632 { 1633 mac_impl_t *mip = (mac_impl_t *)mh; 1634 1635 mutex_enter(&mip->mi_activelink_lock); 1636 ASSERT(mip->mi_activelink); 1637 mip->mi_activelink = B_FALSE; 1638 mutex_exit(&mip->mi_activelink_lock); 1639 } 1640 1641 /* 1642 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1643 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1644 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1645 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1646 * cannot disappear while we are accessing it. 1647 */ 1648 typedef struct i_mac_info_state_s { 1649 const char *mi_name; 1650 mac_info_t *mi_infop; 1651 } i_mac_info_state_t; 1652 1653 /*ARGSUSED*/ 1654 static uint_t 1655 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1656 { 1657 i_mac_info_state_t *statep = arg; 1658 mac_impl_t *mip = (mac_impl_t *)val; 1659 1660 if (mip->mi_disabled) 1661 return (MH_WALK_CONTINUE); 1662 1663 if (strcmp(statep->mi_name, 1664 ddi_driver_name(mip->mi_dip)) != 0) 1665 return (MH_WALK_CONTINUE); 1666 1667 statep->mi_infop = &mip->mi_info; 1668 return (MH_WALK_TERMINATE); 1669 } 1670 1671 boolean_t 1672 mac_info_get(const char *name, mac_info_t *minfop) 1673 { 1674 i_mac_info_state_t state; 1675 1676 rw_enter(&i_mac_impl_lock, RW_READER); 1677 state.mi_name = name; 1678 state.mi_infop = NULL; 1679 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1680 if (state.mi_infop == NULL) { 1681 rw_exit(&i_mac_impl_lock); 1682 return (B_FALSE); 1683 } 1684 *minfop = *state.mi_infop; 1685 rw_exit(&i_mac_impl_lock); 1686 return (B_TRUE); 1687 } 1688 1689 boolean_t 1690 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 1691 { 1692 mac_impl_t *mip = (mac_impl_t *)mh; 1693 1694 if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 1695 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 1696 else 1697 return (B_FALSE); 1698 } 1699 1700 boolean_t 1701 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 1702 { 1703 mac_impl_t *mip = (mac_impl_t *)mh; 1704 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 1705 mip->mi_pdata)); 1706 } 1707 1708 mblk_t * 1709 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 1710 size_t extra_len) 1711 { 1712 mac_impl_t *mip = (mac_impl_t *)mh; 1713 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 1714 mip->mi_pdata, payload, extra_len)); 1715 } 1716 1717 int 1718 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 1719 { 1720 mac_impl_t *mip = (mac_impl_t *)mh; 1721 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 1722 mhip)); 1723 } 1724 1725 mblk_t * 1726 mac_header_cook(mac_handle_t mh, mblk_t *mp) 1727 { 1728 mac_impl_t *mip = (mac_impl_t *)mh; 1729 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 1730 if (DB_REF(mp) > 1) { 1731 mblk_t *newmp = copymsg(mp); 1732 if (newmp == NULL) 1733 return (NULL); 1734 freemsg(mp); 1735 mp = newmp; 1736 } 1737 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 1738 mip->mi_pdata)); 1739 } 1740 return (mp); 1741 } 1742 1743 mblk_t * 1744 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 1745 { 1746 mac_impl_t *mip = (mac_impl_t *)mh; 1747 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 1748 if (DB_REF(mp) > 1) { 1749 mblk_t *newmp = copymsg(mp); 1750 if (newmp == NULL) 1751 return (NULL); 1752 freemsg(mp); 1753 mp = newmp; 1754 } 1755 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 1756 mip->mi_pdata)); 1757 } 1758 return (mp); 1759 } 1760 1761 void 1762 mac_init_ops(struct dev_ops *ops, const char *name) 1763 { 1764 dld_init_ops(ops, name); 1765 } 1766 1767 void 1768 mac_fini_ops(struct dev_ops *ops) 1769 { 1770 dld_fini_ops(ops); 1771 } 1772 1773 /* 1774 * MAC Type Plugin functions. 1775 */ 1776 1777 mactype_register_t * 1778 mactype_alloc(uint_t mactype_version) 1779 { 1780 mactype_register_t *mtrp; 1781 1782 /* 1783 * Make sure there isn't a version mismatch between the plugin and 1784 * the framework. In the future, if multiple versions are 1785 * supported, this check could become more sophisticated. 1786 */ 1787 if (mactype_version != MACTYPE_VERSION) 1788 return (NULL); 1789 1790 mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 1791 mtrp->mtr_version = mactype_version; 1792 return (mtrp); 1793 } 1794 1795 void 1796 mactype_free(mactype_register_t *mtrp) 1797 { 1798 kmem_free(mtrp, sizeof (mactype_register_t)); 1799 } 1800 1801 int 1802 mactype_register(mactype_register_t *mtrp) 1803 { 1804 mactype_t *mtp; 1805 mactype_ops_t *ops = mtrp->mtr_ops; 1806 1807 /* Do some sanity checking before we register this MAC type. */ 1808 if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 1809 return (EINVAL); 1810 1811 /* 1812 * Verify that all mandatory callbacks are set in the ops 1813 * vector. 1814 */ 1815 if (ops->mtops_unicst_verify == NULL || 1816 ops->mtops_multicst_verify == NULL || 1817 ops->mtops_sap_verify == NULL || 1818 ops->mtops_header == NULL || 1819 ops->mtops_header_info == NULL) { 1820 return (EINVAL); 1821 } 1822 1823 mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 1824 mtp->mt_ident = mtrp->mtr_ident; 1825 mtp->mt_ops = *ops; 1826 mtp->mt_type = mtrp->mtr_mactype; 1827 mtp->mt_nativetype = mtrp->mtr_nativetype; 1828 mtp->mt_addr_length = mtrp->mtr_addrlen; 1829 if (mtrp->mtr_brdcst_addr != NULL) { 1830 mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 1831 bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 1832 mtrp->mtr_addrlen); 1833 } 1834 1835 mtp->mt_stats = mtrp->mtr_stats; 1836 mtp->mt_statcount = mtrp->mtr_statcount; 1837 1838 if (mod_hash_insert(i_mactype_hash, 1839 (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 1840 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1841 kmem_free(mtp, sizeof (*mtp)); 1842 return (EEXIST); 1843 } 1844 return (0); 1845 } 1846 1847 int 1848 mactype_unregister(const char *ident) 1849 { 1850 mactype_t *mtp; 1851 mod_hash_val_t val; 1852 int err; 1853 1854 /* 1855 * Let's not allow MAC drivers to use this plugin while we're 1856 * trying to unregister it. Holding i_mactype_lock also prevents a 1857 * plugin from unregistering while a MAC driver is attempting to 1858 * hold a reference to it in i_mactype_getplugin(). 1859 */ 1860 mutex_enter(&i_mactype_lock); 1861 1862 if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 1863 (mod_hash_val_t *)&mtp)) != 0) { 1864 /* A plugin is trying to unregister, but it never registered. */ 1865 err = ENXIO; 1866 goto done; 1867 } 1868 1869 if (mtp->mt_ref != 0) { 1870 err = EBUSY; 1871 goto done; 1872 } 1873 1874 err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 1875 ASSERT(err == 0); 1876 if (err != 0) { 1877 /* This should never happen, thus the ASSERT() above. */ 1878 err = EINVAL; 1879 goto done; 1880 } 1881 ASSERT(mtp == (mactype_t *)val); 1882 1883 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1884 kmem_free(mtp, sizeof (mactype_t)); 1885 done: 1886 mutex_exit(&i_mactype_lock); 1887 return (err); 1888 } 1889