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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Data-Link Services Module 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/stream.h> 350Sstevel@tonic-gate #include <sys/strsun.h> 360Sstevel@tonic-gate #include <sys/sysmacros.h> 370Sstevel@tonic-gate #include <sys/atomic.h> 380Sstevel@tonic-gate #include <sys/ght.h> 390Sstevel@tonic-gate #include <sys/dlpi.h> 400Sstevel@tonic-gate #include <sys/vlan.h> 410Sstevel@tonic-gate #include <sys/ethernet.h> 420Sstevel@tonic-gate #include <sys/byteorder.h> 430Sstevel@tonic-gate #include <sys/mac.h> 440Sstevel@tonic-gate 450Sstevel@tonic-gate #include <sys/dls.h> 460Sstevel@tonic-gate #include <sys/dls_impl.h> 470Sstevel@tonic-gate 480Sstevel@tonic-gate static kmem_cache_t *i_dls_impl_cachep; 490Sstevel@tonic-gate static uint32_t i_dls_impl_count; 500Sstevel@tonic-gate 510Sstevel@tonic-gate /* 520Sstevel@tonic-gate * Private functions. 530Sstevel@tonic-gate */ 540Sstevel@tonic-gate 550Sstevel@tonic-gate /*ARGSUSED*/ 560Sstevel@tonic-gate static int 570Sstevel@tonic-gate i_dls_constructor(void *buf, void *arg, int kmflag) 580Sstevel@tonic-gate { 590Sstevel@tonic-gate dls_impl_t *dip = buf; 600Sstevel@tonic-gate 610Sstevel@tonic-gate bzero(buf, sizeof (dls_impl_t)); 620Sstevel@tonic-gate 630Sstevel@tonic-gate rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL); 640Sstevel@tonic-gate return (0); 650Sstevel@tonic-gate } 660Sstevel@tonic-gate 670Sstevel@tonic-gate /*ARGSUSED*/ 680Sstevel@tonic-gate static void 690Sstevel@tonic-gate i_dls_destructor(void *buf, void *arg) 700Sstevel@tonic-gate { 710Sstevel@tonic-gate dls_impl_t *dip = buf; 720Sstevel@tonic-gate 730Sstevel@tonic-gate ASSERT(dip->di_dvp == NULL); 740Sstevel@tonic-gate ASSERT(dip->di_mnh == NULL); 750Sstevel@tonic-gate ASSERT(dip->di_dmap == NULL); 760Sstevel@tonic-gate ASSERT(!dip->di_bound); 770Sstevel@tonic-gate ASSERT(dip->di_rx == NULL); 78*56Smeem ASSERT(dip->di_txinfo == NULL); 790Sstevel@tonic-gate 800Sstevel@tonic-gate rw_destroy(&(dip->di_lock)); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 830Sstevel@tonic-gate static void 840Sstevel@tonic-gate i_dls_notify(void *arg, mac_notify_type_t type) 850Sstevel@tonic-gate { 860Sstevel@tonic-gate dls_impl_t *dip = arg; 870Sstevel@tonic-gate 880Sstevel@tonic-gate switch (type) { 890Sstevel@tonic-gate case MAC_NOTE_UNICST: 900Sstevel@tonic-gate mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 910Sstevel@tonic-gate break; 920Sstevel@tonic-gate 930Sstevel@tonic-gate case MAC_NOTE_PROMISC: 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * Every time the MAC interface changes promiscuity we 96*56Smeem * need to reset our transmit information. 970Sstevel@tonic-gate */ 98*56Smeem dip->di_txinfo = mac_tx_get(dip->di_mh); 990Sstevel@tonic-gate break; 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate static mblk_t * 1040Sstevel@tonic-gate i_dls_ether_header(dls_impl_t *dip, const uint8_t *daddr, uint16_t sap, 1050Sstevel@tonic-gate uint_t pri) 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate struct ether_header *ehp; 1080Sstevel@tonic-gate struct ether_vlan_header *evhp; 1090Sstevel@tonic-gate const mac_info_t *mip; 1100Sstevel@tonic-gate uint_t addr_length; 1110Sstevel@tonic-gate uint16_t vid; 1120Sstevel@tonic-gate mblk_t *mp; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate mip = dip->di_mip; 1150Sstevel@tonic-gate addr_length = mip->mi_addr_length; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * Check whether the DLSAP value is legal for ethernet. 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate if (!SAP_LEGAL(mip->mi_media, sap)) 1210Sstevel@tonic-gate return (NULL); 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* 1240Sstevel@tonic-gate * If the interface is a VLAN interface then we need VLAN packet 1250Sstevel@tonic-gate * headers. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate if ((vid = dip->di_dvp->dv_id) != VLAN_ID_NONE) 1280Sstevel@tonic-gate goto vlan; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * Allocate a normal ethernet packet header. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate if ((mp = allocb(sizeof (struct ether_header), BPRI_HI)) == NULL) 1340Sstevel@tonic-gate return (NULL); 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Copy in the given address as the destination, our current unicast 1380Sstevel@tonic-gate * address as the source and the given sap as the type/length. 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate ehp = (struct ether_header *)mp->b_rptr; 1410Sstevel@tonic-gate bcopy(daddr, &(ehp->ether_dhost), addr_length); 1420Sstevel@tonic-gate bcopy(dip->di_unicst_addr, &(ehp->ether_shost), addr_length); 1430Sstevel@tonic-gate ehp->ether_type = htons(sap); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate mp->b_wptr += sizeof (struct ether_header); 1460Sstevel@tonic-gate return (mp); 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate vlan: 1490Sstevel@tonic-gate /* 1500Sstevel@tonic-gate * Allocate a VLAN ethernet packet header. 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate if ((mp = allocb(sizeof (struct ether_vlan_header), BPRI_HI)) == NULL) 1530Sstevel@tonic-gate return (NULL); 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate /* 1560Sstevel@tonic-gate * Copy in the given address as the destination, our current unicast 1570Sstevel@tonic-gate * address as the source, the VLAN tpid and tci and the given sap as 1580Sstevel@tonic-gate * the type/length. 1590Sstevel@tonic-gate */ 1600Sstevel@tonic-gate evhp = (struct ether_vlan_header *)mp->b_rptr; 1610Sstevel@tonic-gate bcopy(daddr, &(evhp->ether_dhost), addr_length); 1620Sstevel@tonic-gate bcopy(dip->di_unicst_addr, &(evhp->ether_shost), addr_length); 1630Sstevel@tonic-gate evhp->ether_tpid = htons(VLAN_TPID); 1640Sstevel@tonic-gate evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 1650Sstevel@tonic-gate evhp->ether_type = htons(sap); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate mp->b_wptr += sizeof (struct ether_vlan_header); 1680Sstevel@tonic-gate return (mp); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /*ARGSUSED*/ 1720Sstevel@tonic-gate static void 1730Sstevel@tonic-gate i_dls_ether_header_info(dls_impl_t *dip, mblk_t *mp, dls_header_info_t *dhip) 1740Sstevel@tonic-gate { 1750Sstevel@tonic-gate struct ether_header *ehp; 1760Sstevel@tonic-gate struct ether_vlan_header *evhp; 1770Sstevel@tonic-gate uint16_t type_length; 1780Sstevel@tonic-gate uint16_t tci; 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct ether_header)); 1810Sstevel@tonic-gate ehp = (struct ether_header *)mp->b_rptr; 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate /* 1840Sstevel@tonic-gate * Determine whether to parse a normal or VLAN ethernet header. 1850Sstevel@tonic-gate */ 1860Sstevel@tonic-gate if ((type_length = ntohs(ehp->ether_type)) == VLAN_TPID) 1870Sstevel@tonic-gate goto vlan; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Specify the length of the header. 1910Sstevel@tonic-gate */ 1920Sstevel@tonic-gate dhip->dhi_length = sizeof (struct ether_header); 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * Get the destination address. 1960Sstevel@tonic-gate */ 1970Sstevel@tonic-gate dhip->dhi_daddr = (const uint8_t *)&(ehp->ether_dhost); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * If the destination address was a group address then 2010Sstevel@tonic-gate * dl_group_address field should be non-zero. 2020Sstevel@tonic-gate */ 2030Sstevel@tonic-gate dhip->dhi_isgroup = (dhip->dhi_daddr[0] & 0x01); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate /* 2060Sstevel@tonic-gate * Get the source address. 2070Sstevel@tonic-gate */ 2080Sstevel@tonic-gate dhip->dhi_saddr = (uint8_t *)&(ehp->ether_shost); 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Get the ethertype 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate dhip->dhi_ethertype = (type_length > ETHERMTU) ? type_length : 0; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2160Sstevel@tonic-gate * The VLAN identifier must be VLAN_ID_NONE. 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate dhip->dhi_vid = VLAN_ID_NONE; 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate return; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate vlan: 2230Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header)); 2240Sstevel@tonic-gate evhp = (struct ether_vlan_header *)mp->b_rptr; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* 2270Sstevel@tonic-gate * Specify the length of the header. 2280Sstevel@tonic-gate */ 2290Sstevel@tonic-gate dhip->dhi_length = sizeof (struct ether_vlan_header); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* 2320Sstevel@tonic-gate * Get the destination address. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate dhip->dhi_daddr = (const uint8_t *)&(evhp->ether_dhost); 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate /* 2370Sstevel@tonic-gate * If the destination address was a group address then 2380Sstevel@tonic-gate * dl_group_address field should be non-zero. 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate dhip->dhi_isgroup = (dhip->dhi_daddr[0] & 0x01); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * Get the source address. 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate dhip->dhi_saddr = (uint8_t *)&(evhp->ether_shost); 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /* 2480Sstevel@tonic-gate * Get the ethertype 2490Sstevel@tonic-gate */ 2500Sstevel@tonic-gate type_length = ntohs(evhp->ether_type); 2510Sstevel@tonic-gate dhip->dhi_ethertype = (type_length > ETHERMTU) ? type_length : 0; 2520Sstevel@tonic-gate ASSERT(dhip->dhi_ethertype != VLAN_TPID); 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * Get the VLAN identifier. 2560Sstevel@tonic-gate */ 2570Sstevel@tonic-gate tci = ntohs(evhp->ether_tci); 2580Sstevel@tonic-gate dhip->dhi_vid = VLAN_ID(tci); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* 2620Sstevel@tonic-gate * Module initialization functions. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate void 2660Sstevel@tonic-gate dls_init(void) 2670Sstevel@tonic-gate { 2680Sstevel@tonic-gate /* 2690Sstevel@tonic-gate * Create a kmem_cache of dls_impl_t. 2700Sstevel@tonic-gate */ 2710Sstevel@tonic-gate i_dls_impl_cachep = kmem_cache_create("dls_cache", 2720Sstevel@tonic-gate sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL, 2730Sstevel@tonic-gate NULL, NULL, 0); 2740Sstevel@tonic-gate ASSERT(i_dls_impl_cachep != NULL); 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate int 2780Sstevel@tonic-gate dls_fini(void) 2790Sstevel@tonic-gate { 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * If there are any dls_impl_t in use then return EBUSY. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate if (i_dls_impl_count != 0) 2840Sstevel@tonic-gate return (EBUSY); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * Destroy the kmem_cache. 2880Sstevel@tonic-gate */ 2890Sstevel@tonic-gate kmem_cache_destroy(i_dls_impl_cachep); 2900Sstevel@tonic-gate return (0); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /* 2940Sstevel@tonic-gate * Client function. 2950Sstevel@tonic-gate */ 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate int 2980Sstevel@tonic-gate dls_create(const char *name, const char *dev, uint_t port, uint16_t vid) 2990Sstevel@tonic-gate { 3000Sstevel@tonic-gate return (dls_vlan_create(name, dev, port, vid)); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate int 3040Sstevel@tonic-gate dls_destroy(const char *name) 3050Sstevel@tonic-gate { 3060Sstevel@tonic-gate return (dls_vlan_destroy(name)); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate int 3100Sstevel@tonic-gate dls_open(const char *name, dls_channel_t *dcp) 3110Sstevel@tonic-gate { 3120Sstevel@tonic-gate dls_impl_t *dip; 3130Sstevel@tonic-gate dls_vlan_t *dvp; 3140Sstevel@tonic-gate dls_link_t *dlp; 3150Sstevel@tonic-gate int err; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Get a reference to the named dls_vlan_t. 3190Sstevel@tonic-gate */ 3200Sstevel@tonic-gate if ((err = dls_vlan_hold(name, &dvp)) != 0) 3210Sstevel@tonic-gate return (err); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate /* 3240Sstevel@tonic-gate * Allocate a new dls_impl_t. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP); 3270Sstevel@tonic-gate dip->di_dvp = dvp; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * Cache a copy of the MAC interface handle, a pointer to the 3310Sstevel@tonic-gate * immutable MAC info and a copy of the current MAC address. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate dlp = dvp->dv_dlp; 3340Sstevel@tonic-gate dip->di_mh = dlp->dl_mh; 3350Sstevel@tonic-gate dip->di_mip = dlp->dl_mip; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* 340*56Smeem * Set the MAC transmit information. 3410Sstevel@tonic-gate */ 342*56Smeem dip->di_txinfo = mac_tx_get(dip->di_mh); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate /* 3450Sstevel@tonic-gate * Set up packet header constructor and parser functions. (We currently 3460Sstevel@tonic-gate * only support ethernet). 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate ASSERT(dip->di_mip->mi_media == DL_ETHER); 3490Sstevel@tonic-gate dip->di_header = i_dls_ether_header; 3500Sstevel@tonic-gate dip->di_header_info = i_dls_ether_header_info; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Add a notification function so that we get updates from the MAC. 3540Sstevel@tonic-gate */ 3550Sstevel@tonic-gate dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip); 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* 3580Sstevel@tonic-gate * Bump the kmem_cache count to make sure it is not prematurely 3590Sstevel@tonic-gate * destroyed. 3600Sstevel@tonic-gate */ 3610Sstevel@tonic-gate atomic_add_32(&i_dls_impl_count, 1); 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * Hand back a reference to the dls_impl_t. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate *dcp = (dls_channel_t)dip; 3670Sstevel@tonic-gate return (0); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate void 3710Sstevel@tonic-gate dls_close(dls_channel_t dc) 3720Sstevel@tonic-gate { 3730Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 3740Sstevel@tonic-gate dls_vlan_t *dvp; 3750Sstevel@tonic-gate dls_link_t *dlp; 3760Sstevel@tonic-gate dls_multicst_addr_t *p; 3770Sstevel@tonic-gate dls_multicst_addr_t *nextp; 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate dls_active_clear(dc); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * Remove the notify function. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate mac_notify_remove(dip->di_mh, dip->di_mnh); 3870Sstevel@tonic-gate dip->di_mnh = NULL; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate /* 3900Sstevel@tonic-gate * If the dls_impl_t is bound then unbind it. 3910Sstevel@tonic-gate */ 3920Sstevel@tonic-gate dvp = dip->di_dvp; 3930Sstevel@tonic-gate dlp = dvp->dv_dlp; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if (dip->di_bound) { 3960Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 3970Sstevel@tonic-gate dls_link_remove(dlp, dip); 3980Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 3990Sstevel@tonic-gate dip->di_rx = NULL; 4000Sstevel@tonic-gate dip->di_rx_arg = NULL; 4010Sstevel@tonic-gate dip->di_bound = B_FALSE; 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate /* 4050Sstevel@tonic-gate * Walk the list of multicast addresses, disabling each at the MAC. 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate for (p = dip->di_dmap; p != NULL; p = nextp) { 4080Sstevel@tonic-gate (void) mac_multicst_remove(dip->di_mh, p->dma_addr); 4090Sstevel@tonic-gate nextp = p->dma_nextp; 4100Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate dip->di_dmap = NULL; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * If the MAC has been set in promiscuous mode then disable it. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate (void) dls_promisc(dc, 0); 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * Free the dls_impl_t back to the cache. 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate dip->di_dvp = NULL; 425*56Smeem dip->di_txinfo = NULL; 4260Sstevel@tonic-gate kmem_cache_free(i_dls_impl_cachep, dip); 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate /* 4290Sstevel@tonic-gate * Decrement the reference count to allow the cache to be destroyed 4300Sstevel@tonic-gate * if there are no more dls_impl_t. 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate atomic_add_32(&i_dls_impl_count, -1); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * Release our reference to the dls_vlan_t allowing that to be 4360Sstevel@tonic-gate * destroyed if there are no more dls_impl_t. 4370Sstevel@tonic-gate */ 4380Sstevel@tonic-gate dls_vlan_rele(dvp); 4390Sstevel@tonic-gate } 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate mac_handle_t 4420Sstevel@tonic-gate dls_mac(dls_channel_t dc) 4430Sstevel@tonic-gate { 4440Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate return (dip->di_mh); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate uint16_t 4500Sstevel@tonic-gate dls_vid(dls_channel_t dc) 4510Sstevel@tonic-gate { 4520Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate return (dip->di_dvp->dv_id); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate int 4580Sstevel@tonic-gate dls_bind(dls_channel_t dc, uint16_t sap) 4590Sstevel@tonic-gate { 4600Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 4610Sstevel@tonic-gate dls_link_t *dlp; 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Check to see the value is legal for the media type. 4650Sstevel@tonic-gate */ 4660Sstevel@tonic-gate if (!SAP_LEGAL(dip->di_mip->mi_media, sap)) 4670Sstevel@tonic-gate return (EINVAL); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * Set up the dls_impl_t to mark it as able to receive packets. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 4730Sstevel@tonic-gate ASSERT(!dip->di_bound); 4740Sstevel@tonic-gate dip->di_sap = sap; 4750Sstevel@tonic-gate dip->di_bound = B_TRUE; 4760Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * Now bind the dls_impl_t by adding it into the hash table in the 4800Sstevel@tonic-gate * dls_link_t. 4810Sstevel@tonic-gate * 4820Sstevel@tonic-gate * NOTE: This must be done without the dls_impl_t lock being held 4830Sstevel@tonic-gate * otherwise deadlock may ensue. 4840Sstevel@tonic-gate */ 4850Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 4860Sstevel@tonic-gate dls_link_add(dlp, 4870Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_SAP) ? DLS_SAP_PROMISC : 4880Sstevel@tonic-gate (uint32_t)sap, dip); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate return (0); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate void 4940Sstevel@tonic-gate dls_unbind(dls_channel_t dc) 4950Sstevel@tonic-gate { 4960Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 4970Sstevel@tonic-gate dls_link_t *dlp; 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * Unbind the dls_impl_t by removing it from the hash table in the 5010Sstevel@tonic-gate * dls_link_t. 5020Sstevel@tonic-gate * 5030Sstevel@tonic-gate * NOTE: This must be done without the dls_impl_t lock being held 5040Sstevel@tonic-gate * otherise deadlock may enuse. 5050Sstevel@tonic-gate */ 5060Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 5070Sstevel@tonic-gate dls_link_remove(dlp, dip); 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* 5100Sstevel@tonic-gate * Mark the dls_impl_t as unable to receive packets This will make 5110Sstevel@tonic-gate * sure that 'receives in flight' will not come our way. 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate dip->di_bound = B_FALSE; 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate int 5170Sstevel@tonic-gate dls_promisc(dls_channel_t dc, uint32_t flags) 5180Sstevel@tonic-gate { 5190Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 5200Sstevel@tonic-gate dls_link_t *dlp; 5210Sstevel@tonic-gate int err = 0; 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 5240Sstevel@tonic-gate DLS_PROMISC_PHYS))); 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* 5270Sstevel@tonic-gate * Check if we need to turn on 'all sap' mode. 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 5300Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 5310Sstevel@tonic-gate if ((flags & DLS_PROMISC_SAP) && 5320Sstevel@tonic-gate !(dip->di_promisc & DLS_PROMISC_SAP)) { 5330Sstevel@tonic-gate dip->di_promisc |= DLS_PROMISC_SAP; 5340Sstevel@tonic-gate if (!dip->di_bound) 5350Sstevel@tonic-gate goto multi; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 5380Sstevel@tonic-gate dls_link_remove(dlp, dip); 5390Sstevel@tonic-gate dls_link_add(dlp, DLS_SAP_PROMISC, dip); 5400Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 5410Sstevel@tonic-gate goto multi; 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * Check if we need to turn off 'all sap' mode. 5460Sstevel@tonic-gate */ 5470Sstevel@tonic-gate if (!(flags & DLS_PROMISC_SAP) && 5480Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_SAP)) { 5490Sstevel@tonic-gate dip->di_promisc &= ~DLS_PROMISC_SAP; 5500Sstevel@tonic-gate if (!dip->di_bound) 5510Sstevel@tonic-gate goto multi; 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 5540Sstevel@tonic-gate dls_link_remove(dlp, dip); 5550Sstevel@tonic-gate dls_link_add(dlp, dip->di_sap, dip); 5560Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate multi: 5600Sstevel@tonic-gate /* 5610Sstevel@tonic-gate * It's easiest to add the txloop handler up-front; if promiscuous 5620Sstevel@tonic-gate * mode cannot be enabled, then we'll remove it before returning. 563*56Smeem * Use dl_promisc_lock to prevent racing with another thread also 564*56Smeem * manipulating the promiscuous state on another dls_impl_t associated 565*56Smeem * with the same dls_link_t. 5660Sstevel@tonic-gate */ 567*56Smeem mutex_enter(&dlp->dl_promisc_lock); 5680Sstevel@tonic-gate if (dlp->dl_npromisc == 0 && 5690Sstevel@tonic-gate (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) { 5700Sstevel@tonic-gate ASSERT(dlp->dl_mth == NULL); 5710Sstevel@tonic-gate dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_loopback, dlp); 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate /* 575*56Smeem * Turn on or off 'all multicast' mode, if necessary. 5760Sstevel@tonic-gate */ 577*56Smeem if (flags & DLS_PROMISC_MULTI) { 578*56Smeem if (!(dip->di_promisc & DLS_PROMISC_MULTI)) { 579*56Smeem err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 580*56Smeem if (err != 0) 581*56Smeem goto done; 582*56Smeem dip->di_promisc |= DLS_PROMISC_MULTI; 583*56Smeem dlp->dl_npromisc++; 584*56Smeem } 585*56Smeem } else { 586*56Smeem if (dip->di_promisc & DLS_PROMISC_MULTI) { 587*56Smeem err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 588*56Smeem if (err != 0) 589*56Smeem goto done; 590*56Smeem dip->di_promisc &= ~DLS_PROMISC_MULTI; 591*56Smeem dlp->dl_npromisc--; 592*56Smeem } 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate /* 596*56Smeem * Turn on or off 'all physical' mode, if necessary. 5970Sstevel@tonic-gate */ 598*56Smeem if (flags & DLS_PROMISC_PHYS) { 599*56Smeem if (!(dip->di_promisc & DLS_PROMISC_PHYS)) { 600*56Smeem err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 601*56Smeem if (err != 0) 602*56Smeem goto done; 603*56Smeem dip->di_promisc |= DLS_PROMISC_PHYS; 604*56Smeem dlp->dl_npromisc++; 605*56Smeem } 606*56Smeem } else { 607*56Smeem if (dip->di_promisc & DLS_PROMISC_PHYS) { 608*56Smeem err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 609*56Smeem if (err != 0) 610*56Smeem goto done; 611*56Smeem dip->di_promisc &= ~DLS_PROMISC_PHYS; 612*56Smeem dlp->dl_npromisc--; 613*56Smeem } 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate done: 6170Sstevel@tonic-gate if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 6180Sstevel@tonic-gate mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 6190Sstevel@tonic-gate dlp->dl_mth = NULL; 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 623*56Smeem mutex_exit(&dlp->dl_promisc_lock); 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 6260Sstevel@tonic-gate return (err); 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate int 6300Sstevel@tonic-gate dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 6310Sstevel@tonic-gate { 6320Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 6330Sstevel@tonic-gate int err; 6340Sstevel@tonic-gate dls_multicst_addr_t **pp; 6350Sstevel@tonic-gate dls_multicst_addr_t *p; 6360Sstevel@tonic-gate uint_t addr_length; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* 6390Sstevel@tonic-gate * Check whether the address is in the list of enabled addresses for 6400Sstevel@tonic-gate * this dls_impl_t. 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 6430Sstevel@tonic-gate addr_length = dip->di_mip->mi_addr_length; 6440Sstevel@tonic-gate for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 6450Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) { 6460Sstevel@tonic-gate /* 6470Sstevel@tonic-gate * It is there so there's nothing to do. 6480Sstevel@tonic-gate */ 6490Sstevel@tonic-gate err = 0; 6500Sstevel@tonic-gate goto done; 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate /* 6550Sstevel@tonic-gate * Allocate a new list item. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 6580Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 6590Sstevel@tonic-gate err = ENOMEM; 6600Sstevel@tonic-gate goto done; 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate /* 6640Sstevel@tonic-gate * Enable the address at the MAC. 6650Sstevel@tonic-gate */ 6660Sstevel@tonic-gate if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 6670Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 6680Sstevel@tonic-gate goto done; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate 6710Sstevel@tonic-gate /* 6720Sstevel@tonic-gate * The address is now enabled at the MAC so add it to the list. 6730Sstevel@tonic-gate */ 6740Sstevel@tonic-gate bcopy(addr, p->dma_addr, addr_length); 6750Sstevel@tonic-gate *pp = p; 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate done: 6780Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 6790Sstevel@tonic-gate return (err); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate int 6830Sstevel@tonic-gate dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 6840Sstevel@tonic-gate { 6850Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 6860Sstevel@tonic-gate int err; 6870Sstevel@tonic-gate dls_multicst_addr_t **pp; 6880Sstevel@tonic-gate dls_multicst_addr_t *p; 6890Sstevel@tonic-gate uint_t addr_length; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * Find the address in the list of enabled addresses for this 6930Sstevel@tonic-gate * dls_impl_t. 6940Sstevel@tonic-gate */ 6950Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 6960Sstevel@tonic-gate addr_length = dip->di_mip->mi_addr_length; 6970Sstevel@tonic-gate for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 6980Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) 6990Sstevel@tonic-gate break; 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* 7030Sstevel@tonic-gate * If we walked to the end of the list then the given address is 7040Sstevel@tonic-gate * not currently enabled for this dls_impl_t. 7050Sstevel@tonic-gate */ 7060Sstevel@tonic-gate if (p == NULL) { 7070Sstevel@tonic-gate err = ENOENT; 7080Sstevel@tonic-gate goto done; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate /* 7120Sstevel@tonic-gate * Disable the address at the MAC. 7130Sstevel@tonic-gate */ 7140Sstevel@tonic-gate if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 7150Sstevel@tonic-gate goto done; 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate /* 7180Sstevel@tonic-gate * Remove the address from the list. 7190Sstevel@tonic-gate */ 7200Sstevel@tonic-gate *pp = p->dma_nextp; 7210Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate done: 7240Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 7250Sstevel@tonic-gate return (err); 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate mblk_t * 7290Sstevel@tonic-gate dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri) 7300Sstevel@tonic-gate { 7310Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate return (dip->di_header(dip, addr, sap, pri)); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate void 7370Sstevel@tonic-gate dls_header_info(dls_channel_t dc, mblk_t *mp, dls_header_info_t *dhip) 7380Sstevel@tonic-gate { 7390Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate dip->di_header_info(dip, mp, dhip); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate void 7450Sstevel@tonic-gate dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 7460Sstevel@tonic-gate { 7470Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 7500Sstevel@tonic-gate dip->di_rx = rx; 7510Sstevel@tonic-gate dip->di_rx_arg = arg; 7520Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate mblk_t * 7560Sstevel@tonic-gate dls_tx(dls_channel_t dc, mblk_t *mp) 7570Sstevel@tonic-gate { 758*56Smeem const mac_txinfo_t *mtp = ((dls_impl_t *)dc)->di_txinfo; 7590Sstevel@tonic-gate 760*56Smeem return (mtp->mt_fn(mtp->mt_arg, mp)); 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * Exported functions. 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate #define ADDR_MATCH(_addr_a, _addr_b, _length, _match) \ 7680Sstevel@tonic-gate { \ 7690Sstevel@tonic-gate uint_t i; \ 7700Sstevel@tonic-gate \ 7710Sstevel@tonic-gate /* \ 7720Sstevel@tonic-gate * Make sure the addresses are 16 bit aligned and that \ 7730Sstevel@tonic-gate * the length is an even number of octets. \ 7740Sstevel@tonic-gate */ \ 7750Sstevel@tonic-gate ASSERT(IS_P2ALIGNED((_addr_a), sizeof (uint16_t))); \ 7760Sstevel@tonic-gate ASSERT(IS_P2ALIGNED((_addr_b), sizeof (uint16_t))); \ 7770Sstevel@tonic-gate ASSERT((_length & 1) == 0); \ 7780Sstevel@tonic-gate \ 7790Sstevel@tonic-gate (_match) = B_TRUE; \ 7800Sstevel@tonic-gate for (i = 0; i < (_length) >> 1; i++) { \ 7810Sstevel@tonic-gate if (((uint16_t *)(_addr_a))[i] != \ 7820Sstevel@tonic-gate ((uint16_t *)(_addr_b))[i]) { \ 7830Sstevel@tonic-gate (_match) = B_FALSE; \ 7840Sstevel@tonic-gate break; \ 7850Sstevel@tonic-gate } \ 7860Sstevel@tonic-gate } \ 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate boolean_t 7900Sstevel@tonic-gate dls_accept(dls_impl_t *dip, const uint8_t *daddr) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate boolean_t match; 7930Sstevel@tonic-gate dls_multicst_addr_t *dmap; 7940Sstevel@tonic-gate uint_t addr_length = dip->di_mip->mi_addr_length; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * We must not accept packets if the dls_impl_t is not marked as bound 7980Sstevel@tonic-gate * or is being removed. 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_READER); 8010Sstevel@tonic-gate if (!dip->di_bound || dip->di_removing) 8020Sstevel@tonic-gate goto refuse; 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate /* 8050Sstevel@tonic-gate * If the dls_impl_t is in 'all physical' mode then always accept. 8060Sstevel@tonic-gate */ 8070Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_PHYS) 8080Sstevel@tonic-gate goto accept; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate /* 8110Sstevel@tonic-gate * Check to see if the destination address matches the dls_impl_t 8120Sstevel@tonic-gate * unicast address. 8130Sstevel@tonic-gate */ 8140Sstevel@tonic-gate ADDR_MATCH(daddr, dip->di_unicst_addr, addr_length, match); 8150Sstevel@tonic-gate if (match) 8160Sstevel@tonic-gate goto accept; 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate /* 8190Sstevel@tonic-gate * Check for a 'group' address. If it is not then refuse it since we 8200Sstevel@tonic-gate * already know it does not match the unicast address. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate if (!(daddr[0] & 0x01)) 8230Sstevel@tonic-gate goto refuse; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate /* 8260Sstevel@tonic-gate * If the address is broadcast then the dls_impl_t will always accept 8270Sstevel@tonic-gate * it. 8280Sstevel@tonic-gate */ 8290Sstevel@tonic-gate ADDR_MATCH(daddr, dip->di_mip->mi_brdcst_addr, addr_length, 8300Sstevel@tonic-gate match); 8310Sstevel@tonic-gate if (match) 8320Sstevel@tonic-gate goto accept; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* 8350Sstevel@tonic-gate * If a group address is not broadcast then it must be multicast so 8360Sstevel@tonic-gate * check it against the list of addresses enabled for this dls_impl_t 8370Sstevel@tonic-gate * or accept it unconditionally if the dls_impl_t is in 'all 8380Sstevel@tonic-gate * multicast' mode. 8390Sstevel@tonic-gate */ 8400Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_MULTI) 8410Sstevel@tonic-gate goto accept; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate for (dmap = dip->di_dmap; dmap != NULL; dmap = dmap->dma_nextp) { 8440Sstevel@tonic-gate ADDR_MATCH(daddr, dmap->dma_addr, addr_length, match); 8450Sstevel@tonic-gate if (match) 8460Sstevel@tonic-gate goto accept; 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate refuse: 8500Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 8510Sstevel@tonic-gate return (B_FALSE); 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate accept: 8540Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 8550Sstevel@tonic-gate return (B_TRUE); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate /*ARGSUSED*/ 8590Sstevel@tonic-gate boolean_t 8600Sstevel@tonic-gate dls_accept_loopback(dls_impl_t *dip, const uint8_t *daddr) 8610Sstevel@tonic-gate { 8620Sstevel@tonic-gate /* 8630Sstevel@tonic-gate * We must not accept packets if the dls_impl_t is not marked as bound 8640Sstevel@tonic-gate * or is being removed. 8650Sstevel@tonic-gate */ 8660Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_READER); 8670Sstevel@tonic-gate if (!dip->di_bound || dip->di_removing) 8680Sstevel@tonic-gate goto refuse; 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * A dls_impl_t should only accept loopback packets if it is in 8720Sstevel@tonic-gate * 'all physical' mode. 8730Sstevel@tonic-gate */ 8740Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_PHYS) 8750Sstevel@tonic-gate goto accept; 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate refuse: 8780Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 8790Sstevel@tonic-gate return (B_FALSE); 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate accept: 8820Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 8830Sstevel@tonic-gate return (B_TRUE); 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate boolean_t 8870Sstevel@tonic-gate dls_active_set(dls_channel_t dc) 8880Sstevel@tonic-gate { 8890Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 8900Sstevel@tonic-gate dls_link_t *dlp = dip->di_dvp->dv_dlp; 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate rw_enter(&dip->di_lock, RW_WRITER); 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* If we're already active, then there's nothing more to do. */ 8950Sstevel@tonic-gate if (dip->di_active) { 8960Sstevel@tonic-gate rw_exit(&dip->di_lock); 8970Sstevel@tonic-gate return (B_TRUE); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate /* 9010Sstevel@tonic-gate * If this is the first active client on this link, notify 9020Sstevel@tonic-gate * the mac that we're becoming an active client. 9030Sstevel@tonic-gate */ 9040Sstevel@tonic-gate if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) { 9050Sstevel@tonic-gate rw_exit(&dip->di_lock); 9060Sstevel@tonic-gate return (B_FALSE); 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate dip->di_active = B_TRUE; 9090Sstevel@tonic-gate mutex_enter(&dlp->dl_lock); 9100Sstevel@tonic-gate dlp->dl_nactive++; 9110Sstevel@tonic-gate mutex_exit(&dlp->dl_lock); 9120Sstevel@tonic-gate rw_exit(&dip->di_lock); 9130Sstevel@tonic-gate return (B_TRUE); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate void 9170Sstevel@tonic-gate dls_active_clear(dls_channel_t dc) 9180Sstevel@tonic-gate { 9190Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 9200Sstevel@tonic-gate dls_link_t *dlp = dip->di_dvp->dv_dlp; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate rw_enter(&dip->di_lock, RW_WRITER); 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate if (!dip->di_active) 9250Sstevel@tonic-gate goto out; 9260Sstevel@tonic-gate dip->di_active = B_FALSE; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate mutex_enter(&dlp->dl_lock); 9290Sstevel@tonic-gate if (--dlp->dl_nactive == 0) 9300Sstevel@tonic-gate mac_active_clear(dip->di_mh); 9310Sstevel@tonic-gate mutex_exit(&dlp->dl_lock); 9320Sstevel@tonic-gate out: 9330Sstevel@tonic-gate rw_exit(&dip->di_lock); 9340Sstevel@tonic-gate } 935