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> 47*4913Sethindra #include <sys/sdt.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */ 500Sstevel@tonic-gate 510Sstevel@tonic-gate static kmem_cache_t *i_mac_impl_cachep; 52269Sericheng static mod_hash_t *i_mac_impl_hash; 53269Sericheng krwlock_t i_mac_impl_lock; 54269Sericheng uint_t i_mac_impl_count; 550Sstevel@tonic-gate 562311Sseb #define MACTYPE_KMODDIR "mac" 572311Sseb #define MACTYPE_HASHSZ 67 582311Sseb static mod_hash_t *i_mactype_hash; 593288Sseb /* 603288Sseb * i_mactype_lock synchronizes threads that obtain references to mactype_t 613288Sseb * structures through i_mactype_getplugin(). 623288Sseb */ 633288Sseb static kmutex_t i_mactype_lock; 642311Sseb 651852Syz147064 static void i_mac_notify_task(void *); 661852Syz147064 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * Private functions. 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate 710Sstevel@tonic-gate /*ARGSUSED*/ 720Sstevel@tonic-gate static int 730Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag) 740Sstevel@tonic-gate { 750Sstevel@tonic-gate mac_impl_t *mip = buf; 760Sstevel@tonic-gate 770Sstevel@tonic-gate bzero(buf, sizeof (mac_impl_t)); 780Sstevel@tonic-gate 792311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 800Sstevel@tonic-gate 810Sstevel@tonic-gate rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 820Sstevel@tonic-gate rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 830Sstevel@tonic-gate rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 840Sstevel@tonic-gate rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 850Sstevel@tonic-gate rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 860Sstevel@tonic-gate rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 870Sstevel@tonic-gate mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 881852Syz147064 mutex_init(&mip->mi_notify_ref_lock, NULL, MUTEX_DRIVER, NULL); 891852Syz147064 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 90*4913Sethindra mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL); 91*4913Sethindra cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL); 920Sstevel@tonic-gate return (0); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate /*ARGSUSED*/ 960Sstevel@tonic-gate static void 970Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg) 980Sstevel@tonic-gate { 990Sstevel@tonic-gate mac_impl_t *mip = buf; 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 1020Sstevel@tonic-gate ASSERT(mip->mi_active == 0); 1032311Sseb ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 1040Sstevel@tonic-gate ASSERT(mip->mi_devpromisc == 0); 1050Sstevel@tonic-gate ASSERT(mip->mi_promisc == 0); 1060Sstevel@tonic-gate ASSERT(mip->mi_mmap == NULL); 1070Sstevel@tonic-gate ASSERT(mip->mi_mnfp == NULL); 1080Sstevel@tonic-gate ASSERT(mip->mi_resource_add == NULL); 1090Sstevel@tonic-gate ASSERT(mip->mi_ksp == NULL); 1102311Sseb ASSERT(mip->mi_kstat_count == 0); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate rw_destroy(&mip->mi_state_lock); 1130Sstevel@tonic-gate rw_destroy(&mip->mi_data_lock); 1140Sstevel@tonic-gate rw_destroy(&mip->mi_notify_lock); 1150Sstevel@tonic-gate rw_destroy(&mip->mi_rx_lock); 1160Sstevel@tonic-gate rw_destroy(&mip->mi_txloop_lock); 1170Sstevel@tonic-gate rw_destroy(&mip->mi_resource_lock); 1180Sstevel@tonic-gate mutex_destroy(&mip->mi_activelink_lock); 1191852Syz147064 mutex_destroy(&mip->mi_notify_ref_lock); 1201852Syz147064 cv_destroy(&mip->mi_notify_cv); 121*4913Sethindra mutex_destroy(&mip->mi_lock); 122*4913Sethindra cv_destroy(&mip->mi_rx_cv); 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate static void 1260Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 1270Sstevel@tonic-gate { 1281852Syz147064 mac_notify_task_arg_t *mnta; 1291852Syz147064 1301852Syz147064 rw_enter(&i_mac_impl_lock, RW_READER); 1311852Syz147064 if (mip->mi_disabled) 1321852Syz147064 goto exit; 1331852Syz147064 1341852Syz147064 if ((mnta = kmem_alloc(sizeof (*mnta), KM_NOSLEEP)) == NULL) { 1351852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): memory " 1361852Syz147064 "allocation failed", mip->mi_name, type); 1371852Syz147064 goto exit; 1381852Syz147064 } 1391852Syz147064 1401852Syz147064 mnta->mnt_mip = mip; 1411852Syz147064 mnta->mnt_type = type; 1421852Syz147064 1431852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1441852Syz147064 mip->mi_notify_ref++; 1451852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1461852Syz147064 1471852Syz147064 rw_exit(&i_mac_impl_lock); 1481852Syz147064 1491852Syz147064 if (taskq_dispatch(system_taskq, i_mac_notify_task, mnta, 1501852Syz147064 TQ_NOSLEEP) == NULL) { 1511852Syz147064 cmn_err(CE_WARN, "i_mac_notify(%s, 0x%x): taskq dispatch " 1521852Syz147064 "failed", mip->mi_name, type); 1531852Syz147064 1541852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 1551852Syz147064 if (--mip->mi_notify_ref == 0) 1561852Syz147064 cv_signal(&mip->mi_notify_cv); 1571852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 1581852Syz147064 1591852Syz147064 kmem_free(mnta, sizeof (*mnta)); 1601852Syz147064 } 1611852Syz147064 return; 1621852Syz147064 1631852Syz147064 exit: 1641852Syz147064 rw_exit(&i_mac_impl_lock); 1651852Syz147064 } 1661852Syz147064 1671852Syz147064 static void 1684403Sgd78059 i_mac_log_link_state(mac_impl_t *mip) 1694403Sgd78059 { 1704403Sgd78059 /* 1714403Sgd78059 * If no change, then it is not interesting. 1724403Sgd78059 */ 1734403Sgd78059 if (mip->mi_lastlinkstate == mip->mi_linkstate) 1744403Sgd78059 return; 1754403Sgd78059 1764403Sgd78059 switch (mip->mi_linkstate) { 1774403Sgd78059 case LINK_STATE_UP: 1784403Sgd78059 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) { 1794403Sgd78059 char det[200]; 1804403Sgd78059 1814403Sgd78059 mip->mi_type->mt_ops.mtops_link_details(det, 1824403Sgd78059 sizeof (det), (mac_handle_t)mip, mip->mi_pdata); 1834403Sgd78059 1844403Sgd78059 cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det); 1854403Sgd78059 } else { 1864403Sgd78059 cmn_err(CE_NOTE, "!%s link up", mip->mi_name); 1874403Sgd78059 } 1884403Sgd78059 break; 1894403Sgd78059 1904403Sgd78059 case LINK_STATE_DOWN: 1914403Sgd78059 /* 1924403Sgd78059 * Only transitions from UP to DOWN are interesting 1934403Sgd78059 */ 1944403Sgd78059 if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN) 1954403Sgd78059 cmn_err(CE_NOTE, "!%s link down", mip->mi_name); 1964403Sgd78059 break; 1974403Sgd78059 1984403Sgd78059 case LINK_STATE_UNKNOWN: 1994403Sgd78059 /* 2004403Sgd78059 * This case is normally not interesting. 2014403Sgd78059 */ 2024403Sgd78059 break; 2034403Sgd78059 } 2044403Sgd78059 mip->mi_lastlinkstate = mip->mi_linkstate; 2054403Sgd78059 } 2064403Sgd78059 2074403Sgd78059 static void 2081852Syz147064 i_mac_notify_task(void *notify_arg) 2091852Syz147064 { 2101852Syz147064 mac_notify_task_arg_t *mnta = (mac_notify_task_arg_t *)notify_arg; 2111852Syz147064 mac_impl_t *mip; 2121852Syz147064 mac_notify_type_t type; 2130Sstevel@tonic-gate mac_notify_fn_t *mnfp; 2140Sstevel@tonic-gate mac_notify_t notify; 2150Sstevel@tonic-gate void *arg; 2160Sstevel@tonic-gate 2171852Syz147064 mip = mnta->mnt_mip; 2181852Syz147064 type = mnta->mnt_type; 2191852Syz147064 kmem_free(mnta, sizeof (*mnta)); 2201852Syz147064 2210Sstevel@tonic-gate /* 2224403Sgd78059 * Log it. 2234403Sgd78059 */ 2244403Sgd78059 if (type == MAC_NOTE_LINK) 2254403Sgd78059 i_mac_log_link_state(mip); 2264403Sgd78059 2274403Sgd78059 /* 2280Sstevel@tonic-gate * Walk the list of notifications. 2290Sstevel@tonic-gate */ 2301852Syz147064 rw_enter(&mip->mi_notify_lock, RW_READER); 2310Sstevel@tonic-gate for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 2320Sstevel@tonic-gate notify = mnfp->mnf_fn; 2330Sstevel@tonic-gate arg = mnfp->mnf_arg; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate ASSERT(notify != NULL); 2360Sstevel@tonic-gate notify(arg, type); 2370Sstevel@tonic-gate } 2381852Syz147064 rw_exit(&mip->mi_notify_lock); 2391852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 2401852Syz147064 if (--mip->mi_notify_ref == 0) 2411852Syz147064 cv_signal(&mip->mi_notify_cv); 2421852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2452311Sseb static mactype_t * 2463288Sseb i_mactype_getplugin(const char *pname) 2472311Sseb { 2482311Sseb mactype_t *mtype = NULL; 2492311Sseb boolean_t tried_modload = B_FALSE; 2502311Sseb 2513288Sseb mutex_enter(&i_mactype_lock); 2523288Sseb 2532311Sseb find_registered_mactype: 2543288Sseb if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname, 2553288Sseb (mod_hash_val_t *)&mtype) != 0) { 2563288Sseb if (!tried_modload) { 2573288Sseb /* 2583288Sseb * If the plugin has not yet been loaded, then 2593288Sseb * attempt to load it now. If modload() succeeds, 2603288Sseb * the plugin should have registered using 2613288Sseb * mactype_register(), in which case we can go back 2623288Sseb * and attempt to find it again. 2633288Sseb */ 2643288Sseb if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) { 2653288Sseb tried_modload = B_TRUE; 2663288Sseb goto find_registered_mactype; 2673288Sseb } 2683288Sseb } 2693288Sseb } else { 2702311Sseb /* 2713288Sseb * Note that there's no danger that the plugin we've loaded 2723288Sseb * could be unloaded between the modload() step and the 2733288Sseb * reference count bump here, as we're holding 2743288Sseb * i_mactype_lock, which mactype_unregister() also holds. 2752311Sseb */ 2763288Sseb atomic_inc_32(&mtype->mt_ref); 2772311Sseb } 2782311Sseb 2793288Sseb mutex_exit(&i_mactype_lock); 2803288Sseb return (mtype); 2812311Sseb } 2822311Sseb 2830Sstevel@tonic-gate /* 2840Sstevel@tonic-gate * Module initialization functions. 2850Sstevel@tonic-gate */ 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate void 2880Sstevel@tonic-gate mac_init(void) 2890Sstevel@tonic-gate { 2900Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 2912311Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 2922311Sseb NULL, NULL, NULL, 0); 2930Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL); 2940Sstevel@tonic-gate 295269Sericheng i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 296269Sericheng IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 297269Sericheng mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 298269Sericheng rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 299269Sericheng i_mac_impl_count = 0; 3002311Sseb 3012311Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash", 3022311Sseb MACTYPE_HASHSZ, 3032311Sseb mod_hash_null_keydtor, mod_hash_null_valdtor, 3042311Sseb mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate int 3080Sstevel@tonic-gate mac_fini(void) 3090Sstevel@tonic-gate { 310269Sericheng if (i_mac_impl_count > 0) 311269Sericheng return (EBUSY); 3120Sstevel@tonic-gate 313269Sericheng mod_hash_destroy_hash(i_mac_impl_hash); 314269Sericheng rw_destroy(&i_mac_impl_lock); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate kmem_cache_destroy(i_mac_impl_cachep); 3172311Sseb 3182311Sseb mod_hash_destroy_hash(i_mactype_hash); 3190Sstevel@tonic-gate return (0); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Client functions. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate int 3272311Sseb mac_open(const char *macname, uint_t ddi_instance, mac_handle_t *mhp) 3280Sstevel@tonic-gate { 3290Sstevel@tonic-gate char driver[MAXNAMELEN]; 3300Sstevel@tonic-gate uint_t instance; 3310Sstevel@tonic-gate major_t major; 3320Sstevel@tonic-gate dev_info_t *dip; 3330Sstevel@tonic-gate mac_impl_t *mip; 3340Sstevel@tonic-gate int err; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our 3380Sstevel@tonic-gate * buffer. 3390Sstevel@tonic-gate */ 3402311Sseb if (strlen(macname) >= MAXNAMELEN) 3410Sstevel@tonic-gate return (EINVAL); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * Split the device name into driver and instance components. 3450Sstevel@tonic-gate */ 3462311Sseb if (ddi_parse(macname, driver, &instance) != DDI_SUCCESS) 3470Sstevel@tonic-gate return (EINVAL); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * Get the major number of the driver. 3510Sstevel@tonic-gate */ 3520Sstevel@tonic-gate if ((major = ddi_name_to_major(driver)) == (major_t)-1) 3530Sstevel@tonic-gate return (EINVAL); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * Hold the given instance to prevent it from being detached. 357269Sericheng * This will also attach the instance if it is not currently attached. 358269Sericheng * Currently we ensure that mac_register() (called by the driver's 359269Sericheng * attach entry point) and all code paths under it cannot possibly 360269Sericheng * call mac_open() because this would lead to a recursive attach 361269Sericheng * panic. 3620Sstevel@tonic-gate */ 3632311Sseb if ((dip = ddi_hold_devi_by_instance(major, ddi_instance, 0)) == NULL) 3640Sstevel@tonic-gate return (EINVAL); 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* 3670Sstevel@tonic-gate * Look up its entry in the global hash table. 3680Sstevel@tonic-gate */ 3690Sstevel@tonic-gate again: 370269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 3712311Sseb err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 372269Sericheng (mod_hash_val_t *)&mip); 373269Sericheng if (err != 0) { 374269Sericheng err = ENOENT; 3750Sstevel@tonic-gate goto failed; 376269Sericheng } 3770Sstevel@tonic-gate 3781852Syz147064 if (mip->mi_disabled) { 379269Sericheng rw_exit(&i_mac_impl_lock); 3800Sstevel@tonic-gate goto again; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate mip->mi_ref++; 384269Sericheng rw_exit(&i_mac_impl_lock); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate *mhp = (mac_handle_t)mip; 3870Sstevel@tonic-gate return (0); 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate failed: 390269Sericheng rw_exit(&i_mac_impl_lock); 3910Sstevel@tonic-gate ddi_release_devi(dip); 3920Sstevel@tonic-gate return (err); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate void 3960Sstevel@tonic-gate mac_close(mac_handle_t mh) 3970Sstevel@tonic-gate { 3980Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 3992311Sseb dev_info_t *dip = mip->mi_dip; 4000Sstevel@tonic-gate 401269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate ASSERT(mip->mi_ref != 0); 4040Sstevel@tonic-gate if (--mip->mi_ref == 0) { 4050Sstevel@tonic-gate ASSERT(!mip->mi_activelink); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate ddi_release_devi(dip); 408269Sericheng rw_exit(&i_mac_impl_lock); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate const mac_info_t * 4120Sstevel@tonic-gate mac_info(mac_handle_t mh) 4130Sstevel@tonic-gate { 4142311Sseb return (&((mac_impl_t *)mh)->mi_info); 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate 417269Sericheng dev_info_t * 418269Sericheng mac_devinfo_get(mac_handle_t mh) 419269Sericheng { 4202311Sseb return (((mac_impl_t *)mh)->mi_dip); 421269Sericheng } 422269Sericheng 4230Sstevel@tonic-gate uint64_t 4242311Sseb mac_stat_get(mac_handle_t mh, uint_t stat) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4272311Sseb uint64_t val; 4282311Sseb int ret; 4290Sstevel@tonic-gate 4302311Sseb /* 4312311Sseb * The range of stat determines where it is maintained. Stat 4322311Sseb * values from 0 up to (but not including) MAC_STAT_MIN are 4332311Sseb * mainteined by the mac module itself. Everything else is 4342311Sseb * maintained by the driver. 4352311Sseb */ 4362311Sseb if (stat < MAC_STAT_MIN) { 4372311Sseb /* These stats are maintained by the mac module itself. */ 4382311Sseb switch (stat) { 4392311Sseb case MAC_STAT_LINK_STATE: 4402311Sseb return (mip->mi_linkstate); 4412311Sseb case MAC_STAT_LINK_UP: 4422311Sseb return (mip->mi_linkstate == LINK_STATE_UP); 4432311Sseb case MAC_STAT_PROMISC: 4442311Sseb return (mip->mi_devpromisc != 0); 4452311Sseb default: 4462311Sseb ASSERT(B_FALSE); 4472311Sseb } 4482311Sseb } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate /* 4510Sstevel@tonic-gate * Call the driver to get the given statistic. 4520Sstevel@tonic-gate */ 4532311Sseb ret = mip->mi_getstat(mip->mi_driver, stat, &val); 4542311Sseb if (ret != 0) { 4552311Sseb /* 4562311Sseb * The driver doesn't support this statistic. Get the 4572311Sseb * statistic's default value. 4582311Sseb */ 4592311Sseb val = mac_stat_default(mip, stat); 4602311Sseb } 4612311Sseb return (val); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate int 4650Sstevel@tonic-gate mac_start(mac_handle_t mh) 4660Sstevel@tonic-gate { 4670Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 4680Sstevel@tonic-gate int err; 4690Sstevel@tonic-gate 4702311Sseb ASSERT(mip->mi_start != NULL); 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* 4750Sstevel@tonic-gate * Check whether the device is already started. 4760Sstevel@tonic-gate */ 4770Sstevel@tonic-gate if (mip->mi_active++ != 0) { 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * It's already started so there's nothing more to do. 4800Sstevel@tonic-gate */ 4810Sstevel@tonic-gate err = 0; 4820Sstevel@tonic-gate goto done; 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4860Sstevel@tonic-gate * Start the device. 4870Sstevel@tonic-gate */ 4882311Sseb if ((err = mip->mi_start(mip->mi_driver)) != 0) 4890Sstevel@tonic-gate --mip->mi_active; 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate done: 4920Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 4930Sstevel@tonic-gate return (err); 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate void 4970Sstevel@tonic-gate mac_stop(mac_handle_t mh) 4980Sstevel@tonic-gate { 4990Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5000Sstevel@tonic-gate 5012311Sseb ASSERT(mip->mi_stop != NULL); 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate /* 5060Sstevel@tonic-gate * Check whether the device is still needed. 5070Sstevel@tonic-gate */ 5080Sstevel@tonic-gate ASSERT(mip->mi_active != 0); 5090Sstevel@tonic-gate if (--mip->mi_active != 0) { 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * It's still needed so there's nothing more to do. 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate goto done; 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* 5170Sstevel@tonic-gate * Stop the device. 5180Sstevel@tonic-gate */ 5192311Sseb mip->mi_stop(mip->mi_driver); 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate done: 5220Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate int 5260Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 5270Sstevel@tonic-gate { 5280Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5290Sstevel@tonic-gate mac_multicst_addr_t **pp; 5300Sstevel@tonic-gate mac_multicst_addr_t *p; 5310Sstevel@tonic-gate int err; 5320Sstevel@tonic-gate 5332311Sseb ASSERT(mip->mi_multicst != NULL); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate /* 5360Sstevel@tonic-gate * Verify the address. 5370Sstevel@tonic-gate */ 5382311Sseb if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 5392311Sseb mip->mi_pdata)) != 0) { 5402311Sseb return (err); 5412311Sseb } 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * Check whether the given address is already enabled. 5450Sstevel@tonic-gate */ 5460Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 5470Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 5482311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 5492311Sseb 0) { 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * The address is already enabled so just bump the 5520Sstevel@tonic-gate * reference count. 5530Sstevel@tonic-gate */ 5540Sstevel@tonic-gate p->mma_ref++; 5550Sstevel@tonic-gate err = 0; 5560Sstevel@tonic-gate goto done; 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate } 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * Allocate a new list entry. 5620Sstevel@tonic-gate */ 5630Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 5640Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 5650Sstevel@tonic-gate err = ENOMEM; 5660Sstevel@tonic-gate goto done; 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * Enable a new multicast address. 5710Sstevel@tonic-gate */ 5722311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 5730Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 5740Sstevel@tonic-gate goto done; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * Add the address to the list of enabled addresses. 5790Sstevel@tonic-gate */ 5802311Sseb bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 5810Sstevel@tonic-gate p->mma_ref++; 5820Sstevel@tonic-gate *pp = p; 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate done: 5850Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 5860Sstevel@tonic-gate return (err); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate int 5900Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5930Sstevel@tonic-gate mac_multicst_addr_t **pp; 5940Sstevel@tonic-gate mac_multicst_addr_t *p; 5950Sstevel@tonic-gate int err; 5960Sstevel@tonic-gate 5972311Sseb ASSERT(mip->mi_multicst != NULL); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * Find the entry in the list for the given address. 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6030Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 6042311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 6052311Sseb 0) { 6060Sstevel@tonic-gate if (--p->mma_ref == 0) 6070Sstevel@tonic-gate break; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate /* 6100Sstevel@tonic-gate * There is still a reference to this address so 6110Sstevel@tonic-gate * there's nothing more to do. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate err = 0; 6140Sstevel@tonic-gate goto done; 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate /* 6190Sstevel@tonic-gate * We did not find an entry for the given address so it is not 6200Sstevel@tonic-gate * currently enabled. 6210Sstevel@tonic-gate */ 6220Sstevel@tonic-gate if (p == NULL) { 6230Sstevel@tonic-gate err = ENOENT; 6240Sstevel@tonic-gate goto done; 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate ASSERT(p->mma_ref == 0); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * Disable the multicast address. 6300Sstevel@tonic-gate */ 6312311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 6320Sstevel@tonic-gate p->mma_ref++; 6330Sstevel@tonic-gate goto done; 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate /* 6370Sstevel@tonic-gate * Remove it from the list. 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate *pp = p->mma_nextp; 6400Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate done: 6430Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 6440Sstevel@tonic-gate return (err); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6472331Skrgopi /* 6482331Skrgopi * mac_unicst_verify: Verifies the passed address. It fails 6492331Skrgopi * if the passed address is a group address or has incorrect length. 6502331Skrgopi */ 6512331Skrgopi boolean_t 6522331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 6532331Skrgopi { 6542331Skrgopi mac_impl_t *mip = (mac_impl_t *)mh; 6552331Skrgopi 6562331Skrgopi /* 6572331Skrgopi * Verify the address. 6582331Skrgopi */ 6592331Skrgopi if ((len != mip->mi_type->mt_addr_length) || 6602331Skrgopi (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6612331Skrgopi mip->mi_pdata)) != 0) { 6622331Skrgopi return (B_FALSE); 6632331Skrgopi } else { 6642331Skrgopi return (B_TRUE); 6652331Skrgopi } 6662331Skrgopi } 6672331Skrgopi 6680Sstevel@tonic-gate int 6690Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 6700Sstevel@tonic-gate { 6710Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6720Sstevel@tonic-gate int err; 6730Sstevel@tonic-gate boolean_t notify = B_FALSE; 6740Sstevel@tonic-gate 6752311Sseb ASSERT(mip->mi_unicst != NULL); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * Verify the address. 6790Sstevel@tonic-gate */ 6802311Sseb if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 6812311Sseb mip->mi_pdata)) != 0) { 6822311Sseb return (err); 6832311Sseb } 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Program the new unicast address. 6870Sstevel@tonic-gate */ 6880Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * If address doesn't change, do nothing. 6920Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 6930Sstevel@tonic-gate * recursively. 6940Sstevel@tonic-gate */ 6952311Sseb if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) { 6960Sstevel@tonic-gate err = 0; 6970Sstevel@tonic-gate goto done; 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7002311Sseb if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 7010Sstevel@tonic-gate goto done; 7020Sstevel@tonic-gate 7030Sstevel@tonic-gate /* 7040Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 7050Sstevel@tonic-gate */ 7062311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 7070Sstevel@tonic-gate notify = B_TRUE; 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate done: 7100Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate if (notify) 7130Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate return (err); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate void 7190Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate /* 7242311Sseb * Copy out the current unicast source address. 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 7272311Sseb bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 7282311Sseb rw_exit(&(mip->mi_data_lock)); 7292311Sseb } 7302311Sseb 7312311Sseb void 7322311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr) 7332311Sseb { 7342311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 7352311Sseb 7362311Sseb /* 7372311Sseb * Copy out the current destination address. 7382311Sseb */ 7392311Sseb rw_enter(&(mip->mi_data_lock), RW_READER); 7402311Sseb bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 7410Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate int 7450Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 7460Sstevel@tonic-gate { 7470Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7480Sstevel@tonic-gate int err = 0; 7490Sstevel@tonic-gate 7502311Sseb ASSERT(mip->mi_setpromisc != NULL); 7510Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate /* 7540Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 7550Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 7560Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 7570Sstevel@tonic-gate */ 7580Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 7590Sstevel@tonic-gate if (on) { 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 7642311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 7652311Sseb if (err != 0) { 7660Sstevel@tonic-gate mip->mi_devpromisc--; 7670Sstevel@tonic-gate goto done; 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* 7730Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 7740Sstevel@tonic-gate */ 7750Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 7760Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 7770Sstevel@tonic-gate } else { 7780Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 7790Sstevel@tonic-gate err = EPROTO; 7800Sstevel@tonic-gate goto done; 7810Sstevel@tonic-gate } 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 7850Sstevel@tonic-gate * enabling. 7860Sstevel@tonic-gate */ 7870Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 7882311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 7892311Sseb if (err != 0) { 7900Sstevel@tonic-gate mip->mi_devpromisc++; 7910Sstevel@tonic-gate goto done; 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 7980Sstevel@tonic-gate * enabling. 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 8010Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate done: 8050Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 8060Sstevel@tonic-gate return (err); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate boolean_t 8100Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 8110Sstevel@tonic-gate { 8120Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * Return the current promiscuity. 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 8200Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 8210Sstevel@tonic-gate else 8220Sstevel@tonic-gate return (mip->mi_promisc != 0); 8230Sstevel@tonic-gate } 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate void 8260Sstevel@tonic-gate mac_resources(mac_handle_t mh) 8270Sstevel@tonic-gate { 8280Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate /* 8312311Sseb * If the driver supports resource registration, call the driver to 8322311Sseb * ask it to register its resources. 8330Sstevel@tonic-gate */ 8342311Sseb if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 8352311Sseb mip->mi_resources(mip->mi_driver); 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate void 8390Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 8400Sstevel@tonic-gate { 8410Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate /* 8442311Sseb * Call the driver to handle the ioctl. The driver may not support 8452311Sseb * any ioctls, in which case we reply with a NAK on its behalf. 8460Sstevel@tonic-gate */ 8472311Sseb if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 8482311Sseb mip->mi_ioctl(mip->mi_driver, wq, bp); 8492311Sseb else 8502311Sseb miocnak(wq, bp, 0, EINVAL); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 85356Smeem const mac_txinfo_t * 85456Smeem mac_tx_get(mac_handle_t mh) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 85756Smeem mac_txinfo_t *mtp; 85856Smeem 85956Smeem /* 86056Smeem * Grab the lock to prevent us from racing with MAC_PROMISC being 86156Smeem * changed. This is sufficient since MAC clients are careful to always 86256Smeem * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 86356Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 86456Smeem */ 86556Smeem rw_enter(&mip->mi_txloop_lock, RW_READER); 8660Sstevel@tonic-gate 86756Smeem if (mac_promisc_get(mh, MAC_PROMISC)) { 86856Smeem ASSERT(mip->mi_mtfp != NULL); 86956Smeem mtp = &mip->mi_txloopinfo; 87056Smeem } else { 87156Smeem /* 87256Smeem * Note that we cannot ASSERT() that mip->mi_mtfp is NULL, 87356Smeem * because to satisfy the above ASSERT(), we have to disable 87456Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 87556Smeem */ 87656Smeem mtp = &mip->mi_txinfo; 87756Smeem } 87856Smeem 87956Smeem rw_exit(&mip->mi_txloop_lock); 88056Smeem return (mtp); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate link_state_t 8840Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 8850Sstevel@tonic-gate { 8862311Sseb return (((mac_impl_t *)mh)->mi_linkstate); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate mac_notify_handle_t 8900Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 8910Sstevel@tonic-gate { 8920Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8930Sstevel@tonic-gate mac_notify_fn_t *mnfp; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 8960Sstevel@tonic-gate mnfp->mnf_fn = notify; 8970Sstevel@tonic-gate mnfp->mnf_arg = arg; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate /* 9000Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 9010Sstevel@tonic-gate */ 9021852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 9030Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 9040Sstevel@tonic-gate mip->mi_mnfp = mnfp; 9051852Syz147064 rw_exit(&mip->mi_notify_lock); 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate void 9110Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 9120Sstevel@tonic-gate { 9130Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9140Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 9150Sstevel@tonic-gate mac_notify_fn_t **pp; 9160Sstevel@tonic-gate mac_notify_fn_t *p; 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate /* 9190Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 9200Sstevel@tonic-gate */ 9211852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 9220Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 9230Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 9240Sstevel@tonic-gate if (p == mnfp) 9250Sstevel@tonic-gate break; 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate ASSERT(p != NULL); 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * Remove it from the list. 9310Sstevel@tonic-gate */ 9320Sstevel@tonic-gate *pp = p->mnf_nextp; 9331852Syz147064 rw_exit(&mip->mi_notify_lock); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate /* 9360Sstevel@tonic-gate * Free it. 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate void 9420Sstevel@tonic-gate mac_notify(mac_handle_t mh) 9430Sstevel@tonic-gate { 9440Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9450Sstevel@tonic-gate mac_notify_type_t type; 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 9480Sstevel@tonic-gate i_mac_notify(mip, type); 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate 951*4913Sethindra /* 952*4913Sethindra * Register a receive function for this mac. 953*4913Sethindra * More information on this function's interaction with mac_rx() 954*4913Sethindra * can be found atop mac_rx(). 955*4913Sethindra */ 9560Sstevel@tonic-gate mac_rx_handle_t 9570Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 9580Sstevel@tonic-gate { 9590Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9600Sstevel@tonic-gate mac_rx_fn_t *mrfp; 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 9630Sstevel@tonic-gate mrfp->mrf_fn = rx; 9640Sstevel@tonic-gate mrfp->mrf_arg = arg; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 9680Sstevel@tonic-gate */ 9690Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 970*4913Sethindra 971*4913Sethindra /* 972*4913Sethindra * mac_rx() will only call callbacks that are marked inuse. 973*4913Sethindra */ 974*4913Sethindra mrfp->mrf_inuse = B_TRUE; 9750Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 976*4913Sethindra 977*4913Sethindra /* 978*4913Sethindra * mac_rx() could be traversing the remainder of the list 979*4913Sethindra * and miss the new callback we're adding here. This is not a problem 980*4913Sethindra * because we do not guarantee the callback to take effect immediately 981*4913Sethindra * after mac_rx_add() returns. 982*4913Sethindra */ 9830Sstevel@tonic-gate mip->mi_mrfp = mrfp; 9840Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate /* 990*4913Sethindra * Unregister a receive function for this mac. 991*4913Sethindra * This function does not block if wait is B_FALSE. This is useful 992*4913Sethindra * for clients who call mac_rx_remove() from a non-blockable context. 993*4913Sethindra * More information on this function's interaction with mac_rx() 994*4913Sethindra * can be found atop mac_rx(). 9950Sstevel@tonic-gate */ 9960Sstevel@tonic-gate void 997*4913Sethindra mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait) 9980Sstevel@tonic-gate { 9990Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10000Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 10010Sstevel@tonic-gate mac_rx_fn_t **pp; 10020Sstevel@tonic-gate mac_rx_fn_t *p; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate /* 10050Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 10060Sstevel@tonic-gate */ 1007*4913Sethindra rw_enter(&mip->mi_rx_lock, RW_WRITER); 10080Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 10090Sstevel@tonic-gate if (p == mrfp) 10100Sstevel@tonic-gate break; 10110Sstevel@tonic-gate } 10120Sstevel@tonic-gate ASSERT(p != NULL); 10130Sstevel@tonic-gate 1014*4913Sethindra /* 1015*4913Sethindra * If mac_rx() is running, mark callback for deletion 1016*4913Sethindra * and return (if wait is false), or wait until mac_rx() 1017*4913Sethindra * exits (if wait is true). 1018*4913Sethindra */ 1019*4913Sethindra if (mip->mi_rx_ref > 0) { 1020*4913Sethindra DTRACE_PROBE1(defer_delete, mac_impl_t *, mip); 1021*4913Sethindra p->mrf_inuse = B_FALSE; 1022*4913Sethindra mutex_enter(&mip->mi_lock); 1023*4913Sethindra mip->mi_rx_removed++; 1024*4913Sethindra mutex_exit(&mip->mi_lock); 1025*4913Sethindra 1026*4913Sethindra rw_exit(&mip->mi_rx_lock); 1027*4913Sethindra if (wait) 1028*4913Sethindra mac_rx_remove_wait(mh); 1029*4913Sethindra return; 1030*4913Sethindra } 1031*4913Sethindra 10320Sstevel@tonic-gate /* Remove it from the list. */ 10330Sstevel@tonic-gate *pp = p->mrf_nextp; 10340Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 1035*4913Sethindra rw_exit(&mip->mi_rx_lock); 1036*4913Sethindra } 1037*4913Sethindra 1038*4913Sethindra /* 1039*4913Sethindra * Wait for all pending callback removals to be completed by mac_rx(). 1040*4913Sethindra * Note that if we call mac_rx_remove() immediately before this, there is no 1041*4913Sethindra * guarantee we would wait *only* on the callback that we specified. 1042*4913Sethindra * mac_rx_remove() could have been called by other threads and we would have 1043*4913Sethindra * to wait for other marked callbacks to be removed as well. 1044*4913Sethindra */ 1045*4913Sethindra void 1046*4913Sethindra mac_rx_remove_wait(mac_handle_t mh) 1047*4913Sethindra { 1048*4913Sethindra mac_impl_t *mip = (mac_impl_t *)mh; 1049*4913Sethindra 1050*4913Sethindra mutex_enter(&mip->mi_lock); 1051*4913Sethindra while (mip->mi_rx_removed > 0) { 1052*4913Sethindra DTRACE_PROBE1(need_wait, mac_impl_t *, mip); 1053*4913Sethindra cv_wait(&mip->mi_rx_cv, &mip->mi_lock); 1054*4913Sethindra } 1055*4913Sethindra mutex_exit(&mip->mi_lock); 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate mac_txloop_handle_t 10590Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 10600Sstevel@tonic-gate { 10610Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10620Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 10650Sstevel@tonic-gate mtfp->mtf_fn = tx; 10660Sstevel@tonic-gate mtfp->mtf_arg = arg; 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate /* 10690Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 10700Sstevel@tonic-gate */ 10710Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 10720Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 10730Sstevel@tonic-gate mip->mi_mtfp = mtfp; 10740Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate /* 10800Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 10810Sstevel@tonic-gate * from the list of transmit functions for this mac. 10820Sstevel@tonic-gate */ 10830Sstevel@tonic-gate void 10840Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 10850Sstevel@tonic-gate { 10860Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10870Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 10880Sstevel@tonic-gate mac_txloop_fn_t **pp; 10890Sstevel@tonic-gate mac_txloop_fn_t *p; 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate /* 10920Sstevel@tonic-gate * Search the 'tx' callback list for the function. 10930Sstevel@tonic-gate */ 10940Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 10950Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 10960Sstevel@tonic-gate if (p == mtfp) 10970Sstevel@tonic-gate break; 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate ASSERT(p != NULL); 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* Remove it from the list. */ 11020Sstevel@tonic-gate *pp = p->mtf_nextp; 11030Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 11040Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 11050Sstevel@tonic-gate } 11060Sstevel@tonic-gate 11070Sstevel@tonic-gate void 11080Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 11090Sstevel@tonic-gate { 11100Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate /* 11130Sstevel@tonic-gate * Update the 'resource_add' callbacks. 11140Sstevel@tonic-gate */ 11150Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 11160Sstevel@tonic-gate mip->mi_resource_add = add; 11170Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 11180Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate /* 11220Sstevel@tonic-gate * Driver support functions. 11230Sstevel@tonic-gate */ 11240Sstevel@tonic-gate 11252311Sseb mac_register_t * 11262311Sseb mac_alloc(uint_t mac_version) 11270Sstevel@tonic-gate { 11282311Sseb mac_register_t *mregp; 11292311Sseb 11302311Sseb /* 11312311Sseb * Make sure there isn't a version mismatch between the driver and 11322311Sseb * the framework. In the future, if multiple versions are 11332311Sseb * supported, this check could become more sophisticated. 11342311Sseb */ 11352311Sseb if (mac_version != MAC_VERSION) 11362311Sseb return (NULL); 11372311Sseb 11382311Sseb mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 11392311Sseb mregp->m_version = mac_version; 11402311Sseb return (mregp); 11412311Sseb } 11422311Sseb 11432311Sseb void 11442311Sseb mac_free(mac_register_t *mregp) 11452311Sseb { 11462311Sseb kmem_free(mregp, sizeof (mac_register_t)); 11472311Sseb } 11482311Sseb 11492311Sseb /* 11502311Sseb * mac_register() is how drivers register new MACs with the GLDv3 11512311Sseb * framework. The mregp argument is allocated by drivers using the 11522311Sseb * mac_alloc() function, and can be freed using mac_free() immediately upon 11532311Sseb * return from mac_register(). Upon success (0 return value), the mhp 11542311Sseb * opaque pointer becomes the driver's handle to its MAC interface, and is 11552311Sseb * the argument to all other mac module entry points. 11562311Sseb */ 11572311Sseb int 11582311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 11592311Sseb { 11602311Sseb mac_impl_t *mip; 11612311Sseb mactype_t *mtype; 11623969Syz147064 int err = EINVAL; 11630Sstevel@tonic-gate struct devnames *dnp; 11642311Sseb minor_t minor; 11652311Sseb boolean_t style1_created = B_FALSE, style2_created = B_FALSE; 11662311Sseb 11672311Sseb /* Find the required MAC-Type plugin. */ 11682311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 11692311Sseb return (EINVAL); 11702311Sseb 11712311Sseb /* Create a mac_impl_t to represent this MAC. */ 11722311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 11732311Sseb 11742311Sseb /* 11752311Sseb * The mac is not ready for open yet. 11762311Sseb */ 11772311Sseb mip->mi_disabled = B_TRUE; 11782311Sseb 11792311Sseb mip->mi_drvname = ddi_driver_name(mregp->m_dip); 11802311Sseb /* 11812311Sseb * Some drivers such as aggr need to register multiple MACs. Such 11822311Sseb * drivers must supply a non-zero "instance" argument so that each 11832311Sseb * MAC can be assigned a unique MAC name and can have unique 11842311Sseb * kstats. 11852311Sseb */ 11862311Sseb mip->mi_instance = ((mregp->m_instance == 0) ? 11872311Sseb ddi_get_instance(mregp->m_dip) : mregp->m_instance); 11882311Sseb 11892311Sseb /* Construct the MAC name as <drvname><instance> */ 11902311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 11912311Sseb mip->mi_drvname, mip->mi_instance); 11922311Sseb 11932311Sseb mip->mi_driver = mregp->m_driver; 11942311Sseb 11952311Sseb mip->mi_type = mtype; 11962311Sseb mip->mi_info.mi_media = mtype->mt_type; 11973147Sxc151355 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 11982311Sseb mip->mi_info.mi_sdu_min = mregp->m_min_sdu; 11993969Syz147064 if (mregp->m_max_sdu <= mregp->m_min_sdu) 12002311Sseb goto fail; 12012311Sseb mip->mi_info.mi_sdu_max = mregp->m_max_sdu; 12022311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 12032311Sseb /* 12042311Sseb * If the media supports a broadcast address, cache a pointer to it 12052311Sseb * in the mac_info_t so that upper layers can use it. 12062311Sseb */ 12072311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1208269Sericheng 12092311Sseb /* 12102311Sseb * Copy the unicast source address into the mac_info_t, but only if 12112311Sseb * the MAC-Type defines a non-zero address length. We need to 12122311Sseb * handle MAC-Types that have an address length of 0 12132311Sseb * (point-to-point protocol MACs for example). 12142311Sseb */ 12152311Sseb if (mip->mi_type->mt_addr_length > 0) { 12163969Syz147064 if (mregp->m_src_addr == NULL) 12172311Sseb goto fail; 12182311Sseb mip->mi_info.mi_unicst_addr = 12192311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 12202311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 12212311Sseb mip->mi_type->mt_addr_length); 12222311Sseb 12232311Sseb /* 12242311Sseb * Copy the fixed 'factory' MAC address from the immutable 12252311Sseb * info. This is taken to be the MAC address currently in 12262311Sseb * use. 12272311Sseb */ 12282311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 12292311Sseb mip->mi_type->mt_addr_length); 12302311Sseb /* Copy the destination address if one is provided. */ 12312311Sseb if (mregp->m_dst_addr != NULL) { 12322311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 12332311Sseb mip->mi_type->mt_addr_length); 12342311Sseb } 12352311Sseb } else if (mregp->m_src_addr != NULL) { 12362311Sseb goto fail; 1237269Sericheng } 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate /* 12402311Sseb * The format of the m_pdata is specific to the plugin. It is 12412311Sseb * passed in as an argument to all of the plugin callbacks. The 12422311Sseb * driver can update this information by calling 12432311Sseb * mac_pdata_update(). 12440Sstevel@tonic-gate */ 12452311Sseb if (mregp->m_pdata != NULL) { 12462311Sseb /* 12472311Sseb * Verify that the plugin supports MAC plugin data and that 12482311Sseb * the supplied data is valid. 12492311Sseb */ 12503969Syz147064 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 12512311Sseb goto fail; 12522311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 12532311Sseb mregp->m_pdata_size)) { 12542311Sseb goto fail; 12552311Sseb } 12562311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 12572311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 12582311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 12592311Sseb } 12602311Sseb 12612311Sseb /* 12622311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 12632311Sseb * check to make sure all mandatory callbacks are set. 12642311Sseb */ 12652311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 12662311Sseb mregp->m_callbacks->mc_start == NULL || 12672311Sseb mregp->m_callbacks->mc_stop == NULL || 12682311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 12692311Sseb mregp->m_callbacks->mc_multicst == NULL || 12702311Sseb mregp->m_callbacks->mc_unicst == NULL || 12712311Sseb mregp->m_callbacks->mc_tx == NULL) { 12722311Sseb goto fail; 12732311Sseb } 12742311Sseb mip->mi_callbacks = mregp->m_callbacks; 12752311Sseb 12762311Sseb mip->mi_dip = mregp->m_dip; 12772311Sseb 12782311Sseb /* 12792311Sseb * Set up the two possible transmit routines. 12802311Sseb */ 12812311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 12822311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 12832311Sseb mip->mi_txloopinfo.mt_fn = mac_txloop; 12842311Sseb mip->mi_txloopinfo.mt_arg = mip; 12852311Sseb 12862311Sseb /* 12872311Sseb * Initialize the kstats for this device. 12882311Sseb */ 12892311Sseb mac_stat_create(mip); 12900Sstevel@tonic-gate 1291269Sericheng err = EEXIST; 12922311Sseb /* Create a style-2 DLPI device */ 12932311Sseb if (ddi_create_minor_node(mip->mi_dip, (char *)mip->mi_drvname, 12942311Sseb S_IFCHR, 0, DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 12952311Sseb goto fail; 12962311Sseb style2_created = B_TRUE; 1297269Sericheng 12982311Sseb /* Create a style-1 DLPI device */ 12992311Sseb minor = (minor_t)mip->mi_instance + 1; 13002311Sseb if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, minor, 13012311Sseb DDI_NT_NET, 0) != DDI_SUCCESS) 13022311Sseb goto fail; 13032311Sseb style1_created = B_TRUE; 13040Sstevel@tonic-gate 13052311Sseb /* 13062311Sseb * Create a link for this MAC. The link name will be the same as 13072311Sseb * the MAC name. 13082311Sseb */ 13092311Sseb err = dls_create(mip->mi_name, mip->mi_name, 13102311Sseb ddi_get_instance(mip->mi_dip)); 13112311Sseb if (err != 0) 13122311Sseb goto fail; 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 13152311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 13160Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 13170Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 13180Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 13190Sstevel@tonic-gate 13203969Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 13213969Syz147064 if (mod_hash_insert(i_mac_impl_hash, 13223969Syz147064 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 13233969Syz147064 rw_exit(&i_mac_impl_lock); 13243969Syz147064 VERIFY(dls_destroy(mip->mi_name) == 0); 13253969Syz147064 err = EEXIST; 13263969Syz147064 goto fail; 13273969Syz147064 } 13283969Syz147064 13291852Syz147064 /* 13301852Syz147064 * Mark the MAC to be ready for open. 13311852Syz147064 */ 13322311Sseb mip->mi_disabled = B_FALSE; 13332311Sseb 13342311Sseb cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 13353969Syz147064 13361852Syz147064 rw_exit(&i_mac_impl_lock); 13373969Syz147064 13383969Syz147064 atomic_inc_32(&i_mac_impl_count); 13392311Sseb *mhp = (mac_handle_t)mip; 1340269Sericheng return (0); 13410Sstevel@tonic-gate 13422311Sseb fail: 13432311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 13442311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 13452311Sseb mip->mi_type->mt_addr_length); 13462311Sseb mip->mi_info.mi_unicst_addr = NULL; 13472311Sseb } 13482311Sseb if (style1_created) 13492311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 13502311Sseb if (style2_created) 13512311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 13522311Sseb 13532311Sseb mac_stat_destroy(mip); 13542311Sseb 13552311Sseb if (mip->mi_type != NULL) { 13563288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 13572311Sseb mip->mi_type = NULL; 13582311Sseb } 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; 13642311Sseb } 13652311Sseb 13662311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 1367269Sericheng return (err); 13680Sstevel@tonic-gate } 13690Sstevel@tonic-gate 13700Sstevel@tonic-gate int 13712311Sseb mac_unregister(mac_handle_t mh) 13720Sstevel@tonic-gate { 13732311Sseb int err; 13742311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 13752311Sseb mod_hash_val_t val; 13762311Sseb mac_multicst_addr_t *p, *nextp; 1377269Sericheng 13780Sstevel@tonic-gate /* 13790Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 13801852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 13812311Sseb * created while we're destroying this mac. 13820Sstevel@tonic-gate */ 1383269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 13840Sstevel@tonic-gate if (mip->mi_ref > 0) { 1385269Sericheng rw_exit(&i_mac_impl_lock); 13860Sstevel@tonic-gate return (EBUSY); 13870Sstevel@tonic-gate } 13881852Syz147064 mip->mi_disabled = B_TRUE; 1389269Sericheng rw_exit(&i_mac_impl_lock); 13900Sstevel@tonic-gate 13911852Syz147064 /* 13921852Syz147064 * Wait for all taskqs which process the mac notifications to finish. 13931852Syz147064 */ 13941852Syz147064 mutex_enter(&mip->mi_notify_ref_lock); 13951852Syz147064 while (mip->mi_notify_ref != 0) 13961852Syz147064 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_ref_lock); 13971852Syz147064 mutex_exit(&mip->mi_notify_ref_lock); 13981852Syz147064 13992311Sseb if ((err = dls_destroy(mip->mi_name)) != 0) { 1400269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 14011852Syz147064 mip->mi_disabled = B_FALSE; 1402269Sericheng rw_exit(&i_mac_impl_lock); 1403269Sericheng return (err); 14040Sstevel@tonic-gate } 14050Sstevel@tonic-gate 14060Sstevel@tonic-gate /* 14072311Sseb * Remove both style 1 and style 2 minor nodes 14080Sstevel@tonic-gate */ 14092311Sseb ddi_remove_minor_node(mip->mi_dip, (char *)mip->mi_drvname); 14102311Sseb ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 14112311Sseb 14122311Sseb ASSERT(!mip->mi_activelink); 14132311Sseb 14142311Sseb mac_stat_destroy(mip); 14152311Sseb 14162311Sseb (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, 14172311Sseb &val); 14182311Sseb ASSERT(mip == (mac_impl_t *)val); 14192311Sseb 14202311Sseb ASSERT(i_mac_impl_count > 0); 14213288Sseb atomic_dec_32(&i_mac_impl_count); 14222311Sseb 14232311Sseb if (mip->mi_pdata != NULL) 14242311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 14252311Sseb mip->mi_pdata = NULL; 14262311Sseb mip->mi_pdata_size = 0; 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate /* 14292311Sseb * Free the list of multicast addresses. 14300Sstevel@tonic-gate */ 14312311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 14322311Sseb nextp = p->mma_nextp; 14332311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 14342311Sseb } 14352311Sseb mip->mi_mmap = NULL; 14360Sstevel@tonic-gate 14372311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 14382311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 14392311Sseb mip->mi_info.mi_unicst_addr = NULL; 14402311Sseb 14413288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 14422311Sseb mip->mi_type = NULL; 14432311Sseb 14442311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 14452311Sseb 14462311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 14472311Sseb 14480Sstevel@tonic-gate return (0); 14490Sstevel@tonic-gate } 14500Sstevel@tonic-gate 1451*4913Sethindra /* 1452*4913Sethindra * To avoid potential deadlocks, mac_rx() releases mi_rx_lock 1453*4913Sethindra * before invoking its list of upcalls. This introduces races with 1454*4913Sethindra * mac_rx_remove() and mac_rx_add(), who can potentially modify the 1455*4913Sethindra * upcall list while mi_rx_lock is not being held. The race with 1456*4913Sethindra * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering 1457*4913Sethindra * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove() 1458*4913Sethindra * to not modify the list but instead mark an upcall for deletion. 1459*4913Sethindra * before mac_rx() exits, mi_rx_ref is decremented and if it 1460*4913Sethindra * is 0, the marked upcalls will be removed from the list and freed. 1461*4913Sethindra * The race with mac_rx_add() is harmless because mac_rx_add() only 1462*4913Sethindra * prepends to the list and since mac_rx() saves the list head 1463*4913Sethindra * before releasing mi_rx_lock, any prepended upcall won't be seen 1464*4913Sethindra * until the next packet chain arrives. 1465*4913Sethindra * 1466*4913Sethindra * To minimize lock contention between multiple parallel invocations 1467*4913Sethindra * of mac_rx(), mi_rx_lock is acquired as a READER lock. The 1468*4913Sethindra * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock 1469*4913Sethindra * will be upgraded to WRITER mode when there are marked upcalls to be 1470*4913Sethindra * cleaned. 1471*4913Sethindra */ 14720Sstevel@tonic-gate void 1473*4913Sethindra mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) 14740Sstevel@tonic-gate { 14752311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1476*4913Sethindra mblk_t *bp = mp_chain; 14770Sstevel@tonic-gate mac_rx_fn_t *mrfp; 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate /* 14800Sstevel@tonic-gate * Call all registered receive functions. 14810Sstevel@tonic-gate */ 14820Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 1483*4913Sethindra if ((mrfp = mip->mi_mrfp) == NULL) { 14840Sstevel@tonic-gate /* There are no registered receive functions. */ 14850Sstevel@tonic-gate freemsgchain(bp); 14860Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 14870Sstevel@tonic-gate return; 14880Sstevel@tonic-gate } 1489*4913Sethindra atomic_inc_32(&mip->mi_rx_ref); 1490*4913Sethindra rw_exit(&mip->mi_rx_lock); 1491*4913Sethindra 1492*4913Sethindra /* 1493*4913Sethindra * Call registered receive functions. 1494*4913Sethindra */ 14950Sstevel@tonic-gate do { 14960Sstevel@tonic-gate mblk_t *recv_bp; 14970Sstevel@tonic-gate 1498*4913Sethindra recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp; 1499*4913Sethindra if (recv_bp != NULL) { 1500*4913Sethindra if (mrfp->mrf_inuse) { 1501*4913Sethindra /* 1502*4913Sethindra * Send bp itself and keep the copy. 1503*4913Sethindra * If there's only one active receiver, 1504*4913Sethindra * it should get the original message, 1505*4913Sethindra * tagged with the hardware checksum flags. 1506*4913Sethindra */ 1507*4913Sethindra mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp); 1508*4913Sethindra bp = recv_bp; 1509*4913Sethindra } else { 1510*4913Sethindra freemsgchain(recv_bp); 1511*4913Sethindra } 15120Sstevel@tonic-gate } 15130Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 15140Sstevel@tonic-gate } while (mrfp != NULL); 1515*4913Sethindra 1516*4913Sethindra rw_enter(&mip->mi_rx_lock, RW_READER); 1517*4913Sethindra if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) { 1518*4913Sethindra mac_rx_fn_t **pp, *p; 1519*4913Sethindra uint32_t cnt = 0; 1520*4913Sethindra 1521*4913Sethindra DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip); 1522*4913Sethindra 1523*4913Sethindra /* 1524*4913Sethindra * Need to become exclusive before doing cleanup 1525*4913Sethindra */ 1526*4913Sethindra if (rw_tryupgrade(&mip->mi_rx_lock) == 0) { 1527*4913Sethindra rw_exit(&mip->mi_rx_lock); 1528*4913Sethindra rw_enter(&mip->mi_rx_lock, RW_WRITER); 1529*4913Sethindra } 1530*4913Sethindra 1531*4913Sethindra /* 1532*4913Sethindra * We return if another thread has already entered and cleaned 1533*4913Sethindra * up the list. 1534*4913Sethindra */ 1535*4913Sethindra if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) { 1536*4913Sethindra rw_exit(&mip->mi_rx_lock); 1537*4913Sethindra return; 1538*4913Sethindra } 1539*4913Sethindra 1540*4913Sethindra /* 1541*4913Sethindra * Free removed callbacks. 1542*4913Sethindra */ 1543*4913Sethindra pp = &mip->mi_mrfp; 1544*4913Sethindra while (*pp != NULL) { 1545*4913Sethindra if (!(*pp)->mrf_inuse) { 1546*4913Sethindra p = *pp; 1547*4913Sethindra *pp = (*pp)->mrf_nextp; 1548*4913Sethindra kmem_free(p, sizeof (*p)); 1549*4913Sethindra cnt++; 1550*4913Sethindra continue; 1551*4913Sethindra } 1552*4913Sethindra pp = &(*pp)->mrf_nextp; 1553*4913Sethindra } 1554*4913Sethindra 1555*4913Sethindra /* 1556*4913Sethindra * Wake up mac_rx_remove_wait() 1557*4913Sethindra */ 1558*4913Sethindra mutex_enter(&mip->mi_lock); 1559*4913Sethindra ASSERT(mip->mi_rx_removed == cnt); 1560*4913Sethindra mip->mi_rx_removed = 0; 1561*4913Sethindra cv_broadcast(&mip->mi_rx_cv); 1562*4913Sethindra mutex_exit(&mip->mi_lock); 1563*4913Sethindra } 15640Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 15650Sstevel@tonic-gate } 15660Sstevel@tonic-gate 15670Sstevel@tonic-gate /* 15680Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 15690Sstevel@tonic-gate */ 15700Sstevel@tonic-gate mblk_t * 15710Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 15720Sstevel@tonic-gate { 15730Sstevel@tonic-gate mac_impl_t *mip = arg; 15740Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 15750Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 15760Sstevel@tonic-gate 15770Sstevel@tonic-gate while (bp != NULL) { 15780Sstevel@tonic-gate next_bp = bp->b_next; 15790Sstevel@tonic-gate bp->b_next = NULL; 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 15820Sstevel@tonic-gate goto noresources; 15830Sstevel@tonic-gate 15842311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 15850Sstevel@tonic-gate ASSERT(resid_bp == bp); 15860Sstevel@tonic-gate freemsg(loop_bp); 15870Sstevel@tonic-gate goto noresources; 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate 15900Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 15910Sstevel@tonic-gate mtfp = mip->mi_mtfp; 159256Smeem while (mtfp != NULL && loop_bp != NULL) { 15930Sstevel@tonic-gate bp = loop_bp; 159456Smeem 159556Smeem /* XXX counter bump if copymsg() fails? */ 159656Smeem if (mtfp->mtf_nextp != NULL) 15970Sstevel@tonic-gate loop_bp = copymsg(bp); 159856Smeem else 159956Smeem loop_bp = NULL; 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 160256Smeem mtfp = mtfp->mtf_nextp; 16030Sstevel@tonic-gate } 160456Smeem rw_exit(&mip->mi_txloop_lock); 16050Sstevel@tonic-gate 160656Smeem /* 160756Smeem * It's possible we've raced with the disabling of promiscuous 160856Smeem * mode, in which case we can discard our copy. 160956Smeem */ 161056Smeem if (loop_bp != NULL) 161156Smeem freemsg(loop_bp); 161256Smeem 16130Sstevel@tonic-gate bp = next_bp; 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate return (NULL); 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate noresources: 16190Sstevel@tonic-gate bp->b_next = next_bp; 16200Sstevel@tonic-gate return (bp); 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate void 16242311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 16250Sstevel@tonic-gate { 16262311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate /* 16290Sstevel@tonic-gate * Save the link state. 16300Sstevel@tonic-gate */ 16312311Sseb mip->mi_linkstate = link; 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate /* 16340Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 16350Sstevel@tonic-gate */ 16360Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate 16390Sstevel@tonic-gate void 16402311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 16410Sstevel@tonic-gate { 16422311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16430Sstevel@tonic-gate 16442311Sseb if (mip->mi_type->mt_addr_length == 0) 16452311Sseb return; 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate /* 16480Sstevel@tonic-gate * Save the address. 16490Sstevel@tonic-gate */ 16502311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate /* 16530Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 16540Sstevel@tonic-gate */ 16550Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 16560Sstevel@tonic-gate } 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate void 16592311Sseb mac_tx_update(mac_handle_t mh) 16600Sstevel@tonic-gate { 16610Sstevel@tonic-gate /* 16620Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 16630Sstevel@tonic-gate */ 16642311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate void 16682311Sseb mac_resource_update(mac_handle_t mh) 16690Sstevel@tonic-gate { 16700Sstevel@tonic-gate /* 16710Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 16720Sstevel@tonic-gate */ 16732311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate mac_resource_handle_t 16772311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 16780Sstevel@tonic-gate { 16792311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 16800Sstevel@tonic-gate mac_resource_handle_t mrh; 16810Sstevel@tonic-gate mac_resource_add_t add; 16820Sstevel@tonic-gate void *arg; 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 16850Sstevel@tonic-gate add = mip->mi_resource_add; 16860Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 16870Sstevel@tonic-gate 16881184Skrgopi if (add != NULL) 16891184Skrgopi mrh = add(arg, mrp); 16901184Skrgopi else 16911184Skrgopi mrh = NULL; 16920Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate return (mrh); 16950Sstevel@tonic-gate } 16960Sstevel@tonic-gate 16972311Sseb int 16982311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 16992311Sseb { 17002311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17012311Sseb 17022311Sseb /* 17032311Sseb * Verify that the plugin supports MAC plugin data and that the 17042311Sseb * supplied data is valid. 17052311Sseb */ 17062311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 17072311Sseb return (EINVAL); 17082311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 17092311Sseb return (EINVAL); 17102311Sseb 17112311Sseb if (mip->mi_pdata != NULL) 17122311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 17132311Sseb 17142311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 17152311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 17162311Sseb mip->mi_pdata_size = dsize; 17172311Sseb 17182311Sseb /* 17192311Sseb * Since the MAC plugin data is used to construct MAC headers that 17202311Sseb * were cached in fast-path headers, we need to flush fast-path 17212311Sseb * information for links associated with this mac. 17222311Sseb */ 17232311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 17242311Sseb return (0); 17252311Sseb } 17262311Sseb 17270Sstevel@tonic-gate void 17282311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 17290Sstevel@tonic-gate boolean_t add) 17300Sstevel@tonic-gate { 17312311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17320Sstevel@tonic-gate mac_multicst_addr_t *p; 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * If no specific refresh function was given then default to the 17360Sstevel@tonic-gate * driver's m_multicst entry point. 17370Sstevel@tonic-gate */ 17380Sstevel@tonic-gate if (refresh == NULL) { 17392311Sseb refresh = mip->mi_multicst; 17402311Sseb arg = mip->mi_driver; 17410Sstevel@tonic-gate } 17420Sstevel@tonic-gate ASSERT(refresh != NULL); 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate /* 17450Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 17460Sstevel@tonic-gate * each address. 17470Sstevel@tonic-gate */ 17480Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 17490Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 17500Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 17510Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 17520Sstevel@tonic-gate } 17530Sstevel@tonic-gate 17540Sstevel@tonic-gate void 17552311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 17560Sstevel@tonic-gate { 17572311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17580Sstevel@tonic-gate /* 17590Sstevel@tonic-gate * If no specific refresh function was given then default to the 17602311Sseb * driver's mi_unicst entry point. 17610Sstevel@tonic-gate */ 17620Sstevel@tonic-gate if (refresh == NULL) { 17632311Sseb refresh = mip->mi_unicst; 17642311Sseb arg = mip->mi_driver; 17650Sstevel@tonic-gate } 17660Sstevel@tonic-gate ASSERT(refresh != NULL); 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate /* 17690Sstevel@tonic-gate * Call the refresh function with the current unicast address. 17700Sstevel@tonic-gate */ 17710Sstevel@tonic-gate refresh(arg, mip->mi_addr); 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate void 17752311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 17760Sstevel@tonic-gate { 17772311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 17780Sstevel@tonic-gate 17790Sstevel@tonic-gate /* 17800Sstevel@tonic-gate * If no specific refresh function was given then default to the 17810Sstevel@tonic-gate * driver's m_promisc entry point. 17820Sstevel@tonic-gate */ 17830Sstevel@tonic-gate if (refresh == NULL) { 17842311Sseb refresh = mip->mi_setpromisc; 17852311Sseb arg = mip->mi_driver; 17860Sstevel@tonic-gate } 17870Sstevel@tonic-gate ASSERT(refresh != NULL); 17880Sstevel@tonic-gate 17890Sstevel@tonic-gate /* 17900Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 17910Sstevel@tonic-gate */ 17920Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate boolean_t 17960Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 17970Sstevel@tonic-gate { 17980Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 18010Sstevel@tonic-gate if (mip->mi_activelink) { 18020Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 18030Sstevel@tonic-gate return (B_FALSE); 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 18060Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 18070Sstevel@tonic-gate return (B_TRUE); 18080Sstevel@tonic-gate } 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate void 18110Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 18120Sstevel@tonic-gate { 18130Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 18160Sstevel@tonic-gate ASSERT(mip->mi_activelink); 18170Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 18180Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 18190Sstevel@tonic-gate } 1820269Sericheng 1821269Sericheng /* 1822269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 1823269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 1824269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 1825269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 1826269Sericheng * cannot disappear while we are accessing it. 1827269Sericheng */ 1828269Sericheng typedef struct i_mac_info_state_s { 1829269Sericheng const char *mi_name; 1830269Sericheng mac_info_t *mi_infop; 1831269Sericheng } i_mac_info_state_t; 1832269Sericheng 1833269Sericheng /*ARGSUSED*/ 1834269Sericheng static uint_t 1835269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 1836269Sericheng { 1837269Sericheng i_mac_info_state_t *statep = arg; 1838269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 1839269Sericheng 18401852Syz147064 if (mip->mi_disabled) 1841269Sericheng return (MH_WALK_CONTINUE); 1842269Sericheng 1843269Sericheng if (strcmp(statep->mi_name, 18442311Sseb ddi_driver_name(mip->mi_dip)) != 0) 1845269Sericheng return (MH_WALK_CONTINUE); 1846269Sericheng 18472311Sseb statep->mi_infop = &mip->mi_info; 1848269Sericheng return (MH_WALK_TERMINATE); 1849269Sericheng } 1850269Sericheng 1851269Sericheng boolean_t 1852269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 1853269Sericheng { 1854269Sericheng i_mac_info_state_t state; 1855269Sericheng 1856269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 1857269Sericheng state.mi_name = name; 1858269Sericheng state.mi_infop = NULL; 1859269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 1860269Sericheng if (state.mi_infop == NULL) { 1861269Sericheng rw_exit(&i_mac_impl_lock); 1862269Sericheng return (B_FALSE); 1863269Sericheng } 1864269Sericheng *minfop = *state.mi_infop; 1865269Sericheng rw_exit(&i_mac_impl_lock); 1866269Sericheng return (B_TRUE); 1867269Sericheng } 1868269Sericheng 18692311Sseb boolean_t 18702311Sseb mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 18712311Sseb { 18722311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 18732311Sseb 18742311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 18752311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 18762311Sseb else 18772311Sseb return (B_FALSE); 18782311Sseb } 18792311Sseb 18802311Sseb boolean_t 18812311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 18822311Sseb { 18832311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 18842311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 18852311Sseb mip->mi_pdata)); 18862311Sseb } 18872311Sseb 18882311Sseb mblk_t * 18892311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 18902311Sseb size_t extra_len) 18912311Sseb { 18922311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 18932311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 18942311Sseb mip->mi_pdata, payload, extra_len)); 18952311Sseb } 18962311Sseb 18972311Sseb int 18982311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 18992311Sseb { 19002311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 19012311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 19022311Sseb mhip)); 19032311Sseb } 19042311Sseb 19052311Sseb mblk_t * 19062311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 19072311Sseb { 19082311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 19092311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 19102311Sseb if (DB_REF(mp) > 1) { 19112311Sseb mblk_t *newmp = copymsg(mp); 19122760Sdg199075 if (newmp == NULL) 19132760Sdg199075 return (NULL); 19142311Sseb freemsg(mp); 19152311Sseb mp = newmp; 19162311Sseb } 19172311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 19182311Sseb mip->mi_pdata)); 19192311Sseb } 19202311Sseb return (mp); 19212311Sseb } 19222311Sseb 19232311Sseb mblk_t * 19242311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 19252311Sseb { 19262311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 19272311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 19282311Sseb if (DB_REF(mp) > 1) { 19292311Sseb mblk_t *newmp = copymsg(mp); 19302760Sdg199075 if (newmp == NULL) 19312760Sdg199075 return (NULL); 19322311Sseb freemsg(mp); 19332311Sseb mp = newmp; 19342311Sseb } 19352311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 19362311Sseb mip->mi_pdata)); 19372311Sseb } 19382311Sseb return (mp); 19392311Sseb } 19402311Sseb 1941269Sericheng void 1942269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 1943269Sericheng { 1944269Sericheng dld_init_ops(ops, name); 1945269Sericheng } 1946269Sericheng 1947269Sericheng void 1948269Sericheng mac_fini_ops(struct dev_ops *ops) 1949269Sericheng { 1950269Sericheng dld_fini_ops(ops); 1951269Sericheng } 19522311Sseb 19532311Sseb /* 19542311Sseb * MAC Type Plugin functions. 19552311Sseb */ 19562311Sseb 19572311Sseb mactype_register_t * 19582311Sseb mactype_alloc(uint_t mactype_version) 19592311Sseb { 19602311Sseb mactype_register_t *mtrp; 19612311Sseb 19622311Sseb /* 19632311Sseb * Make sure there isn't a version mismatch between the plugin and 19642311Sseb * the framework. In the future, if multiple versions are 19652311Sseb * supported, this check could become more sophisticated. 19662311Sseb */ 19672311Sseb if (mactype_version != MACTYPE_VERSION) 19682311Sseb return (NULL); 19692311Sseb 19702311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 19712311Sseb mtrp->mtr_version = mactype_version; 19722311Sseb return (mtrp); 19732311Sseb } 19742311Sseb 19752311Sseb void 19762311Sseb mactype_free(mactype_register_t *mtrp) 19772311Sseb { 19782311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 19792311Sseb } 19802311Sseb 19812311Sseb int 19822311Sseb mactype_register(mactype_register_t *mtrp) 19832311Sseb { 19842311Sseb mactype_t *mtp; 19852311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 19862311Sseb 19872311Sseb /* Do some sanity checking before we register this MAC type. */ 19882311Sseb if (mtrp->mtr_ident == NULL || ops == NULL || mtrp->mtr_addrlen == 0) 19892311Sseb return (EINVAL); 19902311Sseb 19912311Sseb /* 19922311Sseb * Verify that all mandatory callbacks are set in the ops 19932311Sseb * vector. 19942311Sseb */ 19952311Sseb if (ops->mtops_unicst_verify == NULL || 19962311Sseb ops->mtops_multicst_verify == NULL || 19972311Sseb ops->mtops_sap_verify == NULL || 19982311Sseb ops->mtops_header == NULL || 19992311Sseb ops->mtops_header_info == NULL) { 20002311Sseb return (EINVAL); 20012311Sseb } 20022311Sseb 20032311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 20042311Sseb mtp->mt_ident = mtrp->mtr_ident; 20052311Sseb mtp->mt_ops = *ops; 20062311Sseb mtp->mt_type = mtrp->mtr_mactype; 20073147Sxc151355 mtp->mt_nativetype = mtrp->mtr_nativetype; 20082311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 20092311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 20102311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 20112311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 20122311Sseb mtrp->mtr_addrlen); 20132311Sseb } 20142311Sseb 20152311Sseb mtp->mt_stats = mtrp->mtr_stats; 20162311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 20172311Sseb 20182311Sseb if (mod_hash_insert(i_mactype_hash, 20192311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 20202311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 20212311Sseb kmem_free(mtp, sizeof (*mtp)); 20222311Sseb return (EEXIST); 20232311Sseb } 20242311Sseb return (0); 20252311Sseb } 20262311Sseb 20272311Sseb int 20282311Sseb mactype_unregister(const char *ident) 20292311Sseb { 20302311Sseb mactype_t *mtp; 20312311Sseb mod_hash_val_t val; 20322311Sseb int err; 20332311Sseb 20342311Sseb /* 20352311Sseb * Let's not allow MAC drivers to use this plugin while we're 20363288Sseb * trying to unregister it. Holding i_mactype_lock also prevents a 20373288Sseb * plugin from unregistering while a MAC driver is attempting to 20383288Sseb * hold a reference to it in i_mactype_getplugin(). 20392311Sseb */ 20403288Sseb mutex_enter(&i_mactype_lock); 20412311Sseb 20422311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 20432311Sseb (mod_hash_val_t *)&mtp)) != 0) { 20442311Sseb /* A plugin is trying to unregister, but it never registered. */ 20453288Sseb err = ENXIO; 20463288Sseb goto done; 20472311Sseb } 20482311Sseb 20493288Sseb if (mtp->mt_ref != 0) { 20503288Sseb err = EBUSY; 20513288Sseb goto done; 20522311Sseb } 20532311Sseb 20542311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 20552311Sseb ASSERT(err == 0); 20562311Sseb if (err != 0) { 20572311Sseb /* This should never happen, thus the ASSERT() above. */ 20583288Sseb err = EINVAL; 20593288Sseb goto done; 20602311Sseb } 20612311Sseb ASSERT(mtp == (mactype_t *)val); 20622311Sseb 20632311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 20642311Sseb kmem_free(mtp, sizeof (mactype_t)); 20653288Sseb done: 20663288Sseb mutex_exit(&i_mactype_lock); 20673288Sseb return (err); 20682311Sseb } 20693448Sdh155122 20703448Sdh155122 int 20713448Sdh155122 mac_vlan_create(mac_handle_t mh, const char *name, minor_t minor) 20723448Sdh155122 { 20733448Sdh155122 mac_impl_t *mip = (mac_impl_t *)mh; 20743448Sdh155122 20753448Sdh155122 /* Create a style-1 DLPI device */ 20763448Sdh155122 if (ddi_create_minor_node(mip->mi_dip, (char *)name, S_IFCHR, minor, 20773448Sdh155122 DDI_NT_NET, 0) != DDI_SUCCESS) { 20783448Sdh155122 return (-1); 20793448Sdh155122 } 20803448Sdh155122 return (0); 20813448Sdh155122 } 20823448Sdh155122 20833448Sdh155122 void 20843448Sdh155122 mac_vlan_remove(mac_handle_t mh, const char *name) 20853448Sdh155122 { 20863448Sdh155122 mac_impl_t *mip = (mac_impl_t *)mh; 20873448Sdh155122 dev_info_t *dipp; 20883448Sdh155122 20893448Sdh155122 ddi_remove_minor_node(mip->mi_dip, (char *)name); 20903448Sdh155122 dipp = ddi_get_parent(mip->mi_dip); 20913448Sdh155122 (void) devfs_clean(dipp, NULL, 0); 20923448Sdh155122 } 2093