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