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 */ 215084Sjohnlev 220Sstevel@tonic-gate /* 235895Syz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 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> 345895Syz147064 #include <sys/id_space.h> 356077Syz147064 #include <sys/esunddi.h> 360Sstevel@tonic-gate #include <sys/stat.h> 375895Syz147064 #include <sys/mkdev.h> 380Sstevel@tonic-gate #include <sys/stream.h> 390Sstevel@tonic-gate #include <sys/strsun.h> 400Sstevel@tonic-gate #include <sys/strsubr.h> 410Sstevel@tonic-gate #include <sys/dlpi.h> 425895Syz147064 #include <sys/dls.h> 43269Sericheng #include <sys/modhash.h> 445895Syz147064 #include <sys/vlan.h> 450Sstevel@tonic-gate #include <sys/mac.h> 460Sstevel@tonic-gate #include <sys/mac_impl.h> 47269Sericheng #include <sys/dld.h> 482311Sseb #include <sys/modctl.h> 493448Sdh155122 #include <sys/fs/dv_node.h> 505009Sgd78059 #include <sys/thread.h> 515009Sgd78059 #include <sys/proc.h> 525009Sgd78059 #include <sys/callb.h> 535009Sgd78059 #include <sys/cpuvar.h> 543288Sseb #include <sys/atomic.h> 554913Sethindra #include <sys/sdt.h> 565903Ssowmini #include <inet/nd.h> 576512Ssowmini #include <sys/ethernet.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate static kmem_cache_t *i_mac_impl_cachep; 62269Sericheng static mod_hash_t *i_mac_impl_hash; 63269Sericheng krwlock_t i_mac_impl_lock; 64269Sericheng uint_t i_mac_impl_count; 655084Sjohnlev static kmem_cache_t *mac_vnic_tx_cache; 665895Syz147064 static id_space_t *minor_ids; 675895Syz147064 static uint32_t minor_count; 680Sstevel@tonic-gate 692311Sseb #define MACTYPE_KMODDIR "mac" 702311Sseb #define MACTYPE_HASHSZ 67 712311Sseb static mod_hash_t *i_mactype_hash; 723288Sseb /* 733288Sseb * i_mactype_lock synchronizes threads that obtain references to mactype_t 743288Sseb * structures through i_mactype_getplugin(). 753288Sseb */ 763288Sseb static kmutex_t i_mactype_lock; 772311Sseb 785009Sgd78059 static void i_mac_notify_thread(void *); 795084Sjohnlev static mblk_t *mac_vnic_tx(void *, mblk_t *); 805084Sjohnlev static mblk_t *mac_vnic_txloop(void *, mblk_t *); 816512Ssowmini static void mac_register_priv_prop(mac_impl_t *, mac_priv_prop_t *, uint_t); 82*7406SSowmini.Varadhan@Sun.COM static void mac_unregister_priv_prop(mac_impl_t *); 831852Syz147064 840Sstevel@tonic-gate /* 850Sstevel@tonic-gate * Private functions. 860Sstevel@tonic-gate */ 870Sstevel@tonic-gate 880Sstevel@tonic-gate /*ARGSUSED*/ 890Sstevel@tonic-gate static int 900Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag) 910Sstevel@tonic-gate { 920Sstevel@tonic-gate mac_impl_t *mip = buf; 930Sstevel@tonic-gate 940Sstevel@tonic-gate bzero(buf, sizeof (mac_impl_t)); 950Sstevel@tonic-gate 962311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 970Sstevel@tonic-gate 980Sstevel@tonic-gate rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 995895Syz147064 rw_init(&mip->mi_gen_lock, NULL, RW_DRIVER, NULL); 1000Sstevel@tonic-gate rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 1010Sstevel@tonic-gate rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 1020Sstevel@tonic-gate rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 1035084Sjohnlev rw_init(&mip->mi_tx_lock, NULL, RW_DRIVER, NULL); 1040Sstevel@tonic-gate rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 1050Sstevel@tonic-gate mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 1065009Sgd78059 mutex_init(&mip->mi_notify_bits_lock, NULL, MUTEX_DRIVER, NULL); 1071852Syz147064 cv_init(&mip->mi_notify_cv, NULL, CV_DRIVER, NULL); 1084913Sethindra mutex_init(&mip->mi_lock, NULL, MUTEX_DRIVER, NULL); 1094913Sethindra cv_init(&mip->mi_rx_cv, NULL, CV_DRIVER, NULL); 1100Sstevel@tonic-gate return (0); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /*ARGSUSED*/ 1140Sstevel@tonic-gate static void 1150Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate mac_impl_t *mip = buf; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 1205895Syz147064 ASSERT(!mip->mi_exclusive); 1210Sstevel@tonic-gate ASSERT(mip->mi_active == 0); 1222311Sseb ASSERT(mip->mi_linkstate == LINK_STATE_UNKNOWN); 1230Sstevel@tonic-gate ASSERT(mip->mi_devpromisc == 0); 1240Sstevel@tonic-gate ASSERT(mip->mi_promisc == 0); 1250Sstevel@tonic-gate ASSERT(mip->mi_mmap == NULL); 1265895Syz147064 ASSERT(mip->mi_mmrp == NULL); 1270Sstevel@tonic-gate ASSERT(mip->mi_mnfp == NULL); 1280Sstevel@tonic-gate ASSERT(mip->mi_resource_add == NULL); 1290Sstevel@tonic-gate ASSERT(mip->mi_ksp == NULL); 1302311Sseb ASSERT(mip->mi_kstat_count == 0); 1315009Sgd78059 ASSERT(mip->mi_notify_bits == 0); 1325009Sgd78059 ASSERT(mip->mi_notify_thread == NULL); 1330Sstevel@tonic-gate 1345895Syz147064 rw_destroy(&mip->mi_gen_lock); 1350Sstevel@tonic-gate rw_destroy(&mip->mi_state_lock); 1360Sstevel@tonic-gate rw_destroy(&mip->mi_data_lock); 1370Sstevel@tonic-gate rw_destroy(&mip->mi_notify_lock); 1380Sstevel@tonic-gate rw_destroy(&mip->mi_rx_lock); 1395084Sjohnlev rw_destroy(&mip->mi_tx_lock); 1400Sstevel@tonic-gate rw_destroy(&mip->mi_resource_lock); 1410Sstevel@tonic-gate mutex_destroy(&mip->mi_activelink_lock); 1425009Sgd78059 mutex_destroy(&mip->mi_notify_bits_lock); 1431852Syz147064 cv_destroy(&mip->mi_notify_cv); 1444913Sethindra mutex_destroy(&mip->mi_lock); 1454913Sethindra cv_destroy(&mip->mi_rx_cv); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1485084Sjohnlev /* 1495084Sjohnlev * mac_vnic_tx_t kmem cache support functions. 1505084Sjohnlev */ 1515084Sjohnlev 1525084Sjohnlev /* ARGSUSED */ 1535084Sjohnlev static int 1545084Sjohnlev i_mac_vnic_tx_ctor(void *buf, void *arg, int mkflag) 1555084Sjohnlev { 1565084Sjohnlev mac_vnic_tx_t *vnic_tx = buf; 1575084Sjohnlev 1585084Sjohnlev bzero(buf, sizeof (mac_vnic_tx_t)); 1595084Sjohnlev mutex_init(&vnic_tx->mv_lock, NULL, MUTEX_DRIVER, NULL); 1605084Sjohnlev cv_init(&vnic_tx->mv_cv, NULL, CV_DRIVER, NULL); 1615084Sjohnlev return (0); 1625084Sjohnlev } 1635084Sjohnlev 1645084Sjohnlev /* ARGSUSED */ 1655084Sjohnlev static void 1665084Sjohnlev i_mac_vnic_tx_dtor(void *buf, void *arg) 1675084Sjohnlev { 1685084Sjohnlev mac_vnic_tx_t *vnic_tx = buf; 1695084Sjohnlev 1705084Sjohnlev ASSERT(vnic_tx->mv_refs == 0); 1715084Sjohnlev mutex_destroy(&vnic_tx->mv_lock); 1725084Sjohnlev cv_destroy(&vnic_tx->mv_cv); 1735084Sjohnlev } 1745084Sjohnlev 1750Sstevel@tonic-gate static void 1760Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 1770Sstevel@tonic-gate { 1781852Syz147064 rw_enter(&i_mac_impl_lock, RW_READER); 1791852Syz147064 if (mip->mi_disabled) 1801852Syz147064 goto exit; 1811852Syz147064 1825009Sgd78059 /* 1835009Sgd78059 * Guard against incorrect notifications. (Running a newer 1845009Sgd78059 * mac client against an older implementation?) 1855009Sgd78059 */ 1865009Sgd78059 if (type >= MAC_NNOTE) 1871852Syz147064 goto exit; 1881852Syz147064 1895009Sgd78059 mutex_enter(&mip->mi_notify_bits_lock); 1905009Sgd78059 mip->mi_notify_bits |= (1 << type); 1915009Sgd78059 cv_broadcast(&mip->mi_notify_cv); 1925009Sgd78059 mutex_exit(&mip->mi_notify_bits_lock); 1931852Syz147064 1941852Syz147064 exit: 1951852Syz147064 rw_exit(&i_mac_impl_lock); 1961852Syz147064 } 1971852Syz147064 1981852Syz147064 static void 1994403Sgd78059 i_mac_log_link_state(mac_impl_t *mip) 2004403Sgd78059 { 2014403Sgd78059 /* 2024403Sgd78059 * If no change, then it is not interesting. 2034403Sgd78059 */ 2044403Sgd78059 if (mip->mi_lastlinkstate == mip->mi_linkstate) 2054403Sgd78059 return; 2064403Sgd78059 2074403Sgd78059 switch (mip->mi_linkstate) { 2084403Sgd78059 case LINK_STATE_UP: 2094403Sgd78059 if (mip->mi_type->mt_ops.mtops_ops & MTOPS_LINK_DETAILS) { 2104403Sgd78059 char det[200]; 2114403Sgd78059 2124403Sgd78059 mip->mi_type->mt_ops.mtops_link_details(det, 2134403Sgd78059 sizeof (det), (mac_handle_t)mip, mip->mi_pdata); 2144403Sgd78059 2154403Sgd78059 cmn_err(CE_NOTE, "!%s link up, %s", mip->mi_name, det); 2164403Sgd78059 } else { 2174403Sgd78059 cmn_err(CE_NOTE, "!%s link up", mip->mi_name); 2184403Sgd78059 } 2194403Sgd78059 break; 2204403Sgd78059 2214403Sgd78059 case LINK_STATE_DOWN: 2224403Sgd78059 /* 2234403Sgd78059 * Only transitions from UP to DOWN are interesting 2244403Sgd78059 */ 2254403Sgd78059 if (mip->mi_lastlinkstate != LINK_STATE_UNKNOWN) 2264403Sgd78059 cmn_err(CE_NOTE, "!%s link down", mip->mi_name); 2274403Sgd78059 break; 2284403Sgd78059 2294403Sgd78059 case LINK_STATE_UNKNOWN: 2304403Sgd78059 /* 2314403Sgd78059 * This case is normally not interesting. 2324403Sgd78059 */ 2334403Sgd78059 break; 2344403Sgd78059 } 2354403Sgd78059 mip->mi_lastlinkstate = mip->mi_linkstate; 2364403Sgd78059 } 2374403Sgd78059 2384403Sgd78059 static void 2395009Sgd78059 i_mac_notify_thread(void *arg) 2401852Syz147064 { 2415009Sgd78059 mac_impl_t *mip = arg; 2425009Sgd78059 callb_cpr_t cprinfo; 2435009Sgd78059 2445009Sgd78059 CALLB_CPR_INIT(&cprinfo, &mip->mi_notify_bits_lock, callb_generic_cpr, 2455009Sgd78059 "i_mac_notify_thread"); 2465009Sgd78059 2475009Sgd78059 mutex_enter(&mip->mi_notify_bits_lock); 2485009Sgd78059 for (;;) { 2495009Sgd78059 uint32_t bits; 2505009Sgd78059 uint32_t type; 2510Sstevel@tonic-gate 2525009Sgd78059 bits = mip->mi_notify_bits; 2535009Sgd78059 if (bits == 0) { 2545009Sgd78059 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2555009Sgd78059 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); 2565009Sgd78059 CALLB_CPR_SAFE_END(&cprinfo, &mip->mi_notify_bits_lock); 2575009Sgd78059 continue; 2585009Sgd78059 } 2595009Sgd78059 mip->mi_notify_bits = 0; 2605009Sgd78059 2615009Sgd78059 if ((bits & (1 << MAC_NNOTE)) != 0) { 2625009Sgd78059 /* request to quit */ 2635009Sgd78059 ASSERT(mip->mi_disabled); 2645009Sgd78059 break; 2655009Sgd78059 } 2665009Sgd78059 2675009Sgd78059 mutex_exit(&mip->mi_notify_bits_lock); 2681852Syz147064 2695009Sgd78059 /* 2705009Sgd78059 * Log link changes. 2715009Sgd78059 */ 2725009Sgd78059 if ((bits & (1 << MAC_NOTE_LINK)) != 0) 2735009Sgd78059 i_mac_log_link_state(mip); 2745009Sgd78059 2755009Sgd78059 /* 2765009Sgd78059 * Do notification callbacks for each notification type. 2775009Sgd78059 */ 2785009Sgd78059 for (type = 0; type < MAC_NNOTE; type++) { 2795009Sgd78059 mac_notify_fn_t *mnfp; 2805009Sgd78059 2815009Sgd78059 if ((bits & (1 << type)) == 0) { 2825009Sgd78059 continue; 2835009Sgd78059 } 2844403Sgd78059 2855009Sgd78059 /* 2865009Sgd78059 * Walk the list of notifications. 2875009Sgd78059 */ 2885009Sgd78059 rw_enter(&mip->mi_notify_lock, RW_READER); 2895009Sgd78059 for (mnfp = mip->mi_mnfp; mnfp != NULL; 2905009Sgd78059 mnfp = mnfp->mnf_nextp) { 2910Sstevel@tonic-gate 2925009Sgd78059 mnfp->mnf_fn(mnfp->mnf_arg, type); 2935009Sgd78059 } 2945009Sgd78059 rw_exit(&mip->mi_notify_lock); 2955009Sgd78059 } 2965009Sgd78059 2975009Sgd78059 mutex_enter(&mip->mi_notify_bits_lock); 2980Sstevel@tonic-gate } 2995009Sgd78059 3005009Sgd78059 mip->mi_notify_thread = NULL; 3015009Sgd78059 cv_broadcast(&mip->mi_notify_cv); 3025009Sgd78059 3035009Sgd78059 CALLB_CPR_EXIT(&cprinfo); 3045009Sgd78059 3055009Sgd78059 thread_exit(); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3082311Sseb static mactype_t * 3093288Sseb i_mactype_getplugin(const char *pname) 3102311Sseb { 3112311Sseb mactype_t *mtype = NULL; 3122311Sseb boolean_t tried_modload = B_FALSE; 3132311Sseb 3143288Sseb mutex_enter(&i_mactype_lock); 3153288Sseb 3162311Sseb find_registered_mactype: 3173288Sseb if (mod_hash_find(i_mactype_hash, (mod_hash_key_t)pname, 3183288Sseb (mod_hash_val_t *)&mtype) != 0) { 3193288Sseb if (!tried_modload) { 3203288Sseb /* 3213288Sseb * If the plugin has not yet been loaded, then 3223288Sseb * attempt to load it now. If modload() succeeds, 3233288Sseb * the plugin should have registered using 3243288Sseb * mactype_register(), in which case we can go back 3253288Sseb * and attempt to find it again. 3263288Sseb */ 3273288Sseb if (modload(MACTYPE_KMODDIR, (char *)pname) != -1) { 3283288Sseb tried_modload = B_TRUE; 3293288Sseb goto find_registered_mactype; 3303288Sseb } 3313288Sseb } 3323288Sseb } else { 3332311Sseb /* 3343288Sseb * Note that there's no danger that the plugin we've loaded 3353288Sseb * could be unloaded between the modload() step and the 3363288Sseb * reference count bump here, as we're holding 3373288Sseb * i_mactype_lock, which mactype_unregister() also holds. 3382311Sseb */ 3393288Sseb atomic_inc_32(&mtype->mt_ref); 3402311Sseb } 3412311Sseb 3423288Sseb mutex_exit(&i_mactype_lock); 3433288Sseb return (mtype); 3442311Sseb } 3452311Sseb 3460Sstevel@tonic-gate /* 3470Sstevel@tonic-gate * Module initialization functions. 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate void 3510Sstevel@tonic-gate mac_init(void) 3520Sstevel@tonic-gate { 3530Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 3542311Sseb sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, 3552311Sseb NULL, NULL, NULL, 0); 3560Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL); 3570Sstevel@tonic-gate 3585084Sjohnlev mac_vnic_tx_cache = kmem_cache_create("mac_vnic_tx_cache", 3595084Sjohnlev sizeof (mac_vnic_tx_t), 0, i_mac_vnic_tx_ctor, i_mac_vnic_tx_dtor, 3605084Sjohnlev NULL, NULL, NULL, 0); 3615084Sjohnlev ASSERT(mac_vnic_tx_cache != NULL); 3625084Sjohnlev 363269Sericheng i_mac_impl_hash = mod_hash_create_extended("mac_impl_hash", 364269Sericheng IMPL_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor, 365269Sericheng mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 366269Sericheng rw_init(&i_mac_impl_lock, NULL, RW_DEFAULT, NULL); 367269Sericheng i_mac_impl_count = 0; 3682311Sseb 3692311Sseb i_mactype_hash = mod_hash_create_extended("mactype_hash", 3702311Sseb MACTYPE_HASHSZ, 3712311Sseb mod_hash_null_keydtor, mod_hash_null_valdtor, 3722311Sseb mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP); 3735895Syz147064 3745895Syz147064 /* 3755895Syz147064 * Allocate an id space to manage minor numbers. The range of the 3765895Syz147064 * space will be from MAC_MAX_MINOR+1 to MAXMIN32 (maximum legal 3775895Syz147064 * minor number is MAXMIN, but id_t is type of integer and does not 3785895Syz147064 * allow MAXMIN). 3795895Syz147064 */ 3805895Syz147064 minor_ids = id_space_create("mac_minor_ids", MAC_MAX_MINOR+1, MAXMIN32); 3815895Syz147064 ASSERT(minor_ids != NULL); 3825895Syz147064 minor_count = 0; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate int 3860Sstevel@tonic-gate mac_fini(void) 3870Sstevel@tonic-gate { 3885895Syz147064 if (i_mac_impl_count > 0 || minor_count > 0) 389269Sericheng return (EBUSY); 3900Sstevel@tonic-gate 3915895Syz147064 id_space_destroy(minor_ids); 3925895Syz147064 393269Sericheng mod_hash_destroy_hash(i_mac_impl_hash); 394269Sericheng rw_destroy(&i_mac_impl_lock); 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate kmem_cache_destroy(i_mac_impl_cachep); 3975084Sjohnlev kmem_cache_destroy(mac_vnic_tx_cache); 3982311Sseb 3992311Sseb mod_hash_destroy_hash(i_mactype_hash); 4000Sstevel@tonic-gate return (0); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate /* 4040Sstevel@tonic-gate * Client functions. 4050Sstevel@tonic-gate */ 4060Sstevel@tonic-gate 4075895Syz147064 static int 4085895Syz147064 mac_hold(const char *macname, mac_impl_t **pmip) 4090Sstevel@tonic-gate { 4100Sstevel@tonic-gate mac_impl_t *mip; 4110Sstevel@tonic-gate int err; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate /* 4140Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our 4150Sstevel@tonic-gate * buffer. 4160Sstevel@tonic-gate */ 4172311Sseb if (strlen(macname) >= MAXNAMELEN) 4180Sstevel@tonic-gate return (EINVAL); 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate /* 4215895Syz147064 * Look up its entry in the global hash table. 4220Sstevel@tonic-gate */ 4235895Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 4245895Syz147064 err = mod_hash_find(i_mac_impl_hash, (mod_hash_key_t)macname, 4255895Syz147064 (mod_hash_val_t *)&mip); 4265895Syz147064 4275895Syz147064 if (err != 0) { 4285895Syz147064 rw_exit(&i_mac_impl_lock); 4295895Syz147064 return (ENOENT); 4305895Syz147064 } 4315895Syz147064 4325895Syz147064 if (mip->mi_disabled) { 4335895Syz147064 rw_exit(&i_mac_impl_lock); 4345895Syz147064 return (ENOENT); 4355895Syz147064 } 4365895Syz147064 4375895Syz147064 if (mip->mi_exclusive) { 4385895Syz147064 rw_exit(&i_mac_impl_lock); 4395895Syz147064 return (EBUSY); 4405895Syz147064 } 4415895Syz147064 4425895Syz147064 mip->mi_ref++; 4435895Syz147064 rw_exit(&i_mac_impl_lock); 4445895Syz147064 4455895Syz147064 *pmip = mip; 4465895Syz147064 return (0); 4475895Syz147064 } 4485895Syz147064 4495895Syz147064 static void 4505895Syz147064 mac_rele(mac_impl_t *mip) 4515895Syz147064 { 4525895Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 4535895Syz147064 ASSERT(mip->mi_ref != 0); 4545895Syz147064 if (--mip->mi_ref == 0) 4555895Syz147064 ASSERT(!mip->mi_activelink); 4565895Syz147064 rw_exit(&i_mac_impl_lock); 4575895Syz147064 } 4585895Syz147064 4595895Syz147064 int 4605895Syz147064 mac_hold_exclusive(mac_handle_t mh) 4615895Syz147064 { 4625895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 4635084Sjohnlev 4640Sstevel@tonic-gate /* 4655895Syz147064 * Look up its entry in the global hash table. 4660Sstevel@tonic-gate */ 4675895Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 4685895Syz147064 if (mip->mi_disabled) { 4695895Syz147064 rw_exit(&i_mac_impl_lock); 4705895Syz147064 return (ENOENT); 4715895Syz147064 } 4725895Syz147064 4735895Syz147064 if (mip->mi_ref != 0) { 4745895Syz147064 rw_exit(&i_mac_impl_lock); 4755895Syz147064 return (EBUSY); 4765895Syz147064 } 4775895Syz147064 4785895Syz147064 ASSERT(!mip->mi_exclusive); 4795895Syz147064 4805895Syz147064 mip->mi_ref++; 4815895Syz147064 mip->mi_exclusive = B_TRUE; 4825895Syz147064 rw_exit(&i_mac_impl_lock); 4835895Syz147064 return (0); 4845895Syz147064 } 4855895Syz147064 4865895Syz147064 void 4875895Syz147064 mac_rele_exclusive(mac_handle_t mh) 4885895Syz147064 { 4895895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * Look up its entry in the global hash table. 4930Sstevel@tonic-gate */ 494269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 4955895Syz147064 ASSERT(mip->mi_ref == 1 && mip->mi_exclusive); 4965895Syz147064 mip->mi_ref--; 4975895Syz147064 mip->mi_exclusive = B_FALSE; 4985895Syz147064 rw_exit(&i_mac_impl_lock); 4995895Syz147064 } 5005895Syz147064 5015895Syz147064 int 5025895Syz147064 mac_open(const char *macname, mac_handle_t *mhp) 5035895Syz147064 { 5045895Syz147064 mac_impl_t *mip; 5055895Syz147064 int err; 5065895Syz147064 5075895Syz147064 /* 5085895Syz147064 * Look up its entry in the global hash table. 5095895Syz147064 */ 5105895Syz147064 if ((err = mac_hold(macname, &mip)) != 0) 5115895Syz147064 return (err); 5125895Syz147064 5136077Syz147064 /* 5146077Syz147064 * Hold the dip associated to the MAC to prevent it from being 5156077Syz147064 * detached. For a softmac, its underlying dip is held by the 5166077Syz147064 * mi_open() callback. 5176077Syz147064 * 5186077Syz147064 * This is done to be more tolerant with some defective drivers, 5196077Syz147064 * which incorrectly handle mac_unregister() failure in their 5206077Syz147064 * xxx_detach() routine. For example, some drivers ignore the 5216077Syz147064 * failure of mac_unregister() and free all resources that 5226077Syz147064 * that are needed for data transmition. 5236077Syz147064 */ 5246077Syz147064 e_ddi_hold_devi(mip->mi_dip); 5256077Syz147064 5265895Syz147064 rw_enter(&mip->mi_gen_lock, RW_WRITER); 5275895Syz147064 5285895Syz147064 if ((mip->mi_oref != 0) || 5295895Syz147064 !(mip->mi_callbacks->mc_callbacks & MC_OPEN)) { 5305895Syz147064 goto done; 531269Sericheng } 5320Sstevel@tonic-gate 5335895Syz147064 /* 5345895Syz147064 * Note that we do not hold i_mac_impl_lock when calling the 5355895Syz147064 * mc_open() callback function to avoid deadlock with the 5365895Syz147064 * i_mac_notify() function. 5375895Syz147064 */ 5385895Syz147064 if ((err = mip->mi_open(mip->mi_driver)) != 0) { 5395895Syz147064 rw_exit(&mip->mi_gen_lock); 5406077Syz147064 ddi_release_devi(mip->mi_dip); 5415895Syz147064 mac_rele(mip); 5425895Syz147064 return (err); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5455895Syz147064 done: 5465895Syz147064 mip->mi_oref++; 5475895Syz147064 rw_exit(&mip->mi_gen_lock); 5480Sstevel@tonic-gate *mhp = (mac_handle_t)mip; 5490Sstevel@tonic-gate return (0); 5505895Syz147064 } 5515895Syz147064 5525895Syz147064 int 5535895Syz147064 mac_open_by_linkid(datalink_id_t linkid, mac_handle_t *mhp) 5545895Syz147064 { 5555895Syz147064 dls_dl_handle_t dlh; 5565895Syz147064 int err; 5575895Syz147064 5585895Syz147064 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) 5595895Syz147064 return (err); 5605895Syz147064 5615895Syz147064 if (dls_devnet_vid(dlh) != VLAN_ID_NONE) { 5625895Syz147064 err = EINVAL; 5635895Syz147064 goto done; 5645895Syz147064 } 5655895Syz147064 5666916Sartem dls_devnet_prop_task_wait(dlh); 5676916Sartem 5685895Syz147064 err = mac_open(dls_devnet_mac(dlh), mhp); 5695895Syz147064 5705895Syz147064 done: 5715895Syz147064 dls_devnet_rele_tmp(dlh); 5720Sstevel@tonic-gate return (err); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5755895Syz147064 int 5765895Syz147064 mac_open_by_linkname(const char *link, mac_handle_t *mhp) 5775895Syz147064 { 5785895Syz147064 datalink_id_t linkid; 5795895Syz147064 int err; 5805895Syz147064 5815895Syz147064 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0) 5825895Syz147064 return (err); 5835895Syz147064 return (mac_open_by_linkid(linkid, mhp)); 5845895Syz147064 } 5855895Syz147064 5860Sstevel@tonic-gate void 5870Sstevel@tonic-gate mac_close(mac_handle_t mh) 5880Sstevel@tonic-gate { 5890Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 5905895Syz147064 5915895Syz147064 rw_enter(&mip->mi_gen_lock, RW_WRITER); 5925895Syz147064 5935895Syz147064 ASSERT(mip->mi_oref != 0); 5945895Syz147064 if (--mip->mi_oref == 0) { 5955895Syz147064 if ((mip->mi_callbacks->mc_callbacks & MC_CLOSE)) 5965895Syz147064 mip->mi_close(mip->mi_driver); 5970Sstevel@tonic-gate } 5985895Syz147064 rw_exit(&mip->mi_gen_lock); 5995895Syz147064 6006077Syz147064 ddi_release_devi(mip->mi_dip); 6015895Syz147064 mac_rele(mip); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate const mac_info_t * 6050Sstevel@tonic-gate mac_info(mac_handle_t mh) 6060Sstevel@tonic-gate { 6072311Sseb return (&((mac_impl_t *)mh)->mi_info); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 610269Sericheng dev_info_t * 611269Sericheng mac_devinfo_get(mac_handle_t mh) 612269Sericheng { 6132311Sseb return (((mac_impl_t *)mh)->mi_dip); 614269Sericheng } 615269Sericheng 6165895Syz147064 const char * 6175895Syz147064 mac_name(mac_handle_t mh) 6185895Syz147064 { 6195895Syz147064 return (((mac_impl_t *)mh)->mi_name); 6205895Syz147064 } 6215895Syz147064 6225895Syz147064 minor_t 6235895Syz147064 mac_minor(mac_handle_t mh) 6245895Syz147064 { 6255895Syz147064 return (((mac_impl_t *)mh)->mi_minor); 6265895Syz147064 } 6275895Syz147064 6280Sstevel@tonic-gate uint64_t 6292311Sseb mac_stat_get(mac_handle_t mh, uint_t stat) 6300Sstevel@tonic-gate { 6310Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6322311Sseb uint64_t val; 6332311Sseb int ret; 6340Sstevel@tonic-gate 6352311Sseb /* 6362311Sseb * The range of stat determines where it is maintained. Stat 6372311Sseb * values from 0 up to (but not including) MAC_STAT_MIN are 6382311Sseb * mainteined by the mac module itself. Everything else is 6392311Sseb * maintained by the driver. 6402311Sseb */ 6412311Sseb if (stat < MAC_STAT_MIN) { 6422311Sseb /* These stats are maintained by the mac module itself. */ 6432311Sseb switch (stat) { 6442311Sseb case MAC_STAT_LINK_STATE: 6452311Sseb return (mip->mi_linkstate); 6462311Sseb case MAC_STAT_LINK_UP: 6472311Sseb return (mip->mi_linkstate == LINK_STATE_UP); 6482311Sseb case MAC_STAT_PROMISC: 6492311Sseb return (mip->mi_devpromisc != 0); 6502311Sseb default: 6512311Sseb ASSERT(B_FALSE); 6522311Sseb } 6532311Sseb } 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate /* 6560Sstevel@tonic-gate * Call the driver to get the given statistic. 6570Sstevel@tonic-gate */ 6582311Sseb ret = mip->mi_getstat(mip->mi_driver, stat, &val); 6592311Sseb if (ret != 0) { 6602311Sseb /* 6612311Sseb * The driver doesn't support this statistic. Get the 6622311Sseb * statistic's default value. 6632311Sseb */ 6642311Sseb val = mac_stat_default(mip, stat); 6652311Sseb } 6662311Sseb return (val); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate int 6700Sstevel@tonic-gate mac_start(mac_handle_t mh) 6710Sstevel@tonic-gate { 6720Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 6730Sstevel@tonic-gate int err; 6740Sstevel@tonic-gate 6752311Sseb ASSERT(mip->mi_start != NULL); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /* 6800Sstevel@tonic-gate * Check whether the device is already started. 6810Sstevel@tonic-gate */ 6820Sstevel@tonic-gate if (mip->mi_active++ != 0) { 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * It's already started so there's nothing more to do. 6850Sstevel@tonic-gate */ 6860Sstevel@tonic-gate err = 0; 6870Sstevel@tonic-gate goto done; 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * Start the device. 6920Sstevel@tonic-gate */ 6932311Sseb if ((err = mip->mi_start(mip->mi_driver)) != 0) 6940Sstevel@tonic-gate --mip->mi_active; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate done: 6970Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 6980Sstevel@tonic-gate return (err); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate void 7020Sstevel@tonic-gate mac_stop(mac_handle_t mh) 7030Sstevel@tonic-gate { 7040Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7050Sstevel@tonic-gate 7062311Sseb ASSERT(mip->mi_stop != NULL); 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /* 7110Sstevel@tonic-gate * Check whether the device is still needed. 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate ASSERT(mip->mi_active != 0); 7140Sstevel@tonic-gate if (--mip->mi_active != 0) { 7150Sstevel@tonic-gate /* 7160Sstevel@tonic-gate * It's still needed so there's nothing more to do. 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate goto done; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /* 7220Sstevel@tonic-gate * Stop the device. 7230Sstevel@tonic-gate */ 7242311Sseb mip->mi_stop(mip->mi_driver); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate done: 7270Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate 7300Sstevel@tonic-gate int 7310Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 7320Sstevel@tonic-gate { 7330Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7340Sstevel@tonic-gate mac_multicst_addr_t **pp; 7350Sstevel@tonic-gate mac_multicst_addr_t *p; 7360Sstevel@tonic-gate int err; 7370Sstevel@tonic-gate 7382311Sseb ASSERT(mip->mi_multicst != NULL); 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate /* 7410Sstevel@tonic-gate * Verify the address. 7420Sstevel@tonic-gate */ 7432311Sseb if ((err = mip->mi_type->mt_ops.mtops_multicst_verify(addr, 7442311Sseb mip->mi_pdata)) != 0) { 7452311Sseb return (err); 7462311Sseb } 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * Check whether the given address is already enabled. 7500Sstevel@tonic-gate */ 7510Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 7520Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 7532311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 7542311Sseb 0) { 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * The address is already enabled so just bump the 7570Sstevel@tonic-gate * reference count. 7580Sstevel@tonic-gate */ 7590Sstevel@tonic-gate p->mma_ref++; 7600Sstevel@tonic-gate err = 0; 7610Sstevel@tonic-gate goto done; 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate /* 7660Sstevel@tonic-gate * Allocate a new list entry. 7670Sstevel@tonic-gate */ 7680Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 7690Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 7700Sstevel@tonic-gate err = ENOMEM; 7710Sstevel@tonic-gate goto done; 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * Enable a new multicast address. 7760Sstevel@tonic-gate */ 7772311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_TRUE, addr)) != 0) { 7780Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 7790Sstevel@tonic-gate goto done; 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate /* 7830Sstevel@tonic-gate * Add the address to the list of enabled addresses. 7840Sstevel@tonic-gate */ 7852311Sseb bcopy(addr, p->mma_addr, mip->mi_type->mt_addr_length); 7860Sstevel@tonic-gate p->mma_ref++; 7870Sstevel@tonic-gate *pp = p; 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate done: 7900Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 7910Sstevel@tonic-gate return (err); 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate int 7950Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 7960Sstevel@tonic-gate { 7970Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 7980Sstevel@tonic-gate mac_multicst_addr_t **pp; 7990Sstevel@tonic-gate mac_multicst_addr_t *p; 8000Sstevel@tonic-gate int err; 8010Sstevel@tonic-gate 8022311Sseb ASSERT(mip->mi_multicst != NULL); 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate /* 8050Sstevel@tonic-gate * Find the entry in the list for the given address. 8060Sstevel@tonic-gate */ 8070Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 8080Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 8092311Sseb if (bcmp(p->mma_addr, addr, mip->mi_type->mt_addr_length) == 8102311Sseb 0) { 8110Sstevel@tonic-gate if (--p->mma_ref == 0) 8120Sstevel@tonic-gate break; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* 8150Sstevel@tonic-gate * There is still a reference to this address so 8160Sstevel@tonic-gate * there's nothing more to do. 8170Sstevel@tonic-gate */ 8180Sstevel@tonic-gate err = 0; 8190Sstevel@tonic-gate goto done; 8200Sstevel@tonic-gate } 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * We did not find an entry for the given address so it is not 8250Sstevel@tonic-gate * currently enabled. 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate if (p == NULL) { 8280Sstevel@tonic-gate err = ENOENT; 8290Sstevel@tonic-gate goto done; 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate ASSERT(p->mma_ref == 0); 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * Disable the multicast address. 8350Sstevel@tonic-gate */ 8362311Sseb if ((err = mip->mi_multicst(mip->mi_driver, B_FALSE, addr)) != 0) { 8370Sstevel@tonic-gate p->mma_ref++; 8380Sstevel@tonic-gate goto done; 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate /* 8420Sstevel@tonic-gate * Remove it from the list. 8430Sstevel@tonic-gate */ 8440Sstevel@tonic-gate *pp = p->mma_nextp; 8450Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate done: 8480Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 8490Sstevel@tonic-gate return (err); 8500Sstevel@tonic-gate } 8510Sstevel@tonic-gate 8522331Skrgopi /* 8532331Skrgopi * mac_unicst_verify: Verifies the passed address. It fails 8542331Skrgopi * if the passed address is a group address or has incorrect length. 8552331Skrgopi */ 8562331Skrgopi boolean_t 8572331Skrgopi mac_unicst_verify(mac_handle_t mh, const uint8_t *addr, uint_t len) 8582331Skrgopi { 8592331Skrgopi mac_impl_t *mip = (mac_impl_t *)mh; 8602331Skrgopi 8612331Skrgopi /* 8622331Skrgopi * Verify the address. 8632331Skrgopi */ 8642331Skrgopi if ((len != mip->mi_type->mt_addr_length) || 8652331Skrgopi (mip->mi_type->mt_ops.mtops_unicst_verify(addr, 8662331Skrgopi mip->mi_pdata)) != 0) { 8672331Skrgopi return (B_FALSE); 8682331Skrgopi } else { 8692331Skrgopi return (B_TRUE); 8702331Skrgopi } 8712331Skrgopi } 8722331Skrgopi 8730Sstevel@tonic-gate int 8740Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 8750Sstevel@tonic-gate { 8760Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 8770Sstevel@tonic-gate int err; 8780Sstevel@tonic-gate boolean_t notify = B_FALSE; 8790Sstevel@tonic-gate 8802311Sseb ASSERT(mip->mi_unicst != NULL); 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * Verify the address. 8840Sstevel@tonic-gate */ 8852311Sseb if ((err = mip->mi_type->mt_ops.mtops_unicst_verify(addr, 8862311Sseb mip->mi_pdata)) != 0) { 8872311Sseb return (err); 8882311Sseb } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Program the new unicast address. 8920Sstevel@tonic-gate */ 8930Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate /* 8960Sstevel@tonic-gate * If address doesn't change, do nothing. 8970Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 8980Sstevel@tonic-gate * recursively. 8990Sstevel@tonic-gate */ 9005895Syz147064 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) 9010Sstevel@tonic-gate goto done; 9020Sstevel@tonic-gate 9032311Sseb if ((err = mip->mi_unicst(mip->mi_driver, addr)) != 0) 9040Sstevel@tonic-gate goto done; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /* 9070Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 9080Sstevel@tonic-gate */ 9092311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 9100Sstevel@tonic-gate notify = B_TRUE; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate done: 9130Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate if (notify) 9160Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate return (err); 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate void 9220Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 9230Sstevel@tonic-gate { 9240Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate /* 9272311Sseb * Copy out the current unicast source address. 9280Sstevel@tonic-gate */ 9290Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 9302311Sseb bcopy(mip->mi_addr, addr, mip->mi_type->mt_addr_length); 9312311Sseb rw_exit(&(mip->mi_data_lock)); 9322311Sseb } 9332311Sseb 9342311Sseb void 9352311Sseb mac_dest_get(mac_handle_t mh, uint8_t *addr) 9362311Sseb { 9372311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 9382311Sseb 9392311Sseb /* 9402311Sseb * Copy out the current destination address. 9412311Sseb */ 9422311Sseb rw_enter(&(mip->mi_data_lock), RW_READER); 9432311Sseb bcopy(mip->mi_dstaddr, addr, mip->mi_type->mt_addr_length); 9440Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 9450Sstevel@tonic-gate } 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate int 9480Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 9490Sstevel@tonic-gate { 9500Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 9510Sstevel@tonic-gate int err = 0; 9520Sstevel@tonic-gate 9532311Sseb ASSERT(mip->mi_setpromisc != NULL); 9540Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 9580Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 9590Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 9620Sstevel@tonic-gate if (on) { 9630Sstevel@tonic-gate /* 9640Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 9650Sstevel@tonic-gate */ 9660Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 9672311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_TRUE); 9682311Sseb if (err != 0) { 9690Sstevel@tonic-gate mip->mi_devpromisc--; 9700Sstevel@tonic-gate goto done; 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 9730Sstevel@tonic-gate } 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 9790Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 9800Sstevel@tonic-gate } else { 9810Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 9820Sstevel@tonic-gate err = EPROTO; 9830Sstevel@tonic-gate goto done; 9840Sstevel@tonic-gate } 9850Sstevel@tonic-gate /* 9860Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 9870Sstevel@tonic-gate * enabling. 9880Sstevel@tonic-gate */ 9890Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 9902311Sseb err = mip->mi_setpromisc(mip->mi_driver, B_FALSE); 9912311Sseb if (err != 0) { 9920Sstevel@tonic-gate mip->mi_devpromisc++; 9930Sstevel@tonic-gate goto done; 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate /* 9990Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 10000Sstevel@tonic-gate * enabling. 10010Sstevel@tonic-gate */ 10020Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 10030Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate done: 10070Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 10080Sstevel@tonic-gate return (err); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate boolean_t 10120Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 10130Sstevel@tonic-gate { 10140Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate /* 10190Sstevel@tonic-gate * Return the current promiscuity. 10200Sstevel@tonic-gate */ 10210Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 10220Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 10230Sstevel@tonic-gate else 10240Sstevel@tonic-gate return (mip->mi_promisc != 0); 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate void 10285903Ssowmini mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu) 10295903Ssowmini { 10305903Ssowmini mac_impl_t *mip = (mac_impl_t *)mh; 10315903Ssowmini 10325903Ssowmini if (min_sdu != NULL) 10335903Ssowmini *min_sdu = mip->mi_sdu_min; 10345903Ssowmini if (max_sdu != NULL) 10355903Ssowmini *max_sdu = mip->mi_sdu_max; 10365903Ssowmini } 10375903Ssowmini 10385903Ssowmini void 10390Sstevel@tonic-gate mac_resources(mac_handle_t mh) 10400Sstevel@tonic-gate { 10410Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /* 10442311Sseb * If the driver supports resource registration, call the driver to 10452311Sseb * ask it to register its resources. 10460Sstevel@tonic-gate */ 10472311Sseb if (mip->mi_callbacks->mc_callbacks & MC_RESOURCES) 10482311Sseb mip->mi_resources(mip->mi_driver); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate void 10520Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 10530Sstevel@tonic-gate { 10540Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 10556512Ssowmini int cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; 10566512Ssowmini 10576512Ssowmini if ((cmd == ND_GET && (mip->mi_callbacks->mc_callbacks & MC_GETPROP)) || 10586512Ssowmini (cmd == ND_SET && (mip->mi_callbacks->mc_callbacks & MC_SETPROP))) { 10596512Ssowmini /* 10606512Ssowmini * If ndd props were registered, call them. 10616512Ssowmini * Note that ndd ioctls are Obsolete 10626512Ssowmini */ 10636512Ssowmini mac_ndd_ioctl(mip, wq, bp); 10646512Ssowmini return; 10655903Ssowmini } 10666512Ssowmini 10670Sstevel@tonic-gate /* 10682311Sseb * Call the driver to handle the ioctl. The driver may not support 10692311Sseb * any ioctls, in which case we reply with a NAK on its behalf. 10700Sstevel@tonic-gate */ 10712311Sseb if (mip->mi_callbacks->mc_callbacks & MC_IOCTL) 10722311Sseb mip->mi_ioctl(mip->mi_driver, wq, bp); 10732311Sseb else 10742311Sseb miocnak(wq, bp, 0, EINVAL); 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate 107756Smeem const mac_txinfo_t * 10785084Sjohnlev mac_do_tx_get(mac_handle_t mh, boolean_t is_vnic) 10790Sstevel@tonic-gate { 10800Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 108156Smeem mac_txinfo_t *mtp; 108256Smeem 108356Smeem /* 108456Smeem * Grab the lock to prevent us from racing with MAC_PROMISC being 108556Smeem * changed. This is sufficient since MAC clients are careful to always 108656Smeem * call mac_txloop_add() prior to enabling MAC_PROMISC, and to disable 108756Smeem * MAC_PROMISC prior to calling mac_txloop_remove(). 108856Smeem */ 10895084Sjohnlev rw_enter(&mip->mi_tx_lock, RW_READER); 10900Sstevel@tonic-gate 109156Smeem if (mac_promisc_get(mh, MAC_PROMISC)) { 109256Smeem ASSERT(mip->mi_mtfp != NULL); 10935084Sjohnlev if (mip->mi_vnic_present && !is_vnic) { 10945084Sjohnlev mtp = &mip->mi_vnic_txloopinfo; 10955084Sjohnlev } else { 10965084Sjohnlev mtp = &mip->mi_txloopinfo; 10975084Sjohnlev } 109856Smeem } else { 10995084Sjohnlev if (mip->mi_vnic_present && !is_vnic) { 11005084Sjohnlev mtp = &mip->mi_vnic_txinfo; 11015084Sjohnlev } else { 11025084Sjohnlev /* 11035084Sjohnlev * Note that we cannot ASSERT() that mip->mi_mtfp is 11045084Sjohnlev * NULL, because to satisfy the above ASSERT(), we 11055084Sjohnlev * have to disable MAC_PROMISC prior to calling 11065084Sjohnlev * mac_txloop_remove(). 11075084Sjohnlev */ 11085084Sjohnlev mtp = &mip->mi_txinfo; 11095084Sjohnlev } 111056Smeem } 111156Smeem 11125084Sjohnlev rw_exit(&mip->mi_tx_lock); 111356Smeem return (mtp); 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate 11165084Sjohnlev /* 11175084Sjohnlev * Invoked by VNIC to obtain the transmit entry point. 11185084Sjohnlev */ 11195084Sjohnlev const mac_txinfo_t * 11205084Sjohnlev mac_vnic_tx_get(mac_handle_t mh) 11215084Sjohnlev { 11225084Sjohnlev return (mac_do_tx_get(mh, B_TRUE)); 11235084Sjohnlev } 11245084Sjohnlev 11255084Sjohnlev /* 11265084Sjohnlev * Invoked by any non-VNIC client to obtain the transmit entry point. 11275084Sjohnlev * If a VNIC is present, the VNIC transmit function provided by the VNIC 11285084Sjohnlev * will be returned to the MAC client. 11295084Sjohnlev */ 11305084Sjohnlev const mac_txinfo_t * 11315084Sjohnlev mac_tx_get(mac_handle_t mh) 11325084Sjohnlev { 11335084Sjohnlev return (mac_do_tx_get(mh, B_FALSE)); 11345084Sjohnlev } 11355084Sjohnlev 11360Sstevel@tonic-gate link_state_t 11370Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 11380Sstevel@tonic-gate { 11392311Sseb return (((mac_impl_t *)mh)->mi_linkstate); 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate mac_notify_handle_t 11430Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 11440Sstevel@tonic-gate { 11450Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 11460Sstevel@tonic-gate mac_notify_fn_t *mnfp; 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 11490Sstevel@tonic-gate mnfp->mnf_fn = notify; 11500Sstevel@tonic-gate mnfp->mnf_arg = arg; 11510Sstevel@tonic-gate 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 11540Sstevel@tonic-gate */ 11551852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 11560Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 11570Sstevel@tonic-gate mip->mi_mnfp = mnfp; 11581852Syz147064 rw_exit(&mip->mi_notify_lock); 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate void 11640Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 11650Sstevel@tonic-gate { 11660Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 11670Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 11680Sstevel@tonic-gate mac_notify_fn_t **pp; 11690Sstevel@tonic-gate mac_notify_fn_t *p; 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate /* 11720Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 11730Sstevel@tonic-gate */ 11741852Syz147064 rw_enter(&mip->mi_notify_lock, RW_WRITER); 11750Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 11760Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 11770Sstevel@tonic-gate if (p == mnfp) 11780Sstevel@tonic-gate break; 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate ASSERT(p != NULL); 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate /* 11830Sstevel@tonic-gate * Remove it from the list. 11840Sstevel@tonic-gate */ 11850Sstevel@tonic-gate *pp = p->mnf_nextp; 11861852Syz147064 rw_exit(&mip->mi_notify_lock); 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate /* 11890Sstevel@tonic-gate * Free it. 11900Sstevel@tonic-gate */ 11910Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate void 11950Sstevel@tonic-gate mac_notify(mac_handle_t mh) 11960Sstevel@tonic-gate { 11970Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 11980Sstevel@tonic-gate mac_notify_type_t type; 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 12010Sstevel@tonic-gate i_mac_notify(mip, type); 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate 12044913Sethindra /* 12054913Sethindra * Register a receive function for this mac. 12064913Sethindra * More information on this function's interaction with mac_rx() 12074913Sethindra * can be found atop mac_rx(). 12084913Sethindra */ 12090Sstevel@tonic-gate mac_rx_handle_t 12105084Sjohnlev mac_do_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg, boolean_t is_active) 12110Sstevel@tonic-gate { 12120Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 12130Sstevel@tonic-gate mac_rx_fn_t *mrfp; 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 12160Sstevel@tonic-gate mrfp->mrf_fn = rx; 12170Sstevel@tonic-gate mrfp->mrf_arg = arg; 12185084Sjohnlev mrfp->mrf_active = is_active; 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate /* 12210Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 12220Sstevel@tonic-gate */ 12230Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 12244913Sethindra 12254913Sethindra /* 12264913Sethindra * mac_rx() will only call callbacks that are marked inuse. 12274913Sethindra */ 12284913Sethindra mrfp->mrf_inuse = B_TRUE; 12290Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 12304913Sethindra 12314913Sethindra /* 12324913Sethindra * mac_rx() could be traversing the remainder of the list 12334913Sethindra * and miss the new callback we're adding here. This is not a problem 12344913Sethindra * because we do not guarantee the callback to take effect immediately 12354913Sethindra * after mac_rx_add() returns. 12364913Sethindra */ 12370Sstevel@tonic-gate mip->mi_mrfp = mrfp; 12380Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12435084Sjohnlev mac_rx_handle_t 12445084Sjohnlev mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 12455084Sjohnlev { 12465084Sjohnlev return (mac_do_rx_add(mh, rx, arg, B_FALSE)); 12475084Sjohnlev } 12485084Sjohnlev 12495084Sjohnlev mac_rx_handle_t 12505084Sjohnlev mac_active_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 12515084Sjohnlev { 12525084Sjohnlev return (mac_do_rx_add(mh, rx, arg, B_TRUE)); 12535084Sjohnlev } 12545084Sjohnlev 12550Sstevel@tonic-gate /* 12564913Sethindra * Unregister a receive function for this mac. 12574913Sethindra * This function does not block if wait is B_FALSE. This is useful 12584913Sethindra * for clients who call mac_rx_remove() from a non-blockable context. 12594913Sethindra * More information on this function's interaction with mac_rx() 12604913Sethindra * can be found atop mac_rx(). 12610Sstevel@tonic-gate */ 12620Sstevel@tonic-gate void 12634913Sethindra mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh, boolean_t wait) 12640Sstevel@tonic-gate { 12650Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 12660Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 12670Sstevel@tonic-gate mac_rx_fn_t **pp; 12680Sstevel@tonic-gate mac_rx_fn_t *p; 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate /* 12710Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 12720Sstevel@tonic-gate */ 12734913Sethindra rw_enter(&mip->mi_rx_lock, RW_WRITER); 12740Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 12750Sstevel@tonic-gate if (p == mrfp) 12760Sstevel@tonic-gate break; 12770Sstevel@tonic-gate } 12780Sstevel@tonic-gate ASSERT(p != NULL); 12790Sstevel@tonic-gate 12804913Sethindra /* 12814913Sethindra * If mac_rx() is running, mark callback for deletion 12824913Sethindra * and return (if wait is false), or wait until mac_rx() 12834913Sethindra * exits (if wait is true). 12844913Sethindra */ 12854913Sethindra if (mip->mi_rx_ref > 0) { 12864913Sethindra DTRACE_PROBE1(defer_delete, mac_impl_t *, mip); 12874913Sethindra p->mrf_inuse = B_FALSE; 12884913Sethindra mutex_enter(&mip->mi_lock); 12894913Sethindra mip->mi_rx_removed++; 12904913Sethindra mutex_exit(&mip->mi_lock); 12914913Sethindra 12924913Sethindra rw_exit(&mip->mi_rx_lock); 12934913Sethindra if (wait) 12944913Sethindra mac_rx_remove_wait(mh); 12954913Sethindra return; 12964913Sethindra } 12974913Sethindra 12980Sstevel@tonic-gate /* Remove it from the list. */ 12990Sstevel@tonic-gate *pp = p->mrf_nextp; 13000Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 13014913Sethindra rw_exit(&mip->mi_rx_lock); 13024913Sethindra } 13034913Sethindra 13044913Sethindra /* 13054913Sethindra * Wait for all pending callback removals to be completed by mac_rx(). 13064913Sethindra * Note that if we call mac_rx_remove() immediately before this, there is no 13074913Sethindra * guarantee we would wait *only* on the callback that we specified. 13084913Sethindra * mac_rx_remove() could have been called by other threads and we would have 13094913Sethindra * to wait for other marked callbacks to be removed as well. 13104913Sethindra */ 13114913Sethindra void 13124913Sethindra mac_rx_remove_wait(mac_handle_t mh) 13134913Sethindra { 13144913Sethindra mac_impl_t *mip = (mac_impl_t *)mh; 13154913Sethindra 13164913Sethindra mutex_enter(&mip->mi_lock); 13174913Sethindra while (mip->mi_rx_removed > 0) { 13184913Sethindra DTRACE_PROBE1(need_wait, mac_impl_t *, mip); 13194913Sethindra cv_wait(&mip->mi_rx_cv, &mip->mi_lock); 13204913Sethindra } 13214913Sethindra mutex_exit(&mip->mi_lock); 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate mac_txloop_handle_t 13250Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 13260Sstevel@tonic-gate { 13270Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 13280Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 13310Sstevel@tonic-gate mtfp->mtf_fn = tx; 13320Sstevel@tonic-gate mtfp->mtf_arg = arg; 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate /* 13350Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 13360Sstevel@tonic-gate */ 13375084Sjohnlev rw_enter(&(mip->mi_tx_lock), RW_WRITER); 13380Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 13390Sstevel@tonic-gate mip->mi_mtfp = mtfp; 13405084Sjohnlev rw_exit(&(mip->mi_tx_lock)); 13410Sstevel@tonic-gate 13420Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 13430Sstevel@tonic-gate } 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate /* 13460Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 13470Sstevel@tonic-gate * from the list of transmit functions for this mac. 13480Sstevel@tonic-gate */ 13490Sstevel@tonic-gate void 13500Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 13510Sstevel@tonic-gate { 13520Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 13530Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 13540Sstevel@tonic-gate mac_txloop_fn_t **pp; 13550Sstevel@tonic-gate mac_txloop_fn_t *p; 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate /* 13580Sstevel@tonic-gate * Search the 'tx' callback list for the function. 13590Sstevel@tonic-gate */ 13605084Sjohnlev rw_enter(&(mip->mi_tx_lock), RW_WRITER); 13610Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 13620Sstevel@tonic-gate if (p == mtfp) 13630Sstevel@tonic-gate break; 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate ASSERT(p != NULL); 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate /* Remove it from the list. */ 13680Sstevel@tonic-gate *pp = p->mtf_nextp; 13690Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 13705084Sjohnlev rw_exit(&(mip->mi_tx_lock)); 13710Sstevel@tonic-gate } 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate void 13740Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 13750Sstevel@tonic-gate { 13760Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate /* 13790Sstevel@tonic-gate * Update the 'resource_add' callbacks. 13800Sstevel@tonic-gate */ 13810Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 13820Sstevel@tonic-gate mip->mi_resource_add = add; 13830Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 13840Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 13850Sstevel@tonic-gate } 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * Driver support functions. 13890Sstevel@tonic-gate */ 13900Sstevel@tonic-gate 13912311Sseb mac_register_t * 13922311Sseb mac_alloc(uint_t mac_version) 13930Sstevel@tonic-gate { 13942311Sseb mac_register_t *mregp; 13952311Sseb 13962311Sseb /* 13972311Sseb * Make sure there isn't a version mismatch between the driver and 13982311Sseb * the framework. In the future, if multiple versions are 13992311Sseb * supported, this check could become more sophisticated. 14002311Sseb */ 14012311Sseb if (mac_version != MAC_VERSION) 14022311Sseb return (NULL); 14032311Sseb 14042311Sseb mregp = kmem_zalloc(sizeof (mac_register_t), KM_SLEEP); 14052311Sseb mregp->m_version = mac_version; 14062311Sseb return (mregp); 14072311Sseb } 14082311Sseb 14092311Sseb void 14102311Sseb mac_free(mac_register_t *mregp) 14112311Sseb { 14122311Sseb kmem_free(mregp, sizeof (mac_register_t)); 14132311Sseb } 14142311Sseb 14152311Sseb /* 14165895Syz147064 * Allocate a minor number. 14175895Syz147064 */ 14185895Syz147064 minor_t 14195895Syz147064 mac_minor_hold(boolean_t sleep) 14205895Syz147064 { 14215895Syz147064 minor_t minor; 14225895Syz147064 14235895Syz147064 /* 14245895Syz147064 * Grab a value from the arena. 14255895Syz147064 */ 14265895Syz147064 atomic_add_32(&minor_count, 1); 14275895Syz147064 14285895Syz147064 if (sleep) 14295895Syz147064 minor = (uint_t)id_alloc(minor_ids); 14305895Syz147064 else 14315895Syz147064 minor = (uint_t)id_alloc_nosleep(minor_ids); 14325895Syz147064 14335895Syz147064 if (minor == 0) { 14345895Syz147064 atomic_add_32(&minor_count, -1); 14355895Syz147064 return (0); 14365895Syz147064 } 14375895Syz147064 14385895Syz147064 return (minor); 14395895Syz147064 } 14405895Syz147064 14415895Syz147064 /* 14425895Syz147064 * Release a previously allocated minor number. 14435895Syz147064 */ 14445895Syz147064 void 14455895Syz147064 mac_minor_rele(minor_t minor) 14465895Syz147064 { 14475895Syz147064 /* 14485895Syz147064 * Return the value to the arena. 14495895Syz147064 */ 14505895Syz147064 id_free(minor_ids, minor); 14515895Syz147064 atomic_add_32(&minor_count, -1); 14525895Syz147064 } 14535895Syz147064 14545895Syz147064 uint32_t 14555895Syz147064 mac_no_notification(mac_handle_t mh) 14565895Syz147064 { 14575895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 14585895Syz147064 return (mip->mi_unsup_note); 14595895Syz147064 } 14605895Syz147064 14615895Syz147064 boolean_t 14625895Syz147064 mac_is_legacy(mac_handle_t mh) 14635895Syz147064 { 14645895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 14655895Syz147064 return (mip->mi_legacy); 14665895Syz147064 } 14675895Syz147064 14685895Syz147064 /* 14692311Sseb * mac_register() is how drivers register new MACs with the GLDv3 14702311Sseb * framework. The mregp argument is allocated by drivers using the 14712311Sseb * mac_alloc() function, and can be freed using mac_free() immediately upon 14722311Sseb * return from mac_register(). Upon success (0 return value), the mhp 14732311Sseb * opaque pointer becomes the driver's handle to its MAC interface, and is 14742311Sseb * the argument to all other mac module entry points. 14752311Sseb */ 14762311Sseb int 14772311Sseb mac_register(mac_register_t *mregp, mac_handle_t *mhp) 14782311Sseb { 14795895Syz147064 mac_impl_t *mip; 14805895Syz147064 mactype_t *mtype; 14815895Syz147064 int err = EINVAL; 14825895Syz147064 struct devnames *dnp = NULL; 14835895Syz147064 uint_t instance; 14845895Syz147064 boolean_t style1_created = B_FALSE; 14855895Syz147064 boolean_t style2_created = B_FALSE; 14865895Syz147064 mac_capab_legacy_t legacy; 14875895Syz147064 char *driver; 14885895Syz147064 minor_t minor = 0; 14892311Sseb 14902311Sseb /* Find the required MAC-Type plugin. */ 14912311Sseb if ((mtype = i_mactype_getplugin(mregp->m_type_ident)) == NULL) 14922311Sseb return (EINVAL); 14932311Sseb 14942311Sseb /* Create a mac_impl_t to represent this MAC. */ 14952311Sseb mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 14962311Sseb 14972311Sseb /* 14982311Sseb * The mac is not ready for open yet. 14992311Sseb */ 15002311Sseb mip->mi_disabled = B_TRUE; 15012311Sseb 15022311Sseb /* 15035895Syz147064 * When a mac is registered, the m_instance field can be set to: 15045895Syz147064 * 15055895Syz147064 * 0: Get the mac's instance number from m_dip. 15065895Syz147064 * This is usually used for physical device dips. 15075895Syz147064 * 15085895Syz147064 * [1 .. MAC_MAX_MINOR-1]: Use the value as the mac's instance number. 15095895Syz147064 * For example, when an aggregation is created with the key option, 15105895Syz147064 * "key" will be used as the instance number. 15115895Syz147064 * 15125895Syz147064 * -1: Assign an instance number from [MAC_MAX_MINOR .. MAXMIN-1]. 15135895Syz147064 * This is often used when a MAC of a virtual link is registered 15145895Syz147064 * (e.g., aggregation when "key" is not specified, or vnic). 15155895Syz147064 * 15165895Syz147064 * Note that the instance number is used to derive the mi_minor field 15175895Syz147064 * of mac_impl_t, which will then be used to derive the name of kstats 15185895Syz147064 * and the devfs nodes. The first 2 cases are needed to preserve 15195895Syz147064 * backward compatibility. 15202311Sseb */ 15215895Syz147064 switch (mregp->m_instance) { 15225895Syz147064 case 0: 15235895Syz147064 instance = ddi_get_instance(mregp->m_dip); 15245895Syz147064 break; 15255895Syz147064 case ((uint_t)-1): 15265895Syz147064 minor = mac_minor_hold(B_TRUE); 15275895Syz147064 if (minor == 0) { 15285895Syz147064 err = ENOSPC; 15295895Syz147064 goto fail; 15305895Syz147064 } 15315895Syz147064 instance = minor - 1; 15325895Syz147064 break; 15335895Syz147064 default: 15345895Syz147064 instance = mregp->m_instance; 15355895Syz147064 if (instance >= MAC_MAX_MINOR) { 15365895Syz147064 err = EINVAL; 15375895Syz147064 goto fail; 15385895Syz147064 } 15395895Syz147064 break; 15405895Syz147064 } 15415895Syz147064 15425895Syz147064 mip->mi_minor = (minor_t)(instance + 1); 15435895Syz147064 mip->mi_dip = mregp->m_dip; 15445895Syz147064 15455895Syz147064 driver = (char *)ddi_driver_name(mip->mi_dip); 15462311Sseb 15472311Sseb /* Construct the MAC name as <drvname><instance> */ 15482311Sseb (void) snprintf(mip->mi_name, sizeof (mip->mi_name), "%s%d", 15495895Syz147064 driver, instance); 15502311Sseb 15512311Sseb mip->mi_driver = mregp->m_driver; 15522311Sseb 15532311Sseb mip->mi_type = mtype; 15545895Syz147064 mip->mi_margin = mregp->m_margin; 15552311Sseb mip->mi_info.mi_media = mtype->mt_type; 15563147Sxc151355 mip->mi_info.mi_nativemedia = mtype->mt_nativetype; 15573969Syz147064 if (mregp->m_max_sdu <= mregp->m_min_sdu) 15582311Sseb goto fail; 15595903Ssowmini mip->mi_sdu_min = mregp->m_min_sdu; 15605903Ssowmini mip->mi_sdu_max = mregp->m_max_sdu; 15612311Sseb mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; 15622311Sseb /* 15632311Sseb * If the media supports a broadcast address, cache a pointer to it 15642311Sseb * in the mac_info_t so that upper layers can use it. 15652311Sseb */ 15662311Sseb mip->mi_info.mi_brdcst_addr = mip->mi_type->mt_brdcst_addr; 1567269Sericheng 15682311Sseb /* 15692311Sseb * Copy the unicast source address into the mac_info_t, but only if 15702311Sseb * the MAC-Type defines a non-zero address length. We need to 15712311Sseb * handle MAC-Types that have an address length of 0 15722311Sseb * (point-to-point protocol MACs for example). 15732311Sseb */ 15742311Sseb if (mip->mi_type->mt_addr_length > 0) { 15753969Syz147064 if (mregp->m_src_addr == NULL) 15762311Sseb goto fail; 15772311Sseb mip->mi_info.mi_unicst_addr = 15782311Sseb kmem_alloc(mip->mi_type->mt_addr_length, KM_SLEEP); 15792311Sseb bcopy(mregp->m_src_addr, mip->mi_info.mi_unicst_addr, 15802311Sseb mip->mi_type->mt_addr_length); 15812311Sseb 15822311Sseb /* 15832311Sseb * Copy the fixed 'factory' MAC address from the immutable 15842311Sseb * info. This is taken to be the MAC address currently in 15852311Sseb * use. 15862311Sseb */ 15872311Sseb bcopy(mip->mi_info.mi_unicst_addr, mip->mi_addr, 15882311Sseb mip->mi_type->mt_addr_length); 15892311Sseb /* Copy the destination address if one is provided. */ 15902311Sseb if (mregp->m_dst_addr != NULL) { 15912311Sseb bcopy(mregp->m_dst_addr, mip->mi_dstaddr, 15922311Sseb mip->mi_type->mt_addr_length); 15932311Sseb } 15942311Sseb } else if (mregp->m_src_addr != NULL) { 15952311Sseb goto fail; 1596269Sericheng } 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate /* 15992311Sseb * The format of the m_pdata is specific to the plugin. It is 16002311Sseb * passed in as an argument to all of the plugin callbacks. The 16012311Sseb * driver can update this information by calling 16022311Sseb * mac_pdata_update(). 16030Sstevel@tonic-gate */ 16042311Sseb if (mregp->m_pdata != NULL) { 16052311Sseb /* 16062311Sseb * Verify that the plugin supports MAC plugin data and that 16072311Sseb * the supplied data is valid. 16082311Sseb */ 16093969Syz147064 if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 16102311Sseb goto fail; 16112311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mregp->m_pdata, 16122311Sseb mregp->m_pdata_size)) { 16132311Sseb goto fail; 16142311Sseb } 16152311Sseb mip->mi_pdata = kmem_alloc(mregp->m_pdata_size, KM_SLEEP); 16162311Sseb bcopy(mregp->m_pdata, mip->mi_pdata, mregp->m_pdata_size); 16172311Sseb mip->mi_pdata_size = mregp->m_pdata_size; 16182311Sseb } 16192311Sseb 16202311Sseb /* 16216512Ssowmini * Register the private properties. 16226512Ssowmini */ 16236512Ssowmini mac_register_priv_prop(mip, mregp->m_priv_props, 16246512Ssowmini mregp->m_priv_prop_count); 16256512Ssowmini 16266512Ssowmini /* 16272311Sseb * Stash the driver callbacks into the mac_impl_t, but first sanity 16282311Sseb * check to make sure all mandatory callbacks are set. 16292311Sseb */ 16302311Sseb if (mregp->m_callbacks->mc_getstat == NULL || 16312311Sseb mregp->m_callbacks->mc_start == NULL || 16322311Sseb mregp->m_callbacks->mc_stop == NULL || 16332311Sseb mregp->m_callbacks->mc_setpromisc == NULL || 16342311Sseb mregp->m_callbacks->mc_multicst == NULL || 16352311Sseb mregp->m_callbacks->mc_unicst == NULL || 16362311Sseb mregp->m_callbacks->mc_tx == NULL) { 16372311Sseb goto fail; 16382311Sseb } 16392311Sseb mip->mi_callbacks = mregp->m_callbacks; 16402311Sseb 16412311Sseb /* 16425084Sjohnlev * Set up the possible transmit routines. 16432311Sseb */ 16442311Sseb mip->mi_txinfo.mt_fn = mip->mi_tx; 16452311Sseb mip->mi_txinfo.mt_arg = mip->mi_driver; 16465084Sjohnlev 16475895Syz147064 mip->mi_legacy = mac_capab_get((mac_handle_t)mip, 16485895Syz147064 MAC_CAPAB_LEGACY, &legacy); 16495895Syz147064 16505895Syz147064 if (mip->mi_legacy) { 16515895Syz147064 /* 16525895Syz147064 * Legacy device. Messages being sent will be looped back 16535895Syz147064 * by the underlying driver. Therefore the txloop function 16545895Syz147064 * pointer is the same as the tx function pointer. 16555895Syz147064 */ 16565895Syz147064 mip->mi_txloopinfo.mt_fn = mip->mi_txinfo.mt_fn; 16575895Syz147064 mip->mi_txloopinfo.mt_arg = mip->mi_txinfo.mt_arg; 16585895Syz147064 mip->mi_unsup_note = legacy.ml_unsup_note; 16595895Syz147064 mip->mi_phy_dev = legacy.ml_dev; 16605895Syz147064 } else { 16615895Syz147064 /* 16625895Syz147064 * Normal device. The framework needs to do the loopback. 16635895Syz147064 */ 16645895Syz147064 mip->mi_txloopinfo.mt_fn = mac_txloop; 16655895Syz147064 mip->mi_txloopinfo.mt_arg = mip; 16665895Syz147064 mip->mi_unsup_note = 0; 16675895Syz147064 mip->mi_phy_dev = makedevice(ddi_driver_major(mip->mi_dip), 16685895Syz147064 ddi_get_instance(mip->mi_dip) + 1); 16695895Syz147064 } 16705895Syz147064 16715084Sjohnlev mip->mi_vnic_txinfo.mt_fn = mac_vnic_tx; 16725084Sjohnlev mip->mi_vnic_txinfo.mt_arg = mip; 16735084Sjohnlev 16745084Sjohnlev mip->mi_vnic_txloopinfo.mt_fn = mac_vnic_txloop; 16755084Sjohnlev mip->mi_vnic_txloopinfo.mt_arg = mip; 16765084Sjohnlev 16772311Sseb /* 16785009Sgd78059 * Allocate a notification thread. 16795009Sgd78059 */ 16805009Sgd78059 mip->mi_notify_thread = thread_create(NULL, 0, i_mac_notify_thread, 16815009Sgd78059 mip, 0, &p0, TS_RUN, minclsyspri); 16825009Sgd78059 if (mip->mi_notify_thread == NULL) 16835009Sgd78059 goto fail; 16845009Sgd78059 16855009Sgd78059 /* 16862311Sseb * Initialize the kstats for this device. 16872311Sseb */ 16882311Sseb mac_stat_create(mip); 16890Sstevel@tonic-gate 16906512Ssowmini 16910Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 16922311Sseb dnp = &devnamesp[ddi_driver_major(mip->mi_dip)]; 16930Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 16945895Syz147064 dnp->dn_flags |= (DN_GLDV3_DRIVER | DN_NETWORK_DRIVER); 16950Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 16960Sstevel@tonic-gate 16975895Syz147064 if (mip->mi_minor < MAC_MAX_MINOR + 1) { 16985895Syz147064 /* Create a style-2 DLPI device */ 16995895Syz147064 if (ddi_create_minor_node(mip->mi_dip, driver, S_IFCHR, 0, 17005895Syz147064 DDI_NT_NET, CLONE_DEV) != DDI_SUCCESS) 17015895Syz147064 goto fail; 17025895Syz147064 style2_created = B_TRUE; 17035895Syz147064 17045895Syz147064 /* Create a style-1 DLPI device */ 17055895Syz147064 if (ddi_create_minor_node(mip->mi_dip, mip->mi_name, S_IFCHR, 17065895Syz147064 mip->mi_minor, DDI_NT_NET, 0) != DDI_SUCCESS) 17075895Syz147064 goto fail; 17085895Syz147064 style1_created = B_TRUE; 17095895Syz147064 } 17105895Syz147064 17113969Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 17123969Syz147064 if (mod_hash_insert(i_mac_impl_hash, 17133969Syz147064 (mod_hash_key_t)mip->mi_name, (mod_hash_val_t)mip) != 0) { 17145895Syz147064 17153969Syz147064 rw_exit(&i_mac_impl_lock); 17163969Syz147064 err = EEXIST; 17173969Syz147064 goto fail; 17183969Syz147064 } 17193969Syz147064 17205903Ssowmini DTRACE_PROBE2(mac__register, struct devnames *, dnp, 17215903Ssowmini (mac_impl_t *), mip); 17225903Ssowmini 17231852Syz147064 /* 17241852Syz147064 * Mark the MAC to be ready for open. 17251852Syz147064 */ 17262311Sseb mip->mi_disabled = B_FALSE; 17272311Sseb 17281852Syz147064 rw_exit(&i_mac_impl_lock); 17293969Syz147064 17303969Syz147064 atomic_inc_32(&i_mac_impl_count); 17315895Syz147064 17325895Syz147064 cmn_err(CE_NOTE, "!%s registered", mip->mi_name); 17332311Sseb *mhp = (mac_handle_t)mip; 1734269Sericheng return (0); 17350Sstevel@tonic-gate 17362311Sseb fail: 17375895Syz147064 if (style1_created) 17385895Syz147064 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 17395895Syz147064 17405895Syz147064 if (style2_created) 17415895Syz147064 ddi_remove_minor_node(mip->mi_dip, driver); 17425895Syz147064 17435009Sgd78059 /* clean up notification thread */ 17445009Sgd78059 if (mip->mi_notify_thread != NULL) { 17455009Sgd78059 mutex_enter(&mip->mi_notify_bits_lock); 17465009Sgd78059 mip->mi_notify_bits = (1 << MAC_NNOTE); 17475009Sgd78059 cv_broadcast(&mip->mi_notify_cv); 17485009Sgd78059 while (mip->mi_notify_bits != 0) 17495009Sgd78059 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); 17505009Sgd78059 mutex_exit(&mip->mi_notify_bits_lock); 17515009Sgd78059 } 17525009Sgd78059 17532311Sseb if (mip->mi_info.mi_unicst_addr != NULL) { 17542311Sseb kmem_free(mip->mi_info.mi_unicst_addr, 17552311Sseb mip->mi_type->mt_addr_length); 17562311Sseb mip->mi_info.mi_unicst_addr = NULL; 17572311Sseb } 17582311Sseb 17592311Sseb mac_stat_destroy(mip); 17602311Sseb 17612311Sseb if (mip->mi_type != NULL) { 17623288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 17632311Sseb mip->mi_type = NULL; 17642311Sseb } 17652311Sseb 17662311Sseb if (mip->mi_pdata != NULL) { 17672311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 17682311Sseb mip->mi_pdata = NULL; 17692311Sseb mip->mi_pdata_size = 0; 17702311Sseb } 17712311Sseb 17725895Syz147064 if (minor != 0) { 17735895Syz147064 ASSERT(minor > MAC_MAX_MINOR); 17745895Syz147064 mac_minor_rele(minor); 17755895Syz147064 } 17765895Syz147064 1777*7406SSowmini.Varadhan@Sun.COM mac_unregister_priv_prop(mip); 1778*7406SSowmini.Varadhan@Sun.COM 17792311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 1780269Sericheng return (err); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate int 17845084Sjohnlev mac_disable(mac_handle_t mh) 17850Sstevel@tonic-gate { 17862311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 1787269Sericheng 17880Sstevel@tonic-gate /* 17890Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 17901852Syz147064 * If not, set mi_disabled to prevent any new VLAN's from being 17912311Sseb * created while we're destroying this mac. 17920Sstevel@tonic-gate */ 1793269Sericheng rw_enter(&i_mac_impl_lock, RW_WRITER); 17940Sstevel@tonic-gate if (mip->mi_ref > 0) { 1795269Sericheng rw_exit(&i_mac_impl_lock); 17960Sstevel@tonic-gate return (EBUSY); 17970Sstevel@tonic-gate } 17981852Syz147064 mip->mi_disabled = B_TRUE; 1799269Sericheng rw_exit(&i_mac_impl_lock); 18005084Sjohnlev return (0); 18015084Sjohnlev } 18025084Sjohnlev 18035084Sjohnlev int 18045084Sjohnlev mac_unregister(mac_handle_t mh) 18055084Sjohnlev { 18065084Sjohnlev int err; 18075084Sjohnlev mac_impl_t *mip = (mac_impl_t *)mh; 18085084Sjohnlev mod_hash_val_t val; 18095084Sjohnlev mac_multicst_addr_t *p, *nextp; 18105895Syz147064 mac_margin_req_t *mmr, *nextmmr; 18115084Sjohnlev 18125084Sjohnlev /* 18135084Sjohnlev * See if there are any other references to this mac_t (e.g., VLAN's). 18145084Sjohnlev * If not, set mi_disabled to prevent any new VLAN's from being 18155084Sjohnlev * created while we're destroying this mac. Once mac_disable() returns 18165084Sjohnlev * 0, the rest of mac_unregister() stuff should continue without 18175084Sjohnlev * returning an error. 18185084Sjohnlev */ 18195084Sjohnlev if (!mip->mi_disabled) { 18205084Sjohnlev if ((err = mac_disable(mh)) != 0) 18215084Sjohnlev return (err); 18225084Sjohnlev } 18235084Sjohnlev 18240Sstevel@tonic-gate /* 18255009Sgd78059 * Clean up notification thread (wait for it to exit). 18265009Sgd78059 */ 18275009Sgd78059 mutex_enter(&mip->mi_notify_bits_lock); 18285009Sgd78059 mip->mi_notify_bits = (1 << MAC_NNOTE); 18295009Sgd78059 cv_broadcast(&mip->mi_notify_cv); 18305009Sgd78059 while (mip->mi_notify_bits != 0) 18315009Sgd78059 cv_wait(&mip->mi_notify_cv, &mip->mi_notify_bits_lock); 18325009Sgd78059 mutex_exit(&mip->mi_notify_bits_lock); 18335009Sgd78059 18345895Syz147064 if (mip->mi_minor < MAC_MAX_MINOR + 1) { 18355895Syz147064 ddi_remove_minor_node(mip->mi_dip, mip->mi_name); 18365895Syz147064 ddi_remove_minor_node(mip->mi_dip, 18375895Syz147064 (char *)ddi_driver_name(mip->mi_dip)); 18385895Syz147064 } 18392311Sseb 18402311Sseb ASSERT(!mip->mi_activelink); 18412311Sseb 18422311Sseb mac_stat_destroy(mip); 18432311Sseb 18445895Syz147064 rw_enter(&i_mac_impl_lock, RW_WRITER); 18455895Syz147064 (void) mod_hash_remove(i_mac_impl_hash, 18465895Syz147064 (mod_hash_key_t)mip->mi_name, &val); 18472311Sseb ASSERT(mip == (mac_impl_t *)val); 18482311Sseb 18492311Sseb ASSERT(i_mac_impl_count > 0); 18503288Sseb atomic_dec_32(&i_mac_impl_count); 18515895Syz147064 rw_exit(&i_mac_impl_lock); 18522311Sseb 18532311Sseb if (mip->mi_pdata != NULL) 18542311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 18552311Sseb mip->mi_pdata = NULL; 18562311Sseb mip->mi_pdata_size = 0; 18570Sstevel@tonic-gate 18580Sstevel@tonic-gate /* 18592311Sseb * Free the list of multicast addresses. 18600Sstevel@tonic-gate */ 18612311Sseb for (p = mip->mi_mmap; p != NULL; p = nextp) { 18622311Sseb nextp = p->mma_nextp; 18632311Sseb kmem_free(p, sizeof (mac_multicst_addr_t)); 18642311Sseb } 18652311Sseb mip->mi_mmap = NULL; 18660Sstevel@tonic-gate 18675895Syz147064 /* 18685895Syz147064 * Free the list of margin request. 18695895Syz147064 */ 18705895Syz147064 for (mmr = mip->mi_mmrp; mmr != NULL; mmr = nextmmr) { 18715895Syz147064 nextmmr = mmr->mmr_nextp; 18725895Syz147064 kmem_free(mmr, sizeof (mac_margin_req_t)); 18735895Syz147064 } 18745895Syz147064 mip->mi_mmrp = NULL; 18755895Syz147064 18762311Sseb mip->mi_linkstate = LINK_STATE_UNKNOWN; 18772311Sseb kmem_free(mip->mi_info.mi_unicst_addr, mip->mi_type->mt_addr_length); 18782311Sseb mip->mi_info.mi_unicst_addr = NULL; 18792311Sseb 18803288Sseb atomic_dec_32(&mip->mi_type->mt_ref); 18812311Sseb mip->mi_type = NULL; 18822311Sseb 18835895Syz147064 if (mip->mi_minor > MAC_MAX_MINOR) 18845895Syz147064 mac_minor_rele(mip->mi_minor); 18855895Syz147064 1886*7406SSowmini.Varadhan@Sun.COM mac_unregister_priv_prop(mip); 1887*7406SSowmini.Varadhan@Sun.COM 18882311Sseb cmn_err(CE_NOTE, "!%s unregistered", mip->mi_name); 18892311Sseb 18902311Sseb kmem_cache_free(i_mac_impl_cachep, mip); 18912311Sseb 18920Sstevel@tonic-gate return (0); 18930Sstevel@tonic-gate } 18940Sstevel@tonic-gate 18954913Sethindra /* 18964913Sethindra * To avoid potential deadlocks, mac_rx() releases mi_rx_lock 18974913Sethindra * before invoking its list of upcalls. This introduces races with 18984913Sethindra * mac_rx_remove() and mac_rx_add(), who can potentially modify the 18994913Sethindra * upcall list while mi_rx_lock is not being held. The race with 19004913Sethindra * mac_rx_remove() is handled by incrementing mi_rx_ref upon entering 19014913Sethindra * mac_rx(); a non-zero mi_rx_ref would tell mac_rx_remove() 19024913Sethindra * to not modify the list but instead mark an upcall for deletion. 19034913Sethindra * before mac_rx() exits, mi_rx_ref is decremented and if it 19044913Sethindra * is 0, the marked upcalls will be removed from the list and freed. 19054913Sethindra * The race with mac_rx_add() is harmless because mac_rx_add() only 19064913Sethindra * prepends to the list and since mac_rx() saves the list head 19074913Sethindra * before releasing mi_rx_lock, any prepended upcall won't be seen 19084913Sethindra * until the next packet chain arrives. 19094913Sethindra * 19104913Sethindra * To minimize lock contention between multiple parallel invocations 19114913Sethindra * of mac_rx(), mi_rx_lock is acquired as a READER lock. The 19124913Sethindra * use of atomic operations ensures the sanity of mi_rx_ref. mi_rx_lock 19134913Sethindra * will be upgraded to WRITER mode when there are marked upcalls to be 19144913Sethindra * cleaned. 19154913Sethindra */ 19165084Sjohnlev static void 19175084Sjohnlev mac_do_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain, 19185084Sjohnlev boolean_t active_only) 19190Sstevel@tonic-gate { 19202311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 19214913Sethindra mblk_t *bp = mp_chain; 19220Sstevel@tonic-gate mac_rx_fn_t *mrfp; 19230Sstevel@tonic-gate 19240Sstevel@tonic-gate /* 19250Sstevel@tonic-gate * Call all registered receive functions. 19260Sstevel@tonic-gate */ 19270Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 19284913Sethindra if ((mrfp = mip->mi_mrfp) == NULL) { 19290Sstevel@tonic-gate /* There are no registered receive functions. */ 19300Sstevel@tonic-gate freemsgchain(bp); 19310Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 19320Sstevel@tonic-gate return; 19330Sstevel@tonic-gate } 19344913Sethindra atomic_inc_32(&mip->mi_rx_ref); 19354913Sethindra rw_exit(&mip->mi_rx_lock); 19364913Sethindra 19374913Sethindra /* 19384913Sethindra * Call registered receive functions. 19394913Sethindra */ 19400Sstevel@tonic-gate do { 19410Sstevel@tonic-gate mblk_t *recv_bp; 19420Sstevel@tonic-gate 19435084Sjohnlev if (active_only && !mrfp->mrf_active) { 19445084Sjohnlev mrfp = mrfp->mrf_nextp; 19455084Sjohnlev if (mrfp == NULL) { 19465084Sjohnlev /* 19475084Sjohnlev * We hit the last receiver, but it's not 19485084Sjohnlev * active. 19495084Sjohnlev */ 19505084Sjohnlev freemsgchain(bp); 19515084Sjohnlev } 19525084Sjohnlev continue; 19535084Sjohnlev } 19545084Sjohnlev 19554913Sethindra recv_bp = (mrfp->mrf_nextp != NULL) ? copymsgchain(bp) : bp; 19564913Sethindra if (recv_bp != NULL) { 19574913Sethindra if (mrfp->mrf_inuse) { 19584913Sethindra /* 19594913Sethindra * Send bp itself and keep the copy. 19604913Sethindra * If there's only one active receiver, 19614913Sethindra * it should get the original message, 19624913Sethindra * tagged with the hardware checksum flags. 19634913Sethindra */ 19644913Sethindra mrfp->mrf_fn(mrfp->mrf_arg, mrh, bp); 19654913Sethindra bp = recv_bp; 19664913Sethindra } else { 19674913Sethindra freemsgchain(recv_bp); 19684913Sethindra } 19690Sstevel@tonic-gate } 19705084Sjohnlev 19710Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 19720Sstevel@tonic-gate } while (mrfp != NULL); 19734913Sethindra 19744913Sethindra rw_enter(&mip->mi_rx_lock, RW_READER); 19754913Sethindra if (atomic_dec_32_nv(&mip->mi_rx_ref) == 0 && mip->mi_rx_removed > 0) { 19764913Sethindra mac_rx_fn_t **pp, *p; 19774913Sethindra uint32_t cnt = 0; 19784913Sethindra 19794913Sethindra DTRACE_PROBE1(delete_callbacks, mac_impl_t *, mip); 19804913Sethindra 19814913Sethindra /* 19824913Sethindra * Need to become exclusive before doing cleanup 19834913Sethindra */ 19844913Sethindra if (rw_tryupgrade(&mip->mi_rx_lock) == 0) { 19854913Sethindra rw_exit(&mip->mi_rx_lock); 19864913Sethindra rw_enter(&mip->mi_rx_lock, RW_WRITER); 19874913Sethindra } 19884913Sethindra 19894913Sethindra /* 19904913Sethindra * We return if another thread has already entered and cleaned 19914913Sethindra * up the list. 19924913Sethindra */ 19934913Sethindra if (mip->mi_rx_ref > 0 || mip->mi_rx_removed == 0) { 19944913Sethindra rw_exit(&mip->mi_rx_lock); 19954913Sethindra return; 19964913Sethindra } 19974913Sethindra 19984913Sethindra /* 19994913Sethindra * Free removed callbacks. 20004913Sethindra */ 20014913Sethindra pp = &mip->mi_mrfp; 20024913Sethindra while (*pp != NULL) { 20034913Sethindra if (!(*pp)->mrf_inuse) { 20044913Sethindra p = *pp; 20054913Sethindra *pp = (*pp)->mrf_nextp; 20064913Sethindra kmem_free(p, sizeof (*p)); 20074913Sethindra cnt++; 20084913Sethindra continue; 20094913Sethindra } 20104913Sethindra pp = &(*pp)->mrf_nextp; 20114913Sethindra } 20124913Sethindra 20134913Sethindra /* 20144913Sethindra * Wake up mac_rx_remove_wait() 20154913Sethindra */ 20164913Sethindra mutex_enter(&mip->mi_lock); 20174913Sethindra ASSERT(mip->mi_rx_removed == cnt); 20184913Sethindra mip->mi_rx_removed = 0; 20194913Sethindra cv_broadcast(&mip->mi_rx_cv); 20204913Sethindra mutex_exit(&mip->mi_lock); 20214913Sethindra } 20220Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 20230Sstevel@tonic-gate } 20240Sstevel@tonic-gate 20255084Sjohnlev void 20265084Sjohnlev mac_rx(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) 20275084Sjohnlev { 20285084Sjohnlev mac_do_rx(mh, mrh, mp_chain, B_FALSE); 20295084Sjohnlev } 20305084Sjohnlev 20315084Sjohnlev /* 20325084Sjohnlev * Send a packet chain up to the receive callbacks which declared 20335084Sjohnlev * themselves as being active. 20345084Sjohnlev */ 20355084Sjohnlev void 20365084Sjohnlev mac_active_rx(void *arg, mac_resource_handle_t mrh, mblk_t *mp_chain) 20375084Sjohnlev { 20385084Sjohnlev mac_do_rx(arg, mrh, mp_chain, B_TRUE); 20395084Sjohnlev } 20405084Sjohnlev 20415084Sjohnlev /* 20425084Sjohnlev * Function passed to the active client sharing a VNIC. This function 20435084Sjohnlev * is returned by mac_tx_get() when a VNIC is present. It invokes 20445084Sjohnlev * the VNIC transmit entry point which was specified by the VNIC when 20455084Sjohnlev * it called mac_vnic_set(). The VNIC transmit entry point will 20465084Sjohnlev * pass the packets to the local VNICs and/or to the underlying VNICs 20475084Sjohnlev * if needed. 20485084Sjohnlev */ 20495084Sjohnlev static mblk_t * 20505084Sjohnlev mac_vnic_tx(void *arg, mblk_t *mp) 20515084Sjohnlev { 20525084Sjohnlev mac_impl_t *mip = arg; 20535084Sjohnlev mac_txinfo_t *mtfp; 20545084Sjohnlev mac_vnic_tx_t *mvt; 20555084Sjohnlev 20565084Sjohnlev /* 20575084Sjohnlev * There is a race between the notification of the VNIC 20585084Sjohnlev * addition and removal, and the processing of the VNIC notification 20595084Sjohnlev * by the MAC client. During this window, it is possible for 20605084Sjohnlev * an active MAC client to contine invoking mac_vnic_tx() while 20615084Sjohnlev * the VNIC has already been removed. So we cannot assume 20625084Sjohnlev * that mi_vnic_present will always be true when mac_vnic_tx() 20635084Sjohnlev * is invoked. 20645084Sjohnlev */ 20655084Sjohnlev rw_enter(&mip->mi_tx_lock, RW_READER); 20665084Sjohnlev if (!mip->mi_vnic_present) { 20675084Sjohnlev rw_exit(&mip->mi_tx_lock); 20685084Sjohnlev freemsgchain(mp); 20695084Sjohnlev return (NULL); 20705084Sjohnlev } 20715084Sjohnlev 20725084Sjohnlev ASSERT(mip->mi_vnic_tx != NULL); 20735084Sjohnlev mvt = mip->mi_vnic_tx; 20745084Sjohnlev MAC_VNIC_TXINFO_REFHOLD(mvt); 20755084Sjohnlev rw_exit(&mip->mi_tx_lock); 20765084Sjohnlev 20775084Sjohnlev mtfp = &mvt->mv_txinfo; 20785084Sjohnlev mtfp->mt_fn(mtfp->mt_arg, mp); 20795084Sjohnlev 20805084Sjohnlev MAC_VNIC_TXINFO_REFRELE(mvt); 20815084Sjohnlev return (NULL); 20825084Sjohnlev } 20835084Sjohnlev 20840Sstevel@tonic-gate /* 20850Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 20860Sstevel@tonic-gate */ 20870Sstevel@tonic-gate mblk_t * 20885084Sjohnlev mac_do_txloop(void *arg, mblk_t *bp, boolean_t call_vnic) 20890Sstevel@tonic-gate { 20900Sstevel@tonic-gate mac_impl_t *mip = arg; 20910Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 20920Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 20930Sstevel@tonic-gate 20945084Sjohnlev if (call_vnic) { 20955084Sjohnlev /* 20965084Sjohnlev * In promiscous mode, a copy of the sent packet will 20975084Sjohnlev * be sent to the client's promiscous receive entry 20985084Sjohnlev * points via mac_vnic_tx()-> 20995084Sjohnlev * mac_active_rx_promisc()->mac_rx_default(). 21005084Sjohnlev */ 21015084Sjohnlev return (mac_vnic_tx(arg, bp)); 21025084Sjohnlev } 21035084Sjohnlev 21040Sstevel@tonic-gate while (bp != NULL) { 21050Sstevel@tonic-gate next_bp = bp->b_next; 21060Sstevel@tonic-gate bp->b_next = NULL; 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 21090Sstevel@tonic-gate goto noresources; 21100Sstevel@tonic-gate 21112311Sseb if ((resid_bp = mip->mi_tx(mip->mi_driver, bp)) != NULL) { 21120Sstevel@tonic-gate ASSERT(resid_bp == bp); 21130Sstevel@tonic-gate freemsg(loop_bp); 21140Sstevel@tonic-gate goto noresources; 21150Sstevel@tonic-gate } 21160Sstevel@tonic-gate 21175084Sjohnlev rw_enter(&mip->mi_tx_lock, RW_READER); 21180Sstevel@tonic-gate mtfp = mip->mi_mtfp; 211956Smeem while (mtfp != NULL && loop_bp != NULL) { 21200Sstevel@tonic-gate bp = loop_bp; 212156Smeem 212256Smeem /* XXX counter bump if copymsg() fails? */ 212356Smeem if (mtfp->mtf_nextp != NULL) 21240Sstevel@tonic-gate loop_bp = copymsg(bp); 212556Smeem else 212656Smeem loop_bp = NULL; 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 212956Smeem mtfp = mtfp->mtf_nextp; 21300Sstevel@tonic-gate } 21315084Sjohnlev rw_exit(&mip->mi_tx_lock); 21320Sstevel@tonic-gate 213356Smeem /* 213456Smeem * It's possible we've raced with the disabling of promiscuous 213556Smeem * mode, in which case we can discard our copy. 213656Smeem */ 213756Smeem if (loop_bp != NULL) 213856Smeem freemsg(loop_bp); 213956Smeem 21400Sstevel@tonic-gate bp = next_bp; 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate 21430Sstevel@tonic-gate return (NULL); 21440Sstevel@tonic-gate 21450Sstevel@tonic-gate noresources: 21460Sstevel@tonic-gate bp->b_next = next_bp; 21470Sstevel@tonic-gate return (bp); 21480Sstevel@tonic-gate } 21490Sstevel@tonic-gate 21505084Sjohnlev mblk_t * 21515084Sjohnlev mac_txloop(void *arg, mblk_t *bp) 21525084Sjohnlev { 21535084Sjohnlev return (mac_do_txloop(arg, bp, B_FALSE)); 21545084Sjohnlev } 21555084Sjohnlev 21565084Sjohnlev static mblk_t * 21575084Sjohnlev mac_vnic_txloop(void *arg, mblk_t *bp) 21585084Sjohnlev { 21595084Sjohnlev return (mac_do_txloop(arg, bp, B_TRUE)); 21605084Sjohnlev } 21615084Sjohnlev 21620Sstevel@tonic-gate void 21632311Sseb mac_link_update(mac_handle_t mh, link_state_t link) 21640Sstevel@tonic-gate { 21652311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 21660Sstevel@tonic-gate 21670Sstevel@tonic-gate /* 21680Sstevel@tonic-gate * Save the link state. 21690Sstevel@tonic-gate */ 21702311Sseb mip->mi_linkstate = link; 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate /* 21730Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 21740Sstevel@tonic-gate */ 21750Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 21760Sstevel@tonic-gate } 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate void 21792311Sseb mac_unicst_update(mac_handle_t mh, const uint8_t *addr) 21800Sstevel@tonic-gate { 21812311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 21820Sstevel@tonic-gate 21832311Sseb if (mip->mi_type->mt_addr_length == 0) 21842311Sseb return; 21850Sstevel@tonic-gate 21860Sstevel@tonic-gate /* 21875895Syz147064 * If the address has not changed, do nothing. 21885895Syz147064 */ 21895895Syz147064 if (bcmp(addr, mip->mi_addr, mip->mi_type->mt_addr_length) == 0) 21905895Syz147064 return; 21915895Syz147064 21925895Syz147064 /* 21930Sstevel@tonic-gate * Save the address. 21940Sstevel@tonic-gate */ 21952311Sseb bcopy(addr, mip->mi_addr, mip->mi_type->mt_addr_length); 21960Sstevel@tonic-gate 21970Sstevel@tonic-gate /* 21980Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 21990Sstevel@tonic-gate */ 22000Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 22010Sstevel@tonic-gate } 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate void 22042311Sseb mac_tx_update(mac_handle_t mh) 22050Sstevel@tonic-gate { 22060Sstevel@tonic-gate /* 22070Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 22080Sstevel@tonic-gate */ 22092311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_TX); 22100Sstevel@tonic-gate } 22110Sstevel@tonic-gate 22120Sstevel@tonic-gate void 22132311Sseb mac_resource_update(mac_handle_t mh) 22140Sstevel@tonic-gate { 22150Sstevel@tonic-gate /* 22160Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 22170Sstevel@tonic-gate */ 22182311Sseb i_mac_notify((mac_impl_t *)mh, MAC_NOTE_RESOURCE); 22190Sstevel@tonic-gate } 22200Sstevel@tonic-gate 22210Sstevel@tonic-gate mac_resource_handle_t 22222311Sseb mac_resource_add(mac_handle_t mh, mac_resource_t *mrp) 22230Sstevel@tonic-gate { 22242311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 22250Sstevel@tonic-gate mac_resource_handle_t mrh; 22260Sstevel@tonic-gate mac_resource_add_t add; 22270Sstevel@tonic-gate void *arg; 22280Sstevel@tonic-gate 22290Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 22300Sstevel@tonic-gate add = mip->mi_resource_add; 22310Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 22320Sstevel@tonic-gate 22331184Skrgopi if (add != NULL) 22341184Skrgopi mrh = add(arg, mrp); 22351184Skrgopi else 22361184Skrgopi mrh = NULL; 22370Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 22380Sstevel@tonic-gate 22390Sstevel@tonic-gate return (mrh); 22400Sstevel@tonic-gate } 22410Sstevel@tonic-gate 22422311Sseb int 22432311Sseb mac_pdata_update(mac_handle_t mh, void *mac_pdata, size_t dsize) 22442311Sseb { 22452311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 22462311Sseb 22472311Sseb /* 22482311Sseb * Verify that the plugin supports MAC plugin data and that the 22492311Sseb * supplied data is valid. 22502311Sseb */ 22512311Sseb if (!(mip->mi_type->mt_ops.mtops_ops & MTOPS_PDATA_VERIFY)) 22522311Sseb return (EINVAL); 22532311Sseb if (!mip->mi_type->mt_ops.mtops_pdata_verify(mac_pdata, dsize)) 22542311Sseb return (EINVAL); 22552311Sseb 22562311Sseb if (mip->mi_pdata != NULL) 22572311Sseb kmem_free(mip->mi_pdata, mip->mi_pdata_size); 22582311Sseb 22592311Sseb mip->mi_pdata = kmem_alloc(dsize, KM_SLEEP); 22602311Sseb bcopy(mac_pdata, mip->mi_pdata, dsize); 22612311Sseb mip->mi_pdata_size = dsize; 22622311Sseb 22632311Sseb /* 22642311Sseb * Since the MAC plugin data is used to construct MAC headers that 22652311Sseb * were cached in fast-path headers, we need to flush fast-path 22662311Sseb * information for links associated with this mac. 22672311Sseb */ 22682311Sseb i_mac_notify(mip, MAC_NOTE_FASTPATH_FLUSH); 22692311Sseb return (0); 22702311Sseb } 22712311Sseb 22720Sstevel@tonic-gate void 22732311Sseb mac_multicst_refresh(mac_handle_t mh, mac_multicst_t refresh, void *arg, 22740Sstevel@tonic-gate boolean_t add) 22750Sstevel@tonic-gate { 22762311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 22770Sstevel@tonic-gate mac_multicst_addr_t *p; 22780Sstevel@tonic-gate 22790Sstevel@tonic-gate /* 22800Sstevel@tonic-gate * If no specific refresh function was given then default to the 22810Sstevel@tonic-gate * driver's m_multicst entry point. 22820Sstevel@tonic-gate */ 22830Sstevel@tonic-gate if (refresh == NULL) { 22842311Sseb refresh = mip->mi_multicst; 22852311Sseb arg = mip->mi_driver; 22860Sstevel@tonic-gate } 22870Sstevel@tonic-gate ASSERT(refresh != NULL); 22880Sstevel@tonic-gate 22890Sstevel@tonic-gate /* 22900Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 22910Sstevel@tonic-gate * each address. 22920Sstevel@tonic-gate */ 22930Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 22940Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 22950Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 22960Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 22970Sstevel@tonic-gate } 22980Sstevel@tonic-gate 22990Sstevel@tonic-gate void 23002311Sseb mac_unicst_refresh(mac_handle_t mh, mac_unicst_t refresh, void *arg) 23010Sstevel@tonic-gate { 23022311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 23030Sstevel@tonic-gate /* 23040Sstevel@tonic-gate * If no specific refresh function was given then default to the 23052311Sseb * driver's mi_unicst entry point. 23060Sstevel@tonic-gate */ 23070Sstevel@tonic-gate if (refresh == NULL) { 23082311Sseb refresh = mip->mi_unicst; 23092311Sseb arg = mip->mi_driver; 23100Sstevel@tonic-gate } 23110Sstevel@tonic-gate ASSERT(refresh != NULL); 23120Sstevel@tonic-gate 23130Sstevel@tonic-gate /* 23140Sstevel@tonic-gate * Call the refresh function with the current unicast address. 23150Sstevel@tonic-gate */ 23160Sstevel@tonic-gate refresh(arg, mip->mi_addr); 23170Sstevel@tonic-gate } 23180Sstevel@tonic-gate 23190Sstevel@tonic-gate void 23202311Sseb mac_promisc_refresh(mac_handle_t mh, mac_setpromisc_t refresh, void *arg) 23210Sstevel@tonic-gate { 23222311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 23230Sstevel@tonic-gate 23240Sstevel@tonic-gate /* 23250Sstevel@tonic-gate * If no specific refresh function was given then default to the 23260Sstevel@tonic-gate * driver's m_promisc entry point. 23270Sstevel@tonic-gate */ 23280Sstevel@tonic-gate if (refresh == NULL) { 23292311Sseb refresh = mip->mi_setpromisc; 23302311Sseb arg = mip->mi_driver; 23310Sstevel@tonic-gate } 23320Sstevel@tonic-gate ASSERT(refresh != NULL); 23330Sstevel@tonic-gate 23340Sstevel@tonic-gate /* 23350Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 23360Sstevel@tonic-gate */ 23370Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 23380Sstevel@tonic-gate } 23390Sstevel@tonic-gate 23405895Syz147064 /* 23415895Syz147064 * The mac client requests that the mac not to change its margin size to 23425895Syz147064 * be less than the specified value. If "current" is B_TRUE, then the client 23435895Syz147064 * requests the mac not to change its margin size to be smaller than the 23445895Syz147064 * current size. Further, return the current margin size value in this case. 23455895Syz147064 * 23465895Syz147064 * We keep every requested size in an ordered list from largest to smallest. 23475895Syz147064 */ 23485895Syz147064 int 23495895Syz147064 mac_margin_add(mac_handle_t mh, uint32_t *marginp, boolean_t current) 23505895Syz147064 { 23515895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 23525895Syz147064 mac_margin_req_t **pp, *p; 23535895Syz147064 int err = 0; 23545895Syz147064 23555895Syz147064 rw_enter(&(mip->mi_data_lock), RW_WRITER); 23565895Syz147064 if (current) 23575895Syz147064 *marginp = mip->mi_margin; 23585895Syz147064 23595895Syz147064 /* 23605895Syz147064 * If the current margin value cannot satisfy the margin requested, 23615895Syz147064 * return ENOTSUP directly. 23625895Syz147064 */ 23635895Syz147064 if (*marginp > mip->mi_margin) { 23645895Syz147064 err = ENOTSUP; 23655895Syz147064 goto done; 23665895Syz147064 } 23675895Syz147064 23685895Syz147064 /* 23695895Syz147064 * Check whether the given margin is already in the list. If so, 23705895Syz147064 * bump the reference count. 23715895Syz147064 */ 23725895Syz147064 for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) { 23735895Syz147064 if (p->mmr_margin == *marginp) { 23745895Syz147064 /* 23755895Syz147064 * The margin requested is already in the list, 23765895Syz147064 * so just bump the reference count. 23775895Syz147064 */ 23785895Syz147064 p->mmr_ref++; 23795895Syz147064 goto done; 23805895Syz147064 } 23815895Syz147064 if (p->mmr_margin < *marginp) 23825895Syz147064 break; 23835895Syz147064 } 23845895Syz147064 23855895Syz147064 23865895Syz147064 if ((p = kmem_zalloc(sizeof (mac_margin_req_t), KM_NOSLEEP)) == NULL) { 23875895Syz147064 err = ENOMEM; 23885895Syz147064 goto done; 23895895Syz147064 } 23905895Syz147064 23915895Syz147064 p->mmr_margin = *marginp; 23925895Syz147064 p->mmr_ref++; 23935895Syz147064 p->mmr_nextp = *pp; 23945895Syz147064 *pp = p; 23955895Syz147064 23965895Syz147064 done: 23975895Syz147064 rw_exit(&(mip->mi_data_lock)); 23985895Syz147064 return (err); 23995895Syz147064 } 24005895Syz147064 24015895Syz147064 /* 24025895Syz147064 * The mac client requests to cancel its previous mac_margin_add() request. 24035895Syz147064 * We remove the requested margin size from the list. 24045895Syz147064 */ 24055895Syz147064 int 24065895Syz147064 mac_margin_remove(mac_handle_t mh, uint32_t margin) 24075895Syz147064 { 24085895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 24095895Syz147064 mac_margin_req_t **pp, *p; 24105895Syz147064 int err = 0; 24115895Syz147064 24125895Syz147064 rw_enter(&(mip->mi_data_lock), RW_WRITER); 24135895Syz147064 /* 24145895Syz147064 * Find the entry in the list for the given margin. 24155895Syz147064 */ 24165895Syz147064 for (pp = &(mip->mi_mmrp); (p = *pp) != NULL; pp = &(p->mmr_nextp)) { 24175895Syz147064 if (p->mmr_margin == margin) { 24185895Syz147064 if (--p->mmr_ref == 0) 24195895Syz147064 break; 24205895Syz147064 24215895Syz147064 /* 24225895Syz147064 * There is still a reference to this address so 24235895Syz147064 * there's nothing more to do. 24245895Syz147064 */ 24255895Syz147064 goto done; 24265895Syz147064 } 24275895Syz147064 } 24285895Syz147064 24295895Syz147064 /* 24305895Syz147064 * We did not find an entry for the given margin. 24315895Syz147064 */ 24325895Syz147064 if (p == NULL) { 24335895Syz147064 err = ENOENT; 24345895Syz147064 goto done; 24355895Syz147064 } 24365895Syz147064 24375895Syz147064 ASSERT(p->mmr_ref == 0); 24385895Syz147064 24395895Syz147064 /* 24405895Syz147064 * Remove it from the list. 24415895Syz147064 */ 24425895Syz147064 *pp = p->mmr_nextp; 24435895Syz147064 kmem_free(p, sizeof (mac_margin_req_t)); 24445895Syz147064 done: 24455895Syz147064 rw_exit(&(mip->mi_data_lock)); 24465895Syz147064 return (err); 24475895Syz147064 } 24485895Syz147064 24495895Syz147064 /* 24505895Syz147064 * The mac client requests to get the mac's current margin value. 24515895Syz147064 */ 24525895Syz147064 void 24535895Syz147064 mac_margin_get(mac_handle_t mh, uint32_t *marginp) 24545895Syz147064 { 24555895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 24565895Syz147064 24575895Syz147064 rw_enter(&(mip->mi_data_lock), RW_READER); 24585895Syz147064 *marginp = mip->mi_margin; 24595895Syz147064 rw_exit(&(mip->mi_data_lock)); 24605895Syz147064 } 24615895Syz147064 24625895Syz147064 boolean_t 24635895Syz147064 mac_margin_update(mac_handle_t mh, uint32_t margin) 24645895Syz147064 { 24655895Syz147064 mac_impl_t *mip = (mac_impl_t *)mh; 24665895Syz147064 uint32_t margin_needed = 0; 24675895Syz147064 24685895Syz147064 rw_enter(&(mip->mi_data_lock), RW_WRITER); 24695895Syz147064 24705895Syz147064 if (mip->mi_mmrp != NULL) 24715895Syz147064 margin_needed = mip->mi_mmrp->mmr_margin; 24725895Syz147064 24735895Syz147064 if (margin_needed <= margin) 24745895Syz147064 mip->mi_margin = margin; 24755895Syz147064 24765895Syz147064 rw_exit(&(mip->mi_data_lock)); 24775895Syz147064 24785895Syz147064 if (margin_needed <= margin) 24795895Syz147064 i_mac_notify(mip, MAC_NOTE_MARGIN); 24805895Syz147064 24815895Syz147064 return (margin_needed <= margin); 24825895Syz147064 } 24835895Syz147064 24840Sstevel@tonic-gate boolean_t 24855084Sjohnlev mac_do_active_set(mac_handle_t mh, boolean_t shareable) 24860Sstevel@tonic-gate { 24870Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 24880Sstevel@tonic-gate 24890Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 24900Sstevel@tonic-gate if (mip->mi_activelink) { 24910Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 24920Sstevel@tonic-gate return (B_FALSE); 24930Sstevel@tonic-gate } 24940Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 24955084Sjohnlev mip->mi_shareable = shareable; 24960Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 24970Sstevel@tonic-gate return (B_TRUE); 24980Sstevel@tonic-gate } 24990Sstevel@tonic-gate 25005084Sjohnlev /* 25015084Sjohnlev * Called by MAC clients. By default, active MAC clients cannot 25025084Sjohnlev * share the NIC with VNICs. 25035084Sjohnlev */ 25045084Sjohnlev boolean_t 25055084Sjohnlev mac_active_set(mac_handle_t mh) 25065084Sjohnlev { 25075084Sjohnlev return (mac_do_active_set(mh, B_FALSE)); 25085084Sjohnlev } 25095084Sjohnlev 25105084Sjohnlev /* 25115084Sjohnlev * Called by MAC clients which can share the NIC with VNICS, e.g. DLS. 25125084Sjohnlev */ 25135084Sjohnlev boolean_t 25145084Sjohnlev mac_active_shareable_set(mac_handle_t mh) 25155084Sjohnlev { 25165084Sjohnlev return (mac_do_active_set(mh, B_TRUE)); 25175084Sjohnlev } 25185084Sjohnlev 25190Sstevel@tonic-gate void 25200Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 25210Sstevel@tonic-gate { 25220Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 25230Sstevel@tonic-gate 25240Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 25250Sstevel@tonic-gate ASSERT(mip->mi_activelink); 25260Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 25270Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 25280Sstevel@tonic-gate } 2529269Sericheng 25305084Sjohnlev boolean_t 25315084Sjohnlev mac_vnic_set(mac_handle_t mh, mac_txinfo_t *tx_info, mac_getcapab_t getcapab_fn, 25325084Sjohnlev void *getcapab_arg) 25335084Sjohnlev { 25345084Sjohnlev mac_impl_t *mip = (mac_impl_t *)mh; 25355084Sjohnlev mac_vnic_tx_t *vnic_tx; 25365084Sjohnlev 25375084Sjohnlev mutex_enter(&mip->mi_activelink_lock); 25385084Sjohnlev rw_enter(&mip->mi_tx_lock, RW_WRITER); 25395084Sjohnlev ASSERT(!mip->mi_vnic_present); 25405084Sjohnlev 25415084Sjohnlev if (mip->mi_activelink && !mip->mi_shareable) { 25425084Sjohnlev /* 25435084Sjohnlev * The NIC is already used by an active client which cannot 25445084Sjohnlev * share it with VNICs. 25455084Sjohnlev */ 25465084Sjohnlev rw_exit(&mip->mi_tx_lock); 25475084Sjohnlev mutex_exit(&mip->mi_activelink_lock); 25485084Sjohnlev return (B_FALSE); 25495084Sjohnlev } 25505084Sjohnlev 25515084Sjohnlev vnic_tx = kmem_cache_alloc(mac_vnic_tx_cache, KM_SLEEP); 25525084Sjohnlev vnic_tx->mv_refs = 0; 25535084Sjohnlev vnic_tx->mv_txinfo = *tx_info; 25545084Sjohnlev vnic_tx->mv_clearing = B_FALSE; 25555084Sjohnlev 25565084Sjohnlev mip->mi_vnic_present = B_TRUE; 25575084Sjohnlev mip->mi_vnic_tx = vnic_tx; 25585084Sjohnlev mip->mi_vnic_getcapab_fn = getcapab_fn; 25595084Sjohnlev mip->mi_vnic_getcapab_arg = getcapab_arg; 25605084Sjohnlev rw_exit(&mip->mi_tx_lock); 25615084Sjohnlev mutex_exit(&mip->mi_activelink_lock); 25625084Sjohnlev 25635084Sjohnlev i_mac_notify(mip, MAC_NOTE_VNIC); 25645084Sjohnlev return (B_TRUE); 25655084Sjohnlev } 25665084Sjohnlev 25675084Sjohnlev void 25685084Sjohnlev mac_vnic_clear(mac_handle_t mh) 25695084Sjohnlev { 25705084Sjohnlev mac_impl_t *mip = (mac_impl_t *)mh; 25715084Sjohnlev mac_vnic_tx_t *vnic_tx; 25725084Sjohnlev 25735084Sjohnlev rw_enter(&mip->mi_tx_lock, RW_WRITER); 25745084Sjohnlev ASSERT(mip->mi_vnic_present); 25755084Sjohnlev mip->mi_vnic_present = B_FALSE; 25765084Sjohnlev /* 25775084Sjohnlev * Setting mi_vnic_tx to NULL here under the lock guarantees 25785084Sjohnlev * that no new references to the current VNIC transmit structure 25795084Sjohnlev * will be taken by mac_vnic_tx(). This is a necessary condition 25805084Sjohnlev * for safely waiting for the reference count to drop to 25815084Sjohnlev * zero below. 25825084Sjohnlev */ 25835084Sjohnlev vnic_tx = mip->mi_vnic_tx; 25845084Sjohnlev mip->mi_vnic_tx = NULL; 25855084Sjohnlev mip->mi_vnic_getcapab_fn = NULL; 25865084Sjohnlev mip->mi_vnic_getcapab_arg = NULL; 25875084Sjohnlev rw_exit(&mip->mi_tx_lock); 25885084Sjohnlev 25895084Sjohnlev i_mac_notify(mip, MAC_NOTE_VNIC); 25905084Sjohnlev 25915084Sjohnlev /* 25925084Sjohnlev * Wait for all TX calls referencing the VNIC transmit 25935084Sjohnlev * entry point that was removed to complete. 25945084Sjohnlev */ 25955084Sjohnlev mutex_enter(&vnic_tx->mv_lock); 25965084Sjohnlev vnic_tx->mv_clearing = B_TRUE; 25975084Sjohnlev while (vnic_tx->mv_refs > 0) 25985084Sjohnlev cv_wait(&vnic_tx->mv_cv, &vnic_tx->mv_lock); 25995084Sjohnlev mutex_exit(&vnic_tx->mv_lock); 26005084Sjohnlev kmem_cache_free(mac_vnic_tx_cache, vnic_tx); 26015084Sjohnlev } 26025084Sjohnlev 2603269Sericheng /* 2604269Sericheng * mac_info_get() is used for retrieving the mac_info when a DL_INFO_REQ is 2605269Sericheng * issued before a DL_ATTACH_REQ. we walk the i_mac_impl_hash table and find 2606269Sericheng * the first mac_impl_t with a matching driver name; then we copy its mac_info_t 2607269Sericheng * to the caller. we do all this with i_mac_impl_lock held so the mac_impl_t 2608269Sericheng * cannot disappear while we are accessing it. 2609269Sericheng */ 2610269Sericheng typedef struct i_mac_info_state_s { 2611269Sericheng const char *mi_name; 2612269Sericheng mac_info_t *mi_infop; 2613269Sericheng } i_mac_info_state_t; 2614269Sericheng 2615269Sericheng /*ARGSUSED*/ 2616269Sericheng static uint_t 2617269Sericheng i_mac_info_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 2618269Sericheng { 2619269Sericheng i_mac_info_state_t *statep = arg; 2620269Sericheng mac_impl_t *mip = (mac_impl_t *)val; 2621269Sericheng 26221852Syz147064 if (mip->mi_disabled) 2623269Sericheng return (MH_WALK_CONTINUE); 2624269Sericheng 2625269Sericheng if (strcmp(statep->mi_name, 26262311Sseb ddi_driver_name(mip->mi_dip)) != 0) 2627269Sericheng return (MH_WALK_CONTINUE); 2628269Sericheng 26292311Sseb statep->mi_infop = &mip->mi_info; 2630269Sericheng return (MH_WALK_TERMINATE); 2631269Sericheng } 2632269Sericheng 2633269Sericheng boolean_t 2634269Sericheng mac_info_get(const char *name, mac_info_t *minfop) 2635269Sericheng { 2636269Sericheng i_mac_info_state_t state; 2637269Sericheng 2638269Sericheng rw_enter(&i_mac_impl_lock, RW_READER); 2639269Sericheng state.mi_name = name; 2640269Sericheng state.mi_infop = NULL; 2641269Sericheng mod_hash_walk(i_mac_impl_hash, i_mac_info_walker, &state); 2642269Sericheng if (state.mi_infop == NULL) { 2643269Sericheng rw_exit(&i_mac_impl_lock); 2644269Sericheng return (B_FALSE); 2645269Sericheng } 2646269Sericheng *minfop = *state.mi_infop; 2647269Sericheng rw_exit(&i_mac_impl_lock); 2648269Sericheng return (B_TRUE); 2649269Sericheng } 2650269Sericheng 26512311Sseb boolean_t 26525084Sjohnlev mac_do_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data, 26535084Sjohnlev boolean_t is_vnic) 26542311Sseb { 26552311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 26562311Sseb 26575084Sjohnlev if (!is_vnic) { 26585084Sjohnlev rw_enter(&mip->mi_tx_lock, RW_READER); 26595084Sjohnlev if (mip->mi_vnic_present) { 26605084Sjohnlev boolean_t rv; 26615084Sjohnlev 26625084Sjohnlev rv = mip->mi_vnic_getcapab_fn(mip->mi_vnic_getcapab_arg, 26635084Sjohnlev cap, cap_data); 26645084Sjohnlev rw_exit(&mip->mi_tx_lock); 26655084Sjohnlev return (rv); 26665084Sjohnlev } 26675084Sjohnlev rw_exit(&mip->mi_tx_lock); 26685084Sjohnlev } 26695084Sjohnlev 26702311Sseb if (mip->mi_callbacks->mc_callbacks & MC_GETCAPAB) 26712311Sseb return (mip->mi_getcapab(mip->mi_driver, cap, cap_data)); 26722311Sseb else 26732311Sseb return (B_FALSE); 26742311Sseb } 26752311Sseb 26762311Sseb boolean_t 26775084Sjohnlev mac_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 26785084Sjohnlev { 26795084Sjohnlev return (mac_do_capab_get(mh, cap, cap_data, B_FALSE)); 26805084Sjohnlev } 26815084Sjohnlev 26825084Sjohnlev boolean_t 26835084Sjohnlev mac_vnic_capab_get(mac_handle_t mh, mac_capab_t cap, void *cap_data) 26845084Sjohnlev { 26855084Sjohnlev return (mac_do_capab_get(mh, cap, cap_data, B_TRUE)); 26865084Sjohnlev } 26875084Sjohnlev 26885084Sjohnlev boolean_t 26892311Sseb mac_sap_verify(mac_handle_t mh, uint32_t sap, uint32_t *bind_sap) 26902311Sseb { 26912311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 26922311Sseb return (mip->mi_type->mt_ops.mtops_sap_verify(sap, bind_sap, 26932311Sseb mip->mi_pdata)); 26942311Sseb } 26952311Sseb 26962311Sseb mblk_t * 26972311Sseb mac_header(mac_handle_t mh, const uint8_t *daddr, uint32_t sap, mblk_t *payload, 26982311Sseb size_t extra_len) 26992311Sseb { 27002311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 27012311Sseb return (mip->mi_type->mt_ops.mtops_header(mip->mi_addr, daddr, sap, 27022311Sseb mip->mi_pdata, payload, extra_len)); 27032311Sseb } 27042311Sseb 27052311Sseb int 27062311Sseb mac_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip) 27072311Sseb { 27082311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 27092311Sseb return (mip->mi_type->mt_ops.mtops_header_info(mp, mip->mi_pdata, 27102311Sseb mhip)); 27112311Sseb } 27122311Sseb 27132311Sseb mblk_t * 27142311Sseb mac_header_cook(mac_handle_t mh, mblk_t *mp) 27152311Sseb { 27162311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 27172311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_COOK) { 27182311Sseb if (DB_REF(mp) > 1) { 27192311Sseb mblk_t *newmp = copymsg(mp); 27202760Sdg199075 if (newmp == NULL) 27212760Sdg199075 return (NULL); 27222311Sseb freemsg(mp); 27232311Sseb mp = newmp; 27242311Sseb } 27252311Sseb return (mip->mi_type->mt_ops.mtops_header_cook(mp, 27262311Sseb mip->mi_pdata)); 27272311Sseb } 27282311Sseb return (mp); 27292311Sseb } 27302311Sseb 27312311Sseb mblk_t * 27322311Sseb mac_header_uncook(mac_handle_t mh, mblk_t *mp) 27332311Sseb { 27342311Sseb mac_impl_t *mip = (mac_impl_t *)mh; 27352311Sseb if (mip->mi_type->mt_ops.mtops_ops & MTOPS_HEADER_UNCOOK) { 27362311Sseb if (DB_REF(mp) > 1) { 27372311Sseb mblk_t *newmp = copymsg(mp); 27382760Sdg199075 if (newmp == NULL) 27392760Sdg199075 return (NULL); 27402311Sseb freemsg(mp); 27412311Sseb mp = newmp; 27422311Sseb } 27432311Sseb return (mip->mi_type->mt_ops.mtops_header_uncook(mp, 27442311Sseb mip->mi_pdata)); 27452311Sseb } 27462311Sseb return (mp); 27472311Sseb } 27482311Sseb 2749269Sericheng void 2750269Sericheng mac_init_ops(struct dev_ops *ops, const char *name) 2751269Sericheng { 2752269Sericheng dld_init_ops(ops, name); 2753269Sericheng } 2754269Sericheng 2755269Sericheng void 2756269Sericheng mac_fini_ops(struct dev_ops *ops) 2757269Sericheng { 2758269Sericheng dld_fini_ops(ops); 2759269Sericheng } 27602311Sseb 27612311Sseb /* 27622311Sseb * MAC Type Plugin functions. 27632311Sseb */ 27642311Sseb 27652311Sseb mactype_register_t * 27662311Sseb mactype_alloc(uint_t mactype_version) 27672311Sseb { 27682311Sseb mactype_register_t *mtrp; 27692311Sseb 27702311Sseb /* 27712311Sseb * Make sure there isn't a version mismatch between the plugin and 27722311Sseb * the framework. In the future, if multiple versions are 27732311Sseb * supported, this check could become more sophisticated. 27742311Sseb */ 27752311Sseb if (mactype_version != MACTYPE_VERSION) 27762311Sseb return (NULL); 27772311Sseb 27782311Sseb mtrp = kmem_zalloc(sizeof (mactype_register_t), KM_SLEEP); 27792311Sseb mtrp->mtr_version = mactype_version; 27802311Sseb return (mtrp); 27812311Sseb } 27822311Sseb 27832311Sseb void 27842311Sseb mactype_free(mactype_register_t *mtrp) 27852311Sseb { 27862311Sseb kmem_free(mtrp, sizeof (mactype_register_t)); 27872311Sseb } 27882311Sseb 27892311Sseb int 27902311Sseb mactype_register(mactype_register_t *mtrp) 27912311Sseb { 27922311Sseb mactype_t *mtp; 27932311Sseb mactype_ops_t *ops = mtrp->mtr_ops; 27942311Sseb 27952311Sseb /* Do some sanity checking before we register this MAC type. */ 27966353Sdr146992 if (mtrp->mtr_ident == NULL || ops == NULL) 27972311Sseb return (EINVAL); 27982311Sseb 27992311Sseb /* 28002311Sseb * Verify that all mandatory callbacks are set in the ops 28012311Sseb * vector. 28022311Sseb */ 28032311Sseb if (ops->mtops_unicst_verify == NULL || 28042311Sseb ops->mtops_multicst_verify == NULL || 28052311Sseb ops->mtops_sap_verify == NULL || 28062311Sseb ops->mtops_header == NULL || 28072311Sseb ops->mtops_header_info == NULL) { 28082311Sseb return (EINVAL); 28092311Sseb } 28102311Sseb 28112311Sseb mtp = kmem_zalloc(sizeof (*mtp), KM_SLEEP); 28122311Sseb mtp->mt_ident = mtrp->mtr_ident; 28132311Sseb mtp->mt_ops = *ops; 28142311Sseb mtp->mt_type = mtrp->mtr_mactype; 28153147Sxc151355 mtp->mt_nativetype = mtrp->mtr_nativetype; 28162311Sseb mtp->mt_addr_length = mtrp->mtr_addrlen; 28172311Sseb if (mtrp->mtr_brdcst_addr != NULL) { 28182311Sseb mtp->mt_brdcst_addr = kmem_alloc(mtrp->mtr_addrlen, KM_SLEEP); 28192311Sseb bcopy(mtrp->mtr_brdcst_addr, mtp->mt_brdcst_addr, 28202311Sseb mtrp->mtr_addrlen); 28212311Sseb } 28222311Sseb 28232311Sseb mtp->mt_stats = mtrp->mtr_stats; 28242311Sseb mtp->mt_statcount = mtrp->mtr_statcount; 28252311Sseb 28266512Ssowmini mtp->mt_mapping = mtrp->mtr_mapping; 28276512Ssowmini mtp->mt_mappingcount = mtrp->mtr_mappingcount; 28286512Ssowmini 28292311Sseb if (mod_hash_insert(i_mactype_hash, 28302311Sseb (mod_hash_key_t)mtp->mt_ident, (mod_hash_val_t)mtp) != 0) { 28312311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 28322311Sseb kmem_free(mtp, sizeof (*mtp)); 28332311Sseb return (EEXIST); 28342311Sseb } 28352311Sseb return (0); 28362311Sseb } 28372311Sseb 28382311Sseb int 28392311Sseb mactype_unregister(const char *ident) 28402311Sseb { 28412311Sseb mactype_t *mtp; 28422311Sseb mod_hash_val_t val; 28432311Sseb int err; 28442311Sseb 28452311Sseb /* 28462311Sseb * Let's not allow MAC drivers to use this plugin while we're 28473288Sseb * trying to unregister it. Holding i_mactype_lock also prevents a 28483288Sseb * plugin from unregistering while a MAC driver is attempting to 28493288Sseb * hold a reference to it in i_mactype_getplugin(). 28502311Sseb */ 28513288Sseb mutex_enter(&i_mactype_lock); 28522311Sseb 28532311Sseb if ((err = mod_hash_find(i_mactype_hash, (mod_hash_key_t)ident, 28542311Sseb (mod_hash_val_t *)&mtp)) != 0) { 28552311Sseb /* A plugin is trying to unregister, but it never registered. */ 28563288Sseb err = ENXIO; 28573288Sseb goto done; 28582311Sseb } 28592311Sseb 28603288Sseb if (mtp->mt_ref != 0) { 28613288Sseb err = EBUSY; 28623288Sseb goto done; 28632311Sseb } 28642311Sseb 28652311Sseb err = mod_hash_remove(i_mactype_hash, (mod_hash_key_t)ident, &val); 28662311Sseb ASSERT(err == 0); 28672311Sseb if (err != 0) { 28682311Sseb /* This should never happen, thus the ASSERT() above. */ 28693288Sseb err = EINVAL; 28703288Sseb goto done; 28712311Sseb } 28722311Sseb ASSERT(mtp == (mactype_t *)val); 28732311Sseb 28742311Sseb kmem_free(mtp->mt_brdcst_addr, mtp->mt_addr_length); 28752311Sseb kmem_free(mtp, sizeof (mactype_t)); 28763288Sseb done: 28773288Sseb mutex_exit(&i_mactype_lock); 28783288Sseb return (err); 28792311Sseb } 28805903Ssowmini 28815903Ssowmini int 28825903Ssowmini mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize) 28835903Ssowmini { 28845903Ssowmini int err = ENOTSUP; 28855903Ssowmini mac_impl_t *mip = (mac_impl_t *)mh; 28865903Ssowmini 28875903Ssowmini if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) { 28885903Ssowmini err = mip->mi_callbacks->mc_setprop(mip->mi_driver, 28895903Ssowmini macprop->mp_name, macprop->mp_id, valsize, val); 28905903Ssowmini } 28915903Ssowmini return (err); 28925903Ssowmini } 28935903Ssowmini 28945903Ssowmini int 28955903Ssowmini mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize) 28965903Ssowmini { 28975903Ssowmini int err = ENOTSUP; 28985903Ssowmini mac_impl_t *mip = (mac_impl_t *)mh; 28996512Ssowmini uint32_t sdu; 29006512Ssowmini link_state_t link_state; 29016512Ssowmini 29026512Ssowmini switch (macprop->mp_id) { 29036789Sam223141 case MAC_PROP_MTU: 29046512Ssowmini if (valsize < sizeof (sdu)) 29056512Ssowmini return (EINVAL); 29066789Sam223141 if ((macprop->mp_flags & MAC_PROP_DEFAULT) == 0) { 29076512Ssowmini mac_sdu_get(mh, NULL, &sdu); 29086512Ssowmini bcopy(&sdu, val, sizeof (sdu)); 29096512Ssowmini return (0); 29106512Ssowmini } else { 29116512Ssowmini if (mip->mi_info.mi_media == DL_ETHER) { 29126512Ssowmini sdu = ETHERMTU; 29136512Ssowmini bcopy(&sdu, val, sizeof (sdu)); 29146512Ssowmini return (0); 29156512Ssowmini } 29166512Ssowmini /* 29176512Ssowmini * ask driver for its default. 29186512Ssowmini */ 29196512Ssowmini break; 29206512Ssowmini } 29216789Sam223141 case MAC_PROP_STATUS: 29226512Ssowmini if (valsize < sizeof (link_state)) 29236512Ssowmini return (EINVAL); 29246512Ssowmini link_state = mac_link_get(mh); 29256512Ssowmini bcopy(&link_state, val, sizeof (link_state)); 29266512Ssowmini return (0); 29276512Ssowmini default: 29286512Ssowmini break; 29296512Ssowmini } 29305903Ssowmini if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) { 29315903Ssowmini err = mip->mi_callbacks->mc_getprop(mip->mi_driver, 29326512Ssowmini macprop->mp_name, macprop->mp_id, macprop->mp_flags, 29336512Ssowmini valsize, val); 29345903Ssowmini } 29355903Ssowmini return (err); 29365903Ssowmini } 29375903Ssowmini 29385903Ssowmini int 29395903Ssowmini mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max) 29405903Ssowmini { 29415903Ssowmini mac_impl_t *mip = (mac_impl_t *)mh; 29425903Ssowmini 29435903Ssowmini if (sdu_max <= mip->mi_sdu_min) 29445903Ssowmini return (EINVAL); 29455903Ssowmini mip->mi_sdu_max = sdu_max; 29465903Ssowmini 29475903Ssowmini /* Send a MAC_NOTE_SDU_SIZE notification. */ 29485903Ssowmini i_mac_notify(mip, MAC_NOTE_SDU_SIZE); 29495903Ssowmini return (0); 29505903Ssowmini } 29516512Ssowmini 29526512Ssowmini static void 29536512Ssowmini mac_register_priv_prop(mac_impl_t *mip, mac_priv_prop_t *mpp, uint_t nprop) 29546512Ssowmini { 29556512Ssowmini mac_priv_prop_t *mpriv; 29566512Ssowmini 29576512Ssowmini if (mpp == NULL) 29586512Ssowmini return; 29596512Ssowmini 29606512Ssowmini mpriv = kmem_zalloc(nprop * sizeof (*mpriv), KM_SLEEP); 29616512Ssowmini (void) memcpy(mpriv, mpp, nprop * sizeof (*mpriv)); 29626512Ssowmini mip->mi_priv_prop = mpriv; 29636512Ssowmini mip->mi_priv_prop_count = nprop; 29646512Ssowmini } 2965*7406SSowmini.Varadhan@Sun.COM 2966*7406SSowmini.Varadhan@Sun.COM static void 2967*7406SSowmini.Varadhan@Sun.COM mac_unregister_priv_prop(mac_impl_t *mip) 2968*7406SSowmini.Varadhan@Sun.COM { 2969*7406SSowmini.Varadhan@Sun.COM mac_priv_prop_t *mpriv; 2970*7406SSowmini.Varadhan@Sun.COM 2971*7406SSowmini.Varadhan@Sun.COM mpriv = mip->mi_priv_prop; 2972*7406SSowmini.Varadhan@Sun.COM if (mpriv != NULL) { 2973*7406SSowmini.Varadhan@Sun.COM kmem_free(mpriv, mip->mi_priv_prop_count * sizeof (*mpriv)); 2974*7406SSowmini.Varadhan@Sun.COM mip->mi_priv_prop = NULL; 2975*7406SSowmini.Varadhan@Sun.COM } 2976*7406SSowmini.Varadhan@Sun.COM mip->mi_priv_prop_count = 0; 2977*7406SSowmini.Varadhan@Sun.COM } 2978