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 /* 223448Sdh155122 * Copyright 2007 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> 453448Sdh155122 #include <sys/fs/dv_node.h> 463288Sseb #include <sys/atomic.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */ 490Sstevel@tonic-gate 500Sstevel@tonic-gate static kmem_cache_t *i_mac_impl_cachep; 51269Sericheng static mod_hash_t *i_mac_impl_hash; 52269Sericheng krwlock_t i_mac_impl_lock; 53269Sericheng uint_t i_mac_impl_count; 540Sstevel@tonic-gate 552311Sseb #define MACTYPE_KMODDIR "mac" 562311Sseb #define MACTYPE_HASHSZ 67 572311Sseb static mod_hash_t *i_mactype_hash; 583288Sseb /* 593288Sseb * i_mactype_lock synchronizes threads that obtain references to mactype_t 603288Sseb * structures through i_mactype_getplugin(). 613288Sseb */ 623288Sseb static kmutex_t i_mactype_lock; 632311Sseb 641852Syz147064 static void i_mac_notify_task(void *); 651852Syz147064 660Sstevel@tonic-gate /* 670Sstevel@tonic-gate * Private functions. 680Sstevel@tonic-gate */ 690Sstevel@tonic-gate 700Sstevel@tonic-gate /*ARGSUSED*/ 710Sstevel@tonic-gate static int 720Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag) 730Sstevel@tonic-gate { 740Sstevel@tonic-gate mac_impl_t *mip = buf; 750Sstevel@tonic-gate 760Sstevel@tonic-gate bzero(buf, sizeof (mac_impl_t)); 770Sstevel@tonic-gate 782311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 790Sstevel@tonic-gate 800Sstevel@tonic-gate rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 810Sstevel@tonic-gate rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 820Sstevel@tonic-gate rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 830Sstevel@tonic-gate rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 840Sstevel@tonic-gate rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 850Sstevel@tonic-gate rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 860Sstevel@tonic-gate mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 871852Syz147064 mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL); 881852Syz147064 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 890Sstevel@tonic-gate return (0); 900Sstevel@tonic-gate } 910Sstevel@tonic-gate 920Sstevel@tonic-gate /*ARGSUSED*/ 930Sstevel@tonic-gate static void 940Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate mac_impl_t *mip = buf; 970Sstevel@tonic-gate 980Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 990Sstevel@tonic-gate ASSERT(mip->mi_active == 0); 1002311Sseb ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 1010Sstevel@tonic-gate ASSERT(mip->mi_devpromisc == 0); 1020Sstevel@tonic-gate ASSERT(mip->mi_promisc == 0); 1030Sstevel@tonic-gate ASSERT(mip->mi_mmap == NULL); 1040Sstevel@tonic-gate ASSERT(mip->mi_mnfp == NULL); 1050Sstevel@tonic-gate ASSERT(mip->mi_resource_add == NULL); 1060Sstevel@tonic-gate ASSERT(mip->mi_ksp == NULL); 1072311Sseb ASSERT(mip->mi_kstat_count == 0); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate rw_destroy(&mip->mi_state_lock); 1100Sstevel@tonic-gate rw_destroy(&mip->mi_data_lock); 1110Sstevel@tonic-gate rw_destroy(&mip->mi_notify_lock); 1120Sstevel@tonic-gate rw_destroy(&mip->mi_rx_lock); 1130Sstevel@tonic-gate rw_destroy(&mip->mi_txloop_lock); 1140Sstevel@tonic-gate rw_destroy(&mip->mi_resource_lock); 1150Sstevel@tonic-gate mutex_destroy(&mip->mi_activelink_lock); 1161852Syz147064 mutex_destroy(&mip->mi_notify_ref_lock); 1171852Syz147064 cv_destroy(&mip->mi_notify_cv); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate static void 1210Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 1220Sstevel@tonic-gate { 1231852Syz147064 mac_notify_task_arg_t *mnta; 1241852Syz147064 1251852Syz147064 rw_enter(&i_mac_impl_lock, RW_READER); 1261852Syz147064 if (mip->mi_disabled) 1271852Syz147064 goto exit; 1281852Syz147064 1291852Syz147064 if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) { 1301852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory " 1311852Syz147064 "allocation failed", mip->mi_name, type); 1321852Syz147064 goto exit; 1331852Syz147064 } 1341852Syz147064 1351852Syz147064 mnta->mnt_mip = mip; 1361852Syz147064 mnta->mnt_type = type; 1371852Syz147064 1381852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1391852Syz147064 mip->mi_notify_ref++; 1401852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1411852Syz147064 1421852Syz147064 rw_exit(&i_mac_impl_lock); 1431852Syz147064 1441852Syz147064 if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta, 1451852Syz147064 TQ_NOSLEEP) == NULL) { 1461852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch " 1471852Syz147064 "failed", mip->mi_name, type); 1481852Syz147064 1491852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1501852Syz147064 if (--mip->mi_notify_ref == 0) 1511852Syz147064 cv_signal(&mip->mi_notify_cv); 1521852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1531852Syz147064 1541852Syz147064 kmem_free(mnta, sizeof (*mnta)); 1551852Syz147064 } 1561852Syz147064 return; 1571852Syz147064 1581852Syz147064 exit: 1591852Syz147064 rw_exit(&i_mac_impl_lock); 1601852Syz147064 } 1611852Syz147064 1621852Syz147064 static void 163*4403Sgd78059 i_mac_log_link_state(mac_impl_t *mip) 164*4403Sgd78059 { 165*4403Sgd78059 /* 166*4403Sgd78059 * If no change, then it is not interesting. 167*4403Sgd78059 */ 168*4403Sgd78059 if (mip->mi_lastlinkstate == mip->mi_linkstate) 169*4403Sgd78059 return; 170*4403Sgd78059 171*4403Sgd78059 switch (mip->mi_linkstate) { 172*4403Sgd78059 case LINK_STATE_UP: 173*4403Sgd78059 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) { 174*4403Sgd78059 char det[200]; 175*4403Sgd78059 176*4403Sgd78059 mip->mi_type->mt_ops.mtops_link_details(det, 177*4403Sgd78059 sizeof (det), (mac_handle_t)mip, mip->mi_pdata); 178*4403Sgd78059 179*4403Sgd78059 cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det); 180*4403Sgd78059 } else { 181*4403Sgd78059 cmn_err(CE_NOTE, "!%s link up", mip->mi_name); 182*4403Sgd78059 } 183*4403Sgd78059 break; 184*4403Sgd78059 185*4403Sgd78059 case LINK_STATE_DOWN: 186*4403Sgd78059 /* 187*4403Sgd78059 * Only transitions from UP to DOWN are interesting 188*4403Sgd78059 */ 189*4403Sgd78059 if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN) 190*4403Sgd78059 cmn_err(CE_NOTE, "!%s link down", mip->mi_name); 191*4403Sgd78059 break; 192*4403Sgd78059 193*4403Sgd78059 case LINK_STATE_UNKNOWN: 194*4403Sgd78059 /* 195*4403Sgd78059 * This case is normally not interesting. 196*4403Sgd78059 */ 197*4403Sgd78059 break; 198*4403Sgd78059 } 199*4403Sgd78059 mip->mi_lastlinkstate = mip->mi_linkstate; 200*4403Sgd78059 } 201*4403Sgd78059 202*4403Sgd78059 static void 2031852Syz147064 i_mac_notify_task(void *notify_arg) 2041852Syz147064 { 2051852Syz147064 mac_notify_task_arg_t *mnta = (mac_notify_task_arg_t *)notify_arg; 2061852Syz147064 mac_impl_t *mip; 2071852Syz147064 mac_notify_type_t type; 2080Sstevel@tonic-gate mac_notify_fn_t *mnfp; 2090Sstevel@tonic-gate mac_notify_t notify; 2100Sstevel@tonic-gate void *arg; 2110Sstevel@tonic-gate 2121852Syz147064 mip = mnta->mnt_mip; 2131852Syz147064 type = mnta->mnt_type; 2141852Syz147064 kmem_free(mnta, sizeof (*mnta)); 2151852Syz147064 2160Sstevel@tonic-gate /* 217*4403Sgd78059 * Log it. 218*4403Sgd78059 */ 219*4403Sgd78059 if (type == MAC_NOTE_LINK) 220*4403Sgd78059 i_mac_log_link_state(mip); 221*4403Sgd78059 222*4403Sgd78059 /* 2230Sstevel@tonic-gate * Walk the list of notifications. 2240Sstevel@tonic-gate */ 2251852Syz147064 rw_enter(&mip->mi_notify_lock, RW_READER); 2260Sstevel@tonic-gate for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 2270Sstevel@tonic-gate notify = mnfp->mnf_fn; 2280Sstevel@tonic-gate arg = mnfp->mnf_arg; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate ASSERT(notify != NULL); 2310Sstevel@tonic-gate notify(arg, type); 2320Sstevel@tonic-gate } 2331852Syz147064 rw_exit(&mip->mi_notify_lock); 2341852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 2351852Syz147064 if (--mip->mi_notify_ref == 0) 2361852Syz147064 cv_signal(&mip->mi_notify_cv); 2371852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate 2402311Sseb static mactype_t * 2413288Sseb i_mactype_getplugin(const char *pname) 2422311Sseb { 2432311Sseb mactype_t *mtype = NULL; 2442311Sseb boolean_t tried_modload = B_FALSE; 2452311Sseb 2463288Sseb mutex_enter(&i_mactype_lock); 2473288Sseb 2482311Sseb find_registered_mactype: 2493288Sseb if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname, 2503288Sseb (mod_hash_val_t *)&mtype) != 0) { 2513288Sseb if (!tried_modload) { 2523288Sseb /* 2533288Sseb * If the plugin has not yet been loaded, then 2543288Sseb * attempt to load it now. If modload() succeeds, 2553288Sseb * the plugin should have registered using 2563288Sseb * mactype_register(), in which case we can go back 2573288Sseb * and attempt to find it again. 2583288Sseb */ 2593288Sseb if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) { 2603288Sseb tried_modload = B_TRUE; 2613288Sseb goto find_registered_mactype; 2623288Sseb } 2633288Sseb } 2643288Sseb } else { 2652311Sseb /* 2663288Sseb * Note that there's no danger that the plugin we've loaded 2673288Sseb * could be unloaded between the modload() step and the 2683288Sseb * reference count bump here, as we're holding 2693288Sseb * i_mactype_lock, which mactype_unregister() also holds. 2702311Sseb */ 2713288Sseb atomic_inc_32(&mtype->mt_ref); 2722311Sseb } 2732311Sseb 2743288Sseb mutex_exit(&i_mactype_lock); 2753288Sseb return (mtype); 2762311Sseb } 2772311Sseb 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate * Module initialization functions. 2800Sstevel@tonic-gate */ 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate void 2830Sstevel@tonic-gate mac_init(void) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 2862311Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 2872311Sseb NULL, NULL, NULL, 0); 2880Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL); 2890Sstevel@tonic-gate 290269Sericheng i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 291269Sericheng IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 292269Sericheng mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 293269Sericheng rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 294269Sericheng i_mac_impl_count = 0; 2952311Sseb 2962311Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash", 2972311Sseb MACTYPE_HASHSZ, 2982311Sseb mod_hash_null_keydtor, mod_hash_null_valdtor, 2992311Sseb mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate int 3030Sstevel@tonic-gate mac_fini(void) 3040Sstevel@tonic-gate { 305269Sericheng if (i_mac_impl_count > 0) 306269Sericheng return (EBUSY); 3070Sstevel@tonic-gate 308269Sericheng mod_hash_destroy_hash(i_mac_impl_hash); 309269Sericheng rw_destroy(&i_mac_impl_lock); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate kmem_cache_destroy(i_mac_impl_cachep); 3122311Sseb 3132311Sseb mod_hash_destroy_hash(i_mactype_hash); 3140Sstevel@tonic-gate return (0); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Client functions. 3190Sstevel@tonic-gate */ 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate int 3222311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp) 3230Sstevel@tonic-gate { 3240Sstevel@tonic-gate char driver[MAXNAMELEN]; 3250Sstevel@tonic-gate uint_t instance; 3260Sstevel@tonic-gate major_t major; 3270Sstevel@tonic-gate dev_info_t *dip; 3280Sstevel@tonic-gate mac_impl_t *mip; 3290Sstevel@tonic-gate int err; 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our 3330Sstevel@tonic-gate * buffer. 3340Sstevel@tonic-gate */ 3352311Sseb if (strlen(macname) >= MAXNAMELEN) 3360Sstevel@tonic-gate return (EINVAL); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * Split the device name into driver and instance components. 3400Sstevel@tonic-gate */ 3412311Sseb if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS) 3420Sstevel@tonic-gate return (EINVAL); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate /* 3450Sstevel@tonic-gate * Get the major number of the driver. 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate if ((major = ddi_name_to_major(driver)) == (major_t)-1) 3480Sstevel@tonic-gate return (EINVAL); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate /* 3510Sstevel@tonic-gate * Hold the given instance to prevent it from being detached. 352269Sericheng * This will also attach the instance if it is not currently attached. 353269Sericheng * Currently we ensure that mac_register() (called by the driver's 354269Sericheng * attach entry point) and all code paths under it cannot possibly 355269Sericheng * call mac_open() because this would lead to a recursive attach 356269Sericheng * panic. 3570Sstevel@tonic-gate */ 3582311Sseb if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL) 3590Sstevel@tonic-gate return (EINVAL); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate /* 3620Sstevel@tonic-gate * Look up its entry in the global hash table. 3630Sstevel@tonic-gate */ 3640Sstevel@tonic-gate again: 365269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 3662311Sseb err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 367269Sericheng (mod_hash_val_t *)&mip); 368269Sericheng if (err != 0) { 369269Sericheng err = ENOENT; 3700Sstevel@tonic-gate goto failed; 371269Sericheng } 3720Sstevel@tonic-gate 3731852Syz147064 if (mip->mi_disabled) { 374269Sericheng rw_exit(&i_mac_impl_lock); 3750Sstevel@tonic-gate goto again; 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate mip->mi_ref++; 379269Sericheng rw_exit(&i_mac_impl_lock); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate *mhp = (mac_handle_t)mip; 3820Sstevel@tonic-gate return (0); 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate failed: 385269Sericheng rw_exit(&i_mac_impl_lock); 3860Sstevel@tonic-gate ddi_release_devi(dip); 3870Sstevel@tonic-gate return (err); 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate void 3910Sstevel@tonic-gate mac_close(mac_handle_t mh) 3920Sstevel@tonic-gate { 3930Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 3942311Sseb dev_info_t *dip = mip->mi_dip; 3950Sstevel@tonic-gate 396269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate ASSERT(mip->mi_ref != 0); 3990Sstevel@tonic-gate if (--mip->mi_ref == 0) { 4000Sstevel@tonic-gate ASSERT(!mip->mi_activelink); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate ddi_release_devi(dip); 403269Sericheng rw_exit(&i_mac_impl_lock); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate const mac_info_t * 4070Sstevel@tonic-gate mac_info(mac_handle_t mh) 4080Sstevel@tonic-gate { 4092311Sseb return (&((mac_impl_t *)mh)->mi_info); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 412269Sericheng dev_info_t * 413269Sericheng mac_devinfo_get(mac_handle_t mh) 414269Sericheng { 4152311Sseb return (((mac_impl_t *)mh)->mi_dip); 416269Sericheng } 417269Sericheng 4180Sstevel@tonic-gate uint64_t 4192311Sseb mac_stat_get(mac_handle_t mh, uint_t stat) 4200Sstevel@tonic-gate { 4210Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4222311Sseb uint64_t val; 4232311Sseb int ret; 4240Sstevel@tonic-gate 4252311Sseb /* 4262311Sseb * The range of stat determines where it is maintained. Stat 4272311Sseb * values from 0 up to (but not including) MAC_STAT_MIN are 4282311Sseb * mainteined by the mac module itself. Everything else is 4292311Sseb * maintained by the driver. 4302311Sseb */ 4312311Sseb if (stat < MAC_STAT_MIN) { 4322311Sseb /* These stats are maintained by the mac module itself. */ 4332311Sseb switch (stat) { 4342311Sseb case MAC_STAT_LINK_STATE: 4352311Sseb return (mip->mi_linkstate); 4362311Sseb case MAC_STAT_LINK_UP: 4372311Sseb return (mip->mi_linkstate == LINK_STATE_UP); 4382311Sseb case MAC_STAT_PROMISC: 4392311Sseb return (mip->mi_devpromisc != 0); 4402311Sseb default: 4412311Sseb ASSERT(B_FALSE); 4422311Sseb } 4432311Sseb } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate /* 4460Sstevel@tonic-gate * Call the driver to get the given statistic. 4470Sstevel@tonic-gate */ 4482311Sseb ret = mip->mi_getstat(mip->mi_driver, stat, &val); 4492311Sseb if (ret != 0) { 4502311Sseb /* 4512311Sseb * The driver doesn't support this statistic. Get the 4522311Sseb * statistic's default value. 4532311Sseb */ 4542311Sseb val = mac_stat_default(mip, stat); 4552311Sseb } 4562311Sseb return (val); 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate int 4600Sstevel@tonic-gate mac_start(mac_handle_t mh) 4610Sstevel@tonic-gate { 4620Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4630Sstevel@tonic-gate int err; 4640Sstevel@tonic-gate 4652311Sseb ASSERT(mip->mi_start != NULL); 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * Check whether the device is already started. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate if (mip->mi_active++ != 0) { 4730Sstevel@tonic-gate /* 4740Sstevel@tonic-gate * It's already started so there's nothing more to do. 4750Sstevel@tonic-gate */ 4760Sstevel@tonic-gate err = 0; 4770Sstevel@tonic-gate goto done; 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * Start the device. 4820Sstevel@tonic-gate */ 4832311Sseb if ((err = mip->mi_start(mip->mi_driver)) != 0) 4840Sstevel@tonic-gate --mip->mi_active; 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate done: 4870Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 4880Sstevel@tonic-gate return (err); 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate void 4920Sstevel@tonic-gate mac_stop(mac_handle_t mh) 4930Sstevel@tonic-gate { 4940Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4950Sstevel@tonic-gate 4962311Sseb ASSERT(mip->mi_stop != NULL); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate /* 5010Sstevel@tonic-gate * Check whether the device is still needed. 5020Sstevel@tonic-gate */ 5030Sstevel@tonic-gate ASSERT(mip->mi_active != 0); 5040Sstevel@tonic-gate if (--mip->mi_active != 0) { 5050Sstevel@tonic-gate /* 5060Sstevel@tonic-gate * It's still needed so there's nothing more to do. 5070Sstevel@tonic-gate */ 5080Sstevel@tonic-gate goto done; 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Stop the device. 5130Sstevel@tonic-gate */ 5142311Sseb mip->mi_stop(mip->mi_driver); 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate done: 5170Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate int 5210Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 5220Sstevel@tonic-gate { 5230Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5240Sstevel@tonic-gate mac_multicst_addr_t **pp; 5250Sstevel@tonic-gate mac_multicst_addr_t *p; 5260Sstevel@tonic-gate int err; 5270Sstevel@tonic-gate 5282311Sseb ASSERT(mip->mi_multicst != NULL); 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate /* 5310Sstevel@tonic-gate * Verify the address. 5320Sstevel@tonic-gate */ 5332311Sseb if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 5342311Sseb mip->mi_pdata)) != 0) { 5352311Sseb return (err); 5362311Sseb } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* 5390Sstevel@tonic-gate * Check whether the given address is already enabled. 5400Sstevel@tonic-gate */ 5410Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 5420Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 5432311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 5442311Sseb 0) { 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * The address is already enabled so just bump the 5470Sstevel@tonic-gate * reference count. 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate p->mma_ref++; 5500Sstevel@tonic-gate err = 0; 5510Sstevel@tonic-gate goto done; 5520Sstevel@tonic-gate } 5530Sstevel@tonic-gate } 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate /* 5560Sstevel@tonic-gate * Allocate a new list entry. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 5590Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 5600Sstevel@tonic-gate err = ENOMEM; 5610Sstevel@tonic-gate goto done; 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate /* 5650Sstevel@tonic-gate * Enable a new multicast address. 5660Sstevel@tonic-gate */ 5672311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 5680Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 5690Sstevel@tonic-gate goto done; 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * Add the address to the list of enabled addresses. 5740Sstevel@tonic-gate */ 5752311Sseb bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 5760Sstevel@tonic-gate p->mma_ref++; 5770Sstevel@tonic-gate *pp = p; 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate done: 5800Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 5810Sstevel@tonic-gate return (err); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate int 5850Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 5860Sstevel@tonic-gate { 5870Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5880Sstevel@tonic-gate mac_multicst_addr_t **pp; 5890Sstevel@tonic-gate mac_multicst_addr_t *p; 5900Sstevel@tonic-gate int err; 5910Sstevel@tonic-gate 5922311Sseb ASSERT(mip->mi_multicst != NULL); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate /* 5950Sstevel@tonic-gate * Find the entry in the list for the given address. 5960Sstevel@tonic-gate */ 5970Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 5980Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 5992311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 6002311Sseb 0) { 6010Sstevel@tonic-gate if (--p->mma_ref == 0) 6020Sstevel@tonic-gate break; 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* 6050Sstevel@tonic-gate * There is still a reference to this address so 6060Sstevel@tonic-gate * there's nothing more to do. 6070Sstevel@tonic-gate */ 6080Sstevel@tonic-gate err = 0; 6090Sstevel@tonic-gate goto done; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate } 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate /* 6140Sstevel@tonic-gate * We did not find an entry for the given address so it is not 6150Sstevel@tonic-gate * currently enabled. 6160Sstevel@tonic-gate */ 6170Sstevel@tonic-gate if (p == NULL) { 6180Sstevel@tonic-gate err = ENOENT; 6190Sstevel@tonic-gate goto done; 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate ASSERT(p->mma_ref == 0); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * Disable the multicast address. 6250Sstevel@tonic-gate */ 6262311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 6270Sstevel@tonic-gate p->mma_ref++; 6280Sstevel@tonic-gate goto done; 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* 6320Sstevel@tonic-gate * Remove it from the list. 6330Sstevel@tonic-gate */ 6340Sstevel@tonic-gate *pp = p->mma_nextp; 6350Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate done: 6380Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6390Sstevel@tonic-gate return (err); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6422331Skrgopi /* 6432331Skrgopi * mac_unicst_verify: Verifies the passed address. It fails 6442331Skrgopi * if the passed address is a group address or has incorrect length. 6452331Skrgopi */ 6462331Skrgopi boolean_t 6472331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 6482331Skrgopi { 6492331Skrgopi mac_impl_t *mip = (mac_impl_t *)mh; 6502331Skrgopi 6512331Skrgopi /* 6522331Skrgopi * Verify the address. 6532331Skrgopi */ 6542331Skrgopi if ((len != mip->mi_type->mt_addr_length) || 6552331Skrgopi (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6562331Skrgopi mip->mi_pdata)) != 0) { 6572331Skrgopi return (B_FALSE); 6582331Skrgopi } else { 6592331Skrgopi return (B_TRUE); 6602331Skrgopi } 6612331Skrgopi } 6622331Skrgopi 6630Sstevel@tonic-gate int 6640Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 6650Sstevel@tonic-gate { 6660Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6670Sstevel@tonic-gate int err; 6680Sstevel@tonic-gate boolean_t notify = B_FALSE; 6690Sstevel@tonic-gate 6702311Sseb ASSERT(mip->mi_unicst != NULL); 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate /* 6730Sstevel@tonic-gate * Verify the address. 6740Sstevel@tonic-gate */ 6752311Sseb if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6762311Sseb mip->mi_pdata)) != 0) { 6772311Sseb return (err); 6782311Sseb } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate /* 6810Sstevel@tonic-gate * Program the new unicast address. 6820Sstevel@tonic-gate */ 6830Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * If address doesn't change, do nothing. 6870Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 6880Sstevel@tonic-gate * recursively. 6890Sstevel@tonic-gate */ 6902311Sseb if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 6910Sstevel@tonic-gate err = 0; 6920Sstevel@tonic-gate goto done; 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6952311Sseb if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 6960Sstevel@tonic-gate goto done; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate /* 6990Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 7000Sstevel@tonic-gate */ 7012311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 7020Sstevel@tonic-gate notify = B_TRUE; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate done: 7050Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate if (notify) 7080Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate return (err); 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate void 7140Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 7150Sstevel@tonic-gate { 7160Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate /* 7192311Sseb * Copy out the current unicast source address. 7200Sstevel@tonic-gate */ 7210Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 7222311Sseb bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 7232311Sseb rw_exit(&(mip->mi_data_lock)); 7242311Sseb } 7252311Sseb 7262311Sseb void 7272311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr) 7282311Sseb { 7292311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 7302311Sseb 7312311Sseb /* 7322311Sseb * Copy out the current destination address. 7332311Sseb */ 7342311Sseb rw_enter(&(mip->mi_data_lock), RW_READER); 7352311Sseb bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 7360Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate int 7400Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 7410Sstevel@tonic-gate { 7420Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7430Sstevel@tonic-gate int err = 0; 7440Sstevel@tonic-gate 7452311Sseb ASSERT(mip->mi_setpromisc != NULL); 7460Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 7500Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 7510Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 7520Sstevel@tonic-gate */ 7530Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 7540Sstevel@tonic-gate if (on) { 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 7570Sstevel@tonic-gate */ 7580Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 7592311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 7602311Sseb if (err != 0) { 7610Sstevel@tonic-gate mip->mi_devpromisc--; 7620Sstevel@tonic-gate goto done; 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 7690Sstevel@tonic-gate */ 7700Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 7710Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7720Sstevel@tonic-gate } else { 7730Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 7740Sstevel@tonic-gate err = EPROTO; 7750Sstevel@tonic-gate goto done; 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 7800Sstevel@tonic-gate * enabling. 7810Sstevel@tonic-gate */ 7820Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 7832311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 7842311Sseb if (err != 0) { 7850Sstevel@tonic-gate mip->mi_devpromisc++; 7860Sstevel@tonic-gate goto done; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7890Sstevel@tonic-gate } 7900Sstevel@tonic-gate 7910Sstevel@tonic-gate /* 7920Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 7930Sstevel@tonic-gate * enabling. 7940Sstevel@tonic-gate */ 7950Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 7960Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate done: 8000Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 8010Sstevel@tonic-gate return (err); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate boolean_t 8050Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 8060Sstevel@tonic-gate { 8070Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate /* 8120Sstevel@tonic-gate * Return the current promiscuity. 8130Sstevel@tonic-gate */ 8140Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 8150Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 8160Sstevel@tonic-gate else 8170Sstevel@tonic-gate return (mip->mi_promisc != 0); 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate void 8210Sstevel@tonic-gate mac_resources(mac_handle_t mh) 8220Sstevel@tonic-gate { 8230Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate /* 8262311Sseb * If the driver supports resource registration, call the driver to 8272311Sseb * ask it to register its resources. 8280Sstevel@tonic-gate */ 8292311Sseb if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 8302311Sseb mip->mi_resources(mip->mi_driver); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate void 8340Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 8350Sstevel@tonic-gate { 8360Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate /* 8392311Sseb * Call the driver to handle the ioctl. The driver may not support 8402311Sseb * any ioctls, in which case we reply with a NAK on its behalf. 8410Sstevel@tonic-gate */ 8422311Sseb if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 8432311Sseb mip->mi_ioctl(mip->mi_driver, wq, bp); 8442311Sseb else 8452311Sseb miocnak(wq, bp, 0, EINVAL); 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate 84856Smeem const mac_txinfo_t * 84956Smeem mac_tx_get(mac_handle_t mh) 8500Sstevel@tonic-gate { 8510Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 85256Smeem mac_txinfo_t *mtp; 85356Smeem 85456Smeem /* 85556Smeem * Grab the lock to prevent us from racing with MAC_PROMISC being 85656Smeem * changed. This is sufficient since MAC clients are careful to always 85756Smeem * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 85856Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 85956Smeem */ 86056Smeem rw_enter(&mip->mi_txloop_lock, RW_READER); 8610Sstevel@tonic-gate 86256Smeem if (mac_promisc_get(mh, MAC_PROMISC)) { 86356Smeem ASSERT(mip->mi_mtfp != NULL); 86456Smeem mtp = &mip->mi_txloopinfo; 86556Smeem } else { 86656Smeem /* 86756Smeem * Note that we cannot ASSERT() that mip->mi_mtfp is NULL, 86856Smeem * because to satisfy the above ASSERT(), we have to disable 86956Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 87056Smeem */ 87156Smeem mtp = &mip->mi_txinfo; 87256Smeem } 87356Smeem 87456Smeem rw_exit(&mip->mi_txloop_lock); 87556Smeem return (mtp); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate link_state_t 8790Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 8800Sstevel@tonic-gate { 8812311Sseb return (((mac_impl_t *)mh)->mi_linkstate); 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate mac_notify_handle_t 8850Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 8860Sstevel@tonic-gate { 8870Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8880Sstevel@tonic-gate mac_notify_fn_t *mnfp; 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 8910Sstevel@tonic-gate mnfp->mnf_fn = notify; 8920Sstevel@tonic-gate mnfp->mnf_arg = arg; 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* 8950Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 8960Sstevel@tonic-gate */ 8971852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 8980Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 8990Sstevel@tonic-gate mip->mi_mnfp = mnfp; 9001852Syz147064 rw_exit(&mip->mi_notify_lock); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate void 9060Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 9070Sstevel@tonic-gate { 9080Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9090Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 9100Sstevel@tonic-gate mac_notify_fn_t **pp; 9110Sstevel@tonic-gate mac_notify_fn_t *p; 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* 9140Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 9150Sstevel@tonic-gate */ 9161852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 9170Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 9180Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 9190Sstevel@tonic-gate if (p == mnfp) 9200Sstevel@tonic-gate break; 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate ASSERT(p != NULL); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* 9250Sstevel@tonic-gate * Remove it from the list. 9260Sstevel@tonic-gate */ 9270Sstevel@tonic-gate *pp = p->mnf_nextp; 9281852Syz147064 rw_exit(&mip->mi_notify_lock); 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate /* 9310Sstevel@tonic-gate * Free it. 9320Sstevel@tonic-gate */ 9330Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate void 9370Sstevel@tonic-gate mac_notify(mac_handle_t mh) 9380Sstevel@tonic-gate { 9390Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9400Sstevel@tonic-gate mac_notify_type_t type; 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 9430Sstevel@tonic-gate i_mac_notify(mip, type); 9440Sstevel@tonic-gate } 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate mac_rx_handle_t 9470Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 9480Sstevel@tonic-gate { 9490Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9500Sstevel@tonic-gate mac_rx_fn_t *mrfp; 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 9530Sstevel@tonic-gate mrfp->mrf_fn = rx; 9540Sstevel@tonic-gate mrfp->mrf_arg = arg; 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 9580Sstevel@tonic-gate */ 9590Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9600Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 9610Sstevel@tonic-gate mip->mi_mrfp = mrfp; 9620Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate /* 9680Sstevel@tonic-gate * Unregister a receive function for this mac. This removes the function 9690Sstevel@tonic-gate * from the list of receive functions for this mac. 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate void 9720Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 9730Sstevel@tonic-gate { 9740Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9750Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 9760Sstevel@tonic-gate mac_rx_fn_t **pp; 9770Sstevel@tonic-gate mac_rx_fn_t *p; 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate /* 9800Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 9830Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 9840Sstevel@tonic-gate if (p == mrfp) 9850Sstevel@tonic-gate break; 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate ASSERT(p != NULL); 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* Remove it from the list. */ 9900Sstevel@tonic-gate *pp = p->mrf_nextp; 9910Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 9920Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9930Sstevel@tonic-gate } 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate mac_txloop_handle_t 9960Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 9970Sstevel@tonic-gate { 9980Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9990Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 10020Sstevel@tonic-gate mtfp->mtf_fn = tx; 10030Sstevel@tonic-gate mtfp->mtf_arg = arg; 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate /* 10060Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 10090Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 10100Sstevel@tonic-gate mip->mi_mtfp = mtfp; 10110Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate /* 10170Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 10180Sstevel@tonic-gate * from the list of transmit functions for this mac. 10190Sstevel@tonic-gate */ 10200Sstevel@tonic-gate void 10210Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 10220Sstevel@tonic-gate { 10230Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10240Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 10250Sstevel@tonic-gate mac_txloop_fn_t **pp; 10260Sstevel@tonic-gate mac_txloop_fn_t *p; 10270Sstevel@tonic-gate 10280Sstevel@tonic-gate /* 10290Sstevel@tonic-gate * Search the 'tx' callback list for the function. 10300Sstevel@tonic-gate */ 10310Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 10320Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 10330Sstevel@tonic-gate if (p == mtfp) 10340Sstevel@tonic-gate break; 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate ASSERT(p != NULL); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate /* Remove it from the list. */ 10390Sstevel@tonic-gate *pp = p->mtf_nextp; 10400Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 10410Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate void 10450Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 10460Sstevel@tonic-gate { 10470Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * Update the 'resource_add' callbacks. 10510Sstevel@tonic-gate */ 10520Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 10530Sstevel@tonic-gate mip->mi_resource_add = add; 10540Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 10550Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* 10590Sstevel@tonic-gate * Driver support functions. 10600Sstevel@tonic-gate */ 10610Sstevel@tonic-gate 10622311Sseb mac_register_t * 10632311Sseb mac_alloc(uint_t mac_version) 10640Sstevel@tonic-gate { 10652311Sseb mac_register_t *mregp; 10662311Sseb 10672311Sseb /* 10682311Sseb * Make sure there isn't a version mismatch between the driver and 10692311Sseb * the framework. In the future, if multiple versions are 10702311Sseb * supported, this check could become more sophisticated. 10712311Sseb */ 10722311Sseb if (mac_version != MAC_VERSION) 10732311Sseb return (NULL); 10742311Sseb 10752311Sseb mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 10762311Sseb mregp->m_version = mac_version; 10772311Sseb return (mregp); 10782311Sseb } 10792311Sseb 10802311Sseb void 10812311Sseb mac_free(mac_register_t *mregp) 10822311Sseb { 10832311Sseb kmem_free(mregp, sizeof (mac_register_t)); 10842311Sseb } 10852311Sseb 10862311Sseb /* 10872311Sseb * mac_register() is how drivers register new MACs with the GLDv3 10882311Sseb * framework. The mregp argument is allocated by drivers using the 10892311Sseb * mac_alloc() function, and can be freed using mac_free() immediately upon 10902311Sseb * return from mac_register(). Upon success (0 return value), the mhp 10912311Sseb * opaque pointer becomes the driver's handle to its MAC interface, and is 10922311Sseb * the argument to all other mac module entry points. 10932311Sseb */ 10942311Sseb int 10952311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 10962311Sseb { 10972311Sseb mac_impl_t *mip; 10982311Sseb mactype_t *mtype; 10993969Syz147064 int err = EINVAL; 11000Sstevel@tonic-gate struct devnames *dnp; 11012311Sseb minor_t minor; 11022311Sseb boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 11032311Sseb 11042311Sseb /* Find the required MAC-Type plugin. */ 11052311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 11062311Sseb return (EINVAL); 11072311Sseb 11082311Sseb /* Create a mac_impl_t to represent this MAC. */ 11092311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 11102311Sseb 11112311Sseb /* 11122311Sseb * The mac is not ready for open yet. 11132311Sseb */ 11142311Sseb mip->mi_disabled = B_TRUE; 11152311Sseb 11162311Sseb mip->mi_drvname = ddi_driver_name(mregp->m_dip); 11172311Sseb /* 11182311Sseb * Some drivers such as aggr need to register multiple MACs. Such 11192311Sseb * drivers must supply a non-zero "instance" argument so that each 11202311Sseb * MAC can be assigned a unique MAC name and can have unique 11212311Sseb * kstats. 11222311Sseb */ 11232311Sseb mip->mi_instance = ((mregp->m_instance == 0) ? 11242311Sseb ddi_get_instance(mregp->m_dip) : mregp->m_instance); 11252311Sseb 11262311Sseb /* Construct the MAC name as <drvname><instance> */ 11272311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 11282311Sseb mip->mi_drvname, mip->mi_instance); 11292311Sseb 11302311Sseb mip->mi_driver = mregp->m_driver; 11312311Sseb 11322311Sseb mip->mi_type = mtype; 11332311Sseb mip->mi_info.mi_media = mtype->mt_type; 11343147Sxc151355 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 11352311Sseb mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 11363969Syz147064 if (mregp->m_max_sdu <= mregp->m_min_sdu) 11372311Sseb goto fail; 11382311Sseb mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 11392311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 11402311Sseb /* 11412311Sseb * If the media supports a broadcast address, cache a pointer to it 11422311Sseb * in the mac_info_t so that upper layers can use it. 11432311Sseb */ 11442311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1145269Sericheng 11462311Sseb /* 11472311Sseb * Copy the unicast source address into the mac_info_t, but only if 11482311Sseb * the MAC-Type defines a non-zero address length. We need to 11492311Sseb * handle MAC-Types that have an address length of 0 11502311Sseb * (point-to-point protocol MACs for example). 11512311Sseb */ 11522311Sseb if (mip->mi_type->mt_addr_length > 0) { 11533969Syz147064 if (mregp->m_src_addr == NULL) 11542311Sseb goto fail; 11552311Sseb mip->mi_info.mi_unicst_addr = 11562311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 11572311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 11582311Sseb mip->mi_type->mt_addr_length); 11592311Sseb 11602311Sseb /* 11612311Sseb * Copy the fixed 'factory' MAC address from the immutable 11622311Sseb * info. This is taken to be the MAC address currently in 11632311Sseb * use. 11642311Sseb */ 11652311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 11662311Sseb mip->mi_type->mt_addr_length); 11672311Sseb /* Copy the destination address if one is provided. */ 11682311Sseb if (mregp->m_dst_addr != NULL) { 11692311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 11702311Sseb mip->mi_type->mt_addr_length); 11712311Sseb } 11722311Sseb } else if (mregp->m_src_addr != NULL) { 11732311Sseb goto fail; 1174269Sericheng } 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate /* 11772311Sseb * The format of the m_pdata is specific to the plugin. It is 11782311Sseb * passed in as an argument to all of the plugin callbacks. The 11792311Sseb * driver can update this information by calling 11802311Sseb * mac_pdata_update(). 11810Sstevel@tonic-gate */ 11822311Sseb if (mregp->m_pdata != NULL) { 11832311Sseb /* 11842311Sseb * Verify that the plugin supports MAC plugin data and that 11852311Sseb * the supplied data is valid. 11862311Sseb */ 11873969Syz147064 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 11882311Sseb goto fail; 11892311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 11902311Sseb mregp->m_pdata_size)) { 11912311Sseb goto fail; 11922311Sseb } 11932311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 11942311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 11952311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 11962311Sseb } 11972311Sseb 11982311Sseb /* 11992311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 12002311Sseb * check to make sure all mandatory callbacks are set. 12012311Sseb */ 12022311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 12032311Sseb mregp->m_callbacks->mc_start == NULL || 12042311Sseb mregp->m_callbacks->mc_stop == NULL || 12052311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 12062311Sseb mregp->m_callbacks->mc_multicst == NULL || 12072311Sseb mregp->m_callbacks->mc_unicst == NULL || 12082311Sseb mregp->m_callbacks->mc_tx == NULL) { 12092311Sseb goto fail; 12102311Sseb } 12112311Sseb mip->mi_callbacks = mregp->m_callbacks; 12122311Sseb 12132311Sseb mip->mi_dip = mregp->m_dip; 12142311Sseb 12152311Sseb /* 12162311Sseb * Set up the two possible transmit routines. 12172311Sseb */ 12182311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 12192311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 12202311Sseb mip->mi_txloopinfo.mt_fn = mac_txloop; 12212311Sseb mip->mi_txloopinfo.mt_arg = mip; 12222311Sseb 12232311Sseb /* 12242311Sseb * Initialize the kstats for this device. 12252311Sseb */ 12262311Sseb mac_stat_create(mip); 12270Sstevel@tonic-gate 1228269Sericheng err = EEXIST; 12292311Sseb /* Create a style-2 DLPI device */ 12302311Sseb if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 12312311Sseb S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 12322311Sseb goto fail; 12332311Sseb style2_created = B_TRUE; 1234269Sericheng 12352311Sseb /* Create a style-1 DLPI device */ 12362311Sseb minor = (minor_t)mip->mi_instance + 1; 12372311Sseb if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 12382311Sseb DDI_NT_NET, 0) != DDI_SUCCESS) 12392311Sseb goto fail; 12402311Sseb style1_created = B_TRUE; 12410Sstevel@tonic-gate 12422311Sseb /* 12432311Sseb * Create a link for this MAC. The link name will be the same as 12442311Sseb * the MAC name. 12452311Sseb */ 12462311Sseb err = dls_create(mip->mi_name, mip->mi_name, 12472311Sseb ddi_get_instance(mip->mi_dip)); 12482311Sseb if (err != 0) 12492311Sseb goto fail; 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 12522311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 12530Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 12540Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 12550Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 12560Sstevel@tonic-gate 12573969Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 12583969Syz147064 if (mod_hash_insert(i_mac_impl_hash, 12593969Syz147064 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 12603969Syz147064 rw_exit(&i_mac_impl_lock); 12613969Syz147064 VERIFY(dls_destroy(mip->mi_name) == 0); 12623969Syz147064 err = EEXIST; 12633969Syz147064 goto fail; 12643969Syz147064 } 12653969Syz147064 12661852Syz147064 /* 12671852Syz147064 * Mark the MAC to be ready for open. 12681852Syz147064 */ 12692311Sseb mip->mi_disabled = B_FALSE; 12702311Sseb 12712311Sseb cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 12723969Syz147064 12731852Syz147064 rw_exit(&i_mac_impl_lock); 12743969Syz147064 12753969Syz147064 atomic_inc_32(&i_mac_impl_count); 12762311Sseb *mhp = (mac_handle_t)mip; 1277269Sericheng return (0); 12780Sstevel@tonic-gate 12792311Sseb fail: 12802311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 12812311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 12822311Sseb mip->mi_type->mt_addr_length); 12832311Sseb mip->mi_info.mi_unicst_addr = NULL; 12842311Sseb } 12852311Sseb if (style1_created) 12862311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 12872311Sseb if (style2_created) 12882311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 12892311Sseb 12902311Sseb mac_stat_destroy(mip); 12912311Sseb 12922311Sseb if (mip->mi_type != NULL) { 12933288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 12942311Sseb mip->mi_type = NULL; 12952311Sseb } 12962311Sseb 12972311Sseb if (mip->mi_pdata != NULL) { 12982311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 12992311Sseb mip->mi_pdata = NULL; 13002311Sseb mip->mi_pdata_size = 0; 13012311Sseb } 13022311Sseb 13032311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 1304269Sericheng return (err); 13050Sstevel@tonic-gate } 13060Sstevel@tonic-gate 13070Sstevel@tonic-gate int 13082311Sseb mac_unregister(mac_handle_t mh) 13090Sstevel@tonic-gate { 13102311Sseb int err; 13112311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13122311Sseb mod_hash_val_t val; 13132311Sseb mac_multicst_addr_t *p, *nextp; 1314269Sericheng 13150Sstevel@tonic-gate /* 13160Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 13171852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 13182311Sseb * created while we're destroying this mac. 13190Sstevel@tonic-gate */ 1320269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 13210Sstevel@tonic-gate if (mip->mi_ref > 0) { 1322269Sericheng rw_exit(&i_mac_impl_lock); 13230Sstevel@tonic-gate return (EBUSY); 13240Sstevel@tonic-gate } 13251852Syz147064 mip->mi_disabled = B_TRUE; 1326269Sericheng rw_exit(&i_mac_impl_lock); 13270Sstevel@tonic-gate 13281852Syz147064 /* 13291852Syz147064 * Wait for all taskqs which process the mac notifications to finish. 13301852Syz147064 */ 13311852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 13321852Syz147064 while (mip->mi_notify_ref != 0) 13331852Syz147064 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 13341852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 13351852Syz147064 13362311Sseb if ((err = dls_destroy(mip->mi_name)) != 0) { 1337269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 13381852Syz147064 mip->mi_disabled = B_FALSE; 1339269Sericheng rw_exit(&i_mac_impl_lock); 1340269Sericheng return (err); 13410Sstevel@tonic-gate } 13420Sstevel@tonic-gate 13430Sstevel@tonic-gate /* 13442311Sseb * Remove both style 1 and style 2 minor nodes 13450Sstevel@tonic-gate */ 13462311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 13472311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 13482311Sseb 13492311Sseb ASSERT(!mip->mi_activelink); 13502311Sseb 13512311Sseb mac_stat_destroy(mip); 13522311Sseb 13532311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 13542311Sseb &val); 13552311Sseb ASSERT(mip == (mac_impl_t *)val); 13562311Sseb 13572311Sseb ASSERT(i_mac_impl_count > 0); 13583288Sseb atomic_dec_32(&i_mac_impl_count); 13592311Sseb 13602311Sseb if (mip->mi_pdata != NULL) 13612311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 13622311Sseb mip->mi_pdata = NULL; 13632311Sseb mip->mi_pdata_size = 0; 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate /* 13662311Sseb * Free the list of multicast addresses. 13670Sstevel@tonic-gate */ 13682311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 13692311Sseb nextp = p->mma_nextp; 13702311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 13712311Sseb } 13722311Sseb mip->mi_mmap = NULL; 13730Sstevel@tonic-gate 13742311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 13752311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 13762311Sseb mip->mi_info.mi_unicst_addr = NULL; 13772311Sseb 13783288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 13792311Sseb mip->mi_type = NULL; 13802311Sseb 13812311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 13822311Sseb 13832311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 13842311Sseb 13850Sstevel@tonic-gate return (0); 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate void 13892311Sseb mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *bp) 13900Sstevel@tonic-gate { 13912311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13920Sstevel@tonic-gate mac_rx_fn_t *mrfp; 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate /* 13950Sstevel@tonic-gate * Call all registered receive functions. 13960Sstevel@tonic-gate */ 13970Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 13980Sstevel@tonic-gate mrfp = mip->mi_mrfp; 13990Sstevel@tonic-gate if (mrfp == NULL) { 14000Sstevel@tonic-gate /* There are no registered receive functions. */ 14010Sstevel@tonic-gate freemsgchain(bp); 14020Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 14030Sstevel@tonic-gate return; 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate do { 14060Sstevel@tonic-gate mblk_t *recv_bp; 14070Sstevel@tonic-gate 14080Sstevel@tonic-gate if (mrfp->mrf_nextp != NULL) { 14090Sstevel@tonic-gate /* XXX Do we bump a counter if copymsgchain() fails? */ 14100Sstevel@tonic-gate recv_bp = copymsgchain(bp); 14110Sstevel@tonic-gate } else { 14120Sstevel@tonic-gate recv_bp = bp; 14130Sstevel@tonic-gate } 14140Sstevel@tonic-gate if (recv_bp != NULL) 14150Sstevel@tonic-gate mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 14160Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 14170Sstevel@tonic-gate } while (mrfp != NULL); 14180Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 14190Sstevel@tonic-gate } 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate /* 14220Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 14230Sstevel@tonic-gate */ 14240Sstevel@tonic-gate mblk_t * 14250Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 14260Sstevel@tonic-gate { 14270Sstevel@tonic-gate mac_impl_t *mip = arg; 14280Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 14290Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate while (bp != NULL) { 14320Sstevel@tonic-gate next_bp = bp->b_next; 14330Sstevel@tonic-gate bp->b_next = NULL; 14340Sstevel@tonic-gate 14350Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 14360Sstevel@tonic-gate goto noresources; 14370Sstevel@tonic-gate 14382311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 14390Sstevel@tonic-gate ASSERT(resid_bp == bp); 14400Sstevel@tonic-gate freemsg(loop_bp); 14410Sstevel@tonic-gate goto noresources; 14420Sstevel@tonic-gate } 14430Sstevel@tonic-gate 14440Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 14450Sstevel@tonic-gate mtfp = mip->mi_mtfp; 144656Smeem while (mtfp != NULL && loop_bp != NULL) { 14470Sstevel@tonic-gate bp = loop_bp; 144856Smeem 144956Smeem /* XXX counter bump if copymsg() fails? */ 145056Smeem if (mtfp->mtf_nextp != NULL) 14510Sstevel@tonic-gate loop_bp = copymsg(bp); 145256Smeem else 145356Smeem loop_bp = NULL; 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 145656Smeem mtfp = mtfp->mtf_nextp; 14570Sstevel@tonic-gate } 145856Smeem rw_exit(&mip->mi_txloop_lock); 14590Sstevel@tonic-gate 146056Smeem /* 146156Smeem * It's possible we've raced with the disabling of promiscuous 146256Smeem * mode, in which case we can discard our copy. 146356Smeem */ 146456Smeem if (loop_bp != NULL) 146556Smeem freemsg(loop_bp); 146656Smeem 14670Sstevel@tonic-gate bp = next_bp; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate return (NULL); 14710Sstevel@tonic-gate 14720Sstevel@tonic-gate noresources: 14730Sstevel@tonic-gate bp->b_next = next_bp; 14740Sstevel@tonic-gate return (bp); 14750Sstevel@tonic-gate } 14760Sstevel@tonic-gate 14770Sstevel@tonic-gate void 14782311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 14790Sstevel@tonic-gate { 14802311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14810Sstevel@tonic-gate 14820Sstevel@tonic-gate /* 14830Sstevel@tonic-gate * Save the link state. 14840Sstevel@tonic-gate */ 14852311Sseb mip->mi_linkstate = link; 14860Sstevel@tonic-gate 14870Sstevel@tonic-gate /* 14880Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 14890Sstevel@tonic-gate */ 14900Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 14910Sstevel@tonic-gate } 14920Sstevel@tonic-gate 14930Sstevel@tonic-gate void 14942311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 14950Sstevel@tonic-gate { 14962311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 14970Sstevel@tonic-gate 14982311Sseb if (mip->mi_type->mt_addr_length == 0) 14992311Sseb return; 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate /* 15020Sstevel@tonic-gate * Save the address. 15030Sstevel@tonic-gate */ 15042311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate /* 15070Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 15080Sstevel@tonic-gate */ 15090Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 15100Sstevel@tonic-gate } 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate void 15132311Sseb mac_tx_update(mac_handle_t mh) 15140Sstevel@tonic-gate { 15150Sstevel@tonic-gate /* 15160Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 15170Sstevel@tonic-gate */ 15182311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 15190Sstevel@tonic-gate } 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate void 15222311Sseb mac_resource_update(mac_handle_t mh) 15230Sstevel@tonic-gate { 15240Sstevel@tonic-gate /* 15250Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 15260Sstevel@tonic-gate */ 15272311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 15280Sstevel@tonic-gate } 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate mac_resource_handle_t 15312311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 15320Sstevel@tonic-gate { 15332311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15340Sstevel@tonic-gate mac_resource_handle_t mrh; 15350Sstevel@tonic-gate mac_resource_add_t add; 15360Sstevel@tonic-gate void *arg; 15370Sstevel@tonic-gate 15380Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 15390Sstevel@tonic-gate add = mip->mi_resource_add; 15400Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 15410Sstevel@tonic-gate 15421184Skrgopi if (add != NULL) 15431184Skrgopi mrh = add(arg, mrp); 15441184Skrgopi else 15451184Skrgopi mrh = NULL; 15460Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate return (mrh); 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate 15512311Sseb int 15522311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 15532311Sseb { 15542311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15552311Sseb 15562311Sseb /* 15572311Sseb * Verify that the plugin supports MAC plugin data and that the 15582311Sseb * supplied data is valid. 15592311Sseb */ 15602311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 15612311Sseb return (EINVAL); 15622311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 15632311Sseb return (EINVAL); 15642311Sseb 15652311Sseb if (mip->mi_pdata != NULL) 15662311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 15672311Sseb 15682311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 15692311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 15702311Sseb mip->mi_pdata_size = dsize; 15712311Sseb 15722311Sseb /* 15732311Sseb * Since the MAC plugin data is used to construct MAC headers that 15742311Sseb * were cached in fast-path headers, we need to flush fast-path 15752311Sseb * information for links associated with this mac. 15762311Sseb */ 15772311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 15782311Sseb return (0); 15792311Sseb } 15802311Sseb 15810Sstevel@tonic-gate void 15822311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 15830Sstevel@tonic-gate boolean_t add) 15840Sstevel@tonic-gate { 15852311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 15860Sstevel@tonic-gate mac_multicst_addr_t *p; 15870Sstevel@tonic-gate 15880Sstevel@tonic-gate /* 15890Sstevel@tonic-gate * If no specific refresh function was given then default to the 15900Sstevel@tonic-gate * driver's m_multicst entry point. 15910Sstevel@tonic-gate */ 15920Sstevel@tonic-gate if (refresh == NULL) { 15932311Sseb refresh = mip->mi_multicst; 15942311Sseb arg = mip->mi_driver; 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate ASSERT(refresh != NULL); 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate /* 15990Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 16000Sstevel@tonic-gate * each address. 16010Sstevel@tonic-gate */ 16020Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 16030Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 16040Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 16050Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 16060Sstevel@tonic-gate } 16070Sstevel@tonic-gate 16080Sstevel@tonic-gate void 16092311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 16100Sstevel@tonic-gate { 16112311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16120Sstevel@tonic-gate /* 16130Sstevel@tonic-gate * If no specific refresh function was given then default to the 16142311Sseb * driver's mi_unicst entry point. 16150Sstevel@tonic-gate */ 16160Sstevel@tonic-gate if (refresh == NULL) { 16172311Sseb refresh = mip->mi_unicst; 16182311Sseb arg = mip->mi_driver; 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate ASSERT(refresh != NULL); 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate /* 16230Sstevel@tonic-gate * Call the refresh function with the current unicast address. 16240Sstevel@tonic-gate */ 16250Sstevel@tonic-gate refresh(arg, mip->mi_addr); 16260Sstevel@tonic-gate } 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate void 16292311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 16300Sstevel@tonic-gate { 16312311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate /* 16340Sstevel@tonic-gate * If no specific refresh function was given then default to the 16350Sstevel@tonic-gate * driver's m_promisc entry point. 16360Sstevel@tonic-gate */ 16370Sstevel@tonic-gate if (refresh == NULL) { 16382311Sseb refresh = mip->mi_setpromisc; 16392311Sseb arg = mip->mi_driver; 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate ASSERT(refresh != NULL); 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate /* 16440Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 16450Sstevel@tonic-gate */ 16460Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 16470Sstevel@tonic-gate } 16480Sstevel@tonic-gate 16490Sstevel@tonic-gate boolean_t 16500Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 16510Sstevel@tonic-gate { 16520Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16550Sstevel@tonic-gate if (mip->mi_activelink) { 16560Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16570Sstevel@tonic-gate return (B_FALSE); 16580Sstevel@tonic-gate } 16590Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 16600Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16610Sstevel@tonic-gate return (B_TRUE); 16620Sstevel@tonic-gate } 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate void 16650Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 16660Sstevel@tonic-gate { 16670Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 16700Sstevel@tonic-gate ASSERT(mip->mi_activelink); 16710Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 16720Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 16730Sstevel@tonic-gate } 1674269Sericheng 1675269Sericheng /* 1676269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1677269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1678269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1679269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1680269Sericheng * cannot disappear while we are accessing it. 1681269Sericheng */ 1682269Sericheng typedef struct i_mac_info_state_s { 1683269Sericheng const char *mi_name; 1684269Sericheng mac_info_t *mi_infop; 1685269Sericheng } i_mac_info_state_t; 1686269Sericheng 1687269Sericheng /*ARGSUSED*/ 1688269Sericheng static uint_t 1689269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1690269Sericheng { 1691269Sericheng i_mac_info_state_t *statep = arg; 1692269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 1693269Sericheng 16941852Syz147064 if (mip->mi_disabled) 1695269Sericheng return (MH_WALK_CONTINUE); 1696269Sericheng 1697269Sericheng if (strcmp(statep->mi_name, 16982311Sseb ddi_driver_name(mip->mi_dip)) != 0) 1699269Sericheng return (MH_WALK_CONTINUE); 1700269Sericheng 17012311Sseb statep->mi_infop = &mip->mi_info; 1702269Sericheng return (MH_WALK_TERMINATE); 1703269Sericheng } 1704269Sericheng 1705269Sericheng boolean_t 1706269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 1707269Sericheng { 1708269Sericheng i_mac_info_state_t state; 1709269Sericheng 1710269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 1711269Sericheng state.mi_name = name; 1712269Sericheng state.mi_infop = NULL; 1713269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1714269Sericheng if (state.mi_infop == NULL) { 1715269Sericheng rw_exit(&i_mac_impl_lock); 1716269Sericheng return (B_FALSE); 1717269Sericheng } 1718269Sericheng *minfop = *state.mi_infop; 1719269Sericheng rw_exit(&i_mac_impl_lock); 1720269Sericheng return (B_TRUE); 1721269Sericheng } 1722269Sericheng 17232311Sseb boolean_t 17242311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 17252311Sseb { 17262311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17272311Sseb 17282311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 17292311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 17302311Sseb else 17312311Sseb return (B_FALSE); 17322311Sseb } 17332311Sseb 17342311Sseb boolean_t 17352311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 17362311Sseb { 17372311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17382311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 17392311Sseb mip->mi_pdata)); 17402311Sseb } 17412311Sseb 17422311Sseb mblk_t * 17432311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 17442311Sseb size_t extra_len) 17452311Sseb { 17462311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17472311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 17482311Sseb mip->mi_pdata, payload, extra_len)); 17492311Sseb } 17502311Sseb 17512311Sseb int 17522311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 17532311Sseb { 17542311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17552311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 17562311Sseb mhip)); 17572311Sseb } 17582311Sseb 17592311Sseb mblk_t * 17602311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 17612311Sseb { 17622311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17632311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 17642311Sseb if (DB_REF(mp) > 1) { 17652311Sseb mblk_t *newmp = copymsg(mp); 17662760Sdg199075 if (newmp == NULL) 17672760Sdg199075 return (NULL); 17682311Sseb freemsg(mp); 17692311Sseb mp = newmp; 17702311Sseb } 17712311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 17722311Sseb mip->mi_pdata)); 17732311Sseb } 17742311Sseb return (mp); 17752311Sseb } 17762311Sseb 17772311Sseb mblk_t * 17782311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 17792311Sseb { 17802311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17812311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 17822311Sseb if (DB_REF(mp) > 1) { 17832311Sseb mblk_t *newmp = copymsg(mp); 17842760Sdg199075 if (newmp == NULL) 17852760Sdg199075 return (NULL); 17862311Sseb freemsg(mp); 17872311Sseb mp = newmp; 17882311Sseb } 17892311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 17902311Sseb mip->mi_pdata)); 17912311Sseb } 17922311Sseb return (mp); 17932311Sseb } 17942311Sseb 1795269Sericheng void 1796269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 1797269Sericheng { 1798269Sericheng dld_init_ops(ops, name); 1799269Sericheng } 1800269Sericheng 1801269Sericheng void 1802269Sericheng mac_fini_ops(struct dev_ops *ops) 1803269Sericheng { 1804269Sericheng dld_fini_ops(ops); 1805269Sericheng } 18062311Sseb 18072311Sseb /* 18082311Sseb * MAC Type Plugin functions. 18092311Sseb */ 18102311Sseb 18112311Sseb mactype_register_t * 18122311Sseb mactype_alloc(uint_t mactype_version) 18132311Sseb { 18142311Sseb mactype_register_t *mtrp; 18152311Sseb 18162311Sseb /* 18172311Sseb * Make sure there isn't a version mismatch between the plugin and 18182311Sseb * the framework. In the future, if multiple versions are 18192311Sseb * supported, this check could become more sophisticated. 18202311Sseb */ 18212311Sseb if (mactype_version != MACTYPE_VERSION) 18222311Sseb return (NULL); 18232311Sseb 18242311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 18252311Sseb mtrp->mtr_version = mactype_version; 18262311Sseb return (mtrp); 18272311Sseb } 18282311Sseb 18292311Sseb void 18302311Sseb mactype_free(mactype_register_t *mtrp) 18312311Sseb { 18322311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 18332311Sseb } 18342311Sseb 18352311Sseb int 18362311Sseb mactype_register(mactype_register_t *mtrp) 18372311Sseb { 18382311Sseb mactype_t *mtp; 18392311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 18402311Sseb 18412311Sseb /* Do some sanity checking before we register this MAC type. */ 18422311Sseb if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 18432311Sseb return (EINVAL); 18442311Sseb 18452311Sseb /* 18462311Sseb * Verify that all mandatory callbacks are set in the ops 18472311Sseb * vector. 18482311Sseb */ 18492311Sseb if (ops->mtops_unicst_verify == NULL || 18502311Sseb ops->mtops_multicst_verify == NULL || 18512311Sseb ops->mtops_sap_verify == NULL || 18522311Sseb ops->mtops_header == NULL || 18532311Sseb ops->mtops_header_info == NULL) { 18542311Sseb return (EINVAL); 18552311Sseb } 18562311Sseb 18572311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 18582311Sseb mtp->mt_ident = mtrp->mtr_ident; 18592311Sseb mtp->mt_ops = *ops; 18602311Sseb mtp->mt_type = mtrp->mtr_mactype; 18613147Sxc151355 mtp->mt_nativetype = mtrp->mtr_nativetype; 18622311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 18632311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 18642311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 18652311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 18662311Sseb mtrp->mtr_addrlen); 18672311Sseb } 18682311Sseb 18692311Sseb mtp->mt_stats = mtrp->mtr_stats; 18702311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 18712311Sseb 18722311Sseb if (mod_hash_insert(i_mactype_hash, 18732311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 18742311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 18752311Sseb kmem_free(mtp, sizeof (*mtp)); 18762311Sseb return (EEXIST); 18772311Sseb } 18782311Sseb return (0); 18792311Sseb } 18802311Sseb 18812311Sseb int 18822311Sseb mactype_unregister(const char *ident) 18832311Sseb { 18842311Sseb mactype_t *mtp; 18852311Sseb mod_hash_val_t val; 18862311Sseb int err; 18872311Sseb 18882311Sseb /* 18892311Sseb * Let's not allow MAC drivers to use this plugin while we're 18903288Sseb * trying to unregister it. Holding i_mactype_lock also prevents a 18913288Sseb * plugin from unregistering while a MAC driver is attempting to 18923288Sseb * hold a reference to it in i_mactype_getplugin(). 18932311Sseb */ 18943288Sseb mutex_enter(&i_mactype_lock); 18952311Sseb 18962311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 18972311Sseb (mod_hash_val_t *)&mtp)) != 0) { 18982311Sseb /* A plugin is trying to unregister, but it never registered. */ 18993288Sseb err = ENXIO; 19003288Sseb goto done; 19012311Sseb } 19022311Sseb 19033288Sseb if (mtp->mt_ref != 0) { 19043288Sseb err = EBUSY; 19053288Sseb goto done; 19062311Sseb } 19072311Sseb 19082311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 19092311Sseb ASSERT(err == 0); 19102311Sseb if (err != 0) { 19112311Sseb /* This should never happen, thus the ASSERT() above. */ 19123288Sseb err = EINVAL; 19133288Sseb goto done; 19142311Sseb } 19152311Sseb ASSERT(mtp == (mactype_t *)val); 19162311Sseb 19172311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 19182311Sseb kmem_free(mtp, sizeof (mactype_t)); 19193288Sseb done: 19203288Sseb mutex_exit(&i_mactype_lock); 19213288Sseb return (err); 19222311Sseb } 19233448Sdh155122 19243448Sdh155122 int 19253448Sdh155122 mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor) 19263448Sdh155122 { 19273448Sdh155122 mac_impl_t *mip = (mac_impl_t *)mh; 19283448Sdh155122 19293448Sdh155122 /* Create a style-1 DLPI device */ 19303448Sdh155122 if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor, 19313448Sdh155122 DDI_NT_NET, 0) != DDI_SUCCESS) { 19323448Sdh155122 return (-1); 19333448Sdh155122 } 19343448Sdh155122 return (0); 19353448Sdh155122 } 19363448Sdh155122 19373448Sdh155122 void 19383448Sdh155122 mac_vlan_remove(mac_handle_t mh, const char *name) 19393448Sdh155122 { 19403448Sdh155122 mac_impl_t *mip = (mac_impl_t *)mh; 19413448Sdh155122 dev_info_t *dipp; 19423448Sdh155122 19433448Sdh155122 ddi_remove_minor_node(mip->mi_dip, (char *)name); 19443448Sdh155122 dipp = ddi_get_parent(mip->mi_dip); 19453448Sdh155122 (void) devfs_clean(dipp, NULL, 0); 19463448Sdh155122 } 1947