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