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