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 585*2331Skrgopi /* 586*2331Skrgopi * mac_unicst_verify: Verifies the passed address. It fails 587*2331Skrgopi * if the passed address is a group address or has incorrect length. 588*2331Skrgopi */ 589*2331Skrgopi boolean_t 590*2331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 591*2331Skrgopi { 592*2331Skrgopi mac_impl_t *mip = (mac_impl_t *)mh; 593*2331Skrgopi 594*2331Skrgopi /* 595*2331Skrgopi * Verify the address. 596*2331Skrgopi */ 597*2331Skrgopi if ((len != mip->mi_type->mt_addr_length) || 598*2331Skrgopi (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 599*2331Skrgopi mip->mi_pdata)) != 0) { 600*2331Skrgopi return (B_FALSE); 601*2331Skrgopi } else { 602*2331Skrgopi return (B_TRUE); 603*2331Skrgopi } 604*2331Skrgopi } 605*2331Skrgopi 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 /* ARGSUSED */ 10382311Sseb int 10392311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 10402311Sseb { 10412311Sseb mac_impl_t *mip; 10422311Sseb mactype_t *mtype; 10432311Sseb int err; 10440Sstevel@tonic-gate struct devnames *dnp; 10452311Sseb minor_t minor; 10462311Sseb mod_hash_val_t val; 10472311Sseb boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 10482311Sseb 10492311Sseb /* Find the required MAC-Type plugin. */ 10502311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 10512311Sseb return (EINVAL); 10522311Sseb 10532311Sseb /* Create a mac_impl_t to represent this MAC. */ 10542311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 10552311Sseb 10562311Sseb /* 10572311Sseb * The mac is not ready for open yet. 10582311Sseb */ 10592311Sseb mip->mi_disabled = B_TRUE; 10602311Sseb 10612311Sseb mip->mi_drvname = ddi_driver_name(mregp->m_dip); 10622311Sseb /* 10632311Sseb * Some drivers such as aggr need to register multiple MACs. Such 10642311Sseb * drivers must supply a non-zero "instance" argument so that each 10652311Sseb * MAC can be assigned a unique MAC name and can have unique 10662311Sseb * kstats. 10672311Sseb */ 10682311Sseb mip->mi_instance = ((mregp->m_instance == 0) ? 10692311Sseb ddi_get_instance(mregp->m_dip) : mregp->m_instance); 10702311Sseb 10712311Sseb /* Construct the MAC name as <drvname><instance> */ 10722311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 10732311Sseb mip->mi_drvname, mip->mi_instance); 10742311Sseb 10752311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 10762311Sseb if (mod_hash_insert(i_mac_impl_hash, 10772311Sseb (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 10782311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 10792311Sseb rw_exit(&i_mac_impl_lock); 10802311Sseb return (EEXIST); 10812311Sseb } 10822311Sseb i_mac_impl_count++; 10832311Sseb 10842311Sseb mip->mi_driver = mregp->m_driver; 10852311Sseb 10862311Sseb mip->mi_type = mtype; 10870Sstevel@tonic-gate 10882311Sseb mip->mi_info.mi_media = mtype->mt_type; 10892311Sseb mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 10902311Sseb if (mregp->m_max_sdu <= mregp->m_min_sdu) { 10912311Sseb err = EINVAL; 10922311Sseb goto fail; 10932311Sseb } 10942311Sseb mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 10952311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 10962311Sseb /* 10972311Sseb * If the media supports a broadcast address, cache a pointer to it 10982311Sseb * in the mac_info_t so that upper layers can use it. 10992311Sseb */ 11002311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1101269Sericheng 11022311Sseb /* 11032311Sseb * Copy the unicast source address into the mac_info_t, but only if 11042311Sseb * the MAC-Type defines a non-zero address length. We need to 11052311Sseb * handle MAC-Types that have an address length of 0 11062311Sseb * (point-to-point protocol MACs for example). 11072311Sseb */ 11082311Sseb if (mip->mi_type->mt_addr_length > 0) { 11092311Sseb if (mregp->m_src_addr == NULL) { 11102311Sseb err = EINVAL; 11112311Sseb goto fail; 11122311Sseb } 11132311Sseb mip->mi_info.mi_unicst_addr = 11142311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 11152311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 11162311Sseb mip->mi_type->mt_addr_length); 11172311Sseb 11182311Sseb /* 11192311Sseb * Copy the fixed 'factory' MAC address from the immutable 11202311Sseb * info. This is taken to be the MAC address currently in 11212311Sseb * use. 11222311Sseb */ 11232311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 11242311Sseb mip->mi_type->mt_addr_length); 11252311Sseb /* Copy the destination address if one is provided. */ 11262311Sseb if (mregp->m_dst_addr != NULL) { 11272311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 11282311Sseb mip->mi_type->mt_addr_length); 11292311Sseb } 11302311Sseb } else if (mregp->m_src_addr != NULL) { 11312311Sseb err = EINVAL; 11322311Sseb goto fail; 1133269Sericheng } 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate /* 11362311Sseb * The format of the m_pdata is specific to the plugin. It is 11372311Sseb * passed in as an argument to all of the plugin callbacks. The 11382311Sseb * driver can update this information by calling 11392311Sseb * mac_pdata_update(). 11400Sstevel@tonic-gate */ 11412311Sseb if (mregp->m_pdata != NULL) { 11422311Sseb /* 11432311Sseb * Verify that the plugin supports MAC plugin data and that 11442311Sseb * the supplied data is valid. 11452311Sseb */ 11462311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 11472311Sseb err = EINVAL; 11482311Sseb goto fail; 11492311Sseb } 11502311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 11512311Sseb mregp->m_pdata_size)) { 11522311Sseb err = EINVAL; 11532311Sseb goto fail; 11542311Sseb } 11552311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 11562311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 11572311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 11582311Sseb } 11592311Sseb 11602311Sseb /* 11612311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 11622311Sseb * check to make sure all mandatory callbacks are set. 11632311Sseb */ 11642311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 11652311Sseb mregp->m_callbacks->mc_start == NULL || 11662311Sseb mregp->m_callbacks->mc_stop == NULL || 11672311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 11682311Sseb mregp->m_callbacks->mc_multicst == NULL || 11692311Sseb mregp->m_callbacks->mc_unicst == NULL || 11702311Sseb mregp->m_callbacks->mc_tx == NULL) { 11712311Sseb err = EINVAL; 11722311Sseb goto fail; 11732311Sseb } 11742311Sseb mip->mi_callbacks = mregp->m_callbacks; 11752311Sseb 11762311Sseb mip->mi_dip = mregp->m_dip; 11772311Sseb 11782311Sseb /* 11792311Sseb * Set up the two possible transmit routines. 11802311Sseb */ 11812311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 11822311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 11832311Sseb mip->mi_txloopinfo.mt_fn = mac_txloop; 11842311Sseb mip->mi_txloopinfo.mt_arg = mip; 11852311Sseb 11862311Sseb /* 11872311Sseb * Initialize the kstats for this device. 11882311Sseb */ 11892311Sseb mac_stat_create(mip); 11900Sstevel@tonic-gate 1191269Sericheng err = EEXIST; 11922311Sseb /* Create a style-2 DLPI device */ 11932311Sseb if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 11942311Sseb S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 11952311Sseb goto fail; 11962311Sseb style2_created = B_TRUE; 1197269Sericheng 11982311Sseb /* Create a style-1 DLPI device */ 11992311Sseb minor = (minor_t)mip->mi_instance + 1; 12002311Sseb if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 12012311Sseb DDI_NT_NET, 0) != DDI_SUCCESS) 12022311Sseb goto fail; 12032311Sseb style1_created = B_TRUE; 12040Sstevel@tonic-gate 12052311Sseb /* 12062311Sseb * Create a link for this MAC. The link name will be the same as 12072311Sseb * the MAC name. 12082311Sseb */ 12092311Sseb err = dls_create(mip->mi_name, mip->mi_name, 12102311Sseb ddi_get_instance(mip->mi_dip)); 12112311Sseb if (err != 0) 12122311Sseb goto fail; 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 12152311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 12160Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 12170Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 12180Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 12190Sstevel@tonic-gate 12201852Syz147064 /* 12211852Syz147064 * Mark the MAC to be ready for open. 12221852Syz147064 */ 12232311Sseb mip->mi_disabled = B_FALSE; 12242311Sseb 12252311Sseb cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 12261852Syz147064 rw_exit(&i_mac_impl_lock); 12272311Sseb *mhp = (mac_handle_t)mip; 1228269Sericheng return (0); 12290Sstevel@tonic-gate 12302311Sseb fail: 12312311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 12322311Sseb &val); 12332311Sseb ASSERT(mip == (mac_impl_t *)val); 12342311Sseb i_mac_impl_count--; 12352311Sseb 12362311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 12372311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 12382311Sseb mip->mi_type->mt_addr_length); 12392311Sseb mip->mi_info.mi_unicst_addr = NULL; 12402311Sseb } 12412311Sseb if (style1_created) 12422311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 12432311Sseb if (style2_created) 12442311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 12452311Sseb 12462311Sseb mac_stat_destroy(mip); 12472311Sseb 12482311Sseb if (mip->mi_type != NULL) { 12492311Sseb mip->mi_type->mt_ref--; 12502311Sseb mip->mi_type = NULL; 12512311Sseb } 12522311Sseb 12532311Sseb if (mip->mi_pdata != NULL) { 12542311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 12552311Sseb mip->mi_pdata = NULL; 12562311Sseb mip->mi_pdata_size = 0; 12572311Sseb } 12582311Sseb 12592311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 12602311Sseb rw_exit(&i_mac_impl_lock); 1261269Sericheng return (err); 12620Sstevel@tonic-gate } 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate int 12652311Sseb mac_unregister(mac_handle_t mh) 12660Sstevel@tonic-gate { 12672311Sseb int err; 12682311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 12692311Sseb mod_hash_val_t val; 12702311Sseb mac_multicst_addr_t *p, *nextp; 1271269Sericheng 12720Sstevel@tonic-gate /* 12730Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 12741852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 12752311Sseb * created while we're destroying this mac. 12760Sstevel@tonic-gate */ 1277269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12780Sstevel@tonic-gate if (mip->mi_ref > 0) { 1279269Sericheng rw_exit(&i_mac_impl_lock); 12800Sstevel@tonic-gate return (EBUSY); 12810Sstevel@tonic-gate } 12821852Syz147064 mip->mi_disabled = B_TRUE; 1283269Sericheng rw_exit(&i_mac_impl_lock); 12840Sstevel@tonic-gate 12851852Syz147064 /* 12861852Syz147064 * Wait for all taskqs which process the mac notifications to finish. 12871852Syz147064 */ 12881852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 12891852Syz147064 while (mip->mi_notify_ref != 0) 12901852Syz147064 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 12911852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 12921852Syz147064 12932311Sseb if ((err = dls_destroy(mip->mi_name)) != 0) { 1294269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12951852Syz147064 mip->mi_disabled = B_FALSE; 1296269Sericheng rw_exit(&i_mac_impl_lock); 1297269Sericheng return (err); 12980Sstevel@tonic-gate } 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate /* 13012311Sseb * Remove both style 1 and style 2 minor nodes 13020Sstevel@tonic-gate */ 13032311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 13042311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 13052311Sseb 13062311Sseb ASSERT(!mip->mi_activelink); 13072311Sseb 13082311Sseb mac_stat_destroy(mip); 13092311Sseb 13102311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 13112311Sseb &val); 13122311Sseb ASSERT(mip == (mac_impl_t *)val); 13132311Sseb 13142311Sseb ASSERT(i_mac_impl_count > 0); 13152311Sseb i_mac_impl_count--; 13162311Sseb 13172311Sseb if (mip->mi_pdata != NULL) 13182311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 13192311Sseb mip->mi_pdata = NULL; 13202311Sseb mip->mi_pdata_size = 0; 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate /* 13232311Sseb * Free the list of multicast addresses. 13240Sstevel@tonic-gate */ 13252311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 13262311Sseb nextp = p->mma_nextp; 13272311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 13282311Sseb } 13292311Sseb mip->mi_mmap = NULL; 13300Sstevel@tonic-gate 13312311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 13322311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 13332311Sseb mip->mi_info.mi_unicst_addr = NULL; 13342311Sseb 13352311Sseb mip->mi_type->mt_ref--; 13362311Sseb mip->mi_type = NULL; 13372311Sseb 13382311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 13392311Sseb 13402311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 13412311Sseb 13420Sstevel@tonic-gate return (0); 13430Sstevel@tonic-gate } 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate void 13462311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 13470Sstevel@tonic-gate { 13482311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13490Sstevel@tonic-gate mac_rx_fn_t *mrfp; 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate /* 13520Sstevel@tonic-gate * Call all registered receive functions. 13530Sstevel@tonic-gate */ 13540Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 13550Sstevel@tonic-gate mrfp = mip->mi_mrfp; 13560Sstevel@tonic-gate if (mrfp == NULL) { 13570Sstevel@tonic-gate /* There are no registered receive functions. */ 13580Sstevel@tonic-gate freemsgchain(bp); 13590Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13600Sstevel@tonic-gate return; 13610Sstevel@tonic-gate } 13620Sstevel@tonic-gate do { 13630Sstevel@tonic-gate mblk_t *recv_bp; 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate if (mrfp->mrf_nextp != NULL) { 13660Sstevel@tonic-gate /* XXX Do we bump a counter if copymsgchain() fails? */ 13670Sstevel@tonic-gate recv_bp = copymsgchain(bp); 13680Sstevel@tonic-gate } else { 13690Sstevel@tonic-gate recv_bp = bp; 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate if (recv_bp != NULL) 13720Sstevel@tonic-gate mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 13730Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 13740Sstevel@tonic-gate } while (mrfp != NULL); 13750Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate /* 13790Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 13800Sstevel@tonic-gate */ 13810Sstevel@tonic-gate mblk_t * 13820Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 13830Sstevel@tonic-gate { 13840Sstevel@tonic-gate mac_impl_t *mip = arg; 13850Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 13860Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate while (bp != NULL) { 13890Sstevel@tonic-gate next_bp = bp->b_next; 13900Sstevel@tonic-gate bp->b_next = NULL; 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 13930Sstevel@tonic-gate goto noresources; 13940Sstevel@tonic-gate 13952311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 13960Sstevel@tonic-gate ASSERT(resid_bp == bp); 13970Sstevel@tonic-gate freemsg(loop_bp); 13980Sstevel@tonic-gate goto noresources; 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 14020Sstevel@tonic-gate mtfp = mip->mi_mtfp; 140356Smeem while (mtfp != NULL && loop_bp != NULL) { 14040Sstevel@tonic-gate bp = loop_bp; 140556Smeem 140656Smeem /* XXX counter bump if copymsg() fails? */ 140756Smeem if (mtfp->mtf_nextp != NULL) 14080Sstevel@tonic-gate loop_bp = copymsg(bp); 140956Smeem else 141056Smeem loop_bp = NULL; 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 141356Smeem mtfp = mtfp->mtf_nextp; 14140Sstevel@tonic-gate } 141556Smeem rw_exit(&mip->mi_txloop_lock); 14160Sstevel@tonic-gate 141756Smeem /* 141856Smeem * It's possible we've raced with the disabling of promiscuous 141956Smeem * mode, in which case we can discard our copy. 142056Smeem */ 142156Smeem if (loop_bp != NULL) 142256Smeem freemsg(loop_bp); 142356Smeem 14240Sstevel@tonic-gate bp = next_bp; 14250Sstevel@tonic-gate } 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate return (NULL); 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate noresources: 14300Sstevel@tonic-gate bp->b_next = next_bp; 14310Sstevel@tonic-gate return (bp); 14320Sstevel@tonic-gate } 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate void 14352311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 14360Sstevel@tonic-gate { 14372311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate /* 14400Sstevel@tonic-gate * Save the link state. 14410Sstevel@tonic-gate */ 14422311Sseb mip->mi_linkstate = link; 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate /* 14450Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 14460Sstevel@tonic-gate */ 14470Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 14480Sstevel@tonic-gate } 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate void 14512311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 14520Sstevel@tonic-gate { 14532311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14540Sstevel@tonic-gate 14552311Sseb if (mip->mi_type->mt_addr_length == 0) 14562311Sseb return; 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate /* 14590Sstevel@tonic-gate * Save the address. 14600Sstevel@tonic-gate */ 14612311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate /* 14640Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 14650Sstevel@tonic-gate */ 14660Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate void 14702311Sseb mac_tx_update(mac_handle_t mh) 14710Sstevel@tonic-gate { 14720Sstevel@tonic-gate /* 14730Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 14740Sstevel@tonic-gate */ 14752311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 14760Sstevel@tonic-gate } 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate void 14792311Sseb mac_resource_update(mac_handle_t mh) 14800Sstevel@tonic-gate { 14810Sstevel@tonic-gate /* 14820Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 14830Sstevel@tonic-gate */ 14842311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate mac_resource_handle_t 14882311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 14890Sstevel@tonic-gate { 14902311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14910Sstevel@tonic-gate mac_resource_handle_t mrh; 14920Sstevel@tonic-gate mac_resource_add_t add; 14930Sstevel@tonic-gate void *arg; 14940Sstevel@tonic-gate 14950Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 14960Sstevel@tonic-gate add = mip->mi_resource_add; 14970Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 14980Sstevel@tonic-gate 14991184Skrgopi if (add != NULL) 15001184Skrgopi mrh = add(arg, mrp); 15011184Skrgopi else 15021184Skrgopi mrh = NULL; 15030Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate return (mrh); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate 15082311Sseb int 15092311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 15102311Sseb { 15112311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15122311Sseb 15132311Sseb /* 15142311Sseb * Verify that the plugin supports MAC plugin data and that the 15152311Sseb * supplied data is valid. 15162311Sseb */ 15172311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 15182311Sseb return (EINVAL); 15192311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 15202311Sseb return (EINVAL); 15212311Sseb 15222311Sseb if (mip->mi_pdata != NULL) 15232311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 15242311Sseb 15252311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 15262311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 15272311Sseb mip->mi_pdata_size = dsize; 15282311Sseb 15292311Sseb /* 15302311Sseb * Since the MAC plugin data is used to construct MAC headers that 15312311Sseb * were cached in fast-path headers, we need to flush fast-path 15322311Sseb * information for links associated with this mac. 15332311Sseb */ 15342311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 15352311Sseb return (0); 15362311Sseb } 15372311Sseb 15380Sstevel@tonic-gate void 15392311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 15400Sstevel@tonic-gate boolean_t add) 15410Sstevel@tonic-gate { 15422311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15430Sstevel@tonic-gate mac_multicst_addr_t *p; 15440Sstevel@tonic-gate 15450Sstevel@tonic-gate /* 15460Sstevel@tonic-gate * If no specific refresh function was given then default to the 15470Sstevel@tonic-gate * driver's m_multicst entry point. 15480Sstevel@tonic-gate */ 15490Sstevel@tonic-gate if (refresh == NULL) { 15502311Sseb refresh = mip->mi_multicst; 15512311Sseb arg = mip->mi_driver; 15520Sstevel@tonic-gate } 15530Sstevel@tonic-gate ASSERT(refresh != NULL); 15540Sstevel@tonic-gate 15550Sstevel@tonic-gate /* 15560Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 15570Sstevel@tonic-gate * each address. 15580Sstevel@tonic-gate */ 15590Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 15600Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 15610Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 15620Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 15630Sstevel@tonic-gate } 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate void 15662311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 15670Sstevel@tonic-gate { 15682311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15690Sstevel@tonic-gate /* 15700Sstevel@tonic-gate * If no specific refresh function was given then default to the 15712311Sseb * driver's mi_unicst entry point. 15720Sstevel@tonic-gate */ 15730Sstevel@tonic-gate if (refresh == NULL) { 15742311Sseb refresh = mip->mi_unicst; 15752311Sseb 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 unicast address. 15810Sstevel@tonic-gate */ 15820Sstevel@tonic-gate refresh(arg, mip->mi_addr); 15830Sstevel@tonic-gate } 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate void 15862311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 15870Sstevel@tonic-gate { 15882311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate /* 15910Sstevel@tonic-gate * If no specific refresh function was given then default to the 15920Sstevel@tonic-gate * driver's m_promisc entry point. 15930Sstevel@tonic-gate */ 15940Sstevel@tonic-gate if (refresh == NULL) { 15952311Sseb refresh = mip->mi_setpromisc; 15962311Sseb arg = mip->mi_driver; 15970Sstevel@tonic-gate } 15980Sstevel@tonic-gate ASSERT(refresh != NULL); 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate /* 16010Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 16020Sstevel@tonic-gate */ 16030Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 16040Sstevel@tonic-gate } 16050Sstevel@tonic-gate 16060Sstevel@tonic-gate boolean_t 16070Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 16080Sstevel@tonic-gate { 16090Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16120Sstevel@tonic-gate if (mip->mi_activelink) { 16130Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16140Sstevel@tonic-gate return (B_FALSE); 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 16170Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16180Sstevel@tonic-gate return (B_TRUE); 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate 16210Sstevel@tonic-gate void 16220Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 16230Sstevel@tonic-gate { 16240Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16270Sstevel@tonic-gate ASSERT(mip->mi_activelink); 16280Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 16290Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16300Sstevel@tonic-gate } 1631269Sericheng 1632269Sericheng /* 1633269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1634269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1635269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1636269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1637269Sericheng * cannot disappear while we are accessing it. 1638269Sericheng */ 1639269Sericheng typedef struct i_mac_info_state_s { 1640269Sericheng const char *mi_name; 1641269Sericheng mac_info_t *mi_infop; 1642269Sericheng } i_mac_info_state_t; 1643269Sericheng 1644269Sericheng /*ARGSUSED*/ 1645269Sericheng static uint_t 1646269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1647269Sericheng { 1648269Sericheng i_mac_info_state_t *statep = arg; 1649269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 1650269Sericheng 16511852Syz147064 if (mip->mi_disabled) 1652269Sericheng return (MH_WALK_CONTINUE); 1653269Sericheng 1654269Sericheng if (strcmp(statep->mi_name, 16552311Sseb ddi_driver_name(mip->mi_dip)) != 0) 1656269Sericheng return (MH_WALK_CONTINUE); 1657269Sericheng 16582311Sseb statep->mi_infop = &mip->mi_info; 1659269Sericheng return (MH_WALK_TERMINATE); 1660269Sericheng } 1661269Sericheng 1662269Sericheng boolean_t 1663269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 1664269Sericheng { 1665269Sericheng i_mac_info_state_t state; 1666269Sericheng 1667269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 1668269Sericheng state.mi_name = name; 1669269Sericheng state.mi_infop = NULL; 1670269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1671269Sericheng if (state.mi_infop == NULL) { 1672269Sericheng rw_exit(&i_mac_impl_lock); 1673269Sericheng return (B_FALSE); 1674269Sericheng } 1675269Sericheng *minfop = *state.mi_infop; 1676269Sericheng rw_exit(&i_mac_impl_lock); 1677269Sericheng return (B_TRUE); 1678269Sericheng } 1679269Sericheng 16802311Sseb boolean_t 16812311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 16822311Sseb { 16832311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16842311Sseb 16852311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 16862311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 16872311Sseb else 16882311Sseb return (B_FALSE); 16892311Sseb } 16902311Sseb 16912311Sseb boolean_t 16922311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 16932311Sseb { 16942311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16952311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 16962311Sseb mip->mi_pdata)); 16972311Sseb } 16982311Sseb 16992311Sseb mblk_t * 17002311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 17012311Sseb size_t extra_len) 17022311Sseb { 17032311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17042311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 17052311Sseb mip->mi_pdata, payload, extra_len)); 17062311Sseb } 17072311Sseb 17082311Sseb int 17092311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 17102311Sseb { 17112311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17122311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 17132311Sseb mhip)); 17142311Sseb } 17152311Sseb 17162311Sseb mblk_t * 17172311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 17182311Sseb { 17192311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17202311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 17212311Sseb if (DB_REF(mp) > 1) { 17222311Sseb mblk_t *newmp = copymsg(mp); 17232311Sseb freemsg(mp); 17242311Sseb mp = newmp; 17252311Sseb } 17262311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 17272311Sseb mip->mi_pdata)); 17282311Sseb } 17292311Sseb return (mp); 17302311Sseb } 17312311Sseb 17322311Sseb mblk_t * 17332311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 17342311Sseb { 17352311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17362311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 17372311Sseb if (DB_REF(mp) > 1) { 17382311Sseb mblk_t *newmp = copymsg(mp); 17392311Sseb freemsg(mp); 17402311Sseb mp = newmp; 17412311Sseb } 17422311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 17432311Sseb mip->mi_pdata)); 17442311Sseb } 17452311Sseb return (mp); 17462311Sseb } 17472311Sseb 1748269Sericheng void 1749269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 1750269Sericheng { 1751269Sericheng dld_init_ops(ops, name); 1752269Sericheng } 1753269Sericheng 1754269Sericheng void 1755269Sericheng mac_fini_ops(struct dev_ops *ops) 1756269Sericheng { 1757269Sericheng dld_fini_ops(ops); 1758269Sericheng } 17592311Sseb 17602311Sseb /* 17612311Sseb * MAC Type Plugin functions. 17622311Sseb */ 17632311Sseb 17642311Sseb mactype_register_t * 17652311Sseb mactype_alloc(uint_t mactype_version) 17662311Sseb { 17672311Sseb mactype_register_t *mtrp; 17682311Sseb 17692311Sseb /* 17702311Sseb * Make sure there isn't a version mismatch between the plugin and 17712311Sseb * the framework. In the future, if multiple versions are 17722311Sseb * supported, this check could become more sophisticated. 17732311Sseb */ 17742311Sseb if (mactype_version != MACTYPE_VERSION) 17752311Sseb return (NULL); 17762311Sseb 17772311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 17782311Sseb mtrp->mtr_version = mactype_version; 17792311Sseb return (mtrp); 17802311Sseb } 17812311Sseb 17822311Sseb void 17832311Sseb mactype_free(mactype_register_t *mtrp) 17842311Sseb { 17852311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 17862311Sseb } 17872311Sseb 17882311Sseb int 17892311Sseb mactype_register(mactype_register_t *mtrp) 17902311Sseb { 17912311Sseb mactype_t *mtp; 17922311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 17932311Sseb 17942311Sseb /* Do some sanity checking before we register this MAC type. */ 17952311Sseb if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 17962311Sseb return (EINVAL); 17972311Sseb 17982311Sseb /* 17992311Sseb * Verify that all mandatory callbacks are set in the ops 18002311Sseb * vector. 18012311Sseb */ 18022311Sseb if (ops->mtops_unicst_verify == NULL || 18032311Sseb ops->mtops_multicst_verify == NULL || 18042311Sseb ops->mtops_sap_verify == NULL || 18052311Sseb ops->mtops_header == NULL || 18062311Sseb ops->mtops_header_info == NULL) { 18072311Sseb return (EINVAL); 18082311Sseb } 18092311Sseb 18102311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 18112311Sseb mtp->mt_ident = mtrp->mtr_ident; 18122311Sseb mtp->mt_ops = *ops; 18132311Sseb mtp->mt_type = mtrp->mtr_mactype; 18142311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 18152311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 18162311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 18172311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 18182311Sseb mtrp->mtr_addrlen); 18192311Sseb } 18202311Sseb 18212311Sseb mtp->mt_stats = mtrp->mtr_stats; 18222311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 18232311Sseb 18242311Sseb /* 18252311Sseb * A MAC-Type plugin only registers when i_mactype_getplugin() does 18262311Sseb * an explicit modload() as a result of a driver requesting to use 18272311Sseb * that plugin in mac_register(). We pre-emptively set the initial 18282311Sseb * reference count to 1 here to prevent the plugin module from 18292311Sseb * unloading before the driver's mac_register() completes. If we 18302311Sseb * were to initialize the reference count to 0, then there would be 18312311Sseb * a window during which the module could unload before the 18322311Sseb * reference count could be bumped up to 1. 18332311Sseb */ 18342311Sseb mtp->mt_ref = 1; 18352311Sseb 18362311Sseb if (mod_hash_insert(i_mactype_hash, 18372311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 18382311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18392311Sseb kmem_free(mtp, sizeof (*mtp)); 18402311Sseb return (EEXIST); 18412311Sseb } 18422311Sseb return (0); 18432311Sseb } 18442311Sseb 18452311Sseb int 18462311Sseb mactype_unregister(const char *ident) 18472311Sseb { 18482311Sseb mactype_t *mtp; 18492311Sseb mod_hash_val_t val; 18502311Sseb int err; 18512311Sseb 18522311Sseb /* 18532311Sseb * Let's not allow MAC drivers to use this plugin while we're 18542311Sseb * trying to unregister it... 18552311Sseb */ 18562311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 18572311Sseb 18582311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 18592311Sseb (mod_hash_val_t *)&mtp)) != 0) { 18602311Sseb /* A plugin is trying to unregister, but it never registered. */ 18612311Sseb rw_exit(&i_mac_impl_lock); 18622311Sseb return (ENXIO); 18632311Sseb } 18642311Sseb 18652311Sseb if (mtp->mt_ref > 0) { 18662311Sseb rw_exit(&i_mac_impl_lock); 18672311Sseb return (EBUSY); 18682311Sseb } 18692311Sseb 18702311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 18712311Sseb ASSERT(err == 0); 18722311Sseb if (err != 0) { 18732311Sseb /* This should never happen, thus the ASSERT() above. */ 18742311Sseb rw_exit(&i_mac_impl_lock); 18752311Sseb return (EINVAL); 18762311Sseb } 18772311Sseb ASSERT(mtp == (mactype_t *)val); 18782311Sseb 18792311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18802311Sseb kmem_free(mtp, sizeof (mactype_t)); 18812311Sseb rw_exit(&i_mac_impl_lock); 18822311Sseb 18832311Sseb return (0); 18842311Sseb } 1885