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 int 1038 mac_register(mac_register_t *mregp, mac_handle_t *mhp) 1039 { 1040 mac_impl_t *mip; 1041 mactype_t *mtype; 1042 int err; 1043 struct devnames *dnp; 1044 minor_t minor; 1045 mod_hash_val_t val; 1046 boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 1047 1048 /* Find the required MAC-Type plugin. */ 1049 if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 1050 return (EINVAL); 1051 1052 /* Create a mac_impl_t to represent this MAC. */ 1053 mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 1054 1055 /* 1056 * The mac is not ready for open yet. 1057 */ 1058 mip->mi_disabled = B_TRUE; 1059 1060 mip->mi_drvname = ddi_driver_name(mregp->m_dip); 1061 /* 1062 * Some drivers such as aggr need to register multiple MACs. Such 1063 * drivers must supply a non-zero "instance" argument so that each 1064 * MAC can be assigned a unique MAC name and can have unique 1065 * kstats. 1066 */ 1067 mip->mi_instance = ((mregp->m_instance == 0) ? 1068 ddi_get_instance(mregp->m_dip) : mregp->m_instance); 1069 1070 /* Construct the MAC name as <drvname><instance> */ 1071 (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 1072 mip->mi_drvname, mip->mi_instance); 1073 1074 rw_enter(&i_mac_impl_lock, RW_WRITER); 1075 if (mod_hash_insert(i_mac_impl_hash, 1076 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 1077 kmem_cache_free(i_mac_impl_cachep, mip); 1078 rw_exit(&i_mac_impl_lock); 1079 return (EEXIST); 1080 } 1081 i_mac_impl_count++; 1082 1083 mip->mi_driver = mregp->m_driver; 1084 1085 mip->mi_type = mtype; 1086 mip->mi_info.mi_media = mtype->mt_type; 1087 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 1088 mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 1089 if (mregp->m_max_sdu <= mregp->m_min_sdu) { 1090 err = EINVAL; 1091 goto fail; 1092 } 1093 mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 1094 mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 1095 /* 1096 * If the media supports a broadcast address, cache a pointer to it 1097 * in the mac_info_t so that upper layers can use it. 1098 */ 1099 mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1100 1101 /* 1102 * Copy the unicast source address into the mac_info_t, but only if 1103 * the MAC-Type defines a non-zero address length. We need to 1104 * handle MAC-Types that have an address length of 0 1105 * (point-to-point protocol MACs for example). 1106 */ 1107 if (mip->mi_type->mt_addr_length > 0) { 1108 if (mregp->m_src_addr == NULL) { 1109 err = EINVAL; 1110 goto fail; 1111 } 1112 mip->mi_info.mi_unicst_addr = 1113 kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 1114 bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 1115 mip->mi_type->mt_addr_length); 1116 1117 /* 1118 * Copy the fixed 'factory' MAC address from the immutable 1119 * info. This is taken to be the MAC address currently in 1120 * use. 1121 */ 1122 bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 1123 mip->mi_type->mt_addr_length); 1124 /* Copy the destination address if one is provided. */ 1125 if (mregp->m_dst_addr != NULL) { 1126 bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 1127 mip->mi_type->mt_addr_length); 1128 } 1129 } else if (mregp->m_src_addr != NULL) { 1130 err = EINVAL; 1131 goto fail; 1132 } 1133 1134 /* 1135 * The format of the m_pdata is specific to the plugin. It is 1136 * passed in as an argument to all of the plugin callbacks. The 1137 * driver can update this information by calling 1138 * mac_pdata_update(). 1139 */ 1140 if (mregp->m_pdata != NULL) { 1141 /* 1142 * Verify that the plugin supports MAC plugin data and that 1143 * the supplied data is valid. 1144 */ 1145 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 1146 err = EINVAL; 1147 goto fail; 1148 } 1149 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 1150 mregp->m_pdata_size)) { 1151 err = EINVAL; 1152 goto fail; 1153 } 1154 mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 1155 bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 1156 mip->mi_pdata_size = mregp->m_pdata_size; 1157 } 1158 1159 /* 1160 * Stash the driver callbacks into the mac_impl_t, but first sanity 1161 * check to make sure all mandatory callbacks are set. 1162 */ 1163 if (mregp->m_callbacks->mc_getstat == NULL || 1164 mregp->m_callbacks->mc_start == NULL || 1165 mregp->m_callbacks->mc_stop == NULL || 1166 mregp->m_callbacks->mc_setpromisc == NULL || 1167 mregp->m_callbacks->mc_multicst == NULL || 1168 mregp->m_callbacks->mc_unicst == NULL || 1169 mregp->m_callbacks->mc_tx == NULL) { 1170 err = EINVAL; 1171 goto fail; 1172 } 1173 mip->mi_callbacks = mregp->m_callbacks; 1174 1175 mip->mi_dip = mregp->m_dip; 1176 1177 /* 1178 * Set up the two possible transmit routines. 1179 */ 1180 mip->mi_txinfo.mt_fn = mip->mi_tx; 1181 mip->mi_txinfo.mt_arg = mip->mi_driver; 1182 mip->mi_txloopinfo.mt_fn = mac_txloop; 1183 mip->mi_txloopinfo.mt_arg = mip; 1184 1185 /* 1186 * Initialize the kstats for this device. 1187 */ 1188 mac_stat_create(mip); 1189 1190 err = EEXIST; 1191 /* Create a style-2 DLPI device */ 1192 if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 1193 S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 1194 goto fail; 1195 style2_created = B_TRUE; 1196 1197 /* Create a style-1 DLPI device */ 1198 minor = (minor_t)mip->mi_instance + 1; 1199 if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 1200 DDI_NT_NET, 0) != DDI_SUCCESS) 1201 goto fail; 1202 style1_created = B_TRUE; 1203 1204 /* 1205 * Create a link for this MAC. The link name will be the same as 1206 * the MAC name. 1207 */ 1208 err = dls_create(mip->mi_name, mip->mi_name, 1209 ddi_get_instance(mip->mi_dip)); 1210 if (err != 0) 1211 goto fail; 1212 1213 /* set the gldv3 flag in dn_flags */ 1214 dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 1215 LOCK_DEV_OPS(&dnp->dn_lock); 1216 dnp->dn_flags |= DN_GLDV3_DRIVER; 1217 UNLOCK_DEV_OPS(&dnp->dn_lock); 1218 1219 /* 1220 * Mark the MAC to be ready for open. 1221 */ 1222 mip->mi_disabled = B_FALSE; 1223 1224 cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 1225 rw_exit(&i_mac_impl_lock); 1226 *mhp = (mac_handle_t)mip; 1227 return (0); 1228 1229 fail: 1230 (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1231 &val); 1232 ASSERT(mip == (mac_impl_t *)val); 1233 i_mac_impl_count--; 1234 1235 if (mip->mi_info.mi_unicst_addr != NULL) { 1236 kmem_free(mip->mi_info.mi_unicst_addr, 1237 mip->mi_type->mt_addr_length); 1238 mip->mi_info.mi_unicst_addr = NULL; 1239 } 1240 if (style1_created) 1241 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1242 if (style2_created) 1243 ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1244 1245 mac_stat_destroy(mip); 1246 1247 if (mip->mi_type != NULL) { 1248 mip->mi_type->mt_ref--; 1249 mip->mi_type = NULL; 1250 } 1251 1252 if (mip->mi_pdata != NULL) { 1253 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1254 mip->mi_pdata = NULL; 1255 mip->mi_pdata_size = 0; 1256 } 1257 1258 kmem_cache_free(i_mac_impl_cachep, mip); 1259 rw_exit(&i_mac_impl_lock); 1260 return (err); 1261 } 1262 1263 int 1264 mac_unregister(mac_handle_t mh) 1265 { 1266 int err; 1267 mac_impl_t *mip = (mac_impl_t *)mh; 1268 mod_hash_val_t val; 1269 mac_multicst_addr_t *p, *nextp; 1270 1271 /* 1272 * See if there are any other references to this mac_t (e.g., VLAN's). 1273 * If not, set mi_disabled to prevent any new VLAN's from being 1274 * created while we're destroying this mac. 1275 */ 1276 rw_enter(&i_mac_impl_lock, RW_WRITER); 1277 if (mip->mi_ref > 0) { 1278 rw_exit(&i_mac_impl_lock); 1279 return (EBUSY); 1280 } 1281 mip->mi_disabled = B_TRUE; 1282 rw_exit(&i_mac_impl_lock); 1283 1284 /* 1285 * Wait for all taskqs which process the mac notifications to finish. 1286 */ 1287 mutex_enter(&mip->mi_notify_ref_lock); 1288 while (mip->mi_notify_ref != 0) 1289 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 1290 mutex_exit(&mip->mi_notify_ref_lock); 1291 1292 if ((err = dls_destroy(mip->mi_name)) != 0) { 1293 rw_enter(&i_mac_impl_lock, RW_WRITER); 1294 mip->mi_disabled = B_FALSE; 1295 rw_exit(&i_mac_impl_lock); 1296 return (err); 1297 } 1298 1299 /* 1300 * Remove both style 1 and style 2 minor nodes 1301 */ 1302 ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1303 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1304 1305 ASSERT(!mip->mi_activelink); 1306 1307 mac_stat_destroy(mip); 1308 1309 (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1310 &val); 1311 ASSERT(mip == (mac_impl_t *)val); 1312 1313 ASSERT(i_mac_impl_count > 0); 1314 i_mac_impl_count--; 1315 1316 if (mip->mi_pdata != NULL) 1317 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1318 mip->mi_pdata = NULL; 1319 mip->mi_pdata_size = 0; 1320 1321 /* 1322 * Free the list of multicast addresses. 1323 */ 1324 for (p = mip->mi_mmap; p != NULL; p = nextp) { 1325 nextp = p->mma_nextp; 1326 kmem_free(p, sizeof (mac_multicst_addr_t)); 1327 } 1328 mip->mi_mmap = NULL; 1329 1330 mip->mi_linkstate = LINK_STATE_UNKNOWN; 1331 kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 1332 mip->mi_info.mi_unicst_addr = NULL; 1333 1334 mip->mi_type->mt_ref--; 1335 mip->mi_type = NULL; 1336 1337 cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 1338 1339 kmem_cache_free(i_mac_impl_cachep, mip); 1340 1341 return (0); 1342 } 1343 1344 void 1345 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 1346 { 1347 mac_impl_t *mip = (mac_impl_t *)mh; 1348 mac_rx_fn_t *mrfp; 1349 1350 /* 1351 * Call all registered receive functions. 1352 */ 1353 rw_enter(&mip->mi_rx_lock, RW_READER); 1354 mrfp = mip->mi_mrfp; 1355 if (mrfp == NULL) { 1356 /* There are no registered receive functions. */ 1357 freemsgchain(bp); 1358 rw_exit(&mip->mi_rx_lock); 1359 return; 1360 } 1361 do { 1362 mblk_t *recv_bp; 1363 1364 if (mrfp->mrf_nextp != NULL) { 1365 /* XXX Do we bump a counter if copymsgchain() fails? */ 1366 recv_bp = copymsgchain(bp); 1367 } else { 1368 recv_bp = bp; 1369 } 1370 if (recv_bp != NULL) 1371 mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 1372 mrfp = mrfp->mrf_nextp; 1373 } while (mrfp != NULL); 1374 rw_exit(&mip->mi_rx_lock); 1375 } 1376 1377 /* 1378 * Transmit function -- ONLY used when there are registered loopback listeners. 1379 */ 1380 mblk_t * 1381 mac_txloop(void *arg, mblk_t *bp) 1382 { 1383 mac_impl_t *mip = arg; 1384 mac_txloop_fn_t *mtfp; 1385 mblk_t *loop_bp, *resid_bp, *next_bp; 1386 1387 while (bp != NULL) { 1388 next_bp = bp->b_next; 1389 bp->b_next = NULL; 1390 1391 if ((loop_bp = copymsg(bp)) == NULL) 1392 goto noresources; 1393 1394 if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 1395 ASSERT(resid_bp == bp); 1396 freemsg(loop_bp); 1397 goto noresources; 1398 } 1399 1400 rw_enter(&mip->mi_txloop_lock, RW_READER); 1401 mtfp = mip->mi_mtfp; 1402 while (mtfp != NULL && loop_bp != NULL) { 1403 bp = loop_bp; 1404 1405 /* XXX counter bump if copymsg() fails? */ 1406 if (mtfp->mtf_nextp != NULL) 1407 loop_bp = copymsg(bp); 1408 else 1409 loop_bp = NULL; 1410 1411 mtfp->mtf_fn(mtfp->mtf_arg, bp); 1412 mtfp = mtfp->mtf_nextp; 1413 } 1414 rw_exit(&mip->mi_txloop_lock); 1415 1416 /* 1417 * It's possible we've raced with the disabling of promiscuous 1418 * mode, in which case we can discard our copy. 1419 */ 1420 if (loop_bp != NULL) 1421 freemsg(loop_bp); 1422 1423 bp = next_bp; 1424 } 1425 1426 return (NULL); 1427 1428 noresources: 1429 bp->b_next = next_bp; 1430 return (bp); 1431 } 1432 1433 void 1434 mac_link_update(mac_handle_t mh, link_state_t link) 1435 { 1436 mac_impl_t *mip = (mac_impl_t *)mh; 1437 1438 /* 1439 * Save the link state. 1440 */ 1441 mip->mi_linkstate = link; 1442 1443 /* 1444 * Send a MAC_NOTE_LINK notification. 1445 */ 1446 i_mac_notify(mip, MAC_NOTE_LINK); 1447 } 1448 1449 void 1450 mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 1451 { 1452 mac_impl_t *mip = (mac_impl_t *)mh; 1453 1454 if (mip->mi_type->mt_addr_length == 0) 1455 return; 1456 1457 /* 1458 * Save the address. 1459 */ 1460 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 1461 1462 /* 1463 * Send a MAC_NOTE_UNICST notification. 1464 */ 1465 i_mac_notify(mip, MAC_NOTE_UNICST); 1466 } 1467 1468 void 1469 mac_tx_update(mac_handle_t mh) 1470 { 1471 /* 1472 * Send a MAC_NOTE_TX notification. 1473 */ 1474 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 1475 } 1476 1477 void 1478 mac_resource_update(mac_handle_t mh) 1479 { 1480 /* 1481 * Send a MAC_NOTE_RESOURCE notification. 1482 */ 1483 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 1484 } 1485 1486 mac_resource_handle_t 1487 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 1488 { 1489 mac_impl_t *mip = (mac_impl_t *)mh; 1490 mac_resource_handle_t mrh; 1491 mac_resource_add_t add; 1492 void *arg; 1493 1494 rw_enter(&mip->mi_resource_lock, RW_READER); 1495 add = mip->mi_resource_add; 1496 arg = mip->mi_resource_add_arg; 1497 1498 if (add != NULL) 1499 mrh = add(arg, mrp); 1500 else 1501 mrh = NULL; 1502 rw_exit(&mip->mi_resource_lock); 1503 1504 return (mrh); 1505 } 1506 1507 int 1508 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 1509 { 1510 mac_impl_t *mip = (mac_impl_t *)mh; 1511 1512 /* 1513 * Verify that the plugin supports MAC plugin data and that the 1514 * supplied data is valid. 1515 */ 1516 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 1517 return (EINVAL); 1518 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 1519 return (EINVAL); 1520 1521 if (mip->mi_pdata != NULL) 1522 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1523 1524 mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 1525 bcopy(mac_pdata, mip->mi_pdata, dsize); 1526 mip->mi_pdata_size = dsize; 1527 1528 /* 1529 * Since the MAC plugin data is used to construct MAC headers that 1530 * were cached in fast-path headers, we need to flush fast-path 1531 * information for links associated with this mac. 1532 */ 1533 i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 1534 return (0); 1535 } 1536 1537 void 1538 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 1539 boolean_t add) 1540 { 1541 mac_impl_t *mip = (mac_impl_t *)mh; 1542 mac_multicst_addr_t *p; 1543 1544 /* 1545 * If no specific refresh function was given then default to the 1546 * driver's m_multicst entry point. 1547 */ 1548 if (refresh == NULL) { 1549 refresh = mip->mi_multicst; 1550 arg = mip->mi_driver; 1551 } 1552 ASSERT(refresh != NULL); 1553 1554 /* 1555 * Walk the multicast address list and call the refresh function for 1556 * each address. 1557 */ 1558 rw_enter(&(mip->mi_data_lock), RW_READER); 1559 for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 1560 refresh(arg, add, p->mma_addr); 1561 rw_exit(&(mip->mi_data_lock)); 1562 } 1563 1564 void 1565 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 1566 { 1567 mac_impl_t *mip = (mac_impl_t *)mh; 1568 /* 1569 * If no specific refresh function was given then default to the 1570 * driver's mi_unicst entry point. 1571 */ 1572 if (refresh == NULL) { 1573 refresh = mip->mi_unicst; 1574 arg = mip->mi_driver; 1575 } 1576 ASSERT(refresh != NULL); 1577 1578 /* 1579 * Call the refresh function with the current unicast address. 1580 */ 1581 refresh(arg, mip->mi_addr); 1582 } 1583 1584 void 1585 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 1586 { 1587 mac_impl_t *mip = (mac_impl_t *)mh; 1588 1589 /* 1590 * If no specific refresh function was given then default to the 1591 * driver's m_promisc entry point. 1592 */ 1593 if (refresh == NULL) { 1594 refresh = mip->mi_setpromisc; 1595 arg = mip->mi_driver; 1596 } 1597 ASSERT(refresh != NULL); 1598 1599 /* 1600 * Call the refresh function with the current promiscuity. 1601 */ 1602 refresh(arg, (mip->mi_devpromisc != 0)); 1603 } 1604 1605 boolean_t 1606 mac_active_set(mac_handle_t mh) 1607 { 1608 mac_impl_t *mip = (mac_impl_t *)mh; 1609 1610 mutex_enter(&mip->mi_activelink_lock); 1611 if (mip->mi_activelink) { 1612 mutex_exit(&mip->mi_activelink_lock); 1613 return (B_FALSE); 1614 } 1615 mip->mi_activelink = B_TRUE; 1616 mutex_exit(&mip->mi_activelink_lock); 1617 return (B_TRUE); 1618 } 1619 1620 void 1621 mac_active_clear(mac_handle_t mh) 1622 { 1623 mac_impl_t *mip = (mac_impl_t *)mh; 1624 1625 mutex_enter(&mip->mi_activelink_lock); 1626 ASSERT(mip->mi_activelink); 1627 mip->mi_activelink = B_FALSE; 1628 mutex_exit(&mip->mi_activelink_lock); 1629 } 1630 1631 /* 1632 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1633 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1634 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1635 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1636 * cannot disappear while we are accessing it. 1637 */ 1638 typedef struct i_mac_info_state_s { 1639 const char *mi_name; 1640 mac_info_t *mi_infop; 1641 } i_mac_info_state_t; 1642 1643 /*ARGSUSED*/ 1644 static uint_t 1645 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1646 { 1647 i_mac_info_state_t *statep = arg; 1648 mac_impl_t *mip = (mac_impl_t *)val; 1649 1650 if (mip->mi_disabled) 1651 return (MH_WALK_CONTINUE); 1652 1653 if (strcmp(statep->mi_name, 1654 ddi_driver_name(mip->mi_dip)) != 0) 1655 return (MH_WALK_CONTINUE); 1656 1657 statep->mi_infop = &mip->mi_info; 1658 return (MH_WALK_TERMINATE); 1659 } 1660 1661 boolean_t 1662 mac_info_get(const char *name, mac_info_t *minfop) 1663 { 1664 i_mac_info_state_t state; 1665 1666 rw_enter(&i_mac_impl_lock, RW_READER); 1667 state.mi_name = name; 1668 state.mi_infop = NULL; 1669 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1670 if (state.mi_infop == NULL) { 1671 rw_exit(&i_mac_impl_lock); 1672 return (B_FALSE); 1673 } 1674 *minfop = *state.mi_infop; 1675 rw_exit(&i_mac_impl_lock); 1676 return (B_TRUE); 1677 } 1678 1679 boolean_t 1680 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 1681 { 1682 mac_impl_t *mip = (mac_impl_t *)mh; 1683 1684 if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 1685 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 1686 else 1687 return (B_FALSE); 1688 } 1689 1690 boolean_t 1691 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 1692 { 1693 mac_impl_t *mip = (mac_impl_t *)mh; 1694 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 1695 mip->mi_pdata)); 1696 } 1697 1698 mblk_t * 1699 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 1700 size_t extra_len) 1701 { 1702 mac_impl_t *mip = (mac_impl_t *)mh; 1703 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 1704 mip->mi_pdata, payload, extra_len)); 1705 } 1706 1707 int 1708 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 1709 { 1710 mac_impl_t *mip = (mac_impl_t *)mh; 1711 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 1712 mhip)); 1713 } 1714 1715 mblk_t * 1716 mac_header_cook(mac_handle_t mh, mblk_t *mp) 1717 { 1718 mac_impl_t *mip = (mac_impl_t *)mh; 1719 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 1720 if (DB_REF(mp) > 1) { 1721 mblk_t *newmp = copymsg(mp); 1722 if (newmp == NULL) 1723 return (NULL); 1724 freemsg(mp); 1725 mp = newmp; 1726 } 1727 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 1728 mip->mi_pdata)); 1729 } 1730 return (mp); 1731 } 1732 1733 mblk_t * 1734 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 1735 { 1736 mac_impl_t *mip = (mac_impl_t *)mh; 1737 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 1738 if (DB_REF(mp) > 1) { 1739 mblk_t *newmp = copymsg(mp); 1740 if (newmp == NULL) 1741 return (NULL); 1742 freemsg(mp); 1743 mp = newmp; 1744 } 1745 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 1746 mip->mi_pdata)); 1747 } 1748 return (mp); 1749 } 1750 1751 void 1752 mac_init_ops(struct dev_ops *ops, const char *name) 1753 { 1754 dld_init_ops(ops, name); 1755 } 1756 1757 void 1758 mac_fini_ops(struct dev_ops *ops) 1759 { 1760 dld_fini_ops(ops); 1761 } 1762 1763 /* 1764 * MAC Type Plugin functions. 1765 */ 1766 1767 mactype_register_t * 1768 mactype_alloc(uint_t mactype_version) 1769 { 1770 mactype_register_t *mtrp; 1771 1772 /* 1773 * Make sure there isn't a version mismatch between the plugin and 1774 * the framework. In the future, if multiple versions are 1775 * supported, this check could become more sophisticated. 1776 */ 1777 if (mactype_version != MACTYPE_VERSION) 1778 return (NULL); 1779 1780 mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 1781 mtrp->mtr_version = mactype_version; 1782 return (mtrp); 1783 } 1784 1785 void 1786 mactype_free(mactype_register_t *mtrp) 1787 { 1788 kmem_free(mtrp, sizeof (mactype_register_t)); 1789 } 1790 1791 int 1792 mactype_register(mactype_register_t *mtrp) 1793 { 1794 mactype_t *mtp; 1795 mactype_ops_t *ops = mtrp->mtr_ops; 1796 1797 /* Do some sanity checking before we register this MAC type. */ 1798 if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 1799 return (EINVAL); 1800 1801 /* 1802 * Verify that all mandatory callbacks are set in the ops 1803 * vector. 1804 */ 1805 if (ops->mtops_unicst_verify == NULL || 1806 ops->mtops_multicst_verify == NULL || 1807 ops->mtops_sap_verify == NULL || 1808 ops->mtops_header == NULL || 1809 ops->mtops_header_info == NULL) { 1810 return (EINVAL); 1811 } 1812 1813 mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 1814 mtp->mt_ident = mtrp->mtr_ident; 1815 mtp->mt_ops = *ops; 1816 mtp->mt_type = mtrp->mtr_mactype; 1817 mtp->mt_nativetype = mtrp->mtr_nativetype; 1818 mtp->mt_addr_length = mtrp->mtr_addrlen; 1819 if (mtrp->mtr_brdcst_addr != NULL) { 1820 mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 1821 bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 1822 mtrp->mtr_addrlen); 1823 } 1824 1825 mtp->mt_stats = mtrp->mtr_stats; 1826 mtp->mt_statcount = mtrp->mtr_statcount; 1827 1828 /* 1829 * A MAC-Type plugin only registers when i_mactype_getplugin() does 1830 * an explicit modload() as a result of a driver requesting to use 1831 * that plugin in mac_register(). We pre-emptively set the initial 1832 * reference count to 1 here to prevent the plugin module from 1833 * unloading before the driver's mac_register() completes. If we 1834 * were to initialize the reference count to 0, then there would be 1835 * a window during which the module could unload before the 1836 * reference count could be bumped up to 1. 1837 */ 1838 mtp->mt_ref = 1; 1839 1840 if (mod_hash_insert(i_mactype_hash, 1841 (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 1842 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1843 kmem_free(mtp, sizeof (*mtp)); 1844 return (EEXIST); 1845 } 1846 return (0); 1847 } 1848 1849 int 1850 mactype_unregister(const char *ident) 1851 { 1852 mactype_t *mtp; 1853 mod_hash_val_t val; 1854 int err; 1855 1856 /* 1857 * Let's not allow MAC drivers to use this plugin while we're 1858 * trying to unregister it... 1859 */ 1860 rw_enter(&i_mac_impl_lock, RW_WRITER); 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 rw_exit(&i_mac_impl_lock); 1866 return (ENXIO); 1867 } 1868 1869 if (mtp->mt_ref > 0) { 1870 rw_exit(&i_mac_impl_lock); 1871 return (EBUSY); 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 rw_exit(&i_mac_impl_lock); 1879 return (EINVAL); 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 rw_exit(&i_mac_impl_lock); 1886 1887 return (0); 1888 } 1889