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 int 586 mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 587 { 588 mac_impl_t *mip = (mac_impl_t *)mh; 589 int err; 590 boolean_t notify = B_FALSE; 591 592 ASSERT(mip->mi_unicst != NULL); 593 594 /* 595 * Verify the address. 596 */ 597 if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 598 mip->mi_pdata)) != 0) { 599 return (err); 600 } 601 602 /* 603 * Program the new unicast address. 604 */ 605 rw_enter(&(mip->mi_data_lock), RW_WRITER); 606 607 /* 608 * If address doesn't change, do nothing. 609 * This check is necessary otherwise it may call into mac_unicst_set 610 * recursively. 611 */ 612 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 613 err = 0; 614 goto done; 615 } 616 617 if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 618 goto done; 619 620 /* 621 * Save the address and flag that we need to send a notification. 622 */ 623 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 624 notify = B_TRUE; 625 626 done: 627 rw_exit(&(mip->mi_data_lock)); 628 629 if (notify) 630 i_mac_notify(mip, MAC_NOTE_UNICST); 631 632 return (err); 633 } 634 635 void 636 mac_unicst_get(mac_handle_t mh, uint8_t *addr) 637 { 638 mac_impl_t *mip = (mac_impl_t *)mh; 639 640 /* 641 * Copy out the current unicast source address. 642 */ 643 rw_enter(&(mip->mi_data_lock), RW_READER); 644 bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 645 rw_exit(&(mip->mi_data_lock)); 646 } 647 648 void 649 mac_dest_get(mac_handle_t mh, uint8_t *addr) 650 { 651 mac_impl_t *mip = (mac_impl_t *)mh; 652 653 /* 654 * Copy out the current destination address. 655 */ 656 rw_enter(&(mip->mi_data_lock), RW_READER); 657 bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 658 rw_exit(&(mip->mi_data_lock)); 659 } 660 661 int 662 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 663 { 664 mac_impl_t *mip = (mac_impl_t *)mh; 665 int err = 0; 666 667 ASSERT(mip->mi_setpromisc != NULL); 668 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 669 670 /* 671 * Determine whether we should enable or disable promiscuous mode. 672 * For details on the distinction between "device promiscuous mode" 673 * and "MAC promiscuous mode", see PSARC/2005/289. 674 */ 675 rw_enter(&(mip->mi_data_lock), RW_WRITER); 676 if (on) { 677 /* 678 * Enable promiscuous mode on the device if not yet enabled. 679 */ 680 if (mip->mi_devpromisc++ == 0) { 681 err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 682 if (err != 0) { 683 mip->mi_devpromisc--; 684 goto done; 685 } 686 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 687 } 688 689 /* 690 * Enable promiscuous mode on the MAC if not yet enabled. 691 */ 692 if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 693 i_mac_notify(mip, MAC_NOTE_PROMISC); 694 } else { 695 if (mip->mi_devpromisc == 0) { 696 err = EPROTO; 697 goto done; 698 } 699 700 /* 701 * Disable promiscuous mode on the device if this is the last 702 * enabling. 703 */ 704 if (--mip->mi_devpromisc == 0) { 705 err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 706 if (err != 0) { 707 mip->mi_devpromisc++; 708 goto done; 709 } 710 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 711 } 712 713 /* 714 * Disable promiscuous mode on the MAC if this is the last 715 * enabling. 716 */ 717 if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 718 i_mac_notify(mip, MAC_NOTE_PROMISC); 719 } 720 721 done: 722 rw_exit(&(mip->mi_data_lock)); 723 return (err); 724 } 725 726 boolean_t 727 mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 728 { 729 mac_impl_t *mip = (mac_impl_t *)mh; 730 731 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 732 733 /* 734 * Return the current promiscuity. 735 */ 736 if (ptype == MAC_DEVPROMISC) 737 return (mip->mi_devpromisc != 0); 738 else 739 return (mip->mi_promisc != 0); 740 } 741 742 void 743 mac_resources(mac_handle_t mh) 744 { 745 mac_impl_t *mip = (mac_impl_t *)mh; 746 747 /* 748 * If the driver supports resource registration, call the driver to 749 * ask it to register its resources. 750 */ 751 if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 752 mip->mi_resources(mip->mi_driver); 753 } 754 755 void 756 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 757 { 758 mac_impl_t *mip = (mac_impl_t *)mh; 759 760 /* 761 * Call the driver to handle the ioctl. The driver may not support 762 * any ioctls, in which case we reply with a NAK on its behalf. 763 */ 764 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 765 mip->mi_ioctl(mip->mi_driver, wq, bp); 766 else 767 miocnak(wq, bp, 0, EINVAL); 768 } 769 770 const mac_txinfo_t * 771 mac_tx_get(mac_handle_t mh) 772 { 773 mac_impl_t *mip = (mac_impl_t *)mh; 774 mac_txinfo_t *mtp; 775 776 /* 777 * Grab the lock to prevent us from racing with MAC_PROMISC being 778 * changed. This is sufficient since MAC clients are careful to always 779 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 780 * MAC_PROMISC prior to calling mac_txloop_remove(). 781 */ 782 rw_enter(&mip->mi_txloop_lock, RW_READER); 783 784 if (mac_promisc_get(mh, MAC_PROMISC)) { 785 ASSERT(mip->mi_mtfp != NULL); 786 mtp = &mip->mi_txloopinfo; 787 } else { 788 /* 789 * Note that we cannot ASSERT() that mip->mi_mtfp is NULL, 790 * because to satisfy the above ASSERT(), we have to disable 791 * MAC_PROMISC prior to calling mac_txloop_remove(). 792 */ 793 mtp = &mip->mi_txinfo; 794 } 795 796 rw_exit(&mip->mi_txloop_lock); 797 return (mtp); 798 } 799 800 link_state_t 801 mac_link_get(mac_handle_t mh) 802 { 803 return (((mac_impl_t *)mh)->mi_linkstate); 804 } 805 806 mac_notify_handle_t 807 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 808 { 809 mac_impl_t *mip = (mac_impl_t *)mh; 810 mac_notify_fn_t *mnfp; 811 812 mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 813 mnfp->mnf_fn = notify; 814 mnfp->mnf_arg = arg; 815 816 /* 817 * Add it to the head of the 'notify' callback list. 818 */ 819 rw_enter(&mip->mi_notify_lock, RW_WRITER); 820 mnfp->mnf_nextp = mip->mi_mnfp; 821 mip->mi_mnfp = mnfp; 822 rw_exit(&mip->mi_notify_lock); 823 824 return ((mac_notify_handle_t)mnfp); 825 } 826 827 void 828 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 829 { 830 mac_impl_t *mip = (mac_impl_t *)mh; 831 mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 832 mac_notify_fn_t **pp; 833 mac_notify_fn_t *p; 834 835 /* 836 * Search the 'notify' callback list for the function closure. 837 */ 838 rw_enter(&mip->mi_notify_lock, RW_WRITER); 839 for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 840 pp = &(p->mnf_nextp)) { 841 if (p == mnfp) 842 break; 843 } 844 ASSERT(p != NULL); 845 846 /* 847 * Remove it from the list. 848 */ 849 *pp = p->mnf_nextp; 850 rw_exit(&mip->mi_notify_lock); 851 852 /* 853 * Free it. 854 */ 855 kmem_free(mnfp, sizeof (mac_notify_fn_t)); 856 } 857 858 void 859 mac_notify(mac_handle_t mh) 860 { 861 mac_impl_t *mip = (mac_impl_t *)mh; 862 mac_notify_type_t type; 863 864 for (type = 0; type < MAC_NNOTE; type++) 865 i_mac_notify(mip, type); 866 } 867 868 mac_rx_handle_t 869 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 870 { 871 mac_impl_t *mip = (mac_impl_t *)mh; 872 mac_rx_fn_t *mrfp; 873 874 mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 875 mrfp->mrf_fn = rx; 876 mrfp->mrf_arg = arg; 877 878 /* 879 * Add it to the head of the 'rx' callback list. 880 */ 881 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 882 mrfp->mrf_nextp = mip->mi_mrfp; 883 mip->mi_mrfp = mrfp; 884 rw_exit(&(mip->mi_rx_lock)); 885 886 return ((mac_rx_handle_t)mrfp); 887 } 888 889 /* 890 * Unregister a receive function for this mac. This removes the function 891 * from the list of receive functions for this mac. 892 */ 893 void 894 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 895 { 896 mac_impl_t *mip = (mac_impl_t *)mh; 897 mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 898 mac_rx_fn_t **pp; 899 mac_rx_fn_t *p; 900 901 /* 902 * Search the 'rx' callback list for the function closure. 903 */ 904 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 905 for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 906 if (p == mrfp) 907 break; 908 } 909 ASSERT(p != NULL); 910 911 /* Remove it from the list. */ 912 *pp = p->mrf_nextp; 913 kmem_free(mrfp, sizeof (mac_rx_fn_t)); 914 rw_exit(&(mip->mi_rx_lock)); 915 } 916 917 mac_txloop_handle_t 918 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 919 { 920 mac_impl_t *mip = (mac_impl_t *)mh; 921 mac_txloop_fn_t *mtfp; 922 923 mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 924 mtfp->mtf_fn = tx; 925 mtfp->mtf_arg = arg; 926 927 /* 928 * Add it to the head of the 'tx' callback list. 929 */ 930 rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 931 mtfp->mtf_nextp = mip->mi_mtfp; 932 mip->mi_mtfp = mtfp; 933 rw_exit(&(mip->mi_txloop_lock)); 934 935 return ((mac_txloop_handle_t)mtfp); 936 } 937 938 /* 939 * Unregister a transmit function for this mac. This removes the function 940 * from the list of transmit functions for this mac. 941 */ 942 void 943 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 944 { 945 mac_impl_t *mip = (mac_impl_t *)mh; 946 mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 947 mac_txloop_fn_t **pp; 948 mac_txloop_fn_t *p; 949 950 /* 951 * Search the 'tx' callback list for the function. 952 */ 953 rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 954 for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 955 if (p == mtfp) 956 break; 957 } 958 ASSERT(p != NULL); 959 960 /* Remove it from the list. */ 961 *pp = p->mtf_nextp; 962 kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 963 rw_exit(&(mip->mi_txloop_lock)); 964 } 965 966 void 967 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 968 { 969 mac_impl_t *mip = (mac_impl_t *)mh; 970 971 /* 972 * Update the 'resource_add' callbacks. 973 */ 974 rw_enter(&(mip->mi_resource_lock), RW_WRITER); 975 mip->mi_resource_add = add; 976 mip->mi_resource_add_arg = arg; 977 rw_exit(&(mip->mi_resource_lock)); 978 } 979 980 /* 981 * Driver support functions. 982 */ 983 984 mac_register_t * 985 mac_alloc(uint_t mac_version) 986 { 987 mac_register_t *mregp; 988 989 /* 990 * Make sure there isn't a version mismatch between the driver and 991 * the framework. In the future, if multiple versions are 992 * supported, this check could become more sophisticated. 993 */ 994 if (mac_version != MAC_VERSION) 995 return (NULL); 996 997 mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 998 mregp->m_version = mac_version; 999 return (mregp); 1000 } 1001 1002 void 1003 mac_free(mac_register_t *mregp) 1004 { 1005 kmem_free(mregp, sizeof (mac_register_t)); 1006 } 1007 1008 /* 1009 * mac_register() is how drivers register new MACs with the GLDv3 1010 * framework. The mregp argument is allocated by drivers using the 1011 * mac_alloc() function, and can be freed using mac_free() immediately upon 1012 * return from mac_register(). Upon success (0 return value), the mhp 1013 * opaque pointer becomes the driver's handle to its MAC interface, and is 1014 * the argument to all other mac module entry points. 1015 */ 1016 /* ARGSUSED */ 1017 int 1018 mac_register(mac_register_t *mregp, mac_handle_t *mhp) 1019 { 1020 mac_impl_t *mip; 1021 mactype_t *mtype; 1022 int err; 1023 struct devnames *dnp; 1024 minor_t minor; 1025 mod_hash_val_t val; 1026 boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 1027 1028 /* Find the required MAC-Type plugin. */ 1029 if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 1030 return (EINVAL); 1031 1032 /* Create a mac_impl_t to represent this MAC. */ 1033 mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 1034 1035 /* 1036 * The mac is not ready for open yet. 1037 */ 1038 mip->mi_disabled = B_TRUE; 1039 1040 mip->mi_drvname = ddi_driver_name(mregp->m_dip); 1041 /* 1042 * Some drivers such as aggr need to register multiple MACs. Such 1043 * drivers must supply a non-zero "instance" argument so that each 1044 * MAC can be assigned a unique MAC name and can have unique 1045 * kstats. 1046 */ 1047 mip->mi_instance = ((mregp->m_instance == 0) ? 1048 ddi_get_instance(mregp->m_dip) : mregp->m_instance); 1049 1050 /* Construct the MAC name as <drvname><instance> */ 1051 (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 1052 mip->mi_drvname, mip->mi_instance); 1053 1054 rw_enter(&i_mac_impl_lock, RW_WRITER); 1055 if (mod_hash_insert(i_mac_impl_hash, 1056 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 1057 kmem_cache_free(i_mac_impl_cachep, mip); 1058 rw_exit(&i_mac_impl_lock); 1059 return (EEXIST); 1060 } 1061 i_mac_impl_count++; 1062 1063 mip->mi_driver = mregp->m_driver; 1064 1065 mip->mi_type = mtype; 1066 1067 mip->mi_info.mi_media = mtype->mt_type; 1068 mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 1069 if (mregp->m_max_sdu <= mregp->m_min_sdu) { 1070 err = EINVAL; 1071 goto fail; 1072 } 1073 mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 1074 mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 1075 /* 1076 * If the media supports a broadcast address, cache a pointer to it 1077 * in the mac_info_t so that upper layers can use it. 1078 */ 1079 mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1080 1081 /* 1082 * Copy the unicast source address into the mac_info_t, but only if 1083 * the MAC-Type defines a non-zero address length. We need to 1084 * handle MAC-Types that have an address length of 0 1085 * (point-to-point protocol MACs for example). 1086 */ 1087 if (mip->mi_type->mt_addr_length > 0) { 1088 if (mregp->m_src_addr == NULL) { 1089 err = EINVAL; 1090 goto fail; 1091 } 1092 mip->mi_info.mi_unicst_addr = 1093 kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 1094 bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 1095 mip->mi_type->mt_addr_length); 1096 1097 /* 1098 * Copy the fixed 'factory' MAC address from the immutable 1099 * info. This is taken to be the MAC address currently in 1100 * use. 1101 */ 1102 bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 1103 mip->mi_type->mt_addr_length); 1104 /* Copy the destination address if one is provided. */ 1105 if (mregp->m_dst_addr != NULL) { 1106 bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 1107 mip->mi_type->mt_addr_length); 1108 } 1109 } else if (mregp->m_src_addr != NULL) { 1110 err = EINVAL; 1111 goto fail; 1112 } 1113 1114 /* 1115 * The format of the m_pdata is specific to the plugin. It is 1116 * passed in as an argument to all of the plugin callbacks. The 1117 * driver can update this information by calling 1118 * mac_pdata_update(). 1119 */ 1120 if (mregp->m_pdata != NULL) { 1121 /* 1122 * Verify that the plugin supports MAC plugin data and that 1123 * the supplied data is valid. 1124 */ 1125 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 1126 err = EINVAL; 1127 goto fail; 1128 } 1129 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 1130 mregp->m_pdata_size)) { 1131 err = EINVAL; 1132 goto fail; 1133 } 1134 mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 1135 bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 1136 mip->mi_pdata_size = mregp->m_pdata_size; 1137 } 1138 1139 /* 1140 * Stash the driver callbacks into the mac_impl_t, but first sanity 1141 * check to make sure all mandatory callbacks are set. 1142 */ 1143 if (mregp->m_callbacks->mc_getstat == NULL || 1144 mregp->m_callbacks->mc_start == NULL || 1145 mregp->m_callbacks->mc_stop == NULL || 1146 mregp->m_callbacks->mc_setpromisc == NULL || 1147 mregp->m_callbacks->mc_multicst == NULL || 1148 mregp->m_callbacks->mc_unicst == NULL || 1149 mregp->m_callbacks->mc_tx == NULL) { 1150 err = EINVAL; 1151 goto fail; 1152 } 1153 mip->mi_callbacks = mregp->m_callbacks; 1154 1155 mip->mi_dip = mregp->m_dip; 1156 1157 /* 1158 * Set up the two possible transmit routines. 1159 */ 1160 mip->mi_txinfo.mt_fn = mip->mi_tx; 1161 mip->mi_txinfo.mt_arg = mip->mi_driver; 1162 mip->mi_txloopinfo.mt_fn = mac_txloop; 1163 mip->mi_txloopinfo.mt_arg = mip; 1164 1165 /* 1166 * Initialize the kstats for this device. 1167 */ 1168 mac_stat_create(mip); 1169 1170 err = EEXIST; 1171 /* Create a style-2 DLPI device */ 1172 if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 1173 S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 1174 goto fail; 1175 style2_created = B_TRUE; 1176 1177 /* Create a style-1 DLPI device */ 1178 minor = (minor_t)mip->mi_instance + 1; 1179 if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 1180 DDI_NT_NET, 0) != DDI_SUCCESS) 1181 goto fail; 1182 style1_created = B_TRUE; 1183 1184 /* 1185 * Create a link for this MAC. The link name will be the same as 1186 * the MAC name. 1187 */ 1188 err = dls_create(mip->mi_name, mip->mi_name, 1189 ddi_get_instance(mip->mi_dip)); 1190 if (err != 0) 1191 goto fail; 1192 1193 /* set the gldv3 flag in dn_flags */ 1194 dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 1195 LOCK_DEV_OPS(&dnp->dn_lock); 1196 dnp->dn_flags |= DN_GLDV3_DRIVER; 1197 UNLOCK_DEV_OPS(&dnp->dn_lock); 1198 1199 /* 1200 * Mark the MAC to be ready for open. 1201 */ 1202 mip->mi_disabled = B_FALSE; 1203 1204 cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 1205 rw_exit(&i_mac_impl_lock); 1206 *mhp = (mac_handle_t)mip; 1207 return (0); 1208 1209 fail: 1210 (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1211 &val); 1212 ASSERT(mip == (mac_impl_t *)val); 1213 i_mac_impl_count--; 1214 1215 if (mip->mi_info.mi_unicst_addr != NULL) { 1216 kmem_free(mip->mi_info.mi_unicst_addr, 1217 mip->mi_type->mt_addr_length); 1218 mip->mi_info.mi_unicst_addr = NULL; 1219 } 1220 if (style1_created) 1221 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1222 if (style2_created) 1223 ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1224 1225 mac_stat_destroy(mip); 1226 1227 if (mip->mi_type != NULL) { 1228 mip->mi_type->mt_ref--; 1229 mip->mi_type = NULL; 1230 } 1231 1232 if (mip->mi_pdata != NULL) { 1233 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1234 mip->mi_pdata = NULL; 1235 mip->mi_pdata_size = 0; 1236 } 1237 1238 kmem_cache_free(i_mac_impl_cachep, mip); 1239 rw_exit(&i_mac_impl_lock); 1240 return (err); 1241 } 1242 1243 int 1244 mac_unregister(mac_handle_t mh) 1245 { 1246 int err; 1247 mac_impl_t *mip = (mac_impl_t *)mh; 1248 mod_hash_val_t val; 1249 mac_multicst_addr_t *p, *nextp; 1250 1251 /* 1252 * See if there are any other references to this mac_t (e.g., VLAN's). 1253 * If not, set mi_disabled to prevent any new VLAN's from being 1254 * created while we're destroying this mac. 1255 */ 1256 rw_enter(&i_mac_impl_lock, RW_WRITER); 1257 if (mip->mi_ref > 0) { 1258 rw_exit(&i_mac_impl_lock); 1259 return (EBUSY); 1260 } 1261 mip->mi_disabled = B_TRUE; 1262 rw_exit(&i_mac_impl_lock); 1263 1264 /* 1265 * Wait for all taskqs which process the mac notifications to finish. 1266 */ 1267 mutex_enter(&mip->mi_notify_ref_lock); 1268 while (mip->mi_notify_ref != 0) 1269 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 1270 mutex_exit(&mip->mi_notify_ref_lock); 1271 1272 if ((err = dls_destroy(mip->mi_name)) != 0) { 1273 rw_enter(&i_mac_impl_lock, RW_WRITER); 1274 mip->mi_disabled = B_FALSE; 1275 rw_exit(&i_mac_impl_lock); 1276 return (err); 1277 } 1278 1279 /* 1280 * Remove both style 1 and style 2 minor nodes 1281 */ 1282 ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1283 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1284 1285 ASSERT(!mip->mi_activelink); 1286 1287 mac_stat_destroy(mip); 1288 1289 (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1290 &val); 1291 ASSERT(mip == (mac_impl_t *)val); 1292 1293 ASSERT(i_mac_impl_count > 0); 1294 i_mac_impl_count--; 1295 1296 if (mip->mi_pdata != NULL) 1297 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1298 mip->mi_pdata = NULL; 1299 mip->mi_pdata_size = 0; 1300 1301 /* 1302 * Free the list of multicast addresses. 1303 */ 1304 for (p = mip->mi_mmap; p != NULL; p = nextp) { 1305 nextp = p->mma_nextp; 1306 kmem_free(p, sizeof (mac_multicst_addr_t)); 1307 } 1308 mip->mi_mmap = NULL; 1309 1310 mip->mi_linkstate = LINK_STATE_UNKNOWN; 1311 kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 1312 mip->mi_info.mi_unicst_addr = NULL; 1313 1314 mip->mi_type->mt_ref--; 1315 mip->mi_type = NULL; 1316 1317 cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 1318 1319 kmem_cache_free(i_mac_impl_cachep, mip); 1320 1321 return (0); 1322 } 1323 1324 void 1325 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 1326 { 1327 mac_impl_t *mip = (mac_impl_t *)mh; 1328 mac_rx_fn_t *mrfp; 1329 1330 /* 1331 * Call all registered receive functions. 1332 */ 1333 rw_enter(&mip->mi_rx_lock, RW_READER); 1334 mrfp = mip->mi_mrfp; 1335 if (mrfp == NULL) { 1336 /* There are no registered receive functions. */ 1337 freemsgchain(bp); 1338 rw_exit(&mip->mi_rx_lock); 1339 return; 1340 } 1341 do { 1342 mblk_t *recv_bp; 1343 1344 if (mrfp->mrf_nextp != NULL) { 1345 /* XXX Do we bump a counter if copymsgchain() fails? */ 1346 recv_bp = copymsgchain(bp); 1347 } else { 1348 recv_bp = bp; 1349 } 1350 if (recv_bp != NULL) 1351 mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 1352 mrfp = mrfp->mrf_nextp; 1353 } while (mrfp != NULL); 1354 rw_exit(&mip->mi_rx_lock); 1355 } 1356 1357 /* 1358 * Transmit function -- ONLY used when there are registered loopback listeners. 1359 */ 1360 mblk_t * 1361 mac_txloop(void *arg, mblk_t *bp) 1362 { 1363 mac_impl_t *mip = arg; 1364 mac_txloop_fn_t *mtfp; 1365 mblk_t *loop_bp, *resid_bp, *next_bp; 1366 1367 while (bp != NULL) { 1368 next_bp = bp->b_next; 1369 bp->b_next = NULL; 1370 1371 if ((loop_bp = copymsg(bp)) == NULL) 1372 goto noresources; 1373 1374 if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 1375 ASSERT(resid_bp == bp); 1376 freemsg(loop_bp); 1377 goto noresources; 1378 } 1379 1380 rw_enter(&mip->mi_txloop_lock, RW_READER); 1381 mtfp = mip->mi_mtfp; 1382 while (mtfp != NULL && loop_bp != NULL) { 1383 bp = loop_bp; 1384 1385 /* XXX counter bump if copymsg() fails? */ 1386 if (mtfp->mtf_nextp != NULL) 1387 loop_bp = copymsg(bp); 1388 else 1389 loop_bp = NULL; 1390 1391 mtfp->mtf_fn(mtfp->mtf_arg, bp); 1392 mtfp = mtfp->mtf_nextp; 1393 } 1394 rw_exit(&mip->mi_txloop_lock); 1395 1396 /* 1397 * It's possible we've raced with the disabling of promiscuous 1398 * mode, in which case we can discard our copy. 1399 */ 1400 if (loop_bp != NULL) 1401 freemsg(loop_bp); 1402 1403 bp = next_bp; 1404 } 1405 1406 return (NULL); 1407 1408 noresources: 1409 bp->b_next = next_bp; 1410 return (bp); 1411 } 1412 1413 void 1414 mac_link_update(mac_handle_t mh, link_state_t link) 1415 { 1416 mac_impl_t *mip = (mac_impl_t *)mh; 1417 1418 /* 1419 * Save the link state. 1420 */ 1421 mip->mi_linkstate = link; 1422 1423 /* 1424 * Send a MAC_NOTE_LINK notification. 1425 */ 1426 i_mac_notify(mip, MAC_NOTE_LINK); 1427 } 1428 1429 void 1430 mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 1431 { 1432 mac_impl_t *mip = (mac_impl_t *)mh; 1433 1434 if (mip->mi_type->mt_addr_length == 0) 1435 return; 1436 1437 /* 1438 * Save the address. 1439 */ 1440 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 1441 1442 /* 1443 * Send a MAC_NOTE_UNICST notification. 1444 */ 1445 i_mac_notify(mip, MAC_NOTE_UNICST); 1446 } 1447 1448 void 1449 mac_tx_update(mac_handle_t mh) 1450 { 1451 /* 1452 * Send a MAC_NOTE_TX notification. 1453 */ 1454 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 1455 } 1456 1457 void 1458 mac_resource_update(mac_handle_t mh) 1459 { 1460 /* 1461 * Send a MAC_NOTE_RESOURCE notification. 1462 */ 1463 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 1464 } 1465 1466 mac_resource_handle_t 1467 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 1468 { 1469 mac_impl_t *mip = (mac_impl_t *)mh; 1470 mac_resource_handle_t mrh; 1471 mac_resource_add_t add; 1472 void *arg; 1473 1474 rw_enter(&mip->mi_resource_lock, RW_READER); 1475 add = mip->mi_resource_add; 1476 arg = mip->mi_resource_add_arg; 1477 1478 if (add != NULL) 1479 mrh = add(arg, mrp); 1480 else 1481 mrh = NULL; 1482 rw_exit(&mip->mi_resource_lock); 1483 1484 return (mrh); 1485 } 1486 1487 int 1488 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 1489 { 1490 mac_impl_t *mip = (mac_impl_t *)mh; 1491 1492 /* 1493 * Verify that the plugin supports MAC plugin data and that the 1494 * supplied data is valid. 1495 */ 1496 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 1497 return (EINVAL); 1498 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 1499 return (EINVAL); 1500 1501 if (mip->mi_pdata != NULL) 1502 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1503 1504 mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 1505 bcopy(mac_pdata, mip->mi_pdata, dsize); 1506 mip->mi_pdata_size = dsize; 1507 1508 /* 1509 * Since the MAC plugin data is used to construct MAC headers that 1510 * were cached in fast-path headers, we need to flush fast-path 1511 * information for links associated with this mac. 1512 */ 1513 i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 1514 return (0); 1515 } 1516 1517 void 1518 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 1519 boolean_t add) 1520 { 1521 mac_impl_t *mip = (mac_impl_t *)mh; 1522 mac_multicst_addr_t *p; 1523 1524 /* 1525 * If no specific refresh function was given then default to the 1526 * driver's m_multicst entry point. 1527 */ 1528 if (refresh == NULL) { 1529 refresh = mip->mi_multicst; 1530 arg = mip->mi_driver; 1531 } 1532 ASSERT(refresh != NULL); 1533 1534 /* 1535 * Walk the multicast address list and call the refresh function for 1536 * each address. 1537 */ 1538 rw_enter(&(mip->mi_data_lock), RW_READER); 1539 for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 1540 refresh(arg, add, p->mma_addr); 1541 rw_exit(&(mip->mi_data_lock)); 1542 } 1543 1544 void 1545 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 1546 { 1547 mac_impl_t *mip = (mac_impl_t *)mh; 1548 /* 1549 * If no specific refresh function was given then default to the 1550 * driver's mi_unicst entry point. 1551 */ 1552 if (refresh == NULL) { 1553 refresh = mip->mi_unicst; 1554 arg = mip->mi_driver; 1555 } 1556 ASSERT(refresh != NULL); 1557 1558 /* 1559 * Call the refresh function with the current unicast address. 1560 */ 1561 refresh(arg, mip->mi_addr); 1562 } 1563 1564 void 1565 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 1566 { 1567 mac_impl_t *mip = (mac_impl_t *)mh; 1568 1569 /* 1570 * If no specific refresh function was given then default to the 1571 * driver's m_promisc entry point. 1572 */ 1573 if (refresh == NULL) { 1574 refresh = mip->mi_setpromisc; 1575 arg = mip->mi_driver; 1576 } 1577 ASSERT(refresh != NULL); 1578 1579 /* 1580 * Call the refresh function with the current promiscuity. 1581 */ 1582 refresh(arg, (mip->mi_devpromisc != 0)); 1583 } 1584 1585 boolean_t 1586 mac_active_set(mac_handle_t mh) 1587 { 1588 mac_impl_t *mip = (mac_impl_t *)mh; 1589 1590 mutex_enter(&mip->mi_activelink_lock); 1591 if (mip->mi_activelink) { 1592 mutex_exit(&mip->mi_activelink_lock); 1593 return (B_FALSE); 1594 } 1595 mip->mi_activelink = B_TRUE; 1596 mutex_exit(&mip->mi_activelink_lock); 1597 return (B_TRUE); 1598 } 1599 1600 void 1601 mac_active_clear(mac_handle_t mh) 1602 { 1603 mac_impl_t *mip = (mac_impl_t *)mh; 1604 1605 mutex_enter(&mip->mi_activelink_lock); 1606 ASSERT(mip->mi_activelink); 1607 mip->mi_activelink = B_FALSE; 1608 mutex_exit(&mip->mi_activelink_lock); 1609 } 1610 1611 /* 1612 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1613 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1614 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1615 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1616 * cannot disappear while we are accessing it. 1617 */ 1618 typedef struct i_mac_info_state_s { 1619 const char *mi_name; 1620 mac_info_t *mi_infop; 1621 } i_mac_info_state_t; 1622 1623 /*ARGSUSED*/ 1624 static uint_t 1625 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1626 { 1627 i_mac_info_state_t *statep = arg; 1628 mac_impl_t *mip = (mac_impl_t *)val; 1629 1630 if (mip->mi_disabled) 1631 return (MH_WALK_CONTINUE); 1632 1633 if (strcmp(statep->mi_name, 1634 ddi_driver_name(mip->mi_dip)) != 0) 1635 return (MH_WALK_CONTINUE); 1636 1637 statep->mi_infop = &mip->mi_info; 1638 return (MH_WALK_TERMINATE); 1639 } 1640 1641 boolean_t 1642 mac_info_get(const char *name, mac_info_t *minfop) 1643 { 1644 i_mac_info_state_t state; 1645 1646 rw_enter(&i_mac_impl_lock, RW_READER); 1647 state.mi_name = name; 1648 state.mi_infop = NULL; 1649 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1650 if (state.mi_infop == NULL) { 1651 rw_exit(&i_mac_impl_lock); 1652 return (B_FALSE); 1653 } 1654 *minfop = *state.mi_infop; 1655 rw_exit(&i_mac_impl_lock); 1656 return (B_TRUE); 1657 } 1658 1659 boolean_t 1660 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 1661 { 1662 mac_impl_t *mip = (mac_impl_t *)mh; 1663 1664 if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 1665 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 1666 else 1667 return (B_FALSE); 1668 } 1669 1670 boolean_t 1671 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 1672 { 1673 mac_impl_t *mip = (mac_impl_t *)mh; 1674 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 1675 mip->mi_pdata)); 1676 } 1677 1678 mblk_t * 1679 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 1680 size_t extra_len) 1681 { 1682 mac_impl_t *mip = (mac_impl_t *)mh; 1683 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 1684 mip->mi_pdata, payload, extra_len)); 1685 } 1686 1687 int 1688 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 1689 { 1690 mac_impl_t *mip = (mac_impl_t *)mh; 1691 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 1692 mhip)); 1693 } 1694 1695 mblk_t * 1696 mac_header_cook(mac_handle_t mh, mblk_t *mp) 1697 { 1698 mac_impl_t *mip = (mac_impl_t *)mh; 1699 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 1700 if (DB_REF(mp) > 1) { 1701 mblk_t *newmp = copymsg(mp); 1702 freemsg(mp); 1703 mp = newmp; 1704 } 1705 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 1706 mip->mi_pdata)); 1707 } 1708 return (mp); 1709 } 1710 1711 mblk_t * 1712 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 1713 { 1714 mac_impl_t *mip = (mac_impl_t *)mh; 1715 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 1716 if (DB_REF(mp) > 1) { 1717 mblk_t *newmp = copymsg(mp); 1718 freemsg(mp); 1719 mp = newmp; 1720 } 1721 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 1722 mip->mi_pdata)); 1723 } 1724 return (mp); 1725 } 1726 1727 void 1728 mac_init_ops(struct dev_ops *ops, const char *name) 1729 { 1730 dld_init_ops(ops, name); 1731 } 1732 1733 void 1734 mac_fini_ops(struct dev_ops *ops) 1735 { 1736 dld_fini_ops(ops); 1737 } 1738 1739 /* 1740 * MAC Type Plugin functions. 1741 */ 1742 1743 mactype_register_t * 1744 mactype_alloc(uint_t mactype_version) 1745 { 1746 mactype_register_t *mtrp; 1747 1748 /* 1749 * Make sure there isn't a version mismatch between the plugin and 1750 * the framework. In the future, if multiple versions are 1751 * supported, this check could become more sophisticated. 1752 */ 1753 if (mactype_version != MACTYPE_VERSION) 1754 return (NULL); 1755 1756 mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 1757 mtrp->mtr_version = mactype_version; 1758 return (mtrp); 1759 } 1760 1761 void 1762 mactype_free(mactype_register_t *mtrp) 1763 { 1764 kmem_free(mtrp, sizeof (mactype_register_t)); 1765 } 1766 1767 int 1768 mactype_register(mactype_register_t *mtrp) 1769 { 1770 mactype_t *mtp; 1771 mactype_ops_t *ops = mtrp->mtr_ops; 1772 1773 /* Do some sanity checking before we register this MAC type. */ 1774 if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 1775 return (EINVAL); 1776 1777 /* 1778 * Verify that all mandatory callbacks are set in the ops 1779 * vector. 1780 */ 1781 if (ops->mtops_unicst_verify == NULL || 1782 ops->mtops_multicst_verify == NULL || 1783 ops->mtops_sap_verify == NULL || 1784 ops->mtops_header == NULL || 1785 ops->mtops_header_info == NULL) { 1786 return (EINVAL); 1787 } 1788 1789 mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 1790 mtp->mt_ident = mtrp->mtr_ident; 1791 mtp->mt_ops = *ops; 1792 mtp->mt_type = mtrp->mtr_mactype; 1793 mtp->mt_addr_length = mtrp->mtr_addrlen; 1794 if (mtrp->mtr_brdcst_addr != NULL) { 1795 mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 1796 bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 1797 mtrp->mtr_addrlen); 1798 } 1799 1800 mtp->mt_stats = mtrp->mtr_stats; 1801 mtp->mt_statcount = mtrp->mtr_statcount; 1802 1803 /* 1804 * A MAC-Type plugin only registers when i_mactype_getplugin() does 1805 * an explicit modload() as a result of a driver requesting to use 1806 * that plugin in mac_register(). We pre-emptively set the initial 1807 * reference count to 1 here to prevent the plugin module from 1808 * unloading before the driver's mac_register() completes. If we 1809 * were to initialize the reference count to 0, then there would be 1810 * a window during which the module could unload before the 1811 * reference count could be bumped up to 1. 1812 */ 1813 mtp->mt_ref = 1; 1814 1815 if (mod_hash_insert(i_mactype_hash, 1816 (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 1817 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1818 kmem_free(mtp, sizeof (*mtp)); 1819 return (EEXIST); 1820 } 1821 return (0); 1822 } 1823 1824 int 1825 mactype_unregister(const char *ident) 1826 { 1827 mactype_t *mtp; 1828 mod_hash_val_t val; 1829 int err; 1830 1831 /* 1832 * Let's not allow MAC drivers to use this plugin while we're 1833 * trying to unregister it... 1834 */ 1835 rw_enter(&i_mac_impl_lock, RW_WRITER); 1836 1837 if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 1838 (mod_hash_val_t *)&mtp)) != 0) { 1839 /* A plugin is trying to unregister, but it never registered. */ 1840 rw_exit(&i_mac_impl_lock); 1841 return (ENXIO); 1842 } 1843 1844 if (mtp->mt_ref > 0) { 1845 rw_exit(&i_mac_impl_lock); 1846 return (EBUSY); 1847 } 1848 1849 err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 1850 ASSERT(err == 0); 1851 if (err != 0) { 1852 /* This should never happen, thus the ASSERT() above. */ 1853 rw_exit(&i_mac_impl_lock); 1854 return (EINVAL); 1855 } 1856 ASSERT(mtp == (mactype_t *)val); 1857 1858 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1859 kmem_free(mtp, sizeof (mactype_t)); 1860 rw_exit(&i_mac_impl_lock); 1861 1862 return (0); 1863 } 1864