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 * MAC Services Module 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/conf.h> 35*0Sstevel@tonic-gate #include <sys/stat.h> 36*0Sstevel@tonic-gate #include <sys/stream.h> 37*0Sstevel@tonic-gate #include <sys/strsun.h> 38*0Sstevel@tonic-gate #include <sys/strsubr.h> 39*0Sstevel@tonic-gate #include <sys/dlpi.h> 40*0Sstevel@tonic-gate #include <sys/mac.h> 41*0Sstevel@tonic-gate #include <sys/mac_impl.h> 42*0Sstevel@tonic-gate #include <sys/dld_impl.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #define IMPL_HASHSZ 67 /* prime */ 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate static kmem_cache_t *i_mac_impl_cachep; 47*0Sstevel@tonic-gate static ght_t i_mac_impl_hash; 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* 50*0Sstevel@tonic-gate * Private functions. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate /*ARGSUSED*/ 54*0Sstevel@tonic-gate static boolean_t 55*0Sstevel@tonic-gate i_mac_ether_unicst_verify(mac_impl_t *mip, const uint8_t *addr) 56*0Sstevel@tonic-gate { 57*0Sstevel@tonic-gate /* 58*0Sstevel@tonic-gate * Check the address is not a group address. 59*0Sstevel@tonic-gate */ 60*0Sstevel@tonic-gate if (addr[0] & 0x01) 61*0Sstevel@tonic-gate return (B_FALSE); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate return (B_TRUE); 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate static boolean_t 67*0Sstevel@tonic-gate i_mac_ether_multicst_verify(mac_impl_t *mip, const uint8_t *addr) 68*0Sstevel@tonic-gate { 69*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * Check the address is a group address. 73*0Sstevel@tonic-gate */ 74*0Sstevel@tonic-gate if (!(addr[0] & 0x01)) 75*0Sstevel@tonic-gate return (B_FALSE); 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate /* 78*0Sstevel@tonic-gate * Check the address is not the media broadcast address. 79*0Sstevel@tonic-gate */ 80*0Sstevel@tonic-gate if (bcmp(addr, mp->m_info.mi_brdcst_addr, mip->mi_addr_length) == 0) 81*0Sstevel@tonic-gate return (B_FALSE); 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate return (B_TRUE); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /*ARGSUSED*/ 87*0Sstevel@tonic-gate static int 88*0Sstevel@tonic-gate i_mac_constructor(void *buf, void *arg, int kmflag) 89*0Sstevel@tonic-gate { 90*0Sstevel@tonic-gate mac_impl_t *mip = buf; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate bzero(buf, sizeof (mac_impl_t)); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate mip->mi_link = LINK_STATE_UNKNOWN; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate rw_init(&mip->mi_state_lock, NULL, RW_DRIVER, NULL); 97*0Sstevel@tonic-gate rw_init(&mip->mi_data_lock, NULL, RW_DRIVER, NULL); 98*0Sstevel@tonic-gate rw_init(&mip->mi_notify_lock, NULL, RW_DRIVER, NULL); 99*0Sstevel@tonic-gate rw_init(&mip->mi_rx_lock, NULL, RW_DRIVER, NULL); 100*0Sstevel@tonic-gate rw_init(&mip->mi_txloop_lock, NULL, RW_DRIVER, NULL); 101*0Sstevel@tonic-gate rw_init(&mip->mi_resource_lock, NULL, RW_DRIVER, NULL); 102*0Sstevel@tonic-gate mutex_init(&mip->mi_activelink_lock, NULL, MUTEX_DEFAULT, NULL); 103*0Sstevel@tonic-gate return (0); 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /*ARGSUSED*/ 107*0Sstevel@tonic-gate static void 108*0Sstevel@tonic-gate i_mac_destructor(void *buf, void *arg) 109*0Sstevel@tonic-gate { 110*0Sstevel@tonic-gate mac_impl_t *mip = buf; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate ASSERT(mip->mi_mp == NULL); 113*0Sstevel@tonic-gate ASSERT(mip->mi_hte == NULL); 114*0Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 115*0Sstevel@tonic-gate ASSERT(mip->mi_active == 0); 116*0Sstevel@tonic-gate ASSERT(mip->mi_link == LINK_STATE_UNKNOWN); 117*0Sstevel@tonic-gate ASSERT(mip->mi_devpromisc == 0); 118*0Sstevel@tonic-gate ASSERT(mip->mi_promisc == 0); 119*0Sstevel@tonic-gate ASSERT(mip->mi_mmap == NULL); 120*0Sstevel@tonic-gate ASSERT(mip->mi_mnfp == NULL); 121*0Sstevel@tonic-gate ASSERT(mip->mi_resource_add == NULL); 122*0Sstevel@tonic-gate ASSERT(mip->mi_ksp == NULL); 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate rw_destroy(&mip->mi_state_lock); 125*0Sstevel@tonic-gate rw_destroy(&mip->mi_data_lock); 126*0Sstevel@tonic-gate rw_destroy(&mip->mi_notify_lock); 127*0Sstevel@tonic-gate rw_destroy(&mip->mi_rx_lock); 128*0Sstevel@tonic-gate rw_destroy(&mip->mi_txloop_lock); 129*0Sstevel@tonic-gate rw_destroy(&mip->mi_resource_lock); 130*0Sstevel@tonic-gate mutex_destroy(&mip->mi_activelink_lock); 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate int 134*0Sstevel@tonic-gate i_mac_create(mac_t *mp) 135*0Sstevel@tonic-gate { 136*0Sstevel@tonic-gate dev_info_t *dip; 137*0Sstevel@tonic-gate mac_impl_t *mip; 138*0Sstevel@tonic-gate int err; 139*0Sstevel@tonic-gate ghte_t hte; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate dip = mp->m_dip; 142*0Sstevel@tonic-gate ASSERT(dip != NULL); 143*0Sstevel@tonic-gate ASSERT(ddi_get_instance(dip) >= 0); 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * Allocate a new mac_impl_t. 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate mip = kmem_cache_alloc(i_mac_impl_cachep, KM_SLEEP); 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* 151*0Sstevel@tonic-gate * Construct a name. 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate (void) snprintf(mip->mi_dev, MAXNAMELEN - 1, "%s%d", 154*0Sstevel@tonic-gate ddi_driver_name(dip), ddi_get_instance(dip)); 155*0Sstevel@tonic-gate mip->mi_port = mp->m_port; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate MAC_NAME(mip->mi_name, mip->mi_dev, mip->mi_port); 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Set the mac_t/mac_impl_t cross-references. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate mip->mi_mp = mp; 163*0Sstevel@tonic-gate mp->m_impl = (void *)mip; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate /* 166*0Sstevel@tonic-gate * Allocate a hash table entry. 167*0Sstevel@tonic-gate */ 168*0Sstevel@tonic-gate hte = ght_alloc(i_mac_impl_hash, KM_SLEEP); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate GHT_KEY(hte) = GHT_PTR_TO_KEY(mip->mi_name); 171*0Sstevel@tonic-gate GHT_VAL(hte) = GHT_PTR_TO_VAL(mip); 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * Insert the hash table entry. 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate ght_lock(i_mac_impl_hash, GHT_WRITE); 177*0Sstevel@tonic-gate if ((err = ght_insert(hte)) != 0) { 178*0Sstevel@tonic-gate ght_free(hte); 179*0Sstevel@tonic-gate kmem_cache_free(i_mac_impl_cachep, mip); 180*0Sstevel@tonic-gate goto done; 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate mip->mi_hte = hte; 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Copy the fixed 'factory' MAC address from the immutable info. 187*0Sstevel@tonic-gate * This is taken to be the MAC address currently in use. 188*0Sstevel@tonic-gate */ 189*0Sstevel@tonic-gate mip->mi_addr_length = mp->m_info.mi_addr_length; 190*0Sstevel@tonic-gate bcopy(mp->m_info.mi_unicst_addr, mip->mi_addr, mip->mi_addr_length); 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate /* 193*0Sstevel@tonic-gate * Set up the address verification functions. 194*0Sstevel@tonic-gate */ 195*0Sstevel@tonic-gate ASSERT(mp->m_info.mi_media == DL_ETHER); 196*0Sstevel@tonic-gate mip->mi_unicst_verify = i_mac_ether_unicst_verify; 197*0Sstevel@tonic-gate mip->mi_multicst_verify = i_mac_ether_multicst_verify; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * Initialize the kstats for this device. 201*0Sstevel@tonic-gate */ 202*0Sstevel@tonic-gate mac_stat_create(mip); 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate done: 205*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 206*0Sstevel@tonic-gate return (err); 207*0Sstevel@tonic-gate } 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate static void 210*0Sstevel@tonic-gate i_mac_destroy(mac_t *mp) 211*0Sstevel@tonic-gate { 212*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 213*0Sstevel@tonic-gate ghte_t hte; 214*0Sstevel@tonic-gate mac_multicst_addr_t *p, *nextp; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate ght_lock(i_mac_impl_hash, GHT_WRITE); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate ASSERT(mip->mi_ref == 0); 219*0Sstevel@tonic-gate ASSERT(!mip->mi_activelink); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate /* 222*0Sstevel@tonic-gate * Destroy the kstats. 223*0Sstevel@tonic-gate */ 224*0Sstevel@tonic-gate mac_stat_destroy(mip); 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate /* 227*0Sstevel@tonic-gate * Remove and destroy the hash table entry. 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate hte = mip->mi_hte; 230*0Sstevel@tonic-gate ght_remove(hte); 231*0Sstevel@tonic-gate ght_free(hte); 232*0Sstevel@tonic-gate mip->mi_hte = NULL; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* 235*0Sstevel@tonic-gate * Free the list of multicast addresses. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = nextp) { 238*0Sstevel@tonic-gate nextp = p->mma_nextp; 239*0Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate mip->mi_mmap = NULL; 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate /* 244*0Sstevel@tonic-gate * Clean up the mac_impl_t ready to go back into the cache. 245*0Sstevel@tonic-gate */ 246*0Sstevel@tonic-gate mp->m_impl = NULL; 247*0Sstevel@tonic-gate mip->mi_mp = NULL; 248*0Sstevel@tonic-gate mip->mi_link = LINK_STATE_UNKNOWN; 249*0Sstevel@tonic-gate mip->mi_destroying = B_FALSE; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * Free the structure back to the cache. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate kmem_cache_free(i_mac_impl_cachep, mip); 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate static void 260*0Sstevel@tonic-gate i_mac_notify(mac_impl_t *mip, mac_notify_type_t type) 261*0Sstevel@tonic-gate { 262*0Sstevel@tonic-gate mac_notify_fn_t *mnfp; 263*0Sstevel@tonic-gate mac_notify_t notify; 264*0Sstevel@tonic-gate void *arg; 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * Walk the list of notifications. 268*0Sstevel@tonic-gate */ 269*0Sstevel@tonic-gate rw_enter(&(mip->mi_notify_lock), RW_READER); 270*0Sstevel@tonic-gate for (mnfp = mip->mi_mnfp; mnfp != NULL; mnfp = mnfp->mnf_nextp) { 271*0Sstevel@tonic-gate notify = mnfp->mnf_fn; 272*0Sstevel@tonic-gate arg = mnfp->mnf_arg; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate ASSERT(notify != NULL); 275*0Sstevel@tonic-gate notify(arg, type); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate rw_exit(&(mip->mi_notify_lock)); 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* 281*0Sstevel@tonic-gate * Module initialization functions. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate void 285*0Sstevel@tonic-gate mac_init(void) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate int err; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate i_mac_impl_cachep = kmem_cache_create("mac_impl_cache", 290*0Sstevel@tonic-gate sizeof (mac_impl_t), 0, i_mac_constructor, i_mac_destructor, NULL, 291*0Sstevel@tonic-gate NULL, NULL, 0); 292*0Sstevel@tonic-gate ASSERT(i_mac_impl_cachep != NULL); 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate err = ght_str_create("mac_impl_hash", IMPL_HASHSZ, &i_mac_impl_hash); 295*0Sstevel@tonic-gate ASSERT(err == 0); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate int 299*0Sstevel@tonic-gate mac_fini(void) 300*0Sstevel@tonic-gate { 301*0Sstevel@tonic-gate int err; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate if ((err = ght_destroy(i_mac_impl_hash)) != 0) 304*0Sstevel@tonic-gate return (err); 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate kmem_cache_destroy(i_mac_impl_cachep); 307*0Sstevel@tonic-gate return (0); 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * Client functions. 312*0Sstevel@tonic-gate */ 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate int 315*0Sstevel@tonic-gate mac_open(const char *dev, uint_t port, mac_handle_t *mhp) 316*0Sstevel@tonic-gate { 317*0Sstevel@tonic-gate char name[MAXNAMELEN]; 318*0Sstevel@tonic-gate char driver[MAXNAMELEN]; 319*0Sstevel@tonic-gate uint_t instance; 320*0Sstevel@tonic-gate major_t major; 321*0Sstevel@tonic-gate dev_info_t *dip; 322*0Sstevel@tonic-gate mac_impl_t *mip; 323*0Sstevel@tonic-gate ghte_t hte; 324*0Sstevel@tonic-gate int err; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* 327*0Sstevel@tonic-gate * Check the device name length to make sure it won't overflow our 328*0Sstevel@tonic-gate * buffer. 329*0Sstevel@tonic-gate */ 330*0Sstevel@tonic-gate if (strlen(dev) >= MAXNAMELEN) 331*0Sstevel@tonic-gate return (EINVAL); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * Split the device name into driver and instance components. 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate if (ddi_parse(dev, driver, &instance) != DDI_SUCCESS) 337*0Sstevel@tonic-gate return (EINVAL); 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * Get the major number of the driver. 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate if ((major = ddi_name_to_major(driver)) == (major_t)-1) 343*0Sstevel@tonic-gate return (EINVAL); 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* 346*0Sstevel@tonic-gate * Hold the given instance to prevent it from being detached. 347*0Sstevel@tonic-gate * (This will also attach it if it is not currently attached). 348*0Sstevel@tonic-gate */ 349*0Sstevel@tonic-gate if ((dip = ddi_hold_devi_by_instance(major, instance, 0)) == NULL) 350*0Sstevel@tonic-gate return (EINVAL); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate /* 353*0Sstevel@tonic-gate * Construct the name of the MAC interface. 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate MAC_NAME(name, dev, port); 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate /* 358*0Sstevel@tonic-gate * Look up its entry in the global hash table. 359*0Sstevel@tonic-gate */ 360*0Sstevel@tonic-gate again: 361*0Sstevel@tonic-gate ght_lock(i_mac_impl_hash, GHT_WRITE); 362*0Sstevel@tonic-gate if ((err = ght_find(i_mac_impl_hash, GHT_PTR_TO_KEY(name), &hte)) != 0) 363*0Sstevel@tonic-gate goto failed; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate mip = (mac_impl_t *)GHT_VAL(hte); 366*0Sstevel@tonic-gate ASSERT(mip->mi_mp->m_dip == dip); 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate if (mip->mi_destroying) { 369*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 370*0Sstevel@tonic-gate goto again; 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate mip->mi_ref++; 374*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate *mhp = (mac_handle_t)mip; 377*0Sstevel@tonic-gate return (0); 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate failed: 380*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 381*0Sstevel@tonic-gate ddi_release_devi(dip); 382*0Sstevel@tonic-gate return (err); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate void 386*0Sstevel@tonic-gate mac_close(mac_handle_t mh) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 389*0Sstevel@tonic-gate dev_info_t *dip = mip->mi_mp->m_dip; 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate ght_lock(i_mac_impl_hash, GHT_WRITE); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate ASSERT(mip->mi_ref != 0); 394*0Sstevel@tonic-gate if (--mip->mi_ref == 0) { 395*0Sstevel@tonic-gate ASSERT(!mip->mi_activelink); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate ddi_release_devi(dip); 398*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate const mac_info_t * 402*0Sstevel@tonic-gate mac_info(mac_handle_t mh) 403*0Sstevel@tonic-gate { 404*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 405*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate /* 408*0Sstevel@tonic-gate * Return a pointer to the mac_info_t embedded in the mac_t. 409*0Sstevel@tonic-gate */ 410*0Sstevel@tonic-gate return (&(mp->m_info)); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate uint64_t 414*0Sstevel@tonic-gate mac_stat_get(mac_handle_t mh, enum mac_stat stat) 415*0Sstevel@tonic-gate { 416*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 417*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate ASSERT(mp->m_info.mi_stat[stat]); 420*0Sstevel@tonic-gate ASSERT(mp->m_stat != NULL); 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * Call the driver to get the given statistic. 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate return (mp->m_stat(mp->m_driver, stat)); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate int 429*0Sstevel@tonic-gate mac_start(mac_handle_t mh) 430*0Sstevel@tonic-gate { 431*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 432*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 433*0Sstevel@tonic-gate int err; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate ASSERT(mp->m_start != NULL); 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate /* 440*0Sstevel@tonic-gate * Check whether the device is already started. 441*0Sstevel@tonic-gate */ 442*0Sstevel@tonic-gate if (mip->mi_active++ != 0) { 443*0Sstevel@tonic-gate /* 444*0Sstevel@tonic-gate * It's already started so there's nothing more to do. 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate err = 0; 447*0Sstevel@tonic-gate goto done; 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * Start the device. 452*0Sstevel@tonic-gate */ 453*0Sstevel@tonic-gate if ((err = mp->m_start(mp->m_driver)) != 0) 454*0Sstevel@tonic-gate --mip->mi_active; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate done: 457*0Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 458*0Sstevel@tonic-gate return (err); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate void 462*0Sstevel@tonic-gate mac_stop(mac_handle_t mh) 463*0Sstevel@tonic-gate { 464*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 465*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate ASSERT(mp->m_stop != NULL); 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate rw_enter(&(mip->mi_state_lock), RW_WRITER); 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate /* 472*0Sstevel@tonic-gate * Check whether the device is still needed. 473*0Sstevel@tonic-gate */ 474*0Sstevel@tonic-gate ASSERT(mip->mi_active != 0); 475*0Sstevel@tonic-gate if (--mip->mi_active != 0) { 476*0Sstevel@tonic-gate /* 477*0Sstevel@tonic-gate * It's still needed so there's nothing more to do. 478*0Sstevel@tonic-gate */ 479*0Sstevel@tonic-gate goto done; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate /* 483*0Sstevel@tonic-gate * Stop the device. 484*0Sstevel@tonic-gate */ 485*0Sstevel@tonic-gate mp->m_stop(mp->m_driver); 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate done: 488*0Sstevel@tonic-gate rw_exit(&(mip->mi_state_lock)); 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate int 492*0Sstevel@tonic-gate mac_multicst_add(mac_handle_t mh, const uint8_t *addr) 493*0Sstevel@tonic-gate { 494*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 495*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 496*0Sstevel@tonic-gate mac_multicst_addr_t **pp; 497*0Sstevel@tonic-gate mac_multicst_addr_t *p; 498*0Sstevel@tonic-gate int err; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate ASSERT(mp->m_multicst != NULL); 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate /* 503*0Sstevel@tonic-gate * Verify the address. 504*0Sstevel@tonic-gate */ 505*0Sstevel@tonic-gate if (!(mip->mi_multicst_verify(mip, addr))) 506*0Sstevel@tonic-gate return (EINVAL); 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* 509*0Sstevel@tonic-gate * Check whether the given address is already enabled. 510*0Sstevel@tonic-gate */ 511*0Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 512*0Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 513*0Sstevel@tonic-gate if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) { 514*0Sstevel@tonic-gate /* 515*0Sstevel@tonic-gate * The address is already enabled so just bump the 516*0Sstevel@tonic-gate * reference count. 517*0Sstevel@tonic-gate */ 518*0Sstevel@tonic-gate p->mma_ref++; 519*0Sstevel@tonic-gate err = 0; 520*0Sstevel@tonic-gate goto done; 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate /* 525*0Sstevel@tonic-gate * Allocate a new list entry. 526*0Sstevel@tonic-gate */ 527*0Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (mac_multicst_addr_t), 528*0Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 529*0Sstevel@tonic-gate err = ENOMEM; 530*0Sstevel@tonic-gate goto done; 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate /* 534*0Sstevel@tonic-gate * Enable a new multicast address. 535*0Sstevel@tonic-gate */ 536*0Sstevel@tonic-gate if ((err = mp->m_multicst(mp->m_driver, B_TRUE, addr)) != 0) { 537*0Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 538*0Sstevel@tonic-gate goto done; 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /* 542*0Sstevel@tonic-gate * Add the address to the list of enabled addresses. 543*0Sstevel@tonic-gate */ 544*0Sstevel@tonic-gate bcopy(addr, p->mma_addr, mip->mi_addr_length); 545*0Sstevel@tonic-gate p->mma_ref++; 546*0Sstevel@tonic-gate *pp = p; 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate done: 549*0Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 550*0Sstevel@tonic-gate return (err); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate int 554*0Sstevel@tonic-gate mac_multicst_remove(mac_handle_t mh, const uint8_t *addr) 555*0Sstevel@tonic-gate { 556*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 557*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 558*0Sstevel@tonic-gate mac_multicst_addr_t **pp; 559*0Sstevel@tonic-gate mac_multicst_addr_t *p; 560*0Sstevel@tonic-gate int err; 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate ASSERT(mp->m_multicst != NULL); 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate /* 565*0Sstevel@tonic-gate * Find the entry in the list for the given address. 566*0Sstevel@tonic-gate */ 567*0Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 568*0Sstevel@tonic-gate for (pp = &(mip->mi_mmap); (p = *pp) != NULL; pp = &(p->mma_nextp)) { 569*0Sstevel@tonic-gate if (bcmp(p->mma_addr, addr, mip->mi_addr_length) == 0) { 570*0Sstevel@tonic-gate if (--p->mma_ref == 0) 571*0Sstevel@tonic-gate break; 572*0Sstevel@tonic-gate 573*0Sstevel@tonic-gate /* 574*0Sstevel@tonic-gate * There is still a reference to this address so 575*0Sstevel@tonic-gate * there's nothing more to do. 576*0Sstevel@tonic-gate */ 577*0Sstevel@tonic-gate err = 0; 578*0Sstevel@tonic-gate goto done; 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate /* 583*0Sstevel@tonic-gate * We did not find an entry for the given address so it is not 584*0Sstevel@tonic-gate * currently enabled. 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate if (p == NULL) { 587*0Sstevel@tonic-gate err = ENOENT; 588*0Sstevel@tonic-gate goto done; 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate ASSERT(p->mma_ref == 0); 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * Disable the multicast address. 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate if ((err = mp->m_multicst(mp->m_driver, B_FALSE, addr)) != 0) { 596*0Sstevel@tonic-gate p->mma_ref++; 597*0Sstevel@tonic-gate goto done; 598*0Sstevel@tonic-gate } 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate /* 601*0Sstevel@tonic-gate * Remove it from the list. 602*0Sstevel@tonic-gate */ 603*0Sstevel@tonic-gate *pp = p->mma_nextp; 604*0Sstevel@tonic-gate kmem_free(p, sizeof (mac_multicst_addr_t)); 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate done: 607*0Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 608*0Sstevel@tonic-gate return (err); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate int 612*0Sstevel@tonic-gate mac_unicst_set(mac_handle_t mh, const uint8_t *addr) 613*0Sstevel@tonic-gate { 614*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 615*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 616*0Sstevel@tonic-gate int err; 617*0Sstevel@tonic-gate boolean_t notify = B_FALSE; 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate ASSERT(mp->m_unicst != NULL); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate /* 622*0Sstevel@tonic-gate * Verify the address. 623*0Sstevel@tonic-gate */ 624*0Sstevel@tonic-gate if (!(mip->mi_unicst_verify(mip, addr))) 625*0Sstevel@tonic-gate return (EINVAL); 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate /* 628*0Sstevel@tonic-gate * Program the new unicast address. 629*0Sstevel@tonic-gate */ 630*0Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* 633*0Sstevel@tonic-gate * If address doesn't change, do nothing. 634*0Sstevel@tonic-gate * This check is necessary otherwise it may call into mac_unicst_set 635*0Sstevel@tonic-gate * recursively. 636*0Sstevel@tonic-gate */ 637*0Sstevel@tonic-gate if (bcmp(addr, mip->mi_addr, mip->mi_addr_length) == 0) { 638*0Sstevel@tonic-gate err = 0; 639*0Sstevel@tonic-gate goto done; 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate if ((err = mp->m_unicst(mp->m_driver, addr)) != 0) 643*0Sstevel@tonic-gate goto done; 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * Save the address and flag that we need to send a notification. 647*0Sstevel@tonic-gate */ 648*0Sstevel@tonic-gate bcopy(addr, mip->mi_addr, mip->mi_addr_length); 649*0Sstevel@tonic-gate notify = B_TRUE; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate done: 652*0Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (notify) 655*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate return (err); 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate void 661*0Sstevel@tonic-gate mac_unicst_get(mac_handle_t mh, uint8_t *addr) 662*0Sstevel@tonic-gate { 663*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate /* 666*0Sstevel@tonic-gate * Copy out the current unicast address. 667*0Sstevel@tonic-gate */ 668*0Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 669*0Sstevel@tonic-gate bcopy(mip->mi_addr, addr, mip->mi_addr_length); 670*0Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate int 674*0Sstevel@tonic-gate mac_promisc_set(mac_handle_t mh, boolean_t on, mac_promisc_type_t ptype) 675*0Sstevel@tonic-gate { 676*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 677*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 678*0Sstevel@tonic-gate int err = 0; 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate ASSERT(mp->m_promisc != NULL); 681*0Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Determine whether we should enable or disable promiscuous mode. 685*0Sstevel@tonic-gate * For details on the distinction between "device promiscuous mode" 686*0Sstevel@tonic-gate * and "MAC promiscuous mode", see PSARC/2005/289. 687*0Sstevel@tonic-gate */ 688*0Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_WRITER); 689*0Sstevel@tonic-gate if (on) { 690*0Sstevel@tonic-gate /* 691*0Sstevel@tonic-gate * Enable promiscuous mode on the device if not yet enabled. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate if (mip->mi_devpromisc++ == 0) { 694*0Sstevel@tonic-gate if ((err = mp->m_promisc(mp->m_driver, B_TRUE)) != 0) { 695*0Sstevel@tonic-gate mip->mi_devpromisc--; 696*0Sstevel@tonic-gate goto done; 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate /* 702*0Sstevel@tonic-gate * Enable promiscuous mode on the MAC if not yet enabled. 703*0Sstevel@tonic-gate */ 704*0Sstevel@tonic-gate if (ptype == MAC_PROMISC && mip->mi_promisc++ == 0) 705*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 706*0Sstevel@tonic-gate } else { 707*0Sstevel@tonic-gate if (mip->mi_devpromisc == 0) { 708*0Sstevel@tonic-gate err = EPROTO; 709*0Sstevel@tonic-gate goto done; 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate /* 713*0Sstevel@tonic-gate * Disable promiscuous mode on the device if this is the last 714*0Sstevel@tonic-gate * enabling. 715*0Sstevel@tonic-gate */ 716*0Sstevel@tonic-gate if (--mip->mi_devpromisc == 0) { 717*0Sstevel@tonic-gate if ((err = mp->m_promisc(mp->m_driver, B_FALSE)) != 0) { 718*0Sstevel@tonic-gate mip->mi_devpromisc++; 719*0Sstevel@tonic-gate goto done; 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_DEVPROMISC); 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate /* 725*0Sstevel@tonic-gate * Disable promiscuous mode on the MAC if this is the last 726*0Sstevel@tonic-gate * enabling. 727*0Sstevel@tonic-gate */ 728*0Sstevel@tonic-gate if (ptype == MAC_PROMISC && --mip->mi_promisc == 0) 729*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_PROMISC); 730*0Sstevel@tonic-gate } 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate done: 733*0Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 734*0Sstevel@tonic-gate return (err); 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate boolean_t 738*0Sstevel@tonic-gate mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) 739*0Sstevel@tonic-gate { 740*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate ASSERT(ptype == MAC_DEVPROMISC || ptype == MAC_PROMISC); 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate /* 745*0Sstevel@tonic-gate * Return the current promiscuity. 746*0Sstevel@tonic-gate */ 747*0Sstevel@tonic-gate if (ptype == MAC_DEVPROMISC) 748*0Sstevel@tonic-gate return (mip->mi_devpromisc != 0); 749*0Sstevel@tonic-gate else 750*0Sstevel@tonic-gate return (mip->mi_promisc != 0); 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate void 754*0Sstevel@tonic-gate mac_resources(mac_handle_t mh) 755*0Sstevel@tonic-gate { 756*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 757*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate ASSERT(mp->m_resources != NULL); 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate /* 762*0Sstevel@tonic-gate * Call the driver to register its resources. 763*0Sstevel@tonic-gate */ 764*0Sstevel@tonic-gate mp->m_resources(mp->m_driver); 765*0Sstevel@tonic-gate } 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate void 768*0Sstevel@tonic-gate mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) 769*0Sstevel@tonic-gate { 770*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 771*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 772*0Sstevel@tonic-gate 773*0Sstevel@tonic-gate ASSERT(mp->m_ioctl != NULL); 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate /* 776*0Sstevel@tonic-gate * Call the driver to handle the ioctl. 777*0Sstevel@tonic-gate */ 778*0Sstevel@tonic-gate mp->m_ioctl(mp->m_driver, wq, bp); 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate void 782*0Sstevel@tonic-gate mac_tx_get(mac_handle_t mh, mac_tx_t *txp, void **argp) 783*0Sstevel@tonic-gate { 784*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 785*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate ASSERT(mp->m_tx != NULL); 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate *txp = mp->m_tx; 790*0Sstevel@tonic-gate *argp = mp->m_driver; 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate link_state_t 794*0Sstevel@tonic-gate mac_link_get(mac_handle_t mh) 795*0Sstevel@tonic-gate { 796*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate /* 799*0Sstevel@tonic-gate * Return the current link state. 800*0Sstevel@tonic-gate */ 801*0Sstevel@tonic-gate return (mip->mi_link); 802*0Sstevel@tonic-gate } 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate mac_notify_handle_t 805*0Sstevel@tonic-gate mac_notify_add(mac_handle_t mh, mac_notify_t notify, void *arg) 806*0Sstevel@tonic-gate { 807*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 808*0Sstevel@tonic-gate mac_notify_fn_t *mnfp; 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate mnfp = kmem_zalloc(sizeof (mac_notify_fn_t), KM_SLEEP); 811*0Sstevel@tonic-gate mnfp->mnf_fn = notify; 812*0Sstevel@tonic-gate mnfp->mnf_arg = arg; 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate /* 815*0Sstevel@tonic-gate * Add it to the head of the 'notify' callback list. 816*0Sstevel@tonic-gate */ 817*0Sstevel@tonic-gate rw_enter(&(mip->mi_notify_lock), RW_WRITER); 818*0Sstevel@tonic-gate mnfp->mnf_nextp = mip->mi_mnfp; 819*0Sstevel@tonic-gate mip->mi_mnfp = mnfp; 820*0Sstevel@tonic-gate rw_exit(&(mip->mi_notify_lock)); 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate return ((mac_notify_handle_t)mnfp); 823*0Sstevel@tonic-gate } 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate void 826*0Sstevel@tonic-gate mac_notify_remove(mac_handle_t mh, mac_notify_handle_t mnh) 827*0Sstevel@tonic-gate { 828*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 829*0Sstevel@tonic-gate mac_notify_fn_t *mnfp = (mac_notify_fn_t *)mnh; 830*0Sstevel@tonic-gate mac_notify_fn_t **pp; 831*0Sstevel@tonic-gate mac_notify_fn_t *p; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate /* 834*0Sstevel@tonic-gate * Search the 'notify' callback list for the function closure. 835*0Sstevel@tonic-gate */ 836*0Sstevel@tonic-gate rw_enter(&(mip->mi_notify_lock), RW_WRITER); 837*0Sstevel@tonic-gate for (pp = &(mip->mi_mnfp); (p = *pp) != NULL; 838*0Sstevel@tonic-gate pp = &(p->mnf_nextp)) { 839*0Sstevel@tonic-gate if (p == mnfp) 840*0Sstevel@tonic-gate break; 841*0Sstevel@tonic-gate } 842*0Sstevel@tonic-gate ASSERT(p != NULL); 843*0Sstevel@tonic-gate 844*0Sstevel@tonic-gate /* 845*0Sstevel@tonic-gate * Remove it from the list. 846*0Sstevel@tonic-gate */ 847*0Sstevel@tonic-gate *pp = p->mnf_nextp; 848*0Sstevel@tonic-gate rw_exit(&(mip->mi_notify_lock)); 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate /* 851*0Sstevel@tonic-gate * Free it. 852*0Sstevel@tonic-gate */ 853*0Sstevel@tonic-gate kmem_free(mnfp, sizeof (mac_notify_fn_t)); 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate void 857*0Sstevel@tonic-gate mac_notify(mac_handle_t mh) 858*0Sstevel@tonic-gate { 859*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 860*0Sstevel@tonic-gate mac_notify_type_t type; 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate for (type = 0; type < MAC_NNOTE; type++) 863*0Sstevel@tonic-gate i_mac_notify(mip, type); 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate 866*0Sstevel@tonic-gate mac_rx_handle_t 867*0Sstevel@tonic-gate mac_rx_add(mac_handle_t mh, mac_rx_t rx, void *arg) 868*0Sstevel@tonic-gate { 869*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 870*0Sstevel@tonic-gate mac_rx_fn_t *mrfp; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate mrfp = kmem_zalloc(sizeof (mac_rx_fn_t), KM_SLEEP); 873*0Sstevel@tonic-gate mrfp->mrf_fn = rx; 874*0Sstevel@tonic-gate mrfp->mrf_arg = arg; 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate /* 877*0Sstevel@tonic-gate * Add it to the head of the 'rx' callback list. 878*0Sstevel@tonic-gate */ 879*0Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 880*0Sstevel@tonic-gate mrfp->mrf_nextp = mip->mi_mrfp; 881*0Sstevel@tonic-gate mip->mi_mrfp = mrfp; 882*0Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate return ((mac_rx_handle_t)mrfp); 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate /* 888*0Sstevel@tonic-gate * Unregister a receive function for this mac. This removes the function 889*0Sstevel@tonic-gate * from the list of receive functions for this mac. 890*0Sstevel@tonic-gate */ 891*0Sstevel@tonic-gate void 892*0Sstevel@tonic-gate mac_rx_remove(mac_handle_t mh, mac_rx_handle_t mrh) 893*0Sstevel@tonic-gate { 894*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 895*0Sstevel@tonic-gate mac_rx_fn_t *mrfp = (mac_rx_fn_t *)mrh; 896*0Sstevel@tonic-gate mac_rx_fn_t **pp; 897*0Sstevel@tonic-gate mac_rx_fn_t *p; 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate /* 900*0Sstevel@tonic-gate * Search the 'rx' callback list for the function closure. 901*0Sstevel@tonic-gate */ 902*0Sstevel@tonic-gate rw_enter(&(mip->mi_rx_lock), RW_WRITER); 903*0Sstevel@tonic-gate for (pp = &(mip->mi_mrfp); (p = *pp) != NULL; pp = &(p->mrf_nextp)) { 904*0Sstevel@tonic-gate if (p == mrfp) 905*0Sstevel@tonic-gate break; 906*0Sstevel@tonic-gate } 907*0Sstevel@tonic-gate ASSERT(p != NULL); 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate /* Remove it from the list. */ 910*0Sstevel@tonic-gate *pp = p->mrf_nextp; 911*0Sstevel@tonic-gate kmem_free(mrfp, sizeof (mac_rx_fn_t)); 912*0Sstevel@tonic-gate rw_exit(&(mip->mi_rx_lock)); 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate mac_txloop_handle_t 916*0Sstevel@tonic-gate mac_txloop_add(mac_handle_t mh, mac_txloop_t tx, void *arg) 917*0Sstevel@tonic-gate { 918*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 919*0Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate mtfp = kmem_zalloc(sizeof (mac_txloop_fn_t), KM_SLEEP); 922*0Sstevel@tonic-gate mtfp->mtf_fn = tx; 923*0Sstevel@tonic-gate mtfp->mtf_arg = arg; 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate /* 926*0Sstevel@tonic-gate * Add it to the head of the 'tx' callback list. 927*0Sstevel@tonic-gate */ 928*0Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 929*0Sstevel@tonic-gate mtfp->mtf_nextp = mip->mi_mtfp; 930*0Sstevel@tonic-gate mip->mi_mtfp = mtfp; 931*0Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate return ((mac_txloop_handle_t)mtfp); 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate /* 937*0Sstevel@tonic-gate * Unregister a transmit function for this mac. This removes the function 938*0Sstevel@tonic-gate * from the list of transmit functions for this mac. 939*0Sstevel@tonic-gate */ 940*0Sstevel@tonic-gate void 941*0Sstevel@tonic-gate mac_txloop_remove(mac_handle_t mh, mac_txloop_handle_t mth) 942*0Sstevel@tonic-gate { 943*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 944*0Sstevel@tonic-gate mac_txloop_fn_t *mtfp = (mac_txloop_fn_t *)mth; 945*0Sstevel@tonic-gate mac_txloop_fn_t **pp; 946*0Sstevel@tonic-gate mac_txloop_fn_t *p; 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate /* 949*0Sstevel@tonic-gate * Search the 'tx' callback list for the function. 950*0Sstevel@tonic-gate */ 951*0Sstevel@tonic-gate rw_enter(&(mip->mi_txloop_lock), RW_WRITER); 952*0Sstevel@tonic-gate for (pp = &(mip->mi_mtfp); (p = *pp) != NULL; pp = &(p->mtf_nextp)) { 953*0Sstevel@tonic-gate if (p == mtfp) 954*0Sstevel@tonic-gate break; 955*0Sstevel@tonic-gate } 956*0Sstevel@tonic-gate ASSERT(p != NULL); 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate /* Remove it from the list. */ 959*0Sstevel@tonic-gate *pp = p->mtf_nextp; 960*0Sstevel@tonic-gate kmem_free(mtfp, sizeof (mac_txloop_fn_t)); 961*0Sstevel@tonic-gate rw_exit(&(mip->mi_txloop_lock)); 962*0Sstevel@tonic-gate } 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate void 965*0Sstevel@tonic-gate mac_resource_set(mac_handle_t mh, mac_resource_add_t add, void *arg) 966*0Sstevel@tonic-gate { 967*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate /* 970*0Sstevel@tonic-gate * Update the 'resource_add' callbacks. 971*0Sstevel@tonic-gate */ 972*0Sstevel@tonic-gate rw_enter(&(mip->mi_resource_lock), RW_WRITER); 973*0Sstevel@tonic-gate mip->mi_resource_add = add; 974*0Sstevel@tonic-gate mip->mi_resource_add_arg = arg; 975*0Sstevel@tonic-gate rw_exit(&(mip->mi_resource_lock)); 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate /* 979*0Sstevel@tonic-gate * Driver support functions. 980*0Sstevel@tonic-gate */ 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate int 983*0Sstevel@tonic-gate mac_register(mac_t *mp) 984*0Sstevel@tonic-gate { 985*0Sstevel@tonic-gate int err; 986*0Sstevel@tonic-gate char name[MAXNAMELEN], aggr_name[MAXNAMELEN]; 987*0Sstevel@tonic-gate struct devnames *dnp; 988*0Sstevel@tonic-gate 989*0Sstevel@tonic-gate #ifdef DEBUG 990*0Sstevel@tonic-gate if (strcmp(mp->m_ident, MAC_IDENT) != 0) 991*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d/%d: possible mac interface mismatch", 992*0Sstevel@tonic-gate ddi_driver_name(mp->m_dip), 993*0Sstevel@tonic-gate ddi_get_instance(mp->m_dip), 994*0Sstevel@tonic-gate mp->m_port); 995*0Sstevel@tonic-gate #endif /* DEBUG */ 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate ASSERT(!(mp->m_info.mi_addr_length & 1)); 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate /* 1000*0Sstevel@tonic-gate * Create a new mac_impl_t to pair with the mac_t. 1001*0Sstevel@tonic-gate */ 1002*0Sstevel@tonic-gate if ((err = i_mac_create(mp)) != 0) 1003*0Sstevel@tonic-gate return (err); 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate /* 1006*0Sstevel@tonic-gate * Create a DDI_NT_MAC minor node such that libdevinfo(3lib) can be 1007*0Sstevel@tonic-gate * used to search for mac interfaces. 1008*0Sstevel@tonic-gate */ 1009*0Sstevel@tonic-gate (void) sprintf(name, "%d", mp->m_port); 1010*0Sstevel@tonic-gate if (ddi_create_minor_node(mp->m_dip, name, S_IFCHR, mp->m_port, 1011*0Sstevel@tonic-gate DDI_NT_MAC, 0) != DDI_SUCCESS) { 1012*0Sstevel@tonic-gate i_mac_destroy(mp); 1013*0Sstevel@tonic-gate return (EEXIST); 1014*0Sstevel@tonic-gate } 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate /* 1017*0Sstevel@tonic-gate * Right now only the "aggr" driver creates nodes at mac_register 1018*0Sstevel@tonic-gate * time, but it is expected that in the future with some 1019*0Sstevel@tonic-gate * enhancement of devfs, all the drivers can create nodes here. 1020*0Sstevel@tonic-gate */ 1021*0Sstevel@tonic-gate if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) { 1022*0Sstevel@tonic-gate (void) snprintf(aggr_name, MAXNAMELEN, "aggr%u", mp->m_port); 1023*0Sstevel@tonic-gate err = dld_ppa_create(aggr_name, AGGR_DEV, mp->m_port, 0); 1024*0Sstevel@tonic-gate if (err != 0) { 1025*0Sstevel@tonic-gate ASSERT(err != EEXIST); 1026*0Sstevel@tonic-gate ddi_remove_minor_node(mp->m_dip, name); 1027*0Sstevel@tonic-gate i_mac_destroy(mp); 1028*0Sstevel@tonic-gate return (err); 1029*0Sstevel@tonic-gate } 1030*0Sstevel@tonic-gate } 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate /* set the gldv3 flag in dn_flags */ 1033*0Sstevel@tonic-gate dnp = &devnamesp[ddi_driver_major(mp->m_dip)]; 1034*0Sstevel@tonic-gate LOCK_DEV_OPS(&dnp->dn_lock); 1035*0Sstevel@tonic-gate dnp->dn_flags |= DN_GLDV3_DRIVER; 1036*0Sstevel@tonic-gate UNLOCK_DEV_OPS(&dnp->dn_lock); 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!%s%d/%d registered", 1039*0Sstevel@tonic-gate ddi_driver_name(mp->m_dip), 1040*0Sstevel@tonic-gate ddi_get_instance(mp->m_dip), 1041*0Sstevel@tonic-gate mp->m_port); 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate return (0); 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate int 1047*0Sstevel@tonic-gate mac_unregister(mac_t *mp) 1048*0Sstevel@tonic-gate { 1049*0Sstevel@tonic-gate int err; 1050*0Sstevel@tonic-gate char name[MAXNAMELEN]; 1051*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate /* 1054*0Sstevel@tonic-gate * See if there are any other references to this mac_t (e.g., VLAN's). 1055*0Sstevel@tonic-gate * If not, set mi_destroying to prevent any new VLAN's from being 1056*0Sstevel@tonic-gate * created before we can perform the i_mac_destroy() below. 1057*0Sstevel@tonic-gate */ 1058*0Sstevel@tonic-gate ght_lock(i_mac_impl_hash, GHT_WRITE); 1059*0Sstevel@tonic-gate if (mip->mi_ref > 0) { 1060*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 1061*0Sstevel@tonic-gate return (EBUSY); 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate mip->mi_destroying = B_TRUE; 1064*0Sstevel@tonic-gate ght_unlock(i_mac_impl_hash); 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate if (strcmp(ddi_driver_name(mp->m_dip), "aggr") == 0) { 1067*0Sstevel@tonic-gate (void) snprintf(name, MAXNAMELEN, "aggr%u", mp->m_port); 1068*0Sstevel@tonic-gate if ((err = dld_ppa_destroy(name)) != 0) 1069*0Sstevel@tonic-gate return (err); 1070*0Sstevel@tonic-gate } 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate /* 1073*0Sstevel@tonic-gate * Destroy the mac_impl_t. 1074*0Sstevel@tonic-gate */ 1075*0Sstevel@tonic-gate i_mac_destroy(mp); 1076*0Sstevel@tonic-gate 1077*0Sstevel@tonic-gate /* 1078*0Sstevel@tonic-gate * Remove the minor node. 1079*0Sstevel@tonic-gate */ 1080*0Sstevel@tonic-gate (void) sprintf(name, "%d", mp->m_port); 1081*0Sstevel@tonic-gate ddi_remove_minor_node(mp->m_dip, name); 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!%s%d/%d unregistered", 1084*0Sstevel@tonic-gate ddi_driver_name(mp->m_dip), 1085*0Sstevel@tonic-gate ddi_get_instance(mp->m_dip), 1086*0Sstevel@tonic-gate mp->m_port); 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate return (0); 1089*0Sstevel@tonic-gate } 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate void 1092*0Sstevel@tonic-gate mac_rx(mac_t *mp, mac_resource_handle_t mrh, mblk_t *bp) 1093*0Sstevel@tonic-gate { 1094*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1095*0Sstevel@tonic-gate mac_rx_fn_t *mrfp; 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate /* 1098*0Sstevel@tonic-gate * Call all registered receive functions. 1099*0Sstevel@tonic-gate */ 1100*0Sstevel@tonic-gate rw_enter(&mip->mi_rx_lock, RW_READER); 1101*0Sstevel@tonic-gate mrfp = mip->mi_mrfp; 1102*0Sstevel@tonic-gate if (mrfp == NULL) { 1103*0Sstevel@tonic-gate /* There are no registered receive functions. */ 1104*0Sstevel@tonic-gate freemsgchain(bp); 1105*0Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 1106*0Sstevel@tonic-gate return; 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate do { 1109*0Sstevel@tonic-gate mblk_t *recv_bp; 1110*0Sstevel@tonic-gate 1111*0Sstevel@tonic-gate if (mrfp->mrf_nextp != NULL) { 1112*0Sstevel@tonic-gate /* XXX Do we bump a counter if copymsgchain() fails? */ 1113*0Sstevel@tonic-gate recv_bp = copymsgchain(bp); 1114*0Sstevel@tonic-gate } else { 1115*0Sstevel@tonic-gate recv_bp = bp; 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate if (recv_bp != NULL) 1118*0Sstevel@tonic-gate mrfp->mrf_fn(mrfp->mrf_arg, mrh, recv_bp); 1119*0Sstevel@tonic-gate mrfp = mrfp->mrf_nextp; 1120*0Sstevel@tonic-gate } while (mrfp != NULL); 1121*0Sstevel@tonic-gate rw_exit(&mip->mi_rx_lock); 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate /* 1125*0Sstevel@tonic-gate * Transmit function -- ONLY used when there are registered loopback listeners. 1126*0Sstevel@tonic-gate */ 1127*0Sstevel@tonic-gate mblk_t * 1128*0Sstevel@tonic-gate mac_txloop(void *arg, mblk_t *bp) 1129*0Sstevel@tonic-gate { 1130*0Sstevel@tonic-gate mac_impl_t *mip = arg; 1131*0Sstevel@tonic-gate mac_t *mp = mip->mi_mp; 1132*0Sstevel@tonic-gate mac_txloop_fn_t *mtfp; 1133*0Sstevel@tonic-gate mblk_t *loop_bp, *resid_bp, *next_bp; 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate while (bp != NULL) { 1136*0Sstevel@tonic-gate next_bp = bp->b_next; 1137*0Sstevel@tonic-gate bp->b_next = NULL; 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate if ((loop_bp = copymsg(bp)) == NULL) 1140*0Sstevel@tonic-gate goto noresources; 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate if ((resid_bp = mp->m_tx(mp->m_driver, bp)) != NULL) { 1143*0Sstevel@tonic-gate ASSERT(resid_bp == bp); 1144*0Sstevel@tonic-gate freemsg(loop_bp); 1145*0Sstevel@tonic-gate goto noresources; 1146*0Sstevel@tonic-gate } 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate rw_enter(&mip->mi_txloop_lock, RW_READER); 1149*0Sstevel@tonic-gate 1150*0Sstevel@tonic-gate mtfp = mip->mi_mtfp; 1151*0Sstevel@tonic-gate for (; mtfp != NULL; mtfp = mtfp->mtf_nextp) { 1152*0Sstevel@tonic-gate bp = loop_bp; 1153*0Sstevel@tonic-gate if (mtfp->mtf_nextp != NULL) { 1154*0Sstevel@tonic-gate loop_bp = copymsg(bp); 1155*0Sstevel@tonic-gate /* XXX counter bump if copymsg() fails? */ 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate 1158*0Sstevel@tonic-gate mtfp->mtf_fn(mtfp->mtf_arg, bp); 1159*0Sstevel@tonic-gate if (loop_bp == NULL) 1160*0Sstevel@tonic-gate break; 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate rw_exit(&mip->mi_txloop_lock); 1164*0Sstevel@tonic-gate bp = next_bp; 1165*0Sstevel@tonic-gate } 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate return (NULL); 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate noresources: 1170*0Sstevel@tonic-gate bp->b_next = next_bp; 1171*0Sstevel@tonic-gate return (bp); 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate void 1175*0Sstevel@tonic-gate mac_link_update(mac_t *mp, link_state_t link) 1176*0Sstevel@tonic-gate { 1177*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate ASSERT(mip->mi_mp == mp); 1180*0Sstevel@tonic-gate 1181*0Sstevel@tonic-gate /* 1182*0Sstevel@tonic-gate * Save the link state. 1183*0Sstevel@tonic-gate */ 1184*0Sstevel@tonic-gate mip->mi_link = link; 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate /* 1187*0Sstevel@tonic-gate * Send a MAC_NOTE_LINK notification. 1188*0Sstevel@tonic-gate */ 1189*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_LINK); 1190*0Sstevel@tonic-gate } 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate void 1193*0Sstevel@tonic-gate mac_unicst_update(mac_t *mp, const uint8_t *addr) 1194*0Sstevel@tonic-gate { 1195*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate ASSERT(mip->mi_mp == mp); 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate /* 1200*0Sstevel@tonic-gate * Save the address. 1201*0Sstevel@tonic-gate */ 1202*0Sstevel@tonic-gate bcopy(addr, mip->mi_addr, mip->mi_addr_length); 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate /* 1205*0Sstevel@tonic-gate * Send a MAC_NOTE_UNICST notification. 1206*0Sstevel@tonic-gate */ 1207*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_UNICST); 1208*0Sstevel@tonic-gate } 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate void 1211*0Sstevel@tonic-gate mac_tx_update(mac_t *mp) 1212*0Sstevel@tonic-gate { 1213*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate ASSERT(mip->mi_mp == mp); 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate /* 1218*0Sstevel@tonic-gate * Send a MAC_NOTE_TX notification. 1219*0Sstevel@tonic-gate */ 1220*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_TX); 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate void 1224*0Sstevel@tonic-gate mac_resource_update(mac_t *mp) 1225*0Sstevel@tonic-gate { 1226*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate ASSERT(mip->mi_mp == mp); 1229*0Sstevel@tonic-gate 1230*0Sstevel@tonic-gate /* 1231*0Sstevel@tonic-gate * Send a MAC_NOTE_RESOURCE notification. 1232*0Sstevel@tonic-gate */ 1233*0Sstevel@tonic-gate i_mac_notify(mip, MAC_NOTE_RESOURCE); 1234*0Sstevel@tonic-gate } 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate mac_resource_handle_t 1237*0Sstevel@tonic-gate mac_resource_add(mac_t *mp, mac_resource_t *mrp) 1238*0Sstevel@tonic-gate { 1239*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1240*0Sstevel@tonic-gate mac_resource_handle_t mrh; 1241*0Sstevel@tonic-gate mac_resource_add_t add; 1242*0Sstevel@tonic-gate void *arg; 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate rw_enter(&mip->mi_resource_lock, RW_READER); 1245*0Sstevel@tonic-gate add = mip->mi_resource_add; 1246*0Sstevel@tonic-gate arg = mip->mi_resource_add_arg; 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate mrh = add(arg, mrp); 1249*0Sstevel@tonic-gate rw_exit(&mip->mi_resource_lock); 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate return (mrh); 1252*0Sstevel@tonic-gate } 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate void 1255*0Sstevel@tonic-gate mac_multicst_refresh(mac_t *mp, mac_multicst_t refresh, void *arg, 1256*0Sstevel@tonic-gate boolean_t add) 1257*0Sstevel@tonic-gate { 1258*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1259*0Sstevel@tonic-gate mac_multicst_addr_t *p; 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate /* 1262*0Sstevel@tonic-gate * If no specific refresh function was given then default to the 1263*0Sstevel@tonic-gate * driver's m_multicst entry point. 1264*0Sstevel@tonic-gate */ 1265*0Sstevel@tonic-gate if (refresh == NULL) { 1266*0Sstevel@tonic-gate refresh = mp->m_multicst; 1267*0Sstevel@tonic-gate arg = mp->m_driver; 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate ASSERT(refresh != NULL); 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate /* 1272*0Sstevel@tonic-gate * Walk the multicast address list and call the refresh function for 1273*0Sstevel@tonic-gate * each address. 1274*0Sstevel@tonic-gate */ 1275*0Sstevel@tonic-gate rw_enter(&(mip->mi_data_lock), RW_READER); 1276*0Sstevel@tonic-gate for (p = mip->mi_mmap; p != NULL; p = p->mma_nextp) 1277*0Sstevel@tonic-gate refresh(arg, add, p->mma_addr); 1278*0Sstevel@tonic-gate rw_exit(&(mip->mi_data_lock)); 1279*0Sstevel@tonic-gate } 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate void 1282*0Sstevel@tonic-gate mac_unicst_refresh(mac_t *mp, mac_unicst_t refresh, void *arg) 1283*0Sstevel@tonic-gate { 1284*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1285*0Sstevel@tonic-gate /* 1286*0Sstevel@tonic-gate * If no specific refresh function was given then default to the 1287*0Sstevel@tonic-gate * driver's m_unicst entry point. 1288*0Sstevel@tonic-gate */ 1289*0Sstevel@tonic-gate if (refresh == NULL) { 1290*0Sstevel@tonic-gate refresh = mp->m_unicst; 1291*0Sstevel@tonic-gate arg = mp->m_driver; 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate ASSERT(refresh != NULL); 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate /* 1296*0Sstevel@tonic-gate * Call the refresh function with the current unicast address. 1297*0Sstevel@tonic-gate */ 1298*0Sstevel@tonic-gate refresh(arg, mip->mi_addr); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate void 1302*0Sstevel@tonic-gate mac_promisc_refresh(mac_t *mp, mac_promisc_t refresh, void *arg) 1303*0Sstevel@tonic-gate { 1304*0Sstevel@tonic-gate mac_impl_t *mip = mp->m_impl; 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate /* 1307*0Sstevel@tonic-gate * If no specific refresh function was given then default to the 1308*0Sstevel@tonic-gate * driver's m_promisc entry point. 1309*0Sstevel@tonic-gate */ 1310*0Sstevel@tonic-gate if (refresh == NULL) { 1311*0Sstevel@tonic-gate refresh = mp->m_promisc; 1312*0Sstevel@tonic-gate arg = mp->m_driver; 1313*0Sstevel@tonic-gate } 1314*0Sstevel@tonic-gate ASSERT(refresh != NULL); 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate /* 1317*0Sstevel@tonic-gate * Call the refresh function with the current promiscuity. 1318*0Sstevel@tonic-gate */ 1319*0Sstevel@tonic-gate refresh(arg, (mip->mi_devpromisc != 0)); 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate boolean_t 1323*0Sstevel@tonic-gate mac_active_set(mac_handle_t mh) 1324*0Sstevel@tonic-gate { 1325*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 1328*0Sstevel@tonic-gate if (mip->mi_activelink) { 1329*0Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 1330*0Sstevel@tonic-gate return (B_FALSE); 1331*0Sstevel@tonic-gate } 1332*0Sstevel@tonic-gate mip->mi_activelink = B_TRUE; 1333*0Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 1334*0Sstevel@tonic-gate return (B_TRUE); 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate void 1338*0Sstevel@tonic-gate mac_active_clear(mac_handle_t mh) 1339*0Sstevel@tonic-gate { 1340*0Sstevel@tonic-gate mac_impl_t *mip = (mac_impl_t *)mh; 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate mutex_enter(&mip->mi_activelink_lock); 1343*0Sstevel@tonic-gate ASSERT(mip->mi_activelink); 1344*0Sstevel@tonic-gate mip->mi_activelink = B_FALSE; 1345*0Sstevel@tonic-gate mutex_exit(&mip->mi_activelink_lock); 1346*0Sstevel@tonic-gate } 1347