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