1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2007-2009 Bruce Simpson. 5 * Copyright (c) 2005 Robert N. M. Watson. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * IPv4 multicast socket, group, and socket option processing module. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/mbuf.h> 43 #include <sys/protosw.h> 44 #include <sys/socket.h> 45 #include <sys/socketvar.h> 46 #include <sys/protosw.h> 47 #include <sys/sysctl.h> 48 #include <sys/ktr.h> 49 #include <sys/taskqueue.h> 50 #include <sys/tree.h> 51 52 #include <net/if.h> 53 #include <net/if_var.h> 54 #include <net/if_dl.h> 55 #include <net/route.h> 56 #include <net/route/nhop.h> 57 #include <net/vnet.h> 58 59 #include <net/ethernet.h> 60 61 #include <netinet/in.h> 62 #include <netinet/in_systm.h> 63 #include <netinet/in_fib.h> 64 #include <netinet/in_pcb.h> 65 #include <netinet/in_var.h> 66 #include <net/if_private.h> 67 #include <netinet/ip_var.h> 68 #include <netinet/igmp_var.h> 69 70 #ifndef KTR_IGMPV3 71 #define KTR_IGMPV3 KTR_INET 72 #endif 73 74 #ifndef __SOCKUNION_DECLARED 75 union sockunion { 76 struct sockaddr_storage ss; 77 struct sockaddr sa; 78 struct sockaddr_dl sdl; 79 struct sockaddr_in sin; 80 }; 81 typedef union sockunion sockunion_t; 82 #define __SOCKUNION_DECLARED 83 #endif /* __SOCKUNION_DECLARED */ 84 85 static MALLOC_DEFINE(M_INMFILTER, "in_mfilter", 86 "IPv4 multicast PCB-layer source filter"); 87 static MALLOC_DEFINE(M_IPMADDR, "in_multi", "IPv4 multicast group"); 88 static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "IPv4 multicast options"); 89 static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource", 90 "IPv4 multicast IGMP-layer source filter"); 91 92 /* 93 * Locking: 94 * 95 * - Lock order is: IN_MULTI_LOCK, INP_WLOCK, IN_MULTI_LIST_LOCK, IGMP_LOCK, 96 * IF_ADDR_LOCK. 97 * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however 98 * it can be taken by code in net/if.c also. 99 * - ip_moptions and in_mfilter are covered by the INP_WLOCK. 100 * 101 * struct in_multi is covered by IN_MULTI_LIST_LOCK. There isn't strictly 102 * any need for in_multi itself to be virtualized -- it is bound to an ifp 103 * anyway no matter what happens. 104 */ 105 struct mtx in_multi_list_mtx; 106 MTX_SYSINIT(in_multi_mtx, &in_multi_list_mtx, "in_multi_list_mtx", MTX_DEF); 107 108 struct mtx in_multi_free_mtx; 109 MTX_SYSINIT(in_multi_free_mtx, &in_multi_free_mtx, "in_multi_free_mtx", MTX_DEF); 110 111 struct sx in_multi_sx; 112 SX_SYSINIT(in_multi_sx, &in_multi_sx, "in_multi_sx"); 113 114 /* 115 * Functions with non-static linkage defined in this file should be 116 * declared in in_var.h: 117 * imo_multi_filter() 118 * in_joingroup() 119 * in_joingroup_locked() 120 * in_leavegroup() 121 * in_leavegroup_locked() 122 * and ip_var.h: 123 * inp_freemoptions() 124 * inp_getmoptions() 125 * inp_setmoptions() 126 */ 127 static void imf_commit(struct in_mfilter *); 128 static int imf_get_source(struct in_mfilter *imf, 129 const struct sockaddr_in *psin, 130 struct in_msource **); 131 static struct in_msource * 132 imf_graft(struct in_mfilter *, const uint8_t, 133 const struct sockaddr_in *); 134 static void imf_leave(struct in_mfilter *); 135 static int imf_prune(struct in_mfilter *, const struct sockaddr_in *); 136 static void imf_purge(struct in_mfilter *); 137 static void imf_rollback(struct in_mfilter *); 138 static void imf_reap(struct in_mfilter *); 139 static struct in_mfilter * 140 imo_match_group(const struct ip_moptions *, 141 const struct ifnet *, const struct sockaddr *); 142 static struct in_msource * 143 imo_match_source(struct in_mfilter *, const struct sockaddr *); 144 static void ims_merge(struct ip_msource *ims, 145 const struct in_msource *lims, const int rollback); 146 static int in_getmulti(struct ifnet *, const struct in_addr *, 147 struct in_multi **); 148 static int inm_get_source(struct in_multi *inm, const in_addr_t haddr, 149 const int noalloc, struct ip_msource **pims); 150 #ifdef KTR 151 static int inm_is_ifp_detached(const struct in_multi *); 152 #endif 153 static int inm_merge(struct in_multi *, /*const*/ struct in_mfilter *); 154 static void inm_purge(struct in_multi *); 155 static void inm_reap(struct in_multi *); 156 static void inm_release(struct in_multi *); 157 static struct ip_moptions * 158 inp_findmoptions(struct inpcb *); 159 static int inp_get_source_filters(struct inpcb *, struct sockopt *); 160 static int inp_join_group(struct inpcb *, struct sockopt *); 161 static int inp_leave_group(struct inpcb *, struct sockopt *); 162 static int inp_block_unblock_source(struct inpcb *, struct sockopt *); 163 static int inp_set_multicast_if(struct inpcb *, struct sockopt *); 164 static int inp_set_source_filters(struct inpcb *, struct sockopt *); 165 static int sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS); 166 167 static SYSCTL_NODE(_net_inet_ip, OID_AUTO, mcast, 168 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 169 "IPv4 multicast"); 170 171 static u_long in_mcast_maxgrpsrc = IP_MAX_GROUP_SRC_FILTER; 172 SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxgrpsrc, 173 CTLFLAG_RWTUN, &in_mcast_maxgrpsrc, 0, 174 "Max source filters per group"); 175 176 static u_long in_mcast_maxsocksrc = IP_MAX_SOCK_SRC_FILTER; 177 SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxsocksrc, 178 CTLFLAG_RWTUN, &in_mcast_maxsocksrc, 0, 179 "Max source filters per socket"); 180 181 int in_mcast_loop = IP_DEFAULT_MULTICAST_LOOP; 182 SYSCTL_INT(_net_inet_ip_mcast, OID_AUTO, loop, CTLFLAG_RWTUN, 183 &in_mcast_loop, 0, "Loopback multicast datagrams by default"); 184 185 static SYSCTL_NODE(_net_inet_ip_mcast, OID_AUTO, filters, 186 CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip_mcast_filters, 187 "Per-interface stack-wide source filters"); 188 189 #ifdef KTR 190 /* 191 * Inline function which wraps assertions for a valid ifp. 192 * The ifnet layer will set the ifma's ifp pointer to NULL if the ifp 193 * is detached. 194 */ 195 static int __inline 196 inm_is_ifp_detached(const struct in_multi *inm) 197 { 198 struct ifnet *ifp; 199 200 KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__)); 201 ifp = inm->inm_ifma->ifma_ifp; 202 if (ifp != NULL) { 203 /* 204 * Sanity check that netinet's notion of ifp is the 205 * same as net's. 206 */ 207 KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__)); 208 } 209 210 return (ifp == NULL); 211 } 212 #endif 213 214 /* 215 * Interface detach can happen in a taskqueue thread context, so we must use a 216 * dedicated thread to avoid deadlocks when draining inm_release tasks. 217 */ 218 TASKQUEUE_DEFINE_THREAD(inm_free); 219 static struct in_multi_head inm_free_list = SLIST_HEAD_INITIALIZER(); 220 static void inm_release_task(void *arg __unused, int pending __unused); 221 static struct task inm_free_task = TASK_INITIALIZER(0, inm_release_task, NULL); 222 223 void 224 inm_release_wait(void *arg __unused) 225 { 226 227 /* 228 * Make sure all pending multicast addresses are freed before 229 * the VNET or network device is destroyed: 230 */ 231 taskqueue_drain(taskqueue_inm_free, &inm_free_task); 232 } 233 #ifdef VIMAGE 234 /* XXX-BZ FIXME, see D24914. */ 235 VNET_SYSUNINIT(inm_release_wait, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, inm_release_wait, NULL); 236 #endif 237 238 void 239 inm_release_list_deferred(struct in_multi_head *inmh) 240 { 241 242 if (SLIST_EMPTY(inmh)) 243 return; 244 mtx_lock(&in_multi_free_mtx); 245 SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele); 246 mtx_unlock(&in_multi_free_mtx); 247 taskqueue_enqueue(taskqueue_inm_free, &inm_free_task); 248 } 249 250 void 251 inm_disconnect(struct in_multi *inm) 252 { 253 struct ifnet *ifp; 254 struct ifmultiaddr *ifma, *ll_ifma; 255 256 ifp = inm->inm_ifp; 257 IF_ADDR_WLOCK_ASSERT(ifp); 258 ifma = inm->inm_ifma; 259 260 if_ref(ifp); 261 if (ifma->ifma_flags & IFMA_F_ENQUEUED) { 262 CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); 263 ifma->ifma_flags &= ~IFMA_F_ENQUEUED; 264 } 265 MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname); 266 if ((ll_ifma = ifma->ifma_llifma) != NULL) { 267 MPASS(ifma != ll_ifma); 268 ifma->ifma_llifma = NULL; 269 MPASS(ll_ifma->ifma_llifma == NULL); 270 MPASS(ll_ifma->ifma_ifp == ifp); 271 if (--ll_ifma->ifma_refcount == 0) { 272 if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) { 273 CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link); 274 ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED; 275 } 276 MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname); 277 if_freemulti(ll_ifma); 278 } 279 } 280 } 281 282 void 283 inm_release_deferred(struct in_multi *inm) 284 { 285 struct in_multi_head tmp; 286 287 IN_MULTI_LIST_LOCK_ASSERT(); 288 MPASS(inm->inm_refcount > 0); 289 if (--inm->inm_refcount == 0) { 290 SLIST_INIT(&tmp); 291 inm_disconnect(inm); 292 inm->inm_ifma->ifma_protospec = NULL; 293 SLIST_INSERT_HEAD(&tmp, inm, inm_nrele); 294 inm_release_list_deferred(&tmp); 295 } 296 } 297 298 static void 299 inm_release_task(void *arg __unused, int pending __unused) 300 { 301 struct in_multi_head inm_free_tmp; 302 struct in_multi *inm, *tinm; 303 304 SLIST_INIT(&inm_free_tmp); 305 mtx_lock(&in_multi_free_mtx); 306 SLIST_CONCAT(&inm_free_tmp, &inm_free_list, in_multi, inm_nrele); 307 mtx_unlock(&in_multi_free_mtx); 308 IN_MULTI_LOCK(); 309 SLIST_FOREACH_SAFE(inm, &inm_free_tmp, inm_nrele, tinm) { 310 SLIST_REMOVE_HEAD(&inm_free_tmp, inm_nrele); 311 MPASS(inm); 312 inm_release(inm); 313 } 314 IN_MULTI_UNLOCK(); 315 } 316 317 /* 318 * Initialize an in_mfilter structure to a known state at t0, t1 319 * with an empty source filter list. 320 */ 321 static __inline void 322 imf_init(struct in_mfilter *imf, const int st0, const int st1) 323 { 324 memset(imf, 0, sizeof(struct in_mfilter)); 325 RB_INIT(&imf->imf_sources); 326 imf->imf_st[0] = st0; 327 imf->imf_st[1] = st1; 328 } 329 330 struct in_mfilter * 331 ip_mfilter_alloc(const int mflags, const int st0, const int st1) 332 { 333 struct in_mfilter *imf; 334 335 imf = malloc(sizeof(*imf), M_INMFILTER, mflags); 336 if (imf != NULL) 337 imf_init(imf, st0, st1); 338 339 return (imf); 340 } 341 342 void 343 ip_mfilter_free(struct in_mfilter *imf) 344 { 345 346 imf_purge(imf); 347 free(imf, M_INMFILTER); 348 } 349 350 /* 351 * Function for looking up an in_multi record for an IPv4 multicast address 352 * on a given interface. ifp must be valid. If no record found, return NULL. 353 * The IN_MULTI_LIST_LOCK and IF_ADDR_LOCK on ifp must be held. 354 */ 355 struct in_multi * 356 inm_lookup_locked(struct ifnet *ifp, const struct in_addr ina) 357 { 358 struct ifmultiaddr *ifma; 359 struct in_multi *inm; 360 361 IN_MULTI_LIST_LOCK_ASSERT(); 362 IF_ADDR_LOCK_ASSERT(ifp); 363 364 CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) { 365 inm = inm_ifmultiaddr_get_inm(ifma); 366 if (inm == NULL) 367 continue; 368 if (inm->inm_addr.s_addr == ina.s_addr) 369 return (inm); 370 } 371 return (NULL); 372 } 373 374 /* 375 * Wrapper for inm_lookup_locked(). 376 * The IF_ADDR_LOCK will be taken on ifp and released on return. 377 */ 378 struct in_multi * 379 inm_lookup(struct ifnet *ifp, const struct in_addr ina) 380 { 381 struct epoch_tracker et; 382 struct in_multi *inm; 383 384 IN_MULTI_LIST_LOCK_ASSERT(); 385 NET_EPOCH_ENTER(et); 386 387 inm = inm_lookup_locked(ifp, ina); 388 NET_EPOCH_EXIT(et); 389 390 return (inm); 391 } 392 393 /* 394 * Find an IPv4 multicast group entry for this ip_moptions instance 395 * which matches the specified group, and optionally an interface. 396 * Return its index into the array, or -1 if not found. 397 */ 398 static struct in_mfilter * 399 imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, 400 const struct sockaddr *group) 401 { 402 const struct sockaddr_in *gsin; 403 struct in_mfilter *imf; 404 struct in_multi *inm; 405 406 gsin = (const struct sockaddr_in *)group; 407 408 IP_MFILTER_FOREACH(imf, &imo->imo_head) { 409 inm = imf->imf_inm; 410 if (inm == NULL) 411 continue; 412 if ((ifp == NULL || (inm->inm_ifp == ifp)) && 413 in_hosteq(inm->inm_addr, gsin->sin_addr)) { 414 break; 415 } 416 } 417 return (imf); 418 } 419 420 /* 421 * Find an IPv4 multicast source entry for this imo which matches 422 * the given group index for this socket, and source address. 423 * 424 * NOTE: This does not check if the entry is in-mode, merely if 425 * it exists, which may not be the desired behaviour. 426 */ 427 static struct in_msource * 428 imo_match_source(struct in_mfilter *imf, const struct sockaddr *src) 429 { 430 struct ip_msource find; 431 struct ip_msource *ims; 432 const sockunion_t *psa; 433 434 KASSERT(src->sa_family == AF_INET, ("%s: !AF_INET", __func__)); 435 436 /* Source trees are keyed in host byte order. */ 437 psa = (const sockunion_t *)src; 438 find.ims_haddr = ntohl(psa->sin.sin_addr.s_addr); 439 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); 440 441 return ((struct in_msource *)ims); 442 } 443 444 /* 445 * Perform filtering for multicast datagrams on a socket by group and source. 446 * 447 * Returns 0 if a datagram should be allowed through, or various error codes 448 * if the socket was not a member of the group, or the source was muted, etc. 449 */ 450 int 451 imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, 452 const struct sockaddr *group, const struct sockaddr *src) 453 { 454 struct in_mfilter *imf; 455 struct in_msource *ims; 456 int mode; 457 458 KASSERT(ifp != NULL, ("%s: null ifp", __func__)); 459 460 imf = imo_match_group(imo, ifp, group); 461 if (imf == NULL) 462 return (MCAST_NOTGMEMBER); 463 464 /* 465 * Check if the source was included in an (S,G) join. 466 * Allow reception on exclusive memberships by default, 467 * reject reception on inclusive memberships by default. 468 * Exclude source only if an in-mode exclude filter exists. 469 * Include source only if an in-mode include filter exists. 470 * NOTE: We are comparing group state here at IGMP t1 (now) 471 * with socket-layer t0 (since last downcall). 472 */ 473 mode = imf->imf_st[1]; 474 ims = imo_match_source(imf, src); 475 476 if ((ims == NULL && mode == MCAST_INCLUDE) || 477 (ims != NULL && ims->imsl_st[0] == MCAST_EXCLUDE)) 478 return (MCAST_NOTSMEMBER); 479 480 return (MCAST_PASS); 481 } 482 483 /* 484 * Find and return a reference to an in_multi record for (ifp, group), 485 * and bump its reference count. 486 * If one does not exist, try to allocate it, and update link-layer multicast 487 * filters on ifp to listen for group. 488 * Assumes the IN_MULTI lock is held across the call. 489 * Return 0 if successful, otherwise return an appropriate error code. 490 */ 491 static int 492 in_getmulti(struct ifnet *ifp, const struct in_addr *group, 493 struct in_multi **pinm) 494 { 495 struct sockaddr_in gsin; 496 struct ifmultiaddr *ifma; 497 struct in_ifinfo *ii; 498 struct in_multi *inm; 499 int error; 500 501 IN_MULTI_LOCK_ASSERT(); 502 503 ii = (struct in_ifinfo *)ifp->if_afdata[AF_INET]; 504 IN_MULTI_LIST_LOCK(); 505 inm = inm_lookup(ifp, *group); 506 if (inm != NULL) { 507 /* 508 * If we already joined this group, just bump the 509 * refcount and return it. 510 */ 511 KASSERT(inm->inm_refcount >= 1, 512 ("%s: bad refcount %d", __func__, inm->inm_refcount)); 513 inm_acquire_locked(inm); 514 *pinm = inm; 515 } 516 IN_MULTI_LIST_UNLOCK(); 517 if (inm != NULL) 518 return (0); 519 520 memset(&gsin, 0, sizeof(gsin)); 521 gsin.sin_family = AF_INET; 522 gsin.sin_len = sizeof(struct sockaddr_in); 523 gsin.sin_addr = *group; 524 525 /* 526 * Check if a link-layer group is already associated 527 * with this network-layer group on the given ifnet. 528 */ 529 error = if_addmulti(ifp, (struct sockaddr *)&gsin, &ifma); 530 if (error != 0) 531 return (error); 532 533 /* XXX ifma_protospec must be covered by IF_ADDR_LOCK */ 534 IN_MULTI_LIST_LOCK(); 535 IF_ADDR_WLOCK(ifp); 536 537 /* 538 * If something other than netinet is occupying the link-layer 539 * group, print a meaningful error message and back out of 540 * the allocation. 541 * Otherwise, bump the refcount on the existing network-layer 542 * group association and return it. 543 */ 544 if (ifma->ifma_protospec != NULL) { 545 inm = (struct in_multi *)ifma->ifma_protospec; 546 #ifdef INVARIANTS 547 KASSERT(ifma->ifma_addr != NULL, ("%s: no ifma_addr", 548 __func__)); 549 KASSERT(ifma->ifma_addr->sa_family == AF_INET, 550 ("%s: ifma not AF_INET", __func__)); 551 KASSERT(inm != NULL, ("%s: no ifma_protospec", __func__)); 552 if (inm->inm_ifma != ifma || inm->inm_ifp != ifp || 553 !in_hosteq(inm->inm_addr, *group)) { 554 char addrbuf[INET_ADDRSTRLEN]; 555 556 panic("%s: ifma %p is inconsistent with %p (%s)", 557 __func__, ifma, inm, inet_ntoa_r(*group, addrbuf)); 558 } 559 #endif 560 inm_acquire_locked(inm); 561 *pinm = inm; 562 goto out_locked; 563 } 564 565 IF_ADDR_WLOCK_ASSERT(ifp); 566 567 /* 568 * A new in_multi record is needed; allocate and initialize it. 569 * We DO NOT perform an IGMP join as the in_ layer may need to 570 * push an initial source list down to IGMP to support SSM. 571 * 572 * The initial source filter state is INCLUDE, {} as per the RFC. 573 */ 574 inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT | M_ZERO); 575 if (inm == NULL) { 576 IF_ADDR_WUNLOCK(ifp); 577 IN_MULTI_LIST_UNLOCK(); 578 if_delmulti_ifma(ifma); 579 return (ENOMEM); 580 } 581 inm->inm_addr = *group; 582 inm->inm_ifp = ifp; 583 inm->inm_igi = ii->ii_igmp; 584 inm->inm_ifma = ifma; 585 inm->inm_refcount = 1; 586 inm->inm_state = IGMP_NOT_MEMBER; 587 mbufq_init(&inm->inm_scq, IGMP_MAX_STATE_CHANGES); 588 inm->inm_st[0].iss_fmode = MCAST_UNDEFINED; 589 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED; 590 RB_INIT(&inm->inm_srcs); 591 592 ifma->ifma_protospec = inm; 593 594 *pinm = inm; 595 out_locked: 596 IF_ADDR_WUNLOCK(ifp); 597 IN_MULTI_LIST_UNLOCK(); 598 return (0); 599 } 600 601 /* 602 * Drop a reference to an in_multi record. 603 * 604 * If the refcount drops to 0, free the in_multi record and 605 * delete the underlying link-layer membership. 606 */ 607 static void 608 inm_release(struct in_multi *inm) 609 { 610 struct ifmultiaddr *ifma; 611 struct ifnet *ifp; 612 613 CTR2(KTR_IGMPV3, "%s: refcount is %d", __func__, inm->inm_refcount); 614 MPASS(inm->inm_refcount == 0); 615 CTR2(KTR_IGMPV3, "%s: freeing inm %p", __func__, inm); 616 617 ifma = inm->inm_ifma; 618 ifp = inm->inm_ifp; 619 620 /* XXX this access is not covered by IF_ADDR_LOCK */ 621 CTR2(KTR_IGMPV3, "%s: purging ifma %p", __func__, ifma); 622 if (ifp != NULL) { 623 CURVNET_SET(ifp->if_vnet); 624 inm_purge(inm); 625 free(inm, M_IPMADDR); 626 if_delmulti_ifma_flags(ifma, 1); 627 CURVNET_RESTORE(); 628 if_rele(ifp); 629 } else { 630 inm_purge(inm); 631 free(inm, M_IPMADDR); 632 if_delmulti_ifma_flags(ifma, 1); 633 } 634 } 635 636 /* 637 * Clear recorded source entries for a group. 638 * Used by the IGMP code. Caller must hold the IN_MULTI lock. 639 * FIXME: Should reap. 640 */ 641 void 642 inm_clear_recorded(struct in_multi *inm) 643 { 644 struct ip_msource *ims; 645 646 IN_MULTI_LIST_LOCK_ASSERT(); 647 648 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 649 if (ims->ims_stp) { 650 ims->ims_stp = 0; 651 --inm->inm_st[1].iss_rec; 652 } 653 } 654 KASSERT(inm->inm_st[1].iss_rec == 0, 655 ("%s: iss_rec %d not 0", __func__, inm->inm_st[1].iss_rec)); 656 } 657 658 /* 659 * Record a source as pending for a Source-Group IGMPv3 query. 660 * This lives here as it modifies the shared tree. 661 * 662 * inm is the group descriptor. 663 * naddr is the address of the source to record in network-byte order. 664 * 665 * If the net.inet.igmp.sgalloc sysctl is non-zero, we will 666 * lazy-allocate a source node in response to an SG query. 667 * Otherwise, no allocation is performed. This saves some memory 668 * with the trade-off that the source will not be reported to the 669 * router if joined in the window between the query response and 670 * the group actually being joined on the local host. 671 * 672 * VIMAGE: XXX: Currently the igmp_sgalloc feature has been removed. 673 * This turns off the allocation of a recorded source entry if 674 * the group has not been joined. 675 * 676 * Return 0 if the source didn't exist or was already marked as recorded. 677 * Return 1 if the source was marked as recorded by this function. 678 * Return <0 if any error occurred (negated errno code). 679 */ 680 int 681 inm_record_source(struct in_multi *inm, const in_addr_t naddr) 682 { 683 struct ip_msource find; 684 struct ip_msource *ims, *nims; 685 686 IN_MULTI_LIST_LOCK_ASSERT(); 687 688 find.ims_haddr = ntohl(naddr); 689 ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find); 690 if (ims && ims->ims_stp) 691 return (0); 692 if (ims == NULL) { 693 if (inm->inm_nsrc == in_mcast_maxgrpsrc) 694 return (-ENOSPC); 695 nims = malloc(sizeof(struct ip_msource), M_IPMSOURCE, 696 M_NOWAIT | M_ZERO); 697 if (nims == NULL) 698 return (-ENOMEM); 699 nims->ims_haddr = find.ims_haddr; 700 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims); 701 ++inm->inm_nsrc; 702 ims = nims; 703 } 704 705 /* 706 * Mark the source as recorded and update the recorded 707 * source count. 708 */ 709 ++ims->ims_stp; 710 ++inm->inm_st[1].iss_rec; 711 712 return (1); 713 } 714 715 /* 716 * Return a pointer to an in_msource owned by an in_mfilter, 717 * given its source address. 718 * Lazy-allocate if needed. If this is a new entry its filter state is 719 * undefined at t0. 720 * 721 * imf is the filter set being modified. 722 * haddr is the source address in *host* byte-order. 723 * 724 * SMPng: May be called with locks held; malloc must not block. 725 */ 726 static int 727 imf_get_source(struct in_mfilter *imf, const struct sockaddr_in *psin, 728 struct in_msource **plims) 729 { 730 struct ip_msource find; 731 struct ip_msource *ims, *nims; 732 struct in_msource *lims; 733 int error; 734 735 error = 0; 736 ims = NULL; 737 lims = NULL; 738 739 /* key is host byte order */ 740 find.ims_haddr = ntohl(psin->sin_addr.s_addr); 741 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); 742 lims = (struct in_msource *)ims; 743 if (lims == NULL) { 744 if (imf->imf_nsrc == in_mcast_maxsocksrc) 745 return (ENOSPC); 746 nims = malloc(sizeof(struct in_msource), M_INMFILTER, 747 M_NOWAIT | M_ZERO); 748 if (nims == NULL) 749 return (ENOMEM); 750 lims = (struct in_msource *)nims; 751 lims->ims_haddr = find.ims_haddr; 752 lims->imsl_st[0] = MCAST_UNDEFINED; 753 RB_INSERT(ip_msource_tree, &imf->imf_sources, nims); 754 ++imf->imf_nsrc; 755 } 756 757 *plims = lims; 758 759 return (error); 760 } 761 762 /* 763 * Graft a source entry into an existing socket-layer filter set, 764 * maintaining any required invariants and checking allocations. 765 * 766 * The source is marked as being in the new filter mode at t1. 767 * 768 * Return the pointer to the new node, otherwise return NULL. 769 */ 770 static struct in_msource * 771 imf_graft(struct in_mfilter *imf, const uint8_t st1, 772 const struct sockaddr_in *psin) 773 { 774 struct ip_msource *nims; 775 struct in_msource *lims; 776 777 nims = malloc(sizeof(struct in_msource), M_INMFILTER, 778 M_NOWAIT | M_ZERO); 779 if (nims == NULL) 780 return (NULL); 781 lims = (struct in_msource *)nims; 782 lims->ims_haddr = ntohl(psin->sin_addr.s_addr); 783 lims->imsl_st[0] = MCAST_UNDEFINED; 784 lims->imsl_st[1] = st1; 785 RB_INSERT(ip_msource_tree, &imf->imf_sources, nims); 786 ++imf->imf_nsrc; 787 788 return (lims); 789 } 790 791 /* 792 * Prune a source entry from an existing socket-layer filter set, 793 * maintaining any required invariants and checking allocations. 794 * 795 * The source is marked as being left at t1, it is not freed. 796 * 797 * Return 0 if no error occurred, otherwise return an errno value. 798 */ 799 static int 800 imf_prune(struct in_mfilter *imf, const struct sockaddr_in *psin) 801 { 802 struct ip_msource find; 803 struct ip_msource *ims; 804 struct in_msource *lims; 805 806 /* key is host byte order */ 807 find.ims_haddr = ntohl(psin->sin_addr.s_addr); 808 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); 809 if (ims == NULL) 810 return (ENOENT); 811 lims = (struct in_msource *)ims; 812 lims->imsl_st[1] = MCAST_UNDEFINED; 813 return (0); 814 } 815 816 /* 817 * Revert socket-layer filter set deltas at t1 to t0 state. 818 */ 819 static void 820 imf_rollback(struct in_mfilter *imf) 821 { 822 struct ip_msource *ims, *tims; 823 struct in_msource *lims; 824 825 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { 826 lims = (struct in_msource *)ims; 827 if (lims->imsl_st[0] == lims->imsl_st[1]) { 828 /* no change at t1 */ 829 continue; 830 } else if (lims->imsl_st[0] != MCAST_UNDEFINED) { 831 /* revert change to existing source at t1 */ 832 lims->imsl_st[1] = lims->imsl_st[0]; 833 } else { 834 /* revert source added t1 */ 835 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims); 836 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); 837 free(ims, M_INMFILTER); 838 imf->imf_nsrc--; 839 } 840 } 841 imf->imf_st[1] = imf->imf_st[0]; 842 } 843 844 /* 845 * Mark socket-layer filter set as INCLUDE {} at t1. 846 */ 847 static void 848 imf_leave(struct in_mfilter *imf) 849 { 850 struct ip_msource *ims; 851 struct in_msource *lims; 852 853 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 854 lims = (struct in_msource *)ims; 855 lims->imsl_st[1] = MCAST_UNDEFINED; 856 } 857 imf->imf_st[1] = MCAST_INCLUDE; 858 } 859 860 /* 861 * Mark socket-layer filter set deltas as committed. 862 */ 863 static void 864 imf_commit(struct in_mfilter *imf) 865 { 866 struct ip_msource *ims; 867 struct in_msource *lims; 868 869 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 870 lims = (struct in_msource *)ims; 871 lims->imsl_st[0] = lims->imsl_st[1]; 872 } 873 imf->imf_st[0] = imf->imf_st[1]; 874 } 875 876 /* 877 * Reap unreferenced sources from socket-layer filter set. 878 */ 879 static void 880 imf_reap(struct in_mfilter *imf) 881 { 882 struct ip_msource *ims, *tims; 883 struct in_msource *lims; 884 885 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { 886 lims = (struct in_msource *)ims; 887 if ((lims->imsl_st[0] == MCAST_UNDEFINED) && 888 (lims->imsl_st[1] == MCAST_UNDEFINED)) { 889 CTR2(KTR_IGMPV3, "%s: free lims %p", __func__, ims); 890 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); 891 free(ims, M_INMFILTER); 892 imf->imf_nsrc--; 893 } 894 } 895 } 896 897 /* 898 * Purge socket-layer filter set. 899 */ 900 static void 901 imf_purge(struct in_mfilter *imf) 902 { 903 struct ip_msource *ims, *tims; 904 905 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { 906 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims); 907 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); 908 free(ims, M_INMFILTER); 909 imf->imf_nsrc--; 910 } 911 imf->imf_st[0] = imf->imf_st[1] = MCAST_UNDEFINED; 912 KASSERT(RB_EMPTY(&imf->imf_sources), 913 ("%s: imf_sources not empty", __func__)); 914 } 915 916 /* 917 * Look up a source filter entry for a multicast group. 918 * 919 * inm is the group descriptor to work with. 920 * haddr is the host-byte-order IPv4 address to look up. 921 * noalloc may be non-zero to suppress allocation of sources. 922 * *pims will be set to the address of the retrieved or allocated source. 923 * 924 * SMPng: NOTE: may be called with locks held. 925 * Return 0 if successful, otherwise return a non-zero error code. 926 */ 927 static int 928 inm_get_source(struct in_multi *inm, const in_addr_t haddr, 929 const int noalloc, struct ip_msource **pims) 930 { 931 struct ip_msource find; 932 struct ip_msource *ims, *nims; 933 934 find.ims_haddr = haddr; 935 ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find); 936 if (ims == NULL && !noalloc) { 937 if (inm->inm_nsrc == in_mcast_maxgrpsrc) 938 return (ENOSPC); 939 nims = malloc(sizeof(struct ip_msource), M_IPMSOURCE, 940 M_NOWAIT | M_ZERO); 941 if (nims == NULL) 942 return (ENOMEM); 943 nims->ims_haddr = haddr; 944 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims); 945 ++inm->inm_nsrc; 946 ims = nims; 947 #ifdef KTR 948 CTR3(KTR_IGMPV3, "%s: allocated 0x%08x as %p", __func__, 949 haddr, ims); 950 #endif 951 } 952 953 *pims = ims; 954 return (0); 955 } 956 957 /* 958 * Merge socket-layer source into IGMP-layer source. 959 * If rollback is non-zero, perform the inverse of the merge. 960 */ 961 static void 962 ims_merge(struct ip_msource *ims, const struct in_msource *lims, 963 const int rollback) 964 { 965 int n = rollback ? -1 : 1; 966 967 if (lims->imsl_st[0] == MCAST_EXCLUDE) { 968 CTR3(KTR_IGMPV3, "%s: t1 ex -= %d on 0x%08x", 969 __func__, n, ims->ims_haddr); 970 ims->ims_st[1].ex -= n; 971 } else if (lims->imsl_st[0] == MCAST_INCLUDE) { 972 CTR3(KTR_IGMPV3, "%s: t1 in -= %d on 0x%08x", 973 __func__, n, ims->ims_haddr); 974 ims->ims_st[1].in -= n; 975 } 976 977 if (lims->imsl_st[1] == MCAST_EXCLUDE) { 978 CTR3(KTR_IGMPV3, "%s: t1 ex += %d on 0x%08x", 979 __func__, n, ims->ims_haddr); 980 ims->ims_st[1].ex += n; 981 } else if (lims->imsl_st[1] == MCAST_INCLUDE) { 982 CTR3(KTR_IGMPV3, "%s: t1 in += %d on 0x%08x", 983 __func__, n, ims->ims_haddr); 984 ims->ims_st[1].in += n; 985 } 986 } 987 988 /* 989 * Atomically update the global in_multi state, when a membership's 990 * filter list is being updated in any way. 991 * 992 * imf is the per-inpcb-membership group filter pointer. 993 * A fake imf may be passed for in-kernel consumers. 994 * 995 * XXX This is a candidate for a set-symmetric-difference style loop 996 * which would eliminate the repeated lookup from root of ims nodes, 997 * as they share the same key space. 998 * 999 * If any error occurred this function will back out of refcounts 1000 * and return a non-zero value. 1001 */ 1002 static int 1003 inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf) 1004 { 1005 struct ip_msource *ims, *nims; 1006 struct in_msource *lims; 1007 int schanged, error; 1008 int nsrc0, nsrc1; 1009 1010 schanged = 0; 1011 error = 0; 1012 nsrc1 = nsrc0 = 0; 1013 IN_MULTI_LIST_LOCK_ASSERT(); 1014 1015 /* 1016 * Update the source filters first, as this may fail. 1017 * Maintain count of in-mode filters at t0, t1. These are 1018 * used to work out if we transition into ASM mode or not. 1019 * Maintain a count of source filters whose state was 1020 * actually modified by this operation. 1021 */ 1022 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 1023 lims = (struct in_msource *)ims; 1024 if (lims->imsl_st[0] == imf->imf_st[0]) nsrc0++; 1025 if (lims->imsl_st[1] == imf->imf_st[1]) nsrc1++; 1026 if (lims->imsl_st[0] == lims->imsl_st[1]) continue; 1027 error = inm_get_source(inm, lims->ims_haddr, 0, &nims); 1028 ++schanged; 1029 if (error) 1030 break; 1031 ims_merge(nims, lims, 0); 1032 } 1033 if (error) { 1034 struct ip_msource *bims; 1035 1036 RB_FOREACH_REVERSE_FROM(ims, ip_msource_tree, nims) { 1037 lims = (struct in_msource *)ims; 1038 if (lims->imsl_st[0] == lims->imsl_st[1]) 1039 continue; 1040 (void)inm_get_source(inm, lims->ims_haddr, 1, &bims); 1041 if (bims == NULL) 1042 continue; 1043 ims_merge(bims, lims, 1); 1044 } 1045 goto out_reap; 1046 } 1047 1048 CTR3(KTR_IGMPV3, "%s: imf filters in-mode: %d at t0, %d at t1", 1049 __func__, nsrc0, nsrc1); 1050 1051 /* Handle transition between INCLUDE {n} and INCLUDE {} on socket. */ 1052 if (imf->imf_st[0] == imf->imf_st[1] && 1053 imf->imf_st[1] == MCAST_INCLUDE) { 1054 if (nsrc1 == 0) { 1055 CTR1(KTR_IGMPV3, "%s: --in on inm at t1", __func__); 1056 --inm->inm_st[1].iss_in; 1057 } 1058 } 1059 1060 /* Handle filter mode transition on socket. */ 1061 if (imf->imf_st[0] != imf->imf_st[1]) { 1062 CTR3(KTR_IGMPV3, "%s: imf transition %d to %d", 1063 __func__, imf->imf_st[0], imf->imf_st[1]); 1064 1065 if (imf->imf_st[0] == MCAST_EXCLUDE) { 1066 CTR1(KTR_IGMPV3, "%s: --ex on inm at t1", __func__); 1067 --inm->inm_st[1].iss_ex; 1068 } else if (imf->imf_st[0] == MCAST_INCLUDE) { 1069 CTR1(KTR_IGMPV3, "%s: --in on inm at t1", __func__); 1070 --inm->inm_st[1].iss_in; 1071 } 1072 1073 if (imf->imf_st[1] == MCAST_EXCLUDE) { 1074 CTR1(KTR_IGMPV3, "%s: ex++ on inm at t1", __func__); 1075 inm->inm_st[1].iss_ex++; 1076 } else if (imf->imf_st[1] == MCAST_INCLUDE && nsrc1 > 0) { 1077 CTR1(KTR_IGMPV3, "%s: in++ on inm at t1", __func__); 1078 inm->inm_st[1].iss_in++; 1079 } 1080 } 1081 1082 /* 1083 * Track inm filter state in terms of listener counts. 1084 * If there are any exclusive listeners, stack-wide 1085 * membership is exclusive. 1086 * Otherwise, if only inclusive listeners, stack-wide is inclusive. 1087 * If no listeners remain, state is undefined at t1, 1088 * and the IGMP lifecycle for this group should finish. 1089 */ 1090 if (inm->inm_st[1].iss_ex > 0) { 1091 CTR1(KTR_IGMPV3, "%s: transition to EX", __func__); 1092 inm->inm_st[1].iss_fmode = MCAST_EXCLUDE; 1093 } else if (inm->inm_st[1].iss_in > 0) { 1094 CTR1(KTR_IGMPV3, "%s: transition to IN", __func__); 1095 inm->inm_st[1].iss_fmode = MCAST_INCLUDE; 1096 } else { 1097 CTR1(KTR_IGMPV3, "%s: transition to UNDEF", __func__); 1098 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED; 1099 } 1100 1101 /* Decrement ASM listener count on transition out of ASM mode. */ 1102 if (imf->imf_st[0] == MCAST_EXCLUDE && nsrc0 == 0) { 1103 if ((imf->imf_st[1] != MCAST_EXCLUDE) || 1104 (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 > 0)) { 1105 CTR1(KTR_IGMPV3, "%s: --asm on inm at t1", __func__); 1106 --inm->inm_st[1].iss_asm; 1107 } 1108 } 1109 1110 /* Increment ASM listener count on transition to ASM mode. */ 1111 if (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 == 0) { 1112 CTR1(KTR_IGMPV3, "%s: asm++ on inm at t1", __func__); 1113 inm->inm_st[1].iss_asm++; 1114 } 1115 1116 CTR3(KTR_IGMPV3, "%s: merged imf %p to inm %p", __func__, imf, inm); 1117 inm_print(inm); 1118 1119 out_reap: 1120 if (schanged > 0) { 1121 CTR1(KTR_IGMPV3, "%s: sources changed; reaping", __func__); 1122 inm_reap(inm); 1123 } 1124 return (error); 1125 } 1126 1127 /* 1128 * Mark an in_multi's filter set deltas as committed. 1129 * Called by IGMP after a state change has been enqueued. 1130 */ 1131 void 1132 inm_commit(struct in_multi *inm) 1133 { 1134 struct ip_msource *ims; 1135 1136 CTR2(KTR_IGMPV3, "%s: commit inm %p", __func__, inm); 1137 CTR1(KTR_IGMPV3, "%s: pre commit:", __func__); 1138 inm_print(inm); 1139 1140 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 1141 ims->ims_st[0] = ims->ims_st[1]; 1142 } 1143 inm->inm_st[0] = inm->inm_st[1]; 1144 } 1145 1146 /* 1147 * Reap unreferenced nodes from an in_multi's filter set. 1148 */ 1149 static void 1150 inm_reap(struct in_multi *inm) 1151 { 1152 struct ip_msource *ims, *tims; 1153 1154 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) { 1155 if (ims->ims_st[0].ex > 0 || ims->ims_st[0].in > 0 || 1156 ims->ims_st[1].ex > 0 || ims->ims_st[1].in > 0 || 1157 ims->ims_stp != 0) 1158 continue; 1159 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims); 1160 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims); 1161 free(ims, M_IPMSOURCE); 1162 inm->inm_nsrc--; 1163 } 1164 } 1165 1166 /* 1167 * Purge all source nodes from an in_multi's filter set. 1168 */ 1169 static void 1170 inm_purge(struct in_multi *inm) 1171 { 1172 struct ip_msource *ims, *tims; 1173 1174 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) { 1175 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims); 1176 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims); 1177 free(ims, M_IPMSOURCE); 1178 inm->inm_nsrc--; 1179 } 1180 mbufq_drain(&inm->inm_scq); 1181 } 1182 1183 /* 1184 * Join a multicast group; unlocked entry point. 1185 * 1186 * SMPng: XXX: in_joingroup() is called from in_control(). Fortunately, 1187 * ifp is unlikely to have been detached at this point, so we assume 1188 * it's OK to recurse. 1189 */ 1190 int 1191 in_joingroup(struct ifnet *ifp, const struct in_addr *gina, 1192 /*const*/ struct in_mfilter *imf, struct in_multi **pinm) 1193 { 1194 int error; 1195 1196 IN_MULTI_LOCK(); 1197 error = in_joingroup_locked(ifp, gina, imf, pinm); 1198 IN_MULTI_UNLOCK(); 1199 1200 return (error); 1201 } 1202 1203 /* 1204 * Join a multicast group; real entry point. 1205 * 1206 * Only preserves atomicity at inm level. 1207 * NOTE: imf argument cannot be const due to sys/tree.h limitations. 1208 * 1209 * If the IGMP downcall fails, the group is not joined, and an error 1210 * code is returned. 1211 */ 1212 int 1213 in_joingroup_locked(struct ifnet *ifp, const struct in_addr *gina, 1214 /*const*/ struct in_mfilter *imf, struct in_multi **pinm) 1215 { 1216 struct in_mfilter timf; 1217 struct in_multi *inm; 1218 int error; 1219 1220 IN_MULTI_LOCK_ASSERT(); 1221 IN_MULTI_LIST_UNLOCK_ASSERT(); 1222 1223 CTR4(KTR_IGMPV3, "%s: join 0x%08x on %p(%s))", __func__, 1224 ntohl(gina->s_addr), ifp, ifp->if_xname); 1225 1226 error = 0; 1227 inm = NULL; 1228 1229 /* 1230 * If no imf was specified (i.e. kernel consumer), 1231 * fake one up and assume it is an ASM join. 1232 */ 1233 if (imf == NULL) { 1234 imf_init(&timf, MCAST_UNDEFINED, MCAST_EXCLUDE); 1235 imf = &timf; 1236 } 1237 1238 error = in_getmulti(ifp, gina, &inm); 1239 if (error) { 1240 CTR1(KTR_IGMPV3, "%s: in_getmulti() failure", __func__); 1241 return (error); 1242 } 1243 IN_MULTI_LIST_LOCK(); 1244 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); 1245 error = inm_merge(inm, imf); 1246 if (error) { 1247 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); 1248 goto out_inm_release; 1249 } 1250 1251 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); 1252 error = igmp_change_state(inm); 1253 if (error) { 1254 CTR1(KTR_IGMPV3, "%s: failed to update source", __func__); 1255 goto out_inm_release; 1256 } 1257 1258 out_inm_release: 1259 if (error) { 1260 CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm); 1261 IF_ADDR_WLOCK(ifp); 1262 inm_release_deferred(inm); 1263 IF_ADDR_WUNLOCK(ifp); 1264 } else { 1265 *pinm = inm; 1266 } 1267 IN_MULTI_LIST_UNLOCK(); 1268 1269 return (error); 1270 } 1271 1272 /* 1273 * Leave a multicast group; unlocked entry point. 1274 */ 1275 int 1276 in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf) 1277 { 1278 int error; 1279 1280 IN_MULTI_LOCK(); 1281 error = in_leavegroup_locked(inm, imf); 1282 IN_MULTI_UNLOCK(); 1283 1284 return (error); 1285 } 1286 1287 /* 1288 * Leave a multicast group; real entry point. 1289 * All source filters will be expunged. 1290 * 1291 * Only preserves atomicity at inm level. 1292 * 1293 * Holding the write lock for the INP which contains imf 1294 * is highly advisable. We can't assert for it as imf does not 1295 * contain a back-pointer to the owning inp. 1296 * 1297 * Note: This is not the same as inm_release(*) as this function also 1298 * makes a state change downcall into IGMP. 1299 */ 1300 int 1301 in_leavegroup_locked(struct in_multi *inm, /*const*/ struct in_mfilter *imf) 1302 { 1303 struct in_mfilter timf; 1304 int error; 1305 1306 IN_MULTI_LOCK_ASSERT(); 1307 IN_MULTI_LIST_UNLOCK_ASSERT(); 1308 1309 error = 0; 1310 1311 CTR5(KTR_IGMPV3, "%s: leave inm %p, 0x%08x/%s, imf %p", __func__, 1312 inm, ntohl(inm->inm_addr.s_addr), 1313 (inm_is_ifp_detached(inm) ? "null" : inm->inm_ifp->if_xname), 1314 imf); 1315 1316 /* 1317 * If no imf was specified (i.e. kernel consumer), 1318 * fake one up and assume it is an ASM join. 1319 */ 1320 if (imf == NULL) { 1321 imf_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED); 1322 imf = &timf; 1323 } 1324 1325 /* 1326 * Begin state merge transaction at IGMP layer. 1327 * 1328 * As this particular invocation should not cause any memory 1329 * to be allocated, and there is no opportunity to roll back 1330 * the transaction, it MUST NOT fail. 1331 */ 1332 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); 1333 IN_MULTI_LIST_LOCK(); 1334 error = inm_merge(inm, imf); 1335 KASSERT(error == 0, ("%s: failed to merge inm state", __func__)); 1336 1337 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); 1338 CURVNET_SET(inm->inm_ifp->if_vnet); 1339 error = igmp_change_state(inm); 1340 IF_ADDR_WLOCK(inm->inm_ifp); 1341 inm_release_deferred(inm); 1342 IF_ADDR_WUNLOCK(inm->inm_ifp); 1343 IN_MULTI_LIST_UNLOCK(); 1344 CURVNET_RESTORE(); 1345 if (error) 1346 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); 1347 1348 CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm); 1349 1350 return (error); 1351 } 1352 1353 /*#ifndef BURN_BRIDGES*/ 1354 1355 /* 1356 * Block or unblock an ASM multicast source on an inpcb. 1357 * This implements the delta-based API described in RFC 3678. 1358 * 1359 * The delta-based API applies only to exclusive-mode memberships. 1360 * An IGMP downcall will be performed. 1361 * 1362 * Return 0 if successful, otherwise return an appropriate error code. 1363 */ 1364 static int 1365 inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) 1366 { 1367 struct epoch_tracker et; 1368 struct group_source_req gsr; 1369 sockunion_t *gsa, *ssa; 1370 struct ifnet *ifp; 1371 struct in_mfilter *imf; 1372 struct ip_moptions *imo; 1373 struct in_msource *ims; 1374 struct in_multi *inm; 1375 uint16_t fmode; 1376 int error, doblock; 1377 1378 ifp = NULL; 1379 error = 0; 1380 doblock = 0; 1381 1382 memset(&gsr, 0, sizeof(struct group_source_req)); 1383 gsa = (sockunion_t *)&gsr.gsr_group; 1384 ssa = (sockunion_t *)&gsr.gsr_source; 1385 1386 switch (sopt->sopt_name) { 1387 case IP_BLOCK_SOURCE: 1388 case IP_UNBLOCK_SOURCE: { 1389 struct ip_mreq_source mreqs; 1390 1391 error = sooptcopyin(sopt, &mreqs, 1392 sizeof(struct ip_mreq_source), 1393 sizeof(struct ip_mreq_source)); 1394 if (error) 1395 return (error); 1396 1397 gsa->sin.sin_family = AF_INET; 1398 gsa->sin.sin_len = sizeof(struct sockaddr_in); 1399 gsa->sin.sin_addr = mreqs.imr_multiaddr; 1400 1401 ssa->sin.sin_family = AF_INET; 1402 ssa->sin.sin_len = sizeof(struct sockaddr_in); 1403 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 1404 1405 if (!in_nullhost(mreqs.imr_interface)) { 1406 NET_EPOCH_ENTER(et); 1407 INADDR_TO_IFP(mreqs.imr_interface, ifp); 1408 /* XXXGL: ifref? */ 1409 NET_EPOCH_EXIT(et); 1410 } 1411 if (sopt->sopt_name == IP_BLOCK_SOURCE) 1412 doblock = 1; 1413 1414 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p", 1415 __func__, ntohl(mreqs.imr_interface.s_addr), ifp); 1416 break; 1417 } 1418 1419 case MCAST_BLOCK_SOURCE: 1420 case MCAST_UNBLOCK_SOURCE: 1421 error = sooptcopyin(sopt, &gsr, 1422 sizeof(struct group_source_req), 1423 sizeof(struct group_source_req)); 1424 if (error) 1425 return (error); 1426 1427 if (gsa->sin.sin_family != AF_INET || 1428 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 1429 return (EINVAL); 1430 1431 if (ssa->sin.sin_family != AF_INET || 1432 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 1433 return (EINVAL); 1434 1435 NET_EPOCH_ENTER(et); 1436 ifp = ifnet_byindex(gsr.gsr_interface); 1437 NET_EPOCH_EXIT(et); 1438 if (ifp == NULL) 1439 return (EADDRNOTAVAIL); 1440 1441 if (sopt->sopt_name == MCAST_BLOCK_SOURCE) 1442 doblock = 1; 1443 break; 1444 1445 default: 1446 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d", 1447 __func__, sopt->sopt_name); 1448 return (EOPNOTSUPP); 1449 break; 1450 } 1451 1452 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 1453 return (EINVAL); 1454 1455 IN_MULTI_LOCK(); 1456 1457 /* 1458 * Check if we are actually a member of this group. 1459 */ 1460 imo = inp_findmoptions(inp); 1461 imf = imo_match_group(imo, ifp, &gsa->sa); 1462 if (imf == NULL) { 1463 error = EADDRNOTAVAIL; 1464 goto out_inp_locked; 1465 } 1466 inm = imf->imf_inm; 1467 1468 /* 1469 * Attempting to use the delta-based API on an 1470 * non exclusive-mode membership is an error. 1471 */ 1472 fmode = imf->imf_st[0]; 1473 if (fmode != MCAST_EXCLUDE) { 1474 error = EINVAL; 1475 goto out_inp_locked; 1476 } 1477 1478 /* 1479 * Deal with error cases up-front: 1480 * Asked to block, but already blocked; or 1481 * Asked to unblock, but nothing to unblock. 1482 * If adding a new block entry, allocate it. 1483 */ 1484 ims = imo_match_source(imf, &ssa->sa); 1485 if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { 1486 CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__, 1487 ntohl(ssa->sin.sin_addr.s_addr), doblock ? "" : "not "); 1488 error = EADDRNOTAVAIL; 1489 goto out_inp_locked; 1490 } 1491 1492 INP_WLOCK_ASSERT(inp); 1493 1494 /* 1495 * Begin state merge transaction at socket layer. 1496 */ 1497 if (doblock) { 1498 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block"); 1499 ims = imf_graft(imf, fmode, &ssa->sin); 1500 if (ims == NULL) 1501 error = ENOMEM; 1502 } else { 1503 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow"); 1504 error = imf_prune(imf, &ssa->sin); 1505 } 1506 1507 if (error) { 1508 CTR1(KTR_IGMPV3, "%s: merge imf state failed", __func__); 1509 goto out_imf_rollback; 1510 } 1511 1512 /* 1513 * Begin state merge transaction at IGMP layer. 1514 */ 1515 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); 1516 IN_MULTI_LIST_LOCK(); 1517 error = inm_merge(inm, imf); 1518 if (error) { 1519 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); 1520 IN_MULTI_LIST_UNLOCK(); 1521 goto out_imf_rollback; 1522 } 1523 1524 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); 1525 error = igmp_change_state(inm); 1526 IN_MULTI_LIST_UNLOCK(); 1527 if (error) 1528 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); 1529 1530 out_imf_rollback: 1531 if (error) 1532 imf_rollback(imf); 1533 else 1534 imf_commit(imf); 1535 1536 imf_reap(imf); 1537 1538 out_inp_locked: 1539 INP_WUNLOCK(inp); 1540 IN_MULTI_UNLOCK(); 1541 return (error); 1542 } 1543 1544 /* 1545 * Given an inpcb, return its multicast options structure pointer. Accepts 1546 * an unlocked inpcb pointer, but will return it locked. May sleep. 1547 * 1548 * SMPng: NOTE: Returns with the INP write lock held. 1549 */ 1550 static struct ip_moptions * 1551 inp_findmoptions(struct inpcb *inp) 1552 { 1553 struct ip_moptions *imo; 1554 1555 INP_WLOCK(inp); 1556 if (inp->inp_moptions != NULL) 1557 return (inp->inp_moptions); 1558 1559 INP_WUNLOCK(inp); 1560 1561 imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK); 1562 1563 imo->imo_multicast_ifp = NULL; 1564 imo->imo_multicast_addr.s_addr = INADDR_ANY; 1565 imo->imo_multicast_vif = -1; 1566 imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 1567 imo->imo_multicast_loop = in_mcast_loop; 1568 STAILQ_INIT(&imo->imo_head); 1569 1570 INP_WLOCK(inp); 1571 if (inp->inp_moptions != NULL) { 1572 free(imo, M_IPMOPTS); 1573 return (inp->inp_moptions); 1574 } 1575 inp->inp_moptions = imo; 1576 return (imo); 1577 } 1578 1579 void 1580 inp_freemoptions(struct ip_moptions *imo) 1581 { 1582 struct in_mfilter *imf; 1583 struct in_multi *inm; 1584 struct ifnet *ifp; 1585 1586 if (imo == NULL) 1587 return; 1588 1589 while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) { 1590 ip_mfilter_remove(&imo->imo_head, imf); 1591 1592 imf_leave(imf); 1593 if ((inm = imf->imf_inm) != NULL) { 1594 if ((ifp = inm->inm_ifp) != NULL) { 1595 CURVNET_SET(ifp->if_vnet); 1596 (void)in_leavegroup(inm, imf); 1597 CURVNET_RESTORE(); 1598 } else { 1599 (void)in_leavegroup(inm, imf); 1600 } 1601 } 1602 ip_mfilter_free(imf); 1603 } 1604 free(imo, M_IPMOPTS); 1605 } 1606 1607 /* 1608 * Atomically get source filters on a socket for an IPv4 multicast group. 1609 * Called with INP lock held; returns with lock released. 1610 */ 1611 static int 1612 inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) 1613 { 1614 struct epoch_tracker et; 1615 struct __msfilterreq msfr; 1616 sockunion_t *gsa; 1617 struct ifnet *ifp; 1618 struct ip_moptions *imo; 1619 struct in_mfilter *imf; 1620 struct ip_msource *ims; 1621 struct in_msource *lims; 1622 struct sockaddr_in *psin; 1623 struct sockaddr_storage *ptss; 1624 struct sockaddr_storage *tss; 1625 int error; 1626 size_t nsrcs, ncsrcs; 1627 1628 INP_WLOCK_ASSERT(inp); 1629 1630 imo = inp->inp_moptions; 1631 KASSERT(imo != NULL, ("%s: null ip_moptions", __func__)); 1632 1633 INP_WUNLOCK(inp); 1634 1635 error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), 1636 sizeof(struct __msfilterreq)); 1637 if (error) 1638 return (error); 1639 1640 NET_EPOCH_ENTER(et); 1641 ifp = ifnet_byindex(msfr.msfr_ifindex); 1642 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifnet pointer left */ 1643 if (ifp == NULL) 1644 return (EINVAL); 1645 1646 INP_WLOCK(inp); 1647 1648 /* 1649 * Lookup group on the socket. 1650 */ 1651 gsa = (sockunion_t *)&msfr.msfr_group; 1652 imf = imo_match_group(imo, ifp, &gsa->sa); 1653 if (imf == NULL) { 1654 INP_WUNLOCK(inp); 1655 return (EADDRNOTAVAIL); 1656 } 1657 1658 /* 1659 * Ignore memberships which are in limbo. 1660 */ 1661 if (imf->imf_st[1] == MCAST_UNDEFINED) { 1662 INP_WUNLOCK(inp); 1663 return (EAGAIN); 1664 } 1665 msfr.msfr_fmode = imf->imf_st[1]; 1666 1667 /* 1668 * If the user specified a buffer, copy out the source filter 1669 * entries to userland gracefully. 1670 * We only copy out the number of entries which userland 1671 * has asked for, but we always tell userland how big the 1672 * buffer really needs to be. 1673 */ 1674 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) 1675 msfr.msfr_nsrcs = in_mcast_maxsocksrc; 1676 tss = NULL; 1677 if (msfr.msfr_srcs != NULL && msfr.msfr_nsrcs > 0) { 1678 tss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs, 1679 M_TEMP, M_NOWAIT | M_ZERO); 1680 if (tss == NULL) { 1681 INP_WUNLOCK(inp); 1682 return (ENOBUFS); 1683 } 1684 } 1685 1686 /* 1687 * Count number of sources in-mode at t0. 1688 * If buffer space exists and remains, copy out source entries. 1689 */ 1690 nsrcs = msfr.msfr_nsrcs; 1691 ncsrcs = 0; 1692 ptss = tss; 1693 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 1694 lims = (struct in_msource *)ims; 1695 if (lims->imsl_st[0] == MCAST_UNDEFINED || 1696 lims->imsl_st[0] != imf->imf_st[0]) 1697 continue; 1698 ++ncsrcs; 1699 if (tss != NULL && nsrcs > 0) { 1700 psin = (struct sockaddr_in *)ptss; 1701 psin->sin_family = AF_INET; 1702 psin->sin_len = sizeof(struct sockaddr_in); 1703 psin->sin_addr.s_addr = htonl(lims->ims_haddr); 1704 psin->sin_port = 0; 1705 ++ptss; 1706 --nsrcs; 1707 } 1708 } 1709 1710 INP_WUNLOCK(inp); 1711 1712 if (tss != NULL) { 1713 error = copyout(tss, msfr.msfr_srcs, 1714 sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); 1715 free(tss, M_TEMP); 1716 if (error) 1717 return (error); 1718 } 1719 1720 msfr.msfr_nsrcs = ncsrcs; 1721 error = sooptcopyout(sopt, &msfr, sizeof(struct __msfilterreq)); 1722 1723 return (error); 1724 } 1725 1726 /* 1727 * Return the IP multicast options in response to user getsockopt(). 1728 */ 1729 int 1730 inp_getmoptions(struct inpcb *inp, struct sockopt *sopt) 1731 { 1732 struct ip_mreqn mreqn; 1733 struct ip_moptions *imo; 1734 struct ifnet *ifp; 1735 struct in_ifaddr *ia; 1736 int error, optval; 1737 u_char coptval; 1738 1739 INP_WLOCK(inp); 1740 imo = inp->inp_moptions; 1741 /* If socket is neither of type SOCK_RAW or SOCK_DGRAM reject it. */ 1742 if (inp->inp_socket->so_proto->pr_type != SOCK_RAW && 1743 inp->inp_socket->so_proto->pr_type != SOCK_DGRAM) { 1744 INP_WUNLOCK(inp); 1745 return (EOPNOTSUPP); 1746 } 1747 1748 error = 0; 1749 switch (sopt->sopt_name) { 1750 case IP_MULTICAST_VIF: 1751 if (imo != NULL) 1752 optval = imo->imo_multicast_vif; 1753 else 1754 optval = -1; 1755 INP_WUNLOCK(inp); 1756 error = sooptcopyout(sopt, &optval, sizeof(int)); 1757 break; 1758 1759 case IP_MULTICAST_IF: 1760 memset(&mreqn, 0, sizeof(struct ip_mreqn)); 1761 if (imo != NULL) { 1762 ifp = imo->imo_multicast_ifp; 1763 if (!in_nullhost(imo->imo_multicast_addr)) { 1764 mreqn.imr_address = imo->imo_multicast_addr; 1765 } else if (ifp != NULL) { 1766 struct epoch_tracker et; 1767 1768 mreqn.imr_ifindex = ifp->if_index; 1769 NET_EPOCH_ENTER(et); 1770 IFP_TO_IA(ifp, ia); 1771 if (ia != NULL) 1772 mreqn.imr_address = 1773 IA_SIN(ia)->sin_addr; 1774 NET_EPOCH_EXIT(et); 1775 } 1776 } 1777 INP_WUNLOCK(inp); 1778 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) { 1779 error = sooptcopyout(sopt, &mreqn, 1780 sizeof(struct ip_mreqn)); 1781 } else { 1782 error = sooptcopyout(sopt, &mreqn.imr_address, 1783 sizeof(struct in_addr)); 1784 } 1785 break; 1786 1787 case IP_MULTICAST_TTL: 1788 if (imo == NULL) 1789 optval = coptval = IP_DEFAULT_MULTICAST_TTL; 1790 else 1791 optval = coptval = imo->imo_multicast_ttl; 1792 INP_WUNLOCK(inp); 1793 if (sopt->sopt_valsize == sizeof(u_char)) 1794 error = sooptcopyout(sopt, &coptval, sizeof(u_char)); 1795 else 1796 error = sooptcopyout(sopt, &optval, sizeof(int)); 1797 break; 1798 1799 case IP_MULTICAST_LOOP: 1800 if (imo == NULL) 1801 optval = coptval = IP_DEFAULT_MULTICAST_LOOP; 1802 else 1803 optval = coptval = imo->imo_multicast_loop; 1804 INP_WUNLOCK(inp); 1805 if (sopt->sopt_valsize == sizeof(u_char)) 1806 error = sooptcopyout(sopt, &coptval, sizeof(u_char)); 1807 else 1808 error = sooptcopyout(sopt, &optval, sizeof(int)); 1809 break; 1810 1811 case IP_MSFILTER: 1812 if (imo == NULL) { 1813 error = EADDRNOTAVAIL; 1814 INP_WUNLOCK(inp); 1815 } else { 1816 error = inp_get_source_filters(inp, sopt); 1817 } 1818 break; 1819 1820 default: 1821 INP_WUNLOCK(inp); 1822 error = ENOPROTOOPT; 1823 break; 1824 } 1825 1826 INP_UNLOCK_ASSERT(inp); 1827 1828 return (error); 1829 } 1830 1831 /* 1832 * Look up the ifnet to join a multicast group membership via legacy 1833 * IP_ADD_MEMBERSHIP or via more modern MCAST_JOIN_GROUP. 1834 * 1835 * If the interface index was specified explicitly, just use it. If the 1836 * address was specified (legacy), try to find matching interface. Else 1837 * (index == 0 && no address) do a route lookup. If that fails for a modern 1838 * MCAST_JOIN_GROUP return failure, for legacy IP_ADD_MEMBERSHIP find first 1839 * multicast capable interface. 1840 */ 1841 static struct ifnet * 1842 inp_lookup_mcast_ifp(const struct inpcb *inp, const struct in_addr maddr, 1843 const struct in_addr *ina, const u_int index) 1844 { 1845 struct ifnet *ifp; 1846 struct nhop_object *nh; 1847 1848 NET_EPOCH_ASSERT(); 1849 1850 if (index != 0) 1851 return (ifnet_byindex_ref(index)); 1852 1853 if (ina != NULL && !in_nullhost(*ina)) { 1854 INADDR_TO_IFP(*ina, ifp); 1855 if (ifp != NULL) 1856 if_ref(ifp); 1857 return (ifp); 1858 } 1859 1860 nh = fib4_lookup(inp->inp_inc.inc_fibnum, maddr, 0, NHR_NONE, 0); 1861 if (nh != NULL) { 1862 ifp = nh->nh_ifp; 1863 if_ref(ifp); 1864 return (ifp); 1865 } 1866 1867 if (ina != NULL) { 1868 struct in_ifaddr *ia; 1869 1870 CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 1871 if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK) && 1872 (ia->ia_ifp->if_flags & IFF_MULTICAST)) { 1873 ifp = ia->ia_ifp; 1874 if_ref(ifp); 1875 return (ifp); 1876 } 1877 } 1878 } 1879 1880 return (NULL); 1881 } 1882 1883 /* 1884 * Join an IPv4 multicast group, possibly with a source. 1885 */ 1886 static int 1887 inp_join_group(struct inpcb *inp, struct sockopt *sopt) 1888 { 1889 struct group_source_req gsr; 1890 sockunion_t *gsa, *ssa; 1891 struct ifnet *ifp; 1892 struct in_mfilter *imf; 1893 struct ip_moptions *imo; 1894 struct in_multi *inm; 1895 struct in_msource *lims; 1896 struct epoch_tracker et; 1897 int error, is_new; 1898 1899 ifp = NULL; 1900 lims = NULL; 1901 error = 0; 1902 1903 memset(&gsr, 0, sizeof(struct group_source_req)); 1904 gsa = (sockunion_t *)&gsr.gsr_group; 1905 gsa->ss.ss_family = AF_UNSPEC; 1906 ssa = (sockunion_t *)&gsr.gsr_source; 1907 ssa->ss.ss_family = AF_UNSPEC; 1908 1909 switch (sopt->sopt_name) { 1910 case IP_ADD_MEMBERSHIP: { 1911 struct ip_mreqn mreqn; 1912 bool mreq; 1913 1914 mreq = (sopt->sopt_valsize != sizeof(struct ip_mreqn)); 1915 1916 error = sooptcopyin(sopt, &mreqn, 1917 mreq ? sizeof(struct ip_mreq) : sizeof(struct ip_mreqn), 1918 mreq ? sizeof(struct ip_mreq) : sizeof(struct ip_mreqn)); 1919 if (error) 1920 return (error); 1921 1922 gsa->sin.sin_family = AF_INET; 1923 gsa->sin.sin_len = sizeof(struct sockaddr_in); 1924 gsa->sin.sin_addr = mreqn.imr_multiaddr; 1925 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 1926 return (EINVAL); 1927 1928 NET_EPOCH_ENTER(et); 1929 ifp = inp_lookup_mcast_ifp(inp, mreqn.imr_multiaddr, 1930 mreq ? &mreqn.imr_address : NULL, 1931 mreq ? 0 : mreqn.imr_ifindex); 1932 NET_EPOCH_EXIT(et); 1933 break; 1934 } 1935 case IP_ADD_SOURCE_MEMBERSHIP: { 1936 struct ip_mreq_source mreqs; 1937 1938 error = sooptcopyin(sopt, &mreqs, sizeof(struct ip_mreq_source), 1939 sizeof(struct ip_mreq_source)); 1940 if (error) 1941 return (error); 1942 1943 gsa->sin.sin_family = ssa->sin.sin_family = AF_INET; 1944 gsa->sin.sin_len = ssa->sin.sin_len = 1945 sizeof(struct sockaddr_in); 1946 1947 gsa->sin.sin_addr = mreqs.imr_multiaddr; 1948 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 1949 return (EINVAL); 1950 1951 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 1952 1953 NET_EPOCH_ENTER(et); 1954 ifp = inp_lookup_mcast_ifp(inp, mreqs.imr_multiaddr, 1955 &mreqs.imr_interface, 0); 1956 NET_EPOCH_EXIT(et); 1957 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p", 1958 __func__, ntohl(mreqs.imr_interface.s_addr), ifp); 1959 break; 1960 } 1961 1962 case MCAST_JOIN_GROUP: 1963 case MCAST_JOIN_SOURCE_GROUP: 1964 if (sopt->sopt_name == MCAST_JOIN_GROUP) { 1965 error = sooptcopyin(sopt, &gsr, 1966 sizeof(struct group_req), 1967 sizeof(struct group_req)); 1968 } else if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) { 1969 error = sooptcopyin(sopt, &gsr, 1970 sizeof(struct group_source_req), 1971 sizeof(struct group_source_req)); 1972 } 1973 if (error) 1974 return (error); 1975 1976 if (gsa->sin.sin_family != AF_INET || 1977 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 1978 return (EINVAL); 1979 1980 /* 1981 * Overwrite the port field if present, as the sockaddr 1982 * being copied in may be matched with a binary comparison. 1983 */ 1984 gsa->sin.sin_port = 0; 1985 if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) { 1986 if (ssa->sin.sin_family != AF_INET || 1987 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 1988 return (EINVAL); 1989 ssa->sin.sin_port = 0; 1990 } 1991 1992 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 1993 return (EINVAL); 1994 1995 NET_EPOCH_ENTER(et); 1996 ifp = inp_lookup_mcast_ifp(inp, gsa->sin.sin_addr, NULL, 1997 gsr.gsr_interface); 1998 NET_EPOCH_EXIT(et); 1999 if (ifp == NULL) 2000 return (EADDRNOTAVAIL); 2001 break; 2002 2003 default: 2004 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d", 2005 __func__, sopt->sopt_name); 2006 return (EOPNOTSUPP); 2007 break; 2008 } 2009 2010 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { 2011 if (ifp != NULL) 2012 if_rele(ifp); 2013 return (EADDRNOTAVAIL); 2014 } 2015 2016 IN_MULTI_LOCK(); 2017 2018 /* 2019 * Find the membership in the membership list. 2020 */ 2021 imo = inp_findmoptions(inp); 2022 imf = imo_match_group(imo, ifp, &gsa->sa); 2023 if (imf == NULL) { 2024 is_new = 1; 2025 inm = NULL; 2026 2027 if (ip_mfilter_count(&imo->imo_head) >= IP_MAX_MEMBERSHIPS) { 2028 error = ENOMEM; 2029 goto out_inp_locked; 2030 } 2031 } else { 2032 is_new = 0; 2033 inm = imf->imf_inm; 2034 2035 if (ssa->ss.ss_family != AF_UNSPEC) { 2036 /* 2037 * MCAST_JOIN_SOURCE_GROUP on an exclusive membership 2038 * is an error. On an existing inclusive membership, 2039 * it just adds the source to the filter list. 2040 */ 2041 if (imf->imf_st[1] != MCAST_INCLUDE) { 2042 error = EINVAL; 2043 goto out_inp_locked; 2044 } 2045 /* 2046 * Throw out duplicates. 2047 * 2048 * XXX FIXME: This makes a naive assumption that 2049 * even if entries exist for *ssa in this imf, 2050 * they will be rejected as dupes, even if they 2051 * are not valid in the current mode (in-mode). 2052 * 2053 * in_msource is transactioned just as for anything 2054 * else in SSM -- but note naive use of inm_graft() 2055 * below for allocating new filter entries. 2056 * 2057 * This is only an issue if someone mixes the 2058 * full-state SSM API with the delta-based API, 2059 * which is discouraged in the relevant RFCs. 2060 */ 2061 lims = imo_match_source(imf, &ssa->sa); 2062 if (lims != NULL /*&& 2063 lims->imsl_st[1] == MCAST_INCLUDE*/) { 2064 error = EADDRNOTAVAIL; 2065 goto out_inp_locked; 2066 } 2067 } else { 2068 /* 2069 * MCAST_JOIN_GROUP on an existing exclusive 2070 * membership is an error; return EADDRINUSE 2071 * to preserve 4.4BSD API idempotence, and 2072 * avoid tedious detour to code below. 2073 * NOTE: This is bending RFC 3678 a bit. 2074 * 2075 * On an existing inclusive membership, this is also 2076 * an error; if you want to change filter mode, 2077 * you must use the userland API setsourcefilter(). 2078 * XXX We don't reject this for imf in UNDEFINED 2079 * state at t1, because allocation of a filter 2080 * is atomic with allocation of a membership. 2081 */ 2082 error = EINVAL; 2083 if (imf->imf_st[1] == MCAST_EXCLUDE) 2084 error = EADDRINUSE; 2085 goto out_inp_locked; 2086 } 2087 } 2088 2089 /* 2090 * Begin state merge transaction at socket layer. 2091 */ 2092 INP_WLOCK_ASSERT(inp); 2093 2094 /* 2095 * Graft new source into filter list for this inpcb's 2096 * membership of the group. The in_multi may not have 2097 * been allocated yet if this is a new membership, however, 2098 * the in_mfilter slot will be allocated and must be initialized. 2099 * 2100 * Note: Grafting of exclusive mode filters doesn't happen 2101 * in this path. 2102 * XXX: Should check for non-NULL lims (node exists but may 2103 * not be in-mode) for interop with full-state API. 2104 */ 2105 if (ssa->ss.ss_family != AF_UNSPEC) { 2106 /* Membership starts in IN mode */ 2107 if (is_new) { 2108 CTR1(KTR_IGMPV3, "%s: new join w/source", __func__); 2109 imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE); 2110 if (imf == NULL) { 2111 error = ENOMEM; 2112 goto out_inp_locked; 2113 } 2114 } else { 2115 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow"); 2116 } 2117 lims = imf_graft(imf, MCAST_INCLUDE, &ssa->sin); 2118 if (lims == NULL) { 2119 CTR1(KTR_IGMPV3, "%s: merge imf state failed", 2120 __func__); 2121 error = ENOMEM; 2122 goto out_inp_locked; 2123 } 2124 } else { 2125 /* No address specified; Membership starts in EX mode */ 2126 if (is_new) { 2127 CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__); 2128 imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE); 2129 if (imf == NULL) { 2130 error = ENOMEM; 2131 goto out_inp_locked; 2132 } 2133 } 2134 } 2135 2136 /* 2137 * Begin state merge transaction at IGMP layer. 2138 */ 2139 if (is_new) { 2140 in_pcbref(inp); 2141 INP_WUNLOCK(inp); 2142 2143 error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf, 2144 &imf->imf_inm); 2145 2146 INP_WLOCK(inp); 2147 if (in_pcbrele_wlocked(inp)) { 2148 error = ENXIO; 2149 goto out_inp_unlocked; 2150 } 2151 if (error) { 2152 CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed", 2153 __func__); 2154 goto out_inp_locked; 2155 } 2156 /* 2157 * NOTE: Refcount from in_joingroup_locked() 2158 * is protecting membership. 2159 */ 2160 ip_mfilter_insert(&imo->imo_head, imf); 2161 } else { 2162 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); 2163 IN_MULTI_LIST_LOCK(); 2164 error = inm_merge(inm, imf); 2165 if (error) { 2166 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", 2167 __func__); 2168 IN_MULTI_LIST_UNLOCK(); 2169 imf_rollback(imf); 2170 imf_reap(imf); 2171 goto out_inp_locked; 2172 } 2173 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); 2174 error = igmp_change_state(inm); 2175 IN_MULTI_LIST_UNLOCK(); 2176 if (error) { 2177 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", 2178 __func__); 2179 imf_rollback(imf); 2180 imf_reap(imf); 2181 goto out_inp_locked; 2182 } 2183 } 2184 2185 imf_commit(imf); 2186 imf = NULL; 2187 2188 out_inp_locked: 2189 INP_WUNLOCK(inp); 2190 out_inp_unlocked: 2191 IN_MULTI_UNLOCK(); 2192 2193 if (is_new && imf) { 2194 if (imf->imf_inm != NULL) { 2195 IN_MULTI_LIST_LOCK(); 2196 IF_ADDR_WLOCK(ifp); 2197 inm_release_deferred(imf->imf_inm); 2198 IF_ADDR_WUNLOCK(ifp); 2199 IN_MULTI_LIST_UNLOCK(); 2200 } 2201 ip_mfilter_free(imf); 2202 } 2203 if_rele(ifp); 2204 return (error); 2205 } 2206 2207 /* 2208 * Leave an IPv4 multicast group on an inpcb, possibly with a source. 2209 */ 2210 static int 2211 inp_leave_group(struct inpcb *inp, struct sockopt *sopt) 2212 { 2213 struct epoch_tracker et; 2214 struct group_source_req gsr; 2215 struct ip_mreq_source mreqs; 2216 sockunion_t *gsa, *ssa; 2217 struct ifnet *ifp; 2218 struct in_mfilter *imf; 2219 struct ip_moptions *imo; 2220 struct in_msource *ims; 2221 struct in_multi *inm; 2222 int error; 2223 bool is_final; 2224 2225 ifp = NULL; 2226 error = 0; 2227 is_final = true; 2228 2229 memset(&gsr, 0, sizeof(struct group_source_req)); 2230 gsa = (sockunion_t *)&gsr.gsr_group; 2231 gsa->ss.ss_family = AF_UNSPEC; 2232 ssa = (sockunion_t *)&gsr.gsr_source; 2233 ssa->ss.ss_family = AF_UNSPEC; 2234 2235 switch (sopt->sopt_name) { 2236 case IP_DROP_MEMBERSHIP: 2237 case IP_DROP_SOURCE_MEMBERSHIP: 2238 if (sopt->sopt_name == IP_DROP_MEMBERSHIP) { 2239 error = sooptcopyin(sopt, &mreqs, 2240 sizeof(struct ip_mreq), 2241 sizeof(struct ip_mreq)); 2242 /* 2243 * Swap interface and sourceaddr arguments, 2244 * as ip_mreq and ip_mreq_source are laid 2245 * out differently. 2246 */ 2247 mreqs.imr_interface = mreqs.imr_sourceaddr; 2248 mreqs.imr_sourceaddr.s_addr = INADDR_ANY; 2249 } else if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) { 2250 error = sooptcopyin(sopt, &mreqs, 2251 sizeof(struct ip_mreq_source), 2252 sizeof(struct ip_mreq_source)); 2253 } 2254 if (error) 2255 return (error); 2256 2257 gsa->sin.sin_family = AF_INET; 2258 gsa->sin.sin_len = sizeof(struct sockaddr_in); 2259 gsa->sin.sin_addr = mreqs.imr_multiaddr; 2260 2261 if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) { 2262 ssa->sin.sin_family = AF_INET; 2263 ssa->sin.sin_len = sizeof(struct sockaddr_in); 2264 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 2265 } 2266 2267 /* 2268 * Attempt to look up hinted ifp from interface address. 2269 * Fallthrough with null ifp iff lookup fails, to 2270 * preserve 4.4BSD mcast API idempotence. 2271 * XXX NOTE WELL: The RFC 3678 API is preferred because 2272 * using an IPv4 address as a key is racy. 2273 */ 2274 if (!in_nullhost(mreqs.imr_interface)) { 2275 NET_EPOCH_ENTER(et); 2276 INADDR_TO_IFP(mreqs.imr_interface, ifp); 2277 /* XXXGL ifref? */ 2278 NET_EPOCH_EXIT(et); 2279 } 2280 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p", 2281 __func__, ntohl(mreqs.imr_interface.s_addr), ifp); 2282 2283 break; 2284 2285 case MCAST_LEAVE_GROUP: 2286 case MCAST_LEAVE_SOURCE_GROUP: 2287 if (sopt->sopt_name == MCAST_LEAVE_GROUP) { 2288 error = sooptcopyin(sopt, &gsr, 2289 sizeof(struct group_req), 2290 sizeof(struct group_req)); 2291 } else if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) { 2292 error = sooptcopyin(sopt, &gsr, 2293 sizeof(struct group_source_req), 2294 sizeof(struct group_source_req)); 2295 } 2296 if (error) 2297 return (error); 2298 2299 if (gsa->sin.sin_family != AF_INET || 2300 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 2301 return (EINVAL); 2302 2303 if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) { 2304 if (ssa->sin.sin_family != AF_INET || 2305 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 2306 return (EINVAL); 2307 } 2308 2309 NET_EPOCH_ENTER(et); 2310 ifp = ifnet_byindex(gsr.gsr_interface); 2311 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */ 2312 if (ifp == NULL) 2313 return (EADDRNOTAVAIL); 2314 break; 2315 2316 default: 2317 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d", 2318 __func__, sopt->sopt_name); 2319 return (EOPNOTSUPP); 2320 break; 2321 } 2322 2323 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2324 return (EINVAL); 2325 2326 IN_MULTI_LOCK(); 2327 2328 /* 2329 * Find the membership in the membership list. 2330 */ 2331 imo = inp_findmoptions(inp); 2332 imf = imo_match_group(imo, ifp, &gsa->sa); 2333 if (imf == NULL) { 2334 error = EADDRNOTAVAIL; 2335 goto out_inp_locked; 2336 } 2337 inm = imf->imf_inm; 2338 2339 if (ssa->ss.ss_family != AF_UNSPEC) 2340 is_final = false; 2341 2342 /* 2343 * Begin state merge transaction at socket layer. 2344 */ 2345 INP_WLOCK_ASSERT(inp); 2346 2347 /* 2348 * If we were instructed only to leave a given source, do so. 2349 * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. 2350 */ 2351 if (is_final) { 2352 ip_mfilter_remove(&imo->imo_head, imf); 2353 imf_leave(imf); 2354 2355 /* 2356 * Give up the multicast address record to which 2357 * the membership points. 2358 */ 2359 (void) in_leavegroup_locked(imf->imf_inm, imf); 2360 } else { 2361 if (imf->imf_st[0] == MCAST_EXCLUDE) { 2362 error = EADDRNOTAVAIL; 2363 goto out_inp_locked; 2364 } 2365 ims = imo_match_source(imf, &ssa->sa); 2366 if (ims == NULL) { 2367 CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", 2368 __func__, ntohl(ssa->sin.sin_addr.s_addr), "not "); 2369 error = EADDRNOTAVAIL; 2370 goto out_inp_locked; 2371 } 2372 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block"); 2373 error = imf_prune(imf, &ssa->sin); 2374 if (error) { 2375 CTR1(KTR_IGMPV3, "%s: merge imf state failed", 2376 __func__); 2377 goto out_inp_locked; 2378 } 2379 } 2380 2381 /* 2382 * Begin state merge transaction at IGMP layer. 2383 */ 2384 if (!is_final) { 2385 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); 2386 IN_MULTI_LIST_LOCK(); 2387 error = inm_merge(inm, imf); 2388 if (error) { 2389 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", 2390 __func__); 2391 IN_MULTI_LIST_UNLOCK(); 2392 imf_rollback(imf); 2393 imf_reap(imf); 2394 goto out_inp_locked; 2395 } 2396 2397 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); 2398 error = igmp_change_state(inm); 2399 IN_MULTI_LIST_UNLOCK(); 2400 if (error) { 2401 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", 2402 __func__); 2403 imf_rollback(imf); 2404 imf_reap(imf); 2405 goto out_inp_locked; 2406 } 2407 } 2408 imf_commit(imf); 2409 imf_reap(imf); 2410 2411 out_inp_locked: 2412 INP_WUNLOCK(inp); 2413 2414 if (is_final && imf) 2415 ip_mfilter_free(imf); 2416 2417 IN_MULTI_UNLOCK(); 2418 return (error); 2419 } 2420 2421 /* 2422 * Select the interface for transmitting IPv4 multicast datagrams. 2423 * 2424 * Either an instance of struct in_addr or an instance of struct ip_mreqn 2425 * may be passed to this socket option. An address of INADDR_ANY or an 2426 * interface index of 0 is used to remove a previous selection. 2427 * When no interface is selected, one is chosen for every send. 2428 */ 2429 static int 2430 inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) 2431 { 2432 struct in_addr addr; 2433 struct ip_mreqn mreqn; 2434 struct ifnet *ifp; 2435 struct ip_moptions *imo; 2436 int error; 2437 2438 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) { 2439 /* 2440 * An interface index was specified using the 2441 * Linux-derived ip_mreqn structure. 2442 */ 2443 error = sooptcopyin(sopt, &mreqn, sizeof(struct ip_mreqn), 2444 sizeof(struct ip_mreqn)); 2445 if (error) 2446 return (error); 2447 2448 if (mreqn.imr_ifindex < 0) 2449 return (EINVAL); 2450 2451 if (mreqn.imr_ifindex == 0) { 2452 ifp = NULL; 2453 } else { 2454 struct epoch_tracker et; 2455 2456 NET_EPOCH_ENTER(et); 2457 ifp = ifnet_byindex(mreqn.imr_ifindex); 2458 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */ 2459 if (ifp == NULL) 2460 return (EADDRNOTAVAIL); 2461 } 2462 } else { 2463 /* 2464 * An interface was specified by IPv4 address. 2465 * This is the traditional BSD usage. 2466 */ 2467 error = sooptcopyin(sopt, &addr, sizeof(struct in_addr), 2468 sizeof(struct in_addr)); 2469 if (error) 2470 return (error); 2471 if (in_nullhost(addr)) { 2472 ifp = NULL; 2473 } else { 2474 struct epoch_tracker et; 2475 2476 NET_EPOCH_ENTER(et); 2477 INADDR_TO_IFP(addr, ifp); 2478 /* XXXGL ifref? */ 2479 NET_EPOCH_EXIT(et); 2480 if (ifp == NULL) 2481 return (EADDRNOTAVAIL); 2482 } 2483 CTR3(KTR_IGMPV3, "%s: ifp = %p, addr = 0x%08x", __func__, ifp, 2484 ntohl(addr.s_addr)); 2485 } 2486 2487 /* Reject interfaces which do not support multicast. */ 2488 if (ifp != NULL && (ifp->if_flags & IFF_MULTICAST) == 0) 2489 return (EOPNOTSUPP); 2490 2491 imo = inp_findmoptions(inp); 2492 imo->imo_multicast_ifp = ifp; 2493 imo->imo_multicast_addr.s_addr = INADDR_ANY; 2494 INP_WUNLOCK(inp); 2495 2496 return (0); 2497 } 2498 2499 /* 2500 * Atomically set source filters on a socket for an IPv4 multicast group. 2501 */ 2502 static int 2503 inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) 2504 { 2505 struct epoch_tracker et; 2506 struct __msfilterreq msfr; 2507 sockunion_t *gsa; 2508 struct ifnet *ifp; 2509 struct in_mfilter *imf; 2510 struct ip_moptions *imo; 2511 struct in_multi *inm; 2512 int error; 2513 2514 error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq), 2515 sizeof(struct __msfilterreq)); 2516 if (error) 2517 return (error); 2518 2519 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) 2520 return (ENOBUFS); 2521 2522 if ((msfr.msfr_fmode != MCAST_EXCLUDE && 2523 msfr.msfr_fmode != MCAST_INCLUDE)) 2524 return (EINVAL); 2525 2526 if (msfr.msfr_group.ss_family != AF_INET || 2527 msfr.msfr_group.ss_len != sizeof(struct sockaddr_in)) 2528 return (EINVAL); 2529 2530 gsa = (sockunion_t *)&msfr.msfr_group; 2531 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2532 return (EINVAL); 2533 2534 gsa->sin.sin_port = 0; /* ignore port */ 2535 2536 NET_EPOCH_ENTER(et); 2537 ifp = ifnet_byindex(msfr.msfr_ifindex); 2538 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */ 2539 if (ifp == NULL) 2540 return (EADDRNOTAVAIL); 2541 2542 IN_MULTI_LOCK(); 2543 2544 /* 2545 * Take the INP write lock. 2546 * Check if this socket is a member of this group. 2547 */ 2548 imo = inp_findmoptions(inp); 2549 imf = imo_match_group(imo, ifp, &gsa->sa); 2550 if (imf == NULL) { 2551 error = EADDRNOTAVAIL; 2552 goto out_inp_locked; 2553 } 2554 inm = imf->imf_inm; 2555 2556 /* 2557 * Begin state merge transaction at socket layer. 2558 */ 2559 INP_WLOCK_ASSERT(inp); 2560 2561 imf->imf_st[1] = msfr.msfr_fmode; 2562 2563 /* 2564 * Apply any new source filters, if present. 2565 * Make a copy of the user-space source vector so 2566 * that we may copy them with a single copyin. This 2567 * allows us to deal with page faults up-front. 2568 */ 2569 if (msfr.msfr_nsrcs > 0) { 2570 struct in_msource *lims; 2571 struct sockaddr_in *psin; 2572 struct sockaddr_storage *kss, *pkss; 2573 int i; 2574 2575 INP_WUNLOCK(inp); 2576 2577 CTR2(KTR_IGMPV3, "%s: loading %lu source list entries", 2578 __func__, (unsigned long)msfr.msfr_nsrcs); 2579 kss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs, 2580 M_TEMP, M_WAITOK); 2581 error = copyin(msfr.msfr_srcs, kss, 2582 sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); 2583 if (error) { 2584 free(kss, M_TEMP); 2585 return (error); 2586 } 2587 2588 INP_WLOCK(inp); 2589 2590 /* 2591 * Mark all source filters as UNDEFINED at t1. 2592 * Restore new group filter mode, as imf_leave() 2593 * will set it to INCLUDE. 2594 */ 2595 imf_leave(imf); 2596 imf->imf_st[1] = msfr.msfr_fmode; 2597 2598 /* 2599 * Update socket layer filters at t1, lazy-allocating 2600 * new entries. This saves a bunch of memory at the 2601 * cost of one RB_FIND() per source entry; duplicate 2602 * entries in the msfr_nsrcs vector are ignored. 2603 * If we encounter an error, rollback transaction. 2604 * 2605 * XXX This too could be replaced with a set-symmetric 2606 * difference like loop to avoid walking from root 2607 * every time, as the key space is common. 2608 */ 2609 for (i = 0, pkss = kss; i < msfr.msfr_nsrcs; i++, pkss++) { 2610 psin = (struct sockaddr_in *)pkss; 2611 if (psin->sin_family != AF_INET) { 2612 error = EAFNOSUPPORT; 2613 break; 2614 } 2615 if (psin->sin_len != sizeof(struct sockaddr_in)) { 2616 error = EINVAL; 2617 break; 2618 } 2619 error = imf_get_source(imf, psin, &lims); 2620 if (error) 2621 break; 2622 lims->imsl_st[1] = imf->imf_st[1]; 2623 } 2624 free(kss, M_TEMP); 2625 } 2626 2627 if (error) 2628 goto out_imf_rollback; 2629 2630 INP_WLOCK_ASSERT(inp); 2631 2632 /* 2633 * Begin state merge transaction at IGMP layer. 2634 */ 2635 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); 2636 IN_MULTI_LIST_LOCK(); 2637 error = inm_merge(inm, imf); 2638 if (error) { 2639 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); 2640 IN_MULTI_LIST_UNLOCK(); 2641 goto out_imf_rollback; 2642 } 2643 2644 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); 2645 error = igmp_change_state(inm); 2646 IN_MULTI_LIST_UNLOCK(); 2647 if (error) 2648 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); 2649 2650 out_imf_rollback: 2651 if (error) 2652 imf_rollback(imf); 2653 else 2654 imf_commit(imf); 2655 2656 imf_reap(imf); 2657 2658 out_inp_locked: 2659 INP_WUNLOCK(inp); 2660 IN_MULTI_UNLOCK(); 2661 return (error); 2662 } 2663 2664 /* 2665 * Set the IP multicast options in response to user setsockopt(). 2666 * 2667 * Many of the socket options handled in this function duplicate the 2668 * functionality of socket options in the regular unicast API. However, 2669 * it is not possible to merge the duplicate code, because the idempotence 2670 * of the IPv4 multicast part of the BSD Sockets API must be preserved; 2671 * the effects of these options must be treated as separate and distinct. 2672 * 2673 * SMPng: XXX: Unlocked read of inp_socket believed OK. 2674 * FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING 2675 * is refactored to no longer use vifs. 2676 */ 2677 int 2678 inp_setmoptions(struct inpcb *inp, struct sockopt *sopt) 2679 { 2680 struct ip_moptions *imo; 2681 int error; 2682 2683 error = 0; 2684 2685 /* If socket is neither of type SOCK_RAW or SOCK_DGRAM, reject it. */ 2686 if (inp->inp_socket->so_proto->pr_type != SOCK_RAW && 2687 inp->inp_socket->so_proto->pr_type != SOCK_DGRAM) 2688 return (EOPNOTSUPP); 2689 2690 switch (sopt->sopt_name) { 2691 case IP_MULTICAST_VIF: { 2692 int vifi; 2693 /* 2694 * Select a multicast VIF for transmission. 2695 * Only useful if multicast forwarding is active. 2696 */ 2697 if (legal_vif_num == NULL) { 2698 error = EOPNOTSUPP; 2699 break; 2700 } 2701 error = sooptcopyin(sopt, &vifi, sizeof(int), sizeof(int)); 2702 if (error) 2703 break; 2704 if (!legal_vif_num(vifi) && (vifi != -1)) { 2705 error = EINVAL; 2706 break; 2707 } 2708 imo = inp_findmoptions(inp); 2709 imo->imo_multicast_vif = vifi; 2710 INP_WUNLOCK(inp); 2711 break; 2712 } 2713 2714 case IP_MULTICAST_IF: 2715 error = inp_set_multicast_if(inp, sopt); 2716 break; 2717 2718 case IP_MULTICAST_TTL: { 2719 u_char ttl; 2720 2721 /* 2722 * Set the IP time-to-live for outgoing multicast packets. 2723 * The original multicast API required a char argument, 2724 * which is inconsistent with the rest of the socket API. 2725 * We allow either a char or an int. 2726 */ 2727 if (sopt->sopt_valsize == sizeof(u_char)) { 2728 error = sooptcopyin(sopt, &ttl, sizeof(u_char), 2729 sizeof(u_char)); 2730 if (error) 2731 break; 2732 } else { 2733 u_int ittl; 2734 2735 error = sooptcopyin(sopt, &ittl, sizeof(u_int), 2736 sizeof(u_int)); 2737 if (error) 2738 break; 2739 if (ittl > 255) { 2740 error = EINVAL; 2741 break; 2742 } 2743 ttl = (u_char)ittl; 2744 } 2745 imo = inp_findmoptions(inp); 2746 imo->imo_multicast_ttl = ttl; 2747 INP_WUNLOCK(inp); 2748 break; 2749 } 2750 2751 case IP_MULTICAST_LOOP: { 2752 u_char loop; 2753 2754 /* 2755 * Set the loopback flag for outgoing multicast packets. 2756 * Must be zero or one. The original multicast API required a 2757 * char argument, which is inconsistent with the rest 2758 * of the socket API. We allow either a char or an int. 2759 */ 2760 if (sopt->sopt_valsize == sizeof(u_char)) { 2761 error = sooptcopyin(sopt, &loop, sizeof(u_char), 2762 sizeof(u_char)); 2763 if (error) 2764 break; 2765 } else { 2766 u_int iloop; 2767 2768 error = sooptcopyin(sopt, &iloop, sizeof(u_int), 2769 sizeof(u_int)); 2770 if (error) 2771 break; 2772 loop = (u_char)iloop; 2773 } 2774 imo = inp_findmoptions(inp); 2775 imo->imo_multicast_loop = !!loop; 2776 INP_WUNLOCK(inp); 2777 break; 2778 } 2779 2780 case IP_ADD_MEMBERSHIP: 2781 case IP_ADD_SOURCE_MEMBERSHIP: 2782 case MCAST_JOIN_GROUP: 2783 case MCAST_JOIN_SOURCE_GROUP: 2784 error = inp_join_group(inp, sopt); 2785 break; 2786 2787 case IP_DROP_MEMBERSHIP: 2788 case IP_DROP_SOURCE_MEMBERSHIP: 2789 case MCAST_LEAVE_GROUP: 2790 case MCAST_LEAVE_SOURCE_GROUP: 2791 error = inp_leave_group(inp, sopt); 2792 break; 2793 2794 case IP_BLOCK_SOURCE: 2795 case IP_UNBLOCK_SOURCE: 2796 case MCAST_BLOCK_SOURCE: 2797 case MCAST_UNBLOCK_SOURCE: 2798 error = inp_block_unblock_source(inp, sopt); 2799 break; 2800 2801 case IP_MSFILTER: 2802 error = inp_set_source_filters(inp, sopt); 2803 break; 2804 2805 default: 2806 error = EOPNOTSUPP; 2807 break; 2808 } 2809 2810 INP_UNLOCK_ASSERT(inp); 2811 2812 return (error); 2813 } 2814 2815 /* 2816 * Expose IGMP's multicast filter mode and source list(s) to userland, 2817 * keyed by (ifindex, group). 2818 * The filter mode is written out as a uint32_t, followed by 2819 * 0..n of struct in_addr. 2820 * For use by ifmcstat(8). 2821 * SMPng: NOTE: unlocked read of ifindex space. 2822 */ 2823 static int 2824 sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS) 2825 { 2826 struct in_addr src, group; 2827 struct epoch_tracker et; 2828 struct ifnet *ifp; 2829 struct ifmultiaddr *ifma; 2830 struct in_multi *inm; 2831 struct ip_msource *ims; 2832 int *name; 2833 int retval; 2834 u_int namelen; 2835 uint32_t fmode, ifindex; 2836 2837 name = (int *)arg1; 2838 namelen = arg2; 2839 2840 if (req->newptr != NULL) 2841 return (EPERM); 2842 2843 if (namelen != 2) 2844 return (EINVAL); 2845 2846 group.s_addr = name[1]; 2847 if (!IN_MULTICAST(ntohl(group.s_addr))) { 2848 CTR2(KTR_IGMPV3, "%s: group 0x%08x is not multicast", 2849 __func__, ntohl(group.s_addr)); 2850 return (EINVAL); 2851 } 2852 2853 ifindex = name[0]; 2854 NET_EPOCH_ENTER(et); 2855 ifp = ifnet_byindex(ifindex); 2856 if (ifp == NULL) { 2857 NET_EPOCH_EXIT(et); 2858 CTR2(KTR_IGMPV3, "%s: no ifp for ifindex %u", 2859 __func__, ifindex); 2860 return (ENOENT); 2861 } 2862 2863 retval = sysctl_wire_old_buffer(req, 2864 sizeof(uint32_t) + (in_mcast_maxgrpsrc * sizeof(struct in_addr))); 2865 if (retval) { 2866 NET_EPOCH_EXIT(et); 2867 return (retval); 2868 } 2869 2870 IN_MULTI_LIST_LOCK(); 2871 2872 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2873 inm = inm_ifmultiaddr_get_inm(ifma); 2874 if (inm == NULL) 2875 continue; 2876 if (!in_hosteq(inm->inm_addr, group)) 2877 continue; 2878 fmode = inm->inm_st[1].iss_fmode; 2879 retval = SYSCTL_OUT(req, &fmode, sizeof(uint32_t)); 2880 if (retval != 0) 2881 break; 2882 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 2883 CTR2(KTR_IGMPV3, "%s: visit node 0x%08x", __func__, 2884 ims->ims_haddr); 2885 /* 2886 * Only copy-out sources which are in-mode. 2887 */ 2888 if (fmode != ims_get_mode(inm, ims, 1)) { 2889 CTR1(KTR_IGMPV3, "%s: skip non-in-mode", 2890 __func__); 2891 continue; 2892 } 2893 src.s_addr = htonl(ims->ims_haddr); 2894 retval = SYSCTL_OUT(req, &src, sizeof(struct in_addr)); 2895 if (retval != 0) 2896 break; 2897 } 2898 } 2899 2900 IN_MULTI_LIST_UNLOCK(); 2901 NET_EPOCH_EXIT(et); 2902 2903 return (retval); 2904 } 2905 2906 #if defined(KTR) && (KTR_COMPILE & KTR_IGMPV3) 2907 2908 static const char *inm_modestrs[] = { 2909 [MCAST_UNDEFINED] = "un", 2910 [MCAST_INCLUDE] = "in", 2911 [MCAST_EXCLUDE] = "ex", 2912 }; 2913 _Static_assert(MCAST_UNDEFINED == 0 && 2914 MCAST_EXCLUDE + 1 == nitems(inm_modestrs), 2915 "inm_modestrs: no longer matches #defines"); 2916 2917 static const char * 2918 inm_mode_str(const int mode) 2919 { 2920 2921 if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) 2922 return (inm_modestrs[mode]); 2923 return ("??"); 2924 } 2925 2926 static const char *inm_statestrs[] = { 2927 [IGMP_NOT_MEMBER] = "not-member", 2928 [IGMP_SILENT_MEMBER] = "silent", 2929 [IGMP_REPORTING_MEMBER] = "reporting", 2930 [IGMP_IDLE_MEMBER] = "idle", 2931 [IGMP_LAZY_MEMBER] = "lazy", 2932 [IGMP_SLEEPING_MEMBER] = "sleeping", 2933 [IGMP_AWAKENING_MEMBER] = "awakening", 2934 [IGMP_G_QUERY_PENDING_MEMBER] = "query-pending", 2935 [IGMP_SG_QUERY_PENDING_MEMBER] = "sg-query-pending", 2936 [IGMP_LEAVING_MEMBER] = "leaving", 2937 }; 2938 _Static_assert(IGMP_NOT_MEMBER == 0 && 2939 IGMP_LEAVING_MEMBER + 1 == nitems(inm_statestrs), 2940 "inm_statetrs: no longer matches #defines"); 2941 2942 static const char * 2943 inm_state_str(const int state) 2944 { 2945 2946 if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER) 2947 return (inm_statestrs[state]); 2948 return ("??"); 2949 } 2950 2951 /* 2952 * Dump an in_multi structure to the console. 2953 */ 2954 void 2955 inm_print(const struct in_multi *inm) 2956 { 2957 int t; 2958 char addrbuf[INET_ADDRSTRLEN]; 2959 2960 if ((ktr_mask & KTR_IGMPV3) == 0) 2961 return; 2962 2963 printf("%s: --- begin inm %p ---\n", __func__, inm); 2964 printf("addr %s ifp %p(%s) ifma %p\n", 2965 inet_ntoa_r(inm->inm_addr, addrbuf), 2966 inm->inm_ifp, 2967 inm->inm_ifp->if_xname, 2968 inm->inm_ifma); 2969 printf("timer %u state %s refcount %u scq.len %u\n", 2970 inm->inm_timer, 2971 inm_state_str(inm->inm_state), 2972 inm->inm_refcount, 2973 inm->inm_scq.mq_len); 2974 printf("igi %p nsrc %lu sctimer %u scrv %u\n", 2975 inm->inm_igi, 2976 inm->inm_nsrc, 2977 inm->inm_sctimer, 2978 inm->inm_scrv); 2979 for (t = 0; t < 2; t++) { 2980 printf("t%d: fmode %s asm %u ex %u in %u rec %u\n", t, 2981 inm_mode_str(inm->inm_st[t].iss_fmode), 2982 inm->inm_st[t].iss_asm, 2983 inm->inm_st[t].iss_ex, 2984 inm->inm_st[t].iss_in, 2985 inm->inm_st[t].iss_rec); 2986 } 2987 printf("%s: --- end inm %p ---\n", __func__, inm); 2988 } 2989 2990 #else /* !KTR || !(KTR_COMPILE & KTR_IGMPV3) */ 2991 2992 void 2993 inm_print(const struct in_multi *inm) 2994 { 2995 2996 } 2997 2998 #endif /* KTR && (KTR_COMPILE & KTR_IGMPV3) */ 2999 3000 RB_GENERATE(ip_msource_tree, ip_msource, ims_link, ip_msource_cmp); 3001