2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 2007-2009 Bruce Simpson.
30 * Copyright (c) 1988 Stephen Deering.
31 * Copyright (c) 1992, 1993
32 * The Regents of the University of California. All rights reserved.
34 * This code is derived from software contributed to Berkeley by
35 * Stephen Deering of Stanford University.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
68 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
69 * support for mandatory and extensible security protections. This notice
70 * is included in support of clause 2.2 (b) of the Apple Public License,
75 * Internet Group Management Protocol (IGMP) routines.
76 * [RFC1112, RFC2236, RFC3376]
78 * Written by Steve Deering, Stanford, May 1988.
79 * Modified by Rosen Sharma, Stanford, Aug 1994.
80 * Modified by Bill Fenner, Xerox PARC, Feb 1995.
81 * Modified to fully comply to IGMPv2 by Bill Fenner, Oct 1995.
82 * Significantly rewritten for IGMPv3, VIMAGE, and SMP by Bruce Simpson.
84 * MULTICAST Revision: 3.5.1.4
87 #include <sys/cdefs.h>
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/malloc.h>
93 #include <sys/socket.h>
94 #include <sys/protosw.h>
95 #include <sys/kernel.h>
96 #include <sys/sysctl.h>
97 #include <sys/mcache.h>
99 #include <libkern/libkern.h>
100 #include <kern/zalloc.h>
103 #include <net/route.h>
105 #include <netinet/in.h>
106 #include <netinet/in_var.h>
107 #include <netinet/in_systm.h>
108 #include <netinet/ip.h>
109 #include <netinet/ip_var.h>
110 #include <netinet/igmp.h>
111 #include <netinet/igmp_var.h>
112 #include <netinet/kpi_ipfilter_var.h>
114 SLIST_HEAD(igmp_inm_relhead
, in_multi
);
116 static void igi_initvar(struct igmp_ifinfo
*, struct ifnet
*, int);
117 static struct igmp_ifinfo
*igi_alloc(zalloc_flags_t
);
118 static void igi_free(struct igmp_ifinfo
*);
119 static void igi_delete(const struct ifnet
*, struct igmp_inm_relhead
*);
120 static void igmp_dispatch_queue(struct igmp_ifinfo
*, struct ifqueue
*,
122 static void igmp_final_leave(struct in_multi
*, struct igmp_ifinfo
*,
123 struct igmp_tparams
*);
124 static int igmp_handle_state_change(struct in_multi
*,
125 struct igmp_ifinfo
*, struct igmp_tparams
*);
126 static int igmp_initial_join(struct in_multi
*, struct igmp_ifinfo
*,
127 struct igmp_tparams
*);
128 static int igmp_input_v1_query(struct ifnet
*, const struct ip
*,
129 const struct igmp
*);
130 static int igmp_input_v2_query(struct ifnet
*, const struct ip
*,
131 const struct igmp
*);
132 static int igmp_input_v3_query(struct ifnet
*, const struct ip
*,
133 /*const*/ struct igmpv3
*);
134 static int igmp_input_v3_group_query(struct in_multi
*,
135 int, /*const*/ struct igmpv3
*);
136 static int igmp_input_v1_report(struct ifnet
*, struct mbuf
*,
137 /*const*/ struct ip
*, /*const*/ struct igmp
*);
138 static int igmp_input_v2_report(struct ifnet
*, struct mbuf
*,
139 /*const*/ struct ip
*, /*const*/ struct igmp
*);
140 static void igmp_sendpkt(struct mbuf
*);
141 static __inline__
int igmp_isgroupreported(const struct in_addr
);
142 static struct mbuf
*igmp_ra_alloc(void);
144 static const char *igmp_rec_type_to_str(const int);
146 static uint32_t igmp_set_version(struct igmp_ifinfo
*, const int);
147 static void igmp_flush_relq(struct igmp_ifinfo
*,
148 struct igmp_inm_relhead
*);
149 static int igmp_v1v2_queue_report(struct in_multi
*, const int);
150 static void igmp_v1v2_process_group_timer(struct in_multi
*, const int);
151 static void igmp_v1v2_process_querier_timers(struct igmp_ifinfo
*);
152 static uint32_t igmp_v2_update_group(struct in_multi
*, const int);
153 static void igmp_v3_cancel_link_timers(struct igmp_ifinfo
*);
154 static uint32_t igmp_v3_dispatch_general_query(struct igmp_ifinfo
*);
156 igmp_v3_encap_report(struct ifnet
*, struct mbuf
*);
157 static int igmp_v3_enqueue_group_record(struct ifqueue
*,
158 struct in_multi
*, const int, const int, const int);
159 static int igmp_v3_enqueue_filter_change(struct ifqueue
*,
161 static void igmp_v3_process_group_timers(struct igmp_ifinfo
*,
162 struct ifqueue
*, struct ifqueue
*, struct in_multi
*,
164 static int igmp_v3_merge_state_changes(struct in_multi
*,
166 static void igmp_v3_suppress_group_record(struct in_multi
*);
167 static int sysctl_igmp_ifinfo SYSCTL_HANDLER_ARGS
;
168 static int sysctl_igmp_gsr SYSCTL_HANDLER_ARGS
;
169 static int sysctl_igmp_default_version SYSCTL_HANDLER_ARGS
;
171 static int igmp_timeout_run
; /* IGMP timer is scheduled to run */
172 static void igmp_timeout(void *);
173 static void igmp_sched_timeout(void);
175 static struct mbuf
*m_raopt
; /* Router Alert option */
177 static int querier_present_timers_running
; /* IGMPv1/v2 older version
179 static int interface_timers_running
; /* IGMPv3 general
181 static int state_change_timers_running
; /* IGMPv3 state-change
183 static int current_state_timers_running
; /* IGMPv1/v2 host
184 * report; IGMPv3 g/sg
188 * Subsystem lock macros.
190 #define IGMP_LOCK() \
191 lck_mtx_lock(&igmp_mtx)
192 #define IGMP_LOCK_ASSERT_HELD() \
193 LCK_MTX_ASSERT(&igmp_mtx, LCK_MTX_ASSERT_OWNED)
194 #define IGMP_LOCK_ASSERT_NOTHELD() \
195 LCK_MTX_ASSERT(&igmp_mtx, LCK_MTX_ASSERT_NOTOWNED)
196 #define IGMP_UNLOCK() \
197 lck_mtx_unlock(&igmp_mtx)
199 static LIST_HEAD(, igmp_ifinfo
) igi_head
;
200 static struct igmpstat_v3 igmpstat_v3
= {
201 .igps_version
= IGPS_VERSION_3
,
202 .igps_len
= sizeof(struct igmpstat_v3
),
204 static struct igmpstat igmpstat
; /* old IGMPv2 stats structure */
205 static struct timeval igmp_gsrdelay
= {.tv_sec
= 10, .tv_usec
= 0};
207 static int igmp_recvifkludge
= 1;
208 static int igmp_sendra
= 1;
209 static int igmp_sendlocal
= 1;
210 static int igmp_v1enable
= 1;
211 static int igmp_v2enable
= 1;
212 static int igmp_legacysupp
= 0;
213 static int igmp_default_version
= IGMP_VERSION_3
;
215 SYSCTL_STRUCT(_net_inet_igmp
, IGMPCTL_STATS
, stats
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
216 &igmpstat
, igmpstat
, "");
217 SYSCTL_STRUCT(_net_inet_igmp
, OID_AUTO
, v3stats
,
218 CTLFLAG_RD
| CTLFLAG_LOCKED
, &igmpstat_v3
, igmpstat_v3
, "");
219 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
, recvifkludge
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
220 &igmp_recvifkludge
, 0,
221 "Rewrite IGMPv1/v2 reports from 0.0.0.0 to contain subnet address");
222 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
, sendra
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
224 "Send IP Router Alert option in IGMPv2/v3 messages");
225 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
, sendlocal
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
227 "Send IGMP membership reports for 224.0.0.0/24 groups");
228 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
, v1enable
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
230 "Enable backwards compatibility with IGMPv1");
231 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
, v2enable
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
233 "Enable backwards compatibility with IGMPv2");
234 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
, legacysupp
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
236 "Allow v1/v2 reports to suppress v3 group responses");
237 SYSCTL_PROC(_net_inet_igmp
, OID_AUTO
, default_version
,
238 CTLTYPE_INT
| CTLFLAG_RW
,
239 &igmp_default_version
, 0, sysctl_igmp_default_version
, "I",
240 "Default version of IGMP to run on each interface");
241 SYSCTL_PROC(_net_inet_igmp
, OID_AUTO
, gsrdelay
,
242 CTLTYPE_INT
| CTLFLAG_RW
,
243 &igmp_gsrdelay
.tv_sec
, 0, sysctl_igmp_gsr
, "I",
244 "Rate limit for IGMPv3 Group-and-Source queries in seconds");
247 SYSCTL_INT(_net_inet_igmp
, OID_AUTO
,
248 debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &igmp_debug
, 0, "");
251 SYSCTL_NODE(_net_inet_igmp
, OID_AUTO
, ifinfo
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
252 sysctl_igmp_ifinfo
, "Per-interface IGMPv3 state");
254 /* Lock group and attribute for igmp_mtx */
255 static lck_attr_t
*igmp_mtx_attr
;
256 static lck_grp_t
*igmp_mtx_grp
;
257 static lck_grp_attr_t
*igmp_mtx_grp_attr
;
260 * Locking and reference counting:
262 * igmp_mtx mainly protects igi_head. In cases where both igmp_mtx and
263 * in_multihead_lock must be held, the former must be acquired first in order
264 * to maintain lock ordering. It is not a requirement that igmp_mtx be
265 * acquired first before in_multihead_lock, but in case both must be acquired
266 * in succession, the correct lock ordering must be followed.
268 * Instead of walking the if_multiaddrs list at the interface and returning
269 * the ifma_protospec value of a matching entry, we search the global list
270 * of in_multi records and find it that way; this is done with in_multihead
271 * lock held. Doing so avoids the race condition issues that many other BSDs
272 * suffer from (therefore in our implementation, ifma_protospec will never be
273 * NULL for as long as the in_multi is valid.)
275 * The above creates a requirement for the in_multi to stay in in_multihead
276 * list even after the final IGMP leave (in IGMPv3 mode) until no longer needs
277 * be retransmitted (this is not required for IGMPv1/v2.) In order to handle
278 * this, the request and reference counts of the in_multi are bumped up when
279 * the state changes to IGMP_LEAVING_MEMBER, and later dropped in the timeout
280 * handler. Each in_multi holds a reference to the underlying igmp_ifinfo.
282 * Thus, the permitted lock oder is:
284 * igmp_mtx, in_multihead_lock, inm_lock, igi_lock
286 * Any may be taken independently, but if any are held at the same time,
287 * the above lock order must be followed.
289 static decl_lck_mtx_data(, igmp_mtx
);
290 static int igmp_timers_are_running
;
292 #define IGMP_ADD_DETACHED_INM(_head, _inm) { \
293 SLIST_INSERT_HEAD(_head, _inm, inm_dtle); \
296 #define IGMP_REMOVE_DETACHED_INM(_head) { \
297 struct in_multi *_inm, *_inm_tmp; \
298 SLIST_FOREACH_SAFE(_inm, _head, inm_dtle, _inm_tmp) { \
299 SLIST_REMOVE(_head, _inm, in_multi, inm_dtle); \
302 VERIFY(SLIST_EMPTY(_head)); \
305 static ZONE_DECLARE(igi_zone
, "igmp_ifinfo",
306 sizeof(struct igmp_ifinfo
), ZC_ZFREE_CLEARMEM
);
308 /* Store IGMPv3 record count in the module private scratch space */
309 #define vt_nrecs pkt_mpriv.__mpriv_u.__mpriv32[0].__mpriv32_u.__val16[0]
312 igmp_save_context(struct mbuf
*m
, struct ifnet
*ifp
)
314 m
->m_pkthdr
.rcvif
= ifp
;
318 igmp_scrub_context(struct mbuf
*m
)
320 m
->m_pkthdr
.rcvif
= NULL
;
324 static __inline
const char *
325 inet_ntop_haddr(in_addr_t haddr
, char *buf
, socklen_t size
)
329 ia
.s_addr
= htonl(haddr
);
330 return inet_ntop(AF_INET
, &ia
, buf
, size
);
335 * Restore context from a queued IGMP output chain.
338 static __inline
struct ifnet
*
339 igmp_restore_context(struct mbuf
*m
)
341 return m
->m_pkthdr
.rcvif
;
345 * Retrieve or set default IGMP version.
348 sysctl_igmp_default_version SYSCTL_HANDLER_ARGS
350 #pragma unused(oidp, arg2)
356 error
= SYSCTL_OUT(req
, arg1
, sizeof(int));
357 if (error
|| !req
->newptr
) {
361 new = igmp_default_version
;
363 error
= SYSCTL_IN(req
, &new, sizeof(int));
368 if (new < IGMP_VERSION_1
|| new > IGMP_VERSION_3
) {
373 IGMP_PRINTF(("%s: change igmp_default_version from %d to %d\n",
374 __func__
, igmp_default_version
, new));
376 igmp_default_version
= new;
384 * Retrieve or set threshold between group-source queries in seconds.
388 sysctl_igmp_gsr SYSCTL_HANDLER_ARGS
390 #pragma unused(arg1, arg2)
396 i
= (int)igmp_gsrdelay
.tv_sec
;
398 error
= sysctl_handle_int(oidp
, &i
, 0, req
);
399 if (error
|| !req
->newptr
) {
403 if (i
< -1 || i
>= 60) {
408 igmp_gsrdelay
.tv_sec
= i
;
416 * Expose struct igmp_ifinfo to userland, keyed by ifindex.
417 * For use by ifmcstat(8).
421 sysctl_igmp_ifinfo SYSCTL_HANDLER_ARGS
428 struct igmp_ifinfo
*igi
;
429 struct igmp_ifinfo_u igi_u
;
434 if (req
->newptr
!= USER_ADDR_NULL
) {
444 if (name
[0] <= 0 || name
[0] > (u_int
)if_index
) {
451 ifnet_head_lock_shared();
452 ifp
= ifindex2ifnet
[name
[0]];
458 bzero(&igi_u
, sizeof(igi_u
));
460 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
462 if (ifp
!= igi
->igi_ifp
) {
466 igi_u
.igi_ifindex
= igi
->igi_ifp
->if_index
;
467 igi_u
.igi_version
= igi
->igi_version
;
468 igi_u
.igi_v1_timer
= igi
->igi_v1_timer
;
469 igi_u
.igi_v2_timer
= igi
->igi_v2_timer
;
470 igi_u
.igi_v3_timer
= igi
->igi_v3_timer
;
471 igi_u
.igi_flags
= igi
->igi_flags
;
472 igi_u
.igi_rv
= igi
->igi_rv
;
473 igi_u
.igi_qi
= igi
->igi_qi
;
474 igi_u
.igi_qri
= igi
->igi_qri
;
475 igi_u
.igi_uri
= igi
->igi_uri
;
478 error
= SYSCTL_OUT(req
, &igi_u
, sizeof(igi_u
));
488 * Dispatch an entire queue of pending packet chains
490 * Must not be called with inm_lock held.
493 igmp_dispatch_queue(struct igmp_ifinfo
*igi
, struct ifqueue
*ifq
, int limit
,
500 IGI_LOCK_ASSERT_HELD(igi
);
508 IGMP_PRINTF(("%s: dispatch 0x%llx from 0x%llx\n", __func__
,
509 (uint64_t)VM_KERNEL_ADDRPERM(ifq
),
510 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
511 ip
= mtod(m
, struct ip
*);
513 m
->m_flags
|= M_IGMP_LOOP
;
528 IGI_LOCK_ASSERT_HELD(igi
);
533 * Filter outgoing IGMP report state by group.
535 * Reports are ALWAYS suppressed for ALL-HOSTS (224.0.0.1).
536 * If the net.inet.igmp.sendlocal sysctl is 0, then IGMP reports are
537 * disabled for all groups in the 224.0.0.0/24 link-local scope. However,
538 * this may break certain IGMP snooping switches which rely on the old
541 * Return zero if the given group is one for which IGMP reports
542 * should be suppressed, or non-zero if reports should be issued.
547 igmp_isgroupreported(const struct in_addr addr
)
549 if (in_allhosts(addr
) ||
550 ((!igmp_sendlocal
&& IN_LOCAL_GROUP(ntohl(addr
.s_addr
))))) {
558 * Construct a Router Alert option to use in outgoing packets.
566 MGET(m
, M_WAITOK
, MT_DATA
);
567 p
= mtod(m
, struct ipoption
*);
568 p
->ipopt_dst
.s_addr
= INADDR_ANY
;
569 p
->ipopt_list
[0] = (char)IPOPT_RA
; /* Router Alert Option */
570 p
->ipopt_list
[1] = 0x04; /* 4 bytes long */
571 p
->ipopt_list
[2] = IPOPT_EOL
; /* End of IP option list */
572 p
->ipopt_list
[3] = 0x00; /* pad byte */
573 m
->m_len
= sizeof(p
->ipopt_dst
) + p
->ipopt_list
[1];
579 * Attach IGMP when PF_INET is attached to an interface.
582 igmp_domifattach(struct ifnet
*ifp
, zalloc_flags_t how
)
584 struct igmp_ifinfo
*igi
;
586 IGMP_PRINTF(("%s: called for ifp 0x%llx(%s)\n",
587 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
));
589 igi
= igi_alloc(how
);
597 igi_initvar(igi
, ifp
, 0);
598 igi
->igi_debug
|= IFD_ATTACHED
;
599 IGI_ADDREF_LOCKED(igi
); /* hold a reference for igi_head */
600 IGI_ADDREF_LOCKED(igi
); /* hold a reference for caller */
602 ifnet_lock_shared(ifp
);
603 igmp_initsilent(ifp
, igi
);
604 ifnet_lock_done(ifp
);
606 LIST_INSERT_HEAD(&igi_head
, igi
, igi_link
);
610 IGMP_PRINTF(("%s: allocate igmp_ifinfo for ifp 0x%llx(%s)\n", __func__
,
611 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
));
617 * Attach IGMP when PF_INET is reattached to an interface. Caller is
618 * expected to have an outstanding reference to the igi.
621 igmp_domifreattach(struct igmp_ifinfo
*igi
)
628 VERIFY(!(igi
->igi_debug
& IFD_ATTACHED
));
631 igi_initvar(igi
, ifp
, 1);
632 igi
->igi_debug
|= IFD_ATTACHED
;
633 IGI_ADDREF_LOCKED(igi
); /* hold a reference for igi_head */
635 ifnet_lock_shared(ifp
);
636 igmp_initsilent(ifp
, igi
);
637 ifnet_lock_done(ifp
);
639 LIST_INSERT_HEAD(&igi_head
, igi
, igi_link
);
643 IGMP_PRINTF(("%s: reattached igmp_ifinfo for ifp 0x%llx(%s)\n",
644 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
));
648 * Hook for domifdetach.
651 igmp_domifdetach(struct ifnet
*ifp
)
653 SLIST_HEAD(, in_multi
) inm_dthead
;
655 SLIST_INIT(&inm_dthead
);
657 IGMP_PRINTF(("%s: called for ifp 0x%llx(%s%d)\n", __func__
,
658 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
, ifp
->if_unit
));
661 igi_delete(ifp
, (struct igmp_inm_relhead
*)&inm_dthead
);
664 /* Now that we're dropped all locks, release detached records */
665 IGMP_REMOVE_DETACHED_INM(&inm_dthead
);
669 * Called at interface detach time. Note that we only flush all deferred
670 * responses and record releases; all remaining inm records and their source
671 * entries related to this interface are left intact, in order to handle
675 igi_delete(const struct ifnet
*ifp
, struct igmp_inm_relhead
*inm_dthead
)
677 struct igmp_ifinfo
*igi
, *tigi
;
679 IGMP_LOCK_ASSERT_HELD();
681 LIST_FOREACH_SAFE(igi
, &igi_head
, igi_link
, tigi
) {
683 if (igi
->igi_ifp
== ifp
) {
685 * Free deferred General Query responses.
687 IF_DRAIN(&igi
->igi_gq
);
688 IF_DRAIN(&igi
->igi_v2q
);
689 igmp_flush_relq(igi
, inm_dthead
);
690 VERIFY(SLIST_EMPTY(&igi
->igi_relinmhead
));
691 igi
->igi_debug
&= ~IFD_ATTACHED
;
694 LIST_REMOVE(igi
, igi_link
);
695 IGI_REMREF(igi
); /* release igi_head reference */
700 panic("%s: igmp_ifinfo not found for ifp %p(%s)\n", __func__
,
704 __private_extern__
void
705 igmp_initsilent(struct ifnet
*ifp
, struct igmp_ifinfo
*igi
)
707 ifnet_lock_assert(ifp
, IFNET_LCK_ASSERT_OWNED
);
709 IGI_LOCK_ASSERT_NOTHELD(igi
);
711 if (!(ifp
->if_flags
& IFF_MULTICAST
)) {
712 igi
->igi_flags
|= IGIF_SILENT
;
714 igi
->igi_flags
&= ~IGIF_SILENT
;
720 igi_initvar(struct igmp_ifinfo
*igi
, struct ifnet
*ifp
, int reattach
)
722 IGI_LOCK_ASSERT_HELD(igi
);
725 igi
->igi_version
= igmp_default_version
;
727 igi
->igi_rv
= IGMP_RV_INIT
;
728 igi
->igi_qi
= IGMP_QI_INIT
;
729 igi
->igi_qri
= IGMP_QRI_INIT
;
730 igi
->igi_uri
= IGMP_URI_INIT
;
733 SLIST_INIT(&igi
->igi_relinmhead
);
737 * Responses to general queries are subject to bounds.
739 igi
->igi_gq
.ifq_maxlen
= IGMP_MAX_RESPONSE_PACKETS
;
740 igi
->igi_v2q
.ifq_maxlen
= IGMP_MAX_RESPONSE_PACKETS
;
743 static struct igmp_ifinfo
*
744 igi_alloc(zalloc_flags_t how
)
746 struct igmp_ifinfo
*igi
= zalloc_flags(igi_zone
, how
| Z_ZERO
);
748 lck_mtx_init(&igi
->igi_lock
, igmp_mtx_grp
, igmp_mtx_attr
);
749 igi
->igi_debug
|= IFD_ALLOC
;
755 igi_free(struct igmp_ifinfo
*igi
)
758 if (igi
->igi_debug
& IFD_ATTACHED
) {
759 panic("%s: attached igi=%p is being freed", __func__
, igi
);
761 } else if (igi
->igi_ifp
!= NULL
) {
762 panic("%s: ifp not NULL for igi=%p", __func__
, igi
);
764 } else if (!(igi
->igi_debug
& IFD_ALLOC
)) {
765 panic("%s: igi %p cannot be freed", __func__
, igi
);
767 } else if (igi
->igi_refcnt
!= 0) {
768 panic("%s: non-zero refcnt igi=%p", __func__
, igi
);
771 igi
->igi_debug
&= ~IFD_ALLOC
;
774 lck_mtx_destroy(&igi
->igi_lock
, igmp_mtx_grp
);
775 zfree(igi_zone
, igi
);
779 igi_addref(struct igmp_ifinfo
*igi
, int locked
)
784 IGI_LOCK_ASSERT_HELD(igi
);
787 if (++igi
->igi_refcnt
== 0) {
788 panic("%s: igi=%p wraparound refcnt", __func__
, igi
);
797 igi_remref(struct igmp_ifinfo
*igi
)
799 SLIST_HEAD(, in_multi
) inm_dthead
;
804 if (igi
->igi_refcnt
== 0) {
805 panic("%s: igi=%p negative refcnt", __func__
, igi
);
810 if (igi
->igi_refcnt
> 0) {
817 IF_DRAIN(&igi
->igi_gq
);
818 IF_DRAIN(&igi
->igi_v2q
);
819 SLIST_INIT(&inm_dthead
);
820 igmp_flush_relq(igi
, (struct igmp_inm_relhead
*)&inm_dthead
);
821 VERIFY(SLIST_EMPTY(&igi
->igi_relinmhead
));
824 /* Now that we're dropped all locks, release detached records */
825 IGMP_REMOVE_DETACHED_INM(&inm_dthead
);
827 IGMP_PRINTF(("%s: freeing igmp_ifinfo for ifp 0x%llx(%s)\n",
828 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
834 * Process a received IGMPv1 query.
835 * Return non-zero if the message should be dropped.
838 igmp_input_v1_query(struct ifnet
*ifp
, const struct ip
*ip
,
839 const struct igmp
*igmp
)
841 struct igmp_ifinfo
*igi
;
842 struct in_multi
*inm
;
843 struct in_multistep step
;
844 struct igmp_tparams itp
= { .qpt
= 0, .it
= 0, .cst
= 0, .sct
= 0 };
846 IGMP_LOCK_ASSERT_NOTHELD();
849 * IGMPv1 Host Membership Queries SHOULD always be addressed to
850 * 224.0.0.1. They are always treated as General Queries.
851 * igmp_group is always ignored. Do not drop it as a userland
852 * daemon may wish to see it.
854 if (!in_allhosts(ip
->ip_dst
) || !in_nullhost(igmp
->igmp_group
)) {
855 IGMPSTAT_INC(igps_rcv_badqueries
);
856 OIGMPSTAT_INC(igps_rcv_badqueries
);
859 IGMPSTAT_INC(igps_rcv_gen_queries
);
861 igi
= IGMP_IFINFO(ifp
);
865 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
866 IGMP_PRINTF(("%s: ignore v1 query on IGIF_LOOPBACK "
867 "ifp 0x%llx(%s)\n", __func__
,
868 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
873 * Switch to IGMPv1 host compatibility mode.
875 itp
.qpt
= igmp_set_version(igi
, IGMP_VERSION_1
);
878 IGMP_PRINTF(("%s: process v1 query on ifp 0x%llx(%s)\n", __func__
,
879 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
882 * Start the timers in all of our group records
883 * for the interface on which the query arrived,
884 * except those which are already running.
886 in_multihead_lock_shared();
887 IN_FIRST_MULTI(step
, inm
);
888 while (inm
!= NULL
) {
890 if (inm
->inm_ifp
!= ifp
|| inm
->inm_timer
!= 0) {
894 switch (inm
->inm_state
) {
895 case IGMP_NOT_MEMBER
:
896 case IGMP_SILENT_MEMBER
:
898 case IGMP_G_QUERY_PENDING_MEMBER
:
899 case IGMP_SG_QUERY_PENDING_MEMBER
:
900 case IGMP_REPORTING_MEMBER
:
901 case IGMP_IDLE_MEMBER
:
902 case IGMP_LAZY_MEMBER
:
903 case IGMP_SLEEPING_MEMBER
:
904 case IGMP_AWAKENING_MEMBER
:
905 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
906 inm
->inm_timer
= IGMP_RANDOM_DELAY(IGMP_V1V2_MAX_RI
);
909 case IGMP_LEAVING_MEMBER
:
914 IN_NEXT_MULTI(step
, inm
);
916 in_multihead_lock_done();
918 igmp_set_timeout(&itp
);
924 * Process a received IGMPv2 general or group-specific query.
927 igmp_input_v2_query(struct ifnet
*ifp
, const struct ip
*ip
,
928 const struct igmp
*igmp
)
930 struct igmp_ifinfo
*igi
;
931 struct in_multi
*inm
;
932 int is_general_query
;
934 struct igmp_tparams itp
= { .qpt
= 0, .it
= 0, .cst
= 0, .sct
= 0 };
936 IGMP_LOCK_ASSERT_NOTHELD();
938 is_general_query
= 0;
941 * Validate address fields upfront.
943 if (in_nullhost(igmp
->igmp_group
)) {
945 * IGMPv2 General Query.
946 * If this was not sent to the all-hosts group, ignore it.
948 if (!in_allhosts(ip
->ip_dst
)) {
951 IGMPSTAT_INC(igps_rcv_gen_queries
);
952 is_general_query
= 1;
954 /* IGMPv2 Group-Specific Query. */
955 IGMPSTAT_INC(igps_rcv_group_queries
);
958 igi
= IGMP_IFINFO(ifp
);
962 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
963 IGMP_PRINTF(("%s: ignore v2 query on IGIF_LOOPBACK "
964 "ifp 0x%llx(%s)\n", __func__
,
965 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
970 * Ignore v2 query if in v1 Compatibility Mode.
972 if (igi
->igi_version
== IGMP_VERSION_1
) {
976 itp
.qpt
= igmp_set_version(igi
, IGMP_VERSION_2
);
979 timer
= igmp
->igmp_code
/ IGMP_TIMER_SCALE
;
984 if (is_general_query
) {
985 struct in_multistep step
;
987 IGMP_PRINTF(("%s: process v2 general query on ifp 0x%llx(%s)\n",
988 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
990 * For each reporting group joined on this
991 * interface, kick the report timer.
993 in_multihead_lock_shared();
994 IN_FIRST_MULTI(step
, inm
);
995 while (inm
!= NULL
) {
997 if (inm
->inm_ifp
== ifp
) {
998 itp
.cst
+= igmp_v2_update_group(inm
, timer
);
1001 IN_NEXT_MULTI(step
, inm
);
1003 in_multihead_lock_done();
1006 * Group-specific IGMPv2 query, we need only
1007 * look up the single group to process it.
1009 in_multihead_lock_shared();
1010 IN_LOOKUP_MULTI(&igmp
->igmp_group
, ifp
, inm
);
1011 in_multihead_lock_done();
1014 IGMP_INET_PRINTF(igmp
->igmp_group
,
1015 ("process v2 query %s on ifp 0x%llx(%s)\n",
1017 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1018 itp
.cst
= igmp_v2_update_group(inm
, timer
);
1020 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1024 igmp_set_timeout(&itp
);
1030 * Update the report timer on a group in response to an IGMPv2 query.
1032 * If we are becoming the reporting member for this group, start the timer.
1033 * If we already are the reporting member for this group, and timer is
1034 * below the threshold, reset it.
1036 * We may be updating the group for the first time since we switched
1037 * to IGMPv3. If we are, then we must clear any recorded source lists,
1038 * and transition to REPORTING state; the group timer is overloaded
1039 * for group and group-source query responses.
1041 * Unlike IGMPv3, the delay per group should be jittered
1042 * to avoid bursts of IGMPv2 reports.
1045 igmp_v2_update_group(struct in_multi
*inm
, const int timer
)
1047 IGMP_INET_PRINTF(inm
->inm_addr
, ("%s: %s/%s timer=%d\n",
1048 __func__
, _igmp_inet_buf
, if_name(inm
->inm_ifp
),
1051 INM_LOCK_ASSERT_HELD(inm
);
1053 switch (inm
->inm_state
) {
1054 case IGMP_NOT_MEMBER
:
1055 case IGMP_SILENT_MEMBER
:
1057 case IGMP_REPORTING_MEMBER
:
1058 if (inm
->inm_timer
!= 0 &&
1059 inm
->inm_timer
<= timer
) {
1060 IGMP_PRINTF(("%s: REPORTING and timer running, "
1061 "skipping.\n", __func__
));
1065 case IGMP_SG_QUERY_PENDING_MEMBER
:
1066 case IGMP_G_QUERY_PENDING_MEMBER
:
1067 case IGMP_IDLE_MEMBER
:
1068 case IGMP_LAZY_MEMBER
:
1069 case IGMP_AWAKENING_MEMBER
:
1070 IGMP_PRINTF(("%s: ->REPORTING\n", __func__
));
1071 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
1072 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1074 case IGMP_SLEEPING_MEMBER
:
1075 IGMP_PRINTF(("%s: ->AWAKENING\n", __func__
));
1076 inm
->inm_state
= IGMP_AWAKENING_MEMBER
;
1078 case IGMP_LEAVING_MEMBER
:
1082 return inm
->inm_timer
;
1086 * Process a received IGMPv3 general, group-specific or
1087 * group-and-source-specific query.
1088 * Assumes m has already been pulled up to the full IGMP message length.
1089 * Return 0 if successful, otherwise an appropriate error code is returned.
1092 igmp_input_v3_query(struct ifnet
*ifp
, const struct ip
*ip
,
1093 /*const*/ struct igmpv3
*igmpv3
)
1095 struct igmp_ifinfo
*igi
;
1096 struct in_multi
*inm
;
1097 int is_general_query
;
1098 uint32_t maxresp
, nsrc
, qqi
;
1101 struct igmp_tparams itp
= { .qpt
= 0, .it
= 0, .cst
= 0, .sct
= 0 };
1103 IGMP_LOCK_ASSERT_NOTHELD();
1105 is_general_query
= 0;
1107 IGMP_PRINTF(("%s: process v3 query on ifp 0x%llx(%s)\n", __func__
,
1108 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1110 maxresp
= igmpv3
->igmp_code
; /* in 1/10ths of a second */
1111 if (maxresp
>= 128) {
1112 maxresp
= IGMP_MANT(igmpv3
->igmp_code
) <<
1113 (IGMP_EXP(igmpv3
->igmp_code
) + 3);
1117 * Robustness must never be less than 2 for on-wire IGMPv3.
1118 * FUTURE: Check if ifp has IGIF_LOOPBACK set, as we will make
1119 * an exception for interfaces whose IGMPv3 state changes
1120 * are redirected to loopback (e.g. MANET).
1122 qrv
= IGMP_QRV(igmpv3
->igmp_misc
);
1124 IGMP_PRINTF(("%s: clamping qrv %d to %d\n", __func__
,
1125 qrv
, IGMP_RV_INIT
));
1129 qqi
= igmpv3
->igmp_qqi
;
1131 qqi
= IGMP_MANT(igmpv3
->igmp_qqi
) <<
1132 (IGMP_EXP(igmpv3
->igmp_qqi
) + 3);
1135 timer
= maxresp
/ IGMP_TIMER_SCALE
;
1140 nsrc
= ntohs(igmpv3
->igmp_numsrc
);
1143 * Validate address fields and versions upfront before
1144 * accepting v3 query.
1146 if (in_nullhost(igmpv3
->igmp_group
)) {
1148 * IGMPv3 General Query.
1150 * General Queries SHOULD be directed to 224.0.0.1.
1151 * A general query with a source list has undefined
1152 * behaviour; discard it.
1154 IGMPSTAT_INC(igps_rcv_gen_queries
);
1155 if (!in_allhosts(ip
->ip_dst
) || nsrc
> 0) {
1156 IGMPSTAT_INC(igps_rcv_badqueries
);
1157 OIGMPSTAT_INC(igps_rcv_badqueries
);
1160 is_general_query
= 1;
1162 /* Group or group-source specific query. */
1164 IGMPSTAT_INC(igps_rcv_group_queries
);
1166 IGMPSTAT_INC(igps_rcv_gsr_queries
);
1170 igi
= IGMP_IFINFO(ifp
);
1171 VERIFY(igi
!= NULL
);
1174 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
1175 IGMP_PRINTF(("%s: ignore v3 query on IGIF_LOOPBACK "
1176 "ifp 0x%llx(%s)\n", __func__
,
1177 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1183 * Discard the v3 query if we're in Compatibility Mode.
1184 * The RFC is not obviously worded that hosts need to stay in
1185 * compatibility mode until the Old Version Querier Present
1188 if (igi
->igi_version
!= IGMP_VERSION_3
) {
1189 IGMP_PRINTF(("%s: ignore v3 query in v%d mode on "
1190 "ifp 0x%llx(%s)\n", __func__
, igi
->igi_version
,
1191 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1196 itp
.qpt
= igmp_set_version(igi
, IGMP_VERSION_3
);
1199 igi
->igi_qri
= MAX(timer
, IGMP_QRI_MIN
);
1201 IGMP_PRINTF(("%s: qrv %d qi %d qri %d\n", __func__
, igi
->igi_rv
,
1202 igi
->igi_qi
, igi
->igi_qri
));
1204 if (is_general_query
) {
1206 * Schedule a current-state report on this ifp for
1207 * all groups, possibly containing source lists.
1208 * If there is a pending General Query response
1209 * scheduled earlier than the selected delay, do
1210 * not schedule any other reports.
1211 * Otherwise, reset the interface timer.
1213 IGMP_PRINTF(("%s: process v3 general query on ifp 0x%llx(%s)\n",
1214 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1215 if (igi
->igi_v3_timer
== 0 || igi
->igi_v3_timer
>= timer
) {
1216 itp
.it
= igi
->igi_v3_timer
= IGMP_RANDOM_DELAY(timer
);
1222 * Group-source-specific queries are throttled on
1223 * a per-group basis to defeat denial-of-service attempts.
1224 * Queries for groups we are not a member of on this
1225 * link are simply ignored.
1227 in_multihead_lock_shared();
1228 IN_LOOKUP_MULTI(&igmpv3
->igmp_group
, ifp
, inm
);
1229 in_multihead_lock_done();
1236 if (!ratecheck(&inm
->inm_lastgsrtv
,
1238 IGMP_PRINTF(("%s: GS query throttled.\n",
1240 IGMPSTAT_INC(igps_drop_gsr_queries
);
1242 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1246 IGMP_INET_PRINTF(igmpv3
->igmp_group
,
1247 ("process v3 %s query on ifp 0x%llx(%s)\n", _igmp_inet_buf
,
1248 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1250 * If there is a pending General Query response
1251 * scheduled sooner than the selected delay, no
1252 * further report need be scheduled.
1253 * Otherwise, prepare to respond to the
1254 * group-specific or group-and-source query.
1257 itp
.it
= igi
->igi_v3_timer
;
1259 if (itp
.it
== 0 || itp
.it
>= timer
) {
1260 (void) igmp_input_v3_group_query(inm
, timer
, igmpv3
);
1261 itp
.cst
= inm
->inm_timer
;
1264 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1268 IGMP_PRINTF(("%s: v3 general query response scheduled in "
1269 "T+%d seconds on ifp 0x%llx(%s)\n", __func__
, itp
.it
,
1270 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1272 igmp_set_timeout(&itp
);
1278 * Process a recieved IGMPv3 group-specific or group-and-source-specific
1280 * Return <0 if any error occured. Currently this is ignored.
1283 igmp_input_v3_group_query(struct in_multi
*inm
,
1284 int timer
, /*const*/ struct igmpv3
*igmpv3
)
1289 INM_LOCK_ASSERT_HELD(inm
);
1293 switch (inm
->inm_state
) {
1294 case IGMP_NOT_MEMBER
:
1295 case IGMP_SILENT_MEMBER
:
1296 case IGMP_SLEEPING_MEMBER
:
1297 case IGMP_LAZY_MEMBER
:
1298 case IGMP_AWAKENING_MEMBER
:
1299 case IGMP_IDLE_MEMBER
:
1300 case IGMP_LEAVING_MEMBER
:
1302 case IGMP_REPORTING_MEMBER
:
1303 case IGMP_G_QUERY_PENDING_MEMBER
:
1304 case IGMP_SG_QUERY_PENDING_MEMBER
:
1308 nsrc
= ntohs(igmpv3
->igmp_numsrc
);
1311 * Deal with group-specific queries upfront.
1312 * If any group query is already pending, purge any recorded
1313 * source-list state if it exists, and schedule a query response
1314 * for this group-specific query.
1317 if (inm
->inm_state
== IGMP_G_QUERY_PENDING_MEMBER
||
1318 inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
) {
1319 inm_clear_recorded(inm
);
1320 timer
= min(inm
->inm_timer
, timer
);
1322 inm
->inm_state
= IGMP_G_QUERY_PENDING_MEMBER
;
1323 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1328 * Deal with the case where a group-and-source-specific query has
1329 * been received but a group-specific query is already pending.
1331 if (inm
->inm_state
== IGMP_G_QUERY_PENDING_MEMBER
) {
1332 timer
= min(inm
->inm_timer
, timer
);
1333 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1338 * Finally, deal with the case where a group-and-source-specific
1339 * query has been received, where a response to a previous g-s-r
1340 * query exists, or none exists.
1341 * In this case, we need to parse the source-list which the Querier
1342 * has provided us with and check if we have any source list filter
1343 * entries at T1 for these sources. If we do not, there is no need
1344 * schedule a report and the query may be dropped.
1345 * If we do, we must record them and schedule a current-state
1346 * report for those sources.
1347 * FIXME: Handling source lists larger than 1 mbuf requires that
1348 * we pass the mbuf chain pointer down to this function, and use
1349 * m_getptr() to walk the chain.
1351 if (inm
->inm_nsrc
> 0) {
1352 const struct in_addr
*ap
;
1355 ap
= (const struct in_addr
*)(igmpv3
+ 1);
1357 for (i
= 0; i
< nsrc
; i
++, ap
++) {
1358 retval
= inm_record_source(inm
, ap
->s_addr
);
1362 nrecorded
+= retval
;
1364 if (nrecorded
> 0) {
1365 IGMP_PRINTF(("%s: schedule response to SG query\n",
1367 inm
->inm_state
= IGMP_SG_QUERY_PENDING_MEMBER
;
1368 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1376 * Process a received IGMPv1 host membership report.
1378 * NOTE: 0.0.0.0 workaround breaks const correctness.
1381 igmp_input_v1_report(struct ifnet
*ifp
, struct mbuf
*m
, /*const*/ struct ip
*ip
,
1382 /*const*/ struct igmp
*igmp
)
1384 struct in_ifaddr
*ia
;
1385 struct in_multi
*inm
;
1387 IGMPSTAT_INC(igps_rcv_reports
);
1388 OIGMPSTAT_INC(igps_rcv_reports
);
1390 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
1391 (m
->m_pkthdr
.pkt_flags
& PKTF_LOOP
)) {
1395 if (!IN_MULTICAST(ntohl(igmp
->igmp_group
.s_addr
) ||
1396 !in_hosteq(igmp
->igmp_group
, ip
->ip_dst
))) {
1397 IGMPSTAT_INC(igps_rcv_badreports
);
1398 OIGMPSTAT_INC(igps_rcv_badreports
);
1403 * RFC 3376, Section 4.2.13, 9.2, 9.3:
1404 * Booting clients may use the source address 0.0.0.0. Some
1405 * IGMP daemons may not know how to use IP_RECVIF to determine
1406 * the interface upon which this message was received.
1407 * Replace 0.0.0.0 with the subnet address if told to do so.
1409 if (igmp_recvifkludge
&& in_nullhost(ip
->ip_src
)) {
1412 IFA_LOCK(&ia
->ia_ifa
);
1413 ip
->ip_src
.s_addr
= htonl(ia
->ia_subnet
);
1414 IFA_UNLOCK(&ia
->ia_ifa
);
1415 IFA_REMREF(&ia
->ia_ifa
);
1419 IGMP_INET_PRINTF(igmp
->igmp_group
,
1420 ("process v1 report %s on ifp 0x%llx(%s)\n", _igmp_inet_buf
,
1421 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1424 * IGMPv1 report suppression.
1425 * If we are a member of this group, and our membership should be
1426 * reported, stop our group timer and transition to the 'lazy' state.
1428 in_multihead_lock_shared();
1429 IN_LOOKUP_MULTI(&igmp
->igmp_group
, ifp
, inm
);
1430 in_multihead_lock_done();
1432 struct igmp_ifinfo
*igi
;
1437 VERIFY(igi
!= NULL
);
1439 IGMPSTAT_INC(igps_rcv_ourreports
);
1440 OIGMPSTAT_INC(igps_rcv_ourreports
);
1443 * If we are in IGMPv3 host mode, do not allow the
1444 * other host's IGMPv1 report to suppress our reports
1445 * unless explicitly configured to do so.
1448 if (igi
->igi_version
== IGMP_VERSION_3
) {
1449 if (igmp_legacysupp
) {
1450 igmp_v3_suppress_group_record(inm
);
1454 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1458 INM_LOCK_ASSERT_HELD(inm
);
1461 switch (inm
->inm_state
) {
1462 case IGMP_NOT_MEMBER
:
1463 case IGMP_SILENT_MEMBER
:
1465 case IGMP_IDLE_MEMBER
:
1466 case IGMP_LAZY_MEMBER
:
1467 case IGMP_AWAKENING_MEMBER
:
1468 IGMP_INET_PRINTF(igmp
->igmp_group
,
1469 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1471 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1473 case IGMP_SLEEPING_MEMBER
:
1474 inm
->inm_state
= IGMP_SLEEPING_MEMBER
;
1476 case IGMP_REPORTING_MEMBER
:
1477 IGMP_INET_PRINTF(igmp
->igmp_group
,
1478 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1480 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1481 if (igi
->igi_version
== IGMP_VERSION_1
) {
1482 inm
->inm_state
= IGMP_LAZY_MEMBER
;
1483 } else if (igi
->igi_version
== IGMP_VERSION_2
) {
1484 inm
->inm_state
= IGMP_SLEEPING_MEMBER
;
1487 case IGMP_G_QUERY_PENDING_MEMBER
:
1488 case IGMP_SG_QUERY_PENDING_MEMBER
:
1489 case IGMP_LEAVING_MEMBER
:
1494 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1501 * Process a received IGMPv2 host membership report.
1503 * NOTE: 0.0.0.0 workaround breaks const correctness.
1506 igmp_input_v2_report(struct ifnet
*ifp
, struct mbuf
*m
, /*const*/ struct ip
*ip
,
1507 /*const*/ struct igmp
*igmp
)
1509 struct in_ifaddr
*ia
;
1510 struct in_multi
*inm
;
1513 * Make sure we don't hear our own membership report. Fast
1514 * leave requires knowing that we are the only member of a
1519 IFA_LOCK(&ia
->ia_ifa
);
1520 if (in_hosteq(ip
->ip_src
, IA_SIN(ia
)->sin_addr
)) {
1521 IFA_UNLOCK(&ia
->ia_ifa
);
1522 IFA_REMREF(&ia
->ia_ifa
);
1525 IFA_UNLOCK(&ia
->ia_ifa
);
1528 IGMPSTAT_INC(igps_rcv_reports
);
1529 OIGMPSTAT_INC(igps_rcv_reports
);
1531 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
1532 (m
->m_pkthdr
.pkt_flags
& PKTF_LOOP
)) {
1534 IFA_REMREF(&ia
->ia_ifa
);
1539 if (!IN_MULTICAST(ntohl(igmp
->igmp_group
.s_addr
)) ||
1540 !in_hosteq(igmp
->igmp_group
, ip
->ip_dst
)) {
1542 IFA_REMREF(&ia
->ia_ifa
);
1544 IGMPSTAT_INC(igps_rcv_badreports
);
1545 OIGMPSTAT_INC(igps_rcv_badreports
);
1550 * RFC 3376, Section 4.2.13, 9.2, 9.3:
1551 * Booting clients may use the source address 0.0.0.0. Some
1552 * IGMP daemons may not know how to use IP_RECVIF to determine
1553 * the interface upon which this message was received.
1554 * Replace 0.0.0.0 with the subnet address if told to do so.
1556 if (igmp_recvifkludge
&& in_nullhost(ip
->ip_src
)) {
1558 IFA_LOCK(&ia
->ia_ifa
);
1559 ip
->ip_src
.s_addr
= htonl(ia
->ia_subnet
);
1560 IFA_UNLOCK(&ia
->ia_ifa
);
1564 IFA_REMREF(&ia
->ia_ifa
);
1567 IGMP_INET_PRINTF(igmp
->igmp_group
,
1568 ("process v2 report %s on ifp 0x%llx(%s)\n", _igmp_inet_buf
,
1569 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1572 * IGMPv2 report suppression.
1573 * If we are a member of this group, and our membership should be
1574 * reported, and our group timer is pending or about to be reset,
1575 * stop our group timer by transitioning to the 'lazy' state.
1577 in_multihead_lock_shared();
1578 IN_LOOKUP_MULTI(&igmp
->igmp_group
, ifp
, inm
);
1579 in_multihead_lock_done();
1581 struct igmp_ifinfo
*igi
;
1585 VERIFY(igi
!= NULL
);
1587 IGMPSTAT_INC(igps_rcv_ourreports
);
1588 OIGMPSTAT_INC(igps_rcv_ourreports
);
1591 * If we are in IGMPv3 host mode, do not allow the
1592 * other host's IGMPv1 report to suppress our reports
1593 * unless explicitly configured to do so.
1596 if (igi
->igi_version
== IGMP_VERSION_3
) {
1597 if (igmp_legacysupp
) {
1598 igmp_v3_suppress_group_record(inm
);
1608 switch (inm
->inm_state
) {
1609 case IGMP_NOT_MEMBER
:
1610 case IGMP_SILENT_MEMBER
:
1611 case IGMP_SLEEPING_MEMBER
:
1613 case IGMP_REPORTING_MEMBER
:
1614 case IGMP_IDLE_MEMBER
:
1615 case IGMP_AWAKENING_MEMBER
:
1616 IGMP_INET_PRINTF(igmp
->igmp_group
,
1617 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1618 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
),
1621 case IGMP_LAZY_MEMBER
:
1622 inm
->inm_state
= IGMP_LAZY_MEMBER
;
1624 case IGMP_G_QUERY_PENDING_MEMBER
:
1625 case IGMP_SG_QUERY_PENDING_MEMBER
:
1626 case IGMP_LEAVING_MEMBER
:
1638 igmp_input(struct mbuf
*m
, int off
)
1648 IGMP_PRINTF(("%s: called w/mbuf (0x%llx,%d)\n", __func__
,
1649 (uint64_t)VM_KERNEL_ADDRPERM(m
), off
));
1651 ifp
= m
->m_pkthdr
.rcvif
;
1653 IGMPSTAT_INC(igps_rcv_total
);
1654 OIGMPSTAT_INC(igps_rcv_total
);
1656 /* Expect 32-bit aligned data pointer on strict-align platforms */
1657 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m
);
1659 ip
= mtod(m
, struct ip
*);
1662 /* By now, ip_len no longer contains the length of IP header */
1663 igmplen
= ip
->ip_len
;
1668 if (igmplen
< IGMP_MINLEN
) {
1669 IGMPSTAT_INC(igps_rcv_tooshort
);
1670 OIGMPSTAT_INC(igps_rcv_tooshort
);
1676 * Always pullup to the minimum size for v1/v2 or v3
1677 * to amortize calls to m_pulldown().
1679 if (igmplen
>= IGMP_V3_QUERY_MINLEN
) {
1680 minlen
= IGMP_V3_QUERY_MINLEN
;
1682 minlen
= IGMP_MINLEN
;
1685 /* A bit more expensive than M_STRUCT_GET, but ensures alignment */
1686 M_STRUCT_GET0(igmp
, struct igmp
*, m
, off
, minlen
);
1688 IGMPSTAT_INC(igps_rcv_tooshort
);
1689 OIGMPSTAT_INC(igps_rcv_tooshort
);
1692 /* N.B.: we assume the packet was correctly aligned in ip_input. */
1695 * Validate checksum.
1697 m
->m_data
+= iphlen
;
1699 if (in_cksum(m
, igmplen
)) {
1700 IGMPSTAT_INC(igps_rcv_badsum
);
1701 OIGMPSTAT_INC(igps_rcv_badsum
);
1705 m
->m_data
-= iphlen
;
1709 * IGMP control traffic is link-scope, and must have a TTL of 1.
1710 * DVMRP traffic (e.g. mrinfo, mtrace) is an exception;
1711 * probe packets may come from beyond the LAN.
1713 if (igmp
->igmp_type
!= IGMP_DVMRP
&& ip
->ip_ttl
!= 1) {
1714 IGMPSTAT_INC(igps_rcv_badttl
);
1719 switch (igmp
->igmp_type
) {
1720 case IGMP_HOST_MEMBERSHIP_QUERY
:
1721 if (igmplen
== IGMP_MINLEN
) {
1722 if (igmp
->igmp_code
== 0) {
1723 queryver
= IGMP_VERSION_1
;
1725 queryver
= IGMP_VERSION_2
;
1727 } else if (igmplen
>= IGMP_V3_QUERY_MINLEN
) {
1728 queryver
= IGMP_VERSION_3
;
1730 IGMPSTAT_INC(igps_rcv_tooshort
);
1731 OIGMPSTAT_INC(igps_rcv_tooshort
);
1736 OIGMPSTAT_INC(igps_rcv_queries
);
1739 case IGMP_VERSION_1
:
1740 IGMPSTAT_INC(igps_rcv_v1v2_queries
);
1741 if (!igmp_v1enable
) {
1744 if (igmp_input_v1_query(ifp
, ip
, igmp
) != 0) {
1750 case IGMP_VERSION_2
:
1751 IGMPSTAT_INC(igps_rcv_v1v2_queries
);
1752 if (!igmp_v2enable
) {
1755 if (igmp_input_v2_query(ifp
, ip
, igmp
) != 0) {
1761 case IGMP_VERSION_3
: {
1762 struct igmpv3
*igmpv3
;
1767 IGMPSTAT_INC(igps_rcv_v3_queries
);
1768 igmpv3
= (struct igmpv3
*)igmp
;
1770 * Validate length based on source count.
1772 nsrc
= ntohs(igmpv3
->igmp_numsrc
);
1774 * The max vaue of nsrc is limited by the
1775 * MTU of the network on which the datagram
1778 if (nsrc
< 0 || nsrc
> IGMP_V3_QUERY_MAX_SRCS
) {
1779 IGMPSTAT_INC(igps_rcv_tooshort
);
1780 OIGMPSTAT_INC(igps_rcv_tooshort
);
1784 srclen
= sizeof(struct in_addr
) * (uint16_t)nsrc
;
1785 if (igmplen
< (IGMP_V3_QUERY_MINLEN
+ srclen
)) {
1786 IGMPSTAT_INC(igps_rcv_tooshort
);
1787 OIGMPSTAT_INC(igps_rcv_tooshort
);
1791 igmpv3len
= IGMP_V3_QUERY_MINLEN
+ srclen
;
1793 * A bit more expensive than M_STRUCT_GET,
1794 * but ensures alignment.
1796 M_STRUCT_GET0(igmpv3
, struct igmpv3
*, m
,
1798 if (igmpv3
== NULL
) {
1799 IGMPSTAT_INC(igps_rcv_tooshort
);
1800 OIGMPSTAT_INC(igps_rcv_tooshort
);
1804 * N.B.: we assume the packet was correctly
1805 * aligned in ip_input.
1807 if (igmp_input_v3_query(ifp
, ip
, igmpv3
) != 0) {
1816 case IGMP_v1_HOST_MEMBERSHIP_REPORT
:
1817 if (!igmp_v1enable
) {
1820 if (igmp_input_v1_report(ifp
, m
, ip
, igmp
) != 0) {
1826 case IGMP_v2_HOST_MEMBERSHIP_REPORT
:
1827 if (!igmp_v2enable
) {
1830 if (!ip_checkrouteralert(m
)) {
1831 IGMPSTAT_INC(igps_rcv_nora
);
1833 if (igmp_input_v2_report(ifp
, m
, ip
, igmp
) != 0) {
1839 case IGMP_v3_HOST_MEMBERSHIP_REPORT
:
1841 * Hosts do not need to process IGMPv3 membership reports,
1842 * as report suppression is no longer required.
1844 if (!ip_checkrouteralert(m
)) {
1845 IGMPSTAT_INC(igps_rcv_nora
);
1853 IGMP_LOCK_ASSERT_NOTHELD();
1855 * Pass all valid IGMP packets up to any process(es) listening on a
1862 * Schedule IGMP timer based on various parameters; caller must ensure that
1863 * lock ordering is maintained as this routine acquires IGMP global lock.
1866 igmp_set_timeout(struct igmp_tparams
*itp
)
1868 IGMP_LOCK_ASSERT_NOTHELD();
1869 VERIFY(itp
!= NULL
);
1871 if (itp
->qpt
!= 0 || itp
->it
!= 0 || itp
->cst
!= 0 || itp
->sct
!= 0) {
1873 if (itp
->qpt
!= 0) {
1874 querier_present_timers_running
= 1;
1877 interface_timers_running
= 1;
1879 if (itp
->cst
!= 0) {
1880 current_state_timers_running
= 1;
1882 if (itp
->sct
!= 0) {
1883 state_change_timers_running
= 1;
1885 igmp_sched_timeout();
1891 * IGMP timer handler (per 1 second).
1894 igmp_timeout(void *arg
)
1897 struct ifqueue scq
; /* State-change packets */
1898 struct ifqueue qrq
; /* Query response packets */
1900 struct igmp_ifinfo
*igi
;
1901 struct in_multi
*inm
;
1902 unsigned int loop
= 0, uri_sec
= 0;
1903 SLIST_HEAD(, in_multi
) inm_dthead
;
1905 SLIST_INIT(&inm_dthead
);
1908 * Update coarse-grained networking timestamp (in sec.); the idea
1909 * is to piggy-back on the timeout callout to update the counter
1910 * returnable via net_uptime().
1912 net_update_uptime();
1916 IGMP_PRINTF(("%s: qpt %d, it %d, cst %d, sct %d\n", __func__
,
1917 querier_present_timers_running
, interface_timers_running
,
1918 current_state_timers_running
, state_change_timers_running
));
1921 * IGMPv1/v2 querier present timer processing.
1923 if (querier_present_timers_running
) {
1924 querier_present_timers_running
= 0;
1925 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
1927 igmp_v1v2_process_querier_timers(igi
);
1928 if (igi
->igi_v1_timer
> 0 || igi
->igi_v2_timer
> 0) {
1929 querier_present_timers_running
= 1;
1936 * IGMPv3 General Query response timer processing.
1938 if (interface_timers_running
) {
1939 IGMP_PRINTF(("%s: interface timers running\n", __func__
));
1940 interface_timers_running
= 0;
1941 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
1943 if (igi
->igi_version
!= IGMP_VERSION_3
) {
1947 if (igi
->igi_v3_timer
== 0) {
1949 } else if (--igi
->igi_v3_timer
== 0) {
1950 if (igmp_v3_dispatch_general_query(igi
) > 0) {
1951 interface_timers_running
= 1;
1954 interface_timers_running
= 1;
1960 if (!current_state_timers_running
&&
1961 !state_change_timers_running
) {
1965 current_state_timers_running
= 0;
1966 state_change_timers_running
= 0;
1968 memset(&qrq
, 0, sizeof(struct ifqueue
));
1969 qrq
.ifq_maxlen
= IGMP_MAX_G_GS_PACKETS
;
1971 memset(&scq
, 0, sizeof(struct ifqueue
));
1972 scq
.ifq_maxlen
= IGMP_MAX_STATE_CHANGE_PACKETS
;
1974 IGMP_PRINTF(("%s: state change timers running\n", __func__
));
1977 * IGMPv1/v2/v3 host report and state-change timer processing.
1978 * Note: Processing a v3 group timer may remove a node.
1980 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
1981 struct in_multistep step
;
1985 loop
= (igi
->igi_flags
& IGIF_LOOPBACK
) ? 1 : 0;
1986 uri_sec
= IGMP_RANDOM_DELAY(igi
->igi_uri
);
1989 in_multihead_lock_shared();
1990 IN_FIRST_MULTI(step
, inm
);
1991 while (inm
!= NULL
) {
1993 if (inm
->inm_ifp
!= ifp
) {
1998 switch (igi
->igi_version
) {
1999 case IGMP_VERSION_1
:
2000 case IGMP_VERSION_2
:
2001 igmp_v1v2_process_group_timer(inm
,
2004 case IGMP_VERSION_3
:
2005 igmp_v3_process_group_timers(igi
, &qrq
,
2006 &scq
, inm
, uri_sec
);
2012 IN_NEXT_MULTI(step
, inm
);
2014 in_multihead_lock_done();
2017 if (igi
->igi_version
== IGMP_VERSION_1
||
2018 igi
->igi_version
== IGMP_VERSION_2
) {
2019 igmp_dispatch_queue(igi
, &igi
->igi_v2q
, 0, loop
);
2020 } else if (igi
->igi_version
== IGMP_VERSION_3
) {
2022 igmp_dispatch_queue(NULL
, &qrq
, 0, loop
);
2023 igmp_dispatch_queue(NULL
, &scq
, 0, loop
);
2024 VERIFY(qrq
.ifq_len
== 0);
2025 VERIFY(scq
.ifq_len
== 0);
2029 * In case there are still any pending membership reports
2030 * which didn't get drained at version change time.
2032 IF_DRAIN(&igi
->igi_v2q
);
2034 * Release all deferred inm records, and drain any locally
2035 * enqueued packets; do it even if the current IGMP version
2036 * for the link is no longer IGMPv3, in order to handle the
2037 * version change case.
2039 igmp_flush_relq(igi
, (struct igmp_inm_relhead
*)&inm_dthead
);
2040 VERIFY(SLIST_EMPTY(&igi
->igi_relinmhead
));
2048 /* re-arm the timer if there's work to do */
2049 igmp_timeout_run
= 0;
2050 igmp_sched_timeout();
2053 /* Now that we're dropped all locks, release detached records */
2054 IGMP_REMOVE_DETACHED_INM(&inm_dthead
);
2058 igmp_sched_timeout(void)
2060 IGMP_LOCK_ASSERT_HELD();
2062 if (!igmp_timeout_run
&&
2063 (querier_present_timers_running
|| current_state_timers_running
||
2064 interface_timers_running
|| state_change_timers_running
)) {
2065 igmp_timeout_run
= 1;
2066 timeout(igmp_timeout
, NULL
, hz
);
2071 * Free the in_multi reference(s) for this IGMP lifecycle.
2073 * Caller must be holding igi_lock.
2076 igmp_flush_relq(struct igmp_ifinfo
*igi
, struct igmp_inm_relhead
*inm_dthead
)
2078 struct in_multi
*inm
;
2081 IGI_LOCK_ASSERT_HELD(igi
);
2082 inm
= SLIST_FIRST(&igi
->igi_relinmhead
);
2086 SLIST_REMOVE_HEAD(&igi
->igi_relinmhead
, inm_nrele
);
2089 in_multihead_lock_exclusive();
2091 VERIFY(inm
->inm_nrelecnt
!= 0);
2092 inm
->inm_nrelecnt
--;
2093 lastref
= in_multi_detach(inm
);
2094 VERIFY(!lastref
|| (!(inm
->inm_debug
& IFD_ATTACHED
) &&
2095 inm
->inm_reqcnt
== 0));
2097 in_multihead_lock_done();
2098 /* from igi_relinmhead */
2100 /* from in_multihead list */
2103 * Defer releasing our final reference, as we
2104 * are holding the IGMP lock at this point, and
2105 * we could end up with locking issues later on
2106 * (while issuing SIOCDELMULTI) when this is the
2107 * final reference count. Let the caller do it
2110 IGMP_ADD_DETACHED_INM(inm_dthead
, inm
);
2118 * Update host report group timer for IGMPv1/v2.
2119 * Will update the global pending timer flags.
2122 igmp_v1v2_process_group_timer(struct in_multi
*inm
, const int igmp_version
)
2124 int report_timer_expired
;
2126 IGMP_LOCK_ASSERT_HELD();
2127 INM_LOCK_ASSERT_HELD(inm
);
2128 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2130 if (inm
->inm_timer
== 0) {
2131 report_timer_expired
= 0;
2132 } else if (--inm
->inm_timer
== 0) {
2133 report_timer_expired
= 1;
2135 current_state_timers_running
= 1;
2136 /* caller will schedule timer */
2140 switch (inm
->inm_state
) {
2141 case IGMP_NOT_MEMBER
:
2142 case IGMP_SILENT_MEMBER
:
2143 case IGMP_IDLE_MEMBER
:
2144 case IGMP_LAZY_MEMBER
:
2145 case IGMP_SLEEPING_MEMBER
:
2146 case IGMP_AWAKENING_MEMBER
:
2148 case IGMP_REPORTING_MEMBER
:
2149 if (report_timer_expired
) {
2150 inm
->inm_state
= IGMP_IDLE_MEMBER
;
2151 (void) igmp_v1v2_queue_report(inm
,
2152 (igmp_version
== IGMP_VERSION_2
) ?
2153 IGMP_v2_HOST_MEMBERSHIP_REPORT
:
2154 IGMP_v1_HOST_MEMBERSHIP_REPORT
);
2155 INM_LOCK_ASSERT_HELD(inm
);
2156 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2159 case IGMP_G_QUERY_PENDING_MEMBER
:
2160 case IGMP_SG_QUERY_PENDING_MEMBER
:
2161 case IGMP_LEAVING_MEMBER
:
2167 * Update a group's timers for IGMPv3.
2168 * Will update the global pending timer flags.
2169 * Note: Unlocked read from igi.
2172 igmp_v3_process_group_timers(struct igmp_ifinfo
*igi
,
2173 struct ifqueue
*qrq
, struct ifqueue
*scq
,
2174 struct in_multi
*inm
, const unsigned int uri_sec
)
2176 int query_response_timer_expired
;
2177 int state_change_retransmit_timer_expired
;
2179 IGMP_LOCK_ASSERT_HELD();
2180 INM_LOCK_ASSERT_HELD(inm
);
2181 IGI_LOCK_ASSERT_HELD(igi
);
2182 VERIFY(igi
== inm
->inm_igi
);
2184 query_response_timer_expired
= 0;
2185 state_change_retransmit_timer_expired
= 0;
2188 * During a transition from v1/v2 compatibility mode back to v3,
2189 * a group record in REPORTING state may still have its group
2190 * timer active. This is a no-op in this function; it is easier
2191 * to deal with it here than to complicate the timeout path.
2193 if (inm
->inm_timer
== 0) {
2194 query_response_timer_expired
= 0;
2195 } else if (--inm
->inm_timer
== 0) {
2196 query_response_timer_expired
= 1;
2198 current_state_timers_running
= 1;
2199 /* caller will schedule timer */
2202 if (inm
->inm_sctimer
== 0) {
2203 state_change_retransmit_timer_expired
= 0;
2204 } else if (--inm
->inm_sctimer
== 0) {
2205 state_change_retransmit_timer_expired
= 1;
2207 state_change_timers_running
= 1;
2208 /* caller will schedule timer */
2211 /* We are in timer callback, so be quick about it. */
2212 if (!state_change_retransmit_timer_expired
&&
2213 !query_response_timer_expired
) {
2217 switch (inm
->inm_state
) {
2218 case IGMP_NOT_MEMBER
:
2219 case IGMP_SILENT_MEMBER
:
2220 case IGMP_SLEEPING_MEMBER
:
2221 case IGMP_LAZY_MEMBER
:
2222 case IGMP_AWAKENING_MEMBER
:
2223 case IGMP_IDLE_MEMBER
:
2225 case IGMP_G_QUERY_PENDING_MEMBER
:
2226 case IGMP_SG_QUERY_PENDING_MEMBER
:
2228 * Respond to a previously pending Group-Specific
2229 * or Group-and-Source-Specific query by enqueueing
2230 * the appropriate Current-State report for
2231 * immediate transmission.
2233 if (query_response_timer_expired
) {
2236 retval
= igmp_v3_enqueue_group_record(qrq
, inm
, 0, 1,
2237 (inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
));
2238 IGMP_PRINTF(("%s: enqueue record = %d\n",
2240 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2241 /* XXX Clear recorded sources for next time. */
2242 inm_clear_recorded(inm
);
2245 case IGMP_REPORTING_MEMBER
:
2246 case IGMP_LEAVING_MEMBER
:
2247 if (state_change_retransmit_timer_expired
) {
2249 * State-change retransmission timer fired.
2250 * If there are any further pending retransmissions,
2251 * set the global pending state-change flag, and
2254 if (--inm
->inm_scrv
> 0) {
2255 inm
->inm_sctimer
= (uint16_t)uri_sec
;
2256 state_change_timers_running
= 1;
2257 /* caller will schedule timer */
2260 * Retransmit the previously computed state-change
2261 * report. If there are no further pending
2262 * retransmissions, the mbuf queue will be consumed.
2263 * Update T0 state to T1 as we have now sent
2266 (void) igmp_v3_merge_state_changes(inm
, scq
);
2269 IGMP_INET_PRINTF(inm
->inm_addr
,
2270 ("%s: T1 -> T0 for %s/%s\n", __func__
,
2271 _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
2274 * If we are leaving the group for good, make sure
2275 * we release IGMP's reference to it.
2276 * This release must be deferred using a SLIST,
2277 * as we are called from a loop which traverses
2278 * the in_multihead list.
2280 if (inm
->inm_state
== IGMP_LEAVING_MEMBER
&&
2281 inm
->inm_scrv
== 0) {
2282 inm
->inm_state
= IGMP_NOT_MEMBER
;
2284 * A reference has already been held in
2285 * igmp_final_leave() for this inm, so
2286 * no need to hold another one. We also
2287 * bumped up its request count then, so
2288 * that it stays in in_multihead. Both
2289 * of them will be released when it is
2290 * dequeued later on.
2292 VERIFY(inm
->inm_nrelecnt
!= 0);
2293 SLIST_INSERT_HEAD(&igi
->igi_relinmhead
,
2302 * Suppress a group's pending response to a group or source/group query.
2304 * Do NOT suppress state changes. This leads to IGMPv3 inconsistency.
2305 * Do NOT update ST1/ST0 as this operation merely suppresses
2306 * the currently pending group record.
2307 * Do NOT suppress the response to a general query. It is possible but
2308 * it would require adding another state or flag.
2311 igmp_v3_suppress_group_record(struct in_multi
*inm
)
2313 INM_LOCK_ASSERT_HELD(inm
);
2314 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2316 VERIFY(inm
->inm_igi
->igi_version
== IGMP_VERSION_3
);
2318 if (inm
->inm_state
!= IGMP_G_QUERY_PENDING_MEMBER
||
2319 inm
->inm_state
!= IGMP_SG_QUERY_PENDING_MEMBER
) {
2323 if (inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
) {
2324 inm_clear_recorded(inm
);
2328 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2332 * Switch to a different IGMP version on the given interface,
2333 * as per Section 7.2.1.
2336 igmp_set_version(struct igmp_ifinfo
*igi
, const int igmp_version
)
2338 int old_version_timer
;
2340 IGI_LOCK_ASSERT_HELD(igi
);
2342 IGMP_PRINTF(("%s: switching to v%d on ifp 0x%llx(%s)\n", __func__
,
2343 igmp_version
, (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2344 if_name(igi
->igi_ifp
)));
2346 if (igmp_version
== IGMP_VERSION_1
|| igmp_version
== IGMP_VERSION_2
) {
2348 * Compute the "Older Version Querier Present" timer as per
2349 * Section 8.12, in seconds.
2351 old_version_timer
= igi
->igi_rv
* igi
->igi_qi
+ igi
->igi_qri
;
2353 if (igmp_version
== IGMP_VERSION_1
) {
2354 igi
->igi_v1_timer
= old_version_timer
;
2355 igi
->igi_v2_timer
= 0;
2356 } else if (igmp_version
== IGMP_VERSION_2
) {
2357 igi
->igi_v1_timer
= 0;
2358 igi
->igi_v2_timer
= old_version_timer
;
2362 if (igi
->igi_v1_timer
== 0 && igi
->igi_v2_timer
> 0) {
2363 if (igi
->igi_version
!= IGMP_VERSION_2
) {
2364 igi
->igi_version
= IGMP_VERSION_2
;
2365 igmp_v3_cancel_link_timers(igi
);
2367 } else if (igi
->igi_v1_timer
> 0) {
2368 if (igi
->igi_version
!= IGMP_VERSION_1
) {
2369 igi
->igi_version
= IGMP_VERSION_1
;
2370 igmp_v3_cancel_link_timers(igi
);
2374 IGI_LOCK_ASSERT_HELD(igi
);
2376 return MAX(igi
->igi_v1_timer
, igi
->igi_v2_timer
);
2380 * Cancel pending IGMPv3 timers for the given link and all groups
2381 * joined on it; state-change, general-query, and group-query timers.
2383 * Only ever called on a transition from v3 to Compatibility mode. Kill
2384 * the timers stone dead (this may be expensive for large N groups), they
2385 * will be restarted if Compatibility Mode deems that they must be due to
2389 igmp_v3_cancel_link_timers(struct igmp_ifinfo
*igi
)
2392 struct in_multi
*inm
;
2393 struct in_multistep step
;
2395 IGI_LOCK_ASSERT_HELD(igi
);
2397 IGMP_PRINTF(("%s: cancel v3 timers on ifp 0x%llx(%s)\n", __func__
,
2398 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
), if_name(igi
->igi_ifp
)));
2401 * Stop the v3 General Query Response on this link stone dead.
2402 * If timer is woken up due to interface_timers_running,
2403 * the flag will be cleared if there are no pending link timers.
2405 igi
->igi_v3_timer
= 0;
2408 * Now clear the current-state and state-change report timers
2409 * for all memberships scoped to this link.
2414 in_multihead_lock_shared();
2415 IN_FIRST_MULTI(step
, inm
);
2416 while (inm
!= NULL
) {
2418 if (inm
->inm_ifp
!= ifp
) {
2422 switch (inm
->inm_state
) {
2423 case IGMP_NOT_MEMBER
:
2424 case IGMP_SILENT_MEMBER
:
2425 case IGMP_IDLE_MEMBER
:
2426 case IGMP_LAZY_MEMBER
:
2427 case IGMP_SLEEPING_MEMBER
:
2428 case IGMP_AWAKENING_MEMBER
:
2430 * These states are either not relevant in v3 mode,
2431 * or are unreported. Do nothing.
2434 case IGMP_LEAVING_MEMBER
:
2436 * If we are leaving the group and switching to
2437 * compatibility mode, we need to release the final
2438 * reference held for issuing the INCLUDE {}, and
2439 * transition to REPORTING to ensure the host leave
2440 * message is sent upstream to the old querier --
2441 * transition to NOT would lose the leave and race.
2442 * During igmp_final_leave(), we bumped up both the
2443 * request and reference counts. Since we cannot
2444 * call in_multi_detach() here, defer this task to
2445 * the timer routine.
2447 VERIFY(inm
->inm_nrelecnt
!= 0);
2449 SLIST_INSERT_HEAD(&igi
->igi_relinmhead
, inm
, inm_nrele
);
2452 case IGMP_G_QUERY_PENDING_MEMBER
:
2453 case IGMP_SG_QUERY_PENDING_MEMBER
:
2454 inm_clear_recorded(inm
);
2456 case IGMP_REPORTING_MEMBER
:
2457 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2461 * Always clear state-change and group report timers.
2462 * Free any pending IGMPv3 state-change records.
2464 inm
->inm_sctimer
= 0;
2466 IF_DRAIN(&inm
->inm_scq
);
2469 IN_NEXT_MULTI(step
, inm
);
2471 in_multihead_lock_done();
2477 * Update the Older Version Querier Present timers for a link.
2478 * See Section 7.2.1 of RFC 3376.
2481 igmp_v1v2_process_querier_timers(struct igmp_ifinfo
*igi
)
2483 IGI_LOCK_ASSERT_HELD(igi
);
2485 if (igi
->igi_v1_timer
== 0 && igi
->igi_v2_timer
== 0) {
2487 * IGMPv1 and IGMPv2 Querier Present timers expired.
2491 if (igi
->igi_version
!= IGMP_VERSION_3
) {
2492 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2493 "on 0x%llx(%s)\n", __func__
,
2494 igi
->igi_version
, IGMP_VERSION_3
,
2495 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2496 if_name(igi
->igi_ifp
)));
2497 igi
->igi_version
= IGMP_VERSION_3
;
2498 IF_DRAIN(&igi
->igi_v2q
);
2500 } else if (igi
->igi_v1_timer
== 0 && igi
->igi_v2_timer
> 0) {
2502 * IGMPv1 Querier Present timer expired,
2503 * IGMPv2 Querier Present timer running.
2504 * If IGMPv2 was disabled since last timeout,
2506 * If IGMPv2 is enabled, revert to IGMPv2.
2508 if (!igmp_v2enable
) {
2509 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2510 "on 0x%llx(%s%d)\n", __func__
,
2511 igi
->igi_version
, IGMP_VERSION_3
,
2512 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2513 igi
->igi_ifp
->if_name
, igi
->igi_ifp
->if_unit
));
2514 igi
->igi_v2_timer
= 0;
2515 igi
->igi_version
= IGMP_VERSION_3
;
2516 IF_DRAIN(&igi
->igi_v2q
);
2518 --igi
->igi_v2_timer
;
2519 if (igi
->igi_version
!= IGMP_VERSION_2
) {
2520 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2521 "on 0x%llx(%s)\n", __func__
,
2522 igi
->igi_version
, IGMP_VERSION_2
,
2523 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2524 if_name(igi
->igi_ifp
)));
2525 igi
->igi_version
= IGMP_VERSION_2
;
2526 IF_DRAIN(&igi
->igi_gq
);
2527 igmp_v3_cancel_link_timers(igi
);
2530 } else if (igi
->igi_v1_timer
> 0) {
2532 * IGMPv1 Querier Present timer running.
2533 * Stop IGMPv2 timer if running.
2535 * If IGMPv1 was disabled since last timeout,
2537 * If IGMPv1 is enabled, reset IGMPv2 timer if running.
2539 if (!igmp_v1enable
) {
2540 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2541 "on 0x%llx(%s%d)\n", __func__
,
2542 igi
->igi_version
, IGMP_VERSION_3
,
2543 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2544 igi
->igi_ifp
->if_name
, igi
->igi_ifp
->if_unit
));
2545 igi
->igi_v1_timer
= 0;
2546 igi
->igi_version
= IGMP_VERSION_3
;
2547 IF_DRAIN(&igi
->igi_v2q
);
2549 --igi
->igi_v1_timer
;
2551 if (igi
->igi_v2_timer
> 0) {
2552 IGMP_PRINTF(("%s: cancel v2 timer on 0x%llx(%s%d)\n",
2554 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2555 igi
->igi_ifp
->if_name
, igi
->igi_ifp
->if_unit
));
2556 igi
->igi_v2_timer
= 0;
2562 * Dispatch an IGMPv1/v2 host report or leave message.
2563 * These are always small enough to fit inside a single mbuf.
2566 igmp_v1v2_queue_report(struct in_multi
*inm
, const int type
)
2574 INM_LOCK_ASSERT_HELD(inm
);
2575 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2579 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
2583 MH_ALIGN(m
, sizeof(struct ip
) + sizeof(struct igmp
));
2585 m
->m_pkthdr
.len
= sizeof(struct ip
) + sizeof(struct igmp
);
2587 m
->m_data
+= sizeof(struct ip
);
2588 m
->m_len
= sizeof(struct igmp
);
2590 igmp
= mtod(m
, struct igmp
*);
2591 igmp
->igmp_type
= (u_char
)type
;
2592 igmp
->igmp_code
= 0;
2593 igmp
->igmp_group
= inm
->inm_addr
;
2594 igmp
->igmp_cksum
= 0;
2595 igmp
->igmp_cksum
= in_cksum(m
, sizeof(struct igmp
));
2597 m
->m_data
-= sizeof(struct ip
);
2598 m
->m_len
+= sizeof(struct ip
);
2600 ip
= mtod(m
, struct ip
*);
2602 ip
->ip_len
= sizeof(struct ip
) + sizeof(struct igmp
);
2604 ip
->ip_p
= IPPROTO_IGMP
;
2605 ip
->ip_src
.s_addr
= INADDR_ANY
;
2607 if (type
== IGMP_HOST_LEAVE_MESSAGE
) {
2608 ip
->ip_dst
.s_addr
= htonl(INADDR_ALLRTRS_GROUP
);
2610 ip
->ip_dst
= inm
->inm_addr
;
2613 igmp_save_context(m
, ifp
);
2615 m
->m_flags
|= M_IGMPV2
;
2616 if (inm
->inm_igi
->igi_flags
& IGIF_LOOPBACK
) {
2617 m
->m_flags
|= M_IGMP_LOOP
;
2621 * Due to the fact that at this point we are possibly holding
2622 * in_multihead_lock in shared or exclusive mode, we can't call
2623 * igmp_sendpkt() here since that will eventually call ip_output(),
2624 * which will try to lock in_multihead_lock and cause a deadlock.
2625 * Instead we defer the work to the igmp_timeout() thread, thus
2626 * avoiding unlocking in_multihead_lock here.
2628 if (IF_QFULL(&inm
->inm_igi
->igi_v2q
)) {
2629 IGMP_PRINTF(("%s: v1/v2 outbound queue full\n", __func__
));
2633 IF_ENQUEUE(&inm
->inm_igi
->igi_v2q
, m
);
2640 * Process a state change from the upper layer for the given IPv4 group.
2642 * Each socket holds a reference on the in_multi in its own ip_moptions.
2643 * The socket layer will have made the necessary updates to the group
2644 * state, it is now up to IGMP to issue a state change report if there
2645 * has been any change between T0 (when the last state-change was issued)
2648 * We use the IGMPv3 state machine at group level. The IGMP module
2649 * however makes the decision as to which IGMP protocol version to speak.
2650 * A state change *from* INCLUDE {} always means an initial join.
2651 * A state change *to* INCLUDE {} always means a final leave.
2653 * FUTURE: If IGIF_V3LITE is enabled for this interface, then we can
2654 * save ourselves a bunch of work; any exclusive mode groups need not
2655 * compute source filter lists.
2658 igmp_change_state(struct in_multi
*inm
, struct igmp_tparams
*itp
)
2660 struct igmp_ifinfo
*igi
;
2664 VERIFY(itp
!= NULL
);
2665 bzero(itp
, sizeof(*itp
));
2667 INM_LOCK_ASSERT_HELD(inm
);
2668 VERIFY(inm
->inm_igi
!= NULL
);
2669 IGI_LOCK_ASSERT_NOTHELD(inm
->inm_igi
);
2672 * Try to detect if the upper layer just asked us to change state
2673 * for an interface which has now gone away.
2675 VERIFY(inm
->inm_ifma
!= NULL
);
2676 ifp
= inm
->inm_ifma
->ifma_ifp
;
2678 * Sanity check that netinet's notion of ifp is the same as net's.
2680 VERIFY(inm
->inm_ifp
== ifp
);
2682 igi
= IGMP_IFINFO(ifp
);
2683 VERIFY(igi
!= NULL
);
2686 * If we detect a state transition to or from MCAST_UNDEFINED
2687 * for this group, then we are starting or finishing an IGMP
2688 * life cycle for this group.
2690 if (inm
->inm_st
[1].iss_fmode
!= inm
->inm_st
[0].iss_fmode
) {
2691 IGMP_PRINTF(("%s: inm transition %d -> %d\n", __func__
,
2692 inm
->inm_st
[0].iss_fmode
, inm
->inm_st
[1].iss_fmode
));
2693 if (inm
->inm_st
[0].iss_fmode
== MCAST_UNDEFINED
) {
2694 IGMP_PRINTF(("%s: initial join\n", __func__
));
2695 error
= igmp_initial_join(inm
, igi
, itp
);
2697 } else if (inm
->inm_st
[1].iss_fmode
== MCAST_UNDEFINED
) {
2698 IGMP_PRINTF(("%s: final leave\n", __func__
));
2699 igmp_final_leave(inm
, igi
, itp
);
2703 IGMP_PRINTF(("%s: filter set change\n", __func__
));
2706 error
= igmp_handle_state_change(inm
, igi
, itp
);
2712 * Perform the initial join for an IGMP group.
2714 * When joining a group:
2715 * If the group should have its IGMP traffic suppressed, do nothing.
2716 * IGMPv1 starts sending IGMPv1 host membership reports.
2717 * IGMPv2 starts sending IGMPv2 host membership reports.
2718 * IGMPv3 will schedule an IGMPv3 state-change report containing the
2719 * initial state of the membership.
2722 igmp_initial_join(struct in_multi
*inm
, struct igmp_ifinfo
*igi
,
2723 struct igmp_tparams
*itp
)
2726 struct ifqueue
*ifq
;
2727 int error
, retval
, syncstates
;
2729 INM_LOCK_ASSERT_HELD(inm
);
2730 IGI_LOCK_ASSERT_NOTHELD(igi
);
2731 VERIFY(itp
!= NULL
);
2733 IGMP_INET_PRINTF(inm
->inm_addr
,
2734 ("%s: initial join %s on ifp 0x%llx(%s)\n", __func__
,
2735 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
),
2736 if_name(inm
->inm_ifp
)));
2744 VERIFY(igi
->igi_ifp
== ifp
);
2747 * Groups joined on loopback or marked as 'not reported',
2748 * e.g. 224.0.0.1, enter the IGMP_SILENT_MEMBER state and
2749 * are never reported in any IGMP protocol exchanges.
2750 * All other groups enter the appropriate IGMP state machine
2751 * for the version in use on this link.
2752 * A link marked as IGIF_SILENT causes IGMP to be completely
2753 * disabled for the link.
2755 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
2756 (igi
->igi_flags
& IGIF_SILENT
) ||
2757 !igmp_isgroupreported(inm
->inm_addr
)) {
2758 IGMP_PRINTF(("%s: not kicking state machine for silent group\n",
2760 inm
->inm_state
= IGMP_SILENT_MEMBER
;
2764 * Deal with overlapping in_multi lifecycle.
2765 * If this group was LEAVING, then make sure
2766 * we drop the reference we picked up to keep the
2767 * group around for the final INCLUDE {} enqueue.
2768 * Since we cannot call in_multi_detach() here,
2769 * defer this task to the timer routine.
2771 if (igi
->igi_version
== IGMP_VERSION_3
&&
2772 inm
->inm_state
== IGMP_LEAVING_MEMBER
) {
2773 VERIFY(inm
->inm_nrelecnt
!= 0);
2774 SLIST_INSERT_HEAD(&igi
->igi_relinmhead
, inm
, inm_nrele
);
2777 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2779 switch (igi
->igi_version
) {
2780 case IGMP_VERSION_1
:
2781 case IGMP_VERSION_2
:
2782 inm
->inm_state
= IGMP_IDLE_MEMBER
;
2783 error
= igmp_v1v2_queue_report(inm
,
2784 (igi
->igi_version
== IGMP_VERSION_2
) ?
2785 IGMP_v2_HOST_MEMBERSHIP_REPORT
:
2786 IGMP_v1_HOST_MEMBERSHIP_REPORT
);
2788 INM_LOCK_ASSERT_HELD(inm
);
2789 IGI_LOCK_ASSERT_HELD(igi
);
2793 IGMP_RANDOM_DELAY(IGMP_V1V2_MAX_RI
);
2798 case IGMP_VERSION_3
:
2800 * Defer update of T0 to T1, until the first copy
2801 * of the state change has been transmitted.
2806 * Immediately enqueue a State-Change Report for
2807 * this interface, freeing any previous reports.
2808 * Don't kick the timers if there is nothing to do,
2809 * or if an error occurred.
2811 ifq
= &inm
->inm_scq
;
2813 retval
= igmp_v3_enqueue_group_record(ifq
, inm
, 1,
2815 itp
->cst
= (ifq
->ifq_len
> 0);
2816 IGMP_PRINTF(("%s: enqueue record = %d\n",
2819 error
= retval
* -1;
2824 * Schedule transmission of pending state-change
2825 * report up to RV times for this link. The timer
2826 * will fire at the next igmp_timeout (1 second),
2827 * giving us an opportunity to merge the reports.
2829 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
2832 VERIFY(igi
->igi_rv
> 1);
2833 inm
->inm_scrv
= (uint16_t)igi
->igi_rv
;
2835 inm
->inm_sctimer
= 1;
2845 * Only update the T0 state if state change is atomic,
2846 * i.e. we don't need to wait for a timer to fire before we
2847 * can consider the state change to have been communicated.
2851 IGMP_INET_PRINTF(inm
->inm_addr
,
2852 ("%s: T1 -> T0 for %s/%s\n", __func__
,
2853 _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
2860 * Issue an intermediate state change during the IGMP life-cycle.
2863 igmp_handle_state_change(struct in_multi
*inm
, struct igmp_ifinfo
*igi
,
2864 struct igmp_tparams
*itp
)
2869 INM_LOCK_ASSERT_HELD(inm
);
2870 IGI_LOCK_ASSERT_NOTHELD(igi
);
2871 VERIFY(itp
!= NULL
);
2873 IGMP_INET_PRINTF(inm
->inm_addr
,
2874 ("%s: state change for %s on ifp 0x%llx(%s)\n", __func__
,
2875 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
),
2876 if_name(inm
->inm_ifp
)));
2881 VERIFY(igi
->igi_ifp
== ifp
);
2883 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
2884 (igi
->igi_flags
& IGIF_SILENT
) ||
2885 !igmp_isgroupreported(inm
->inm_addr
) ||
2886 (igi
->igi_version
!= IGMP_VERSION_3
)) {
2888 if (!igmp_isgroupreported(inm
->inm_addr
)) {
2889 IGMP_PRINTF(("%s: not kicking state "
2890 "machine for silent group\n", __func__
));
2892 IGMP_PRINTF(("%s: nothing to do\n", __func__
));
2894 IGMP_INET_PRINTF(inm
->inm_addr
,
2895 ("%s: T1 -> T0 for %s/%s\n", __func__
,
2896 _igmp_inet_buf
, inm
->inm_ifp
->if_name
));
2900 IF_DRAIN(&inm
->inm_scq
);
2902 retval
= igmp_v3_enqueue_group_record(&inm
->inm_scq
, inm
, 1, 0, 0);
2903 itp
->cst
= (inm
->inm_scq
.ifq_len
> 0);
2904 IGMP_PRINTF(("%s: enqueue record = %d\n", __func__
, retval
));
2911 * If record(s) were enqueued, start the state-change
2912 * report timer for this group.
2914 inm
->inm_scrv
= ((igi
->igi_flags
& IGIF_LOOPBACK
) ? 1 : (uint16_t)igi
->igi_rv
);
2915 inm
->inm_sctimer
= 1;
2923 * Perform the final leave for an IGMP group.
2925 * When leaving a group:
2926 * IGMPv1 does nothing.
2927 * IGMPv2 sends a host leave message, if and only if we are the reporter.
2928 * IGMPv3 enqueues a state-change report containing a transition
2929 * to INCLUDE {} for immediate transmission.
2932 igmp_final_leave(struct in_multi
*inm
, struct igmp_ifinfo
*igi
,
2933 struct igmp_tparams
*itp
)
2937 INM_LOCK_ASSERT_HELD(inm
);
2938 IGI_LOCK_ASSERT_NOTHELD(igi
);
2939 VERIFY(itp
!= NULL
);
2941 IGMP_INET_PRINTF(inm
->inm_addr
,
2942 ("%s: final leave %s on ifp 0x%llx(%s)\n", __func__
,
2943 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
),
2944 if_name(inm
->inm_ifp
)));
2946 switch (inm
->inm_state
) {
2947 case IGMP_NOT_MEMBER
:
2948 case IGMP_SILENT_MEMBER
:
2949 case IGMP_LEAVING_MEMBER
:
2950 /* Already leaving or left; do nothing. */
2951 IGMP_PRINTF(("%s: not kicking state machine for silent group\n",
2954 case IGMP_REPORTING_MEMBER
:
2955 case IGMP_IDLE_MEMBER
:
2956 case IGMP_G_QUERY_PENDING_MEMBER
:
2957 case IGMP_SG_QUERY_PENDING_MEMBER
:
2959 if (igi
->igi_version
== IGMP_VERSION_2
) {
2960 if (inm
->inm_state
== IGMP_G_QUERY_PENDING_MEMBER
||
2961 inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
) {
2962 panic("%s: IGMPv3 state reached, not IGMPv3 "
2963 "mode\n", __func__
);
2966 /* scheduler timer if enqueue is successful */
2967 itp
->cst
= (igmp_v1v2_queue_report(inm
,
2968 IGMP_HOST_LEAVE_MESSAGE
) == 0);
2970 INM_LOCK_ASSERT_HELD(inm
);
2971 IGI_LOCK_ASSERT_HELD(igi
);
2973 inm
->inm_state
= IGMP_NOT_MEMBER
;
2974 } else if (igi
->igi_version
== IGMP_VERSION_3
) {
2976 * Stop group timer and all pending reports.
2977 * Immediately enqueue a state-change report
2978 * TO_IN {} to be sent on the next timeout,
2979 * giving us an opportunity to merge reports.
2981 IF_DRAIN(&inm
->inm_scq
);
2983 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
2986 inm
->inm_scrv
= (uint16_t)igi
->igi_rv
;
2988 IGMP_INET_PRINTF(inm
->inm_addr
,
2989 ("%s: Leaving %s/%s with %d "
2990 "pending retransmissions.\n", __func__
,
2991 _igmp_inet_buf
, if_name(inm
->inm_ifp
),
2993 if (inm
->inm_scrv
== 0) {
2994 inm
->inm_state
= IGMP_NOT_MEMBER
;
2995 inm
->inm_sctimer
= 0;
2999 * Stick around in the in_multihead list;
3000 * the final detach will be issued by
3001 * igmp_v3_process_group_timers() when
3002 * the retransmit timer expires.
3004 INM_ADDREF_LOCKED(inm
);
3005 VERIFY(inm
->inm_debug
& IFD_ATTACHED
);
3007 VERIFY(inm
->inm_reqcnt
>= 1);
3008 inm
->inm_nrelecnt
++;
3009 VERIFY(inm
->inm_nrelecnt
!= 0);
3011 retval
= igmp_v3_enqueue_group_record(
3012 &inm
->inm_scq
, inm
, 1, 0, 0);
3013 itp
->cst
= (inm
->inm_scq
.ifq_len
> 0);
3014 KASSERT(retval
!= 0,
3015 ("%s: enqueue record = %d\n", __func__
,
3018 inm
->inm_state
= IGMP_LEAVING_MEMBER
;
3019 inm
->inm_sctimer
= 1;
3026 case IGMP_LAZY_MEMBER
:
3027 case IGMP_SLEEPING_MEMBER
:
3028 case IGMP_AWAKENING_MEMBER
:
3029 /* Our reports are suppressed; do nothing. */
3035 IGMP_INET_PRINTF(inm
->inm_addr
,
3036 ("%s: T1 -> T0 for %s/%s\n", __func__
,
3037 _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
3038 inm
->inm_st
[1].iss_fmode
= MCAST_UNDEFINED
;
3039 IGMP_INET_PRINTF(inm
->inm_addr
,
3040 ("%s: T1 now MCAST_UNDEFINED for %s/%s\n",
3041 __func__
, _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
3046 * Enqueue an IGMPv3 group record to the given output queue.
3048 * XXX This function could do with having the allocation code
3049 * split out, and the multiple-tree-walks coalesced into a single
3050 * routine as has been done in igmp_v3_enqueue_filter_change().
3052 * If is_state_change is zero, a current-state record is appended.
3053 * If is_state_change is non-zero, a state-change report is appended.
3055 * If is_group_query is non-zero, an mbuf packet chain is allocated.
3056 * If is_group_query is zero, and if there is a packet with free space
3057 * at the tail of the queue, it will be appended to providing there
3058 * is enough free space.
3059 * Otherwise a new mbuf packet chain is allocated.
3061 * If is_source_query is non-zero, each source is checked to see if
3062 * it was recorded for a Group-Source query, and will be omitted if
3063 * it is not both in-mode and recorded.
3065 * The function will attempt to allocate leading space in the packet
3066 * for the IP/IGMP header to be prepended without fragmenting the chain.
3068 * If successful the size of all data appended to the queue is returned,
3069 * otherwise an error code less than zero is returned, or zero if
3070 * no record(s) were appended.
3073 igmp_v3_enqueue_group_record(struct ifqueue
*ifq
, struct in_multi
*inm
,
3074 const int is_state_change
, const int is_group_query
,
3075 const int is_source_query
)
3077 struct igmp_grouprec ig
;
3078 struct igmp_grouprec
*pig
;
3080 struct ip_msource
*ims
, *nims
;
3081 struct mbuf
*m0
, *m
, *md
;
3082 int error
, is_filter_list_change
;
3083 int minrec0len
, m0srcs
, nbytes
, off
;
3085 int record_has_sources
;
3090 u_int16_t ig_numsrc
;
3092 INM_LOCK_ASSERT_HELD(inm
);
3093 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
3097 is_filter_list_change
= 0;
3104 record_has_sources
= 1;
3106 type
= IGMP_DO_NOTHING
;
3107 mode
= inm
->inm_st
[1].iss_fmode
;
3110 * If we did not transition out of ASM mode during t0->t1,
3111 * and there are no source nodes to process, we can skip
3112 * the generation of source records.
3114 if (inm
->inm_st
[0].iss_asm
> 0 && inm
->inm_st
[1].iss_asm
> 0 &&
3115 inm
->inm_nsrc
== 0) {
3116 record_has_sources
= 0;
3119 if (is_state_change
) {
3121 * Queue a state change record.
3122 * If the mode did not change, and there are non-ASM
3123 * listeners or source filters present,
3124 * we potentially need to issue two records for the group.
3125 * If we are transitioning to MCAST_UNDEFINED, we need
3126 * not send any sources.
3127 * If there are ASM listeners, and there was no filter
3128 * mode transition of any kind, do nothing.
3130 if (mode
!= inm
->inm_st
[0].iss_fmode
) {
3131 if (mode
== MCAST_EXCLUDE
) {
3132 IGMP_PRINTF(("%s: change to EXCLUDE\n",
3134 type
= IGMP_CHANGE_TO_EXCLUDE_MODE
;
3136 IGMP_PRINTF(("%s: change to INCLUDE\n",
3138 type
= IGMP_CHANGE_TO_INCLUDE_MODE
;
3139 if (mode
== MCAST_UNDEFINED
) {
3140 record_has_sources
= 0;
3144 if (record_has_sources
) {
3145 is_filter_list_change
= 1;
3147 type
= IGMP_DO_NOTHING
;
3152 * Queue a current state record.
3154 if (mode
== MCAST_EXCLUDE
) {
3155 type
= IGMP_MODE_IS_EXCLUDE
;
3156 } else if (mode
== MCAST_INCLUDE
) {
3157 type
= IGMP_MODE_IS_INCLUDE
;
3158 VERIFY(inm
->inm_st
[1].iss_asm
== 0);
3163 * Generate the filter list changes using a separate function.
3165 if (is_filter_list_change
) {
3166 return igmp_v3_enqueue_filter_change(ifq
, inm
);
3169 if (type
== IGMP_DO_NOTHING
) {
3170 IGMP_INET_PRINTF(inm
->inm_addr
,
3171 ("%s: nothing to do for %s/%s\n",
3172 __func__
, _igmp_inet_buf
,
3173 if_name(inm
->inm_ifp
)));
3178 * If any sources are present, we must be able to fit at least
3179 * one in the trailing space of the tail packet's mbuf,
3182 minrec0len
= sizeof(struct igmp_grouprec
);
3183 if (record_has_sources
) {
3184 minrec0len
+= sizeof(in_addr_t
);
3187 IGMP_INET_PRINTF(inm
->inm_addr
,
3188 ("%s: queueing %s for %s/%s\n", __func__
,
3189 igmp_rec_type_to_str(type
), _igmp_inet_buf
,
3190 if_name(inm
->inm_ifp
)));
3193 * Check if we have a packet in the tail of the queue for this
3194 * group into which the first group record for this group will fit.
3195 * Otherwise allocate a new packet.
3196 * Always allocate leading space for IP+RA_OPT+IGMP+REPORT.
3197 * Note: Group records for G/GSR query responses MUST be sent
3198 * in their own packet.
3201 if (!is_group_query
&&
3203 (m0
->m_pkthdr
.vt_nrecs
+ 1 <= IGMP_V3_REPORT_MAXRECS
) &&
3204 (m0
->m_pkthdr
.len
+ minrec0len
) <
3205 (ifp
->if_mtu
- IGMP_LEADINGSPACE
)) {
3206 m0srcs
= (ifp
->if_mtu
- m0
->m_pkthdr
.len
-
3207 sizeof(struct igmp_grouprec
)) / sizeof(in_addr_t
);
3209 IGMP_PRINTF(("%s: use existing packet\n", __func__
));
3211 if (IF_QFULL(ifq
)) {
3212 IGMP_PRINTF(("%s: outbound queue full\n", __func__
));
3216 m0srcs
= (ifp
->if_mtu
- IGMP_LEADINGSPACE
-
3217 sizeof(struct igmp_grouprec
)) / sizeof(in_addr_t
);
3218 if (!is_state_change
&& !is_group_query
) {
3219 m
= m_getcl(M_DONTWAIT
, MT_DATA
, M_PKTHDR
);
3221 m
->m_data
+= IGMP_LEADINGSPACE
;
3225 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
3227 MH_ALIGN(m
, IGMP_LEADINGSPACE
);
3234 igmp_save_context(m
, ifp
);
3236 IGMP_PRINTF(("%s: allocated first packet\n", __func__
));
3240 * Append group record.
3241 * If we have sources, we don't know how many yet.
3243 ig
.ig_type
= (u_char
)type
;
3246 ig
.ig_group
= inm
->inm_addr
;
3247 if (!m_append(m
, sizeof(struct igmp_grouprec
), (void *)&ig
)) {
3251 IGMP_PRINTF(("%s: m_append() failed.\n", __func__
));
3254 nbytes
+= sizeof(struct igmp_grouprec
);
3257 * Append as many sources as will fit in the first packet.
3258 * If we are appending to a new packet, the chain allocation
3259 * may potentially use clusters; use m_getptr() in this case.
3260 * If we are appending to an existing packet, we need to obtain
3261 * a pointer to the group record after m_append(), in case a new
3262 * mbuf was allocated.
3263 * Only append sources which are in-mode at t1. If we are
3264 * transitioning to MCAST_UNDEFINED state on the group, do not
3265 * include source entries.
3266 * Only report recorded sources in our filter set when responding
3267 * to a group-source query.
3269 if (record_has_sources
) {
3272 pig
= (struct igmp_grouprec
*)(void *)
3273 (mtod(md
, uint8_t *) + md
->m_len
- nbytes
);
3275 md
= m_getptr(m
, 0, &off
);
3276 pig
= (struct igmp_grouprec
*)(void *)
3277 (mtod(md
, uint8_t *) + off
);
3280 RB_FOREACH_SAFE(ims
, ip_msource_tree
, &inm
->inm_srcs
, nims
) {
3282 char buf
[MAX_IPv4_STR_LEN
];
3284 inet_ntop_haddr(ims
->ims_haddr
, buf
, sizeof(buf
));
3285 IGMP_PRINTF(("%s: visit node %s\n", __func__
, buf
));
3287 now
= ims_get_mode(inm
, ims
, 1);
3288 IGMP_PRINTF(("%s: node is %d\n", __func__
, now
));
3289 if ((now
!= mode
) ||
3290 (now
== mode
&& mode
== MCAST_UNDEFINED
)) {
3291 IGMP_PRINTF(("%s: skip node\n", __func__
));
3294 if (is_source_query
&& ims
->ims_stp
== 0) {
3295 IGMP_PRINTF(("%s: skip unrecorded node\n",
3299 IGMP_PRINTF(("%s: append node\n", __func__
));
3300 naddr
= htonl(ims
->ims_haddr
);
3301 if (!m_append(m
, sizeof(in_addr_t
), (void *)&naddr
)) {
3305 IGMP_PRINTF(("%s: m_append() failed.\n",
3309 nbytes
+= sizeof(in_addr_t
);
3311 if (msrcs
== m0srcs
) {
3315 IGMP_PRINTF(("%s: msrcs is %d this packet\n", __func__
,
3317 ig_numsrc
= htons(msrcs
);
3318 bcopy(&ig_numsrc
, &pig
->ig_numsrc
, sizeof(ig_numsrc
));
3319 nbytes
+= (msrcs
* sizeof(in_addr_t
));
3322 if (is_source_query
&& msrcs
== 0) {
3323 IGMP_PRINTF(("%s: no recorded sources to report\n", __func__
));
3331 * We are good to go with first packet.
3334 IGMP_PRINTF(("%s: enqueueing first packet\n", __func__
));
3335 m
->m_pkthdr
.vt_nrecs
= 1;
3338 m
->m_pkthdr
.vt_nrecs
++;
3341 * No further work needed if no source list in packet(s).
3343 if (!record_has_sources
) {
3348 * Whilst sources remain to be announced, we need to allocate
3349 * a new packet and fill out as many sources as will fit.
3350 * Always try for a cluster first.
3352 while (nims
!= NULL
) {
3353 if (IF_QFULL(ifq
)) {
3354 IGMP_PRINTF(("%s: outbound queue full\n", __func__
));
3357 m
= m_getcl(M_DONTWAIT
, MT_DATA
, M_PKTHDR
);
3359 m
->m_data
+= IGMP_LEADINGSPACE
;
3362 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
3364 MH_ALIGN(m
, IGMP_LEADINGSPACE
);
3370 igmp_save_context(m
, ifp
);
3371 md
= m_getptr(m
, 0, &off
);
3372 pig
= (struct igmp_grouprec
*)(void *)
3373 (mtod(md
, uint8_t *) + off
);
3374 IGMP_PRINTF(("%s: allocated next packet\n", __func__
));
3376 if (!m_append(m
, sizeof(struct igmp_grouprec
), (void *)&ig
)) {
3380 IGMP_PRINTF(("%s: m_append() failed.\n", __func__
));
3383 m
->m_pkthdr
.vt_nrecs
= 1;
3384 nbytes
+= sizeof(struct igmp_grouprec
);
3386 m0srcs
= (ifp
->if_mtu
- IGMP_LEADINGSPACE
-
3387 sizeof(struct igmp_grouprec
)) / sizeof(in_addr_t
);
3390 RB_FOREACH_FROM(ims
, ip_msource_tree
, nims
) {
3392 char buf
[MAX_IPv4_STR_LEN
];
3394 inet_ntop_haddr(ims
->ims_haddr
, buf
, sizeof(buf
));
3395 IGMP_PRINTF(("%s: visit node %s\n", __func__
, buf
));
3397 now
= ims_get_mode(inm
, ims
, 1);
3398 if ((now
!= mode
) ||
3399 (now
== mode
&& mode
== MCAST_UNDEFINED
)) {
3400 IGMP_PRINTF(("%s: skip node\n", __func__
));
3403 if (is_source_query
&& ims
->ims_stp
== 0) {
3404 IGMP_PRINTF(("%s: skip unrecorded node\n",
3408 IGMP_PRINTF(("%s: append node\n", __func__
));
3409 naddr
= htonl(ims
->ims_haddr
);
3410 if (!m_append(m
, sizeof(in_addr_t
), (void *)&naddr
)) {
3414 IGMP_PRINTF(("%s: m_append() failed.\n",
3419 if (msrcs
== m0srcs
) {
3423 ig_numsrc
= htons(msrcs
);
3424 bcopy(&ig_numsrc
, &pig
->ig_numsrc
, sizeof(ig_numsrc
));
3425 nbytes
+= (msrcs
* sizeof(in_addr_t
));
3427 IGMP_PRINTF(("%s: enqueueing next packet\n", __func__
));
3435 * Type used to mark record pass completion.
3436 * We exploit the fact we can cast to this easily from the
3437 * current filter modes on each ip_msource node.
3440 REC_NONE
= 0x00, /* MCAST_UNDEFINED */
3441 REC_ALLOW
= 0x01, /* MCAST_INCLUDE */
3442 REC_BLOCK
= 0x02, /* MCAST_EXCLUDE */
3443 REC_FULL
= REC_ALLOW
| REC_BLOCK
3447 * Enqueue an IGMPv3 filter list change to the given output queue.
3449 * Source list filter state is held in an RB-tree. When the filter list
3450 * for a group is changed without changing its mode, we need to compute
3451 * the deltas between T0 and T1 for each source in the filter set,
3452 * and enqueue the appropriate ALLOW_NEW/BLOCK_OLD records.
3454 * As we may potentially queue two record types, and the entire R-B tree
3455 * needs to be walked at once, we break this out into its own function
3456 * so we can generate a tightly packed queue of packets.
3458 * XXX This could be written to only use one tree walk, although that makes
3459 * serializing into the mbuf chains a bit harder. For now we do two walks
3460 * which makes things easier on us, and it may or may not be harder on
3463 * If successful the size of all data appended to the queue is returned,
3464 * otherwise an error code less than zero is returned, or zero if
3465 * no record(s) were appended.
3468 igmp_v3_enqueue_filter_change(struct ifqueue
*ifq
, struct in_multi
*inm
)
3470 static const int MINRECLEN
=
3471 sizeof(struct igmp_grouprec
) + sizeof(in_addr_t
);
3473 struct igmp_grouprec ig
;
3474 struct igmp_grouprec
*pig
;
3475 struct ip_msource
*ims
, *nims
;
3476 struct mbuf
*m
, *m0
, *md
;
3478 int m0srcs
, nbytes
, npbytes
, off
, schanged
;
3483 rectype_t crt
, drt
, nrt
;
3484 u_int16_t ig_numsrc
;
3486 INM_LOCK_ASSERT_HELD(inm
);
3488 if (inm
->inm_nsrc
== 0 ||
3489 (inm
->inm_st
[0].iss_asm
> 0 && inm
->inm_st
[1].iss_asm
> 0)) {
3493 ifp
= inm
->inm_ifp
; /* interface */
3494 mode
= inm
->inm_st
[1].iss_fmode
; /* filter mode at t1 */
3495 crt
= REC_NONE
; /* current group record type */
3496 drt
= REC_NONE
; /* mask of completed group record types */
3497 nrt
= REC_NONE
; /* record type for current node */
3498 m0srcs
= 0; /* # source which will fit in current mbuf chain */
3499 nbytes
= 0; /* # of bytes appended to group's state-change queue */
3500 npbytes
= 0; /* # of bytes appended this packet */
3501 rsrcs
= 0; /* # sources encoded in current record */
3502 schanged
= 0; /* # nodes encoded in overall filter change */
3503 nallow
= 0; /* # of source entries in ALLOW_NEW */
3504 nblock
= 0; /* # of source entries in BLOCK_OLD */
3505 nims
= NULL
; /* next tree node pointer */
3508 * For each possible filter record mode.
3509 * The first kind of source we encounter tells us which
3510 * is the first kind of record we start appending.
3511 * If a node transitioned to UNDEFINED at t1, its mode is treated
3512 * as the inverse of the group's filter mode.
3514 while (drt
!= REC_FULL
) {
3518 (m0
->m_pkthdr
.vt_nrecs
+ 1 <=
3519 IGMP_V3_REPORT_MAXRECS
) &&
3520 (m0
->m_pkthdr
.len
+ MINRECLEN
) <
3521 (ifp
->if_mtu
- IGMP_LEADINGSPACE
)) {
3523 m0srcs
= (ifp
->if_mtu
- m0
->m_pkthdr
.len
-
3524 sizeof(struct igmp_grouprec
)) /
3526 IGMP_PRINTF(("%s: use previous packet\n",
3529 m
= m_getcl(M_DONTWAIT
, MT_DATA
, M_PKTHDR
);
3531 m
->m_data
+= IGMP_LEADINGSPACE
;
3534 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
3536 MH_ALIGN(m
, IGMP_LEADINGSPACE
);
3540 IGMP_PRINTF(("%s: m_get*() failed\n",
3544 m
->m_pkthdr
.vt_nrecs
= 0;
3545 igmp_save_context(m
, ifp
);
3546 m0srcs
= (ifp
->if_mtu
- IGMP_LEADINGSPACE
-
3547 sizeof(struct igmp_grouprec
)) /
3550 IGMP_PRINTF(("%s: allocated new packet\n",
3554 * Append the IGMP group record header to the
3555 * current packet's data area.
3556 * Recalculate pointer to free space for next
3557 * group record, in case m_append() allocated
3558 * a new mbuf or cluster.
3560 memset(&ig
, 0, sizeof(ig
));
3561 ig
.ig_group
= inm
->inm_addr
;
3562 if (!m_append(m
, sizeof(ig
), (void *)&ig
)) {
3566 IGMP_PRINTF(("%s: m_append() failed\n",
3570 npbytes
+= sizeof(struct igmp_grouprec
);
3572 /* new packet; offset in c hain */
3573 md
= m_getptr(m
, npbytes
-
3574 sizeof(struct igmp_grouprec
), &off
);
3575 pig
= (struct igmp_grouprec
*)(void *)(mtod(md
,
3578 /* current packet; offset from last append */
3580 pig
= (struct igmp_grouprec
*)(void *)(mtod(md
,
3581 uint8_t *) + md
->m_len
-
3582 sizeof(struct igmp_grouprec
));
3585 * Begin walking the tree for this record type
3586 * pass, or continue from where we left off
3587 * previously if we had to allocate a new packet.
3588 * Only report deltas in-mode at t1.
3589 * We need not report included sources as allowed
3590 * if we are in inclusive mode on the group,
3591 * however the converse is not true.
3595 nims
= RB_MIN(ip_msource_tree
, &inm
->inm_srcs
);
3597 RB_FOREACH_FROM(ims
, ip_msource_tree
, nims
) {
3599 char buf
[MAX_IPv4_STR_LEN
];
3601 inet_ntop_haddr(ims
->ims_haddr
, buf
, sizeof(buf
));
3602 IGMP_PRINTF(("%s: visit node %s\n", __func__
, buf
));
3604 now
= ims_get_mode(inm
, ims
, 1);
3605 then
= ims_get_mode(inm
, ims
, 0);
3606 IGMP_PRINTF(("%s: mode: t0 %d, t1 %d\n",
3607 __func__
, then
, now
));
3609 IGMP_PRINTF(("%s: skip unchanged\n",
3613 if (mode
== MCAST_EXCLUDE
&&
3614 now
== MCAST_INCLUDE
) {
3615 IGMP_PRINTF(("%s: skip IN src on EX "
3616 "group\n", __func__
));
3619 nrt
= (rectype_t
)now
;
3620 if (nrt
== REC_NONE
) {
3621 nrt
= (rectype_t
)(~mode
& REC_FULL
);
3623 if (schanged
++ == 0) {
3625 } else if (crt
!= nrt
) {
3628 naddr
= htonl(ims
->ims_haddr
);
3629 if (!m_append(m
, sizeof(in_addr_t
),
3634 IGMP_PRINTF(("%s: m_append() failed\n",
3638 nallow
+= !!(crt
== REC_ALLOW
);
3639 nblock
+= !!(crt
== REC_BLOCK
);
3640 if (++rsrcs
== m0srcs
) {
3645 * If we did not append any tree nodes on this
3646 * pass, back out of allocations.
3649 npbytes
-= sizeof(struct igmp_grouprec
);
3651 IGMP_PRINTF(("%s: m_free(m)\n",
3655 IGMP_PRINTF(("%s: m_adj(m, -ig)\n",
3657 m_adj(m
, -((int)sizeof(
3658 struct igmp_grouprec
)));
3662 npbytes
+= (rsrcs
* sizeof(in_addr_t
));
3663 if (crt
== REC_ALLOW
) {
3664 pig
->ig_type
= IGMP_ALLOW_NEW_SOURCES
;
3665 } else if (crt
== REC_BLOCK
) {
3666 pig
->ig_type
= IGMP_BLOCK_OLD_SOURCES
;
3668 ig_numsrc
= htons(rsrcs
);
3669 bcopy(&ig_numsrc
, &pig
->ig_numsrc
, sizeof(ig_numsrc
));
3671 * Count the new group record, and enqueue this
3672 * packet if it wasn't already queued.
3674 m
->m_pkthdr
.vt_nrecs
++;
3679 } while (nims
!= NULL
);
3681 crt
= (~crt
& REC_FULL
);
3684 IGMP_PRINTF(("%s: queued %d ALLOW_NEW, %d BLOCK_OLD\n", __func__
,
3691 igmp_v3_merge_state_changes(struct in_multi
*inm
, struct ifqueue
*ifscq
)
3694 struct mbuf
*m
; /* pending state-change */
3695 struct mbuf
*m0
; /* copy of pending state-change */
3696 struct mbuf
*mt
; /* last state-change in packet */
3698 int docopy
, domerge
;
3701 INM_LOCK_ASSERT_HELD(inm
);
3708 * If there are further pending retransmissions, make a writable
3709 * copy of each queued state-change message before merging.
3711 if (inm
->inm_scrv
> 0) {
3717 if (gq
->ifq_head
== NULL
) {
3718 IGMP_PRINTF(("%s: WARNING: queue for inm 0x%llx is empty\n",
3719 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(inm
)));
3724 * Use IF_REMQUEUE() instead of IF_DEQUEUE() below, since the
3725 * packet might not always be at the head of the ifqueue.
3730 * Only merge the report into the current packet if
3731 * there is sufficient space to do so; an IGMPv3 report
3732 * packet may only contain 65,535 group records.
3733 * Always use a simple mbuf chain concatentation to do this,
3734 * as large state changes for single groups may have
3735 * allocated clusters.
3738 mt
= ifscq
->ifq_tail
;
3740 recslen
= m_length(m
);
3742 if ((mt
->m_pkthdr
.vt_nrecs
+
3743 m
->m_pkthdr
.vt_nrecs
<=
3744 IGMP_V3_REPORT_MAXRECS
) &&
3745 (mt
->m_pkthdr
.len
+ recslen
<=
3746 (inm
->inm_ifp
->if_mtu
- IGMP_LEADINGSPACE
))) {
3751 if (!domerge
&& IF_QFULL(gq
)) {
3752 IGMP_PRINTF(("%s: outbound queue full, skipping whole "
3753 "packet 0x%llx\n", __func__
,
3754 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3765 IGMP_PRINTF(("%s: dequeueing 0x%llx\n", __func__
,
3766 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3772 IGMP_PRINTF(("%s: copying 0x%llx\n", __func__
,
3773 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3774 m0
= m_dup(m
, M_NOWAIT
);
3778 m0
->m_nextpkt
= NULL
;
3783 IGMP_PRINTF(("%s: queueing 0x%llx to ifscq 0x%llx)\n",
3784 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(m0
),
3785 (uint64_t)VM_KERNEL_ADDRPERM(ifscq
)));
3786 IF_ENQUEUE(ifscq
, m0
);
3788 struct mbuf
*mtl
; /* last mbuf of packet mt */
3790 IGMP_PRINTF(("%s: merging 0x%llx with ifscq tail "
3791 "0x%llx)\n", __func__
,
3792 (uint64_t)VM_KERNEL_ADDRPERM(m0
),
3793 (uint64_t)VM_KERNEL_ADDRPERM(mt
)));
3796 m0
->m_flags
&= ~M_PKTHDR
;
3797 mt
->m_pkthdr
.len
+= recslen
;
3798 mt
->m_pkthdr
.vt_nrecs
+=
3799 m0
->m_pkthdr
.vt_nrecs
;
3809 * Respond to a pending IGMPv3 General Query.
3812 igmp_v3_dispatch_general_query(struct igmp_ifinfo
*igi
)
3815 struct in_multi
*inm
;
3816 struct in_multistep step
;
3819 IGI_LOCK_ASSERT_HELD(igi
);
3821 VERIFY(igi
->igi_version
== IGMP_VERSION_3
);
3826 in_multihead_lock_shared();
3827 IN_FIRST_MULTI(step
, inm
);
3828 while (inm
!= NULL
) {
3830 if (inm
->inm_ifp
!= ifp
) {
3834 switch (inm
->inm_state
) {
3835 case IGMP_NOT_MEMBER
:
3836 case IGMP_SILENT_MEMBER
:
3838 case IGMP_REPORTING_MEMBER
:
3839 case IGMP_IDLE_MEMBER
:
3840 case IGMP_LAZY_MEMBER
:
3841 case IGMP_SLEEPING_MEMBER
:
3842 case IGMP_AWAKENING_MEMBER
:
3843 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
3845 retval
= igmp_v3_enqueue_group_record(&igi
->igi_gq
,
3848 IGMP_PRINTF(("%s: enqueue record = %d\n",
3851 case IGMP_G_QUERY_PENDING_MEMBER
:
3852 case IGMP_SG_QUERY_PENDING_MEMBER
:
3853 case IGMP_LEAVING_MEMBER
:
3858 IN_NEXT_MULTI(step
, inm
);
3860 in_multihead_lock_done();
3863 loop
= (igi
->igi_flags
& IGIF_LOOPBACK
) ? 1 : 0;
3864 igmp_dispatch_queue(igi
, &igi
->igi_gq
, IGMP_MAX_RESPONSE_BURST
,
3866 IGI_LOCK_ASSERT_HELD(igi
);
3868 * Slew transmission of bursts over 1 second intervals.
3870 if (igi
->igi_gq
.ifq_head
!= NULL
) {
3871 igi
->igi_v3_timer
= 1 + IGMP_RANDOM_DELAY(
3872 IGMP_RESPONSE_BURST_INTERVAL
);
3875 return igi
->igi_v3_timer
;
3879 * Transmit the next pending IGMP message in the output queue.
3881 * Must not be called with inm_lock or igi_lock held.
3884 igmp_sendpkt(struct mbuf
*m
)
3886 struct ip_moptions
*imo
;
3887 struct mbuf
*ipopts
, *m0
;
3892 IGMP_PRINTF(("%s: transmit 0x%llx\n", __func__
,
3893 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3895 ifp
= igmp_restore_context(m
);
3897 * Check if the ifnet is still attached.
3899 if (ifp
== NULL
|| !ifnet_is_attached(ifp
, 0)) {
3900 IGMP_PRINTF(("%s: dropped 0x%llx as ifp went away.\n",
3901 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3903 OSAddAtomic(1, &ipstat
.ips_noroute
);
3907 ipopts
= igmp_sendra
? m_raopt
: NULL
;
3909 imo
= ip_allocmoptions(Z_WAITOK
);
3915 imo
->imo_multicast_ttl
= 1;
3916 imo
->imo_multicast_vif
= -1;
3917 imo
->imo_multicast_loop
= 0;
3920 * If the user requested that IGMP traffic be explicitly
3921 * redirected to the loopback interface (e.g. they are running a
3922 * MANET interface and the routing protocol needs to see the
3923 * updates), handle this now.
3925 if (m
->m_flags
& M_IGMP_LOOP
) {
3926 imo
->imo_multicast_ifp
= lo_ifp
;
3928 imo
->imo_multicast_ifp
= ifp
;
3931 if (m
->m_flags
& M_IGMPV2
) {
3934 m0
= igmp_v3_encap_report(ifp
, m
);
3937 * If igmp_v3_encap_report() failed, then M_PREPEND()
3938 * already freed the original mbuf chain.
3939 * This means that we don't have to m_freem(m) here.
3941 IGMP_PRINTF(("%s: dropped 0x%llx\n", __func__
,
3942 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3944 atomic_add_32(&ipstat
.ips_odropped
, 1);
3949 igmp_scrub_context(m0
);
3950 m
->m_flags
&= ~(M_PROTOFLAGS
| M_IGMP_LOOP
);
3951 m0
->m_pkthdr
.rcvif
= lo_ifp
;
3953 if (ifp
->if_eflags
& IFEF_TXSTART
) {
3955 * Use control service class if the interface supports
3956 * transmit-start model.
3958 (void) m_set_service_class(m0
, MBUF_SC_CTL
);
3960 bzero(&ro
, sizeof(ro
));
3961 error
= ip_output(m0
, ipopts
, &ro
, 0, imo
, NULL
);
3967 IGMP_PRINTF(("%s: ip_output(0x%llx) = %d\n", __func__
,
3968 (uint64_t)VM_KERNEL_ADDRPERM(m0
), error
));
3972 IGMPSTAT_INC(igps_snd_reports
);
3973 OIGMPSTAT_INC(igps_snd_reports
);
3976 * Encapsulate an IGMPv3 report.
3978 * The internal mbuf flag M_IGMPV3_HDR is used to indicate that the mbuf
3979 * chain has already had its IP/IGMPv3 header prepended. In this case
3980 * the function will not attempt to prepend; the lengths and checksums
3981 * will however be re-computed.
3983 * Returns a pointer to the new mbuf chain head, or NULL if the
3984 * allocation failed.
3986 static struct mbuf
*
3987 igmp_v3_encap_report(struct ifnet
*ifp
, struct mbuf
*m
)
3989 struct igmp_report
*igmp
;
3991 unsigned int hdrlen
, igmpreclen
;
3993 VERIFY((m
->m_flags
& M_PKTHDR
));
3995 igmpreclen
= m_length(m
);
3996 hdrlen
= sizeof(struct ip
) + sizeof(struct igmp_report
);
3998 if (m
->m_flags
& M_IGMPV3_HDR
) {
3999 igmpreclen
-= hdrlen
;
4001 M_PREPEND(m
, hdrlen
, M_DONTWAIT
, 1);
4005 m
->m_flags
|= M_IGMPV3_HDR
;
4007 if (hdrlen
+ igmpreclen
> USHRT_MAX
) {
4008 IGMP_PRINTF(("%s: invalid length %d\n", __func__
, hdrlen
+ igmpreclen
));
4014 IGMP_PRINTF(("%s: igmpreclen is %d\n", __func__
, igmpreclen
));
4016 m
->m_data
+= sizeof(struct ip
);
4017 m
->m_len
-= sizeof(struct ip
);
4019 igmp
= mtod(m
, struct igmp_report
*);
4020 igmp
->ir_type
= IGMP_v3_HOST_MEMBERSHIP_REPORT
;
4023 igmp
->ir_numgrps
= htons(m
->m_pkthdr
.vt_nrecs
);
4025 igmp
->ir_cksum
= in_cksum(m
, sizeof(struct igmp_report
) + igmpreclen
);
4026 m
->m_pkthdr
.vt_nrecs
= 0;
4028 m
->m_data
-= sizeof(struct ip
);
4029 m
->m_len
+= sizeof(struct ip
);
4031 ip
= mtod(m
, struct ip
*);
4032 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
4033 ip
->ip_len
= (u_short
)(hdrlen
+ igmpreclen
);
4035 ip
->ip_p
= IPPROTO_IGMP
;
4038 ip
->ip_src
.s_addr
= INADDR_ANY
;
4040 if (m
->m_flags
& M_IGMP_LOOP
) {
4041 struct in_ifaddr
*ia
;
4045 IFA_LOCK(&ia
->ia_ifa
);
4046 ip
->ip_src
= ia
->ia_addr
.sin_addr
;
4047 IFA_UNLOCK(&ia
->ia_ifa
);
4048 IFA_REMREF(&ia
->ia_ifa
);
4052 ip
->ip_dst
.s_addr
= htonl(INADDR_ALLRPTS_GROUP
);
4059 igmp_rec_type_to_str(const int type
)
4062 case IGMP_CHANGE_TO_EXCLUDE_MODE
:
4064 case IGMP_CHANGE_TO_INCLUDE_MODE
:
4066 case IGMP_MODE_IS_EXCLUDE
:
4068 case IGMP_MODE_IS_INCLUDE
:
4070 case IGMP_ALLOW_NEW_SOURCES
:
4072 case IGMP_BLOCK_OLD_SOURCES
:
4082 igmp_init(struct protosw
*pp
, struct domain
*dp
)
4085 static int igmp_initialized
= 0;
4087 VERIFY((pp
->pr_flags
& (PR_INITIALIZED
| PR_ATTACHED
)) == PR_ATTACHED
);
4089 if (igmp_initialized
) {
4092 igmp_initialized
= 1;
4094 IGMP_PRINTF(("%s: initializing\n", __func__
));
4096 igmp_timers_are_running
= 0;
4098 /* Setup lock group and attribute for igmp_mtx */
4099 igmp_mtx_grp_attr
= lck_grp_attr_alloc_init();
4100 igmp_mtx_grp
= lck_grp_alloc_init("igmp_mtx", igmp_mtx_grp_attr
);
4101 igmp_mtx_attr
= lck_attr_alloc_init();
4102 lck_mtx_init(&igmp_mtx
, igmp_mtx_grp
, igmp_mtx_attr
);
4104 LIST_INIT(&igi_head
);
4105 m_raopt
= igmp_ra_alloc();