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