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