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