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#ifdef MROUTING 1898 case IP_MULTICAST_VIF: 1899 if (imo != NULL) { 1900 IMO_LOCK(imo); 1901 optval = imo->imo_multicast_vif; 1902 IMO_UNLOCK(imo); 1903 } else 1904 optval = -1; 1905 error = sooptcopyout(sopt, &optval, sizeof(int)); 1906 break; 1907#endif /* MROUTING */ 1908 1909 case IP_MULTICAST_IF: 1910 memset(&mreqn, 0, sizeof(struct ip_mreqn)); 1911 if (imo != NULL) { 1912 IMO_LOCK(imo); 1913 ifp = imo->imo_multicast_ifp; 1914 if (!in_nullhost(imo->imo_multicast_addr)) { 1915 mreqn.imr_address = imo->imo_multicast_addr; 1916 } else if (ifp != NULL) { 1917 mreqn.imr_ifindex = ifp->if_index; 1918 IFP_TO_IA(ifp, ia); 1919 if (ia != NULL) { 1920 IFA_LOCK_SPIN(&ia->ia_ifa); 1921 mreqn.imr_address = 1922 IA_SIN(ia)->sin_addr; 1923 IFA_UNLOCK(&ia->ia_ifa); 1924 IFA_REMREF(&ia->ia_ifa); 1925 } 1926 } 1927 IMO_UNLOCK(imo); 1928 } 1929 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) { 1930 error = sooptcopyout(sopt, &mreqn, 1931 sizeof(struct ip_mreqn)); 1932 } else { 1933 error = sooptcopyout(sopt, &mreqn.imr_address, 1934 sizeof(struct in_addr)); 1935 } 1936 break; 1937 1938 case IP_MULTICAST_IFINDEX: 1939 if (imo != NULL) 1940 IMO_LOCK(imo); 1941 if (imo == NULL || imo->imo_multicast_ifp == NULL) { 1942 ifindex = 0; 1943 } else { 1944 ifindex = imo->imo_multicast_ifp->if_index; 1945 } 1946 if (imo != NULL) 1947 IMO_UNLOCK(imo); 1948 error = sooptcopyout(sopt, &ifindex, sizeof (ifindex)); 1949 break; 1950 1951 case IP_MULTICAST_TTL: 1952 if (imo == NULL) 1953 optval = coptval = IP_DEFAULT_MULTICAST_TTL; 1954 else { 1955 IMO_LOCK(imo); 1956 optval = coptval = imo->imo_multicast_ttl; 1957 IMO_UNLOCK(imo); 1958 } 1959 if (sopt->sopt_valsize == sizeof(u_char)) 1960 error = sooptcopyout(sopt, &coptval, sizeof(u_char)); 1961 else 1962 error = sooptcopyout(sopt, &optval, sizeof(int)); 1963 break; 1964 1965 case IP_MULTICAST_LOOP: 1966 if (imo == 0) 1967 optval = coptval = IP_DEFAULT_MULTICAST_LOOP; 1968 else { 1969 IMO_LOCK(imo); 1970 optval = coptval = imo->imo_multicast_loop; 1971 IMO_UNLOCK(imo); 1972 } 1973 if (sopt->sopt_valsize == sizeof(u_char)) 1974 error = sooptcopyout(sopt, &coptval, sizeof(u_char)); 1975 else 1976 error = sooptcopyout(sopt, &optval, sizeof(int)); 1977 break; 1978 1979 case IP_MSFILTER: 1980 if (imo == NULL) { 1981 error = EADDRNOTAVAIL; 1982 } else { 1983 error = inp_get_source_filters(inp, sopt); 1984 } 1985 break; 1986 1987 default: 1988 error = ENOPROTOOPT; 1989 break; 1990 } 1991 1992 return (error); 1993} 1994 1995/* 1996 * Look up the ifnet to use for a multicast group membership, 1997 * given the IPv4 address of an interface, and the IPv4 group address. 1998 * 1999 * This routine exists to support legacy multicast applications 2000 * which do not understand that multicast memberships are scoped to 2001 * specific physical links in the networking stack, or which need 2002 * to join link-scope groups before IPv4 addresses are configured. 2003 * 2004 * If inp is non-NULL and is bound to an interface, use this socket's 2005 * inp_boundif for any required routing table lookup. 2006 * 2007 * If the route lookup fails, attempt to use the first non-loopback 2008 * interface with multicast capability in the system as a 2009 * last resort. The legacy IPv4 ASM API requires that we do 2010 * this in order to allow groups to be joined when the routing 2011 * table has not yet been populated during boot. 2012 * 2013 * Returns NULL if no ifp could be found. 2014 * 2015 */ 2016static struct ifnet * 2017inp_lookup_mcast_ifp(const struct inpcb *inp, 2018 const struct sockaddr_in *gsin, const struct in_addr ina) 2019{ 2020 struct ifnet *ifp; 2021 unsigned int ifindex = 0; 2022 2023 VERIFY(gsin->sin_family == AF_INET); 2024 VERIFY(IN_MULTICAST(ntohl(gsin->sin_addr.s_addr))); 2025 2026 ifp = NULL; 2027 if (!in_nullhost(ina)) { 2028 struct in_addr new_ina; 2029 memcpy(&new_ina, &ina, sizeof(struct in_addr)); 2030 ifp = ip_multicast_if(&new_ina, &ifindex); 2031 } else { 2032 struct route ro; 2033 unsigned int ifscope = IFSCOPE_NONE; 2034 2035 if (inp != NULL && (inp->inp_flags & INP_BOUND_IF)) 2036 ifscope = inp->inp_boundifp->if_index; 2037 2038 bzero(&ro, sizeof (ro)); 2039 memcpy(&ro.ro_dst, gsin, sizeof(struct sockaddr_in)); 2040 rtalloc_scoped_ign(&ro, 0, ifscope); 2041 if (ro.ro_rt != NULL) { 2042 ifp = ro.ro_rt->rt_ifp; 2043 VERIFY(ifp != NULL); 2044 } else { 2045 struct in_ifaddr *ia; 2046 struct ifnet *mifp; 2047 2048 mifp = NULL; 2049 lck_rw_lock_shared(in_ifaddr_rwlock); 2050 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 2051 IFA_LOCK_SPIN(&ia->ia_ifa); 2052 mifp = ia->ia_ifp; 2053 IFA_UNLOCK(&ia->ia_ifa); 2054 if (!(mifp->if_flags & IFF_LOOPBACK) && 2055 (mifp->if_flags & IFF_MULTICAST)) { 2056 ifp = mifp; 2057 break; 2058 } 2059 } 2060 lck_rw_done(in_ifaddr_rwlock); 2061 } 2062 ROUTE_RELEASE(&ro); 2063 } 2064 2065 return (ifp); 2066} 2067 2068/* 2069 * Join an IPv4 multicast group, possibly with a source. 2070 * 2071 * NB: sopt->sopt_val might point to the kernel address space. This means that 2072 * we were called by the IPv6 stack due to the presence of an IPv6 v4 mapped 2073 * address. In this scenario, sopt_p points to kernproc and sooptcopyin() will 2074 * just issue an in-kernel memcpy. 2075 */ 2076int 2077inp_join_group(struct inpcb *inp, struct sockopt *sopt) 2078{ 2079 struct group_source_req gsr; 2080 sockunion_t *gsa, *ssa; 2081 struct ifnet *ifp; 2082 struct in_mfilter *imf; 2083 struct ip_moptions *imo; 2084 struct in_multi *inm = NULL; 2085 struct in_msource *lims; 2086 size_t idx; 2087 int error, is_new; 2088 struct igmp_tparams itp; 2089 2090 bzero(&itp, sizeof (itp)); 2091 ifp = NULL; 2092 imf = NULL; 2093 error = 0; 2094 is_new = 0; 2095 2096 memset(&gsr, 0, sizeof(struct group_source_req)); 2097 gsa = (sockunion_t *)&gsr.gsr_group; 2098 gsa->ss.ss_family = AF_UNSPEC; 2099 ssa = (sockunion_t *)&gsr.gsr_source; 2100 ssa->ss.ss_family = AF_UNSPEC; 2101 2102 switch (sopt->sopt_name) { 2103 case IP_ADD_MEMBERSHIP: 2104 case IP_ADD_SOURCE_MEMBERSHIP: { 2105 struct ip_mreq_source mreqs; 2106 2107 if (sopt->sopt_name == IP_ADD_MEMBERSHIP) { 2108 error = sooptcopyin(sopt, &mreqs, 2109 sizeof(struct ip_mreq), 2110 sizeof(struct ip_mreq)); 2111 /* 2112 * Do argument switcharoo from ip_mreq into 2113 * ip_mreq_source to avoid using two instances. 2114 */ 2115 mreqs.imr_interface = mreqs.imr_sourceaddr; 2116 mreqs.imr_sourceaddr.s_addr = INADDR_ANY; 2117 } else if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) { 2118 error = sooptcopyin(sopt, &mreqs, 2119 sizeof(struct ip_mreq_source), 2120 sizeof(struct ip_mreq_source)); 2121 } 2122 if (error) { 2123 IGMP_PRINTF(("%s: error copyin IP_ADD_MEMBERSHIP/" 2124 "IP_ADD_SOURCE_MEMBERSHIP %d err=%d\n", 2125 __func__, sopt->sopt_name, error)); 2126 return (error); 2127 } 2128 2129 gsa->sin.sin_family = AF_INET; 2130 gsa->sin.sin_len = sizeof(struct sockaddr_in); 2131 gsa->sin.sin_addr = mreqs.imr_multiaddr; 2132 2133 if (sopt->sopt_name == IP_ADD_SOURCE_MEMBERSHIP) { 2134 ssa->sin.sin_family = AF_INET; 2135 ssa->sin.sin_len = sizeof(struct sockaddr_in); 2136 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 2137 } 2138 2139 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2140 return (EINVAL); 2141 2142 ifp = inp_lookup_mcast_ifp(inp, &gsa->sin, 2143 mreqs.imr_interface); 2144 IGMP_INET_PRINTF(mreqs.imr_interface, 2145 ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, 2146 _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); 2147 break; 2148 } 2149 2150 case MCAST_JOIN_GROUP: 2151 case MCAST_JOIN_SOURCE_GROUP: 2152 if (sopt->sopt_name == MCAST_JOIN_GROUP) { 2153 error = sooptcopyin(sopt, &gsr, 2154 sizeof(struct group_req), 2155 sizeof(struct group_req)); 2156 } else if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) { 2157 error = sooptcopyin(sopt, &gsr, 2158 sizeof(struct group_source_req), 2159 sizeof(struct group_source_req)); 2160 } 2161 if (error) 2162 return (error); 2163 2164 if (gsa->sin.sin_family != AF_INET || 2165 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 2166 return (EINVAL); 2167 2168 /* 2169 * Overwrite the port field if present, as the sockaddr 2170 * being copied in may be matched with a binary comparison. 2171 */ 2172 gsa->sin.sin_port = 0; 2173 if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) { 2174 if (ssa->sin.sin_family != AF_INET || 2175 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 2176 return (EINVAL); 2177 ssa->sin.sin_port = 0; 2178 } 2179 2180 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2181 return (EINVAL); 2182 2183 ifnet_head_lock_shared(); 2184 if (gsr.gsr_interface == 0 || 2185 (u_int)if_index < gsr.gsr_interface) { 2186 ifnet_head_done(); 2187 return (EADDRNOTAVAIL); 2188 } 2189 ifp = ifindex2ifnet[gsr.gsr_interface]; 2190 ifnet_head_done(); 2191 2192 break; 2193 2194 default: 2195 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 2196 __func__, sopt->sopt_name)); 2197 return (EOPNOTSUPP); 2198 break; 2199 } 2200 2201 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) 2202 return (EADDRNOTAVAIL); 2203 2204 imo = inp_findmoptions(inp); 2205 if (imo == NULL) 2206 return (ENOMEM); 2207 2208 IMO_LOCK(imo); 2209 idx = imo_match_group(imo, ifp, &gsa->sa); 2210 if (idx == (size_t)-1) { 2211 is_new = 1; 2212 } else { 2213 inm = imo->imo_membership[idx]; 2214 imf = &imo->imo_mfilters[idx]; 2215 if (ssa->ss.ss_family != AF_UNSPEC) { 2216 /* 2217 * MCAST_JOIN_SOURCE_GROUP on an exclusive membership 2218 * is an error. On an existing inclusive membership, 2219 * it just adds the source to the filter list. 2220 */ 2221 if (imf->imf_st[1] != MCAST_INCLUDE) { 2222 error = EINVAL; 2223 goto out_imo_locked; 2224 } 2225 /* 2226 * Throw out duplicates. 2227 * 2228 * XXX FIXME: This makes a naive assumption that 2229 * even if entries exist for *ssa in this imf, 2230 * they will be rejected as dupes, even if they 2231 * are not valid in the current mode (in-mode). 2232 * 2233 * in_msource is transactioned just as for anything 2234 * else in SSM -- but note naive use of inm_graft() 2235 * below for allocating new filter entries. 2236 * 2237 * This is only an issue if someone mixes the 2238 * full-state SSM API with the delta-based API, 2239 * which is discouraged in the relevant RFCs. 2240 */ 2241 lims = imo_match_source(imo, idx, &ssa->sa); 2242 if (lims != NULL /*&& 2243 lims->imsl_st[1] == MCAST_INCLUDE*/) { 2244 error = EADDRNOTAVAIL; 2245 goto out_imo_locked; 2246 } 2247 } else { 2248 /* 2249 * MCAST_JOIN_GROUP on an existing exclusive 2250 * membership is an error; return EADDRINUSE 2251 * to preserve 4.4BSD API idempotence, and 2252 * avoid tedious detour to code below. 2253 * NOTE: This is bending RFC 3678 a bit. 2254 * 2255 * On an existing inclusive membership, this is also 2256 * an error; if you want to change filter mode, 2257 * you must use the userland API setsourcefilter(). 2258 * XXX We don't reject this for imf in UNDEFINED 2259 * state at t1, because allocation of a filter 2260 * is atomic with allocation of a membership. 2261 */ 2262 error = EINVAL; 2263 /* See comments above for EADDRINUSE */ 2264 if (imf->imf_st[1] == MCAST_EXCLUDE) 2265 error = EADDRINUSE; 2266 goto out_imo_locked; 2267 } 2268 } 2269 2270 /* 2271 * Begin state merge transaction at socket layer. 2272 */ 2273 2274 if (is_new) { 2275 if (imo->imo_num_memberships == imo->imo_max_memberships) { 2276 error = imo_grow(imo, 0); 2277 if (error) 2278 goto out_imo_locked; 2279 } 2280 /* 2281 * Allocate the new slot upfront so we can deal with 2282 * grafting the new source filter in same code path 2283 * as for join-source on existing membership. 2284 */ 2285 idx = imo->imo_num_memberships; 2286 imo->imo_membership[idx] = NULL; 2287 imo->imo_num_memberships++; 2288 VERIFY(imo->imo_mfilters != NULL); 2289 imf = &imo->imo_mfilters[idx]; 2290 VERIFY(RB_EMPTY(&imf->imf_sources)); 2291 } 2292 2293 /* 2294 * Graft new source into filter list for this inpcb's 2295 * membership of the group. The in_multi may not have 2296 * been allocated yet if this is a new membership, however, 2297 * the in_mfilter slot will be allocated and must be initialized. 2298 */ 2299 if (ssa->ss.ss_family != AF_UNSPEC) { 2300 /* Membership starts in IN mode */ 2301 if (is_new) { 2302 IGMP_PRINTF(("%s: new join w/source\n", __func__)); 2303 imf_init(imf, MCAST_UNDEFINED, MCAST_INCLUDE); 2304 } else { 2305 IGMP_PRINTF(("%s: %s source\n", __func__, "allow")); 2306 } 2307 lims = imf_graft(imf, MCAST_INCLUDE, &ssa->sin); 2308 if (lims == NULL) { 2309 IGMP_PRINTF(("%s: merge imf state failed\n", 2310 __func__)); 2311 error = ENOMEM; 2312 goto out_imo_free; 2313 } 2314 } else { 2315 /* No address specified; Membership starts in EX mode */ 2316 if (is_new) { 2317 IGMP_PRINTF(("%s: new join w/o source\n", __func__)); 2318 imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); 2319 } 2320 } 2321 2322 /* 2323 * Begin state merge transaction at IGMP layer. 2324 */ 2325 2326 if (is_new) { 2327 VERIFY(inm == NULL); 2328 error = in_joingroup(ifp, &gsa->sin.sin_addr, imf, &inm); 2329 VERIFY(inm != NULL || error != 0); 2330 if (error) 2331 goto out_imo_free; 2332 imo->imo_membership[idx] = inm; /* from in_joingroup() */ 2333 } else { 2334 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 2335 INM_LOCK(inm); 2336 error = inm_merge(inm, imf); 2337 if (error) { 2338 IGMP_PRINTF(("%s: failed to merge inm state\n", 2339 __func__)); 2340 INM_UNLOCK(inm); 2341 goto out_imf_rollback; 2342 } 2343 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 2344 error = igmp_change_state(inm, &itp); 2345 INM_UNLOCK(inm); 2346 if (error) { 2347 IGMP_PRINTF(("%s: failed igmp downcall\n", 2348 __func__)); 2349 goto out_imf_rollback; 2350 } 2351 } 2352 2353out_imf_rollback: 2354 if (error) { 2355 imf_rollback(imf); 2356 if (is_new) 2357 imf_purge(imf); 2358 else 2359 imf_reap(imf); 2360 } else { 2361 imf_commit(imf); 2362 } 2363 2364out_imo_free: 2365 if (error && is_new) { 2366 VERIFY(inm == NULL); 2367 imo->imo_membership[idx] = NULL; 2368 --imo->imo_num_memberships; 2369 } 2370 2371out_imo_locked: 2372 IMO_UNLOCK(imo); 2373 IMO_REMREF(imo); /* from inp_findmoptions() */ 2374 2375 /* schedule timer now that we've dropped the lock(s) */ 2376 igmp_set_timeout(&itp); 2377 2378 return (error); 2379} 2380 2381/* 2382 * Leave an IPv4 multicast group on an inpcb, possibly with a source. 2383 * 2384 * NB: sopt->sopt_val might point to the kernel address space. Refer to the 2385 * block comment on top of inp_join_group() for more information. 2386 */ 2387int 2388inp_leave_group(struct inpcb *inp, struct sockopt *sopt) 2389{ 2390 struct group_source_req gsr; 2391 struct ip_mreq_source mreqs; 2392 sockunion_t *gsa, *ssa; 2393 struct ifnet *ifp; 2394 struct in_mfilter *imf; 2395 struct ip_moptions *imo; 2396 struct in_msource *ims; 2397 struct in_multi *inm = NULL; 2398 size_t idx; 2399 int error, is_final; 2400 unsigned int ifindex = 0; 2401 struct igmp_tparams itp; 2402 2403 bzero(&itp, sizeof (itp)); 2404 ifp = NULL; 2405 error = 0; 2406 is_final = 1; 2407 2408 memset(&gsr, 0, sizeof(struct group_source_req)); 2409 gsa = (sockunion_t *)&gsr.gsr_group; 2410 gsa->ss.ss_family = AF_UNSPEC; 2411 ssa = (sockunion_t *)&gsr.gsr_source; 2412 ssa->ss.ss_family = AF_UNSPEC; 2413 2414 switch (sopt->sopt_name) { 2415 case IP_DROP_MEMBERSHIP: 2416 case IP_DROP_SOURCE_MEMBERSHIP: 2417 if (sopt->sopt_name == IP_DROP_MEMBERSHIP) { 2418 error = sooptcopyin(sopt, &mreqs, 2419 sizeof(struct ip_mreq), 2420 sizeof(struct ip_mreq)); 2421 /* 2422 * Swap interface and sourceaddr arguments, 2423 * as ip_mreq and ip_mreq_source are laid 2424 * out differently. 2425 */ 2426 mreqs.imr_interface = mreqs.imr_sourceaddr; 2427 mreqs.imr_sourceaddr.s_addr = INADDR_ANY; 2428 } else if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) { 2429 error = sooptcopyin(sopt, &mreqs, 2430 sizeof(struct ip_mreq_source), 2431 sizeof(struct ip_mreq_source)); 2432 } 2433 if (error) 2434 return (error); 2435 2436 gsa->sin.sin_family = AF_INET; 2437 gsa->sin.sin_len = sizeof(struct sockaddr_in); 2438 gsa->sin.sin_addr = mreqs.imr_multiaddr; 2439 2440 if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) { 2441 ssa->sin.sin_family = AF_INET; 2442 ssa->sin.sin_len = sizeof(struct sockaddr_in); 2443 ssa->sin.sin_addr = mreqs.imr_sourceaddr; 2444 } 2445 /* 2446 * Attempt to look up hinted ifp from interface address. 2447 * Fallthrough with null ifp iff lookup fails, to 2448 * preserve 4.4BSD mcast API idempotence. 2449 * XXX NOTE WELL: The RFC 3678 API is preferred because 2450 * using an IPv4 address as a key is racy. 2451 */ 2452 if (!in_nullhost(mreqs.imr_interface)) 2453 ifp = ip_multicast_if(&mreqs.imr_interface, &ifindex); 2454 2455 IGMP_INET_PRINTF(mreqs.imr_interface, 2456 ("%s: imr_interface = %s, ifp = 0x%llx\n", __func__, 2457 _igmp_inet_buf, (uint64_t)VM_KERNEL_ADDRPERM(ifp))); 2458 2459 break; 2460 2461 case MCAST_LEAVE_GROUP: 2462 case MCAST_LEAVE_SOURCE_GROUP: 2463 if (sopt->sopt_name == MCAST_LEAVE_GROUP) { 2464 error = sooptcopyin(sopt, &gsr, 2465 sizeof(struct group_req), 2466 sizeof(struct group_req)); 2467 } else if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) { 2468 error = sooptcopyin(sopt, &gsr, 2469 sizeof(struct group_source_req), 2470 sizeof(struct group_source_req)); 2471 } 2472 if (error) 2473 return (error); 2474 2475 if (gsa->sin.sin_family != AF_INET || 2476 gsa->sin.sin_len != sizeof(struct sockaddr_in)) 2477 return (EINVAL); 2478 2479 if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) { 2480 if (ssa->sin.sin_family != AF_INET || 2481 ssa->sin.sin_len != sizeof(struct sockaddr_in)) 2482 return (EINVAL); 2483 } 2484 2485 ifnet_head_lock_shared(); 2486 if (gsr.gsr_interface == 0 || 2487 (u_int)if_index < gsr.gsr_interface) { 2488 ifnet_head_done(); 2489 return (EADDRNOTAVAIL); 2490 } 2491 2492 ifp = ifindex2ifnet[gsr.gsr_interface]; 2493 ifnet_head_done(); 2494 break; 2495 2496 default: 2497 IGMP_PRINTF(("%s: unknown sopt_name %d\n", 2498 __func__, sopt->sopt_name)); 2499 return (EOPNOTSUPP); 2500 break; 2501 } 2502 2503 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2504 return (EINVAL); 2505 2506 /* 2507 * Find the membership in the membership array. 2508 */ 2509 imo = inp_findmoptions(inp); 2510 if (imo == NULL) 2511 return (ENOMEM); 2512 2513 IMO_LOCK(imo); 2514 idx = imo_match_group(imo, ifp, &gsa->sa); 2515 if (idx == (size_t)-1) { 2516 error = EADDRNOTAVAIL; 2517 goto out_locked; 2518 } 2519 inm = imo->imo_membership[idx]; 2520 imf = &imo->imo_mfilters[idx]; 2521 2522 if (ssa->ss.ss_family != AF_UNSPEC) { 2523 IGMP_PRINTF(("%s: opt=%d is_final=0\n", __func__, 2524 sopt->sopt_name)); 2525 is_final = 0; 2526 } 2527 2528 /* 2529 * Begin state merge transaction at socket layer. 2530 */ 2531 2532 /* 2533 * If we were instructed only to leave a given source, do so. 2534 * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships. 2535 */ 2536 if (is_final) { 2537 imf_leave(imf); 2538 } else { 2539 if (imf->imf_st[0] == MCAST_EXCLUDE) { 2540 error = EADDRNOTAVAIL; 2541 goto out_locked; 2542 } 2543 ims = imo_match_source(imo, idx, &ssa->sa); 2544 if (ims == NULL) { 2545 IGMP_INET_PRINTF(ssa->sin.sin_addr, 2546 ("%s: source %s %spresent\n", __func__, 2547 _igmp_inet_buf, "not ")); 2548 error = EADDRNOTAVAIL; 2549 goto out_locked; 2550 } 2551 IGMP_PRINTF(("%s: %s source\n", __func__, "block")); 2552 error = imf_prune(imf, &ssa->sin); 2553 if (error) { 2554 IGMP_PRINTF(("%s: merge imf state failed\n", 2555 __func__)); 2556 goto out_locked; 2557 } 2558 } 2559 2560 /* 2561 * Begin state merge transaction at IGMP layer. 2562 */ 2563 2564 if (is_final) { 2565 /* 2566 * Give up the multicast address record to which 2567 * the membership points. Reference held in imo 2568 * will be released below. 2569 */ 2570 (void) in_leavegroup(inm, imf); 2571 } else { 2572 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 2573 INM_LOCK(inm); 2574 error = inm_merge(inm, imf); 2575 if (error) { 2576 IGMP_PRINTF(("%s: failed to merge inm state\n", 2577 __func__)); 2578 INM_UNLOCK(inm); 2579 goto out_imf_rollback; 2580 } 2581 2582 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 2583 error = igmp_change_state(inm, &itp); 2584 if (error) { 2585 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); 2586 } 2587 INM_UNLOCK(inm); 2588 } 2589 2590out_imf_rollback: 2591 if (error) 2592 imf_rollback(imf); 2593 else 2594 imf_commit(imf); 2595 2596 imf_reap(imf); 2597 2598 if (is_final) { 2599 /* Remove the gap in the membership and filter array. */ 2600 VERIFY(inm == imo->imo_membership[idx]); 2601 imo->imo_membership[idx] = NULL; 2602 INM_REMREF(inm); 2603 for (++idx; idx < imo->imo_num_memberships; ++idx) { 2604 imo->imo_membership[idx-1] = imo->imo_membership[idx]; 2605 imo->imo_mfilters[idx-1] = imo->imo_mfilters[idx]; 2606 } 2607 imo->imo_num_memberships--; 2608 } 2609 2610out_locked: 2611 IMO_UNLOCK(imo); 2612 IMO_REMREF(imo); /* from inp_findmoptions() */ 2613 2614 /* schedule timer now that we've dropped the lock(s) */ 2615 igmp_set_timeout(&itp); 2616 2617 return (error); 2618} 2619 2620/* 2621 * Select the interface for transmitting IPv4 multicast datagrams. 2622 * 2623 * Either an instance of struct in_addr or an instance of struct ip_mreqn 2624 * may be passed to this socket option. An address of INADDR_ANY or an 2625 * interface index of 0 is used to remove a previous selection. 2626 * When no interface is selected, one is chosen for every send. 2627 */ 2628static int 2629inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) 2630{ 2631 struct in_addr addr; 2632 struct ip_mreqn mreqn; 2633 struct ifnet *ifp; 2634 struct ip_moptions *imo; 2635 int error = 0 ; 2636 unsigned int ifindex = 0; 2637 2638 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) { 2639 /* 2640 * An interface index was specified using the 2641 * Linux-derived ip_mreqn structure. 2642 */ 2643 error = sooptcopyin(sopt, &mreqn, sizeof(struct ip_mreqn), 2644 sizeof(struct ip_mreqn)); 2645 if (error) 2646 return (error); 2647 2648 ifnet_head_lock_shared(); 2649 if (mreqn.imr_ifindex < 0 || if_index < mreqn.imr_ifindex) { 2650 ifnet_head_done(); 2651 return (EINVAL); 2652 } 2653 2654 if (mreqn.imr_ifindex == 0) { 2655 ifp = NULL; 2656 } else { 2657 ifp = ifindex2ifnet[mreqn.imr_ifindex]; 2658 if (ifp == NULL) { 2659 ifnet_head_done(); 2660 return (EADDRNOTAVAIL); 2661 } 2662 } 2663 ifnet_head_done(); 2664 } else { 2665 /* 2666 * An interface was specified by IPv4 address. 2667 * This is the traditional BSD usage. 2668 */ 2669 error = sooptcopyin(sopt, &addr, sizeof(struct in_addr), 2670 sizeof(struct in_addr)); 2671 if (error) 2672 return (error); 2673 if (in_nullhost(addr)) { 2674 ifp = NULL; 2675 } else { 2676 ifp = ip_multicast_if(&addr, &ifindex); 2677 if (ifp == NULL) { 2678 IGMP_INET_PRINTF(addr, 2679 ("%s: can't find ifp for addr=%s\n", 2680 __func__, _igmp_inet_buf)); 2681 return (EADDRNOTAVAIL); 2682 } 2683 } 2684 /* XXX remove? */ 2685#ifdef IGMP_DEBUG0 2686 IGMP_PRINTF(("%s: ifp = 0x%llx, addr = %s\n", __func__, 2687 (uint64_t)VM_KERNEL_ADDRPERM(ifp), inet_ntoa(addr))); 2688#endif 2689 } 2690 2691 /* Reject interfaces which do not support multicast. */ 2692 if (ifp != NULL && (ifp->if_flags & IFF_MULTICAST) == 0) 2693 return (EOPNOTSUPP); 2694 2695 imo = inp_findmoptions(inp); 2696 if (imo == NULL) 2697 return (ENOMEM); 2698 2699 IMO_LOCK(imo); 2700 imo->imo_multicast_ifp = ifp; 2701 if (ifindex) 2702 imo->imo_multicast_addr = addr; 2703 else 2704 imo->imo_multicast_addr.s_addr = INADDR_ANY; 2705 IMO_UNLOCK(imo); 2706 IMO_REMREF(imo); /* from inp_findmoptions() */ 2707 2708 return (0); 2709} 2710 2711/* 2712 * Atomically set source filters on a socket for an IPv4 multicast group. 2713 */ 2714static int 2715inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) 2716{ 2717 struct __msfilterreq64 msfr, msfr64; 2718 struct __msfilterreq32 msfr32; 2719 sockunion_t *gsa; 2720 struct ifnet *ifp; 2721 struct in_mfilter *imf; 2722 struct ip_moptions *imo; 2723 struct in_multi *inm; 2724 size_t idx; 2725 int error; 2726 user_addr_t tmp_ptr; 2727 struct igmp_tparams itp; 2728 2729 bzero(&itp, sizeof (itp)); 2730 2731 if (IS_64BIT_PROCESS(current_proc())) { 2732 error = sooptcopyin(sopt, &msfr64, 2733 sizeof(struct __msfilterreq64), 2734 sizeof(struct __msfilterreq64)); 2735 if (error) 2736 return (error); 2737 /* we never use msfr.msfr_srcs; */ 2738 memcpy(&msfr, &msfr64, sizeof(msfr)); 2739 } else { 2740 error = sooptcopyin(sopt, &msfr32, 2741 sizeof(struct __msfilterreq32), 2742 sizeof(struct __msfilterreq32)); 2743 if (error) 2744 return (error); 2745 /* we never use msfr.msfr_srcs; */ 2746 memcpy(&msfr, &msfr32, sizeof(msfr)); 2747 } 2748 2749 if ((size_t) msfr.msfr_nsrcs > 2750 UINT32_MAX / sizeof(struct sockaddr_storage)) 2751 msfr.msfr_nsrcs = UINT32_MAX / sizeof(struct sockaddr_storage); 2752 2753 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) 2754 return (ENOBUFS); 2755 2756 if ((msfr.msfr_fmode != MCAST_EXCLUDE && 2757 msfr.msfr_fmode != MCAST_INCLUDE)) 2758 return (EINVAL); 2759 2760 if (msfr.msfr_group.ss_family != AF_INET || 2761 msfr.msfr_group.ss_len != sizeof(struct sockaddr_in)) 2762 return (EINVAL); 2763 2764 gsa = (sockunion_t *)&msfr.msfr_group; 2765 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) 2766 return (EINVAL); 2767 2768 gsa->sin.sin_port = 0; /* ignore port */ 2769 2770 ifnet_head_lock_shared(); 2771 if (msfr.msfr_ifindex == 0 || (u_int)if_index < msfr.msfr_ifindex) { 2772 ifnet_head_done(); 2773 return (EADDRNOTAVAIL); 2774 } 2775 2776 ifp = ifindex2ifnet[msfr.msfr_ifindex]; 2777 ifnet_head_done(); 2778 if (ifp == NULL) 2779 return (EADDRNOTAVAIL); 2780 2781 /* 2782 * Check if this socket is a member of this group. 2783 */ 2784 imo = inp_findmoptions(inp); 2785 if (imo == NULL) 2786 return (ENOMEM); 2787 2788 IMO_LOCK(imo); 2789 idx = imo_match_group(imo, ifp, &gsa->sa); 2790 if (idx == (size_t)-1 || imo->imo_mfilters == NULL) { 2791 error = EADDRNOTAVAIL; 2792 goto out_imo_locked; 2793 } 2794 inm = imo->imo_membership[idx]; 2795 imf = &imo->imo_mfilters[idx]; 2796 2797 /* 2798 * Begin state merge transaction at socket layer. 2799 */ 2800 2801 imf->imf_st[1] = msfr.msfr_fmode; 2802 2803 /* 2804 * Apply any new source filters, if present. 2805 * Make a copy of the user-space source vector so 2806 * that we may copy them with a single copyin. This 2807 * allows us to deal with page faults up-front. 2808 */ 2809 if (msfr.msfr_nsrcs > 0) { 2810 struct in_msource *lims; 2811 struct sockaddr_in *psin; 2812 struct sockaddr_storage *kss, *pkss; 2813 int i; 2814 2815 if (IS_64BIT_PROCESS(current_proc())) 2816 tmp_ptr = msfr64.msfr_srcs; 2817 else 2818 tmp_ptr = CAST_USER_ADDR_T(msfr32.msfr_srcs); 2819 2820 IGMP_PRINTF(("%s: loading %lu source list entries\n", 2821 __func__, (unsigned long)msfr.msfr_nsrcs)); 2822 kss = _MALLOC((size_t) msfr.msfr_nsrcs * sizeof(*kss), 2823 M_TEMP, M_WAITOK); 2824 if (kss == NULL) { 2825 error = ENOMEM; 2826 goto out_imo_locked; 2827 } 2828 error = copyin(tmp_ptr, kss, 2829 (size_t) msfr.msfr_nsrcs * sizeof(*kss)); 2830 if (error) { 2831 FREE(kss, M_TEMP); 2832 goto out_imo_locked; 2833 } 2834 2835 /* 2836 * Mark all source filters as UNDEFINED at t1. 2837 * Restore new group filter mode, as imf_leave() 2838 * will set it to INCLUDE. 2839 */ 2840 imf_leave(imf); 2841 imf->imf_st[1] = msfr.msfr_fmode; 2842 2843 /* 2844 * Update socket layer filters at t1, lazy-allocating 2845 * new entries. This saves a bunch of memory at the 2846 * cost of one RB_FIND() per source entry; duplicate 2847 * entries in the msfr_nsrcs vector are ignored. 2848 * If we encounter an error, rollback transaction. 2849 * 2850 * XXX This too could be replaced with a set-symmetric 2851 * difference like loop to avoid walking from root 2852 * every time, as the key space is common. 2853 */ 2854 for (i = 0, pkss = kss; (u_int)i < msfr.msfr_nsrcs; 2855 i++, pkss++) { 2856 psin = (struct sockaddr_in *)pkss; 2857 if (psin->sin_family != AF_INET) { 2858 error = EAFNOSUPPORT; 2859 break; 2860 } 2861 if (psin->sin_len != sizeof(struct sockaddr_in)) { 2862 error = EINVAL; 2863 break; 2864 } 2865 error = imf_get_source(imf, psin, &lims); 2866 if (error) 2867 break; 2868 lims->imsl_st[1] = imf->imf_st[1]; 2869 } 2870 FREE(kss, M_TEMP); 2871 } 2872 2873 if (error) 2874 goto out_imf_rollback; 2875 2876 /* 2877 * Begin state merge transaction at IGMP layer. 2878 */ 2879 INM_LOCK(inm); 2880 IGMP_PRINTF(("%s: merge inm state\n", __func__)); 2881 error = inm_merge(inm, imf); 2882 if (error) { 2883 IGMP_PRINTF(("%s: failed to merge inm state\n", __func__)); 2884 INM_UNLOCK(inm); 2885 goto out_imf_rollback; 2886 } 2887 2888 IGMP_PRINTF(("%s: doing igmp downcall\n", __func__)); 2889 error = igmp_change_state(inm, &itp); 2890 INM_UNLOCK(inm); 2891#ifdef IGMP_DEBUG 2892 if (error) 2893 IGMP_PRINTF(("%s: failed igmp downcall\n", __func__)); 2894#endif 2895 2896out_imf_rollback: 2897 if (error) 2898 imf_rollback(imf); 2899 else 2900 imf_commit(imf); 2901 2902 imf_reap(imf); 2903 2904out_imo_locked: 2905 IMO_UNLOCK(imo); 2906 IMO_REMREF(imo); /* from inp_findmoptions() */ 2907 2908 /* schedule timer now that we've dropped the lock(s) */ 2909 igmp_set_timeout(&itp); 2910 2911 return (error); 2912} 2913 2914/* 2915 * Set the IP multicast options in response to user setsockopt(). 2916 * 2917 * Many of the socket options handled in this function duplicate the 2918 * functionality of socket options in the regular unicast API. However, 2919 * it is not possible to merge the duplicate code, because the idempotence 2920 * of the IPv4 multicast part of the BSD Sockets API must be preserved; 2921 * the effects of these options must be treated as separate and distinct. 2922 * 2923 * FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING 2924 * is refactored to no longer use vifs. 2925 */ 2926int 2927inp_setmoptions(struct inpcb *inp, struct sockopt *sopt) 2928{ 2929 struct ip_moptions *imo; 2930 int error; 2931 unsigned int ifindex; 2932 struct ifnet *ifp; 2933 2934 error = 0; 2935 2936 /* 2937 * If socket is neither of type SOCK_RAW or SOCK_DGRAM, 2938 * or is a divert socket, reject it. 2939 */ 2940 if (SOCK_PROTO(inp->inp_socket) == IPPROTO_DIVERT || 2941 (SOCK_TYPE(inp->inp_socket) != SOCK_RAW && 2942 SOCK_TYPE(inp->inp_socket) != SOCK_DGRAM)) 2943 return (EOPNOTSUPP); 2944 2945 switch (sopt->sopt_name) { 2946#if MROUTING 2947 case IP_MULTICAST_VIF: { 2948 int vifi; 2949 /* 2950 * Select a multicast VIF for transmission. 2951 * Only useful if multicast forwarding is active. 2952 */ 2953 if (legal_vif_num == NULL) { 2954 error = EOPNOTSUPP; 2955 break; 2956 } 2957 error = sooptcopyin(sopt, &vifi, sizeof(int), sizeof(int)); 2958 if (error) 2959 break; 2960 if (!legal_vif_num(vifi) && (vifi != -1)) { 2961 error = EINVAL; 2962 break; 2963 } 2964 imo = inp_findmoptions(inp); 2965 if (imo == NULL) { 2966 error = ENOMEM; 2967 break; 2968 } 2969 IMO_LOCK(imo); 2970 imo->imo_multicast_vif = vifi; 2971 IMO_UNLOCK(imo); 2972 IMO_REMREF(imo); /* from inp_findmoptions() */ 2973 break; 2974 } 2975#endif 2976 case IP_MULTICAST_IF: 2977 error = inp_set_multicast_if(inp, sopt); 2978 break; 2979 2980 case IP_MULTICAST_IFINDEX: 2981 /* 2982 * Select the interface for outgoing multicast packets. 2983 */ 2984 error = sooptcopyin(sopt, &ifindex, sizeof (ifindex), 2985 sizeof (ifindex)); 2986 if (error) 2987 break; 2988 2989 imo = inp_findmoptions(inp); 2990 if (imo == NULL) { 2991 error = ENOMEM; 2992 break; 2993 } 2994 /* 2995 * Index 0 is used to remove a previous selection. 2996 * When no interface is selected, a default one is 2997 * chosen every time a multicast packet is sent. 2998 */ 2999 if (ifindex == 0) { 3000 IMO_LOCK(imo); 3001 imo->imo_multicast_ifp = NULL; 3002 IMO_UNLOCK(imo); 3003 IMO_REMREF(imo); /* from inp_findmoptions() */ 3004 break; 3005 } 3006 3007 ifnet_head_lock_shared(); 3008 /* Don't need to check is ifindex is < 0 since it's unsigned */ 3009 if ((unsigned int)if_index < ifindex) { 3010 ifnet_head_done(); 3011 IMO_REMREF(imo); /* from inp_findmoptions() */ 3012 error = ENXIO; /* per IPV6_MULTICAST_IF */ 3013 break; 3014 } 3015 ifp = ifindex2ifnet[ifindex]; 3016 ifnet_head_done(); 3017 3018 /* If it's detached or isn't a multicast interface, bail out */ 3019 if (ifp == NULL || !(ifp->if_flags & IFF_MULTICAST)) { 3020 IMO_REMREF(imo); /* from inp_findmoptions() */ 3021 error = EADDRNOTAVAIL; 3022 break; 3023 } 3024 IMO_LOCK(imo); 3025 imo->imo_multicast_ifp = ifp; 3026 /* 3027 * Clear out any remnants of past IP_MULTICAST_IF. The addr 3028 * isn't really used anywhere in the kernel; we could have 3029 * iterated thru the addresses of the interface and pick one 3030 * here, but that is redundant since ip_getmoptions() already 3031 * takes care of that for INADDR_ANY. 3032 */ 3033 imo->imo_multicast_addr.s_addr = INADDR_ANY; 3034 IMO_UNLOCK(imo); 3035 IMO_REMREF(imo); /* from inp_findmoptions() */ 3036 break; 3037 3038 case IP_MULTICAST_TTL: { 3039 u_char ttl; 3040 3041 /* 3042 * Set the IP time-to-live for outgoing multicast packets. 3043 * The original multicast API required a char argument, 3044 * which is inconsistent with the rest of the socket API. 3045 * We allow either a char or an int. 3046 */ 3047 if (sopt->sopt_valsize == sizeof(u_char)) { 3048 error = sooptcopyin(sopt, &ttl, sizeof(u_char), 3049 sizeof(u_char)); 3050 if (error) 3051 break; 3052 } else { 3053 u_int ittl; 3054 3055 error = sooptcopyin(sopt, &ittl, sizeof(u_int), 3056 sizeof(u_int)); 3057 if (error) 3058 break; 3059 if (ittl > 255) { 3060 error = EINVAL; 3061 break; 3062 } 3063 ttl = (u_char)ittl; 3064 } 3065 imo = inp_findmoptions(inp); 3066 if (imo == NULL) { 3067 error = ENOMEM; 3068 break; 3069 } 3070 IMO_LOCK(imo); 3071 imo->imo_multicast_ttl = ttl; 3072 IMO_UNLOCK(imo); 3073 IMO_REMREF(imo); /* from inp_findmoptions() */ 3074 break; 3075 } 3076 3077 case IP_MULTICAST_LOOP: { 3078 u_char loop; 3079 3080 /* 3081 * Set the loopback flag for outgoing multicast packets. 3082 * Must be zero or one. The original multicast API required a 3083 * char argument, which is inconsistent with the rest 3084 * of the socket API. We allow either a char or an int. 3085 */ 3086 if (sopt->sopt_valsize == sizeof(u_char)) { 3087 error = sooptcopyin(sopt, &loop, sizeof(u_char), 3088 sizeof(u_char)); 3089 if (error) 3090 break; 3091 } else { 3092 u_int iloop; 3093 3094 error = sooptcopyin(sopt, &iloop, sizeof(u_int), 3095 sizeof(u_int)); 3096 if (error) 3097 break; 3098 loop = (u_char)iloop; 3099 } 3100 imo = inp_findmoptions(inp); 3101 if (imo == NULL) { 3102 error = ENOMEM; 3103 break; 3104 } 3105 IMO_LOCK(imo); 3106 imo->imo_multicast_loop = !!loop; 3107 IMO_UNLOCK(imo); 3108 IMO_REMREF(imo); /* from inp_findmoptions() */ 3109 break; 3110 } 3111 3112 case IP_ADD_MEMBERSHIP: 3113 case IP_ADD_SOURCE_MEMBERSHIP: 3114 case MCAST_JOIN_GROUP: 3115 case MCAST_JOIN_SOURCE_GROUP: 3116 error = inp_join_group(inp, sopt); 3117 break; 3118 3119 case IP_DROP_MEMBERSHIP: 3120 case IP_DROP_SOURCE_MEMBERSHIP: 3121 case MCAST_LEAVE_GROUP: 3122 case MCAST_LEAVE_SOURCE_GROUP: 3123 error = inp_leave_group(inp, sopt); 3124 break; 3125 3126 case IP_BLOCK_SOURCE: 3127 case IP_UNBLOCK_SOURCE: 3128 case MCAST_BLOCK_SOURCE: 3129 case MCAST_UNBLOCK_SOURCE: 3130 error = inp_block_unblock_source(inp, sopt); 3131 break; 3132 3133 case IP_MSFILTER: 3134 error = inp_set_source_filters(inp, sopt); 3135 break; 3136 3137 default: 3138 error = EOPNOTSUPP; 3139 break; 3140 } 3141 3142 return (error); 3143} 3144 3145/* 3146 * Expose IGMP's multicast filter mode and source list(s) to userland, 3147 * keyed by (ifindex, group). 3148 * The filter mode is written out as a uint32_t, followed by 3149 * 0..n of struct in_addr. 3150 * For use by ifmcstat(8). 3151 */ 3152static int 3153sysctl_ip_mcast_filters SYSCTL_HANDLER_ARGS 3154{ 3155#pragma unused(oidp) 3156 3157 struct in_addr src, group; 3158 struct ifnet *ifp; 3159 struct in_multi *inm; 3160 struct in_multistep step; 3161 struct ip_msource *ims; 3162 int *name; 3163 int retval = 0; 3164 u_int namelen; 3165 uint32_t fmode, ifindex; 3166 3167 name = (int *)arg1; 3168 namelen = (u_int)arg2; 3169 3170 if (req->newptr != USER_ADDR_NULL) 3171 return (EPERM); 3172 3173 if (namelen != 2) 3174 return (EINVAL); 3175 3176 ifindex = name[0]; 3177 ifnet_head_lock_shared(); 3178 if (ifindex <= 0 || ifindex > (u_int)if_index) { 3179 IGMP_PRINTF(("%s: ifindex %u out of range\n", 3180 __func__, ifindex)); 3181 ifnet_head_done(); 3182 return (ENOENT); 3183 } 3184 3185 group.s_addr = name[1]; 3186 if (!IN_MULTICAST(ntohl(group.s_addr))) { 3187 IGMP_INET_PRINTF(group, 3188 ("%s: group %s is not multicast\n", 3189 __func__, _igmp_inet_buf)); 3190 ifnet_head_done(); 3191 return (EINVAL); 3192 } 3193 3194 ifp = ifindex2ifnet[ifindex]; 3195 ifnet_head_done(); 3196 if (ifp == NULL) { 3197 IGMP_PRINTF(("%s: no ifp for ifindex %u\n", __func__, ifindex)); 3198 return (ENOENT); 3199 } 3200 3201 in_multihead_lock_shared(); 3202 IN_FIRST_MULTI(step, inm); 3203 while (inm != NULL) { 3204 INM_LOCK(inm); 3205 if (inm->inm_ifp != ifp) 3206 goto next; 3207 3208 if (!in_hosteq(inm->inm_addr, group)) 3209 goto next; 3210 3211 fmode = inm->inm_st[1].iss_fmode; 3212 retval = SYSCTL_OUT(req, &fmode, sizeof(uint32_t)); 3213 if (retval != 0) { 3214 INM_UNLOCK(inm); 3215 break; /* abort */ 3216 } 3217 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) { 3218#ifdef IGMP_DEBUG 3219 struct in_addr ina; 3220 ina.s_addr = htonl(ims->ims_haddr); 3221 IGMP_INET_PRINTF(ina, 3222 ("%s: visit node %s\n", __func__, _igmp_inet_buf)); 3223#endif 3224 /* 3225 * Only copy-out sources which are in-mode. 3226 */ 3227 if (fmode != ims_get_mode(inm, ims, 1)) { 3228 IGMP_PRINTF(("%s: skip non-in-mode\n", 3229 __func__)); 3230 continue; /* process next source */ 3231 } 3232 src.s_addr = htonl(ims->ims_haddr); 3233 retval = SYSCTL_OUT(req, &src, sizeof(struct in_addr)); 3234 if (retval != 0) 3235 break; /* process next inm */ 3236 } 3237next: 3238 INM_UNLOCK(inm); 3239 IN_NEXT_MULTI(step, inm); 3240 } 3241 in_multihead_lock_done(); 3242 3243 return (retval); 3244} 3245 3246/* 3247 * XXX 3248 * The whole multicast option thing needs to be re-thought. 3249 * Several of these options are equally applicable to non-multicast 3250 * transmission, and one (IP_MULTICAST_TTL) totally duplicates a 3251 * standard option (IP_TTL). 3252 */ 3253/* 3254 * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. 3255 */ 3256static struct ifnet * 3257ip_multicast_if(struct in_addr *a, unsigned int *ifindexp) 3258{ 3259 unsigned int ifindex; 3260 struct ifnet *ifp; 3261 3262 if (ifindexp != NULL) 3263 *ifindexp = 0; 3264 if (ntohl(a->s_addr) >> 24 == 0) { 3265 ifindex = ntohl(a->s_addr) & 0xffffff; 3266 ifnet_head_lock_shared(); 3267 /* Don't need to check is ifindex is < 0 since it's unsigned */ 3268 if ((unsigned int)if_index < ifindex) { 3269 ifnet_head_done(); 3270 return (NULL); 3271 } 3272 ifp = ifindex2ifnet[ifindex]; 3273 ifnet_head_done(); 3274 if (ifp != NULL && ifindexp != NULL) 3275 *ifindexp = ifindex; 3276 } else { 3277 INADDR_TO_IFP(*a, ifp); 3278 } 3279 return (ifp); 3280} 3281 3282void 3283in_multi_init(void) 3284{ 3285 PE_parse_boot_argn("ifa_debug", &inm_debug, sizeof (inm_debug)); 3286 3287 /* Setup lock group and attribute for in_multihead */ 3288 in_multihead_lock_grp_attr = lck_grp_attr_alloc_init(); 3289 in_multihead_lock_grp = lck_grp_alloc_init("in_multihead", 3290 in_multihead_lock_grp_attr); 3291 in_multihead_lock_attr = lck_attr_alloc_init(); 3292 lck_rw_init(&in_multihead_lock, in_multihead_lock_grp, 3293 in_multihead_lock_attr); 3294 3295 lck_mtx_init(&inm_trash_lock, in_multihead_lock_grp, 3296 in_multihead_lock_attr); 3297 TAILQ_INIT(&inm_trash_head); 3298 3299 inm_size = (inm_debug == 0) ? sizeof (struct in_multi) : 3300 sizeof (struct in_multi_dbg); 3301 inm_zone = zinit(inm_size, INM_ZONE_MAX * inm_size, 3302 0, INM_ZONE_NAME); 3303 if (inm_zone == NULL) { 3304 panic("%s: failed allocating %s", __func__, INM_ZONE_NAME); 3305 /* NOTREACHED */ 3306 } 3307 zone_change(inm_zone, Z_EXPAND, TRUE); 3308 3309 ipms_size = sizeof (struct ip_msource); 3310 ipms_zone = zinit(ipms_size, IPMS_ZONE_MAX * ipms_size, 3311 0, IPMS_ZONE_NAME); 3312 if (ipms_zone == NULL) { 3313 panic("%s: failed allocating %s", __func__, IPMS_ZONE_NAME); 3314 /* NOTREACHED */ 3315 } 3316 zone_change(ipms_zone, Z_EXPAND, TRUE); 3317 3318 inms_size = sizeof (struct in_msource); 3319 inms_zone = zinit(inms_size, INMS_ZONE_MAX * inms_size, 3320 0, INMS_ZONE_NAME); 3321 if (inms_zone == NULL) { 3322 panic("%s: failed allocating %s", __func__, INMS_ZONE_NAME); 3323 /* NOTREACHED */ 3324 } 3325 zone_change(inms_zone, Z_EXPAND, TRUE); 3326} 3327 3328static struct in_multi * 3329in_multi_alloc(int how) 3330{ 3331 struct in_multi *inm; 3332 3333 inm = (how == M_WAITOK) ? zalloc(inm_zone) : zalloc_noblock(inm_zone); 3334 if (inm != NULL) { 3335 bzero(inm, inm_size); 3336 lck_mtx_init(&inm->inm_lock, in_multihead_lock_grp, 3337 in_multihead_lock_attr); 3338 inm->inm_debug |= IFD_ALLOC; 3339 if (inm_debug != 0) { 3340 inm->inm_debug |= IFD_DEBUG; 3341 inm->inm_trace = inm_trace; 3342 } 3343 } 3344 return (inm); 3345} 3346 3347static void 3348in_multi_free(struct in_multi *inm) 3349{ 3350 INM_LOCK(inm); 3351 if (inm->inm_debug & IFD_ATTACHED) { 3352 panic("%s: attached inm=%p is being freed", __func__, inm); 3353 /* NOTREACHED */ 3354 } else if (inm->inm_ifma != NULL) { 3355 panic("%s: ifma not NULL for inm=%p", __func__, inm); 3356 /* NOTREACHED */ 3357 } else if (!(inm->inm_debug & IFD_ALLOC)) { 3358 panic("%s: inm %p cannot be freed", __func__, inm); 3359 /* NOTREACHED */ 3360 } else if (inm->inm_refcount != 0) { 3361 panic("%s: non-zero refcount inm=%p", __func__, inm); 3362 /* NOTREACHED */ 3363 } else if (inm->inm_reqcnt != 0) { 3364 panic("%s: non-zero reqcnt inm=%p", __func__, inm); 3365 /* NOTREACHED */ 3366 } 3367 3368 /* Free any pending IGMPv3 state-change records */ 3369 IF_DRAIN(&inm->inm_scq); 3370 3371 inm->inm_debug &= ~IFD_ALLOC; 3372 if ((inm->inm_debug & (IFD_DEBUG | IFD_TRASHED)) == 3373 (IFD_DEBUG | IFD_TRASHED)) { 3374 lck_mtx_lock(&inm_trash_lock); 3375 TAILQ_REMOVE(&inm_trash_head, (struct in_multi_dbg *)inm, 3376 inm_trash_link); 3377 lck_mtx_unlock(&inm_trash_lock); 3378 inm->inm_debug &= ~IFD_TRASHED; 3379 } 3380 INM_UNLOCK(inm); 3381 3382 lck_mtx_destroy(&inm->inm_lock, in_multihead_lock_grp); 3383 zfree(inm_zone, inm); 3384} 3385 3386static void 3387in_multi_attach(struct in_multi *inm) 3388{ 3389 in_multihead_lock_assert(LCK_RW_ASSERT_EXCLUSIVE); 3390 INM_LOCK_ASSERT_HELD(inm); 3391 3392 if (inm->inm_debug & IFD_ATTACHED) { 3393 panic("%s: Attempt to attach an already attached inm=%p", 3394 __func__, inm); 3395 /* NOTREACHED */ 3396 } else if (inm->inm_debug & IFD_TRASHED) { 3397 panic("%s: Attempt to reattach a detached inm=%p", 3398 __func__, inm); 3399 /* NOTREACHED */ 3400 } 3401 3402 inm->inm_reqcnt++; 3403 VERIFY(inm->inm_reqcnt == 1); 3404 INM_ADDREF_LOCKED(inm); 3405 inm->inm_debug |= IFD_ATTACHED; 3406 /* 3407 * Reattach case: If debugging is enabled, take it 3408 * out of the trash list and clear IFD_TRASHED. 3409 */ 3410 if ((inm->inm_debug & (IFD_DEBUG | IFD_TRASHED)) == 3411 (IFD_DEBUG | IFD_TRASHED)) { 3412 /* Become a regular mutex, just in case */ 3413 INM_CONVERT_LOCK(inm); 3414 lck_mtx_lock(&inm_trash_lock); 3415 TAILQ_REMOVE(&inm_trash_head, (struct in_multi_dbg *)inm, 3416 inm_trash_link); 3417 lck_mtx_unlock(&inm_trash_lock); 3418 inm->inm_debug &= ~IFD_TRASHED; 3419 } 3420 3421 LIST_INSERT_HEAD(&in_multihead, inm, inm_link); 3422} 3423 3424int 3425in_multi_detach(struct in_multi *inm) 3426{ 3427 in_multihead_lock_assert(LCK_RW_ASSERT_EXCLUSIVE); 3428 INM_LOCK_ASSERT_HELD(inm); 3429 3430 if (inm->inm_reqcnt == 0) { 3431 panic("%s: inm=%p negative reqcnt", __func__, inm); 3432 /* NOTREACHED */ 3433 } 3434 3435 --inm->inm_reqcnt; 3436 if (inm->inm_reqcnt > 0) 3437 return (0); 3438 3439 if (!(inm->inm_debug & IFD_ATTACHED)) { 3440 panic("%s: Attempt to detach an unattached record inm=%p", 3441 __func__, inm); 3442 /* NOTREACHED */ 3443 } else if (inm->inm_debug & IFD_TRASHED) { 3444 panic("%s: inm %p is already in trash list", __func__, inm); 3445 /* NOTREACHED */ 3446 } 3447 3448 /* 3449 * NOTE: Caller calls IFMA_REMREF 3450 */ 3451 inm->inm_debug &= ~IFD_ATTACHED; 3452 LIST_REMOVE(inm, inm_link); 3453 3454 if (inm->inm_debug & IFD_DEBUG) { 3455 /* Become a regular mutex, just in case */ 3456 INM_CONVERT_LOCK(inm); 3457 lck_mtx_lock(&inm_trash_lock); 3458 TAILQ_INSERT_TAIL(&inm_trash_head, 3459 (struct in_multi_dbg *)inm, inm_trash_link); 3460 lck_mtx_unlock(&inm_trash_lock); 3461 inm->inm_debug |= IFD_TRASHED; 3462 } 3463 3464 return (1); 3465} 3466 3467void 3468inm_addref(struct in_multi *inm, int locked) 3469{ 3470 if (!locked) 3471 INM_LOCK_SPIN(inm); 3472 else 3473 INM_LOCK_ASSERT_HELD(inm); 3474 3475 if (++inm->inm_refcount == 0) { 3476 panic("%s: inm=%p wraparound refcnt", __func__, inm); 3477 /* NOTREACHED */ 3478 } else if (inm->inm_trace != NULL) { 3479 (*inm->inm_trace)(inm, TRUE); 3480 } 3481 if (!locked) 3482 INM_UNLOCK(inm); 3483} 3484 3485void 3486inm_remref(struct in_multi *inm, int locked) 3487{ 3488 struct ifmultiaddr *ifma; 3489 struct igmp_ifinfo *igi; 3490 3491 if (!locked) 3492 INM_LOCK_SPIN(inm); 3493 else 3494 INM_LOCK_ASSERT_HELD(inm); 3495 3496 if (inm->inm_refcount == 0 || (inm->inm_refcount == 1 && locked)) { 3497 panic("%s: inm=%p negative/missing refcnt", __func__, inm); 3498 /* NOTREACHED */ 3499 } else if (inm->inm_trace != NULL) { 3500 (*inm->inm_trace)(inm, FALSE); 3501 } 3502 3503 --inm->inm_refcount; 3504 if (inm->inm_refcount > 0) { 3505 if (!locked) 3506 INM_UNLOCK(inm); 3507 return; 3508 } 3509 3510 /* 3511 * Synchronization with in_getmulti(). In the event the inm has been 3512 * detached, the underlying ifma would still be in the if_multiaddrs 3513 * list, and thus can be looked up via if_addmulti(). At that point, 3514 * the only way to find this inm is via ifma_protospec. To avoid 3515 * race conditions between the last inm_remref() of that inm and its 3516 * use via ifma_protospec, in_multihead lock is used for serialization. 3517 * In order to avoid violating the lock order, we must drop inm_lock 3518 * before acquiring in_multihead lock. To prevent the inm from being 3519 * freed prematurely, we hold an extra reference. 3520 */ 3521 ++inm->inm_refcount; 3522 INM_UNLOCK(inm); 3523 in_multihead_lock_shared(); 3524 INM_LOCK_SPIN(inm); 3525 --inm->inm_refcount; 3526 if (inm->inm_refcount > 0) { 3527 /* We've lost the race, so abort since inm is still in use */ 3528 INM_UNLOCK(inm); 3529 in_multihead_lock_done(); 3530 /* If it was locked, return it as such */ 3531 if (locked) 3532 INM_LOCK(inm); 3533 return; 3534 } 3535 inm_purge(inm); 3536 ifma = inm->inm_ifma; 3537 inm->inm_ifma = NULL; 3538 inm->inm_ifp = NULL; 3539 igi = inm->inm_igi; 3540 inm->inm_igi = NULL; 3541 INM_UNLOCK(inm); 3542 IFMA_LOCK_SPIN(ifma); 3543 ifma->ifma_protospec = NULL; 3544 IFMA_UNLOCK(ifma); 3545 in_multihead_lock_done(); 3546 3547 in_multi_free(inm); 3548 if_delmulti_ifma(ifma); 3549 /* Release reference held to the underlying ifmultiaddr */ 3550 IFMA_REMREF(ifma); 3551 3552 if (igi != NULL) 3553 IGI_REMREF(igi); 3554} 3555 3556static void 3557inm_trace(struct in_multi *inm, int refhold) 3558{ 3559 struct in_multi_dbg *inm_dbg = (struct in_multi_dbg *)inm; 3560 ctrace_t *tr; 3561 u_int32_t idx; 3562 u_int16_t *cnt; 3563 3564 if (!(inm->inm_debug & IFD_DEBUG)) { 3565 panic("%s: inm %p has no debug structure", __func__, inm); 3566 /* NOTREACHED */ 3567 } 3568 if (refhold) { 3569 cnt = &inm_dbg->inm_refhold_cnt; 3570 tr = inm_dbg->inm_refhold; 3571 } else { 3572 cnt = &inm_dbg->inm_refrele_cnt; 3573 tr = inm_dbg->inm_refrele; 3574 } 3575 3576 idx = atomic_add_16_ov(cnt, 1) % INM_TRACE_HIST_SIZE; 3577 ctrace_record(&tr[idx]); 3578} 3579 3580void 3581in_multihead_lock_exclusive(void) 3582{ 3583 lck_rw_lock_exclusive(&in_multihead_lock); 3584} 3585 3586void 3587in_multihead_lock_shared(void) 3588{ 3589 lck_rw_lock_shared(&in_multihead_lock); 3590} 3591 3592void 3593in_multihead_lock_assert(int what) 3594{ 3595 lck_rw_assert(&in_multihead_lock, what); 3596} 3597 3598void 3599in_multihead_lock_done(void) 3600{ 3601 lck_rw_done(&in_multihead_lock); 3602} 3603 3604static struct ip_msource * 3605ipms_alloc(int how) 3606{ 3607 struct ip_msource *ims; 3608 3609 ims = (how == M_WAITOK) ? zalloc(ipms_zone) : zalloc_noblock(ipms_zone); 3610 if (ims != NULL) 3611 bzero(ims, ipms_size); 3612 3613 return (ims); 3614} 3615 3616static void 3617ipms_free(struct ip_msource *ims) 3618{ 3619 zfree(ipms_zone, ims); 3620} 3621 3622static struct in_msource * 3623inms_alloc(int how) 3624{ 3625 struct in_msource *inms; 3626 3627 inms = (how == M_WAITOK) ? zalloc(inms_zone) : 3628 zalloc_noblock(inms_zone); 3629 if (inms != NULL) 3630 bzero(inms, inms_size); 3631 3632 return (inms); 3633} 3634 3635static void 3636inms_free(struct in_msource *inms) 3637{ 3638 zfree(inms_zone, inms); 3639} 3640 3641#ifdef IGMP_DEBUG 3642 3643static const char *inm_modestrs[] = { "un\n", "in", "ex" }; 3644 3645static const char * 3646inm_mode_str(const int mode) 3647{ 3648 if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) 3649 return (inm_modestrs[mode]); 3650 return ("??"); 3651} 3652 3653static const char *inm_statestrs[] = { 3654 "not-member\n", 3655 "silent\n", 3656 "reporting\n", 3657 "idle\n", 3658 "lazy\n", 3659 "sleeping\n", 3660 "awakening\n", 3661 "query-pending\n", 3662 "sg-query-pending\n", 3663 "leaving" 3664}; 3665 3666static const char * 3667inm_state_str(const int state) 3668{ 3669 if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER) 3670 return (inm_statestrs[state]); 3671 return ("??"); 3672} 3673 3674/* 3675 * Dump an in_multi structure to the console. 3676 */ 3677void 3678inm_print(const struct in_multi *inm) 3679{ 3680 int t; 3681 char buf[MAX_IPv4_STR_LEN]; 3682 3683 INM_LOCK_ASSERT_HELD(__DECONST(struct in_multi *, inm)); 3684 3685 if (igmp_debug == 0) 3686 return; 3687 3688 inet_ntop(AF_INET, &inm->inm_addr, buf, sizeof(buf)); 3689 printf("%s: --- begin inm 0x%llx ---\n", __func__, 3690 (uint64_t)VM_KERNEL_ADDRPERM(inm)); 3691 printf("addr %s ifp 0x%llx(%s) ifma 0x%llx\n", 3692 buf, 3693 (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_ifp), 3694 if_name(inm->inm_ifp), 3695 (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_ifma)); 3696 printf("timer %u state %s refcount %u scq.len %u\n", 3697 inm->inm_timer, 3698 inm_state_str(inm->inm_state), 3699 inm->inm_refcount, 3700 inm->inm_scq.ifq_len); 3701 printf("igi 0x%llx nsrc %lu sctimer %u scrv %u\n", 3702 (uint64_t)VM_KERNEL_ADDRPERM(inm->inm_igi), 3703 inm->inm_nsrc, 3704 inm->inm_sctimer, 3705 inm->inm_scrv); 3706 for (t = 0; t < 2; t++) { 3707 printf("t%d: fmode %s asm %u ex %u in %u rec %u\n", t, 3708 inm_mode_str(inm->inm_st[t].iss_fmode), 3709 inm->inm_st[t].iss_asm, 3710 inm->inm_st[t].iss_ex, 3711 inm->inm_st[t].iss_in, 3712 inm->inm_st[t].iss_rec); 3713 } 3714 printf("%s: --- end inm 0x%llx ---\n", __func__, 3715 (uint64_t)VM_KERNEL_ADDRPERM(inm)); 3716} 3717 3718#else 3719 3720void 3721inm_print(__unused const struct in_multi *inm) 3722{ 3723 3724} 3725 3726#endif 3727