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> 442311Sseb #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 532311Sseb #define MACTYPE_KMODDIR "mac" 542311Sseb #define MACTYPE_HASHSZ 67 552311Sseb static mod_hash_t *i_mactype_hash; 562311Sseb 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 712311Sseb 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); 932311Sseb 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); 1002311Sseb 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 1872311Sseb static mactype_t * 1882311Sseb i_mactype_getplugin(const char *plugin_name) 1892311Sseb { 1902311Sseb mactype_t *mtype = NULL; 1912311Sseb boolean_t tried_modload = B_FALSE; 1922311Sseb 1932311Sseb find_registered_mactype: 1942311Sseb if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)plugin_name, 1952311Sseb (mod_hash_val_t *)&mtype) == 0) { 1962311Sseb /* 1972311Sseb * Because the reference count is initialized at 1 (see 1982311Sseb * mactype_register()), we don't need to bump up the 1992311Sseb * reference count if we're the first reference. 2002311Sseb */ 2012311Sseb if (!tried_modload) 2022311Sseb mtype->mt_ref++; 2032311Sseb return (mtype); 2042311Sseb } else if (tried_modload) { 2052311Sseb return (NULL); 2062311Sseb } 2072311Sseb 2082311Sseb /* 2092311Sseb * If the plugin has not yet been loaded, then attempt to load it 2102311Sseb * now. If modload succeeds, the plugin should have registered 2112311Sseb * using mactype_register(), in which case we can go back and 2122311Sseb * attempt to find it again. 2132311Sseb */ 2142311Sseb if (modload(MACTYPE_KMODDIR, (char *)plugin_name) != -1) { 2152311Sseb tried_modload = B_TRUE; 2162311Sseb goto find_registered_mactype; 2172311Sseb } 2182311Sseb return (NULL); 2192311Sseb } 2202311Sseb 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", 2292311Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 2302311Sseb 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; 2382311Sseb 2392311Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash", 2402311Sseb MACTYPE_HASHSZ, 2412311Sseb mod_hash_null_keydtor, mod_hash_null_valdtor, 2422311Sseb 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); 2552311Sseb 2562311Sseb 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 2652311Sseb 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 */ 2782311Sseb 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 */ 2842311Sseb 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 */ 3012311Sseb 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); 3092311Sseb 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; 3372311Sseb 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 { 3522311Sseb 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 { 3582311Sseb return (((mac_impl_t *)mh)->mi_dip); 359269Sericheng } 360269Sericheng 3610Sstevel@tonic-gate uint64_t 3622311Sseb mac_stat_get(mac_handle_t mh, uint_t stat) 3630Sstevel@tonic-gate { 3640Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 3652311Sseb uint64_t val; 3662311Sseb int ret; 3670Sstevel@tonic-gate 3682311Sseb /* 3692311Sseb * The range of stat determines where it is maintained. Stat 3702311Sseb * values from 0 up to (but not including) MAC_STAT_MIN are 3712311Sseb * mainteined by the mac module itself. Everything else is 3722311Sseb * maintained by the driver. 3732311Sseb */ 3742311Sseb if (stat < MAC_STAT_MIN) { 3752311Sseb /* These stats are maintained by the mac module itself. */ 3762311Sseb switch (stat) { 3772311Sseb case MAC_STAT_LINK_STATE: 3782311Sseb return (mip->mi_linkstate); 3792311Sseb case MAC_STAT_LINK_UP: 3802311Sseb return (mip->mi_linkstate == LINK_STATE_UP); 3812311Sseb case MAC_STAT_PROMISC: 3822311Sseb return (mip->mi_devpromisc != 0); 3832311Sseb default: 3842311Sseb ASSERT(B_FALSE); 3852311Sseb } 3862311Sseb } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * Call the driver to get the given statistic. 3900Sstevel@tonic-gate */ 3912311Sseb ret = mip->mi_getstat(mip->mi_driver, stat, &val); 3922311Sseb if (ret != 0) { 3932311Sseb /* 3942311Sseb * The driver doesn't support this statistic. Get the 3952311Sseb * statistic's default value. 3962311Sseb */ 3972311Sseb val = mac_stat_default(mip, stat); 3982311Sseb } 3992311Sseb 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 4082311Sseb 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 */ 4262311Sseb 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 4392311Sseb 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 */ 4572311Sseb 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 4712311Sseb ASSERT(mip->mi_multicst != NULL); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * Verify the address. 4750Sstevel@tonic-gate */ 4762311Sseb if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 4772311Sseb mip->mi_pdata)) != 0) { 4782311Sseb return (err); 4792311Sseb } 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)) { 4862311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 4872311Sseb 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 */ 5102311Sseb 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 */ 5182311Sseb 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 5352311Sseb 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)) { 5422311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 5432311Sseb 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 */ 5692311Sseb 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 5852331Skrgopi /* 5862331Skrgopi * mac_unicst_verify: Verifies the passed address. It fails 5872331Skrgopi * if the passed address is a group address or has incorrect length. 5882331Skrgopi */ 5892331Skrgopi boolean_t 5902331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 5912331Skrgopi { 5922331Skrgopi mac_impl_t *mip = (mac_impl_t *)mh; 5932331Skrgopi 5942331Skrgopi /* 5952331Skrgopi * Verify the address. 5962331Skrgopi */ 5972331Skrgopi if ((len != mip->mi_type->mt_addr_length) || 5982331Skrgopi (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 5992331Skrgopi mip->mi_pdata)) != 0) { 6002331Skrgopi return (B_FALSE); 6012331Skrgopi } else { 6022331Skrgopi return (B_TRUE); 6032331Skrgopi } 6042331Skrgopi } 6052331Skrgopi 6060Sstevel@tonic-gate int 6070Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 6080Sstevel@tonic-gate { 6090Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6100Sstevel@tonic-gate int err; 6110Sstevel@tonic-gate boolean_t notify = B_FALSE; 6120Sstevel@tonic-gate 6132311Sseb ASSERT(mip->mi_unicst != NULL); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* 6160Sstevel@tonic-gate * Verify the address. 6170Sstevel@tonic-gate */ 6182311Sseb if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6192311Sseb mip->mi_pdata)) != 0) { 6202311Sseb return (err); 6212311Sseb } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * Program the new unicast address. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * If address doesn't change, do nothing. 6300Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 6310Sstevel@tonic-gate * recursively. 6320Sstevel@tonic-gate */ 6332311Sseb if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 6340Sstevel@tonic-gate err = 0; 6350Sstevel@tonic-gate goto done; 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6382311Sseb if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 6390Sstevel@tonic-gate goto done; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate /* 6420Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 6430Sstevel@tonic-gate */ 6442311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 6450Sstevel@tonic-gate notify = B_TRUE; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate done: 6480Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate if (notify) 6510Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate return (err); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate void 6570Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 6580Sstevel@tonic-gate { 6590Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate /* 6622311Sseb * Copy out the current unicast source address. 6630Sstevel@tonic-gate */ 6640Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 6652311Sseb bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 6662311Sseb rw_exit(&(mip->mi_data_lock)); 6672311Sseb } 6682311Sseb 6692311Sseb void 6702311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr) 6712311Sseb { 6722311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 6732311Sseb 6742311Sseb /* 6752311Sseb * Copy out the current destination address. 6762311Sseb */ 6772311Sseb rw_enter(&(mip->mi_data_lock), RW_READER); 6782311Sseb bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 6790Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate int 6830Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 6840Sstevel@tonic-gate { 6850Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6860Sstevel@tonic-gate int err = 0; 6870Sstevel@tonic-gate 6882311Sseb ASSERT(mip->mi_setpromisc != NULL); 6890Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 6930Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 6940Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 6950Sstevel@tonic-gate */ 6960Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6970Sstevel@tonic-gate if (on) { 6980Sstevel@tonic-gate /* 6990Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 7000Sstevel@tonic-gate */ 7010Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 7022311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 7032311Sseb if (err != 0) { 7040Sstevel@tonic-gate mip->mi_devpromisc--; 7050Sstevel@tonic-gate goto done; 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /* 7110Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 7140Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7150Sstevel@tonic-gate } else { 7160Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 7170Sstevel@tonic-gate err = EPROTO; 7180Sstevel@tonic-gate goto done; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 7230Sstevel@tonic-gate * enabling. 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 7262311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 7272311Sseb if (err != 0) { 7280Sstevel@tonic-gate mip->mi_devpromisc++; 7290Sstevel@tonic-gate goto done; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate /* 7350Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 7360Sstevel@tonic-gate * enabling. 7370Sstevel@tonic-gate */ 7380Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 7390Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate done: 7430Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7440Sstevel@tonic-gate return (err); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate boolean_t 7480Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 7490Sstevel@tonic-gate { 7500Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate /* 7550Sstevel@tonic-gate * Return the current promiscuity. 7560Sstevel@tonic-gate */ 7570Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 7580Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 7590Sstevel@tonic-gate else 7600Sstevel@tonic-gate return (mip->mi_promisc != 0); 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate void 7640Sstevel@tonic-gate mac_resources(mac_handle_t mh) 7650Sstevel@tonic-gate { 7660Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate /* 7692311Sseb * If the driver supports resource registration, call the driver to 7702311Sseb * ask it to register its resources. 7710Sstevel@tonic-gate */ 7722311Sseb if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 7732311Sseb mip->mi_resources(mip->mi_driver); 7740Sstevel@tonic-gate } 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate void 7770Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 7780Sstevel@tonic-gate { 7790Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate /* 7822311Sseb * Call the driver to handle the ioctl. The driver may not support 7832311Sseb * any ioctls, in which case we reply with a NAK on its behalf. 7840Sstevel@tonic-gate */ 7852311Sseb if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 7862311Sseb mip->mi_ioctl(mip->mi_driver, wq, bp); 7872311Sseb else 7882311Sseb miocnak(wq, bp, 0, EINVAL); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate 79156Smeem const mac_txinfo_t * 79256Smeem mac_tx_get(mac_handle_t mh) 7930Sstevel@tonic-gate { 7940Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 79556Smeem mac_txinfo_t *mtp; 79656Smeem 79756Smeem /* 79856Smeem * Grab the lock to prevent us from racing with MAC_PROMISC being 79956Smeem * changed. This is sufficient since MAC clients are careful to always 80056Smeem * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 80156Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 80256Smeem */ 80356Smeem rw_enter(&mip->mi_txloop_lock, RW_READER); 8040Sstevel@tonic-gate 80556Smeem if (mac_promisc_get(mh, MAC_PROMISC)) { 80656Smeem ASSERT(mip->mi_mtfp != NULL); 80756Smeem mtp = &mip->mi_txloopinfo; 80856Smeem } else { 80956Smeem /* 81056Smeem * Note that we cannot ASSERT() that mip->mi_mtfp is NULL, 81156Smeem * because to satisfy the above ASSERT(), we have to disable 81256Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 81356Smeem */ 81456Smeem mtp = &mip->mi_txinfo; 81556Smeem } 81656Smeem 81756Smeem rw_exit(&mip->mi_txloop_lock); 81856Smeem return (mtp); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate link_state_t 8220Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 8230Sstevel@tonic-gate { 8242311Sseb return (((mac_impl_t *)mh)->mi_linkstate); 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate mac_notify_handle_t 8280Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 8290Sstevel@tonic-gate { 8300Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8310Sstevel@tonic-gate mac_notify_fn_t *mnfp; 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 8340Sstevel@tonic-gate mnfp->mnf_fn = notify; 8350Sstevel@tonic-gate mnfp->mnf_arg = arg; 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate /* 8380Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 8390Sstevel@tonic-gate */ 8401852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8410Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 8420Sstevel@tonic-gate mip->mi_mnfp = mnfp; 8431852Syz147064 rw_exit(&mip->mi_notify_lock); 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate void 8490Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 8500Sstevel@tonic-gate { 8510Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8520Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 8530Sstevel@tonic-gate mac_notify_fn_t **pp; 8540Sstevel@tonic-gate mac_notify_fn_t *p; 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate /* 8570Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 8580Sstevel@tonic-gate */ 8591852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8600Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 8610Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 8620Sstevel@tonic-gate if (p == mnfp) 8630Sstevel@tonic-gate break; 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate ASSERT(p != NULL); 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * Remove it from the list. 8690Sstevel@tonic-gate */ 8700Sstevel@tonic-gate *pp = p->mnf_nextp; 8711852Syz147064 rw_exit(&mip->mi_notify_lock); 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate /* 8740Sstevel@tonic-gate * Free it. 8750Sstevel@tonic-gate */ 8760Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate void 8800Sstevel@tonic-gate mac_notify(mac_handle_t mh) 8810Sstevel@tonic-gate { 8820Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8830Sstevel@tonic-gate mac_notify_type_t type; 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 8860Sstevel@tonic-gate i_mac_notify(mip, type); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate mac_rx_handle_t 8900Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 8910Sstevel@tonic-gate { 8920Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8930Sstevel@tonic-gate mac_rx_fn_t *mrfp; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 8960Sstevel@tonic-gate mrfp->mrf_fn = rx; 8970Sstevel@tonic-gate mrfp->mrf_arg = arg; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate /* 9000Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 9010Sstevel@tonic-gate */ 9020Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9030Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 9040Sstevel@tonic-gate mip->mi_mrfp = mrfp; 9050Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate /* 9110Sstevel@tonic-gate * Unregister a receive function for this mac. This removes the function 9120Sstevel@tonic-gate * from the list of receive functions for this mac. 9130Sstevel@tonic-gate */ 9140Sstevel@tonic-gate void 9150Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 9160Sstevel@tonic-gate { 9170Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9180Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 9190Sstevel@tonic-gate mac_rx_fn_t **pp; 9200Sstevel@tonic-gate mac_rx_fn_t *p; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate /* 9230Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9260Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 9270Sstevel@tonic-gate if (p == mrfp) 9280Sstevel@tonic-gate break; 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate ASSERT(p != NULL); 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* Remove it from the list. */ 9330Sstevel@tonic-gate *pp = p->mrf_nextp; 9340Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 9350Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate mac_txloop_handle_t 9390Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 9400Sstevel@tonic-gate { 9410Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9420Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 9450Sstevel@tonic-gate mtfp->mtf_fn = tx; 9460Sstevel@tonic-gate mtfp->mtf_arg = arg; 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate /* 9490Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 9500Sstevel@tonic-gate */ 9510Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 9520Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 9530Sstevel@tonic-gate mip->mi_mtfp = mtfp; 9540Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate /* 9600Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 9610Sstevel@tonic-gate * from the list of transmit functions for this mac. 9620Sstevel@tonic-gate */ 9630Sstevel@tonic-gate void 9640Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 9650Sstevel@tonic-gate { 9660Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9670Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 9680Sstevel@tonic-gate mac_txloop_fn_t **pp; 9690Sstevel@tonic-gate mac_txloop_fn_t *p; 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate /* 9720Sstevel@tonic-gate * Search the 'tx' callback list for the function. 9730Sstevel@tonic-gate */ 9740Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 9750Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 9760Sstevel@tonic-gate if (p == mtfp) 9770Sstevel@tonic-gate break; 9780Sstevel@tonic-gate } 9790Sstevel@tonic-gate ASSERT(p != NULL); 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate /* Remove it from the list. */ 9820Sstevel@tonic-gate *pp = p->mtf_nextp; 9830Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 9840Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate void 9880Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 9890Sstevel@tonic-gate { 9900Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate /* 9930Sstevel@tonic-gate * Update the 'resource_add' callbacks. 9940Sstevel@tonic-gate */ 9950Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 9960Sstevel@tonic-gate mip->mi_resource_add = add; 9970Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 9980Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate /* 10020Sstevel@tonic-gate * Driver support functions. 10030Sstevel@tonic-gate */ 10040Sstevel@tonic-gate 10052311Sseb mac_register_t * 10062311Sseb mac_alloc(uint_t mac_version) 10070Sstevel@tonic-gate { 10082311Sseb mac_register_t *mregp; 10092311Sseb 10102311Sseb /* 10112311Sseb * Make sure there isn't a version mismatch between the driver and 10122311Sseb * the framework. In the future, if multiple versions are 10132311Sseb * supported, this check could become more sophisticated. 10142311Sseb */ 10152311Sseb if (mac_version != MAC_VERSION) 10162311Sseb return (NULL); 10172311Sseb 10182311Sseb mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 10192311Sseb mregp->m_version = mac_version; 10202311Sseb return (mregp); 10212311Sseb } 10222311Sseb 10232311Sseb void 10242311Sseb mac_free(mac_register_t *mregp) 10252311Sseb { 10262311Sseb kmem_free(mregp, sizeof (mac_register_t)); 10272311Sseb } 10282311Sseb 10292311Sseb /* 10302311Sseb * mac_register() is how drivers register new MACs with the GLDv3 10312311Sseb * framework. The mregp argument is allocated by drivers using the 10322311Sseb * mac_alloc() function, and can be freed using mac_free() immediately upon 10332311Sseb * return from mac_register(). Upon success (0 return value), the mhp 10342311Sseb * opaque pointer becomes the driver's handle to its MAC interface, and is 10352311Sseb * the argument to all other mac module entry points. 10362311Sseb */ 10372311Sseb int 10382311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 10392311Sseb { 10402311Sseb mac_impl_t *mip; 10412311Sseb mactype_t *mtype; 10422311Sseb int err; 10430Sstevel@tonic-gate struct devnames *dnp; 10442311Sseb minor_t minor; 10452311Sseb mod_hash_val_t val; 10462311Sseb boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 10472311Sseb 10482311Sseb /* Find the required MAC-Type plugin. */ 10492311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 10502311Sseb return (EINVAL); 10512311Sseb 10522311Sseb /* Create a mac_impl_t to represent this MAC. */ 10532311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 10542311Sseb 10552311Sseb /* 10562311Sseb * The mac is not ready for open yet. 10572311Sseb */ 10582311Sseb mip->mi_disabled = B_TRUE; 10592311Sseb 10602311Sseb mip->mi_drvname = ddi_driver_name(mregp->m_dip); 10612311Sseb /* 10622311Sseb * Some drivers such as aggr need to register multiple MACs. Such 10632311Sseb * drivers must supply a non-zero "instance" argument so that each 10642311Sseb * MAC can be assigned a unique MAC name and can have unique 10652311Sseb * kstats. 10662311Sseb */ 10672311Sseb mip->mi_instance = ((mregp->m_instance == 0) ? 10682311Sseb ddi_get_instance(mregp->m_dip) : mregp->m_instance); 10692311Sseb 10702311Sseb /* Construct the MAC name as <drvname><instance> */ 10712311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 10722311Sseb mip->mi_drvname, mip->mi_instance); 10732311Sseb 10742311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 10752311Sseb if (mod_hash_insert(i_mac_impl_hash, 10762311Sseb (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 10772311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 10782311Sseb rw_exit(&i_mac_impl_lock); 10792311Sseb return (EEXIST); 10802311Sseb } 10812311Sseb i_mac_impl_count++; 10822311Sseb 10832311Sseb mip->mi_driver = mregp->m_driver; 10842311Sseb 10852311Sseb mip->mi_type = mtype; 10860Sstevel@tonic-gate 10872311Sseb mip->mi_info.mi_media = mtype->mt_type; 10882311Sseb mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 10892311Sseb if (mregp->m_max_sdu <= mregp->m_min_sdu) { 10902311Sseb err = EINVAL; 10912311Sseb goto fail; 10922311Sseb } 10932311Sseb mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 10942311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 10952311Sseb /* 10962311Sseb * If the media supports a broadcast address, cache a pointer to it 10972311Sseb * in the mac_info_t so that upper layers can use it. 10982311Sseb */ 10992311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1100269Sericheng 11012311Sseb /* 11022311Sseb * Copy the unicast source address into the mac_info_t, but only if 11032311Sseb * the MAC-Type defines a non-zero address length. We need to 11042311Sseb * handle MAC-Types that have an address length of 0 11052311Sseb * (point-to-point protocol MACs for example). 11062311Sseb */ 11072311Sseb if (mip->mi_type->mt_addr_length > 0) { 11082311Sseb if (mregp->m_src_addr == NULL) { 11092311Sseb err = EINVAL; 11102311Sseb goto fail; 11112311Sseb } 11122311Sseb mip->mi_info.mi_unicst_addr = 11132311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 11142311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 11152311Sseb mip->mi_type->mt_addr_length); 11162311Sseb 11172311Sseb /* 11182311Sseb * Copy the fixed 'factory' MAC address from the immutable 11192311Sseb * info. This is taken to be the MAC address currently in 11202311Sseb * use. 11212311Sseb */ 11222311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 11232311Sseb mip->mi_type->mt_addr_length); 11242311Sseb /* Copy the destination address if one is provided. */ 11252311Sseb if (mregp->m_dst_addr != NULL) { 11262311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 11272311Sseb mip->mi_type->mt_addr_length); 11282311Sseb } 11292311Sseb } else if (mregp->m_src_addr != NULL) { 11302311Sseb err = EINVAL; 11312311Sseb goto fail; 1132269Sericheng } 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate /* 11352311Sseb * The format of the m_pdata is specific to the plugin. It is 11362311Sseb * passed in as an argument to all of the plugin callbacks. The 11372311Sseb * driver can update this information by calling 11382311Sseb * mac_pdata_update(). 11390Sstevel@tonic-gate */ 11402311Sseb if (mregp->m_pdata != NULL) { 11412311Sseb /* 11422311Sseb * Verify that the plugin supports MAC plugin data and that 11432311Sseb * the supplied data is valid. 11442311Sseb */ 11452311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 11462311Sseb err = EINVAL; 11472311Sseb goto fail; 11482311Sseb } 11492311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 11502311Sseb mregp->m_pdata_size)) { 11512311Sseb err = EINVAL; 11522311Sseb goto fail; 11532311Sseb } 11542311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 11552311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 11562311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 11572311Sseb } 11582311Sseb 11592311Sseb /* 11602311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 11612311Sseb * check to make sure all mandatory callbacks are set. 11622311Sseb */ 11632311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 11642311Sseb mregp->m_callbacks->mc_start == NULL || 11652311Sseb mregp->m_callbacks->mc_stop == NULL || 11662311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 11672311Sseb mregp->m_callbacks->mc_multicst == NULL || 11682311Sseb mregp->m_callbacks->mc_unicst == NULL || 11692311Sseb mregp->m_callbacks->mc_tx == NULL) { 11702311Sseb err = EINVAL; 11712311Sseb goto fail; 11722311Sseb } 11732311Sseb mip->mi_callbacks = mregp->m_callbacks; 11742311Sseb 11752311Sseb mip->mi_dip = mregp->m_dip; 11762311Sseb 11772311Sseb /* 11782311Sseb * Set up the two possible transmit routines. 11792311Sseb */ 11802311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 11812311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 11822311Sseb mip->mi_txloopinfo.mt_fn = mac_txloop; 11832311Sseb mip->mi_txloopinfo.mt_arg = mip; 11842311Sseb 11852311Sseb /* 11862311Sseb * Initialize the kstats for this device. 11872311Sseb */ 11882311Sseb mac_stat_create(mip); 11890Sstevel@tonic-gate 1190269Sericheng err = EEXIST; 11912311Sseb /* Create a style-2 DLPI device */ 11922311Sseb if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 11932311Sseb S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 11942311Sseb goto fail; 11952311Sseb style2_created = B_TRUE; 1196269Sericheng 11972311Sseb /* Create a style-1 DLPI device */ 11982311Sseb minor = (minor_t)mip->mi_instance + 1; 11992311Sseb if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 12002311Sseb DDI_NT_NET, 0) != DDI_SUCCESS) 12012311Sseb goto fail; 12022311Sseb style1_created = B_TRUE; 12030Sstevel@tonic-gate 12042311Sseb /* 12052311Sseb * Create a link for this MAC. The link name will be the same as 12062311Sseb * the MAC name. 12072311Sseb */ 12082311Sseb err = dls_create(mip->mi_name, mip->mi_name, 12092311Sseb ddi_get_instance(mip->mi_dip)); 12102311Sseb if (err != 0) 12112311Sseb goto fail; 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 12142311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 12150Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 12160Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 12170Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 12180Sstevel@tonic-gate 12191852Syz147064 /* 12201852Syz147064 * Mark the MAC to be ready for open. 12211852Syz147064 */ 12222311Sseb mip->mi_disabled = B_FALSE; 12232311Sseb 12242311Sseb cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 12251852Syz147064 rw_exit(&i_mac_impl_lock); 12262311Sseb *mhp = (mac_handle_t)mip; 1227269Sericheng return (0); 12280Sstevel@tonic-gate 12292311Sseb fail: 12302311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 12312311Sseb &val); 12322311Sseb ASSERT(mip == (mac_impl_t *)val); 12332311Sseb i_mac_impl_count--; 12342311Sseb 12352311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 12362311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 12372311Sseb mip->mi_type->mt_addr_length); 12382311Sseb mip->mi_info.mi_unicst_addr = NULL; 12392311Sseb } 12402311Sseb if (style1_created) 12412311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 12422311Sseb if (style2_created) 12432311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 12442311Sseb 12452311Sseb mac_stat_destroy(mip); 12462311Sseb 12472311Sseb if (mip->mi_type != NULL) { 12482311Sseb mip->mi_type->mt_ref--; 12492311Sseb mip->mi_type = NULL; 12502311Sseb } 12512311Sseb 12522311Sseb if (mip->mi_pdata != NULL) { 12532311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 12542311Sseb mip->mi_pdata = NULL; 12552311Sseb mip->mi_pdata_size = 0; 12562311Sseb } 12572311Sseb 12582311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 12592311Sseb rw_exit(&i_mac_impl_lock); 1260269Sericheng return (err); 12610Sstevel@tonic-gate } 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate int 12642311Sseb mac_unregister(mac_handle_t mh) 12650Sstevel@tonic-gate { 12662311Sseb int err; 12672311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 12682311Sseb mod_hash_val_t val; 12692311Sseb mac_multicst_addr_t *p, *nextp; 1270269Sericheng 12710Sstevel@tonic-gate /* 12720Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 12731852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 12742311Sseb * created while we're destroying this mac. 12750Sstevel@tonic-gate */ 1276269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12770Sstevel@tonic-gate if (mip->mi_ref > 0) { 1278269Sericheng rw_exit(&i_mac_impl_lock); 12790Sstevel@tonic-gate return (EBUSY); 12800Sstevel@tonic-gate } 12811852Syz147064 mip->mi_disabled = B_TRUE; 1282269Sericheng rw_exit(&i_mac_impl_lock); 12830Sstevel@tonic-gate 12841852Syz147064 /* 12851852Syz147064 * Wait for all taskqs which process the mac notifications to finish. 12861852Syz147064 */ 12871852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 12881852Syz147064 while (mip->mi_notify_ref != 0) 12891852Syz147064 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 12901852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 12911852Syz147064 12922311Sseb if ((err = dls_destroy(mip->mi_name)) != 0) { 1293269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12941852Syz147064 mip->mi_disabled = B_FALSE; 1295269Sericheng rw_exit(&i_mac_impl_lock); 1296269Sericheng return (err); 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13002311Sseb * Remove both style 1 and style 2 minor nodes 13010Sstevel@tonic-gate */ 13022311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 13032311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 13042311Sseb 13052311Sseb ASSERT(!mip->mi_activelink); 13062311Sseb 13072311Sseb mac_stat_destroy(mip); 13082311Sseb 13092311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 13102311Sseb &val); 13112311Sseb ASSERT(mip == (mac_impl_t *)val); 13122311Sseb 13132311Sseb ASSERT(i_mac_impl_count > 0); 13142311Sseb i_mac_impl_count--; 13152311Sseb 13162311Sseb if (mip->mi_pdata != NULL) 13172311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 13182311Sseb mip->mi_pdata = NULL; 13192311Sseb mip->mi_pdata_size = 0; 13200Sstevel@tonic-gate 13210Sstevel@tonic-gate /* 13222311Sseb * Free the list of multicast addresses. 13230Sstevel@tonic-gate */ 13242311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 13252311Sseb nextp = p->mma_nextp; 13262311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 13272311Sseb } 13282311Sseb mip->mi_mmap = NULL; 13290Sstevel@tonic-gate 13302311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 13312311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 13322311Sseb mip->mi_info.mi_unicst_addr = NULL; 13332311Sseb 13342311Sseb mip->mi_type->mt_ref--; 13352311Sseb mip->mi_type = NULL; 13362311Sseb 13372311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 13382311Sseb 13392311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 13402311Sseb 13410Sstevel@tonic-gate return (0); 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate void 13452311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 13460Sstevel@tonic-gate { 13472311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13480Sstevel@tonic-gate mac_rx_fn_t *mrfp; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate /* 13510Sstevel@tonic-gate * Call all registered receive functions. 13520Sstevel@tonic-gate */ 13530Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 13540Sstevel@tonic-gate mrfp = mip->mi_mrfp; 13550Sstevel@tonic-gate if (mrfp == NULL) { 13560Sstevel@tonic-gate /* There are no registered receive functions. */ 13570Sstevel@tonic-gate freemsgchain(bp); 13580Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13590Sstevel@tonic-gate return; 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate do { 13620Sstevel@tonic-gate mblk_t *recv_bp; 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate if (mrfp->mrf_nextp != NULL) { 13650Sstevel@tonic-gate /* XXX Do we bump a counter if copymsgchain() fails? */ 13660Sstevel@tonic-gate recv_bp = copymsgchain(bp); 13670Sstevel@tonic-gate } else { 13680Sstevel@tonic-gate recv_bp = bp; 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate if (recv_bp != NULL) 13710Sstevel@tonic-gate mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 13720Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 13730Sstevel@tonic-gate } while (mrfp != NULL); 13740Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13750Sstevel@tonic-gate } 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate /* 13780Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 13790Sstevel@tonic-gate */ 13800Sstevel@tonic-gate mblk_t * 13810Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 13820Sstevel@tonic-gate { 13830Sstevel@tonic-gate mac_impl_t *mip = arg; 13840Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 13850Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate while (bp != NULL) { 13880Sstevel@tonic-gate next_bp = bp->b_next; 13890Sstevel@tonic-gate bp->b_next = NULL; 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 13920Sstevel@tonic-gate goto noresources; 13930Sstevel@tonic-gate 13942311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 13950Sstevel@tonic-gate ASSERT(resid_bp == bp); 13960Sstevel@tonic-gate freemsg(loop_bp); 13970Sstevel@tonic-gate goto noresources; 13980Sstevel@tonic-gate } 13990Sstevel@tonic-gate 14000Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 14010Sstevel@tonic-gate mtfp = mip->mi_mtfp; 140256Smeem while (mtfp != NULL && loop_bp != NULL) { 14030Sstevel@tonic-gate bp = loop_bp; 140456Smeem 140556Smeem /* XXX counter bump if copymsg() fails? */ 140656Smeem if (mtfp->mtf_nextp != NULL) 14070Sstevel@tonic-gate loop_bp = copymsg(bp); 140856Smeem else 140956Smeem loop_bp = NULL; 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 141256Smeem mtfp = mtfp->mtf_nextp; 14130Sstevel@tonic-gate } 141456Smeem rw_exit(&mip->mi_txloop_lock); 14150Sstevel@tonic-gate 141656Smeem /* 141756Smeem * It's possible we've raced with the disabling of promiscuous 141856Smeem * mode, in which case we can discard our copy. 141956Smeem */ 142056Smeem if (loop_bp != NULL) 142156Smeem freemsg(loop_bp); 142256Smeem 14230Sstevel@tonic-gate bp = next_bp; 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate return (NULL); 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate noresources: 14290Sstevel@tonic-gate bp->b_next = next_bp; 14300Sstevel@tonic-gate return (bp); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate void 14342311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 14350Sstevel@tonic-gate { 14362311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14370Sstevel@tonic-gate 14380Sstevel@tonic-gate /* 14390Sstevel@tonic-gate * Save the link state. 14400Sstevel@tonic-gate */ 14412311Sseb mip->mi_linkstate = link; 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate /* 14440Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 14450Sstevel@tonic-gate */ 14460Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 14470Sstevel@tonic-gate } 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate void 14502311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 14510Sstevel@tonic-gate { 14522311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14530Sstevel@tonic-gate 14542311Sseb if (mip->mi_type->mt_addr_length == 0) 14552311Sseb return; 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate /* 14580Sstevel@tonic-gate * Save the address. 14590Sstevel@tonic-gate */ 14602311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate /* 14630Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 14640Sstevel@tonic-gate */ 14650Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate void 14692311Sseb mac_tx_update(mac_handle_t mh) 14700Sstevel@tonic-gate { 14710Sstevel@tonic-gate /* 14720Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 14730Sstevel@tonic-gate */ 14742311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate void 14782311Sseb mac_resource_update(mac_handle_t mh) 14790Sstevel@tonic-gate { 14800Sstevel@tonic-gate /* 14810Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 14820Sstevel@tonic-gate */ 14832311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate mac_resource_handle_t 14872311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 14880Sstevel@tonic-gate { 14892311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14900Sstevel@tonic-gate mac_resource_handle_t mrh; 14910Sstevel@tonic-gate mac_resource_add_t add; 14920Sstevel@tonic-gate void *arg; 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 14950Sstevel@tonic-gate add = mip->mi_resource_add; 14960Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 14970Sstevel@tonic-gate 14981184Skrgopi if (add != NULL) 14991184Skrgopi mrh = add(arg, mrp); 15001184Skrgopi else 15011184Skrgopi mrh = NULL; 15020Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate return (mrh); 15050Sstevel@tonic-gate } 15060Sstevel@tonic-gate 15072311Sseb int 15082311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 15092311Sseb { 15102311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15112311Sseb 15122311Sseb /* 15132311Sseb * Verify that the plugin supports MAC plugin data and that the 15142311Sseb * supplied data is valid. 15152311Sseb */ 15162311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 15172311Sseb return (EINVAL); 15182311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 15192311Sseb return (EINVAL); 15202311Sseb 15212311Sseb if (mip->mi_pdata != NULL) 15222311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 15232311Sseb 15242311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 15252311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 15262311Sseb mip->mi_pdata_size = dsize; 15272311Sseb 15282311Sseb /* 15292311Sseb * Since the MAC plugin data is used to construct MAC headers that 15302311Sseb * were cached in fast-path headers, we need to flush fast-path 15312311Sseb * information for links associated with this mac. 15322311Sseb */ 15332311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 15342311Sseb return (0); 15352311Sseb } 15362311Sseb 15370Sstevel@tonic-gate void 15382311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 15390Sstevel@tonic-gate boolean_t add) 15400Sstevel@tonic-gate { 15412311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15420Sstevel@tonic-gate mac_multicst_addr_t *p; 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate /* 15450Sstevel@tonic-gate * If no specific refresh function was given then default to the 15460Sstevel@tonic-gate * driver's m_multicst entry point. 15470Sstevel@tonic-gate */ 15480Sstevel@tonic-gate if (refresh == NULL) { 15492311Sseb refresh = mip->mi_multicst; 15502311Sseb arg = mip->mi_driver; 15510Sstevel@tonic-gate } 15520Sstevel@tonic-gate ASSERT(refresh != NULL); 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate /* 15550Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 15560Sstevel@tonic-gate * each address. 15570Sstevel@tonic-gate */ 15580Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 15590Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 15600Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 15610Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate 15640Sstevel@tonic-gate void 15652311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 15660Sstevel@tonic-gate { 15672311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15680Sstevel@tonic-gate /* 15690Sstevel@tonic-gate * If no specific refresh function was given then default to the 15702311Sseb * driver's mi_unicst entry point. 15710Sstevel@tonic-gate */ 15720Sstevel@tonic-gate if (refresh == NULL) { 15732311Sseb refresh = mip->mi_unicst; 15742311Sseb arg = mip->mi_driver; 15750Sstevel@tonic-gate } 15760Sstevel@tonic-gate ASSERT(refresh != NULL); 15770Sstevel@tonic-gate 15780Sstevel@tonic-gate /* 15790Sstevel@tonic-gate * Call the refresh function with the current unicast address. 15800Sstevel@tonic-gate */ 15810Sstevel@tonic-gate refresh(arg, mip->mi_addr); 15820Sstevel@tonic-gate } 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate void 15852311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 15860Sstevel@tonic-gate { 15872311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate /* 15900Sstevel@tonic-gate * If no specific refresh function was given then default to the 15910Sstevel@tonic-gate * driver's m_promisc entry point. 15920Sstevel@tonic-gate */ 15930Sstevel@tonic-gate if (refresh == NULL) { 15942311Sseb refresh = mip->mi_setpromisc; 15952311Sseb arg = mip->mi_driver; 15960Sstevel@tonic-gate } 15970Sstevel@tonic-gate ASSERT(refresh != NULL); 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate /* 16000Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 16010Sstevel@tonic-gate */ 16020Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 16030Sstevel@tonic-gate } 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate boolean_t 16060Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 16070Sstevel@tonic-gate { 16080Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16110Sstevel@tonic-gate if (mip->mi_activelink) { 16120Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16130Sstevel@tonic-gate return (B_FALSE); 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 16160Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16170Sstevel@tonic-gate return (B_TRUE); 16180Sstevel@tonic-gate } 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate void 16210Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 16220Sstevel@tonic-gate { 16230Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16240Sstevel@tonic-gate 16250Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16260Sstevel@tonic-gate ASSERT(mip->mi_activelink); 16270Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 16280Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16290Sstevel@tonic-gate } 1630269Sericheng 1631269Sericheng /* 1632269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1633269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1634269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1635269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1636269Sericheng * cannot disappear while we are accessing it. 1637269Sericheng */ 1638269Sericheng typedef struct i_mac_info_state_s { 1639269Sericheng const char *mi_name; 1640269Sericheng mac_info_t *mi_infop; 1641269Sericheng } i_mac_info_state_t; 1642269Sericheng 1643269Sericheng /*ARGSUSED*/ 1644269Sericheng static uint_t 1645269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1646269Sericheng { 1647269Sericheng i_mac_info_state_t *statep = arg; 1648269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 1649269Sericheng 16501852Syz147064 if (mip->mi_disabled) 1651269Sericheng return (MH_WALK_CONTINUE); 1652269Sericheng 1653269Sericheng if (strcmp(statep->mi_name, 16542311Sseb ddi_driver_name(mip->mi_dip)) != 0) 1655269Sericheng return (MH_WALK_CONTINUE); 1656269Sericheng 16572311Sseb statep->mi_infop = &mip->mi_info; 1658269Sericheng return (MH_WALK_TERMINATE); 1659269Sericheng } 1660269Sericheng 1661269Sericheng boolean_t 1662269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 1663269Sericheng { 1664269Sericheng i_mac_info_state_t state; 1665269Sericheng 1666269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 1667269Sericheng state.mi_name = name; 1668269Sericheng state.mi_infop = NULL; 1669269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1670269Sericheng if (state.mi_infop == NULL) { 1671269Sericheng rw_exit(&i_mac_impl_lock); 1672269Sericheng return (B_FALSE); 1673269Sericheng } 1674269Sericheng *minfop = *state.mi_infop; 1675269Sericheng rw_exit(&i_mac_impl_lock); 1676269Sericheng return (B_TRUE); 1677269Sericheng } 1678269Sericheng 16792311Sseb boolean_t 16802311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 16812311Sseb { 16822311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16832311Sseb 16842311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 16852311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 16862311Sseb else 16872311Sseb return (B_FALSE); 16882311Sseb } 16892311Sseb 16902311Sseb boolean_t 16912311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 16922311Sseb { 16932311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16942311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 16952311Sseb mip->mi_pdata)); 16962311Sseb } 16972311Sseb 16982311Sseb mblk_t * 16992311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 17002311Sseb size_t extra_len) 17012311Sseb { 17022311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17032311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 17042311Sseb mip->mi_pdata, payload, extra_len)); 17052311Sseb } 17062311Sseb 17072311Sseb int 17082311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 17092311Sseb { 17102311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17112311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 17122311Sseb mhip)); 17132311Sseb } 17142311Sseb 17152311Sseb mblk_t * 17162311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 17172311Sseb { 17182311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17192311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 17202311Sseb if (DB_REF(mp) > 1) { 17212311Sseb mblk_t *newmp = copymsg(mp); 1722*2760Sdg199075 if (newmp == NULL) 1723*2760Sdg199075 return (NULL); 17242311Sseb freemsg(mp); 17252311Sseb mp = newmp; 17262311Sseb } 17272311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 17282311Sseb mip->mi_pdata)); 17292311Sseb } 17302311Sseb return (mp); 17312311Sseb } 17322311Sseb 17332311Sseb mblk_t * 17342311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 17352311Sseb { 17362311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17372311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 17382311Sseb if (DB_REF(mp) > 1) { 17392311Sseb mblk_t *newmp = copymsg(mp); 1740*2760Sdg199075 if (newmp == NULL) 1741*2760Sdg199075 return (NULL); 17422311Sseb freemsg(mp); 17432311Sseb mp = newmp; 17442311Sseb } 17452311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 17462311Sseb mip->mi_pdata)); 17472311Sseb } 17482311Sseb return (mp); 17492311Sseb } 17502311Sseb 1751269Sericheng void 1752269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 1753269Sericheng { 1754269Sericheng dld_init_ops(ops, name); 1755269Sericheng } 1756269Sericheng 1757269Sericheng void 1758269Sericheng mac_fini_ops(struct dev_ops *ops) 1759269Sericheng { 1760269Sericheng dld_fini_ops(ops); 1761269Sericheng } 17622311Sseb 17632311Sseb /* 17642311Sseb * MAC Type Plugin functions. 17652311Sseb */ 17662311Sseb 17672311Sseb mactype_register_t * 17682311Sseb mactype_alloc(uint_t mactype_version) 17692311Sseb { 17702311Sseb mactype_register_t *mtrp; 17712311Sseb 17722311Sseb /* 17732311Sseb * Make sure there isn't a version mismatch between the plugin and 17742311Sseb * the framework. In the future, if multiple versions are 17752311Sseb * supported, this check could become more sophisticated. 17762311Sseb */ 17772311Sseb if (mactype_version != MACTYPE_VERSION) 17782311Sseb return (NULL); 17792311Sseb 17802311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 17812311Sseb mtrp->mtr_version = mactype_version; 17822311Sseb return (mtrp); 17832311Sseb } 17842311Sseb 17852311Sseb void 17862311Sseb mactype_free(mactype_register_t *mtrp) 17872311Sseb { 17882311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 17892311Sseb } 17902311Sseb 17912311Sseb int 17922311Sseb mactype_register(mactype_register_t *mtrp) 17932311Sseb { 17942311Sseb mactype_t *mtp; 17952311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 17962311Sseb 17972311Sseb /* Do some sanity checking before we register this MAC type. */ 17982311Sseb if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 17992311Sseb return (EINVAL); 18002311Sseb 18012311Sseb /* 18022311Sseb * Verify that all mandatory callbacks are set in the ops 18032311Sseb * vector. 18042311Sseb */ 18052311Sseb if (ops->mtops_unicst_verify == NULL || 18062311Sseb ops->mtops_multicst_verify == NULL || 18072311Sseb ops->mtops_sap_verify == NULL || 18082311Sseb ops->mtops_header == NULL || 18092311Sseb ops->mtops_header_info == NULL) { 18102311Sseb return (EINVAL); 18112311Sseb } 18122311Sseb 18132311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 18142311Sseb mtp->mt_ident = mtrp->mtr_ident; 18152311Sseb mtp->mt_ops = *ops; 18162311Sseb mtp->mt_type = mtrp->mtr_mactype; 18172311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 18182311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 18192311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 18202311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 18212311Sseb mtrp->mtr_addrlen); 18222311Sseb } 18232311Sseb 18242311Sseb mtp->mt_stats = mtrp->mtr_stats; 18252311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 18262311Sseb 18272311Sseb /* 18282311Sseb * A MAC-Type plugin only registers when i_mactype_getplugin() does 18292311Sseb * an explicit modload() as a result of a driver requesting to use 18302311Sseb * that plugin in mac_register(). We pre-emptively set the initial 18312311Sseb * reference count to 1 here to prevent the plugin module from 18322311Sseb * unloading before the driver's mac_register() completes. If we 18332311Sseb * were to initialize the reference count to 0, then there would be 18342311Sseb * a window during which the module could unload before the 18352311Sseb * reference count could be bumped up to 1. 18362311Sseb */ 18372311Sseb mtp->mt_ref = 1; 18382311Sseb 18392311Sseb if (mod_hash_insert(i_mactype_hash, 18402311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 18412311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18422311Sseb kmem_free(mtp, sizeof (*mtp)); 18432311Sseb return (EEXIST); 18442311Sseb } 18452311Sseb return (0); 18462311Sseb } 18472311Sseb 18482311Sseb int 18492311Sseb mactype_unregister(const char *ident) 18502311Sseb { 18512311Sseb mactype_t *mtp; 18522311Sseb mod_hash_val_t val; 18532311Sseb int err; 18542311Sseb 18552311Sseb /* 18562311Sseb * Let's not allow MAC drivers to use this plugin while we're 18572311Sseb * trying to unregister it... 18582311Sseb */ 18592311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 18602311Sseb 18612311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 18622311Sseb (mod_hash_val_t *)&mtp)) != 0) { 18632311Sseb /* A plugin is trying to unregister, but it never registered. */ 18642311Sseb rw_exit(&i_mac_impl_lock); 18652311Sseb return (ENXIO); 18662311Sseb } 18672311Sseb 18682311Sseb if (mtp->mt_ref > 0) { 18692311Sseb rw_exit(&i_mac_impl_lock); 18702311Sseb return (EBUSY); 18712311Sseb } 18722311Sseb 18732311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 18742311Sseb ASSERT(err == 0); 18752311Sseb if (err != 0) { 18762311Sseb /* This should never happen, thus the ASSERT() above. */ 18772311Sseb rw_exit(&i_mac_impl_lock); 18782311Sseb return (EINVAL); 18792311Sseb } 18802311Sseb ASSERT(mtp == (mactype_t *)val); 18812311Sseb 18822311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18832311Sseb kmem_free(mtp, sizeof (mactype_t)); 18842311Sseb rw_exit(&i_mac_impl_lock); 18852311Sseb 18862311Sseb return (0); 18872311Sseb } 1888