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 51502Sericheng * Common Development and Distribution License (the "License"). 61502Sericheng * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 221502Sericheng * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Data-Link Services Module 300Sstevel@tonic-gate */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/stream.h> 340Sstevel@tonic-gate #include <sys/strsun.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #include <sys/atomic.h> 370Sstevel@tonic-gate #include <sys/dlpi.h> 380Sstevel@tonic-gate #include <sys/vlan.h> 390Sstevel@tonic-gate #include <sys/ethernet.h> 400Sstevel@tonic-gate #include <sys/byteorder.h> 410Sstevel@tonic-gate #include <sys/mac.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate #include <sys/dls.h> 440Sstevel@tonic-gate #include <sys/dls_impl.h> 451184Skrgopi #include <sys/dls_soft_ring.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate static kmem_cache_t *i_dls_impl_cachep; 480Sstevel@tonic-gate static uint32_t i_dls_impl_count; 490Sstevel@tonic-gate 501184Skrgopi static kstat_t *dls_ksp = (kstat_t *)NULL; 511184Skrgopi struct dls_kstats dls_kstat = 521184Skrgopi { 531184Skrgopi { "soft_ring_pkt_drop", KSTAT_DATA_UINT32 }, 541184Skrgopi }; 551184Skrgopi 561184Skrgopi 570Sstevel@tonic-gate /* 580Sstevel@tonic-gate * Private functions. 590Sstevel@tonic-gate */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate /*ARGSUSED*/ 620Sstevel@tonic-gate static int 630Sstevel@tonic-gate i_dls_constructor(void *buf, void *arg, int kmflag) 640Sstevel@tonic-gate { 650Sstevel@tonic-gate dls_impl_t *dip = buf; 660Sstevel@tonic-gate 670Sstevel@tonic-gate bzero(buf, sizeof (dls_impl_t)); 680Sstevel@tonic-gate 690Sstevel@tonic-gate rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL); 700Sstevel@tonic-gate return (0); 710Sstevel@tonic-gate } 720Sstevel@tonic-gate 730Sstevel@tonic-gate /*ARGSUSED*/ 740Sstevel@tonic-gate static void 750Sstevel@tonic-gate i_dls_destructor(void *buf, void *arg) 760Sstevel@tonic-gate { 770Sstevel@tonic-gate dls_impl_t *dip = buf; 780Sstevel@tonic-gate 790Sstevel@tonic-gate ASSERT(dip->di_dvp == NULL); 800Sstevel@tonic-gate ASSERT(dip->di_mnh == NULL); 810Sstevel@tonic-gate ASSERT(dip->di_dmap == NULL); 820Sstevel@tonic-gate ASSERT(!dip->di_bound); 830Sstevel@tonic-gate ASSERT(dip->di_rx == NULL); 8456Smeem ASSERT(dip->di_txinfo == NULL); 850Sstevel@tonic-gate 860Sstevel@tonic-gate rw_destroy(&(dip->di_lock)); 870Sstevel@tonic-gate } 880Sstevel@tonic-gate 890Sstevel@tonic-gate static void 900Sstevel@tonic-gate i_dls_notify(void *arg, mac_notify_type_t type) 910Sstevel@tonic-gate { 920Sstevel@tonic-gate dls_impl_t *dip = arg; 930Sstevel@tonic-gate 940Sstevel@tonic-gate switch (type) { 950Sstevel@tonic-gate case MAC_NOTE_UNICST: 960Sstevel@tonic-gate mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 970Sstevel@tonic-gate break; 980Sstevel@tonic-gate 990Sstevel@tonic-gate case MAC_NOTE_PROMISC: 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Every time the MAC interface changes promiscuity we 10256Smeem * need to reset our transmit information. 1030Sstevel@tonic-gate */ 10456Smeem dip->di_txinfo = mac_tx_get(dip->di_mh); 1050Sstevel@tonic-gate break; 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate 1091184Skrgopi static void 1101184Skrgopi dls_stat_init() 1111184Skrgopi { 1121184Skrgopi if ((dls_ksp = kstat_create("dls", 0, "dls_stat", 1131184Skrgopi "net", KSTAT_TYPE_NAMED, 1141184Skrgopi sizeof (dls_kstat) / sizeof (kstat_named_t), 1151184Skrgopi KSTAT_FLAG_VIRTUAL)) == NULL) { 1161184Skrgopi cmn_err(CE_WARN, 1171184Skrgopi "DLS: failed to create kstat structure for dls stats"); 1181184Skrgopi return; 1191184Skrgopi } 1201184Skrgopi dls_ksp->ks_data = (void *)&dls_kstat; 1211184Skrgopi kstat_install(dls_ksp); 1221184Skrgopi } 1231184Skrgopi 1241184Skrgopi static void 1251184Skrgopi dls_stat_destroy() 1261184Skrgopi { 1271184Skrgopi kstat_delete(dls_ksp); 1281184Skrgopi } 1291184Skrgopi 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Module initialization functions. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate void 1350Sstevel@tonic-gate dls_init(void) 1360Sstevel@tonic-gate { 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Create a kmem_cache of dls_impl_t. 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate i_dls_impl_cachep = kmem_cache_create("dls_cache", 1410Sstevel@tonic-gate sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL, 1420Sstevel@tonic-gate NULL, NULL, 0); 1430Sstevel@tonic-gate ASSERT(i_dls_impl_cachep != NULL); 1441184Skrgopi soft_ring_init(); 1451184Skrgopi dls_stat_init(); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate int 1490Sstevel@tonic-gate dls_fini(void) 1500Sstevel@tonic-gate { 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * If there are any dls_impl_t in use then return EBUSY. 1530Sstevel@tonic-gate */ 1540Sstevel@tonic-gate if (i_dls_impl_count != 0) 1550Sstevel@tonic-gate return (EBUSY); 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * Destroy the kmem_cache. 1590Sstevel@tonic-gate */ 1600Sstevel@tonic-gate kmem_cache_destroy(i_dls_impl_cachep); 1611184Skrgopi dls_stat_destroy(); 1620Sstevel@tonic-gate return (0); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /* 1660Sstevel@tonic-gate * Client function. 1670Sstevel@tonic-gate */ 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate int 1702311Sseb dls_create(const char *linkname, const char *macname, uint_t ddi_instance) 1710Sstevel@tonic-gate { 1722311Sseb return (dls_vlan_create(linkname, macname, ddi_instance, 0)); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate int 1760Sstevel@tonic-gate dls_destroy(const char *name) 1770Sstevel@tonic-gate { 1780Sstevel@tonic-gate return (dls_vlan_destroy(name)); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate int 1820Sstevel@tonic-gate dls_open(const char *name, dls_channel_t *dcp) 1830Sstevel@tonic-gate { 1840Sstevel@tonic-gate dls_impl_t *dip; 1850Sstevel@tonic-gate dls_vlan_t *dvp; 1860Sstevel@tonic-gate dls_link_t *dlp; 1870Sstevel@tonic-gate int err; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Get a reference to the named dls_vlan_t. 191269Sericheng * Tagged vlans get created automatically. 1920Sstevel@tonic-gate */ 193269Sericheng if ((err = dls_vlan_hold(name, &dvp, B_TRUE)) != 0) 1940Sstevel@tonic-gate return (err); 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * Allocate a new dls_impl_t. 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP); 2000Sstevel@tonic-gate dip->di_dvp = dvp; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * Cache a copy of the MAC interface handle, a pointer to the 2040Sstevel@tonic-gate * immutable MAC info and a copy of the current MAC address. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate dlp = dvp->dv_dlp; 2070Sstevel@tonic-gate dip->di_mh = dlp->dl_mh; 2080Sstevel@tonic-gate dip->di_mip = dlp->dl_mip; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* 21356Smeem * Set the MAC transmit information. 2140Sstevel@tonic-gate */ 21556Smeem dip->di_txinfo = mac_tx_get(dip->di_mh); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate /* 2180Sstevel@tonic-gate * Add a notification function so that we get updates from the MAC. 2190Sstevel@tonic-gate */ 2200Sstevel@tonic-gate dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* 2230Sstevel@tonic-gate * Bump the kmem_cache count to make sure it is not prematurely 2240Sstevel@tonic-gate * destroyed. 2250Sstevel@tonic-gate */ 2260Sstevel@tonic-gate atomic_add_32(&i_dls_impl_count, 1); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* 2290Sstevel@tonic-gate * Hand back a reference to the dls_impl_t. 2300Sstevel@tonic-gate */ 2310Sstevel@tonic-gate *dcp = (dls_channel_t)dip; 2320Sstevel@tonic-gate return (0); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate void 2360Sstevel@tonic-gate dls_close(dls_channel_t dc) 2370Sstevel@tonic-gate { 2380Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 2390Sstevel@tonic-gate dls_vlan_t *dvp; 2400Sstevel@tonic-gate dls_link_t *dlp; 2410Sstevel@tonic-gate dls_multicst_addr_t *p; 2420Sstevel@tonic-gate dls_multicst_addr_t *nextp; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate dls_active_clear(dc); 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * Remove the notify function. 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate mac_notify_remove(dip->di_mh, dip->di_mnh); 2520Sstevel@tonic-gate dip->di_mnh = NULL; 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * If the dls_impl_t is bound then unbind it. 2560Sstevel@tonic-gate */ 2570Sstevel@tonic-gate dvp = dip->di_dvp; 2580Sstevel@tonic-gate dlp = dvp->dv_dlp; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if (dip->di_bound) { 2610Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 2620Sstevel@tonic-gate dls_link_remove(dlp, dip); 2630Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 2640Sstevel@tonic-gate dip->di_bound = B_FALSE; 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2672311Sseb dip->di_rx = NULL; 2682311Sseb dip->di_rx_arg = NULL; 2692311Sseb 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * Walk the list of multicast addresses, disabling each at the MAC. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate for (p = dip->di_dmap; p != NULL; p = nextp) { 2740Sstevel@tonic-gate (void) mac_multicst_remove(dip->di_mh, p->dma_addr); 2750Sstevel@tonic-gate nextp = p->dma_nextp; 2760Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 2770Sstevel@tonic-gate } 2780Sstevel@tonic-gate dip->di_dmap = NULL; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate /* 2830Sstevel@tonic-gate * If the MAC has been set in promiscuous mode then disable it. 2840Sstevel@tonic-gate */ 2850Sstevel@tonic-gate (void) dls_promisc(dc, 0); 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate /* 2880Sstevel@tonic-gate * Free the dls_impl_t back to the cache. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate dip->di_dvp = NULL; 29156Smeem dip->di_txinfo = NULL; 2921184Skrgopi 2931184Skrgopi if (dip->di_soft_ring_list != NULL) { 2941184Skrgopi soft_ring_set_destroy(dip->di_soft_ring_list, 2951184Skrgopi dip->di_soft_ring_size); 2961184Skrgopi dip->di_soft_ring_list = NULL; 2971184Skrgopi } 2981184Skrgopi dip->di_soft_ring_size = 0; 2991184Skrgopi 3000Sstevel@tonic-gate kmem_cache_free(i_dls_impl_cachep, dip); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /* 3030Sstevel@tonic-gate * Decrement the reference count to allow the cache to be destroyed 3040Sstevel@tonic-gate * if there are no more dls_impl_t. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate atomic_add_32(&i_dls_impl_count, -1); 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * Release our reference to the dls_vlan_t allowing that to be 310269Sericheng * destroyed if there are no more dls_impl_t. An unreferenced tagged 311269Sericheng * vlan gets destroyed automatically. 3120Sstevel@tonic-gate */ 3130Sstevel@tonic-gate dls_vlan_rele(dvp); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate mac_handle_t 3170Sstevel@tonic-gate dls_mac(dls_channel_t dc) 3180Sstevel@tonic-gate { 3192311Sseb return (((dls_impl_t *)dc)->di_mh); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate uint16_t 3230Sstevel@tonic-gate dls_vid(dls_channel_t dc) 3240Sstevel@tonic-gate { 3252311Sseb return (((dls_impl_t *)dc)->di_dvp->dv_id); 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate int 3292311Sseb dls_bind(dls_channel_t dc, uint32_t sap) 3300Sstevel@tonic-gate { 3310Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 3320Sstevel@tonic-gate dls_link_t *dlp; 3332311Sseb uint32_t dls_sap; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * Check to see the value is legal for the media type. 3370Sstevel@tonic-gate */ 3382311Sseb if (!mac_sap_verify(dip->di_mh, sap, &dls_sap)) 3390Sstevel@tonic-gate return (EINVAL); 3402311Sseb if (dip->di_promisc & DLS_PROMISC_SAP) 3412311Sseb dls_sap = DLS_SAP_PROMISC; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * Set up the dls_impl_t to mark it as able to receive packets. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 3470Sstevel@tonic-gate ASSERT(!dip->di_bound); 3480Sstevel@tonic-gate dip->di_sap = sap; 3490Sstevel@tonic-gate dip->di_bound = B_TRUE; 3500Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Now bind the dls_impl_t by adding it into the hash table in the 3540Sstevel@tonic-gate * dls_link_t. 3550Sstevel@tonic-gate * 3560Sstevel@tonic-gate * NOTE: This must be done without the dls_impl_t lock being held 3570Sstevel@tonic-gate * otherwise deadlock may ensue. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 3602311Sseb dls_link_add(dlp, dls_sap, dip); 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate return (0); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate void 3660Sstevel@tonic-gate dls_unbind(dls_channel_t dc) 3670Sstevel@tonic-gate { 3680Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 3690Sstevel@tonic-gate dls_link_t *dlp; 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate /* 3720Sstevel@tonic-gate * Unbind the dls_impl_t by removing it from the hash table in the 3730Sstevel@tonic-gate * dls_link_t. 3740Sstevel@tonic-gate * 3750Sstevel@tonic-gate * NOTE: This must be done without the dls_impl_t lock being held 3760Sstevel@tonic-gate * otherise deadlock may enuse. 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 3790Sstevel@tonic-gate dls_link_remove(dlp, dip); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Mark the dls_impl_t as unable to receive packets This will make 3830Sstevel@tonic-gate * sure that 'receives in flight' will not come our way. 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate dip->di_bound = B_FALSE; 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate int 3890Sstevel@tonic-gate dls_promisc(dls_channel_t dc, uint32_t flags) 3900Sstevel@tonic-gate { 3910Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 3920Sstevel@tonic-gate dls_link_t *dlp; 3930Sstevel@tonic-gate int err = 0; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 3960Sstevel@tonic-gate DLS_PROMISC_PHYS))); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate /* 3990Sstevel@tonic-gate * Check if we need to turn on 'all sap' mode. 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 4020Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 4030Sstevel@tonic-gate if ((flags & DLS_PROMISC_SAP) && 4040Sstevel@tonic-gate !(dip->di_promisc & DLS_PROMISC_SAP)) { 4050Sstevel@tonic-gate dip->di_promisc |= DLS_PROMISC_SAP; 4060Sstevel@tonic-gate if (!dip->di_bound) 4070Sstevel@tonic-gate goto multi; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 4100Sstevel@tonic-gate dls_link_remove(dlp, dip); 4110Sstevel@tonic-gate dls_link_add(dlp, DLS_SAP_PROMISC, dip); 4120Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 4130Sstevel@tonic-gate goto multi; 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * Check if we need to turn off 'all sap' mode. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate if (!(flags & DLS_PROMISC_SAP) && 4200Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_SAP)) { 4212311Sseb uint32_t dls_sap; 4222311Sseb 4230Sstevel@tonic-gate dip->di_promisc &= ~DLS_PROMISC_SAP; 4240Sstevel@tonic-gate if (!dip->di_bound) 4250Sstevel@tonic-gate goto multi; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 4280Sstevel@tonic-gate dls_link_remove(dlp, dip); 4292311Sseb (void) mac_sap_verify(dip->di_mh, dip->di_sap, &dls_sap); 4302311Sseb dls_link_add(dlp, dls_sap, dip); 4310Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate multi: 4350Sstevel@tonic-gate /* 4360Sstevel@tonic-gate * It's easiest to add the txloop handler up-front; if promiscuous 4370Sstevel@tonic-gate * mode cannot be enabled, then we'll remove it before returning. 43856Smeem * Use dl_promisc_lock to prevent racing with another thread also 43956Smeem * manipulating the promiscuous state on another dls_impl_t associated 44056Smeem * with the same dls_link_t. 4410Sstevel@tonic-gate */ 44256Smeem mutex_enter(&dlp->dl_promisc_lock); 4430Sstevel@tonic-gate if (dlp->dl_npromisc == 0 && 4440Sstevel@tonic-gate (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) { 4450Sstevel@tonic-gate ASSERT(dlp->dl_mth == NULL); 4462311Sseb dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_txloop, dlp); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 45056Smeem * Turn on or off 'all multicast' mode, if necessary. 4510Sstevel@tonic-gate */ 45256Smeem if (flags & DLS_PROMISC_MULTI) { 45356Smeem if (!(dip->di_promisc & DLS_PROMISC_MULTI)) { 45456Smeem err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 45556Smeem if (err != 0) 45656Smeem goto done; 45756Smeem dip->di_promisc |= DLS_PROMISC_MULTI; 45856Smeem dlp->dl_npromisc++; 45956Smeem } 46056Smeem } else { 46156Smeem if (dip->di_promisc & DLS_PROMISC_MULTI) { 46256Smeem err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 46356Smeem if (err != 0) 46456Smeem goto done; 46556Smeem dip->di_promisc &= ~DLS_PROMISC_MULTI; 46656Smeem dlp->dl_npromisc--; 46756Smeem } 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate /* 47156Smeem * Turn on or off 'all physical' mode, if necessary. 4720Sstevel@tonic-gate */ 47356Smeem if (flags & DLS_PROMISC_PHYS) { 47456Smeem if (!(dip->di_promisc & DLS_PROMISC_PHYS)) { 47556Smeem err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 47656Smeem if (err != 0) 47756Smeem goto done; 47856Smeem dip->di_promisc |= DLS_PROMISC_PHYS; 47956Smeem dlp->dl_npromisc++; 48056Smeem } 48156Smeem } else { 48256Smeem if (dip->di_promisc & DLS_PROMISC_PHYS) { 48356Smeem err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 48456Smeem if (err != 0) 48556Smeem goto done; 48656Smeem dip->di_promisc &= ~DLS_PROMISC_PHYS; 48756Smeem dlp->dl_npromisc--; 48856Smeem } 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate done: 4920Sstevel@tonic-gate if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 4930Sstevel@tonic-gate mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 4940Sstevel@tonic-gate dlp->dl_mth = NULL; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 49856Smeem mutex_exit(&dlp->dl_promisc_lock); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 5010Sstevel@tonic-gate return (err); 5020Sstevel@tonic-gate } 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate int 5050Sstevel@tonic-gate dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 5060Sstevel@tonic-gate { 5070Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 5080Sstevel@tonic-gate int err; 5090Sstevel@tonic-gate dls_multicst_addr_t **pp; 5100Sstevel@tonic-gate dls_multicst_addr_t *p; 5110Sstevel@tonic-gate uint_t addr_length; 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * Check whether the address is in the list of enabled addresses for 5150Sstevel@tonic-gate * this dls_impl_t. 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 5180Sstevel@tonic-gate addr_length = dip->di_mip->mi_addr_length; 5190Sstevel@tonic-gate for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 5200Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) { 5210Sstevel@tonic-gate /* 5220Sstevel@tonic-gate * It is there so there's nothing to do. 5230Sstevel@tonic-gate */ 5240Sstevel@tonic-gate err = 0; 5250Sstevel@tonic-gate goto done; 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /* 5300Sstevel@tonic-gate * Allocate a new list item. 5310Sstevel@tonic-gate */ 5320Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 5330Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 5340Sstevel@tonic-gate err = ENOMEM; 5350Sstevel@tonic-gate goto done; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* 5390Sstevel@tonic-gate * Enable the address at the MAC. 5400Sstevel@tonic-gate */ 5410Sstevel@tonic-gate if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 5420Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 5430Sstevel@tonic-gate goto done; 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * The address is now enabled at the MAC so add it to the list. 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate bcopy(addr, p->dma_addr, addr_length); 5500Sstevel@tonic-gate *pp = p; 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate done: 5530Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 5540Sstevel@tonic-gate return (err); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate int 5580Sstevel@tonic-gate dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 5590Sstevel@tonic-gate { 5600Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 5610Sstevel@tonic-gate int err; 5620Sstevel@tonic-gate dls_multicst_addr_t **pp; 5630Sstevel@tonic-gate dls_multicst_addr_t *p; 5640Sstevel@tonic-gate uint_t addr_length; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * Find the address in the list of enabled addresses for this 5680Sstevel@tonic-gate * dls_impl_t. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 5710Sstevel@tonic-gate addr_length = dip->di_mip->mi_addr_length; 5720Sstevel@tonic-gate for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 5730Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) 5740Sstevel@tonic-gate break; 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * If we walked to the end of the list then the given address is 5790Sstevel@tonic-gate * not currently enabled for this dls_impl_t. 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate if (p == NULL) { 5820Sstevel@tonic-gate err = ENOENT; 5830Sstevel@tonic-gate goto done; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate /* 5870Sstevel@tonic-gate * Disable the address at the MAC. 5880Sstevel@tonic-gate */ 5890Sstevel@tonic-gate if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 5900Sstevel@tonic-gate goto done; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate /* 5930Sstevel@tonic-gate * Remove the address from the list. 5940Sstevel@tonic-gate */ 5950Sstevel@tonic-gate *pp = p->dma_nextp; 5960Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate done: 5990Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 6000Sstevel@tonic-gate return (err); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate mblk_t * 6042311Sseb dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri, 605*2760Sdg199075 mblk_t **payloadp) 6060Sstevel@tonic-gate { 607*2760Sdg199075 dls_impl_t *dip = (dls_impl_t *)dc; 608*2760Sdg199075 uint16_t vid; 609*2760Sdg199075 size_t extra_len; 610*2760Sdg199075 uint16_t mac_sap; 611*2760Sdg199075 mblk_t *mp, *payload; 612*2760Sdg199075 boolean_t is_ethernet = (dip->di_mip->mi_media == DL_ETHER); 6132311Sseb struct ether_vlan_header *evhp; 6140Sstevel@tonic-gate 6152311Sseb vid = dip->di_dvp->dv_id; 616*2760Sdg199075 payload = (payloadp == NULL) ? NULL : (*payloadp); 617*2760Sdg199075 618*2760Sdg199075 /* 619*2760Sdg199075 * If the following conditions are satisfied: 620*2760Sdg199075 * - This is not a ETHERTYPE_VLAN listener; and 621*2760Sdg199075 * - This is either a VLAN stream or this is a physical stream 622*2760Sdg199075 * but the priority is not 0. 623*2760Sdg199075 * 624*2760Sdg199075 * then we know ahead of time that we'll need to fill in additional 625*2760Sdg199075 * VLAN information in the link-layer header. We will tell the MAC 626*2760Sdg199075 * layer to pre-allocate some space at the end of the Ethernet 627*2760Sdg199075 * header for us. 628*2760Sdg199075 */ 629*2760Sdg199075 if (is_ethernet && sap != ETHERTYPE_VLAN && 630*2760Sdg199075 (vid != VLAN_ID_NONE || pri != 0)) { 6312311Sseb extra_len = sizeof (struct ether_vlan_header) - 6322311Sseb sizeof (struct ether_header); 633*2760Sdg199075 mac_sap = ETHERTYPE_VLAN; 6342311Sseb } else { 6352311Sseb extra_len = 0; 6362311Sseb mac_sap = sap; 6372311Sseb } 6382311Sseb 6392311Sseb mp = mac_header(dip->di_mh, addr, mac_sap, payload, extra_len); 640*2760Sdg199075 if (mp == NULL) 641*2760Sdg199075 return (NULL); 642*2760Sdg199075 643*2760Sdg199075 if ((vid == VLAN_ID_NONE && pri == 0) || !is_ethernet) 6442311Sseb return (mp); 6452311Sseb 646*2760Sdg199075 /* 647*2760Sdg199075 * Fill in the tag information. 648*2760Sdg199075 */ 6492311Sseb ASSERT(MBLKL(mp) == sizeof (struct ether_header)); 650*2760Sdg199075 if (extra_len != 0) { 651*2760Sdg199075 mp->b_wptr += extra_len; 652*2760Sdg199075 evhp = (struct ether_vlan_header *)mp->b_rptr; 653*2760Sdg199075 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 654*2760Sdg199075 evhp->ether_type = htons(sap); 655*2760Sdg199075 } else { 656*2760Sdg199075 /* 657*2760Sdg199075 * The stream is ETHERTYPE_VLAN listener, so its VLAN tag is 658*2760Sdg199075 * in the payload. Update the priority. 659*2760Sdg199075 */ 660*2760Sdg199075 struct ether_vlan_extinfo *extinfo; 661*2760Sdg199075 size_t len = sizeof (struct ether_vlan_extinfo); 662*2760Sdg199075 663*2760Sdg199075 ASSERT(sap == ETHERTYPE_VLAN); 664*2760Sdg199075 ASSERT(payload != NULL); 665*2760Sdg199075 666*2760Sdg199075 if ((DB_REF(payload) > 1) || (MBLKL(payload) < len)) { 667*2760Sdg199075 mblk_t *newmp; 668*2760Sdg199075 669*2760Sdg199075 /* 670*2760Sdg199075 * Because some DLS consumers only check the db_ref 671*2760Sdg199075 * count of the first mblk, we pullup 'payload' into 672*2760Sdg199075 * a single mblk. 673*2760Sdg199075 */ 674*2760Sdg199075 newmp = msgpullup(payload, -1); 675*2760Sdg199075 if ((newmp == NULL) || (MBLKL(newmp) < len)) { 676*2760Sdg199075 freemsg(newmp); 677*2760Sdg199075 freemsg(mp); 678*2760Sdg199075 return (NULL); 679*2760Sdg199075 } else { 680*2760Sdg199075 freemsg(payload); 681*2760Sdg199075 *payloadp = payload = newmp; 682*2760Sdg199075 } 683*2760Sdg199075 } 684*2760Sdg199075 685*2760Sdg199075 extinfo = (struct ether_vlan_extinfo *)payload->b_rptr; 686*2760Sdg199075 extinfo->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, 687*2760Sdg199075 VLAN_ID(ntohs(extinfo->ether_tci)))); 688*2760Sdg199075 } 6892311Sseb return (mp); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate 6922311Sseb int 6932311Sseb dls_header_info(dls_channel_t dc, mblk_t *mp, mac_header_info_t *mhip) 6940Sstevel@tonic-gate { 6952311Sseb return (dls_link_header_info(((dls_impl_t *)dc)->di_dvp->dv_dlp, 696*2760Sdg199075 mp, mhip)); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate void 7000Sstevel@tonic-gate dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 7010Sstevel@tonic-gate { 7020Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 7050Sstevel@tonic-gate dip->di_rx = rx; 7060Sstevel@tonic-gate dip->di_rx_arg = arg; 7070Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate mblk_t * 7110Sstevel@tonic-gate dls_tx(dls_channel_t dc, mblk_t *mp) 7120Sstevel@tonic-gate { 71356Smeem const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo; 7140Sstevel@tonic-gate 71556Smeem return (mtp->mt_fn(mtp->mt_arg, mp)); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate boolean_t 7192311Sseb dls_accept(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 720449Sericheng void **di_rx_arg) 7210Sstevel@tonic-gate { 7220Sstevel@tonic-gate dls_multicst_addr_t *dmap; 7232311Sseb size_t addr_length = dip->di_mip->mi_addr_length; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate /* 7260Sstevel@tonic-gate * We must not accept packets if the dls_impl_t is not marked as bound 7270Sstevel@tonic-gate * or is being removed. 7280Sstevel@tonic-gate */ 7290Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_READER); 7300Sstevel@tonic-gate if (!dip->di_bound || dip->di_removing) 7310Sstevel@tonic-gate goto refuse; 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate /* 7340Sstevel@tonic-gate * If the dls_impl_t is in 'all physical' mode then always accept. 7350Sstevel@tonic-gate */ 7360Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_PHYS) 7370Sstevel@tonic-gate goto accept; 7380Sstevel@tonic-gate 7392311Sseb switch (mhip->mhi_dsttype) { 7402311Sseb case MAC_ADDRTYPE_UNICAST: 7412311Sseb /* 7422311Sseb * Check to see if the destination address matches the 7432311Sseb * dls_impl_t unicast address. 7442311Sseb */ 7452311Sseb if (memcmp(mhip->mhi_daddr, dip->di_unicst_addr, addr_length) == 7462311Sseb 0) { 7472311Sseb goto accept; 7482311Sseb } 7492311Sseb break; 7502311Sseb case MAC_ADDRTYPE_MULTICAST: 7512311Sseb /* 7522311Sseb * Check the address against the list of addresses enabled 7532311Sseb * for this dls_impl_t or accept it unconditionally if the 7542311Sseb * dls_impl_t is in 'all multicast' mode. 7552311Sseb */ 7562311Sseb if (dip->di_promisc & DLS_PROMISC_MULTI) 7572311Sseb goto accept; 7582311Sseb for (dmap = dip->di_dmap; dmap != NULL; 7592311Sseb dmap = dmap->dma_nextp) { 7602311Sseb if (memcmp(mhip->mhi_daddr, dmap->dma_addr, 7612311Sseb addr_length) == 0) { 7622311Sseb goto accept; 7632311Sseb } 7642311Sseb } 7652311Sseb break; 7662311Sseb case MAC_ADDRTYPE_BROADCAST: 7672311Sseb /* 7682311Sseb * If the address is broadcast then the dls_impl_t will 7692311Sseb * always accept it. 7702311Sseb */ 7710Sstevel@tonic-gate goto accept; 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate refuse: 7750Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 7760Sstevel@tonic-gate return (B_FALSE); 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate accept: 779449Sericheng /* 780449Sericheng * Since we hold di_lock here, the returned di_rx and di_rx_arg will 781449Sericheng * always be in sync. 782449Sericheng */ 783449Sericheng *di_rx = dip->di_rx; 784449Sericheng *di_rx_arg = dip->di_rx_arg; 7850Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 7860Sstevel@tonic-gate return (B_TRUE); 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 789*2760Sdg199075 /* ARGSUSED */ 7900Sstevel@tonic-gate boolean_t 791*2760Sdg199075 dls_accept_loopback(dls_impl_t *dip, mac_header_info_t *mhip, dls_rx_t *di_rx, 792*2760Sdg199075 void **di_rx_arg) 7930Sstevel@tonic-gate { 7940Sstevel@tonic-gate /* 7950Sstevel@tonic-gate * We must not accept packets if the dls_impl_t is not marked as bound 7960Sstevel@tonic-gate * or is being removed. 7970Sstevel@tonic-gate */ 7980Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_READER); 7990Sstevel@tonic-gate if (!dip->di_bound || dip->di_removing) 8000Sstevel@tonic-gate goto refuse; 8010Sstevel@tonic-gate 8020Sstevel@tonic-gate /* 8030Sstevel@tonic-gate * A dls_impl_t should only accept loopback packets if it is in 8040Sstevel@tonic-gate * 'all physical' mode. 8050Sstevel@tonic-gate */ 8060Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_PHYS) 8070Sstevel@tonic-gate goto accept; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate refuse: 8100Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 8110Sstevel@tonic-gate return (B_FALSE); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate accept: 814449Sericheng /* 815449Sericheng * Since we hold di_lock here, the returned di_rx and di_rx_arg will 816449Sericheng * always be in sync. 817449Sericheng */ 818449Sericheng *di_rx = dip->di_rx; 819449Sericheng *di_rx_arg = dip->di_rx_arg; 8200Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 8210Sstevel@tonic-gate return (B_TRUE); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate boolean_t 8250Sstevel@tonic-gate dls_active_set(dls_channel_t dc) 8260Sstevel@tonic-gate { 8270Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 8280Sstevel@tonic-gate dls_link_t *dlp = dip->di_dvp->dv_dlp; 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate rw_enter(&dip->di_lock, RW_WRITER); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate /* If we're already active, then there's nothing more to do. */ 8330Sstevel@tonic-gate if (dip->di_active) { 8340Sstevel@tonic-gate rw_exit(&dip->di_lock); 8350Sstevel@tonic-gate return (B_TRUE); 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate /* 8390Sstevel@tonic-gate * If this is the first active client on this link, notify 8400Sstevel@tonic-gate * the mac that we're becoming an active client. 8410Sstevel@tonic-gate */ 8420Sstevel@tonic-gate if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) { 8430Sstevel@tonic-gate rw_exit(&dip->di_lock); 8440Sstevel@tonic-gate return (B_FALSE); 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate dip->di_active = B_TRUE; 8470Sstevel@tonic-gate mutex_enter(&dlp->dl_lock); 8480Sstevel@tonic-gate dlp->dl_nactive++; 8490Sstevel@tonic-gate mutex_exit(&dlp->dl_lock); 8500Sstevel@tonic-gate rw_exit(&dip->di_lock); 8510Sstevel@tonic-gate return (B_TRUE); 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate void 8550Sstevel@tonic-gate dls_active_clear(dls_channel_t dc) 8560Sstevel@tonic-gate { 8570Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 8580Sstevel@tonic-gate dls_link_t *dlp = dip->di_dvp->dv_dlp; 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate rw_enter(&dip->di_lock, RW_WRITER); 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate if (!dip->di_active) 8630Sstevel@tonic-gate goto out; 8640Sstevel@tonic-gate dip->di_active = B_FALSE; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate mutex_enter(&dlp->dl_lock); 8670Sstevel@tonic-gate if (--dlp->dl_nactive == 0) 8680Sstevel@tonic-gate mac_active_clear(dip->di_mh); 8690Sstevel@tonic-gate mutex_exit(&dlp->dl_lock); 8700Sstevel@tonic-gate out: 8710Sstevel@tonic-gate rw_exit(&dip->di_lock); 8720Sstevel@tonic-gate } 873