1 /*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*-
29 * Copyright (c) 2009 Bruce Simpson.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior written
41 * permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56 /*
57 * Copyright (c) 1988 Stephen Deering.
58 * Copyright (c) 1992, 1993
59 * The Regents of the University of California. All rights reserved.
60 *
61 * This code is derived from software contributed to Berkeley by
62 * Stephen Deering of Stanford University.
63 *
64 * Redistribution and use in source and binary forms, with or without
65 * modification, are permitted provided that the following conditions
66 * are met:
67 * 1. Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * 2. Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in the
71 * documentation and/or other materials provided with the distribution.
72 * 3. All advertising materials mentioning features or use of this software
73 * must display the following acknowledgement:
74 * This product includes software developed by the University of
75 * California, Berkeley and its contributors.
76 * 4. Neither the name of the University nor the names of its contributors
77 * may be used to endorse or promote products derived from this software
78 * without specific prior written permission.
79 *
80 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
81 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
82 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
83 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
84 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
85 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
86 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
87 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90 * SUCH DAMAGE.
91 *
92 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
93 */
94 /*
95 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
96 * support for mandatory and extensible security protections. This notice
97 * is included in support of clause 2.2 (b) of the Apple Public License,
98 * Version 2.0.
99 */
100
101 #include <sys/cdefs.h>
102
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/mbuf.h>
106 #include <sys/socket.h>
107 #include <sys/protosw.h>
108 #include <sys/kernel.h>
109 #include <sys/malloc.h>
110 #include <sys/mcache.h>
111
112 #include <dev/random/randomdev.h>
113
114 #include <kern/zalloc.h>
115 #include <kern/uipc_domain.h>
116
117 #include <net/if.h>
118 #include <net/route.h>
119 #include <net/net_sysctl.h>
120
121 #include <netinet/in.h>
122 #include <netinet/in_var.h>
123 #include <netinet6/in6_var.h>
124 #include <netinet/ip6.h>
125 #include <netinet6/ip6_var.h>
126 #include <netinet6/scope6_var.h>
127 #include <netinet/icmp6.h>
128 #include <netinet6/mld6.h>
129 #include <netinet6/mld6_var.h>
130
131 #include <os/log.h>
132
133 /* Lock group and attribute for mld_mtx */
134 static LCK_ATTR_DECLARE(mld_mtx_attr, 0, 0);
135 static LCK_GRP_DECLARE(mld_mtx_grp, "mld_mtx");
136
137 /*
138 * Locking and reference counting:
139 *
140 * mld_mtx mainly protects mli_head. In cases where both mld_mtx and
141 * in6_multihead_lock must be held, the former must be acquired first in order
142 * to maintain lock ordering. It is not a requirement that mld_mtx be
143 * acquired first before in6_multihead_lock, but in case both must be acquired
144 * in succession, the correct lock ordering must be followed.
145 *
146 * Instead of walking the if_multiaddrs list at the interface and returning
147 * the ifma_protospec value of a matching entry, we search the global list
148 * of in6_multi records and find it that way; this is done with in6_multihead
149 * lock held. Doing so avoids the race condition issues that many other BSDs
150 * suffer from (therefore in our implementation, ifma_protospec will never be
151 * NULL for as long as the in6_multi is valid.)
152 *
153 * The above creates a requirement for the in6_multi to stay in in6_multihead
154 * list even after the final MLD leave (in MLDv2 mode) until no longer needs
155 * be retransmitted (this is not required for MLDv1.) In order to handle
156 * this, the request and reference counts of the in6_multi are bumped up when
157 * the state changes to MLD_LEAVING_MEMBER, and later dropped in the timeout
158 * handler. Each in6_multi holds a reference to the underlying mld_ifinfo.
159 *
160 * Thus, the permitted lock order is:
161 *
162 * mld_mtx, in6_multihead_lock, inm6_lock, mli_lock
163 *
164 * Any may be taken independently, but if any are held at the same time,
165 * the above lock order must be followed.
166 */
167 static LCK_MTX_DECLARE_ATTR(mld_mtx, &mld_mtx_grp, &mld_mtx_attr);
168
169 SLIST_HEAD(mld_in6m_relhead, in6_multi);
170
171 static void mli_initvar(struct mld_ifinfo *, struct ifnet *, int);
172 static struct mld_ifinfo *mli_alloc(zalloc_flags_t);
173 static void mli_free(struct mld_ifinfo *);
174 static void mli_delete(const struct ifnet *, struct mld_in6m_relhead *);
175 static void mld_dispatch_packet(struct mbuf *);
176 static void mld_final_leave(struct in6_multi *, struct mld_ifinfo *,
177 struct mld_tparams *);
178 static int mld_handle_state_change(struct in6_multi *, struct mld_ifinfo *,
179 struct mld_tparams *);
180 static int mld_initial_join(struct in6_multi *, struct mld_ifinfo *,
181 struct mld_tparams *, const int);
182 #ifdef MLD_DEBUG
183 static const char * mld_rec_type_to_str(const int);
184 #endif
185 static uint32_t mld_set_version(struct mld_ifinfo *, const int);
186 static void mld_append_relq(struct mld_ifinfo *, struct in6_multi *);
187 static void mld_flush_relq(struct mld_ifinfo *, struct mld_in6m_relhead *);
188 static void mld_dispatch_queue_locked(struct mld_ifinfo *, struct ifqueue *, int);
189 static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *,
190 /*const*/ struct mld_hdr *);
191 static int mld_v1_input_report(struct ifnet *, struct mbuf *,
192 const struct ip6_hdr *, /*const*/ struct mld_hdr *);
193 static void mld_v1_process_group_timer(struct in6_multi *, const int);
194 static void mld_v1_process_querier_timers(struct mld_ifinfo *);
195 static int mld_v1_transmit_report(struct in6_multi *, const uint8_t);
196 static uint32_t mld_v1_update_group(struct in6_multi *, const int);
197 static void mld_v2_cancel_link_timers(struct mld_ifinfo *);
198 static uint32_t mld_v2_dispatch_general_query(struct mld_ifinfo *);
199 static struct mbuf *
200 mld_v2_encap_report(struct ifnet *, struct mbuf *);
201 static int mld_v2_enqueue_filter_change(struct ifqueue *,
202 struct in6_multi *);
203 static int mld_v2_enqueue_group_record(struct ifqueue *,
204 struct in6_multi *, const int, const int, const int,
205 const int);
206 static int mld_v2_input_query(struct ifnet *, const struct ip6_hdr *,
207 struct mbuf *, const int, const int);
208 static int mld_v2_merge_state_changes(struct in6_multi *,
209 struct ifqueue *);
210 static void mld_v2_process_group_timers(struct mld_ifinfo *,
211 struct ifqueue *, struct ifqueue *,
212 struct in6_multi *, const int);
213 static int mld_v2_process_group_query(struct in6_multi *,
214 int, struct mbuf *, const int);
215 static int sysctl_mld_gsr SYSCTL_HANDLER_ARGS;
216 static int sysctl_mld_ifinfo SYSCTL_HANDLER_ARGS;
217 static int sysctl_mld_v2enable SYSCTL_HANDLER_ARGS;
218
219 static const uint32_t mld_timeout_delay = 1000; /* in milliseconds */
220 static const uint32_t mld_timeout_leeway = 500; /* in millseconds */
221 static bool mld_timeout_run; /* MLD timer is scheduled to run */
222 static bool mld_fast_timeout_run; /* MLD fast timer is scheduled to run */
223 static void mld_timeout(thread_call_param_t, thread_call_param_t);
224 static void mld_sched_timeout(void);
225 static void mld_sched_fast_timeout(void);
226
227 /*
228 * Normative references: RFC 2710, RFC 3590, RFC 3810.
229 */
230 static struct timeval mld_gsrdelay = {.tv_sec = 10, .tv_usec = 0};
231 static LIST_HEAD(, mld_ifinfo) mli_head;
232
233 static int querier_present_timers_running6;
234 static int interface_timers_running6;
235 static int state_change_timers_running6;
236 static int current_state_timers_running6;
237
238 static unsigned int mld_mli_list_genid;
239 /*
240 * Subsystem lock macros.
241 */
242 #define MLD_LOCK() \
243 lck_mtx_lock(&mld_mtx)
244 #define MLD_LOCK_ASSERT_HELD() \
245 LCK_MTX_ASSERT(&mld_mtx, LCK_MTX_ASSERT_OWNED)
246 #define MLD_LOCK_ASSERT_NOTHELD() \
247 LCK_MTX_ASSERT(&mld_mtx, LCK_MTX_ASSERT_NOTOWNED)
248 #define MLD_UNLOCK() \
249 lck_mtx_unlock(&mld_mtx)
250
251 #define MLD_ADD_DETACHED_IN6M(_head, _in6m) { \
252 SLIST_INSERT_HEAD(_head, _in6m, in6m_dtle); \
253 }
254
255 #define MLD_REMOVE_DETACHED_IN6M(_head) { \
256 struct in6_multi *_in6m, *_inm_tmp; \
257 SLIST_FOREACH_SAFE(_in6m, _head, in6m_dtle, _inm_tmp) { \
258 SLIST_REMOVE(_head, _in6m, in6_multi, in6m_dtle); \
259 IN6M_REMREF(_in6m); \
260 } \
261 VERIFY(SLIST_EMPTY(_head)); \
262 }
263
264 static KALLOC_TYPE_DEFINE(mli_zone, struct mld_ifinfo, NET_KT_DEFAULT);
265
266 SYSCTL_DECL(_net_inet6); /* Note: Not in any common header. */
267
268 SYSCTL_NODE(_net_inet6, OID_AUTO, mld, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
269 "IPv6 Multicast Listener Discovery");
270 SYSCTL_PROC(_net_inet6_mld, OID_AUTO, gsrdelay,
271 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
272 &mld_gsrdelay.tv_sec, 0, sysctl_mld_gsr, "I",
273 "Rate limit for MLDv2 Group-and-Source queries in seconds");
274
275 SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo, CTLFLAG_RD | CTLFLAG_LOCKED,
276 sysctl_mld_ifinfo, "Per-interface MLDv2 state");
277
278 static int mld_v1enable = 1;
279 SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RW | CTLFLAG_LOCKED,
280 &mld_v1enable, 0, "Enable fallback to MLDv1");
281
282 static int mld_v2enable = 1;
283 SYSCTL_PROC(_net_inet6_mld, OID_AUTO, v2enable,
284 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
285 &mld_v2enable, 0, sysctl_mld_v2enable, "I",
286 "Enable MLDv2 (debug purposes only)");
287
288 static int mld_use_allow = 1;
289 SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RW | CTLFLAG_LOCKED,
290 &mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
291
292 #ifdef MLD_DEBUG
293 int mld_debug = 0;
294 SYSCTL_INT(_net_inet6_mld, OID_AUTO,
295 debug, CTLFLAG_RW | CTLFLAG_LOCKED, &mld_debug, 0, "");
296 #endif
297 /*
298 * Packed Router Alert option structure declaration.
299 */
300 struct mld_raopt {
301 struct ip6_hbh hbh;
302 struct ip6_opt pad;
303 struct ip6_opt_router ra;
304 } __packed;
305
306 /*
307 * Router Alert hop-by-hop option header.
308 */
309 static struct mld_raopt mld_ra = {
310 .hbh = { .ip6h_nxt = 0, .ip6h_len = 0 },
311 .pad = { .ip6o_type = IP6OPT_PADN, .ip6o_len = 0 },
312 .ra = {
313 .ip6or_type = (u_int8_t)IP6OPT_ROUTER_ALERT,
314 .ip6or_len = (u_int8_t)(IP6OPT_RTALERT_LEN - 2),
315 .ip6or_value = {((IP6OPT_RTALERT_MLD >> 8) & 0xFF),
316 (IP6OPT_RTALERT_MLD & 0xFF) }
317 }
318 };
319 static struct ip6_pktopts mld_po;
320
321 /* Store MLDv2 record count in the module private scratch space */
322 #define vt_nrecs pkt_mpriv.__mpriv_u.__mpriv32[0].__mpriv32_u.__val16[0]
323
324 static __inline void
mld_save_context(struct mbuf * m,struct ifnet * ifp)325 mld_save_context(struct mbuf *m, struct ifnet *ifp)
326 {
327 m->m_pkthdr.rcvif = ifp;
328 }
329
330 static __inline void
mld_scrub_context(struct mbuf * m)331 mld_scrub_context(struct mbuf *m)
332 {
333 m->m_pkthdr.rcvif = NULL;
334 }
335
336 /*
337 * Restore context from a queued output chain.
338 * Return saved ifp.
339 */
340 static __inline struct ifnet *
mld_restore_context(struct mbuf * m)341 mld_restore_context(struct mbuf *m)
342 {
343 return m->m_pkthdr.rcvif;
344 }
345
346 /*
347 * Retrieve or set threshold between group-source queries in seconds.
348 */
349 static int
350 sysctl_mld_gsr SYSCTL_HANDLER_ARGS
351 {
352 #pragma unused(arg1, arg2)
353 int error;
354 int i;
355
356 MLD_LOCK();
357
358 i = (int)mld_gsrdelay.tv_sec;
359
360 error = sysctl_handle_int(oidp, &i, 0, req);
361 if (error || !req->newptr) {
362 goto out_locked;
363 }
364
365 if (i < -1 || i >= 60) {
366 error = EINVAL;
367 goto out_locked;
368 }
369
370 mld_gsrdelay.tv_sec = i;
371
372 out_locked:
373 MLD_UNLOCK();
374 return error;
375 }
376 /*
377 * Expose struct mld_ifinfo to userland, keyed by ifindex.
378 * For use by ifmcstat(8).
379 *
380 */
381 static int
382 sysctl_mld_ifinfo SYSCTL_HANDLER_ARGS
383 {
384 #pragma unused(oidp)
385 DECLARE_SYSCTL_HANDLER_ARG_ARRAY(int, 1, name, namelen);
386 int error;
387 struct ifnet *ifp;
388 struct mld_ifinfo *mli;
389 struct mld_ifinfo_u mli_u;
390
391 if (req->newptr != USER_ADDR_NULL) {
392 return EPERM;
393 }
394
395 MLD_LOCK();
396
397 if (name[0] <= 0 || name[0] > (u_int)if_index) {
398 error = ENOENT;
399 goto out_locked;
400 }
401
402 error = ENOENT;
403
404 ifnet_head_lock_shared();
405 ifp = ifindex2ifnet[name[0]];
406 ifnet_head_done();
407 if (ifp == NULL) {
408 goto out_locked;
409 }
410
411 bzero(&mli_u, sizeof(mli_u));
412
413 LIST_FOREACH(mli, &mli_head, mli_link) {
414 MLI_LOCK(mli);
415 if (ifp != mli->mli_ifp) {
416 MLI_UNLOCK(mli);
417 continue;
418 }
419
420 mli_u.mli_ifindex = mli->mli_ifp->if_index;
421 mli_u.mli_version = mli->mli_version;
422 mli_u.mli_v1_timer = mli->mli_v1_timer;
423 mli_u.mli_v2_timer = mli->mli_v2_timer;
424 mli_u.mli_flags = mli->mli_flags;
425 mli_u.mli_rv = mli->mli_rv;
426 mli_u.mli_qi = mli->mli_qi;
427 mli_u.mli_qri = mli->mli_qri;
428 mli_u.mli_uri = mli->mli_uri;
429 MLI_UNLOCK(mli);
430
431 error = SYSCTL_OUT(req, &mli_u, sizeof(mli_u));
432 break;
433 }
434
435 out_locked:
436 MLD_UNLOCK();
437 return error;
438 }
439
440 static int
441 sysctl_mld_v2enable SYSCTL_HANDLER_ARGS
442 {
443 #pragma unused(arg1, arg2)
444 int error;
445 int i;
446 struct mld_ifinfo *mli;
447 struct mld_tparams mtp = { .qpt = 0, .it = 0, .cst = 0, .sct = 0 };
448
449 MLD_LOCK();
450
451 i = mld_v2enable;
452
453 error = sysctl_handle_int(oidp, &i, 0, req);
454 if (error || !req->newptr) {
455 goto out_locked;
456 }
457
458 if (i < 0 || i > 1) {
459 error = EINVAL;
460 goto out_locked;
461 }
462
463 mld_v2enable = i;
464 /*
465 * If we enabled v2, the state transition will take care of upgrading
466 * the MLD version back to v2. Otherwise, we have to explicitly
467 * downgrade. Note that this functionality is to be used for debugging.
468 */
469 if (mld_v2enable == 1) {
470 goto out_locked;
471 }
472
473 LIST_FOREACH(mli, &mli_head, mli_link) {
474 MLI_LOCK(mli);
475 if (mld_set_version(mli, MLD_VERSION_1) > 0) {
476 mtp.qpt = 1;
477 }
478 MLI_UNLOCK(mli);
479 }
480
481 out_locked:
482 MLD_UNLOCK();
483
484 mld_set_timeout(&mtp);
485
486 return error;
487 }
488
489 /*
490 * Dispatch an entire queue of pending packet chains.
491 *
492 * Must not be called with in6m_lock held.
493 * XXX This routine unlocks MLD global lock and also mli locks.
494 * Make sure that the calling routine takes reference on the mli
495 * before calling this routine.
496 * Also if we are traversing mli_head, remember to check for
497 * mli list generation count and restart the loop if generation count
498 * has changed.
499 */
500 static void
mld_dispatch_queue_locked(struct mld_ifinfo * mli,struct ifqueue * ifq,int limit)501 mld_dispatch_queue_locked(struct mld_ifinfo *mli, struct ifqueue *ifq, int limit)
502 {
503 struct mbuf *m;
504
505 MLD_LOCK_ASSERT_HELD();
506
507 if (mli != NULL) {
508 MLI_LOCK_ASSERT_HELD(mli);
509 }
510
511 for (;;) {
512 IF_DEQUEUE(ifq, m);
513 if (m == NULL) {
514 break;
515 }
516 MLD_PRINTF(("%s: dispatch 0x%llx from 0x%llx\n", __func__,
517 (uint64_t)VM_KERNEL_ADDRPERM(ifq),
518 (uint64_t)VM_KERNEL_ADDRPERM(m)));
519
520 if (mli != NULL) {
521 MLI_UNLOCK(mli);
522 }
523 MLD_UNLOCK();
524
525 mld_dispatch_packet(m);
526
527 MLD_LOCK();
528 if (mli != NULL) {
529 MLI_LOCK(mli);
530 }
531
532 if (--limit == 0) {
533 break;
534 }
535 }
536
537 if (mli != NULL) {
538 MLI_LOCK_ASSERT_HELD(mli);
539 }
540 }
541
542 /*
543 * Filter outgoing MLD report state by group.
544 *
545 * Reports are ALWAYS suppressed for ALL-HOSTS (ff02::1)
546 * and node-local addresses. However, kernel and socket consumers
547 * always embed the KAME scope ID in the address provided, so strip it
548 * when performing comparison.
549 * Note: This is not the same as the *multicast* scope.
550 *
551 * Return zero if the given group is one for which MLD reports
552 * should be suppressed, or non-zero if reports should be issued.
553 */
554 static __inline__ int
mld_is_addr_reported(const struct in6_addr * addr)555 mld_is_addr_reported(const struct in6_addr *addr)
556 {
557 VERIFY(IN6_IS_ADDR_MULTICAST(addr));
558
559 if (IPV6_ADDR_MC_SCOPE(addr) == IPV6_ADDR_SCOPE_NODELOCAL) {
560 return 0;
561 }
562
563 if (IPV6_ADDR_MC_SCOPE(addr) == IPV6_ADDR_SCOPE_LINKLOCAL && !IN6_IS_ADDR_UNICAST_BASED_MULTICAST(addr)) {
564 struct in6_addr tmp = *addr;
565 in6_clearscope(&tmp);
566 if (IN6_ARE_ADDR_EQUAL(&tmp, &in6addr_linklocal_allnodes)) {
567 return 0;
568 }
569 }
570
571 return 1;
572 }
573
574 /*
575 * Attach MLD when PF_INET6 is attached to an interface.
576 */
577 struct mld_ifinfo *
mld_domifattach(struct ifnet * ifp,zalloc_flags_t how)578 mld_domifattach(struct ifnet *ifp, zalloc_flags_t how)
579 {
580 struct mld_ifinfo *mli;
581
582 os_log_debug(OS_LOG_DEFAULT, "%s: called for ifp %s\n", __func__,
583 if_name(ifp));
584
585 mli = mli_alloc(how);
586 if (mli == NULL) {
587 return NULL;
588 }
589
590 MLD_LOCK();
591
592 MLI_LOCK(mli);
593 mli_initvar(mli, ifp, 0);
594 mli->mli_debug |= IFD_ATTACHED;
595 MLI_ADDREF_LOCKED(mli); /* hold a reference for mli_head */
596 MLI_ADDREF_LOCKED(mli); /* hold a reference for caller */
597 MLI_UNLOCK(mli);
598 ifnet_lock_shared(ifp);
599 mld6_initsilent(ifp, mli);
600 ifnet_lock_done(ifp);
601
602 LIST_INSERT_HEAD(&mli_head, mli, mli_link);
603 mld_mli_list_genid++;
604
605 MLD_UNLOCK();
606
607 os_log_info(OS_LOG_DEFAULT, "%s: allocated mld_ifinfo for ifp %s\n",
608 __func__, if_name(ifp));
609
610 return mli;
611 }
612
613 /*
614 * Attach MLD when PF_INET6 is reattached to an interface. Caller is
615 * expected to have an outstanding reference to the mli.
616 */
617 void
mld_domifreattach(struct mld_ifinfo * mli)618 mld_domifreattach(struct mld_ifinfo *mli)
619 {
620 struct ifnet *ifp;
621
622 MLD_LOCK();
623
624 MLI_LOCK(mli);
625 VERIFY(!(mli->mli_debug & IFD_ATTACHED));
626 ifp = mli->mli_ifp;
627 VERIFY(ifp != NULL);
628 mli_initvar(mli, ifp, 1);
629 mli->mli_debug |= IFD_ATTACHED;
630 MLI_ADDREF_LOCKED(mli); /* hold a reference for mli_head */
631 MLI_UNLOCK(mli);
632 ifnet_lock_shared(ifp);
633 mld6_initsilent(ifp, mli);
634 ifnet_lock_done(ifp);
635
636 LIST_INSERT_HEAD(&mli_head, mli, mli_link);
637 mld_mli_list_genid++;
638
639 MLD_UNLOCK();
640
641 os_log_info(OS_LOG_DEFAULT, "%s: reattached mld_ifinfo for ifp %s\n",
642 __func__, if_name(ifp));
643 }
644
645 /*
646 * Hook for domifdetach.
647 */
648 void
mld_domifdetach(struct ifnet * ifp)649 mld_domifdetach(struct ifnet *ifp)
650 {
651 SLIST_HEAD(, in6_multi) in6m_dthead;
652
653 SLIST_INIT(&in6m_dthead);
654
655 os_log_info(OS_LOG_DEFAULT, "%s: called for ifp %s\n", __func__,
656 if_name(ifp));
657
658 MLD_LOCK();
659 mli_delete(ifp, (struct mld_in6m_relhead *)&in6m_dthead);
660 MLD_UNLOCK();
661
662 /* Now that we're dropped all locks, release detached records */
663 MLD_REMOVE_DETACHED_IN6M(&in6m_dthead);
664 }
665
666 /*
667 * Called at interface detach time. Note that we only flush all deferred
668 * responses and record releases; all remaining inm records and their source
669 * entries related to this interface are left intact, in order to handle
670 * the reattach case.
671 */
672 static void
mli_delete(const struct ifnet * ifp,struct mld_in6m_relhead * in6m_dthead)673 mli_delete(const struct ifnet *ifp, struct mld_in6m_relhead *in6m_dthead)
674 {
675 struct mld_ifinfo *mli, *tmli;
676
677 MLD_LOCK_ASSERT_HELD();
678
679 LIST_FOREACH_SAFE(mli, &mli_head, mli_link, tmli) {
680 MLI_LOCK(mli);
681 if (mli->mli_ifp == ifp) {
682 /*
683 * Free deferred General Query responses.
684 */
685 IF_DRAIN(&mli->mli_gq);
686 IF_DRAIN(&mli->mli_v1q);
687 mld_flush_relq(mli, in6m_dthead);
688 mli->mli_debug &= ~IFD_ATTACHED;
689 MLI_UNLOCK(mli);
690
691 LIST_REMOVE(mli, mli_link);
692 MLI_REMREF(mli); /* release mli_head reference */
693 mld_mli_list_genid++;
694 return;
695 }
696 MLI_UNLOCK(mli);
697 }
698 panic("%s: mld_ifinfo not found for ifp %p(%s)", __func__,
699 ifp, ifp->if_xname);
700 }
701
702 __private_extern__ void
mld6_initsilent(struct ifnet * ifp,struct mld_ifinfo * mli)703 mld6_initsilent(struct ifnet *ifp, struct mld_ifinfo *mli)
704 {
705 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_OWNED);
706
707 MLI_LOCK_ASSERT_NOTHELD(mli);
708 MLI_LOCK(mli);
709 if (!(ifp->if_flags & IFF_MULTICAST) &&
710 (ifp->if_eflags & (IFEF_IPV6_ND6ALT | IFEF_LOCALNET_PRIVATE))) {
711 mli->mli_flags |= MLIF_SILENT;
712 } else {
713 mli->mli_flags &= ~MLIF_SILENT;
714 }
715 MLI_UNLOCK(mli);
716 }
717
718 static void
mli_initvar(struct mld_ifinfo * mli,struct ifnet * ifp,int reattach)719 mli_initvar(struct mld_ifinfo *mli, struct ifnet *ifp, int reattach)
720 {
721 MLI_LOCK_ASSERT_HELD(mli);
722
723 mli->mli_ifp = ifp;
724 if (mld_v2enable) {
725 mli->mli_version = MLD_VERSION_2;
726 } else {
727 mli->mli_version = MLD_VERSION_1;
728 }
729 mli->mli_flags = 0;
730 mli->mli_rv = MLD_RV_INIT;
731 mli->mli_qi = MLD_QI_INIT;
732 mli->mli_qri = MLD_QRI_INIT;
733 mli->mli_uri = MLD_URI_INIT;
734
735 if (mld_use_allow) {
736 mli->mli_flags |= MLIF_USEALLOW;
737 }
738 if (!reattach) {
739 SLIST_INIT(&mli->mli_relinmhead);
740 }
741
742 /*
743 * Responses to general queries are subject to bounds.
744 */
745 mli->mli_gq.ifq_maxlen = MLD_MAX_RESPONSE_PACKETS;
746 mli->mli_v1q.ifq_maxlen = MLD_MAX_RESPONSE_PACKETS;
747 }
748
749 static struct mld_ifinfo *
mli_alloc(zalloc_flags_t how)750 mli_alloc(zalloc_flags_t how)
751 {
752 struct mld_ifinfo *mli = zalloc_flags(mli_zone, how | Z_ZERO);
753 if (mli != NULL) {
754 lck_mtx_init(&mli->mli_lock, &mld_mtx_grp, &mld_mtx_attr);
755 mli->mli_debug |= IFD_ALLOC;
756 }
757 return mli;
758 }
759
760 static void
mli_free(struct mld_ifinfo * mli)761 mli_free(struct mld_ifinfo *mli)
762 {
763 MLI_LOCK(mli);
764 if (mli->mli_debug & IFD_ATTACHED) {
765 panic("%s: attached mli=%p is being freed", __func__, mli);
766 /* NOTREACHED */
767 } else if (mli->mli_ifp != NULL) {
768 panic("%s: ifp not NULL for mli=%p", __func__, mli);
769 /* NOTREACHED */
770 } else if (!(mli->mli_debug & IFD_ALLOC)) {
771 panic("%s: mli %p cannot be freed", __func__, mli);
772 /* NOTREACHED */
773 } else if (mli->mli_refcnt != 0) {
774 panic("%s: non-zero refcnt mli=%p", __func__, mli);
775 /* NOTREACHED */
776 }
777 mli->mli_debug &= ~IFD_ALLOC;
778 MLI_UNLOCK(mli);
779
780 lck_mtx_destroy(&mli->mli_lock, &mld_mtx_grp);
781 zfree(mli_zone, mli);
782 }
783
784 void
mli_addref(struct mld_ifinfo * mli,int locked)785 mli_addref(struct mld_ifinfo *mli, int locked)
786 {
787 if (!locked) {
788 MLI_LOCK_SPIN(mli);
789 } else {
790 MLI_LOCK_ASSERT_HELD(mli);
791 }
792
793 if (++mli->mli_refcnt == 0) {
794 panic("%s: mli=%p wraparound refcnt", __func__, mli);
795 /* NOTREACHED */
796 }
797 if (!locked) {
798 MLI_UNLOCK(mli);
799 }
800 }
801
802 void
mli_remref(struct mld_ifinfo * mli)803 mli_remref(struct mld_ifinfo *mli)
804 {
805 SLIST_HEAD(, in6_multi) in6m_dthead;
806 struct ifnet *ifp;
807
808 MLI_LOCK_SPIN(mli);
809
810 if (mli->mli_refcnt == 0) {
811 panic("%s: mli=%p negative refcnt", __func__, mli);
812 /* NOTREACHED */
813 }
814
815 --mli->mli_refcnt;
816 if (mli->mli_refcnt > 0) {
817 MLI_UNLOCK(mli);
818 return;
819 }
820
821 ifp = mli->mli_ifp;
822 mli->mli_ifp = NULL;
823 IF_DRAIN(&mli->mli_gq);
824 IF_DRAIN(&mli->mli_v1q);
825 SLIST_INIT(&in6m_dthead);
826 mld_flush_relq(mli, (struct mld_in6m_relhead *)&in6m_dthead);
827 MLI_UNLOCK(mli);
828
829 /* Now that we're dropped all locks, release detached records */
830 MLD_REMOVE_DETACHED_IN6M(&in6m_dthead);
831
832 os_log(OS_LOG_DEFAULT, "%s: freeing mld_ifinfo for ifp %s\n",
833 __func__, if_name(ifp));
834
835 mli_free(mli);
836 }
837
838 /*
839 * Process a received MLDv1 general or address-specific query.
840 * Assumes that the query header has been pulled up to sizeof(mld_hdr).
841 *
842 * NOTE: Can't be fully const correct as we temporarily embed scope ID in
843 * mld_addr. This is OK as we own the mbuf chain.
844 */
845 static int
mld_v1_input_query(struct ifnet * ifp,const struct ip6_hdr * ip6,struct mld_hdr * mld)846 mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
847 /*const*/ struct mld_hdr *mld)
848 {
849 struct mld_ifinfo *mli;
850 struct in6_multi *inm;
851 int err = 0, is_general_query;
852 uint16_t timer;
853 struct mld_tparams mtp = { .qpt = 0, .it = 0, .cst = 0, .sct = 0 };
854
855 MLD_LOCK_ASSERT_NOTHELD();
856
857 is_general_query = 0;
858
859 if (!mld_v1enable) {
860 os_log_info(OS_LOG_DEFAULT, "%s: ignore v1 query on ifp %s\n",
861 __func__, if_name(ifp));
862 goto done;
863 }
864
865 /*
866 * RFC3810 Section 6.2: MLD queries must originate from
867 * a router's link-local address.
868 */
869 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
870 os_log_info(OS_LOG_DEFAULT, "%s: ignore v1 query src %s on ifp %s\n",
871 __func__, ip6_sprintf(&ip6->ip6_src),
872 if_name(ifp));
873 goto done;
874 }
875
876 /*
877 * Do address field validation upfront before we accept
878 * the query.
879 */
880 if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
881 /*
882 * MLDv1 General Query.
883 * If this was not sent to the all-nodes group, ignore it.
884 */
885 struct in6_addr dst;
886
887 dst = ip6->ip6_dst;
888 in6_clearscope(&dst);
889 if (!IN6_ARE_ADDR_EQUAL(&dst, &in6addr_linklocal_allnodes)) {
890 err = EINVAL;
891 goto done;
892 }
893 is_general_query = 1;
894 } else {
895 /*
896 * Embed scope ID of receiving interface in MLD query for
897 * lookup whilst we don't hold other locks.
898 */
899 (void)in6_setscope(&mld->mld_addr, ifp, NULL);
900 }
901
902 /*
903 * Switch to MLDv1 host compatibility mode.
904 */
905 mli = MLD_IFINFO(ifp);
906 VERIFY(mli != NULL);
907
908 MLI_LOCK(mli);
909 mtp.qpt = mld_set_version(mli, MLD_VERSION_1);
910 MLI_UNLOCK(mli);
911
912 timer = ntohs(mld->mld_maxdelay) / MLD_TIMER_SCALE;
913 if (timer == 0) {
914 timer = 1;
915 }
916
917 if (is_general_query) {
918 struct in6_multistep step;
919
920 os_log_debug(OS_LOG_DEFAULT, "%s: process v1 general query on ifp %s\n",
921 __func__, if_name(ifp));
922 /*
923 * For each reporting group joined on this
924 * interface, kick the report timer.
925 */
926 in6_multihead_lock_shared();
927 IN6_FIRST_MULTI(step, inm);
928 while (inm != NULL) {
929 IN6M_LOCK(inm);
930 if (inm->in6m_ifp == ifp) {
931 mtp.cst += mld_v1_update_group(inm, timer);
932 }
933 IN6M_UNLOCK(inm);
934 IN6_NEXT_MULTI(step, inm);
935 }
936 in6_multihead_lock_done();
937 } else {
938 /*
939 * MLDv1 Group-Specific Query.
940 * If this is a group-specific MLDv1 query, we need only
941 * look up the single group to process it.
942 */
943 in6_multihead_lock_shared();
944 IN6_LOOKUP_MULTI(&mld->mld_addr, ifp, inm);
945 in6_multihead_lock_done();
946
947 if (inm != NULL) {
948 IN6M_LOCK(inm);
949 os_log_debug(OS_LOG_DEFAULT, "%s: process v1 query %s on "
950 "ifp %s\n", __func__,
951 ip6_sprintf(&mld->mld_addr),
952 if_name(ifp));
953 mtp.cst = mld_v1_update_group(inm, timer);
954 IN6M_UNLOCK(inm);
955 IN6M_REMREF(inm); /* from IN6_LOOKUP_MULTI */
956 }
957 /* XXX Clear embedded scope ID as userland won't expect it. */
958 in6_clearscope(&mld->mld_addr);
959 }
960 done:
961 mld_set_timeout(&mtp);
962
963 return err;
964 }
965
966 /*
967 * Update the report timer on a group in response to an MLDv1 query.
968 *
969 * If we are becoming the reporting member for this group, start the timer.
970 * If we already are the reporting member for this group, and timer is
971 * below the threshold, reset it.
972 *
973 * We may be updating the group for the first time since we switched
974 * to MLDv2. If we are, then we must clear any recorded source lists,
975 * and transition to REPORTING state; the group timer is overloaded
976 * for group and group-source query responses.
977 *
978 * Unlike MLDv2, the delay per group should be jittered
979 * to avoid bursts of MLDv1 reports.
980 */
981 static uint32_t
mld_v1_update_group(struct in6_multi * inm,const int timer)982 mld_v1_update_group(struct in6_multi *inm, const int timer)
983 {
984 IN6M_LOCK_ASSERT_HELD(inm);
985
986 MLD_PRINTF(("%s: %s/%s timer=%d\n", __func__,
987 ip6_sprintf(&inm->in6m_addr),
988 if_name(inm->in6m_ifp), timer));
989
990 switch (inm->in6m_state) {
991 case MLD_NOT_MEMBER:
992 case MLD_SILENT_MEMBER:
993 break;
994 case MLD_REPORTING_MEMBER:
995 if (inm->in6m_timer != 0 &&
996 inm->in6m_timer <= timer) {
997 MLD_PRINTF(("%s: REPORTING and timer running, "
998 "skipping.\n", __func__));
999 break;
1000 }
1001 OS_FALLTHROUGH;
1002 case MLD_SG_QUERY_PENDING_MEMBER:
1003 case MLD_G_QUERY_PENDING_MEMBER:
1004 case MLD_IDLE_MEMBER:
1005 case MLD_LAZY_MEMBER:
1006 case MLD_AWAKENING_MEMBER:
1007 MLD_PRINTF(("%s: ->REPORTING\n", __func__));
1008 inm->in6m_state = MLD_REPORTING_MEMBER;
1009 inm->in6m_timer = MLD_RANDOM_DELAY(timer);
1010 break;
1011 case MLD_SLEEPING_MEMBER:
1012 MLD_PRINTF(("%s: ->AWAKENING\n", __func__));
1013 inm->in6m_state = MLD_AWAKENING_MEMBER;
1014 break;
1015 case MLD_LEAVING_MEMBER:
1016 break;
1017 }
1018
1019 return inm->in6m_timer;
1020 }
1021
1022 /*
1023 * Process a received MLDv2 general, group-specific or
1024 * group-and-source-specific query.
1025 *
1026 * Assumes that the query header has been pulled up to sizeof(mldv2_query).
1027 *
1028 * Return 0 if successful, otherwise an appropriate error code is returned.
1029 */
1030 static int
mld_v2_input_query(struct ifnet * ifp,const struct ip6_hdr * ip6,struct mbuf * m,const int off,const int icmp6len)1031 mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
1032 struct mbuf *m, const int off, const int icmp6len)
1033 {
1034 struct mld_ifinfo *mli;
1035 struct mldv2_query *mld;
1036 struct in6_multi *inm;
1037 uint32_t maxdelay, nsrc, qqi, timer;
1038 int err = 0, is_general_query;
1039 uint8_t qrv;
1040 struct mld_tparams mtp = { .qpt = 0, .it = 0, .cst = 0, .sct = 0 };
1041
1042 MLD_LOCK_ASSERT_NOTHELD();
1043
1044 is_general_query = 0;
1045
1046 if (!mld_v2enable) {
1047 os_log_info(OS_LOG_DEFAULT, "%s: ignore v2 query on ifp %s\n",
1048 __func__, if_name(ifp));
1049 goto done;
1050 }
1051
1052 /*
1053 * RFC3810 Section 6.2: MLD queries must originate from
1054 * a router's link-local address.
1055 */
1056 if (!IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
1057 os_log_info(OS_LOG_DEFAULT,
1058 "%s: ignore v1 query src %s on ifp %s\n",
1059 __func__, ip6_sprintf(&ip6->ip6_src),
1060 if_name(ifp));
1061 goto done;
1062 }
1063
1064 os_log_debug(OS_LOG_DEFAULT,
1065 "%s: input v2 query on ifp %s\n", __func__,
1066 if_name(ifp));
1067
1068 mld = (struct mldv2_query *)(mtod(m, uint8_t *) + off);
1069
1070 maxdelay = ntohs(mld->mld_maxdelay); /* in 1/10ths of a second */
1071 if (maxdelay > SHRT_MAX) {
1072 maxdelay = (MLD_MRC_MANT((uint16_t)maxdelay) | 0x1000) <<
1073 (MLD_MRC_EXP((uint16_t)maxdelay) + 3);
1074 }
1075 timer = maxdelay / MLD_TIMER_SCALE;
1076 if (timer == 0) {
1077 timer = 1;
1078 }
1079
1080 qrv = MLD_QRV(mld->mld_misc);
1081 if (qrv < 2) {
1082 MLD_PRINTF(("%s: clamping qrv %d to %d\n", __func__,
1083 qrv, MLD_RV_INIT));
1084 qrv = MLD_RV_INIT;
1085 }
1086
1087 qqi = mld->mld_qqi;
1088 if (qqi >= 128) {
1089 qqi = MLD_QQIC_MANT(mld->mld_qqi) <<
1090 (MLD_QQIC_EXP(mld->mld_qqi) + 3);
1091 }
1092
1093 nsrc = ntohs(mld->mld_numsrc);
1094 if (nsrc > MLD_MAX_GS_SOURCES) {
1095 err = EMSGSIZE;
1096 goto done;
1097 }
1098 if (icmp6len < sizeof(struct mldv2_query) +
1099 (nsrc * sizeof(struct in6_addr))) {
1100 err = EMSGSIZE;
1101 goto done;
1102 }
1103
1104 /*
1105 * Do further input validation upfront to avoid resetting timers
1106 * should we need to discard this query.
1107 */
1108 if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
1109 /*
1110 * A general query with a source list has undefined
1111 * behaviour; discard it.
1112 */
1113 if (nsrc > 0) {
1114 err = EINVAL;
1115 goto done;
1116 }
1117 is_general_query = 1;
1118 } else {
1119 /*
1120 * Embed scope ID of receiving interface in MLD query for
1121 * lookup whilst we don't hold other locks (due to KAME
1122 * locking lameness). We own this mbuf chain just now.
1123 */
1124 (void)in6_setscope(&mld->mld_addr, ifp, NULL);
1125 }
1126
1127 mli = MLD_IFINFO(ifp);
1128 VERIFY(mli != NULL);
1129
1130 MLI_LOCK(mli);
1131 /*
1132 * Discard the v2 query if we're in Compatibility Mode.
1133 * The RFC is pretty clear that hosts need to stay in MLDv1 mode
1134 * until the Old Version Querier Present timer expires.
1135 */
1136 if (mli->mli_version != MLD_VERSION_2) {
1137 MLI_UNLOCK(mli);
1138 goto done;
1139 }
1140
1141 mtp.qpt = mld_set_version(mli, MLD_VERSION_2);
1142 mli->mli_rv = qrv;
1143 mli->mli_qi = qqi;
1144 mli->mli_qri = MAX(timer, MLD_QRI_MIN);
1145
1146 MLD_PRINTF(("%s: qrv %d qi %d qri %d\n", __func__, mli->mli_rv,
1147 mli->mli_qi, mli->mli_qri));
1148
1149 if (is_general_query) {
1150 /*
1151 * MLDv2 General Query.
1152 *
1153 * Schedule a current-state report on this ifp for
1154 * all groups, possibly containing source lists.
1155 *
1156 * If there is a pending General Query response
1157 * scheduled earlier than the selected delay, do
1158 * not schedule any other reports.
1159 * Otherwise, reset the interface timer.
1160 */
1161 os_log_debug(OS_LOG_DEFAULT, "%s: process v2 general query on ifp %s\n",
1162 __func__, if_name(ifp));
1163 if (mli->mli_v2_timer == 0 || mli->mli_v2_timer >= timer) {
1164 mtp.it = mli->mli_v2_timer = MLD_RANDOM_DELAY(timer);
1165 }
1166 MLI_UNLOCK(mli);
1167 } else {
1168 MLI_UNLOCK(mli);
1169 /*
1170 * MLDv2 Group-specific or Group-and-source-specific Query.
1171 *
1172 * Group-source-specific queries are throttled on
1173 * a per-group basis to defeat denial-of-service attempts.
1174 * Queries for groups we are not a member of on this
1175 * link are simply ignored.
1176 */
1177 in6_multihead_lock_shared();
1178 IN6_LOOKUP_MULTI(&mld->mld_addr, ifp, inm);
1179 in6_multihead_lock_done();
1180 if (inm == NULL) {
1181 goto done;
1182 }
1183
1184 IN6M_LOCK(inm);
1185 if (nsrc > 0) {
1186 if (!ratecheck(&inm->in6m_lastgsrtv,
1187 &mld_gsrdelay)) {
1188 os_log_info(OS_LOG_DEFAULT, "%s: GS query throttled\n",
1189 __func__);
1190 IN6M_UNLOCK(inm);
1191 IN6M_REMREF(inm); /* from IN6_LOOKUP_MULTI */
1192 goto done;
1193 }
1194 }
1195 os_log_debug(OS_LOG_DEFAULT, "%s: process v2 group query on ifp %s\n",
1196 __func__, if_name(ifp));
1197 /*
1198 * If there is a pending General Query response
1199 * scheduled sooner than the selected delay, no
1200 * further report need be scheduled.
1201 * Otherwise, prepare to respond to the
1202 * group-specific or group-and-source query.
1203 */
1204 MLI_LOCK(mli);
1205 mtp.it = mli->mli_v2_timer;
1206 MLI_UNLOCK(mli);
1207 if (mtp.it == 0 || mtp.it >= timer) {
1208 (void) mld_v2_process_group_query(inm, timer, m, off);
1209 mtp.cst = inm->in6m_timer;
1210 }
1211 IN6M_UNLOCK(inm);
1212 IN6M_REMREF(inm); /* from IN6_LOOKUP_MULTI */
1213 /* XXX Clear embedded scope ID as userland won't expect it. */
1214 in6_clearscope(&mld->mld_addr);
1215 }
1216 done:
1217 if (mtp.it > 0) {
1218 os_log_debug(OS_LOG_DEFAULT, "%s: v2 general query response scheduled in "
1219 "T+%d seconds on ifp %s\n", __func__, mtp.it,
1220 if_name(ifp));
1221 }
1222 mld_set_timeout(&mtp);
1223
1224 return err;
1225 }
1226
1227 /*
1228 * Process a recieved MLDv2 group-specific or group-and-source-specific
1229 * query.
1230 * Return <0 if any error occured. Currently this is ignored.
1231 */
1232 static int
mld_v2_process_group_query(struct in6_multi * inm,int timer,struct mbuf * m0,const int off)1233 mld_v2_process_group_query(struct in6_multi *inm, int timer, struct mbuf *m0,
1234 const int off)
1235 {
1236 struct mldv2_query *mld;
1237 int retval;
1238 uint16_t nsrc;
1239
1240 IN6M_LOCK_ASSERT_HELD(inm);
1241
1242 retval = 0;
1243 mld = (struct mldv2_query *)(mtod(m0, uint8_t *) + off);
1244
1245 switch (inm->in6m_state) {
1246 case MLD_NOT_MEMBER:
1247 case MLD_SILENT_MEMBER:
1248 case MLD_SLEEPING_MEMBER:
1249 case MLD_LAZY_MEMBER:
1250 case MLD_AWAKENING_MEMBER:
1251 case MLD_IDLE_MEMBER:
1252 case MLD_LEAVING_MEMBER:
1253 return retval;
1254 case MLD_REPORTING_MEMBER:
1255 case MLD_G_QUERY_PENDING_MEMBER:
1256 case MLD_SG_QUERY_PENDING_MEMBER:
1257 break;
1258 }
1259
1260 nsrc = ntohs(mld->mld_numsrc);
1261
1262 /*
1263 * Deal with group-specific queries upfront.
1264 * If any group query is already pending, purge any recorded
1265 * source-list state if it exists, and schedule a query response
1266 * for this group-specific query.
1267 */
1268 if (nsrc == 0) {
1269 if (inm->in6m_state == MLD_G_QUERY_PENDING_MEMBER ||
1270 inm->in6m_state == MLD_SG_QUERY_PENDING_MEMBER) {
1271 in6m_clear_recorded(inm);
1272 timer = min(inm->in6m_timer, timer);
1273 }
1274 inm->in6m_state = MLD_G_QUERY_PENDING_MEMBER;
1275 inm->in6m_timer = MLD_RANDOM_DELAY(timer);
1276 return retval;
1277 }
1278
1279 /*
1280 * Deal with the case where a group-and-source-specific query has
1281 * been received but a group-specific query is already pending.
1282 */
1283 if (inm->in6m_state == MLD_G_QUERY_PENDING_MEMBER) {
1284 timer = min(inm->in6m_timer, timer);
1285 inm->in6m_timer = MLD_RANDOM_DELAY(timer);
1286 return retval;
1287 }
1288
1289 /*
1290 * Finally, deal with the case where a group-and-source-specific
1291 * query has been received, where a response to a previous g-s-r
1292 * query exists, or none exists.
1293 * In this case, we need to parse the source-list which the Querier
1294 * has provided us with and check if we have any source list filter
1295 * entries at T1 for these sources. If we do not, there is no need
1296 * schedule a report and the query may be dropped.
1297 * If we do, we must record them and schedule a current-state
1298 * report for those sources.
1299 */
1300 if (inm->in6m_nsrc > 0) {
1301 struct mbuf *m;
1302 struct in6_addr addr;
1303 int i, nrecorded;
1304 int soff;
1305
1306 m = m0;
1307 soff = off + sizeof(struct mldv2_query);
1308 nrecorded = 0;
1309 for (i = 0; i < nsrc; i++) {
1310 m_copydata(m, soff, sizeof(addr), &addr);
1311 retval = in6m_record_source(inm, &addr);
1312 if (retval < 0) {
1313 break;
1314 }
1315 nrecorded += retval;
1316 soff += sizeof(struct in6_addr);
1317
1318 while (m && (soff >= m->m_len)) {
1319 soff -= m->m_len;
1320 m = m->m_next;
1321 }
1322
1323 /* should not be possible: */
1324 if (m == NULL) {
1325 break;
1326 }
1327 }
1328 if (nrecorded > 0) {
1329 MLD_PRINTF(("%s: schedule response to SG query\n",
1330 __func__));
1331 inm->in6m_state = MLD_SG_QUERY_PENDING_MEMBER;
1332 inm->in6m_timer = MLD_RANDOM_DELAY(timer);
1333 }
1334 }
1335
1336 return retval;
1337 }
1338
1339 /*
1340 * Process a received MLDv1 host membership report.
1341 * Assumes mld points to mld_hdr in pulled up mbuf chain.
1342 *
1343 * NOTE: Can't be fully const correct as we temporarily embed scope ID in
1344 * mld_addr. This is OK as we own the mbuf chain.
1345 */
1346 static int
mld_v1_input_report(struct ifnet * ifp,struct mbuf * m,const struct ip6_hdr * ip6,struct mld_hdr * mld)1347 mld_v1_input_report(struct ifnet *ifp, struct mbuf *m,
1348 const struct ip6_hdr *ip6, /*const*/ struct mld_hdr *mld)
1349 {
1350 struct in6_addr src, dst;
1351 struct in6_ifaddr *ia;
1352 struct in6_multi *inm;
1353
1354 if (!mld_v1enable) {
1355 os_log_info(OS_LOG_DEFAULT, "%s: ignore v1 report on ifp %s\n",
1356 __func__, if_name(ifp));
1357 return 0;
1358 }
1359
1360 if ((ifp->if_flags & IFF_LOOPBACK) ||
1361 (m->m_pkthdr.pkt_flags & PKTF_LOOP)) {
1362 return 0;
1363 }
1364
1365 /*
1366 * MLDv1 reports must originate from a host's link-local address,
1367 * or the unspecified address (when booting).
1368 */
1369 src = ip6->ip6_src;
1370 in6_clearscope(&src);
1371 if (!IN6_IS_SCOPE_LINKLOCAL(&src) && !IN6_IS_ADDR_UNSPECIFIED(&src)) {
1372 os_log_info(OS_LOG_DEFAULT, "%s: ignore v1 query src %s on ifp %s\n",
1373 __func__, ip6_sprintf(&ip6->ip6_src),
1374 if_name(ifp));
1375 return EINVAL;
1376 }
1377
1378 /*
1379 * RFC2710 Section 4: MLDv1 reports must pertain to a multicast
1380 * group, and must be directed to the group itself.
1381 */
1382 dst = ip6->ip6_dst;
1383 in6_clearscope(&dst);
1384 if (!IN6_IS_ADDR_MULTICAST(&mld->mld_addr) ||
1385 !IN6_ARE_ADDR_EQUAL(&mld->mld_addr, &dst)) {
1386 os_log_info(OS_LOG_DEFAULT, "%s: ignore v1 query dst %s on ifp %s\n",
1387 __func__, ip6_sprintf(&ip6->ip6_dst),
1388 if_name(ifp));
1389 return EINVAL;
1390 }
1391
1392 /*
1393 * Make sure we don't hear our own membership report, as fast
1394 * leave requires knowing that we are the only member of a
1395 * group. Assume we used the link-local address if available,
1396 * otherwise look for ::.
1397 *
1398 * XXX Note that scope ID comparison is needed for the address
1399 * returned by in6ifa_ifpforlinklocal(), but SHOULD NOT be
1400 * performed for the on-wire address.
1401 */
1402 ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
1403 if (ia != NULL) {
1404 IFA_LOCK(&ia->ia_ifa);
1405 if ((IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, IA6_IN6(ia)))) {
1406 IFA_UNLOCK(&ia->ia_ifa);
1407 ifa_remref(&ia->ia_ifa);
1408 return 0;
1409 }
1410 IFA_UNLOCK(&ia->ia_ifa);
1411 ifa_remref(&ia->ia_ifa);
1412 } else if (IN6_IS_ADDR_UNSPECIFIED(&src)) {
1413 return 0;
1414 }
1415
1416 os_log_debug(OS_LOG_DEFAULT, "%s: process v1 report %s on ifp %s\n",
1417 __func__, ip6_sprintf(&mld->mld_addr),
1418 if_name(ifp));
1419
1420 /*
1421 * Embed scope ID of receiving interface in MLD query for lookup
1422 * whilst we don't hold other locks (due to KAME locking lameness).
1423 */
1424 if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) {
1425 (void)in6_setscope(&mld->mld_addr, ifp, NULL);
1426 }
1427
1428 /*
1429 * MLDv1 report suppression.
1430 * If we are a member of this group, and our membership should be
1431 * reported, and our group timer is pending or about to be reset,
1432 * stop our group timer by transitioning to the 'lazy' state.
1433 */
1434 in6_multihead_lock_shared();
1435 IN6_LOOKUP_MULTI(&mld->mld_addr, ifp, inm);
1436 in6_multihead_lock_done();
1437
1438 if (inm != NULL) {
1439 struct mld_ifinfo *mli;
1440
1441 IN6M_LOCK(inm);
1442 mli = inm->in6m_mli;
1443 VERIFY(mli != NULL);
1444
1445 MLI_LOCK(mli);
1446 /*
1447 * If we are in MLDv2 host mode, do not allow the
1448 * other host's MLDv1 report to suppress our reports.
1449 */
1450 if (mli->mli_version == MLD_VERSION_2) {
1451 MLI_UNLOCK(mli);
1452 IN6M_UNLOCK(inm);
1453 IN6M_REMREF(inm); /* from IN6_LOOKUP_MULTI */
1454 goto out;
1455 }
1456 MLI_UNLOCK(mli);
1457
1458 inm->in6m_timer = 0;
1459
1460 switch (inm->in6m_state) {
1461 case MLD_NOT_MEMBER:
1462 case MLD_SILENT_MEMBER:
1463 case MLD_SLEEPING_MEMBER:
1464 break;
1465 case MLD_REPORTING_MEMBER:
1466 case MLD_IDLE_MEMBER:
1467 case MLD_AWAKENING_MEMBER:
1468 MLD_PRINTF(("%s: report suppressed for %s on "
1469 "ifp 0x%llx(%s)\n", __func__,
1470 ip6_sprintf(&mld->mld_addr),
1471 (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
1472 OS_FALLTHROUGH;
1473 case MLD_LAZY_MEMBER:
1474 inm->in6m_state = MLD_LAZY_MEMBER;
1475 break;
1476 case MLD_G_QUERY_PENDING_MEMBER:
1477 case MLD_SG_QUERY_PENDING_MEMBER:
1478 case MLD_LEAVING_MEMBER:
1479 break;
1480 }
1481 IN6M_UNLOCK(inm);
1482 IN6M_REMREF(inm); /* from IN6_LOOKUP_MULTI */
1483 }
1484
1485 out:
1486 /* XXX Clear embedded scope ID as userland won't expect it. */
1487 in6_clearscope(&mld->mld_addr);
1488
1489 return 0;
1490 }
1491
1492 /*
1493 * MLD input path.
1494 *
1495 * Assume query messages which fit in a single ICMPv6 message header
1496 * have been pulled up.
1497 * Assume that userland will want to see the message, even if it
1498 * otherwise fails kernel input validation; do not free it.
1499 * Pullup may however free the mbuf chain m if it fails.
1500 *
1501 * Return IPPROTO_DONE if we freed m. Otherwise, return 0.
1502 */
1503 int
mld_input(struct mbuf * m,int off,int icmp6len)1504 mld_input(struct mbuf *m, int off, int icmp6len)
1505 {
1506 struct ifnet *ifp = NULL;
1507 struct ip6_hdr *ip6 = NULL;
1508 struct mld_hdr *mld = NULL;
1509 int mldlen = 0;
1510
1511 MLD_PRINTF(("%s: called w/mbuf (0x%llx,%d)\n", __func__,
1512 (uint64_t)VM_KERNEL_ADDRPERM(m), off));
1513
1514 ifp = m->m_pkthdr.rcvif;
1515
1516 /* Pullup to appropriate size. */
1517 mld = (struct mld_hdr *)(mtod(m, uint8_t *) + off);
1518 if (mld->mld_type == MLD_LISTENER_QUERY &&
1519 icmp6len >= sizeof(struct mldv2_query)) {
1520 mldlen = sizeof(struct mldv2_query);
1521 } else {
1522 mldlen = sizeof(struct mld_hdr);
1523 }
1524 // check if mldv2_query/mld_hdr fits in the first mbuf
1525 IP6_EXTHDR_CHECK(m, off, mldlen, return IPPROTO_DONE);
1526 IP6_EXTHDR_GET(mld, struct mld_hdr *, m, off, mldlen);
1527 if (mld == NULL) {
1528 icmp6stat.icp6s_badlen++;
1529 return IPPROTO_DONE;
1530 }
1531 ip6 = mtod(m, struct ip6_hdr *);
1532
1533 /*
1534 * Userland needs to see all of this traffic for implementing
1535 * the endpoint discovery portion of multicast routing.
1536 */
1537 switch (mld->mld_type) {
1538 case MLD_LISTENER_QUERY:
1539 icmp6_ifstat_inc(ifp, ifs6_in_mldquery);
1540 if (icmp6len == sizeof(struct mld_hdr)) {
1541 if (mld_v1_input_query(ifp, ip6, mld) != 0) {
1542 return 0;
1543 }
1544 } else if (icmp6len >= sizeof(struct mldv2_query)) {
1545 if (mld_v2_input_query(ifp, ip6, m, off,
1546 icmp6len) != 0) {
1547 return 0;
1548 }
1549 }
1550 break;
1551 case MLD_LISTENER_REPORT:
1552 icmp6_ifstat_inc(ifp, ifs6_in_mldreport);
1553 if (mld_v1_input_report(ifp, m, ip6, mld) != 0) {
1554 return 0;
1555 }
1556 break;
1557 case MLDV2_LISTENER_REPORT:
1558 icmp6_ifstat_inc(ifp, ifs6_in_mldreport);
1559 break;
1560 case MLD_LISTENER_DONE:
1561 icmp6_ifstat_inc(ifp, ifs6_in_mlddone);
1562 break;
1563 default:
1564 break;
1565 }
1566
1567 return 0;
1568 }
1569
1570 /*
1571 * Schedule MLD timer based on various parameters; caller must ensure that
1572 * lock ordering is maintained as this routine acquires MLD global lock.
1573 */
1574 void
mld_set_timeout(struct mld_tparams * mtp)1575 mld_set_timeout(struct mld_tparams *mtp)
1576 {
1577 MLD_LOCK_ASSERT_NOTHELD();
1578 VERIFY(mtp != NULL);
1579
1580 if (mtp->qpt != 0 || mtp->it != 0 || mtp->cst != 0 || mtp->sct != 0) {
1581 MLD_LOCK();
1582 if (mtp->qpt != 0) {
1583 querier_present_timers_running6 = 1;
1584 }
1585 if (mtp->it != 0) {
1586 interface_timers_running6 = 1;
1587 }
1588 if (mtp->cst != 0) {
1589 current_state_timers_running6 = 1;
1590 }
1591 if (mtp->sct != 0) {
1592 state_change_timers_running6 = 1;
1593 }
1594 if (mtp->fast) {
1595 mld_sched_fast_timeout();
1596 } else {
1597 mld_sched_timeout();
1598 }
1599 MLD_UNLOCK();
1600 }
1601 }
1602
1603 void
mld_set_fast_timeout(struct mld_tparams * mtp)1604 mld_set_fast_timeout(struct mld_tparams *mtp)
1605 {
1606 VERIFY(mtp != NULL);
1607 mtp->fast = true;
1608 mld_set_timeout(mtp);
1609 }
1610
1611 /*
1612 * MLD6 timer handler (per 1 second).
1613 */
1614 static void
mld_timeout(thread_call_param_t arg0,thread_call_param_t arg1 __unused)1615 mld_timeout(thread_call_param_t arg0, thread_call_param_t arg1 __unused)
1616 {
1617 struct ifqueue scq; /* State-change packets */
1618 struct ifqueue qrq; /* Query response packets */
1619 struct ifnet *ifp;
1620 struct mld_ifinfo *mli;
1621 struct in6_multi *inm;
1622 int uri_sec = 0;
1623 unsigned int genid = mld_mli_list_genid;
1624 bool fast = arg0 != NULL;
1625
1626 SLIST_HEAD(, in6_multi) in6m_dthead;
1627
1628 SLIST_INIT(&in6m_dthead);
1629
1630 /*
1631 * Update coarse-grained networking timestamp (in sec.); the idea
1632 * is to piggy-back on the timeout callout to update the counter
1633 * returnable via net_uptime().
1634 */
1635 net_update_uptime();
1636
1637 MLD_LOCK();
1638
1639 MLD_PRINTF(("%s: qpt %d, it %d, cst %d, sct %d, fast %d\n", __func__,
1640 querier_present_timers_running6, interface_timers_running6,
1641 current_state_timers_running6, state_change_timers_running6, fast));
1642
1643 if (fast) {
1644 /*
1645 * When running the fast timer, skip processing
1646 * of "querier present" timers since they are
1647 * based on 1-second intervals.
1648 */
1649 goto skip_query_timers;
1650 }
1651 /*
1652 * MLDv1 querier present timer processing.
1653 */
1654 if (querier_present_timers_running6) {
1655 querier_present_timers_running6 = 0;
1656 LIST_FOREACH(mli, &mli_head, mli_link) {
1657 MLI_LOCK(mli);
1658 mld_v1_process_querier_timers(mli);
1659 if (mli->mli_v1_timer > 0) {
1660 querier_present_timers_running6 = 1;
1661 }
1662 MLI_UNLOCK(mli);
1663 }
1664 }
1665
1666 /*
1667 * MLDv2 General Query response timer processing.
1668 */
1669 if (interface_timers_running6) {
1670 MLD_PRINTF(("%s: interface timers running\n", __func__));
1671 interface_timers_running6 = 0;
1672 mli = LIST_FIRST(&mli_head);
1673
1674 while (mli != NULL) {
1675 if (mli->mli_flags & MLIF_PROCESSED) {
1676 mli = LIST_NEXT(mli, mli_link);
1677 continue;
1678 }
1679
1680 MLI_LOCK(mli);
1681 if (mli->mli_version != MLD_VERSION_2) {
1682 MLI_UNLOCK(mli);
1683 mli = LIST_NEXT(mli, mli_link);
1684 continue;
1685 }
1686 /*
1687 * XXX The logic below ends up calling
1688 * mld_dispatch_packet which can unlock mli
1689 * and the global MLD lock.
1690 * Therefore grab a reference on MLI and also
1691 * check for generation count to see if we should
1692 * iterate the list again.
1693 */
1694 MLI_ADDREF_LOCKED(mli);
1695
1696 if (mli->mli_v2_timer == 0) {
1697 /* Do nothing. */
1698 } else if (--mli->mli_v2_timer == 0) {
1699 if (mld_v2_dispatch_general_query(mli) > 0) {
1700 interface_timers_running6 = 1;
1701 }
1702 } else {
1703 interface_timers_running6 = 1;
1704 }
1705 mli->mli_flags |= MLIF_PROCESSED;
1706 MLI_UNLOCK(mli);
1707 MLI_REMREF(mli);
1708
1709 if (genid != mld_mli_list_genid) {
1710 MLD_PRINTF(("%s: MLD information list changed "
1711 "in the middle of iteration! Restart iteration.\n",
1712 __func__));
1713 mli = LIST_FIRST(&mli_head);
1714 genid = mld_mli_list_genid;
1715 } else {
1716 mli = LIST_NEXT(mli, mli_link);
1717 }
1718 }
1719
1720 LIST_FOREACH(mli, &mli_head, mli_link)
1721 mli->mli_flags &= ~MLIF_PROCESSED;
1722 }
1723
1724 skip_query_timers:
1725 if (!current_state_timers_running6 &&
1726 !state_change_timers_running6) {
1727 goto out_locked;
1728 }
1729
1730 current_state_timers_running6 = 0;
1731 state_change_timers_running6 = 0;
1732
1733 MLD_PRINTF(("%s: state change timers running\n", __func__));
1734
1735 memset(&qrq, 0, sizeof(struct ifqueue));
1736 qrq.ifq_maxlen = MLD_MAX_G_GS_PACKETS;
1737
1738 memset(&scq, 0, sizeof(struct ifqueue));
1739 scq.ifq_maxlen = MLD_MAX_STATE_CHANGE_PACKETS;
1740
1741 /*
1742 * MLD host report and state-change timer processing.
1743 * Note: Processing a v2 group timer may remove a node.
1744 */
1745 mli = LIST_FIRST(&mli_head);
1746
1747 while (mli != NULL) {
1748 struct in6_multistep step;
1749
1750 if (mli->mli_flags & MLIF_PROCESSED) {
1751 mli = LIST_NEXT(mli, mli_link);
1752 continue;
1753 }
1754
1755 MLI_LOCK(mli);
1756 ifp = mli->mli_ifp;
1757 uri_sec = MLD_RANDOM_DELAY(mli->mli_uri);
1758 MLI_UNLOCK(mli);
1759
1760 in6_multihead_lock_shared();
1761 IN6_FIRST_MULTI(step, inm);
1762 while (inm != NULL) {
1763 IN6M_LOCK(inm);
1764 if (inm->in6m_ifp != ifp) {
1765 goto next;
1766 }
1767
1768 MLI_LOCK(mli);
1769 switch (mli->mli_version) {
1770 case MLD_VERSION_1:
1771 mld_v1_process_group_timer(inm,
1772 mli->mli_version);
1773 break;
1774 case MLD_VERSION_2:
1775 mld_v2_process_group_timers(mli, &qrq,
1776 &scq, inm, uri_sec);
1777 break;
1778 }
1779 MLI_UNLOCK(mli);
1780 next:
1781 IN6M_UNLOCK(inm);
1782 IN6_NEXT_MULTI(step, inm);
1783 }
1784 in6_multihead_lock_done();
1785
1786 /*
1787 * XXX The logic below ends up calling
1788 * mld_dispatch_packet which can unlock mli
1789 * and the global MLD lock.
1790 * Therefore grab a reference on MLI and also
1791 * check for generation count to see if we should
1792 * iterate the list again.
1793 */
1794 MLI_LOCK(mli);
1795 MLI_ADDREF_LOCKED(mli);
1796 if (mli->mli_version == MLD_VERSION_1) {
1797 mld_dispatch_queue_locked(mli, &mli->mli_v1q, 0);
1798 } else if (mli->mli_version == MLD_VERSION_2) {
1799 MLI_UNLOCK(mli);
1800 mld_dispatch_queue_locked(NULL, &qrq, 0);
1801 mld_dispatch_queue_locked(NULL, &scq, 0);
1802 VERIFY(qrq.ifq_len == 0);
1803 VERIFY(scq.ifq_len == 0);
1804 MLI_LOCK(mli);
1805 }
1806 /*
1807 * In case there are still any pending membership reports
1808 * which didn't get drained at version change time.
1809 */
1810 IF_DRAIN(&mli->mli_v1q);
1811 /*
1812 * Release all deferred inm records, and drain any locally
1813 * enqueued packets; do it even if the current MLD version
1814 * for the link is no longer MLDv2, in order to handle the
1815 * version change case.
1816 */
1817 mld_flush_relq(mli, (struct mld_in6m_relhead *)&in6m_dthead);
1818 mli->mli_flags |= MLIF_PROCESSED;
1819 MLI_UNLOCK(mli);
1820 MLI_REMREF(mli);
1821
1822 IF_DRAIN(&qrq);
1823 IF_DRAIN(&scq);
1824
1825 if (genid != mld_mli_list_genid) {
1826 MLD_PRINTF(("%s: MLD information list changed "
1827 "in the middle of iteration! Restart iteration.\n",
1828 __func__));
1829 mli = LIST_FIRST(&mli_head);
1830 genid = mld_mli_list_genid;
1831 } else {
1832 mli = LIST_NEXT(mli, mli_link);
1833 }
1834 }
1835
1836 LIST_FOREACH(mli, &mli_head, mli_link)
1837 mli->mli_flags &= ~MLIF_PROCESSED;
1838
1839 out_locked:
1840 /* re-arm the timer if there's work to do */
1841 if (fast) {
1842 mld_fast_timeout_run = false;
1843 } else {
1844 mld_timeout_run = false;
1845 }
1846 mld_sched_timeout();
1847 MLD_UNLOCK();
1848
1849 /* Now that we're dropped all locks, release detached records */
1850 MLD_REMOVE_DETACHED_IN6M(&in6m_dthead);
1851 }
1852
1853 static void
mld_sched_timeout(void)1854 mld_sched_timeout(void)
1855 {
1856 static thread_call_t mld_timeout_tcall;
1857 uint64_t deadline = 0, leeway = 0;
1858
1859 MLD_LOCK_ASSERT_HELD();
1860 if (mld_timeout_tcall == NULL) {
1861 mld_timeout_tcall =
1862 thread_call_allocate_with_options(mld_timeout,
1863 NULL,
1864 THREAD_CALL_PRIORITY_KERNEL,
1865 THREAD_CALL_OPTIONS_ONCE);
1866 }
1867
1868 if (!mld_timeout_run &&
1869 (querier_present_timers_running6 || current_state_timers_running6 ||
1870 interface_timers_running6 || state_change_timers_running6)) {
1871 mld_timeout_run = true;
1872 clock_interval_to_deadline(mld_timeout_delay, NSEC_PER_MSEC,
1873 &deadline);
1874 clock_interval_to_absolutetime_interval(mld_timeout_leeway,
1875 NSEC_PER_MSEC, &leeway);
1876 thread_call_enter_delayed_with_leeway(mld_timeout_tcall, NULL,
1877 deadline, leeway,
1878 THREAD_CALL_DELAY_LEEWAY);
1879 }
1880 }
1881
1882 static void
mld_sched_fast_timeout(void)1883 mld_sched_fast_timeout(void)
1884 {
1885 static thread_call_t mld_fast_timeout_tcall;
1886
1887 MLD_LOCK_ASSERT_HELD();
1888 if (mld_fast_timeout_tcall == NULL) {
1889 mld_fast_timeout_tcall =
1890 thread_call_allocate_with_options(mld_timeout,
1891 mld_sched_fast_timeout,
1892 THREAD_CALL_PRIORITY_KERNEL,
1893 THREAD_CALL_OPTIONS_ONCE);
1894 }
1895 if (!mld_fast_timeout_run &&
1896 (current_state_timers_running6 || state_change_timers_running6)) {
1897 mld_fast_timeout_run = true;
1898 thread_call_enter(mld_fast_timeout_tcall);
1899 }
1900 }
1901
1902 /*
1903 * Appends an in6_multi to the list to be released later.
1904 *
1905 * Caller must be holding mli_lock.
1906 */
1907 static void
mld_append_relq(struct mld_ifinfo * mli,struct in6_multi * inm)1908 mld_append_relq(struct mld_ifinfo *mli, struct in6_multi *inm)
1909 {
1910 MLI_LOCK_ASSERT_HELD(mli);
1911 if (inm->in6m_in_nrele) {
1912 os_log_debug(OS_LOG_DEFAULT, "%s: inm %llx already on relq ifp %s\n",
1913 __func__, (uint64_t)VM_KERNEL_ADDRPERM(inm),
1914 mli->mli_ifp != NULL ? if_name(mli->mli_ifp) : "<null>");
1915 return;
1916 }
1917 os_log_debug(OS_LOG_DEFAULT, "%s: adding inm %llx on relq ifp %s\n",
1918 __func__, (uint64_t)VM_KERNEL_ADDRPERM(inm),
1919 mli->mli_ifp != NULL ? if_name(mli->mli_ifp) : "<null>");
1920 inm->in6m_in_nrele = true;
1921 SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm, in6m_nrele);
1922 }
1923
1924 /*
1925 * Free the in6_multi reference(s) for this MLD lifecycle.
1926 *
1927 * Caller must be holding mli_lock.
1928 */
1929 static void
mld_flush_relq(struct mld_ifinfo * mli,struct mld_in6m_relhead * in6m_dthead)1930 mld_flush_relq(struct mld_ifinfo *mli, struct mld_in6m_relhead *in6m_dthead)
1931 {
1932 struct in6_multi *inm;
1933 SLIST_HEAD(, in6_multi) temp_relinmhead;
1934
1935 /*
1936 * Before dropping the mli_lock, copy all the items in the
1937 * release list to a temporary list to prevent other threads
1938 * from changing mli_relinmhead while we are traversing it.
1939 */
1940 MLI_LOCK_ASSERT_HELD(mli);
1941 SLIST_INIT(&temp_relinmhead);
1942 while ((inm = SLIST_FIRST(&mli->mli_relinmhead)) != NULL) {
1943 SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele);
1944 SLIST_INSERT_HEAD(&temp_relinmhead, inm, in6m_nrele);
1945 }
1946 MLI_UNLOCK(mli);
1947 in6_multihead_lock_exclusive();
1948 while ((inm = SLIST_FIRST(&temp_relinmhead)) != NULL) {
1949 int lastref;
1950
1951 SLIST_REMOVE_HEAD(&temp_relinmhead, in6m_nrele);
1952 IN6M_LOCK(inm);
1953 os_log_debug(OS_LOG_DEFAULT, "%s: flushing inm %llx on relq ifp %s\n",
1954 __func__, (uint64_t)VM_KERNEL_ADDRPERM(inm),
1955 inm->in6m_ifp != NULL ? if_name(inm->in6m_ifp) : "<null>");
1956 VERIFY(inm->in6m_in_nrele == true);
1957 inm->in6m_in_nrele = false;
1958 VERIFY(inm->in6m_nrelecnt != 0);
1959 inm->in6m_nrelecnt--;
1960 lastref = in6_multi_detach(inm);
1961 VERIFY(!lastref || (!(inm->in6m_debug & IFD_ATTACHED) &&
1962 inm->in6m_reqcnt == 0));
1963 IN6M_UNLOCK(inm);
1964 /* from mli_relinmhead */
1965 IN6M_REMREF(inm);
1966 /* from in6_multihead_list */
1967 if (lastref) {
1968 /*
1969 * Defer releasing our final reference, as we
1970 * are holding the MLD lock at this point, and
1971 * we could end up with locking issues later on
1972 * (while issuing SIOCDELMULTI) when this is the
1973 * final reference count. Let the caller do it
1974 * when it is safe.
1975 */
1976 MLD_ADD_DETACHED_IN6M(in6m_dthead, inm);
1977 }
1978 }
1979 in6_multihead_lock_done();
1980 MLI_LOCK(mli);
1981 }
1982
1983 /*
1984 * Update host report group timer.
1985 * Will update the global pending timer flags.
1986 */
1987 static void
mld_v1_process_group_timer(struct in6_multi * inm,const int mld_version)1988 mld_v1_process_group_timer(struct in6_multi *inm, const int mld_version)
1989 {
1990 #pragma unused(mld_version)
1991 int report_timer_expired;
1992
1993 MLD_LOCK_ASSERT_HELD();
1994 IN6M_LOCK_ASSERT_HELD(inm);
1995 MLI_LOCK_ASSERT_HELD(inm->in6m_mli);
1996
1997 if (inm->in6m_timer == 0) {
1998 report_timer_expired = 0;
1999 } else if (--inm->in6m_timer == 0) {
2000 report_timer_expired = 1;
2001 } else {
2002 current_state_timers_running6 = 1;
2003 /* caller will schedule timer */
2004 return;
2005 }
2006
2007 switch (inm->in6m_state) {
2008 case MLD_NOT_MEMBER:
2009 case MLD_SILENT_MEMBER:
2010 case MLD_IDLE_MEMBER:
2011 case MLD_LAZY_MEMBER:
2012 case MLD_SLEEPING_MEMBER:
2013 case MLD_AWAKENING_MEMBER:
2014 break;
2015 case MLD_REPORTING_MEMBER:
2016 if (report_timer_expired) {
2017 inm->in6m_state = MLD_IDLE_MEMBER;
2018 (void) mld_v1_transmit_report(inm,
2019 MLD_LISTENER_REPORT);
2020 IN6M_LOCK_ASSERT_HELD(inm);
2021 MLI_LOCK_ASSERT_HELD(inm->in6m_mli);
2022 }
2023 break;
2024 case MLD_G_QUERY_PENDING_MEMBER:
2025 case MLD_SG_QUERY_PENDING_MEMBER:
2026 case MLD_LEAVING_MEMBER:
2027 break;
2028 }
2029 }
2030
2031 /*
2032 * Update a group's timers for MLDv2.
2033 * Will update the global pending timer flags.
2034 * Note: Unlocked read from mli.
2035 */
2036 static void
mld_v2_process_group_timers(struct mld_ifinfo * mli,struct ifqueue * qrq,struct ifqueue * scq,struct in6_multi * inm,const int uri_sec)2037 mld_v2_process_group_timers(struct mld_ifinfo *mli,
2038 struct ifqueue *qrq, struct ifqueue *scq,
2039 struct in6_multi *inm, const int uri_sec)
2040 {
2041 int query_response_timer_expired;
2042 int state_change_retransmit_timer_expired;
2043
2044 MLD_LOCK_ASSERT_HELD();
2045 IN6M_LOCK_ASSERT_HELD(inm);
2046 MLI_LOCK_ASSERT_HELD(mli);
2047 VERIFY(mli == inm->in6m_mli);
2048
2049 query_response_timer_expired = 0;
2050 state_change_retransmit_timer_expired = 0;
2051
2052 /*
2053 * During a transition from compatibility mode back to MLDv2,
2054 * a group record in REPORTING state may still have its group
2055 * timer active. This is a no-op in this function; it is easier
2056 * to deal with it here than to complicate the timeout path.
2057 */
2058 if (inm->in6m_timer == 0) {
2059 query_response_timer_expired = 0;
2060 } else if (--inm->in6m_timer == 0) {
2061 query_response_timer_expired = 1;
2062 } else {
2063 current_state_timers_running6 = 1;
2064 /* caller will schedule timer */
2065 }
2066
2067 if (inm->in6m_sctimer == 0) {
2068 state_change_retransmit_timer_expired = 0;
2069 } else if (--inm->in6m_sctimer == 0) {
2070 state_change_retransmit_timer_expired = 1;
2071 } else {
2072 state_change_timers_running6 = 1;
2073 /* caller will schedule timer */
2074 }
2075
2076 /* We are in timer callback, so be quick about it. */
2077 if (!state_change_retransmit_timer_expired &&
2078 !query_response_timer_expired) {
2079 return;
2080 }
2081
2082 switch (inm->in6m_state) {
2083 case MLD_NOT_MEMBER:
2084 case MLD_SILENT_MEMBER:
2085 case MLD_SLEEPING_MEMBER:
2086 case MLD_LAZY_MEMBER:
2087 case MLD_AWAKENING_MEMBER:
2088 case MLD_IDLE_MEMBER:
2089 break;
2090 case MLD_G_QUERY_PENDING_MEMBER:
2091 case MLD_SG_QUERY_PENDING_MEMBER:
2092 /*
2093 * Respond to a previously pending Group-Specific
2094 * or Group-and-Source-Specific query by enqueueing
2095 * the appropriate Current-State report for
2096 * immediate transmission.
2097 */
2098 if (query_response_timer_expired) {
2099 int retval;
2100
2101 retval = mld_v2_enqueue_group_record(qrq, inm, 0, 1,
2102 (inm->in6m_state == MLD_SG_QUERY_PENDING_MEMBER),
2103 0);
2104 MLD_PRINTF(("%s: enqueue record = %d\n",
2105 __func__, retval));
2106 inm->in6m_state = MLD_REPORTING_MEMBER;
2107 in6m_clear_recorded(inm);
2108 }
2109 OS_FALLTHROUGH;
2110 case MLD_REPORTING_MEMBER:
2111 case MLD_LEAVING_MEMBER:
2112 if (state_change_retransmit_timer_expired) {
2113 /*
2114 * State-change retransmission timer fired.
2115 * If there are any further pending retransmissions,
2116 * set the global pending state-change flag, and
2117 * reset the timer.
2118 */
2119 if (--inm->in6m_scrv > 0) {
2120 inm->in6m_sctimer = (uint16_t)uri_sec;
2121 state_change_timers_running6 = 1;
2122 /* caller will schedule timer */
2123 }
2124 /*
2125 * Retransmit the previously computed state-change
2126 * report. If there are no further pending
2127 * retransmissions, the mbuf queue will be consumed.
2128 * Update T0 state to T1 as we have now sent
2129 * a state-change.
2130 */
2131 (void) mld_v2_merge_state_changes(inm, scq);
2132
2133 in6m_commit(inm);
2134 MLD_PRINTF(("%s: T1 -> T0 for %s/%s\n", __func__,
2135 ip6_sprintf(&inm->in6m_addr),
2136 if_name(inm->in6m_ifp)));
2137
2138 /*
2139 * If we are leaving the group for good, make sure
2140 * we release MLD's reference to it.
2141 * This release must be deferred using a SLIST,
2142 * as we are called from a loop which traverses
2143 * the in_ifmultiaddr TAILQ.
2144 */
2145 if (inm->in6m_state == MLD_LEAVING_MEMBER &&
2146 inm->in6m_scrv == 0) {
2147 inm->in6m_state = MLD_NOT_MEMBER;
2148 /*
2149 * A reference has already been held in
2150 * mld_final_leave() for this inm, so
2151 * no need to hold another one. We also
2152 * bumped up its request count then, so
2153 * that it stays in in6_multihead. Both
2154 * of them will be released when it is
2155 * dequeued later on.
2156 */
2157 VERIFY(inm->in6m_nrelecnt != 0);
2158 mld_append_relq(mli, inm);
2159 }
2160 }
2161 break;
2162 }
2163 }
2164
2165 /*
2166 * Switch to a different version on the given interface,
2167 * as per Section 9.12.
2168 */
2169 static uint32_t
mld_set_version(struct mld_ifinfo * mli,const int mld_version)2170 mld_set_version(struct mld_ifinfo *mli, const int mld_version)
2171 {
2172 int old_version_timer;
2173
2174 MLI_LOCK_ASSERT_HELD(mli);
2175
2176 os_log(OS_LOG_DEFAULT, "%s: switching to v%d on ifp %s\n", __func__,
2177 mld_version, if_name(mli->mli_ifp));
2178
2179 if (mld_version == MLD_VERSION_1) {
2180 /*
2181 * Compute the "Older Version Querier Present" timer as per
2182 * Section 9.12, in seconds.
2183 */
2184 old_version_timer = (mli->mli_rv * mli->mli_qi) + mli->mli_qri;
2185 mli->mli_v1_timer = old_version_timer;
2186 }
2187
2188 if (mli->mli_v1_timer > 0 && mli->mli_version != MLD_VERSION_1) {
2189 mli->mli_version = MLD_VERSION_1;
2190 mld_v2_cancel_link_timers(mli);
2191 }
2192
2193 MLI_LOCK_ASSERT_HELD(mli);
2194
2195 return mli->mli_v1_timer;
2196 }
2197
2198 /*
2199 * Cancel pending MLDv2 timers for the given link and all groups
2200 * joined on it; state-change, general-query, and group-query timers.
2201 *
2202 * Only ever called on a transition from v2 to Compatibility mode. Kill
2203 * the timers stone dead (this may be expensive for large N groups), they
2204 * will be restarted if Compatibility Mode deems that they must be due to
2205 * query processing.
2206 */
2207 static void
mld_v2_cancel_link_timers(struct mld_ifinfo * mli)2208 mld_v2_cancel_link_timers(struct mld_ifinfo *mli)
2209 {
2210 struct ifnet *ifp;
2211 struct in6_multi *inm;
2212 struct in6_multistep step;
2213
2214 MLI_LOCK_ASSERT_HELD(mli);
2215
2216 MLD_PRINTF(("%s: cancel v2 timers on ifp 0x%llx(%s)\n", __func__,
2217 (uint64_t)VM_KERNEL_ADDRPERM(mli->mli_ifp), if_name(mli->mli_ifp)));
2218
2219 /*
2220 * Stop the v2 General Query Response on this link stone dead.
2221 * If timer is woken up due to interface_timers_running6,
2222 * the flag will be cleared if there are no pending link timers.
2223 */
2224 mli->mli_v2_timer = 0;
2225
2226 /*
2227 * Now clear the current-state and state-change report timers
2228 * for all memberships scoped to this link.
2229 */
2230 ifp = mli->mli_ifp;
2231 MLI_UNLOCK(mli);
2232
2233 in6_multihead_lock_shared();
2234 IN6_FIRST_MULTI(step, inm);
2235 while (inm != NULL) {
2236 IN6M_LOCK(inm);
2237 if (inm->in6m_ifp != ifp) {
2238 goto next;
2239 }
2240
2241 switch (inm->in6m_state) {
2242 case MLD_NOT_MEMBER:
2243 case MLD_SILENT_MEMBER:
2244 case MLD_IDLE_MEMBER:
2245 case MLD_LAZY_MEMBER:
2246 case MLD_SLEEPING_MEMBER:
2247 case MLD_AWAKENING_MEMBER:
2248 /*
2249 * These states are either not relevant in v2 mode,
2250 * or are unreported. Do nothing.
2251 */
2252 break;
2253 case MLD_LEAVING_MEMBER:
2254 /*
2255 * If we are leaving the group and switching
2256 * version, we need to release the final
2257 * reference held for issuing the INCLUDE {}.
2258 * During mld_final_leave(), we bumped up both the
2259 * request and reference counts. Since we cannot
2260 * call in6_multi_detach() here, defer this task to
2261 * the timer routine.
2262 */
2263 VERIFY(inm->in6m_nrelecnt != 0);
2264 MLI_LOCK(mli);
2265 mld_append_relq(mli, inm);
2266 MLI_UNLOCK(mli);
2267 OS_FALLTHROUGH;
2268 case MLD_G_QUERY_PENDING_MEMBER:
2269 case MLD_SG_QUERY_PENDING_MEMBER:
2270 in6m_clear_recorded(inm);
2271 OS_FALLTHROUGH;
2272 case MLD_REPORTING_MEMBER:
2273 inm->in6m_state = MLD_REPORTING_MEMBER;
2274 break;
2275 }
2276 /*
2277 * Always clear state-change and group report timers.
2278 * Free any pending MLDv2 state-change records.
2279 */
2280 inm->in6m_sctimer = 0;
2281 inm->in6m_timer = 0;
2282 IF_DRAIN(&inm->in6m_scq);
2283 next:
2284 IN6M_UNLOCK(inm);
2285 IN6_NEXT_MULTI(step, inm);
2286 }
2287 in6_multihead_lock_done();
2288
2289 MLI_LOCK(mli);
2290 }
2291
2292 /*
2293 * Update the Older Version Querier Present timers for a link.
2294 * See Section 9.12 of RFC 3810.
2295 */
2296 static void
mld_v1_process_querier_timers(struct mld_ifinfo * mli)2297 mld_v1_process_querier_timers(struct mld_ifinfo *mli)
2298 {
2299 MLI_LOCK_ASSERT_HELD(mli);
2300
2301 if (mld_v2enable && mli->mli_version != MLD_VERSION_2 &&
2302 --mli->mli_v1_timer == 0) {
2303 /*
2304 * MLDv1 Querier Present timer expired; revert to MLDv2.
2305 */
2306 os_log(OS_LOG_DEFAULT, "%s: transition from v%d -> v%d on %s\n",
2307 __func__, mli->mli_version, MLD_VERSION_2,
2308 if_name(mli->mli_ifp));
2309 mli->mli_version = MLD_VERSION_2;
2310 }
2311 }
2312
2313 /*
2314 * Transmit an MLDv1 report immediately.
2315 */
2316 static int
mld_v1_transmit_report(struct in6_multi * in6m,const uint8_t type)2317 mld_v1_transmit_report(struct in6_multi *in6m, const uint8_t type)
2318 {
2319 struct ifnet *ifp;
2320 struct in6_ifaddr *ia;
2321 struct ip6_hdr *ip6;
2322 struct mbuf *mh, *md;
2323 struct mld_hdr *mld;
2324 int error = 0;
2325
2326 IN6M_LOCK_ASSERT_HELD(in6m);
2327 MLI_LOCK_ASSERT_HELD(in6m->in6m_mli);
2328
2329 ifp = in6m->in6m_ifp;
2330 /* ia may be NULL if link-local address is tentative. */
2331 ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
2332
2333 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
2334 if (mh == NULL) {
2335 if (ia != NULL) {
2336 ifa_remref(&ia->ia_ifa);
2337 }
2338 return ENOMEM;
2339 }
2340 MGET(md, M_DONTWAIT, MT_DATA);
2341 if (md == NULL) {
2342 m_free(mh);
2343 if (ia != NULL) {
2344 ifa_remref(&ia->ia_ifa);
2345 }
2346 return ENOMEM;
2347 }
2348 mh->m_next = md;
2349
2350 /*
2351 * FUTURE: Consider increasing alignment by ETHER_HDR_LEN, so
2352 * that ether_output() does not need to allocate another mbuf
2353 * for the header in the most common case.
2354 */
2355 MH_ALIGN(mh, sizeof(struct ip6_hdr));
2356 mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr);
2357 mh->m_len = sizeof(struct ip6_hdr);
2358
2359 ip6 = mtod(mh, struct ip6_hdr *);
2360 ip6->ip6_flow = 0;
2361 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
2362 ip6->ip6_vfc |= IPV6_VERSION;
2363 ip6->ip6_nxt = IPPROTO_ICMPV6;
2364 if (ia != NULL) {
2365 IFA_LOCK(&ia->ia_ifa);
2366 }
2367 ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
2368 ip6_output_setsrcifscope(mh, IFSCOPE_NONE, ia);
2369 if (ia != NULL) {
2370 IFA_UNLOCK(&ia->ia_ifa);
2371 ifa_remref(&ia->ia_ifa);
2372 ia = NULL;
2373 }
2374 ip6->ip6_dst = in6m->in6m_addr;
2375 ip6_output_setdstifscope(mh, in6m->ifscope, NULL);
2376
2377 md->m_len = sizeof(struct mld_hdr);
2378 mld = mtod(md, struct mld_hdr *);
2379 mld->mld_type = type;
2380 mld->mld_code = 0;
2381 mld->mld_cksum = 0;
2382 mld->mld_maxdelay = 0;
2383 mld->mld_reserved = 0;
2384 mld->mld_addr = in6m->in6m_addr;
2385 in6_clearscope(&mld->mld_addr);
2386 mld->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6,
2387 sizeof(struct ip6_hdr), sizeof(struct mld_hdr));
2388
2389 mld_save_context(mh, ifp);
2390 mh->m_flags |= M_MLDV1;
2391
2392 /*
2393 * Due to the fact that at this point we are possibly holding
2394 * in6_multihead_lock in shared or exclusive mode, we can't call
2395 * mld_dispatch_packet() here since that will eventually call
2396 * ip6_output(), which will try to lock in6_multihead_lock and cause
2397 * a deadlock.
2398 * Instead we defer the work to the mld_timeout() thread, thus
2399 * avoiding unlocking in_multihead_lock here.
2400 */
2401 if (IF_QFULL(&in6m->in6m_mli->mli_v1q)) {
2402 os_log_error(OS_LOG_DEFAULT, "%s: v1 outbound queue full\n", __func__);
2403 error = ENOMEM;
2404 m_freem(mh);
2405 } else {
2406 IF_ENQUEUE(&in6m->in6m_mli->mli_v1q, mh);
2407 VERIFY(error == 0);
2408 }
2409
2410 return error;
2411 }
2412
2413 /*
2414 * Process a state change from the upper layer for the given IPv6 group.
2415 *
2416 * Each socket holds a reference on the in6_multi in its own ip_moptions.
2417 * The socket layer will have made the necessary updates to.the group
2418 * state, it is now up to MLD to issue a state change report if there
2419 * has been any change between T0 (when the last state-change was issued)
2420 * and T1 (now).
2421 *
2422 * We use the MLDv2 state machine at group level. The MLd module
2423 * however makes the decision as to which MLD protocol version to speak.
2424 * A state change *from* INCLUDE {} always means an initial join.
2425 * A state change *to* INCLUDE {} always means a final leave.
2426 *
2427 * If delay is non-zero, and the state change is an initial multicast
2428 * join, the state change report will be delayed by 'delay' ticks
2429 * in units of seconds if MLDv1 is active on the link; otherwise
2430 * the initial MLDv2 state change report will be delayed by whichever
2431 * is sooner, a pending state-change timer or delay itself.
2432 */
2433 int
mld_change_state(struct in6_multi * inm,struct mld_tparams * mtp,const int delay)2434 mld_change_state(struct in6_multi *inm, struct mld_tparams *mtp,
2435 const int delay)
2436 {
2437 struct mld_ifinfo *mli;
2438 struct ifnet *ifp;
2439 int error = 0;
2440
2441 VERIFY(mtp != NULL);
2442 bzero(mtp, sizeof(*mtp));
2443
2444 IN6M_LOCK_ASSERT_HELD(inm);
2445 VERIFY(inm->in6m_mli != NULL);
2446 MLI_LOCK_ASSERT_NOTHELD(inm->in6m_mli);
2447
2448 /*
2449 * Try to detect if the upper layer just asked us to change state
2450 * for an interface which has now gone away.
2451 */
2452 VERIFY(inm->in6m_ifma != NULL);
2453 ifp = inm->in6m_ifma->ifma_ifp;
2454 /*
2455 * Sanity check that netinet6's notion of ifp is the same as net's.
2456 */
2457 VERIFY(inm->in6m_ifp == ifp);
2458
2459 mli = MLD_IFINFO(ifp);
2460 VERIFY(mli != NULL);
2461
2462 /*
2463 * If we detect a state transition to or from MCAST_UNDEFINED
2464 * for this group, then we are starting or finishing an MLD
2465 * life cycle for this group.
2466 */
2467 if (inm->in6m_st[1].iss_fmode != inm->in6m_st[0].iss_fmode) {
2468 MLD_PRINTF(("%s: inm transition %d -> %d\n", __func__,
2469 inm->in6m_st[0].iss_fmode, inm->in6m_st[1].iss_fmode));
2470 if (inm->in6m_st[0].iss_fmode == MCAST_UNDEFINED) {
2471 MLD_PRINTF(("%s: initial join\n", __func__));
2472 error = mld_initial_join(inm, mli, mtp, delay);
2473 goto out;
2474 } else if (inm->in6m_st[1].iss_fmode == MCAST_UNDEFINED) {
2475 MLD_PRINTF(("%s: final leave\n", __func__));
2476 mld_final_leave(inm, mli, mtp);
2477 goto out;
2478 }
2479 } else {
2480 MLD_PRINTF(("%s: filter set change\n", __func__));
2481 }
2482
2483 error = mld_handle_state_change(inm, mli, mtp);
2484 out:
2485 return error;
2486 }
2487
2488 /*
2489 * Perform the initial join for an MLD group.
2490 *
2491 * When joining a group:
2492 * If the group should have its MLD traffic suppressed, do nothing.
2493 * MLDv1 starts sending MLDv1 host membership reports.
2494 * MLDv2 will schedule an MLDv2 state-change report containing the
2495 * initial state of the membership.
2496 *
2497 * If the delay argument is non-zero, then we must delay sending the
2498 * initial state change for delay ticks (in units of seconds).
2499 */
2500 static int
mld_initial_join(struct in6_multi * inm,struct mld_ifinfo * mli,struct mld_tparams * mtp,const int delay)2501 mld_initial_join(struct in6_multi *inm, struct mld_ifinfo *mli,
2502 struct mld_tparams *mtp, const int delay)
2503 {
2504 struct ifnet *ifp;
2505 struct ifqueue *ifq;
2506 int error, retval, syncstates;
2507 int odelay;
2508
2509 IN6M_LOCK_ASSERT_HELD(inm);
2510 MLI_LOCK_ASSERT_NOTHELD(mli);
2511 VERIFY(mtp != NULL);
2512
2513 MLD_PRINTF(("%s: initial join %s on ifp 0x%llx(%s)\n",
2514 __func__, ip6_sprintf(&inm->in6m_addr),
2515 (uint64_t)VM_KERNEL_ADDRPERM(inm->in6m_ifp),
2516 if_name(inm->in6m_ifp)));
2517
2518 error = 0;
2519 syncstates = 1;
2520
2521 ifp = inm->in6m_ifp;
2522
2523 MLI_LOCK(mli);
2524 VERIFY(mli->mli_ifp == ifp);
2525
2526 /*
2527 * Avoid MLD if group is :
2528 * 1. Joined on loopback, OR
2529 * 2. On a link that is marked MLIF_SILENT
2530 * 3. rdar://problem/19227650 Is link local scoped and
2531 * on cellular interface
2532 * 4. Is a type that should not be reported (node local
2533 * or all node link local multicast.
2534 * All other groups enter the appropriate state machine
2535 * for the version in use on this link.
2536 */
2537 if ((ifp->if_flags & IFF_LOOPBACK) ||
2538 (mli->mli_flags & MLIF_SILENT) ||
2539 (IFNET_IS_CELLULAR(ifp) &&
2540 (IN6_IS_ADDR_MC_LINKLOCAL(&inm->in6m_addr) || IN6_IS_ADDR_MC_UNICAST_BASED_LINKLOCAL(&inm->in6m_addr))) ||
2541 !mld_is_addr_reported(&inm->in6m_addr)) {
2542 MLD_PRINTF(("%s: not kicking state machine for silent group\n",
2543 __func__));
2544 inm->in6m_state = MLD_SILENT_MEMBER;
2545 inm->in6m_timer = 0;
2546 } else {
2547 /*
2548 * Deal with overlapping in6_multi lifecycle.
2549 * If this group was LEAVING, then make sure
2550 * we drop the reference we picked up to keep the
2551 * group around for the final INCLUDE {} enqueue.
2552 * Since we cannot call in6_multi_detach() here,
2553 * defer this task to the timer routine.
2554 */
2555 if (mli->mli_version == MLD_VERSION_2 &&
2556 inm->in6m_state == MLD_LEAVING_MEMBER) {
2557 VERIFY(inm->in6m_nrelecnt != 0);
2558 mld_append_relq(mli, inm);
2559 }
2560
2561 inm->in6m_state = MLD_REPORTING_MEMBER;
2562
2563 switch (mli->mli_version) {
2564 case MLD_VERSION_1:
2565 /*
2566 * If a delay was provided, only use it if
2567 * it is greater than the delay normally
2568 * used for an MLDv1 state change report,
2569 * and delay sending the initial MLDv1 report
2570 * by not transitioning to the IDLE state.
2571 */
2572 odelay = MLD_RANDOM_DELAY(MLD_V1_MAX_RI);
2573 if (delay) {
2574 inm->in6m_timer = max(delay, odelay);
2575 mtp->cst = 1;
2576 } else {
2577 inm->in6m_state = MLD_IDLE_MEMBER;
2578 error = mld_v1_transmit_report(inm,
2579 MLD_LISTENER_REPORT);
2580
2581 IN6M_LOCK_ASSERT_HELD(inm);
2582 MLI_LOCK_ASSERT_HELD(mli);
2583
2584 if (error == 0) {
2585 inm->in6m_timer = odelay;
2586 mtp->cst = 1;
2587 }
2588 }
2589 break;
2590
2591 case MLD_VERSION_2:
2592 /*
2593 * Defer update of T0 to T1, until the first copy
2594 * of the state change has been transmitted.
2595 */
2596 syncstates = 0;
2597
2598 /*
2599 * Immediately enqueue a State-Change Report for
2600 * this interface, freeing any previous reports.
2601 * Don't kick the timers if there is nothing to do,
2602 * or if an error occurred.
2603 */
2604 ifq = &inm->in6m_scq;
2605 IF_DRAIN(ifq);
2606 retval = mld_v2_enqueue_group_record(ifq, inm, 1,
2607 0, 0, (mli->mli_flags & MLIF_USEALLOW));
2608 mtp->cst = (ifq->ifq_len > 0);
2609 MLD_PRINTF(("%s: enqueue record = %d\n",
2610 __func__, retval));
2611 if (retval <= 0) {
2612 error = retval * -1;
2613 break;
2614 }
2615
2616 /*
2617 * Schedule transmission of pending state-change
2618 * report up to RV times for this link. The timer
2619 * will fire at the next mld_timeout (1 second)),
2620 * giving us an opportunity to merge the reports.
2621 *
2622 * If a delay was provided to this function, only
2623 * use this delay if sooner than the existing one.
2624 */
2625 VERIFY(mli->mli_rv > 1);
2626 inm->in6m_scrv = (uint16_t)mli->mli_rv;
2627 if (delay) {
2628 if (inm->in6m_sctimer > 1) {
2629 inm->in6m_sctimer =
2630 MIN(inm->in6m_sctimer, (uint16_t)delay);
2631 } else {
2632 inm->in6m_sctimer = (uint16_t)delay;
2633 }
2634 } else {
2635 inm->in6m_sctimer = 1;
2636 }
2637 mtp->sct = 1;
2638 error = 0;
2639 break;
2640 }
2641 }
2642 MLI_UNLOCK(mli);
2643
2644 /*
2645 * Only update the T0 state if state change is atomic,
2646 * i.e. we don't need to wait for a timer to fire before we
2647 * can consider the state change to have been communicated.
2648 */
2649 if (syncstates) {
2650 in6m_commit(inm);
2651 MLD_PRINTF(("%s: T1 -> T0 for %s/%s\n", __func__,
2652 ip6_sprintf(&inm->in6m_addr),
2653 if_name(inm->in6m_ifp)));
2654 }
2655
2656 return error;
2657 }
2658
2659 /*
2660 * Issue an intermediate state change during the life-cycle.
2661 */
2662 static int
mld_handle_state_change(struct in6_multi * inm,struct mld_ifinfo * mli,struct mld_tparams * mtp)2663 mld_handle_state_change(struct in6_multi *inm, struct mld_ifinfo *mli,
2664 struct mld_tparams *mtp)
2665 {
2666 struct ifnet *ifp;
2667
2668 IN6M_LOCK_ASSERT_HELD(inm);
2669 MLI_LOCK_ASSERT_NOTHELD(mli);
2670 VERIFY(mtp != NULL);
2671
2672 MLD_PRINTF(("%s: state change for %s on ifp 0x%llx(%s)\n",
2673 __func__, ip6_sprintf(&inm->in6m_addr),
2674 (uint64_t)VM_KERNEL_ADDRPERM(inm->in6m_ifp),
2675 if_name(inm->in6m_ifp)));
2676
2677 ifp = inm->in6m_ifp;
2678
2679 MLI_LOCK(mli);
2680 VERIFY(mli->mli_ifp == ifp);
2681
2682 if ((ifp->if_flags & IFF_LOOPBACK) ||
2683 (mli->mli_flags & MLIF_SILENT) ||
2684 !mld_is_addr_reported(&inm->in6m_addr) ||
2685 (mli->mli_version != MLD_VERSION_2)) {
2686 MLI_UNLOCK(mli);
2687 if (!mld_is_addr_reported(&inm->in6m_addr)) {
2688 MLD_PRINTF(("%s: not kicking state machine for silent "
2689 "group\n", __func__));
2690 }
2691 MLD_PRINTF(("%s: nothing to do\n", __func__));
2692 in6m_commit(inm);
2693 MLD_PRINTF(("%s: T1 -> T0 for %s/%s\n", __func__,
2694 ip6_sprintf(&inm->in6m_addr),
2695 if_name(inm->in6m_ifp)));
2696 goto done;
2697 }
2698
2699 IF_DRAIN(&inm->in6m_scq);
2700
2701 int retval = mld_v2_enqueue_group_record(&inm->in6m_scq, inm, 1, 0, 0,
2702 (mli->mli_flags & MLIF_USEALLOW));
2703 mtp->cst = (inm->in6m_scq.ifq_len > 0);
2704 MLD_PRINTF(("%s: enqueue record = %d\n", __func__, retval));
2705 if (retval <= 0) {
2706 MLI_UNLOCK(mli);
2707 return -retval;
2708 }
2709
2710 /*
2711 * If record(s) were enqueued, start the state-change
2712 * report timer for this group.
2713 */
2714 inm->in6m_scrv = (uint16_t)mli->mli_rv;
2715 inm->in6m_sctimer = 1;
2716 mtp->sct = 1;
2717 MLI_UNLOCK(mli);
2718
2719 done:
2720 return 0;
2721 }
2722
2723 /*
2724 * Perform the final leave for a multicast address.
2725 *
2726 * When leaving a group:
2727 * MLDv1 sends a DONE message, if and only if we are the reporter.
2728 * MLDv2 enqueues a state-change report containing a transition
2729 * to INCLUDE {} for immediate transmission.
2730 */
2731 static void
mld_final_leave(struct in6_multi * inm,struct mld_ifinfo * mli,struct mld_tparams * mtp)2732 mld_final_leave(struct in6_multi *inm, struct mld_ifinfo *mli,
2733 struct mld_tparams *mtp)
2734 {
2735 int syncstates = 1;
2736
2737 IN6M_LOCK_ASSERT_HELD(inm);
2738 MLI_LOCK_ASSERT_NOTHELD(mli);
2739 VERIFY(mtp != NULL);
2740
2741 MLD_PRINTF(("%s: final leave %s on ifp 0x%llx(%s)\n",
2742 __func__, ip6_sprintf(&inm->in6m_addr),
2743 (uint64_t)VM_KERNEL_ADDRPERM(inm->in6m_ifp),
2744 if_name(inm->in6m_ifp)));
2745
2746 switch (inm->in6m_state) {
2747 case MLD_NOT_MEMBER:
2748 case MLD_SILENT_MEMBER:
2749 case MLD_LEAVING_MEMBER:
2750 /* Already leaving or left; do nothing. */
2751 MLD_PRINTF(("%s: not kicking state machine for silent group\n",
2752 __func__));
2753 break;
2754 case MLD_REPORTING_MEMBER:
2755 case MLD_IDLE_MEMBER:
2756 case MLD_G_QUERY_PENDING_MEMBER:
2757 case MLD_SG_QUERY_PENDING_MEMBER:
2758 MLI_LOCK(mli);
2759 if (mli->mli_version == MLD_VERSION_1) {
2760 if (inm->in6m_state == MLD_G_QUERY_PENDING_MEMBER ||
2761 inm->in6m_state == MLD_SG_QUERY_PENDING_MEMBER) {
2762 panic("%s: MLDv2 state reached, not MLDv2 "
2763 "mode\n", __func__);
2764 /* NOTREACHED */
2765 }
2766 /* scheduler timer if enqueue is successful */
2767 mtp->cst = (mld_v1_transmit_report(inm,
2768 MLD_LISTENER_DONE) == 0);
2769
2770 IN6M_LOCK_ASSERT_HELD(inm);
2771 MLI_LOCK_ASSERT_HELD(mli);
2772
2773 inm->in6m_state = MLD_NOT_MEMBER;
2774 } else if (mli->mli_version == MLD_VERSION_2) {
2775 /*
2776 * Stop group timer and all pending reports.
2777 * Immediately enqueue a state-change report
2778 * TO_IN {} to be sent on the next timeout,
2779 * giving us an opportunity to merge reports.
2780 */
2781 IF_DRAIN(&inm->in6m_scq);
2782 inm->in6m_timer = 0;
2783 inm->in6m_scrv = (uint16_t)mli->mli_rv;
2784 MLD_PRINTF(("%s: Leaving %s/%s with %d "
2785 "pending retransmissions.\n", __func__,
2786 ip6_sprintf(&inm->in6m_addr),
2787 if_name(inm->in6m_ifp),
2788 inm->in6m_scrv));
2789 if (inm->in6m_scrv == 0) {
2790 inm->in6m_state = MLD_NOT_MEMBER;
2791 inm->in6m_sctimer = 0;
2792 } else {
2793 int retval;
2794 /*
2795 * Stick around in the in6_multihead list;
2796 * the final detach will be issued by
2797 * mld_v2_process_group_timers() when
2798 * the retransmit timer expires.
2799 */
2800 IN6M_ADDREF_LOCKED(inm);
2801 VERIFY(inm->in6m_debug & IFD_ATTACHED);
2802 inm->in6m_reqcnt++;
2803 VERIFY(inm->in6m_reqcnt >= 1);
2804 inm->in6m_nrelecnt++;
2805 VERIFY(inm->in6m_nrelecnt != 0);
2806
2807 retval = mld_v2_enqueue_group_record(
2808 &inm->in6m_scq, inm, 1, 0, 0,
2809 (mli->mli_flags & MLIF_USEALLOW));
2810 mtp->cst = (inm->in6m_scq.ifq_len > 0);
2811 KASSERT(retval != 0,
2812 ("%s: enqueue record = %d\n", __func__,
2813 retval));
2814
2815 inm->in6m_state = MLD_LEAVING_MEMBER;
2816 inm->in6m_sctimer = 1;
2817 mtp->sct = 1;
2818 syncstates = 0;
2819 }
2820 }
2821 MLI_UNLOCK(mli);
2822 break;
2823 case MLD_LAZY_MEMBER:
2824 case MLD_SLEEPING_MEMBER:
2825 case MLD_AWAKENING_MEMBER:
2826 /* Our reports are suppressed; do nothing. */
2827 break;
2828 }
2829
2830 if (syncstates) {
2831 in6m_commit(inm);
2832 MLD_PRINTF(("%s: T1 -> T0 for %s/%s\n", __func__,
2833 ip6_sprintf(&inm->in6m_addr),
2834 if_name(inm->in6m_ifp)));
2835 inm->in6m_st[1].iss_fmode = MCAST_UNDEFINED;
2836 MLD_PRINTF(("%s: T1 now MCAST_UNDEFINED for 0x%llx/%s\n",
2837 __func__, (uint64_t)VM_KERNEL_ADDRPERM(&inm->in6m_addr),
2838 if_name(inm->in6m_ifp)));
2839 }
2840 }
2841
2842 /*
2843 * Enqueue an MLDv2 group record to the given output queue.
2844 *
2845 * If is_state_change is zero, a current-state record is appended.
2846 * If is_state_change is non-zero, a state-change report is appended.
2847 *
2848 * If is_group_query is non-zero, an mbuf packet chain is allocated.
2849 * If is_group_query is zero, and if there is a packet with free space
2850 * at the tail of the queue, it will be appended to providing there
2851 * is enough free space.
2852 * Otherwise a new mbuf packet chain is allocated.
2853 *
2854 * If is_source_query is non-zero, each source is checked to see if
2855 * it was recorded for a Group-Source query, and will be omitted if
2856 * it is not both in-mode and recorded.
2857 *
2858 * If use_block_allow is non-zero, state change reports for initial join
2859 * and final leave, on an inclusive mode group with a source list, will be
2860 * rewritten to use the ALLOW_NEW and BLOCK_OLD record types, respectively.
2861 *
2862 * The function will attempt to allocate leading space in the packet
2863 * for the IPv6+ICMP headers to be prepended without fragmenting the chain.
2864 *
2865 * If successful the size of all data appended to the queue is returned,
2866 * otherwise an error code less than zero is returned, or zero if
2867 * no record(s) were appended.
2868 */
2869 static int
mld_v2_enqueue_group_record(struct ifqueue * ifq,struct in6_multi * inm,const int is_state_change,const int is_group_query,const int is_source_query,const int use_block_allow)2870 mld_v2_enqueue_group_record(struct ifqueue *ifq, struct in6_multi *inm,
2871 const int is_state_change, const int is_group_query,
2872 const int is_source_query, const int use_block_allow)
2873 {
2874 struct mldv2_record mr;
2875 struct mldv2_record *pmr;
2876 struct ifnet *ifp;
2877 struct ip6_msource *ims, *nims;
2878 mbuf_ref_t m0, m, md;
2879 int error, is_filter_list_change;
2880 int minrec0len, m0srcs, msrcs, nbytes, off;
2881 int record_has_sources;
2882 int now;
2883 uint8_t type;
2884 uint8_t mode;
2885
2886 IN6M_LOCK_ASSERT_HELD(inm);
2887 MLI_LOCK_ASSERT_HELD(inm->in6m_mli);
2888
2889 error = 0;
2890 ifp = inm->in6m_ifp;
2891 is_filter_list_change = 0;
2892 m = NULL;
2893 m0 = NULL;
2894 m0srcs = 0;
2895 msrcs = 0;
2896 nbytes = 0;
2897 nims = NULL;
2898 record_has_sources = 1;
2899 pmr = NULL;
2900 type = MLD_DO_NOTHING;
2901 mode = (uint8_t)inm->in6m_st[1].iss_fmode;
2902
2903 /*
2904 * If we did not transition out of ASM mode during t0->t1,
2905 * and there are no source nodes to process, we can skip
2906 * the generation of source records.
2907 */
2908 if (inm->in6m_st[0].iss_asm > 0 && inm->in6m_st[1].iss_asm > 0 &&
2909 inm->in6m_nsrc == 0) {
2910 record_has_sources = 0;
2911 }
2912
2913 if (is_state_change) {
2914 /*
2915 * Queue a state change record.
2916 * If the mode did not change, and there are non-ASM
2917 * listeners or source filters present,
2918 * we potentially need to issue two records for the group.
2919 * If there are ASM listeners, and there was no filter
2920 * mode transition of any kind, do nothing.
2921 *
2922 * If we are transitioning to MCAST_UNDEFINED, we need
2923 * not send any sources. A transition to/from this state is
2924 * considered inclusive with some special treatment.
2925 *
2926 * If we are rewriting initial joins/leaves to use
2927 * ALLOW/BLOCK, and the group's membership is inclusive,
2928 * we need to send sources in all cases.
2929 */
2930 if (mode != inm->in6m_st[0].iss_fmode) {
2931 if (mode == MCAST_EXCLUDE) {
2932 MLD_PRINTF(("%s: change to EXCLUDE\n",
2933 __func__));
2934 type = MLD_CHANGE_TO_EXCLUDE_MODE;
2935 } else {
2936 MLD_PRINTF(("%s: change to INCLUDE\n",
2937 __func__));
2938 if (use_block_allow) {
2939 /*
2940 * XXX
2941 * Here we're interested in state
2942 * edges either direction between
2943 * MCAST_UNDEFINED and MCAST_INCLUDE.
2944 * Perhaps we should just check
2945 * the group state, rather than
2946 * the filter mode.
2947 */
2948 if (mode == MCAST_UNDEFINED) {
2949 type = MLD_BLOCK_OLD_SOURCES;
2950 } else {
2951 type = MLD_ALLOW_NEW_SOURCES;
2952 }
2953 } else {
2954 type = MLD_CHANGE_TO_INCLUDE_MODE;
2955 if (mode == MCAST_UNDEFINED) {
2956 record_has_sources = 0;
2957 }
2958 }
2959 }
2960 } else {
2961 if (record_has_sources) {
2962 is_filter_list_change = 1;
2963 } else {
2964 type = MLD_DO_NOTHING;
2965 }
2966 }
2967 } else {
2968 /*
2969 * Queue a current state record.
2970 */
2971 if (mode == MCAST_EXCLUDE) {
2972 type = MLD_MODE_IS_EXCLUDE;
2973 } else if (mode == MCAST_INCLUDE) {
2974 type = MLD_MODE_IS_INCLUDE;
2975 VERIFY(inm->in6m_st[1].iss_asm == 0);
2976 }
2977 }
2978
2979 /*
2980 * Generate the filter list changes using a separate function.
2981 */
2982 if (is_filter_list_change) {
2983 return mld_v2_enqueue_filter_change(ifq, inm);
2984 }
2985
2986 if (type == MLD_DO_NOTHING) {
2987 MLD_PRINTF(("%s: nothing to do for %s/%s\n",
2988 __func__, ip6_sprintf(&inm->in6m_addr),
2989 if_name(inm->in6m_ifp)));
2990 return 0;
2991 }
2992
2993 /*
2994 * If any sources are present, we must be able to fit at least
2995 * one in the trailing space of the tail packet's mbuf,
2996 * ideally more.
2997 */
2998 minrec0len = sizeof(struct mldv2_record);
2999 if (record_has_sources) {
3000 minrec0len += sizeof(struct in6_addr);
3001 }
3002 MLD_PRINTF(("%s: queueing %s for %s/%s\n", __func__,
3003 mld_rec_type_to_str(type),
3004 ip6_sprintf(&inm->in6m_addr),
3005 if_name(inm->in6m_ifp)));
3006
3007 /*
3008 * Check if we have a packet in the tail of the queue for this
3009 * group into which the first group record for this group will fit.
3010 * Otherwise allocate a new packet.
3011 * Always allocate leading space for IP6+RA+ICMPV6+REPORT.
3012 * Note: Group records for G/GSR query responses MUST be sent
3013 * in their own packet.
3014 */
3015 m0 = ifq->ifq_tail;
3016 if (!is_group_query &&
3017 m0 != NULL &&
3018 (m0->m_pkthdr.vt_nrecs + 1 <= MLD_V2_REPORT_MAXRECS) &&
3019 (m0->m_pkthdr.len + minrec0len) <
3020 (ifp->if_mtu - MLD_MTUSPACE)) {
3021 m0srcs = (ifp->if_mtu - m0->m_pkthdr.len -
3022 sizeof(struct mldv2_record)) /
3023 sizeof(struct in6_addr);
3024 m = m0;
3025 MLD_PRINTF(("%s: use existing packet\n", __func__));
3026 } else {
3027 if (IF_QFULL(ifq)) {
3028 os_log_error(OS_LOG_DEFAULT,
3029 "%s: outbound queue full\n", __func__);
3030 return -ENOMEM;
3031 }
3032 m = NULL;
3033 m0srcs = (ifp->if_mtu - MLD_MTUSPACE -
3034 sizeof(struct mldv2_record)) / sizeof(struct in6_addr);
3035 if (!is_state_change && !is_group_query) {
3036 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
3037 }
3038 if (m == NULL) {
3039 m = m_gethdr(M_DONTWAIT, MT_DATA);
3040 }
3041 if (m == NULL) {
3042 return -ENOMEM;
3043 }
3044
3045 mld_save_context(m, ifp);
3046
3047 MLD_PRINTF(("%s: allocated first packet\n", __func__));
3048 }
3049
3050 /*
3051 * Append group record.
3052 * If we have sources, we don't know how many yet.
3053 */
3054 mr.mr_type = type;
3055 mr.mr_datalen = 0;
3056 mr.mr_numsrc = 0;
3057 mr.mr_addr = inm->in6m_addr;
3058 in6_clearscope(&mr.mr_addr);
3059 if (!m_append(m, sizeof(struct mldv2_record), (void *)&mr)) {
3060 if (m != m0) {
3061 m_freem(m);
3062 }
3063 os_log_error(OS_LOG_DEFAULT, "%s: m_append() failed.\n", __func__);
3064 return -ENOMEM;
3065 }
3066 nbytes += sizeof(struct mldv2_record);
3067
3068 /*
3069 * Append as many sources as will fit in the first packet.
3070 * If we are appending to a new packet, the chain allocation
3071 * may potentially use clusters; use m_getptr() in this case.
3072 * If we are appending to an existing packet, we need to obtain
3073 * a pointer to the group record after m_append(), in case a new
3074 * mbuf was allocated.
3075 *
3076 * Only append sources which are in-mode at t1. If we are
3077 * transitioning to MCAST_UNDEFINED state on the group, and
3078 * use_block_allow is zero, do not include source entries.
3079 * Otherwise, we need to include this source in the report.
3080 *
3081 * Only report recorded sources in our filter set when responding
3082 * to a group-source query.
3083 */
3084 if (record_has_sources) {
3085 if (m == m0) {
3086 md = m_last(m);
3087 pmr = (struct mldv2_record *)(mtod(md, uint8_t *) +
3088 md->m_len - nbytes);
3089 } else {
3090 md = m_getptr(m, 0, &off);
3091 pmr = (struct mldv2_record *)(mtod(md, uint8_t *) +
3092 off);
3093 }
3094 msrcs = 0;
3095 RB_FOREACH_SAFE(ims, ip6_msource_tree, &inm->in6m_srcs,
3096 nims) {
3097 MLD_PRINTF(("%s: visit node %s\n", __func__,
3098 ip6_sprintf(&ims->im6s_addr)));
3099 now = im6s_get_mode(inm, ims, 1);
3100 MLD_PRINTF(("%s: node is %d\n", __func__, now));
3101 if ((now != mode) ||
3102 (now == mode &&
3103 (!use_block_allow && mode == MCAST_UNDEFINED))) {
3104 MLD_PRINTF(("%s: skip node\n", __func__));
3105 continue;
3106 }
3107 if (is_source_query && ims->im6s_stp == 0) {
3108 MLD_PRINTF(("%s: skip unrecorded node\n",
3109 __func__));
3110 continue;
3111 }
3112 MLD_PRINTF(("%s: append node\n", __func__));
3113 if (!m_append(m, sizeof(struct in6_addr),
3114 (void *)&ims->im6s_addr)) {
3115 if (m != m0) {
3116 m_freem(m);
3117 }
3118 os_log_error(OS_LOG_DEFAULT,
3119 "%s: m_append() failed\n",
3120 __func__);
3121 return -ENOMEM;
3122 }
3123 nbytes += sizeof(struct in6_addr);
3124 ++msrcs;
3125 if (msrcs == m0srcs) {
3126 break;
3127 }
3128 }
3129 MLD_PRINTF(("%s: msrcs is %d this packet\n", __func__,
3130 msrcs));
3131 pmr->mr_numsrc = htons((uint16_t)msrcs);
3132 nbytes += (msrcs * sizeof(struct in6_addr));
3133 }
3134
3135 if (is_source_query && msrcs == 0) {
3136 MLD_PRINTF(("%s: no recorded sources to report\n", __func__));
3137 if (m != m0) {
3138 m_freem(m);
3139 }
3140 return 0;
3141 }
3142
3143 /*
3144 * We are good to go with first packet.
3145 */
3146 if (m != m0) {
3147 MLD_PRINTF(("%s: enqueueing first packet\n", __func__));
3148 m->m_pkthdr.vt_nrecs = 1;
3149 IF_ENQUEUE(ifq, m);
3150 } else {
3151 m->m_pkthdr.vt_nrecs++;
3152 }
3153 /*
3154 * No further work needed if no source list in packet(s).
3155 */
3156 if (!record_has_sources) {
3157 return nbytes;
3158 }
3159
3160 /*
3161 * Whilst sources remain to be announced, we need to allocate
3162 * a new packet and fill out as many sources as will fit.
3163 * Always try for a cluster first.
3164 */
3165 while (nims != NULL) {
3166 if (IF_QFULL(ifq)) {
3167 os_log_error(OS_LOG_DEFAULT, "%s: outbound queue full\n", __func__);
3168 return -ENOMEM;
3169 }
3170 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
3171 if (m == NULL) {
3172 m = m_gethdr(M_DONTWAIT, MT_DATA);
3173 }
3174 if (m == NULL) {
3175 return -ENOMEM;
3176 }
3177 mld_save_context(m, ifp);
3178 md = m_getptr(m, 0, &off);
3179 pmr = (struct mldv2_record *)(mtod(md, uint8_t *) + off);
3180 MLD_PRINTF(("%s: allocated next packet\n", __func__));
3181
3182 if (!m_append(m, sizeof(struct mldv2_record), (void *)&mr)) {
3183 if (m != m0) {
3184 m_freem(m);
3185 }
3186 os_log_error(OS_LOG_DEFAULT, "%s: m_append() failed.\n", __func__);
3187 return -ENOMEM;
3188 }
3189 m->m_pkthdr.vt_nrecs = 1;
3190 nbytes += sizeof(struct mldv2_record);
3191
3192 m0srcs = (ifp->if_mtu - MLD_MTUSPACE -
3193 sizeof(struct mldv2_record)) / sizeof(struct in6_addr);
3194
3195 msrcs = 0;
3196 RB_FOREACH_FROM(ims, ip6_msource_tree, nims) {
3197 MLD_PRINTF(("%s: visit node %s\n",
3198 __func__, ip6_sprintf(&ims->im6s_addr)));
3199 now = im6s_get_mode(inm, ims, 1);
3200 if ((now != mode) ||
3201 (now == mode &&
3202 (!use_block_allow && mode == MCAST_UNDEFINED))) {
3203 MLD_PRINTF(("%s: skip node\n", __func__));
3204 continue;
3205 }
3206 if (is_source_query && ims->im6s_stp == 0) {
3207 MLD_PRINTF(("%s: skip unrecorded node\n",
3208 __func__));
3209 continue;
3210 }
3211 MLD_PRINTF(("%s: append node\n", __func__));
3212 if (!m_append(m, sizeof(struct in6_addr),
3213 (void *)&ims->im6s_addr)) {
3214 if (m != m0) {
3215 m_freem(m);
3216 }
3217 os_log_error(OS_LOG_DEFAULT, "%s: m_append() failed\n",
3218 __func__);
3219 return -ENOMEM;
3220 }
3221 ++msrcs;
3222 if (msrcs == m0srcs) {
3223 break;
3224 }
3225 }
3226 pmr->mr_numsrc = htons((uint16_t)msrcs);
3227 nbytes += (msrcs * sizeof(struct in6_addr));
3228
3229 MLD_PRINTF(("%s: enqueueing next packet\n", __func__));
3230 IF_ENQUEUE(ifq, m);
3231 }
3232
3233 return nbytes;
3234 }
3235
3236 /*
3237 * Type used to mark record pass completion.
3238 * We exploit the fact we can cast to this easily from the
3239 * current filter modes on each ip_msource node.
3240 */
3241 typedef enum {
3242 REC_NONE = 0x00, /* MCAST_UNDEFINED */
3243 REC_ALLOW = 0x01, /* MCAST_INCLUDE */
3244 REC_BLOCK = 0x02, /* MCAST_EXCLUDE */
3245 REC_FULL = REC_ALLOW | REC_BLOCK
3246 } rectype_t;
3247
3248 /*
3249 * Enqueue an MLDv2 filter list change to the given output queue.
3250 *
3251 * Source list filter state is held in an RB-tree. When the filter list
3252 * for a group is changed without changing its mode, we need to compute
3253 * the deltas between T0 and T1 for each source in the filter set,
3254 * and enqueue the appropriate ALLOW_NEW/BLOCK_OLD records.
3255 *
3256 * As we may potentially queue two record types, and the entire R-B tree
3257 * needs to be walked at once, we break this out into its own function
3258 * so we can generate a tightly packed queue of packets.
3259 *
3260 * XXX This could be written to only use one tree walk, although that makes
3261 * serializing into the mbuf chains a bit harder. For now we do two walks
3262 * which makes things easier on us, and it may or may not be harder on
3263 * the L2 cache.
3264 *
3265 * If successful the size of all data appended to the queue is returned,
3266 * otherwise an error code less than zero is returned, or zero if
3267 * no record(s) were appended.
3268 */
3269 static int
mld_v2_enqueue_filter_change(struct ifqueue * ifq,struct in6_multi * inm)3270 mld_v2_enqueue_filter_change(struct ifqueue *ifq, struct in6_multi *inm)
3271 {
3272 static const int MINRECLEN =
3273 sizeof(struct mldv2_record) + sizeof(struct in6_addr);
3274 struct ifnet *ifp;
3275 struct mldv2_record mr;
3276 struct mldv2_record *pmr;
3277 struct ip6_msource *ims, *nims;
3278 mbuf_ref_t m, m0, md;
3279 int m0srcs, nbytes, npbytes, off, rsrcs, schanged;
3280 int nallow, nblock;
3281 uint8_t mode, now, then;
3282 rectype_t crt, drt, nrt;
3283
3284 IN6M_LOCK_ASSERT_HELD(inm);
3285
3286 if (inm->in6m_nsrc == 0 ||
3287 (inm->in6m_st[0].iss_asm > 0 && inm->in6m_st[1].iss_asm > 0)) {
3288 return 0;
3289 }
3290
3291 ifp = inm->in6m_ifp; /* interface */
3292 mode = (uint8_t)inm->in6m_st[1].iss_fmode; /* filter mode at t1 */
3293 crt = REC_NONE; /* current group record type */
3294 drt = REC_NONE; /* mask of completed group record types */
3295 nrt = REC_NONE; /* record type for current node */
3296 m0srcs = 0; /* # source which will fit in current mbuf chain */
3297 npbytes = 0; /* # of bytes appended this packet */
3298 nbytes = 0; /* # of bytes appended to group's state-change queue */
3299 rsrcs = 0; /* # sources encoded in current record */
3300 schanged = 0; /* # nodes encoded in overall filter change */
3301 nallow = 0; /* # of source entries in ALLOW_NEW */
3302 nblock = 0; /* # of source entries in BLOCK_OLD */
3303 nims = NULL; /* next tree node pointer */
3304
3305 /*
3306 * For each possible filter record mode.
3307 * The first kind of source we encounter tells us which
3308 * is the first kind of record we start appending.
3309 * If a node transitioned to UNDEFINED at t1, its mode is treated
3310 * as the inverse of the group's filter mode.
3311 */
3312 while (drt != REC_FULL) {
3313 do {
3314 m0 = ifq->ifq_tail;
3315 if (m0 != NULL &&
3316 (m0->m_pkthdr.vt_nrecs + 1 <=
3317 MLD_V2_REPORT_MAXRECS) &&
3318 (m0->m_pkthdr.len + MINRECLEN) <
3319 (ifp->if_mtu - MLD_MTUSPACE)) {
3320 m = m0;
3321 m0srcs = (ifp->if_mtu - m0->m_pkthdr.len -
3322 sizeof(struct mldv2_record)) /
3323 sizeof(struct in6_addr);
3324 MLD_PRINTF(("%s: use previous packet\n",
3325 __func__));
3326 } else {
3327 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
3328 if (m == NULL) {
3329 m = m_gethdr(M_DONTWAIT, MT_DATA);
3330 }
3331 if (m == NULL) {
3332 os_log_error(OS_LOG_DEFAULT, "%s: m_get*() failed\n",
3333 __func__);
3334 return -ENOMEM;
3335 }
3336 m->m_pkthdr.vt_nrecs = 0;
3337 mld_save_context(m, ifp);
3338 m0srcs = (ifp->if_mtu - MLD_MTUSPACE -
3339 sizeof(struct mldv2_record)) /
3340 sizeof(struct in6_addr);
3341 npbytes = 0;
3342 MLD_PRINTF(("%s: allocated new packet\n",
3343 __func__));
3344 }
3345 /*
3346 * Append the MLD group record header to the
3347 * current packet's data area.
3348 * Recalculate pointer to free space for next
3349 * group record, in case m_append() allocated
3350 * a new mbuf or cluster.
3351 */
3352 memset(&mr, 0, sizeof(mr));
3353 mr.mr_addr = inm->in6m_addr;
3354 in6_clearscope(&mr.mr_addr);
3355 if (!m_append(m, sizeof(mr), (void *)&mr)) {
3356 if (m != m0) {
3357 m_freem(m);
3358 }
3359 os_log_error(OS_LOG_DEFAULT, "%s: m_append() failed\n",
3360 __func__);
3361 return -ENOMEM;
3362 }
3363 npbytes += sizeof(struct mldv2_record);
3364 if (m != m0) {
3365 /* new packet; offset in chain */
3366 md = m_getptr(m, npbytes -
3367 sizeof(struct mldv2_record), &off);
3368 pmr = (struct mldv2_record *)(mtod(md,
3369 uint8_t *) + off);
3370 } else {
3371 /* current packet; offset from last append */
3372 md = m_last(m);
3373 pmr = (struct mldv2_record *)(mtod(md,
3374 uint8_t *) + md->m_len -
3375 sizeof(struct mldv2_record));
3376 }
3377 /*
3378 * Begin walking the tree for this record type
3379 * pass, or continue from where we left off
3380 * previously if we had to allocate a new packet.
3381 * Only report deltas in-mode at t1.
3382 * We need not report included sources as allowed
3383 * if we are in inclusive mode on the group,
3384 * however the converse is not true.
3385 */
3386 rsrcs = 0;
3387 if (nims == NULL) {
3388 nims = RB_MIN(ip6_msource_tree,
3389 &inm->in6m_srcs);
3390 }
3391 RB_FOREACH_FROM(ims, ip6_msource_tree, nims) {
3392 MLD_PRINTF(("%s: visit node %s\n", __func__,
3393 ip6_sprintf(&ims->im6s_addr)));
3394 now = im6s_get_mode(inm, ims, 1);
3395 then = im6s_get_mode(inm, ims, 0);
3396 MLD_PRINTF(("%s: mode: t0 %d, t1 %d\n",
3397 __func__, then, now));
3398 if (now == then) {
3399 MLD_PRINTF(("%s: skip unchanged\n",
3400 __func__));
3401 continue;
3402 }
3403 if (mode == MCAST_EXCLUDE &&
3404 now == MCAST_INCLUDE) {
3405 MLD_PRINTF(("%s: skip IN src on EX "
3406 "group\n", __func__));
3407 continue;
3408 }
3409 nrt = (rectype_t)now;
3410 if (nrt == REC_NONE) {
3411 nrt = (rectype_t)(~mode & REC_FULL);
3412 }
3413 if (schanged++ == 0) {
3414 crt = nrt;
3415 } else if (crt != nrt) {
3416 continue;
3417 }
3418 if (!m_append(m, sizeof(struct in6_addr),
3419 (void *)&ims->im6s_addr)) {
3420 if (m != m0) {
3421 m_freem(m);
3422 }
3423 os_log_error(OS_LOG_DEFAULT, "%s: m_append() failed\n",
3424 __func__);
3425 return -ENOMEM;
3426 }
3427 nallow += !!(crt == REC_ALLOW);
3428 nblock += !!(crt == REC_BLOCK);
3429 if (++rsrcs == m0srcs) {
3430 break;
3431 }
3432 }
3433 /*
3434 * If we did not append any tree nodes on this
3435 * pass, back out of allocations.
3436 */
3437 if (rsrcs == 0) {
3438 npbytes -= sizeof(struct mldv2_record);
3439 if (m != m0) {
3440 MLD_PRINTF(("%s: m_free(m)\n",
3441 __func__));
3442 m_freem(m);
3443 } else {
3444 MLD_PRINTF(("%s: m_adj(m, -mr)\n",
3445 __func__));
3446 m_adj(m, -((int)sizeof(
3447 struct mldv2_record)));
3448 }
3449 continue;
3450 }
3451 npbytes += (rsrcs * sizeof(struct in6_addr));
3452 if (crt == REC_ALLOW) {
3453 pmr->mr_type = MLD_ALLOW_NEW_SOURCES;
3454 } else if (crt == REC_BLOCK) {
3455 pmr->mr_type = MLD_BLOCK_OLD_SOURCES;
3456 }
3457 pmr->mr_numsrc = htons((uint16_t)rsrcs);
3458 /*
3459 * Count the new group record, and enqueue this
3460 * packet if it wasn't already queued.
3461 */
3462 m->m_pkthdr.vt_nrecs++;
3463 if (m != m0) {
3464 IF_ENQUEUE(ifq, m);
3465 }
3466 nbytes += npbytes;
3467 } while (nims != NULL);
3468 drt |= crt;
3469 crt = (~crt & REC_FULL);
3470 }
3471
3472 MLD_PRINTF(("%s: queued %d ALLOW_NEW, %d BLOCK_OLD\n", __func__,
3473 nallow, nblock));
3474
3475 return nbytes;
3476 }
3477
3478 static int
mld_v2_merge_state_changes(struct in6_multi * inm,struct ifqueue * ifscq)3479 mld_v2_merge_state_changes(struct in6_multi *inm, struct ifqueue *ifscq)
3480 {
3481 struct ifqueue *gq;
3482 mbuf_ref_t m; /* pending state-change */
3483 mbuf_ref_t m0; /* copy of pending state-change */
3484 mbuf_ref_t mt; /* last state-change in packet */
3485 mbuf_ref_t n;
3486 int docopy, domerge;
3487 u_int recslen;
3488
3489 IN6M_LOCK_ASSERT_HELD(inm);
3490
3491 docopy = 0;
3492 domerge = 0;
3493 recslen = 0;
3494
3495 /*
3496 * If there are further pending retransmissions, make a writable
3497 * copy of each queued state-change message before merging.
3498 */
3499 if (inm->in6m_scrv > 0) {
3500 docopy = 1;
3501 }
3502
3503 gq = &inm->in6m_scq;
3504 #ifdef MLD_DEBUG
3505 if (gq->ifq_head == NULL) {
3506 MLD_PRINTF(("%s: WARNING: queue for inm 0x%llx is empty\n",
3507 __func__, (uint64_t)VM_KERNEL_ADDRPERM(inm)));
3508 }
3509 #endif
3510
3511 /*
3512 * Use IF_REMQUEUE() instead of IF_DEQUEUE() below, since the
3513 * packet might not always be at the head of the ifqueue.
3514 */
3515 m = gq->ifq_head;
3516 while (m != NULL) {
3517 /*
3518 * Only merge the report into the current packet if
3519 * there is sufficient space to do so; an MLDv2 report
3520 * packet may only contain 65,535 group records.
3521 * Always use a simple mbuf chain concatentation to do this,
3522 * as large state changes for single groups may have
3523 * allocated clusters.
3524 */
3525 domerge = 0;
3526 mt = ifscq->ifq_tail;
3527 if (mt != NULL) {
3528 recslen = m_length(m);
3529
3530 if ((mt->m_pkthdr.vt_nrecs +
3531 m->m_pkthdr.vt_nrecs <=
3532 MLD_V2_REPORT_MAXRECS) &&
3533 (mt->m_pkthdr.len + recslen <=
3534 (inm->in6m_ifp->if_mtu - MLD_MTUSPACE))) {
3535 domerge = 1;
3536 }
3537 }
3538
3539 if (!domerge && IF_QFULL(gq)) {
3540 os_log_info(OS_LOG_DEFAULT, "%s: outbound queue full",
3541 __func__);
3542 n = m->m_nextpkt;
3543 if (!docopy) {
3544 IF_REMQUEUE(gq, m);
3545 m_freem(m);
3546 }
3547 m = n;
3548 continue;
3549 }
3550
3551 if (!docopy) {
3552 MLD_PRINTF(("%s: dequeueing 0x%llx\n", __func__,
3553 (uint64_t)VM_KERNEL_ADDRPERM(m)));
3554 n = m->m_nextpkt;
3555 IF_REMQUEUE(gq, m);
3556 m0 = m;
3557 m = n;
3558 } else {
3559 MLD_PRINTF(("%s: copying 0x%llx\n", __func__,
3560 (uint64_t)VM_KERNEL_ADDRPERM(m)));
3561 m0 = m_dup(m, M_NOWAIT);
3562 if (m0 == NULL) {
3563 return ENOMEM;
3564 }
3565 m0->m_nextpkt = NULL;
3566 m = m->m_nextpkt;
3567 }
3568
3569 if (!domerge) {
3570 MLD_PRINTF(("%s: queueing 0x%llx to ifscq 0x%llx)\n",
3571 __func__, (uint64_t)VM_KERNEL_ADDRPERM(m0),
3572 (uint64_t)VM_KERNEL_ADDRPERM(ifscq)));
3573 IF_ENQUEUE(ifscq, m0);
3574 } else {
3575 struct mbuf *mtl; /* last mbuf of packet mt */
3576
3577 MLD_PRINTF(("%s: merging 0x%llx with ifscq tail "
3578 "0x%llx)\n", __func__,
3579 (uint64_t)VM_KERNEL_ADDRPERM(m0),
3580 (uint64_t)VM_KERNEL_ADDRPERM(mt)));
3581
3582 mtl = m_last(mt);
3583 m0->m_flags &= ~M_PKTHDR;
3584 mt->m_pkthdr.len += recslen;
3585 mt->m_pkthdr.vt_nrecs +=
3586 m0->m_pkthdr.vt_nrecs;
3587
3588 mtl->m_next = m0;
3589 }
3590 }
3591
3592 return 0;
3593 }
3594
3595 /*
3596 * Respond to a pending MLDv2 General Query.
3597 */
3598 static uint32_t
mld_v2_dispatch_general_query(struct mld_ifinfo * mli)3599 mld_v2_dispatch_general_query(struct mld_ifinfo *mli)
3600 {
3601 struct ifnet *ifp;
3602 struct in6_multi *inm;
3603 struct in6_multistep step;
3604 int retval;
3605
3606 MLI_LOCK_ASSERT_HELD(mli);
3607
3608 VERIFY(mli->mli_version == MLD_VERSION_2);
3609
3610 ifp = mli->mli_ifp;
3611 MLI_UNLOCK(mli);
3612
3613 in6_multihead_lock_shared();
3614 IN6_FIRST_MULTI(step, inm);
3615 while (inm != NULL) {
3616 IN6M_LOCK(inm);
3617 if (inm->in6m_ifp != ifp) {
3618 goto next;
3619 }
3620
3621 switch (inm->in6m_state) {
3622 case MLD_NOT_MEMBER:
3623 case MLD_SILENT_MEMBER:
3624 break;
3625 case MLD_REPORTING_MEMBER:
3626 case MLD_IDLE_MEMBER:
3627 case MLD_LAZY_MEMBER:
3628 case MLD_SLEEPING_MEMBER:
3629 case MLD_AWAKENING_MEMBER:
3630 inm->in6m_state = MLD_REPORTING_MEMBER;
3631 MLI_LOCK(mli);
3632 retval = mld_v2_enqueue_group_record(&mli->mli_gq,
3633 inm, 0, 0, 0, 0);
3634 MLI_UNLOCK(mli);
3635 MLD_PRINTF(("%s: enqueue record = %d\n",
3636 __func__, retval));
3637 break;
3638 case MLD_G_QUERY_PENDING_MEMBER:
3639 case MLD_SG_QUERY_PENDING_MEMBER:
3640 case MLD_LEAVING_MEMBER:
3641 break;
3642 }
3643 next:
3644 IN6M_UNLOCK(inm);
3645 IN6_NEXT_MULTI(step, inm);
3646 }
3647 in6_multihead_lock_done();
3648
3649 MLI_LOCK(mli);
3650 mld_dispatch_queue_locked(mli, &mli->mli_gq, MLD_MAX_RESPONSE_BURST);
3651 MLI_LOCK_ASSERT_HELD(mli);
3652
3653 /*
3654 * Slew transmission of bursts over 1 second intervals.
3655 */
3656 if (mli->mli_gq.ifq_head != NULL) {
3657 mli->mli_v2_timer = 1 + MLD_RANDOM_DELAY(
3658 MLD_RESPONSE_BURST_INTERVAL);
3659 }
3660
3661 return mli->mli_v2_timer;
3662 }
3663
3664 /*
3665 * Transmit the next pending message in the output queue.
3666 *
3667 * Must not be called with in6m_lockm or mli_lock held.
3668 */
3669 __attribute__((noinline))
3670 static void
mld_dispatch_packet(struct mbuf * m)3671 mld_dispatch_packet(struct mbuf *m)
3672 {
3673 struct ip6_moptions *im6o;
3674 struct ifnet *ifp;
3675 struct ifnet *__single oifp = NULL;
3676 mbuf_ref_t m0, md;
3677 struct ip6_hdr *ip6;
3678 struct icmp6_hdr *icmp6;
3679 int error;
3680 int off;
3681 int type;
3682
3683 MLD_PRINTF(("%s: transmit 0x%llx\n", __func__,
3684 (uint64_t)VM_KERNEL_ADDRPERM(m)));
3685
3686 /*
3687 * Check if the ifnet is still attached.
3688 */
3689 ifp = mld_restore_context(m);
3690 if (ifp == NULL || !ifnet_is_fully_attached(ifp)) {
3691 os_log_error(OS_LOG_DEFAULT, "%s: dropped 0x%llx as interface went away\n",
3692 __func__, (uint64_t)VM_KERNEL_ADDRPERM(m));
3693 m_freem(m);
3694 ip6stat.ip6s_noroute++;
3695 return;
3696 }
3697 im6o = ip6_allocmoptions(Z_WAITOK);
3698 if (im6o == NULL) {
3699 m_freem(m);
3700 return;
3701 }
3702
3703 im6o->im6o_multicast_hlim = 1;
3704 im6o->im6o_multicast_loop = 0;
3705 im6o->im6o_multicast_ifp = ifp;
3706 if (m->m_flags & M_MLDV1) {
3707 m0 = m;
3708 } else {
3709 m0 = mld_v2_encap_report(ifp, m);
3710 if (m0 == NULL) {
3711 os_log_error(OS_LOG_DEFAULT, "%s: dropped 0x%llx\n", __func__,
3712 (uint64_t)VM_KERNEL_ADDRPERM(m));
3713 /*
3714 * mld_v2_encap_report() has already freed our mbuf.
3715 */
3716 IM6O_REMREF(im6o);
3717 ip6stat.ip6s_odropped++;
3718 return;
3719 }
3720 }
3721 mld_scrub_context(m0);
3722 m->m_flags &= ~(M_PROTOFLAGS);
3723 m0->m_pkthdr.rcvif = lo_ifp;
3724
3725 ip6 = mtod(m0, struct ip6_hdr *);
3726 (void)in6_setscope(&ip6->ip6_dst, ifp, NULL);
3727 ip6_output_setdstifscope(m0, ifp->if_index, NULL);
3728 /*
3729 * Retrieve the ICMPv6 type before handoff to ip6_output(),
3730 * so we can bump the stats.
3731 */
3732 md = m_getptr(m0, sizeof(struct ip6_hdr), &off);
3733 icmp6 = (struct icmp6_hdr *)(mtod(md, uint8_t *) + off);
3734 type = icmp6->icmp6_type;
3735
3736 if (ifp->if_eflags & IFEF_TXSTART) {
3737 /*
3738 * Use control service class if the outgoing
3739 * interface supports transmit-start model.
3740 */
3741 (void) m_set_service_class(m0, MBUF_SC_CTL);
3742 }
3743
3744 error = ip6_output(m0, &mld_po, NULL, IPV6_UNSPECSRC, im6o,
3745 &oifp, NULL);
3746
3747 IM6O_REMREF(im6o);
3748
3749 if (error) {
3750 os_log_error(OS_LOG_DEFAULT, "%s: ip6_output(0x%llx) = %d\n", __func__,
3751 (uint64_t)VM_KERNEL_ADDRPERM(m0), error);
3752 if (oifp != NULL) {
3753 ifnet_release(oifp);
3754 }
3755 return;
3756 }
3757
3758 icmp6stat.icp6s_outhist[type]++;
3759 if (oifp != NULL) {
3760 icmp6_ifstat_inc(oifp, ifs6_out_msg);
3761 switch (type) {
3762 case MLD_LISTENER_REPORT:
3763 case MLDV2_LISTENER_REPORT:
3764 icmp6_ifstat_inc(oifp, ifs6_out_mldreport);
3765 break;
3766 case MLD_LISTENER_DONE:
3767 icmp6_ifstat_inc(oifp, ifs6_out_mlddone);
3768 break;
3769 }
3770 ifnet_release(oifp);
3771 }
3772 }
3773
3774 /*
3775 * Encapsulate an MLDv2 report.
3776 *
3777 * KAME IPv6 requires that hop-by-hop options be passed separately,
3778 * and that the IPv6 header be prepended in a separate mbuf.
3779 *
3780 * Returns a pointer to the new mbuf chain head, or NULL if the
3781 * allocation failed.
3782 */
3783 static struct mbuf *
mld_v2_encap_report(struct ifnet * ifp,struct mbuf * m)3784 mld_v2_encap_report(struct ifnet *ifp, struct mbuf *m)
3785 {
3786 struct mbuf *mh;
3787 struct mldv2_report *mld;
3788 struct ip6_hdr *ip6;
3789 struct in6_ifaddr *ia;
3790 int mldreclen;
3791
3792 VERIFY(m->m_flags & M_PKTHDR);
3793
3794 /*
3795 * RFC3590: OK to send as :: or tentative during DAD.
3796 */
3797 ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
3798 if (ia == NULL) {
3799 MLD_PRINTF(("%s: warning: ia is NULL\n", __func__));
3800 }
3801
3802 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
3803 if (mh == NULL) {
3804 if (ia != NULL) {
3805 ifa_remref(&ia->ia_ifa);
3806 }
3807 m_freem(m);
3808 return NULL;
3809 }
3810 MH_ALIGN(mh, sizeof(struct ip6_hdr) + sizeof(struct mldv2_report));
3811
3812 mldreclen = m_length(m);
3813 MLD_PRINTF(("%s: mldreclen is %d\n", __func__, mldreclen));
3814
3815 mh->m_len = sizeof(struct ip6_hdr) + sizeof(struct mldv2_report);
3816 mh->m_pkthdr.len = sizeof(struct ip6_hdr) +
3817 sizeof(struct mldv2_report) + mldreclen;
3818
3819 ip6 = mtod(mh, struct ip6_hdr *);
3820 ip6->ip6_flow = 0;
3821 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
3822 ip6->ip6_vfc |= IPV6_VERSION;
3823 ip6->ip6_nxt = IPPROTO_ICMPV6;
3824 if (ia != NULL) {
3825 IFA_LOCK(&ia->ia_ifa);
3826 }
3827 ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
3828 ip6_output_setsrcifscope(mh, IFSCOPE_NONE, ia);
3829
3830 if (ia != NULL) {
3831 IFA_UNLOCK(&ia->ia_ifa);
3832 ifa_remref(&ia->ia_ifa);
3833 ia = NULL;
3834 }
3835 ip6->ip6_dst = in6addr_linklocal_allv2routers;
3836 ip6_output_setdstifscope(mh, ifp->if_index, NULL);
3837 /* scope ID will be set in netisr */
3838
3839 mld = (struct mldv2_report *)(ip6 + 1);
3840 mld->mld_type = MLDV2_LISTENER_REPORT;
3841 mld->mld_code = 0;
3842 mld->mld_cksum = 0;
3843 mld->mld_v2_reserved = 0;
3844 mld->mld_v2_numrecs = htons(m->m_pkthdr.vt_nrecs);
3845 m->m_pkthdr.vt_nrecs = 0;
3846 m->m_flags &= ~M_PKTHDR;
3847
3848 mh->m_next = m;
3849 mld->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6,
3850 sizeof(struct ip6_hdr), sizeof(struct mldv2_report) + mldreclen);
3851 return mh;
3852 }
3853
3854 #ifdef MLD_DEBUG
3855 static const char *
mld_rec_type_to_str(const int type)3856 mld_rec_type_to_str(const int type)
3857 {
3858 switch (type) {
3859 case MLD_CHANGE_TO_EXCLUDE_MODE:
3860 return "TO_EX";
3861 case MLD_CHANGE_TO_INCLUDE_MODE:
3862 return "TO_IN";
3863 case MLD_MODE_IS_EXCLUDE:
3864 return "MODE_EX";
3865 case MLD_MODE_IS_INCLUDE:
3866 return "MODE_IN";
3867 case MLD_ALLOW_NEW_SOURCES:
3868 return "ALLOW_NEW";
3869 case MLD_BLOCK_OLD_SOURCES:
3870 return "BLOCK_OLD";
3871 default:
3872 break;
3873 }
3874 return "unknown";
3875 }
3876 #endif
3877
3878 void
mld_init(void)3879 mld_init(void)
3880 {
3881 os_log(OS_LOG_DEFAULT, "%s: initializing\n", __func__);
3882
3883 ip6_initpktopts(&mld_po);
3884 mld_po.ip6po_hlim = 1;
3885 mld_po.ip6po_hbh = &mld_ra.hbh;
3886 mld_po.ip6po_prefer_tempaddr = IP6PO_TEMPADDR_NOTPREFER;
3887 mld_po.ip6po_flags = IP6PO_DONTFRAG;
3888 LIST_INIT(&mli_head);
3889 }
3890