1/* 2 * Copyright (c) 2010-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/*- 29 * Copyright (c) 2007-2009 Bruce Simpson. 30 * Copyright (c) 2005 Robert N. M. Watson. 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. The name of the author may not be used to endorse or promote 42 * products derived from this software without specific prior written 43 * permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 */ 57 58/* 59 * IPv4 multicast socket, group, and socket option processing module. 60 */ 61 62#include <sys/cdefs.h> 63 64#include <sys/param.h> 65#include <sys/systm.h> 66#include <sys/kernel.h> 67#include <sys/malloc.h> 68#include <sys/mbuf.h> 69#include <sys/protosw.h> 70#include <sys/socket.h> 71#include <sys/socketvar.h> 72#include <sys/protosw.h> 73#include <sys/sysctl.h> 74#include <sys/tree.h> 75#include <sys/mcache.h> 76 77#include <kern/zalloc.h> 78 79#include <pexpert/pexpert.h> 80 81#include <net/if.h> 82#include <net/if_dl.h> 83#include <net/route.h> 84 85#include <netinet/in.h> 86#include <netinet/in_systm.h> 87#include <netinet/in_pcb.h> 88#include <netinet/in_var.h> 89#include <netinet/ip_var.h> 90#include <netinet/igmp_var.h> 91 92#ifndef __SOCKUNION_DECLARED 93union sockunion { 94 struct sockaddr_storage ss; 95 struct sockaddr sa; 96 struct sockaddr_dl sdl; 97 struct sockaddr_in sin; 98}; 99typedef union sockunion sockunion_t; 100#define __SOCKUNION_DECLARED 101#endif /* __SOCKUNION_DECLARED */ 102 103/* 104 * Functions with non-static linkage defined in this file should be 105 * declared in in_var.h: 106 * imo_multi_filter() 107 * in_addmulti() 108 * in_delmulti() 109 * in_joingroup() 110 * in_leavegroup() 111 * and ip_var.h: 112 * inp_freemoptions() 113 * inp_getmoptions() 114 * inp_setmoptions() 115 * 116 * XXX: Both carp and pf need to use the legacy (*,G) KPIs in_addmulti() 117 * and in_delmulti(). 118 */ 119static void imf_commit(struct in_mfilter *); 120static int imf_get_source(struct in_mfilter *imf, 121 const struct sockaddr_in *psin, 122 struct in_msource **); 123static struct in_msource * 124 imf_graft(struct in_mfilter *, const uint8_t, 125 const struct sockaddr_in *); 126static int imf_prune(struct in_mfilter *, const struct sockaddr_in *); 127static void imf_rollback(struct in_mfilter *); 128static void imf_reap(struct in_mfilter *); 129static int imo_grow(struct ip_moptions *, size_t); 130static size_t imo_match_group(const struct ip_moptions *, 131 const struct ifnet *, const struct sockaddr *); 132static struct in_msource * 133 imo_match_source(const struct ip_moptions *, const size_t, 134 const struct sockaddr *); 135static void ims_merge(struct ip_msource *ims, 136 const struct in_msource *lims, const int rollback); 137static int in_getmulti(struct ifnet *, const struct in_addr *, 138 struct in_multi **); 139static int in_joingroup(struct ifnet *, const struct in_addr *, 140 struct in_mfilter *, struct in_multi **); 141static int inm_get_source(struct in_multi *inm, const in_addr_t haddr, 142 const int noalloc, struct ip_msource **pims); 143static int inm_is_ifp_detached(const struct in_multi *); 144static int inm_merge(struct in_multi *, /*const*/ struct in_mfilter *); 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 struct ifnet * 150 inp_lookup_mcast_ifp(const struct inpcb *, 151 const struct sockaddr_in *, const struct in_addr); 152static int inp_block_unblock_source(struct inpcb *, struct sockopt *); 153static int inp_set_multicast_if(struct inpcb *, struct sockopt *); 154static int inp_set_source_filters(struct inpcb *, struct sockopt *); 155static int sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS; 156static struct ifnet * ip_multicast_if(struct in_addr *, unsigned int *); 157static __inline__ int ip_msource_cmp(const struct ip_msource *, 158 const struct ip_msource *); 159 160SYSCTL_NODE(_net_inet_ip, OID_AUTO, mcast, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "IPv4 multicast"); 161 162static u_long in_mcast_maxgrpsrc = IP_MAX_GROUP_SRC_FILTER; 163SYSCTL_LONG(_net_inet_ip_mcast, OID_AUTO, maxgrpsrc, 164 CTLFLAG_RW | CTLFLAG_LOCKED, &in_mcast_maxgrpsrc, "Max source filters per group"); 165 166static u_long in_mcast_maxsocksrc = IP_MAX_SOCK_SRC_FILTER; 167SYSCTL_LONG(_net_inet_ip_mcast, OID_AUTO, maxsocksrc, 168 CTLFLAG_RW | CTLFLAG_LOCKED, &in_mcast_maxsocksrc, 169 "Max source filters per socket"); 170 171int in_mcast_loop = IP_DEFAULT_MULTICAST_LOOP; 172SYSCTL_INT(_net_inet_ip_mcast, OID_AUTO, loop, CTLFLAG_RW | CTLFLAG_LOCKED, 173 &in_mcast_loop, 0, "Loopback multicast datagrams by default"); 174 175SYSCTL_NODE(_net_inet_ip_mcast, OID_AUTO, filters, 176 CTLFLAG_RD | CTLFLAG_LOCKED, sysctl_ip_mcast_filters, 177 "Per-interface stack-wide source filters"); 178 179RB_GENERATE_PREV(ip_msource_tree, ip_msource, ims_link, ip_msource_cmp); 180 181#define INM_TRACE_HIST_SIZE 32 /* size of trace history */ 182 183/* For gdb */ 184__private_extern__ unsigned int inm_trace_hist_size = INM_TRACE_HIST_SIZE; 185 186struct in_multi_dbg { 187 struct in_multi inm; /* in_multi */ 188 u_int16_t inm_refhold_cnt; /* # of ref */ 189 u_int16_t inm_refrele_cnt; /* # of rele */ 190 /* 191 * Circular lists of inm_addref and inm_remref callers. 192 */ 193 ctrace_t inm_refhold[INM_TRACE_HIST_SIZE]; 194 ctrace_t inm_refrele[INM_TRACE_HIST_SIZE]; 195 /* 196 * Trash list linkage 197 */ 198 TAILQ_ENTRY(in_multi_dbg) inm_trash_link; 199}; 200 201/* List of trash in_multi entries protected by inm_trash_lock */ 202static TAILQ_HEAD(, in_multi_dbg) inm_trash_head; 203static decl_lck_mtx_data(, inm_trash_lock); 204 205#define INM_ZONE_MAX 64 /* maximum elements in zone */ 206#define INM_ZONE_NAME "in_multi" /* zone name */ 207 208#if DEBUG 209static unsigned int inm_debug = 1; /* debugging (enabled) */ 210#else 211static unsigned int inm_debug; /* debugging (disabled) */ 212#endif /* !DEBUG */ 213static unsigned int inm_size; /* size of zone element */ 214static struct zone *inm_zone; /* zone for in_multi */ 215 216#define IPMS_ZONE_MAX 64 /* maximum elements in zone */ 217#define IPMS_ZONE_NAME "ip_msource" /* zone name */ 218 219static unsigned int ipms_size; /* size of zone element */ 220static struct zone *ipms_zone; /* zone for ip_msource */ 221 222#define INMS_ZONE_MAX 64 /* maximum elements in zone */ 223#define INMS_ZONE_NAME "in_msource" /* zone name */ 224 225static unsigned int inms_size; /* size of zone element */ 226static struct zone *inms_zone; /* zone for in_msource */ 227 228/* Lock group and attribute for in_multihead_lock lock */ 229static lck_attr_t *in_multihead_lock_attr; 230static lck_grp_t *in_multihead_lock_grp; 231static lck_grp_attr_t *in_multihead_lock_grp_attr; 232 233static decl_lck_rw_data(, in_multihead_lock); 234struct in_multihead in_multihead; 235 236static struct in_multi *in_multi_alloc(int); 237static void in_multi_free(struct in_multi *); 238static void in_multi_attach(struct in_multi *); 239static void inm_trace(struct in_multi *, int); 240 241static struct ip_msource *ipms_alloc(int); 242static void ipms_free(struct ip_msource *); 243static struct in_msource *inms_alloc(int); 244static void inms_free(struct in_msource *); 245 246static __inline int 247ip_msource_cmp(const struct ip_msource *a, const struct ip_msource *b) 248{ 249 250 if (a->ims_haddr < b->ims_haddr) 251 return (-1); 252 if (a->ims_haddr == b->ims_haddr) 253 return (0); 254 return (1); 255} 256 257/* 258 * Inline function which wraps assertions for a valid ifp. 259 */ 260static __inline__ int 261inm_is_ifp_detached(const struct in_multi *inm) 262{ 263 VERIFY(inm->inm_ifma != NULL); 264 VERIFY(inm->inm_ifp == inm->inm_ifma->ifma_ifp); 265 266 return (!ifnet_is_attached(inm->inm_ifp, 0)); 267} 268 269/* 270 * Initialize an in_mfilter structure to a known state at t0, t1 271 * with an empty source filter list. 272 */ 273static __inline__ void 274imf_init(struct in_mfilter *imf, const int st0, const int st1) 275{ 276 memset(imf, 0, sizeof(struct in_mfilter)); 277 RB_INIT(&imf->imf_sources); 278 imf->imf_st[0] = st0; 279 imf->imf_st[1] = st1; 280} 281 282/* 283 * Resize the ip_moptions vector to the next power-of-two minus 1. 284 */ 285static int 286imo_grow(struct ip_moptions *imo, size_t newmax) 287{ 288 struct in_multi **nmships; 289 struct in_multi **omships; 290 struct in_mfilter *nmfilters; 291 struct in_mfilter *omfilters; 292 size_t idx; 293 size_t oldmax; 294 295 IMO_LOCK_ASSERT_HELD(imo); 296 297 nmships = NULL; 298 nmfilters = NULL; 299 omships = imo->imo_membership; 300 omfilters = imo->imo_mfilters; 301 oldmax = imo->imo_max_memberships; 302 if (newmax == 0) 303 newmax = ((oldmax + 1) * 2) - 1; 304 305 if (newmax > IP_MAX_MEMBERSHIPS) 306 return (ETOOMANYREFS); 307 308 if ((nmships = (struct in_multi **)_REALLOC(omships, 309 sizeof (struct in_multi *) * newmax, M_IPMOPTS, 310 M_WAITOK | M_ZERO)) == NULL) 311 return (ENOMEM); 312 313 imo->imo_membership = nmships; 314 315 if ((nmfilters = (struct in_mfilter *)_REALLOC(omfilters, 316 sizeof (struct in_mfilter) * newmax, M_INMFILTER, 317 M_WAITOK | M_ZERO)) == NULL) 318 return (ENOMEM); 319 320 imo->imo_mfilters = nmfilters; 321 322 /* Initialize newly allocated source filter heads. */ 323 for (idx = oldmax; idx < newmax; idx++) 324 imf_init(&nmfilters[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); 325 326 imo->imo_max_memberships = newmax; 327 328 return (0); 329} 330 331/* 332 * Find an IPv4 multicast group entry for this ip_moptions instance 333 * which matches the specified group, and optionally an interface. 334 * Return its index into the array, or -1 if not found. 335 */ 336static size_t 337imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp, 338 const struct sockaddr *group) 339{ 340 const struct sockaddr_in *gsin; 341 struct in_multi *pinm; 342 int idx; 343 int nmships; 344 345 IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo)); 346 347 gsin = (struct sockaddr_in *)(uintptr_t)(size_t)group; 348 349 /* The imo_membership array may be lazy allocated. */ 350 if (imo->imo_membership == NULL || imo->imo_num_memberships == 0) 351 return (-1); 352 353 nmships = imo->imo_num_memberships; 354 for (idx = 0; idx < nmships; idx++) { 355 pinm = imo->imo_membership[idx]; 356 if (pinm == NULL) 357 continue; 358 INM_LOCK(pinm); 359 if ((ifp == NULL || (pinm->inm_ifp == ifp)) && 360 in_hosteq(pinm->inm_addr, gsin->sin_addr)) { 361 INM_UNLOCK(pinm); 362 break; 363 } 364 INM_UNLOCK(pinm); 365 } 366 if (idx >= nmships) 367 idx = -1; 368 369 return (idx); 370} 371 372/* 373 * Find an IPv4 multicast source entry for this imo which matches 374 * the given group index for this socket, and source address. 375 * 376 * NOTE: This does not check if the entry is in-mode, merely if 377 * it exists, which may not be the desired behaviour. 378 */ 379static struct in_msource * 380imo_match_source(const struct ip_moptions *imo, const size_t gidx, 381 const struct sockaddr *src) 382{ 383 struct ip_msource find; 384 struct in_mfilter *imf; 385 struct ip_msource *ims; 386 const sockunion_t *psa; 387 388 IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo)); 389 390 VERIFY(src->sa_family == AF_INET); 391 VERIFY(gidx != (size_t)-1 && gidx < imo->imo_num_memberships); 392 393 /* The imo_mfilters array may be lazy allocated. */ 394 if (imo->imo_mfilters == NULL) 395 return (NULL); 396 imf = &imo->imo_mfilters[gidx]; 397 398 /* Source trees are keyed in host byte order. */ 399 psa = (sockunion_t *)(uintptr_t)(size_t)src; 400 find.ims_haddr = ntohl(psa->sin.sin_addr.s_addr); 401 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); 402 403 return ((struct in_msource *)ims); 404} 405 406/* 407 * Perform filtering for multicast datagrams on a socket by group and source. 408 * 409 * Returns 0 if a datagram should be allowed through, or various error codes 410 * if the socket was not a member of the group, or the source was muted, etc. 411 */ 412int 413imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp, 414 const struct sockaddr *group, const struct sockaddr *src) 415{ 416 size_t gidx; 417 struct in_msource *ims; 418 int mode; 419 420 IMO_LOCK_ASSERT_HELD(__DECONST(struct ip_moptions *, imo)); 421 VERIFY(ifp != NULL); 422 423 gidx = imo_match_group(imo, ifp, group); 424 if (gidx == (size_t)-1) 425 return (MCAST_NOTGMEMBER); 426 427 /* 428 * Check if the source was included in an (S,G) join. 429 * Allow reception on exclusive memberships by default, 430 * reject reception on inclusive memberships by default. 431 * Exclude source only if an in-mode exclude filter exists. 432 * Include source only if an in-mode include filter exists. 433 * NOTE: We are comparing group state here at IGMP t1 (now) 434 * with socket-layer t0 (since last downcall). 435 */ 436 mode = imo->imo_mfilters[gidx].imf_st[1]; 437 ims = imo_match_source(imo, gidx, src); 438 439 if ((ims == NULL && mode == MCAST_INCLUDE) || 440 (ims != NULL && ims->imsl_st[0] != mode)) { 441 return (MCAST_NOTSMEMBER); 442 } 443 444 return (MCAST_PASS); 445} 446 447int 448imo_clone(struct inpcb *from_inp, struct inpcb *to_inp) 449{ 450 int i, err = 0; 451 struct ip_moptions *from; 452 struct ip_moptions *to; 453 454 from = inp_findmoptions(from_inp); 455 if (from == NULL) 456 return (ENOMEM); 457 458 to = inp_findmoptions(to_inp); 459 if (to == NULL) { 460 IMO_REMREF(from); 461 return (ENOMEM); 462 } 463 464 IMO_LOCK(from); 465 IMO_LOCK(to); 466 467 to->imo_multicast_ifp = from->imo_multicast_ifp; 468 to->imo_multicast_vif = from->imo_multicast_vif; 469 to->imo_multicast_ttl = from->imo_multicast_ttl; 470 to->imo_multicast_loop = from->imo_multicast_loop; 471 472 /* 473 * We're cloning, so drop any existing memberships and source 474 * filters on the destination ip_moptions. 475 */ 476 for (i = 0; i < to->imo_num_memberships; ++i) { 477 struct in_mfilter *imf; 478 479 imf = to->imo_mfilters ? &to->imo_mfilters[i] : NULL; 480 if (imf != NULL) 481 imf_leave(imf); 482 483 (void) in_leavegroup(to->imo_membership[i], imf); 484 485 if (imf != NULL) 486 imf_purge(imf); 487 488 INM_REMREF(to->imo_membership[i]); 489 to->imo_membership[i] = NULL; 490 } 491 to->imo_num_memberships = 0; 492 493 VERIFY(to->imo_max_memberships != 0 && from->imo_max_memberships != 0); 494 if (to->imo_max_memberships < from->imo_max_memberships) { 495 /* 496 * Ensure source and destination ip_moptions memberships 497 * and source filters arrays are at least equal in size. 498 */ 499 err = imo_grow(to, from->imo_max_memberships); 500 if (err != 0) 501 goto done; 502 } 503 VERIFY(to->imo_max_memberships >= from->imo_max_memberships); 504 505 /* 506 * Source filtering doesn't apply to OpenTransport socket, 507 * so simply hold additional reference count per membership. 508 */ 509 for (i = 0; i < from->imo_num_memberships; i++) { 510 to->imo_membership[i] = 511 in_addmulti(&from->imo_membership[i]->inm_addr, 512 from->imo_membership[i]->inm_ifp); 513 if (to->imo_membership[i] == NULL) 514 break; 515 to->imo_num_memberships++; 516 } 517 VERIFY(to->imo_num_memberships == from->imo_num_memberships); 518 519done: 520 IMO_UNLOCK(to); 521 IMO_REMREF(to); 522 IMO_UNLOCK(from); 523 IMO_REMREF(from); 524 525 return (err); 526} 527 528/* 529 * Find and return a reference to an in_multi record for (ifp, group), 530 * and bump its reference count. 531 * If one does not exist, try to allocate it, and update link-layer multicast 532 * filters on ifp to listen for group. 533 * Return 0 if successful, otherwise return an appropriate error code. 534 */ 535static int 536in_getmulti(struct ifnet *ifp, const struct in_addr *group, 537 struct in_multi **pinm) 538{ 539 struct sockaddr_in gsin; 540 struct ifmultiaddr *ifma; 541 struct in_multi *inm; 542 int error; 543 544 in_multihead_lock_shared(); 545 IN_LOOKUP_MULTI(group, ifp, inm); 546 if (inm != NULL) { 547 INM_LOCK(inm); 548 VERIFY(inm->inm_reqcnt >= 1); 549 inm->inm_reqcnt++; 550 VERIFY(inm->inm_reqcnt != 0); 551 *pinm = inm; 552 INM_UNLOCK(inm); 553 in_multihead_lock_done(); 554 /* 555 * We already joined this group; return the inm 556 * with a refcount held (via lookup) for caller. 557 */ 558 return (0); 559 } 560 in_multihead_lock_done(); 561 562 bzero(&gsin, sizeof(gsin)); 563 gsin.sin_family = AF_INET; 564 gsin.sin_len = sizeof(struct sockaddr_in); 565 gsin.sin_addr = *group; 566 567 /* 568 * Check if a link-layer group is already associated 569 * with this network-layer group on the given ifnet. 570 */ 571 error = if_addmulti(ifp, (struct sockaddr *)&gsin, &ifma); 572 if (error != 0) 573 return (error); 574 575 /* 576 * See comments in inm_remref() for access to ifma_protospec. 577 */ 578 in_multihead_lock_exclusive(); 579 IFMA_LOCK(ifma); 580 if ((inm = ifma->ifma_protospec) != NULL) { 581 VERIFY(ifma->ifma_addr != NULL); 582 VERIFY(ifma->ifma_addr->sa_family == AF_INET); 583 INM_ADDREF(inm); /* for caller */ 584 IFMA_UNLOCK(ifma); 585 INM_LOCK(inm); 586 VERIFY(inm->inm_ifma == ifma); 587 VERIFY(inm->inm_ifp == ifp); 588 VERIFY(in_hosteq(inm->inm_addr, *group)); 589 if (inm->inm_debug & IFD_ATTACHED) { 590 VERIFY(inm->inm_reqcnt >= 1); 591 inm->inm_reqcnt++; 592 VERIFY(inm->inm_reqcnt != 0); 593 *pinm = inm; 594 INM_UNLOCK(inm); 595 in_multihead_lock_done(); 596 IFMA_REMREF(ifma); 597 /* 598 * We lost the race with another thread doing 599 * in_getmulti(); since this group has already 600 * been joined; return the inm with a refcount 601 * held for caller. 602 */ 603 return (0); 604 } 605 /* 606 * We lost the race with another thread doing in_delmulti(); 607 * the inm referring to the ifma has been detached, thus we 608 * reattach it back to the in_multihead list and return the 609 * inm with a refcount held for the caller. 610 */ 611 in_multi_attach(inm); 612 VERIFY((inm->inm_debug & 613 (IFD_ATTACHED | IFD_TRASHED)) == IFD_ATTACHED); 614 *pinm = inm; 615 INM_UNLOCK(inm); 616 in_multihead_lock_done(); 617 IFMA_REMREF(ifma); 618 return (0); 619 } 620 IFMA_UNLOCK(ifma); 621 622 /* 623 * A new in_multi record is needed; allocate and initialize it. 624 * We DO NOT perform an IGMP join as the in_ layer may need to 625 * push an initial source list down to IGMP to support SSM. 626 * 627 * The initial source filter state is INCLUDE, {} as per the RFC. 628 */ 629 inm = in_multi_alloc(M_WAITOK); 630 if (inm == NULL) { 631 in_multihead_lock_done(); 632 IFMA_REMREF(ifma); 633 return (ENOMEM); 634 } 635 INM_LOCK(inm); 636 inm->inm_addr = *group; 637 inm->inm_ifp = ifp; 638 inm->inm_igi = IGMP_IFINFO(ifp); 639 VERIFY(inm->inm_igi != NULL); 640 IGI_ADDREF(inm->inm_igi); 641 inm->inm_ifma = ifma; /* keep refcount from if_addmulti() */ 642 inm->inm_state = IGMP_NOT_MEMBER; 643 /* 644 * Pending state-changes per group are subject to a bounds check. 645 */ 646 inm->inm_scq.ifq_maxlen = IGMP_MAX_STATE_CHANGES; 647 inm->inm_st[0].iss_fmode = MCAST_UNDEFINED; 648 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED; 649 RB_INIT(&inm->inm_srcs); 650 *pinm = inm; 651 in_multi_attach(inm); 652 VERIFY((inm->inm_debug & (IFD_ATTACHED | IFD_TRASHED)) == IFD_ATTACHED); 653 INM_ADDREF_LOCKED(inm); /* for caller */ 654 INM_UNLOCK(inm); 655 656 IFMA_LOCK(ifma); 657 VERIFY(ifma->ifma_protospec == NULL); 658 ifma->ifma_protospec = inm; 659 IFMA_UNLOCK(ifma); 660 in_multihead_lock_done(); 661 662 return (0); 663} 664 665/* 666 * Clear recorded source entries for a group. 667 * Used by the IGMP code. 668 * FIXME: Should reap. 669 */ 670void 671inm_clear_recorded(struct in_multi *inm) 672{ 673 struct ip_msource *ims; 674 675 INM_LOCK_ASSERT_HELD(inm); 676 677 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 678 if (ims->ims_stp) { 679 ims->ims_stp = 0; 680 --inm->inm_st[1].iss_rec; 681 } 682 } 683 VERIFY(inm->inm_st[1].iss_rec == 0); 684} 685 686/* 687 * Record a source as pending for a Source-Group IGMPv3 query. 688 * This lives here as it modifies the shared tree. 689 * 690 * inm is the group descriptor. 691 * naddr is the address of the source to record in network-byte order. 692 * 693 * If the net.inet.igmp.sgalloc sysctl is non-zero, we will 694 * lazy-allocate a source node in response to an SG query. 695 * Otherwise, no allocation is performed. This saves some memory 696 * with the trade-off that the source will not be reported to the 697 * router if joined in the window between the query response and 698 * the group actually being joined on the local host. 699 * 700 * Return 0 if the source didn't exist or was already marked as recorded. 701 * Return 1 if the source was marked as recorded by this function. 702 * Return <0 if any error occured (negated errno code). 703 */ 704int 705inm_record_source(struct in_multi *inm, const in_addr_t naddr) 706{ 707 struct ip_msource find; 708 struct ip_msource *ims, *nims; 709 710 INM_LOCK_ASSERT_HELD(inm); 711 712 find.ims_haddr = ntohl(naddr); 713 ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find); 714 if (ims && ims->ims_stp) 715 return (0); 716 if (ims == NULL) { 717 if (inm->inm_nsrc == in_mcast_maxgrpsrc) 718 return (-ENOSPC); 719 nims = ipms_alloc(M_WAITOK); 720 if (nims == NULL) 721 return (-ENOMEM); 722 nims->ims_haddr = find.ims_haddr; 723 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims); 724 ++inm->inm_nsrc; 725 ims = nims; 726 } 727 728 /* 729 * Mark the source as recorded and update the recorded 730 * source count. 731 */ 732 ++ims->ims_stp; 733 ++inm->inm_st[1].iss_rec; 734 735 return (1); 736} 737 738/* 739 * Return a pointer to an in_msource owned by an in_mfilter, 740 * given its source address. 741 * Lazy-allocate if needed. If this is a new entry its filter state is 742 * undefined at t0. 743 * 744 * imf is the filter set being modified. 745 * haddr is the source address in *host* byte-order. 746 * 747 * Caller is expected to be holding imo_lock. 748 */ 749static int 750imf_get_source(struct in_mfilter *imf, const struct sockaddr_in *psin, 751 struct in_msource **plims) 752{ 753 struct ip_msource find; 754 struct ip_msource *ims; 755 struct in_msource *lims; 756 int error; 757 758 error = 0; 759 ims = NULL; 760 lims = NULL; 761 762 /* key is host byte order */ 763 find.ims_haddr = ntohl(psin->sin_addr.s_addr); 764 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); 765 lims = (struct in_msource *)ims; 766 if (lims == NULL) { 767 if (imf->imf_nsrc == in_mcast_maxsocksrc) 768 return (ENOSPC); 769 lims = inms_alloc(M_WAITOK); 770 if (lims == NULL) 771 return (ENOMEM); 772 lims->ims_haddr = find.ims_haddr; 773 lims->imsl_st[0] = MCAST_UNDEFINED; 774 RB_INSERT(ip_msource_tree, &imf->imf_sources, 775 (struct ip_msource *)lims); 776 ++imf->imf_nsrc; 777 } 778 779 *plims = lims; 780 781 return (error); 782} 783 784/* 785 * Graft a source entry into an existing socket-layer filter set, 786 * maintaining any required invariants and checking allocations. 787 * 788 * The source is marked as being in the new filter mode at t1. 789 * 790 * Return the pointer to the new node, otherwise return NULL. 791 * 792 * Caller is expected to be holding imo_lock. 793 */ 794static struct in_msource * 795imf_graft(struct in_mfilter *imf, const uint8_t st1, 796 const struct sockaddr_in *psin) 797{ 798 struct in_msource *lims; 799 800 lims = inms_alloc(M_WAITOK); 801 if (lims == NULL) 802 return (NULL); 803 lims->ims_haddr = ntohl(psin->sin_addr.s_addr); 804 lims->imsl_st[0] = MCAST_UNDEFINED; 805 lims->imsl_st[1] = st1; 806 RB_INSERT(ip_msource_tree, &imf->imf_sources, 807 (struct ip_msource *)lims); 808 ++imf->imf_nsrc; 809 810 return (lims); 811} 812 813/* 814 * Prune a source entry from an existing socket-layer filter set, 815 * maintaining any required invariants and checking allocations. 816 * 817 * The source is marked as being left at t1, it is not freed. 818 * 819 * Return 0 if no error occurred, otherwise return an errno value. 820 * 821 * Caller is expected to be holding imo_lock. 822 */ 823static int 824imf_prune(struct in_mfilter *imf, const struct sockaddr_in *psin) 825{ 826 struct ip_msource find; 827 struct ip_msource *ims; 828 struct in_msource *lims; 829 830 /* key is host byte order */ 831 find.ims_haddr = ntohl(psin->sin_addr.s_addr); 832 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find); 833 if (ims == NULL) 834 return (ENOENT); 835 lims = (struct in_msource *)ims; 836 lims->imsl_st[1] = MCAST_UNDEFINED; 837 return (0); 838} 839 840/* 841 * Revert socket-layer filter set deltas at t1 to t0 state. 842 * 843 * Caller is expected to be holding imo_lock. 844 */ 845static void 846imf_rollback(struct in_mfilter *imf) 847{ 848 struct ip_msource *ims, *tims; 849 struct in_msource *lims; 850 851 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { 852 lims = (struct in_msource *)ims; 853 if (lims->imsl_st[0] == lims->imsl_st[1]) { 854 /* no change at t1 */ 855 continue; 856 } else if (lims->imsl_st[0] != MCAST_UNDEFINED) { 857 /* revert change to existing source at t1 */ 858 lims->imsl_st[1] = lims->imsl_st[0]; 859 } else { 860 /* revert source added t1 */ 861 IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__, 862 (uint64_t)VM_KERNEL_ADDRPERM(lims))); 863 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); 864 inms_free(lims); 865 imf->imf_nsrc--; 866 } 867 } 868 imf->imf_st[1] = imf->imf_st[0]; 869} 870 871/* 872 * Mark socket-layer filter set as INCLUDE {} at t1. 873 * 874 * Caller is expected to be holding imo_lock. 875 */ 876void 877imf_leave(struct in_mfilter *imf) 878{ 879 struct ip_msource *ims; 880 struct in_msource *lims; 881 882 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 883 lims = (struct in_msource *)ims; 884 lims->imsl_st[1] = MCAST_UNDEFINED; 885 } 886 imf->imf_st[1] = MCAST_INCLUDE; 887} 888 889/* 890 * Mark socket-layer filter set deltas as committed. 891 * 892 * Caller is expected to be holding imo_lock. 893 */ 894static void 895imf_commit(struct in_mfilter *imf) 896{ 897 struct ip_msource *ims; 898 struct in_msource *lims; 899 900 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 901 lims = (struct in_msource *)ims; 902 lims->imsl_st[0] = lims->imsl_st[1]; 903 } 904 imf->imf_st[0] = imf->imf_st[1]; 905} 906 907/* 908 * Reap unreferenced sources from socket-layer filter set. 909 * 910 * Caller is expected to be holding imo_lock. 911 */ 912static void 913imf_reap(struct in_mfilter *imf) 914{ 915 struct ip_msource *ims, *tims; 916 struct in_msource *lims; 917 918 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { 919 lims = (struct in_msource *)ims; 920 if ((lims->imsl_st[0] == MCAST_UNDEFINED) && 921 (lims->imsl_st[1] == MCAST_UNDEFINED)) { 922 IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__, 923 (uint64_t)VM_KERNEL_ADDRPERM(lims))); 924 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); 925 inms_free(lims); 926 imf->imf_nsrc--; 927 } 928 } 929} 930 931/* 932 * Purge socket-layer filter set. 933 * 934 * Caller is expected to be holding imo_lock. 935 */ 936void 937imf_purge(struct in_mfilter *imf) 938{ 939 struct ip_msource *ims, *tims; 940 struct in_msource *lims; 941 942 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) { 943 lims = (struct in_msource *)ims; 944 IGMP_PRINTF(("%s: free inms 0x%llx\n", __func__, 945 (uint64_t)VM_KERNEL_ADDRPERM(lims))); 946 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims); 947 inms_free(lims); 948 imf->imf_nsrc--; 949 } 950 imf->imf_st[0] = imf->imf_st[1] = MCAST_UNDEFINED; 951 VERIFY(RB_EMPTY(&imf->imf_sources)); 952} 953 954/* 955 * Look up a source filter entry for a multicast group. 956 * 957 * inm is the group descriptor to work with. 958 * haddr is the host-byte-order IPv4 address to look up. 959 * noalloc may be non-zero to suppress allocation of sources. 960 * *pims will be set to the address of the retrieved or allocated source. 961 * 962 * Return 0 if successful, otherwise return a non-zero error code. 963 */ 964static int 965inm_get_source(struct in_multi *inm, const in_addr_t haddr, 966 const int noalloc, struct ip_msource **pims) 967{ 968 struct ip_msource find; 969 struct ip_msource *ims, *nims; 970#ifdef IGMP_DEBUG 971 struct in_addr ia; 972 char buf[MAX_IPv4_STR_LEN]; 973#endif 974 INM_LOCK_ASSERT_HELD(inm); 975 976 find.ims_haddr = haddr; 977 ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find); 978 if (ims == NULL && !noalloc) { 979 if (inm->inm_nsrc == in_mcast_maxgrpsrc) 980 return (ENOSPC); 981 nims = ipms_alloc(M_WAITOK); 982 if (nims == NULL) 983 return (ENOMEM); 984 nims->ims_haddr = haddr; 985 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims); 986 ++inm->inm_nsrc; 987 ims = nims; 988#ifdef IGMP_DEBUG 989 ia.s_addr = htonl(haddr); 990 inet_ntop(AF_INET, &ia, buf, sizeof(buf)); 991 IGMP_PRINTF(("%s: allocated %s as 0x%llx\n", __func__, 992 buf, (uint64_t)VM_KERNEL_ADDRPERM(ims))); 993#endif 994 } 995 996 *pims = ims; 997 return (0); 998} 999 1000/* 1001 * Helper function to derive the filter mode on a source entry 1002 * from its internal counters. Predicates are: 1003 * A source is only excluded if all listeners exclude it. 1004 * A source is only included if no listeners exclude it, 1005 * and at least one listener includes it. 1006 * May be used by ifmcstat(8). 1007 */ 1008uint8_t 1009ims_get_mode(const struct in_multi *inm, const struct ip_msource *ims, 1010 uint8_t t) 1011{ 1012 INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi *, inm)); 1013 1014 t = !!t; 1015 if (inm->inm_st[t].iss_ex > 0 && 1016 inm->inm_st[t].iss_ex == ims->ims_st[t].ex) 1017 return (MCAST_EXCLUDE); 1018 else if (ims->ims_st[t].in > 0 && ims->ims_st[t].ex == 0) 1019 return (MCAST_INCLUDE); 1020 return (MCAST_UNDEFINED); 1021} 1022 1023/* 1024 * Merge socket-layer source into IGMP-layer source. 1025 * If rollback is non-zero, perform the inverse of the merge. 1026 */ 1027static void 1028ims_merge(struct ip_msource *ims, const struct in_msource *lims, 1029 const int rollback) 1030{ 1031 int n = rollback ? -1 : 1; 1032#ifdef IGMP_DEBUG 1033 struct in_addr ia; 1034 1035 ia.s_addr = htonl(ims->ims_haddr); 1036#endif 1037 1038 if (lims->imsl_st[0] == MCAST_EXCLUDE) { 1039 IGMP_INET_PRINTF(ia, 1040 ("%s: t1 ex -= %d on %s\n", 1041 __func__, n, _igmp_inet_buf)); 1042 ims->ims_st[1].ex -= n; 1043 } else if (lims->imsl_st[0] == MCAST_INCLUDE) { 1044 IGMP_INET_PRINTF(ia, 1045 ("%s: t1 in -= %d on %s\n", 1046 __func__, n, _igmp_inet_buf)); 1047 ims->ims_st[1].in -= n; 1048 } 1049 1050 if (lims->imsl_st[1] == MCAST_EXCLUDE) { 1051 IGMP_INET_PRINTF(ia, 1052 ("%s: t1 ex += %d on %s\n", 1053 __func__, n, _igmp_inet_buf)); 1054 ims->ims_st[1].ex += n; 1055 } else if (lims->imsl_st[1] == MCAST_INCLUDE) { 1056 IGMP_INET_PRINTF(ia, 1057 ("%s: t1 in += %d on %s\n", 1058 __func__, n, _igmp_inet_buf)); 1059 ims->ims_st[1].in += n; 1060 } 1061} 1062 1063/* 1064 * Atomically update the global in_multi state, when a membership's 1065 * filter list is being updated in any way. 1066 * 1067 * imf is the per-inpcb-membership group filter pointer. 1068 * A fake imf may be passed for in-kernel consumers. 1069 * 1070 * XXX This is a candidate for a set-symmetric-difference style loop 1071 * which would eliminate the repeated lookup from root of ims nodes, 1072 * as they share the same key space. 1073 * 1074 * If any error occurred this function will back out of refcounts 1075 * and return a non-zero value. 1076 */ 1077static int 1078inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf) 1079{ 1080 struct ip_msource *ims, *nims; 1081 struct in_msource *lims; 1082 int schanged, error; 1083 int nsrc0, nsrc1; 1084 1085 INM_LOCK_ASSERT_HELD(inm); 1086 1087 schanged = 0; 1088 error = 0; 1089 nsrc1 = nsrc0 = 0; 1090 1091 /* 1092 * Update the source filters first, as this may fail. 1093 * Maintain count of in-mode filters at t0, t1. These are 1094 * used to work out if we transition into ASM mode or not. 1095 * Maintain a count of source filters whose state was 1096 * actually modified by this operation. 1097 */ 1098 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 1099 lims = (struct in_msource *)ims; 1100 if (lims->imsl_st[0] == imf->imf_st[0]) nsrc0++; 1101 if (lims->imsl_st[1] == imf->imf_st[1]) nsrc1++; 1102 if (lims->imsl_st[0] == lims->imsl_st[1]) continue; 1103 error = inm_get_source(inm, lims->ims_haddr, 0, &nims); 1104 ++schanged; 1105 if (error) 1106 break; 1107 ims_merge(nims, lims, 0); 1108 } 1109 if (error) { 1110 struct ip_msource *bims; 1111 1112 RB_FOREACH_REVERSE_FROM(ims, ip_msource_tree, nims) { 1113 lims = (struct in_msource *)ims; 1114 if (lims->imsl_st[0] == lims->imsl_st[1]) 1115 continue; 1116 (void) inm_get_source(inm, lims->ims_haddr, 1, &bims); 1117 if (bims == NULL) 1118 continue; 1119 ims_merge(bims, lims, 1); 1120 } 1121 goto out_reap; 1122 } 1123 1124 IGMP_PRINTF(("%s: imf filters in-mode: %d at t0, %d at t1\n", 1125 __func__, nsrc0, nsrc1)); 1126 1127 /* Handle transition between INCLUDE {n} and INCLUDE {} on socket. */ 1128 if (imf->imf_st[0] == imf->imf_st[1] && 1129 imf->imf_st[1] == MCAST_INCLUDE) { 1130 if (nsrc1 == 0) { 1131 IGMP_PRINTF(("%s: --in on inm at t1\n", __func__)); 1132 --inm->inm_st[1].iss_in; 1133 } 1134 } 1135 1136 /* Handle filter mode transition on socket. */ 1137 if (imf->imf_st[0] != imf->imf_st[1]) { 1138 IGMP_PRINTF(("%s: imf transition %d to %d\n", 1139 __func__, imf->imf_st[0], imf->imf_st[1])); 1140 1141 if (imf->imf_st[0] == MCAST_EXCLUDE) { 1142 IGMP_PRINTF(("%s: --ex on inm at t1\n", __func__)); 1143 --inm->inm_st[1].iss_ex; 1144 } else if (imf->imf_st[0] == MCAST_INCLUDE) { 1145 IGMP_PRINTF(("%s: --in on inm at t1\n", __func__)); 1146 --inm->inm_st[1].iss_in; 1147 } 1148 1149 if (imf->imf_st[1] == MCAST_EXCLUDE) { 1150 IGMP_PRINTF(("%s: ex++ on inm at t1\n", __func__)); 1151 inm->inm_st[1].iss_ex++; 1152 } else if (imf->imf_st[1] == MCAST_INCLUDE && nsrc1 > 0) { 1153 IGMP_PRINTF(("%s: in++ on inm at t1\n", __func__)); 1154 inm->inm_st[1].iss_in++; 1155 } 1156 } 1157 1158 /* 1159 * Track inm filter state in terms of listener counts. 1160 * If there are any exclusive listeners, stack-wide 1161 * membership is exclusive. 1162 * Otherwise, if only inclusive listeners, stack-wide is inclusive. 1163 * If no listeners remain, state is undefined at t1, 1164 * and the IGMP lifecycle for this group should finish. 1165 */ 1166 if (inm->inm_st[1].iss_ex > 0) { 1167 IGMP_PRINTF(("%s: transition to EX\n", __func__)); 1168 inm->inm_st[1].iss_fmode = MCAST_EXCLUDE; 1169 } else if (inm->inm_st[1].iss_in > 0) { 1170 IGMP_PRINTF(("%s: transition to IN\n", __func__)); 1171 inm->inm_st[1].iss_fmode = MCAST_INCLUDE; 1172 } else { 1173 IGMP_PRINTF(("%s: transition to UNDEF\n", __func__)); 1174 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED; 1175 } 1176 1177 /* Decrement ASM listener count on transition out of ASM mode. */ 1178 if (imf->imf_st[0] == MCAST_EXCLUDE && nsrc0 == 0) { 1179 if ((imf->imf_st[1] != MCAST_EXCLUDE) || 1180 (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 > 0)) { 1181 IGMP_PRINTF(("%s: --asm on inm at t1\n", __func__)); 1182 --inm->inm_st[1].iss_asm; 1183 } 1184 } 1185 1186 /* Increment ASM listener count on transition to ASM mode. */ 1187 if (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 == 0) { 1188 IGMP_PRINTF(("%s: asm++ on inm at t1\n", __func__)); 1189 inm->inm_st[1].iss_asm++; 1190 } 1191 1192 IGMP_PRINTF(("%s: merged imf 0x%llx to inm 0x%llx\n", __func__, 1193 (uint64_t)VM_KERNEL_ADDRPERM(imf), 1194 (uint64_t)VM_KERNEL_ADDRPERM(inm))); 1195 inm_print(inm); 1196 1197out_reap: 1198 if (schanged > 0) { 1199 IGMP_PRINTF(("%s: sources changed; reaping\n", __func__)); 1200 inm_reap(inm); 1201 } 1202 return (error); 1203} 1204 1205/* 1206 * Mark an in_multi's filter set deltas as committed. 1207 * Called by IGMP after a state change has been enqueued. 1208 */ 1209void 1210inm_commit(struct in_multi *inm) 1211{ 1212 struct ip_msource *ims; 1213 1214 INM_LOCK_ASSERT_HELD(inm); 1215 1216 IGMP_PRINTF(("%s: commit inm 0x%llx\n", __func__, 1217 (uint64_t)VM_KERNEL_ADDRPERM(inm))); 1218 IGMP_PRINTF(("%s: pre commit:\n", __func__)); 1219 inm_print(inm); 1220 1221 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 1222 ims->ims_st[0] = ims->ims_st[1]; 1223 } 1224 inm->inm_st[0] = inm->inm_st[1]; 1225} 1226 1227/* 1228 * Reap unreferenced nodes from an in_multi's filter set. 1229 */ 1230static void 1231inm_reap(struct in_multi *inm) 1232{ 1233 struct ip_msource *ims, *tims; 1234 1235 INM_LOCK_ASSERT_HELD(inm); 1236 1237 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) { 1238 if (ims->ims_st[0].ex > 0 || ims->ims_st[0].in > 0 || 1239 ims->ims_st[1].ex > 0 || ims->ims_st[1].in > 0 || 1240 ims->ims_stp != 0) 1241 continue; 1242 IGMP_PRINTF(("%s: free ims 0x%llx\n", __func__, 1243 (uint64_t)VM_KERNEL_ADDRPERM(ims))); 1244 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims); 1245 ipms_free(ims); 1246 inm->inm_nsrc--; 1247 } 1248} 1249 1250/* 1251 * Purge all source nodes from an in_multi's filter set. 1252 */ 1253void 1254inm_purge(struct in_multi *inm) 1255{ 1256 struct ip_msource *ims, *tims; 1257 1258 INM_LOCK_ASSERT_HELD(inm); 1259 1260 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) { 1261 IGMP_PRINTF(("%s: free ims 0x%llx\n", __func__, 1262 (uint64_t)VM_KERNEL_ADDRPERM(ims))); 1263 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims); 1264 ipms_free(ims); 1265 inm->inm_nsrc--; 1266 } 1267} 1268 1269/* 1270 * Join a multicast group; real entry point. 1271 * 1272 * Only preserves atomicity at inm level. 1273 * NOTE: imf argument cannot be const due to sys/tree.h limitations. 1274 * 1275 * If the IGMP downcall fails, the group is not joined, and an error 1276 * code is returned. 1277 */ 1278static int 1279in_joingroup(struct ifnet *ifp, const struct in_addr *gina, 1280 /*const*/ struct in_mfilter *imf, struct in_multi **pinm) 1281{ 1282 struct in_mfilter timf; 1283 struct in_multi *inm = NULL; 1284 int error = 0; 1285 struct igmp_tparams itp; 1286 1287 IGMP_INET_PRINTF(*gina, ("%s: join %s on 0x%llx(%s))\n", __func__, 1288 _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp))); 1289 1290 bzero(&itp, sizeof (itp)); 1291 *pinm = NULL; 1292 1293 /* 1294 * If no imf was specified (i.e. kernel consumer), 1295 * fake one up and assume it is an ASM join. 1296 */ 1297 if (imf == NULL) { 1298 imf_init(&timf, MCAST_UNDEFINED, MCAST_EXCLUDE); 1299 imf = &timf; 1300 } 1301 1302 error = in_getmulti(ifp, gina, &inm); 1303 if (error) { 1304 IGMP_PRINTF(("%s: in_getmulti() failure\n", __func__)); 1305 return (error); 1306 } 1307 1308 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 1309 1310 INM_LOCK(inm); 1311 error = inm_merge(inm, imf); 1312 if (error) { 1313 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__)); 1314 goto out_inm_release; 1315 } 1316 1317 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 1318 error = igmp_change_state(inm, &itp); 1319 if (error) { 1320 IGMP_PRINTF(("%s: failed to update source\n", __func__)); 1321 imf_rollback(imf); 1322 goto out_inm_release; 1323 } 1324 1325out_inm_release: 1326 if (error) { 1327 IGMP_PRINTF(("%s: dropping ref on 0x%llx\n", __func__, 1328 (uint64_t)VM_KERNEL_ADDRPERM(inm))); 1329 INM_UNLOCK(inm); 1330 INM_REMREF(inm); 1331 } else { 1332 INM_UNLOCK(inm); 1333 *pinm = inm; /* keep refcount from in_getmulti() */ 1334 } 1335 1336 /* schedule timer now that we've dropped the lock(s) */ 1337 igmp_set_timeout(&itp); 1338 1339 return (error); 1340} 1341 1342/* 1343 * Leave a multicast group; real entry point. 1344 * All source filters will be expunged. 1345 * 1346 * Only preserves atomicity at inm level. 1347 * 1348 * Note: This is not the same as inm_release(*) as this function also 1349 * makes a state change downcall into IGMP. 1350 */ 1351int 1352in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf) 1353{ 1354 struct in_mfilter timf; 1355 int error, lastref; 1356 struct igmp_tparams itp; 1357 1358 bzero(&itp, sizeof (itp)); 1359 error = 0; 1360 1361 INM_LOCK_ASSERT_NOTHELD(inm); 1362 1363 in_multihead_lock_exclusive(); 1364 INM_LOCK(inm); 1365 1366 IGMP_INET_PRINTF(inm->inm_addr, 1367 ("%s: leave inm 0x%llx, %s/%s%d, imf 0x%llx\n", __func__, 1368 (uint64_t)VM_KERNEL_ADDRPERM(inm), _igmp_inet_buf, 1369 (inm_is_ifp_detached(inm) ? "null" : inm->inm_ifp->if_name), 1370 inm->inm_ifp->if_unit, (uint64_t)VM_KERNEL_ADDRPERM(imf))); 1371 1372 /* 1373 * If no imf was specified (i.e. kernel consumer), 1374 * fake one up and assume it is an ASM join. 1375 */ 1376 if (imf == NULL) { 1377 imf_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED); 1378 imf = &timf; 1379 } 1380 1381 /* 1382 * Begin state merge transaction at IGMP layer. 1383 * 1384 * As this particular invocation should not cause any memory 1385 * to be allocated, and there is no opportunity to roll back 1386 * the transaction, it MUST NOT fail. 1387 */ 1388 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 1389 1390 error = inm_merge(inm, imf); 1391 KASSERT(error == 0, ("%s: failed to merge inm state\n", __func__)); 1392 1393 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 1394 error = igmp_change_state(inm, &itp); 1395#if IGMP_DEBUG 1396 if (error) 1397 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); 1398#endif 1399 lastref = in_multi_detach(inm); 1400 VERIFY(!lastref || (!(inm->inm_debug & IFD_ATTACHED) && 1401 inm->inm_reqcnt == 0)); 1402 INM_UNLOCK(inm); 1403 in_multihead_lock_done(); 1404 1405 if (lastref) 1406 INM_REMREF(inm); /* for in_multihead list */ 1407 1408 /* schedule timer now that we've dropped the lock(s) */ 1409 igmp_set_timeout(&itp); 1410 1411 return (error); 1412} 1413 1414/* 1415 * Join an IPv4 multicast group in (*,G) exclusive mode. 1416 * The group must be a 224.0.0.0/24 link-scope group. 1417 * This KPI is for legacy kernel consumers only. 1418 */ 1419struct in_multi * 1420in_addmulti(struct in_addr *ap, struct ifnet *ifp) 1421{ 1422 struct in_multi *pinm = NULL; 1423 int error; 1424 1425 KASSERT(IN_LOCAL_GROUP(ntohl(ap->s_addr)), 1426 ("%s: %s not in 224.0.0.0/24\n", __func__, inet_ntoa(*ap))); 1427 1428 error = in_joingroup(ifp, ap, NULL, &pinm); 1429 VERIFY(pinm != NULL || error != 0); 1430 1431 return (pinm); 1432} 1433 1434/* 1435 * Leave an IPv4 multicast group, assumed to be in exclusive (*,G) mode. 1436 * This KPI is for legacy kernel consumers only. 1437 */ 1438void 1439in_delmulti(struct in_multi *inm) 1440{ 1441 1442 (void) in_leavegroup(inm, NULL); 1443} 1444 1445/* 1446 * Block or unblock an ASM multicast source on an inpcb. 1447 * This implements the delta-based API described in RFC 3678. 1448 * 1449 * The delta-based API applies only to exclusive-mode memberships. 1450 * An IGMP downcall will be performed. 1451 * 1452 * Return 0 if successful, otherwise return an appropriate error code. 1453 */ 1454static int 1455inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) 1456{ 1457 struct group_source_req gsr; 1458 sockunion_t *gsa, *ssa; 1459 struct ifnet *ifp; 1460 struct in_mfilter *imf; 1461 struct ip_moptions *imo; 1462 struct in_msource *ims; 1463 struct in_multi *inm; 1464 size_t idx; 1465 uint16_t fmode; 1466 int error, doblock; 1467 unsigned int ifindex = 0; 1468 struct igmp_tparams itp; 1469 1470 bzero(&itp, sizeof (itp)); 1471 ifp = NULL; 1472 error = 0; 1473 doblock = 0; 1474 1475 memset(&gsr, 0, sizeof(struct group_source_req)); 1476 gsa = (sockunion_t *)&gsr.gsr_group; 1477 ssa = (sockunion_t *)&gsr.gsr_source; 1478 1479 switch (sopt->sopt_name) { 1480 case IP_BLOCK_SOURCE: 1481 case IP_UNBLOCK_SOURCE: { 1482 struct ip_mreq_source mreqs; 1483 1484 error = sooptcopyin(sopt, &mreqs, 1485 sizeof(struct ip_mreq_source), 1486 sizeof(struct ip_mreq_source)); 1487 if (error) 1488 return (error); 1489 1490 gsa->sin.sin_family = AF_INET; 1491 gsa->sin.sin_len = sizeof(struct sockaddr_in); 1492 gsa->sin.sin_addr = mreqs.imr_multiaddr; 1493 1494 ssa->sin.sin_family = AF_INET; 1495 ssa->sin.sin_len = sizeof(struct sockaddr_in); 1496 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 1497 1498 if (!in_nullhost(mreqs.imr_interface)) 1499 ifp = ip_multicast_if(&mreqs.imr_interface, &ifindex); 1500 1501 if (sopt->sopt_name == IP_BLOCK_SOURCE) 1502 doblock = 1; 1503 1504 IGMP_INET_PRINTF(mreqs.imr_interface, 1505 ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, 1506 _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); 1507 break; 1508 } 1509 1510 case MCAST_BLOCK_SOURCE: 1511 case MCAST_UNBLOCK_SOURCE: 1512 error = sooptcopyin(sopt, &gsr, 1513 sizeof(struct group_source_req), 1514 sizeof(struct group_source_req)); 1515 if (error) 1516 return (error); 1517 1518 if (gsa->sin.sin_family != AF_INET || 1519 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 1520 return (EINVAL); 1521 1522 if (ssa->sin.sin_family != AF_INET || 1523 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 1524 return (EINVAL); 1525 1526 ifnet_head_lock_shared(); 1527 if (gsr.gsr_interface == 0 || 1528 (u_int)if_index < gsr.gsr_interface) { 1529 ifnet_head_done(); 1530 return (EADDRNOTAVAIL); 1531 } 1532 1533 ifp = ifindex2ifnet[gsr.gsr_interface]; 1534 ifnet_head_done(); 1535 1536 if (ifp == NULL) 1537 return (EADDRNOTAVAIL); 1538 1539 if (sopt->sopt_name == MCAST_BLOCK_SOURCE) 1540 doblock = 1; 1541 break; 1542 1543 default: 1544 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 1545 __func__, sopt->sopt_name)); 1546 return (EOPNOTSUPP); 1547 break; 1548 } 1549 1550 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 1551 return (EINVAL); 1552 1553 /* 1554 * Check if we are actually a member of this group. 1555 */ 1556 imo = inp_findmoptions(inp); 1557 if (imo == NULL) 1558 return (ENOMEM); 1559 1560 IMO_LOCK(imo); 1561 idx = imo_match_group(imo, ifp, &gsa->sa); 1562 if (idx == (size_t)-1 || imo->imo_mfilters == NULL) { 1563 error = EADDRNOTAVAIL; 1564 goto out_imo_locked; 1565 } 1566 1567 VERIFY(imo->imo_mfilters != NULL); 1568 imf = &imo->imo_mfilters[idx]; 1569 inm = imo->imo_membership[idx]; 1570 1571 /* 1572 * Attempting to use the delta-based API on an 1573 * non exclusive-mode membership is an error. 1574 */ 1575 fmode = imf->imf_st[0]; 1576 if (fmode != MCAST_EXCLUDE) { 1577 error = EINVAL; 1578 goto out_imo_locked; 1579 } 1580 1581 /* 1582 * Deal with error cases up-front: 1583 * Asked to block, but already blocked; or 1584 * Asked to unblock, but nothing to unblock. 1585 * If adding a new block entry, allocate it. 1586 */ 1587 ims = imo_match_source(imo, idx, &ssa->sa); 1588 if ((ims != NULL && doblock) || (ims == NULL && !doblock)) { 1589 IGMP_INET_PRINTF(ssa->sin.sin_addr, 1590 ("%s: source %s %spresent\n", __func__, 1591 _igmp_inet_buf, doblock ? "" : "not ")); 1592 error = EADDRNOTAVAIL; 1593 goto out_imo_locked; 1594 } 1595 1596 /* 1597 * Begin state merge transaction at socket layer. 1598 */ 1599 if (doblock) { 1600 IGMP_PRINTF(("%s: %s source\n", __func__, "block")); 1601 ims = imf_graft(imf, fmode, &ssa->sin); 1602 if (ims == NULL) 1603 error = ENOMEM; 1604 } else { 1605 IGMP_PRINTF(("%s: %s source\n", __func__, "allow")); 1606 error = imf_prune(imf, &ssa->sin); 1607 } 1608 1609 if (error) { 1610 IGMP_PRINTF(("%s: merge imf state failed\n", __func__)); 1611 goto out_imf_rollback; 1612 } 1613 1614 /* 1615 * Begin state merge transaction at IGMP layer. 1616 */ 1617 INM_LOCK(inm); 1618 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 1619 error = inm_merge(inm, imf); 1620 if (error) { 1621 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__)); 1622 INM_UNLOCK(inm); 1623 goto out_imf_rollback; 1624 } 1625 1626 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 1627 error = igmp_change_state(inm, &itp); 1628 INM_UNLOCK(inm); 1629#if IGMP_DEBUG 1630 if (error) 1631 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); 1632#endif 1633 1634out_imf_rollback: 1635 if (error) 1636 imf_rollback(imf); 1637 else 1638 imf_commit(imf); 1639 1640 imf_reap(imf); 1641 1642out_imo_locked: 1643 IMO_UNLOCK(imo); 1644 IMO_REMREF(imo); /* from inp_findmoptions() */ 1645 1646 /* schedule timer now that we've dropped the lock(s) */ 1647 igmp_set_timeout(&itp); 1648 1649 return (error); 1650} 1651 1652/* 1653 * Given an inpcb, return its multicast options structure pointer. 1654 * 1655 * Caller is responsible for locking the inpcb, and releasing the 1656 * extra reference held on the imo, upon a successful return. 1657 */ 1658static struct ip_moptions * 1659inp_findmoptions(struct inpcb *inp) 1660{ 1661 struct ip_moptions *imo; 1662 struct in_multi **immp; 1663 struct in_mfilter *imfp; 1664 size_t idx; 1665 1666 if ((imo = inp->inp_moptions) != NULL) { 1667 IMO_ADDREF(imo); /* for caller */ 1668 return (imo); 1669 } 1670 1671 imo = ip_allocmoptions(M_WAITOK); 1672 if (imo == NULL) 1673 return (NULL); 1674 1675 immp = _MALLOC(sizeof (*immp) * IP_MIN_MEMBERSHIPS, M_IPMOPTS, 1676 M_WAITOK | M_ZERO); 1677 if (immp == NULL) { 1678 IMO_REMREF(imo); 1679 return (NULL); 1680 } 1681 1682 imfp = _MALLOC(sizeof (struct in_mfilter) * IP_MIN_MEMBERSHIPS, 1683 M_INMFILTER, M_WAITOK | M_ZERO); 1684 if (imfp == NULL) { 1685 _FREE(immp, M_IPMOPTS); 1686 IMO_REMREF(imo); 1687 return (NULL); 1688 } 1689 1690 imo->imo_multicast_ifp = NULL; 1691 imo->imo_multicast_addr.s_addr = INADDR_ANY; 1692 imo->imo_multicast_vif = -1; 1693 imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 1694 imo->imo_multicast_loop = in_mcast_loop; 1695 imo->imo_num_memberships = 0; 1696 imo->imo_max_memberships = IP_MIN_MEMBERSHIPS; 1697 imo->imo_membership = immp; 1698 1699 /* Initialize per-group source filters. */ 1700 for (idx = 0; idx < IP_MIN_MEMBERSHIPS; idx++) 1701 imf_init(&imfp[idx], MCAST_UNDEFINED, MCAST_EXCLUDE); 1702 1703 imo->imo_mfilters = imfp; 1704 inp->inp_moptions = imo; /* keep reference from ip_allocmoptions() */ 1705 IMO_ADDREF(imo); /* for caller */ 1706 1707 return (imo); 1708} 1709/* 1710 * Atomically get source filters on a socket for an IPv4 multicast group. 1711 */ 1712static int 1713inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt) 1714{ 1715 struct __msfilterreq64 msfr, msfr64; 1716 struct __msfilterreq32 msfr32; 1717 sockunion_t *gsa; 1718 struct ifnet *ifp; 1719 struct ip_moptions *imo; 1720 struct in_mfilter *imf; 1721 struct ip_msource *ims; 1722 struct in_msource *lims; 1723 struct sockaddr_in *psin; 1724 struct sockaddr_storage *ptss; 1725 struct sockaddr_storage *tss; 1726 int error; 1727 size_t idx, nsrcs, ncsrcs; 1728 user_addr_t tmp_ptr; 1729 1730 imo = inp->inp_moptions; 1731 VERIFY(imo != NULL); 1732 1733 if (IS_64BIT_PROCESS(current_proc())) { 1734 error = sooptcopyin(sopt, &msfr64, 1735 sizeof(struct __msfilterreq64), 1736 sizeof(struct __msfilterreq64)); 1737 if (error) 1738 return (error); 1739 /* we never use msfr.msfr_srcs; */ 1740 memcpy(&msfr, &msfr64, sizeof(msfr)); 1741 } else { 1742 error = sooptcopyin(sopt, &msfr32, 1743 sizeof(struct __msfilterreq32), 1744 sizeof(struct __msfilterreq32)); 1745 if (error) 1746 return (error); 1747 /* we never use msfr.msfr_srcs; */ 1748 memcpy(&msfr, &msfr32, sizeof(msfr)); 1749 } 1750 1751 ifnet_head_lock_shared(); 1752 if (msfr.msfr_ifindex == 0 || (u_int)if_index < msfr.msfr_ifindex) { 1753 ifnet_head_done(); 1754 return (EADDRNOTAVAIL); 1755 } 1756 1757 ifp = ifindex2ifnet[msfr.msfr_ifindex]; 1758 ifnet_head_done(); 1759 1760 if (ifp == NULL) 1761 return (EADDRNOTAVAIL); 1762 1763 if ((size_t) msfr.msfr_nsrcs > 1764 UINT32_MAX / sizeof(struct sockaddr_storage)) 1765 msfr.msfr_nsrcs = UINT32_MAX / sizeof(struct sockaddr_storage); 1766 1767 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) 1768 msfr.msfr_nsrcs = in_mcast_maxsocksrc; 1769 1770 IMO_LOCK(imo); 1771 /* 1772 * Lookup group on the socket. 1773 */ 1774 gsa = (sockunion_t *)&msfr.msfr_group; 1775 idx = imo_match_group(imo, ifp, &gsa->sa); 1776 if (idx == (size_t)-1 || imo->imo_mfilters == NULL) { 1777 IMO_UNLOCK(imo); 1778 return (EADDRNOTAVAIL); 1779 } 1780 imf = &imo->imo_mfilters[idx]; 1781 1782 /* 1783 * Ignore memberships which are in limbo. 1784 */ 1785 if (imf->imf_st[1] == MCAST_UNDEFINED) { 1786 IMO_UNLOCK(imo); 1787 return (EAGAIN); 1788 } 1789 msfr.msfr_fmode = imf->imf_st[1]; 1790 1791 /* 1792 * If the user specified a buffer, copy out the source filter 1793 * entries to userland gracefully. 1794 * We only copy out the number of entries which userland 1795 * has asked for, but we always tell userland how big the 1796 * buffer really needs to be. 1797 */ 1798 1799 if (IS_64BIT_PROCESS(current_proc())) 1800 tmp_ptr = msfr64.msfr_srcs; 1801 else 1802 tmp_ptr = CAST_USER_ADDR_T(msfr32.msfr_srcs); 1803 1804 tss = NULL; 1805 if (tmp_ptr != USER_ADDR_NULL && msfr.msfr_nsrcs > 0) { 1806 tss = _MALLOC((size_t) msfr.msfr_nsrcs * sizeof(*tss), 1807 M_TEMP, M_WAITOK | M_ZERO); 1808 if (tss == NULL) { 1809 IMO_UNLOCK(imo); 1810 return (ENOBUFS); 1811 } 1812 bzero(tss, (size_t) msfr.msfr_nsrcs * sizeof(*tss)); 1813 } 1814 1815 /* 1816 * Count number of sources in-mode at t0. 1817 * If buffer space exists and remains, copy out source entries. 1818 */ 1819 nsrcs = msfr.msfr_nsrcs; 1820 ncsrcs = 0; 1821 ptss = tss; 1822 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) { 1823 lims = (struct in_msource *)ims; 1824 if (lims->imsl_st[0] == MCAST_UNDEFINED || 1825 lims->imsl_st[0] != imf->imf_st[0]) 1826 continue; 1827 if (tss != NULL && nsrcs > 0) { 1828 psin = (struct sockaddr_in *)ptss; 1829 psin->sin_family = AF_INET; 1830 psin->sin_len = sizeof(struct sockaddr_in); 1831 psin->sin_addr.s_addr = htonl(lims->ims_haddr); 1832 psin->sin_port = 0; 1833 ++ptss; 1834 --nsrcs; 1835 ++ncsrcs; 1836 } 1837 } 1838 1839 IMO_UNLOCK(imo); 1840 1841 if (tss != NULL) { 1842 error = copyout(tss, tmp_ptr, ncsrcs * sizeof(*tss)); 1843 FREE(tss, M_TEMP); 1844 if (error) 1845 return (error); 1846 } 1847 1848 msfr.msfr_nsrcs = ncsrcs; 1849 if (IS_64BIT_PROCESS(current_proc())) { 1850 msfr64.msfr_ifindex = msfr.msfr_ifindex; 1851 msfr64.msfr_fmode = msfr.msfr_fmode; 1852 msfr64.msfr_nsrcs = msfr.msfr_nsrcs; 1853 memcpy(&msfr64.msfr_group, &msfr.msfr_group, 1854 sizeof(struct sockaddr_storage)); 1855 error = sooptcopyout(sopt, &msfr64, 1856 sizeof(struct __msfilterreq64)); 1857 } else { 1858 msfr32.msfr_ifindex = msfr.msfr_ifindex; 1859 msfr32.msfr_fmode = msfr.msfr_fmode; 1860 msfr32.msfr_nsrcs = msfr.msfr_nsrcs; 1861 memcpy(&msfr64.msfr_group, &msfr.msfr_group, 1862 sizeof(struct sockaddr_storage)); 1863 error = sooptcopyout(sopt, &msfr32, 1864 sizeof(struct __msfilterreq32)); 1865 } 1866 1867 return (error); 1868} 1869 1870/* 1871 * Return the IP multicast options in response to user getsockopt(). 1872 */ 1873int 1874inp_getmoptions(struct inpcb *inp, struct sockopt *sopt) 1875{ 1876 struct ip_mreqn mreqn; 1877 struct ip_moptions *imo; 1878 struct ifnet *ifp; 1879 struct in_ifaddr *ia; 1880 int error, optval; 1881 unsigned int ifindex; 1882 u_char coptval; 1883 1884 imo = inp->inp_moptions; 1885 /* 1886 * If socket is neither of type SOCK_RAW or SOCK_DGRAM, 1887 * or is a divert socket, reject it. 1888 */ 1889 if (SOCK_PROTO(inp->inp_socket) == IPPROTO_DIVERT || 1890 (SOCK_TYPE(inp->inp_socket) != SOCK_RAW && 1891 SOCK_TYPE(inp->inp_socket) != SOCK_DGRAM)) { 1892 return (EOPNOTSUPP); 1893 } 1894 1895 error = 0; 1896 switch (sopt->sopt_name) { 1897 case IP_MULTICAST_IF: 1898 memset(&mreqn, 0, sizeof(struct ip_mreqn)); 1899 if (imo != NULL) { 1900 IMO_LOCK(imo); 1901 ifp = imo->imo_multicast_ifp; 1902 if (!in_nullhost(imo->imo_multicast_addr)) { 1903 mreqn.imr_address = imo->imo_multicast_addr; 1904 } else if (ifp != NULL) { 1905 mreqn.imr_ifindex = ifp->if_index; 1906 IFP_TO_IA(ifp, ia); 1907 if (ia != NULL) { 1908 IFA_LOCK_SPIN(&ia->ia_ifa); 1909 mreqn.imr_address = 1910 IA_SIN(ia)->sin_addr; 1911 IFA_UNLOCK(&ia->ia_ifa); 1912 IFA_REMREF(&ia->ia_ifa); 1913 } 1914 } 1915 IMO_UNLOCK(imo); 1916 } 1917 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) { 1918 error = sooptcopyout(sopt, &mreqn, 1919 sizeof(struct ip_mreqn)); 1920 } else { 1921 error = sooptcopyout(sopt, &mreqn.imr_address, 1922 sizeof(struct in_addr)); 1923 } 1924 break; 1925 1926 case IP_MULTICAST_IFINDEX: 1927 if (imo != NULL) 1928 IMO_LOCK(imo); 1929 if (imo == NULL || imo->imo_multicast_ifp == NULL) { 1930 ifindex = 0; 1931 } else { 1932 ifindex = imo->imo_multicast_ifp->if_index; 1933 } 1934 if (imo != NULL) 1935 IMO_UNLOCK(imo); 1936 error = sooptcopyout(sopt, &ifindex, sizeof (ifindex)); 1937 break; 1938 1939 case IP_MULTICAST_TTL: 1940 if (imo == NULL) 1941 optval = coptval = IP_DEFAULT_MULTICAST_TTL; 1942 else { 1943 IMO_LOCK(imo); 1944 optval = coptval = imo->imo_multicast_ttl; 1945 IMO_UNLOCK(imo); 1946 } 1947 if (sopt->sopt_valsize == sizeof(u_char)) 1948 error = sooptcopyout(sopt, &coptval, sizeof(u_char)); 1949 else 1950 error = sooptcopyout(sopt, &optval, sizeof(int)); 1951 break; 1952 1953 case IP_MULTICAST_LOOP: 1954 if (imo == 0) 1955 optval = coptval = IP_DEFAULT_MULTICAST_LOOP; 1956 else { 1957 IMO_LOCK(imo); 1958 optval = coptval = imo->imo_multicast_loop; 1959 IMO_UNLOCK(imo); 1960 } 1961 if (sopt->sopt_valsize == sizeof(u_char)) 1962 error = sooptcopyout(sopt, &coptval, sizeof(u_char)); 1963 else 1964 error = sooptcopyout(sopt, &optval, sizeof(int)); 1965 break; 1966 1967 case IP_MSFILTER: 1968 if (imo == NULL) { 1969 error = EADDRNOTAVAIL; 1970 } else { 1971 error = inp_get_source_filters(inp, sopt); 1972 } 1973 break; 1974 1975 default: 1976 error = ENOPROTOOPT; 1977 break; 1978 } 1979 1980 return (error); 1981} 1982 1983/* 1984 * Look up the ifnet to use for a multicast group membership, 1985 * given the IPv4 address of an interface, and the IPv4 group address. 1986 * 1987 * This routine exists to support legacy multicast applications 1988 * which do not understand that multicast memberships are scoped to 1989 * specific physical links in the networking stack, or which need 1990 * to join link-scope groups before IPv4 addresses are configured. 1991 * 1992 * If inp is non-NULL and is bound to an interface, use this socket's 1993 * inp_boundif for any required routing table lookup. 1994 * 1995 * If the route lookup fails, attempt to use the first non-loopback 1996 * interface with multicast capability in the system as a 1997 * last resort. The legacy IPv4 ASM API requires that we do 1998 * this in order to allow groups to be joined when the routing 1999 * table has not yet been populated during boot. 2000 * 2001 * Returns NULL if no ifp could be found. 2002 * 2003 */ 2004static struct ifnet * 2005inp_lookup_mcast_ifp(const struct inpcb *inp, 2006 const struct sockaddr_in *gsin, const struct in_addr ina) 2007{ 2008 struct ifnet *ifp; 2009 unsigned int ifindex = 0; 2010 2011 VERIFY(gsin->sin_family == AF_INET); 2012 VERIFY(IN_MULTICAST(ntohl(gsin->sin_addr.s_addr))); 2013 2014 ifp = NULL; 2015 if (!in_nullhost(ina)) { 2016 struct in_addr new_ina; 2017 memcpy(&new_ina, &ina, sizeof(struct in_addr)); 2018 ifp = ip_multicast_if(&new_ina, &ifindex); 2019 } else { 2020 struct route ro; 2021 unsigned int ifscope = IFSCOPE_NONE; 2022 2023 if (inp != NULL && (inp->inp_flags & INP_BOUND_IF)) 2024 ifscope = inp->inp_boundifp->if_index; 2025 2026 bzero(&ro, sizeof (ro)); 2027 memcpy(&ro.ro_dst, gsin, sizeof(struct sockaddr_in)); 2028 rtalloc_scoped_ign(&ro, 0, ifscope); 2029 if (ro.ro_rt != NULL) { 2030 ifp = ro.ro_rt->rt_ifp; 2031 VERIFY(ifp != NULL); 2032 } else { 2033 struct in_ifaddr *ia; 2034 struct ifnet *mifp; 2035 2036 mifp = NULL; 2037 lck_rw_lock_shared(in_ifaddr_rwlock); 2038 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 2039 IFA_LOCK_SPIN(&ia->ia_ifa); 2040 mifp = ia->ia_ifp; 2041 IFA_UNLOCK(&ia->ia_ifa); 2042 if (!(mifp->if_flags & IFF_LOOPBACK) && 2043 (mifp->if_flags & IFF_MULTICAST)) { 2044 ifp = mifp; 2045 break; 2046 } 2047 } 2048 lck_rw_done(in_ifaddr_rwlock); 2049 } 2050 ROUTE_RELEASE(&ro); 2051 } 2052 2053 return (ifp); 2054} 2055 2056/* 2057 * Join an IPv4 multicast group, possibly with a source. 2058 * 2059 * NB: sopt->sopt_val might point to the kernel address space. This means that 2060 * we were called by the IPv6 stack due to the presence of an IPv6 v4 mapped 2061 * address. In this scenario, sopt_p points to kernproc and sooptcopyin() will 2062 * just issue an in-kernel memcpy. 2063 */ 2064int 2065inp_join_group(struct inpcb *inp, struct sockopt *sopt) 2066{ 2067 struct group_source_req gsr; 2068 sockunion_t *gsa, *ssa; 2069 struct ifnet *ifp; 2070 struct in_mfilter *imf; 2071 struct ip_moptions *imo; 2072 struct in_multi *inm = NULL; 2073 struct in_msource *lims; 2074 size_t idx; 2075 int error, is_new; 2076 struct igmp_tparams itp; 2077 2078 bzero(&itp, sizeof (itp)); 2079 ifp = NULL; 2080 imf = NULL; 2081 error = 0; 2082 is_new = 0; 2083 2084 memset(&gsr, 0, sizeof(struct group_source_req)); 2085 gsa = (sockunion_t *)&gsr.gsr_group; 2086 gsa->ss.ss_family = AF_UNSPEC; 2087 ssa = (sockunion_t *)&gsr.gsr_source; 2088 ssa->ss.ss_family = AF_UNSPEC; 2089 2090 switch (sopt->sopt_name) { 2091 case IP_ADD_MEMBERSHIP: 2092 case IP_ADD_SOURCE_MEMBERSHIP: { 2093 struct ip_mreq_source mreqs; 2094 2095 if (sopt->sopt_name == IP_ADD_MEMBERSHIP) { 2096 error = sooptcopyin(sopt, &mreqs, 2097 sizeof(struct ip_mreq), 2098 sizeof(struct ip_mreq)); 2099 /* 2100 * Do argument switcharoo from ip_mreq into 2101 * ip_mreq_source to avoid using two instances. 2102 */ 2103 mreqs.imr_interface = mreqs.imr_sourceaddr; 2104 mreqs.imr_sourceaddr.s_addr = INADDR_ANY; 2105 } else if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) { 2106 error = sooptcopyin(sopt, &mreqs, 2107 sizeof(struct ip_mreq_source), 2108 sizeof(struct ip_mreq_source)); 2109 } 2110 if (error) { 2111 IGMP_PRINTF(("%s: error copyin IP_ADD_MEMBERSHIP/" 2112 "IP_ADD_SOURCE_MEMBERSHIP %d err=%d\n", 2113 __func__, sopt->sopt_name, error)); 2114 return (error); 2115 } 2116 2117 gsa->sin.sin_family = AF_INET; 2118 gsa->sin.sin_len = sizeof(struct sockaddr_in); 2119 gsa->sin.sin_addr = mreqs.imr_multiaddr; 2120 2121 if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) { 2122 ssa->sin.sin_family = AF_INET; 2123 ssa->sin.sin_len = sizeof(struct sockaddr_in); 2124 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 2125 } 2126 2127 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2128 return (EINVAL); 2129 2130 ifp = inp_lookup_mcast_ifp(inp, &gsa->sin, 2131 mreqs.imr_interface); 2132 IGMP_INET_PRINTF(mreqs.imr_interface, 2133 ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, 2134 _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); 2135 break; 2136 } 2137 2138 case MCAST_JOIN_GROUP: 2139 case MCAST_JOIN_SOURCE_GROUP: 2140 if (sopt->sopt_name == MCAST_JOIN_GROUP) { 2141 error = sooptcopyin(sopt, &gsr, 2142 sizeof(struct group_req), 2143 sizeof(struct group_req)); 2144 } else if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) { 2145 error = sooptcopyin(sopt, &gsr, 2146 sizeof(struct group_source_req), 2147 sizeof(struct group_source_req)); 2148 } 2149 if (error) 2150 return (error); 2151 2152 if (gsa->sin.sin_family != AF_INET || 2153 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 2154 return (EINVAL); 2155 2156 /* 2157 * Overwrite the port field if present, as the sockaddr 2158 * being copied in may be matched with a binary comparison. 2159 */ 2160 gsa->sin.sin_port = 0; 2161 if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) { 2162 if (ssa->sin.sin_family != AF_INET || 2163 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 2164 return (EINVAL); 2165 ssa->sin.sin_port = 0; 2166 } 2167 2168 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2169 return (EINVAL); 2170 2171 ifnet_head_lock_shared(); 2172 if (gsr.gsr_interface == 0 || 2173 (u_int)if_index < gsr.gsr_interface) { 2174 ifnet_head_done(); 2175 return (EADDRNOTAVAIL); 2176 } 2177 ifp = ifindex2ifnet[gsr.gsr_interface]; 2178 ifnet_head_done(); 2179 2180 break; 2181 2182 default: 2183 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 2184 __func__, sopt->sopt_name)); 2185 return (EOPNOTSUPP); 2186 break; 2187 } 2188 2189 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) 2190 return (EADDRNOTAVAIL); 2191 2192 imo = inp_findmoptions(inp); 2193 if (imo == NULL) 2194 return (ENOMEM); 2195 2196 IMO_LOCK(imo); 2197 idx = imo_match_group(imo, ifp, &gsa->sa); 2198 if (idx == (size_t)-1) { 2199 is_new = 1; 2200 } else { 2201 inm = imo->imo_membership[idx]; 2202 imf = &imo->imo_mfilters[idx]; 2203 if (ssa->ss.ss_family != AF_UNSPEC) { 2204 /* 2205 * MCAST_JOIN_SOURCE_GROUP on an exclusive membership 2206 * is an error. On an existing inclusive membership, 2207 * it just adds the source to the filter list. 2208 */ 2209 if (imf->imf_st[1] != MCAST_INCLUDE) { 2210 error = EINVAL; 2211 goto out_imo_locked; 2212 } 2213 /* 2214 * Throw out duplicates. 2215 * 2216 * XXX FIXME: This makes a naive assumption that 2217 * even if entries exist for *ssa in this imf, 2218 * they will be rejected as dupes, even if they 2219 * are not valid in the current mode (in-mode). 2220 * 2221 * in_msource is transactioned just as for anything 2222 * else in SSM -- but note naive use of inm_graft() 2223 * below for allocating new filter entries. 2224 * 2225 * This is only an issue if someone mixes the 2226 * full-state SSM API with the delta-based API, 2227 * which is discouraged in the relevant RFCs. 2228 */ 2229 lims = imo_match_source(imo, idx, &ssa->sa); 2230 if (lims != NULL /*&& 2231 lims->imsl_st[1] == MCAST_INCLUDE*/) { 2232 error = EADDRNOTAVAIL; 2233 goto out_imo_locked; 2234 } 2235 } else { 2236 /* 2237 * MCAST_JOIN_GROUP on an existing exclusive 2238 * membership is an error; return EADDRINUSE 2239 * to preserve 4.4BSD API idempotence, and 2240 * avoid tedious detour to code below. 2241 * NOTE: This is bending RFC 3678 a bit. 2242 * 2243 * On an existing inclusive membership, this is also 2244 * an error; if you want to change filter mode, 2245 * you must use the userland API setsourcefilter(). 2246 * XXX We don't reject this for imf in UNDEFINED 2247 * state at t1, because allocation of a filter 2248 * is atomic with allocation of a membership. 2249 */ 2250 error = EINVAL; 2251 /* See comments above for EADDRINUSE */ 2252 if (imf->imf_st[1] == MCAST_EXCLUDE) 2253 error = EADDRINUSE; 2254 goto out_imo_locked; 2255 } 2256 } 2257 2258 /* 2259 * Begin state merge transaction at socket layer. 2260 */ 2261 2262 if (is_new) { 2263 if (imo->imo_num_memberships == imo->imo_max_memberships) { 2264 error = imo_grow(imo, 0); 2265 if (error) 2266 goto out_imo_locked; 2267 } 2268 /* 2269 * Allocate the new slot upfront so we can deal with 2270 * grafting the new source filter in same code path 2271 * as for join-source on existing membership. 2272 */ 2273 idx = imo->imo_num_memberships; 2274 imo->imo_membership[idx] = NULL; 2275 imo->imo_num_memberships++; 2276 VERIFY(imo->imo_mfilters != NULL); 2277 imf = &imo->imo_mfilters[idx]; 2278 VERIFY(RB_EMPTY(&imf->imf_sources)); 2279 } 2280 2281 /* 2282 * Graft new source into filter list for this inpcb's 2283 * membership of the group. The in_multi may not have 2284 * been allocated yet if this is a new membership, however, 2285 * the in_mfilter slot will be allocated and must be initialized. 2286 */ 2287 if (ssa->ss.ss_family != AF_UNSPEC) { 2288 /* Membership starts in IN mode */ 2289 if (is_new) { 2290 IGMP_PRINTF(("%s: new join w/source\n", __func__)); 2291 imf_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); 2292 } else { 2293 IGMP_PRINTF(("%s: %s source\n", __func__, "allow")); 2294 } 2295 lims = imf_graft(imf, MCAST_INCLUDE, &ssa->sin); 2296 if (lims == NULL) { 2297 IGMP_PRINTF(("%s: merge imf state failed\n", 2298 __func__)); 2299 error = ENOMEM; 2300 goto out_imo_free; 2301 } 2302 } else { 2303 /* No address specified; Membership starts in EX mode */ 2304 if (is_new) { 2305 IGMP_PRINTF(("%s: new join w/o source\n", __func__)); 2306 imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); 2307 } 2308 } 2309 2310 /* 2311 * Begin state merge transaction at IGMP layer. 2312 */ 2313 2314 if (is_new) { 2315 VERIFY(inm == NULL); 2316 error = in_joingroup(ifp, &gsa->sin.sin_addr, imf, &inm); 2317 VERIFY(inm != NULL || error != 0); 2318 if (error) 2319 goto out_imo_free; 2320 imo->imo_membership[idx] = inm; /* from in_joingroup() */ 2321 } else { 2322 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 2323 INM_LOCK(inm); 2324 error = inm_merge(inm, imf); 2325 if (error) { 2326 IGMP_PRINTF(("%s: failed to merge inm state\n", 2327 __func__)); 2328 INM_UNLOCK(inm); 2329 goto out_imf_rollback; 2330 } 2331 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 2332 error = igmp_change_state(inm, &itp); 2333 INM_UNLOCK(inm); 2334 if (error) { 2335 IGMP_PRINTF(("%s: failed igmp downcall\n", 2336 __func__)); 2337 goto out_imf_rollback; 2338 } 2339 } 2340 2341out_imf_rollback: 2342 if (error) { 2343 imf_rollback(imf); 2344 if (is_new) 2345 imf_purge(imf); 2346 else 2347 imf_reap(imf); 2348 } else { 2349 imf_commit(imf); 2350 } 2351 2352out_imo_free: 2353 if (error && is_new) { 2354 VERIFY(inm == NULL); 2355 imo->imo_membership[idx] = NULL; 2356 --imo->imo_num_memberships; 2357 } 2358 2359out_imo_locked: 2360 IMO_UNLOCK(imo); 2361 IMO_REMREF(imo); /* from inp_findmoptions() */ 2362 2363 /* schedule timer now that we've dropped the lock(s) */ 2364 igmp_set_timeout(&itp); 2365 2366 return (error); 2367} 2368 2369/* 2370 * Leave an IPv4 multicast group on an inpcb, possibly with a source. 2371 * 2372 * NB: sopt->sopt_val might point to the kernel address space. Refer to the 2373 * block comment on top of inp_join_group() for more information. 2374 */ 2375int 2376inp_leave_group(struct inpcb *inp, struct sockopt *sopt) 2377{ 2378 struct group_source_req gsr; 2379 struct ip_mreq_source mreqs; 2380 sockunion_t *gsa, *ssa; 2381 struct ifnet *ifp; 2382 struct in_mfilter *imf; 2383 struct ip_moptions *imo; 2384 struct in_msource *ims; 2385 struct in_multi *inm = NULL; 2386 size_t idx; 2387 int error, is_final; 2388 unsigned int ifindex = 0; 2389 struct igmp_tparams itp; 2390 2391 bzero(&itp, sizeof (itp)); 2392 ifp = NULL; 2393 error = 0; 2394 is_final = 1; 2395 2396 memset(&gsr, 0, sizeof(struct group_source_req)); 2397 gsa = (sockunion_t *)&gsr.gsr_group; 2398 gsa->ss.ss_family = AF_UNSPEC; 2399 ssa = (sockunion_t *)&gsr.gsr_source; 2400 ssa->ss.ss_family = AF_UNSPEC; 2401 2402 switch (sopt->sopt_name) { 2403 case IP_DROP_MEMBERSHIP: 2404 case IP_DROP_SOURCE_MEMBERSHIP: 2405 if (sopt->sopt_name == IP_DROP_MEMBERSHIP) { 2406 error = sooptcopyin(sopt, &mreqs, 2407 sizeof(struct ip_mreq), 2408 sizeof(struct ip_mreq)); 2409 /* 2410 * Swap interface and sourceaddr arguments, 2411 * as ip_mreq and ip_mreq_source are laid 2412 * out differently. 2413 */ 2414 mreqs.imr_interface = mreqs.imr_sourceaddr; 2415 mreqs.imr_sourceaddr.s_addr = INADDR_ANY; 2416 } else if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) { 2417 error = sooptcopyin(sopt, &mreqs, 2418 sizeof(struct ip_mreq_source), 2419 sizeof(struct ip_mreq_source)); 2420 } 2421 if (error) 2422 return (error); 2423 2424 gsa->sin.sin_family = AF_INET; 2425 gsa->sin.sin_len = sizeof(struct sockaddr_in); 2426 gsa->sin.sin_addr = mreqs.imr_multiaddr; 2427 2428 if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) { 2429 ssa->sin.sin_family = AF_INET; 2430 ssa->sin.sin_len = sizeof(struct sockaddr_in); 2431 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 2432 } 2433 /* 2434 * Attempt to look up hinted ifp from interface address. 2435 * Fallthrough with null ifp iff lookup fails, to 2436 * preserve 4.4BSD mcast API idempotence. 2437 * XXX NOTE WELL: The RFC 3678 API is preferred because 2438 * using an IPv4 address as a key is racy. 2439 */ 2440 if (!in_nullhost(mreqs.imr_interface)) 2441 ifp = ip_multicast_if(&mreqs.imr_interface, &ifindex); 2442 2443 IGMP_INET_PRINTF(mreqs.imr_interface, 2444 ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, 2445 _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); 2446 2447 break; 2448 2449 case MCAST_LEAVE_GROUP: 2450 case MCAST_LEAVE_SOURCE_GROUP: 2451 if (sopt->sopt_name == MCAST_LEAVE_GROUP) { 2452 error = sooptcopyin(sopt, &gsr, 2453 sizeof(struct group_req), 2454 sizeof(struct group_req)); 2455 } else if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) { 2456 error = sooptcopyin(sopt, &gsr, 2457 sizeof(struct group_source_req), 2458 sizeof(struct group_source_req)); 2459 } 2460 if (error) 2461 return (error); 2462 2463 if (gsa->sin.sin_family != AF_INET || 2464 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 2465 return (EINVAL); 2466 2467 if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) { 2468 if (ssa->sin.sin_family != AF_INET || 2469 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 2470 return (EINVAL); 2471 } 2472 2473 ifnet_head_lock_shared(); 2474 if (gsr.gsr_interface == 0 || 2475 (u_int)if_index < gsr.gsr_interface) { 2476 ifnet_head_done(); 2477 return (EADDRNOTAVAIL); 2478 } 2479 2480 ifp = ifindex2ifnet[gsr.gsr_interface]; 2481 ifnet_head_done(); 2482 break; 2483 2484 default: 2485 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 2486 __func__, sopt->sopt_name)); 2487 return (EOPNOTSUPP); 2488 break; 2489 } 2490 2491 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2492 return (EINVAL); 2493 2494 /* 2495 * Find the membership in the membership array. 2496 */ 2497 imo = inp_findmoptions(inp); 2498 if (imo == NULL) 2499 return (ENOMEM); 2500 2501 IMO_LOCK(imo); 2502 idx = imo_match_group(imo, ifp, &gsa->sa); 2503 if (idx == (size_t)-1) { 2504 error = EADDRNOTAVAIL; 2505 goto out_locked; 2506 } 2507 inm = imo->imo_membership[idx]; 2508 imf = &imo->imo_mfilters[idx]; 2509 2510 if (ssa->ss.ss_family != AF_UNSPEC) { 2511 IGMP_PRINTF(("%s: opt=%d is_final=0\n", __func__, 2512 sopt->sopt_name)); 2513 is_final = 0; 2514 } 2515 2516 /* 2517 * Begin state merge transaction at socket layer. 2518 */ 2519 2520 /* 2521 * If we were instructed only to leave a given source, do so. 2522 * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. 2523 */ 2524 if (is_final) { 2525 imf_leave(imf); 2526 } else { 2527 if (imf->imf_st[0] == MCAST_EXCLUDE) { 2528 error = EADDRNOTAVAIL; 2529 goto out_locked; 2530 } 2531 ims = imo_match_source(imo, idx, &ssa->sa); 2532 if (ims == NULL) { 2533 IGMP_INET_PRINTF(ssa->sin.sin_addr, 2534 ("%s: source %s %spresent\n", __func__, 2535 _igmp_inet_buf, "not ")); 2536 error = EADDRNOTAVAIL; 2537 goto out_locked; 2538 } 2539 IGMP_PRINTF(("%s: %s source\n", __func__, "block")); 2540 error = imf_prune(imf, &ssa->sin); 2541 if (error) { 2542 IGMP_PRINTF(("%s: merge imf state failed\n", 2543 __func__)); 2544 goto out_locked; 2545 } 2546 } 2547 2548 /* 2549 * Begin state merge transaction at IGMP layer. 2550 */ 2551 2552 if (is_final) { 2553 /* 2554 * Give up the multicast address record to which 2555 * the membership points. Reference held in imo 2556 * will be released below. 2557 */ 2558 (void) in_leavegroup(inm, imf); 2559 } else { 2560 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 2561 INM_LOCK(inm); 2562 error = inm_merge(inm, imf); 2563 if (error) { 2564 IGMP_PRINTF(("%s: failed to merge inm state\n", 2565 __func__)); 2566 INM_UNLOCK(inm); 2567 goto out_imf_rollback; 2568 } 2569 2570 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 2571 error = igmp_change_state(inm, &itp); 2572 if (error) { 2573 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); 2574 } 2575 INM_UNLOCK(inm); 2576 } 2577 2578out_imf_rollback: 2579 if (error) 2580 imf_rollback(imf); 2581 else 2582 imf_commit(imf); 2583 2584 imf_reap(imf); 2585 2586 if (is_final) { 2587 /* Remove the gap in the membership and filter array. */ 2588 VERIFY(inm == imo->imo_membership[idx]); 2589 imo->imo_membership[idx] = NULL; 2590 INM_REMREF(inm); 2591 for (++idx; idx < imo->imo_num_memberships; ++idx) { 2592 imo->imo_membership[idx-1] = imo->imo_membership[idx]; 2593 imo->imo_mfilters[idx-1] = imo->imo_mfilters[idx]; 2594 } 2595 imo->imo_num_memberships--; 2596 } 2597 2598out_locked: 2599 IMO_UNLOCK(imo); 2600 IMO_REMREF(imo); /* from inp_findmoptions() */ 2601 2602 /* schedule timer now that we've dropped the lock(s) */ 2603 igmp_set_timeout(&itp); 2604 2605 return (error); 2606} 2607 2608/* 2609 * Select the interface for transmitting IPv4 multicast datagrams. 2610 * 2611 * Either an instance of struct in_addr or an instance of struct ip_mreqn 2612 * may be passed to this socket option. An address of INADDR_ANY or an 2613 * interface index of 0 is used to remove a previous selection. 2614 * When no interface is selected, one is chosen for every send. 2615 */ 2616static int 2617inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) 2618{ 2619 struct in_addr addr; 2620 struct ip_mreqn mreqn; 2621 struct ifnet *ifp; 2622 struct ip_moptions *imo; 2623 int error = 0 ; 2624 unsigned int ifindex = 0; 2625 2626 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) { 2627 /* 2628 * An interface index was specified using the 2629 * Linux-derived ip_mreqn structure. 2630 */ 2631 error = sooptcopyin(sopt, &mreqn, sizeof(struct ip_mreqn), 2632 sizeof(struct ip_mreqn)); 2633 if (error) 2634 return (error); 2635 2636 ifnet_head_lock_shared(); 2637 if (mreqn.imr_ifindex < 0 || if_index < mreqn.imr_ifindex) { 2638 ifnet_head_done(); 2639 return (EINVAL); 2640 } 2641 2642 if (mreqn.imr_ifindex == 0) { 2643 ifp = NULL; 2644 } else { 2645 ifp = ifindex2ifnet[mreqn.imr_ifindex]; 2646 if (ifp == NULL) { 2647 ifnet_head_done(); 2648 return (EADDRNOTAVAIL); 2649 } 2650 } 2651 ifnet_head_done(); 2652 } else { 2653 /* 2654 * An interface was specified by IPv4 address. 2655 * This is the traditional BSD usage. 2656 */ 2657 error = sooptcopyin(sopt, &addr, sizeof(struct in_addr), 2658 sizeof(struct in_addr)); 2659 if (error) 2660 return (error); 2661 if (in_nullhost(addr)) { 2662 ifp = NULL; 2663 } else { 2664 ifp = ip_multicast_if(&addr, &ifindex); 2665 if (ifp == NULL) { 2666 IGMP_INET_PRINTF(addr, 2667 ("%s: can't find ifp for addr=%s\n", 2668 __func__, _igmp_inet_buf)); 2669 return (EADDRNOTAVAIL); 2670 } 2671 } 2672 /* XXX remove? */ 2673#ifdef IGMP_DEBUG0 2674 IGMP_PRINTF(("%s: ifp = 0x%llx, addr = %s\n", __func__, 2675 (uint64_t)VM_KERNEL_ADDRPERM(ifp), inet_ntoa(addr))); 2676#endif 2677 } 2678 2679 /* Reject interfaces which do not support multicast. */ 2680 if (ifp != NULL && (ifp->if_flags & IFF_MULTICAST) == 0) 2681 return (EOPNOTSUPP); 2682 2683 imo = inp_findmoptions(inp); 2684 if (imo == NULL) 2685 return (ENOMEM); 2686 2687 IMO_LOCK(imo); 2688 imo->imo_multicast_ifp = ifp; 2689 if (ifindex) 2690 imo->imo_multicast_addr = addr; 2691 else 2692 imo->imo_multicast_addr.s_addr = INADDR_ANY; 2693 IMO_UNLOCK(imo); 2694 IMO_REMREF(imo); /* from inp_findmoptions() */ 2695 2696 return (0); 2697} 2698 2699/* 2700 * Atomically set source filters on a socket for an IPv4 multicast group. 2701 */ 2702static int 2703inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) 2704{ 2705 struct __msfilterreq64 msfr, msfr64; 2706 struct __msfilterreq32 msfr32; 2707 sockunion_t *gsa; 2708 struct ifnet *ifp; 2709 struct in_mfilter *imf; 2710 struct ip_moptions *imo; 2711 struct in_multi *inm; 2712 size_t idx; 2713 int error; 2714 user_addr_t tmp_ptr; 2715 struct igmp_tparams itp; 2716 2717 bzero(&itp, sizeof (itp)); 2718 2719 if (IS_64BIT_PROCESS(current_proc())) { 2720 error = sooptcopyin(sopt, &msfr64, 2721 sizeof(struct __msfilterreq64), 2722 sizeof(struct __msfilterreq64)); 2723 if (error) 2724 return (error); 2725 /* we never use msfr.msfr_srcs; */ 2726 memcpy(&msfr, &msfr64, sizeof(msfr)); 2727 } else { 2728 error = sooptcopyin(sopt, &msfr32, 2729 sizeof(struct __msfilterreq32), 2730 sizeof(struct __msfilterreq32)); 2731 if (error) 2732 return (error); 2733 /* we never use msfr.msfr_srcs; */ 2734 memcpy(&msfr, &msfr32, sizeof(msfr)); 2735 } 2736 2737 if ((size_t) msfr.msfr_nsrcs > 2738 UINT32_MAX / sizeof(struct sockaddr_storage)) 2739 msfr.msfr_nsrcs = UINT32_MAX / sizeof(struct sockaddr_storage); 2740 2741 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) 2742 return (ENOBUFS); 2743 2744 if ((msfr.msfr_fmode != MCAST_EXCLUDE && 2745 msfr.msfr_fmode != MCAST_INCLUDE)) 2746 return (EINVAL); 2747 2748 if (msfr.msfr_group.ss_family != AF_INET || 2749 msfr.msfr_group.ss_len != sizeof(struct sockaddr_in)) 2750 return (EINVAL); 2751 2752 gsa = (sockunion_t *)&msfr.msfr_group; 2753 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2754 return (EINVAL); 2755 2756 gsa->sin.sin_port = 0; /* ignore port */ 2757 2758 ifnet_head_lock_shared(); 2759 if (msfr.msfr_ifindex == 0 || (u_int)if_index < msfr.msfr_ifindex) { 2760 ifnet_head_done(); 2761 return (EADDRNOTAVAIL); 2762 } 2763 2764 ifp = ifindex2ifnet[msfr.msfr_ifindex]; 2765 ifnet_head_done(); 2766 if (ifp == NULL) 2767 return (EADDRNOTAVAIL); 2768 2769 /* 2770 * Check if this socket is a member of this group. 2771 */ 2772 imo = inp_findmoptions(inp); 2773 if (imo == NULL) 2774 return (ENOMEM); 2775 2776 IMO_LOCK(imo); 2777 idx = imo_match_group(imo, ifp, &gsa->sa); 2778 if (idx == (size_t)-1 || imo->imo_mfilters == NULL) { 2779 error = EADDRNOTAVAIL; 2780 goto out_imo_locked; 2781 } 2782 inm = imo->imo_membership[idx]; 2783 imf = &imo->imo_mfilters[idx]; 2784 2785 /* 2786 * Begin state merge transaction at socket layer. 2787 */ 2788 2789 imf->imf_st[1] = msfr.msfr_fmode; 2790 2791 /* 2792 * Apply any new source filters, if present. 2793 * Make a copy of the user-space source vector so 2794 * that we may copy them with a single copyin. This 2795 * allows us to deal with page faults up-front. 2796 */ 2797 if (msfr.msfr_nsrcs > 0) { 2798 struct in_msource *lims; 2799 struct sockaddr_in *psin; 2800 struct sockaddr_storage *kss, *pkss; 2801 int i; 2802 2803 if (IS_64BIT_PROCESS(current_proc())) 2804 tmp_ptr = msfr64.msfr_srcs; 2805 else 2806 tmp_ptr = CAST_USER_ADDR_T(msfr32.msfr_srcs); 2807 2808 IGMP_PRINTF(("%s: loading %lu source list entries\n", 2809 __func__, (unsigned long)msfr.msfr_nsrcs)); 2810 kss = _MALLOC((size_t) msfr.msfr_nsrcs * sizeof(*kss), 2811 M_TEMP, M_WAITOK); 2812 if (kss == NULL) { 2813 error = ENOMEM; 2814 goto out_imo_locked; 2815 } 2816 error = copyin(tmp_ptr, kss, 2817 (size_t) msfr.msfr_nsrcs * sizeof(*kss)); 2818 if (error) { 2819 FREE(kss, M_TEMP); 2820 goto out_imo_locked; 2821 } 2822 2823 /* 2824 * Mark all source filters as UNDEFINED at t1. 2825 * Restore new group filter mode, as imf_leave() 2826 * will set it to INCLUDE. 2827 */ 2828 imf_leave(imf); 2829 imf->imf_st[1] = msfr.msfr_fmode; 2830 2831 /* 2832 * Update socket layer filters at t1, lazy-allocating 2833 * new entries. This saves a bunch of memory at the 2834 * cost of one RB_FIND() per source entry; duplicate 2835 * entries in the msfr_nsrcs vector are ignored. 2836 * If we encounter an error, rollback transaction. 2837 * 2838 * XXX This too could be replaced with a set-symmetric 2839 * difference like loop to avoid walking from root 2840 * every time, as the key space is common. 2841 */ 2842 for (i = 0, pkss = kss; (u_int)i < msfr.msfr_nsrcs; 2843 i++, pkss++) { 2844 psin = (struct sockaddr_in *)pkss; 2845 if (psin->sin_family != AF_INET) { 2846 error = EAFNOSUPPORT; 2847 break; 2848 } 2849 if (psin->sin_len != sizeof(struct sockaddr_in)) { 2850 error = EINVAL; 2851 break; 2852 } 2853 error = imf_get_source(imf, psin, &lims); 2854 if (error) 2855 break; 2856 lims->imsl_st[1] = imf->imf_st[1]; 2857 } 2858 FREE(kss, M_TEMP); 2859 } 2860 2861 if (error) 2862 goto out_imf_rollback; 2863 2864 /* 2865 * Begin state merge transaction at IGMP layer. 2866 */ 2867 INM_LOCK(inm); 2868 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 2869 error = inm_merge(inm, imf); 2870 if (error) { 2871 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__)); 2872 INM_UNLOCK(inm); 2873 goto out_imf_rollback; 2874 } 2875 2876 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 2877 error = igmp_change_state(inm, &itp); 2878 INM_UNLOCK(inm); 2879#ifdef IGMP_DEBUG 2880 if (error) 2881 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); 2882#endif 2883 2884out_imf_rollback: 2885 if (error) 2886 imf_rollback(imf); 2887 else 2888 imf_commit(imf); 2889 2890 imf_reap(imf); 2891 2892out_imo_locked: 2893 IMO_UNLOCK(imo); 2894 IMO_REMREF(imo); /* from inp_findmoptions() */ 2895 2896 /* schedule timer now that we've dropped the lock(s) */ 2897 igmp_set_timeout(&itp); 2898 2899 return (error); 2900} 2901 2902/* 2903 * Set the IP multicast options in response to user setsockopt(). 2904 * 2905 * Many of the socket options handled in this function duplicate the 2906 * functionality of socket options in the regular unicast API. However, 2907 * it is not possible to merge the duplicate code, because the idempotence 2908 * of the IPv4 multicast part of the BSD Sockets API must be preserved; 2909 * the effects of these options must be treated as separate and distinct. 2910 */ 2911int 2912inp_setmoptions(struct inpcb *inp, struct sockopt *sopt) 2913{ 2914 struct ip_moptions *imo; 2915 int error; 2916 unsigned int ifindex; 2917 struct ifnet *ifp; 2918 2919 error = 0; 2920 2921 /* 2922 * If socket is neither of type SOCK_RAW or SOCK_DGRAM, 2923 * or is a divert socket, reject it. 2924 */ 2925 if (SOCK_PROTO(inp->inp_socket) == IPPROTO_DIVERT || 2926 (SOCK_TYPE(inp->inp_socket) != SOCK_RAW && 2927 SOCK_TYPE(inp->inp_socket) != SOCK_DGRAM)) 2928 return (EOPNOTSUPP); 2929 2930 switch (sopt->sopt_name) { 2931 case IP_MULTICAST_IF: 2932 error = inp_set_multicast_if(inp, sopt); 2933 break; 2934 2935 case IP_MULTICAST_IFINDEX: 2936 /* 2937 * Select the interface for outgoing multicast packets. 2938 */ 2939 error = sooptcopyin(sopt, &ifindex, sizeof (ifindex), 2940 sizeof (ifindex)); 2941 if (error) 2942 break; 2943 2944 imo = inp_findmoptions(inp); 2945 if (imo == NULL) { 2946 error = ENOMEM; 2947 break; 2948 } 2949 /* 2950 * Index 0 is used to remove a previous selection. 2951 * When no interface is selected, a default one is 2952 * chosen every time a multicast packet is sent. 2953 */ 2954 if (ifindex == 0) { 2955 IMO_LOCK(imo); 2956 imo->imo_multicast_ifp = NULL; 2957 IMO_UNLOCK(imo); 2958 IMO_REMREF(imo); /* from inp_findmoptions() */ 2959 break; 2960 } 2961 2962 ifnet_head_lock_shared(); 2963 /* Don't need to check is ifindex is < 0 since it's unsigned */ 2964 if ((unsigned int)if_index < ifindex) { 2965 ifnet_head_done(); 2966 IMO_REMREF(imo); /* from inp_findmoptions() */ 2967 error = ENXIO; /* per IPV6_MULTICAST_IF */ 2968 break; 2969 } 2970 ifp = ifindex2ifnet[ifindex]; 2971 ifnet_head_done(); 2972 2973 /* If it's detached or isn't a multicast interface, bail out */ 2974 if (ifp == NULL || !(ifp->if_flags & IFF_MULTICAST)) { 2975 IMO_REMREF(imo); /* from inp_findmoptions() */ 2976 error = EADDRNOTAVAIL; 2977 break; 2978 } 2979 IMO_LOCK(imo); 2980 imo->imo_multicast_ifp = ifp; 2981 /* 2982 * Clear out any remnants of past IP_MULTICAST_IF. The addr 2983 * isn't really used anywhere in the kernel; we could have 2984 * iterated thru the addresses of the interface and pick one 2985 * here, but that is redundant since ip_getmoptions() already 2986 * takes care of that for INADDR_ANY. 2987 */ 2988 imo->imo_multicast_addr.s_addr = INADDR_ANY; 2989 IMO_UNLOCK(imo); 2990 IMO_REMREF(imo); /* from inp_findmoptions() */ 2991 break; 2992 2993 case IP_MULTICAST_TTL: { 2994 u_char ttl; 2995 2996 /* 2997 * Set the IP time-to-live for outgoing multicast packets. 2998 * The original multicast API required a char argument, 2999 * which is inconsistent with the rest of the socket API. 3000 * We allow either a char or an int. 3001 */ 3002 if (sopt->sopt_valsize == sizeof(u_char)) { 3003 error = sooptcopyin(sopt, &ttl, sizeof(u_char), 3004 sizeof(u_char)); 3005 if (error) 3006 break; 3007 } else { 3008 u_int ittl; 3009 3010 error = sooptcopyin(sopt, &ittl, sizeof(u_int), 3011 sizeof(u_int)); 3012 if (error) 3013 break; 3014 if (ittl > 255) { 3015 error = EINVAL; 3016 break; 3017 } 3018 ttl = (u_char)ittl; 3019 } 3020 imo = inp_findmoptions(inp); 3021 if (imo == NULL) { 3022 error = ENOMEM; 3023 break; 3024 } 3025 IMO_LOCK(imo); 3026 imo->imo_multicast_ttl = ttl; 3027 IMO_UNLOCK(imo); 3028 IMO_REMREF(imo); /* from inp_findmoptions() */ 3029 break; 3030 } 3031 3032 case IP_MULTICAST_LOOP: { 3033 u_char loop; 3034 3035 /* 3036 * Set the loopback flag for outgoing multicast packets. 3037 * Must be zero or one. The original multicast API required a 3038 * char argument, which is inconsistent with the rest 3039 * of the socket API. We allow either a char or an int. 3040 */ 3041 if (sopt->sopt_valsize == sizeof(u_char)) { 3042 error = sooptcopyin(sopt, &loop, sizeof(u_char), 3043 sizeof(u_char)); 3044 if (error) 3045 break; 3046 } else { 3047 u_int iloop; 3048 3049 error = sooptcopyin(sopt, &iloop, sizeof(u_int), 3050 sizeof(u_int)); 3051 if (error) 3052 break; 3053 loop = (u_char)iloop; 3054 } 3055 imo = inp_findmoptions(inp); 3056 if (imo == NULL) { 3057 error = ENOMEM; 3058 break; 3059 } 3060 IMO_LOCK(imo); 3061 imo->imo_multicast_loop = !!loop; 3062 IMO_UNLOCK(imo); 3063 IMO_REMREF(imo); /* from inp_findmoptions() */ 3064 break; 3065 } 3066 3067 case IP_ADD_MEMBERSHIP: 3068 case IP_ADD_SOURCE_MEMBERSHIP: 3069 case MCAST_JOIN_GROUP: 3070 case MCAST_JOIN_SOURCE_GROUP: 3071 error = inp_join_group(inp, sopt); 3072 break; 3073 3074 case IP_DROP_MEMBERSHIP: 3075 case IP_DROP_SOURCE_MEMBERSHIP: 3076 case MCAST_LEAVE_GROUP: 3077 case MCAST_LEAVE_SOURCE_GROUP: 3078 error = inp_leave_group(inp, sopt); 3079 break; 3080 3081 case IP_BLOCK_SOURCE: 3082 case IP_UNBLOCK_SOURCE: 3083 case MCAST_BLOCK_SOURCE: 3084 case MCAST_UNBLOCK_SOURCE: 3085 error = inp_block_unblock_source(inp, sopt); 3086 break; 3087 3088 case IP_MSFILTER: 3089 error = inp_set_source_filters(inp, sopt); 3090 break; 3091 3092 default: 3093 error = EOPNOTSUPP; 3094 break; 3095 } 3096 3097 return (error); 3098} 3099 3100/* 3101 * Expose IGMP's multicast filter mode and source list(s) to userland, 3102 * keyed by (ifindex, group). 3103 * The filter mode is written out as a uint32_t, followed by 3104 * 0..n of struct in_addr. 3105 * For use by ifmcstat(8). 3106 */ 3107static int 3108sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS 3109{ 3110#pragma unused(oidp) 3111 3112 struct in_addr src, group; 3113 struct ifnet *ifp; 3114 struct in_multi *inm; 3115 struct in_multistep step; 3116 struct ip_msource *ims; 3117 int *name; 3118 int retval = 0; 3119 u_int namelen; 3120 uint32_t fmode, ifindex; 3121 3122 name = (int *)arg1; 3123 namelen = (u_int)arg2; 3124 3125 if (req->newptr != USER_ADDR_NULL) 3126 return (EPERM); 3127 3128 if (namelen != 2) 3129 return (EINVAL); 3130 3131 ifindex = name[0]; 3132 ifnet_head_lock_shared(); 3133 if (ifindex <= 0 || ifindex > (u_int)if_index) { 3134 IGMP_PRINTF(("%s: ifindex %u out of range\n", 3135 __func__, ifindex)); 3136 ifnet_head_done(); 3137 return (ENOENT); 3138 } 3139 3140 group.s_addr = name[1]; 3141 if (!IN_MULTICAST(ntohl(group.s_addr))) { 3142 IGMP_INET_PRINTF(group, 3143 ("%s: group %s is not multicast\n", 3144 __func__, _igmp_inet_buf)); 3145 ifnet_head_done(); 3146 return (EINVAL); 3147 } 3148 3149 ifp = ifindex2ifnet[ifindex]; 3150 ifnet_head_done(); 3151 if (ifp == NULL) { 3152 IGMP_PRINTF(("%s: no ifp for ifindex %u\n", __func__, ifindex)); 3153 return (ENOENT); 3154 } 3155 3156 in_multihead_lock_shared(); 3157 IN_FIRST_MULTI(step, inm); 3158 while (inm != NULL) { 3159 INM_LOCK(inm); 3160 if (inm->inm_ifp != ifp) 3161 goto next; 3162 3163 if (!in_hosteq(inm->inm_addr, group)) 3164 goto next; 3165 3166 fmode = inm->inm_st[1].iss_fmode; 3167 retval = SYSCTL_OUT(req, &fmode, sizeof(uint32_t)); 3168 if (retval != 0) { 3169 INM_UNLOCK(inm); 3170 break; /* abort */ 3171 } 3172 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 3173#ifdef IGMP_DEBUG 3174 struct in_addr ina; 3175 ina.s_addr = htonl(ims->ims_haddr); 3176 IGMP_INET_PRINTF(ina, 3177 ("%s: visit node %s\n", __func__, _igmp_inet_buf)); 3178#endif 3179 /* 3180 * Only copy-out sources which are in-mode. 3181 */ 3182 if (fmode != ims_get_mode(inm, ims, 1)) { 3183 IGMP_PRINTF(("%s: skip non-in-mode\n", 3184 __func__)); 3185 continue; /* process next source */ 3186 } 3187 src.s_addr = htonl(ims->ims_haddr); 3188 retval = SYSCTL_OUT(req, &src, sizeof(struct in_addr)); 3189 if (retval != 0) 3190 break; /* process next inm */ 3191 } 3192next: 3193 INM_UNLOCK(inm); 3194 IN_NEXT_MULTI(step, inm); 3195 } 3196 in_multihead_lock_done(); 3197 3198 return (retval); 3199} 3200 3201/* 3202 * XXX 3203 * The whole multicast option thing needs to be re-thought. 3204 * Several of these options are equally applicable to non-multicast 3205 * transmission, and one (IP_MULTICAST_TTL) totally duplicates a 3206 * standard option (IP_TTL). 3207 */ 3208/* 3209 * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. 3210 */ 3211static struct ifnet * 3212ip_multicast_if(struct in_addr *a, unsigned int *ifindexp) 3213{ 3214 unsigned int ifindex; 3215 struct ifnet *ifp; 3216 3217 if (ifindexp != NULL) 3218 *ifindexp = 0; 3219 if (ntohl(a->s_addr) >> 24 == 0) { 3220 ifindex = ntohl(a->s_addr) & 0xffffff; 3221 ifnet_head_lock_shared(); 3222 /* Don't need to check is ifindex is < 0 since it's unsigned */ 3223 if ((unsigned int)if_index < ifindex) { 3224 ifnet_head_done(); 3225 return (NULL); 3226 } 3227 ifp = ifindex2ifnet[ifindex]; 3228 ifnet_head_done(); 3229 if (ifp != NULL && ifindexp != NULL) 3230 *ifindexp = ifindex; 3231 } else { 3232 INADDR_TO_IFP(*a, ifp); 3233 } 3234 return (ifp); 3235} 3236 3237void 3238in_multi_init(void) 3239{ 3240 PE_parse_boot_argn("ifa_debug", &inm_debug, sizeof (inm_debug)); 3241 3242 /* Setup lock group and attribute for in_multihead */ 3243 in_multihead_lock_grp_attr = lck_grp_attr_alloc_init(); 3244 in_multihead_lock_grp = lck_grp_alloc_init("in_multihead", 3245 in_multihead_lock_grp_attr); 3246 in_multihead_lock_attr = lck_attr_alloc_init(); 3247 lck_rw_init(&in_multihead_lock, in_multihead_lock_grp, 3248 in_multihead_lock_attr); 3249 3250 lck_mtx_init(&inm_trash_lock, in_multihead_lock_grp, 3251 in_multihead_lock_attr); 3252 TAILQ_INIT(&inm_trash_head); 3253 3254 inm_size = (inm_debug == 0) ? sizeof (struct in_multi) : 3255 sizeof (struct in_multi_dbg); 3256 inm_zone = zinit(inm_size, INM_ZONE_MAX * inm_size, 3257 0, INM_ZONE_NAME); 3258 if (inm_zone == NULL) { 3259 panic("%s: failed allocating %s", __func__, INM_ZONE_NAME); 3260 /* NOTREACHED */ 3261 } 3262 zone_change(inm_zone, Z_EXPAND, TRUE); 3263 3264 ipms_size = sizeof (struct ip_msource); 3265 ipms_zone = zinit(ipms_size, IPMS_ZONE_MAX * ipms_size, 3266 0, IPMS_ZONE_NAME); 3267 if (ipms_zone == NULL) { 3268 panic("%s: failed allocating %s", __func__, IPMS_ZONE_NAME); 3269 /* NOTREACHED */ 3270 } 3271 zone_change(ipms_zone, Z_EXPAND, TRUE); 3272 3273 inms_size = sizeof (struct in_msource); 3274 inms_zone = zinit(inms_size, INMS_ZONE_MAX * inms_size, 3275 0, INMS_ZONE_NAME); 3276 if (inms_zone == NULL) { 3277 panic("%s: failed allocating %s", __func__, INMS_ZONE_NAME); 3278 /* NOTREACHED */ 3279 } 3280 zone_change(inms_zone, Z_EXPAND, TRUE); 3281} 3282 3283static struct in_multi * 3284in_multi_alloc(int how) 3285{ 3286 struct in_multi *inm; 3287 3288 inm = (how == M_WAITOK) ? zalloc(inm_zone) : zalloc_noblock(inm_zone); 3289 if (inm != NULL) { 3290 bzero(inm, inm_size); 3291 lck_mtx_init(&inm->inm_lock, in_multihead_lock_grp, 3292 in_multihead_lock_attr); 3293 inm->inm_debug |= IFD_ALLOC; 3294 if (inm_debug != 0) { 3295 inm->inm_debug |= IFD_DEBUG; 3296 inm->inm_trace = inm_trace; 3297 } 3298 } 3299 return (inm); 3300} 3301 3302static void 3303in_multi_free(struct in_multi *inm) 3304{ 3305 INM_LOCK(inm); 3306 if (inm->inm_debug & IFD_ATTACHED) { 3307 panic("%s: attached inm=%p is being freed", __func__, inm); 3308 /* NOTREACHED */ 3309 } else if (inm->inm_ifma != NULL) { 3310 panic("%s: ifma not NULL for inm=%p", __func__, inm); 3311 /* NOTREACHED */ 3312 } else if (!(inm->inm_debug & IFD_ALLOC)) { 3313 panic("%s: inm %p cannot be freed", __func__, inm); 3314 /* NOTREACHED */ 3315 } else if (inm->inm_refcount != 0) { 3316 panic("%s: non-zero refcount inm=%p", __func__, inm); 3317 /* NOTREACHED */ 3318 } else if (inm->inm_reqcnt != 0) { 3319 panic("%s: non-zero reqcnt inm=%p", __func__, inm); 3320 /* NOTREACHED */ 3321 } 3322 3323 /* Free any pending IGMPv3 state-change records */ 3324 IF_DRAIN(&inm->inm_scq); 3325 3326 inm->inm_debug &= ~IFD_ALLOC; 3327 if ((inm->inm_debug & (IFD_DEBUG | IFD_TRASHED)) == 3328 (IFD_DEBUG | IFD_TRASHED)) { 3329 lck_mtx_lock(&inm_trash_lock); 3330 TAILQ_REMOVE(&inm_trash_head, (struct in_multi_dbg *)inm, 3331 inm_trash_link); 3332 lck_mtx_unlock(&inm_trash_lock); 3333 inm->inm_debug &= ~IFD_TRASHED; 3334 } 3335 INM_UNLOCK(inm); 3336 3337 lck_mtx_destroy(&inm->inm_lock, in_multihead_lock_grp); 3338 zfree(inm_zone, inm); 3339} 3340 3341static void 3342in_multi_attach(struct in_multi *inm) 3343{ 3344 in_multihead_lock_assert(LCK_RW_ASSERT_EXCLUSIVE); 3345 INM_LOCK_ASSERT_HELD(inm); 3346 3347 if (inm->inm_debug & IFD_ATTACHED) { 3348 panic("%s: Attempt to attach an already attached inm=%p", 3349 __func__, inm); 3350 /* NOTREACHED */ 3351 } else if (inm->inm_debug & IFD_TRASHED) { 3352 panic("%s: Attempt to reattach a detached inm=%p", 3353 __func__, inm); 3354 /* NOTREACHED */ 3355 } 3356 3357 inm->inm_reqcnt++; 3358 VERIFY(inm->inm_reqcnt == 1); 3359 INM_ADDREF_LOCKED(inm); 3360 inm->inm_debug |= IFD_ATTACHED; 3361 /* 3362 * Reattach case: If debugging is enabled, take it 3363 * out of the trash list and clear IFD_TRASHED. 3364 */ 3365 if ((inm->inm_debug & (IFD_DEBUG | IFD_TRASHED)) == 3366 (IFD_DEBUG | IFD_TRASHED)) { 3367 /* Become a regular mutex, just in case */ 3368 INM_CONVERT_LOCK(inm); 3369 lck_mtx_lock(&inm_trash_lock); 3370 TAILQ_REMOVE(&inm_trash_head, (struct in_multi_dbg *)inm, 3371 inm_trash_link); 3372 lck_mtx_unlock(&inm_trash_lock); 3373 inm->inm_debug &= ~IFD_TRASHED; 3374 } 3375 3376 LIST_INSERT_HEAD(&in_multihead, inm, inm_link); 3377} 3378 3379int 3380in_multi_detach(struct in_multi *inm) 3381{ 3382 in_multihead_lock_assert(LCK_RW_ASSERT_EXCLUSIVE); 3383 INM_LOCK_ASSERT_HELD(inm); 3384 3385 if (inm->inm_reqcnt == 0) { 3386 panic("%s: inm=%p negative reqcnt", __func__, inm); 3387 /* NOTREACHED */ 3388 } 3389 3390 --inm->inm_reqcnt; 3391 if (inm->inm_reqcnt > 0) 3392 return (0); 3393 3394 if (!(inm->inm_debug & IFD_ATTACHED)) { 3395 panic("%s: Attempt to detach an unattached record inm=%p", 3396 __func__, inm); 3397 /* NOTREACHED */ 3398 } else if (inm->inm_debug & IFD_TRASHED) { 3399 panic("%s: inm %p is already in trash list", __func__, inm); 3400 /* NOTREACHED */ 3401 } 3402 3403 /* 3404 * NOTE: Caller calls IFMA_REMREF 3405 */ 3406 inm->inm_debug &= ~IFD_ATTACHED; 3407 LIST_REMOVE(inm, inm_link); 3408 3409 if (inm->inm_debug & IFD_DEBUG) { 3410 /* Become a regular mutex, just in case */ 3411 INM_CONVERT_LOCK(inm); 3412 lck_mtx_lock(&inm_trash_lock); 3413 TAILQ_INSERT_TAIL(&inm_trash_head, 3414 (struct in_multi_dbg *)inm, inm_trash_link); 3415 lck_mtx_unlock(&inm_trash_lock); 3416 inm->inm_debug |= IFD_TRASHED; 3417 } 3418 3419 return (1); 3420} 3421 3422void 3423inm_addref(struct in_multi *inm, int locked) 3424{ 3425 if (!locked) 3426 INM_LOCK_SPIN(inm); 3427 else 3428 INM_LOCK_ASSERT_HELD(inm); 3429 3430 if (++inm->inm_refcount == 0) { 3431 panic("%s: inm=%p wraparound refcnt", __func__, inm); 3432 /* NOTREACHED */ 3433 } else if (inm->inm_trace != NULL) { 3434 (*inm->inm_trace)(inm, TRUE); 3435 } 3436 if (!locked) 3437 INM_UNLOCK(inm); 3438} 3439 3440void 3441inm_remref(struct in_multi *inm, int locked) 3442{ 3443 struct ifmultiaddr *ifma; 3444 struct igmp_ifinfo *igi; 3445 3446 if (!locked) 3447 INM_LOCK_SPIN(inm); 3448 else 3449 INM_LOCK_ASSERT_HELD(inm); 3450 3451 if (inm->inm_refcount == 0 || (inm->inm_refcount == 1 && locked)) { 3452 panic("%s: inm=%p negative/missing refcnt", __func__, inm); 3453 /* NOTREACHED */ 3454 } else if (inm->inm_trace != NULL) { 3455 (*inm->inm_trace)(inm, FALSE); 3456 } 3457 3458 --inm->inm_refcount; 3459 if (inm->inm_refcount > 0) { 3460 if (!locked) 3461 INM_UNLOCK(inm); 3462 return; 3463 } 3464 3465 /* 3466 * Synchronization with in_getmulti(). In the event the inm has been 3467 * detached, the underlying ifma would still be in the if_multiaddrs 3468 * list, and thus can be looked up via if_addmulti(). At that point, 3469 * the only way to find this inm is via ifma_protospec. To avoid 3470 * race conditions between the last inm_remref() of that inm and its 3471 * use via ifma_protospec, in_multihead lock is used for serialization. 3472 * In order to avoid violating the lock order, we must drop inm_lock 3473 * before acquiring in_multihead lock. To prevent the inm from being 3474 * freed prematurely, we hold an extra reference. 3475 */ 3476 ++inm->inm_refcount; 3477 INM_UNLOCK(inm); 3478 in_multihead_lock_shared(); 3479 INM_LOCK_SPIN(inm); 3480 --inm->inm_refcount; 3481 if (inm->inm_refcount > 0) { 3482 /* We've lost the race, so abort since inm is still in use */ 3483 INM_UNLOCK(inm); 3484 in_multihead_lock_done(); 3485 /* If it was locked, return it as such */ 3486 if (locked) 3487 INM_LOCK(inm); 3488 return; 3489 } 3490 inm_purge(inm); 3491 ifma = inm->inm_ifma; 3492 inm->inm_ifma = NULL; 3493 inm->inm_ifp = NULL; 3494 igi = inm->inm_igi; 3495 inm->inm_igi = NULL; 3496 INM_UNLOCK(inm); 3497 IFMA_LOCK_SPIN(ifma); 3498 ifma->ifma_protospec = NULL; 3499 IFMA_UNLOCK(ifma); 3500 in_multihead_lock_done(); 3501 3502 in_multi_free(inm); 3503 if_delmulti_ifma(ifma); 3504 /* Release reference held to the underlying ifmultiaddr */ 3505 IFMA_REMREF(ifma); 3506 3507 if (igi != NULL) 3508 IGI_REMREF(igi); 3509} 3510 3511static void 3512inm_trace(struct in_multi *inm, int refhold) 3513{ 3514 struct in_multi_dbg *inm_dbg = (struct in_multi_dbg *)inm; 3515 ctrace_t *tr; 3516 u_int32_t idx; 3517 u_int16_t *cnt; 3518 3519 if (!(inm->inm_debug & IFD_DEBUG)) { 3520 panic("%s: inm %p has no debug structure", __func__, inm); 3521 /* NOTREACHED */ 3522 } 3523 if (refhold) { 3524 cnt = &inm_dbg->inm_refhold_cnt; 3525 tr = inm_dbg->inm_refhold; 3526 } else { 3527 cnt = &inm_dbg->inm_refrele_cnt; 3528 tr = inm_dbg->inm_refrele; 3529 } 3530 3531 idx = atomic_add_16_ov(cnt, 1) % INM_TRACE_HIST_SIZE; 3532 ctrace_record(&tr[idx]); 3533} 3534 3535void 3536in_multihead_lock_exclusive(void) 3537{ 3538 lck_rw_lock_exclusive(&in_multihead_lock); 3539} 3540 3541void 3542in_multihead_lock_shared(void) 3543{ 3544 lck_rw_lock_shared(&in_multihead_lock); 3545} 3546 3547void 3548in_multihead_lock_assert(int what) 3549{ 3550 lck_rw_assert(&in_multihead_lock, what); 3551} 3552 3553void 3554in_multihead_lock_done(void) 3555{ 3556 lck_rw_done(&in_multihead_lock); 3557} 3558 3559static struct ip_msource * 3560ipms_alloc(int how) 3561{ 3562 struct ip_msource *ims; 3563 3564 ims = (how == M_WAITOK) ? zalloc(ipms_zone) : zalloc_noblock(ipms_zone); 3565 if (ims != NULL) 3566 bzero(ims, ipms_size); 3567 3568 return (ims); 3569} 3570 3571static void 3572ipms_free(struct ip_msource *ims) 3573{ 3574 zfree(ipms_zone, ims); 3575} 3576 3577static struct in_msource * 3578inms_alloc(int how) 3579{ 3580 struct in_msource *inms; 3581 3582 inms = (how == M_WAITOK) ? zalloc(inms_zone) : 3583 zalloc_noblock(inms_zone); 3584 if (inms != NULL) 3585 bzero(inms, inms_size); 3586 3587 return (inms); 3588} 3589 3590static void 3591inms_free(struct in_msource *inms) 3592{ 3593 zfree(inms_zone, inms); 3594} 3595 3596#ifdef IGMP_DEBUG 3597 3598static const char *inm_modestrs[] = { "un\n", "in", "ex" }; 3599 3600static const char * 3601inm_mode_str(const int mode) 3602{ 3603 if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) 3604 return (inm_modestrs[mode]); 3605 return ("??"); 3606} 3607 3608static const char *inm_statestrs[] = { 3609 "not-member\n", 3610 "silent\n", 3611 "reporting\n", 3612 "idle\n", 3613 "lazy\n", 3614 "sleeping\n", 3615 "awakening\n", 3616 "query-pending\n", 3617 "sg-query-pending\n", 3618 "leaving" 3619}; 3620 3621static const char * 3622inm_state_str(const int state) 3623{ 3624 if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER) 3625 return (inm_statestrs[state]); 3626 return ("??"); 3627} 3628 3629/* 3630 * Dump an in_multi structure to the console. 3631 */ 3632void 3633inm_print(const struct in_multi *inm) 3634{ 3635 int t; 3636 char buf[MAX_IPv4_STR_LEN]; 3637 3638 INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi *, inm)); 3639 3640 if (igmp_debug == 0) 3641 return; 3642 3643 inet_ntop(AF_INET, &inm->inm_addr, buf, sizeof(buf)); 3644 printf("%s: --- begin inm 0x%llx ---\n", __func__, 3645 (uint64_t)VM_KERNEL_ADDRPERM(inm)); 3646 printf("addr %s ifp 0x%llx(%s) ifma 0x%llx\n", 3647 buf, 3648 (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_ifp), 3649 if_name(inm->inm_ifp), 3650 (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_ifma)); 3651 printf("timer %u state %s refcount %u scq.len %u\n", 3652 inm->inm_timer, 3653 inm_state_str(inm->inm_state), 3654 inm->inm_refcount, 3655 inm->inm_scq.ifq_len); 3656 printf("igi 0x%llx nsrc %lu sctimer %u scrv %u\n", 3657 (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_igi), 3658 inm->inm_nsrc, 3659 inm->inm_sctimer, 3660 inm->inm_scrv); 3661 for (t = 0; t < 2; t++) { 3662 printf("t%d: fmode %s asm %u ex %u in %u rec %u\n", t, 3663 inm_mode_str(inm->inm_st[t].iss_fmode), 3664 inm->inm_st[t].iss_asm, 3665 inm->inm_st[t].iss_ex, 3666 inm->inm_st[t].iss_in, 3667 inm->inm_st[t].iss_rec); 3668 } 3669 printf("%s: --- end inm 0x%llx ---\n", __func__, 3670 (uint64_t)VM_KERNEL_ADDRPERM(inm)); 3671} 3672 3673#else 3674 3675void 3676inm_print(__unused const struct in_multi *inm) 3677{ 3678 3679} 3680 3681#endif 3682