Home | History | Annotate | Download | only in mac
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/sysmacros.h>
     28 #include <sys/conf.h>
     29 #include <sys/cmn_err.h>
     30 #include <sys/list.h>
     31 #include <sys/kmem.h>
     32 #include <sys/stream.h>
     33 #include <sys/modctl.h>
     34 #include <sys/ddi.h>
     35 #include <sys/sunddi.h>
     36 #include <sys/atomic.h>
     37 #include <sys/stat.h>
     38 #include <sys/modhash.h>
     39 #include <sys/strsubr.h>
     40 #include <sys/strsun.h>
     41 #include <sys/sdt.h>
     42 #include <sys/mac.h>
     43 #include <sys/mac_impl.h>
     44 #include <sys/mac_client_impl.h>
     45 #include <sys/mac_client_priv.h>
     46 #include <sys/mac_flow_impl.h>
     47 
     48 /*
     49  * Broadcast and multicast traffic must be distributed to the MAC clients
     50  * that are defined on top of the same MAC. The set of
     51  * destinations to which a multicast packet must be sent is a subset
     52  * of all MAC clients defined on top of the MAC. A MAC client can be member
     53  * of more than one such subset.
     54  *
     55  * To accomodate these requirements, we introduce broadcast groups.
     56  * A broadcast group is associated with a broadcast or multicast
     57  * address. The members of a broadcast group consist of the MAC clients
     58  * that should received copies of packets sent to the address
     59  * associated with the group, and are defined on top of the
     60  * same MAC.
     61  *
     62  * The broadcast groups defined on top of a MAC are chained,
     63  * hanging off the mac_impl_t. The broadcast group id's are
     64  * unique globally (tracked by mac_bcast_id).
     65  */
     66 
     67 /*
     68  * The same MAC client may be added for different <addr,vid> tuple,
     69  * we maintain a ref count for the number of times it has been added
     70  * to account for deleting the MAC client from the group.
     71  */
     72 typedef struct mac_bcast_grp_mcip_s {
     73 	mac_client_impl_t	*mgb_client;
     74 	int			mgb_client_ref;
     75 } mac_bcast_grp_mcip_t;
     76 
     77 typedef struct mac_bcast_grp_s {			/* Protected by */
     78 	struct mac_bcast_grp_s	*mbg_next;		/* SL */
     79 	void			*mbg_addr;		/* SL */
     80 	uint16_t		mbg_vid;		/* SL */
     81 	mac_impl_t		*mbg_mac_impl;		/* WO */
     82 	mac_addrtype_t		mbg_addrtype;		/* WO */
     83 	flow_entry_t		*mbg_flow_ent;		/* WO */
     84 	mac_bcast_grp_mcip_t	*mbg_clients;		/* mi_rw_lock */
     85 	uint_t			mbg_nclients;		/* mi_rw_lock */
     86 	uint_t			mbg_nclients_alloc;	/* SL */
     87 	uint64_t		mbg_clients_gen;	/* mi_rw_lock */
     88 	uint32_t		mbg_id;			/* atomic */
     89 } mac_bcast_grp_t;
     90 
     91 static kmem_cache_t *mac_bcast_grp_cache;
     92 static uint32_t mac_bcast_id = 0;
     93 
     94 void
     95 mac_bcast_init(void)
     96 {
     97 	mac_bcast_grp_cache = kmem_cache_create("mac_bcast_grp_cache",
     98 	    sizeof (mac_bcast_grp_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
     99 }
    100 
    101 void
    102 mac_bcast_fini(void)
    103 {
    104 	kmem_cache_destroy(mac_bcast_grp_cache);
    105 }
    106 
    107 mac_impl_t *
    108 mac_bcast_grp_mip(void *grp)
    109 {
    110 	mac_bcast_grp_t *bcast_grp = grp;
    111 
    112 	return (bcast_grp->mbg_mac_impl);
    113 }
    114 
    115 /*
    116  * Free the specific broadcast group. Invoked when the last reference
    117  * to the group is released.
    118  */
    119 void
    120 mac_bcast_grp_free(void *bcast_grp)
    121 {
    122 	mac_bcast_grp_t	*grp = bcast_grp;
    123 	mac_impl_t *mip = grp->mbg_mac_impl;
    124 
    125 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
    126 
    127 	ASSERT(grp->mbg_addr != NULL);
    128 	kmem_free(grp->mbg_addr, mip->mi_type->mt_addr_length);
    129 	kmem_free(grp->mbg_clients,
    130 	    grp->mbg_nclients_alloc * sizeof (mac_bcast_grp_mcip_t));
    131 	mip->mi_bcast_ngrps--;
    132 	kmem_cache_free(mac_bcast_grp_cache, grp);
    133 }
    134 
    135 /*
    136  * arg1: broadcast group
    137  * arg2: sender MAC client if it is being sent by a MAC client,
    138  * NULL if it was received from the wire.
    139  */
    140 void
    141 mac_bcast_send(void *arg1, void *arg2, mblk_t *mp_chain, boolean_t is_loopback)
    142 {
    143 	mac_bcast_grp_t *grp = arg1;
    144 	mac_client_impl_t *src_mcip = arg2, *dst_mcip;
    145 	mac_impl_t *mip = grp->mbg_mac_impl;
    146 	uint64_t gen;
    147 	uint_t i;
    148 	mblk_t *mp_chain1;
    149 	flow_entry_t	*flent;
    150 	int err;
    151 
    152 	rw_enter(&mip->mi_rw_lock, RW_READER);
    153 
    154 	/*
    155 	 * Pass a copy of the mp chain to every MAC client except the sender
    156 	 * MAC client, if the packet was not received from the underlying NIC.
    157 	 *
    158 	 * The broadcast group lock should not be held across calls to
    159 	 * the flow's callback function, since the same group could
    160 	 * potentially be accessed from the same context. When the lock
    161 	 * is reacquired, changes to the broadcast group while the lock
    162 	 * was released are caught using a generation counter incremented
    163 	 * each time the list of MAC clients associated with the broadcast
    164 	 * group is changed.
    165 	 */
    166 	for (i = 0; i < grp->mbg_nclients_alloc; i++) {
    167 		dst_mcip = grp->mbg_clients[i].mgb_client;
    168 		if (dst_mcip == NULL)
    169 			continue;
    170 		flent = dst_mcip->mci_flent;
    171 		if (flent == NULL || dst_mcip == src_mcip) {
    172 			/*
    173 			 * Don't send a copy of the packet back to
    174 			 * its sender.
    175 			 */
    176 			continue;
    177 		}
    178 
    179 		/*
    180 		 * It is important to hold a reference on the
    181 		 * flow_ent here.
    182 		 */
    183 		if ((mp_chain1 = mac_copymsgchain_cksum(mp_chain)) == NULL)
    184 			break;
    185 		/*
    186 		 * Fix the checksum for packets originating
    187 		 * from the local machine.
    188 		 */
    189 		if ((src_mcip != NULL) &&
    190 		    (mp_chain1 = mac_fix_cksum(mp_chain1)) == NULL)
    191 			break;
    192 
    193 		FLOW_TRY_REFHOLD(flent, err);
    194 		if (err != 0) {
    195 			freemsgchain(mp_chain1);
    196 			continue;
    197 		}
    198 
    199 		gen = grp->mbg_clients_gen;
    200 
    201 		rw_exit(&mip->mi_rw_lock);
    202 
    203 		DTRACE_PROBE4(mac__bcast__send__to, mac_client_impl_t *,
    204 		    src_mcip, flow_fn_t, dst_mcip->mci_flent->fe_cb_fn,
    205 		    void *, dst_mcip->mci_flent->fe_cb_arg1,
    206 		    void *, dst_mcip->mci_flent->fe_cb_arg2);
    207 
    208 		(dst_mcip->mci_flent->fe_cb_fn)(dst_mcip->mci_flent->fe_cb_arg1,
    209 		    dst_mcip->mci_flent->fe_cb_arg2, mp_chain1, is_loopback);
    210 		FLOW_REFRELE(flent);
    211 
    212 		rw_enter(&mip->mi_rw_lock, RW_READER);
    213 
    214 		/* update stats */
    215 		if (grp->mbg_addrtype == MAC_ADDRTYPE_MULTICAST)
    216 			dst_mcip->mci_stat_multircv++;
    217 		else
    218 			dst_mcip->mci_stat_brdcstrcv++;
    219 
    220 		if (grp->mbg_clients_gen != gen) {
    221 			/*
    222 			 * The list of MAC clients associated with the group
    223 			 * was changed while the lock was released.
    224 			 * Give up on the current packet.
    225 			 */
    226 			rw_exit(&mip->mi_rw_lock);
    227 			freemsgchain(mp_chain);
    228 			return;
    229 		}
    230 	}
    231 	rw_exit(&mip->mi_rw_lock);
    232 
    233 	if (src_mcip != NULL) {
    234 		/*
    235 		 * The packet was sent from one of the MAC clients,
    236 		 * so we need to send a copy of the packet to the
    237 		 * underlying NIC so that it can be sent on the wire.
    238 		 */
    239 		src_mcip->mci_stat_multixmt++;
    240 		src_mcip->mci_stat_brdcstxmt++;
    241 
    242 		MAC_TX(mip, mip->mi_default_tx_ring, mp_chain, B_FALSE);
    243 		if (mp_chain != NULL)
    244 			freemsgchain(mp_chain);
    245 	} else {
    246 		freemsgchain(mp_chain);
    247 	}
    248 }
    249 
    250 /*
    251  * Add the specified MAC client to the group corresponding to the specified
    252  * broadcast or multicast address.
    253  * Return 0 on success, or an errno value on failure.
    254  */
    255 int
    256 mac_bcast_add(mac_client_impl_t *mcip, const uint8_t *addr, uint16_t vid,
    257     mac_addrtype_t addrtype)
    258 {
    259 	mac_impl_t 		*mip = mcip->mci_mip;
    260 	mac_bcast_grp_t		*grp = NULL, **last_grp;
    261 	size_t			addr_len = mip->mi_type->mt_addr_length;
    262 	int			rc = 0;
    263 	int			i, index = -1;
    264 	mac_mcast_addrs_t	**prev_mi_addr = NULL;
    265 	mac_mcast_addrs_t	**prev_mci_addr = NULL;
    266 
    267 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
    268 
    269 	ASSERT(addrtype == MAC_ADDRTYPE_MULTICAST ||
    270 	    addrtype == MAC_ADDRTYPE_BROADCAST);
    271 
    272 	/*
    273 	 * Add the MAC client to the list of MAC clients associated
    274 	 * with the group.
    275 	 */
    276 	if (addrtype == MAC_ADDRTYPE_MULTICAST) {
    277 		mac_mcast_addrs_t	*maddr;
    278 
    279 		/*
    280 		 * In case of a driver (say aggr), we need this information
    281 		 * on a per MAC instance basis.
    282 		 */
    283 		prev_mi_addr = &mip->mi_mcast_addrs;
    284 		for (maddr = *prev_mi_addr; maddr != NULL;
    285 		    prev_mi_addr = &maddr->mma_next, maddr = maddr->mma_next) {
    286 			if (bcmp(maddr->mma_addr, addr, addr_len) == 0)
    287 				break;
    288 		}
    289 		if (maddr == NULL) {
    290 			/*
    291 			 * For multicast addresses, have the underlying MAC
    292 			 * join the corresponding multicast group.
    293 			 */
    294 			rc = mip->mi_multicst(mip->mi_driver, B_TRUE, addr);
    295 			if (rc != 0)
    296 				return (rc);
    297 			maddr = kmem_zalloc(sizeof (mac_mcast_addrs_t),
    298 			    KM_SLEEP);
    299 			bcopy(addr, maddr->mma_addr, addr_len);
    300 			*prev_mi_addr = maddr;
    301 		} else {
    302 			prev_mi_addr = NULL;
    303 		}
    304 		maddr->mma_ref++;
    305 
    306 		/*
    307 		 * We maintain a separate list for each MAC client. Get
    308 		 * the entry or add, if it is not present.
    309 		 */
    310 		prev_mci_addr = &mcip->mci_mcast_addrs;
    311 		for (maddr = *prev_mci_addr; maddr != NULL;
    312 		    prev_mci_addr = &maddr->mma_next, maddr = maddr->mma_next) {
    313 			if (bcmp(maddr->mma_addr, addr, addr_len) == 0)
    314 				break;
    315 		}
    316 		if (maddr == NULL) {
    317 			maddr = kmem_zalloc(sizeof (mac_mcast_addrs_t),
    318 			    KM_SLEEP);
    319 			bcopy(addr, maddr->mma_addr, addr_len);
    320 			*prev_mci_addr = maddr;
    321 		} else {
    322 			prev_mci_addr = NULL;
    323 		}
    324 		maddr->mma_ref++;
    325 	}
    326 
    327 	/* The list is protected by the perimeter */
    328 	last_grp = &mip->mi_bcast_grp;
    329 	for (grp = *last_grp; grp != NULL;
    330 	    last_grp = &grp->mbg_next, grp = grp->mbg_next) {
    331 		if (bcmp(grp->mbg_addr, addr, addr_len) == 0 &&
    332 		    grp->mbg_vid == vid)
    333 			break;
    334 	}
    335 
    336 	if (grp == NULL) {
    337 		/*
    338 		 * The group does not yet exist, create it.
    339 		 */
    340 		flow_desc_t flow_desc;
    341 		char flow_name[MAXFLOWNAMELEN];
    342 
    343 		grp = kmem_cache_alloc(mac_bcast_grp_cache, KM_SLEEP);
    344 		bzero(grp, sizeof (mac_bcast_grp_t));
    345 		grp->mbg_next = NULL;
    346 		grp->mbg_mac_impl = mip;
    347 
    348 		DTRACE_PROBE1(mac__bcast__add__new__group, mac_bcast_grp_t *,
    349 		    grp);
    350 
    351 		grp->mbg_addr = kmem_zalloc(addr_len, KM_SLEEP);
    352 		bcopy(addr, grp->mbg_addr, addr_len);
    353 		grp->mbg_addrtype = addrtype;
    354 		grp->mbg_vid = vid;
    355 
    356 		/*
    357 		 * Add a new flow to the underlying MAC.
    358 		 */
    359 		bzero(&flow_desc, sizeof (flow_desc));
    360 		bcopy(addr, &flow_desc.fd_dst_mac, addr_len);
    361 		flow_desc.fd_mac_len = (uint32_t)addr_len;
    362 
    363 		flow_desc.fd_mask = FLOW_LINK_DST;
    364 		if (vid != 0) {
    365 			flow_desc.fd_vid = vid;
    366 			flow_desc.fd_mask |= FLOW_LINK_VID;
    367 		}
    368 
    369 		grp->mbg_id = atomic_add_32_nv(&mac_bcast_id, 1);
    370 		(void) sprintf(flow_name,
    371 		    "mac/%s/mcast%d", mip->mi_name, grp->mbg_id);
    372 
    373 		rc = mac_flow_create(&flow_desc, NULL, flow_name,
    374 		    grp, FLOW_MCAST, &grp->mbg_flow_ent);
    375 		if (rc != 0) {
    376 			kmem_free(grp->mbg_addr, addr_len);
    377 			kmem_cache_free(mac_bcast_grp_cache, grp);
    378 			goto fail;
    379 		}
    380 		grp->mbg_flow_ent->fe_mbg = grp;
    381 		mip->mi_bcast_ngrps++;
    382 
    383 		/*
    384 		 * Initial creation reference on the flow. This is released
    385 		 * in the corresponding delete action i_mac_bcast_delete()
    386 		 */
    387 		FLOW_REFHOLD(grp->mbg_flow_ent);
    388 
    389 		/*
    390 		 * When the multicast and broadcast packet is received
    391 		 * by the underlying NIC, mac_rx_classify() will invoke
    392 		 * mac_bcast_send() with arg2=NULL, which will cause
    393 		 * mac_bcast_send() to send a copy of the packet(s)
    394 		 * to every MAC client opened on top of the underlying MAC.
    395 		 *
    396 		 * When the mac_bcast_send() function is invoked from
    397 		 * the transmit path of a MAC client, it will specify the
    398 		 * transmitting MAC client as the arg2 value, which will
    399 		 * allow mac_bcast_send() to skip that MAC client and not
    400 		 * send it a copy of the packet.
    401 		 *
    402 		 * We program the classifier to dispatch matching broadcast
    403 		 * packets to mac_bcast_send().
    404 		 */
    405 
    406 		grp->mbg_flow_ent->fe_cb_fn = mac_bcast_send;
    407 		grp->mbg_flow_ent->fe_cb_arg1 = grp;
    408 		grp->mbg_flow_ent->fe_cb_arg2 = NULL;
    409 
    410 		rc = mac_flow_add(mip->mi_flow_tab, grp->mbg_flow_ent);
    411 		if (rc != 0) {
    412 			FLOW_FINAL_REFRELE(grp->mbg_flow_ent);
    413 			goto fail;
    414 		}
    415 
    416 		*last_grp = grp;
    417 	}
    418 
    419 	ASSERT(grp->mbg_addrtype == addrtype);
    420 
    421 	/*
    422 	 * Add the MAC client to the list of MAC clients associated
    423 	 * with the group.
    424 	 */
    425 	rw_enter(&mip->mi_rw_lock, RW_WRITER);
    426 	for (i = 0; i < grp->mbg_nclients_alloc; i++) {
    427 		/*
    428 		 * The MAC client was already added, say when we have
    429 		 * different unicast addresses with the same vid.
    430 		 * Just increment the ref and we are done.
    431 		 */
    432 		if (grp->mbg_clients[i].mgb_client == mcip) {
    433 			grp->mbg_clients[i].mgb_client_ref++;
    434 			rw_exit(&mip->mi_rw_lock);
    435 			return (0);
    436 		} else if (grp->mbg_clients[i].mgb_client == NULL &&
    437 		    index == -1) {
    438 			index = i;
    439 		}
    440 	}
    441 	if (grp->mbg_nclients_alloc == grp->mbg_nclients) {
    442 		mac_bcast_grp_mcip_t	*new_clients;
    443 		uint_t			new_size = grp->mbg_nclients+1;
    444 
    445 		new_clients = kmem_zalloc(new_size *
    446 		    sizeof (mac_bcast_grp_mcip_t), KM_SLEEP);
    447 
    448 		if (grp->mbg_nclients > 0) {
    449 			ASSERT(grp->mbg_clients != NULL);
    450 			bcopy(grp->mbg_clients, new_clients, grp->mbg_nclients *
    451 			    sizeof (mac_bcast_grp_mcip_t));
    452 			kmem_free(grp->mbg_clients, grp->mbg_nclients *
    453 			    sizeof (mac_bcast_grp_mcip_t));
    454 		}
    455 
    456 		grp->mbg_clients = new_clients;
    457 		grp->mbg_nclients_alloc = new_size;
    458 		index = new_size - 1;
    459 	}
    460 
    461 	ASSERT(index != -1);
    462 	grp->mbg_clients[index].mgb_client = mcip;
    463 	grp->mbg_clients[index].mgb_client_ref = 1;
    464 	grp->mbg_nclients++;
    465 	/*
    466 	 * Since we're adding to the list of MAC clients using that group,
    467 	 * kick the generation count, which will allow mac_bcast_send()
    468 	 * to detect that condition after re-acquiring the lock.
    469 	 */
    470 	grp->mbg_clients_gen++;
    471 	rw_exit(&mip->mi_rw_lock);
    472 	return (0);
    473 
    474 fail:
    475 	if (prev_mi_addr != NULL) {
    476 		kmem_free(*prev_mi_addr, sizeof (mac_mcast_addrs_t));
    477 		*prev_mi_addr = NULL;
    478 		(void) mip->mi_multicst(mip->mi_driver, B_FALSE, addr);
    479 	}
    480 	if (prev_mci_addr != NULL) {
    481 		kmem_free(*prev_mci_addr, sizeof (mac_mcast_addrs_t));
    482 		*prev_mci_addr = NULL;
    483 	}
    484 	return (rc);
    485 }
    486 
    487 /*
    488  * Remove the specified MAC client from the group corresponding to
    489  * the specific broadcast or multicast address.
    490  *
    491  * Note: mac_bcast_delete() calls  mac_remove_flow() which
    492  * will call cv_wait for fe_refcnt to drop to 0. So this function
    493  * should not be called from interrupt or STREAMS context.
    494  */
    495 void
    496 mac_bcast_delete(mac_client_impl_t *mcip, const uint8_t *addr, uint16_t vid)
    497 {
    498 	mac_impl_t *mip = mcip->mci_mip;
    499 	mac_bcast_grp_t *grp = NULL, **prev;
    500 	size_t addr_len = mip->mi_type->mt_addr_length;
    501 	flow_entry_t *flent;
    502 	uint_t i;
    503 	mac_mcast_addrs_t	*maddr = NULL;
    504 	mac_mcast_addrs_t	**mprev;
    505 
    506 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
    507 
    508 	/* find the broadcast group. The list is protected by the perimeter */
    509 	prev = &mip->mi_bcast_grp;
    510 	for (grp = mip->mi_bcast_grp; grp != NULL; prev = &grp->mbg_next,
    511 	    grp = grp->mbg_next) {
    512 		if (bcmp(grp->mbg_addr, addr, addr_len) == 0 &&
    513 		    grp->mbg_vid == vid)
    514 			break;
    515 	}
    516 	ASSERT(grp != NULL);
    517 
    518 	/*
    519 	 * Remove the MAC client from the list of MAC clients associated
    520 	 * with that broadcast group.
    521 	 *
    522 	 * We mark the mbg_clients[] location corresponding to the removed MAC
    523 	 * client NULL and reuse that location when we add a new MAC client.
    524 	 */
    525 
    526 	rw_enter(&mip->mi_rw_lock, RW_WRITER);
    527 
    528 	for (i = 0; i < grp->mbg_nclients_alloc; i++) {
    529 		if (grp->mbg_clients[i].mgb_client == mcip)
    530 			break;
    531 	}
    532 
    533 	ASSERT(i < grp->mbg_nclients_alloc);
    534 	/*
    535 	 * If there are more references to this MAC client, then we let
    536 	 * it remain till it goes to 0.
    537 	 */
    538 	if (--grp->mbg_clients[i].mgb_client_ref > 0)
    539 		goto update_maddr;
    540 
    541 	grp->mbg_clients[i].mgb_client = NULL;
    542 	grp->mbg_clients[i].mgb_client_ref = 0;
    543 
    544 	/*
    545 	 * Since we're removing from the list of MAC clients using that group,
    546 	 * kick the generation count, which will allow mac_bcast_send()
    547 	 * to detect that condition.
    548 	 */
    549 	grp->mbg_clients_gen++;
    550 
    551 	if (--grp->mbg_nclients == 0) {
    552 		/*
    553 		 * The last MAC client of the group was just removed.
    554 		 * Unlink the current group from the list of groups
    555 		 * defined on top of the underlying NIC. The group
    556 		 * structure will stay around until the last reference
    557 		 * is dropped.
    558 		 */
    559 		*prev = grp->mbg_next;
    560 	}
    561 update_maddr:
    562 	rw_exit(&mip->mi_rw_lock);
    563 
    564 	if (grp->mbg_addrtype == MAC_ADDRTYPE_MULTICAST) {
    565 		mprev = &mcip->mci_mcast_addrs;
    566 		for (maddr = mcip->mci_mcast_addrs; maddr != NULL;
    567 		    mprev = &maddr->mma_next, maddr = maddr->mma_next) {
    568 			if (bcmp(grp->mbg_addr, maddr->mma_addr,
    569 			    mip->mi_type->mt_addr_length) == 0)
    570 				break;
    571 		}
    572 		ASSERT(maddr != NULL);
    573 		if (--maddr->mma_ref == 0) {
    574 			*mprev = maddr->mma_next;
    575 			maddr->mma_next = NULL;
    576 			kmem_free(maddr, sizeof (mac_mcast_addrs_t));
    577 		}
    578 
    579 		mprev = &mip->mi_mcast_addrs;
    580 		for (maddr = mip->mi_mcast_addrs; maddr != NULL;
    581 		    mprev = &maddr->mma_next, maddr = maddr->mma_next) {
    582 			if (bcmp(grp->mbg_addr, maddr->mma_addr,
    583 			    mip->mi_type->mt_addr_length) == 0)
    584 				break;
    585 		}
    586 		ASSERT(maddr != NULL);
    587 		if (--maddr->mma_ref == 0) {
    588 			(void) mip->mi_multicst(mip->mi_driver, B_FALSE, addr);
    589 			*mprev = maddr->mma_next;
    590 			maddr->mma_next = NULL;
    591 			kmem_free(maddr, sizeof (mac_mcast_addrs_t));
    592 		}
    593 	}
    594 
    595 	/*
    596 	 * If the group itself is being removed, remove the
    597 	 * corresponding flow from the underlying NIC.
    598 	 */
    599 	flent = grp->mbg_flow_ent;
    600 	if (grp->mbg_nclients == 0) {
    601 		mac_flow_remove(mip->mi_flow_tab, flent, B_FALSE);
    602 		mac_flow_wait(flent, FLOW_DRIVER_UPCALL);
    603 		FLOW_FINAL_REFRELE(flent);
    604 	}
    605 }
    606 
    607 /*
    608  * This will be called by a driver, such as aggr, when a port is added/removed
    609  * to add/remove the port to/from all the multcast addresses for that aggr.
    610  */
    611 void
    612 mac_bcast_refresh(mac_impl_t *mip, mac_multicst_t refresh_fn, void *arg,
    613     boolean_t add)
    614 {
    615 	mac_mcast_addrs_t *grp, *next;
    616 
    617 	ASSERT(refresh_fn != NULL);
    618 
    619 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
    620 
    621 	/*
    622 	 * Walk the multicast address list and call the refresh function for
    623 	 * each address.
    624 	 */
    625 
    626 	for (grp = mip->mi_mcast_addrs; grp != NULL; grp = next) {
    627 		/*
    628 		 * Save the next pointer just in case the refresh
    629 		 * function's action causes the group entry to be
    630 		 * freed.
    631 		 * We won't be adding to this list as part of the
    632 		 * refresh.
    633 		 */
    634 		next = grp->mma_next;
    635 		refresh_fn(arg, add, grp->mma_addr);
    636 	}
    637 }
    638 
    639 /*
    640  * Walk the MAC client's multicast address list and add/remove the addr/vid
    641  * ('arg' is 'flent') to all the addresses.
    642  */
    643 void
    644 mac_client_bcast_refresh(mac_client_impl_t *mcip, mac_multicst_t refresh_fn,
    645     void *arg, boolean_t add)
    646 {
    647 	mac_mcast_addrs_t *grp, *next;
    648 	mac_impl_t		*mip = mcip->mci_mip;
    649 
    650 	ASSERT(refresh_fn != NULL);
    651 
    652 	ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
    653 	/*
    654 	 * Walk the multicast address list and call the refresh function for
    655 	 * each address.
    656 	 * Broadcast addresses are not added or removed through the multicast
    657 	 * entry points, so don't include them as part of the refresh.
    658 	 */
    659 	for (grp = mcip->mci_mcast_addrs; grp != NULL; grp = next) {
    660 		/*
    661 		 * Save the next pointer just in case the refresh
    662 		 * function's action causes the group entry to be
    663 		 * freed.
    664 		 * We won't be adding to this list as part of the
    665 		 * refresh.
    666 		 */
    667 		next = grp->mma_next;
    668 		refresh_fn(arg, add, grp->mma_addr);
    669 	}
    670 }
    671