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