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