10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51852Syz147064 * Common Development and Distribution License (the "License"). 61852Syz147064 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221852Syz147064 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * MAC Services Module 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/conf.h> 340Sstevel@tonic-gate #include <sys/stat.h> 350Sstevel@tonic-gate #include <sys/stream.h> 360Sstevel@tonic-gate #include <sys/strsun.h> 370Sstevel@tonic-gate #include <sys/strsubr.h> 380Sstevel@tonic-gate #include <sys/dlpi.h> 39269Sericheng #include <sys/modhash.h> 400Sstevel@tonic-gate #include <sys/mac.h> 410Sstevel@tonic-gate #include <sys/mac_impl.h> 42269Sericheng #include <sys/dls.h> 43269Sericheng #include <sys/dld.h> 44*2311Sseb #include <sys/modctl.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */ 470Sstevel@tonic-gate 480Sstevel@tonic-gate static kmem_cache_t *i_mac_impl_cachep; 49269Sericheng static mod_hash_t *i_mac_impl_hash; 50269Sericheng krwlock_t i_mac_impl_lock; 51269Sericheng uint_t i_mac_impl_count; 520Sstevel@tonic-gate 53*2311Sseb #define MACTYPE_KMODDIR "mac" 54*2311Sseb #define MACTYPE_HASHSZ 67 55*2311Sseb static mod_hash_t *i_mactype_hash; 56*2311Sseb 571852Syz147064 static void i_mac_notify_task(void *); 581852Syz147064 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * Private functions. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate /*ARGSUSED*/ 640Sstevel@tonic-gate static int 650Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag) 660Sstevel@tonic-gate { 670Sstevel@tonic-gate mac_impl_t *mip = buf; 680Sstevel@tonic-gate 690Sstevel@tonic-gate bzero(buf, sizeof (mac_impl_t)); 700Sstevel@tonic-gate 71*2311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 720Sstevel@tonic-gate 730Sstevel@tonic-gate rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 740Sstevel@tonic-gate rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 750Sstevel@tonic-gate rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 760Sstevel@tonic-gate rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 770Sstevel@tonic-gate rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 780Sstevel@tonic-gate rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 790Sstevel@tonic-gate mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 801852Syz147064 mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL); 811852Syz147064 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 820Sstevel@tonic-gate return (0); 830Sstevel@tonic-gate } 840Sstevel@tonic-gate 850Sstevel@tonic-gate /*ARGSUSED*/ 860Sstevel@tonic-gate static void 870Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg) 880Sstevel@tonic-gate { 890Sstevel@tonic-gate mac_impl_t *mip = buf; 900Sstevel@tonic-gate 910Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 920Sstevel@tonic-gate ASSERT(mip->mi_active == 0); 93*2311Sseb ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 940Sstevel@tonic-gate ASSERT(mip->mi_devpromisc == 0); 950Sstevel@tonic-gate ASSERT(mip->mi_promisc == 0); 960Sstevel@tonic-gate ASSERT(mip->mi_mmap == NULL); 970Sstevel@tonic-gate ASSERT(mip->mi_mnfp == NULL); 980Sstevel@tonic-gate ASSERT(mip->mi_resource_add == NULL); 990Sstevel@tonic-gate ASSERT(mip->mi_ksp == NULL); 100*2311Sseb ASSERT(mip->mi_kstat_count == 0); 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate rw_destroy(&mip->mi_state_lock); 1030Sstevel@tonic-gate rw_destroy(&mip->mi_data_lock); 1040Sstevel@tonic-gate rw_destroy(&mip->mi_notify_lock); 1050Sstevel@tonic-gate rw_destroy(&mip->mi_rx_lock); 1060Sstevel@tonic-gate rw_destroy(&mip->mi_txloop_lock); 1070Sstevel@tonic-gate rw_destroy(&mip->mi_resource_lock); 1080Sstevel@tonic-gate mutex_destroy(&mip->mi_activelink_lock); 1091852Syz147064 mutex_destroy(&mip->mi_notify_ref_lock); 1101852Syz147064 cv_destroy(&mip->mi_notify_cv); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static void 1140Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 1150Sstevel@tonic-gate { 1161852Syz147064 mac_notify_task_arg_t *mnta; 1171852Syz147064 1181852Syz147064 rw_enter(&i_mac_impl_lock, RW_READER); 1191852Syz147064 if (mip->mi_disabled) 1201852Syz147064 goto exit; 1211852Syz147064 1221852Syz147064 if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) { 1231852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory " 1241852Syz147064 "allocation failed", mip->mi_name, type); 1251852Syz147064 goto exit; 1261852Syz147064 } 1271852Syz147064 1281852Syz147064 mnta->mnt_mip = mip; 1291852Syz147064 mnta->mnt_type = type; 1301852Syz147064 1311852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1321852Syz147064 mip->mi_notify_ref++; 1331852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1341852Syz147064 1351852Syz147064 rw_exit(&i_mac_impl_lock); 1361852Syz147064 1371852Syz147064 if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta, 1381852Syz147064 TQ_NOSLEEP) == NULL) { 1391852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch " 1401852Syz147064 "failed", mip->mi_name, type); 1411852Syz147064 1421852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1431852Syz147064 if (--mip->mi_notify_ref == 0) 1441852Syz147064 cv_signal(&mip->mi_notify_cv); 1451852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1461852Syz147064 1471852Syz147064 kmem_free(mnta, sizeof (*mnta)); 1481852Syz147064 } 1491852Syz147064 return; 1501852Syz147064 1511852Syz147064 exit: 1521852Syz147064 rw_exit(&i_mac_impl_lock); 1531852Syz147064 } 1541852Syz147064 1551852Syz147064 static void 1561852Syz147064 i_mac_notify_task(void *notify_arg) 1571852Syz147064 { 1581852Syz147064 mac_notify_task_arg_t *mnta = (mac_notify_task_arg_t *)notify_arg; 1591852Syz147064 mac_impl_t *mip; 1601852Syz147064 mac_notify_type_t type; 1610Sstevel@tonic-gate mac_notify_fn_t *mnfp; 1620Sstevel@tonic-gate mac_notify_t notify; 1630Sstevel@tonic-gate void *arg; 1640Sstevel@tonic-gate 1651852Syz147064 mip = mnta->mnt_mip; 1661852Syz147064 type = mnta->mnt_type; 1671852Syz147064 kmem_free(mnta, sizeof (*mnta)); 1681852Syz147064 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * Walk the list of notifications. 1710Sstevel@tonic-gate */ 1721852Syz147064 rw_enter(&mip->mi_notify_lock, RW_READER); 1730Sstevel@tonic-gate for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 1740Sstevel@tonic-gate notify = mnfp->mnf_fn; 1750Sstevel@tonic-gate arg = mnfp->mnf_arg; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate ASSERT(notify != NULL); 1780Sstevel@tonic-gate notify(arg, type); 1790Sstevel@tonic-gate } 1801852Syz147064 rw_exit(&mip->mi_notify_lock); 1811852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1821852Syz147064 if (--mip->mi_notify_ref == 0) 1831852Syz147064 cv_signal(&mip->mi_notify_cv); 1841852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 187*2311Sseb static mactype_t * 188*2311Sseb i_mactype_getplugin(const char *plugin_name) 189*2311Sseb { 190*2311Sseb mactype_t *mtype = NULL; 191*2311Sseb boolean_t tried_modload = B_FALSE; 192*2311Sseb 193*2311Sseb find_registered_mactype: 194*2311Sseb if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)plugin_name, 195*2311Sseb (mod_hash_val_t *)&mtype) == 0) { 196*2311Sseb /* 197*2311Sseb * Because the reference count is initialized at 1 (see 198*2311Sseb * mactype_register()), we don't need to bump up the 199*2311Sseb * reference count if we're the first reference. 200*2311Sseb */ 201*2311Sseb if (!tried_modload) 202*2311Sseb mtype->mt_ref++; 203*2311Sseb return (mtype); 204*2311Sseb } else if (tried_modload) { 205*2311Sseb return (NULL); 206*2311Sseb } 207*2311Sseb 208*2311Sseb /* 209*2311Sseb * If the plugin has not yet been loaded, then attempt to load it 210*2311Sseb * now. If modload succeeds, the plugin should have registered 211*2311Sseb * using mactype_register(), in which case we can go back and 212*2311Sseb * attempt to find it again. 213*2311Sseb */ 214*2311Sseb if (modload(MACTYPE_KMODDIR, (char *)plugin_name) != -1) { 215*2311Sseb tried_modload = B_TRUE; 216*2311Sseb goto find_registered_mactype; 217*2311Sseb } 218*2311Sseb return (NULL); 219*2311Sseb } 220*2311Sseb 2210Sstevel@tonic-gate /* 2220Sstevel@tonic-gate * Module initialization functions. 2230Sstevel@tonic-gate */ 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate void 2260Sstevel@tonic-gate mac_init(void) 2270Sstevel@tonic-gate { 2280Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 229*2311Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 230*2311Sseb NULL, NULL, NULL, 0); 2310Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL); 2320Sstevel@tonic-gate 233269Sericheng i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 234269Sericheng IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 235269Sericheng mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 236269Sericheng rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 237269Sericheng i_mac_impl_count = 0; 238*2311Sseb 239*2311Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash", 240*2311Sseb MACTYPE_HASHSZ, 241*2311Sseb mod_hash_null_keydtor, mod_hash_null_valdtor, 242*2311Sseb mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate int 2460Sstevel@tonic-gate mac_fini(void) 2470Sstevel@tonic-gate { 248269Sericheng if (i_mac_impl_count > 0) 249269Sericheng return (EBUSY); 2500Sstevel@tonic-gate 251269Sericheng mod_hash_destroy_hash(i_mac_impl_hash); 252269Sericheng rw_destroy(&i_mac_impl_lock); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate kmem_cache_destroy(i_mac_impl_cachep); 255*2311Sseb 256*2311Sseb mod_hash_destroy_hash(i_mactype_hash); 2570Sstevel@tonic-gate return (0); 2580Sstevel@tonic-gate } 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate /* 2610Sstevel@tonic-gate * Client functions. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate int 265*2311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp) 2660Sstevel@tonic-gate { 2670Sstevel@tonic-gate char driver[MAXNAMELEN]; 2680Sstevel@tonic-gate uint_t instance; 2690Sstevel@tonic-gate major_t major; 2700Sstevel@tonic-gate dev_info_t *dip; 2710Sstevel@tonic-gate mac_impl_t *mip; 2720Sstevel@tonic-gate int err; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our 2760Sstevel@tonic-gate * buffer. 2770Sstevel@tonic-gate */ 278*2311Sseb if (strlen(macname) >= MAXNAMELEN) 2790Sstevel@tonic-gate return (EINVAL); 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * Split the device name into driver and instance components. 2830Sstevel@tonic-gate */ 284*2311Sseb if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS) 2850Sstevel@tonic-gate return (EINVAL); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * Get the major number of the driver. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate if ((major = ddi_name_to_major(driver)) == (major_t)-1) 2910Sstevel@tonic-gate return (EINVAL); 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /* 2940Sstevel@tonic-gate * Hold the given instance to prevent it from being detached. 295269Sericheng * This will also attach the instance if it is not currently attached. 296269Sericheng * Currently we ensure that mac_register() (called by the driver's 297269Sericheng * attach entry point) and all code paths under it cannot possibly 298269Sericheng * call mac_open() because this would lead to a recursive attach 299269Sericheng * panic. 3000Sstevel@tonic-gate */ 301*2311Sseb if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL) 3020Sstevel@tonic-gate return (EINVAL); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * Look up its entry in the global hash table. 3060Sstevel@tonic-gate */ 3070Sstevel@tonic-gate again: 308269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 309*2311Sseb err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 310269Sericheng (mod_hash_val_t *)&mip); 311269Sericheng if (err != 0) { 312269Sericheng err = ENOENT; 3130Sstevel@tonic-gate goto failed; 314269Sericheng } 3150Sstevel@tonic-gate 3161852Syz147064 if (mip->mi_disabled) { 317269Sericheng rw_exit(&i_mac_impl_lock); 3180Sstevel@tonic-gate goto again; 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate mip->mi_ref++; 322269Sericheng rw_exit(&i_mac_impl_lock); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate *mhp = (mac_handle_t)mip; 3250Sstevel@tonic-gate return (0); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate failed: 328269Sericheng rw_exit(&i_mac_impl_lock); 3290Sstevel@tonic-gate ddi_release_devi(dip); 3300Sstevel@tonic-gate return (err); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate void 3340Sstevel@tonic-gate mac_close(mac_handle_t mh) 3350Sstevel@tonic-gate { 3360Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 337*2311Sseb dev_info_t *dip = mip->mi_dip; 3380Sstevel@tonic-gate 339269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate ASSERT(mip->mi_ref != 0); 3420Sstevel@tonic-gate if (--mip->mi_ref == 0) { 3430Sstevel@tonic-gate ASSERT(!mip->mi_activelink); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate ddi_release_devi(dip); 346269Sericheng rw_exit(&i_mac_impl_lock); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate const mac_info_t * 3500Sstevel@tonic-gate mac_info(mac_handle_t mh) 3510Sstevel@tonic-gate { 352*2311Sseb return (&((mac_impl_t *)mh)->mi_info); 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 355269Sericheng dev_info_t * 356269Sericheng mac_devinfo_get(mac_handle_t mh) 357269Sericheng { 358*2311Sseb return (((mac_impl_t *)mh)->mi_dip); 359269Sericheng } 360269Sericheng 3610Sstevel@tonic-gate uint64_t 362*2311Sseb mac_stat_get(mac_handle_t mh, uint_t stat) 3630Sstevel@tonic-gate { 3640Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 365*2311Sseb uint64_t val; 366*2311Sseb int ret; 3670Sstevel@tonic-gate 368*2311Sseb /* 369*2311Sseb * The range of stat determines where it is maintained. Stat 370*2311Sseb * values from 0 up to (but not including) MAC_STAT_MIN are 371*2311Sseb * mainteined by the mac module itself. Everything else is 372*2311Sseb * maintained by the driver. 373*2311Sseb */ 374*2311Sseb if (stat < MAC_STAT_MIN) { 375*2311Sseb /* These stats are maintained by the mac module itself. */ 376*2311Sseb switch (stat) { 377*2311Sseb case MAC_STAT_LINK_STATE: 378*2311Sseb return (mip->mi_linkstate); 379*2311Sseb case MAC_STAT_LINK_UP: 380*2311Sseb return (mip->mi_linkstate == LINK_STATE_UP); 381*2311Sseb case MAC_STAT_PROMISC: 382*2311Sseb return (mip->mi_devpromisc != 0); 383*2311Sseb default: 384*2311Sseb ASSERT(B_FALSE); 385*2311Sseb } 386*2311Sseb } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * Call the driver to get the given statistic. 3900Sstevel@tonic-gate */ 391*2311Sseb ret = mip->mi_getstat(mip->mi_driver, stat, &val); 392*2311Sseb if (ret != 0) { 393*2311Sseb /* 394*2311Sseb * The driver doesn't support this statistic. Get the 395*2311Sseb * statistic's default value. 396*2311Sseb */ 397*2311Sseb val = mac_stat_default(mip, stat); 398*2311Sseb } 399*2311Sseb return (val); 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate int 4030Sstevel@tonic-gate mac_start(mac_handle_t mh) 4040Sstevel@tonic-gate { 4050Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4060Sstevel@tonic-gate int err; 4070Sstevel@tonic-gate 408*2311Sseb ASSERT(mip->mi_start != NULL); 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Check whether the device is already started. 4140Sstevel@tonic-gate */ 4150Sstevel@tonic-gate if (mip->mi_active++ != 0) { 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * It's already started so there's nothing more to do. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate err = 0; 4200Sstevel@tonic-gate goto done; 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* 4240Sstevel@tonic-gate * Start the device. 4250Sstevel@tonic-gate */ 426*2311Sseb if ((err = mip->mi_start(mip->mi_driver)) != 0) 4270Sstevel@tonic-gate --mip->mi_active; 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate done: 4300Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 4310Sstevel@tonic-gate return (err); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate void 4350Sstevel@tonic-gate mac_stop(mac_handle_t mh) 4360Sstevel@tonic-gate { 4370Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4380Sstevel@tonic-gate 439*2311Sseb ASSERT(mip->mi_stop != NULL); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate /* 4440Sstevel@tonic-gate * Check whether the device is still needed. 4450Sstevel@tonic-gate */ 4460Sstevel@tonic-gate ASSERT(mip->mi_active != 0); 4470Sstevel@tonic-gate if (--mip->mi_active != 0) { 4480Sstevel@tonic-gate /* 4490Sstevel@tonic-gate * It's still needed so there's nothing more to do. 4500Sstevel@tonic-gate */ 4510Sstevel@tonic-gate goto done; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* 4550Sstevel@tonic-gate * Stop the device. 4560Sstevel@tonic-gate */ 457*2311Sseb mip->mi_stop(mip->mi_driver); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate done: 4600Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate int 4640Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 4650Sstevel@tonic-gate { 4660Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4670Sstevel@tonic-gate mac_multicst_addr_t **pp; 4680Sstevel@tonic-gate mac_multicst_addr_t *p; 4690Sstevel@tonic-gate int err; 4700Sstevel@tonic-gate 471*2311Sseb ASSERT(mip->mi_multicst != NULL); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * Verify the address. 4750Sstevel@tonic-gate */ 476*2311Sseb if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 477*2311Sseb mip->mi_pdata)) != 0) { 478*2311Sseb return (err); 479*2311Sseb } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate /* 4820Sstevel@tonic-gate * Check whether the given address is already enabled. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 4850Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 486*2311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 487*2311Sseb 0) { 4880Sstevel@tonic-gate /* 4890Sstevel@tonic-gate * The address is already enabled so just bump the 4900Sstevel@tonic-gate * reference count. 4910Sstevel@tonic-gate */ 4920Sstevel@tonic-gate p->mma_ref++; 4930Sstevel@tonic-gate err = 0; 4940Sstevel@tonic-gate goto done; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* 4990Sstevel@tonic-gate * Allocate a new list entry. 5000Sstevel@tonic-gate */ 5010Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 5020Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 5030Sstevel@tonic-gate err = ENOMEM; 5040Sstevel@tonic-gate goto done; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate /* 5080Sstevel@tonic-gate * Enable a new multicast address. 5090Sstevel@tonic-gate */ 510*2311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 5110Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 5120Sstevel@tonic-gate goto done; 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* 5160Sstevel@tonic-gate * Add the address to the list of enabled addresses. 5170Sstevel@tonic-gate */ 518*2311Sseb bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 5190Sstevel@tonic-gate p->mma_ref++; 5200Sstevel@tonic-gate *pp = p; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate done: 5230Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 5240Sstevel@tonic-gate return (err); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate int 5280Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 5290Sstevel@tonic-gate { 5300Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5310Sstevel@tonic-gate mac_multicst_addr_t **pp; 5320Sstevel@tonic-gate mac_multicst_addr_t *p; 5330Sstevel@tonic-gate int err; 5340Sstevel@tonic-gate 535*2311Sseb ASSERT(mip->mi_multicst != NULL); 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /* 5380Sstevel@tonic-gate * Find the entry in the list for the given address. 5390Sstevel@tonic-gate */ 5400Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 5410Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 542*2311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 543*2311Sseb 0) { 5440Sstevel@tonic-gate if (--p->mma_ref == 0) 5450Sstevel@tonic-gate break; 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * There is still a reference to this address so 5490Sstevel@tonic-gate * there's nothing more to do. 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate err = 0; 5520Sstevel@tonic-gate goto done; 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate /* 5570Sstevel@tonic-gate * We did not find an entry for the given address so it is not 5580Sstevel@tonic-gate * currently enabled. 5590Sstevel@tonic-gate */ 5600Sstevel@tonic-gate if (p == NULL) { 5610Sstevel@tonic-gate err = ENOENT; 5620Sstevel@tonic-gate goto done; 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate ASSERT(p->mma_ref == 0); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * Disable the multicast address. 5680Sstevel@tonic-gate */ 569*2311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 5700Sstevel@tonic-gate p->mma_ref++; 5710Sstevel@tonic-gate goto done; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* 5750Sstevel@tonic-gate * Remove it from the list. 5760Sstevel@tonic-gate */ 5770Sstevel@tonic-gate *pp = p->mma_nextp; 5780Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate done: 5810Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 5820Sstevel@tonic-gate return (err); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate int 5860Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 5870Sstevel@tonic-gate { 5880Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5890Sstevel@tonic-gate int err; 5900Sstevel@tonic-gate boolean_t notify = B_FALSE; 5910Sstevel@tonic-gate 592*2311Sseb ASSERT(mip->mi_unicst != NULL); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * Verify the address. 5960Sstevel@tonic-gate */ 597*2311Sseb if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 598*2311Sseb mip->mi_pdata)) != 0) { 599*2311Sseb return (err); 600*2311Sseb } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* 6030Sstevel@tonic-gate * Program the new unicast address. 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * If address doesn't change, do nothing. 6090Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 6100Sstevel@tonic-gate * recursively. 6110Sstevel@tonic-gate */ 612*2311Sseb if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 6130Sstevel@tonic-gate err = 0; 6140Sstevel@tonic-gate goto done; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 617*2311Sseb if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 6180Sstevel@tonic-gate goto done; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* 6210Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 6220Sstevel@tonic-gate */ 623*2311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 6240Sstevel@tonic-gate notify = B_TRUE; 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate done: 6270Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if (notify) 6300Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate return (err); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate void 6360Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 6370Sstevel@tonic-gate { 6380Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /* 641*2311Sseb * Copy out the current unicast source address. 6420Sstevel@tonic-gate */ 6430Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 644*2311Sseb bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 645*2311Sseb rw_exit(&(mip->mi_data_lock)); 646*2311Sseb } 647*2311Sseb 648*2311Sseb void 649*2311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr) 650*2311Sseb { 651*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 652*2311Sseb 653*2311Sseb /* 654*2311Sseb * Copy out the current destination address. 655*2311Sseb */ 656*2311Sseb rw_enter(&(mip->mi_data_lock), RW_READER); 657*2311Sseb bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 6580Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate int 6620Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 6630Sstevel@tonic-gate { 6640Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6650Sstevel@tonic-gate int err = 0; 6660Sstevel@tonic-gate 667*2311Sseb ASSERT(mip->mi_setpromisc != NULL); 6680Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 6720Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 6730Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 6740Sstevel@tonic-gate */ 6750Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6760Sstevel@tonic-gate if (on) { 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 6790Sstevel@tonic-gate */ 6800Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 681*2311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 682*2311Sseb if (err != 0) { 6830Sstevel@tonic-gate mip->mi_devpromisc--; 6840Sstevel@tonic-gate goto done; 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate /* 6900Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 6910Sstevel@tonic-gate */ 6920Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 6930Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 6940Sstevel@tonic-gate } else { 6950Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 6960Sstevel@tonic-gate err = EPROTO; 6970Sstevel@tonic-gate goto done; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 7020Sstevel@tonic-gate * enabling. 7030Sstevel@tonic-gate */ 7040Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 705*2311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 706*2311Sseb if (err != 0) { 7070Sstevel@tonic-gate mip->mi_devpromisc++; 7080Sstevel@tonic-gate goto done; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 7150Sstevel@tonic-gate * enabling. 7160Sstevel@tonic-gate */ 7170Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 7180Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate done: 7220Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7230Sstevel@tonic-gate return (err); 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate boolean_t 7270Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 7280Sstevel@tonic-gate { 7290Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate /* 7340Sstevel@tonic-gate * Return the current promiscuity. 7350Sstevel@tonic-gate */ 7360Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 7370Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 7380Sstevel@tonic-gate else 7390Sstevel@tonic-gate return (mip->mi_promisc != 0); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate void 7430Sstevel@tonic-gate mac_resources(mac_handle_t mh) 7440Sstevel@tonic-gate { 7450Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate /* 748*2311Sseb * If the driver supports resource registration, call the driver to 749*2311Sseb * ask it to register its resources. 7500Sstevel@tonic-gate */ 751*2311Sseb if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 752*2311Sseb mip->mi_resources(mip->mi_driver); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate void 7560Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 7570Sstevel@tonic-gate { 7580Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 761*2311Sseb * Call the driver to handle the ioctl. The driver may not support 762*2311Sseb * any ioctls, in which case we reply with a NAK on its behalf. 7630Sstevel@tonic-gate */ 764*2311Sseb if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 765*2311Sseb mip->mi_ioctl(mip->mi_driver, wq, bp); 766*2311Sseb else 767*2311Sseb miocnak(wq, bp, 0, EINVAL); 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 77056Smeem const mac_txinfo_t * 77156Smeem mac_tx_get(mac_handle_t mh) 7720Sstevel@tonic-gate { 7730Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 77456Smeem mac_txinfo_t *mtp; 77556Smeem 77656Smeem /* 77756Smeem * Grab the lock to prevent us from racing with MAC_PROMISC being 77856Smeem * changed. This is sufficient since MAC clients are careful to always 77956Smeem * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 78056Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 78156Smeem */ 78256Smeem rw_enter(&mip->mi_txloop_lock, RW_READER); 7830Sstevel@tonic-gate 78456Smeem if (mac_promisc_get(mh, MAC_PROMISC)) { 78556Smeem ASSERT(mip->mi_mtfp != NULL); 78656Smeem mtp = &mip->mi_txloopinfo; 78756Smeem } else { 78856Smeem /* 78956Smeem * Note that we cannot ASSERT() that mip->mi_mtfp is NULL, 79056Smeem * because to satisfy the above ASSERT(), we have to disable 79156Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 79256Smeem */ 79356Smeem mtp = &mip->mi_txinfo; 79456Smeem } 79556Smeem 79656Smeem rw_exit(&mip->mi_txloop_lock); 79756Smeem return (mtp); 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate link_state_t 8010Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 8020Sstevel@tonic-gate { 803*2311Sseb return (((mac_impl_t *)mh)->mi_linkstate); 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate mac_notify_handle_t 8070Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 8080Sstevel@tonic-gate { 8090Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8100Sstevel@tonic-gate mac_notify_fn_t *mnfp; 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 8130Sstevel@tonic-gate mnfp->mnf_fn = notify; 8140Sstevel@tonic-gate mnfp->mnf_arg = arg; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 8180Sstevel@tonic-gate */ 8191852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8200Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 8210Sstevel@tonic-gate mip->mi_mnfp = mnfp; 8221852Syz147064 rw_exit(&mip->mi_notify_lock); 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate void 8280Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 8290Sstevel@tonic-gate { 8300Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8310Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 8320Sstevel@tonic-gate mac_notify_fn_t **pp; 8330Sstevel@tonic-gate mac_notify_fn_t *p; 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 8370Sstevel@tonic-gate */ 8381852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8390Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 8400Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 8410Sstevel@tonic-gate if (p == mnfp) 8420Sstevel@tonic-gate break; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate ASSERT(p != NULL); 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate /* 8470Sstevel@tonic-gate * Remove it from the list. 8480Sstevel@tonic-gate */ 8490Sstevel@tonic-gate *pp = p->mnf_nextp; 8501852Syz147064 rw_exit(&mip->mi_notify_lock); 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate /* 8530Sstevel@tonic-gate * Free it. 8540Sstevel@tonic-gate */ 8550Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate void 8590Sstevel@tonic-gate mac_notify(mac_handle_t mh) 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8620Sstevel@tonic-gate mac_notify_type_t type; 8630Sstevel@tonic-gate 8640Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 8650Sstevel@tonic-gate i_mac_notify(mip, type); 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate mac_rx_handle_t 8690Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 8700Sstevel@tonic-gate { 8710Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8720Sstevel@tonic-gate mac_rx_fn_t *mrfp; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 8750Sstevel@tonic-gate mrfp->mrf_fn = rx; 8760Sstevel@tonic-gate mrfp->mrf_arg = arg; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate /* 8790Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 8800Sstevel@tonic-gate */ 8810Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 8820Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 8830Sstevel@tonic-gate mip->mi_mrfp = mrfp; 8840Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate /* 8900Sstevel@tonic-gate * Unregister a receive function for this mac. This removes the function 8910Sstevel@tonic-gate * from the list of receive functions for this mac. 8920Sstevel@tonic-gate */ 8930Sstevel@tonic-gate void 8940Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 8950Sstevel@tonic-gate { 8960Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8970Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 8980Sstevel@tonic-gate mac_rx_fn_t **pp; 8990Sstevel@tonic-gate mac_rx_fn_t *p; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate /* 9020Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 9030Sstevel@tonic-gate */ 9040Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9050Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 9060Sstevel@tonic-gate if (p == mrfp) 9070Sstevel@tonic-gate break; 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate ASSERT(p != NULL); 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate /* Remove it from the list. */ 9120Sstevel@tonic-gate *pp = p->mrf_nextp; 9130Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 9140Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate mac_txloop_handle_t 9180Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 9190Sstevel@tonic-gate { 9200Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9210Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 9240Sstevel@tonic-gate mtfp->mtf_fn = tx; 9250Sstevel@tonic-gate mtfp->mtf_arg = arg; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* 9280Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 9310Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 9320Sstevel@tonic-gate mip->mi_mtfp = mtfp; 9330Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* 9390Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 9400Sstevel@tonic-gate * from the list of transmit functions for this mac. 9410Sstevel@tonic-gate */ 9420Sstevel@tonic-gate void 9430Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9460Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 9470Sstevel@tonic-gate mac_txloop_fn_t **pp; 9480Sstevel@tonic-gate mac_txloop_fn_t *p; 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate /* 9510Sstevel@tonic-gate * Search the 'tx' callback list for the function. 9520Sstevel@tonic-gate */ 9530Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 9540Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 9550Sstevel@tonic-gate if (p == mtfp) 9560Sstevel@tonic-gate break; 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate ASSERT(p != NULL); 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* Remove it from the list. */ 9610Sstevel@tonic-gate *pp = p->mtf_nextp; 9620Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 9630Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 9640Sstevel@tonic-gate } 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate void 9670Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 9680Sstevel@tonic-gate { 9690Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate /* 9720Sstevel@tonic-gate * Update the 'resource_add' callbacks. 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 9750Sstevel@tonic-gate mip->mi_resource_add = add; 9760Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 9770Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate /* 9810Sstevel@tonic-gate * Driver support functions. 9820Sstevel@tonic-gate */ 9830Sstevel@tonic-gate 984*2311Sseb mac_register_t * 985*2311Sseb mac_alloc(uint_t mac_version) 9860Sstevel@tonic-gate { 987*2311Sseb mac_register_t *mregp; 988*2311Sseb 989*2311Sseb /* 990*2311Sseb * Make sure there isn't a version mismatch between the driver and 991*2311Sseb * the framework. In the future, if multiple versions are 992*2311Sseb * supported, this check could become more sophisticated. 993*2311Sseb */ 994*2311Sseb if (mac_version != MAC_VERSION) 995*2311Sseb return (NULL); 996*2311Sseb 997*2311Sseb mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 998*2311Sseb mregp->m_version = mac_version; 999*2311Sseb return (mregp); 1000*2311Sseb } 1001*2311Sseb 1002*2311Sseb void 1003*2311Sseb mac_free(mac_register_t *mregp) 1004*2311Sseb { 1005*2311Sseb kmem_free(mregp, sizeof (mac_register_t)); 1006*2311Sseb } 1007*2311Sseb 1008*2311Sseb /* 1009*2311Sseb * mac_register() is how drivers register new MACs with the GLDv3 1010*2311Sseb * framework. The mregp argument is allocated by drivers using the 1011*2311Sseb * mac_alloc() function, and can be freed using mac_free() immediately upon 1012*2311Sseb * return from mac_register(). Upon success (0 return value), the mhp 1013*2311Sseb * opaque pointer becomes the driver's handle to its MAC interface, and is 1014*2311Sseb * the argument to all other mac module entry points. 1015*2311Sseb */ 1016*2311Sseb /* ARGSUSED */ 1017*2311Sseb int 1018*2311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 1019*2311Sseb { 1020*2311Sseb mac_impl_t *mip; 1021*2311Sseb mactype_t *mtype; 1022*2311Sseb int err; 10230Sstevel@tonic-gate struct devnames *dnp; 1024*2311Sseb minor_t minor; 1025*2311Sseb mod_hash_val_t val; 1026*2311Sseb boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 1027*2311Sseb 1028*2311Sseb /* Find the required MAC-Type plugin. */ 1029*2311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 1030*2311Sseb return (EINVAL); 1031*2311Sseb 1032*2311Sseb /* Create a mac_impl_t to represent this MAC. */ 1033*2311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 1034*2311Sseb 1035*2311Sseb /* 1036*2311Sseb * The mac is not ready for open yet. 1037*2311Sseb */ 1038*2311Sseb mip->mi_disabled = B_TRUE; 1039*2311Sseb 1040*2311Sseb mip->mi_drvname = ddi_driver_name(mregp->m_dip); 1041*2311Sseb /* 1042*2311Sseb * Some drivers such as aggr need to register multiple MACs. Such 1043*2311Sseb * drivers must supply a non-zero "instance" argument so that each 1044*2311Sseb * MAC can be assigned a unique MAC name and can have unique 1045*2311Sseb * kstats. 1046*2311Sseb */ 1047*2311Sseb mip->mi_instance = ((mregp->m_instance == 0) ? 1048*2311Sseb ddi_get_instance(mregp->m_dip) : mregp->m_instance); 1049*2311Sseb 1050*2311Sseb /* Construct the MAC name as <drvname><instance> */ 1051*2311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 1052*2311Sseb mip->mi_drvname, mip->mi_instance); 1053*2311Sseb 1054*2311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 1055*2311Sseb if (mod_hash_insert(i_mac_impl_hash, 1056*2311Sseb (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 1057*2311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 1058*2311Sseb rw_exit(&i_mac_impl_lock); 1059*2311Sseb return (EEXIST); 1060*2311Sseb } 1061*2311Sseb i_mac_impl_count++; 1062*2311Sseb 1063*2311Sseb mip->mi_driver = mregp->m_driver; 1064*2311Sseb 1065*2311Sseb mip->mi_type = mtype; 10660Sstevel@tonic-gate 1067*2311Sseb mip->mi_info.mi_media = mtype->mt_type; 1068*2311Sseb mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 1069*2311Sseb if (mregp->m_max_sdu <= mregp->m_min_sdu) { 1070*2311Sseb err = EINVAL; 1071*2311Sseb goto fail; 1072*2311Sseb } 1073*2311Sseb mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 1074*2311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 1075*2311Sseb /* 1076*2311Sseb * If the media supports a broadcast address, cache a pointer to it 1077*2311Sseb * in the mac_info_t so that upper layers can use it. 1078*2311Sseb */ 1079*2311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1080269Sericheng 1081*2311Sseb /* 1082*2311Sseb * Copy the unicast source address into the mac_info_t, but only if 1083*2311Sseb * the MAC-Type defines a non-zero address length. We need to 1084*2311Sseb * handle MAC-Types that have an address length of 0 1085*2311Sseb * (point-to-point protocol MACs for example). 1086*2311Sseb */ 1087*2311Sseb if (mip->mi_type->mt_addr_length > 0) { 1088*2311Sseb if (mregp->m_src_addr == NULL) { 1089*2311Sseb err = EINVAL; 1090*2311Sseb goto fail; 1091*2311Sseb } 1092*2311Sseb mip->mi_info.mi_unicst_addr = 1093*2311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 1094*2311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 1095*2311Sseb mip->mi_type->mt_addr_length); 1096*2311Sseb 1097*2311Sseb /* 1098*2311Sseb * Copy the fixed 'factory' MAC address from the immutable 1099*2311Sseb * info. This is taken to be the MAC address currently in 1100*2311Sseb * use. 1101*2311Sseb */ 1102*2311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 1103*2311Sseb mip->mi_type->mt_addr_length); 1104*2311Sseb /* Copy the destination address if one is provided. */ 1105*2311Sseb if (mregp->m_dst_addr != NULL) { 1106*2311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 1107*2311Sseb mip->mi_type->mt_addr_length); 1108*2311Sseb } 1109*2311Sseb } else if (mregp->m_src_addr != NULL) { 1110*2311Sseb err = EINVAL; 1111*2311Sseb goto fail; 1112269Sericheng } 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 1115*2311Sseb * The format of the m_pdata is specific to the plugin. It is 1116*2311Sseb * passed in as an argument to all of the plugin callbacks. The 1117*2311Sseb * driver can update this information by calling 1118*2311Sseb * mac_pdata_update(). 11190Sstevel@tonic-gate */ 1120*2311Sseb if (mregp->m_pdata != NULL) { 1121*2311Sseb /* 1122*2311Sseb * Verify that the plugin supports MAC plugin data and that 1123*2311Sseb * the supplied data is valid. 1124*2311Sseb */ 1125*2311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 1126*2311Sseb err = EINVAL; 1127*2311Sseb goto fail; 1128*2311Sseb } 1129*2311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 1130*2311Sseb mregp->m_pdata_size)) { 1131*2311Sseb err = EINVAL; 1132*2311Sseb goto fail; 1133*2311Sseb } 1134*2311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 1135*2311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 1136*2311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 1137*2311Sseb } 1138*2311Sseb 1139*2311Sseb /* 1140*2311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 1141*2311Sseb * check to make sure all mandatory callbacks are set. 1142*2311Sseb */ 1143*2311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 1144*2311Sseb mregp->m_callbacks->mc_start == NULL || 1145*2311Sseb mregp->m_callbacks->mc_stop == NULL || 1146*2311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 1147*2311Sseb mregp->m_callbacks->mc_multicst == NULL || 1148*2311Sseb mregp->m_callbacks->mc_unicst == NULL || 1149*2311Sseb mregp->m_callbacks->mc_tx == NULL) { 1150*2311Sseb err = EINVAL; 1151*2311Sseb goto fail; 1152*2311Sseb } 1153*2311Sseb mip->mi_callbacks = mregp->m_callbacks; 1154*2311Sseb 1155*2311Sseb mip->mi_dip = mregp->m_dip; 1156*2311Sseb 1157*2311Sseb /* 1158*2311Sseb * Set up the two possible transmit routines. 1159*2311Sseb */ 1160*2311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 1161*2311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 1162*2311Sseb mip->mi_txloopinfo.mt_fn = mac_txloop; 1163*2311Sseb mip->mi_txloopinfo.mt_arg = mip; 1164*2311Sseb 1165*2311Sseb /* 1166*2311Sseb * Initialize the kstats for this device. 1167*2311Sseb */ 1168*2311Sseb mac_stat_create(mip); 11690Sstevel@tonic-gate 1170269Sericheng err = EEXIST; 1171*2311Sseb /* Create a style-2 DLPI device */ 1172*2311Sseb if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 1173*2311Sseb S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 1174*2311Sseb goto fail; 1175*2311Sseb style2_created = B_TRUE; 1176269Sericheng 1177*2311Sseb /* Create a style-1 DLPI device */ 1178*2311Sseb minor = (minor_t)mip->mi_instance + 1; 1179*2311Sseb if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 1180*2311Sseb DDI_NT_NET, 0) != DDI_SUCCESS) 1181*2311Sseb goto fail; 1182*2311Sseb style1_created = B_TRUE; 11830Sstevel@tonic-gate 1184*2311Sseb /* 1185*2311Sseb * Create a link for this MAC. The link name will be the same as 1186*2311Sseb * the MAC name. 1187*2311Sseb */ 1188*2311Sseb err = dls_create(mip->mi_name, mip->mi_name, 1189*2311Sseb ddi_get_instance(mip->mi_dip)); 1190*2311Sseb if (err != 0) 1191*2311Sseb goto fail; 11920Sstevel@tonic-gate 11930Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 1194*2311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 11950Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 11960Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 11970Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 11980Sstevel@tonic-gate 11991852Syz147064 /* 12001852Syz147064 * Mark the MAC to be ready for open. 12011852Syz147064 */ 1202*2311Sseb mip->mi_disabled = B_FALSE; 1203*2311Sseb 1204*2311Sseb cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 12051852Syz147064 rw_exit(&i_mac_impl_lock); 1206*2311Sseb *mhp = (mac_handle_t)mip; 1207269Sericheng return (0); 12080Sstevel@tonic-gate 1209*2311Sseb fail: 1210*2311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1211*2311Sseb &val); 1212*2311Sseb ASSERT(mip == (mac_impl_t *)val); 1213*2311Sseb i_mac_impl_count--; 1214*2311Sseb 1215*2311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 1216*2311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 1217*2311Sseb mip->mi_type->mt_addr_length); 1218*2311Sseb mip->mi_info.mi_unicst_addr = NULL; 1219*2311Sseb } 1220*2311Sseb if (style1_created) 1221*2311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1222*2311Sseb if (style2_created) 1223*2311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1224*2311Sseb 1225*2311Sseb mac_stat_destroy(mip); 1226*2311Sseb 1227*2311Sseb if (mip->mi_type != NULL) { 1228*2311Sseb mip->mi_type->mt_ref--; 1229*2311Sseb mip->mi_type = NULL; 1230*2311Sseb } 1231*2311Sseb 1232*2311Sseb if (mip->mi_pdata != NULL) { 1233*2311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1234*2311Sseb mip->mi_pdata = NULL; 1235*2311Sseb mip->mi_pdata_size = 0; 1236*2311Sseb } 1237*2311Sseb 1238*2311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 1239*2311Sseb rw_exit(&i_mac_impl_lock); 1240269Sericheng return (err); 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate int 1244*2311Sseb mac_unregister(mac_handle_t mh) 12450Sstevel@tonic-gate { 1246*2311Sseb int err; 1247*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1248*2311Sseb mod_hash_val_t val; 1249*2311Sseb mac_multicst_addr_t *p, *nextp; 1250269Sericheng 12510Sstevel@tonic-gate /* 12520Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 12531852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 1254*2311Sseb * created while we're destroying this mac. 12550Sstevel@tonic-gate */ 1256269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12570Sstevel@tonic-gate if (mip->mi_ref > 0) { 1258269Sericheng rw_exit(&i_mac_impl_lock); 12590Sstevel@tonic-gate return (EBUSY); 12600Sstevel@tonic-gate } 12611852Syz147064 mip->mi_disabled = B_TRUE; 1262269Sericheng rw_exit(&i_mac_impl_lock); 12630Sstevel@tonic-gate 12641852Syz147064 /* 12651852Syz147064 * Wait for all taskqs which process the mac notifications to finish. 12661852Syz147064 */ 12671852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 12681852Syz147064 while (mip->mi_notify_ref != 0) 12691852Syz147064 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 12701852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 12711852Syz147064 1272*2311Sseb if ((err = dls_destroy(mip->mi_name)) != 0) { 1273269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12741852Syz147064 mip->mi_disabled = B_FALSE; 1275269Sericheng rw_exit(&i_mac_impl_lock); 1276269Sericheng return (err); 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate 12790Sstevel@tonic-gate /* 1280*2311Sseb * Remove both style 1 and style 2 minor nodes 12810Sstevel@tonic-gate */ 1282*2311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 1283*2311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 1284*2311Sseb 1285*2311Sseb ASSERT(!mip->mi_activelink); 1286*2311Sseb 1287*2311Sseb mac_stat_destroy(mip); 1288*2311Sseb 1289*2311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 1290*2311Sseb &val); 1291*2311Sseb ASSERT(mip == (mac_impl_t *)val); 1292*2311Sseb 1293*2311Sseb ASSERT(i_mac_impl_count > 0); 1294*2311Sseb i_mac_impl_count--; 1295*2311Sseb 1296*2311Sseb if (mip->mi_pdata != NULL) 1297*2311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1298*2311Sseb mip->mi_pdata = NULL; 1299*2311Sseb mip->mi_pdata_size = 0; 13000Sstevel@tonic-gate 13010Sstevel@tonic-gate /* 1302*2311Sseb * Free the list of multicast addresses. 13030Sstevel@tonic-gate */ 1304*2311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 1305*2311Sseb nextp = p->mma_nextp; 1306*2311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 1307*2311Sseb } 1308*2311Sseb mip->mi_mmap = NULL; 13090Sstevel@tonic-gate 1310*2311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 1311*2311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 1312*2311Sseb mip->mi_info.mi_unicst_addr = NULL; 1313*2311Sseb 1314*2311Sseb mip->mi_type->mt_ref--; 1315*2311Sseb mip->mi_type = NULL; 1316*2311Sseb 1317*2311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 1318*2311Sseb 1319*2311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 1320*2311Sseb 13210Sstevel@tonic-gate return (0); 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate void 1325*2311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 13260Sstevel@tonic-gate { 1327*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13280Sstevel@tonic-gate mac_rx_fn_t *mrfp; 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate /* 13310Sstevel@tonic-gate * Call all registered receive functions. 13320Sstevel@tonic-gate */ 13330Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 13340Sstevel@tonic-gate mrfp = mip->mi_mrfp; 13350Sstevel@tonic-gate if (mrfp == NULL) { 13360Sstevel@tonic-gate /* There are no registered receive functions. */ 13370Sstevel@tonic-gate freemsgchain(bp); 13380Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13390Sstevel@tonic-gate return; 13400Sstevel@tonic-gate } 13410Sstevel@tonic-gate do { 13420Sstevel@tonic-gate mblk_t *recv_bp; 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate if (mrfp->mrf_nextp != NULL) { 13450Sstevel@tonic-gate /* XXX Do we bump a counter if copymsgchain() fails? */ 13460Sstevel@tonic-gate recv_bp = copymsgchain(bp); 13470Sstevel@tonic-gate } else { 13480Sstevel@tonic-gate recv_bp = bp; 13490Sstevel@tonic-gate } 13500Sstevel@tonic-gate if (recv_bp != NULL) 13510Sstevel@tonic-gate mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 13520Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 13530Sstevel@tonic-gate } while (mrfp != NULL); 13540Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13550Sstevel@tonic-gate } 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate /* 13580Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 13590Sstevel@tonic-gate */ 13600Sstevel@tonic-gate mblk_t * 13610Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 13620Sstevel@tonic-gate { 13630Sstevel@tonic-gate mac_impl_t *mip = arg; 13640Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 13650Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate while (bp != NULL) { 13680Sstevel@tonic-gate next_bp = bp->b_next; 13690Sstevel@tonic-gate bp->b_next = NULL; 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 13720Sstevel@tonic-gate goto noresources; 13730Sstevel@tonic-gate 1374*2311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 13750Sstevel@tonic-gate ASSERT(resid_bp == bp); 13760Sstevel@tonic-gate freemsg(loop_bp); 13770Sstevel@tonic-gate goto noresources; 13780Sstevel@tonic-gate } 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 13810Sstevel@tonic-gate mtfp = mip->mi_mtfp; 138256Smeem while (mtfp != NULL && loop_bp != NULL) { 13830Sstevel@tonic-gate bp = loop_bp; 138456Smeem 138556Smeem /* XXX counter bump if copymsg() fails? */ 138656Smeem if (mtfp->mtf_nextp != NULL) 13870Sstevel@tonic-gate loop_bp = copymsg(bp); 138856Smeem else 138956Smeem loop_bp = NULL; 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 139256Smeem mtfp = mtfp->mtf_nextp; 13930Sstevel@tonic-gate } 139456Smeem rw_exit(&mip->mi_txloop_lock); 13950Sstevel@tonic-gate 139656Smeem /* 139756Smeem * It's possible we've raced with the disabling of promiscuous 139856Smeem * mode, in which case we can discard our copy. 139956Smeem */ 140056Smeem if (loop_bp != NULL) 140156Smeem freemsg(loop_bp); 140256Smeem 14030Sstevel@tonic-gate bp = next_bp; 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate return (NULL); 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate noresources: 14090Sstevel@tonic-gate bp->b_next = next_bp; 14100Sstevel@tonic-gate return (bp); 14110Sstevel@tonic-gate } 14120Sstevel@tonic-gate 14130Sstevel@tonic-gate void 1414*2311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 14150Sstevel@tonic-gate { 1416*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14170Sstevel@tonic-gate 14180Sstevel@tonic-gate /* 14190Sstevel@tonic-gate * Save the link state. 14200Sstevel@tonic-gate */ 1421*2311Sseb mip->mi_linkstate = link; 14220Sstevel@tonic-gate 14230Sstevel@tonic-gate /* 14240Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 14250Sstevel@tonic-gate */ 14260Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 14270Sstevel@tonic-gate } 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate void 1430*2311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 14310Sstevel@tonic-gate { 1432*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14330Sstevel@tonic-gate 1434*2311Sseb if (mip->mi_type->mt_addr_length == 0) 1435*2311Sseb return; 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate /* 14380Sstevel@tonic-gate * Save the address. 14390Sstevel@tonic-gate */ 1440*2311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 14410Sstevel@tonic-gate 14420Sstevel@tonic-gate /* 14430Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 14440Sstevel@tonic-gate */ 14450Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 14460Sstevel@tonic-gate } 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate void 1449*2311Sseb mac_tx_update(mac_handle_t mh) 14500Sstevel@tonic-gate { 14510Sstevel@tonic-gate /* 14520Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 14530Sstevel@tonic-gate */ 1454*2311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 14550Sstevel@tonic-gate } 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate void 1458*2311Sseb mac_resource_update(mac_handle_t mh) 14590Sstevel@tonic-gate { 14600Sstevel@tonic-gate /* 14610Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 14620Sstevel@tonic-gate */ 1463*2311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 14640Sstevel@tonic-gate } 14650Sstevel@tonic-gate 14660Sstevel@tonic-gate mac_resource_handle_t 1467*2311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 14680Sstevel@tonic-gate { 1469*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14700Sstevel@tonic-gate mac_resource_handle_t mrh; 14710Sstevel@tonic-gate mac_resource_add_t add; 14720Sstevel@tonic-gate void *arg; 14730Sstevel@tonic-gate 14740Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 14750Sstevel@tonic-gate add = mip->mi_resource_add; 14760Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 14770Sstevel@tonic-gate 14781184Skrgopi if (add != NULL) 14791184Skrgopi mrh = add(arg, mrp); 14801184Skrgopi else 14811184Skrgopi mrh = NULL; 14820Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate return (mrh); 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate 1487*2311Sseb int 1488*2311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 1489*2311Sseb { 1490*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1491*2311Sseb 1492*2311Sseb /* 1493*2311Sseb * Verify that the plugin supports MAC plugin data and that the 1494*2311Sseb * supplied data is valid. 1495*2311Sseb */ 1496*2311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 1497*2311Sseb return (EINVAL); 1498*2311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 1499*2311Sseb return (EINVAL); 1500*2311Sseb 1501*2311Sseb if (mip->mi_pdata != NULL) 1502*2311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 1503*2311Sseb 1504*2311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 1505*2311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 1506*2311Sseb mip->mi_pdata_size = dsize; 1507*2311Sseb 1508*2311Sseb /* 1509*2311Sseb * Since the MAC plugin data is used to construct MAC headers that 1510*2311Sseb * were cached in fast-path headers, we need to flush fast-path 1511*2311Sseb * information for links associated with this mac. 1512*2311Sseb */ 1513*2311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 1514*2311Sseb return (0); 1515*2311Sseb } 1516*2311Sseb 15170Sstevel@tonic-gate void 1518*2311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 15190Sstevel@tonic-gate boolean_t add) 15200Sstevel@tonic-gate { 1521*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15220Sstevel@tonic-gate mac_multicst_addr_t *p; 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * If no specific refresh function was given then default to the 15260Sstevel@tonic-gate * driver's m_multicst entry point. 15270Sstevel@tonic-gate */ 15280Sstevel@tonic-gate if (refresh == NULL) { 1529*2311Sseb refresh = mip->mi_multicst; 1530*2311Sseb arg = mip->mi_driver; 15310Sstevel@tonic-gate } 15320Sstevel@tonic-gate ASSERT(refresh != NULL); 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate /* 15350Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 15360Sstevel@tonic-gate * each address. 15370Sstevel@tonic-gate */ 15380Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 15390Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 15400Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 15410Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate void 1545*2311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 15460Sstevel@tonic-gate { 1547*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15480Sstevel@tonic-gate /* 15490Sstevel@tonic-gate * If no specific refresh function was given then default to the 1550*2311Sseb * driver's mi_unicst entry point. 15510Sstevel@tonic-gate */ 15520Sstevel@tonic-gate if (refresh == NULL) { 1553*2311Sseb refresh = mip->mi_unicst; 1554*2311Sseb arg = mip->mi_driver; 15550Sstevel@tonic-gate } 15560Sstevel@tonic-gate ASSERT(refresh != NULL); 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate /* 15590Sstevel@tonic-gate * Call the refresh function with the current unicast address. 15600Sstevel@tonic-gate */ 15610Sstevel@tonic-gate refresh(arg, mip->mi_addr); 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate 15640Sstevel@tonic-gate void 1565*2311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 15660Sstevel@tonic-gate { 1567*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate /* 15700Sstevel@tonic-gate * If no specific refresh function was given then default to the 15710Sstevel@tonic-gate * driver's m_promisc entry point. 15720Sstevel@tonic-gate */ 15730Sstevel@tonic-gate if (refresh == NULL) { 1574*2311Sseb refresh = mip->mi_setpromisc; 1575*2311Sseb arg = mip->mi_driver; 15760Sstevel@tonic-gate } 15770Sstevel@tonic-gate ASSERT(refresh != NULL); 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate /* 15800Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 15810Sstevel@tonic-gate */ 15820Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 15830Sstevel@tonic-gate } 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate boolean_t 15860Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 15870Sstevel@tonic-gate { 15880Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 15910Sstevel@tonic-gate if (mip->mi_activelink) { 15920Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 15930Sstevel@tonic-gate return (B_FALSE); 15940Sstevel@tonic-gate } 15950Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 15960Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 15970Sstevel@tonic-gate return (B_TRUE); 15980Sstevel@tonic-gate } 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate void 16010Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 16020Sstevel@tonic-gate { 16030Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16060Sstevel@tonic-gate ASSERT(mip->mi_activelink); 16070Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 16080Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16090Sstevel@tonic-gate } 1610269Sericheng 1611269Sericheng /* 1612269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1613269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1614269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1615269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1616269Sericheng * cannot disappear while we are accessing it. 1617269Sericheng */ 1618269Sericheng typedef struct i_mac_info_state_s { 1619269Sericheng const char *mi_name; 1620269Sericheng mac_info_t *mi_infop; 1621269Sericheng } i_mac_info_state_t; 1622269Sericheng 1623269Sericheng /*ARGSUSED*/ 1624269Sericheng static uint_t 1625269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1626269Sericheng { 1627269Sericheng i_mac_info_state_t *statep = arg; 1628269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 1629269Sericheng 16301852Syz147064 if (mip->mi_disabled) 1631269Sericheng return (MH_WALK_CONTINUE); 1632269Sericheng 1633269Sericheng if (strcmp(statep->mi_name, 1634*2311Sseb ddi_driver_name(mip->mi_dip)) != 0) 1635269Sericheng return (MH_WALK_CONTINUE); 1636269Sericheng 1637*2311Sseb statep->mi_infop = &mip->mi_info; 1638269Sericheng return (MH_WALK_TERMINATE); 1639269Sericheng } 1640269Sericheng 1641269Sericheng boolean_t 1642269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 1643269Sericheng { 1644269Sericheng i_mac_info_state_t state; 1645269Sericheng 1646269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 1647269Sericheng state.mi_name = name; 1648269Sericheng state.mi_infop = NULL; 1649269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1650269Sericheng if (state.mi_infop == NULL) { 1651269Sericheng rw_exit(&i_mac_impl_lock); 1652269Sericheng return (B_FALSE); 1653269Sericheng } 1654269Sericheng *minfop = *state.mi_infop; 1655269Sericheng rw_exit(&i_mac_impl_lock); 1656269Sericheng return (B_TRUE); 1657269Sericheng } 1658269Sericheng 1659*2311Sseb boolean_t 1660*2311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 1661*2311Sseb { 1662*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1663*2311Sseb 1664*2311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 1665*2311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 1666*2311Sseb else 1667*2311Sseb return (B_FALSE); 1668*2311Sseb } 1669*2311Sseb 1670*2311Sseb boolean_t 1671*2311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 1672*2311Sseb { 1673*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1674*2311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 1675*2311Sseb mip->mi_pdata)); 1676*2311Sseb } 1677*2311Sseb 1678*2311Sseb mblk_t * 1679*2311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 1680*2311Sseb size_t extra_len) 1681*2311Sseb { 1682*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1683*2311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 1684*2311Sseb mip->mi_pdata, payload, extra_len)); 1685*2311Sseb } 1686*2311Sseb 1687*2311Sseb int 1688*2311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 1689*2311Sseb { 1690*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1691*2311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 1692*2311Sseb mhip)); 1693*2311Sseb } 1694*2311Sseb 1695*2311Sseb mblk_t * 1696*2311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 1697*2311Sseb { 1698*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1699*2311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 1700*2311Sseb if (DB_REF(mp) > 1) { 1701*2311Sseb mblk_t *newmp = copymsg(mp); 1702*2311Sseb freemsg(mp); 1703*2311Sseb mp = newmp; 1704*2311Sseb } 1705*2311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 1706*2311Sseb mip->mi_pdata)); 1707*2311Sseb } 1708*2311Sseb return (mp); 1709*2311Sseb } 1710*2311Sseb 1711*2311Sseb mblk_t * 1712*2311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 1713*2311Sseb { 1714*2311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1715*2311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 1716*2311Sseb if (DB_REF(mp) > 1) { 1717*2311Sseb mblk_t *newmp = copymsg(mp); 1718*2311Sseb freemsg(mp); 1719*2311Sseb mp = newmp; 1720*2311Sseb } 1721*2311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 1722*2311Sseb mip->mi_pdata)); 1723*2311Sseb } 1724*2311Sseb return (mp); 1725*2311Sseb } 1726*2311Sseb 1727269Sericheng void 1728269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 1729269Sericheng { 1730269Sericheng dld_init_ops(ops, name); 1731269Sericheng } 1732269Sericheng 1733269Sericheng void 1734269Sericheng mac_fini_ops(struct dev_ops *ops) 1735269Sericheng { 1736269Sericheng dld_fini_ops(ops); 1737269Sericheng } 1738*2311Sseb 1739*2311Sseb /* 1740*2311Sseb * MAC Type Plugin functions. 1741*2311Sseb */ 1742*2311Sseb 1743*2311Sseb mactype_register_t * 1744*2311Sseb mactype_alloc(uint_t mactype_version) 1745*2311Sseb { 1746*2311Sseb mactype_register_t *mtrp; 1747*2311Sseb 1748*2311Sseb /* 1749*2311Sseb * Make sure there isn't a version mismatch between the plugin and 1750*2311Sseb * the framework. In the future, if multiple versions are 1751*2311Sseb * supported, this check could become more sophisticated. 1752*2311Sseb */ 1753*2311Sseb if (mactype_version != MACTYPE_VERSION) 1754*2311Sseb return (NULL); 1755*2311Sseb 1756*2311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 1757*2311Sseb mtrp->mtr_version = mactype_version; 1758*2311Sseb return (mtrp); 1759*2311Sseb } 1760*2311Sseb 1761*2311Sseb void 1762*2311Sseb mactype_free(mactype_register_t *mtrp) 1763*2311Sseb { 1764*2311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 1765*2311Sseb } 1766*2311Sseb 1767*2311Sseb int 1768*2311Sseb mactype_register(mactype_register_t *mtrp) 1769*2311Sseb { 1770*2311Sseb mactype_t *mtp; 1771*2311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 1772*2311Sseb 1773*2311Sseb /* Do some sanity checking before we register this MAC type. */ 1774*2311Sseb if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 1775*2311Sseb return (EINVAL); 1776*2311Sseb 1777*2311Sseb /* 1778*2311Sseb * Verify that all mandatory callbacks are set in the ops 1779*2311Sseb * vector. 1780*2311Sseb */ 1781*2311Sseb if (ops->mtops_unicst_verify == NULL || 1782*2311Sseb ops->mtops_multicst_verify == NULL || 1783*2311Sseb ops->mtops_sap_verify == NULL || 1784*2311Sseb ops->mtops_header == NULL || 1785*2311Sseb ops->mtops_header_info == NULL) { 1786*2311Sseb return (EINVAL); 1787*2311Sseb } 1788*2311Sseb 1789*2311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 1790*2311Sseb mtp->mt_ident = mtrp->mtr_ident; 1791*2311Sseb mtp->mt_ops = *ops; 1792*2311Sseb mtp->mt_type = mtrp->mtr_mactype; 1793*2311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 1794*2311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 1795*2311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 1796*2311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 1797*2311Sseb mtrp->mtr_addrlen); 1798*2311Sseb } 1799*2311Sseb 1800*2311Sseb mtp->mt_stats = mtrp->mtr_stats; 1801*2311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 1802*2311Sseb 1803*2311Sseb /* 1804*2311Sseb * A MAC-Type plugin only registers when i_mactype_getplugin() does 1805*2311Sseb * an explicit modload() as a result of a driver requesting to use 1806*2311Sseb * that plugin in mac_register(). We pre-emptively set the initial 1807*2311Sseb * reference count to 1 here to prevent the plugin module from 1808*2311Sseb * unloading before the driver's mac_register() completes. If we 1809*2311Sseb * were to initialize the reference count to 0, then there would be 1810*2311Sseb * a window during which the module could unload before the 1811*2311Sseb * reference count could be bumped up to 1. 1812*2311Sseb */ 1813*2311Sseb mtp->mt_ref = 1; 1814*2311Sseb 1815*2311Sseb if (mod_hash_insert(i_mactype_hash, 1816*2311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 1817*2311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1818*2311Sseb kmem_free(mtp, sizeof (*mtp)); 1819*2311Sseb return (EEXIST); 1820*2311Sseb } 1821*2311Sseb return (0); 1822*2311Sseb } 1823*2311Sseb 1824*2311Sseb int 1825*2311Sseb mactype_unregister(const char *ident) 1826*2311Sseb { 1827*2311Sseb mactype_t *mtp; 1828*2311Sseb mod_hash_val_t val; 1829*2311Sseb int err; 1830*2311Sseb 1831*2311Sseb /* 1832*2311Sseb * Let's not allow MAC drivers to use this plugin while we're 1833*2311Sseb * trying to unregister it... 1834*2311Sseb */ 1835*2311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 1836*2311Sseb 1837*2311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 1838*2311Sseb (mod_hash_val_t *)&mtp)) != 0) { 1839*2311Sseb /* A plugin is trying to unregister, but it never registered. */ 1840*2311Sseb rw_exit(&i_mac_impl_lock); 1841*2311Sseb return (ENXIO); 1842*2311Sseb } 1843*2311Sseb 1844*2311Sseb if (mtp->mt_ref > 0) { 1845*2311Sseb rw_exit(&i_mac_impl_lock); 1846*2311Sseb return (EBUSY); 1847*2311Sseb } 1848*2311Sseb 1849*2311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 1850*2311Sseb ASSERT(err == 0); 1851*2311Sseb if (err != 0) { 1852*2311Sseb /* This should never happen, thus the ASSERT() above. */ 1853*2311Sseb rw_exit(&i_mac_impl_lock); 1854*2311Sseb return (EINVAL); 1855*2311Sseb } 1856*2311Sseb ASSERT(mtp == (mactype_t *)val); 1857*2311Sseb 1858*2311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 1859*2311Sseb kmem_free(mtp, sizeof (mactype_t)); 1860*2311Sseb rw_exit(&i_mac_impl_lock); 1861*2311Sseb 1862*2311Sseb return (0); 1863*2311Sseb } 1864