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