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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * MAC Services Module 31 */ 32 33 #include <sys/types.h> 34 #include <sys/conf.h> 35 #include <sys/id_space.h> 36 #include <sys/esunddi.h> 37 #include <sys/stat.h> 38 #include <sys/mkdev.h> 39 #include <sys/stream.h> 40 #include <sys/strsun.h> 41 #include <sys/strsubr.h> 42 #include <sys/dlpi.h> 43 #include <sys/dls.h> 44 #include <sys/modhash.h> 45 #include <sys/vlan.h> 46 #include <sys/mac.h> 47 #include <sys/mac_impl.h> 48 #include <sys/dld.h> 49 #include <sys/modctl.h> 50 #include <sys/fs/dv_node.h> 51 #include <sys/thread.h> 52 #include <sys/proc.h> 53 #include <sys/callb.h> 54 #include <sys/cpuvar.h> 55 #include <sys/atomic.h> 56 #include <sys/sdt.h> 57 #include <inet/nd.h> 58 59 #define IMPL_HASHSZ 67 /* prime */ 60 61 static kmem_cache_t *i_mac_impl_cachep; 62 static mod_hash_t *i_mac_impl_hash; 63 krwlock_t i_mac_impl_lock; 64 uint_t i_mac_impl_count; 65 static kmem_cache_t *mac_vnic_tx_cache; 66 static id_space_t *minor_ids; 67 static uint32_t minor_count; 68 69 #define MACTYPE_KMODDIR "mac" 70 #define MACTYPE_HASHSZ 67 71 static mod_hash_t *i_mactype_hash; 72 /* 73 * i_mactype_lock synchronizes threads that obtain references to mactype_t 74 * structures through i_mactype_getplugin(). 75 */ 76 static kmutex_t i_mactype_lock; 77 78 static void i_mac_notify_thread(void *); 79 static mblk_t *mac_vnic_tx(void *, mblk_t *); 80 static mblk_t *mac_vnic_txloop(void *, mblk_t *); 81 82 /* 83 * Private functions. 84 */ 85 86 /*ARGSUSED*/ 87 static int 88 i_mac_constructor(void *buf, void *arg, int kmflag) 89 { 90 mac_impl_t *mip = buf; 91 92 bzero(buf, sizeof (mac_impl_t)); 93 94 mip->mi_linkstate = LINK_STATE_UNKNOWN; 95 96 rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 97 rw_init(&mip->mi_gen_lock, NULL, RW_DRIVER, NULL); 98 rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 99 rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 100 rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 101 rw_init(&mip->mi_tx_lock, NULL, RW_DRIVER, NULL); 102 rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 103 mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 104 mutex_init(&mip->mi_notify_bits_lock, NULL, MUTEX_DRIVER, NULL); 105 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 106 mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL); 107 cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL); 108 return (0); 109 } 110 111 /*ARGSUSED*/ 112 static void 113 i_mac_destructor(void *buf, void *arg) 114 { 115 mac_impl_t *mip = buf; 116 117 ASSERT(mip->mi_ref == 0); 118 ASSERT(!mip->mi_exclusive); 119 ASSERT(mip->mi_active == 0); 120 ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 121 ASSERT(mip->mi_devpromisc == 0); 122 ASSERT(mip->mi_promisc == 0); 123 ASSERT(mip->mi_mmap == NULL); 124 ASSERT(mip->mi_mmrp == NULL); 125 ASSERT(mip->mi_mnfp == NULL); 126 ASSERT(mip->mi_resource_add == NULL); 127 ASSERT(mip->mi_ksp == NULL); 128 ASSERT(mip->mi_kstat_count == 0); 129 ASSERT(mip->mi_notify_bits == 0); 130 ASSERT(mip->mi_notify_thread == NULL); 131 132 rw_destroy(&mip->mi_gen_lock); 133 rw_destroy(&mip->mi_state_lock); 134 rw_destroy(&mip->mi_data_lock); 135 rw_destroy(&mip->mi_notify_lock); 136 rw_destroy(&mip->mi_rx_lock); 137 rw_destroy(&mip->mi_tx_lock); 138 rw_destroy(&mip->mi_resource_lock); 139 mutex_destroy(&mip->mi_activelink_lock); 140 mutex_destroy(&mip->mi_notify_bits_lock); 141 cv_destroy(&mip->mi_notify_cv); 142 mutex_destroy(&mip->mi_lock); 143 cv_destroy(&mip->mi_rx_cv); 144 } 145 146 /* 147 * mac_vnic_tx_t kmem cache support functions. 148 */ 149 150 /* ARGSUSED */ 151 static int 152 i_mac_vnic_tx_ctor(void *buf, void *arg, int mkflag) 153 { 154 mac_vnic_tx_t *vnic_tx = buf; 155 156 bzero(buf, sizeof (mac_vnic_tx_t)); 157 mutex_init(&vnic_tx->mv_lock, NULL, MUTEX_DRIVER, NULL); 158 cv_init(&vnic_tx->mv_cv, NULL, CV_DRIVER, NULL); 159 return (0); 160 } 161 162 /* ARGSUSED */ 163 static void 164 i_mac_vnic_tx_dtor(void *buf, void *arg) 165 { 166 mac_vnic_tx_t *vnic_tx = buf; 167 168 ASSERT(vnic_tx->mv_refs == 0); 169 mutex_destroy(&vnic_tx->mv_lock); 170 cv_destroy(&vnic_tx->mv_cv); 171 } 172 173 static void 174 i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 175 { 176 rw_enter(&i_mac_impl_lock, RW_READER); 177 if (mip->mi_disabled) 178 goto exit; 179 180 /* 181 * Guard against incorrect notifications. (Running a newer 182 * mac client against an older implementation?) 183 */ 184 if (type >= MAC_NNOTE) 185 goto exit; 186 187 mutex_enter(&mip->mi_notify_bits_lock); 188 mip->mi_notify_bits |= (1 << type); 189 cv_broadcast(&mip->mi_notify_cv); 190 mutex_exit(&mip->mi_notify_bits_lock); 191 192 exit: 193 rw_exit(&i_mac_impl_lock); 194 } 195 196 static void 197 i_mac_log_link_state(mac_impl_t *mip) 198 { 199 /* 200 * If no change, then it is not interesting. 201 */ 202 if (mip->mi_lastlinkstate == mip->mi_linkstate) 203 return; 204 205 switch (mip->mi_linkstate) { 206 case LINK_STATE_UP: 207 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) { 208 char det[200]; 209 210 mip->mi_type->mt_ops.mtops_link_details(det, 211 sizeof (det), (mac_handle_t)mip, mip->mi_pdata); 212 213 cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det); 214 } else { 215 cmn_err(CE_NOTE, "!%s link up", mip->mi_name); 216 } 217 break; 218 219 case LINK_STATE_DOWN: 220 /* 221 * Only transitions from UP to DOWN are interesting 222 */ 223 if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN) 224 cmn_err(CE_NOTE, "!%s link down", mip->mi_name); 225 break; 226 227 case LINK_STATE_UNKNOWN: 228 /* 229 * This case is normally not interesting. 230 */ 231 break; 232 } 233 mip->mi_lastlinkstate = mip->mi_linkstate; 234 } 235 236 static void 237 i_mac_notify_thread(void *arg) 238 { 239 mac_impl_t *mip = arg; 240 callb_cpr_t cprinfo; 241 242 CALLB_CPR_INIT(&cprinfo, &mip->mi_notify_bits_lock, callb_generic_cpr, 243 "i_mac_notify_thread"); 244 245 mutex_enter(&mip->mi_notify_bits_lock); 246 for (;;) { 247 uint32_t bits; 248 uint32_t type; 249 250 bits = mip->mi_notify_bits; 251 if (bits == 0) { 252 CALLB_CPR_SAFE_BEGIN(&cprinfo); 253 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); 254 CALLB_CPR_SAFE_END(&cprinfo, &mip->mi_notify_bits_lock); 255 continue; 256 } 257 mip->mi_notify_bits = 0; 258 259 if ((bits & (1 << MAC_NNOTE)) != 0) { 260 /* request to quit */ 261 ASSERT(mip->mi_disabled); 262 break; 263 } 264 265 mutex_exit(&mip->mi_notify_bits_lock); 266 267 /* 268 * Log link changes. 269 */ 270 if ((bits & (1 << MAC_NOTE_LINK)) != 0) 271 i_mac_log_link_state(mip); 272 273 /* 274 * Do notification callbacks for each notification type. 275 */ 276 for (type = 0; type < MAC_NNOTE; type++) { 277 mac_notify_fn_t *mnfp; 278 279 if ((bits & (1 << type)) == 0) { 280 continue; 281 } 282 283 /* 284 * Walk the list of notifications. 285 */ 286 rw_enter(&mip->mi_notify_lock, RW_READER); 287 for (mnfp = mip->mi_mnfp; mnfp != NULL; 288 mnfp = mnfp->mnf_nextp) { 289 290 mnfp->mnf_fn(mnfp->mnf_arg, type); 291 } 292 rw_exit(&mip->mi_notify_lock); 293 } 294 295 mutex_enter(&mip->mi_notify_bits_lock); 296 } 297 298 mip->mi_notify_thread = NULL; 299 cv_broadcast(&mip->mi_notify_cv); 300 301 CALLB_CPR_EXIT(&cprinfo); 302 303 thread_exit(); 304 } 305 306 static mactype_t * 307 i_mactype_getplugin(const char *pname) 308 { 309 mactype_t *mtype = NULL; 310 boolean_t tried_modload = B_FALSE; 311 312 mutex_enter(&i_mactype_lock); 313 314 find_registered_mactype: 315 if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname, 316 (mod_hash_val_t *)&mtype) != 0) { 317 if (!tried_modload) { 318 /* 319 * If the plugin has not yet been loaded, then 320 * attempt to load it now. If modload() succeeds, 321 * the plugin should have registered using 322 * mactype_register(), in which case we can go back 323 * and attempt to find it again. 324 */ 325 if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) { 326 tried_modload = B_TRUE; 327 goto find_registered_mactype; 328 } 329 } 330 } else { 331 /* 332 * Note that there's no danger that the plugin we've loaded 333 * could be unloaded between the modload() step and the 334 * reference count bump here, as we're holding 335 * i_mactype_lock, which mactype_unregister() also holds. 336 */ 337 atomic_inc_32(&mtype->mt_ref); 338 } 339 340 mutex_exit(&i_mactype_lock); 341 return (mtype); 342 } 343 344 /* 345 * Module initialization functions. 346 */ 347 348 void 349 mac_init(void) 350 { 351 i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 352 sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 353 NULL, NULL, NULL, 0); 354 ASSERT(i_mac_impl_cachep != NULL); 355 356 mac_vnic_tx_cache = kmem_cache_create("mac_vnic_tx_cache", 357 sizeof (mac_vnic_tx_t), 0, i_mac_vnic_tx_ctor, i_mac_vnic_tx_dtor, 358 NULL, NULL, NULL, 0); 359 ASSERT(mac_vnic_tx_cache != NULL); 360 361 i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 362 IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 363 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 364 rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 365 i_mac_impl_count = 0; 366 367 i_mactype_hash = mod_hash_create_extended("mactype_hash", 368 MACTYPE_HASHSZ, 369 mod_hash_null_keydtor, mod_hash_null_valdtor, 370 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 371 372 /* 373 * Allocate an id space to manage minor numbers. The range of the 374 * space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal 375 * minor number is MAXMIN, but id_t is type of integer and does not 376 * allow MAXMIN). 377 */ 378 minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1, MAXMIN32); 379 ASSERT(minor_ids != NULL); 380 minor_count = 0; 381 } 382 383 int 384 mac_fini(void) 385 { 386 if (i_mac_impl_count > 0 || minor_count > 0) 387 return (EBUSY); 388 389 id_space_destroy(minor_ids); 390 391 mod_hash_destroy_hash(i_mac_impl_hash); 392 rw_destroy(&i_mac_impl_lock); 393 394 kmem_cache_destroy(i_mac_impl_cachep); 395 kmem_cache_destroy(mac_vnic_tx_cache); 396 397 mod_hash_destroy_hash(i_mactype_hash); 398 return (0); 399 } 400 401 /* 402 * Client functions. 403 */ 404 405 static int 406 mac_hold(const char *macname, mac_impl_t **pmip) 407 { 408 mac_impl_t *mip; 409 int err; 410 411 /* 412 * Check the device name length to make sure it won't overflow our 413 * buffer. 414 */ 415 if (strlen(macname) >= MAXNAMELEN) 416 return (EINVAL); 417 418 /* 419 * Look up its entry in the global hash table. 420 */ 421 rw_enter(&i_mac_impl_lock, RW_WRITER); 422 err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 423 (mod_hash_val_t *)&mip); 424 425 if (err != 0) { 426 rw_exit(&i_mac_impl_lock); 427 return (ENOENT); 428 } 429 430 if (mip->mi_disabled) { 431 rw_exit(&i_mac_impl_lock); 432 return (ENOENT); 433 } 434 435 if (mip->mi_exclusive) { 436 rw_exit(&i_mac_impl_lock); 437 return (EBUSY); 438 } 439 440 mip->mi_ref++; 441 rw_exit(&i_mac_impl_lock); 442 443 *pmip = mip; 444 return (0); 445 } 446 447 static void 448 mac_rele(mac_impl_t *mip) 449 { 450 rw_enter(&i_mac_impl_lock, RW_WRITER); 451 ASSERT(mip->mi_ref != 0); 452 if (--mip->mi_ref == 0) 453 ASSERT(!mip->mi_activelink); 454 rw_exit(&i_mac_impl_lock); 455 } 456 457 int 458 mac_hold_exclusive(mac_handle_t mh) 459 { 460 mac_impl_t *mip = (mac_impl_t *)mh; 461 462 /* 463 * Look up its entry in the global hash table. 464 */ 465 rw_enter(&i_mac_impl_lock, RW_WRITER); 466 if (mip->mi_disabled) { 467 rw_exit(&i_mac_impl_lock); 468 return (ENOENT); 469 } 470 471 if (mip->mi_ref != 0) { 472 rw_exit(&i_mac_impl_lock); 473 return (EBUSY); 474 } 475 476 ASSERT(!mip->mi_exclusive); 477 478 mip->mi_ref++; 479 mip->mi_exclusive = B_TRUE; 480 rw_exit(&i_mac_impl_lock); 481 return (0); 482 } 483 484 void 485 mac_rele_exclusive(mac_handle_t mh) 486 { 487 mac_impl_t *mip = (mac_impl_t *)mh; 488 489 /* 490 * Look up its entry in the global hash table. 491 */ 492 rw_enter(&i_mac_impl_lock, RW_WRITER); 493 ASSERT(mip->mi_ref == 1 && mip->mi_exclusive); 494 mip->mi_ref--; 495 mip->mi_exclusive = B_FALSE; 496 rw_exit(&i_mac_impl_lock); 497 } 498 499 int 500 mac_open(const char *macname, mac_handle_t *mhp) 501 { 502 mac_impl_t *mip; 503 int err; 504 505 /* 506 * Look up its entry in the global hash table. 507 */ 508 if ((err = mac_hold(macname, &mip)) != 0) 509 return (err); 510 511 /* 512 * Hold the dip associated to the MAC to prevent it from being 513 * detached. For a softmac, its underlying dip is held by the 514 * mi_open() callback. 515 * 516 * This is done to be more tolerant with some defective drivers, 517 * which incorrectly handle mac_unregister() failure in their 518 * xxx_detach() routine. For example, some drivers ignore the 519 * failure of mac_unregister() and free all resources that 520 * that are needed for data transmition. 521 */ 522 e_ddi_hold_devi(mip->mi_dip); 523 524 rw_enter(&mip->mi_gen_lock, RW_WRITER); 525 526 if ((mip->mi_oref != 0) || 527 !(mip->mi_callbacks->mc_callbacks & MC_OPEN)) { 528 goto done; 529 } 530 531 /* 532 * Note that we do not hold i_mac_impl_lock when calling the 533 * mc_open() callback function to avoid deadlock with the 534 * i_mac_notify() function. 535 */ 536 if ((err = mip->mi_open(mip->mi_driver)) != 0) { 537 rw_exit(&mip->mi_gen_lock); 538 ddi_release_devi(mip->mi_dip); 539 mac_rele(mip); 540 return (err); 541 } 542 543 done: 544 mip->mi_oref++; 545 rw_exit(&mip->mi_gen_lock); 546 *mhp = (mac_handle_t)mip; 547 return (0); 548 } 549 550 int 551 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp) 552 { 553 dls_dl_handle_t dlh; 554 int err; 555 556 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 557 return (err); 558 559 if (dls_devnet_vid(dlh) != VLAN_ID_NONE) { 560 err = EINVAL; 561 goto done; 562 } 563 564 err = mac_open(dls_devnet_mac(dlh), mhp); 565 566 done: 567 dls_devnet_rele_tmp(dlh); 568 return (err); 569 } 570 571 int 572 mac_open_by_linkname(const char *link, mac_handle_t *mhp) 573 { 574 datalink_id_t linkid; 575 int err; 576 577 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0) 578 return (err); 579 return (mac_open_by_linkid(linkid, mhp)); 580 } 581 582 void 583 mac_close(mac_handle_t mh) 584 { 585 mac_impl_t *mip = (mac_impl_t *)mh; 586 587 rw_enter(&mip->mi_gen_lock, RW_WRITER); 588 589 ASSERT(mip->mi_oref != 0); 590 if (--mip->mi_oref == 0) { 591 if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE)) 592 mip->mi_close(mip->mi_driver); 593 } 594 rw_exit(&mip->mi_gen_lock); 595 596 ddi_release_devi(mip->mi_dip); 597 mac_rele(mip); 598 } 599 600 const mac_info_t * 601 mac_info(mac_handle_t mh) 602 { 603 return (&((mac_impl_t *)mh)->mi_info); 604 } 605 606 dev_info_t * 607 mac_devinfo_get(mac_handle_t mh) 608 { 609 return (((mac_impl_t *)mh)->mi_dip); 610 } 611 612 const char * 613 mac_name(mac_handle_t mh) 614 { 615 return (((mac_impl_t *)mh)->mi_name); 616 } 617 618 minor_t 619 mac_minor(mac_handle_t mh) 620 { 621 return (((mac_impl_t *)mh)->mi_minor); 622 } 623 624 uint64_t 625 mac_stat_get(mac_handle_t mh, uint_t stat) 626 { 627 mac_impl_t *mip = (mac_impl_t *)mh; 628 uint64_t val; 629 int ret; 630 631 /* 632 * The range of stat determines where it is maintained. Stat 633 * values from 0 up to (but not including) MAC_STAT_MIN are 634 * mainteined by the mac module itself. Everything else is 635 * maintained by the driver. 636 */ 637 if (stat < MAC_STAT_MIN) { 638 /* These stats are maintained by the mac module itself. */ 639 switch (stat) { 640 case MAC_STAT_LINK_STATE: 641 return (mip->mi_linkstate); 642 case MAC_STAT_LINK_UP: 643 return (mip->mi_linkstate == LINK_STATE_UP); 644 case MAC_STAT_PROMISC: 645 return (mip->mi_devpromisc != 0); 646 default: 647 ASSERT(B_FALSE); 648 } 649 } 650 651 /* 652 * Call the driver to get the given statistic. 653 */ 654 ret = mip->mi_getstat(mip->mi_driver, stat, &val); 655 if (ret != 0) { 656 /* 657 * The driver doesn't support this statistic. Get the 658 * statistic's default value. 659 */ 660 val = mac_stat_default(mip, stat); 661 } 662 return (val); 663 } 664 665 int 666 mac_start(mac_handle_t mh) 667 { 668 mac_impl_t *mip = (mac_impl_t *)mh; 669 int err; 670 671 ASSERT(mip->mi_start != NULL); 672 673 rw_enter(&(mip->mi_state_lock), RW_WRITER); 674 675 /* 676 * Check whether the device is already started. 677 */ 678 if (mip->mi_active++ != 0) { 679 /* 680 * It's already started so there's nothing more to do. 681 */ 682 err = 0; 683 goto done; 684 } 685 686 /* 687 * Start the device. 688 */ 689 if ((err = mip->mi_start(mip->mi_driver)) != 0) 690 --mip->mi_active; 691 692 done: 693 rw_exit(&(mip->mi_state_lock)); 694 return (err); 695 } 696 697 void 698 mac_stop(mac_handle_t mh) 699 { 700 mac_impl_t *mip = (mac_impl_t *)mh; 701 702 ASSERT(mip->mi_stop != NULL); 703 704 rw_enter(&(mip->mi_state_lock), RW_WRITER); 705 706 /* 707 * Check whether the device is still needed. 708 */ 709 ASSERT(mip->mi_active != 0); 710 if (--mip->mi_active != 0) { 711 /* 712 * It's still needed so there's nothing more to do. 713 */ 714 goto done; 715 } 716 717 /* 718 * Stop the device. 719 */ 720 mip->mi_stop(mip->mi_driver); 721 722 done: 723 rw_exit(&(mip->mi_state_lock)); 724 } 725 726 int 727 mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 728 { 729 mac_impl_t *mip = (mac_impl_t *)mh; 730 mac_multicst_addr_t **pp; 731 mac_multicst_addr_t *p; 732 int err; 733 734 ASSERT(mip->mi_multicst != NULL); 735 736 /* 737 * Verify the address. 738 */ 739 if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 740 mip->mi_pdata)) != 0) { 741 return (err); 742 } 743 744 /* 745 * Check whether the given address is already enabled. 746 */ 747 rw_enter(&(mip->mi_data_lock), RW_WRITER); 748 for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 749 if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 750 0) { 751 /* 752 * The address is already enabled so just bump the 753 * reference count. 754 */ 755 p->mma_ref++; 756 err = 0; 757 goto done; 758 } 759 } 760 761 /* 762 * Allocate a new list entry. 763 */ 764 if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 765 KM_NOSLEEP)) == NULL) { 766 err = ENOMEM; 767 goto done; 768 } 769 770 /* 771 * Enable a new multicast address. 772 */ 773 if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 774 kmem_free(p, sizeof (mac_multicst_addr_t)); 775 goto done; 776 } 777 778 /* 779 * Add the address to the list of enabled addresses. 780 */ 781 bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 782 p->mma_ref++; 783 *pp = p; 784 785 done: 786 rw_exit(&(mip->mi_data_lock)); 787 return (err); 788 } 789 790 int 791 mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 792 { 793 mac_impl_t *mip = (mac_impl_t *)mh; 794 mac_multicst_addr_t **pp; 795 mac_multicst_addr_t *p; 796 int err; 797 798 ASSERT(mip->mi_multicst != NULL); 799 800 /* 801 * Find the entry in the list for the given address. 802 */ 803 rw_enter(&(mip->mi_data_lock), RW_WRITER); 804 for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 805 if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 806 0) { 807 if (--p->mma_ref == 0) 808 break; 809 810 /* 811 * There is still a reference to this address so 812 * there's nothing more to do. 813 */ 814 err = 0; 815 goto done; 816 } 817 } 818 819 /* 820 * We did not find an entry for the given address so it is not 821 * currently enabled. 822 */ 823 if (p == NULL) { 824 err = ENOENT; 825 goto done; 826 } 827 ASSERT(p->mma_ref == 0); 828 829 /* 830 * Disable the multicast address. 831 */ 832 if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 833 p->mma_ref++; 834 goto done; 835 } 836 837 /* 838 * Remove it from the list. 839 */ 840 *pp = p->mma_nextp; 841 kmem_free(p, sizeof (mac_multicst_addr_t)); 842 843 done: 844 rw_exit(&(mip->mi_data_lock)); 845 return (err); 846 } 847 848 /* 849 * mac_unicst_verify: Verifies the passed address. It fails 850 * if the passed address is a group address or has incorrect length. 851 */ 852 boolean_t 853 mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 854 { 855 mac_impl_t *mip = (mac_impl_t *)mh; 856 857 /* 858 * Verify the address. 859 */ 860 if ((len != mip->mi_type->mt_addr_length) || 861 (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 862 mip->mi_pdata)) != 0) { 863 return (B_FALSE); 864 } else { 865 return (B_TRUE); 866 } 867 } 868 869 int 870 mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 871 { 872 mac_impl_t *mip = (mac_impl_t *)mh; 873 int err; 874 boolean_t notify = B_FALSE; 875 876 ASSERT(mip->mi_unicst != NULL); 877 878 /* 879 * Verify the address. 880 */ 881 if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 882 mip->mi_pdata)) != 0) { 883 return (err); 884 } 885 886 /* 887 * Program the new unicast address. 888 */ 889 rw_enter(&(mip->mi_data_lock), RW_WRITER); 890 891 /* 892 * If address doesn't change, do nothing. 893 * This check is necessary otherwise it may call into mac_unicst_set 894 * recursively. 895 */ 896 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) 897 goto done; 898 899 if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 900 goto done; 901 902 /* 903 * Save the address and flag that we need to send a notification. 904 */ 905 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 906 notify = B_TRUE; 907 908 done: 909 rw_exit(&(mip->mi_data_lock)); 910 911 if (notify) 912 i_mac_notify(mip, MAC_NOTE_UNICST); 913 914 return (err); 915 } 916 917 void 918 mac_unicst_get(mac_handle_t mh, uint8_t *addr) 919 { 920 mac_impl_t *mip = (mac_impl_t *)mh; 921 922 /* 923 * Copy out the current unicast source address. 924 */ 925 rw_enter(&(mip->mi_data_lock), RW_READER); 926 bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 927 rw_exit(&(mip->mi_data_lock)); 928 } 929 930 void 931 mac_dest_get(mac_handle_t mh, uint8_t *addr) 932 { 933 mac_impl_t *mip = (mac_impl_t *)mh; 934 935 /* 936 * Copy out the current destination address. 937 */ 938 rw_enter(&(mip->mi_data_lock), RW_READER); 939 bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 940 rw_exit(&(mip->mi_data_lock)); 941 } 942 943 int 944 mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 945 { 946 mac_impl_t *mip = (mac_impl_t *)mh; 947 int err = 0; 948 949 ASSERT(mip->mi_setpromisc != NULL); 950 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 951 952 /* 953 * Determine whether we should enable or disable promiscuous mode. 954 * For details on the distinction between "device promiscuous mode" 955 * and "MAC promiscuous mode", see PSARC/2005/289. 956 */ 957 rw_enter(&(mip->mi_data_lock), RW_WRITER); 958 if (on) { 959 /* 960 * Enable promiscuous mode on the device if not yet enabled. 961 */ 962 if (mip->mi_devpromisc++ == 0) { 963 err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 964 if (err != 0) { 965 mip->mi_devpromisc--; 966 goto done; 967 } 968 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 969 } 970 971 /* 972 * Enable promiscuous mode on the MAC if not yet enabled. 973 */ 974 if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 975 i_mac_notify(mip, MAC_NOTE_PROMISC); 976 } else { 977 if (mip->mi_devpromisc == 0) { 978 err = EPROTO; 979 goto done; 980 } 981 /* 982 * Disable promiscuous mode on the device if this is the last 983 * enabling. 984 */ 985 if (--mip->mi_devpromisc == 0) { 986 err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 987 if (err != 0) { 988 mip->mi_devpromisc++; 989 goto done; 990 } 991 i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 992 } 993 994 /* 995 * Disable promiscuous mode on the MAC if this is the last 996 * enabling. 997 */ 998 if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 999 i_mac_notify(mip, MAC_NOTE_PROMISC); 1000 } 1001 1002 done: 1003 rw_exit(&(mip->mi_data_lock)); 1004 return (err); 1005 } 1006 1007 boolean_t 1008 mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 1009 { 1010 mac_impl_t *mip = (mac_impl_t *)mh; 1011 1012 ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 1013 1014 /* 1015 * Return the current promiscuity. 1016 */ 1017 if (ptype == MAC_DEVPROMISC) 1018 return (mip->mi_devpromisc != 0); 1019 else 1020 return (mip->mi_promisc != 0); 1021 } 1022 1023 void 1024 mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu) 1025 { 1026 mac_impl_t *mip = (mac_impl_t *)mh; 1027 1028 if (min_sdu != NULL) 1029 *min_sdu = mip->mi_sdu_min; 1030 if (max_sdu != NULL) 1031 *max_sdu = mip->mi_sdu_max; 1032 } 1033 1034 void 1035 mac_resources(mac_handle_t mh) 1036 { 1037 mac_impl_t *mip = (mac_impl_t *)mh; 1038 1039 /* 1040 * If the driver supports resource registration, call the driver to 1041 * ask it to register its resources. 1042 */ 1043 if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 1044 mip->mi_resources(mip->mi_driver); 1045 } 1046 1047 void 1048 mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 1049 { 1050 mac_impl_t *mip = (mac_impl_t *)mh; 1051 int cmd; 1052 1053 if (mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP)) { 1054 cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; 1055 if (cmd == ND_SET || cmd == ND_GET) { 1056 /* 1057 * ndd ioctls are Obsolete 1058 */ 1059 cmn_err(CE_WARN, 1060 "The ndd commands are obsolete and may be removed " 1061 "in a future release of Solaris. " 1062 "Use dladm(1M) to manage driver tunables\n"); 1063 } 1064 } 1065 /* 1066 * Call the driver to handle the ioctl. The driver may not support 1067 * any ioctls, in which case we reply with a NAK on its behalf. 1068 */ 1069 if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 1070 mip->mi_ioctl(mip->mi_driver, wq, bp); 1071 else 1072 miocnak(wq, bp, 0, EINVAL); 1073 } 1074 1075 const mac_txinfo_t * 1076 mac_do_tx_get(mac_handle_t mh, boolean_t is_vnic) 1077 { 1078 mac_impl_t *mip = (mac_impl_t *)mh; 1079 mac_txinfo_t *mtp; 1080 1081 /* 1082 * Grab the lock to prevent us from racing with MAC_PROMISC being 1083 * changed. This is sufficient since MAC clients are careful to always 1084 * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 1085 * MAC_PROMISC prior to calling mac_txloop_remove(). 1086 */ 1087 rw_enter(&mip->mi_tx_lock, RW_READER); 1088 1089 if (mac_promisc_get(mh, MAC_PROMISC)) { 1090 ASSERT(mip->mi_mtfp != NULL); 1091 if (mip->mi_vnic_present && !is_vnic) { 1092 mtp = &mip->mi_vnic_txloopinfo; 1093 } else { 1094 mtp = &mip->mi_txloopinfo; 1095 } 1096 } else { 1097 if (mip->mi_vnic_present && !is_vnic) { 1098 mtp = &mip->mi_vnic_txinfo; 1099 } else { 1100 /* 1101 * Note that we cannot ASSERT() that mip->mi_mtfp is 1102 * NULL, because to satisfy the above ASSERT(), we 1103 * have to disable MAC_PROMISC prior to calling 1104 * mac_txloop_remove(). 1105 */ 1106 mtp = &mip->mi_txinfo; 1107 } 1108 } 1109 1110 rw_exit(&mip->mi_tx_lock); 1111 return (mtp); 1112 } 1113 1114 /* 1115 * Invoked by VNIC to obtain the transmit entry point. 1116 */ 1117 const mac_txinfo_t * 1118 mac_vnic_tx_get(mac_handle_t mh) 1119 { 1120 return (mac_do_tx_get(mh, B_TRUE)); 1121 } 1122 1123 /* 1124 * Invoked by any non-VNIC client to obtain the transmit entry point. 1125 * If a VNIC is present, the VNIC transmit function provided by the VNIC 1126 * will be returned to the MAC client. 1127 */ 1128 const mac_txinfo_t * 1129 mac_tx_get(mac_handle_t mh) 1130 { 1131 return (mac_do_tx_get(mh, B_FALSE)); 1132 } 1133 1134 link_state_t 1135 mac_link_get(mac_handle_t mh) 1136 { 1137 return (((mac_impl_t *)mh)->mi_linkstate); 1138 } 1139 1140 mac_notify_handle_t 1141 mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 1142 { 1143 mac_impl_t *mip = (mac_impl_t *)mh; 1144 mac_notify_fn_t *mnfp; 1145 1146 mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 1147 mnfp->mnf_fn = notify; 1148 mnfp->mnf_arg = arg; 1149 1150 /* 1151 * Add it to the head of the 'notify' callback list. 1152 */ 1153 rw_enter(&mip->mi_notify_lock, RW_WRITER); 1154 mnfp->mnf_nextp = mip->mi_mnfp; 1155 mip->mi_mnfp = mnfp; 1156 rw_exit(&mip->mi_notify_lock); 1157 1158 return ((mac_notify_handle_t)mnfp); 1159 } 1160 1161 void 1162 mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 1163 { 1164 mac_impl_t *mip = (mac_impl_t *)mh; 1165 mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 1166 mac_notify_fn_t **pp; 1167 mac_notify_fn_t *p; 1168 1169 /* 1170 * Search the 'notify' callback list for the function closure. 1171 */ 1172 rw_enter(&mip->mi_notify_lock, RW_WRITER); 1173 for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 1174 pp = &(p->mnf_nextp)) { 1175 if (p == mnfp) 1176 break; 1177 } 1178 ASSERT(p != NULL); 1179 1180 /* 1181 * Remove it from the list. 1182 */ 1183 *pp = p->mnf_nextp; 1184 rw_exit(&mip->mi_notify_lock); 1185 1186 /* 1187 * Free it. 1188 */ 1189 kmem_free(mnfp, sizeof (mac_notify_fn_t)); 1190 } 1191 1192 void 1193 mac_notify(mac_handle_t mh) 1194 { 1195 mac_impl_t *mip = (mac_impl_t *)mh; 1196 mac_notify_type_t type; 1197 1198 for (type = 0; type < MAC_NNOTE; type++) 1199 i_mac_notify(mip, type); 1200 } 1201 1202 /* 1203 * Register a receive function for this mac. 1204 * More information on this function's interaction with mac_rx() 1205 * can be found atop mac_rx(). 1206 */ 1207 mac_rx_handle_t 1208 mac_do_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg, boolean_t is_active) 1209 { 1210 mac_impl_t *mip = (mac_impl_t *)mh; 1211 mac_rx_fn_t *mrfp; 1212 1213 mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 1214 mrfp->mrf_fn = rx; 1215 mrfp->mrf_arg = arg; 1216 mrfp->mrf_active = is_active; 1217 1218 /* 1219 * Add it to the head of the 'rx' callback list. 1220 */ 1221 rw_enter(&(mip->mi_rx_lock), RW_WRITER); 1222 1223 /* 1224 * mac_rx() will only call callbacks that are marked inuse. 1225 */ 1226 mrfp->mrf_inuse = B_TRUE; 1227 mrfp->mrf_nextp = mip->mi_mrfp; 1228 1229 /* 1230 * mac_rx() could be traversing the remainder of the list 1231 * and miss the new callback we're adding here. This is not a problem 1232 * because we do not guarantee the callback to take effect immediately 1233 * after mac_rx_add() returns. 1234 */ 1235 mip->mi_mrfp = mrfp; 1236 rw_exit(&(mip->mi_rx_lock)); 1237 1238 return ((mac_rx_handle_t)mrfp); 1239 } 1240 1241 mac_rx_handle_t 1242 mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 1243 { 1244 return (mac_do_rx_add(mh, rx, arg, B_FALSE)); 1245 } 1246 1247 mac_rx_handle_t 1248 mac_active_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 1249 { 1250 return (mac_do_rx_add(mh, rx, arg, B_TRUE)); 1251 } 1252 1253 /* 1254 * Unregister a receive function for this mac. 1255 * This function does not block if wait is B_FALSE. This is useful 1256 * for clients who call mac_rx_remove() from a non-blockable context. 1257 * More information on this function's interaction with mac_rx() 1258 * can be found atop mac_rx(). 1259 */ 1260 void 1261 mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait) 1262 { 1263 mac_impl_t *mip = (mac_impl_t *)mh; 1264 mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 1265 mac_rx_fn_t **pp; 1266 mac_rx_fn_t *p; 1267 1268 /* 1269 * Search the 'rx' callback list for the function closure. 1270 */ 1271 rw_enter(&mip->mi_rx_lock, RW_WRITER); 1272 for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 1273 if (p == mrfp) 1274 break; 1275 } 1276 ASSERT(p != NULL); 1277 1278 /* 1279 * If mac_rx() is running, mark callback for deletion 1280 * and return (if wait is false), or wait until mac_rx() 1281 * exits (if wait is true). 1282 */ 1283 if (mip->mi_rx_ref > 0) { 1284 DTRACE_PROBE1(defer_delete, mac_impl_t *, mip); 1285 p->mrf_inuse = B_FALSE; 1286 mutex_enter(&mip->mi_lock); 1287 mip->mi_rx_removed++; 1288 mutex_exit(&mip->mi_lock); 1289 1290 rw_exit(&mip->mi_rx_lock); 1291 if (wait) 1292 mac_rx_remove_wait(mh); 1293 return; 1294 } 1295 1296 /* Remove it from the list. */ 1297 *pp = p->mrf_nextp; 1298 kmem_free(mrfp, sizeof (mac_rx_fn_t)); 1299 rw_exit(&mip->mi_rx_lock); 1300 } 1301 1302 /* 1303 * Wait for all pending callback removals to be completed by mac_rx(). 1304 * Note that if we call mac_rx_remove() immediately before this, there is no 1305 * guarantee we would wait *only* on the callback that we specified. 1306 * mac_rx_remove() could have been called by other threads and we would have 1307 * to wait for other marked callbacks to be removed as well. 1308 */ 1309 void 1310 mac_rx_remove_wait(mac_handle_t mh) 1311 { 1312 mac_impl_t *mip = (mac_impl_t *)mh; 1313 1314 mutex_enter(&mip->mi_lock); 1315 while (mip->mi_rx_removed > 0) { 1316 DTRACE_PROBE1(need_wait, mac_impl_t *, mip); 1317 cv_wait(&mip->mi_rx_cv, &mip->mi_lock); 1318 } 1319 mutex_exit(&mip->mi_lock); 1320 } 1321 1322 mac_txloop_handle_t 1323 mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 1324 { 1325 mac_impl_t *mip = (mac_impl_t *)mh; 1326 mac_txloop_fn_t *mtfp; 1327 1328 mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 1329 mtfp->mtf_fn = tx; 1330 mtfp->mtf_arg = arg; 1331 1332 /* 1333 * Add it to the head of the 'tx' callback list. 1334 */ 1335 rw_enter(&(mip->mi_tx_lock), RW_WRITER); 1336 mtfp->mtf_nextp = mip->mi_mtfp; 1337 mip->mi_mtfp = mtfp; 1338 rw_exit(&(mip->mi_tx_lock)); 1339 1340 return ((mac_txloop_handle_t)mtfp); 1341 } 1342 1343 /* 1344 * Unregister a transmit function for this mac. This removes the function 1345 * from the list of transmit functions for this mac. 1346 */ 1347 void 1348 mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 1349 { 1350 mac_impl_t *mip = (mac_impl_t *)mh; 1351 mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 1352 mac_txloop_fn_t **pp; 1353 mac_txloop_fn_t *p; 1354 1355 /* 1356 * Search the 'tx' callback list for the function. 1357 */ 1358 rw_enter(&(mip->mi_tx_lock), RW_WRITER); 1359 for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 1360 if (p == mtfp) 1361 break; 1362 } 1363 ASSERT(p != NULL); 1364 1365 /* Remove it from the list. */ 1366 *pp = p->mtf_nextp; 1367 kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 1368 rw_exit(&(mip->mi_tx_lock)); 1369 } 1370 1371 void 1372 mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 1373 { 1374 mac_impl_t *mip = (mac_impl_t *)mh; 1375 1376 /* 1377 * Update the 'resource_add' callbacks. 1378 */ 1379 rw_enter(&(mip->mi_resource_lock), RW_WRITER); 1380 mip->mi_resource_add = add; 1381 mip->mi_resource_add_arg = arg; 1382 rw_exit(&(mip->mi_resource_lock)); 1383 } 1384 1385 /* 1386 * Driver support functions. 1387 */ 1388 1389 mac_register_t * 1390 mac_alloc(uint_t mac_version) 1391 { 1392 mac_register_t *mregp; 1393 1394 /* 1395 * Make sure there isn't a version mismatch between the driver and 1396 * the framework. In the future, if multiple versions are 1397 * supported, this check could become more sophisticated. 1398 */ 1399 if (mac_version != MAC_VERSION) 1400 return (NULL); 1401 1402 mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 1403 mregp->m_version = mac_version; 1404 return (mregp); 1405 } 1406 1407 void 1408 mac_free(mac_register_t *mregp) 1409 { 1410 kmem_free(mregp, sizeof (mac_register_t)); 1411 } 1412 1413 /* 1414 * Allocate a minor number. 1415 */ 1416 minor_t 1417 mac_minor_hold(boolean_t sleep) 1418 { 1419 minor_t minor; 1420 1421 /* 1422 * Grab a value from the arena. 1423 */ 1424 atomic_add_32(&minor_count, 1); 1425 1426 if (sleep) 1427 minor = (uint_t)id_alloc(minor_ids); 1428 else 1429 minor = (uint_t)id_alloc_nosleep(minor_ids); 1430 1431 if (minor == 0) { 1432 atomic_add_32(&minor_count, -1); 1433 return (0); 1434 } 1435 1436 return (minor); 1437 } 1438 1439 /* 1440 * Release a previously allocated minor number. 1441 */ 1442 void 1443 mac_minor_rele(minor_t minor) 1444 { 1445 /* 1446 * Return the value to the arena. 1447 */ 1448 id_free(minor_ids, minor); 1449 atomic_add_32(&minor_count, -1); 1450 } 1451 1452 uint32_t 1453 mac_no_notification(mac_handle_t mh) 1454 { 1455 mac_impl_t *mip = (mac_impl_t *)mh; 1456 return (mip->mi_unsup_note); 1457 } 1458 1459 boolean_t 1460 mac_is_legacy(mac_handle_t mh) 1461 { 1462 mac_impl_t *mip = (mac_impl_t *)mh; 1463 return (mip->mi_legacy); 1464 } 1465 1466 /* 1467 * mac_register() is how drivers register new MACs with the GLDv3 1468 * framework. The mregp argument is allocated by drivers using the 1469 * mac_alloc() function, and can be freed using mac_free() immediately upon 1470 * return from mac_register(). Upon success (0 return value), the mhp 1471 * opaque pointer becomes the driver's handle to its MAC interface, and is 1472 * the argument to all other mac module entry points. 1473 */ 1474 int 1475 mac_register(mac_register_t *mregp, mac_handle_t *mhp) 1476 { 1477 mac_impl_t *mip; 1478 mactype_t *mtype; 1479 int err = EINVAL; 1480 struct devnames *dnp = NULL; 1481 uint_t instance; 1482 boolean_t style1_created = B_FALSE; 1483 boolean_t style2_created = B_FALSE; 1484 mac_capab_legacy_t legacy; 1485 char *driver; 1486 minor_t minor = 0; 1487 1488 /* Find the required MAC-Type plugin. */ 1489 if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 1490 return (EINVAL); 1491 1492 /* Create a mac_impl_t to represent this MAC. */ 1493 mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 1494 1495 /* 1496 * The mac is not ready for open yet. 1497 */ 1498 mip->mi_disabled = B_TRUE; 1499 1500 /* 1501 * When a mac is registered, the m_instance field can be set to: 1502 * 1503 * 0: Get the mac's instance number from m_dip. 1504 * This is usually used for physical device dips. 1505 * 1506 * [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number. 1507 * For example, when an aggregation is created with the key option, 1508 * "key" will be used as the instance number. 1509 * 1510 * -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1]. 1511 * This is often used when a MAC of a virtual link is registered 1512 * (e.g., aggregation when "key" is not specified, or vnic). 1513 * 1514 * Note that the instance number is used to derive the mi_minor field 1515 * of mac_impl_t, which will then be used to derive the name of kstats 1516 * and the devfs nodes. The first 2 cases are needed to preserve 1517 * backward compatibility. 1518 */ 1519 switch (mregp->m_instance) { 1520 case 0: 1521 instance = ddi_get_instance(mregp->m_dip); 1522 break; 1523 case ((uint_t)-1): 1524 minor = mac_minor_hold(B_TRUE); 1525 if (minor == 0) { 1526 err = ENOSPC; 1527 goto fail; 1528 } 1529 instance = minor - 1; 1530 break; 1531 default: 1532 instance = mregp->m_instance; 1533 if (instance >= MAC_MAX_MINOR) { 1534 err = EINVAL; 1535 goto fail; 1536 } 1537 break; 1538 } 1539 1540 mip->mi_minor = (minor_t)(instance + 1); 1541 mip->mi_dip = mregp->m_dip; 1542 1543 driver = (char *)ddi_driver_name(mip->mi_dip); 1544 1545 /* Construct the MAC name as <drvname><instance> */ 1546 (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 1547 driver, instance); 1548 1549 mip->mi_driver = mregp->m_driver; 1550 1551 mip->mi_type = mtype; 1552 mip->mi_margin = mregp->m_margin; 1553 mip->mi_info.mi_media = mtype->mt_type; 1554 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 1555 if (mregp->m_max_sdu <= mregp->m_min_sdu) 1556 goto fail; 1557 mip->mi_sdu_min = mregp->m_min_sdu; 1558 mip->mi_sdu_max = mregp->m_max_sdu; 1559 mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 1560 /* 1561 * If the media supports a broadcast address, cache a pointer to it 1562 * in the mac_info_t so that upper layers can use it. 1563 */ 1564 mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1565 1566 /* 1567 * Copy the unicast source address into the mac_info_t, but only if 1568 * the MAC-Type defines a non-zero address length. We need to 1569 * handle MAC-Types that have an address length of 0 1570 * (point-to-point protocol MACs for example). 1571 */ 1572 if (mip->mi_type->mt_addr_length > 0) { 1573 if (mregp->m_src_addr == NULL) 1574 goto fail; 1575 mip->mi_info.mi_unicst_addr = 1576 kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 1577 bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 1578 mip->mi_type->mt_addr_length); 1579 1580 /* 1581 * Copy the fixed 'factory' MAC address from the immutable 1582 * info. This is taken to be the MAC address currently in 1583 * use. 1584 */ 1585 bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 1586 mip->mi_type->mt_addr_length); 1587 /* Copy the destination address if one is provided. */ 1588 if (mregp->m_dst_addr != NULL) { 1589 bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 1590 mip->mi_type->mt_addr_length); 1591 } 1592 } else if (mregp->m_src_addr != NULL) { 1593 goto fail; 1594 } 1595 1596 /* 1597 * The format of the m_pdata is specific to the plugin. It is 1598 * passed in as an argument to all of the plugin callbacks. The 1599 * driver can update this information by calling 1600 * mac_pdata_update(). 1601 */ 1602 if (mregp->m_pdata != NULL) { 1603 /* 1604 * Verify that the plugin supports MAC plugin data and that 1605 * the supplied data is valid. 1606 */ 1607 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 1608 goto fail; 1609 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 1610 mregp->m_pdata_size)) { 1611 goto fail; 1612 } 1613 mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 1614 bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 1615 mip->mi_pdata_size = mregp->m_pdata_size; 1616 } 1617 1618 /* 1619 * Stash the driver callbacks into the mac_impl_t, but first sanity 1620 * check to make sure all mandatory callbacks are set. 1621 */ 1622 if (mregp->m_callbacks->mc_getstat == NULL || 1623 mregp->m_callbacks->mc_start == NULL || 1624 mregp->m_callbacks->mc_stop == NULL || 1625 mregp->m_callbacks->mc_setpromisc == NULL || 1626 mregp->m_callbacks->mc_multicst == NULL || 1627 mregp->m_callbacks->mc_unicst == NULL || 1628 mregp->m_callbacks->mc_tx == NULL) { 1629 goto fail; 1630 } 1631 mip->mi_callbacks = mregp->m_callbacks; 1632 1633 /* 1634 * Set up the possible transmit routines. 1635 */ 1636 mip->mi_txinfo.mt_fn = mip->mi_tx; 1637 mip->mi_txinfo.mt_arg = mip->mi_driver; 1638 1639 mip->mi_legacy = mac_capab_get((mac_handle_t)mip, 1640 MAC_CAPAB_LEGACY, &legacy); 1641 1642 if (mip->mi_legacy) { 1643 /* 1644 * Legacy device. Messages being sent will be looped back 1645 * by the underlying driver. Therefore the txloop function 1646 * pointer is the same as the tx function pointer. 1647 */ 1648 mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn; 1649 mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg; 1650 mip->mi_unsup_note = legacy.ml_unsup_note; 1651 mip->mi_phy_dev = legacy.ml_dev; 1652 } else { 1653 /* 1654 * Normal device. The framework needs to do the loopback. 1655 */ 1656 mip->mi_txloopinfo.mt_fn = mac_txloop; 1657 mip->mi_txloopinfo.mt_arg = mip; 1658 mip->mi_unsup_note = 0; 1659 mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip), 1660 ddi_get_instance(mip->mi_dip) + 1); 1661 } 1662 1663 mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx; 1664 mip->mi_vnic_txinfo.mt_arg = mip; 1665 1666 mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop; 1667 mip->mi_vnic_txloopinfo.mt_arg = mip; 1668 1669 /* 1670 * Allocate a notification thread. 1671 */ 1672 mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread, 1673 mip, 0, &p0, TS_RUN, minclsyspri); 1674 if (mip->mi_notify_thread == NULL) 1675 goto fail; 1676 1677 /* 1678 * Initialize the kstats for this device. 1679 */ 1680 mac_stat_create(mip); 1681 1682 /* set the gldv3 flag in dn_flags */ 1683 dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 1684 LOCK_DEV_OPS(&dnp->dn_lock); 1685 dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER); 1686 UNLOCK_DEV_OPS(&dnp->dn_lock); 1687 1688 if (mip->mi_minor < MAC_MAX_MINOR + 1) { 1689 /* Create a style-2 DLPI device */ 1690 if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0, 1691 DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 1692 goto fail; 1693 style2_created = B_TRUE; 1694 1695 /* Create a style-1 DLPI device */ 1696 if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, 1697 mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS) 1698 goto fail; 1699 style1_created = B_TRUE; 1700 } 1701 1702 rw_enter(&i_mac_impl_lock, RW_WRITER); 1703 if (mod_hash_insert(i_mac_impl_hash, 1704 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 1705 1706 rw_exit(&i_mac_impl_lock); 1707 err = EEXIST; 1708 goto fail; 1709 } 1710 1711 DTRACE_PROBE2(mac__register, struct devnames *, dnp, 1712 (mac_impl_t *), mip); 1713 1714 /* 1715 * Mark the MAC to be ready for open. 1716 */ 1717 mip->mi_disabled = B_FALSE; 1718 1719 rw_exit(&i_mac_impl_lock); 1720 1721 atomic_inc_32(&i_mac_impl_count); 1722 1723 cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 1724 *mhp = (mac_handle_t)mip; 1725 return (0); 1726 1727 fail: 1728 if (style1_created) 1729 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1730 1731 if (style2_created) 1732 ddi_remove_minor_node(mip->mi_dip, driver); 1733 1734 /* clean up notification thread */ 1735 if (mip->mi_notify_thread != NULL) { 1736 mutex_enter(&mip->mi_notify_bits_lock); 1737 mip->mi_notify_bits = (1 << MAC_NNOTE); 1738 cv_broadcast(&mip->mi_notify_cv); 1739 while (mip->mi_notify_bits != 0) 1740 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); 1741 mutex_exit(&mip->mi_notify_bits_lock); 1742 } 1743 1744 if (mip->mi_info.mi_unicst_addr != NULL) { 1745 kmem_free(mip->mi_info.mi_unicst_addr, 1746 mip->mi_type->mt_addr_length); 1747 mip->mi_info.mi_unicst_addr = NULL; 1748 } 1749 1750 mac_stat_destroy(mip); 1751 1752 if (mip->mi_type != NULL) { 1753 atomic_dec_32(&mip->mi_type->mt_ref); 1754 mip->mi_type = NULL; 1755 } 1756 1757 if (mip->mi_pdata != NULL) { 1758 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1759 mip->mi_pdata = NULL; 1760 mip->mi_pdata_size = 0; 1761 } 1762 1763 if (minor != 0) { 1764 ASSERT(minor > MAC_MAX_MINOR); 1765 mac_minor_rele(minor); 1766 } 1767 1768 kmem_cache_free(i_mac_impl_cachep, mip); 1769 return (err); 1770 } 1771 1772 int 1773 mac_disable(mac_handle_t mh) 1774 { 1775 mac_impl_t *mip = (mac_impl_t *)mh; 1776 1777 /* 1778 * See if there are any other references to this mac_t (e.g., VLAN's). 1779 * If not, set mi_disabled to prevent any new VLAN's from being 1780 * created while we're destroying this mac. 1781 */ 1782 rw_enter(&i_mac_impl_lock, RW_WRITER); 1783 if (mip->mi_ref > 0) { 1784 rw_exit(&i_mac_impl_lock); 1785 return (EBUSY); 1786 } 1787 mip->mi_disabled = B_TRUE; 1788 rw_exit(&i_mac_impl_lock); 1789 return (0); 1790 } 1791 1792 int 1793 mac_unregister(mac_handle_t mh) 1794 { 1795 int err; 1796 mac_impl_t *mip = (mac_impl_t *)mh; 1797 mod_hash_val_t val; 1798 mac_multicst_addr_t *p, *nextp; 1799 mac_margin_req_t *mmr, *nextmmr; 1800 1801 /* 1802 * See if there are any other references to this mac_t (e.g., VLAN's). 1803 * If not, set mi_disabled to prevent any new VLAN's from being 1804 * created while we're destroying this mac. Once mac_disable() returns 1805 * 0, the rest of mac_unregister() stuff should continue without 1806 * returning an error. 1807 */ 1808 if (!mip->mi_disabled) { 1809 if ((err = mac_disable(mh)) != 0) 1810 return (err); 1811 } 1812 1813 /* 1814 * Clean up notification thread (wait for it to exit). 1815 */ 1816 mutex_enter(&mip->mi_notify_bits_lock); 1817 mip->mi_notify_bits = (1 << MAC_NNOTE); 1818 cv_broadcast(&mip->mi_notify_cv); 1819 while (mip->mi_notify_bits != 0) 1820 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); 1821 mutex_exit(&mip->mi_notify_bits_lock); 1822 1823 if (mip->mi_minor < MAC_MAX_MINOR + 1) { 1824 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1825 ddi_remove_minor_node(mip->mi_dip, 1826 (char *)ddi_driver_name(mip->mi_dip)); 1827 } 1828 1829 ASSERT(!mip->mi_activelink); 1830 1831 mac_stat_destroy(mip); 1832 1833 rw_enter(&i_mac_impl_lock, RW_WRITER); 1834 (void) mod_hash_remove(i_mac_impl_hash, 1835 (mod_hash_key_t)mip->mi_name, &val); 1836 ASSERT(mip == (mac_impl_t *)val); 1837 1838 ASSERT(i_mac_impl_count > 0); 1839 atomic_dec_32(&i_mac_impl_count); 1840 rw_exit(&i_mac_impl_lock); 1841 1842 if (mip->mi_pdata != NULL) 1843 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1844 mip->mi_pdata = NULL; 1845 mip->mi_pdata_size = 0; 1846 1847 /* 1848 * Free the list of multicast addresses. 1849 */ 1850 for (p = mip->mi_mmap; p != NULL; p = nextp) { 1851 nextp = p->mma_nextp; 1852 kmem_free(p, sizeof (mac_multicst_addr_t)); 1853 } 1854 mip->mi_mmap = NULL; 1855 1856 /* 1857 * Free the list of margin request. 1858 */ 1859 for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) { 1860 nextmmr = mmr->mmr_nextp; 1861 kmem_free(mmr, sizeof (mac_margin_req_t)); 1862 } 1863 mip->mi_mmrp = NULL; 1864 1865 mip->mi_linkstate = LINK_STATE_UNKNOWN; 1866 kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 1867 mip->mi_info.mi_unicst_addr = NULL; 1868 1869 atomic_dec_32(&mip->mi_type->mt_ref); 1870 mip->mi_type = NULL; 1871 1872 if (mip->mi_minor > MAC_MAX_MINOR) 1873 mac_minor_rele(mip->mi_minor); 1874 1875 cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 1876 1877 kmem_cache_free(i_mac_impl_cachep, mip); 1878 1879 return (0); 1880 } 1881 1882 /* 1883 * To avoid potential deadlocks, mac_rx() releases mi_rx_lock 1884 * before invoking its list of upcalls. This introduces races with 1885 * mac_rx_remove() and mac_rx_add(), who can potentially modify the 1886 * upcall list while mi_rx_lock is not being held. The race with 1887 * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering 1888 * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove() 1889 * to not modify the list but instead mark an upcall for deletion. 1890 * before mac_rx() exits, mi_rx_ref is decremented and if it 1891 * is 0, the marked upcalls will be removed from the list and freed. 1892 * The race with mac_rx_add() is harmless because mac_rx_add() only 1893 * prepends to the list and since mac_rx() saves the list head 1894 * before releasing mi_rx_lock, any prepended upcall won't be seen 1895 * until the next packet chain arrives. 1896 * 1897 * To minimize lock contention between multiple parallel invocations 1898 * of mac_rx(), mi_rx_lock is acquired as a READER lock. The 1899 * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock 1900 * will be upgraded to WRITER mode when there are marked upcalls to be 1901 * cleaned. 1902 */ 1903 static void 1904 mac_do_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain, 1905 boolean_t active_only) 1906 { 1907 mac_impl_t *mip = (mac_impl_t *)mh; 1908 mblk_t *bp = mp_chain; 1909 mac_rx_fn_t *mrfp; 1910 1911 /* 1912 * Call all registered receive functions. 1913 */ 1914 rw_enter(&mip->mi_rx_lock, RW_READER); 1915 if ((mrfp = mip->mi_mrfp) == NULL) { 1916 /* There are no registered receive functions. */ 1917 freemsgchain(bp); 1918 rw_exit(&mip->mi_rx_lock); 1919 return; 1920 } 1921 atomic_inc_32(&mip->mi_rx_ref); 1922 rw_exit(&mip->mi_rx_lock); 1923 1924 /* 1925 * Call registered receive functions. 1926 */ 1927 do { 1928 mblk_t *recv_bp; 1929 1930 if (active_only && !mrfp->mrf_active) { 1931 mrfp = mrfp->mrf_nextp; 1932 if (mrfp == NULL) { 1933 /* 1934 * We hit the last receiver, but it's not 1935 * active. 1936 */ 1937 freemsgchain(bp); 1938 } 1939 continue; 1940 } 1941 1942 recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp; 1943 if (recv_bp != NULL) { 1944 if (mrfp->mrf_inuse) { 1945 /* 1946 * Send bp itself and keep the copy. 1947 * If there's only one active receiver, 1948 * it should get the original message, 1949 * tagged with the hardware checksum flags. 1950 */ 1951 mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp); 1952 bp = recv_bp; 1953 } else { 1954 freemsgchain(recv_bp); 1955 } 1956 } 1957 1958 mrfp = mrfp->mrf_nextp; 1959 } while (mrfp != NULL); 1960 1961 rw_enter(&mip->mi_rx_lock, RW_READER); 1962 if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) { 1963 mac_rx_fn_t **pp, *p; 1964 uint32_t cnt = 0; 1965 1966 DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip); 1967 1968 /* 1969 * Need to become exclusive before doing cleanup 1970 */ 1971 if (rw_tryupgrade(&mip->mi_rx_lock) == 0) { 1972 rw_exit(&mip->mi_rx_lock); 1973 rw_enter(&mip->mi_rx_lock, RW_WRITER); 1974 } 1975 1976 /* 1977 * We return if another thread has already entered and cleaned 1978 * up the list. 1979 */ 1980 if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) { 1981 rw_exit(&mip->mi_rx_lock); 1982 return; 1983 } 1984 1985 /* 1986 * Free removed callbacks. 1987 */ 1988 pp = &mip->mi_mrfp; 1989 while (*pp != NULL) { 1990 if (!(*pp)->mrf_inuse) { 1991 p = *pp; 1992 *pp = (*pp)->mrf_nextp; 1993 kmem_free(p, sizeof (*p)); 1994 cnt++; 1995 continue; 1996 } 1997 pp = &(*pp)->mrf_nextp; 1998 } 1999 2000 /* 2001 * Wake up mac_rx_remove_wait() 2002 */ 2003 mutex_enter(&mip->mi_lock); 2004 ASSERT(mip->mi_rx_removed == cnt); 2005 mip->mi_rx_removed = 0; 2006 cv_broadcast(&mip->mi_rx_cv); 2007 mutex_exit(&mip->mi_lock); 2008 } 2009 rw_exit(&mip->mi_rx_lock); 2010 } 2011 2012 void 2013 mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) 2014 { 2015 mac_do_rx(mh, mrh, mp_chain, B_FALSE); 2016 } 2017 2018 /* 2019 * Send a packet chain up to the receive callbacks which declared 2020 * themselves as being active. 2021 */ 2022 void 2023 mac_active_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp_chain) 2024 { 2025 mac_do_rx(arg, mrh, mp_chain, B_TRUE); 2026 } 2027 2028 /* 2029 * Function passed to the active client sharing a VNIC. This function 2030 * is returned by mac_tx_get() when a VNIC is present. It invokes 2031 * the VNIC transmit entry point which was specified by the VNIC when 2032 * it called mac_vnic_set(). The VNIC transmit entry point will 2033 * pass the packets to the local VNICs and/or to the underlying VNICs 2034 * if needed. 2035 */ 2036 static mblk_t * 2037 mac_vnic_tx(void *arg, mblk_t *mp) 2038 { 2039 mac_impl_t *mip = arg; 2040 mac_txinfo_t *mtfp; 2041 mac_vnic_tx_t *mvt; 2042 2043 /* 2044 * There is a race between the notification of the VNIC 2045 * addition and removal, and the processing of the VNIC notification 2046 * by the MAC client. During this window, it is possible for 2047 * an active MAC client to contine invoking mac_vnic_tx() while 2048 * the VNIC has already been removed. So we cannot assume 2049 * that mi_vnic_present will always be true when mac_vnic_tx() 2050 * is invoked. 2051 */ 2052 rw_enter(&mip->mi_tx_lock, RW_READER); 2053 if (!mip->mi_vnic_present) { 2054 rw_exit(&mip->mi_tx_lock); 2055 freemsgchain(mp); 2056 return (NULL); 2057 } 2058 2059 ASSERT(mip->mi_vnic_tx != NULL); 2060 mvt = mip->mi_vnic_tx; 2061 MAC_VNIC_TXINFO_REFHOLD(mvt); 2062 rw_exit(&mip->mi_tx_lock); 2063 2064 mtfp = &mvt->mv_txinfo; 2065 mtfp->mt_fn(mtfp->mt_arg, mp); 2066 2067 MAC_VNIC_TXINFO_REFRELE(mvt); 2068 return (NULL); 2069 } 2070 2071 /* 2072 * Transmit function -- ONLY used when there are registered loopback listeners. 2073 */ 2074 mblk_t * 2075 mac_do_txloop(void *arg, mblk_t *bp, boolean_t call_vnic) 2076 { 2077 mac_impl_t *mip = arg; 2078 mac_txloop_fn_t *mtfp; 2079 mblk_t *loop_bp, *resid_bp, *next_bp; 2080 2081 if (call_vnic) { 2082 /* 2083 * In promiscous mode, a copy of the sent packet will 2084 * be sent to the client's promiscous receive entry 2085 * points via mac_vnic_tx()-> 2086 * mac_active_rx_promisc()->mac_rx_default(). 2087 */ 2088 return (mac_vnic_tx(arg, bp)); 2089 } 2090 2091 while (bp != NULL) { 2092 next_bp = bp->b_next; 2093 bp->b_next = NULL; 2094 2095 if ((loop_bp = copymsg(bp)) == NULL) 2096 goto noresources; 2097 2098 if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 2099 ASSERT(resid_bp == bp); 2100 freemsg(loop_bp); 2101 goto noresources; 2102 } 2103 2104 rw_enter(&mip->mi_tx_lock, RW_READER); 2105 mtfp = mip->mi_mtfp; 2106 while (mtfp != NULL && loop_bp != NULL) { 2107 bp = loop_bp; 2108 2109 /* XXX counter bump if copymsg() fails? */ 2110 if (mtfp->mtf_nextp != NULL) 2111 loop_bp = copymsg(bp); 2112 else 2113 loop_bp = NULL; 2114 2115 mtfp->mtf_fn(mtfp->mtf_arg, bp); 2116 mtfp = mtfp->mtf_nextp; 2117 } 2118 rw_exit(&mip->mi_tx_lock); 2119 2120 /* 2121 * It's possible we've raced with the disabling of promiscuous 2122 * mode, in which case we can discard our copy. 2123 */ 2124 if (loop_bp != NULL) 2125 freemsg(loop_bp); 2126 2127 bp = next_bp; 2128 } 2129 2130 return (NULL); 2131 2132 noresources: 2133 bp->b_next = next_bp; 2134 return (bp); 2135 } 2136 2137 mblk_t * 2138 mac_txloop(void *arg, mblk_t *bp) 2139 { 2140 return (mac_do_txloop(arg, bp, B_FALSE)); 2141 } 2142 2143 static mblk_t * 2144 mac_vnic_txloop(void *arg, mblk_t *bp) 2145 { 2146 return (mac_do_txloop(arg, bp, B_TRUE)); 2147 } 2148 2149 void 2150 mac_link_update(mac_handle_t mh, link_state_t link) 2151 { 2152 mac_impl_t *mip = (mac_impl_t *)mh; 2153 2154 /* 2155 * Save the link state. 2156 */ 2157 mip->mi_linkstate = link; 2158 2159 /* 2160 * Send a MAC_NOTE_LINK notification. 2161 */ 2162 i_mac_notify(mip, MAC_NOTE_LINK); 2163 } 2164 2165 void 2166 mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 2167 { 2168 mac_impl_t *mip = (mac_impl_t *)mh; 2169 2170 if (mip->mi_type->mt_addr_length == 0) 2171 return; 2172 2173 /* 2174 * If the address has not changed, do nothing. 2175 */ 2176 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) 2177 return; 2178 2179 /* 2180 * Save the address. 2181 */ 2182 bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 2183 2184 /* 2185 * Send a MAC_NOTE_UNICST notification. 2186 */ 2187 i_mac_notify(mip, MAC_NOTE_UNICST); 2188 } 2189 2190 void 2191 mac_tx_update(mac_handle_t mh) 2192 { 2193 /* 2194 * Send a MAC_NOTE_TX notification. 2195 */ 2196 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 2197 } 2198 2199 void 2200 mac_resource_update(mac_handle_t mh) 2201 { 2202 /* 2203 * Send a MAC_NOTE_RESOURCE notification. 2204 */ 2205 i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 2206 } 2207 2208 mac_resource_handle_t 2209 mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 2210 { 2211 mac_impl_t *mip = (mac_impl_t *)mh; 2212 mac_resource_handle_t mrh; 2213 mac_resource_add_t add; 2214 void *arg; 2215 2216 rw_enter(&mip->mi_resource_lock, RW_READER); 2217 add = mip->mi_resource_add; 2218 arg = mip->mi_resource_add_arg; 2219 2220 if (add != NULL) 2221 mrh = add(arg, mrp); 2222 else 2223 mrh = NULL; 2224 rw_exit(&mip->mi_resource_lock); 2225 2226 return (mrh); 2227 } 2228 2229 int 2230 mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 2231 { 2232 mac_impl_t *mip = (mac_impl_t *)mh; 2233 2234 /* 2235 * Verify that the plugin supports MAC plugin data and that the 2236 * supplied data is valid. 2237 */ 2238 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 2239 return (EINVAL); 2240 if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 2241 return (EINVAL); 2242 2243 if (mip->mi_pdata != NULL) 2244 kmem_free(mip->mi_pdata, mip->mi_pdata_size); 2245 2246 mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 2247 bcopy(mac_pdata, mip->mi_pdata, dsize); 2248 mip->mi_pdata_size = dsize; 2249 2250 /* 2251 * Since the MAC plugin data is used to construct MAC headers that 2252 * were cached in fast-path headers, we need to flush fast-path 2253 * information for links associated with this mac. 2254 */ 2255 i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 2256 return (0); 2257 } 2258 2259 void 2260 mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 2261 boolean_t add) 2262 { 2263 mac_impl_t *mip = (mac_impl_t *)mh; 2264 mac_multicst_addr_t *p; 2265 2266 /* 2267 * If no specific refresh function was given then default to the 2268 * driver's m_multicst entry point. 2269 */ 2270 if (refresh == NULL) { 2271 refresh = mip->mi_multicst; 2272 arg = mip->mi_driver; 2273 } 2274 ASSERT(refresh != NULL); 2275 2276 /* 2277 * Walk the multicast address list and call the refresh function for 2278 * each address. 2279 */ 2280 rw_enter(&(mip->mi_data_lock), RW_READER); 2281 for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 2282 refresh(arg, add, p->mma_addr); 2283 rw_exit(&(mip->mi_data_lock)); 2284 } 2285 2286 void 2287 mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 2288 { 2289 mac_impl_t *mip = (mac_impl_t *)mh; 2290 /* 2291 * If no specific refresh function was given then default to the 2292 * driver's mi_unicst entry point. 2293 */ 2294 if (refresh == NULL) { 2295 refresh = mip->mi_unicst; 2296 arg = mip->mi_driver; 2297 } 2298 ASSERT(refresh != NULL); 2299 2300 /* 2301 * Call the refresh function with the current unicast address. 2302 */ 2303 refresh(arg, mip->mi_addr); 2304 } 2305 2306 void 2307 mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 2308 { 2309 mac_impl_t *mip = (mac_impl_t *)mh; 2310 2311 /* 2312 * If no specific refresh function was given then default to the 2313 * driver's m_promisc entry point. 2314 */ 2315 if (refresh == NULL) { 2316 refresh = mip->mi_setpromisc; 2317 arg = mip->mi_driver; 2318 } 2319 ASSERT(refresh != NULL); 2320 2321 /* 2322 * Call the refresh function with the current promiscuity. 2323 */ 2324 refresh(arg, (mip->mi_devpromisc != 0)); 2325 } 2326 2327 /* 2328 * The mac client requests that the mac not to change its margin size to 2329 * be less than the specified value. If "current" is B_TRUE, then the client 2330 * requests the mac not to change its margin size to be smaller than the 2331 * current size. Further, return the current margin size value in this case. 2332 * 2333 * We keep every requested size in an ordered list from largest to smallest. 2334 */ 2335 int 2336 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current) 2337 { 2338 mac_impl_t *mip = (mac_impl_t *)mh; 2339 mac_margin_req_t **pp, *p; 2340 int err = 0; 2341 2342 rw_enter(&(mip->mi_data_lock), RW_WRITER); 2343 if (current) 2344 *marginp = mip->mi_margin; 2345 2346 /* 2347 * If the current margin value cannot satisfy the margin requested, 2348 * return ENOTSUP directly. 2349 */ 2350 if (*marginp > mip->mi_margin) { 2351 err = ENOTSUP; 2352 goto done; 2353 } 2354 2355 /* 2356 * Check whether the given margin is already in the list. If so, 2357 * bump the reference count. 2358 */ 2359 for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) { 2360 if (p->mmr_margin == *marginp) { 2361 /* 2362 * The margin requested is already in the list, 2363 * so just bump the reference count. 2364 */ 2365 p->mmr_ref++; 2366 goto done; 2367 } 2368 if (p->mmr_margin < *marginp) 2369 break; 2370 } 2371 2372 2373 if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) { 2374 err = ENOMEM; 2375 goto done; 2376 } 2377 2378 p->mmr_margin = *marginp; 2379 p->mmr_ref++; 2380 p->mmr_nextp = *pp; 2381 *pp = p; 2382 2383 done: 2384 rw_exit(&(mip->mi_data_lock)); 2385 return (err); 2386 } 2387 2388 /* 2389 * The mac client requests to cancel its previous mac_margin_add() request. 2390 * We remove the requested margin size from the list. 2391 */ 2392 int 2393 mac_margin_remove(mac_handle_t mh, uint32_t margin) 2394 { 2395 mac_impl_t *mip = (mac_impl_t *)mh; 2396 mac_margin_req_t **pp, *p; 2397 int err = 0; 2398 2399 rw_enter(&(mip->mi_data_lock), RW_WRITER); 2400 /* 2401 * Find the entry in the list for the given margin. 2402 */ 2403 for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) { 2404 if (p->mmr_margin == margin) { 2405 if (--p->mmr_ref == 0) 2406 break; 2407 2408 /* 2409 * There is still a reference to this address so 2410 * there's nothing more to do. 2411 */ 2412 goto done; 2413 } 2414 } 2415 2416 /* 2417 * We did not find an entry for the given margin. 2418 */ 2419 if (p == NULL) { 2420 err = ENOENT; 2421 goto done; 2422 } 2423 2424 ASSERT(p->mmr_ref == 0); 2425 2426 /* 2427 * Remove it from the list. 2428 */ 2429 *pp = p->mmr_nextp; 2430 kmem_free(p, sizeof (mac_margin_req_t)); 2431 done: 2432 rw_exit(&(mip->mi_data_lock)); 2433 return (err); 2434 } 2435 2436 /* 2437 * The mac client requests to get the mac's current margin value. 2438 */ 2439 void 2440 mac_margin_get(mac_handle_t mh, uint32_t *marginp) 2441 { 2442 mac_impl_t *mip = (mac_impl_t *)mh; 2443 2444 rw_enter(&(mip->mi_data_lock), RW_READER); 2445 *marginp = mip->mi_margin; 2446 rw_exit(&(mip->mi_data_lock)); 2447 } 2448 2449 boolean_t 2450 mac_margin_update(mac_handle_t mh, uint32_t margin) 2451 { 2452 mac_impl_t *mip = (mac_impl_t *)mh; 2453 uint32_t margin_needed = 0; 2454 2455 rw_enter(&(mip->mi_data_lock), RW_WRITER); 2456 2457 if (mip->mi_mmrp != NULL) 2458 margin_needed = mip->mi_mmrp->mmr_margin; 2459 2460 if (margin_needed <= margin) 2461 mip->mi_margin = margin; 2462 2463 rw_exit(&(mip->mi_data_lock)); 2464 2465 if (margin_needed <= margin) 2466 i_mac_notify(mip, MAC_NOTE_MARGIN); 2467 2468 return (margin_needed <= margin); 2469 } 2470 2471 boolean_t 2472 mac_do_active_set(mac_handle_t mh, boolean_t shareable) 2473 { 2474 mac_impl_t *mip = (mac_impl_t *)mh; 2475 2476 mutex_enter(&mip->mi_activelink_lock); 2477 if (mip->mi_activelink) { 2478 mutex_exit(&mip->mi_activelink_lock); 2479 return (B_FALSE); 2480 } 2481 mip->mi_activelink = B_TRUE; 2482 mip->mi_shareable = shareable; 2483 mutex_exit(&mip->mi_activelink_lock); 2484 return (B_TRUE); 2485 } 2486 2487 /* 2488 * Called by MAC clients. By default, active MAC clients cannot 2489 * share the NIC with VNICs. 2490 */ 2491 boolean_t 2492 mac_active_set(mac_handle_t mh) 2493 { 2494 return (mac_do_active_set(mh, B_FALSE)); 2495 } 2496 2497 /* 2498 * Called by MAC clients which can share the NIC with VNICS, e.g. DLS. 2499 */ 2500 boolean_t 2501 mac_active_shareable_set(mac_handle_t mh) 2502 { 2503 return (mac_do_active_set(mh, B_TRUE)); 2504 } 2505 2506 void 2507 mac_active_clear(mac_handle_t mh) 2508 { 2509 mac_impl_t *mip = (mac_impl_t *)mh; 2510 2511 mutex_enter(&mip->mi_activelink_lock); 2512 ASSERT(mip->mi_activelink); 2513 mip->mi_activelink = B_FALSE; 2514 mutex_exit(&mip->mi_activelink_lock); 2515 } 2516 2517 boolean_t 2518 mac_vnic_set(mac_handle_t mh, mac_txinfo_t *tx_info, mac_getcapab_t getcapab_fn, 2519 void *getcapab_arg) 2520 { 2521 mac_impl_t *mip = (mac_impl_t *)mh; 2522 mac_vnic_tx_t *vnic_tx; 2523 2524 mutex_enter(&mip->mi_activelink_lock); 2525 rw_enter(&mip->mi_tx_lock, RW_WRITER); 2526 ASSERT(!mip->mi_vnic_present); 2527 2528 if (mip->mi_activelink && !mip->mi_shareable) { 2529 /* 2530 * The NIC is already used by an active client which cannot 2531 * share it with VNICs. 2532 */ 2533 rw_exit(&mip->mi_tx_lock); 2534 mutex_exit(&mip->mi_activelink_lock); 2535 return (B_FALSE); 2536 } 2537 2538 vnic_tx = kmem_cache_alloc(mac_vnic_tx_cache, KM_SLEEP); 2539 vnic_tx->mv_refs = 0; 2540 vnic_tx->mv_txinfo = *tx_info; 2541 vnic_tx->mv_clearing = B_FALSE; 2542 2543 mip->mi_vnic_present = B_TRUE; 2544 mip->mi_vnic_tx = vnic_tx; 2545 mip->mi_vnic_getcapab_fn = getcapab_fn; 2546 mip->mi_vnic_getcapab_arg = getcapab_arg; 2547 rw_exit(&mip->mi_tx_lock); 2548 mutex_exit(&mip->mi_activelink_lock); 2549 2550 i_mac_notify(mip, MAC_NOTE_VNIC); 2551 return (B_TRUE); 2552 } 2553 2554 void 2555 mac_vnic_clear(mac_handle_t mh) 2556 { 2557 mac_impl_t *mip = (mac_impl_t *)mh; 2558 mac_vnic_tx_t *vnic_tx; 2559 2560 rw_enter(&mip->mi_tx_lock, RW_WRITER); 2561 ASSERT(mip->mi_vnic_present); 2562 mip->mi_vnic_present = B_FALSE; 2563 /* 2564 * Setting mi_vnic_tx to NULL here under the lock guarantees 2565 * that no new references to the current VNIC transmit structure 2566 * will be taken by mac_vnic_tx(). This is a necessary condition 2567 * for safely waiting for the reference count to drop to 2568 * zero below. 2569 */ 2570 vnic_tx = mip->mi_vnic_tx; 2571 mip->mi_vnic_tx = NULL; 2572 mip->mi_vnic_getcapab_fn = NULL; 2573 mip->mi_vnic_getcapab_arg = NULL; 2574 rw_exit(&mip->mi_tx_lock); 2575 2576 i_mac_notify(mip, MAC_NOTE_VNIC); 2577 2578 /* 2579 * Wait for all TX calls referencing the VNIC transmit 2580 * entry point that was removed to complete. 2581 */ 2582 mutex_enter(&vnic_tx->mv_lock); 2583 vnic_tx->mv_clearing = B_TRUE; 2584 while (vnic_tx->mv_refs > 0) 2585 cv_wait(&vnic_tx->mv_cv, &vnic_tx->mv_lock); 2586 mutex_exit(&vnic_tx->mv_lock); 2587 kmem_cache_free(mac_vnic_tx_cache, vnic_tx); 2588 } 2589 2590 /* 2591 * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 2592 * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 2593 * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 2594 * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 2595 * cannot disappear while we are accessing it. 2596 */ 2597 typedef struct i_mac_info_state_s { 2598 const char *mi_name; 2599 mac_info_t *mi_infop; 2600 } i_mac_info_state_t; 2601 2602 /*ARGSUSED*/ 2603 static uint_t 2604 i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 2605 { 2606 i_mac_info_state_t *statep = arg; 2607 mac_impl_t *mip = (mac_impl_t *)val; 2608 2609 if (mip->mi_disabled) 2610 return (MH_WALK_CONTINUE); 2611 2612 if (strcmp(statep->mi_name, 2613 ddi_driver_name(mip->mi_dip)) != 0) 2614 return (MH_WALK_CONTINUE); 2615 2616 statep->mi_infop = &mip->mi_info; 2617 return (MH_WALK_TERMINATE); 2618 } 2619 2620 boolean_t 2621 mac_info_get(const char *name, mac_info_t *minfop) 2622 { 2623 i_mac_info_state_t state; 2624 2625 rw_enter(&i_mac_impl_lock, RW_READER); 2626 state.mi_name = name; 2627 state.mi_infop = NULL; 2628 mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 2629 if (state.mi_infop == NULL) { 2630 rw_exit(&i_mac_impl_lock); 2631 return (B_FALSE); 2632 } 2633 *minfop = *state.mi_infop; 2634 rw_exit(&i_mac_impl_lock); 2635 return (B_TRUE); 2636 } 2637 2638 boolean_t 2639 mac_do_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data, 2640 boolean_t is_vnic) 2641 { 2642 mac_impl_t *mip = (mac_impl_t *)mh; 2643 2644 if (!is_vnic) { 2645 rw_enter(&mip->mi_tx_lock, RW_READER); 2646 if (mip->mi_vnic_present) { 2647 boolean_t rv; 2648 2649 rv = mip->mi_vnic_getcapab_fn(mip->mi_vnic_getcapab_arg, 2650 cap, cap_data); 2651 rw_exit(&mip->mi_tx_lock); 2652 return (rv); 2653 } 2654 rw_exit(&mip->mi_tx_lock); 2655 } 2656 2657 if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 2658 return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 2659 else 2660 return (B_FALSE); 2661 } 2662 2663 boolean_t 2664 mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 2665 { 2666 return (mac_do_capab_get(mh, cap, cap_data, B_FALSE)); 2667 } 2668 2669 boolean_t 2670 mac_vnic_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 2671 { 2672 return (mac_do_capab_get(mh, cap, cap_data, B_TRUE)); 2673 } 2674 2675 boolean_t 2676 mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 2677 { 2678 mac_impl_t *mip = (mac_impl_t *)mh; 2679 return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 2680 mip->mi_pdata)); 2681 } 2682 2683 mblk_t * 2684 mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 2685 size_t extra_len) 2686 { 2687 mac_impl_t *mip = (mac_impl_t *)mh; 2688 return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 2689 mip->mi_pdata, payload, extra_len)); 2690 } 2691 2692 int 2693 mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 2694 { 2695 mac_impl_t *mip = (mac_impl_t *)mh; 2696 return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 2697 mhip)); 2698 } 2699 2700 mblk_t * 2701 mac_header_cook(mac_handle_t mh, mblk_t *mp) 2702 { 2703 mac_impl_t *mip = (mac_impl_t *)mh; 2704 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 2705 if (DB_REF(mp) > 1) { 2706 mblk_t *newmp = copymsg(mp); 2707 if (newmp == NULL) 2708 return (NULL); 2709 freemsg(mp); 2710 mp = newmp; 2711 } 2712 return (mip->mi_type->mt_ops.mtops_header_cook(mp, 2713 mip->mi_pdata)); 2714 } 2715 return (mp); 2716 } 2717 2718 mblk_t * 2719 mac_header_uncook(mac_handle_t mh, mblk_t *mp) 2720 { 2721 mac_impl_t *mip = (mac_impl_t *)mh; 2722 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 2723 if (DB_REF(mp) > 1) { 2724 mblk_t *newmp = copymsg(mp); 2725 if (newmp == NULL) 2726 return (NULL); 2727 freemsg(mp); 2728 mp = newmp; 2729 } 2730 return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 2731 mip->mi_pdata)); 2732 } 2733 return (mp); 2734 } 2735 2736 void 2737 mac_init_ops(struct dev_ops *ops, const char *name) 2738 { 2739 dld_init_ops(ops, name); 2740 } 2741 2742 void 2743 mac_fini_ops(struct dev_ops *ops) 2744 { 2745 dld_fini_ops(ops); 2746 } 2747 2748 /* 2749 * MAC Type Plugin functions. 2750 */ 2751 2752 mactype_register_t * 2753 mactype_alloc(uint_t mactype_version) 2754 { 2755 mactype_register_t *mtrp; 2756 2757 /* 2758 * Make sure there isn't a version mismatch between the plugin and 2759 * the framework. In the future, if multiple versions are 2760 * supported, this check could become more sophisticated. 2761 */ 2762 if (mactype_version != MACTYPE_VERSION) 2763 return (NULL); 2764 2765 mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 2766 mtrp->mtr_version = mactype_version; 2767 return (mtrp); 2768 } 2769 2770 void 2771 mactype_free(mactype_register_t *mtrp) 2772 { 2773 kmem_free(mtrp, sizeof (mactype_register_t)); 2774 } 2775 2776 int 2777 mactype_register(mactype_register_t *mtrp) 2778 { 2779 mactype_t *mtp; 2780 mactype_ops_t *ops = mtrp->mtr_ops; 2781 2782 /* Do some sanity checking before we register this MAC type. */ 2783 if (mtrp->mtr_ident == NULL || ops == NULL) 2784 return (EINVAL); 2785 2786 /* 2787 * Verify that all mandatory callbacks are set in the ops 2788 * vector. 2789 */ 2790 if (ops->mtops_unicst_verify == NULL || 2791 ops->mtops_multicst_verify == NULL || 2792 ops->mtops_sap_verify == NULL || 2793 ops->mtops_header == NULL || 2794 ops->mtops_header_info == NULL) { 2795 return (EINVAL); 2796 } 2797 2798 mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 2799 mtp->mt_ident = mtrp->mtr_ident; 2800 mtp->mt_ops = *ops; 2801 mtp->mt_type = mtrp->mtr_mactype; 2802 mtp->mt_nativetype = mtrp->mtr_nativetype; 2803 mtp->mt_addr_length = mtrp->mtr_addrlen; 2804 if (mtrp->mtr_brdcst_addr != NULL) { 2805 mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 2806 bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 2807 mtrp->mtr_addrlen); 2808 } 2809 2810 mtp->mt_stats = mtrp->mtr_stats; 2811 mtp->mt_statcount = mtrp->mtr_statcount; 2812 2813 if (mod_hash_insert(i_mactype_hash, 2814 (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 2815 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 2816 kmem_free(mtp, sizeof (*mtp)); 2817 return (EEXIST); 2818 } 2819 return (0); 2820 } 2821 2822 int 2823 mactype_unregister(const char *ident) 2824 { 2825 mactype_t *mtp; 2826 mod_hash_val_t val; 2827 int err; 2828 2829 /* 2830 * Let's not allow MAC drivers to use this plugin while we're 2831 * trying to unregister it. Holding i_mactype_lock also prevents a 2832 * plugin from unregistering while a MAC driver is attempting to 2833 * hold a reference to it in i_mactype_getplugin(). 2834 */ 2835 mutex_enter(&i_mactype_lock); 2836 2837 if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 2838 (mod_hash_val_t *)&mtp)) != 0) { 2839 /* A plugin is trying to unregister, but it never registered. */ 2840 err = ENXIO; 2841 goto done; 2842 } 2843 2844 if (mtp->mt_ref != 0) { 2845 err = EBUSY; 2846 goto done; 2847 } 2848 2849 err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 2850 ASSERT(err == 0); 2851 if (err != 0) { 2852 /* This should never happen, thus the ASSERT() above. */ 2853 err = EINVAL; 2854 goto done; 2855 } 2856 ASSERT(mtp == (mactype_t *)val); 2857 2858 kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 2859 kmem_free(mtp, sizeof (mactype_t)); 2860 done: 2861 mutex_exit(&i_mactype_lock); 2862 return (err); 2863 } 2864 2865 int 2866 mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize) 2867 { 2868 int err = ENOTSUP; 2869 mac_impl_t *mip = (mac_impl_t *)mh; 2870 2871 if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) { 2872 err = mip->mi_callbacks->mc_setprop(mip->mi_driver, 2873 macprop->mp_name, macprop->mp_id, valsize, val); 2874 } 2875 return (err); 2876 } 2877 2878 int 2879 mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize) 2880 { 2881 int err = ENOTSUP; 2882 mac_impl_t *mip = (mac_impl_t *)mh; 2883 2884 if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) { 2885 err = mip->mi_callbacks->mc_getprop(mip->mi_driver, 2886 macprop->mp_name, macprop->mp_id, valsize, val); 2887 } 2888 return (err); 2889 } 2890 2891 int 2892 mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max) 2893 { 2894 mac_impl_t *mip = (mac_impl_t *)mh; 2895 2896 if (sdu_max <= mip->mi_sdu_min) 2897 return (EINVAL); 2898 mip->mi_sdu_max = sdu_max; 2899 2900 /* Send a MAC_NOTE_SDU_SIZE notification. */ 2901 i_mac_notify(mip, MAC_NOTE_SDU_SIZE); 2902 return (0); 2903 } 2904