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