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