1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1676 jpk * Common Development and Distribution License (the "License"). 6 1676 jpk * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8485 Peter * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel /* Copyright (c) 1990 Mentat Inc. */ 26 0 stevel 27 0 stevel #include <sys/types.h> 28 0 stevel #include <sys/stream.h> 29 0 stevel #include <sys/dlpi.h> 30 0 stevel #include <sys/stropts.h> 31 0 stevel #include <sys/strsun.h> 32 0 stevel #include <sys/ddi.h> 33 0 stevel #include <sys/cmn_err.h> 34 2958 dr146992 #include <sys/sdt.h> 35 0 stevel #include <sys/zone.h> 36 0 stevel 37 0 stevel #include <sys/param.h> 38 0 stevel #include <sys/socket.h> 39 1676 jpk #include <sys/sockio.h> 40 0 stevel #include <net/if.h> 41 0 stevel #include <sys/systm.h> 42 5758 jarrett #include <sys/strsubr.h> 43 0 stevel #include <net/route.h> 44 0 stevel #include <netinet/in.h> 45 0 stevel #include <net/if_dl.h> 46 0 stevel #include <netinet/ip6.h> 47 0 stevel #include <netinet/icmp6.h> 48 0 stevel 49 0 stevel #include <inet/common.h> 50 0 stevel #include <inet/mi.h> 51 0 stevel #include <inet/nd.h> 52 0 stevel #include <inet/arp.h> 53 0 stevel #include <inet/ip.h> 54 0 stevel #include <inet/ip6.h> 55 0 stevel #include <inet/ip_if.h> 56 0 stevel #include <inet/ip_ndp.h> 57 0 stevel #include <inet/ip_multi.h> 58 0 stevel #include <inet/ipclassifier.h> 59 0 stevel #include <inet/ipsec_impl.h> 60 0 stevel #include <inet/sctp_ip.h> 61 0 stevel #include <inet/ip_listutils.h> 62 741 masputra #include <inet/udp_impl.h> 63 0 stevel 64 0 stevel /* igmpv3/mldv2 source filter manipulation */ 65 0 stevel static void ilm_bld_flists(conn_t *conn, void *arg); 66 0 stevel static void ilm_gen_filter(ilm_t *ilm, mcast_record_t *fmode, 67 0 stevel slist_t *flist); 68 0 stevel 69 11042 Erik static ilm_t *ilm_add(ill_t *ill, const in6_addr_t *group, 70 0 stevel ilg_stat_t ilgstat, mcast_record_t ilg_fmode, slist_t *ilg_flist, 71 8485 Peter zoneid_t zoneid); 72 0 stevel static void ilm_delete(ilm_t *ilm); 73 11042 Erik static int ilm_numentries(ill_t *, const in6_addr_t *); 74 11042 Erik 75 11042 Erik static ilm_t *ip_addmulti_serial(const in6_addr_t *, ill_t *, zoneid_t, 76 11042 Erik ilg_stat_t, mcast_record_t, slist_t *, int *); 77 11042 Erik static ilm_t *ip_addmulti_impl(const in6_addr_t *, ill_t *, 78 11042 Erik zoneid_t, ilg_stat_t, mcast_record_t, slist_t *, int *); 79 11042 Erik static int ip_delmulti_serial(ilm_t *, boolean_t, boolean_t); 80 11042 Erik static int ip_delmulti_impl(ilm_t *, boolean_t, boolean_t); 81 11042 Erik 82 11042 Erik static int ip_ll_multireq(ill_t *ill, const in6_addr_t *group, 83 11042 Erik t_uscalar_t); 84 11042 Erik static ilg_t *ilg_lookup(conn_t *, const in6_addr_t *, ipaddr_t ifaddr, 85 11042 Erik uint_t ifindex); 86 11042 Erik 87 11042 Erik static int ilg_add(conn_t *connp, const in6_addr_t *group, 88 11042 Erik ipaddr_t ifaddr, uint_t ifindex, ill_t *ill, mcast_record_t fmode, 89 11042 Erik const in6_addr_t *v6src); 90 0 stevel static void ilg_delete(conn_t *connp, ilg_t *ilg, const in6_addr_t *src); 91 0 stevel static mblk_t *ill_create_dl(ill_t *ill, uint32_t dl_primitive, 92 11042 Erik uint32_t *addr_lenp, uint32_t *addr_offp); 93 11042 Erik static int ip_opt_delete_group_excl(conn_t *connp, 94 11042 Erik const in6_addr_t *v6group, ipaddr_t ifaddr, uint_t ifindex, 95 11042 Erik mcast_record_t fmode, const in6_addr_t *v6src); 96 11042 Erik 97 11042 Erik static ilm_t *ilm_lookup(ill_t *, const in6_addr_t *, zoneid_t); 98 11042 Erik 99 11042 Erik static int ip_msfilter_ill(conn_t *, mblk_t *, const ip_ioctl_cmd_t *, 100 11042 Erik ill_t **); 101 11042 Erik 102 11042 Erik static void ilg_check_detach(conn_t *, ill_t *); 103 11042 Erik static void ilg_check_reattach(conn_t *); 104 0 stevel 105 0 stevel /* 106 0 stevel * MT notes: 107 0 stevel * 108 0 stevel * Multicast joins operate on both the ilg and ilm structures. Multiple 109 0 stevel * threads operating on an conn (socket) trying to do multicast joins 110 8485 Peter * need to synchronize when operating on the ilg. Multiple threads 111 0 stevel * potentially operating on different conn (socket endpoints) trying to 112 0 stevel * do multicast joins could eventually end up trying to manipulate the 113 11042 Erik * ilm simulatenously and need to synchronize on the access to the ilm. 114 11042 Erik * The access and lookup of the ilm, as well as other ill multicast state, 115 11042 Erik * is under ill_mcast_lock. 116 11042 Erik * The modifications and lookup of ilg entries is serialized using conn_ilg_lock 117 11042 Erik * rwlock. An ilg will not be freed until ilg_refcnt drops to zero. 118 11042 Erik * 119 11042 Erik * In some cases we hold ill_mcast_lock and then acquire conn_ilg_lock, but 120 11042 Erik * never the other way around. 121 0 stevel * 122 0 stevel * An ilm is an IP data structure used to track multicast join/leave. 123 0 stevel * An ilm is associated with a <multicast group, ipif> tuple in IPv4 and 124 0 stevel * with just <multicast group> in IPv6. ilm_refcnt is the number of ilg's 125 11042 Erik * referencing the ilm. 126 11042 Erik * The modifications and lookup of ilm entries is serialized using the 127 11042 Erik * ill_mcast_lock rwlock; that lock handles all the igmp/mld modifications 128 11042 Erik * of the ilm state. 129 11042 Erik * ilms are created / destroyed only as writer. ilms 130 11042 Erik * are not passed around. The datapath (anything outside of this file 131 11042 Erik * and igmp.c) use functions that do not return ilms - just the number 132 11042 Erik * of members. So we don't need a dynamic refcount of the number 133 0 stevel * of threads holding reference to an ilm. 134 0 stevel * 135 11042 Erik * In the cases where we serially access the ilg and ilm, which happens when 136 11042 Erik * we handle the applications requests to join or leave groups and sources, 137 11042 Erik * we use the ill_mcast_serializer mutex to ensure that a multithreaded 138 11042 Erik * application which does concurrent joins and/or leaves on the same group on 139 11042 Erik * the same socket always results in a consistent order for the ilg and ilm 140 11042 Erik * modifications. 141 0 stevel * 142 11042 Erik * When a multicast operation results in needing to send a message to 143 11042 Erik * the driver (to join/leave a L2 multicast address), we use ill_dlpi_queue() 144 11042 Erik * which serialized the DLPI requests. The IGMP/MLD code uses ill_mcast_queue() 145 11042 Erik * to send IGMP/MLD IP packet to avoid dropping the lock just to send a packet. 146 0 stevel */ 147 0 stevel 148 0 stevel #define GETSTRUCT(structure, number) \ 149 0 stevel ((structure *)mi_zalloc(sizeof (structure) * (number))) 150 0 stevel 151 11042 Erik /* 152 11042 Erik * Caller must ensure that the ilg has not been condemned 153 11042 Erik * The condemned flag is only set in ilg_delete under conn_ilg_lock. 154 11042 Erik * 155 11042 Erik * The caller must hold conn_ilg_lock as writer. 156 11042 Erik */ 157 11042 Erik static void 158 11042 Erik ilg_refhold(ilg_t *ilg) 159 11042 Erik { 160 11042 Erik ASSERT(ilg->ilg_refcnt != 0); 161 11042 Erik ASSERT(!ilg->ilg_condemned); 162 11042 Erik ASSERT(RW_WRITE_HELD(&ilg->ilg_connp->conn_ilg_lock)); 163 11042 Erik 164 11042 Erik ilg->ilg_refcnt++; 165 11042 Erik } 166 11042 Erik 167 11042 Erik static void 168 11042 Erik ilg_inactive(ilg_t *ilg) 169 11042 Erik { 170 11042 Erik ASSERT(ilg->ilg_ill == NULL); 171 11042 Erik ASSERT(ilg->ilg_ilm == NULL); 172 11042 Erik ASSERT(ilg->ilg_filter == NULL); 173 11042 Erik ASSERT(ilg->ilg_condemned); 174 11042 Erik 175 11042 Erik /* Unlink from list */ 176 11042 Erik *ilg->ilg_ptpn = ilg->ilg_next; 177 11042 Erik if (ilg->ilg_next != NULL) 178 11042 Erik ilg->ilg_next->ilg_ptpn = ilg->ilg_ptpn; 179 11042 Erik ilg->ilg_next = NULL; 180 11042 Erik ilg->ilg_ptpn = NULL; 181 11042 Erik 182 11042 Erik ilg->ilg_connp = NULL; 183 11042 Erik kmem_free(ilg, sizeof (*ilg)); 184 11042 Erik } 185 0 stevel 186 0 stevel /* 187 11042 Erik * The caller must hold conn_ilg_lock as writer. 188 11042 Erik */ 189 11042 Erik static void 190 11042 Erik ilg_refrele(ilg_t *ilg) 191 11042 Erik { 192 11042 Erik ASSERT(RW_WRITE_HELD(&ilg->ilg_connp->conn_ilg_lock)); 193 11042 Erik ASSERT(ilg->ilg_refcnt != 0); 194 11042 Erik if (--ilg->ilg_refcnt == 0) 195 11042 Erik ilg_inactive(ilg); 196 11042 Erik } 197 11042 Erik 198 11042 Erik /* 199 11042 Erik * Acquire reference on ilg and drop reference on held_ilg. 200 11042 Erik * In the case when held_ilg is the same as ilg we already have 201 11042 Erik * a reference, but the held_ilg might be condemned. In that case 202 11042 Erik * we avoid the ilg_refhold/rele so that we can assert in ire_refhold 203 11042 Erik * that the ilg isn't condemned. 204 11042 Erik */ 205 11042 Erik static void 206 11042 Erik ilg_transfer_hold(ilg_t *held_ilg, ilg_t *ilg) 207 11042 Erik { 208 11042 Erik if (held_ilg == ilg) 209 11042 Erik return; 210 11042 Erik 211 11042 Erik ilg_refhold(ilg); 212 11042 Erik if (held_ilg != NULL) 213 11042 Erik ilg_refrele(held_ilg); 214 11042 Erik } 215 11042 Erik 216 11042 Erik /* 217 11042 Erik * Allocate a new ilg_t and links it into conn_ilg. 218 11042 Erik * Returns NULL on failure, in which case `*errp' will be 219 8485 Peter * filled in with the reason. 220 0 stevel * 221 11042 Erik * Assumes connp->conn_ilg_lock is held. 222 0 stevel */ 223 0 stevel static ilg_t * 224 8485 Peter conn_ilg_alloc(conn_t *connp, int *errp) 225 0 stevel { 226 11042 Erik ilg_t *ilg; 227 0 stevel 228 11042 Erik ASSERT(RW_WRITE_HELD(&connp->conn_ilg_lock)); 229 0 stevel 230 8485 Peter /* 231 8485 Peter * If CONN_CLOSING is set, conn_ilg cleanup has begun and we must not 232 8485 Peter * create any ilgs. 233 8485 Peter */ 234 8485 Peter if (connp->conn_state_flags & CONN_CLOSING) { 235 8485 Peter *errp = EINVAL; 236 8485 Peter return (NULL); 237 8485 Peter } 238 8485 Peter 239 11042 Erik ilg = kmem_zalloc(sizeof (ilg_t), KM_NOSLEEP); 240 11042 Erik if (ilg == NULL) { 241 11042 Erik *errp = ENOMEM; 242 11042 Erik return (NULL); 243 0 stevel } 244 0 stevel 245 11042 Erik ilg->ilg_refcnt = 1; 246 11042 Erik 247 11042 Erik /* Insert at head */ 248 11042 Erik if (connp->conn_ilg != NULL) 249 11042 Erik connp->conn_ilg->ilg_ptpn = &ilg->ilg_next; 250 11042 Erik ilg->ilg_next = connp->conn_ilg; 251 11042 Erik ilg->ilg_ptpn = &connp->conn_ilg; 252 11042 Erik connp->conn_ilg = ilg; 253 11042 Erik 254 11042 Erik ilg->ilg_connp = connp; 255 11042 Erik return (ilg); 256 0 stevel } 257 0 stevel 258 0 stevel typedef struct ilm_fbld_s { 259 0 stevel ilm_t *fbld_ilm; 260 0 stevel int fbld_in_cnt; 261 0 stevel int fbld_ex_cnt; 262 0 stevel slist_t fbld_in; 263 0 stevel slist_t fbld_ex; 264 0 stevel boolean_t fbld_in_overflow; 265 0 stevel } ilm_fbld_t; 266 0 stevel 267 11042 Erik /* 268 11042 Erik * Caller must hold ill_mcast_lock 269 11042 Erik */ 270 0 stevel static void 271 11042 Erik ilm_bld_flists(conn_t *connp, void *arg) 272 0 stevel { 273 11042 Erik ilg_t *ilg; 274 0 stevel ilm_fbld_t *fbld = (ilm_fbld_t *)(arg); 275 0 stevel ilm_t *ilm = fbld->fbld_ilm; 276 0 stevel in6_addr_t *v6group = &ilm->ilm_v6addr; 277 0 stevel 278 11042 Erik if (connp->conn_ilg == NULL) 279 0 stevel return; 280 0 stevel 281 0 stevel /* 282 0 stevel * Since we can't break out of the ipcl_walk once started, we still 283 0 stevel * have to look at every conn. But if we've already found one 284 0 stevel * (EXCLUDE, NULL) list, there's no need to keep checking individual 285 0 stevel * ilgs--that will be our state. 286 0 stevel */ 287 0 stevel if (fbld->fbld_ex_cnt > 0 && fbld->fbld_ex.sl_numsrc == 0) 288 0 stevel return; 289 0 stevel 290 0 stevel /* 291 0 stevel * Check this conn's ilgs to see if any are interested in our 292 0 stevel * ilm (group, interface match). If so, update the master 293 0 stevel * include and exclude lists we're building in the fbld struct 294 0 stevel * with this ilg's filter info. 295 11042 Erik * 296 11042 Erik * Note that the caller has already serialized on the ill we care 297 11042 Erik * about. 298 0 stevel */ 299 11042 Erik ASSERT(MUTEX_HELD(&ilm->ilm_ill->ill_mcast_serializer)); 300 11042 Erik 301 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_READER); 302 11042 Erik for (ilg = connp->conn_ilg; ilg != NULL; ilg = ilg->ilg_next) { 303 11042 Erik if (ilg->ilg_condemned) 304 11042 Erik continue; 305 11042 Erik 306 11042 Erik /* 307 11042 Erik * Since we are under the ill_mcast_serializer we know 308 11042 Erik * that any ilg+ilm operations on this ilm have either 309 11042 Erik * not started or completed, except for the last ilg 310 11042 Erik * (the one that caused us to be called) which doesn't 311 11042 Erik * have ilg_ilm set yet. Hence we compare using ilg_ill 312 11042 Erik * and the address. 313 11042 Erik */ 314 0 stevel if ((ilg->ilg_ill == ilm->ilm_ill) && 315 0 stevel IN6_ARE_ADDR_EQUAL(&ilg->ilg_v6group, v6group)) { 316 0 stevel if (ilg->ilg_fmode == MODE_IS_INCLUDE) { 317 0 stevel fbld->fbld_in_cnt++; 318 0 stevel if (!fbld->fbld_in_overflow) 319 0 stevel l_union_in_a(&fbld->fbld_in, 320 0 stevel ilg->ilg_filter, 321 0 stevel &fbld->fbld_in_overflow); 322 0 stevel } else { 323 0 stevel fbld->fbld_ex_cnt++; 324 0 stevel /* 325 0 stevel * On the first exclude list, don't try to do 326 0 stevel * an intersection, as the master exclude list 327 0 stevel * is intentionally empty. If the master list 328 0 stevel * is still empty on later iterations, that 329 0 stevel * means we have at least one ilg with an empty 330 0 stevel * exclude list, so that should be reflected 331 0 stevel * when we take the intersection. 332 0 stevel */ 333 0 stevel if (fbld->fbld_ex_cnt == 1) { 334 0 stevel if (ilg->ilg_filter != NULL) 335 0 stevel l_copy(ilg->ilg_filter, 336 0 stevel &fbld->fbld_ex); 337 0 stevel } else { 338 0 stevel l_intersection_in_a(&fbld->fbld_ex, 339 0 stevel ilg->ilg_filter); 340 0 stevel } 341 0 stevel } 342 0 stevel /* there will only be one match, so break now. */ 343 0 stevel break; 344 0 stevel } 345 0 stevel } 346 11042 Erik rw_exit(&connp->conn_ilg_lock); 347 0 stevel } 348 0 stevel 349 11042 Erik /* 350 11042 Erik * Caller must hold ill_mcast_lock 351 11042 Erik */ 352 0 stevel static void 353 0 stevel ilm_gen_filter(ilm_t *ilm, mcast_record_t *fmode, slist_t *flist) 354 0 stevel { 355 0 stevel ilm_fbld_t fbld; 356 3448 dh155122 ip_stack_t *ipst = ilm->ilm_ipst; 357 0 stevel 358 0 stevel fbld.fbld_ilm = ilm; 359 0 stevel fbld.fbld_in_cnt = fbld.fbld_ex_cnt = 0; 360 0 stevel fbld.fbld_in.sl_numsrc = fbld.fbld_ex.sl_numsrc = 0; 361 0 stevel fbld.fbld_in_overflow = B_FALSE; 362 0 stevel 363 0 stevel /* first, construct our master include and exclude lists */ 364 3448 dh155122 ipcl_walk(ilm_bld_flists, (caddr_t)&fbld, ipst); 365 0 stevel 366 0 stevel /* now use those master lists to generate the interface filter */ 367 0 stevel 368 0 stevel /* if include list overflowed, filter is (EXCLUDE, NULL) */ 369 0 stevel if (fbld.fbld_in_overflow) { 370 0 stevel *fmode = MODE_IS_EXCLUDE; 371 0 stevel flist->sl_numsrc = 0; 372 0 stevel return; 373 0 stevel } 374 0 stevel 375 0 stevel /* if nobody interested, interface filter is (INCLUDE, NULL) */ 376 0 stevel if (fbld.fbld_in_cnt == 0 && fbld.fbld_ex_cnt == 0) { 377 0 stevel *fmode = MODE_IS_INCLUDE; 378 0 stevel flist->sl_numsrc = 0; 379 0 stevel return; 380 0 stevel } 381 0 stevel 382 0 stevel /* 383 0 stevel * If there are no exclude lists, then the interface filter 384 0 stevel * is INCLUDE, with its filter list equal to fbld_in. A single 385 0 stevel * exclude list makes the interface filter EXCLUDE, with its 386 0 stevel * filter list equal to (fbld_ex - fbld_in). 387 0 stevel */ 388 0 stevel if (fbld.fbld_ex_cnt == 0) { 389 0 stevel *fmode = MODE_IS_INCLUDE; 390 0 stevel l_copy(&fbld.fbld_in, flist); 391 0 stevel } else { 392 0 stevel *fmode = MODE_IS_EXCLUDE; 393 0 stevel l_difference(&fbld.fbld_ex, &fbld.fbld_in, flist); 394 0 stevel } 395 0 stevel } 396 0 stevel 397 11042 Erik /* 398 11042 Erik * Caller must hold ill_mcast_lock 399 11042 Erik */ 400 0 stevel static int 401 11042 Erik ilm_update_add(ilm_t *ilm, ilg_stat_t ilgstat, slist_t *ilg_flist) 402 0 stevel { 403 0 stevel mcast_record_t fmode; 404 0 stevel slist_t *flist; 405 0 stevel boolean_t fdefault; 406 0 stevel char buf[INET6_ADDRSTRLEN]; 407 11042 Erik ill_t *ill = ilm->ilm_ill; 408 0 stevel 409 0 stevel /* 410 0 stevel * There are several cases where the ilm's filter state 411 0 stevel * defaults to (EXCLUDE, NULL): 412 0 stevel * - we've had previous joins without associated ilgs 413 0 stevel * - this join has no associated ilg 414 0 stevel * - the ilg's filter state is (EXCLUDE, NULL) 415 0 stevel */ 416 0 stevel fdefault = (ilm->ilm_no_ilg_cnt > 0) || 417 0 stevel (ilgstat == ILGSTAT_NONE) || SLIST_IS_EMPTY(ilg_flist); 418 0 stevel 419 0 stevel /* attempt mallocs (if needed) before doing anything else */ 420 0 stevel if ((flist = l_alloc()) == NULL) 421 0 stevel return (ENOMEM); 422 0 stevel if (!fdefault && ilm->ilm_filter == NULL) { 423 0 stevel ilm->ilm_filter = l_alloc(); 424 0 stevel if (ilm->ilm_filter == NULL) { 425 0 stevel l_free(flist); 426 0 stevel return (ENOMEM); 427 0 stevel } 428 0 stevel } 429 0 stevel 430 0 stevel if (ilgstat != ILGSTAT_CHANGE) 431 0 stevel ilm->ilm_refcnt++; 432 0 stevel 433 0 stevel if (ilgstat == ILGSTAT_NONE) 434 0 stevel ilm->ilm_no_ilg_cnt++; 435 0 stevel 436 0 stevel /* 437 0 stevel * Determine new filter state. If it's not the default 438 0 stevel * (EXCLUDE, NULL), we must walk the conn list to find 439 0 stevel * any ilgs interested in this group, and re-build the 440 0 stevel * ilm filter. 441 0 stevel */ 442 0 stevel if (fdefault) { 443 0 stevel fmode = MODE_IS_EXCLUDE; 444 0 stevel flist->sl_numsrc = 0; 445 0 stevel } else { 446 0 stevel ilm_gen_filter(ilm, &fmode, flist); 447 0 stevel } 448 0 stevel 449 0 stevel /* make sure state actually changed; nothing to do if not. */ 450 0 stevel if ((ilm->ilm_fmode == fmode) && 451 0 stevel !lists_are_different(ilm->ilm_filter, flist)) { 452 0 stevel l_free(flist); 453 0 stevel return (0); 454 0 stevel } 455 0 stevel 456 0 stevel /* send the state change report */ 457 4459 kcpoon if (!IS_LOOPBACK(ill)) { 458 11042 Erik if (ill->ill_isv6) 459 0 stevel mld_statechange(ilm, fmode, flist); 460 0 stevel else 461 0 stevel igmp_statechange(ilm, fmode, flist); 462 0 stevel } 463 0 stevel 464 0 stevel /* update the ilm state */ 465 0 stevel ilm->ilm_fmode = fmode; 466 0 stevel if (flist->sl_numsrc > 0) 467 0 stevel l_copy(flist, ilm->ilm_filter); 468 0 stevel else 469 0 stevel CLEAR_SLIST(ilm->ilm_filter); 470 0 stevel 471 0 stevel ip1dbg(("ilm_update: new if filter mode %d, group %s\n", ilm->ilm_fmode, 472 0 stevel inet_ntop(AF_INET6, &ilm->ilm_v6addr, buf, sizeof (buf)))); 473 0 stevel 474 0 stevel l_free(flist); 475 0 stevel return (0); 476 0 stevel } 477 0 stevel 478 11042 Erik /* 479 11042 Erik * Caller must hold ill_mcast_lock 480 11042 Erik */ 481 0 stevel static int 482 11042 Erik ilm_update_del(ilm_t *ilm) 483 0 stevel { 484 0 stevel mcast_record_t fmode; 485 0 stevel slist_t *flist; 486 11042 Erik ill_t *ill = ilm->ilm_ill; 487 0 stevel 488 0 stevel ip1dbg(("ilm_update_del: still %d left; updating state\n", 489 0 stevel ilm->ilm_refcnt)); 490 0 stevel 491 0 stevel if ((flist = l_alloc()) == NULL) 492 0 stevel return (ENOMEM); 493 0 stevel 494 0 stevel /* 495 0 stevel * If present, the ilg in question has already either been 496 0 stevel * updated or removed from our list; so all we need to do 497 0 stevel * now is walk the list to update the ilm filter state. 498 0 stevel * 499 0 stevel * Skip the list walk if we have any no-ilg joins, which 500 0 stevel * cause the filter state to revert to (EXCLUDE, NULL). 501 0 stevel */ 502 0 stevel if (ilm->ilm_no_ilg_cnt != 0) { 503 0 stevel fmode = MODE_IS_EXCLUDE; 504 0 stevel flist->sl_numsrc = 0; 505 0 stevel } else { 506 0 stevel ilm_gen_filter(ilm, &fmode, flist); 507 0 stevel } 508 0 stevel 509 0 stevel /* check to see if state needs to be updated */ 510 0 stevel if ((ilm->ilm_fmode == fmode) && 511 0 stevel (!lists_are_different(ilm->ilm_filter, flist))) { 512 0 stevel l_free(flist); 513 0 stevel return (0); 514 0 stevel } 515 0 stevel 516 4459 kcpoon if (!IS_LOOPBACK(ill)) { 517 11042 Erik if (ill->ill_isv6) 518 0 stevel mld_statechange(ilm, fmode, flist); 519 0 stevel else 520 0 stevel igmp_statechange(ilm, fmode, flist); 521 0 stevel } 522 0 stevel 523 0 stevel ilm->ilm_fmode = fmode; 524 0 stevel if (flist->sl_numsrc > 0) { 525 0 stevel if (ilm->ilm_filter == NULL) { 526 0 stevel ilm->ilm_filter = l_alloc(); 527 0 stevel if (ilm->ilm_filter == NULL) { 528 0 stevel char buf[INET6_ADDRSTRLEN]; 529 0 stevel ip1dbg(("ilm_update_del: failed to alloc ilm " 530 0 stevel "filter; no source filtering for %s on %s", 531 0 stevel inet_ntop(AF_INET6, &ilm->ilm_v6addr, 532 0 stevel buf, sizeof (buf)), ill->ill_name)); 533 0 stevel ilm->ilm_fmode = MODE_IS_EXCLUDE; 534 0 stevel l_free(flist); 535 0 stevel return (0); 536 0 stevel } 537 0 stevel } 538 0 stevel l_copy(flist, ilm->ilm_filter); 539 0 stevel } else { 540 0 stevel CLEAR_SLIST(ilm->ilm_filter); 541 0 stevel } 542 0 stevel 543 0 stevel l_free(flist); 544 0 stevel return (0); 545 0 stevel } 546 0 stevel 547 0 stevel /* 548 11042 Erik * Create/update the ilm for the group/ill. Used by other parts of IP to 549 11042 Erik * do the ILGSTAT_NONE (no ilg), MODE_IS_EXCLUDE, with no slist join. 550 11042 Erik * Returns with a refhold on the ilm. 551 11042 Erik * 552 11042 Erik * The unspecified address means all multicast addresses for in both the 553 11042 Erik * case of IPv4 and IPv6. 554 11042 Erik * 555 11042 Erik * The caller should have already mapped an IPMP under ill to the upper. 556 0 stevel */ 557 11042 Erik ilm_t * 558 11042 Erik ip_addmulti(const in6_addr_t *v6group, ill_t *ill, zoneid_t zoneid, 559 11042 Erik int *errorp) 560 0 stevel { 561 11042 Erik ilm_t *ilm; 562 0 stevel 563 11042 Erik /* Acquire serializer to keep assert in ilm_bld_flists happy */ 564 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 565 11042 Erik ilm = ip_addmulti_serial(v6group, ill, zoneid, ILGSTAT_NONE, 566 11042 Erik MODE_IS_EXCLUDE, NULL, errorp); 567 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 568 11042 Erik return (ilm); 569 0 stevel } 570 0 stevel 571 0 stevel /* 572 11042 Erik * Create/update the ilm for the group/ill. If ILGSTAT_CHANGE is not set 573 11042 Erik * then this returns with a refhold on the ilm. 574 8485 Peter * 575 11042 Erik * Internal routine which assumes the caller has already acquired 576 11042 Erik * ill_multi_serializer. 577 11042 Erik * 578 11042 Erik * The unspecified address means all multicast addresses for in both the 579 11042 Erik * case of IPv4 and IPv6. 580 0 stevel * 581 0 stevel * ilgstat tells us if there's an ilg associated with this join, 582 0 stevel * and if so, if it's a new ilg or a change to an existing one. 583 0 stevel * ilg_fmode and ilg_flist give us the current filter state of 584 0 stevel * the ilg (and will be EXCLUDE {NULL} in the case of no ilg). 585 11042 Erik * 586 11042 Erik * The caller should have already mapped an IPMP under ill to the upper. 587 0 stevel */ 588 11042 Erik static ilm_t * 589 11042 Erik ip_addmulti_serial(const in6_addr_t *v6group, ill_t *ill, zoneid_t zoneid, 590 11042 Erik ilg_stat_t ilgstat, mcast_record_t ilg_fmode, slist_t *ilg_flist, 591 11042 Erik int *errorp) 592 11042 Erik { 593 11042 Erik ilm_t *ilm; 594 11042 Erik 595 11042 Erik ASSERT(MUTEX_HELD(&ill->ill_mcast_serializer)); 596 11042 Erik 597 11042 Erik if (ill->ill_isv6) { 598 11042 Erik if (!IN6_IS_ADDR_MULTICAST(v6group) && 599 11042 Erik !IN6_IS_ADDR_UNSPECIFIED(v6group)) { 600 11042 Erik *errorp = EINVAL; 601 11042 Erik return (NULL); 602 11042 Erik } 603 11042 Erik } else { 604 11042 Erik if (IN6_IS_ADDR_V4MAPPED(v6group)) { 605 11042 Erik ipaddr_t v4group; 606 11042 Erik 607 11042 Erik IN6_V4MAPPED_TO_IPADDR(v6group, v4group); 608 11042 Erik if (!CLASSD(v4group)) { 609 11042 Erik *errorp = EINVAL; 610 11042 Erik return (NULL); 611 11042 Erik } 612 11042 Erik } else if (!IN6_IS_ADDR_UNSPECIFIED(v6group)) { 613 11042 Erik *errorp = EINVAL; 614 11042 Erik return (NULL); 615 11042 Erik } 616 11042 Erik } 617 11042 Erik 618 11042 Erik if (IS_UNDER_IPMP(ill)) { 619 11042 Erik *errorp = EINVAL; 620 11042 Erik return (NULL); 621 11042 Erik } 622 11042 Erik 623 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_WRITER); 624 11042 Erik /* 625 11042 Erik * We do the equivalent of a lookup by checking after we get the lock 626 11042 Erik * This is needed since the ill could have been condemned after 627 11042 Erik * we looked it up, and we need to check condemned after we hold 628 11042 Erik * ill_mcast_lock to synchronize with the unplumb code. 629 11042 Erik */ 630 11042 Erik if (ill->ill_state_flags & ILL_CONDEMNED) { 631 11042 Erik rw_exit(&ill->ill_mcast_lock); 632 11042 Erik *errorp = ENXIO; 633 11042 Erik return (NULL); 634 11042 Erik } 635 11042 Erik ilm = ip_addmulti_impl(v6group, ill, zoneid, ilgstat, ilg_fmode, 636 11042 Erik ilg_flist, errorp); 637 11042 Erik rw_exit(&ill->ill_mcast_lock); 638 11042 Erik 639 11042 Erik /* Send any deferred/queued DLPI or IP packets */ 640 11042 Erik ill_mcast_send_queued(ill); 641 11042 Erik ill_dlpi_send_queued(ill); 642 11042 Erik ill_mcast_timer_start(ill->ill_ipst); 643 11042 Erik return (ilm); 644 11042 Erik } 645 11042 Erik 646 11042 Erik static ilm_t * 647 11042 Erik ip_addmulti_impl(const in6_addr_t *v6group, ill_t *ill, zoneid_t zoneid, 648 11042 Erik ilg_stat_t ilgstat, mcast_record_t ilg_fmode, slist_t *ilg_flist, 649 11042 Erik int *errorp) 650 0 stevel { 651 0 stevel ilm_t *ilm; 652 11042 Erik int ret = 0; 653 0 stevel 654 11042 Erik ASSERT(RW_WRITE_HELD(&ill->ill_mcast_lock)); 655 11042 Erik *errorp = 0; 656 8485 Peter 657 8485 Peter /* 658 8485 Peter * An ilm is uniquely identified by the tuple of (group, ill) where 659 8485 Peter * `group' is the multicast group address, and `ill' is the interface 660 8485 Peter * on which it is currently joined. 661 8485 Peter */ 662 0 stevel 663 11042 Erik ilm = ilm_lookup(ill, v6group, zoneid); 664 11042 Erik if (ilm != NULL) { 665 11042 Erik /* ilm_update_add bumps ilm_refcnt unless ILGSTAT_CHANGE */ 666 11042 Erik ret = ilm_update_add(ilm, ilgstat, ilg_flist); 667 11042 Erik if (ret == 0) 668 11042 Erik return (ilm); 669 11042 Erik 670 11042 Erik *errorp = ret; 671 11042 Erik return (NULL); 672 11042 Erik } 673 11042 Erik 674 11042 Erik /* 675 11042 Erik * The callers checks on the ilg and the ilg+ilm consistency under 676 11042 Erik * ill_mcast_serializer ensures that we can not have ILGSTAT_CHANGE 677 11042 Erik * and no ilm. 678 11042 Erik */ 679 11042 Erik ASSERT(ilgstat != ILGSTAT_CHANGE); 680 11042 Erik ilm = ilm_add(ill, v6group, ilgstat, ilg_fmode, ilg_flist, zoneid); 681 11042 Erik if (ilm == NULL) { 682 11042 Erik *errorp = ENOMEM; 683 11042 Erik return (NULL); 684 11042 Erik } 685 0 stevel 686 0 stevel if (IN6_IS_ADDR_UNSPECIFIED(v6group)) { 687 0 stevel /* 688 11042 Erik * If we have more then one we should not tell the driver 689 11042 Erik * to join this time. 690 0 stevel */ 691 11042 Erik if (ilm_numentries(ill, v6group) == 1) { 692 11042 Erik ret = ill_join_allmulti(ill); 693 11042 Erik } 694 11042 Erik } else { 695 11042 Erik if (!IS_LOOPBACK(ill)) { 696 11042 Erik if (ill->ill_isv6) 697 11042 Erik mld_joingroup(ilm); 698 11042 Erik else 699 11042 Erik igmp_joingroup(ilm); 700 11042 Erik } 701 11042 Erik 702 11042 Erik /* 703 11042 Erik * If we have more then one we should not tell the driver 704 11042 Erik * to join this time. 705 11042 Erik */ 706 11042 Erik if (ilm_numentries(ill, v6group) == 1) { 707 11042 Erik ret = ip_ll_multireq(ill, v6group, DL_ENABMULTI_REQ); 708 11042 Erik } 709 0 stevel } 710 11042 Erik if (ret != 0) { 711 11042 Erik if (ret == ENETDOWN) { 712 11042 Erik char buf[INET6_ADDRSTRLEN]; 713 0 stevel 714 11042 Erik ip0dbg(("ip_addmulti: ENETDOWN for %s on %s", 715 11042 Erik inet_ntop(AF_INET6, &ilm->ilm_v6addr, 716 11042 Erik buf, sizeof (buf)), ill->ill_name)); 717 11042 Erik } 718 0 stevel ilm_delete(ilm); 719 11042 Erik *errorp = ret; 720 11042 Erik return (NULL); 721 11042 Erik } else { 722 11042 Erik return (ilm); 723 11042 Erik } 724 0 stevel } 725 0 stevel 726 0 stevel /* 727 11042 Erik * Send a multicast request to the driver for enabling or disabling 728 11042 Erik * multicast reception for v6groupp address. The caller has already 729 11042 Erik * checked whether it is appropriate to send one or not. 730 11042 Erik * 731 11042 Erik * For IPMP we switch to the cast_ill since it has the right hardware 732 11042 Erik * information. 733 9073 Cathy */ 734 11042 Erik static int 735 11042 Erik ip_ll_send_multireq(ill_t *ill, const in6_addr_t *v6groupp, t_uscalar_t prim) 736 0 stevel { 737 0 stevel mblk_t *mp; 738 0 stevel uint32_t addrlen, addroff; 739 11042 Erik ill_t *release_ill = NULL; 740 11042 Erik int err = 0; 741 0 stevel 742 11042 Erik ASSERT(RW_LOCK_HELD(&ill->ill_mcast_lock)); 743 8485 Peter 744 11042 Erik if (IS_IPMP(ill)) { 745 11042 Erik /* On the upper IPMP ill. */ 746 11042 Erik release_ill = ipmp_illgrp_hold_cast_ill(ill->ill_grp); 747 11042 Erik if (release_ill == NULL) { 748 11042 Erik /* 749 11042 Erik * Avoid sending it down to the ipmpstub. 750 11042 Erik * We will be called again once the members of the 751 11042 Erik * group are in place 752 11042 Erik */ 753 11042 Erik ip1dbg(("ip_ll_send_multireq: no cast_ill for %s %d\n", 754 11042 Erik ill->ill_name, ill->ill_isv6)); 755 11042 Erik return (0); 756 11042 Erik } 757 11042 Erik ill = release_ill; 758 11042 Erik } 759 11042 Erik /* Create a DL_ENABMULTI_REQ or DL_DISABMULTI_REQ message. */ 760 11042 Erik mp = ill_create_dl(ill, prim, &addrlen, &addroff); 761 11042 Erik if (mp == NULL) { 762 11042 Erik err = ENOMEM; 763 11042 Erik goto done; 764 11042 Erik } 765 0 stevel 766 11042 Erik mp = ndp_mcastreq(ill, v6groupp, addrlen, addroff, mp); 767 11042 Erik if (mp == NULL) { 768 11042 Erik ip0dbg(("null from ndp_mcastreq(ill %s)\n", ill->ill_name)); 769 11042 Erik err = ENOMEM; 770 11042 Erik goto done; 771 11042 Erik } 772 9073 Cathy 773 11042 Erik switch (((union DL_primitives *)mp->b_rptr)->dl_primitive) { 774 11042 Erik case DL_ENABMULTI_REQ: 775 11042 Erik mutex_enter(&ill->ill_lock); 776 9073 Cathy /* Track the state if this is the first enabmulti */ 777 9073 Cathy if (ill->ill_dlpi_multicast_state == IDS_UNKNOWN) 778 9073 Cathy ill->ill_dlpi_multicast_state = IDS_INPROGRESS; 779 11042 Erik mutex_exit(&ill->ill_lock); 780 11042 Erik break; 781 0 stevel } 782 11042 Erik ill_dlpi_queue(ill, mp); 783 11042 Erik done: 784 11042 Erik if (release_ill != NULL) 785 11042 Erik ill_refrele(release_ill); 786 11042 Erik return (err); 787 0 stevel } 788 0 stevel 789 0 stevel /* 790 0 stevel * Send a multicast request to the driver for enabling multicast 791 0 stevel * membership for v6group if appropriate. 792 0 stevel */ 793 0 stevel static int 794 11042 Erik ip_ll_multireq(ill_t *ill, const in6_addr_t *v6groupp, t_uscalar_t prim) 795 0 stevel { 796 0 stevel if (ill->ill_net_type != IRE_IF_RESOLVER || 797 11042 Erik ill->ill_ipif->ipif_flags & IPIF_POINTOPOINT) { 798 11042 Erik ip1dbg(("ip_ll_multireq: not resolver\n")); 799 0 stevel return (0); /* Must be IRE_IF_NORESOLVER */ 800 0 stevel } 801 0 stevel 802 0 stevel if (ill->ill_phyint->phyint_flags & PHYI_MULTI_BCAST) { 803 11042 Erik ip1dbg(("ip_ll_multireq: MULTI_BCAST\n")); 804 0 stevel return (0); 805 0 stevel } 806 11042 Erik return (ip_ll_send_multireq(ill, v6groupp, prim)); 807 0 stevel } 808 0 stevel 809 0 stevel /* 810 11042 Erik * Delete the ilm. Used by other parts of IP for the case of no_ilg/leaving 811 11042 Erik * being true. 812 0 stevel */ 813 0 stevel int 814 11042 Erik ip_delmulti(ilm_t *ilm) 815 0 stevel { 816 11042 Erik ill_t *ill = ilm->ilm_ill; 817 11042 Erik int error; 818 11042 Erik 819 11042 Erik /* Acquire serializer to keep assert in ilm_bld_flists happy */ 820 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 821 11042 Erik error = ip_delmulti_serial(ilm, B_TRUE, B_TRUE); 822 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 823 11042 Erik return (error); 824 11042 Erik } 825 11042 Erik 826 11042 Erik 827 11042 Erik /* 828 11042 Erik * Delete the ilm. 829 11042 Erik * Assumes ill_multi_serializer is held by the caller. 830 11042 Erik */ 831 11042 Erik static int 832 11042 Erik ip_delmulti_serial(ilm_t *ilm, boolean_t no_ilg, boolean_t leaving) 833 11042 Erik { 834 11042 Erik ill_t *ill = ilm->ilm_ill; 835 11042 Erik int ret; 836 11042 Erik 837 11042 Erik ASSERT(MUTEX_HELD(&ill->ill_mcast_serializer)); 838 11042 Erik ASSERT(!(IS_UNDER_IPMP(ill))); 839 11042 Erik 840 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_WRITER); 841 11042 Erik ret = ip_delmulti_impl(ilm, no_ilg, leaving); 842 11042 Erik rw_exit(&ill->ill_mcast_lock); 843 11042 Erik /* Send any deferred/queued DLPI or IP packets */ 844 11042 Erik ill_mcast_send_queued(ill); 845 11042 Erik ill_dlpi_send_queued(ill); 846 11042 Erik ill_mcast_timer_start(ill->ill_ipst); 847 11042 Erik 848 11042 Erik return (ret); 849 11042 Erik } 850 11042 Erik 851 11042 Erik static int 852 11042 Erik ip_delmulti_impl(ilm_t *ilm, boolean_t no_ilg, boolean_t leaving) 853 11042 Erik { 854 11042 Erik ill_t *ill = ilm->ilm_ill; 855 11042 Erik int error; 856 0 stevel in6_addr_t v6group; 857 0 stevel 858 11042 Erik ASSERT(RW_WRITE_HELD(&ill->ill_mcast_lock)); 859 0 stevel 860 0 stevel /* Update counters */ 861 0 stevel if (no_ilg) 862 0 stevel ilm->ilm_no_ilg_cnt--; 863 0 stevel 864 0 stevel if (leaving) 865 0 stevel ilm->ilm_refcnt--; 866 0 stevel 867 0 stevel if (ilm->ilm_refcnt > 0) 868 11042 Erik return (ilm_update_del(ilm)); 869 0 stevel 870 11042 Erik v6group = ilm->ilm_v6addr; 871 11042 Erik 872 11042 Erik if (IN6_IS_ADDR_UNSPECIFIED(&ilm->ilm_v6addr)) { 873 0 stevel ilm_delete(ilm); 874 0 stevel /* 875 11042 Erik * If we have some left then one we should not tell the driver 876 11042 Erik * to leave. 877 0 stevel */ 878 11042 Erik if (ilm_numentries(ill, &v6group) != 0) 879 0 stevel return (0); 880 0 stevel 881 11042 Erik ill_leave_allmulti(ill); 882 8485 Peter 883 8023 Phil return (0); 884 0 stevel } 885 0 stevel 886 11042 Erik if (!IS_LOOPBACK(ill)) { 887 11042 Erik if (ill->ill_isv6) 888 11042 Erik mld_leavegroup(ilm); 889 11042 Erik else 890 11042 Erik igmp_leavegroup(ilm); 891 11042 Erik } 892 0 stevel 893 0 stevel ilm_delete(ilm); 894 0 stevel /* 895 11042 Erik * If we have some left then one we should not tell the driver 896 11042 Erik * to leave. 897 0 stevel */ 898 11042 Erik if (ilm_numentries(ill, &v6group) != 0) 899 0 stevel return (0); 900 11042 Erik 901 11042 Erik error = ip_ll_multireq(ill, &v6group, DL_DISABMULTI_REQ); 902 11042 Erik /* We ignore the case when ill_dl_up is not set */ 903 11042 Erik if (error == ENETDOWN) { 904 11042 Erik char buf[INET6_ADDRSTRLEN]; 905 11042 Erik 906 11042 Erik ip0dbg(("ip_delmulti: ENETDOWN for %s on %s", 907 11042 Erik inet_ntop(AF_INET6, &v6group, buf, sizeof (buf)), 908 11042 Erik ill->ill_name)); 909 11042 Erik } 910 11042 Erik return (error); 911 0 stevel } 912 0 stevel 913 0 stevel /* 914 11042 Erik * Make the driver pass up all multicast packets. 915 0 stevel */ 916 0 stevel int 917 8023 Phil ill_join_allmulti(ill_t *ill) 918 8023 Phil { 919 11042 Erik mblk_t *promiscon_mp, *promiscoff_mp = NULL; 920 0 stevel uint32_t addrlen, addroff; 921 11042 Erik ill_t *release_ill = NULL; 922 0 stevel 923 11042 Erik ASSERT(RW_WRITE_HELD(&ill->ill_mcast_lock)); 924 0 stevel 925 11077 Erik if (IS_LOOPBACK(ill)) 926 11077 Erik return (0); 927 11077 Erik 928 4770 meem if (!ill->ill_dl_up) { 929 0 stevel /* 930 0 stevel * Nobody there. All multicast addresses will be re-joined 931 0 stevel * when we get the DL_BIND_ACK bringing the interface up. 932 0 stevel */ 933 11042 Erik return (ENETDOWN); 934 0 stevel } 935 0 stevel 936 11042 Erik if (IS_IPMP(ill)) { 937 11042 Erik /* On the upper IPMP ill. */ 938 11042 Erik release_ill = ipmp_illgrp_hold_cast_ill(ill->ill_grp); 939 11042 Erik if (release_ill == NULL) { 940 11042 Erik /* 941 11042 Erik * Avoid sending it down to the ipmpstub. 942 11042 Erik * We will be called again once the members of the 943 11042 Erik * group are in place 944 11042 Erik */ 945 11042 Erik ip1dbg(("ill_join_allmulti: no cast_ill for %s %d\n", 946 11042 Erik ill->ill_name, ill->ill_isv6)); 947 11042 Erik return (0); 948 11042 Erik } 949 11042 Erik ill = release_ill; 950 11042 Erik if (!ill->ill_dl_up) { 951 11042 Erik ill_refrele(ill); 952 11042 Erik return (ENETDOWN); 953 11042 Erik } 954 11042 Erik } 955 0 stevel 956 0 stevel /* 957 8023 Phil * Create a DL_PROMISCON_REQ message and send it directly to the DLPI 958 8023 Phil * provider. We don't need to do this for certain media types for 959 8023 Phil * which we never need to turn promiscuous mode on. While we're here, 960 8023 Phil * pre-allocate a DL_PROMISCOFF_REQ message to make sure that 961 8023 Phil * ill_leave_allmulti() will not fail due to low memory conditions. 962 0 stevel */ 963 0 stevel if ((ill->ill_net_type == IRE_IF_RESOLVER) && 964 0 stevel !(ill->ill_phyint->phyint_flags & PHYI_MULTI_BCAST)) { 965 8023 Phil promiscon_mp = ill_create_dl(ill, DL_PROMISCON_REQ, 966 11042 Erik &addrlen, &addroff); 967 11042 Erik if (ill->ill_promiscoff_mp == NULL) 968 11042 Erik promiscoff_mp = ill_create_dl(ill, DL_PROMISCOFF_REQ, 969 11042 Erik &addrlen, &addroff); 970 11042 Erik if (promiscon_mp == NULL || 971 11042 Erik (ill->ill_promiscoff_mp == NULL && promiscoff_mp == NULL)) { 972 8023 Phil freemsg(promiscon_mp); 973 8023 Phil freemsg(promiscoff_mp); 974 11042 Erik if (release_ill != NULL) 975 11042 Erik ill_refrele(release_ill); 976 8023 Phil return (ENOMEM); 977 8023 Phil } 978 11042 Erik if (ill->ill_promiscoff_mp == NULL) 979 11042 Erik ill->ill_promiscoff_mp = promiscoff_mp; 980 11042 Erik ill_dlpi_queue(ill, promiscon_mp); 981 0 stevel } 982 11042 Erik if (release_ill != NULL) 983 11042 Erik ill_refrele(release_ill); 984 0 stevel return (0); 985 0 stevel } 986 0 stevel 987 0 stevel /* 988 0 stevel * Make the driver stop passing up all multicast packets 989 0 stevel */ 990 8023 Phil void 991 8023 Phil ill_leave_allmulti(ill_t *ill) 992 8023 Phil { 993 8485 Peter mblk_t *promiscoff_mp; 994 11042 Erik ill_t *release_ill = NULL; 995 8023 Phil 996 11042 Erik ASSERT(RW_WRITE_HELD(&ill->ill_mcast_lock)); 997 11077 Erik 998 11077 Erik if (IS_LOOPBACK(ill)) 999 11077 Erik return; 1000 0 stevel 1001 4770 meem if (!ill->ill_dl_up) { 1002 0 stevel /* 1003 0 stevel * Nobody there. All multicast addresses will be re-joined 1004 0 stevel * when we get the DL_BIND_ACK bringing the interface up. 1005 0 stevel */ 1006 8023 Phil return; 1007 0 stevel } 1008 0 stevel 1009 11042 Erik if (IS_IPMP(ill)) { 1010 11042 Erik /* On the upper IPMP ill. */ 1011 11042 Erik release_ill = ipmp_illgrp_hold_cast_ill(ill->ill_grp); 1012 11042 Erik if (release_ill == NULL) { 1013 11042 Erik /* 1014 11042 Erik * Avoid sending it down to the ipmpstub. 1015 11042 Erik * We will be called again once the members of the 1016 11042 Erik * group are in place 1017 11042 Erik */ 1018 11042 Erik ip1dbg(("ill_leave_allmulti: no cast_ill on %s %d\n", 1019 11042 Erik ill->ill_name, ill->ill_isv6)); 1020 11042 Erik return; 1021 11042 Erik } 1022 11042 Erik ill = release_ill; 1023 11042 Erik if (!ill->ill_dl_up) 1024 11042 Erik goto done; 1025 11042 Erik } 1026 0 stevel 1027 0 stevel /* 1028 11042 Erik * In the case of IPMP and ill_dl_up not being set when we joined 1029 11042 Erik * we didn't allocate a promiscoff_mp. In that case we have 1030 11042 Erik * nothing to do when we leave. 1031 11042 Erik * Ditto for PHYI_MULTI_BCAST 1032 0 stevel */ 1033 11042 Erik promiscoff_mp = ill->ill_promiscoff_mp; 1034 11042 Erik if (promiscoff_mp != NULL) { 1035 8023 Phil ill->ill_promiscoff_mp = NULL; 1036 11042 Erik ill_dlpi_queue(ill, promiscoff_mp); 1037 0 stevel } 1038 11042 Erik done: 1039 11042 Erik if (release_ill != NULL) 1040 11042 Erik ill_refrele(release_ill); 1041 8023 Phil } 1042 8023 Phil 1043 8023 Phil int 1044 8023 Phil ip_join_allmulti(uint_t ifindex, boolean_t isv6, ip_stack_t *ipst) 1045 8023 Phil { 1046 8023 Phil ill_t *ill; 1047 11042 Erik int ret; 1048 11042 Erik ilm_t *ilm; 1049 8023 Phil 1050 11042 Erik ill = ill_lookup_on_ifindex(ifindex, isv6, ipst); 1051 11042 Erik if (ill == NULL) 1052 8023 Phil return (ENODEV); 1053 8485 Peter 1054 8485 Peter /* 1055 11042 Erik * The ip_addmulti() function doesn't allow IPMP underlying interfaces 1056 8485 Peter * to join allmulti since only the nominated underlying interface in 1057 8485 Peter * the group should receive multicast. We silently succeed to avoid 1058 8485 Peter * having to teach IPobs (currently the only caller of this routine) 1059 8485 Peter * to ignore failures in this case. 1060 8485 Peter */ 1061 11042 Erik if (IS_UNDER_IPMP(ill)) { 1062 11042 Erik ill_refrele(ill); 1063 11042 Erik return (0); 1064 11042 Erik } 1065 11042 Erik mutex_enter(&ill->ill_lock); 1066 11042 Erik if (ill->ill_ipallmulti_cnt > 0) { 1067 11042 Erik /* Already joined */ 1068 11042 Erik ASSERT(ill->ill_ipallmulti_ilm != NULL); 1069 11042 Erik ill->ill_ipallmulti_cnt++; 1070 11042 Erik mutex_exit(&ill->ill_lock); 1071 11042 Erik goto done; 1072 11042 Erik } 1073 11042 Erik mutex_exit(&ill->ill_lock); 1074 8485 Peter 1075 11042 Erik ilm = ip_addmulti(&ipv6_all_zeros, ill, ill->ill_zoneid, &ret); 1076 11042 Erik if (ilm == NULL) { 1077 11042 Erik ASSERT(ret != 0); 1078 11042 Erik ill_refrele(ill); 1079 11042 Erik return (ret); 1080 8023 Phil } 1081 11042 Erik 1082 11042 Erik mutex_enter(&ill->ill_lock); 1083 11042 Erik if (ill->ill_ipallmulti_cnt > 0) { 1084 11042 Erik /* Another thread added it concurrently */ 1085 11042 Erik (void) ip_delmulti(ilm); 1086 11042 Erik mutex_exit(&ill->ill_lock); 1087 11042 Erik goto done; 1088 11042 Erik } 1089 11042 Erik ASSERT(ill->ill_ipallmulti_ilm == NULL); 1090 11042 Erik ill->ill_ipallmulti_ilm = ilm; 1091 8023 Phil ill->ill_ipallmulti_cnt++; 1092 11042 Erik mutex_exit(&ill->ill_lock); 1093 11042 Erik done: 1094 11042 Erik ill_refrele(ill); 1095 11042 Erik return (0); 1096 8023 Phil } 1097 8485 Peter 1098 8023 Phil int 1099 8023 Phil ip_leave_allmulti(uint_t ifindex, boolean_t isv6, ip_stack_t *ipst) 1100 8023 Phil { 1101 8023 Phil ill_t *ill; 1102 11042 Erik ilm_t *ilm; 1103 8023 Phil 1104 11042 Erik ill = ill_lookup_on_ifindex(ifindex, isv6, ipst); 1105 11042 Erik if (ill == NULL) 1106 8023 Phil return (ENODEV); 1107 8485 Peter 1108 11042 Erik if (IS_UNDER_IPMP(ill)) { 1109 11042 Erik ill_refrele(ill); 1110 11042 Erik return (0); 1111 8485 Peter } 1112 11042 Erik 1113 11042 Erik mutex_enter(&ill->ill_lock); 1114 11042 Erik if (ill->ill_ipallmulti_cnt == 0) { 1115 11042 Erik /* ip_purge_allmulti could have removed them all */ 1116 11042 Erik mutex_exit(&ill->ill_lock); 1117 11042 Erik goto done; 1118 11042 Erik } 1119 11042 Erik ill->ill_ipallmulti_cnt--; 1120 11042 Erik if (ill->ill_ipallmulti_cnt == 0) { 1121 11042 Erik /* Last one */ 1122 11042 Erik ilm = ill->ill_ipallmulti_ilm; 1123 11042 Erik ill->ill_ipallmulti_ilm = NULL; 1124 11042 Erik } else { 1125 11042 Erik ilm = NULL; 1126 11042 Erik } 1127 11042 Erik mutex_exit(&ill->ill_lock); 1128 11042 Erik if (ilm != NULL) 1129 11042 Erik (void) ip_delmulti(ilm); 1130 11042 Erik 1131 11042 Erik done: 1132 11042 Erik ill_refrele(ill); 1133 8023 Phil return (0); 1134 8023 Phil } 1135 8023 Phil 1136 8023 Phil /* 1137 8023 Phil * Delete the allmulti memberships that were added as part of 1138 8023 Phil * ip_join_allmulti(). 1139 8023 Phil */ 1140 8023 Phil void 1141 8023 Phil ip_purge_allmulti(ill_t *ill) 1142 8023 Phil { 1143 11042 Erik ilm_t *ilm; 1144 11042 Erik 1145 8023 Phil ASSERT(IAM_WRITER_ILL(ill)); 1146 8023 Phil 1147 11042 Erik mutex_enter(&ill->ill_lock); 1148 11042 Erik ilm = ill->ill_ipallmulti_ilm; 1149 11042 Erik ill->ill_ipallmulti_ilm = NULL; 1150 11042 Erik ill->ill_ipallmulti_cnt = 0; 1151 11042 Erik mutex_exit(&ill->ill_lock); 1152 11042 Erik 1153 11042 Erik if (ilm != NULL) 1154 11042 Erik (void) ip_delmulti(ilm); 1155 0 stevel } 1156 0 stevel 1157 0 stevel /* 1158 11042 Erik * Create a dlpi message with room for phys+sap. Later 1159 11042 Erik * we will strip the sap for those primitives which 1160 11042 Erik * only need a physical address. 1161 0 stevel */ 1162 0 stevel static mblk_t * 1163 11042 Erik ill_create_dl(ill_t *ill, uint32_t dl_primitive, 1164 0 stevel uint32_t *addr_lenp, uint32_t *addr_offp) 1165 0 stevel { 1166 0 stevel mblk_t *mp; 1167 0 stevel uint32_t hw_addr_length; 1168 0 stevel char *cp; 1169 0 stevel uint32_t offset; 1170 11042 Erik uint32_t length; 1171 0 stevel uint32_t size; 1172 0 stevel 1173 0 stevel *addr_lenp = *addr_offp = 0; 1174 0 stevel 1175 0 stevel hw_addr_length = ill->ill_phys_addr_length; 1176 0 stevel if (!hw_addr_length) { 1177 0 stevel ip0dbg(("ip_create_dl: hw addr length = 0\n")); 1178 0 stevel return (NULL); 1179 0 stevel } 1180 0 stevel 1181 0 stevel switch (dl_primitive) { 1182 0 stevel case DL_ENABMULTI_REQ: 1183 11042 Erik length = sizeof (dl_enabmulti_req_t); 1184 11042 Erik size = length + hw_addr_length; 1185 11042 Erik break; 1186 0 stevel case DL_DISABMULTI_REQ: 1187 11042 Erik length = sizeof (dl_disabmulti_req_t); 1188 11042 Erik size = length + hw_addr_length; 1189 0 stevel break; 1190 0 stevel case DL_PROMISCON_REQ: 1191 0 stevel case DL_PROMISCOFF_REQ: 1192 11042 Erik size = length = sizeof (dl_promiscon_req_t); 1193 0 stevel break; 1194 0 stevel default: 1195 0 stevel return (NULL); 1196 0 stevel } 1197 0 stevel mp = allocb(size, BPRI_HI); 1198 0 stevel if (!mp) 1199 0 stevel return (NULL); 1200 0 stevel mp->b_wptr += size; 1201 0 stevel mp->b_datap->db_type = M_PROTO; 1202 0 stevel 1203 0 stevel cp = (char *)mp->b_rptr; 1204 0 stevel offset = length; 1205 0 stevel 1206 0 stevel switch (dl_primitive) { 1207 0 stevel case DL_ENABMULTI_REQ: { 1208 0 stevel dl_enabmulti_req_t *dl = (dl_enabmulti_req_t *)cp; 1209 0 stevel 1210 0 stevel dl->dl_primitive = dl_primitive; 1211 0 stevel dl->dl_addr_offset = offset; 1212 0 stevel *addr_lenp = dl->dl_addr_length = hw_addr_length; 1213 0 stevel *addr_offp = offset; 1214 0 stevel break; 1215 0 stevel } 1216 0 stevel case DL_DISABMULTI_REQ: { 1217 0 stevel dl_disabmulti_req_t *dl = (dl_disabmulti_req_t *)cp; 1218 0 stevel 1219 0 stevel dl->dl_primitive = dl_primitive; 1220 0 stevel dl->dl_addr_offset = offset; 1221 0 stevel *addr_lenp = dl->dl_addr_length = hw_addr_length; 1222 0 stevel *addr_offp = offset; 1223 0 stevel break; 1224 0 stevel } 1225 0 stevel case DL_PROMISCON_REQ: 1226 0 stevel case DL_PROMISCOFF_REQ: { 1227 0 stevel dl_promiscon_req_t *dl = (dl_promiscon_req_t *)cp; 1228 0 stevel 1229 0 stevel dl->dl_primitive = dl_primitive; 1230 0 stevel dl->dl_level = DL_PROMISC_MULTI; 1231 0 stevel break; 1232 0 stevel } 1233 0 stevel } 1234 0 stevel ip1dbg(("ill_create_dl: addr_len %d, addr_off %d\n", 1235 4459 kcpoon *addr_lenp, *addr_offp)); 1236 0 stevel return (mp); 1237 0 stevel } 1238 0 stevel 1239 0 stevel /* 1240 11042 Erik * Rejoin any groups for which we have ilms. 1241 11042 Erik * 1242 11042 Erik * This is only needed for IPMP when the cast_ill changes since that 1243 11042 Erik * change is invisible to the ilm. Other interface changes are handled 1244 11042 Erik * by conn_update_ill. 1245 0 stevel */ 1246 0 stevel void 1247 0 stevel ill_recover_multicast(ill_t *ill) 1248 0 stevel { 1249 0 stevel ilm_t *ilm; 1250 0 stevel char addrbuf[INET6_ADDRSTRLEN]; 1251 8023 Phil 1252 8023 Phil ill->ill_need_recover_multicast = 0; 1253 8023 Phil 1254 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_WRITER); 1255 0 stevel for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { 1256 0 stevel /* 1257 11042 Erik * If we have more then one ilm for the group (e.g., with 1258 11042 Erik * different zoneid) then we should not tell the driver 1259 11042 Erik * to join unless this is the first ilm for the group. 1260 0 stevel */ 1261 11042 Erik if (ilm_numentries(ill, &ilm->ilm_v6addr) > 1 && 1262 11042 Erik ilm_lookup(ill, &ilm->ilm_v6addr, ALL_ZONES) != ilm) { 1263 8485 Peter continue; 1264 8485 Peter } 1265 8485 Peter 1266 8485 Peter ip1dbg(("ill_recover_multicast: %s\n", inet_ntop(AF_INET6, 1267 8485 Peter &ilm->ilm_v6addr, addrbuf, sizeof (addrbuf)))); 1268 8485 Peter 1269 0 stevel if (IN6_IS_ADDR_UNSPECIFIED(&ilm->ilm_v6addr)) { 1270 8485 Peter (void) ill_join_allmulti(ill); 1271 8485 Peter } else { 1272 8485 Peter if (ill->ill_isv6) 1273 8485 Peter mld_joingroup(ilm); 1274 8485 Peter else 1275 8485 Peter igmp_joingroup(ilm); 1276 8485 Peter 1277 11042 Erik (void) ip_ll_multireq(ill, &ilm->ilm_v6addr, 1278 11042 Erik DL_ENABMULTI_REQ); 1279 8485 Peter } 1280 8485 Peter } 1281 11042 Erik rw_exit(&ill->ill_mcast_lock); 1282 11042 Erik /* Send any deferred/queued DLPI or IP packets */ 1283 11042 Erik ill_mcast_send_queued(ill); 1284 11042 Erik ill_dlpi_send_queued(ill); 1285 11042 Erik ill_mcast_timer_start(ill->ill_ipst); 1286 0 stevel } 1287 0 stevel 1288 0 stevel /* 1289 0 stevel * The opposite of ill_recover_multicast() -- leaves all multicast groups 1290 8485 Peter * that were explicitly joined. 1291 11042 Erik * 1292 11042 Erik * This is only needed for IPMP when the cast_ill changes since that 1293 11042 Erik * change is invisible to the ilm. Other interface changes are handled 1294 11042 Erik * by conn_update_ill. 1295 0 stevel */ 1296 0 stevel void 1297 0 stevel ill_leave_multicast(ill_t *ill) 1298 0 stevel { 1299 0 stevel ilm_t *ilm; 1300 0 stevel char addrbuf[INET6_ADDRSTRLEN]; 1301 8023 Phil 1302 8023 Phil ill->ill_need_recover_multicast = 1; 1303 8023 Phil 1304 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_WRITER); 1305 0 stevel for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { 1306 0 stevel /* 1307 11042 Erik * If we have more then one ilm for the group (e.g., with 1308 11042 Erik * different zoneid) then we should not tell the driver 1309 11042 Erik * to leave unless this is the first ilm for the group. 1310 0 stevel */ 1311 11042 Erik if (ilm_numentries(ill, &ilm->ilm_v6addr) > 1 && 1312 11042 Erik ilm_lookup(ill, &ilm->ilm_v6addr, ALL_ZONES) != ilm) { 1313 8485 Peter continue; 1314 8485 Peter } 1315 8485 Peter 1316 8485 Peter ip1dbg(("ill_leave_multicast: %s\n", inet_ntop(AF_INET6, 1317 8485 Peter &ilm->ilm_v6addr, addrbuf, sizeof (addrbuf)))); 1318 8485 Peter 1319 0 stevel if (IN6_IS_ADDR_UNSPECIFIED(&ilm->ilm_v6addr)) { 1320 8023 Phil ill_leave_allmulti(ill); 1321 8485 Peter } else { 1322 8485 Peter if (ill->ill_isv6) 1323 8485 Peter mld_leavegroup(ilm); 1324 8485 Peter else 1325 8485 Peter igmp_leavegroup(ilm); 1326 8485 Peter 1327 11042 Erik (void) ip_ll_multireq(ill, &ilm->ilm_v6addr, 1328 11042 Erik DL_DISABMULTI_REQ); 1329 8485 Peter } 1330 8485 Peter } 1331 11042 Erik rw_exit(&ill->ill_mcast_lock); 1332 11042 Erik /* Send any deferred/queued DLPI or IP packets */ 1333 11042 Erik ill_mcast_send_queued(ill); 1334 11042 Erik ill_dlpi_send_queued(ill); 1335 11042 Erik ill_mcast_timer_start(ill->ill_ipst); 1336 4770 meem } 1337 0 stevel 1338 11042 Erik /* 1339 11042 Erik * Interface used by IP input/output. 1340 11042 Erik * Returns true if there is a member on the ill for any zoneid. 1341 11042 Erik */ 1342 11042 Erik boolean_t 1343 11042 Erik ill_hasmembers_v6(ill_t *ill, const in6_addr_t *v6group) 1344 11042 Erik { 1345 11042 Erik ilm_t *ilm; 1346 11042 Erik 1347 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_READER); 1348 11042 Erik ilm = ilm_lookup(ill, v6group, ALL_ZONES); 1349 11042 Erik rw_exit(&ill->ill_mcast_lock); 1350 11042 Erik return (ilm != NULL); 1351 11042 Erik } 1352 11042 Erik 1353 11042 Erik /* 1354 11042 Erik * Interface used by IP input/output. 1355 11042 Erik * Returns true if there is a member on the ill for any zoneid. 1356 11042 Erik * 1357 11042 Erik * The group and source can't be INADDR_ANY here so no need to translate to 1358 11042 Erik * the unspecified IPv6 address. 1359 11042 Erik */ 1360 11042 Erik boolean_t 1361 11042 Erik ill_hasmembers_v4(ill_t *ill, ipaddr_t group) 1362 0 stevel { 1363 0 stevel in6_addr_t v6group; 1364 0 stevel 1365 11042 Erik IN6_IPADDR_TO_V4MAPPED(group, &v6group); 1366 11042 Erik return (ill_hasmembers_v6(ill, &v6group)); 1367 8485 Peter } 1368 8485 Peter 1369 8485 Peter /* 1370 11042 Erik * Interface used by IP input/output. 1371 11042 Erik * Returns true if there is a member on the ill for any zoneid except skipzone. 1372 8485 Peter */ 1373 11042 Erik boolean_t 1374 11042 Erik ill_hasmembers_otherzones_v6(ill_t *ill, const in6_addr_t *v6group, 1375 11042 Erik zoneid_t skipzone) 1376 11042 Erik { 1377 11042 Erik ilm_t *ilm; 1378 11042 Erik 1379 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_READER); 1380 11042 Erik for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { 1381 11042 Erik if (IN6_ARE_ADDR_EQUAL(&ilm->ilm_v6addr, v6group) && 1382 11042 Erik ilm->ilm_zoneid != skipzone) { 1383 11042 Erik rw_exit(&ill->ill_mcast_lock); 1384 11042 Erik return (B_TRUE); 1385 11042 Erik } 1386 11042 Erik } 1387 11042 Erik rw_exit(&ill->ill_mcast_lock); 1388 11042 Erik return (B_FALSE); 1389 11042 Erik } 1390 11042 Erik 1391 11042 Erik /* 1392 11042 Erik * Interface used by IP input/output. 1393 11042 Erik * Returns true if there is a member on the ill for any zoneid except skipzone. 1394 11042 Erik * 1395 11042 Erik * The group and source can't be INADDR_ANY here so no need to translate to 1396 11042 Erik * the unspecified IPv6 address. 1397 11042 Erik */ 1398 11042 Erik boolean_t 1399 11042 Erik ill_hasmembers_otherzones_v4(ill_t *ill, ipaddr_t group, zoneid_t skipzone) 1400 11042 Erik { 1401 11042 Erik in6_addr_t v6group; 1402 11042 Erik 1403 11042 Erik IN6_IPADDR_TO_V4MAPPED(group, &v6group); 1404 11042 Erik return (ill_hasmembers_otherzones_v6(ill, &v6group, skipzone)); 1405 11042 Erik } 1406 11042 Erik 1407 11042 Erik /* 1408 11042 Erik * Interface used by IP input. 1409 11042 Erik * Returns the next numerically larger zoneid that has a member. If none exist 1410 11042 Erik * then returns -1 (ALL_ZONES). 1411 11042 Erik * The normal usage is for the caller to start with a -1 zoneid (ALL_ZONES) 1412 11042 Erik * to find the first zoneid which has a member, and then pass that in for 1413 11042 Erik * subsequent calls until ALL_ZONES is returned. 1414 11042 Erik * 1415 11042 Erik * The implementation of ill_hasmembers_nextzone() assumes the ilms 1416 11042 Erik * are sorted by zoneid for efficiency. 1417 11042 Erik */ 1418 11042 Erik zoneid_t 1419 11042 Erik ill_hasmembers_nextzone_v6(ill_t *ill, const in6_addr_t *v6group, 1420 11042 Erik zoneid_t zoneid) 1421 11042 Erik { 1422 11042 Erik ilm_t *ilm; 1423 11042 Erik 1424 11042 Erik rw_enter(&ill->ill_mcast_lock, RW_READER); 1425 11042 Erik for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { 1426 11042 Erik if (IN6_ARE_ADDR_EQUAL(&ilm->ilm_v6addr, v6group) && 1427 11042 Erik ilm->ilm_zoneid > zoneid) { 1428 11042 Erik zoneid = ilm->ilm_zoneid; 1429 11042 Erik rw_exit(&ill->ill_mcast_lock); 1430 11042 Erik return (zoneid); 1431 11042 Erik } 1432 11042 Erik } 1433 11042 Erik rw_exit(&ill->ill_mcast_lock); 1434 11042 Erik return (ALL_ZONES); 1435 11042 Erik } 1436 11042 Erik 1437 11042 Erik /* 1438 11042 Erik * Interface used by IP input. 1439 11042 Erik * Returns the next numerically larger zoneid that has a member. If none exist 1440 11042 Erik * then returns -1 (ALL_ZONES). 1441 11042 Erik * 1442 11042 Erik * The group and source can't be INADDR_ANY here so no need to translate to 1443 11042 Erik * the unspecified IPv6 address. 1444 11042 Erik */ 1445 11042 Erik zoneid_t 1446 11042 Erik ill_hasmembers_nextzone_v4(ill_t *ill, ipaddr_t group, zoneid_t zoneid) 1447 11042 Erik { 1448 11042 Erik in6_addr_t v6group; 1449 11042 Erik 1450 11042 Erik IN6_IPADDR_TO_V4MAPPED(group, &v6group); 1451 11042 Erik 1452 11042 Erik return (ill_hasmembers_nextzone_v6(ill, &v6group, zoneid)); 1453 11042 Erik } 1454 11042 Erik 1455 11042 Erik /* 1456 11042 Erik * Find an ilm matching the ill, group, and zoneid. 1457 11042 Erik */ 1458 11042 Erik static ilm_t * 1459 11042 Erik ilm_lookup(ill_t *ill, const in6_addr_t *v6group, zoneid_t zoneid) 1460 8485 Peter { 1461 8485 Peter ilm_t *ilm; 1462 8485 Peter 1463 11042 Erik ASSERT(RW_LOCK_HELD(&ill->ill_mcast_lock)); 1464 8485 Peter 1465 11042 Erik for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { 1466 8485 Peter if (!IN6_ARE_ADDR_EQUAL(&ilm->ilm_v6addr, v6group)) 1467 8485 Peter continue; 1468 8485 Peter if (zoneid != ALL_ZONES && zoneid != ilm->ilm_zoneid) 1469 8485 Peter continue; 1470 11042 Erik 1471 11042 Erik ASSERT(ilm->ilm_ill == ill); 1472 11042 Erik return (ilm); 1473 8485 Peter } 1474 11042 Erik return (NULL); 1475 0 stevel } 1476 0 stevel 1477 0 stevel /* 1478 0 stevel * How many members on this ill? 1479 11042 Erik * Since each shared-IP zone has a separate ilm for the same group/ill 1480 11042 Erik * we can have several. 1481 0 stevel */ 1482 11042 Erik static int 1483 11042 Erik ilm_numentries(ill_t *ill, const in6_addr_t *v6group) 1484 0 stevel { 1485 0 stevel ilm_t *ilm; 1486 0 stevel int i = 0; 1487 0 stevel 1488 11042 Erik ASSERT(RW_LOCK_HELD(&ill->ill_mcast_lock)); 1489 0 stevel for (ilm = ill->ill_ilm; ilm; ilm = ilm->ilm_next) { 1490 0 stevel if (IN6_ARE_ADDR_EQUAL(&ilm->ilm_v6addr, v6group)) { 1491 0 stevel i++; 1492 0 stevel } 1493 0 stevel } 1494 0 stevel return (i); 1495 0 stevel } 1496 0 stevel 1497 0 stevel /* Caller guarantees that the group is not already on the list */ 1498 0 stevel static ilm_t * 1499 11042 Erik ilm_add(ill_t *ill, const in6_addr_t *v6group, ilg_stat_t ilgstat, 1500 8485 Peter mcast_record_t ilg_fmode, slist_t *ilg_flist, zoneid_t zoneid) 1501 0 stevel { 1502 0 stevel ilm_t *ilm; 1503 0 stevel ilm_t *ilm_cur; 1504 0 stevel ilm_t **ilm_ptpn; 1505 0 stevel 1506 11042 Erik ASSERT(RW_WRITE_HELD(&ill->ill_mcast_lock)); 1507 0 stevel ilm = GETSTRUCT(ilm_t, 1); 1508 0 stevel if (ilm == NULL) 1509 0 stevel return (NULL); 1510 0 stevel if (ilgstat != ILGSTAT_NONE && !SLIST_IS_EMPTY(ilg_flist)) { 1511 0 stevel ilm->ilm_filter = l_alloc(); 1512 0 stevel if (ilm->ilm_filter == NULL) { 1513 0 stevel mi_free(ilm); 1514 0 stevel return (NULL); 1515 0 stevel } 1516 0 stevel } 1517 0 stevel ilm->ilm_v6addr = *v6group; 1518 0 stevel ilm->ilm_refcnt = 1; 1519 0 stevel ilm->ilm_zoneid = zoneid; 1520 0 stevel ilm->ilm_timer = INFINITY; 1521 0 stevel ilm->ilm_rtx.rtx_timer = INFINITY; 1522 1676 jpk 1523 11042 Erik ilm->ilm_ill = ill; 1524 11042 Erik DTRACE_PROBE3(ill__incr__cnt, (ill_t *), ill, 1525 11042 Erik (char *), "ilm", (void *), ilm); 1526 11042 Erik ill->ill_ilm_cnt++; 1527 8485 Peter 1528 3448 dh155122 ASSERT(ill->ill_ipst); 1529 3448 dh155122 ilm->ilm_ipst = ill->ill_ipst; /* No netstack_hold */ 1530 0 stevel 1531 11042 Erik /* The ill/ipif could have just been marked as condemned */ 1532 0 stevel 1533 0 stevel /* 1534 11042 Erik * To make ill_hasmembers_nextzone_v6 work we keep the list 1535 11042 Erik * sorted by zoneid. 1536 0 stevel */ 1537 0 stevel ilm_cur = ill->ill_ilm; 1538 0 stevel ilm_ptpn = &ill->ill_ilm; 1539 11042 Erik while (ilm_cur != NULL && ilm_cur->ilm_zoneid < ilm->ilm_zoneid) { 1540 0 stevel ilm_ptpn = &ilm_cur->ilm_next; 1541 0 stevel ilm_cur = ilm_cur->ilm_next; 1542 0 stevel } 1543 0 stevel ilm->ilm_next = ilm_cur; 1544 0 stevel *ilm_ptpn = ilm; 1545 0 stevel 1546 0 stevel /* 1547 0 stevel * If we have an associated ilg, use its filter state; if not, 1548 0 stevel * default to (EXCLUDE, NULL) and set no_ilg_cnt to track this. 1549 0 stevel */ 1550 0 stevel if (ilgstat != ILGSTAT_NONE) { 1551 0 stevel if (!SLIST_IS_EMPTY(ilg_flist)) 1552 0 stevel l_copy(ilg_flist, ilm->ilm_filter); 1553 0 stevel ilm->ilm_fmode = ilg_fmode; 1554 0 stevel } else { 1555 0 stevel ilm->ilm_no_ilg_cnt = 1; 1556 0 stevel ilm->ilm_fmode = MODE_IS_EXCLUDE; 1557 0 stevel } 1558 0 stevel 1559 0 stevel return (ilm); 1560 0 stevel } 1561 0 stevel 1562 6763 sowmini void 1563 6255 sowmini ilm_inactive(ilm_t *ilm) 1564 6255 sowmini { 1565 0 stevel FREE_SLIST(ilm->ilm_filter); 1566 0 stevel FREE_SLIST(ilm->ilm_pendsrcs); 1567 0 stevel FREE_SLIST(ilm->ilm_rtx.rtx_allow); 1568 0 stevel FREE_SLIST(ilm->ilm_rtx.rtx_block); 1569 3448 dh155122 ilm->ilm_ipst = NULL; 1570 0 stevel mi_free((char *)ilm); 1571 0 stevel } 1572 0 stevel 1573 6255 sowmini /* 1574 6255 sowmini * Unlink ilm and free it. 1575 6255 sowmini */ 1576 6255 sowmini static void 1577 6255 sowmini ilm_delete(ilm_t *ilm) 1578 6255 sowmini { 1579 11042 Erik ill_t *ill = ilm->ilm_ill; 1580 6255 sowmini ilm_t **ilmp; 1581 6255 sowmini boolean_t need_wakeup; 1582 6255 sowmini 1583 6255 sowmini /* 1584 6255 sowmini * Delete under lock protection so that readers don't stumble 1585 6255 sowmini * on bad ilm_next 1586 6255 sowmini */ 1587 11042 Erik ASSERT(RW_WRITE_HELD(&ill->ill_mcast_lock)); 1588 6255 sowmini 1589 6255 sowmini for (ilmp = &ill->ill_ilm; *ilmp != ilm; ilmp = &(*ilmp)->ilm_next) 1590 11042 Erik ; 1591 11042 Erik 1592 6255 sowmini *ilmp = ilm->ilm_next; 1593 6255 sowmini 1594 11042 Erik mutex_enter(&ill->ill_lock); 1595 6255 sowmini /* 1596 11042 Erik * if we are the last reference to the ill, we may need to wakeup any 1597 11042 Erik * pending FREE or unplumb operations. This is because conn_update_ill 1598 11042 Erik * bails if there is a ilg_delete_all in progress. 1599 6255 sowmini */ 1600 6255 sowmini need_wakeup = B_FALSE; 1601 11042 Erik DTRACE_PROBE3(ill__decr__cnt, (ill_t *), ill, 1602 11042 Erik (char *), "ilm", (void *), ilm); 1603 11042 Erik ASSERT(ill->ill_ilm_cnt > 0); 1604 11042 Erik ill->ill_ilm_cnt--; 1605 11042 Erik if (ILL_FREE_OK(ill)) 1606 11042 Erik need_wakeup = B_TRUE; 1607 6255 sowmini 1608 6255 sowmini ilm_inactive(ilm); /* frees this ilm */ 1609 6255 sowmini 1610 6255 sowmini if (need_wakeup) { 1611 6255 sowmini /* drops ill lock */ 1612 6255 sowmini ipif_ill_refrele_tail(ill); 1613 6255 sowmini } else { 1614 6255 sowmini mutex_exit(&ill->ill_lock); 1615 6255 sowmini } 1616 6255 sowmini } 1617 6255 sowmini 1618 11042 Erik /* 1619 11042 Erik * Lookup an ill based on the group, ifindex, ifaddr, and zoneid. 1620 11042 Erik * Applies to both IPv4 and IPv6, although ifaddr is only used with 1621 11042 Erik * IPv4. 1622 11042 Erik * Returns an error for IS_UNDER_IPMP and VNI interfaces. 1623 11042 Erik * On error it sets *errorp. 1624 11042 Erik */ 1625 11042 Erik static ill_t * 1626 11042 Erik ill_mcast_lookup(const in6_addr_t *group, ipaddr_t ifaddr, uint_t ifindex, 1627 11042 Erik zoneid_t zoneid, ip_stack_t *ipst, int *errorp) 1628 8485 Peter { 1629 11042 Erik ill_t *ill; 1630 11042 Erik ipaddr_t v4group; 1631 8485 Peter 1632 11042 Erik if (IN6_IS_ADDR_V4MAPPED(group)) { 1633 11042 Erik IN6_V4MAPPED_TO_IPADDR(group, v4group); 1634 11042 Erik 1635 11042 Erik if (ifindex != 0) { 1636 11042 Erik ill = ill_lookup_on_ifindex_zoneid(ifindex, zoneid, 1637 11042 Erik B_FALSE, ipst); 1638 11042 Erik } else if (ifaddr != INADDR_ANY) { 1639 11042 Erik ipif_t *ipif; 1640 11042 Erik 1641 11042 Erik ipif = ipif_lookup_addr(ifaddr, NULL, zoneid, ipst); 1642 11042 Erik if (ipif == NULL) { 1643 11042 Erik ill = NULL; 1644 11042 Erik } else { 1645 11042 Erik ill = ipif->ipif_ill; 1646 11042 Erik ill_refhold(ill); 1647 11042 Erik ipif_refrele(ipif); 1648 11042 Erik } 1649 11042 Erik } else { 1650 11042 Erik ill = ill_lookup_group_v4(v4group, zoneid, ipst, NULL, 1651 11042 Erik NULL); 1652 11042 Erik } 1653 11042 Erik } else { 1654 11042 Erik if (ifindex != 0) { 1655 11042 Erik ill = ill_lookup_on_ifindex_zoneid(ifindex, zoneid, 1656 11042 Erik B_TRUE, ipst); 1657 11042 Erik } else { 1658 11042 Erik ill = ill_lookup_group_v6(group, zoneid, ipst, NULL, 1659 11042 Erik NULL); 1660 11042 Erik } 1661 11042 Erik } 1662 11042 Erik if (ill == NULL) { 1663 11042 Erik if (ifindex != 0) 1664 11042 Erik *errorp = ENXIO; 1665 11042 Erik else 1666 11042 Erik *errorp = EADDRNOTAVAIL; 1667 11042 Erik return (NULL); 1668 11042 Erik } 1669 11042 Erik /* operation not supported on the virtual network interface */ 1670 11042 Erik if (IS_UNDER_IPMP(ill) || IS_VNI(ill)) { 1671 11042 Erik ill_refrele(ill); 1672 11042 Erik *errorp = EINVAL; 1673 11042 Erik return (NULL); 1674 11042 Erik } 1675 11042 Erik return (ill); 1676 8485 Peter } 1677 8485 Peter 1678 8485 Peter /* 1679 11042 Erik * Looks up the appropriate ill given an interface index (or interface address) 1680 11042 Erik * and multicast group. On success, returns 0, with *illpp pointing to the 1681 11042 Erik * found struct. On failure, returns an errno and *illpp is set to NULL. 1682 11042 Erik * 1683 11042 Erik * Returns an error for IS_UNDER_IPMP and VNI interfaces. 1684 11042 Erik * 1685 11042 Erik * Handles both IPv4 and IPv6. The ifaddr argument only applies in the 1686 11042 Erik * case of IPv4. 1687 0 stevel */ 1688 0 stevel int 1689 11042 Erik ip_opt_check(conn_t *connp, const in6_addr_t *v6group, 1690 11042 Erik const in6_addr_t *v6src, ipaddr_t ifaddr, uint_t ifindex, ill_t **illpp) 1691 0 stevel { 1692 0 stevel boolean_t src_unspec; 1693 0 stevel ill_t *ill = NULL; 1694 3448 dh155122 ip_stack_t *ipst = connp->conn_netstack->netstack_ip; 1695 11042 Erik int error = 0; 1696 11042 Erik 1697 11042 Erik *illpp = NULL; 1698 0 stevel 1699 0 stevel src_unspec = IN6_IS_ADDR_UNSPECIFIED(v6src); 1700 0 stevel 1701 0 stevel if (IN6_IS_ADDR_V4MAPPED(v6group)) { 1702 11042 Erik ipaddr_t v4group; 1703 11042 Erik ipaddr_t v4src; 1704 11042 Erik 1705 0 stevel if (!IN6_IS_ADDR_V4MAPPED(v6src) && !src_unspec) 1706 0 stevel return (EINVAL); 1707 11042 Erik IN6_V4MAPPED_TO_IPADDR(v6group, v4group); 1708 0 stevel if (src_unspec) { 1709 11042 Erik v4src = INADDR_ANY; 1710 0 stevel } else { 1711 11042 Erik IN6_V4MAPPED_TO_IPADDR(v6src, v4src); 1712 0 stevel } 1713 11042 Erik if (!CLASSD(v4group) || CLASSD(v4src)) 1714 0 stevel return (EINVAL); 1715 0 stevel } else { 1716 0 stevel if (IN6_IS_ADDR_V4MAPPED(v6src) && !src_unspec) 1717 0 stevel return (EINVAL); 1718 0 stevel if (!IN6_IS_ADDR_MULTICAST(v6group) || 1719 0 stevel IN6_IS_ADDR_MULTICAST(v6src)) { 1720 0 stevel return (EINVAL); 1721 0 stevel } 1722 0 stevel } 1723 0 stevel 1724 11042 Erik ill = ill_mcast_lookup(v6group, ifaddr, ifindex, IPCL_ZONEID(connp), 1725 11042 Erik ipst, &error); 1726 0 stevel *illpp = ill; 1727 11042 Erik return (error); 1728 0 stevel } 1729 0 stevel 1730 0 stevel static int 1731 0 stevel ip_get_srcfilter(conn_t *connp, struct group_filter *gf, 1732 11042 Erik struct ip_msfilter *imsf, const struct in6_addr *group, boolean_t issin6) 1733 0 stevel { 1734 0 stevel ilg_t *ilg; 1735 0 stevel int i, numsrc, fmode, outsrcs; 1736 0 stevel struct sockaddr_in *sin; 1737 0 stevel struct sockaddr_in6 *sin6; 1738 0 stevel struct in_addr *addrp; 1739 0 stevel slist_t *fp; 1740 0 stevel boolean_t is_v4only_api; 1741 11042 Erik ipaddr_t ifaddr; 1742 11042 Erik uint_t ifindex; 1743 0 stevel 1744 0 stevel if (gf == NULL) { 1745 0 stevel ASSERT(imsf != NULL); 1746 11042 Erik ASSERT(!issin6); 1747 0 stevel is_v4only_api = B_TRUE; 1748 0 stevel outsrcs = imsf->imsf_numsrc; 1749 11042 Erik ifaddr = imsf->imsf_interface.s_addr; 1750 11042 Erik ifindex = 0; 1751 0 stevel } else { 1752 0 stevel ASSERT(imsf == NULL); 1753 0 stevel is_v4only_api = B_FALSE; 1754 0 stevel outsrcs = gf->gf_numsrc; 1755 11042 Erik ifaddr = INADDR_ANY; 1756 11042 Erik ifindex = gf->gf_interface; 1757 11042 Erik } 1758 11042 Erik 1759 11042 Erik /* No need to use ill_mcast_serializer for the reader */ 1760 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_READER); 1761 11042 Erik ilg = ilg_lookup(connp, group, ifaddr, ifindex); 1762 11042 Erik if (ilg == NULL) { 1763 11042 Erik rw_exit(&connp->conn_ilg_lock); 1764 11042 Erik return (EADDRNOTAVAIL); 1765 0 stevel } 1766 0 stevel 1767 0 stevel /* 1768 0 stevel * In the kernel, we use the state definitions MODE_IS_[IN|EX]CLUDE 1769 0 stevel * to identify the filter mode; but the API uses MCAST_[IN|EX]CLUDE. 1770 0 stevel * So we need to translate here. 1771 0 stevel */ 1772 0 stevel fmode = (ilg->ilg_fmode == MODE_IS_INCLUDE) ? 1773 0 stevel MCAST_INCLUDE : MCAST_EXCLUDE; 1774 0 stevel if ((fp = ilg->ilg_filter) == NULL) { 1775 0 stevel numsrc = 0; 1776 0 stevel } else { 1777 0 stevel for (i = 0; i < outsrcs; i++) { 1778 0 stevel if (i == fp->sl_numsrc) 1779 0 stevel break; 1780 11042 Erik if (issin6) { 1781 0 stevel sin6 = (struct sockaddr_in6 *)&gf->gf_slist[i]; 1782 0 stevel sin6->sin6_family = AF_INET6; 1783 0 stevel sin6->sin6_addr = fp->sl_addr[i]; 1784 0 stevel } else { 1785 0 stevel if (is_v4only_api) { 1786 0 stevel addrp = &imsf->imsf_slist[i]; 1787 0 stevel } else { 1788 0 stevel sin = (struct sockaddr_in *) 1789 0 stevel &gf->gf_slist[i]; 1790 0 stevel sin->sin_family = AF_INET; 1791 0 stevel addrp = &sin->sin_addr; 1792 0 stevel } 1793 0 stevel IN6_V4MAPPED_TO_INADDR(&fp->sl_addr[i], addrp); 1794 0 stevel } 1795 0 stevel } 1796 0 stevel numsrc = fp->sl_numsrc; 1797 0 stevel } 1798 0 stevel 1799 0 stevel if (is_v4only_api) { 1800 0 stevel imsf->imsf_numsrc = numsrc; 1801 0 stevel imsf->imsf_fmode = fmode; 1802 0 stevel } else { 1803 0 stevel gf->gf_numsrc = numsrc; 1804 0 stevel gf->gf_fmode = fmode; 1805 0 stevel } 1806 0 stevel 1807 11042 Erik rw_exit(&connp->conn_ilg_lock); 1808 0 stevel 1809 0 stevel return (0); 1810 0 stevel } 1811 0 stevel 1812 11042 Erik /* 1813 11042 Erik * Common for IPv4 and IPv6. 1814 11042 Erik */ 1815 0 stevel static int 1816 0 stevel ip_set_srcfilter(conn_t *connp, struct group_filter *gf, 1817 11042 Erik struct ip_msfilter *imsf, const struct in6_addr *group, ill_t *ill, 1818 11042 Erik boolean_t issin6) 1819 0 stevel { 1820 0 stevel ilg_t *ilg; 1821 6827 blu int i, err, infmode, new_fmode; 1822 6827 blu uint_t insrcs; 1823 0 stevel struct sockaddr_in *sin; 1824 0 stevel struct sockaddr_in6 *sin6; 1825 0 stevel struct in_addr *addrp; 1826 0 stevel slist_t *orig_filter = NULL; 1827 0 stevel slist_t *new_filter = NULL; 1828 0 stevel mcast_record_t orig_fmode; 1829 11042 Erik boolean_t leave_group, is_v4only_api; 1830 0 stevel ilg_stat_t ilgstat; 1831 11042 Erik ilm_t *ilm; 1832 11042 Erik ipaddr_t ifaddr; 1833 11042 Erik uint_t ifindex; 1834 0 stevel 1835 0 stevel if (gf == NULL) { 1836 0 stevel ASSERT(imsf != NULL); 1837 11042 Erik ASSERT(!issin6); 1838 0 stevel is_v4only_api = B_TRUE; 1839 0 stevel insrcs = imsf->imsf_numsrc; 1840 0 stevel infmode = imsf->imsf_fmode; 1841 11042 Erik ifaddr = imsf->imsf_interface.s_addr; 1842 11042 Erik ifindex = 0; 1843 0 stevel } else { 1844 0 stevel ASSERT(imsf == NULL); 1845 0 stevel is_v4only_api = B_FALSE; 1846 0 stevel insrcs = gf->gf_numsrc; 1847 0 stevel infmode = gf->gf_fmode; 1848 11042 Erik ifaddr = INADDR_ANY; 1849 11042 Erik ifindex = gf->gf_interface; 1850 0 stevel } 1851 0 stevel 1852 0 stevel /* Make sure we can handle the source list */ 1853 0 stevel if (insrcs > MAX_FILTER_SIZE) 1854 0 stevel return (ENOBUFS); 1855 0 stevel 1856 0 stevel /* 1857 0 stevel * setting the filter to (INCLUDE, NULL) is treated 1858 0 stevel * as a request to leave the group. 1859 0 stevel */ 1860 11042 Erik leave_group = (infmode == MCAST_INCLUDE && insrcs == 0); 1861 0 stevel 1862 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 1863 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 1864 11042 Erik ilg = ilg_lookup(connp, group, ifaddr, ifindex); 1865 0 stevel if (ilg == NULL) { 1866 0 stevel /* 1867 0 stevel * if the request was actually to leave, and we 1868 0 stevel * didn't find an ilg, there's nothing to do. 1869 0 stevel */ 1870 11042 Erik if (leave_group) { 1871 11042 Erik rw_exit(&connp->conn_ilg_lock); 1872 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 1873 11042 Erik return (0); 1874 11042 Erik } 1875 11042 Erik ilg = conn_ilg_alloc(connp, &err); 1876 11042 Erik if (ilg == NULL) { 1877 11042 Erik rw_exit(&connp->conn_ilg_lock); 1878 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 1879 11042 Erik return (err); 1880 0 stevel } 1881 0 stevel ilgstat = ILGSTAT_NEW; 1882 11042 Erik ilg->ilg_v6group = *group; 1883 11042 Erik ilg->ilg_ill = ill; 1884 11042 Erik ilg->ilg_ifaddr = ifaddr; 1885 11042 Erik ilg->ilg_ifindex = ifindex; 1886 11042 Erik } else if (leave_group) { 1887 11042 Erik /* 1888 11042 Erik * Make sure we have the correct serializer. The ill argument 1889 11042 Erik * might not match ilg_ill. 1890 11042 Erik */ 1891 11042 Erik ilg_refhold(ilg); 1892 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 1893 11042 Erik ill = ilg->ilg_ill; 1894 11042 Erik rw_exit(&connp->conn_ilg_lock); 1895 11042 Erik 1896 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 1897 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 1898 11042 Erik ilm = ilg->ilg_ilm; 1899 11042 Erik ilg->ilg_ilm = NULL; 1900 0 stevel ilg_delete(connp, ilg, NULL); 1901 11042 Erik ilg_refrele(ilg); 1902 11042 Erik rw_exit(&connp->conn_ilg_lock); 1903 11042 Erik if (ilm != NULL) 1904 11042 Erik (void) ip_delmulti_serial(ilm, B_FALSE, B_TRUE); 1905 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 1906 0 stevel return (0); 1907 0 stevel } else { 1908 0 stevel ilgstat = ILGSTAT_CHANGE; 1909 0 stevel /* Preserve existing state in case ip_addmulti() fails */ 1910 0 stevel orig_fmode = ilg->ilg_fmode; 1911 0 stevel if (ilg->ilg_filter == NULL) { 1912 0 stevel orig_filter = NULL; 1913 0 stevel } else { 1914 0 stevel orig_filter = l_alloc_copy(ilg->ilg_filter); 1915 0 stevel if (orig_filter == NULL) { 1916 11042 Erik rw_exit(&connp->conn_ilg_lock); 1917 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 1918 0 stevel return (ENOMEM); 1919 0 stevel } 1920 0 stevel } 1921 0 stevel } 1922 0 stevel 1923 0 stevel /* 1924 0 stevel * Alloc buffer to copy new state into (see below) before 1925 0 stevel * we make any changes, so we can bail if it fails. 1926 0 stevel */ 1927 0 stevel if ((new_filter = l_alloc()) == NULL) { 1928 11042 Erik rw_exit(&connp->conn_ilg_lock); 1929 0 stevel err = ENOMEM; 1930 0 stevel goto free_and_exit; 1931 0 stevel } 1932 0 stevel 1933 0 stevel if (insrcs == 0) { 1934 0 stevel CLEAR_SLIST(ilg->ilg_filter); 1935 0 stevel } else { 1936 0 stevel slist_t *fp; 1937 0 stevel if (ilg->ilg_filter == NULL) { 1938 0 stevel fp = l_alloc(); 1939 0 stevel if (fp == NULL) { 1940 0 stevel if (ilgstat == ILGSTAT_NEW) 1941 0 stevel ilg_delete(connp, ilg, NULL); 1942 11042 Erik rw_exit(&connp->conn_ilg_lock); 1943 0 stevel err = ENOMEM; 1944 0 stevel goto free_and_exit; 1945 0 stevel } 1946 0 stevel } else { 1947 0 stevel fp = ilg->ilg_filter; 1948 0 stevel } 1949 0 stevel for (i = 0; i < insrcs; i++) { 1950 11042 Erik if (issin6) { 1951 0 stevel sin6 = (struct sockaddr_in6 *)&gf->gf_slist[i]; 1952 0 stevel fp->sl_addr[i] = sin6->sin6_addr; 1953 0 stevel } else { 1954 0 stevel if (is_v4only_api) { 1955 0 stevel addrp = &imsf->imsf_slist[i]; 1956 0 stevel } else { 1957 0 stevel sin = (struct sockaddr_in *) 1958 0 stevel &gf->gf_slist[i]; 1959 0 stevel addrp = &sin->sin_addr; 1960 0 stevel } 1961 0 stevel IN6_INADDR_TO_V4MAPPED(addrp, &fp->sl_addr[i]); 1962 0 stevel } 1963 0 stevel } 1964 0 stevel fp->sl_numsrc = insrcs; 1965 0 stevel ilg->ilg_filter = fp; 1966 0 stevel } 1967 0 stevel /* 1968 0 stevel * In the kernel, we use the state definitions MODE_IS_[IN|EX]CLUDE 1969 0 stevel * to identify the filter mode; but the API uses MCAST_[IN|EX]CLUDE. 1970 0 stevel * So we need to translate here. 1971 0 stevel */ 1972 0 stevel ilg->ilg_fmode = (infmode == MCAST_INCLUDE) ? 1973 4459 kcpoon MODE_IS_INCLUDE : MODE_IS_EXCLUDE; 1974 0 stevel 1975 0 stevel /* 1976 0 stevel * Save copy of ilg's filter state to pass to other functions, 1977 11042 Erik * so we can release conn_ilg_lock now. 1978 0 stevel */ 1979 0 stevel new_fmode = ilg->ilg_fmode; 1980 0 stevel l_copy(ilg->ilg_filter, new_filter); 1981 0 stevel 1982 11042 Erik rw_exit(&connp->conn_ilg_lock); 1983 0 stevel 1984 11042 Erik /* 1985 11042 Erik * Now update the ill. We wait to do this until after the ilg 1986 11042 Erik * has been updated because we need to update the src filter 1987 11042 Erik * info for the ill, which involves looking at the status of 1988 11042 Erik * all the ilgs associated with this group/interface pair. 1989 11042 Erik */ 1990 11042 Erik ilm = ip_addmulti_serial(group, ill, connp->conn_zoneid, ilgstat, 1991 11042 Erik new_fmode, new_filter, &err); 1992 11042 Erik 1993 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 1994 11042 Erik /* 1995 11042 Erik * Must look up the ilg again since we've not been holding 1996 11042 Erik * conn_ilg_lock. The ilg could have disappeared due to an unplumb 1997 11042 Erik * having called conn_update_ill, which can run once we dropped the 1998 11042 Erik * conn_ilg_lock above. 1999 11042 Erik */ 2000 11042 Erik ilg = ilg_lookup(connp, group, ifaddr, ifindex); 2001 11042 Erik if (ilg == NULL) { 2002 11042 Erik rw_exit(&connp->conn_ilg_lock); 2003 11042 Erik if (ilm != NULL) { 2004 11042 Erik (void) ip_delmulti_serial(ilm, B_FALSE, 2005 11042 Erik (ilgstat == ILGSTAT_NEW)); 2006 11042 Erik } 2007 11042 Erik err = ENXIO; 2008 11042 Erik goto free_and_exit; 2009 11042 Erik } 2010 11042 Erik 2011 11042 Erik if (ilm != NULL) { 2012 11042 Erik /* Succeeded. Update the ilg to point at the ilm */ 2013 11042 Erik if (ilgstat == ILGSTAT_NEW) { 2014 11042 Erik ASSERT(ilg->ilg_ilm == NULL); 2015 11042 Erik ilg->ilg_ilm = ilm; 2016 11042 Erik ilm->ilm_ifaddr = ifaddr; /* For netstat */ 2017 11042 Erik } else { 2018 11042 Erik /* 2019 11042 Erik * ip_addmulti didn't get a held ilm for 2020 11042 Erik * ILGSTAT_CHANGE; ilm_refcnt was unchanged. 2021 11042 Erik */ 2022 11042 Erik ASSERT(ilg->ilg_ilm == ilm); 2023 11042 Erik } 2024 11042 Erik } else { 2025 11042 Erik ASSERT(err != 0); 2026 0 stevel /* 2027 11042 Erik * Failed to allocate the ilm. 2028 0 stevel * Restore the original filter state, or delete the 2029 11042 Erik * newly-created ilg. 2030 11042 Erik * If ENETDOWN just clear ill_ilg since so that we 2031 11042 Erik * will rejoin when the ill comes back; don't report ENETDOWN 2032 11042 Erik * to application. 2033 0 stevel */ 2034 0 stevel if (ilgstat == ILGSTAT_NEW) { 2035 11042 Erik if (err == ENETDOWN) { 2036 11042 Erik ilg->ilg_ill = NULL; 2037 11042 Erik err = 0; 2038 11042 Erik } else { 2039 11042 Erik ilg_delete(connp, ilg, NULL); 2040 11042 Erik } 2041 0 stevel } else { 2042 0 stevel ilg->ilg_fmode = orig_fmode; 2043 0 stevel if (SLIST_IS_EMPTY(orig_filter)) { 2044 0 stevel CLEAR_SLIST(ilg->ilg_filter); 2045 0 stevel } else { 2046 0 stevel /* 2047 0 stevel * We didn't free the filter, even if we 2048 0 stevel * were trying to make the source list empty; 2049 0 stevel * so if orig_filter isn't empty, the ilg 2050 0 stevel * must still have a filter alloc'd. 2051 0 stevel */ 2052 0 stevel l_copy(orig_filter, ilg->ilg_filter); 2053 0 stevel } 2054 0 stevel } 2055 0 stevel } 2056 11042 Erik rw_exit(&connp->conn_ilg_lock); 2057 0 stevel 2058 0 stevel free_and_exit: 2059 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 2060 0 stevel l_free(orig_filter); 2061 0 stevel l_free(new_filter); 2062 0 stevel 2063 0 stevel return (err); 2064 0 stevel } 2065 0 stevel 2066 0 stevel /* 2067 0 stevel * Process the SIOC[GS]MSFILTER and SIOC[GS]IPMSFILTER ioctls. 2068 0 stevel */ 2069 0 stevel /* ARGSUSED */ 2070 0 stevel int 2071 0 stevel ip_sioctl_msfilter(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, 2072 0 stevel ip_ioctl_cmd_t *ipip, void *ifreq) 2073 0 stevel { 2074 0 stevel struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 2075 0 stevel /* existence verified in ip_wput_nondata() */ 2076 0 stevel mblk_t *data_mp = mp->b_cont->b_cont; 2077 0 stevel int datalen, err, cmd, minsize; 2078 6827 blu uint_t expsize = 0; 2079 0 stevel conn_t *connp; 2080 0 stevel boolean_t isv6, is_v4only_api, getcmd; 2081 0 stevel struct sockaddr_in *gsin; 2082 0 stevel struct sockaddr_in6 *gsin6; 2083 11042 Erik ipaddr_t v4group; 2084 11042 Erik in6_addr_t v6group; 2085 0 stevel struct group_filter *gf = NULL; 2086 0 stevel struct ip_msfilter *imsf = NULL; 2087 0 stevel mblk_t *ndp; 2088 11042 Erik ill_t *ill; 2089 11042 Erik 2090 11042 Erik connp = Q_TO_CONN(q); 2091 11042 Erik err = ip_msfilter_ill(connp, mp, ipip, &ill); 2092 11042 Erik if (err != 0) 2093 11042 Erik return (err); 2094 0 stevel 2095 0 stevel if (data_mp->b_cont != NULL) { 2096 0 stevel if ((ndp = msgpullup(data_mp, -1)) == NULL) 2097 0 stevel return (ENOMEM); 2098 0 stevel freemsg(data_mp); 2099 0 stevel data_mp = ndp; 2100 0 stevel mp->b_cont->b_cont = data_mp; 2101 0 stevel } 2102 0 stevel 2103 0 stevel cmd = iocp->ioc_cmd; 2104 0 stevel getcmd = (cmd == SIOCGIPMSFILTER || cmd == SIOCGMSFILTER); 2105 0 stevel is_v4only_api = (cmd == SIOCGIPMSFILTER || cmd == SIOCSIPMSFILTER); 2106 0 stevel minsize = (is_v4only_api) ? IP_MSFILTER_SIZE(0) : GROUP_FILTER_SIZE(0); 2107 0 stevel datalen = MBLKL(data_mp); 2108 0 stevel 2109 0 stevel if (datalen < minsize) 2110 0 stevel return (EINVAL); 2111 0 stevel 2112 0 stevel /* 2113 0 stevel * now we know we have at least have the initial structure, 2114 0 stevel * but need to check for the source list array. 2115 0 stevel */ 2116 0 stevel if (is_v4only_api) { 2117 0 stevel imsf = (struct ip_msfilter *)data_mp->b_rptr; 2118 0 stevel isv6 = B_FALSE; 2119 0 stevel expsize = IP_MSFILTER_SIZE(imsf->imsf_numsrc); 2120 0 stevel } else { 2121 0 stevel gf = (struct group_filter *)data_mp->b_rptr; 2122 0 stevel if (gf->gf_group.ss_family == AF_INET6) { 2123 0 stevel gsin6 = (struct sockaddr_in6 *)&gf->gf_group; 2124 0 stevel isv6 = !(IN6_IS_ADDR_V4MAPPED(&gsin6->sin6_addr)); 2125 0 stevel } else { 2126 0 stevel isv6 = B_FALSE; 2127 0 stevel } 2128 0 stevel expsize = GROUP_FILTER_SIZE(gf->gf_numsrc); 2129 0 stevel } 2130 0 stevel if (datalen < expsize) 2131 0 stevel return (EINVAL); 2132 0 stevel 2133 0 stevel if (isv6) { 2134 0 stevel gsin6 = (struct sockaddr_in6 *)&gf->gf_group; 2135 11042 Erik v6group = gsin6->sin6_addr; 2136 11042 Erik if (getcmd) { 2137 11042 Erik err = ip_get_srcfilter(connp, gf, NULL, &v6group, 2138 11042 Erik B_TRUE); 2139 11042 Erik } else { 2140 11042 Erik err = ip_set_srcfilter(connp, gf, NULL, &v6group, ill, 2141 11042 Erik B_TRUE); 2142 11042 Erik } 2143 0 stevel } else { 2144 11042 Erik boolean_t issin6 = B_FALSE; 2145 0 stevel if (is_v4only_api) { 2146 11042 Erik v4group = (ipaddr_t)imsf->imsf_multiaddr.s_addr; 2147 11042 Erik IN6_IPADDR_TO_V4MAPPED(v4group, &v6group); 2148 0 stevel } else { 2149 0 stevel if (gf->gf_group.ss_family == AF_INET) { 2150 0 stevel gsin = (struct sockaddr_in *)&gf->gf_group; 2151 11042 Erik v4group = (ipaddr_t)gsin->sin_addr.s_addr; 2152 11042 Erik IN6_IPADDR_TO_V4MAPPED(v4group, &v6group); 2153 0 stevel } else { 2154 0 stevel gsin6 = (struct sockaddr_in6 *)&gf->gf_group; 2155 0 stevel IN6_V4MAPPED_TO_IPADDR(&gsin6->sin6_addr, 2156 11042 Erik v4group); 2157 11042 Erik issin6 = B_TRUE; 2158 0 stevel } 2159 0 stevel } 2160 11042 Erik /* 2161 11042 Erik * INADDR_ANY is represented as the IPv6 unspecifed addr. 2162 11042 Erik */ 2163 11042 Erik if (v4group == INADDR_ANY) 2164 11042 Erik v6group = ipv6_all_zeros; 2165 0 stevel else 2166 11042 Erik IN6_IPADDR_TO_V4MAPPED(v4group, &v6group); 2167 11042 Erik 2168 11042 Erik if (getcmd) { 2169 11042 Erik err = ip_get_srcfilter(connp, gf, imsf, &v6group, 2170 11042 Erik issin6); 2171 11042 Erik } else { 2172 11042 Erik err = ip_set_srcfilter(connp, gf, imsf, &v6group, ill, 2173 11042 Erik issin6); 2174 11042 Erik } 2175 0 stevel } 2176 11042 Erik ill_refrele(ill); 2177 0 stevel 2178 0 stevel return (err); 2179 0 stevel } 2180 0 stevel 2181 0 stevel /* 2182 11042 Erik * Determine the ill for the SIOC*MSFILTER ioctls 2183 11042 Erik * 2184 11042 Erik * Returns an error for IS_UNDER_IPMP interfaces. 2185 11042 Erik * 2186 11042 Erik * Finds the ill based on information in the ioctl headers. 2187 4972 meem */ 2188 11042 Erik static int 2189 11042 Erik ip_msfilter_ill(conn_t *connp, mblk_t *mp, const ip_ioctl_cmd_t *ipip, 2190 11042 Erik ill_t **illp) 2191 4972 meem { 2192 4972 meem int cmd = ipip->ipi_cmd; 2193 4972 meem int err = 0; 2194 11042 Erik ill_t *ill; 2195 0 stevel /* caller has verified this mblk exists */ 2196 0 stevel char *dbuf = (char *)mp->b_cont->b_cont->b_rptr; 2197 0 stevel struct ip_msfilter *imsf; 2198 0 stevel struct group_filter *gf; 2199 11042 Erik ipaddr_t v4addr, v4group; 2200 11042 Erik in6_addr_t v6group; 2201 0 stevel uint32_t index; 2202 3448 dh155122 ip_stack_t *ipst; 2203 0 stevel 2204 3448 dh155122 ipst = connp->conn_netstack->netstack_ip; 2205 11042 Erik 2206 11042 Erik *illp = NULL; 2207 0 stevel 2208 0 stevel /* don't allow multicast operations on a tcp conn */ 2209 741 masputra if (IPCL_IS_TCP(connp)) 2210 0 stevel return (ENOPROTOOPT); 2211 0 stevel 2212 0 stevel if (cmd == SIOCSIPMSFILTER || cmd == SIOCGIPMSFILTER) { 2213 0 stevel /* don't allow v4-specific ioctls on v6 socket */ 2214 11042 Erik if (connp->conn_family == AF_INET6) 2215 0 stevel return (EAFNOSUPPORT); 2216 0 stevel 2217 0 stevel imsf = (struct ip_msfilter *)dbuf; 2218 0 stevel v4addr = imsf->imsf_interface.s_addr; 2219 11042 Erik v4group = imsf->imsf_multiaddr.s_addr; 2220 11042 Erik IN6_IPADDR_TO_V4MAPPED(v4group, &v6group); 2221 11042 Erik ill = ill_mcast_lookup(&v6group, v4addr, 0, IPCL_ZONEID(connp), 2222 11042 Erik ipst, &err); 2223 11042 Erik if (ill == NULL && v4addr != INADDR_ANY) 2224 11042 Erik err = ENXIO; 2225 0 stevel } else { 2226 0 stevel gf = (struct group_filter *)dbuf; 2227 0 stevel index = gf->gf_interface; 2228 0 stevel if (gf->gf_group.ss_family == AF_INET6) { 2229 0 stevel struct sockaddr_in6 *sin6; 2230 11042 Erik 2231 0 stevel sin6 = (struct sockaddr_in6 *)&gf->gf_group; 2232 11042 Erik v6group = sin6->sin6_addr; 2233 0 stevel } else if (gf->gf_group.ss_family == AF_INET) { 2234 0 stevel struct sockaddr_in *sin; 2235 11042 Erik 2236 0 stevel sin = (struct sockaddr_in *)&gf->gf_group; 2237 11042 Erik v4group = sin->sin_addr.s_addr; 2238 11042 Erik IN6_IPADDR_TO_V4MAPPED(v4group, &v6group); 2239 0 stevel } else { 2240 0 stevel return (EAFNOSUPPORT); 2241 0 stevel } 2242 11042 Erik ill = ill_mcast_lookup(&v6group, INADDR_ANY, index, 2243 11042 Erik IPCL_ZONEID(connp), ipst, &err); 2244 0 stevel } 2245 11042 Erik *illp = ill; 2246 0 stevel return (err); 2247 0 stevel } 2248 0 stevel 2249 0 stevel /* 2250 0 stevel * The structures used for the SIOC*MSFILTER ioctls usually must be copied 2251 0 stevel * in in two stages, as the first copyin tells us the size of the attached 2252 0 stevel * source buffer. This function is called by ip_wput_nondata() after the 2253 0 stevel * first copyin has completed; it figures out how big the second stage 2254 0 stevel * needs to be, and kicks it off. 2255 0 stevel * 2256 0 stevel * In some cases (numsrc < 2), the second copyin is not needed as the 2257 0 stevel * first one gets a complete structure containing 1 source addr. 2258 0 stevel * 2259 0 stevel * The function returns 0 if a second copyin has been started (i.e. there's 2260 0 stevel * no more work to be done right now), or 1 if the second copyin is not 2261 0 stevel * needed and ip_wput_nondata() can continue its processing. 2262 0 stevel */ 2263 0 stevel int 2264 0 stevel ip_copyin_msfilter(queue_t *q, mblk_t *mp) 2265 0 stevel { 2266 0 stevel struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 2267 0 stevel int cmd = iocp->ioc_cmd; 2268 0 stevel /* validity of this checked in ip_wput_nondata() */ 2269 0 stevel mblk_t *mp1 = mp->b_cont->b_cont; 2270 0 stevel int copysize = 0; 2271 0 stevel int offset; 2272 0 stevel 2273 0 stevel if (cmd == SIOCSMSFILTER || cmd == SIOCGMSFILTER) { 2274 0 stevel struct group_filter *gf = (struct group_filter *)mp1->b_rptr; 2275 0 stevel if (gf->gf_numsrc >= 2) { 2276 0 stevel offset = sizeof (struct group_filter); 2277 0 stevel copysize = GROUP_FILTER_SIZE(gf->gf_numsrc) - offset; 2278 0 stevel } 2279 0 stevel } else { 2280 0 stevel struct ip_msfilter *imsf = (struct ip_msfilter *)mp1->b_rptr; 2281 0 stevel if (imsf->imsf_numsrc >= 2) { 2282 0 stevel offset = sizeof (struct ip_msfilter); 2283 0 stevel copysize = IP_MSFILTER_SIZE(imsf->imsf_numsrc) - offset; 2284 0 stevel } 2285 0 stevel } 2286 0 stevel if (copysize > 0) { 2287 0 stevel mi_copyin_n(q, mp, offset, copysize); 2288 0 stevel return (0); 2289 0 stevel } 2290 0 stevel return (1); 2291 0 stevel } 2292 0 stevel 2293 0 stevel /* 2294 0 stevel * Handle the following optmgmt: 2295 0 stevel * IP_ADD_MEMBERSHIP must not have joined already 2296 11042 Erik * IPV6_JOIN_GROUP must not have joined already 2297 0 stevel * MCAST_JOIN_GROUP must not have joined already 2298 0 stevel * IP_BLOCK_SOURCE must have joined already 2299 0 stevel * MCAST_BLOCK_SOURCE must have joined already 2300 0 stevel * IP_JOIN_SOURCE_GROUP may have joined already 2301 0 stevel * MCAST_JOIN_SOURCE_GROUP may have joined already 2302 0 stevel * 2303 0 stevel * fmode and src parameters may be used to determine which option is 2304 11042 Erik * being set, as follows (IPV6_JOIN_GROUP and MCAST_JOIN_GROUP options 2305 0 stevel * are functionally equivalent): 2306 11042 Erik * opt fmode v6src 2307 11042 Erik * IP_ADD_MEMBERSHIP MODE_IS_EXCLUDE unspecified 2308 11042 Erik * IPV6_JOIN_GROUP MODE_IS_EXCLUDE unspecified 2309 11042 Erik * MCAST_JOIN_GROUP MODE_IS_EXCLUDE unspecified 2310 11042 Erik * IP_BLOCK_SOURCE MODE_IS_EXCLUDE IPv4-mapped addr 2311 11042 Erik * MCAST_BLOCK_SOURCE MODE_IS_EXCLUDE v6 addr 2312 11042 Erik * IP_JOIN_SOURCE_GROUP MODE_IS_INCLUDE IPv4-mapped addr 2313 11042 Erik * MCAST_JOIN_SOURCE_GROUP MODE_IS_INCLUDE v6 addr 2314 0 stevel * 2315 0 stevel * Changing the filter mode is not allowed; if a matching ilg already 2316 0 stevel * exists and fmode != ilg->ilg_fmode, EINVAL is returned. 2317 0 stevel * 2318 0 stevel * Verifies that there is a source address of appropriate scope for 2319 0 stevel * the group; if not, EADDRNOTAVAIL is returned. 2320 0 stevel * 2321 11042 Erik * The interface to be used may be identified by an IPv4 address or by an 2322 11042 Erik * interface index. 2323 11042 Erik * 2324 11042 Erik * Handles IPv4-mapped IPv6 multicast addresses by associating them 2325 11042 Erik * with the IPv4 address. Assumes that if v6group is v4-mapped, 2326 11042 Erik * v6src is also v4-mapped. 2327 0 stevel */ 2328 0 stevel int 2329 11042 Erik ip_opt_add_group(conn_t *connp, boolean_t checkonly, 2330 11042 Erik const in6_addr_t *v6group, ipaddr_t ifaddr, uint_t ifindex, 2331 11042 Erik mcast_record_t fmode, const in6_addr_t *v6src) 2332 0 stevel { 2333 11042 Erik ill_t *ill; 2334 11042 Erik char buf[INET6_ADDRSTRLEN]; 2335 11042 Erik int err; 2336 0 stevel 2337 11042 Erik err = ip_opt_check(connp, v6group, v6src, ifaddr, ifindex, &ill); 2338 0 stevel if (err != 0) { 2339 11042 Erik ip1dbg(("ip_opt_add_group: no ill for group %s/" 2340 11042 Erik "index %d\n", inet_ntop(AF_INET6, v6group, buf, 2341 11042 Erik sizeof (buf)), ifindex)); 2342 0 stevel return (err); 2343 0 stevel } 2344 0 stevel 2345 0 stevel if (checkonly) { 2346 0 stevel /* 2347 0 stevel * do not do operation, just pretend to - new T_CHECK 2348 0 stevel * semantics. The error return case above if encountered 2349 0 stevel * considered a good enough "check" here. 2350 0 stevel */ 2351 11042 Erik ill_refrele(ill); 2352 0 stevel return (0); 2353 0 stevel } 2354 0 stevel 2355 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 2356 11042 Erik err = ilg_add(connp, v6group, ifaddr, ifindex, ill, fmode, v6src); 2357 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 2358 11042 Erik ill_refrele(ill); 2359 0 stevel return (err); 2360 0 stevel } 2361 0 stevel 2362 0 stevel /* 2363 11042 Erik * Common for IPv6 and IPv4. 2364 11042 Erik * Here we handle ilgs that are still attached to their original ill 2365 11042 Erik * (the one ifaddr/ifindex points at), as well as detached ones. 2366 11042 Erik * The detached ones might have been attached to some other ill. 2367 0 stevel */ 2368 11042 Erik static int 2369 11042 Erik ip_opt_delete_group_excl(conn_t *connp, const in6_addr_t *v6group, 2370 11042 Erik ipaddr_t ifaddr, uint_t ifindex, mcast_record_t fmode, 2371 11042 Erik const in6_addr_t *v6src) 2372 0 stevel { 2373 11042 Erik ilg_t *ilg; 2374 11042 Erik boolean_t leaving; 2375 11042 Erik ilm_t *ilm; 2376 0 stevel ill_t *ill; 2377 11042 Erik int err = 0; 2378 0 stevel 2379 11042 Erik retry: 2380 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2381 11042 Erik ilg = ilg_lookup(connp, v6group, ifaddr, ifindex); 2382 11042 Erik if (ilg == NULL) { 2383 11042 Erik rw_exit(&connp->conn_ilg_lock); 2384 11042 Erik /* 2385 11042 Erik * Since we didn't have any ilg we now do the error checks 2386 11042 Erik * to determine the best errno. 2387 11042 Erik */ 2388 11042 Erik err = ip_opt_check(connp, v6group, v6src, ifaddr, ifindex, 2389 11042 Erik &ill); 2390 11042 Erik if (ill != NULL) { 2391 11042 Erik /* The only error was a missing ilg for the group */ 2392 11042 Erik ill_refrele(ill); 2393 11042 Erik err = EADDRNOTAVAIL; 2394 0 stevel } 2395 0 stevel return (err); 2396 0 stevel } 2397 0 stevel 2398 11042 Erik /* If the ilg is attached then we serialize using that ill */ 2399 11042 Erik ill = ilg->ilg_ill; 2400 11042 Erik if (ill != NULL) { 2401 11042 Erik /* Prevent the ill and ilg from being freed */ 2402 11042 Erik ill_refhold(ill); 2403 11042 Erik ilg_refhold(ilg); 2404 11042 Erik rw_exit(&connp->conn_ilg_lock); 2405 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 2406 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2407 11042 Erik if (ilg->ilg_condemned) { 2408 11042 Erik /* Disappeared */ 2409 11042 Erik ilg_refrele(ilg); 2410 11042 Erik rw_exit(&connp->conn_ilg_lock); 2411 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 2412 0 stevel ill_refrele(ill); 2413 11042 Erik goto retry; 2414 0 stevel } 2415 0 stevel } 2416 0 stevel 2417 0 stevel /* 2418 0 stevel * Decide if we're actually deleting the ilg or just removing a 2419 0 stevel * source filter address; if just removing an addr, make sure we 2420 0 stevel * aren't trying to change the filter mode, and that the addr is 2421 0 stevel * actually in our filter list already. If we're removing the 2422 0 stevel * last src in an include list, just delete the ilg. 2423 0 stevel */ 2424 11042 Erik if (IN6_IS_ADDR_UNSPECIFIED(v6src)) { 2425 0 stevel leaving = B_TRUE; 2426 0 stevel } else { 2427 0 stevel if (fmode != ilg->ilg_fmode) 2428 0 stevel err = EINVAL; 2429 0 stevel else if (ilg->ilg_filter == NULL || 2430 0 stevel !list_has_addr(ilg->ilg_filter, v6src)) 2431 0 stevel err = EADDRNOTAVAIL; 2432 0 stevel if (err != 0) { 2433 11042 Erik if (ill != NULL) 2434 11042 Erik ilg_refrele(ilg); 2435 11042 Erik rw_exit(&connp->conn_ilg_lock); 2436 11042 Erik goto done; 2437 0 stevel } 2438 0 stevel if (fmode == MODE_IS_INCLUDE && 2439 11042 Erik ilg->ilg_filter->sl_numsrc == 1) { 2440 11042 Erik leaving = B_TRUE; 2441 0 stevel v6src = NULL; 2442 11042 Erik } else { 2443 0 stevel leaving = B_FALSE; 2444 11042 Erik } 2445 0 stevel } 2446 11042 Erik ilm = ilg->ilg_ilm; 2447 11042 Erik if (leaving) 2448 11042 Erik ilg->ilg_ilm = NULL; 2449 0 stevel 2450 0 stevel ilg_delete(connp, ilg, v6src); 2451 11042 Erik if (ill != NULL) 2452 11042 Erik ilg_refrele(ilg); 2453 11042 Erik rw_exit(&connp->conn_ilg_lock); 2454 0 stevel 2455 11042 Erik if (ilm != NULL) { 2456 11042 Erik ASSERT(ill != NULL); 2457 11042 Erik (void) ip_delmulti_serial(ilm, B_FALSE, leaving); 2458 11042 Erik } 2459 11042 Erik done: 2460 11042 Erik if (ill != NULL) { 2461 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 2462 11042 Erik ill_refrele(ill); 2463 11042 Erik } 2464 11042 Erik return (err); 2465 0 stevel } 2466 0 stevel 2467 0 stevel /* 2468 0 stevel * Handle the following optmgmt: 2469 0 stevel * IP_DROP_MEMBERSHIP will leave 2470 11042 Erik * IPV6_LEAVE_GROUP will leave 2471 0 stevel * MCAST_LEAVE_GROUP will leave 2472 0 stevel * IP_UNBLOCK_SOURCE will not leave 2473 0 stevel * MCAST_UNBLOCK_SOURCE will not leave 2474 0 stevel * IP_LEAVE_SOURCE_GROUP may leave (if leaving last source) 2475 0 stevel * MCAST_LEAVE_SOURCE_GROUP may leave (if leaving last source) 2476 0 stevel * 2477 0 stevel * fmode and src parameters may be used to determine which option is 2478 11042 Erik * being set, as follows: 2479 0 stevel * opt fmode v6src 2480 11042 Erik * IP_DROP_MEMBERSHIP MODE_IS_INCLUDE unspecified 2481 0 stevel * IPV6_LEAVE_GROUP MODE_IS_INCLUDE unspecified 2482 0 stevel * MCAST_LEAVE_GROUP MODE_IS_INCLUDE unspecified 2483 11042 Erik * IP_UNBLOCK_SOURCE MODE_IS_EXCLUDE IPv4-mapped addr 2484 0 stevel * MCAST_UNBLOCK_SOURCE MODE_IS_EXCLUDE v6 addr 2485 11042 Erik * IP_LEAVE_SOURCE_GROUP MODE_IS_INCLUDE IPv4-mapped addr 2486 0 stevel * MCAST_LEAVE_SOURCE_GROUP MODE_IS_INCLUDE v6 addr 2487 0 stevel * 2488 0 stevel * Changing the filter mode is not allowed; if a matching ilg already 2489 0 stevel * exists and fmode != ilg->ilg_fmode, EINVAL is returned. 2490 0 stevel * 2491 11042 Erik * The interface to be used may be identified by an IPv4 address or by an 2492 11042 Erik * interface index. 2493 11042 Erik * 2494 0 stevel * Handles IPv4-mapped IPv6 multicast addresses by associating them 2495 11042 Erik * with the IPv4 address. Assumes that if v6group is v4-mapped, 2496 0 stevel * v6src is also v4-mapped. 2497 0 stevel */ 2498 0 stevel int 2499 11042 Erik ip_opt_delete_group(conn_t *connp, boolean_t checkonly, 2500 11042 Erik const in6_addr_t *v6group, ipaddr_t ifaddr, uint_t ifindex, 2501 11042 Erik mcast_record_t fmode, const in6_addr_t *v6src) 2502 0 stevel { 2503 0 stevel 2504 11042 Erik /* 2505 11042 Erik * In the normal case below we don't check for the ill existing. 2506 11042 Erik * Instead we look for an existing ilg in _excl. 2507 11042 Erik * If checkonly we sanity check the arguments 2508 11042 Erik */ 2509 11042 Erik if (checkonly) { 2510 11042 Erik ill_t *ill; 2511 11042 Erik int err; 2512 11042 Erik 2513 11042 Erik err = ip_opt_check(connp, v6group, v6src, ifaddr, ifindex, 2514 11042 Erik &ill); 2515 11042 Erik /* 2516 11042 Erik * do not do operation, just pretend to - new T_CHECK semantics. 2517 11042 Erik * ip_opt_check is considered a good enough "check" here. 2518 11042 Erik */ 2519 11042 Erik if (ill != NULL) 2520 11042 Erik ill_refrele(ill); 2521 0 stevel return (err); 2522 0 stevel } 2523 11042 Erik return (ip_opt_delete_group_excl(connp, v6group, ifaddr, ifindex, 2524 11042 Erik fmode, v6src)); 2525 0 stevel } 2526 0 stevel 2527 0 stevel /* 2528 0 stevel * Group mgmt for upper conn that passes things down 2529 0 stevel * to the interface multicast list (and DLPI) 2530 0 stevel * These routines can handle new style options that specify an interface name 2531 0 stevel * as opposed to an interface address (needed for general handling of 2532 0 stevel * unnumbered interfaces.) 2533 0 stevel */ 2534 0 stevel 2535 0 stevel /* 2536 0 stevel * Add a group to an upper conn group data structure and pass things down 2537 0 stevel * to the interface multicast list (and DLPI) 2538 11042 Erik * Common for IPv4 and IPv6; for IPv4 we can have an ifaddr. 2539 0 stevel */ 2540 0 stevel static int 2541 11042 Erik ilg_add(conn_t *connp, const in6_addr_t *v6group, ipaddr_t ifaddr, 2542 11042 Erik uint_t ifindex, ill_t *ill, mcast_record_t fmode, const in6_addr_t *v6src) 2543 0 stevel { 2544 0 stevel int error = 0; 2545 0 stevel ilg_t *ilg; 2546 0 stevel ilg_stat_t ilgstat; 2547 0 stevel slist_t *new_filter = NULL; 2548 0 stevel int new_fmode; 2549 11042 Erik ilm_t *ilm; 2550 0 stevel 2551 0 stevel if (!(ill->ill_flags & ILLF_MULTICAST)) 2552 0 stevel return (EADDRNOTAVAIL); 2553 0 stevel 2554 11042 Erik /* conn_ilg_lock protects the ilg list. */ 2555 11042 Erik ASSERT(MUTEX_HELD(&ill->ill_mcast_serializer)); 2556 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2557 11042 Erik ilg = ilg_lookup(connp, v6group, ifaddr, ifindex); 2558 0 stevel 2559 0 stevel /* 2560 0 stevel * Depending on the option we're handling, may or may not be okay 2561 0 stevel * if group has already been added. Figure out our rules based 2562 0 stevel * on fmode and src params. Also make sure there's enough room 2563 0 stevel * in the filter if we're adding a source to an existing filter. 2564 0 stevel */ 2565 0 stevel if (IN6_IS_ADDR_UNSPECIFIED(v6src)) { 2566 0 stevel /* we're joining for all sources, must not have joined */ 2567 0 stevel if (ilg != NULL) 2568 0 stevel error = EADDRINUSE; 2569 0 stevel } else { 2570 0 stevel if (fmode == MODE_IS_EXCLUDE) { 2571 0 stevel /* (excl {addr}) => block source, must have joined */ 2572 0 stevel if (ilg == NULL) 2573 0 stevel error = EADDRNOTAVAIL; 2574 0 stevel } 2575 0 stevel /* (incl {addr}) => join source, may have joined */ 2576 0 stevel 2577 0 stevel if (ilg != NULL && 2578 0 stevel SLIST_CNT(ilg->ilg_filter) == MAX_FILTER_SIZE) 2579 0 stevel error = ENOBUFS; 2580 0 stevel } 2581 0 stevel if (error != 0) { 2582 11042 Erik rw_exit(&connp->conn_ilg_lock); 2583 0 stevel return (error); 2584 0 stevel } 2585 0 stevel 2586 0 stevel /* 2587 0 stevel * Alloc buffer to copy new state into (see below) before 2588 0 stevel * we make any changes, so we can bail if it fails. 2589 0 stevel */ 2590 0 stevel if ((new_filter = l_alloc()) == NULL) { 2591 11042 Erik rw_exit(&connp->conn_ilg_lock); 2592 0 stevel return (ENOMEM); 2593 0 stevel } 2594 0 stevel 2595 0 stevel if (ilg == NULL) { 2596 8485 Peter if ((ilg = conn_ilg_alloc(connp, &error)) == NULL) { 2597 11042 Erik rw_exit(&connp->conn_ilg_lock); 2598 8485 Peter l_free(new_filter); 2599 8485 Peter return (error); 2600 0 stevel } 2601 11042 Erik ilg->ilg_ifindex = ifindex; 2602 11042 Erik ilg->ilg_ifaddr = ifaddr; 2603 0 stevel if (!IN6_IS_ADDR_UNSPECIFIED(v6src)) { 2604 0 stevel ilg->ilg_filter = l_alloc(); 2605 0 stevel if (ilg->ilg_filter == NULL) { 2606 0 stevel ilg_delete(connp, ilg, NULL); 2607 11042 Erik rw_exit(&connp->conn_ilg_lock); 2608 0 stevel l_free(new_filter); 2609 0 stevel return (ENOMEM); 2610 0 stevel } 2611 0 stevel ilg->ilg_filter->sl_numsrc = 1; 2612 0 stevel ilg->ilg_filter->sl_addr[0] = *v6src; 2613 0 stevel } 2614 0 stevel ilgstat = ILGSTAT_NEW; 2615 0 stevel ilg->ilg_v6group = *v6group; 2616 0 stevel ilg->ilg_fmode = fmode; 2617 0 stevel ilg->ilg_ill = ill; 2618 0 stevel } else { 2619 0 stevel int index; 2620 0 stevel if (ilg->ilg_fmode != fmode || IN6_IS_ADDR_UNSPECIFIED(v6src)) { 2621 11042 Erik rw_exit(&connp->conn_ilg_lock); 2622 0 stevel l_free(new_filter); 2623 0 stevel return (EINVAL); 2624 0 stevel } 2625 0 stevel if (ilg->ilg_filter == NULL) { 2626 0 stevel ilg->ilg_filter = l_alloc(); 2627 0 stevel if (ilg->ilg_filter == NULL) { 2628 11042 Erik rw_exit(&connp->conn_ilg_lock); 2629 0 stevel l_free(new_filter); 2630 0 stevel return (ENOMEM); 2631 0 stevel } 2632 0 stevel } 2633 0 stevel if (list_has_addr(ilg->ilg_filter, v6src)) { 2634 11042 Erik rw_exit(&connp->conn_ilg_lock); 2635 0 stevel l_free(new_filter); 2636 0 stevel return (EADDRNOTAVAIL); 2637 0 stevel } 2638 0 stevel ilgstat = ILGSTAT_CHANGE; 2639 0 stevel index = ilg->ilg_filter->sl_numsrc++; 2640 0 stevel ilg->ilg_filter->sl_addr[index] = *v6src; 2641 0 stevel } 2642 0 stevel 2643 0 stevel /* 2644 0 stevel * Save copy of ilg's filter state to pass to other functions, 2645 11042 Erik * so we can release conn_ilg_lock now. 2646 0 stevel */ 2647 0 stevel new_fmode = ilg->ilg_fmode; 2648 0 stevel l_copy(ilg->ilg_filter, new_filter); 2649 0 stevel 2650 11042 Erik rw_exit(&connp->conn_ilg_lock); 2651 0 stevel 2652 0 stevel /* 2653 0 stevel * Now update the ill. We wait to do this until after the ilg 2654 0 stevel * has been updated because we need to update the src filter 2655 0 stevel * info for the ill, which involves looking at the status of 2656 0 stevel * all the ilgs associated with this group/interface pair. 2657 0 stevel */ 2658 11042 Erik ilm = ip_addmulti_serial(v6group, ill, connp->conn_zoneid, ilgstat, 2659 11042 Erik new_fmode, new_filter, &error); 2660 11042 Erik 2661 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2662 11042 Erik /* 2663 11042 Erik * Must look up the ilg again since we've not been holding 2664 11042 Erik * conn_ilg_lock. The ilg could have disappeared due to an unplumb 2665 11042 Erik * having called conn_update_ill, which can run once we dropped the 2666 11042 Erik * conn_ilg_lock above. 2667 11042 Erik */ 2668 11042 Erik ilg = ilg_lookup(connp, v6group, ifaddr, ifindex); 2669 11042 Erik if (ilg == NULL) { 2670 11042 Erik rw_exit(&connp->conn_ilg_lock); 2671 11042 Erik if (ilm != NULL) { 2672 11042 Erik (void) ip_delmulti_serial(ilm, B_FALSE, 2673 11042 Erik (ilgstat == ILGSTAT_NEW)); 2674 11042 Erik } 2675 11042 Erik error = ENXIO; 2676 11042 Erik goto free_and_exit; 2677 0 stevel } 2678 0 stevel 2679 11042 Erik if (ilm != NULL) { 2680 11042 Erik /* Succeeded. Update the ilg to point at the ilm */ 2681 11042 Erik if (ilgstat == ILGSTAT_NEW) { 2682 11042 Erik ASSERT(ilg->ilg_ilm == NULL); 2683 11042 Erik ilg->ilg_ilm = ilm; 2684 11042 Erik ilm->ilm_ifaddr = ifaddr; /* For netstat */ 2685 11042 Erik } else { 2686 11042 Erik /* 2687 11042 Erik * ip_addmulti didn't get a held ilm for 2688 11042 Erik * ILGSTAT_CHANGE; ilm_refcnt was unchanged. 2689 11042 Erik */ 2690 11042 Erik ASSERT(ilg->ilg_ilm == ilm); 2691 11042 Erik } 2692 11042 Erik } else { 2693 11042 Erik ASSERT(error != 0); 2694 11042 Erik /* 2695 11042 Erik * Failed to allocate the ilm. 2696 11042 Erik * Need to undo what we did before calling ip_addmulti() 2697 11042 Erik * If ENETDOWN just clear ill_ilg since so that we 2698 11042 Erik * will rejoin when the ill comes back; don't report ENETDOWN 2699 11042 Erik * to application. 2700 11042 Erik */ 2701 11042 Erik if (ilgstat == ILGSTAT_NEW && error == ENETDOWN) { 2702 11042 Erik ilg->ilg_ill = NULL; 2703 11042 Erik error = 0; 2704 11042 Erik } else { 2705 11042 Erik in6_addr_t delsrc = 2706 11042 Erik (ilgstat == ILGSTAT_NEW) ? ipv6_all_zeros : *v6src; 2707 11042 Erik 2708 11042 Erik ilg_delete(connp, ilg, &delsrc); 2709 11042 Erik } 2710 11042 Erik } 2711 11042 Erik rw_exit(&connp->conn_ilg_lock); 2712 11042 Erik 2713 11042 Erik free_and_exit: 2714 0 stevel l_free(new_filter); 2715 11042 Erik return (error); 2716 0 stevel } 2717 0 stevel 2718 0 stevel /* 2719 11042 Erik * Find an IPv4 ilg matching group, ill and source. 2720 11042 Erik * The group and source can't be INADDR_ANY here so no need to translate to 2721 11042 Erik * the unspecified IPv6 address. 2722 0 stevel */ 2723 11042 Erik boolean_t 2724 11042 Erik conn_hasmembers_ill_withsrc_v4(conn_t *connp, ipaddr_t group, ipaddr_t src, 2725 11042 Erik ill_t *ill) 2726 0 stevel { 2727 0 stevel in6_addr_t v6group, v6src; 2728 0 stevel int i; 2729 0 stevel boolean_t isinlist; 2730 0 stevel ilg_t *ilg; 2731 0 stevel 2732 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_READER); 2733 11042 Erik IN6_IPADDR_TO_V4MAPPED(group, &v6group); 2734 11042 Erik for (ilg = connp->conn_ilg; ilg != NULL; ilg = ilg->ilg_next) { 2735 11042 Erik if (ilg->ilg_condemned) 2736 11042 Erik continue; 2737 0 stevel 2738 11042 Erik /* ilg_ill could be NULL if an add is in progress */ 2739 11042 Erik if (ilg->ilg_ill != ill) 2740 11042 Erik continue; 2741 0 stevel 2742 11042 Erik /* The callers use upper ill for IPMP */ 2743 11042 Erik ASSERT(!IS_UNDER_IPMP(ill)); 2744 11042 Erik if (IN6_ARE_ADDR_EQUAL(&ilg->ilg_v6group, &v6group)) { 2745 0 stevel if (SLIST_IS_EMPTY(ilg->ilg_filter)) { 2746 0 stevel /* no source filter, so this is a match */ 2747 11042 Erik rw_exit(&connp->conn_ilg_lock); 2748 11042 Erik return (B_TRUE); 2749 0 stevel } 2750 0 stevel break; 2751 0 stevel } 2752 0 stevel } 2753 11042 Erik if (ilg == NULL) { 2754 11042 Erik rw_exit(&connp->conn_ilg_lock); 2755 11042 Erik return (B_FALSE); 2756 11042 Erik } 2757 0 stevel 2758 0 stevel /* 2759 0 stevel * we have an ilg with matching ill and group; but 2760 0 stevel * the ilg has a source list that we must check. 2761 0 stevel */ 2762 0 stevel IN6_IPADDR_TO_V4MAPPED(src, &v6src); 2763 0 stevel isinlist = B_FALSE; 2764 0 stevel for (i = 0; i < ilg->ilg_filter->sl_numsrc; i++) { 2765 0 stevel if (IN6_ARE_ADDR_EQUAL(&v6src, &ilg->ilg_filter->sl_addr[i])) { 2766 0 stevel isinlist = B_TRUE; 2767 0 stevel break; 2768 0 stevel } 2769 0 stevel } 2770 0 stevel 2771 0 stevel if ((isinlist && ilg->ilg_fmode == MODE_IS_INCLUDE) || 2772 11042 Erik (!isinlist && ilg->ilg_fmode == MODE_IS_EXCLUDE)) { 2773 11042 Erik rw_exit(&connp->conn_ilg_lock); 2774 11042 Erik return (B_TRUE); 2775 11042 Erik } 2776 11042 Erik rw_exit(&connp->conn_ilg_lock); 2777 11042 Erik return (B_FALSE); 2778 0 stevel } 2779 0 stevel 2780 0 stevel /* 2781 0 stevel * Find an IPv6 ilg matching group, ill, and source 2782 0 stevel */ 2783 11042 Erik boolean_t 2784 11042 Erik conn_hasmembers_ill_withsrc_v6(conn_t *connp, const in6_addr_t *v6group, 2785 0 stevel const in6_addr_t *v6src, ill_t *ill) 2786 0 stevel { 2787 0 stevel int i; 2788 0 stevel boolean_t isinlist; 2789 0 stevel ilg_t *ilg; 2790 0 stevel 2791 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_READER); 2792 11042 Erik for (ilg = connp->conn_ilg; ilg != NULL; ilg = ilg->ilg_next) { 2793 11042 Erik if (ilg->ilg_condemned) 2794 11042 Erik continue; 2795 0 stevel 2796 11042 Erik /* ilg_ill could be NULL if an add is in progress */ 2797 11042 Erik if (ilg->ilg_ill != ill) 2798 0 stevel continue; 2799 11042 Erik 2800 11042 Erik /* The callers use upper ill for IPMP */ 2801 11042 Erik ASSERT(!IS_UNDER_IPMP(ill)); 2802 11042 Erik if (IN6_ARE_ADDR_EQUAL(&ilg->ilg_v6group, v6group)) { 2803 0 stevel if (SLIST_IS_EMPTY(ilg->ilg_filter)) { 2804 0 stevel /* no source filter, so this is a match */ 2805 11042 Erik rw_exit(&connp->conn_ilg_lock); 2806 11042 Erik return (B_TRUE); 2807 0 stevel } 2808 0 stevel break; 2809 0 stevel } 2810 0 stevel } 2811 11042 Erik if (ilg == NULL) { 2812 11042 Erik rw_exit(&connp->conn_ilg_lock); 2813 11042 Erik return (B_FALSE); 2814 11042 Erik } 2815 0 stevel 2816 0 stevel /* 2817 0 stevel * we have an ilg with matching ill and group; but 2818 0 stevel * the ilg has a source list that we must check. 2819 0 stevel */ 2820 0 stevel isinlist = B_FALSE; 2821 0 stevel for (i = 0; i < ilg->ilg_filter->sl_numsrc; i++) { 2822 0 stevel if (IN6_ARE_ADDR_EQUAL(v6src, &ilg->ilg_filter->sl_addr[i])) { 2823 0 stevel isinlist = B_TRUE; 2824 0 stevel break; 2825 0 stevel } 2826 0 stevel } 2827 0 stevel 2828 0 stevel if ((isinlist && ilg->ilg_fmode == MODE_IS_INCLUDE) || 2829 11042 Erik (!isinlist && ilg->ilg_fmode == MODE_IS_EXCLUDE)) { 2830 11042 Erik rw_exit(&connp->conn_ilg_lock); 2831 11042 Erik return (B_TRUE); 2832 11042 Erik } 2833 11042 Erik rw_exit(&connp->conn_ilg_lock); 2834 11042 Erik return (B_FALSE); 2835 0 stevel } 2836 0 stevel 2837 0 stevel /* 2838 11042 Erik * Find an ilg matching group and ifaddr/ifindex. 2839 11042 Erik * We check both ifaddr and ifindex even though at most one of them 2840 11042 Erik * will be non-zero; that way we always find the right one. 2841 0 stevel */ 2842 11042 Erik static ilg_t * 2843 11042 Erik ilg_lookup(conn_t *connp, const in6_addr_t *v6group, ipaddr_t ifaddr, 2844 11042 Erik uint_t ifindex) 2845 0 stevel { 2846 0 stevel ilg_t *ilg; 2847 0 stevel 2848 11042 Erik ASSERT(RW_LOCK_HELD(&connp->conn_ilg_lock)); 2849 0 stevel 2850 11042 Erik for (ilg = connp->conn_ilg; ilg != NULL; ilg = ilg->ilg_next) { 2851 11042 Erik if (ilg->ilg_condemned) 2852 0 stevel continue; 2853 11042 Erik 2854 11042 Erik if (ilg->ilg_ifaddr == ifaddr && 2855 11042 Erik ilg->ilg_ifindex == ifindex && 2856 0 stevel IN6_ARE_ADDR_EQUAL(&ilg->ilg_v6group, v6group)) 2857 6379 sowmini return (ilg); 2858 0 stevel } 2859 0 stevel return (NULL); 2860 0 stevel } 2861 0 stevel 2862 0 stevel /* 2863 0 stevel * If a source address is passed in (src != NULL and src is not 2864 0 stevel * unspecified), remove the specified src addr from the given ilg's 2865 0 stevel * filter list, else delete the ilg. 2866 0 stevel */ 2867 0 stevel static void 2868 0 stevel ilg_delete(conn_t *connp, ilg_t *ilg, const in6_addr_t *src) 2869 0 stevel { 2870 11042 Erik ASSERT(RW_WRITE_HELD(&connp->conn_ilg_lock)); 2871 11042 Erik ASSERT(ilg->ilg_ptpn != NULL); 2872 11042 Erik ASSERT(!ilg->ilg_condemned); 2873 0 stevel 2874 0 stevel if (src == NULL || IN6_IS_ADDR_UNSPECIFIED(src)) { 2875 11042 Erik FREE_SLIST(ilg->ilg_filter); 2876 11042 Erik ilg->ilg_filter = NULL; 2877 0 stevel 2878 11042 Erik ASSERT(ilg->ilg_ilm == NULL); 2879 11042 Erik ilg->ilg_ill = NULL; 2880 11042 Erik ilg->ilg_condemned = B_TRUE; 2881 0 stevel 2882 11042 Erik /* ilg_inactive will unlink from the list */ 2883 11042 Erik ilg_refrele(ilg); 2884 0 stevel } else { 2885 0 stevel l_remove(ilg->ilg_filter, src); 2886 0 stevel } 2887 0 stevel } 2888 0 stevel 2889 0 stevel /* 2890 11042 Erik * Called from conn close. No new ilg can be added or removed 2891 0 stevel * because CONN_CLOSING has been set by ip_close. ilg_add / ilg_delete 2892 0 stevel * will return error if conn has started closing. 2893 11042 Erik * 2894 11042 Erik * We handle locking as follows. 2895 11042 Erik * Under conn_ilg_lock we get the first ilg. As we drop the conn_ilg_lock to 2896 11042 Erik * proceed with the ilm part of the delete we hold a reference on both the ill 2897 11042 Erik * and the ilg. This doesn't prevent changes to the ilg, but prevents it from 2898 11042 Erik * being deleted. 2899 11042 Erik * 2900 11042 Erik * Since the ilg_add code path uses two locks (conn_ilg_lock for the ilg part, 2901 11042 Erik * and ill_mcast_lock for the ip_addmulti part) we can run at a point between 2902 11042 Erik * the two. At that point ilg_ill is set, but ilg_ilm hasn't yet been set. In 2903 11042 Erik * that case we delete the ilg here, which makes ilg_add discover that the ilg 2904 11042 Erik * has disappeared when ip_addmulti returns, so it will discard the ilm it just 2905 11042 Erik * added. 2906 0 stevel */ 2907 0 stevel void 2908 0 stevel ilg_delete_all(conn_t *connp) 2909 0 stevel { 2910 11042 Erik ilg_t *ilg, *next_ilg, *held_ilg; 2911 11042 Erik ilm_t *ilm; 2912 11042 Erik ill_t *ill; 2913 11042 Erik boolean_t need_refrele; 2914 0 stevel 2915 11042 Erik /* 2916 11042 Erik * Can not run if there is a conn_update_ill already running. 2917 11042 Erik * Wait for it to complete. Caller should have already set CONN_CLOSING 2918 11042 Erik * which prevents any new threads to run in conn_update_ill. 2919 11042 Erik */ 2920 0 stevel mutex_enter(&connp->conn_lock); 2921 11042 Erik ASSERT(connp->conn_state_flags & CONN_CLOSING); 2922 11042 Erik while (connp->conn_state_flags & CONN_UPDATE_ILL) 2923 11042 Erik cv_wait(&connp->conn_cv, &connp->conn_lock); 2924 11042 Erik mutex_exit(&connp->conn_lock); 2925 11042 Erik 2926 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2927 11042 Erik ilg = connp->conn_ilg; 2928 11042 Erik held_ilg = NULL; 2929 11042 Erik while (ilg != NULL) { 2930 11042 Erik if (ilg->ilg_condemned) { 2931 11042 Erik ilg = ilg->ilg_next; 2932 8485 Peter continue; 2933 0 stevel } 2934 11042 Erik /* If the ilg is detached then no need to serialize */ 2935 11042 Erik if (ilg->ilg_ilm == NULL) { 2936 11042 Erik next_ilg = ilg->ilg_next; 2937 11042 Erik ilg_delete(connp, ilg, NULL); 2938 11042 Erik ilg = next_ilg; 2939 11042 Erik continue; 2940 11042 Erik } 2941 11042 Erik ill = ilg->ilg_ilm->ilm_ill; 2942 8485 Peter 2943 0 stevel /* 2944 11042 Erik * In order to serialize on the ill we try to enter 2945 11042 Erik * and if that fails we unlock and relock and then 2946 11042 Erik * check that we still have an ilm. 2947 0 stevel */ 2948 11042 Erik need_refrele = B_FALSE; 2949 11042 Erik if (!mutex_tryenter(&ill->ill_mcast_serializer)) { 2950 11042 Erik ill_refhold(ill); 2951 11042 Erik need_refrele = B_TRUE; 2952 11042 Erik ilg_refhold(ilg); 2953 11042 Erik if (held_ilg != NULL) 2954 11042 Erik ilg_refrele(held_ilg); 2955 11042 Erik held_ilg = ilg; 2956 11042 Erik rw_exit(&connp->conn_ilg_lock); 2957 11042 Erik mutex_enter(&ill->ill_mcast_serializer); 2958 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2959 11042 Erik if (ilg->ilg_condemned) { 2960 11042 Erik ilg = ilg->ilg_next; 2961 11042 Erik goto next; 2962 11042 Erik } 2963 11042 Erik } 2964 11042 Erik ilm = ilg->ilg_ilm; 2965 11042 Erik ilg->ilg_ilm = NULL; 2966 11042 Erik next_ilg = ilg->ilg_next; 2967 11042 Erik ilg_delete(connp, ilg, NULL); 2968 11042 Erik ilg = next_ilg; 2969 11042 Erik rw_exit(&connp->conn_ilg_lock); 2970 8485 Peter 2971 11042 Erik if (ilm != NULL) 2972 11042 Erik (void) ip_delmulti_serial(ilm, B_FALSE, B_TRUE); 2973 8485 Peter 2974 11042 Erik next: 2975 11042 Erik mutex_exit(&ill->ill_mcast_serializer); 2976 11042 Erik if (need_refrele) { 2977 11042 Erik /* Drop ill reference while we hold no locks */ 2978 11042 Erik ill_refrele(ill); 2979 0 stevel } 2980 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 2981 0 stevel } 2982 11042 Erik if (held_ilg != NULL) 2983 11042 Erik ilg_refrele(held_ilg); 2984 11042 Erik rw_exit(&connp->conn_ilg_lock); 2985 0 stevel } 2986 0 stevel 2987 0 stevel /* 2988 11042 Erik * Attach the ilg to an ilm on the ill. If it fails we leave ilg_ill as NULL so 2989 11042 Erik * that a subsequent attempt can attach it. 2990 11042 Erik * Drops and reacquires conn_ilg_lock. 2991 0 stevel */ 2992 0 stevel static void 2993 11042 Erik ilg_attach(conn_t *connp, ilg_t *ilg, ill_t *ill) 2994 0 stevel { 2995 11042 Erik ilg_stat_t ilgstat; 2996 11042 Erik slist_t *new_filter; 2997 11042 Erik int new_fmode; 2998 11042 Erik in6_addr_t v6group; 2999 11042 Erik ipaddr_t ifaddr; 3000 11042 Erik uint_t ifindex; 3001 11042 Erik ilm_t *ilm; 3002 11042 Erik int error = 0; 3003 11042 Erik 3004 11042 Erik ASSERT(RW_WRITE_HELD(&connp->conn_ilg_lock)); 3005 11042 Erik /* 3006 11042 Erik * Alloc buffer to copy new state into (see below) before 3007 11042 Erik * we make any changes, so we can bail if it fails. 3008 11042 Erik */ 3009 11042 Erik if ((new_filter = l_alloc()) == NULL) 3010 11042 Erik return; 3011 0 stevel 3012 0 stevel /* 3013 11042 Erik * Save copy of ilg's filter state to pass to other functions, so 3014 11042 Erik * we can release conn_ilg_lock now. 3015 11042 Erik * Set ilg_ill so that an unplumb can find us. 3016 0 stevel */ 3017 11042 Erik new_fmode = ilg->ilg_fmode; 3018 11042 Erik l_copy(ilg->ilg_filter, new_filter); 3019 11042 Erik v6group = ilg->ilg_v6group; 3020 11042 Erik ifaddr = ilg->ilg_ifaddr; 3021 11042 Erik ifindex = ilg->ilg_ifindex; 3022 11042 Erik ilgstat = ILGSTAT_NEW; 3023 0 stevel 3024 11042 Erik ilg->ilg_ill = ill; 3025 11042 Erik ASSERT(ilg->ilg_ilm == NULL); 3026 11042 Erik rw_exit(&connp->conn_ilg_lock); 3027 11042 Erik 3028 11042 Erik ilm = ip_addmulti_serial(&v6group, ill, connp->conn_zoneid, ilgstat, 3029 11042 Erik new_fmode, new_filter, &error); 3030 11042 Erik l_free(new_filter); 3031 11042 Erik 3032 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 3033 0 stevel /* 3034 11042 Erik * Must look up the ilg again since we've not been holding 3035 11042 Erik * conn_ilg_lock. The ilg could have disappeared due to an unplumb 3036 11042 Erik * having called conn_update_ill, which can run once we dropped the 3037 11042 Erik * conn_ilg_lock above. 3038 0 stevel */ 3039 11042 Erik ilg = ilg_lookup(connp, &v6group, ifaddr, ifindex); 3040 11042 Erik if (ilg == NULL) { 3041 11042 Erik if (ilm != NULL) { 3042 11042 Erik rw_exit(&connp->conn_ilg_lock); 3043 11042 Erik (void) ip_delmulti_serial(ilm, B_FALSE, 3044 11042 Erik (ilgstat == ILGSTAT_NEW)); 3045 11042 Erik rw_enter(&connp->conn_ilg_lock, RW_WRITER); 3046 11042 Erik } 3047 11042 Erik return; 3048 0 stevel } 3049 11042 Erik if (ilm == NULL) { 3050 11042 Erik ilg->ilg_ill = NULL; 3051 11042 Erik return; 3052 0 stevel } 3053 11042 Erik ASSERT(ilg->ilg_ilm == NULL); 3054 11042 Erik ilg->ilg_ilm = ilm; 3055 11042 Erik ilm->ilm_ifaddr = ifaddr; /* For netstat */ 3056 0 stevel } 3057 0 stevel 3058 0 stevel /* 3059 0 stevel * Called when an ill is unplumbed to make sure that there are no 3060 11042 Erik * dangling conn references to that ill. In that case ill is non-NULL and 3061 11042 Erik * we make sure we remove all references to it. 3062 11042 Erik * Also called when we should revisit the ilg_ill used for multicast 3063 11042 Erik * memberships, in which case ill is NULL. 3064 11042 Erik * 3065 11042 Erik * conn is held by caller. 3066 11042 Erik * 3067 11042 Erik * Note that ipcl_walk only walks conns that are not yet condemned. 3068 11042 Erik * condemned conns can't be refheld. For this reason, conn must become clean 3069 11042 Erik * first, i.e. it must not refer to any ill/ire and then only set 3070 11042 Erik * condemned flag. 3071 11042 Erik * 3072