1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2007-2009 Bruce Simpson.
5 * Copyright (c) 2005 Robert N. M. Watson.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * IPv4 multicast socket, group, and socket option processing module.
35 */
36
37 #include <sys/cdefs.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/protosw.h>
48 #include <sys/sysctl.h>
49 #include <sys/ktr.h>
50 #include <sys/taskqueue.h>
51 #include <sys/tree.h>
52
53 #include <net/if.h>
54 #include <net/if_var.h>
55 #include <net/if_dl.h>
56 #include <net/route.h>
57 #include <net/route/nhop.h>
58 #include <net/vnet.h>
59
60 #include <net/ethernet.h>
61
62 #include <netinet/in.h>
63 #include <netinet/in_systm.h>
64 #include <netinet/in_fib.h>
65 #include <netinet/in_pcb.h>
66 #include <netinet/in_var.h>
67 #include <net/if_private.h>
68 #include <netinet/ip_var.h>
69 #include <netinet/igmp_var.h>
70
71 #ifndef KTR_IGMPV3
72 #define KTR_IGMPV3 KTR_INET
73 #endif
74
75 #ifndef __SOCKUNION_DECLARED
76 union sockunion {
77 struct sockaddr_storage ss;
78 struct sockaddr sa;
79 struct sockaddr_dl sdl;
80 struct sockaddr_in sin;
81 };
82 typedef union sockunion sockunion_t;
83 #define __SOCKUNION_DECLARED
84 #endif /* __SOCKUNION_DECLARED */
85
86 static MALLOC_DEFINE(M_INMFILTER, "in_mfilter",
87 "IPv4 multicast PCB-layer source filter");
88 static MALLOC_DEFINE(M_IPMADDR, "in_multi", "IPv4 multicast group");
89 static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "IPv4 multicast options");
90 static MALLOC_DEFINE(M_IPMSOURCE, "ip_msource",
91 "IPv4 multicast IGMP-layer source filter");
92
93 /*
94 * Locking:
95 *
96 * - Lock order is: IN_MULTI_LOCK, INP_WLOCK, IN_MULTI_LIST_LOCK, IGMP_LOCK,
97 * IF_ADDR_LOCK.
98 * - The IF_ADDR_LOCK is implicitly taken by inm_lookup() earlier, however
99 * it can be taken by code in net/if.c also.
100 * - ip_moptions and in_mfilter are covered by the INP_WLOCK.
101 *
102 * struct in_multi is covered by IN_MULTI_LIST_LOCK. There isn't strictly
103 * any need for in_multi itself to be virtualized -- it is bound to an ifp
104 * anyway no matter what happens.
105 */
106 struct mtx in_multi_list_mtx;
107 MTX_SYSINIT(in_multi_mtx, &in_multi_list_mtx, "in_multi_list_mtx", MTX_DEF);
108
109 struct mtx in_multi_free_mtx;
110 MTX_SYSINIT(in_multi_free_mtx, &in_multi_free_mtx, "in_multi_free_mtx", MTX_DEF);
111
112 struct sx in_multi_sx;
113 SX_SYSINIT(in_multi_sx, &in_multi_sx, "in_multi_sx");
114
115 /*
116 * Functions with non-static linkage defined in this file should be
117 * declared in in_var.h:
118 * imo_multi_filter()
119 * in_joingroup()
120 * in_joingroup_locked()
121 * in_leavegroup()
122 * in_leavegroup_locked()
123 * and ip_var.h:
124 * inp_freemoptions()
125 * inp_getmoptions()
126 * inp_setmoptions()
127 */
128 static void imf_commit(struct in_mfilter *);
129 static int imf_get_source(struct in_mfilter *imf,
130 const struct sockaddr_in *psin,
131 struct in_msource **);
132 static struct in_msource *
133 imf_graft(struct in_mfilter *, const uint8_t,
134 const struct sockaddr_in *);
135 static void imf_leave(struct in_mfilter *);
136 static int imf_prune(struct in_mfilter *, const struct sockaddr_in *);
137 static void imf_purge(struct in_mfilter *);
138 static void imf_rollback(struct in_mfilter *);
139 static void imf_reap(struct in_mfilter *);
140 static struct in_mfilter *
141 imo_match_group(const struct ip_moptions *,
142 const struct ifnet *, const struct sockaddr *);
143 static struct in_msource *
144 imo_match_source(struct in_mfilter *, const struct sockaddr *);
145 static void ims_merge(struct ip_msource *ims,
146 const struct in_msource *lims, const int rollback);
147 static int in_getmulti(struct ifnet *, const struct in_addr *,
148 struct in_multi **);
149 static int inm_get_source(struct in_multi *inm, const in_addr_t haddr,
150 const int noalloc, struct ip_msource **pims);
151 #ifdef KTR
152 static int inm_is_ifp_detached(const struct in_multi *);
153 #endif
154 static int inm_merge(struct in_multi *, /*const*/ struct in_mfilter *);
155 static void inm_purge(struct in_multi *);
156 static void inm_reap(struct in_multi *);
157 static void inm_release(struct in_multi *);
158 static struct ip_moptions *
159 inp_findmoptions(struct inpcb *);
160 static int inp_get_source_filters(struct inpcb *, struct sockopt *);
161 static int inp_join_group(struct inpcb *, struct sockopt *);
162 static int inp_leave_group(struct inpcb *, struct sockopt *);
163 static struct ifnet *
164 inp_lookup_mcast_ifp(const struct inpcb *,
165 const struct sockaddr_in *, const struct in_addr);
166 static int inp_block_unblock_source(struct inpcb *, struct sockopt *);
167 static int inp_set_multicast_if(struct inpcb *, struct sockopt *);
168 static int inp_set_source_filters(struct inpcb *, struct sockopt *);
169 static int sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS);
170
171 static SYSCTL_NODE(_net_inet_ip, OID_AUTO, mcast,
172 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
173 "IPv4 multicast");
174
175 static u_long in_mcast_maxgrpsrc = IP_MAX_GROUP_SRC_FILTER;
176 SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxgrpsrc,
177 CTLFLAG_RWTUN, &in_mcast_maxgrpsrc, 0,
178 "Max source filters per group");
179
180 static u_long in_mcast_maxsocksrc = IP_MAX_SOCK_SRC_FILTER;
181 SYSCTL_ULONG(_net_inet_ip_mcast, OID_AUTO, maxsocksrc,
182 CTLFLAG_RWTUN, &in_mcast_maxsocksrc, 0,
183 "Max source filters per socket");
184
185 int in_mcast_loop = IP_DEFAULT_MULTICAST_LOOP;
186 SYSCTL_INT(_net_inet_ip_mcast, OID_AUTO, loop, CTLFLAG_RWTUN,
187 &in_mcast_loop, 0, "Loopback multicast datagrams by default");
188
189 static SYSCTL_NODE(_net_inet_ip_mcast, OID_AUTO, filters,
190 CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_ip_mcast_filters,
191 "Per-interface stack-wide source filters");
192
193 #ifdef KTR
194 /*
195 * Inline function which wraps assertions for a valid ifp.
196 * The ifnet layer will set the ifma's ifp pointer to NULL if the ifp
197 * is detached.
198 */
199 static int __inline
inm_is_ifp_detached(const struct in_multi * inm)200 inm_is_ifp_detached(const struct in_multi *inm)
201 {
202 struct ifnet *ifp;
203
204 KASSERT(inm->inm_ifma != NULL, ("%s: no ifma", __func__));
205 ifp = inm->inm_ifma->ifma_ifp;
206 if (ifp != NULL) {
207 /*
208 * Sanity check that netinet's notion of ifp is the
209 * same as net's.
210 */
211 KASSERT(inm->inm_ifp == ifp, ("%s: bad ifp", __func__));
212 }
213
214 return (ifp == NULL);
215 }
216 #endif
217
218 /*
219 * Interface detach can happen in a taskqueue thread context, so we must use a
220 * dedicated thread to avoid deadlocks when draining inm_release tasks.
221 */
222 TASKQUEUE_DEFINE_THREAD(inm_free);
223 static struct in_multi_head inm_free_list = SLIST_HEAD_INITIALIZER();
224 static void inm_release_task(void *arg __unused, int pending __unused);
225 static struct task inm_free_task = TASK_INITIALIZER(0, inm_release_task, NULL);
226
227 void
inm_release_wait(void * arg __unused)228 inm_release_wait(void *arg __unused)
229 {
230
231 /*
232 * Make sure all pending multicast addresses are freed before
233 * the VNET or network device is destroyed:
234 */
235 taskqueue_drain(taskqueue_inm_free, &inm_free_task);
236 }
237 #ifdef VIMAGE
238 /* XXX-BZ FIXME, see D24914. */
239 VNET_SYSUNINIT(inm_release_wait, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST, inm_release_wait, NULL);
240 #endif
241
242 void
inm_release_list_deferred(struct in_multi_head * inmh)243 inm_release_list_deferred(struct in_multi_head *inmh)
244 {
245
246 if (SLIST_EMPTY(inmh))
247 return;
248 mtx_lock(&in_multi_free_mtx);
249 SLIST_CONCAT(&inm_free_list, inmh, in_multi, inm_nrele);
250 mtx_unlock(&in_multi_free_mtx);
251 taskqueue_enqueue(taskqueue_inm_free, &inm_free_task);
252 }
253
254 void
inm_disconnect(struct in_multi * inm)255 inm_disconnect(struct in_multi *inm)
256 {
257 struct ifnet *ifp;
258 struct ifmultiaddr *ifma, *ll_ifma;
259
260 ifp = inm->inm_ifp;
261 IF_ADDR_WLOCK_ASSERT(ifp);
262 ifma = inm->inm_ifma;
263
264 if_ref(ifp);
265 if (ifma->ifma_flags & IFMA_F_ENQUEUED) {
266 CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
267 ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
268 }
269 MCDPRINTF("removed ifma: %p from %s\n", ifma, ifp->if_xname);
270 if ((ll_ifma = ifma->ifma_llifma) != NULL) {
271 MPASS(ifma != ll_ifma);
272 ifma->ifma_llifma = NULL;
273 MPASS(ll_ifma->ifma_llifma == NULL);
274 MPASS(ll_ifma->ifma_ifp == ifp);
275 if (--ll_ifma->ifma_refcount == 0) {
276 if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
277 CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, ifma_link);
278 ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
279 }
280 MCDPRINTF("removed ll_ifma: %p from %s\n", ll_ifma, ifp->if_xname);
281 if_freemulti(ll_ifma);
282 }
283 }
284 }
285
286 void
inm_release_deferred(struct in_multi * inm)287 inm_release_deferred(struct in_multi *inm)
288 {
289 struct in_multi_head tmp;
290
291 IN_MULTI_LIST_LOCK_ASSERT();
292 MPASS(inm->inm_refcount > 0);
293 if (--inm->inm_refcount == 0) {
294 SLIST_INIT(&tmp);
295 inm_disconnect(inm);
296 inm->inm_ifma->ifma_protospec = NULL;
297 SLIST_INSERT_HEAD(&tmp, inm, inm_nrele);
298 inm_release_list_deferred(&tmp);
299 }
300 }
301
302 static void
inm_release_task(void * arg __unused,int pending __unused)303 inm_release_task(void *arg __unused, int pending __unused)
304 {
305 struct in_multi_head inm_free_tmp;
306 struct in_multi *inm, *tinm;
307
308 SLIST_INIT(&inm_free_tmp);
309 mtx_lock(&in_multi_free_mtx);
310 SLIST_CONCAT(&inm_free_tmp, &inm_free_list, in_multi, inm_nrele);
311 mtx_unlock(&in_multi_free_mtx);
312 IN_MULTI_LOCK();
313 SLIST_FOREACH_SAFE(inm, &inm_free_tmp, inm_nrele, tinm) {
314 SLIST_REMOVE_HEAD(&inm_free_tmp, inm_nrele);
315 MPASS(inm);
316 inm_release(inm);
317 }
318 IN_MULTI_UNLOCK();
319 }
320
321 /*
322 * Initialize an in_mfilter structure to a known state at t0, t1
323 * with an empty source filter list.
324 */
325 static __inline void
imf_init(struct in_mfilter * imf,const int st0,const int st1)326 imf_init(struct in_mfilter *imf, const int st0, const int st1)
327 {
328 memset(imf, 0, sizeof(struct in_mfilter));
329 RB_INIT(&imf->imf_sources);
330 imf->imf_st[0] = st0;
331 imf->imf_st[1] = st1;
332 }
333
334 struct in_mfilter *
ip_mfilter_alloc(const int mflags,const int st0,const int st1)335 ip_mfilter_alloc(const int mflags, const int st0, const int st1)
336 {
337 struct in_mfilter *imf;
338
339 imf = malloc(sizeof(*imf), M_INMFILTER, mflags);
340 if (imf != NULL)
341 imf_init(imf, st0, st1);
342
343 return (imf);
344 }
345
346 void
ip_mfilter_free(struct in_mfilter * imf)347 ip_mfilter_free(struct in_mfilter *imf)
348 {
349
350 imf_purge(imf);
351 free(imf, M_INMFILTER);
352 }
353
354 /*
355 * Function for looking up an in_multi record for an IPv4 multicast address
356 * on a given interface. ifp must be valid. If no record found, return NULL.
357 * The IN_MULTI_LIST_LOCK and IF_ADDR_LOCK on ifp must be held.
358 */
359 struct in_multi *
inm_lookup_locked(struct ifnet * ifp,const struct in_addr ina)360 inm_lookup_locked(struct ifnet *ifp, const struct in_addr ina)
361 {
362 struct ifmultiaddr *ifma;
363 struct in_multi *inm;
364
365 IN_MULTI_LIST_LOCK_ASSERT();
366 IF_ADDR_LOCK_ASSERT(ifp);
367
368 CK_STAILQ_FOREACH(ifma, &((ifp)->if_multiaddrs), ifma_link) {
369 inm = inm_ifmultiaddr_get_inm(ifma);
370 if (inm == NULL)
371 continue;
372 if (inm->inm_addr.s_addr == ina.s_addr)
373 return (inm);
374 }
375 return (NULL);
376 }
377
378 /*
379 * Wrapper for inm_lookup_locked().
380 * The IF_ADDR_LOCK will be taken on ifp and released on return.
381 */
382 struct in_multi *
inm_lookup(struct ifnet * ifp,const struct in_addr ina)383 inm_lookup(struct ifnet *ifp, const struct in_addr ina)
384 {
385 struct epoch_tracker et;
386 struct in_multi *inm;
387
388 IN_MULTI_LIST_LOCK_ASSERT();
389 NET_EPOCH_ENTER(et);
390
391 inm = inm_lookup_locked(ifp, ina);
392 NET_EPOCH_EXIT(et);
393
394 return (inm);
395 }
396
397 /*
398 * Find an IPv4 multicast group entry for this ip_moptions instance
399 * which matches the specified group, and optionally an interface.
400 * Return its index into the array, or -1 if not found.
401 */
402 static struct in_mfilter *
imo_match_group(const struct ip_moptions * imo,const struct ifnet * ifp,const struct sockaddr * group)403 imo_match_group(const struct ip_moptions *imo, const struct ifnet *ifp,
404 const struct sockaddr *group)
405 {
406 const struct sockaddr_in *gsin;
407 struct in_mfilter *imf;
408 struct in_multi *inm;
409
410 gsin = (const struct sockaddr_in *)group;
411
412 IP_MFILTER_FOREACH(imf, &imo->imo_head) {
413 inm = imf->imf_inm;
414 if (inm == NULL)
415 continue;
416 if ((ifp == NULL || (inm->inm_ifp == ifp)) &&
417 in_hosteq(inm->inm_addr, gsin->sin_addr)) {
418 break;
419 }
420 }
421 return (imf);
422 }
423
424 /*
425 * Find an IPv4 multicast source entry for this imo which matches
426 * the given group index for this socket, and source address.
427 *
428 * NOTE: This does not check if the entry is in-mode, merely if
429 * it exists, which may not be the desired behaviour.
430 */
431 static struct in_msource *
imo_match_source(struct in_mfilter * imf,const struct sockaddr * src)432 imo_match_source(struct in_mfilter *imf, const struct sockaddr *src)
433 {
434 struct ip_msource find;
435 struct ip_msource *ims;
436 const sockunion_t *psa;
437
438 KASSERT(src->sa_family == AF_INET, ("%s: !AF_INET", __func__));
439
440 /* Source trees are keyed in host byte order. */
441 psa = (const sockunion_t *)src;
442 find.ims_haddr = ntohl(psa->sin.sin_addr.s_addr);
443 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
444
445 return ((struct in_msource *)ims);
446 }
447
448 /*
449 * Perform filtering for multicast datagrams on a socket by group and source.
450 *
451 * Returns 0 if a datagram should be allowed through, or various error codes
452 * if the socket was not a member of the group, or the source was muted, etc.
453 */
454 int
imo_multi_filter(const struct ip_moptions * imo,const struct ifnet * ifp,const struct sockaddr * group,const struct sockaddr * src)455 imo_multi_filter(const struct ip_moptions *imo, const struct ifnet *ifp,
456 const struct sockaddr *group, const struct sockaddr *src)
457 {
458 struct in_mfilter *imf;
459 struct in_msource *ims;
460 int mode;
461
462 KASSERT(ifp != NULL, ("%s: null ifp", __func__));
463
464 imf = imo_match_group(imo, ifp, group);
465 if (imf == NULL)
466 return (MCAST_NOTGMEMBER);
467
468 /*
469 * Check if the source was included in an (S,G) join.
470 * Allow reception on exclusive memberships by default,
471 * reject reception on inclusive memberships by default.
472 * Exclude source only if an in-mode exclude filter exists.
473 * Include source only if an in-mode include filter exists.
474 * NOTE: We are comparing group state here at IGMP t1 (now)
475 * with socket-layer t0 (since last downcall).
476 */
477 mode = imf->imf_st[1];
478 ims = imo_match_source(imf, src);
479
480 if ((ims == NULL && mode == MCAST_INCLUDE) ||
481 (ims != NULL && ims->imsl_st[0] == MCAST_EXCLUDE))
482 return (MCAST_NOTSMEMBER);
483
484 return (MCAST_PASS);
485 }
486
487 /*
488 * Find and return a reference to an in_multi record for (ifp, group),
489 * and bump its reference count.
490 * If one does not exist, try to allocate it, and update link-layer multicast
491 * filters on ifp to listen for group.
492 * Assumes the IN_MULTI lock is held across the call.
493 * Return 0 if successful, otherwise return an appropriate error code.
494 */
495 static int
in_getmulti(struct ifnet * ifp,const struct in_addr * group,struct in_multi ** pinm)496 in_getmulti(struct ifnet *ifp, const struct in_addr *group,
497 struct in_multi **pinm)
498 {
499 struct sockaddr_in gsin;
500 struct ifmultiaddr *ifma;
501 struct in_ifinfo *ii;
502 struct in_multi *inm;
503 int error;
504
505 IN_MULTI_LOCK_ASSERT();
506
507 ii = (struct in_ifinfo *)ifp->if_afdata[AF_INET];
508 IN_MULTI_LIST_LOCK();
509 inm = inm_lookup(ifp, *group);
510 if (inm != NULL) {
511 /*
512 * If we already joined this group, just bump the
513 * refcount and return it.
514 */
515 KASSERT(inm->inm_refcount >= 1,
516 ("%s: bad refcount %d", __func__, inm->inm_refcount));
517 inm_acquire_locked(inm);
518 *pinm = inm;
519 }
520 IN_MULTI_LIST_UNLOCK();
521 if (inm != NULL)
522 return (0);
523
524 memset(&gsin, 0, sizeof(gsin));
525 gsin.sin_family = AF_INET;
526 gsin.sin_len = sizeof(struct sockaddr_in);
527 gsin.sin_addr = *group;
528
529 /*
530 * Check if a link-layer group is already associated
531 * with this network-layer group on the given ifnet.
532 */
533 error = if_addmulti(ifp, (struct sockaddr *)&gsin, &ifma);
534 if (error != 0)
535 return (error);
536
537 /* XXX ifma_protospec must be covered by IF_ADDR_LOCK */
538 IN_MULTI_LIST_LOCK();
539 IF_ADDR_WLOCK(ifp);
540
541 /*
542 * If something other than netinet is occupying the link-layer
543 * group, print a meaningful error message and back out of
544 * the allocation.
545 * Otherwise, bump the refcount on the existing network-layer
546 * group association and return it.
547 */
548 if (ifma->ifma_protospec != NULL) {
549 inm = (struct in_multi *)ifma->ifma_protospec;
550 #ifdef INVARIANTS
551 KASSERT(ifma->ifma_addr != NULL, ("%s: no ifma_addr",
552 __func__));
553 KASSERT(ifma->ifma_addr->sa_family == AF_INET,
554 ("%s: ifma not AF_INET", __func__));
555 KASSERT(inm != NULL, ("%s: no ifma_protospec", __func__));
556 if (inm->inm_ifma != ifma || inm->inm_ifp != ifp ||
557 !in_hosteq(inm->inm_addr, *group)) {
558 char addrbuf[INET_ADDRSTRLEN];
559
560 panic("%s: ifma %p is inconsistent with %p (%s)",
561 __func__, ifma, inm, inet_ntoa_r(*group, addrbuf));
562 }
563 #endif
564 inm_acquire_locked(inm);
565 *pinm = inm;
566 goto out_locked;
567 }
568
569 IF_ADDR_WLOCK_ASSERT(ifp);
570
571 /*
572 * A new in_multi record is needed; allocate and initialize it.
573 * We DO NOT perform an IGMP join as the in_ layer may need to
574 * push an initial source list down to IGMP to support SSM.
575 *
576 * The initial source filter state is INCLUDE, {} as per the RFC.
577 */
578 inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT | M_ZERO);
579 if (inm == NULL) {
580 IF_ADDR_WUNLOCK(ifp);
581 IN_MULTI_LIST_UNLOCK();
582 if_delmulti_ifma(ifma);
583 return (ENOMEM);
584 }
585 inm->inm_addr = *group;
586 inm->inm_ifp = ifp;
587 inm->inm_igi = ii->ii_igmp;
588 inm->inm_ifma = ifma;
589 inm->inm_refcount = 1;
590 inm->inm_state = IGMP_NOT_MEMBER;
591 mbufq_init(&inm->inm_scq, IGMP_MAX_STATE_CHANGES);
592 inm->inm_st[0].iss_fmode = MCAST_UNDEFINED;
593 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED;
594 RB_INIT(&inm->inm_srcs);
595
596 ifma->ifma_protospec = inm;
597
598 *pinm = inm;
599 out_locked:
600 IF_ADDR_WUNLOCK(ifp);
601 IN_MULTI_LIST_UNLOCK();
602 return (0);
603 }
604
605 /*
606 * Drop a reference to an in_multi record.
607 *
608 * If the refcount drops to 0, free the in_multi record and
609 * delete the underlying link-layer membership.
610 */
611 static void
inm_release(struct in_multi * inm)612 inm_release(struct in_multi *inm)
613 {
614 struct ifmultiaddr *ifma;
615 struct ifnet *ifp;
616
617 CTR2(KTR_IGMPV3, "%s: refcount is %d", __func__, inm->inm_refcount);
618 MPASS(inm->inm_refcount == 0);
619 CTR2(KTR_IGMPV3, "%s: freeing inm %p", __func__, inm);
620
621 ifma = inm->inm_ifma;
622 ifp = inm->inm_ifp;
623
624 /* XXX this access is not covered by IF_ADDR_LOCK */
625 CTR2(KTR_IGMPV3, "%s: purging ifma %p", __func__, ifma);
626 if (ifp != NULL) {
627 CURVNET_SET(ifp->if_vnet);
628 inm_purge(inm);
629 free(inm, M_IPMADDR);
630 if_delmulti_ifma_flags(ifma, 1);
631 CURVNET_RESTORE();
632 if_rele(ifp);
633 } else {
634 inm_purge(inm);
635 free(inm, M_IPMADDR);
636 if_delmulti_ifma_flags(ifma, 1);
637 }
638 }
639
640 /*
641 * Clear recorded source entries for a group.
642 * Used by the IGMP code. Caller must hold the IN_MULTI lock.
643 * FIXME: Should reap.
644 */
645 void
inm_clear_recorded(struct in_multi * inm)646 inm_clear_recorded(struct in_multi *inm)
647 {
648 struct ip_msource *ims;
649
650 IN_MULTI_LIST_LOCK_ASSERT();
651
652 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) {
653 if (ims->ims_stp) {
654 ims->ims_stp = 0;
655 --inm->inm_st[1].iss_rec;
656 }
657 }
658 KASSERT(inm->inm_st[1].iss_rec == 0,
659 ("%s: iss_rec %d not 0", __func__, inm->inm_st[1].iss_rec));
660 }
661
662 /*
663 * Record a source as pending for a Source-Group IGMPv3 query.
664 * This lives here as it modifies the shared tree.
665 *
666 * inm is the group descriptor.
667 * naddr is the address of the source to record in network-byte order.
668 *
669 * If the net.inet.igmp.sgalloc sysctl is non-zero, we will
670 * lazy-allocate a source node in response to an SG query.
671 * Otherwise, no allocation is performed. This saves some memory
672 * with the trade-off that the source will not be reported to the
673 * router if joined in the window between the query response and
674 * the group actually being joined on the local host.
675 *
676 * VIMAGE: XXX: Currently the igmp_sgalloc feature has been removed.
677 * This turns off the allocation of a recorded source entry if
678 * the group has not been joined.
679 *
680 * Return 0 if the source didn't exist or was already marked as recorded.
681 * Return 1 if the source was marked as recorded by this function.
682 * Return <0 if any error occurred (negated errno code).
683 */
684 int
inm_record_source(struct in_multi * inm,const in_addr_t naddr)685 inm_record_source(struct in_multi *inm, const in_addr_t naddr)
686 {
687 struct ip_msource find;
688 struct ip_msource *ims, *nims;
689
690 IN_MULTI_LIST_LOCK_ASSERT();
691
692 find.ims_haddr = ntohl(naddr);
693 ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find);
694 if (ims && ims->ims_stp)
695 return (0);
696 if (ims == NULL) {
697 if (inm->inm_nsrc == in_mcast_maxgrpsrc)
698 return (-ENOSPC);
699 nims = malloc(sizeof(struct ip_msource), M_IPMSOURCE,
700 M_NOWAIT | M_ZERO);
701 if (nims == NULL)
702 return (-ENOMEM);
703 nims->ims_haddr = find.ims_haddr;
704 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims);
705 ++inm->inm_nsrc;
706 ims = nims;
707 }
708
709 /*
710 * Mark the source as recorded and update the recorded
711 * source count.
712 */
713 ++ims->ims_stp;
714 ++inm->inm_st[1].iss_rec;
715
716 return (1);
717 }
718
719 /*
720 * Return a pointer to an in_msource owned by an in_mfilter,
721 * given its source address.
722 * Lazy-allocate if needed. If this is a new entry its filter state is
723 * undefined at t0.
724 *
725 * imf is the filter set being modified.
726 * haddr is the source address in *host* byte-order.
727 *
728 * SMPng: May be called with locks held; malloc must not block.
729 */
730 static int
imf_get_source(struct in_mfilter * imf,const struct sockaddr_in * psin,struct in_msource ** plims)731 imf_get_source(struct in_mfilter *imf, const struct sockaddr_in *psin,
732 struct in_msource **plims)
733 {
734 struct ip_msource find;
735 struct ip_msource *ims, *nims;
736 struct in_msource *lims;
737 int error;
738
739 error = 0;
740 ims = NULL;
741 lims = NULL;
742
743 /* key is host byte order */
744 find.ims_haddr = ntohl(psin->sin_addr.s_addr);
745 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
746 lims = (struct in_msource *)ims;
747 if (lims == NULL) {
748 if (imf->imf_nsrc == in_mcast_maxsocksrc)
749 return (ENOSPC);
750 nims = malloc(sizeof(struct in_msource), M_INMFILTER,
751 M_NOWAIT | M_ZERO);
752 if (nims == NULL)
753 return (ENOMEM);
754 lims = (struct in_msource *)nims;
755 lims->ims_haddr = find.ims_haddr;
756 lims->imsl_st[0] = MCAST_UNDEFINED;
757 RB_INSERT(ip_msource_tree, &imf->imf_sources, nims);
758 ++imf->imf_nsrc;
759 }
760
761 *plims = lims;
762
763 return (error);
764 }
765
766 /*
767 * Graft a source entry into an existing socket-layer filter set,
768 * maintaining any required invariants and checking allocations.
769 *
770 * The source is marked as being in the new filter mode at t1.
771 *
772 * Return the pointer to the new node, otherwise return NULL.
773 */
774 static struct in_msource *
imf_graft(struct in_mfilter * imf,const uint8_t st1,const struct sockaddr_in * psin)775 imf_graft(struct in_mfilter *imf, const uint8_t st1,
776 const struct sockaddr_in *psin)
777 {
778 struct ip_msource *nims;
779 struct in_msource *lims;
780
781 nims = malloc(sizeof(struct in_msource), M_INMFILTER,
782 M_NOWAIT | M_ZERO);
783 if (nims == NULL)
784 return (NULL);
785 lims = (struct in_msource *)nims;
786 lims->ims_haddr = ntohl(psin->sin_addr.s_addr);
787 lims->imsl_st[0] = MCAST_UNDEFINED;
788 lims->imsl_st[1] = st1;
789 RB_INSERT(ip_msource_tree, &imf->imf_sources, nims);
790 ++imf->imf_nsrc;
791
792 return (lims);
793 }
794
795 /*
796 * Prune a source entry from an existing socket-layer filter set,
797 * maintaining any required invariants and checking allocations.
798 *
799 * The source is marked as being left at t1, it is not freed.
800 *
801 * Return 0 if no error occurred, otherwise return an errno value.
802 */
803 static int
imf_prune(struct in_mfilter * imf,const struct sockaddr_in * psin)804 imf_prune(struct in_mfilter *imf, const struct sockaddr_in *psin)
805 {
806 struct ip_msource find;
807 struct ip_msource *ims;
808 struct in_msource *lims;
809
810 /* key is host byte order */
811 find.ims_haddr = ntohl(psin->sin_addr.s_addr);
812 ims = RB_FIND(ip_msource_tree, &imf->imf_sources, &find);
813 if (ims == NULL)
814 return (ENOENT);
815 lims = (struct in_msource *)ims;
816 lims->imsl_st[1] = MCAST_UNDEFINED;
817 return (0);
818 }
819
820 /*
821 * Revert socket-layer filter set deltas at t1 to t0 state.
822 */
823 static void
imf_rollback(struct in_mfilter * imf)824 imf_rollback(struct in_mfilter *imf)
825 {
826 struct ip_msource *ims, *tims;
827 struct in_msource *lims;
828
829 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) {
830 lims = (struct in_msource *)ims;
831 if (lims->imsl_st[0] == lims->imsl_st[1]) {
832 /* no change at t1 */
833 continue;
834 } else if (lims->imsl_st[0] != MCAST_UNDEFINED) {
835 /* revert change to existing source at t1 */
836 lims->imsl_st[1] = lims->imsl_st[0];
837 } else {
838 /* revert source added t1 */
839 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
840 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims);
841 free(ims, M_INMFILTER);
842 imf->imf_nsrc--;
843 }
844 }
845 imf->imf_st[1] = imf->imf_st[0];
846 }
847
848 /*
849 * Mark socket-layer filter set as INCLUDE {} at t1.
850 */
851 static void
imf_leave(struct in_mfilter * imf)852 imf_leave(struct in_mfilter *imf)
853 {
854 struct ip_msource *ims;
855 struct in_msource *lims;
856
857 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
858 lims = (struct in_msource *)ims;
859 lims->imsl_st[1] = MCAST_UNDEFINED;
860 }
861 imf->imf_st[1] = MCAST_INCLUDE;
862 }
863
864 /*
865 * Mark socket-layer filter set deltas as committed.
866 */
867 static void
imf_commit(struct in_mfilter * imf)868 imf_commit(struct in_mfilter *imf)
869 {
870 struct ip_msource *ims;
871 struct in_msource *lims;
872
873 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
874 lims = (struct in_msource *)ims;
875 lims->imsl_st[0] = lims->imsl_st[1];
876 }
877 imf->imf_st[0] = imf->imf_st[1];
878 }
879
880 /*
881 * Reap unreferenced sources from socket-layer filter set.
882 */
883 static void
imf_reap(struct in_mfilter * imf)884 imf_reap(struct in_mfilter *imf)
885 {
886 struct ip_msource *ims, *tims;
887 struct in_msource *lims;
888
889 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) {
890 lims = (struct in_msource *)ims;
891 if ((lims->imsl_st[0] == MCAST_UNDEFINED) &&
892 (lims->imsl_st[1] == MCAST_UNDEFINED)) {
893 CTR2(KTR_IGMPV3, "%s: free lims %p", __func__, ims);
894 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims);
895 free(ims, M_INMFILTER);
896 imf->imf_nsrc--;
897 }
898 }
899 }
900
901 /*
902 * Purge socket-layer filter set.
903 */
904 static void
imf_purge(struct in_mfilter * imf)905 imf_purge(struct in_mfilter *imf)
906 {
907 struct ip_msource *ims, *tims;
908
909 RB_FOREACH_SAFE(ims, ip_msource_tree, &imf->imf_sources, tims) {
910 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
911 RB_REMOVE(ip_msource_tree, &imf->imf_sources, ims);
912 free(ims, M_INMFILTER);
913 imf->imf_nsrc--;
914 }
915 imf->imf_st[0] = imf->imf_st[1] = MCAST_UNDEFINED;
916 KASSERT(RB_EMPTY(&imf->imf_sources),
917 ("%s: imf_sources not empty", __func__));
918 }
919
920 /*
921 * Look up a source filter entry for a multicast group.
922 *
923 * inm is the group descriptor to work with.
924 * haddr is the host-byte-order IPv4 address to look up.
925 * noalloc may be non-zero to suppress allocation of sources.
926 * *pims will be set to the address of the retrieved or allocated source.
927 *
928 * SMPng: NOTE: may be called with locks held.
929 * Return 0 if successful, otherwise return a non-zero error code.
930 */
931 static int
inm_get_source(struct in_multi * inm,const in_addr_t haddr,const int noalloc,struct ip_msource ** pims)932 inm_get_source(struct in_multi *inm, const in_addr_t haddr,
933 const int noalloc, struct ip_msource **pims)
934 {
935 struct ip_msource find;
936 struct ip_msource *ims, *nims;
937
938 find.ims_haddr = haddr;
939 ims = RB_FIND(ip_msource_tree, &inm->inm_srcs, &find);
940 if (ims == NULL && !noalloc) {
941 if (inm->inm_nsrc == in_mcast_maxgrpsrc)
942 return (ENOSPC);
943 nims = malloc(sizeof(struct ip_msource), M_IPMSOURCE,
944 M_NOWAIT | M_ZERO);
945 if (nims == NULL)
946 return (ENOMEM);
947 nims->ims_haddr = haddr;
948 RB_INSERT(ip_msource_tree, &inm->inm_srcs, nims);
949 ++inm->inm_nsrc;
950 ims = nims;
951 #ifdef KTR
952 CTR3(KTR_IGMPV3, "%s: allocated 0x%08x as %p", __func__,
953 haddr, ims);
954 #endif
955 }
956
957 *pims = ims;
958 return (0);
959 }
960
961 /*
962 * Merge socket-layer source into IGMP-layer source.
963 * If rollback is non-zero, perform the inverse of the merge.
964 */
965 static void
ims_merge(struct ip_msource * ims,const struct in_msource * lims,const int rollback)966 ims_merge(struct ip_msource *ims, const struct in_msource *lims,
967 const int rollback)
968 {
969 int n = rollback ? -1 : 1;
970
971 if (lims->imsl_st[0] == MCAST_EXCLUDE) {
972 CTR3(KTR_IGMPV3, "%s: t1 ex -= %d on 0x%08x",
973 __func__, n, ims->ims_haddr);
974 ims->ims_st[1].ex -= n;
975 } else if (lims->imsl_st[0] == MCAST_INCLUDE) {
976 CTR3(KTR_IGMPV3, "%s: t1 in -= %d on 0x%08x",
977 __func__, n, ims->ims_haddr);
978 ims->ims_st[1].in -= n;
979 }
980
981 if (lims->imsl_st[1] == MCAST_EXCLUDE) {
982 CTR3(KTR_IGMPV3, "%s: t1 ex += %d on 0x%08x",
983 __func__, n, ims->ims_haddr);
984 ims->ims_st[1].ex += n;
985 } else if (lims->imsl_st[1] == MCAST_INCLUDE) {
986 CTR3(KTR_IGMPV3, "%s: t1 in += %d on 0x%08x",
987 __func__, n, ims->ims_haddr);
988 ims->ims_st[1].in += n;
989 }
990 }
991
992 /*
993 * Atomically update the global in_multi state, when a membership's
994 * filter list is being updated in any way.
995 *
996 * imf is the per-inpcb-membership group filter pointer.
997 * A fake imf may be passed for in-kernel consumers.
998 *
999 * XXX This is a candidate for a set-symmetric-difference style loop
1000 * which would eliminate the repeated lookup from root of ims nodes,
1001 * as they share the same key space.
1002 *
1003 * If any error occurred this function will back out of refcounts
1004 * and return a non-zero value.
1005 */
1006 static int
inm_merge(struct in_multi * inm,struct in_mfilter * imf)1007 inm_merge(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
1008 {
1009 struct ip_msource *ims, *nims;
1010 struct in_msource *lims;
1011 int schanged, error;
1012 int nsrc0, nsrc1;
1013
1014 schanged = 0;
1015 error = 0;
1016 nsrc1 = nsrc0 = 0;
1017 IN_MULTI_LIST_LOCK_ASSERT();
1018
1019 /*
1020 * Update the source filters first, as this may fail.
1021 * Maintain count of in-mode filters at t0, t1. These are
1022 * used to work out if we transition into ASM mode or not.
1023 * Maintain a count of source filters whose state was
1024 * actually modified by this operation.
1025 */
1026 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
1027 lims = (struct in_msource *)ims;
1028 if (lims->imsl_st[0] == imf->imf_st[0]) nsrc0++;
1029 if (lims->imsl_st[1] == imf->imf_st[1]) nsrc1++;
1030 if (lims->imsl_st[0] == lims->imsl_st[1]) continue;
1031 error = inm_get_source(inm, lims->ims_haddr, 0, &nims);
1032 ++schanged;
1033 if (error)
1034 break;
1035 ims_merge(nims, lims, 0);
1036 }
1037 if (error) {
1038 struct ip_msource *bims;
1039
1040 RB_FOREACH_REVERSE_FROM(ims, ip_msource_tree, nims) {
1041 lims = (struct in_msource *)ims;
1042 if (lims->imsl_st[0] == lims->imsl_st[1])
1043 continue;
1044 (void)inm_get_source(inm, lims->ims_haddr, 1, &bims);
1045 if (bims == NULL)
1046 continue;
1047 ims_merge(bims, lims, 1);
1048 }
1049 goto out_reap;
1050 }
1051
1052 CTR3(KTR_IGMPV3, "%s: imf filters in-mode: %d at t0, %d at t1",
1053 __func__, nsrc0, nsrc1);
1054
1055 /* Handle transition between INCLUDE {n} and INCLUDE {} on socket. */
1056 if (imf->imf_st[0] == imf->imf_st[1] &&
1057 imf->imf_st[1] == MCAST_INCLUDE) {
1058 if (nsrc1 == 0) {
1059 CTR1(KTR_IGMPV3, "%s: --in on inm at t1", __func__);
1060 --inm->inm_st[1].iss_in;
1061 }
1062 }
1063
1064 /* Handle filter mode transition on socket. */
1065 if (imf->imf_st[0] != imf->imf_st[1]) {
1066 CTR3(KTR_IGMPV3, "%s: imf transition %d to %d",
1067 __func__, imf->imf_st[0], imf->imf_st[1]);
1068
1069 if (imf->imf_st[0] == MCAST_EXCLUDE) {
1070 CTR1(KTR_IGMPV3, "%s: --ex on inm at t1", __func__);
1071 --inm->inm_st[1].iss_ex;
1072 } else if (imf->imf_st[0] == MCAST_INCLUDE) {
1073 CTR1(KTR_IGMPV3, "%s: --in on inm at t1", __func__);
1074 --inm->inm_st[1].iss_in;
1075 }
1076
1077 if (imf->imf_st[1] == MCAST_EXCLUDE) {
1078 CTR1(KTR_IGMPV3, "%s: ex++ on inm at t1", __func__);
1079 inm->inm_st[1].iss_ex++;
1080 } else if (imf->imf_st[1] == MCAST_INCLUDE && nsrc1 > 0) {
1081 CTR1(KTR_IGMPV3, "%s: in++ on inm at t1", __func__);
1082 inm->inm_st[1].iss_in++;
1083 }
1084 }
1085
1086 /*
1087 * Track inm filter state in terms of listener counts.
1088 * If there are any exclusive listeners, stack-wide
1089 * membership is exclusive.
1090 * Otherwise, if only inclusive listeners, stack-wide is inclusive.
1091 * If no listeners remain, state is undefined at t1,
1092 * and the IGMP lifecycle for this group should finish.
1093 */
1094 if (inm->inm_st[1].iss_ex > 0) {
1095 CTR1(KTR_IGMPV3, "%s: transition to EX", __func__);
1096 inm->inm_st[1].iss_fmode = MCAST_EXCLUDE;
1097 } else if (inm->inm_st[1].iss_in > 0) {
1098 CTR1(KTR_IGMPV3, "%s: transition to IN", __func__);
1099 inm->inm_st[1].iss_fmode = MCAST_INCLUDE;
1100 } else {
1101 CTR1(KTR_IGMPV3, "%s: transition to UNDEF", __func__);
1102 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED;
1103 }
1104
1105 /* Decrement ASM listener count on transition out of ASM mode. */
1106 if (imf->imf_st[0] == MCAST_EXCLUDE && nsrc0 == 0) {
1107 if ((imf->imf_st[1] != MCAST_EXCLUDE) ||
1108 (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 > 0)) {
1109 CTR1(KTR_IGMPV3, "%s: --asm on inm at t1", __func__);
1110 --inm->inm_st[1].iss_asm;
1111 }
1112 }
1113
1114 /* Increment ASM listener count on transition to ASM mode. */
1115 if (imf->imf_st[1] == MCAST_EXCLUDE && nsrc1 == 0) {
1116 CTR1(KTR_IGMPV3, "%s: asm++ on inm at t1", __func__);
1117 inm->inm_st[1].iss_asm++;
1118 }
1119
1120 CTR3(KTR_IGMPV3, "%s: merged imf %p to inm %p", __func__, imf, inm);
1121 inm_print(inm);
1122
1123 out_reap:
1124 if (schanged > 0) {
1125 CTR1(KTR_IGMPV3, "%s: sources changed; reaping", __func__);
1126 inm_reap(inm);
1127 }
1128 return (error);
1129 }
1130
1131 /*
1132 * Mark an in_multi's filter set deltas as committed.
1133 * Called by IGMP after a state change has been enqueued.
1134 */
1135 void
inm_commit(struct in_multi * inm)1136 inm_commit(struct in_multi *inm)
1137 {
1138 struct ip_msource *ims;
1139
1140 CTR2(KTR_IGMPV3, "%s: commit inm %p", __func__, inm);
1141 CTR1(KTR_IGMPV3, "%s: pre commit:", __func__);
1142 inm_print(inm);
1143
1144 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) {
1145 ims->ims_st[0] = ims->ims_st[1];
1146 }
1147 inm->inm_st[0] = inm->inm_st[1];
1148 }
1149
1150 /*
1151 * Reap unreferenced nodes from an in_multi's filter set.
1152 */
1153 static void
inm_reap(struct in_multi * inm)1154 inm_reap(struct in_multi *inm)
1155 {
1156 struct ip_msource *ims, *tims;
1157
1158 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) {
1159 if (ims->ims_st[0].ex > 0 || ims->ims_st[0].in > 0 ||
1160 ims->ims_st[1].ex > 0 || ims->ims_st[1].in > 0 ||
1161 ims->ims_stp != 0)
1162 continue;
1163 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
1164 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims);
1165 free(ims, M_IPMSOURCE);
1166 inm->inm_nsrc--;
1167 }
1168 }
1169
1170 /*
1171 * Purge all source nodes from an in_multi's filter set.
1172 */
1173 static void
inm_purge(struct in_multi * inm)1174 inm_purge(struct in_multi *inm)
1175 {
1176 struct ip_msource *ims, *tims;
1177
1178 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, tims) {
1179 CTR2(KTR_IGMPV3, "%s: free ims %p", __func__, ims);
1180 RB_REMOVE(ip_msource_tree, &inm->inm_srcs, ims);
1181 free(ims, M_IPMSOURCE);
1182 inm->inm_nsrc--;
1183 }
1184 mbufq_drain(&inm->inm_scq);
1185 }
1186
1187 /*
1188 * Join a multicast group; unlocked entry point.
1189 *
1190 * SMPng: XXX: in_joingroup() is called from in_control(). Fortunately,
1191 * ifp is unlikely to have been detached at this point, so we assume
1192 * it's OK to recurse.
1193 */
1194 int
in_joingroup(struct ifnet * ifp,const struct in_addr * gina,struct in_mfilter * imf,struct in_multi ** pinm)1195 in_joingroup(struct ifnet *ifp, const struct in_addr *gina,
1196 /*const*/ struct in_mfilter *imf, struct in_multi **pinm)
1197 {
1198 int error;
1199
1200 IN_MULTI_LOCK();
1201 error = in_joingroup_locked(ifp, gina, imf, pinm);
1202 IN_MULTI_UNLOCK();
1203
1204 return (error);
1205 }
1206
1207 /*
1208 * Join a multicast group; real entry point.
1209 *
1210 * Only preserves atomicity at inm level.
1211 * NOTE: imf argument cannot be const due to sys/tree.h limitations.
1212 *
1213 * If the IGMP downcall fails, the group is not joined, and an error
1214 * code is returned.
1215 */
1216 int
in_joingroup_locked(struct ifnet * ifp,const struct in_addr * gina,struct in_mfilter * imf,struct in_multi ** pinm)1217 in_joingroup_locked(struct ifnet *ifp, const struct in_addr *gina,
1218 /*const*/ struct in_mfilter *imf, struct in_multi **pinm)
1219 {
1220 struct in_mfilter timf;
1221 struct in_multi *inm;
1222 int error;
1223
1224 IN_MULTI_LOCK_ASSERT();
1225 IN_MULTI_LIST_UNLOCK_ASSERT();
1226
1227 CTR4(KTR_IGMPV3, "%s: join 0x%08x on %p(%s))", __func__,
1228 ntohl(gina->s_addr), ifp, ifp->if_xname);
1229
1230 error = 0;
1231 inm = NULL;
1232
1233 /*
1234 * If no imf was specified (i.e. kernel consumer),
1235 * fake one up and assume it is an ASM join.
1236 */
1237 if (imf == NULL) {
1238 imf_init(&timf, MCAST_UNDEFINED, MCAST_EXCLUDE);
1239 imf = &timf;
1240 }
1241
1242 error = in_getmulti(ifp, gina, &inm);
1243 if (error) {
1244 CTR1(KTR_IGMPV3, "%s: in_getmulti() failure", __func__);
1245 return (error);
1246 }
1247 IN_MULTI_LIST_LOCK();
1248 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
1249 error = inm_merge(inm, imf);
1250 if (error) {
1251 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__);
1252 goto out_inm_release;
1253 }
1254
1255 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
1256 error = igmp_change_state(inm);
1257 if (error) {
1258 CTR1(KTR_IGMPV3, "%s: failed to update source", __func__);
1259 goto out_inm_release;
1260 }
1261
1262 out_inm_release:
1263 if (error) {
1264 CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm);
1265 IF_ADDR_WLOCK(ifp);
1266 inm_release_deferred(inm);
1267 IF_ADDR_WUNLOCK(ifp);
1268 } else {
1269 *pinm = inm;
1270 }
1271 IN_MULTI_LIST_UNLOCK();
1272
1273 return (error);
1274 }
1275
1276 /*
1277 * Leave a multicast group; unlocked entry point.
1278 */
1279 int
in_leavegroup(struct in_multi * inm,struct in_mfilter * imf)1280 in_leavegroup(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
1281 {
1282 int error;
1283
1284 IN_MULTI_LOCK();
1285 error = in_leavegroup_locked(inm, imf);
1286 IN_MULTI_UNLOCK();
1287
1288 return (error);
1289 }
1290
1291 /*
1292 * Leave a multicast group; real entry point.
1293 * All source filters will be expunged.
1294 *
1295 * Only preserves atomicity at inm level.
1296 *
1297 * Holding the write lock for the INP which contains imf
1298 * is highly advisable. We can't assert for it as imf does not
1299 * contain a back-pointer to the owning inp.
1300 *
1301 * Note: This is not the same as inm_release(*) as this function also
1302 * makes a state change downcall into IGMP.
1303 */
1304 int
in_leavegroup_locked(struct in_multi * inm,struct in_mfilter * imf)1305 in_leavegroup_locked(struct in_multi *inm, /*const*/ struct in_mfilter *imf)
1306 {
1307 struct in_mfilter timf;
1308 int error;
1309
1310 IN_MULTI_LOCK_ASSERT();
1311 IN_MULTI_LIST_UNLOCK_ASSERT();
1312
1313 error = 0;
1314
1315 CTR5(KTR_IGMPV3, "%s: leave inm %p, 0x%08x/%s, imf %p", __func__,
1316 inm, ntohl(inm->inm_addr.s_addr),
1317 (inm_is_ifp_detached(inm) ? "null" : inm->inm_ifp->if_xname),
1318 imf);
1319
1320 /*
1321 * If no imf was specified (i.e. kernel consumer),
1322 * fake one up and assume it is an ASM join.
1323 */
1324 if (imf == NULL) {
1325 imf_init(&timf, MCAST_EXCLUDE, MCAST_UNDEFINED);
1326 imf = &timf;
1327 }
1328
1329 /*
1330 * Begin state merge transaction at IGMP layer.
1331 *
1332 * As this particular invocation should not cause any memory
1333 * to be allocated, and there is no opportunity to roll back
1334 * the transaction, it MUST NOT fail.
1335 */
1336 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
1337 IN_MULTI_LIST_LOCK();
1338 error = inm_merge(inm, imf);
1339 KASSERT(error == 0, ("%s: failed to merge inm state", __func__));
1340
1341 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
1342 CURVNET_SET(inm->inm_ifp->if_vnet);
1343 error = igmp_change_state(inm);
1344 IF_ADDR_WLOCK(inm->inm_ifp);
1345 inm_release_deferred(inm);
1346 IF_ADDR_WUNLOCK(inm->inm_ifp);
1347 IN_MULTI_LIST_UNLOCK();
1348 CURVNET_RESTORE();
1349 if (error)
1350 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
1351
1352 CTR2(KTR_IGMPV3, "%s: dropping ref on %p", __func__, inm);
1353
1354 return (error);
1355 }
1356
1357 /*#ifndef BURN_BRIDGES*/
1358
1359 /*
1360 * Block or unblock an ASM multicast source on an inpcb.
1361 * This implements the delta-based API described in RFC 3678.
1362 *
1363 * The delta-based API applies only to exclusive-mode memberships.
1364 * An IGMP downcall will be performed.
1365 *
1366 * Return 0 if successful, otherwise return an appropriate error code.
1367 */
1368 static int
inp_block_unblock_source(struct inpcb * inp,struct sockopt * sopt)1369 inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt)
1370 {
1371 struct epoch_tracker et;
1372 struct group_source_req gsr;
1373 sockunion_t *gsa, *ssa;
1374 struct ifnet *ifp;
1375 struct in_mfilter *imf;
1376 struct ip_moptions *imo;
1377 struct in_msource *ims;
1378 struct in_multi *inm;
1379 uint16_t fmode;
1380 int error, doblock;
1381
1382 ifp = NULL;
1383 error = 0;
1384 doblock = 0;
1385
1386 memset(&gsr, 0, sizeof(struct group_source_req));
1387 gsa = (sockunion_t *)&gsr.gsr_group;
1388 ssa = (sockunion_t *)&gsr.gsr_source;
1389
1390 switch (sopt->sopt_name) {
1391 case IP_BLOCK_SOURCE:
1392 case IP_UNBLOCK_SOURCE: {
1393 struct ip_mreq_source mreqs;
1394
1395 error = sooptcopyin(sopt, &mreqs,
1396 sizeof(struct ip_mreq_source),
1397 sizeof(struct ip_mreq_source));
1398 if (error)
1399 return (error);
1400
1401 gsa->sin.sin_family = AF_INET;
1402 gsa->sin.sin_len = sizeof(struct sockaddr_in);
1403 gsa->sin.sin_addr = mreqs.imr_multiaddr;
1404
1405 ssa->sin.sin_family = AF_INET;
1406 ssa->sin.sin_len = sizeof(struct sockaddr_in);
1407 ssa->sin.sin_addr = mreqs.imr_sourceaddr;
1408
1409 if (!in_nullhost(mreqs.imr_interface)) {
1410 NET_EPOCH_ENTER(et);
1411 INADDR_TO_IFP(mreqs.imr_interface, ifp);
1412 /* XXXGL: ifref? */
1413 NET_EPOCH_EXIT(et);
1414 }
1415 if (sopt->sopt_name == IP_BLOCK_SOURCE)
1416 doblock = 1;
1417
1418 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
1419 __func__, ntohl(mreqs.imr_interface.s_addr), ifp);
1420 break;
1421 }
1422
1423 case MCAST_BLOCK_SOURCE:
1424 case MCAST_UNBLOCK_SOURCE:
1425 error = sooptcopyin(sopt, &gsr,
1426 sizeof(struct group_source_req),
1427 sizeof(struct group_source_req));
1428 if (error)
1429 return (error);
1430
1431 if (gsa->sin.sin_family != AF_INET ||
1432 gsa->sin.sin_len != sizeof(struct sockaddr_in))
1433 return (EINVAL);
1434
1435 if (ssa->sin.sin_family != AF_INET ||
1436 ssa->sin.sin_len != sizeof(struct sockaddr_in))
1437 return (EINVAL);
1438
1439 NET_EPOCH_ENTER(et);
1440 ifp = ifnet_byindex(gsr.gsr_interface);
1441 NET_EPOCH_EXIT(et);
1442 if (ifp == NULL)
1443 return (EADDRNOTAVAIL);
1444
1445 if (sopt->sopt_name == MCAST_BLOCK_SOURCE)
1446 doblock = 1;
1447 break;
1448
1449 default:
1450 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d",
1451 __func__, sopt->sopt_name);
1452 return (EOPNOTSUPP);
1453 break;
1454 }
1455
1456 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
1457 return (EINVAL);
1458
1459 IN_MULTI_LOCK();
1460
1461 /*
1462 * Check if we are actually a member of this group.
1463 */
1464 imo = inp_findmoptions(inp);
1465 imf = imo_match_group(imo, ifp, &gsa->sa);
1466 if (imf == NULL) {
1467 error = EADDRNOTAVAIL;
1468 goto out_inp_locked;
1469 }
1470 inm = imf->imf_inm;
1471
1472 /*
1473 * Attempting to use the delta-based API on an
1474 * non exclusive-mode membership is an error.
1475 */
1476 fmode = imf->imf_st[0];
1477 if (fmode != MCAST_EXCLUDE) {
1478 error = EINVAL;
1479 goto out_inp_locked;
1480 }
1481
1482 /*
1483 * Deal with error cases up-front:
1484 * Asked to block, but already blocked; or
1485 * Asked to unblock, but nothing to unblock.
1486 * If adding a new block entry, allocate it.
1487 */
1488 ims = imo_match_source(imf, &ssa->sa);
1489 if ((ims != NULL && doblock) || (ims == NULL && !doblock)) {
1490 CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent", __func__,
1491 ntohl(ssa->sin.sin_addr.s_addr), doblock ? "" : "not ");
1492 error = EADDRNOTAVAIL;
1493 goto out_inp_locked;
1494 }
1495
1496 INP_WLOCK_ASSERT(inp);
1497
1498 /*
1499 * Begin state merge transaction at socket layer.
1500 */
1501 if (doblock) {
1502 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block");
1503 ims = imf_graft(imf, fmode, &ssa->sin);
1504 if (ims == NULL)
1505 error = ENOMEM;
1506 } else {
1507 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow");
1508 error = imf_prune(imf, &ssa->sin);
1509 }
1510
1511 if (error) {
1512 CTR1(KTR_IGMPV3, "%s: merge imf state failed", __func__);
1513 goto out_imf_rollback;
1514 }
1515
1516 /*
1517 * Begin state merge transaction at IGMP layer.
1518 */
1519 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
1520 IN_MULTI_LIST_LOCK();
1521 error = inm_merge(inm, imf);
1522 if (error) {
1523 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__);
1524 IN_MULTI_LIST_UNLOCK();
1525 goto out_imf_rollback;
1526 }
1527
1528 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
1529 error = igmp_change_state(inm);
1530 IN_MULTI_LIST_UNLOCK();
1531 if (error)
1532 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
1533
1534 out_imf_rollback:
1535 if (error)
1536 imf_rollback(imf);
1537 else
1538 imf_commit(imf);
1539
1540 imf_reap(imf);
1541
1542 out_inp_locked:
1543 INP_WUNLOCK(inp);
1544 IN_MULTI_UNLOCK();
1545 return (error);
1546 }
1547
1548 /*
1549 * Given an inpcb, return its multicast options structure pointer. Accepts
1550 * an unlocked inpcb pointer, but will return it locked. May sleep.
1551 *
1552 * SMPng: NOTE: Returns with the INP write lock held.
1553 */
1554 static struct ip_moptions *
inp_findmoptions(struct inpcb * inp)1555 inp_findmoptions(struct inpcb *inp)
1556 {
1557 struct ip_moptions *imo;
1558
1559 INP_WLOCK(inp);
1560 if (inp->inp_moptions != NULL)
1561 return (inp->inp_moptions);
1562
1563 INP_WUNLOCK(inp);
1564
1565 imo = malloc(sizeof(*imo), M_IPMOPTS, M_WAITOK);
1566
1567 imo->imo_multicast_ifp = NULL;
1568 imo->imo_multicast_addr.s_addr = INADDR_ANY;
1569 imo->imo_multicast_vif = -1;
1570 imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
1571 imo->imo_multicast_loop = in_mcast_loop;
1572 STAILQ_INIT(&imo->imo_head);
1573
1574 INP_WLOCK(inp);
1575 if (inp->inp_moptions != NULL) {
1576 free(imo, M_IPMOPTS);
1577 return (inp->inp_moptions);
1578 }
1579 inp->inp_moptions = imo;
1580 return (imo);
1581 }
1582
1583 void
inp_freemoptions(struct ip_moptions * imo)1584 inp_freemoptions(struct ip_moptions *imo)
1585 {
1586 struct in_mfilter *imf;
1587 struct in_multi *inm;
1588 struct ifnet *ifp;
1589
1590 if (imo == NULL)
1591 return;
1592
1593 while ((imf = ip_mfilter_first(&imo->imo_head)) != NULL) {
1594 ip_mfilter_remove(&imo->imo_head, imf);
1595
1596 imf_leave(imf);
1597 if ((inm = imf->imf_inm) != NULL) {
1598 if ((ifp = inm->inm_ifp) != NULL) {
1599 CURVNET_SET(ifp->if_vnet);
1600 (void)in_leavegroup(inm, imf);
1601 CURVNET_RESTORE();
1602 } else {
1603 (void)in_leavegroup(inm, imf);
1604 }
1605 }
1606 ip_mfilter_free(imf);
1607 }
1608 free(imo, M_IPMOPTS);
1609 }
1610
1611 /*
1612 * Atomically get source filters on a socket for an IPv4 multicast group.
1613 * Called with INP lock held; returns with lock released.
1614 */
1615 static int
inp_get_source_filters(struct inpcb * inp,struct sockopt * sopt)1616 inp_get_source_filters(struct inpcb *inp, struct sockopt *sopt)
1617 {
1618 struct epoch_tracker et;
1619 struct __msfilterreq msfr;
1620 sockunion_t *gsa;
1621 struct ifnet *ifp;
1622 struct ip_moptions *imo;
1623 struct in_mfilter *imf;
1624 struct ip_msource *ims;
1625 struct in_msource *lims;
1626 struct sockaddr_in *psin;
1627 struct sockaddr_storage *ptss;
1628 struct sockaddr_storage *tss;
1629 int error;
1630 size_t nsrcs, ncsrcs;
1631
1632 INP_WLOCK_ASSERT(inp);
1633
1634 imo = inp->inp_moptions;
1635 KASSERT(imo != NULL, ("%s: null ip_moptions", __func__));
1636
1637 INP_WUNLOCK(inp);
1638
1639 error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq),
1640 sizeof(struct __msfilterreq));
1641 if (error)
1642 return (error);
1643
1644 NET_EPOCH_ENTER(et);
1645 ifp = ifnet_byindex(msfr.msfr_ifindex);
1646 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifnet pointer left */
1647 if (ifp == NULL)
1648 return (EINVAL);
1649
1650 INP_WLOCK(inp);
1651
1652 /*
1653 * Lookup group on the socket.
1654 */
1655 gsa = (sockunion_t *)&msfr.msfr_group;
1656 imf = imo_match_group(imo, ifp, &gsa->sa);
1657 if (imf == NULL) {
1658 INP_WUNLOCK(inp);
1659 return (EADDRNOTAVAIL);
1660 }
1661
1662 /*
1663 * Ignore memberships which are in limbo.
1664 */
1665 if (imf->imf_st[1] == MCAST_UNDEFINED) {
1666 INP_WUNLOCK(inp);
1667 return (EAGAIN);
1668 }
1669 msfr.msfr_fmode = imf->imf_st[1];
1670
1671 /*
1672 * If the user specified a buffer, copy out the source filter
1673 * entries to userland gracefully.
1674 * We only copy out the number of entries which userland
1675 * has asked for, but we always tell userland how big the
1676 * buffer really needs to be.
1677 */
1678 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc)
1679 msfr.msfr_nsrcs = in_mcast_maxsocksrc;
1680 tss = NULL;
1681 if (msfr.msfr_srcs != NULL && msfr.msfr_nsrcs > 0) {
1682 tss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs,
1683 M_TEMP, M_NOWAIT | M_ZERO);
1684 if (tss == NULL) {
1685 INP_WUNLOCK(inp);
1686 return (ENOBUFS);
1687 }
1688 }
1689
1690 /*
1691 * Count number of sources in-mode at t0.
1692 * If buffer space exists and remains, copy out source entries.
1693 */
1694 nsrcs = msfr.msfr_nsrcs;
1695 ncsrcs = 0;
1696 ptss = tss;
1697 RB_FOREACH(ims, ip_msource_tree, &imf->imf_sources) {
1698 lims = (struct in_msource *)ims;
1699 if (lims->imsl_st[0] == MCAST_UNDEFINED ||
1700 lims->imsl_st[0] != imf->imf_st[0])
1701 continue;
1702 ++ncsrcs;
1703 if (tss != NULL && nsrcs > 0) {
1704 psin = (struct sockaddr_in *)ptss;
1705 psin->sin_family = AF_INET;
1706 psin->sin_len = sizeof(struct sockaddr_in);
1707 psin->sin_addr.s_addr = htonl(lims->ims_haddr);
1708 psin->sin_port = 0;
1709 ++ptss;
1710 --nsrcs;
1711 }
1712 }
1713
1714 INP_WUNLOCK(inp);
1715
1716 if (tss != NULL) {
1717 error = copyout(tss, msfr.msfr_srcs,
1718 sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs);
1719 free(tss, M_TEMP);
1720 if (error)
1721 return (error);
1722 }
1723
1724 msfr.msfr_nsrcs = ncsrcs;
1725 error = sooptcopyout(sopt, &msfr, sizeof(struct __msfilterreq));
1726
1727 return (error);
1728 }
1729
1730 /*
1731 * Return the IP multicast options in response to user getsockopt().
1732 */
1733 int
inp_getmoptions(struct inpcb * inp,struct sockopt * sopt)1734 inp_getmoptions(struct inpcb *inp, struct sockopt *sopt)
1735 {
1736 struct ip_mreqn mreqn;
1737 struct ip_moptions *imo;
1738 struct ifnet *ifp;
1739 struct in_ifaddr *ia;
1740 int error, optval;
1741 u_char coptval;
1742
1743 INP_WLOCK(inp);
1744 imo = inp->inp_moptions;
1745 /* If socket is neither of type SOCK_RAW or SOCK_DGRAM reject it. */
1746 if (inp->inp_socket->so_proto->pr_type != SOCK_RAW &&
1747 inp->inp_socket->so_proto->pr_type != SOCK_DGRAM) {
1748 INP_WUNLOCK(inp);
1749 return (EOPNOTSUPP);
1750 }
1751
1752 error = 0;
1753 switch (sopt->sopt_name) {
1754 case IP_MULTICAST_VIF:
1755 if (imo != NULL)
1756 optval = imo->imo_multicast_vif;
1757 else
1758 optval = -1;
1759 INP_WUNLOCK(inp);
1760 error = sooptcopyout(sopt, &optval, sizeof(int));
1761 break;
1762
1763 case IP_MULTICAST_IF:
1764 memset(&mreqn, 0, sizeof(struct ip_mreqn));
1765 if (imo != NULL) {
1766 ifp = imo->imo_multicast_ifp;
1767 if (!in_nullhost(imo->imo_multicast_addr)) {
1768 mreqn.imr_address = imo->imo_multicast_addr;
1769 } else if (ifp != NULL) {
1770 struct epoch_tracker et;
1771
1772 mreqn.imr_ifindex = ifp->if_index;
1773 NET_EPOCH_ENTER(et);
1774 IFP_TO_IA(ifp, ia);
1775 if (ia != NULL)
1776 mreqn.imr_address =
1777 IA_SIN(ia)->sin_addr;
1778 NET_EPOCH_EXIT(et);
1779 }
1780 }
1781 INP_WUNLOCK(inp);
1782 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) {
1783 error = sooptcopyout(sopt, &mreqn,
1784 sizeof(struct ip_mreqn));
1785 } else {
1786 error = sooptcopyout(sopt, &mreqn.imr_address,
1787 sizeof(struct in_addr));
1788 }
1789 break;
1790
1791 case IP_MULTICAST_TTL:
1792 if (imo == NULL)
1793 optval = coptval = IP_DEFAULT_MULTICAST_TTL;
1794 else
1795 optval = coptval = imo->imo_multicast_ttl;
1796 INP_WUNLOCK(inp);
1797 if (sopt->sopt_valsize == sizeof(u_char))
1798 error = sooptcopyout(sopt, &coptval, sizeof(u_char));
1799 else
1800 error = sooptcopyout(sopt, &optval, sizeof(int));
1801 break;
1802
1803 case IP_MULTICAST_LOOP:
1804 if (imo == NULL)
1805 optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
1806 else
1807 optval = coptval = imo->imo_multicast_loop;
1808 INP_WUNLOCK(inp);
1809 if (sopt->sopt_valsize == sizeof(u_char))
1810 error = sooptcopyout(sopt, &coptval, sizeof(u_char));
1811 else
1812 error = sooptcopyout(sopt, &optval, sizeof(int));
1813 break;
1814
1815 case IP_MSFILTER:
1816 if (imo == NULL) {
1817 error = EADDRNOTAVAIL;
1818 INP_WUNLOCK(inp);
1819 } else {
1820 error = inp_get_source_filters(inp, sopt);
1821 }
1822 break;
1823
1824 default:
1825 INP_WUNLOCK(inp);
1826 error = ENOPROTOOPT;
1827 break;
1828 }
1829
1830 INP_UNLOCK_ASSERT(inp);
1831
1832 return (error);
1833 }
1834
1835 /*
1836 * Look up the ifnet to use for a multicast group membership,
1837 * given the IPv4 address of an interface, and the IPv4 group address.
1838 *
1839 * This routine exists to support legacy multicast applications
1840 * which do not understand that multicast memberships are scoped to
1841 * specific physical links in the networking stack, or which need
1842 * to join link-scope groups before IPv4 addresses are configured.
1843 *
1844 * Use this socket's current FIB number for any required FIB lookup.
1845 * If ina is INADDR_ANY, look up the group address in the unicast FIB,
1846 * and use its ifp; usually, this points to the default next-hop.
1847 *
1848 * If the FIB lookup fails, attempt to use the first non-loopback
1849 * interface with multicast capability in the system as a
1850 * last resort. The legacy IPv4 ASM API requires that we do
1851 * this in order to allow groups to be joined when the routing
1852 * table has not yet been populated during boot.
1853 *
1854 * Returns NULL if no ifp could be found, otherwise return referenced ifp.
1855 *
1856 * FUTURE: Implement IPv4 source-address selection.
1857 */
1858 static struct ifnet *
inp_lookup_mcast_ifp(const struct inpcb * inp,const struct sockaddr_in * gsin,const struct in_addr ina)1859 inp_lookup_mcast_ifp(const struct inpcb *inp,
1860 const struct sockaddr_in *gsin, const struct in_addr ina)
1861 {
1862 struct ifnet *ifp;
1863 struct nhop_object *nh;
1864
1865 NET_EPOCH_ASSERT();
1866 KASSERT(inp != NULL, ("%s: inp must not be NULL", __func__));
1867 KASSERT(gsin->sin_family == AF_INET, ("%s: not AF_INET", __func__));
1868 KASSERT(IN_MULTICAST(ntohl(gsin->sin_addr.s_addr)),
1869 ("%s: not multicast", __func__));
1870
1871 ifp = NULL;
1872 if (!in_nullhost(ina)) {
1873 INADDR_TO_IFP(ina, ifp);
1874 if (ifp != NULL)
1875 if_ref(ifp);
1876 } else {
1877 nh = fib4_lookup(inp->inp_inc.inc_fibnum, gsin->sin_addr, 0, NHR_NONE, 0);
1878 if (nh != NULL) {
1879 ifp = nh->nh_ifp;
1880 if_ref(ifp);
1881 } else {
1882 struct in_ifaddr *ia;
1883 struct ifnet *mifp;
1884
1885 mifp = NULL;
1886 CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
1887 mifp = ia->ia_ifp;
1888 if (!(mifp->if_flags & IFF_LOOPBACK) &&
1889 (mifp->if_flags & IFF_MULTICAST)) {
1890 ifp = mifp;
1891 if_ref(ifp);
1892 break;
1893 }
1894 }
1895 }
1896 }
1897
1898 return (ifp);
1899 }
1900
1901 /*
1902 * Join an IPv4 multicast group, possibly with a source.
1903 */
1904 static int
inp_join_group(struct inpcb * inp,struct sockopt * sopt)1905 inp_join_group(struct inpcb *inp, struct sockopt *sopt)
1906 {
1907 struct group_source_req gsr;
1908 sockunion_t *gsa, *ssa;
1909 struct ifnet *ifp;
1910 struct in_mfilter *imf;
1911 struct ip_moptions *imo;
1912 struct in_multi *inm;
1913 struct in_msource *lims;
1914 struct epoch_tracker et;
1915 int error, is_new;
1916
1917 ifp = NULL;
1918 lims = NULL;
1919 error = 0;
1920
1921 memset(&gsr, 0, sizeof(struct group_source_req));
1922 gsa = (sockunion_t *)&gsr.gsr_group;
1923 gsa->ss.ss_family = AF_UNSPEC;
1924 ssa = (sockunion_t *)&gsr.gsr_source;
1925 ssa->ss.ss_family = AF_UNSPEC;
1926
1927 switch (sopt->sopt_name) {
1928 case IP_ADD_MEMBERSHIP: {
1929 struct ip_mreqn mreqn;
1930
1931 if (sopt->sopt_valsize == sizeof(struct ip_mreqn))
1932 error = sooptcopyin(sopt, &mreqn,
1933 sizeof(struct ip_mreqn), sizeof(struct ip_mreqn));
1934 else
1935 error = sooptcopyin(sopt, &mreqn,
1936 sizeof(struct ip_mreq), sizeof(struct ip_mreq));
1937 if (error)
1938 return (error);
1939
1940 gsa->sin.sin_family = AF_INET;
1941 gsa->sin.sin_len = sizeof(struct sockaddr_in);
1942 gsa->sin.sin_addr = mreqn.imr_multiaddr;
1943 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
1944 return (EINVAL);
1945
1946 NET_EPOCH_ENTER(et);
1947 if (sopt->sopt_valsize == sizeof(struct ip_mreqn) &&
1948 mreqn.imr_ifindex != 0)
1949 ifp = ifnet_byindex_ref(mreqn.imr_ifindex);
1950 else
1951 ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
1952 mreqn.imr_address);
1953 NET_EPOCH_EXIT(et);
1954 break;
1955 }
1956 case IP_ADD_SOURCE_MEMBERSHIP: {
1957 struct ip_mreq_source mreqs;
1958
1959 error = sooptcopyin(sopt, &mreqs, sizeof(struct ip_mreq_source),
1960 sizeof(struct ip_mreq_source));
1961 if (error)
1962 return (error);
1963
1964 gsa->sin.sin_family = ssa->sin.sin_family = AF_INET;
1965 gsa->sin.sin_len = ssa->sin.sin_len =
1966 sizeof(struct sockaddr_in);
1967
1968 gsa->sin.sin_addr = mreqs.imr_multiaddr;
1969 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
1970 return (EINVAL);
1971
1972 ssa->sin.sin_addr = mreqs.imr_sourceaddr;
1973
1974 NET_EPOCH_ENTER(et);
1975 ifp = inp_lookup_mcast_ifp(inp, &gsa->sin,
1976 mreqs.imr_interface);
1977 NET_EPOCH_EXIT(et);
1978 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
1979 __func__, ntohl(mreqs.imr_interface.s_addr), ifp);
1980 break;
1981 }
1982
1983 case MCAST_JOIN_GROUP:
1984 case MCAST_JOIN_SOURCE_GROUP:
1985 if (sopt->sopt_name == MCAST_JOIN_GROUP) {
1986 error = sooptcopyin(sopt, &gsr,
1987 sizeof(struct group_req),
1988 sizeof(struct group_req));
1989 } else if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) {
1990 error = sooptcopyin(sopt, &gsr,
1991 sizeof(struct group_source_req),
1992 sizeof(struct group_source_req));
1993 }
1994 if (error)
1995 return (error);
1996
1997 if (gsa->sin.sin_family != AF_INET ||
1998 gsa->sin.sin_len != sizeof(struct sockaddr_in))
1999 return (EINVAL);
2000
2001 /*
2002 * Overwrite the port field if present, as the sockaddr
2003 * being copied in may be matched with a binary comparison.
2004 */
2005 gsa->sin.sin_port = 0;
2006 if (sopt->sopt_name == MCAST_JOIN_SOURCE_GROUP) {
2007 if (ssa->sin.sin_family != AF_INET ||
2008 ssa->sin.sin_len != sizeof(struct sockaddr_in))
2009 return (EINVAL);
2010 ssa->sin.sin_port = 0;
2011 }
2012
2013 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
2014 return (EINVAL);
2015
2016 NET_EPOCH_ENTER(et);
2017 ifp = ifnet_byindex_ref(gsr.gsr_interface);
2018 NET_EPOCH_EXIT(et);
2019 if (ifp == NULL)
2020 return (EADDRNOTAVAIL);
2021 break;
2022
2023 default:
2024 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d",
2025 __func__, sopt->sopt_name);
2026 return (EOPNOTSUPP);
2027 break;
2028 }
2029
2030 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2031 if (ifp != NULL)
2032 if_rele(ifp);
2033 return (EADDRNOTAVAIL);
2034 }
2035
2036 IN_MULTI_LOCK();
2037
2038 /*
2039 * Find the membership in the membership list.
2040 */
2041 imo = inp_findmoptions(inp);
2042 imf = imo_match_group(imo, ifp, &gsa->sa);
2043 if (imf == NULL) {
2044 is_new = 1;
2045 inm = NULL;
2046
2047 if (ip_mfilter_count(&imo->imo_head) >= IP_MAX_MEMBERSHIPS) {
2048 error = ENOMEM;
2049 goto out_inp_locked;
2050 }
2051 } else {
2052 is_new = 0;
2053 inm = imf->imf_inm;
2054
2055 if (ssa->ss.ss_family != AF_UNSPEC) {
2056 /*
2057 * MCAST_JOIN_SOURCE_GROUP on an exclusive membership
2058 * is an error. On an existing inclusive membership,
2059 * it just adds the source to the filter list.
2060 */
2061 if (imf->imf_st[1] != MCAST_INCLUDE) {
2062 error = EINVAL;
2063 goto out_inp_locked;
2064 }
2065 /*
2066 * Throw out duplicates.
2067 *
2068 * XXX FIXME: This makes a naive assumption that
2069 * even if entries exist for *ssa in this imf,
2070 * they will be rejected as dupes, even if they
2071 * are not valid in the current mode (in-mode).
2072 *
2073 * in_msource is transactioned just as for anything
2074 * else in SSM -- but note naive use of inm_graft()
2075 * below for allocating new filter entries.
2076 *
2077 * This is only an issue if someone mixes the
2078 * full-state SSM API with the delta-based API,
2079 * which is discouraged in the relevant RFCs.
2080 */
2081 lims = imo_match_source(imf, &ssa->sa);
2082 if (lims != NULL /*&&
2083 lims->imsl_st[1] == MCAST_INCLUDE*/) {
2084 error = EADDRNOTAVAIL;
2085 goto out_inp_locked;
2086 }
2087 } else {
2088 /*
2089 * MCAST_JOIN_GROUP on an existing exclusive
2090 * membership is an error; return EADDRINUSE
2091 * to preserve 4.4BSD API idempotence, and
2092 * avoid tedious detour to code below.
2093 * NOTE: This is bending RFC 3678 a bit.
2094 *
2095 * On an existing inclusive membership, this is also
2096 * an error; if you want to change filter mode,
2097 * you must use the userland API setsourcefilter().
2098 * XXX We don't reject this for imf in UNDEFINED
2099 * state at t1, because allocation of a filter
2100 * is atomic with allocation of a membership.
2101 */
2102 error = EINVAL;
2103 if (imf->imf_st[1] == MCAST_EXCLUDE)
2104 error = EADDRINUSE;
2105 goto out_inp_locked;
2106 }
2107 }
2108
2109 /*
2110 * Begin state merge transaction at socket layer.
2111 */
2112 INP_WLOCK_ASSERT(inp);
2113
2114 /*
2115 * Graft new source into filter list for this inpcb's
2116 * membership of the group. The in_multi may not have
2117 * been allocated yet if this is a new membership, however,
2118 * the in_mfilter slot will be allocated and must be initialized.
2119 *
2120 * Note: Grafting of exclusive mode filters doesn't happen
2121 * in this path.
2122 * XXX: Should check for non-NULL lims (node exists but may
2123 * not be in-mode) for interop with full-state API.
2124 */
2125 if (ssa->ss.ss_family != AF_UNSPEC) {
2126 /* Membership starts in IN mode */
2127 if (is_new) {
2128 CTR1(KTR_IGMPV3, "%s: new join w/source", __func__);
2129 imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_INCLUDE);
2130 if (imf == NULL) {
2131 error = ENOMEM;
2132 goto out_inp_locked;
2133 }
2134 } else {
2135 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "allow");
2136 }
2137 lims = imf_graft(imf, MCAST_INCLUDE, &ssa->sin);
2138 if (lims == NULL) {
2139 CTR1(KTR_IGMPV3, "%s: merge imf state failed",
2140 __func__);
2141 error = ENOMEM;
2142 goto out_inp_locked;
2143 }
2144 } else {
2145 /* No address specified; Membership starts in EX mode */
2146 if (is_new) {
2147 CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__);
2148 imf = ip_mfilter_alloc(M_NOWAIT, MCAST_UNDEFINED, MCAST_EXCLUDE);
2149 if (imf == NULL) {
2150 error = ENOMEM;
2151 goto out_inp_locked;
2152 }
2153 }
2154 }
2155
2156 /*
2157 * Begin state merge transaction at IGMP layer.
2158 */
2159 if (is_new) {
2160 in_pcbref(inp);
2161 INP_WUNLOCK(inp);
2162
2163 error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf,
2164 &imf->imf_inm);
2165
2166 INP_WLOCK(inp);
2167 if (in_pcbrele_wlocked(inp)) {
2168 error = ENXIO;
2169 goto out_inp_unlocked;
2170 }
2171 if (error) {
2172 CTR1(KTR_IGMPV3, "%s: in_joingroup_locked failed",
2173 __func__);
2174 goto out_inp_locked;
2175 }
2176 /*
2177 * NOTE: Refcount from in_joingroup_locked()
2178 * is protecting membership.
2179 */
2180 ip_mfilter_insert(&imo->imo_head, imf);
2181 } else {
2182 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
2183 IN_MULTI_LIST_LOCK();
2184 error = inm_merge(inm, imf);
2185 if (error) {
2186 CTR1(KTR_IGMPV3, "%s: failed to merge inm state",
2187 __func__);
2188 IN_MULTI_LIST_UNLOCK();
2189 imf_rollback(imf);
2190 imf_reap(imf);
2191 goto out_inp_locked;
2192 }
2193 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
2194 error = igmp_change_state(inm);
2195 IN_MULTI_LIST_UNLOCK();
2196 if (error) {
2197 CTR1(KTR_IGMPV3, "%s: failed igmp downcall",
2198 __func__);
2199 imf_rollback(imf);
2200 imf_reap(imf);
2201 goto out_inp_locked;
2202 }
2203 }
2204
2205 imf_commit(imf);
2206 imf = NULL;
2207
2208 out_inp_locked:
2209 INP_WUNLOCK(inp);
2210 out_inp_unlocked:
2211 IN_MULTI_UNLOCK();
2212
2213 if (is_new && imf) {
2214 if (imf->imf_inm != NULL) {
2215 IN_MULTI_LIST_LOCK();
2216 IF_ADDR_WLOCK(ifp);
2217 inm_release_deferred(imf->imf_inm);
2218 IF_ADDR_WUNLOCK(ifp);
2219 IN_MULTI_LIST_UNLOCK();
2220 }
2221 ip_mfilter_free(imf);
2222 }
2223 if_rele(ifp);
2224 return (error);
2225 }
2226
2227 /*
2228 * Leave an IPv4 multicast group on an inpcb, possibly with a source.
2229 */
2230 static int
inp_leave_group(struct inpcb * inp,struct sockopt * sopt)2231 inp_leave_group(struct inpcb *inp, struct sockopt *sopt)
2232 {
2233 struct epoch_tracker et;
2234 struct group_source_req gsr;
2235 struct ip_mreq_source mreqs;
2236 sockunion_t *gsa, *ssa;
2237 struct ifnet *ifp;
2238 struct in_mfilter *imf;
2239 struct ip_moptions *imo;
2240 struct in_msource *ims;
2241 struct in_multi *inm;
2242 int error;
2243 bool is_final;
2244
2245 ifp = NULL;
2246 error = 0;
2247 is_final = true;
2248
2249 memset(&gsr, 0, sizeof(struct group_source_req));
2250 gsa = (sockunion_t *)&gsr.gsr_group;
2251 gsa->ss.ss_family = AF_UNSPEC;
2252 ssa = (sockunion_t *)&gsr.gsr_source;
2253 ssa->ss.ss_family = AF_UNSPEC;
2254
2255 switch (sopt->sopt_name) {
2256 case IP_DROP_MEMBERSHIP:
2257 case IP_DROP_SOURCE_MEMBERSHIP:
2258 if (sopt->sopt_name == IP_DROP_MEMBERSHIP) {
2259 error = sooptcopyin(sopt, &mreqs,
2260 sizeof(struct ip_mreq),
2261 sizeof(struct ip_mreq));
2262 /*
2263 * Swap interface and sourceaddr arguments,
2264 * as ip_mreq and ip_mreq_source are laid
2265 * out differently.
2266 */
2267 mreqs.imr_interface = mreqs.imr_sourceaddr;
2268 mreqs.imr_sourceaddr.s_addr = INADDR_ANY;
2269 } else if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) {
2270 error = sooptcopyin(sopt, &mreqs,
2271 sizeof(struct ip_mreq_source),
2272 sizeof(struct ip_mreq_source));
2273 }
2274 if (error)
2275 return (error);
2276
2277 gsa->sin.sin_family = AF_INET;
2278 gsa->sin.sin_len = sizeof(struct sockaddr_in);
2279 gsa->sin.sin_addr = mreqs.imr_multiaddr;
2280
2281 if (sopt->sopt_name == IP_DROP_SOURCE_MEMBERSHIP) {
2282 ssa->sin.sin_family = AF_INET;
2283 ssa->sin.sin_len = sizeof(struct sockaddr_in);
2284 ssa->sin.sin_addr = mreqs.imr_sourceaddr;
2285 }
2286
2287 /*
2288 * Attempt to look up hinted ifp from interface address.
2289 * Fallthrough with null ifp iff lookup fails, to
2290 * preserve 4.4BSD mcast API idempotence.
2291 * XXX NOTE WELL: The RFC 3678 API is preferred because
2292 * using an IPv4 address as a key is racy.
2293 */
2294 if (!in_nullhost(mreqs.imr_interface)) {
2295 NET_EPOCH_ENTER(et);
2296 INADDR_TO_IFP(mreqs.imr_interface, ifp);
2297 /* XXXGL ifref? */
2298 NET_EPOCH_EXIT(et);
2299 }
2300 CTR3(KTR_IGMPV3, "%s: imr_interface = 0x%08x, ifp = %p",
2301 __func__, ntohl(mreqs.imr_interface.s_addr), ifp);
2302
2303 break;
2304
2305 case MCAST_LEAVE_GROUP:
2306 case MCAST_LEAVE_SOURCE_GROUP:
2307 if (sopt->sopt_name == MCAST_LEAVE_GROUP) {
2308 error = sooptcopyin(sopt, &gsr,
2309 sizeof(struct group_req),
2310 sizeof(struct group_req));
2311 } else if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) {
2312 error = sooptcopyin(sopt, &gsr,
2313 sizeof(struct group_source_req),
2314 sizeof(struct group_source_req));
2315 }
2316 if (error)
2317 return (error);
2318
2319 if (gsa->sin.sin_family != AF_INET ||
2320 gsa->sin.sin_len != sizeof(struct sockaddr_in))
2321 return (EINVAL);
2322
2323 if (sopt->sopt_name == MCAST_LEAVE_SOURCE_GROUP) {
2324 if (ssa->sin.sin_family != AF_INET ||
2325 ssa->sin.sin_len != sizeof(struct sockaddr_in))
2326 return (EINVAL);
2327 }
2328
2329 NET_EPOCH_ENTER(et);
2330 ifp = ifnet_byindex(gsr.gsr_interface);
2331 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */
2332 if (ifp == NULL)
2333 return (EADDRNOTAVAIL);
2334 break;
2335
2336 default:
2337 CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d",
2338 __func__, sopt->sopt_name);
2339 return (EOPNOTSUPP);
2340 break;
2341 }
2342
2343 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
2344 return (EINVAL);
2345
2346 IN_MULTI_LOCK();
2347
2348 /*
2349 * Find the membership in the membership list.
2350 */
2351 imo = inp_findmoptions(inp);
2352 imf = imo_match_group(imo, ifp, &gsa->sa);
2353 if (imf == NULL) {
2354 error = EADDRNOTAVAIL;
2355 goto out_inp_locked;
2356 }
2357 inm = imf->imf_inm;
2358
2359 if (ssa->ss.ss_family != AF_UNSPEC)
2360 is_final = false;
2361
2362 /*
2363 * Begin state merge transaction at socket layer.
2364 */
2365 INP_WLOCK_ASSERT(inp);
2366
2367 /*
2368 * If we were instructed only to leave a given source, do so.
2369 * MCAST_LEAVE_SOURCE_GROUP is only valid for inclusive memberships.
2370 */
2371 if (is_final) {
2372 ip_mfilter_remove(&imo->imo_head, imf);
2373 imf_leave(imf);
2374
2375 /*
2376 * Give up the multicast address record to which
2377 * the membership points.
2378 */
2379 (void) in_leavegroup_locked(imf->imf_inm, imf);
2380 } else {
2381 if (imf->imf_st[0] == MCAST_EXCLUDE) {
2382 error = EADDRNOTAVAIL;
2383 goto out_inp_locked;
2384 }
2385 ims = imo_match_source(imf, &ssa->sa);
2386 if (ims == NULL) {
2387 CTR3(KTR_IGMPV3, "%s: source 0x%08x %spresent",
2388 __func__, ntohl(ssa->sin.sin_addr.s_addr), "not ");
2389 error = EADDRNOTAVAIL;
2390 goto out_inp_locked;
2391 }
2392 CTR2(KTR_IGMPV3, "%s: %s source", __func__, "block");
2393 error = imf_prune(imf, &ssa->sin);
2394 if (error) {
2395 CTR1(KTR_IGMPV3, "%s: merge imf state failed",
2396 __func__);
2397 goto out_inp_locked;
2398 }
2399 }
2400
2401 /*
2402 * Begin state merge transaction at IGMP layer.
2403 */
2404 if (!is_final) {
2405 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
2406 IN_MULTI_LIST_LOCK();
2407 error = inm_merge(inm, imf);
2408 if (error) {
2409 CTR1(KTR_IGMPV3, "%s: failed to merge inm state",
2410 __func__);
2411 IN_MULTI_LIST_UNLOCK();
2412 imf_rollback(imf);
2413 imf_reap(imf);
2414 goto out_inp_locked;
2415 }
2416
2417 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
2418 error = igmp_change_state(inm);
2419 IN_MULTI_LIST_UNLOCK();
2420 if (error) {
2421 CTR1(KTR_IGMPV3, "%s: failed igmp downcall",
2422 __func__);
2423 imf_rollback(imf);
2424 imf_reap(imf);
2425 goto out_inp_locked;
2426 }
2427 }
2428 imf_commit(imf);
2429 imf_reap(imf);
2430
2431 out_inp_locked:
2432 INP_WUNLOCK(inp);
2433
2434 if (is_final && imf)
2435 ip_mfilter_free(imf);
2436
2437 IN_MULTI_UNLOCK();
2438 return (error);
2439 }
2440
2441 /*
2442 * Select the interface for transmitting IPv4 multicast datagrams.
2443 *
2444 * Either an instance of struct in_addr or an instance of struct ip_mreqn
2445 * may be passed to this socket option. An address of INADDR_ANY or an
2446 * interface index of 0 is used to remove a previous selection.
2447 * When no interface is selected, one is chosen for every send.
2448 */
2449 static int
inp_set_multicast_if(struct inpcb * inp,struct sockopt * sopt)2450 inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt)
2451 {
2452 struct in_addr addr;
2453 struct ip_mreqn mreqn;
2454 struct ifnet *ifp;
2455 struct ip_moptions *imo;
2456 int error;
2457
2458 if (sopt->sopt_valsize == sizeof(struct ip_mreqn)) {
2459 /*
2460 * An interface index was specified using the
2461 * Linux-derived ip_mreqn structure.
2462 */
2463 error = sooptcopyin(sopt, &mreqn, sizeof(struct ip_mreqn),
2464 sizeof(struct ip_mreqn));
2465 if (error)
2466 return (error);
2467
2468 if (mreqn.imr_ifindex < 0)
2469 return (EINVAL);
2470
2471 if (mreqn.imr_ifindex == 0) {
2472 ifp = NULL;
2473 } else {
2474 struct epoch_tracker et;
2475
2476 NET_EPOCH_ENTER(et);
2477 ifp = ifnet_byindex(mreqn.imr_ifindex);
2478 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */
2479 if (ifp == NULL)
2480 return (EADDRNOTAVAIL);
2481 }
2482 } else {
2483 /*
2484 * An interface was specified by IPv4 address.
2485 * This is the traditional BSD usage.
2486 */
2487 error = sooptcopyin(sopt, &addr, sizeof(struct in_addr),
2488 sizeof(struct in_addr));
2489 if (error)
2490 return (error);
2491 if (in_nullhost(addr)) {
2492 ifp = NULL;
2493 } else {
2494 struct epoch_tracker et;
2495
2496 NET_EPOCH_ENTER(et);
2497 INADDR_TO_IFP(addr, ifp);
2498 /* XXXGL ifref? */
2499 NET_EPOCH_EXIT(et);
2500 if (ifp == NULL)
2501 return (EADDRNOTAVAIL);
2502 }
2503 CTR3(KTR_IGMPV3, "%s: ifp = %p, addr = 0x%08x", __func__, ifp,
2504 ntohl(addr.s_addr));
2505 }
2506
2507 /* Reject interfaces which do not support multicast. */
2508 if (ifp != NULL && (ifp->if_flags & IFF_MULTICAST) == 0)
2509 return (EOPNOTSUPP);
2510
2511 imo = inp_findmoptions(inp);
2512 imo->imo_multicast_ifp = ifp;
2513 imo->imo_multicast_addr.s_addr = INADDR_ANY;
2514 INP_WUNLOCK(inp);
2515
2516 return (0);
2517 }
2518
2519 /*
2520 * Atomically set source filters on a socket for an IPv4 multicast group.
2521 */
2522 static int
inp_set_source_filters(struct inpcb * inp,struct sockopt * sopt)2523 inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt)
2524 {
2525 struct epoch_tracker et;
2526 struct __msfilterreq msfr;
2527 sockunion_t *gsa;
2528 struct ifnet *ifp;
2529 struct in_mfilter *imf;
2530 struct ip_moptions *imo;
2531 struct in_multi *inm;
2532 int error;
2533
2534 error = sooptcopyin(sopt, &msfr, sizeof(struct __msfilterreq),
2535 sizeof(struct __msfilterreq));
2536 if (error)
2537 return (error);
2538
2539 if (msfr.msfr_nsrcs > in_mcast_maxsocksrc)
2540 return (ENOBUFS);
2541
2542 if ((msfr.msfr_fmode != MCAST_EXCLUDE &&
2543 msfr.msfr_fmode != MCAST_INCLUDE))
2544 return (EINVAL);
2545
2546 if (msfr.msfr_group.ss_family != AF_INET ||
2547 msfr.msfr_group.ss_len != sizeof(struct sockaddr_in))
2548 return (EINVAL);
2549
2550 gsa = (sockunion_t *)&msfr.msfr_group;
2551 if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
2552 return (EINVAL);
2553
2554 gsa->sin.sin_port = 0; /* ignore port */
2555
2556 NET_EPOCH_ENTER(et);
2557 ifp = ifnet_byindex(msfr.msfr_ifindex);
2558 NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */
2559 if (ifp == NULL)
2560 return (EADDRNOTAVAIL);
2561
2562 IN_MULTI_LOCK();
2563
2564 /*
2565 * Take the INP write lock.
2566 * Check if this socket is a member of this group.
2567 */
2568 imo = inp_findmoptions(inp);
2569 imf = imo_match_group(imo, ifp, &gsa->sa);
2570 if (imf == NULL) {
2571 error = EADDRNOTAVAIL;
2572 goto out_inp_locked;
2573 }
2574 inm = imf->imf_inm;
2575
2576 /*
2577 * Begin state merge transaction at socket layer.
2578 */
2579 INP_WLOCK_ASSERT(inp);
2580
2581 imf->imf_st[1] = msfr.msfr_fmode;
2582
2583 /*
2584 * Apply any new source filters, if present.
2585 * Make a copy of the user-space source vector so
2586 * that we may copy them with a single copyin. This
2587 * allows us to deal with page faults up-front.
2588 */
2589 if (msfr.msfr_nsrcs > 0) {
2590 struct in_msource *lims;
2591 struct sockaddr_in *psin;
2592 struct sockaddr_storage *kss, *pkss;
2593 int i;
2594
2595 INP_WUNLOCK(inp);
2596
2597 CTR2(KTR_IGMPV3, "%s: loading %lu source list entries",
2598 __func__, (unsigned long)msfr.msfr_nsrcs);
2599 kss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs,
2600 M_TEMP, M_WAITOK);
2601 error = copyin(msfr.msfr_srcs, kss,
2602 sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs);
2603 if (error) {
2604 free(kss, M_TEMP);
2605 return (error);
2606 }
2607
2608 INP_WLOCK(inp);
2609
2610 /*
2611 * Mark all source filters as UNDEFINED at t1.
2612 * Restore new group filter mode, as imf_leave()
2613 * will set it to INCLUDE.
2614 */
2615 imf_leave(imf);
2616 imf->imf_st[1] = msfr.msfr_fmode;
2617
2618 /*
2619 * Update socket layer filters at t1, lazy-allocating
2620 * new entries. This saves a bunch of memory at the
2621 * cost of one RB_FIND() per source entry; duplicate
2622 * entries in the msfr_nsrcs vector are ignored.
2623 * If we encounter an error, rollback transaction.
2624 *
2625 * XXX This too could be replaced with a set-symmetric
2626 * difference like loop to avoid walking from root
2627 * every time, as the key space is common.
2628 */
2629 for (i = 0, pkss = kss; i < msfr.msfr_nsrcs; i++, pkss++) {
2630 psin = (struct sockaddr_in *)pkss;
2631 if (psin->sin_family != AF_INET) {
2632 error = EAFNOSUPPORT;
2633 break;
2634 }
2635 if (psin->sin_len != sizeof(struct sockaddr_in)) {
2636 error = EINVAL;
2637 break;
2638 }
2639 error = imf_get_source(imf, psin, &lims);
2640 if (error)
2641 break;
2642 lims->imsl_st[1] = imf->imf_st[1];
2643 }
2644 free(kss, M_TEMP);
2645 }
2646
2647 if (error)
2648 goto out_imf_rollback;
2649
2650 INP_WLOCK_ASSERT(inp);
2651
2652 /*
2653 * Begin state merge transaction at IGMP layer.
2654 */
2655 CTR1(KTR_IGMPV3, "%s: merge inm state", __func__);
2656 IN_MULTI_LIST_LOCK();
2657 error = inm_merge(inm, imf);
2658 if (error) {
2659 CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__);
2660 IN_MULTI_LIST_UNLOCK();
2661 goto out_imf_rollback;
2662 }
2663
2664 CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__);
2665 error = igmp_change_state(inm);
2666 IN_MULTI_LIST_UNLOCK();
2667 if (error)
2668 CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__);
2669
2670 out_imf_rollback:
2671 if (error)
2672 imf_rollback(imf);
2673 else
2674 imf_commit(imf);
2675
2676 imf_reap(imf);
2677
2678 out_inp_locked:
2679 INP_WUNLOCK(inp);
2680 IN_MULTI_UNLOCK();
2681 return (error);
2682 }
2683
2684 /*
2685 * Set the IP multicast options in response to user setsockopt().
2686 *
2687 * Many of the socket options handled in this function duplicate the
2688 * functionality of socket options in the regular unicast API. However,
2689 * it is not possible to merge the duplicate code, because the idempotence
2690 * of the IPv4 multicast part of the BSD Sockets API must be preserved;
2691 * the effects of these options must be treated as separate and distinct.
2692 *
2693 * SMPng: XXX: Unlocked read of inp_socket believed OK.
2694 * FUTURE: The IP_MULTICAST_VIF option may be eliminated if MROUTING
2695 * is refactored to no longer use vifs.
2696 */
2697 int
inp_setmoptions(struct inpcb * inp,struct sockopt * sopt)2698 inp_setmoptions(struct inpcb *inp, struct sockopt *sopt)
2699 {
2700 struct ip_moptions *imo;
2701 int error;
2702
2703 error = 0;
2704
2705 /* If socket is neither of type SOCK_RAW or SOCK_DGRAM, reject it. */
2706 if (inp->inp_socket->so_proto->pr_type != SOCK_RAW &&
2707 inp->inp_socket->so_proto->pr_type != SOCK_DGRAM)
2708 return (EOPNOTSUPP);
2709
2710 switch (sopt->sopt_name) {
2711 case IP_MULTICAST_VIF: {
2712 int vifi;
2713 /*
2714 * Select a multicast VIF for transmission.
2715 * Only useful if multicast forwarding is active.
2716 */
2717 if (legal_vif_num == NULL) {
2718 error = EOPNOTSUPP;
2719 break;
2720 }
2721 error = sooptcopyin(sopt, &vifi, sizeof(int), sizeof(int));
2722 if (error)
2723 break;
2724 if (!legal_vif_num(vifi) && (vifi != -1)) {
2725 error = EINVAL;
2726 break;
2727 }
2728 imo = inp_findmoptions(inp);
2729 imo->imo_multicast_vif = vifi;
2730 INP_WUNLOCK(inp);
2731 break;
2732 }
2733
2734 case IP_MULTICAST_IF:
2735 error = inp_set_multicast_if(inp, sopt);
2736 break;
2737
2738 case IP_MULTICAST_TTL: {
2739 u_char ttl;
2740
2741 /*
2742 * Set the IP time-to-live for outgoing multicast packets.
2743 * The original multicast API required a char argument,
2744 * which is inconsistent with the rest of the socket API.
2745 * We allow either a char or an int.
2746 */
2747 if (sopt->sopt_valsize == sizeof(u_char)) {
2748 error = sooptcopyin(sopt, &ttl, sizeof(u_char),
2749 sizeof(u_char));
2750 if (error)
2751 break;
2752 } else {
2753 u_int ittl;
2754
2755 error = sooptcopyin(sopt, &ittl, sizeof(u_int),
2756 sizeof(u_int));
2757 if (error)
2758 break;
2759 if (ittl > 255) {
2760 error = EINVAL;
2761 break;
2762 }
2763 ttl = (u_char)ittl;
2764 }
2765 imo = inp_findmoptions(inp);
2766 imo->imo_multicast_ttl = ttl;
2767 INP_WUNLOCK(inp);
2768 break;
2769 }
2770
2771 case IP_MULTICAST_LOOP: {
2772 u_char loop;
2773
2774 /*
2775 * Set the loopback flag for outgoing multicast packets.
2776 * Must be zero or one. The original multicast API required a
2777 * char argument, which is inconsistent with the rest
2778 * of the socket API. We allow either a char or an int.
2779 */
2780 if (sopt->sopt_valsize == sizeof(u_char)) {
2781 error = sooptcopyin(sopt, &loop, sizeof(u_char),
2782 sizeof(u_char));
2783 if (error)
2784 break;
2785 } else {
2786 u_int iloop;
2787
2788 error = sooptcopyin(sopt, &iloop, sizeof(u_int),
2789 sizeof(u_int));
2790 if (error)
2791 break;
2792 loop = (u_char)iloop;
2793 }
2794 imo = inp_findmoptions(inp);
2795 imo->imo_multicast_loop = !!loop;
2796 INP_WUNLOCK(inp);
2797 break;
2798 }
2799
2800 case IP_ADD_MEMBERSHIP:
2801 case IP_ADD_SOURCE_MEMBERSHIP:
2802 case MCAST_JOIN_GROUP:
2803 case MCAST_JOIN_SOURCE_GROUP:
2804 error = inp_join_group(inp, sopt);
2805 break;
2806
2807 case IP_DROP_MEMBERSHIP:
2808 case IP_DROP_SOURCE_MEMBERSHIP:
2809 case MCAST_LEAVE_GROUP:
2810 case MCAST_LEAVE_SOURCE_GROUP:
2811 error = inp_leave_group(inp, sopt);
2812 break;
2813
2814 case IP_BLOCK_SOURCE:
2815 case IP_UNBLOCK_SOURCE:
2816 case MCAST_BLOCK_SOURCE:
2817 case MCAST_UNBLOCK_SOURCE:
2818 error = inp_block_unblock_source(inp, sopt);
2819 break;
2820
2821 case IP_MSFILTER:
2822 error = inp_set_source_filters(inp, sopt);
2823 break;
2824
2825 default:
2826 error = EOPNOTSUPP;
2827 break;
2828 }
2829
2830 INP_UNLOCK_ASSERT(inp);
2831
2832 return (error);
2833 }
2834
2835 /*
2836 * Expose IGMP's multicast filter mode and source list(s) to userland,
2837 * keyed by (ifindex, group).
2838 * The filter mode is written out as a uint32_t, followed by
2839 * 0..n of struct in_addr.
2840 * For use by ifmcstat(8).
2841 * SMPng: NOTE: unlocked read of ifindex space.
2842 */
2843 static int
sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS)2844 sysctl_ip_mcast_filters(SYSCTL_HANDLER_ARGS)
2845 {
2846 struct in_addr src, group;
2847 struct epoch_tracker et;
2848 struct ifnet *ifp;
2849 struct ifmultiaddr *ifma;
2850 struct in_multi *inm;
2851 struct ip_msource *ims;
2852 int *name;
2853 int retval;
2854 u_int namelen;
2855 uint32_t fmode, ifindex;
2856
2857 name = (int *)arg1;
2858 namelen = arg2;
2859
2860 if (req->newptr != NULL)
2861 return (EPERM);
2862
2863 if (namelen != 2)
2864 return (EINVAL);
2865
2866 group.s_addr = name[1];
2867 if (!IN_MULTICAST(ntohl(group.s_addr))) {
2868 CTR2(KTR_IGMPV3, "%s: group 0x%08x is not multicast",
2869 __func__, ntohl(group.s_addr));
2870 return (EINVAL);
2871 }
2872
2873 ifindex = name[0];
2874 NET_EPOCH_ENTER(et);
2875 ifp = ifnet_byindex(ifindex);
2876 if (ifp == NULL) {
2877 NET_EPOCH_EXIT(et);
2878 CTR2(KTR_IGMPV3, "%s: no ifp for ifindex %u",
2879 __func__, ifindex);
2880 return (ENOENT);
2881 }
2882
2883 retval = sysctl_wire_old_buffer(req,
2884 sizeof(uint32_t) + (in_mcast_maxgrpsrc * sizeof(struct in_addr)));
2885 if (retval) {
2886 NET_EPOCH_EXIT(et);
2887 return (retval);
2888 }
2889
2890 IN_MULTI_LIST_LOCK();
2891
2892 CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2893 inm = inm_ifmultiaddr_get_inm(ifma);
2894 if (inm == NULL)
2895 continue;
2896 if (!in_hosteq(inm->inm_addr, group))
2897 continue;
2898 fmode = inm->inm_st[1].iss_fmode;
2899 retval = SYSCTL_OUT(req, &fmode, sizeof(uint32_t));
2900 if (retval != 0)
2901 break;
2902 RB_FOREACH(ims, ip_msource_tree, &inm->inm_srcs) {
2903 CTR2(KTR_IGMPV3, "%s: visit node 0x%08x", __func__,
2904 ims->ims_haddr);
2905 /*
2906 * Only copy-out sources which are in-mode.
2907 */
2908 if (fmode != ims_get_mode(inm, ims, 1)) {
2909 CTR1(KTR_IGMPV3, "%s: skip non-in-mode",
2910 __func__);
2911 continue;
2912 }
2913 src.s_addr = htonl(ims->ims_haddr);
2914 retval = SYSCTL_OUT(req, &src, sizeof(struct in_addr));
2915 if (retval != 0)
2916 break;
2917 }
2918 }
2919
2920 IN_MULTI_LIST_UNLOCK();
2921 NET_EPOCH_EXIT(et);
2922
2923 return (retval);
2924 }
2925
2926 #if defined(KTR) && (KTR_COMPILE & KTR_IGMPV3)
2927
2928 static const char *inm_modestrs[] = {
2929 [MCAST_UNDEFINED] = "un",
2930 [MCAST_INCLUDE] = "in",
2931 [MCAST_EXCLUDE] = "ex",
2932 };
2933 _Static_assert(MCAST_UNDEFINED == 0 &&
2934 MCAST_EXCLUDE + 1 == nitems(inm_modestrs),
2935 "inm_modestrs: no longer matches #defines");
2936
2937 static const char *
inm_mode_str(const int mode)2938 inm_mode_str(const int mode)
2939 {
2940
2941 if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE)
2942 return (inm_modestrs[mode]);
2943 return ("??");
2944 }
2945
2946 static const char *inm_statestrs[] = {
2947 [IGMP_NOT_MEMBER] = "not-member",
2948 [IGMP_SILENT_MEMBER] = "silent",
2949 [IGMP_REPORTING_MEMBER] = "reporting",
2950 [IGMP_IDLE_MEMBER] = "idle",
2951 [IGMP_LAZY_MEMBER] = "lazy",
2952 [IGMP_SLEEPING_MEMBER] = "sleeping",
2953 [IGMP_AWAKENING_MEMBER] = "awakening",
2954 [IGMP_G_QUERY_PENDING_MEMBER] = "query-pending",
2955 [IGMP_SG_QUERY_PENDING_MEMBER] = "sg-query-pending",
2956 [IGMP_LEAVING_MEMBER] = "leaving",
2957 };
2958 _Static_assert(IGMP_NOT_MEMBER == 0 &&
2959 IGMP_LEAVING_MEMBER + 1 == nitems(inm_statestrs),
2960 "inm_statetrs: no longer matches #defines");
2961
2962 static const char *
inm_state_str(const int state)2963 inm_state_str(const int state)
2964 {
2965
2966 if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER)
2967 return (inm_statestrs[state]);
2968 return ("??");
2969 }
2970
2971 /*
2972 * Dump an in_multi structure to the console.
2973 */
2974 void
inm_print(const struct in_multi * inm)2975 inm_print(const struct in_multi *inm)
2976 {
2977 int t;
2978 char addrbuf[INET_ADDRSTRLEN];
2979
2980 if ((ktr_mask & KTR_IGMPV3) == 0)
2981 return;
2982
2983 printf("%s: --- begin inm %p ---\n", __func__, inm);
2984 printf("addr %s ifp %p(%s) ifma %p\n",
2985 inet_ntoa_r(inm->inm_addr, addrbuf),
2986 inm->inm_ifp,
2987 inm->inm_ifp->if_xname,
2988 inm->inm_ifma);
2989 printf("timer %u state %s refcount %u scq.len %u\n",
2990 inm->inm_timer,
2991 inm_state_str(inm->inm_state),
2992 inm->inm_refcount,
2993 inm->inm_scq.mq_len);
2994 printf("igi %p nsrc %lu sctimer %u scrv %u\n",
2995 inm->inm_igi,
2996 inm->inm_nsrc,
2997 inm->inm_sctimer,
2998 inm->inm_scrv);
2999 for (t = 0; t < 2; t++) {
3000 printf("t%d: fmode %s asm %u ex %u in %u rec %u\n", t,
3001 inm_mode_str(inm->inm_st[t].iss_fmode),
3002 inm->inm_st[t].iss_asm,
3003 inm->inm_st[t].iss_ex,
3004 inm->inm_st[t].iss_in,
3005 inm->inm_st[t].iss_rec);
3006 }
3007 printf("%s: --- end inm %p ---\n", __func__, inm);
3008 }
3009
3010 #else /* !KTR || !(KTR_COMPILE & KTR_IGMPV3) */
3011
3012 void
inm_print(const struct in_multi * inm)3013 inm_print(const struct in_multi *inm)
3014 {
3015
3016 }
3017
3018 #endif /* KTR && (KTR_COMPILE & KTR_IGMPV3) */
3019
3020 RB_GENERATE(ip_msource_tree, ip_msource, ims_link, ip_msource_cmp);
3021