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> 45*3288Sseb #include <sys/atomic.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate static kmem_cache_t *i_mac_impl_cachep; 50269Sericheng static mod_hash_t *i_mac_impl_hash; 51269Sericheng krwlock_t i_mac_impl_lock; 52269Sericheng uint_t i_mac_impl_count; 530Sstevel@tonic-gate 542311Sseb #define MACTYPE_KMODDIR "mac" 552311Sseb #define MACTYPE_HASHSZ 67 562311Sseb static mod_hash_t *i_mactype_hash; 57*3288Sseb /* 58*3288Sseb * i_mactype_lock synchronizes threads that obtain references to mactype_t 59*3288Sseb * structures through i_mactype_getplugin(). 60*3288Sseb */ 61*3288Sseb static kmutex_t i_mactype_lock; 622311Sseb 631852Syz147064 static void i_mac_notify_task(void *); 641852Syz147064 650Sstevel@tonic-gate /* 660Sstevel@tonic-gate * Private functions. 670Sstevel@tonic-gate */ 680Sstevel@tonic-gate 690Sstevel@tonic-gate /*ARGSUSED*/ 700Sstevel@tonic-gate static int 710Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag) 720Sstevel@tonic-gate { 730Sstevel@tonic-gate mac_impl_t *mip = buf; 740Sstevel@tonic-gate 750Sstevel@tonic-gate bzero(buf, sizeof (mac_impl_t)); 760Sstevel@tonic-gate 772311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 780Sstevel@tonic-gate 790Sstevel@tonic-gate rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 800Sstevel@tonic-gate rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 810Sstevel@tonic-gate rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 820Sstevel@tonic-gate rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 830Sstevel@tonic-gate rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 840Sstevel@tonic-gate rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 850Sstevel@tonic-gate mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 861852Syz147064 mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL); 871852Syz147064 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 880Sstevel@tonic-gate return (0); 890Sstevel@tonic-gate } 900Sstevel@tonic-gate 910Sstevel@tonic-gate /*ARGSUSED*/ 920Sstevel@tonic-gate static void 930Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate mac_impl_t *mip = buf; 960Sstevel@tonic-gate 970Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 980Sstevel@tonic-gate ASSERT(mip->mi_active == 0); 992311Sseb ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 1000Sstevel@tonic-gate ASSERT(mip->mi_devpromisc == 0); 1010Sstevel@tonic-gate ASSERT(mip->mi_promisc == 0); 1020Sstevel@tonic-gate ASSERT(mip->mi_mmap == NULL); 1030Sstevel@tonic-gate ASSERT(mip->mi_mnfp == NULL); 1040Sstevel@tonic-gate ASSERT(mip->mi_resource_add == NULL); 1050Sstevel@tonic-gate ASSERT(mip->mi_ksp == NULL); 1062311Sseb ASSERT(mip->mi_kstat_count == 0); 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate rw_destroy(&mip->mi_state_lock); 1090Sstevel@tonic-gate rw_destroy(&mip->mi_data_lock); 1100Sstevel@tonic-gate rw_destroy(&mip->mi_notify_lock); 1110Sstevel@tonic-gate rw_destroy(&mip->mi_rx_lock); 1120Sstevel@tonic-gate rw_destroy(&mip->mi_txloop_lock); 1130Sstevel@tonic-gate rw_destroy(&mip->mi_resource_lock); 1140Sstevel@tonic-gate mutex_destroy(&mip->mi_activelink_lock); 1151852Syz147064 mutex_destroy(&mip->mi_notify_ref_lock); 1161852Syz147064 cv_destroy(&mip->mi_notify_cv); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate static void 1200Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 1210Sstevel@tonic-gate { 1221852Syz147064 mac_notify_task_arg_t *mnta; 1231852Syz147064 1241852Syz147064 rw_enter(&i_mac_impl_lock, RW_READER); 1251852Syz147064 if (mip->mi_disabled) 1261852Syz147064 goto exit; 1271852Syz147064 1281852Syz147064 if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) { 1291852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory " 1301852Syz147064 "allocation failed", mip->mi_name, type); 1311852Syz147064 goto exit; 1321852Syz147064 } 1331852Syz147064 1341852Syz147064 mnta->mnt_mip = mip; 1351852Syz147064 mnta->mnt_type = type; 1361852Syz147064 1371852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1381852Syz147064 mip->mi_notify_ref++; 1391852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1401852Syz147064 1411852Syz147064 rw_exit(&i_mac_impl_lock); 1421852Syz147064 1431852Syz147064 if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta, 1441852Syz147064 TQ_NOSLEEP) == NULL) { 1451852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch " 1461852Syz147064 "failed", mip->mi_name, type); 1471852Syz147064 1481852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1491852Syz147064 if (--mip->mi_notify_ref == 0) 1501852Syz147064 cv_signal(&mip->mi_notify_cv); 1511852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1521852Syz147064 1531852Syz147064 kmem_free(mnta, sizeof (*mnta)); 1541852Syz147064 } 1551852Syz147064 return; 1561852Syz147064 1571852Syz147064 exit: 1581852Syz147064 rw_exit(&i_mac_impl_lock); 1591852Syz147064 } 1601852Syz147064 1611852Syz147064 static void 1621852Syz147064 i_mac_notify_task(void *notify_arg) 1631852Syz147064 { 1641852Syz147064 mac_notify_task_arg_t *mnta = (mac_notify_task_arg_t *)notify_arg; 1651852Syz147064 mac_impl_t *mip; 1661852Syz147064 mac_notify_type_t type; 1670Sstevel@tonic-gate mac_notify_fn_t *mnfp; 1680Sstevel@tonic-gate mac_notify_t notify; 1690Sstevel@tonic-gate void *arg; 1700Sstevel@tonic-gate 1711852Syz147064 mip = mnta->mnt_mip; 1721852Syz147064 type = mnta->mnt_type; 1731852Syz147064 kmem_free(mnta, sizeof (*mnta)); 1741852Syz147064 1750Sstevel@tonic-gate /* 1760Sstevel@tonic-gate * Walk the list of notifications. 1770Sstevel@tonic-gate */ 1781852Syz147064 rw_enter(&mip->mi_notify_lock, RW_READER); 1790Sstevel@tonic-gate for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 1800Sstevel@tonic-gate notify = mnfp->mnf_fn; 1810Sstevel@tonic-gate arg = mnfp->mnf_arg; 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate ASSERT(notify != NULL); 1840Sstevel@tonic-gate notify(arg, type); 1850Sstevel@tonic-gate } 1861852Syz147064 rw_exit(&mip->mi_notify_lock); 1871852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1881852Syz147064 if (--mip->mi_notify_ref == 0) 1891852Syz147064 cv_signal(&mip->mi_notify_cv); 1901852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1910Sstevel@tonic-gate } 1920Sstevel@tonic-gate 1932311Sseb static mactype_t * 194*3288Sseb i_mactype_getplugin(const char *pname) 1952311Sseb { 1962311Sseb mactype_t *mtype = NULL; 1972311Sseb boolean_t tried_modload = B_FALSE; 1982311Sseb 199*3288Sseb mutex_enter(&i_mactype_lock); 200*3288Sseb 2012311Sseb find_registered_mactype: 202*3288Sseb if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname, 203*3288Sseb (mod_hash_val_t *)&mtype) != 0) { 204*3288Sseb if (!tried_modload) { 205*3288Sseb /* 206*3288Sseb * If the plugin has not yet been loaded, then 207*3288Sseb * attempt to load it now. If modload() succeeds, 208*3288Sseb * the plugin should have registered using 209*3288Sseb * mactype_register(), in which case we can go back 210*3288Sseb * and attempt to find it again. 211*3288Sseb */ 212*3288Sseb if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) { 213*3288Sseb tried_modload = B_TRUE; 214*3288Sseb goto find_registered_mactype; 215*3288Sseb } 216*3288Sseb } 217*3288Sseb } else { 2182311Sseb /* 219*3288Sseb * Note that there's no danger that the plugin we've loaded 220*3288Sseb * could be unloaded between the modload() step and the 221*3288Sseb * reference count bump here, as we're holding 222*3288Sseb * i_mactype_lock, which mactype_unregister() also holds. 2232311Sseb */ 224*3288Sseb atomic_inc_32(&mtype->mt_ref); 2252311Sseb } 2262311Sseb 227*3288Sseb mutex_exit(&i_mactype_lock); 228*3288Sseb return (mtype); 2292311Sseb } 2302311Sseb 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * Module initialization functions. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate void 2360Sstevel@tonic-gate mac_init(void) 2370Sstevel@tonic-gate { 2380Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 2392311Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 2402311Sseb NULL, NULL, NULL, 0); 2410Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL); 2420Sstevel@tonic-gate 243269Sericheng i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 244269Sericheng IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 245269Sericheng mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 246269Sericheng rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 247269Sericheng i_mac_impl_count = 0; 2482311Sseb 2492311Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash", 2502311Sseb MACTYPE_HASHSZ, 2512311Sseb mod_hash_null_keydtor, mod_hash_null_valdtor, 2522311Sseb mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate int 2560Sstevel@tonic-gate mac_fini(void) 2570Sstevel@tonic-gate { 258269Sericheng if (i_mac_impl_count > 0) 259269Sericheng return (EBUSY); 2600Sstevel@tonic-gate 261269Sericheng mod_hash_destroy_hash(i_mac_impl_hash); 262269Sericheng rw_destroy(&i_mac_impl_lock); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate kmem_cache_destroy(i_mac_impl_cachep); 2652311Sseb 2662311Sseb mod_hash_destroy_hash(i_mactype_hash); 2670Sstevel@tonic-gate return (0); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * Client functions. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate int 2752311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp) 2760Sstevel@tonic-gate { 2770Sstevel@tonic-gate char driver[MAXNAMELEN]; 2780Sstevel@tonic-gate uint_t instance; 2790Sstevel@tonic-gate major_t major; 2800Sstevel@tonic-gate dev_info_t *dip; 2810Sstevel@tonic-gate mac_impl_t *mip; 2820Sstevel@tonic-gate int err; 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate /* 2850Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our 2860Sstevel@tonic-gate * buffer. 2870Sstevel@tonic-gate */ 2882311Sseb if (strlen(macname) >= MAXNAMELEN) 2890Sstevel@tonic-gate return (EINVAL); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Split the device name into driver and instance components. 2930Sstevel@tonic-gate */ 2942311Sseb if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS) 2950Sstevel@tonic-gate return (EINVAL); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * Get the major number of the driver. 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate if ((major = ddi_name_to_major(driver)) == (major_t)-1) 3010Sstevel@tonic-gate return (EINVAL); 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * Hold the given instance to prevent it from being detached. 305269Sericheng * This will also attach the instance if it is not currently attached. 306269Sericheng * Currently we ensure that mac_register() (called by the driver's 307269Sericheng * attach entry point) and all code paths under it cannot possibly 308269Sericheng * call mac_open() because this would lead to a recursive attach 309269Sericheng * panic. 3100Sstevel@tonic-gate */ 3112311Sseb if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL) 3120Sstevel@tonic-gate return (EINVAL); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * Look up its entry in the global hash table. 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate again: 318269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 3192311Sseb err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 320269Sericheng (mod_hash_val_t *)&mip); 321269Sericheng if (err != 0) { 322269Sericheng err = ENOENT; 3230Sstevel@tonic-gate goto failed; 324269Sericheng } 3250Sstevel@tonic-gate 3261852Syz147064 if (mip->mi_disabled) { 327269Sericheng rw_exit(&i_mac_impl_lock); 3280Sstevel@tonic-gate goto again; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate mip->mi_ref++; 332269Sericheng rw_exit(&i_mac_impl_lock); 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate *mhp = (mac_handle_t)mip; 3350Sstevel@tonic-gate return (0); 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate failed: 338269Sericheng rw_exit(&i_mac_impl_lock); 3390Sstevel@tonic-gate ddi_release_devi(dip); 3400Sstevel@tonic-gate return (err); 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate void 3440Sstevel@tonic-gate mac_close(mac_handle_t mh) 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 3472311Sseb dev_info_t *dip = mip->mi_dip; 3480Sstevel@tonic-gate 349269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate ASSERT(mip->mi_ref != 0); 3520Sstevel@tonic-gate if (--mip->mi_ref == 0) { 3530Sstevel@tonic-gate ASSERT(!mip->mi_activelink); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate ddi_release_devi(dip); 356269Sericheng rw_exit(&i_mac_impl_lock); 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate const mac_info_t * 3600Sstevel@tonic-gate mac_info(mac_handle_t mh) 3610Sstevel@tonic-gate { 3622311Sseb return (&((mac_impl_t *)mh)->mi_info); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 365269Sericheng dev_info_t * 366269Sericheng mac_devinfo_get(mac_handle_t mh) 367269Sericheng { 3682311Sseb return (((mac_impl_t *)mh)->mi_dip); 369269Sericheng } 370269Sericheng 3710Sstevel@tonic-gate uint64_t 3722311Sseb mac_stat_get(mac_handle_t mh, uint_t stat) 3730Sstevel@tonic-gate { 3740Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 3752311Sseb uint64_t val; 3762311Sseb int ret; 3770Sstevel@tonic-gate 3782311Sseb /* 3792311Sseb * The range of stat determines where it is maintained. Stat 3802311Sseb * values from 0 up to (but not including) MAC_STAT_MIN are 3812311Sseb * mainteined by the mac module itself. Everything else is 3822311Sseb * maintained by the driver. 3832311Sseb */ 3842311Sseb if (stat < MAC_STAT_MIN) { 3852311Sseb /* These stats are maintained by the mac module itself. */ 3862311Sseb switch (stat) { 3872311Sseb case MAC_STAT_LINK_STATE: 3882311Sseb return (mip->mi_linkstate); 3892311Sseb case MAC_STAT_LINK_UP: 3902311Sseb return (mip->mi_linkstate == LINK_STATE_UP); 3912311Sseb case MAC_STAT_PROMISC: 3922311Sseb return (mip->mi_devpromisc != 0); 3932311Sseb default: 3942311Sseb ASSERT(B_FALSE); 3952311Sseb } 3962311Sseb } 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate /* 3990Sstevel@tonic-gate * Call the driver to get the given statistic. 4000Sstevel@tonic-gate */ 4012311Sseb ret = mip->mi_getstat(mip->mi_driver, stat, &val); 4022311Sseb if (ret != 0) { 4032311Sseb /* 4042311Sseb * The driver doesn't support this statistic. Get the 4052311Sseb * statistic's default value. 4062311Sseb */ 4072311Sseb val = mac_stat_default(mip, stat); 4082311Sseb } 4092311Sseb return (val); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate int 4130Sstevel@tonic-gate mac_start(mac_handle_t mh) 4140Sstevel@tonic-gate { 4150Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4160Sstevel@tonic-gate int err; 4170Sstevel@tonic-gate 4182311Sseb ASSERT(mip->mi_start != NULL); 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * Check whether the device is already started. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate if (mip->mi_active++ != 0) { 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * It's already started so there's nothing more to do. 4280Sstevel@tonic-gate */ 4290Sstevel@tonic-gate err = 0; 4300Sstevel@tonic-gate goto done; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate /* 4340Sstevel@tonic-gate * Start the device. 4350Sstevel@tonic-gate */ 4362311Sseb if ((err = mip->mi_start(mip->mi_driver)) != 0) 4370Sstevel@tonic-gate --mip->mi_active; 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate done: 4400Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 4410Sstevel@tonic-gate return (err); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate void 4450Sstevel@tonic-gate mac_stop(mac_handle_t mh) 4460Sstevel@tonic-gate { 4470Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4480Sstevel@tonic-gate 4492311Sseb ASSERT(mip->mi_stop != NULL); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* 4540Sstevel@tonic-gate * Check whether the device is still needed. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate ASSERT(mip->mi_active != 0); 4570Sstevel@tonic-gate if (--mip->mi_active != 0) { 4580Sstevel@tonic-gate /* 4590Sstevel@tonic-gate * It's still needed so there's nothing more to do. 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate goto done; 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * Stop the device. 4660Sstevel@tonic-gate */ 4672311Sseb mip->mi_stop(mip->mi_driver); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate done: 4700Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate int 4740Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 4750Sstevel@tonic-gate { 4760Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4770Sstevel@tonic-gate mac_multicst_addr_t **pp; 4780Sstevel@tonic-gate mac_multicst_addr_t *p; 4790Sstevel@tonic-gate int err; 4800Sstevel@tonic-gate 4812311Sseb ASSERT(mip->mi_multicst != NULL); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate /* 4840Sstevel@tonic-gate * Verify the address. 4850Sstevel@tonic-gate */ 4862311Sseb if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 4872311Sseb mip->mi_pdata)) != 0) { 4882311Sseb return (err); 4892311Sseb } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * Check whether the given address is already enabled. 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 4950Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 4962311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 4972311Sseb 0) { 4980Sstevel@tonic-gate /* 4990Sstevel@tonic-gate * The address is already enabled so just bump the 5000Sstevel@tonic-gate * reference count. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate p->mma_ref++; 5030Sstevel@tonic-gate err = 0; 5040Sstevel@tonic-gate goto done; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * Allocate a new list entry. 5100Sstevel@tonic-gate */ 5110Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 5120Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 5130Sstevel@tonic-gate err = ENOMEM; 5140Sstevel@tonic-gate goto done; 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate /* 5180Sstevel@tonic-gate * Enable a new multicast address. 5190Sstevel@tonic-gate */ 5202311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 5210Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 5220Sstevel@tonic-gate goto done; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate /* 5260Sstevel@tonic-gate * Add the address to the list of enabled addresses. 5270Sstevel@tonic-gate */ 5282311Sseb bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 5290Sstevel@tonic-gate p->mma_ref++; 5300Sstevel@tonic-gate *pp = p; 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate done: 5330Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 5340Sstevel@tonic-gate return (err); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate int 5380Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 5390Sstevel@tonic-gate { 5400Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5410Sstevel@tonic-gate mac_multicst_addr_t **pp; 5420Sstevel@tonic-gate mac_multicst_addr_t *p; 5430Sstevel@tonic-gate int err; 5440Sstevel@tonic-gate 5452311Sseb ASSERT(mip->mi_multicst != NULL); 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * Find the entry in the list for the given address. 5490Sstevel@tonic-gate */ 5500Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 5510Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 5522311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 5532311Sseb 0) { 5540Sstevel@tonic-gate if (--p->mma_ref == 0) 5550Sstevel@tonic-gate break; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate /* 5580Sstevel@tonic-gate * There is still a reference to this address so 5590Sstevel@tonic-gate * there's nothing more to do. 5600Sstevel@tonic-gate */ 5610Sstevel@tonic-gate err = 0; 5620Sstevel@tonic-gate goto done; 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * We did not find an entry for the given address so it is not 5680Sstevel@tonic-gate * currently enabled. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate if (p == NULL) { 5710Sstevel@tonic-gate err = ENOENT; 5720Sstevel@tonic-gate goto done; 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate ASSERT(p->mma_ref == 0); 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* 5770Sstevel@tonic-gate * Disable the multicast address. 5780Sstevel@tonic-gate */ 5792311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 5800Sstevel@tonic-gate p->mma_ref++; 5810Sstevel@tonic-gate goto done; 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* 5850Sstevel@tonic-gate * Remove it from the list. 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate *pp = p->mma_nextp; 5880Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate done: 5910Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 5920Sstevel@tonic-gate return (err); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5952331Skrgopi /* 5962331Skrgopi * mac_unicst_verify: Verifies the passed address. It fails 5972331Skrgopi * if the passed address is a group address or has incorrect length. 5982331Skrgopi */ 5992331Skrgopi boolean_t 6002331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 6012331Skrgopi { 6022331Skrgopi mac_impl_t *mip = (mac_impl_t *)mh; 6032331Skrgopi 6042331Skrgopi /* 6052331Skrgopi * Verify the address. 6062331Skrgopi */ 6072331Skrgopi if ((len != mip->mi_type->mt_addr_length) || 6082331Skrgopi (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6092331Skrgopi mip->mi_pdata)) != 0) { 6102331Skrgopi return (B_FALSE); 6112331Skrgopi } else { 6122331Skrgopi return (B_TRUE); 6132331Skrgopi } 6142331Skrgopi } 6152331Skrgopi 6160Sstevel@tonic-gate int 6170Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 6180Sstevel@tonic-gate { 6190Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6200Sstevel@tonic-gate int err; 6210Sstevel@tonic-gate boolean_t notify = B_FALSE; 6220Sstevel@tonic-gate 6232311Sseb ASSERT(mip->mi_unicst != NULL); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate /* 6260Sstevel@tonic-gate * Verify the address. 6270Sstevel@tonic-gate */ 6282311Sseb if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6292311Sseb mip->mi_pdata)) != 0) { 6302311Sseb return (err); 6312311Sseb } 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate /* 6340Sstevel@tonic-gate * Program the new unicast address. 6350Sstevel@tonic-gate */ 6360Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* 6390Sstevel@tonic-gate * If address doesn't change, do nothing. 6400Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 6410Sstevel@tonic-gate * recursively. 6420Sstevel@tonic-gate */ 6432311Sseb if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 6440Sstevel@tonic-gate err = 0; 6450Sstevel@tonic-gate goto done; 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6482311Sseb if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 6490Sstevel@tonic-gate goto done; 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 6530Sstevel@tonic-gate */ 6542311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 6550Sstevel@tonic-gate notify = B_TRUE; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate done: 6580Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate if (notify) 6610Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate return (err); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate void 6670Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 6680Sstevel@tonic-gate { 6690Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6722311Sseb * Copy out the current unicast source address. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 6752311Sseb bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 6762311Sseb rw_exit(&(mip->mi_data_lock)); 6772311Sseb } 6782311Sseb 6792311Sseb void 6802311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr) 6812311Sseb { 6822311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 6832311Sseb 6842311Sseb /* 6852311Sseb * Copy out the current destination address. 6862311Sseb */ 6872311Sseb rw_enter(&(mip->mi_data_lock), RW_READER); 6882311Sseb bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 6890Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate int 6930Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 6940Sstevel@tonic-gate { 6950Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6960Sstevel@tonic-gate int err = 0; 6970Sstevel@tonic-gate 6982311Sseb ASSERT(mip->mi_setpromisc != NULL); 6990Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate /* 7020Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 7030Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 7040Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 7050Sstevel@tonic-gate */ 7060Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 7070Sstevel@tonic-gate if (on) { 7080Sstevel@tonic-gate /* 7090Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 7100Sstevel@tonic-gate */ 7110Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 7122311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 7132311Sseb if (err != 0) { 7140Sstevel@tonic-gate mip->mi_devpromisc--; 7150Sstevel@tonic-gate goto done; 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 7220Sstevel@tonic-gate */ 7230Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 7240Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7250Sstevel@tonic-gate } else { 7260Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 7270Sstevel@tonic-gate err = EPROTO; 7280Sstevel@tonic-gate goto done; 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate /* 7320Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 7330Sstevel@tonic-gate * enabling. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 7362311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 7372311Sseb if (err != 0) { 7380Sstevel@tonic-gate mip->mi_devpromisc++; 7390Sstevel@tonic-gate goto done; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 7460Sstevel@tonic-gate * enabling. 7470Sstevel@tonic-gate */ 7480Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 7490Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate done: 7530Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7540Sstevel@tonic-gate return (err); 7550Sstevel@tonic-gate } 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate boolean_t 7580Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 7590Sstevel@tonic-gate { 7600Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate /* 7650Sstevel@tonic-gate * Return the current promiscuity. 7660Sstevel@tonic-gate */ 7670Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 7680Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 7690Sstevel@tonic-gate else 7700Sstevel@tonic-gate return (mip->mi_promisc != 0); 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate void 7740Sstevel@tonic-gate mac_resources(mac_handle_t mh) 7750Sstevel@tonic-gate { 7760Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate /* 7792311Sseb * If the driver supports resource registration, call the driver to 7802311Sseb * ask it to register its resources. 7810Sstevel@tonic-gate */ 7822311Sseb if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 7832311Sseb mip->mi_resources(mip->mi_driver); 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate void 7870Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 7880Sstevel@tonic-gate { 7890Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate /* 7922311Sseb * Call the driver to handle the ioctl. The driver may not support 7932311Sseb * any ioctls, in which case we reply with a NAK on its behalf. 7940Sstevel@tonic-gate */ 7952311Sseb if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 7962311Sseb mip->mi_ioctl(mip->mi_driver, wq, bp); 7972311Sseb else 7982311Sseb miocnak(wq, bp, 0, EINVAL); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 80156Smeem const mac_txinfo_t * 80256Smeem mac_tx_get(mac_handle_t mh) 8030Sstevel@tonic-gate { 8040Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 80556Smeem mac_txinfo_t *mtp; 80656Smeem 80756Smeem /* 80856Smeem * Grab the lock to prevent us from racing with MAC_PROMISC being 80956Smeem * changed. This is sufficient since MAC clients are careful to always 81056Smeem * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 81156Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 81256Smeem */ 81356Smeem rw_enter(&mip->mi_txloop_lock, RW_READER); 8140Sstevel@tonic-gate 81556Smeem if (mac_promisc_get(mh, MAC_PROMISC)) { 81656Smeem ASSERT(mip->mi_mtfp != NULL); 81756Smeem mtp = &mip->mi_txloopinfo; 81856Smeem } else { 81956Smeem /* 82056Smeem * Note that we cannot ASSERT() that mip->mi_mtfp is NULL, 82156Smeem * because to satisfy the above ASSERT(), we have to disable 82256Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 82356Smeem */ 82456Smeem mtp = &mip->mi_txinfo; 82556Smeem } 82656Smeem 82756Smeem rw_exit(&mip->mi_txloop_lock); 82856Smeem return (mtp); 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate link_state_t 8320Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 8330Sstevel@tonic-gate { 8342311Sseb return (((mac_impl_t *)mh)->mi_linkstate); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate mac_notify_handle_t 8380Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 8390Sstevel@tonic-gate { 8400Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8410Sstevel@tonic-gate mac_notify_fn_t *mnfp; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 8440Sstevel@tonic-gate mnfp->mnf_fn = notify; 8450Sstevel@tonic-gate mnfp->mnf_arg = arg; 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 8490Sstevel@tonic-gate */ 8501852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8510Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 8520Sstevel@tonic-gate mip->mi_mnfp = mnfp; 8531852Syz147064 rw_exit(&mip->mi_notify_lock); 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate void 8590Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 8600Sstevel@tonic-gate { 8610Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8620Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 8630Sstevel@tonic-gate mac_notify_fn_t **pp; 8640Sstevel@tonic-gate mac_notify_fn_t *p; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate /* 8670Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 8680Sstevel@tonic-gate */ 8691852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8700Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 8710Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 8720Sstevel@tonic-gate if (p == mnfp) 8730Sstevel@tonic-gate break; 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate ASSERT(p != NULL); 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate /* 8780Sstevel@tonic-gate * Remove it from the list. 8790Sstevel@tonic-gate */ 8800Sstevel@tonic-gate *pp = p->mnf_nextp; 8811852Syz147064 rw_exit(&mip->mi_notify_lock); 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate /* 8840Sstevel@tonic-gate * Free it. 8850Sstevel@tonic-gate */ 8860Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate void 8900Sstevel@tonic-gate mac_notify(mac_handle_t mh) 8910Sstevel@tonic-gate { 8920Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8930Sstevel@tonic-gate mac_notify_type_t type; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 8960Sstevel@tonic-gate i_mac_notify(mip, type); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate mac_rx_handle_t 9000Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 9010Sstevel@tonic-gate { 9020Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9030Sstevel@tonic-gate mac_rx_fn_t *mrfp; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 9060Sstevel@tonic-gate mrfp->mrf_fn = rx; 9070Sstevel@tonic-gate mrfp->mrf_arg = arg; 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9130Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 9140Sstevel@tonic-gate mip->mi_mrfp = mrfp; 9150Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate /* 9210Sstevel@tonic-gate * Unregister a receive function for this mac. This removes the function 9220Sstevel@tonic-gate * from the list of receive functions for this mac. 9230Sstevel@tonic-gate */ 9240Sstevel@tonic-gate void 9250Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 9260Sstevel@tonic-gate { 9270Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9280Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 9290Sstevel@tonic-gate mac_rx_fn_t **pp; 9300Sstevel@tonic-gate mac_rx_fn_t *p; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* 9330Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 9340Sstevel@tonic-gate */ 9350Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9360Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 9370Sstevel@tonic-gate if (p == mrfp) 9380Sstevel@tonic-gate break; 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate ASSERT(p != NULL); 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /* Remove it from the list. */ 9430Sstevel@tonic-gate *pp = p->mrf_nextp; 9440Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 9450Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate mac_txloop_handle_t 9490Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 9500Sstevel@tonic-gate { 9510Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9520Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 9550Sstevel@tonic-gate mtfp->mtf_fn = tx; 9560Sstevel@tonic-gate mtfp->mtf_arg = arg; 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 9620Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 9630Sstevel@tonic-gate mip->mi_mtfp = mtfp; 9640Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate 9690Sstevel@tonic-gate /* 9700Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 9710Sstevel@tonic-gate * from the list of transmit functions for this mac. 9720Sstevel@tonic-gate */ 9730Sstevel@tonic-gate void 9740Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 9750Sstevel@tonic-gate { 9760Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9770Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 9780Sstevel@tonic-gate mac_txloop_fn_t **pp; 9790Sstevel@tonic-gate mac_txloop_fn_t *p; 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate /* 9820Sstevel@tonic-gate * Search the 'tx' callback list for the function. 9830Sstevel@tonic-gate */ 9840Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 9850Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 9860Sstevel@tonic-gate if (p == mtfp) 9870Sstevel@tonic-gate break; 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate ASSERT(p != NULL); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate /* Remove it from the list. */ 9920Sstevel@tonic-gate *pp = p->mtf_nextp; 9930Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 9940Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate 9970Sstevel@tonic-gate void 9980Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 9990Sstevel@tonic-gate { 10000Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate /* 10030Sstevel@tonic-gate * Update the 'resource_add' callbacks. 10040Sstevel@tonic-gate */ 10050Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 10060Sstevel@tonic-gate mip->mi_resource_add = add; 10070Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 10080Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate /* 10120Sstevel@tonic-gate * Driver support functions. 10130Sstevel@tonic-gate */ 10140Sstevel@tonic-gate 10152311Sseb mac_register_t * 10162311Sseb mac_alloc(uint_t mac_version) 10170Sstevel@tonic-gate { 10182311Sseb mac_register_t *mregp; 10192311Sseb 10202311Sseb /* 10212311Sseb * Make sure there isn't a version mismatch between the driver and 10222311Sseb * the framework. In the future, if multiple versions are 10232311Sseb * supported, this check could become more sophisticated. 10242311Sseb */ 10252311Sseb if (mac_version != MAC_VERSION) 10262311Sseb return (NULL); 10272311Sseb 10282311Sseb mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 10292311Sseb mregp->m_version = mac_version; 10302311Sseb return (mregp); 10312311Sseb } 10322311Sseb 10332311Sseb void 10342311Sseb mac_free(mac_register_t *mregp) 10352311Sseb { 10362311Sseb kmem_free(mregp, sizeof (mac_register_t)); 10372311Sseb } 10382311Sseb 10392311Sseb /* 10402311Sseb * mac_register() is how drivers register new MACs with the GLDv3 10412311Sseb * framework. The mregp argument is allocated by drivers using the 10422311Sseb * mac_alloc() function, and can be freed using mac_free() immediately upon 10432311Sseb * return from mac_register(). Upon success (0 return value), the mhp 10442311Sseb * opaque pointer becomes the driver's handle to its MAC interface, and is 10452311Sseb * the argument to all other mac module entry points. 10462311Sseb */ 10472311Sseb int 10482311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 10492311Sseb { 10502311Sseb mac_impl_t *mip; 10512311Sseb mactype_t *mtype; 10522311Sseb int err; 10530Sstevel@tonic-gate struct devnames *dnp; 10542311Sseb minor_t minor; 10552311Sseb mod_hash_val_t val; 10562311Sseb boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 10572311Sseb 10582311Sseb /* Find the required MAC-Type plugin. */ 10592311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 10602311Sseb return (EINVAL); 10612311Sseb 10622311Sseb /* Create a mac_impl_t to represent this MAC. */ 10632311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 10642311Sseb 10652311Sseb /* 10662311Sseb * The mac is not ready for open yet. 10672311Sseb */ 10682311Sseb mip->mi_disabled = B_TRUE; 10692311Sseb 10702311Sseb mip->mi_drvname = ddi_driver_name(mregp->m_dip); 10712311Sseb /* 10722311Sseb * Some drivers such as aggr need to register multiple MACs. Such 10732311Sseb * drivers must supply a non-zero "instance" argument so that each 10742311Sseb * MAC can be assigned a unique MAC name and can have unique 10752311Sseb * kstats. 10762311Sseb */ 10772311Sseb mip->mi_instance = ((mregp->m_instance == 0) ? 10782311Sseb ddi_get_instance(mregp->m_dip) : mregp->m_instance); 10792311Sseb 10802311Sseb /* Construct the MAC name as <drvname><instance> */ 10812311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 10822311Sseb mip->mi_drvname, mip->mi_instance); 10832311Sseb 10842311Sseb rw_enter(&i_mac_impl_lock, RW_WRITER); 10852311Sseb if (mod_hash_insert(i_mac_impl_hash, 10862311Sseb (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 10872311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 10882311Sseb rw_exit(&i_mac_impl_lock); 10892311Sseb return (EEXIST); 10902311Sseb } 1091*3288Sseb atomic_inc_32(&i_mac_impl_count); 10922311Sseb 10932311Sseb mip->mi_driver = mregp->m_driver; 10942311Sseb 10952311Sseb mip->mi_type = mtype; 10962311Sseb mip->mi_info.mi_media = mtype->mt_type; 10973147Sxc151355 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 10982311Sseb mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 10992311Sseb if (mregp->m_max_sdu <= mregp->m_min_sdu) { 11002311Sseb err = EINVAL; 11012311Sseb goto fail; 11022311Sseb } 11032311Sseb mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 11042311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 11052311Sseb /* 11062311Sseb * If the media supports a broadcast address, cache a pointer to it 11072311Sseb * in the mac_info_t so that upper layers can use it. 11082311Sseb */ 11092311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1110269Sericheng 11112311Sseb /* 11122311Sseb * Copy the unicast source address into the mac_info_t, but only if 11132311Sseb * the MAC-Type defines a non-zero address length. We need to 11142311Sseb * handle MAC-Types that have an address length of 0 11152311Sseb * (point-to-point protocol MACs for example). 11162311Sseb */ 11172311Sseb if (mip->mi_type->mt_addr_length > 0) { 11182311Sseb if (mregp->m_src_addr == NULL) { 11192311Sseb err = EINVAL; 11202311Sseb goto fail; 11212311Sseb } 11222311Sseb mip->mi_info.mi_unicst_addr = 11232311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 11242311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 11252311Sseb mip->mi_type->mt_addr_length); 11262311Sseb 11272311Sseb /* 11282311Sseb * Copy the fixed 'factory' MAC address from the immutable 11292311Sseb * info. This is taken to be the MAC address currently in 11302311Sseb * use. 11312311Sseb */ 11322311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 11332311Sseb mip->mi_type->mt_addr_length); 11342311Sseb /* Copy the destination address if one is provided. */ 11352311Sseb if (mregp->m_dst_addr != NULL) { 11362311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 11372311Sseb mip->mi_type->mt_addr_length); 11382311Sseb } 11392311Sseb } else if (mregp->m_src_addr != NULL) { 11402311Sseb err = EINVAL; 11412311Sseb goto fail; 1142269Sericheng } 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate /* 11452311Sseb * The format of the m_pdata is specific to the plugin. It is 11462311Sseb * passed in as an argument to all of the plugin callbacks. The 11472311Sseb * driver can update this information by calling 11482311Sseb * mac_pdata_update(). 11490Sstevel@tonic-gate */ 11502311Sseb if (mregp->m_pdata != NULL) { 11512311Sseb /* 11522311Sseb * Verify that the plugin supports MAC plugin data and that 11532311Sseb * the supplied data is valid. 11542311Sseb */ 11552311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) { 11562311Sseb err = EINVAL; 11572311Sseb goto fail; 11582311Sseb } 11592311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 11602311Sseb mregp->m_pdata_size)) { 11612311Sseb err = EINVAL; 11622311Sseb goto fail; 11632311Sseb } 11642311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 11652311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 11662311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 11672311Sseb } 11682311Sseb 11692311Sseb /* 11702311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 11712311Sseb * check to make sure all mandatory callbacks are set. 11722311Sseb */ 11732311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 11742311Sseb mregp->m_callbacks->mc_start == NULL || 11752311Sseb mregp->m_callbacks->mc_stop == NULL || 11762311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 11772311Sseb mregp->m_callbacks->mc_multicst == NULL || 11782311Sseb mregp->m_callbacks->mc_unicst == NULL || 11792311Sseb mregp->m_callbacks->mc_tx == NULL) { 11802311Sseb err = EINVAL; 11812311Sseb goto fail; 11822311Sseb } 11832311Sseb mip->mi_callbacks = mregp->m_callbacks; 11842311Sseb 11852311Sseb mip->mi_dip = mregp->m_dip; 11862311Sseb 11872311Sseb /* 11882311Sseb * Set up the two possible transmit routines. 11892311Sseb */ 11902311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 11912311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 11922311Sseb mip->mi_txloopinfo.mt_fn = mac_txloop; 11932311Sseb mip->mi_txloopinfo.mt_arg = mip; 11942311Sseb 11952311Sseb /* 11962311Sseb * Initialize the kstats for this device. 11972311Sseb */ 11982311Sseb mac_stat_create(mip); 11990Sstevel@tonic-gate 1200269Sericheng err = EEXIST; 12012311Sseb /* Create a style-2 DLPI device */ 12022311Sseb if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 12032311Sseb S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 12042311Sseb goto fail; 12052311Sseb style2_created = B_TRUE; 1206269Sericheng 12072311Sseb /* Create a style-1 DLPI device */ 12082311Sseb minor = (minor_t)mip->mi_instance + 1; 12092311Sseb if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 12102311Sseb DDI_NT_NET, 0) != DDI_SUCCESS) 12112311Sseb goto fail; 12122311Sseb style1_created = B_TRUE; 12130Sstevel@tonic-gate 12142311Sseb /* 12152311Sseb * Create a link for this MAC. The link name will be the same as 12162311Sseb * the MAC name. 12172311Sseb */ 12182311Sseb err = dls_create(mip->mi_name, mip->mi_name, 12192311Sseb ddi_get_instance(mip->mi_dip)); 12202311Sseb if (err != 0) 12212311Sseb goto fail; 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 12242311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 12250Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 12260Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 12270Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 12280Sstevel@tonic-gate 12291852Syz147064 /* 12301852Syz147064 * Mark the MAC to be ready for open. 12311852Syz147064 */ 12322311Sseb mip->mi_disabled = B_FALSE; 12332311Sseb 12342311Sseb cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 12351852Syz147064 rw_exit(&i_mac_impl_lock); 12362311Sseb *mhp = (mac_handle_t)mip; 1237269Sericheng return (0); 12380Sstevel@tonic-gate 12392311Sseb fail: 12402311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 12412311Sseb &val); 12422311Sseb ASSERT(mip == (mac_impl_t *)val); 1243*3288Sseb atomic_dec_32(&i_mac_impl_count); 12442311Sseb 12452311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 12462311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 12472311Sseb mip->mi_type->mt_addr_length); 12482311Sseb mip->mi_info.mi_unicst_addr = NULL; 12492311Sseb } 12502311Sseb if (style1_created) 12512311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 12522311Sseb if (style2_created) 12532311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 12542311Sseb 12552311Sseb mac_stat_destroy(mip); 12562311Sseb 12572311Sseb if (mip->mi_type != NULL) { 1258*3288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 12592311Sseb mip->mi_type = NULL; 12602311Sseb } 12612311Sseb 12622311Sseb if (mip->mi_pdata != NULL) { 12632311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 12642311Sseb mip->mi_pdata = NULL; 12652311Sseb mip->mi_pdata_size = 0; 12662311Sseb } 12672311Sseb 12682311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 12692311Sseb rw_exit(&i_mac_impl_lock); 1270269Sericheng return (err); 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate int 12742311Sseb mac_unregister(mac_handle_t mh) 12750Sstevel@tonic-gate { 12762311Sseb int err; 12772311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 12782311Sseb mod_hash_val_t val; 12792311Sseb mac_multicst_addr_t *p, *nextp; 1280269Sericheng 12810Sstevel@tonic-gate /* 12820Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 12831852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 12842311Sseb * created while we're destroying this mac. 12850Sstevel@tonic-gate */ 1286269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 12870Sstevel@tonic-gate if (mip->mi_ref > 0) { 1288269Sericheng rw_exit(&i_mac_impl_lock); 12890Sstevel@tonic-gate return (EBUSY); 12900Sstevel@tonic-gate } 12911852Syz147064 mip->mi_disabled = B_TRUE; 1292269Sericheng rw_exit(&i_mac_impl_lock); 12930Sstevel@tonic-gate 12941852Syz147064 /* 12951852Syz147064 * Wait for all taskqs which process the mac notifications to finish. 12961852Syz147064 */ 12971852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 12981852Syz147064 while (mip->mi_notify_ref != 0) 12991852Syz147064 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 13001852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 13011852Syz147064 13022311Sseb if ((err = dls_destroy(mip->mi_name)) != 0) { 1303269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 13041852Syz147064 mip->mi_disabled = B_FALSE; 1305269Sericheng rw_exit(&i_mac_impl_lock); 1306269Sericheng return (err); 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate /* 13102311Sseb * Remove both style 1 and style 2 minor nodes 13110Sstevel@tonic-gate */ 13122311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 13132311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 13142311Sseb 13152311Sseb ASSERT(!mip->mi_activelink); 13162311Sseb 13172311Sseb mac_stat_destroy(mip); 13182311Sseb 13192311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 13202311Sseb &val); 13212311Sseb ASSERT(mip == (mac_impl_t *)val); 13222311Sseb 13232311Sseb ASSERT(i_mac_impl_count > 0); 1324*3288Sseb atomic_dec_32(&i_mac_impl_count); 13252311Sseb 13262311Sseb if (mip->mi_pdata != NULL) 13272311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 13282311Sseb mip->mi_pdata = NULL; 13292311Sseb mip->mi_pdata_size = 0; 13300Sstevel@tonic-gate 13310Sstevel@tonic-gate /* 13322311Sseb * Free the list of multicast addresses. 13330Sstevel@tonic-gate */ 13342311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 13352311Sseb nextp = p->mma_nextp; 13362311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 13372311Sseb } 13382311Sseb mip->mi_mmap = NULL; 13390Sstevel@tonic-gate 13402311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 13412311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 13422311Sseb mip->mi_info.mi_unicst_addr = NULL; 13432311Sseb 1344*3288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 13452311Sseb mip->mi_type = NULL; 13462311Sseb 13472311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 13482311Sseb 13492311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 13502311Sseb 13510Sstevel@tonic-gate return (0); 13520Sstevel@tonic-gate } 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate void 13552311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 13560Sstevel@tonic-gate { 13572311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13580Sstevel@tonic-gate mac_rx_fn_t *mrfp; 13590Sstevel@tonic-gate 13600Sstevel@tonic-gate /* 13610Sstevel@tonic-gate * Call all registered receive functions. 13620Sstevel@tonic-gate */ 13630Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 13640Sstevel@tonic-gate mrfp = mip->mi_mrfp; 13650Sstevel@tonic-gate if (mrfp == NULL) { 13660Sstevel@tonic-gate /* There are no registered receive functions. */ 13670Sstevel@tonic-gate freemsgchain(bp); 13680Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13690Sstevel@tonic-gate return; 13700Sstevel@tonic-gate } 13710Sstevel@tonic-gate do { 13720Sstevel@tonic-gate mblk_t *recv_bp; 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate if (mrfp->mrf_nextp != NULL) { 13750Sstevel@tonic-gate /* XXX Do we bump a counter if copymsgchain() fails? */ 13760Sstevel@tonic-gate recv_bp = copymsgchain(bp); 13770Sstevel@tonic-gate } else { 13780Sstevel@tonic-gate recv_bp = bp; 13790Sstevel@tonic-gate } 13800Sstevel@tonic-gate if (recv_bp != NULL) 13810Sstevel@tonic-gate mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 13820Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 13830Sstevel@tonic-gate } while (mrfp != NULL); 13840Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 13850Sstevel@tonic-gate } 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 13890Sstevel@tonic-gate */ 13900Sstevel@tonic-gate mblk_t * 13910Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 13920Sstevel@tonic-gate { 13930Sstevel@tonic-gate mac_impl_t *mip = arg; 13940Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 13950Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate while (bp != NULL) { 13980Sstevel@tonic-gate next_bp = bp->b_next; 13990Sstevel@tonic-gate bp->b_next = NULL; 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 14020Sstevel@tonic-gate goto noresources; 14030Sstevel@tonic-gate 14042311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 14050Sstevel@tonic-gate ASSERT(resid_bp == bp); 14060Sstevel@tonic-gate freemsg(loop_bp); 14070Sstevel@tonic-gate goto noresources; 14080Sstevel@tonic-gate } 14090Sstevel@tonic-gate 14100Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 14110Sstevel@tonic-gate mtfp = mip->mi_mtfp; 141256Smeem while (mtfp != NULL && loop_bp != NULL) { 14130Sstevel@tonic-gate bp = loop_bp; 141456Smeem 141556Smeem /* XXX counter bump if copymsg() fails? */ 141656Smeem if (mtfp->mtf_nextp != NULL) 14170Sstevel@tonic-gate loop_bp = copymsg(bp); 141856Smeem else 141956Smeem loop_bp = NULL; 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 142256Smeem mtfp = mtfp->mtf_nextp; 14230Sstevel@tonic-gate } 142456Smeem rw_exit(&mip->mi_txloop_lock); 14250Sstevel@tonic-gate 142656Smeem /* 142756Smeem * It's possible we've raced with the disabling of promiscuous 142856Smeem * mode, in which case we can discard our copy. 142956Smeem */ 143056Smeem if (loop_bp != NULL) 143156Smeem freemsg(loop_bp); 143256Smeem 14330Sstevel@tonic-gate bp = next_bp; 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate 14360Sstevel@tonic-gate return (NULL); 14370Sstevel@tonic-gate 14380Sstevel@tonic-gate noresources: 14390Sstevel@tonic-gate bp->b_next = next_bp; 14400Sstevel@tonic-gate return (bp); 14410Sstevel@tonic-gate } 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate void 14442311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 14450Sstevel@tonic-gate { 14462311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14470Sstevel@tonic-gate 14480Sstevel@tonic-gate /* 14490Sstevel@tonic-gate * Save the link state. 14500Sstevel@tonic-gate */ 14512311Sseb mip->mi_linkstate = link; 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate /* 14540Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 14550Sstevel@tonic-gate */ 14560Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 14570Sstevel@tonic-gate } 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate void 14602311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 14610Sstevel@tonic-gate { 14622311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14630Sstevel@tonic-gate 14642311Sseb if (mip->mi_type->mt_addr_length == 0) 14652311Sseb return; 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate /* 14680Sstevel@tonic-gate * Save the address. 14690Sstevel@tonic-gate */ 14702311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 14710Sstevel@tonic-gate 14720Sstevel@tonic-gate /* 14730Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 14740Sstevel@tonic-gate */ 14750Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 14760Sstevel@tonic-gate } 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate void 14792311Sseb mac_tx_update(mac_handle_t mh) 14800Sstevel@tonic-gate { 14810Sstevel@tonic-gate /* 14820Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 14830Sstevel@tonic-gate */ 14842311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 14850Sstevel@tonic-gate } 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate void 14882311Sseb mac_resource_update(mac_handle_t mh) 14890Sstevel@tonic-gate { 14900Sstevel@tonic-gate /* 14910Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 14920Sstevel@tonic-gate */ 14932311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 14940Sstevel@tonic-gate } 14950Sstevel@tonic-gate 14960Sstevel@tonic-gate mac_resource_handle_t 14972311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 14980Sstevel@tonic-gate { 14992311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15000Sstevel@tonic-gate mac_resource_handle_t mrh; 15010Sstevel@tonic-gate mac_resource_add_t add; 15020Sstevel@tonic-gate void *arg; 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 15050Sstevel@tonic-gate add = mip->mi_resource_add; 15060Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 15070Sstevel@tonic-gate 15081184Skrgopi if (add != NULL) 15091184Skrgopi mrh = add(arg, mrp); 15101184Skrgopi else 15111184Skrgopi mrh = NULL; 15120Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 15130Sstevel@tonic-gate 15140Sstevel@tonic-gate return (mrh); 15150Sstevel@tonic-gate } 15160Sstevel@tonic-gate 15172311Sseb int 15182311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 15192311Sseb { 15202311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15212311Sseb 15222311Sseb /* 15232311Sseb * Verify that the plugin supports MAC plugin data and that the 15242311Sseb * supplied data is valid. 15252311Sseb */ 15262311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 15272311Sseb return (EINVAL); 15282311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 15292311Sseb return (EINVAL); 15302311Sseb 15312311Sseb if (mip->mi_pdata != NULL) 15322311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 15332311Sseb 15342311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 15352311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 15362311Sseb mip->mi_pdata_size = dsize; 15372311Sseb 15382311Sseb /* 15392311Sseb * Since the MAC plugin data is used to construct MAC headers that 15402311Sseb * were cached in fast-path headers, we need to flush fast-path 15412311Sseb * information for links associated with this mac. 15422311Sseb */ 15432311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 15442311Sseb return (0); 15452311Sseb } 15462311Sseb 15470Sstevel@tonic-gate void 15482311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 15490Sstevel@tonic-gate boolean_t add) 15500Sstevel@tonic-gate { 15512311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15520Sstevel@tonic-gate mac_multicst_addr_t *p; 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate /* 15550Sstevel@tonic-gate * If no specific refresh function was given then default to the 15560Sstevel@tonic-gate * driver's m_multicst entry point. 15570Sstevel@tonic-gate */ 15580Sstevel@tonic-gate if (refresh == NULL) { 15592311Sseb refresh = mip->mi_multicst; 15602311Sseb arg = mip->mi_driver; 15610Sstevel@tonic-gate } 15620Sstevel@tonic-gate ASSERT(refresh != NULL); 15630Sstevel@tonic-gate 15640Sstevel@tonic-gate /* 15650Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 15660Sstevel@tonic-gate * each address. 15670Sstevel@tonic-gate */ 15680Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 15690Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 15700Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 15710Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate void 15752311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 15760Sstevel@tonic-gate { 15772311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15780Sstevel@tonic-gate /* 15790Sstevel@tonic-gate * If no specific refresh function was given then default to the 15802311Sseb * driver's mi_unicst entry point. 15810Sstevel@tonic-gate */ 15820Sstevel@tonic-gate if (refresh == NULL) { 15832311Sseb refresh = mip->mi_unicst; 15842311Sseb arg = mip->mi_driver; 15850Sstevel@tonic-gate } 15860Sstevel@tonic-gate ASSERT(refresh != NULL); 15870Sstevel@tonic-gate 15880Sstevel@tonic-gate /* 15890Sstevel@tonic-gate * Call the refresh function with the current unicast address. 15900Sstevel@tonic-gate */ 15910Sstevel@tonic-gate refresh(arg, mip->mi_addr); 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate void 15952311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 15960Sstevel@tonic-gate { 15972311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15980Sstevel@tonic-gate 15990Sstevel@tonic-gate /* 16000Sstevel@tonic-gate * If no specific refresh function was given then default to the 16010Sstevel@tonic-gate * driver's m_promisc entry point. 16020Sstevel@tonic-gate */ 16030Sstevel@tonic-gate if (refresh == NULL) { 16042311Sseb refresh = mip->mi_setpromisc; 16052311Sseb arg = mip->mi_driver; 16060Sstevel@tonic-gate } 16070Sstevel@tonic-gate ASSERT(refresh != NULL); 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate /* 16100Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 16110Sstevel@tonic-gate */ 16120Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 16130Sstevel@tonic-gate } 16140Sstevel@tonic-gate 16150Sstevel@tonic-gate boolean_t 16160Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 16170Sstevel@tonic-gate { 16180Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16210Sstevel@tonic-gate if (mip->mi_activelink) { 16220Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16230Sstevel@tonic-gate return (B_FALSE); 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 16260Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16270Sstevel@tonic-gate return (B_TRUE); 16280Sstevel@tonic-gate } 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate void 16310Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 16320Sstevel@tonic-gate { 16330Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16340Sstevel@tonic-gate 16350Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16360Sstevel@tonic-gate ASSERT(mip->mi_activelink); 16370Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 16380Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16390Sstevel@tonic-gate } 1640269Sericheng 1641269Sericheng /* 1642269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1643269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1644269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1645269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1646269Sericheng * cannot disappear while we are accessing it. 1647269Sericheng */ 1648269Sericheng typedef struct i_mac_info_state_s { 1649269Sericheng const char *mi_name; 1650269Sericheng mac_info_t *mi_infop; 1651269Sericheng } i_mac_info_state_t; 1652269Sericheng 1653269Sericheng /*ARGSUSED*/ 1654269Sericheng static uint_t 1655269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1656269Sericheng { 1657269Sericheng i_mac_info_state_t *statep = arg; 1658269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 1659269Sericheng 16601852Syz147064 if (mip->mi_disabled) 1661269Sericheng return (MH_WALK_CONTINUE); 1662269Sericheng 1663269Sericheng if (strcmp(statep->mi_name, 16642311Sseb ddi_driver_name(mip->mi_dip)) != 0) 1665269Sericheng return (MH_WALK_CONTINUE); 1666269Sericheng 16672311Sseb statep->mi_infop = &mip->mi_info; 1668269Sericheng return (MH_WALK_TERMINATE); 1669269Sericheng } 1670269Sericheng 1671269Sericheng boolean_t 1672269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 1673269Sericheng { 1674269Sericheng i_mac_info_state_t state; 1675269Sericheng 1676269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 1677269Sericheng state.mi_name = name; 1678269Sericheng state.mi_infop = NULL; 1679269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1680269Sericheng if (state.mi_infop == NULL) { 1681269Sericheng rw_exit(&i_mac_impl_lock); 1682269Sericheng return (B_FALSE); 1683269Sericheng } 1684269Sericheng *minfop = *state.mi_infop; 1685269Sericheng rw_exit(&i_mac_impl_lock); 1686269Sericheng return (B_TRUE); 1687269Sericheng } 1688269Sericheng 16892311Sseb boolean_t 16902311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 16912311Sseb { 16922311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16932311Sseb 16942311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 16952311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 16962311Sseb else 16972311Sseb return (B_FALSE); 16982311Sseb } 16992311Sseb 17002311Sseb boolean_t 17012311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 17022311Sseb { 17032311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17042311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 17052311Sseb mip->mi_pdata)); 17062311Sseb } 17072311Sseb 17082311Sseb mblk_t * 17092311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 17102311Sseb size_t extra_len) 17112311Sseb { 17122311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17132311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 17142311Sseb mip->mi_pdata, payload, extra_len)); 17152311Sseb } 17162311Sseb 17172311Sseb int 17182311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 17192311Sseb { 17202311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17212311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 17222311Sseb mhip)); 17232311Sseb } 17242311Sseb 17252311Sseb mblk_t * 17262311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 17272311Sseb { 17282311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17292311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 17302311Sseb if (DB_REF(mp) > 1) { 17312311Sseb mblk_t *newmp = copymsg(mp); 17322760Sdg199075 if (newmp == NULL) 17332760Sdg199075 return (NULL); 17342311Sseb freemsg(mp); 17352311Sseb mp = newmp; 17362311Sseb } 17372311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 17382311Sseb mip->mi_pdata)); 17392311Sseb } 17402311Sseb return (mp); 17412311Sseb } 17422311Sseb 17432311Sseb mblk_t * 17442311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 17452311Sseb { 17462311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17472311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 17482311Sseb if (DB_REF(mp) > 1) { 17492311Sseb mblk_t *newmp = copymsg(mp); 17502760Sdg199075 if (newmp == NULL) 17512760Sdg199075 return (NULL); 17522311Sseb freemsg(mp); 17532311Sseb mp = newmp; 17542311Sseb } 17552311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 17562311Sseb mip->mi_pdata)); 17572311Sseb } 17582311Sseb return (mp); 17592311Sseb } 17602311Sseb 1761269Sericheng void 1762269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 1763269Sericheng { 1764269Sericheng dld_init_ops(ops, name); 1765269Sericheng } 1766269Sericheng 1767269Sericheng void 1768269Sericheng mac_fini_ops(struct dev_ops *ops) 1769269Sericheng { 1770269Sericheng dld_fini_ops(ops); 1771269Sericheng } 17722311Sseb 17732311Sseb /* 17742311Sseb * MAC Type Plugin functions. 17752311Sseb */ 17762311Sseb 17772311Sseb mactype_register_t * 17782311Sseb mactype_alloc(uint_t mactype_version) 17792311Sseb { 17802311Sseb mactype_register_t *mtrp; 17812311Sseb 17822311Sseb /* 17832311Sseb * Make sure there isn't a version mismatch between the plugin and 17842311Sseb * the framework. In the future, if multiple versions are 17852311Sseb * supported, this check could become more sophisticated. 17862311Sseb */ 17872311Sseb if (mactype_version != MACTYPE_VERSION) 17882311Sseb return (NULL); 17892311Sseb 17902311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 17912311Sseb mtrp->mtr_version = mactype_version; 17922311Sseb return (mtrp); 17932311Sseb } 17942311Sseb 17952311Sseb void 17962311Sseb mactype_free(mactype_register_t *mtrp) 17972311Sseb { 17982311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 17992311Sseb } 18002311Sseb 18012311Sseb int 18022311Sseb mactype_register(mactype_register_t *mtrp) 18032311Sseb { 18042311Sseb mactype_t *mtp; 18052311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 18062311Sseb 18072311Sseb /* Do some sanity checking before we register this MAC type. */ 18082311Sseb if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 18092311Sseb return (EINVAL); 18102311Sseb 18112311Sseb /* 18122311Sseb * Verify that all mandatory callbacks are set in the ops 18132311Sseb * vector. 18142311Sseb */ 18152311Sseb if (ops->mtops_unicst_verify == NULL || 18162311Sseb ops->mtops_multicst_verify == NULL || 18172311Sseb ops->mtops_sap_verify == NULL || 18182311Sseb ops->mtops_header == NULL || 18192311Sseb ops->mtops_header_info == NULL) { 18202311Sseb return (EINVAL); 18212311Sseb } 18222311Sseb 18232311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 18242311Sseb mtp->mt_ident = mtrp->mtr_ident; 18252311Sseb mtp->mt_ops = *ops; 18262311Sseb mtp->mt_type = mtrp->mtr_mactype; 18273147Sxc151355 mtp->mt_nativetype = mtrp->mtr_nativetype; 18282311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 18292311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 18302311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 18312311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 18322311Sseb mtrp->mtr_addrlen); 18332311Sseb } 18342311Sseb 18352311Sseb mtp->mt_stats = mtrp->mtr_stats; 18362311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 18372311Sseb 18382311Sseb if (mod_hash_insert(i_mactype_hash, 18392311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 18402311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18412311Sseb kmem_free(mtp, sizeof (*mtp)); 18422311Sseb return (EEXIST); 18432311Sseb } 18442311Sseb return (0); 18452311Sseb } 18462311Sseb 18472311Sseb int 18482311Sseb mactype_unregister(const char *ident) 18492311Sseb { 18502311Sseb mactype_t *mtp; 18512311Sseb mod_hash_val_t val; 18522311Sseb int err; 18532311Sseb 18542311Sseb /* 18552311Sseb * Let's not allow MAC drivers to use this plugin while we're 1856*3288Sseb * trying to unregister it. Holding i_mactype_lock also prevents a 1857*3288Sseb * plugin from unregistering while a MAC driver is attempting to 1858*3288Sseb * hold a reference to it in i_mactype_getplugin(). 18592311Sseb */ 1860*3288Sseb mutex_enter(&i_mactype_lock); 18612311Sseb 18622311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 18632311Sseb (mod_hash_val_t *)&mtp)) != 0) { 18642311Sseb /* A plugin is trying to unregister, but it never registered. */ 1865*3288Sseb err = ENXIO; 1866*3288Sseb goto done; 18672311Sseb } 18682311Sseb 1869*3288Sseb if (mtp->mt_ref != 0) { 1870*3288Sseb err = EBUSY; 1871*3288Sseb goto done; 18722311Sseb } 18732311Sseb 18742311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 18752311Sseb ASSERT(err == 0); 18762311Sseb if (err != 0) { 18772311Sseb /* This should never happen, thus the ASSERT() above. */ 1878*3288Sseb err = EINVAL; 1879*3288Sseb goto done; 18802311Sseb } 18812311Sseb ASSERT(mtp == (mactype_t *)val); 18822311Sseb 18832311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18842311Sseb kmem_free(mtp, sizeof (mactype_t)); 1885*3288Sseb done: 1886*3288Sseb mutex_exit(&i_mactype_lock); 1887*3288Sseb return (err); 18882311Sseb } 1889