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