1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Data-Link Services Module 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/stream.h> 35*0Sstevel@tonic-gate #include <sys/strsun.h> 36*0Sstevel@tonic-gate #include <sys/sysmacros.h> 37*0Sstevel@tonic-gate #include <sys/atomic.h> 38*0Sstevel@tonic-gate #include <sys/ght.h> 39*0Sstevel@tonic-gate #include <sys/dlpi.h> 40*0Sstevel@tonic-gate #include <sys/vlan.h> 41*0Sstevel@tonic-gate #include <sys/ethernet.h> 42*0Sstevel@tonic-gate #include <sys/byteorder.h> 43*0Sstevel@tonic-gate #include <sys/mac.h> 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #include <sys/dls.h> 46*0Sstevel@tonic-gate #include <sys/dls_impl.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate static kmem_cache_t *i_dls_impl_cachep; 49*0Sstevel@tonic-gate static uint32_t i_dls_impl_count; 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate /* 52*0Sstevel@tonic-gate * Private functions. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate /*ARGSUSED*/ 56*0Sstevel@tonic-gate static int 57*0Sstevel@tonic-gate i_dls_constructor(void *buf, void *arg, int kmflag) 58*0Sstevel@tonic-gate { 59*0Sstevel@tonic-gate dls_impl_t *dip = buf; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate bzero(buf, sizeof (dls_impl_t)); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate rw_init(&(dip->di_lock), NULL, RW_DRIVER, NULL); 64*0Sstevel@tonic-gate return (0); 65*0Sstevel@tonic-gate } 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate /*ARGSUSED*/ 68*0Sstevel@tonic-gate static void 69*0Sstevel@tonic-gate i_dls_destructor(void *buf, void *arg) 70*0Sstevel@tonic-gate { 71*0Sstevel@tonic-gate dls_impl_t *dip = buf; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate ASSERT(dip->di_dvp == NULL); 74*0Sstevel@tonic-gate ASSERT(dip->di_mnh == NULL); 75*0Sstevel@tonic-gate ASSERT(dip->di_dmap == NULL); 76*0Sstevel@tonic-gate ASSERT(!dip->di_bound); 77*0Sstevel@tonic-gate ASSERT(dip->di_rx == NULL); 78*0Sstevel@tonic-gate ASSERT(dip->di_tx == NULL); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate rw_destroy(&(dip->di_lock)); 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static void 84*0Sstevel@tonic-gate i_dls_notify(void *arg, mac_notify_type_t type) 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate dls_impl_t *dip = arg; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate switch (type) { 89*0Sstevel@tonic-gate case MAC_NOTE_UNICST: 90*0Sstevel@tonic-gate mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 91*0Sstevel@tonic-gate break; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate case MAC_NOTE_PROMISC: 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Every time the MAC interface changes promiscuity we 96*0Sstevel@tonic-gate * need to reset the transmit function: 97*0Sstevel@tonic-gate * 98*0Sstevel@tonic-gate * - In non-promiscuous mode we simply copy the function 99*0Sstevel@tonic-gate * pointer from the MAC module. 100*0Sstevel@tonic-gate * 101*0Sstevel@tonic-gate * - In promiscuous mode we use mac_txloop(), which will 102*0Sstevel@tonic-gate * handle the loopback case. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate if (mac_promisc_get(dip->di_mh, MAC_PROMISC)) { 105*0Sstevel@tonic-gate dip->di_tx = mac_txloop; 106*0Sstevel@tonic-gate dip->di_tx_arg = dip->di_mh; 107*0Sstevel@tonic-gate } else { 108*0Sstevel@tonic-gate mac_tx_get(dip->di_mh, &dip->di_tx, &dip->di_tx_arg); 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate break; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate static mblk_t * 115*0Sstevel@tonic-gate i_dls_ether_header(dls_impl_t *dip, const uint8_t *daddr, uint16_t sap, 116*0Sstevel@tonic-gate uint_t pri) 117*0Sstevel@tonic-gate { 118*0Sstevel@tonic-gate struct ether_header *ehp; 119*0Sstevel@tonic-gate struct ether_vlan_header *evhp; 120*0Sstevel@tonic-gate const mac_info_t *mip; 121*0Sstevel@tonic-gate uint_t addr_length; 122*0Sstevel@tonic-gate uint16_t vid; 123*0Sstevel@tonic-gate mblk_t *mp; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate mip = dip->di_mip; 126*0Sstevel@tonic-gate addr_length = mip->mi_addr_length; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* 129*0Sstevel@tonic-gate * Check whether the DLSAP value is legal for ethernet. 130*0Sstevel@tonic-gate */ 131*0Sstevel@tonic-gate if (!SAP_LEGAL(mip->mi_media, sap)) 132*0Sstevel@tonic-gate return (NULL); 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * If the interface is a VLAN interface then we need VLAN packet 136*0Sstevel@tonic-gate * headers. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate if ((vid = dip->di_dvp->dv_id) != VLAN_ID_NONE) 139*0Sstevel@tonic-gate goto vlan; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate /* 142*0Sstevel@tonic-gate * Allocate a normal ethernet packet header. 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate if ((mp = allocb(sizeof (struct ether_header), BPRI_HI)) == NULL) 145*0Sstevel@tonic-gate return (NULL); 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate /* 148*0Sstevel@tonic-gate * Copy in the given address as the destination, our current unicast 149*0Sstevel@tonic-gate * address as the source and the given sap as the type/length. 150*0Sstevel@tonic-gate */ 151*0Sstevel@tonic-gate ehp = (struct ether_header *)mp->b_rptr; 152*0Sstevel@tonic-gate bcopy(daddr, &(ehp->ether_dhost), addr_length); 153*0Sstevel@tonic-gate bcopy(dip->di_unicst_addr, &(ehp->ether_shost), addr_length); 154*0Sstevel@tonic-gate ehp->ether_type = htons(sap); 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate mp->b_wptr += sizeof (struct ether_header); 157*0Sstevel@tonic-gate return (mp); 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate vlan: 160*0Sstevel@tonic-gate /* 161*0Sstevel@tonic-gate * Allocate a VLAN ethernet packet header. 162*0Sstevel@tonic-gate */ 163*0Sstevel@tonic-gate if ((mp = allocb(sizeof (struct ether_vlan_header), BPRI_HI)) == NULL) 164*0Sstevel@tonic-gate return (NULL); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * Copy in the given address as the destination, our current unicast 168*0Sstevel@tonic-gate * address as the source, the VLAN tpid and tci and the given sap as 169*0Sstevel@tonic-gate * the type/length. 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate evhp = (struct ether_vlan_header *)mp->b_rptr; 172*0Sstevel@tonic-gate bcopy(daddr, &(evhp->ether_dhost), addr_length); 173*0Sstevel@tonic-gate bcopy(dip->di_unicst_addr, &(evhp->ether_shost), addr_length); 174*0Sstevel@tonic-gate evhp->ether_tpid = htons(VLAN_TPID); 175*0Sstevel@tonic-gate evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid)); 176*0Sstevel@tonic-gate evhp->ether_type = htons(sap); 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate mp->b_wptr += sizeof (struct ether_vlan_header); 179*0Sstevel@tonic-gate return (mp); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /*ARGSUSED*/ 183*0Sstevel@tonic-gate static void 184*0Sstevel@tonic-gate i_dls_ether_header_info(dls_impl_t *dip, mblk_t *mp, dls_header_info_t *dhip) 185*0Sstevel@tonic-gate { 186*0Sstevel@tonic-gate struct ether_header *ehp; 187*0Sstevel@tonic-gate struct ether_vlan_header *evhp; 188*0Sstevel@tonic-gate uint16_t type_length; 189*0Sstevel@tonic-gate uint16_t tci; 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct ether_header)); 192*0Sstevel@tonic-gate ehp = (struct ether_header *)mp->b_rptr; 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * Determine whether to parse a normal or VLAN ethernet header. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate if ((type_length = ntohs(ehp->ether_type)) == VLAN_TPID) 198*0Sstevel@tonic-gate goto vlan; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* 201*0Sstevel@tonic-gate * Specify the length of the header. 202*0Sstevel@tonic-gate */ 203*0Sstevel@tonic-gate dhip->dhi_length = sizeof (struct ether_header); 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate /* 206*0Sstevel@tonic-gate * Get the destination address. 207*0Sstevel@tonic-gate */ 208*0Sstevel@tonic-gate dhip->dhi_daddr = (const uint8_t *)&(ehp->ether_dhost); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * If the destination address was a group address then 212*0Sstevel@tonic-gate * dl_group_address field should be non-zero. 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate dhip->dhi_isgroup = (dhip->dhi_daddr[0] & 0x01); 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * Get the source address. 218*0Sstevel@tonic-gate */ 219*0Sstevel@tonic-gate dhip->dhi_saddr = (uint8_t *)&(ehp->ether_shost); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * Get the ethertype 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate dhip->dhi_ethertype = (type_length > ETHERMTU) ? type_length : 0; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate /* 227*0Sstevel@tonic-gate * The VLAN identifier must be VLAN_ID_NONE. 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate dhip->dhi_vid = VLAN_ID_NONE; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate return; 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate vlan: 234*0Sstevel@tonic-gate ASSERT(MBLKL(mp) >= sizeof (struct ether_vlan_header)); 235*0Sstevel@tonic-gate evhp = (struct ether_vlan_header *)mp->b_rptr; 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * Specify the length of the header. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate dhip->dhi_length = sizeof (struct ether_vlan_header); 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * Get the destination address. 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate dhip->dhi_daddr = (const uint8_t *)&(evhp->ether_dhost); 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * If the destination address was a group address then 249*0Sstevel@tonic-gate * dl_group_address field should be non-zero. 250*0Sstevel@tonic-gate */ 251*0Sstevel@tonic-gate dhip->dhi_isgroup = (dhip->dhi_daddr[0] & 0x01); 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * Get the source address. 255*0Sstevel@tonic-gate */ 256*0Sstevel@tonic-gate dhip->dhi_saddr = (uint8_t *)&(evhp->ether_shost); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * Get the ethertype 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate type_length = ntohs(evhp->ether_type); 262*0Sstevel@tonic-gate dhip->dhi_ethertype = (type_length > ETHERMTU) ? type_length : 0; 263*0Sstevel@tonic-gate ASSERT(dhip->dhi_ethertype != VLAN_TPID); 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * Get the VLAN identifier. 267*0Sstevel@tonic-gate */ 268*0Sstevel@tonic-gate tci = ntohs(evhp->ether_tci); 269*0Sstevel@tonic-gate dhip->dhi_vid = VLAN_ID(tci); 270*0Sstevel@tonic-gate } 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate /* 273*0Sstevel@tonic-gate * Module initialization functions. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate void 277*0Sstevel@tonic-gate dls_init(void) 278*0Sstevel@tonic-gate { 279*0Sstevel@tonic-gate /* 280*0Sstevel@tonic-gate * Create a kmem_cache of dls_impl_t. 281*0Sstevel@tonic-gate */ 282*0Sstevel@tonic-gate i_dls_impl_cachep = kmem_cache_create("dls_cache", 283*0Sstevel@tonic-gate sizeof (dls_impl_t), 0, i_dls_constructor, i_dls_destructor, NULL, 284*0Sstevel@tonic-gate NULL, NULL, 0); 285*0Sstevel@tonic-gate ASSERT(i_dls_impl_cachep != NULL); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate int 289*0Sstevel@tonic-gate dls_fini(void) 290*0Sstevel@tonic-gate { 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * If there are any dls_impl_t in use then return EBUSY. 293*0Sstevel@tonic-gate */ 294*0Sstevel@tonic-gate if (i_dls_impl_count != 0) 295*0Sstevel@tonic-gate return (EBUSY); 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate /* 298*0Sstevel@tonic-gate * Destroy the kmem_cache. 299*0Sstevel@tonic-gate */ 300*0Sstevel@tonic-gate kmem_cache_destroy(i_dls_impl_cachep); 301*0Sstevel@tonic-gate return (0); 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * Client function. 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate int 309*0Sstevel@tonic-gate dls_create(const char *name, const char *dev, uint_t port, uint16_t vid) 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate return (dls_vlan_create(name, dev, port, vid)); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate int 315*0Sstevel@tonic-gate dls_destroy(const char *name) 316*0Sstevel@tonic-gate { 317*0Sstevel@tonic-gate return (dls_vlan_destroy(name)); 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate int 321*0Sstevel@tonic-gate dls_open(const char *name, dls_channel_t *dcp) 322*0Sstevel@tonic-gate { 323*0Sstevel@tonic-gate dls_impl_t *dip; 324*0Sstevel@tonic-gate dls_vlan_t *dvp; 325*0Sstevel@tonic-gate dls_link_t *dlp; 326*0Sstevel@tonic-gate int err; 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * Get a reference to the named dls_vlan_t. 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate if ((err = dls_vlan_hold(name, &dvp)) != 0) 332*0Sstevel@tonic-gate return (err); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate /* 335*0Sstevel@tonic-gate * Allocate a new dls_impl_t. 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate dip = kmem_cache_alloc(i_dls_impl_cachep, KM_SLEEP); 338*0Sstevel@tonic-gate dip->di_dvp = dvp; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* 341*0Sstevel@tonic-gate * Cache a copy of the MAC interface handle, a pointer to the 342*0Sstevel@tonic-gate * immutable MAC info and a copy of the current MAC address. 343*0Sstevel@tonic-gate */ 344*0Sstevel@tonic-gate dlp = dvp->dv_dlp; 345*0Sstevel@tonic-gate dip->di_mh = dlp->dl_mh; 346*0Sstevel@tonic-gate dip->di_mip = dlp->dl_mip; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate mac_unicst_get(dip->di_mh, dip->di_unicst_addr); 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * Set the MAC transmit function. 352*0Sstevel@tonic-gate * 353*0Sstevel@tonic-gate * NOTE: We know that the MAC is not in promiscuous mode so we 354*0Sstevel@tonic-gate * simply copy the values from the MAC. 355*0Sstevel@tonic-gate * (See comment in i_dls_notify() for further explanation). 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate mac_tx_get(dip->di_mh, &dip->di_tx, &dip->di_tx_arg); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate /* 360*0Sstevel@tonic-gate * Set up packet header constructor and parser functions. (We currently 361*0Sstevel@tonic-gate * only support ethernet). 362*0Sstevel@tonic-gate */ 363*0Sstevel@tonic-gate ASSERT(dip->di_mip->mi_media == DL_ETHER); 364*0Sstevel@tonic-gate dip->di_header = i_dls_ether_header; 365*0Sstevel@tonic-gate dip->di_header_info = i_dls_ether_header_info; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /* 368*0Sstevel@tonic-gate * Add a notification function so that we get updates from the MAC. 369*0Sstevel@tonic-gate */ 370*0Sstevel@tonic-gate dip->di_mnh = mac_notify_add(dip->di_mh, i_dls_notify, (void *)dip); 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * Bump the kmem_cache count to make sure it is not prematurely 374*0Sstevel@tonic-gate * destroyed. 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate atomic_add_32(&i_dls_impl_count, 1); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * Hand back a reference to the dls_impl_t. 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate *dcp = (dls_channel_t)dip; 382*0Sstevel@tonic-gate return (0); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate void 386*0Sstevel@tonic-gate dls_close(dls_channel_t dc) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 389*0Sstevel@tonic-gate dls_vlan_t *dvp; 390*0Sstevel@tonic-gate dls_link_t *dlp; 391*0Sstevel@tonic-gate dls_multicst_addr_t *p; 392*0Sstevel@tonic-gate dls_multicst_addr_t *nextp; 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate dls_active_clear(dc); 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * Remove the notify function. 400*0Sstevel@tonic-gate */ 401*0Sstevel@tonic-gate mac_notify_remove(dip->di_mh, dip->di_mnh); 402*0Sstevel@tonic-gate dip->di_mnh = NULL; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* 405*0Sstevel@tonic-gate * If the dls_impl_t is bound then unbind it. 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate dvp = dip->di_dvp; 408*0Sstevel@tonic-gate dlp = dvp->dv_dlp; 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate if (dip->di_bound) { 411*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 412*0Sstevel@tonic-gate dls_link_remove(dlp, dip); 413*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 414*0Sstevel@tonic-gate dip->di_rx = NULL; 415*0Sstevel@tonic-gate dip->di_rx_arg = NULL; 416*0Sstevel@tonic-gate dip->di_bound = B_FALSE; 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * Walk the list of multicast addresses, disabling each at the MAC. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate for (p = dip->di_dmap; p != NULL; p = nextp) { 423*0Sstevel@tonic-gate (void) mac_multicst_remove(dip->di_mh, p->dma_addr); 424*0Sstevel@tonic-gate nextp = p->dma_nextp; 425*0Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate dip->di_dmap = NULL; 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate /* 432*0Sstevel@tonic-gate * If the MAC has been set in promiscuous mode then disable it. 433*0Sstevel@tonic-gate */ 434*0Sstevel@tonic-gate (void) dls_promisc(dc, 0); 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* 437*0Sstevel@tonic-gate * Free the dls_impl_t back to the cache. 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate dip->di_dvp = NULL; 440*0Sstevel@tonic-gate dip->di_tx = NULL; 441*0Sstevel@tonic-gate dip->di_tx_arg = NULL; 442*0Sstevel@tonic-gate kmem_cache_free(i_dls_impl_cachep, dip); 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* 445*0Sstevel@tonic-gate * Decrement the reference count to allow the cache to be destroyed 446*0Sstevel@tonic-gate * if there are no more dls_impl_t. 447*0Sstevel@tonic-gate */ 448*0Sstevel@tonic-gate atomic_add_32(&i_dls_impl_count, -1); 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * Release our reference to the dls_vlan_t allowing that to be 452*0Sstevel@tonic-gate * destroyed if there are no more dls_impl_t. 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate dls_vlan_rele(dvp); 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate mac_handle_t 458*0Sstevel@tonic-gate dls_mac(dls_channel_t dc) 459*0Sstevel@tonic-gate { 460*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate return (dip->di_mh); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate uint16_t 466*0Sstevel@tonic-gate dls_vid(dls_channel_t dc) 467*0Sstevel@tonic-gate { 468*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate return (dip->di_dvp->dv_id); 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate int 474*0Sstevel@tonic-gate dls_bind(dls_channel_t dc, uint16_t sap) 475*0Sstevel@tonic-gate { 476*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 477*0Sstevel@tonic-gate dls_link_t *dlp; 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * Check to see the value is legal for the media type. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate if (!SAP_LEGAL(dip->di_mip->mi_media, sap)) 483*0Sstevel@tonic-gate return (EINVAL); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate /* 486*0Sstevel@tonic-gate * Set up the dls_impl_t to mark it as able to receive packets. 487*0Sstevel@tonic-gate */ 488*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 489*0Sstevel@tonic-gate ASSERT(!dip->di_bound); 490*0Sstevel@tonic-gate dip->di_sap = sap; 491*0Sstevel@tonic-gate dip->di_bound = B_TRUE; 492*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* 495*0Sstevel@tonic-gate * Now bind the dls_impl_t by adding it into the hash table in the 496*0Sstevel@tonic-gate * dls_link_t. 497*0Sstevel@tonic-gate * 498*0Sstevel@tonic-gate * NOTE: This must be done without the dls_impl_t lock being held 499*0Sstevel@tonic-gate * otherwise deadlock may ensue. 500*0Sstevel@tonic-gate */ 501*0Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 502*0Sstevel@tonic-gate dls_link_add(dlp, 503*0Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_SAP) ? DLS_SAP_PROMISC : 504*0Sstevel@tonic-gate (uint32_t)sap, dip); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate return (0); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate void 510*0Sstevel@tonic-gate dls_unbind(dls_channel_t dc) 511*0Sstevel@tonic-gate { 512*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 513*0Sstevel@tonic-gate dls_link_t *dlp; 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate /* 516*0Sstevel@tonic-gate * Unbind the dls_impl_t by removing it from the hash table in the 517*0Sstevel@tonic-gate * dls_link_t. 518*0Sstevel@tonic-gate * 519*0Sstevel@tonic-gate * NOTE: This must be done without the dls_impl_t lock being held 520*0Sstevel@tonic-gate * otherise deadlock may enuse. 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 523*0Sstevel@tonic-gate dls_link_remove(dlp, dip); 524*0Sstevel@tonic-gate 525*0Sstevel@tonic-gate /* 526*0Sstevel@tonic-gate * Mark the dls_impl_t as unable to receive packets This will make 527*0Sstevel@tonic-gate * sure that 'receives in flight' will not come our way. 528*0Sstevel@tonic-gate */ 529*0Sstevel@tonic-gate dip->di_bound = B_FALSE; 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate int 533*0Sstevel@tonic-gate dls_promisc(dls_channel_t dc, uint32_t flags) 534*0Sstevel@tonic-gate { 535*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 536*0Sstevel@tonic-gate dls_link_t *dlp; 537*0Sstevel@tonic-gate int err = 0; 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate ASSERT(!(flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI | 540*0Sstevel@tonic-gate DLS_PROMISC_PHYS))); 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* 543*0Sstevel@tonic-gate * Check if we need to turn on 'all sap' mode. 544*0Sstevel@tonic-gate */ 545*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 546*0Sstevel@tonic-gate dlp = dip->di_dvp->dv_dlp; 547*0Sstevel@tonic-gate if ((flags & DLS_PROMISC_SAP) && 548*0Sstevel@tonic-gate !(dip->di_promisc & DLS_PROMISC_SAP)) { 549*0Sstevel@tonic-gate dip->di_promisc |= DLS_PROMISC_SAP; 550*0Sstevel@tonic-gate if (!dip->di_bound) 551*0Sstevel@tonic-gate goto multi; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 554*0Sstevel@tonic-gate dls_link_remove(dlp, dip); 555*0Sstevel@tonic-gate dls_link_add(dlp, DLS_SAP_PROMISC, dip); 556*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 557*0Sstevel@tonic-gate goto multi; 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate /* 561*0Sstevel@tonic-gate * Check if we need to turn off 'all sap' mode. 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate if (!(flags & DLS_PROMISC_SAP) && 564*0Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_SAP)) { 565*0Sstevel@tonic-gate dip->di_promisc &= ~DLS_PROMISC_SAP; 566*0Sstevel@tonic-gate if (!dip->di_bound) 567*0Sstevel@tonic-gate goto multi; 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 570*0Sstevel@tonic-gate dls_link_remove(dlp, dip); 571*0Sstevel@tonic-gate dls_link_add(dlp, dip->di_sap, dip); 572*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 573*0Sstevel@tonic-gate } 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate multi: 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * It's easiest to add the txloop handler up-front; if promiscuous 578*0Sstevel@tonic-gate * mode cannot be enabled, then we'll remove it before returning. 579*0Sstevel@tonic-gate */ 580*0Sstevel@tonic-gate if (dlp->dl_npromisc == 0 && 581*0Sstevel@tonic-gate (flags & (DLS_PROMISC_MULTI|DLS_PROMISC_PHYS))) { 582*0Sstevel@tonic-gate ASSERT(dlp->dl_mth == NULL); 583*0Sstevel@tonic-gate dlp->dl_mth = mac_txloop_add(dlp->dl_mh, dlp->dl_loopback, dlp); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * Check if we need to turn on 'all multicast' mode. 588*0Sstevel@tonic-gate */ 589*0Sstevel@tonic-gate if ((flags & DLS_PROMISC_MULTI) && 590*0Sstevel@tonic-gate !(dip->di_promisc & DLS_PROMISC_MULTI)) { 591*0Sstevel@tonic-gate err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 592*0Sstevel@tonic-gate if (err != 0) 593*0Sstevel@tonic-gate goto done; 594*0Sstevel@tonic-gate dip->di_promisc |= DLS_PROMISC_MULTI; 595*0Sstevel@tonic-gate dlp->dl_npromisc++; 596*0Sstevel@tonic-gate goto phys; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * Check if we need to turn off 'all multicast' mode. 601*0Sstevel@tonic-gate */ 602*0Sstevel@tonic-gate if (!(flags & DLS_PROMISC_MULTI) && 603*0Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_MULTI)) { 604*0Sstevel@tonic-gate err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 605*0Sstevel@tonic-gate if (err != 0) 606*0Sstevel@tonic-gate goto done; 607*0Sstevel@tonic-gate dip->di_promisc &= ~DLS_PROMISC_MULTI; 608*0Sstevel@tonic-gate dlp->dl_npromisc--; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate phys: 612*0Sstevel@tonic-gate /* 613*0Sstevel@tonic-gate * Check if we need to turn on 'all physical' mode. 614*0Sstevel@tonic-gate */ 615*0Sstevel@tonic-gate if ((flags & DLS_PROMISC_PHYS) && 616*0Sstevel@tonic-gate !(dip->di_promisc & DLS_PROMISC_PHYS)) { 617*0Sstevel@tonic-gate err = mac_promisc_set(dip->di_mh, B_TRUE, MAC_PROMISC); 618*0Sstevel@tonic-gate if (err != 0) 619*0Sstevel@tonic-gate goto done; 620*0Sstevel@tonic-gate dip->di_promisc |= DLS_PROMISC_PHYS; 621*0Sstevel@tonic-gate dlp->dl_npromisc++; 622*0Sstevel@tonic-gate goto done; 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* 626*0Sstevel@tonic-gate * Check if we need to turn off 'all physical' mode. 627*0Sstevel@tonic-gate */ 628*0Sstevel@tonic-gate if (!(flags & DLS_PROMISC_PHYS) && 629*0Sstevel@tonic-gate (dip->di_promisc & DLS_PROMISC_PHYS)) { 630*0Sstevel@tonic-gate err = mac_promisc_set(dip->di_mh, B_FALSE, MAC_PROMISC); 631*0Sstevel@tonic-gate if (err != 0) 632*0Sstevel@tonic-gate goto done; 633*0Sstevel@tonic-gate dip->di_promisc &= ~DLS_PROMISC_PHYS; 634*0Sstevel@tonic-gate dlp->dl_npromisc--; 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate done: 638*0Sstevel@tonic-gate if (dlp->dl_npromisc == 0 && dlp->dl_mth != NULL) { 639*0Sstevel@tonic-gate mac_txloop_remove(dlp->dl_mh, dlp->dl_mth); 640*0Sstevel@tonic-gate dlp->dl_mth = NULL; 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate ASSERT(dlp->dl_npromisc == 0 || dlp->dl_mth != NULL); 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 646*0Sstevel@tonic-gate return (err); 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate int 650*0Sstevel@tonic-gate dls_multicst_add(dls_channel_t dc, const uint8_t *addr) 651*0Sstevel@tonic-gate { 652*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 653*0Sstevel@tonic-gate int err; 654*0Sstevel@tonic-gate dls_multicst_addr_t **pp; 655*0Sstevel@tonic-gate dls_multicst_addr_t *p; 656*0Sstevel@tonic-gate uint_t addr_length; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate /* 659*0Sstevel@tonic-gate * Check whether the address is in the list of enabled addresses for 660*0Sstevel@tonic-gate * this dls_impl_t. 661*0Sstevel@tonic-gate */ 662*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 663*0Sstevel@tonic-gate addr_length = dip->di_mip->mi_addr_length; 664*0Sstevel@tonic-gate for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 665*0Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) { 666*0Sstevel@tonic-gate /* 667*0Sstevel@tonic-gate * It is there so there's nothing to do. 668*0Sstevel@tonic-gate */ 669*0Sstevel@tonic-gate err = 0; 670*0Sstevel@tonic-gate goto done; 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate /* 675*0Sstevel@tonic-gate * Allocate a new list item. 676*0Sstevel@tonic-gate */ 677*0Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (dls_multicst_addr_t), 678*0Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 679*0Sstevel@tonic-gate err = ENOMEM; 680*0Sstevel@tonic-gate goto done; 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Enable the address at the MAC. 685*0Sstevel@tonic-gate */ 686*0Sstevel@tonic-gate if ((err = mac_multicst_add(dip->di_mh, addr)) != 0) { 687*0Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 688*0Sstevel@tonic-gate goto done; 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate /* 692*0Sstevel@tonic-gate * The address is now enabled at the MAC so add it to the list. 693*0Sstevel@tonic-gate */ 694*0Sstevel@tonic-gate bcopy(addr, p->dma_addr, addr_length); 695*0Sstevel@tonic-gate *pp = p; 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate done: 698*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 699*0Sstevel@tonic-gate return (err); 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate int 703*0Sstevel@tonic-gate dls_multicst_remove(dls_channel_t dc, const uint8_t *addr) 704*0Sstevel@tonic-gate { 705*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 706*0Sstevel@tonic-gate int err; 707*0Sstevel@tonic-gate dls_multicst_addr_t **pp; 708*0Sstevel@tonic-gate dls_multicst_addr_t *p; 709*0Sstevel@tonic-gate uint_t addr_length; 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate /* 712*0Sstevel@tonic-gate * Find the address in the list of enabled addresses for this 713*0Sstevel@tonic-gate * dls_impl_t. 714*0Sstevel@tonic-gate */ 715*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 716*0Sstevel@tonic-gate addr_length = dip->di_mip->mi_addr_length; 717*0Sstevel@tonic-gate for (pp = &(dip->di_dmap); (p = *pp) != NULL; pp = &(p->dma_nextp)) { 718*0Sstevel@tonic-gate if (bcmp(addr, p->dma_addr, addr_length) == 0) 719*0Sstevel@tonic-gate break; 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate /* 723*0Sstevel@tonic-gate * If we walked to the end of the list then the given address is 724*0Sstevel@tonic-gate * not currently enabled for this dls_impl_t. 725*0Sstevel@tonic-gate */ 726*0Sstevel@tonic-gate if (p == NULL) { 727*0Sstevel@tonic-gate err = ENOENT; 728*0Sstevel@tonic-gate goto done; 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate /* 732*0Sstevel@tonic-gate * Disable the address at the MAC. 733*0Sstevel@tonic-gate */ 734*0Sstevel@tonic-gate if ((err = mac_multicst_remove(dip->di_mh, addr)) != 0) 735*0Sstevel@tonic-gate goto done; 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate /* 738*0Sstevel@tonic-gate * Remove the address from the list. 739*0Sstevel@tonic-gate */ 740*0Sstevel@tonic-gate *pp = p->dma_nextp; 741*0Sstevel@tonic-gate kmem_free(p, sizeof (dls_multicst_addr_t)); 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate done: 744*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 745*0Sstevel@tonic-gate return (err); 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate mblk_t * 749*0Sstevel@tonic-gate dls_header(dls_channel_t dc, const uint8_t *addr, uint16_t sap, uint_t pri) 750*0Sstevel@tonic-gate { 751*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate return (dip->di_header(dip, addr, sap, pri)); 754*0Sstevel@tonic-gate } 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate void 757*0Sstevel@tonic-gate dls_header_info(dls_channel_t dc, mblk_t *mp, dls_header_info_t *dhip) 758*0Sstevel@tonic-gate { 759*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate dip->di_header_info(dip, mp, dhip); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate void 765*0Sstevel@tonic-gate dls_rx_set(dls_channel_t dc, dls_rx_t rx, void *arg) 766*0Sstevel@tonic-gate { 767*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_WRITER); 770*0Sstevel@tonic-gate dip->di_rx = rx; 771*0Sstevel@tonic-gate dip->di_rx_arg = arg; 772*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate mblk_t * 776*0Sstevel@tonic-gate dls_tx(dls_channel_t dc, mblk_t *mp) 777*0Sstevel@tonic-gate { 778*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate return (dip->di_tx(dip->di_tx_arg, mp)); 781*0Sstevel@tonic-gate } 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate /* 784*0Sstevel@tonic-gate * Exported functions. 785*0Sstevel@tonic-gate */ 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate #define ADDR_MATCH(_addr_a, _addr_b, _length, _match) \ 788*0Sstevel@tonic-gate { \ 789*0Sstevel@tonic-gate uint_t i; \ 790*0Sstevel@tonic-gate \ 791*0Sstevel@tonic-gate /* \ 792*0Sstevel@tonic-gate * Make sure the addresses are 16 bit aligned and that \ 793*0Sstevel@tonic-gate * the length is an even number of octets. \ 794*0Sstevel@tonic-gate */ \ 795*0Sstevel@tonic-gate ASSERT(IS_P2ALIGNED((_addr_a), sizeof (uint16_t))); \ 796*0Sstevel@tonic-gate ASSERT(IS_P2ALIGNED((_addr_b), sizeof (uint16_t))); \ 797*0Sstevel@tonic-gate ASSERT((_length & 1) == 0); \ 798*0Sstevel@tonic-gate \ 799*0Sstevel@tonic-gate (_match) = B_TRUE; \ 800*0Sstevel@tonic-gate for (i = 0; i < (_length) >> 1; i++) { \ 801*0Sstevel@tonic-gate if (((uint16_t *)(_addr_a))[i] != \ 802*0Sstevel@tonic-gate ((uint16_t *)(_addr_b))[i]) { \ 803*0Sstevel@tonic-gate (_match) = B_FALSE; \ 804*0Sstevel@tonic-gate break; \ 805*0Sstevel@tonic-gate } \ 806*0Sstevel@tonic-gate } \ 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate boolean_t 810*0Sstevel@tonic-gate dls_accept(dls_impl_t *dip, const uint8_t *daddr) 811*0Sstevel@tonic-gate { 812*0Sstevel@tonic-gate boolean_t match; 813*0Sstevel@tonic-gate dls_multicst_addr_t *dmap; 814*0Sstevel@tonic-gate uint_t addr_length = dip->di_mip->mi_addr_length; 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate /* 817*0Sstevel@tonic-gate * We must not accept packets if the dls_impl_t is not marked as bound 818*0Sstevel@tonic-gate * or is being removed. 819*0Sstevel@tonic-gate */ 820*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_READER); 821*0Sstevel@tonic-gate if (!dip->di_bound || dip->di_removing) 822*0Sstevel@tonic-gate goto refuse; 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate /* 825*0Sstevel@tonic-gate * If the dls_impl_t is in 'all physical' mode then always accept. 826*0Sstevel@tonic-gate */ 827*0Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_PHYS) 828*0Sstevel@tonic-gate goto accept; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate /* 831*0Sstevel@tonic-gate * Check to see if the destination address matches the dls_impl_t 832*0Sstevel@tonic-gate * unicast address. 833*0Sstevel@tonic-gate */ 834*0Sstevel@tonic-gate ADDR_MATCH(daddr, dip->di_unicst_addr, addr_length, match); 835*0Sstevel@tonic-gate if (match) 836*0Sstevel@tonic-gate goto accept; 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate /* 839*0Sstevel@tonic-gate * Check for a 'group' address. If it is not then refuse it since we 840*0Sstevel@tonic-gate * already know it does not match the unicast address. 841*0Sstevel@tonic-gate */ 842*0Sstevel@tonic-gate if (!(daddr[0] & 0x01)) 843*0Sstevel@tonic-gate goto refuse; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate /* 846*0Sstevel@tonic-gate * If the address is broadcast then the dls_impl_t will always accept 847*0Sstevel@tonic-gate * it. 848*0Sstevel@tonic-gate */ 849*0Sstevel@tonic-gate ADDR_MATCH(daddr, dip->di_mip->mi_brdcst_addr, addr_length, 850*0Sstevel@tonic-gate match); 851*0Sstevel@tonic-gate if (match) 852*0Sstevel@tonic-gate goto accept; 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate /* 855*0Sstevel@tonic-gate * If a group address is not broadcast then it must be multicast so 856*0Sstevel@tonic-gate * check it against the list of addresses enabled for this dls_impl_t 857*0Sstevel@tonic-gate * or accept it unconditionally if the dls_impl_t is in 'all 858*0Sstevel@tonic-gate * multicast' mode. 859*0Sstevel@tonic-gate */ 860*0Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_MULTI) 861*0Sstevel@tonic-gate goto accept; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate for (dmap = dip->di_dmap; dmap != NULL; dmap = dmap->dma_nextp) { 864*0Sstevel@tonic-gate ADDR_MATCH(daddr, dmap->dma_addr, addr_length, match); 865*0Sstevel@tonic-gate if (match) 866*0Sstevel@tonic-gate goto accept; 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate 869*0Sstevel@tonic-gate refuse: 870*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 871*0Sstevel@tonic-gate return (B_FALSE); 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate accept: 874*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 875*0Sstevel@tonic-gate return (B_TRUE); 876*0Sstevel@tonic-gate } 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate /*ARGSUSED*/ 879*0Sstevel@tonic-gate boolean_t 880*0Sstevel@tonic-gate dls_accept_loopback(dls_impl_t *dip, const uint8_t *daddr) 881*0Sstevel@tonic-gate { 882*0Sstevel@tonic-gate /* 883*0Sstevel@tonic-gate * We must not accept packets if the dls_impl_t is not marked as bound 884*0Sstevel@tonic-gate * or is being removed. 885*0Sstevel@tonic-gate */ 886*0Sstevel@tonic-gate rw_enter(&(dip->di_lock), RW_READER); 887*0Sstevel@tonic-gate if (!dip->di_bound || dip->di_removing) 888*0Sstevel@tonic-gate goto refuse; 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate /* 891*0Sstevel@tonic-gate * A dls_impl_t should only accept loopback packets if it is in 892*0Sstevel@tonic-gate * 'all physical' mode. 893*0Sstevel@tonic-gate */ 894*0Sstevel@tonic-gate if (dip->di_promisc & DLS_PROMISC_PHYS) 895*0Sstevel@tonic-gate goto accept; 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate refuse: 898*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 899*0Sstevel@tonic-gate return (B_FALSE); 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate accept: 902*0Sstevel@tonic-gate rw_exit(&(dip->di_lock)); 903*0Sstevel@tonic-gate return (B_TRUE); 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate boolean_t 907*0Sstevel@tonic-gate dls_active_set(dls_channel_t dc) 908*0Sstevel@tonic-gate { 909*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 910*0Sstevel@tonic-gate dls_link_t *dlp = dip->di_dvp->dv_dlp; 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate rw_enter(&dip->di_lock, RW_WRITER); 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate /* If we're already active, then there's nothing more to do. */ 915*0Sstevel@tonic-gate if (dip->di_active) { 916*0Sstevel@tonic-gate rw_exit(&dip->di_lock); 917*0Sstevel@tonic-gate return (B_TRUE); 918*0Sstevel@tonic-gate } 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate /* 921*0Sstevel@tonic-gate * If this is the first active client on this link, notify 922*0Sstevel@tonic-gate * the mac that we're becoming an active client. 923*0Sstevel@tonic-gate */ 924*0Sstevel@tonic-gate if (dlp->dl_nactive == 0 && !mac_active_set(dlp->dl_mh)) { 925*0Sstevel@tonic-gate rw_exit(&dip->di_lock); 926*0Sstevel@tonic-gate return (B_FALSE); 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate dip->di_active = B_TRUE; 929*0Sstevel@tonic-gate mutex_enter(&dlp->dl_lock); 930*0Sstevel@tonic-gate dlp->dl_nactive++; 931*0Sstevel@tonic-gate mutex_exit(&dlp->dl_lock); 932*0Sstevel@tonic-gate rw_exit(&dip->di_lock); 933*0Sstevel@tonic-gate return (B_TRUE); 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate void 937*0Sstevel@tonic-gate dls_active_clear(dls_channel_t dc) 938*0Sstevel@tonic-gate { 939*0Sstevel@tonic-gate dls_impl_t *dip = (dls_impl_t *)dc; 940*0Sstevel@tonic-gate dls_link_t *dlp = dip->di_dvp->dv_dlp; 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate rw_enter(&dip->di_lock, RW_WRITER); 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate if (!dip->di_active) 945*0Sstevel@tonic-gate goto out; 946*0Sstevel@tonic-gate dip->di_active = B_FALSE; 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate mutex_enter(&dlp->dl_lock); 949*0Sstevel@tonic-gate if (--dlp->dl_nactive == 0) 950*0Sstevel@tonic-gate mac_active_clear(dip->di_mh); 951*0Sstevel@tonic-gate mutex_exit(&dlp->dl_lock); 952*0Sstevel@tonic-gate out: 953*0Sstevel@tonic-gate rw_exit(&dip->di_lock); 954*0Sstevel@tonic-gate } 955