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