2 * Copyright (c) 2000-2019 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(int);
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 #define IGI_ZONE_MAX 64 /* maximum elements in zone */
306 #define IGI_ZONE_NAME "igmp_ifinfo" /* zone name */
308 static unsigned int igi_size
; /* size of zone element */
309 static struct zone
*igi_zone
; /* zone for igmp_ifinfo */
311 /* Store IGMPv3 record count in the module private scratch space */
312 #define vt_nrecs pkt_mpriv.__mpriv_u.__mpriv32[0].__mpriv32_u.__val16[0]
315 igmp_save_context(struct mbuf
*m
, struct ifnet
*ifp
)
317 m
->m_pkthdr
.rcvif
= ifp
;
321 igmp_scrub_context(struct mbuf
*m
)
323 m
->m_pkthdr
.rcvif
= NULL
;
327 static __inline
const char *
328 inet_ntop_haddr(in_addr_t haddr
, char *buf
, socklen_t size
)
332 ia
.s_addr
= htonl(haddr
);
333 return inet_ntop(AF_INET
, &ia
, buf
, size
);
338 * Restore context from a queued IGMP output chain.
341 static __inline
struct ifnet
*
342 igmp_restore_context(struct mbuf
*m
)
344 return m
->m_pkthdr
.rcvif
;
348 * Retrieve or set default IGMP version.
351 sysctl_igmp_default_version SYSCTL_HANDLER_ARGS
353 #pragma unused(oidp, arg2)
359 error
= SYSCTL_OUT(req
, arg1
, sizeof(int));
360 if (error
|| !req
->newptr
) {
364 new = igmp_default_version
;
366 error
= SYSCTL_IN(req
, &new, sizeof(int));
371 if (new < IGMP_VERSION_1
|| new > IGMP_VERSION_3
) {
376 IGMP_PRINTF(("%s: change igmp_default_version from %d to %d\n",
377 __func__
, igmp_default_version
, new));
379 igmp_default_version
= new;
387 * Retrieve or set threshold between group-source queries in seconds.
391 sysctl_igmp_gsr SYSCTL_HANDLER_ARGS
393 #pragma unused(arg1, arg2)
399 i
= igmp_gsrdelay
.tv_sec
;
401 error
= sysctl_handle_int(oidp
, &i
, 0, req
);
402 if (error
|| !req
->newptr
) {
406 if (i
< -1 || i
>= 60) {
411 igmp_gsrdelay
.tv_sec
= i
;
419 * Expose struct igmp_ifinfo to userland, keyed by ifindex.
420 * For use by ifmcstat(8).
424 sysctl_igmp_ifinfo SYSCTL_HANDLER_ARGS
431 struct igmp_ifinfo
*igi
;
432 struct igmp_ifinfo_u igi_u
;
437 if (req
->newptr
!= USER_ADDR_NULL
) {
447 if (name
[0] <= 0 || name
[0] > (u_int
)if_index
) {
454 ifnet_head_lock_shared();
455 ifp
= ifindex2ifnet
[name
[0]];
461 bzero(&igi_u
, sizeof(igi_u
));
463 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
465 if (ifp
!= igi
->igi_ifp
) {
469 igi_u
.igi_ifindex
= igi
->igi_ifp
->if_index
;
470 igi_u
.igi_version
= igi
->igi_version
;
471 igi_u
.igi_v1_timer
= igi
->igi_v1_timer
;
472 igi_u
.igi_v2_timer
= igi
->igi_v2_timer
;
473 igi_u
.igi_v3_timer
= igi
->igi_v3_timer
;
474 igi_u
.igi_flags
= igi
->igi_flags
;
475 igi_u
.igi_rv
= igi
->igi_rv
;
476 igi_u
.igi_qi
= igi
->igi_qi
;
477 igi_u
.igi_qri
= igi
->igi_qri
;
478 igi_u
.igi_uri
= igi
->igi_uri
;
481 error
= SYSCTL_OUT(req
, &igi_u
, sizeof(igi_u
));
491 * Dispatch an entire queue of pending packet chains
493 * Must not be called with inm_lock held.
496 igmp_dispatch_queue(struct igmp_ifinfo
*igi
, struct ifqueue
*ifq
, int limit
,
503 IGI_LOCK_ASSERT_HELD(igi
);
511 IGMP_PRINTF(("%s: dispatch 0x%llx from 0x%llx\n", __func__
,
512 (uint64_t)VM_KERNEL_ADDRPERM(ifq
),
513 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
514 ip
= mtod(m
, struct ip
*);
516 m
->m_flags
|= M_IGMP_LOOP
;
531 IGI_LOCK_ASSERT_HELD(igi
);
536 * Filter outgoing IGMP report state by group.
538 * Reports are ALWAYS suppressed for ALL-HOSTS (224.0.0.1).
539 * If the net.inet.igmp.sendlocal sysctl is 0, then IGMP reports are
540 * disabled for all groups in the 224.0.0.0/24 link-local scope. However,
541 * this may break certain IGMP snooping switches which rely on the old
544 * Return zero if the given group is one for which IGMP reports
545 * should be suppressed, or non-zero if reports should be issued.
550 igmp_isgroupreported(const struct in_addr addr
)
552 if (in_allhosts(addr
) ||
553 ((!igmp_sendlocal
&& IN_LOCAL_GROUP(ntohl(addr
.s_addr
))))) {
561 * Construct a Router Alert option to use in outgoing packets.
569 MGET(m
, M_WAITOK
, MT_DATA
);
570 p
= mtod(m
, struct ipoption
*);
571 p
->ipopt_dst
.s_addr
= INADDR_ANY
;
572 p
->ipopt_list
[0] = (char)IPOPT_RA
; /* Router Alert Option */
573 p
->ipopt_list
[1] = 0x04; /* 4 bytes long */
574 p
->ipopt_list
[2] = IPOPT_EOL
; /* End of IP option list */
575 p
->ipopt_list
[3] = 0x00; /* pad byte */
576 m
->m_len
= sizeof(p
->ipopt_dst
) + p
->ipopt_list
[1];
582 * Attach IGMP when PF_INET is attached to an interface.
585 igmp_domifattach(struct ifnet
*ifp
, int how
)
587 struct igmp_ifinfo
*igi
;
589 IGMP_PRINTF(("%s: called for ifp 0x%llx(%s)\n",
590 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
));
592 igi
= igi_alloc(how
);
600 igi_initvar(igi
, ifp
, 0);
601 igi
->igi_debug
|= IFD_ATTACHED
;
602 IGI_ADDREF_LOCKED(igi
); /* hold a reference for igi_head */
603 IGI_ADDREF_LOCKED(igi
); /* hold a reference for caller */
605 ifnet_lock_shared(ifp
);
606 igmp_initsilent(ifp
, igi
);
607 ifnet_lock_done(ifp
);
609 LIST_INSERT_HEAD(&igi_head
, igi
, igi_link
);
613 IGMP_PRINTF(("%s: allocate igmp_ifinfo for ifp 0x%llx(%s)\n", __func__
,
614 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
));
620 * Attach IGMP when PF_INET is reattached to an interface. Caller is
621 * expected to have an outstanding reference to the igi.
624 igmp_domifreattach(struct igmp_ifinfo
*igi
)
631 VERIFY(!(igi
->igi_debug
& IFD_ATTACHED
));
634 igi_initvar(igi
, ifp
, 1);
635 igi
->igi_debug
|= IFD_ATTACHED
;
636 IGI_ADDREF_LOCKED(igi
); /* hold a reference for igi_head */
638 ifnet_lock_shared(ifp
);
639 igmp_initsilent(ifp
, igi
);
640 ifnet_lock_done(ifp
);
642 LIST_INSERT_HEAD(&igi_head
, igi
, igi_link
);
646 IGMP_PRINTF(("%s: reattached igmp_ifinfo for ifp 0x%llx(%s)\n",
647 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
));
651 * Hook for domifdetach.
654 igmp_domifdetach(struct ifnet
*ifp
)
656 SLIST_HEAD(, in_multi
) inm_dthead
;
658 SLIST_INIT(&inm_dthead
);
660 IGMP_PRINTF(("%s: called for ifp 0x%llx(%s%d)\n", __func__
,
661 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), ifp
->if_name
, ifp
->if_unit
));
664 igi_delete(ifp
, (struct igmp_inm_relhead
*)&inm_dthead
);
667 /* Now that we're dropped all locks, release detached records */
668 IGMP_REMOVE_DETACHED_INM(&inm_dthead
);
672 * Called at interface detach time. Note that we only flush all deferred
673 * responses and record releases; all remaining inm records and their source
674 * entries related to this interface are left intact, in order to handle
678 igi_delete(const struct ifnet
*ifp
, struct igmp_inm_relhead
*inm_dthead
)
680 struct igmp_ifinfo
*igi
, *tigi
;
682 IGMP_LOCK_ASSERT_HELD();
684 LIST_FOREACH_SAFE(igi
, &igi_head
, igi_link
, tigi
) {
686 if (igi
->igi_ifp
== ifp
) {
688 * Free deferred General Query responses.
690 IF_DRAIN(&igi
->igi_gq
);
691 IF_DRAIN(&igi
->igi_v2q
);
692 igmp_flush_relq(igi
, inm_dthead
);
693 VERIFY(SLIST_EMPTY(&igi
->igi_relinmhead
));
694 igi
->igi_debug
&= ~IFD_ATTACHED
;
697 LIST_REMOVE(igi
, igi_link
);
698 IGI_REMREF(igi
); /* release igi_head reference */
703 panic("%s: igmp_ifinfo not found for ifp %p(%s)\n", __func__
,
707 __private_extern__
void
708 igmp_initsilent(struct ifnet
*ifp
, struct igmp_ifinfo
*igi
)
710 ifnet_lock_assert(ifp
, IFNET_LCK_ASSERT_OWNED
);
712 IGI_LOCK_ASSERT_NOTHELD(igi
);
714 if (!(ifp
->if_flags
& IFF_MULTICAST
)) {
715 igi
->igi_flags
|= IGIF_SILENT
;
717 igi
->igi_flags
&= ~IGIF_SILENT
;
723 igi_initvar(struct igmp_ifinfo
*igi
, struct ifnet
*ifp
, int reattach
)
725 IGI_LOCK_ASSERT_HELD(igi
);
728 igi
->igi_version
= igmp_default_version
;
730 igi
->igi_rv
= IGMP_RV_INIT
;
731 igi
->igi_qi
= IGMP_QI_INIT
;
732 igi
->igi_qri
= IGMP_QRI_INIT
;
733 igi
->igi_uri
= IGMP_URI_INIT
;
736 SLIST_INIT(&igi
->igi_relinmhead
);
740 * Responses to general queries are subject to bounds.
742 igi
->igi_gq
.ifq_maxlen
= IGMP_MAX_RESPONSE_PACKETS
;
743 igi
->igi_v2q
.ifq_maxlen
= IGMP_MAX_RESPONSE_PACKETS
;
746 static struct igmp_ifinfo
*
749 struct igmp_ifinfo
*igi
;
751 igi
= (how
== M_WAITOK
) ? zalloc(igi_zone
) : zalloc_noblock(igi_zone
);
753 bzero(igi
, igi_size
);
754 lck_mtx_init(&igi
->igi_lock
, igmp_mtx_grp
, igmp_mtx_attr
);
755 igi
->igi_debug
|= IFD_ALLOC
;
761 igi_free(struct igmp_ifinfo
*igi
)
764 if (igi
->igi_debug
& IFD_ATTACHED
) {
765 panic("%s: attached igi=%p is being freed", __func__
, igi
);
767 } else if (igi
->igi_ifp
!= NULL
) {
768 panic("%s: ifp not NULL for igi=%p", __func__
, igi
);
770 } else if (!(igi
->igi_debug
& IFD_ALLOC
)) {
771 panic("%s: igi %p cannot be freed", __func__
, igi
);
773 } else if (igi
->igi_refcnt
!= 0) {
774 panic("%s: non-zero refcnt igi=%p", __func__
, igi
);
777 igi
->igi_debug
&= ~IFD_ALLOC
;
780 lck_mtx_destroy(&igi
->igi_lock
, igmp_mtx_grp
);
781 zfree(igi_zone
, igi
);
785 igi_addref(struct igmp_ifinfo
*igi
, int locked
)
790 IGI_LOCK_ASSERT_HELD(igi
);
793 if (++igi
->igi_refcnt
== 0) {
794 panic("%s: igi=%p wraparound refcnt", __func__
, igi
);
803 igi_remref(struct igmp_ifinfo
*igi
)
805 SLIST_HEAD(, in_multi
) inm_dthead
;
810 if (igi
->igi_refcnt
== 0) {
811 panic("%s: igi=%p negative refcnt", __func__
, igi
);
816 if (igi
->igi_refcnt
> 0) {
823 IF_DRAIN(&igi
->igi_gq
);
824 IF_DRAIN(&igi
->igi_v2q
);
825 SLIST_INIT(&inm_dthead
);
826 igmp_flush_relq(igi
, (struct igmp_inm_relhead
*)&inm_dthead
);
827 VERIFY(SLIST_EMPTY(&igi
->igi_relinmhead
));
830 /* Now that we're dropped all locks, release detached records */
831 IGMP_REMOVE_DETACHED_INM(&inm_dthead
);
833 IGMP_PRINTF(("%s: freeing igmp_ifinfo for ifp 0x%llx(%s)\n",
834 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
840 * Process a received IGMPv1 query.
841 * Return non-zero if the message should be dropped.
844 igmp_input_v1_query(struct ifnet
*ifp
, const struct ip
*ip
,
845 const struct igmp
*igmp
)
847 struct igmp_ifinfo
*igi
;
848 struct in_multi
*inm
;
849 struct in_multistep step
;
850 struct igmp_tparams itp
= { .qpt
= 0, .it
= 0, .cst
= 0, .sct
= 0 };
852 IGMP_LOCK_ASSERT_NOTHELD();
855 * IGMPv1 Host Membership Queries SHOULD always be addressed to
856 * 224.0.0.1. They are always treated as General Queries.
857 * igmp_group is always ignored. Do not drop it as a userland
858 * daemon may wish to see it.
860 if (!in_allhosts(ip
->ip_dst
) || !in_nullhost(igmp
->igmp_group
)) {
861 IGMPSTAT_INC(igps_rcv_badqueries
);
862 OIGMPSTAT_INC(igps_rcv_badqueries
);
865 IGMPSTAT_INC(igps_rcv_gen_queries
);
867 igi
= IGMP_IFINFO(ifp
);
871 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
872 IGMP_PRINTF(("%s: ignore v1 query on IGIF_LOOPBACK "
873 "ifp 0x%llx(%s)\n", __func__
,
874 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
879 * Switch to IGMPv1 host compatibility mode.
881 itp
.qpt
= igmp_set_version(igi
, IGMP_VERSION_1
);
884 IGMP_PRINTF(("%s: process v1 query on ifp 0x%llx(%s)\n", __func__
,
885 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
888 * Start the timers in all of our group records
889 * for the interface on which the query arrived,
890 * except those which are already running.
892 in_multihead_lock_shared();
893 IN_FIRST_MULTI(step
, inm
);
894 while (inm
!= NULL
) {
896 if (inm
->inm_ifp
!= ifp
|| inm
->inm_timer
!= 0) {
900 switch (inm
->inm_state
) {
901 case IGMP_NOT_MEMBER
:
902 case IGMP_SILENT_MEMBER
:
904 case IGMP_G_QUERY_PENDING_MEMBER
:
905 case IGMP_SG_QUERY_PENDING_MEMBER
:
906 case IGMP_REPORTING_MEMBER
:
907 case IGMP_IDLE_MEMBER
:
908 case IGMP_LAZY_MEMBER
:
909 case IGMP_SLEEPING_MEMBER
:
910 case IGMP_AWAKENING_MEMBER
:
911 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
912 inm
->inm_timer
= IGMP_RANDOM_DELAY(IGMP_V1V2_MAX_RI
);
915 case IGMP_LEAVING_MEMBER
:
920 IN_NEXT_MULTI(step
, inm
);
922 in_multihead_lock_done();
924 igmp_set_timeout(&itp
);
930 * Process a received IGMPv2 general or group-specific query.
933 igmp_input_v2_query(struct ifnet
*ifp
, const struct ip
*ip
,
934 const struct igmp
*igmp
)
936 struct igmp_ifinfo
*igi
;
937 struct in_multi
*inm
;
938 int is_general_query
;
940 struct igmp_tparams itp
= { .qpt
= 0, .it
= 0, .cst
= 0, .sct
= 0 };
942 IGMP_LOCK_ASSERT_NOTHELD();
944 is_general_query
= 0;
947 * Validate address fields upfront.
949 if (in_nullhost(igmp
->igmp_group
)) {
951 * IGMPv2 General Query.
952 * If this was not sent to the all-hosts group, ignore it.
954 if (!in_allhosts(ip
->ip_dst
)) {
957 IGMPSTAT_INC(igps_rcv_gen_queries
);
958 is_general_query
= 1;
960 /* IGMPv2 Group-Specific Query. */
961 IGMPSTAT_INC(igps_rcv_group_queries
);
964 igi
= IGMP_IFINFO(ifp
);
968 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
969 IGMP_PRINTF(("%s: ignore v2 query on IGIF_LOOPBACK "
970 "ifp 0x%llx(%s)\n", __func__
,
971 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
976 * Ignore v2 query if in v1 Compatibility Mode.
978 if (igi
->igi_version
== IGMP_VERSION_1
) {
982 itp
.qpt
= igmp_set_version(igi
, IGMP_VERSION_2
);
985 timer
= igmp
->igmp_code
/ IGMP_TIMER_SCALE
;
990 if (is_general_query
) {
991 struct in_multistep step
;
993 IGMP_PRINTF(("%s: process v2 general query on ifp 0x%llx(%s)\n",
994 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
996 * For each reporting group joined on this
997 * interface, kick the report timer.
999 in_multihead_lock_shared();
1000 IN_FIRST_MULTI(step
, inm
);
1001 while (inm
!= NULL
) {
1003 if (inm
->inm_ifp
== ifp
) {
1004 itp
.cst
+= igmp_v2_update_group(inm
, timer
);
1007 IN_NEXT_MULTI(step
, inm
);
1009 in_multihead_lock_done();
1012 * Group-specific IGMPv2 query, we need only
1013 * look up the single group to process it.
1015 in_multihead_lock_shared();
1016 IN_LOOKUP_MULTI(&igmp
->igmp_group
, ifp
, inm
);
1017 in_multihead_lock_done();
1020 IGMP_INET_PRINTF(igmp
->igmp_group
,
1021 ("process v2 query %s on ifp 0x%llx(%s)\n",
1023 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1024 itp
.cst
= igmp_v2_update_group(inm
, timer
);
1026 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1030 igmp_set_timeout(&itp
);
1036 * Update the report timer on a group in response to an IGMPv2 query.
1038 * If we are becoming the reporting member for this group, start the timer.
1039 * If we already are the reporting member for this group, and timer is
1040 * below the threshold, reset it.
1042 * We may be updating the group for the first time since we switched
1043 * to IGMPv3. If we are, then we must clear any recorded source lists,
1044 * and transition to REPORTING state; the group timer is overloaded
1045 * for group and group-source query responses.
1047 * Unlike IGMPv3, the delay per group should be jittered
1048 * to avoid bursts of IGMPv2 reports.
1051 igmp_v2_update_group(struct in_multi
*inm
, const int timer
)
1053 IGMP_INET_PRINTF(inm
->inm_addr
, ("%s: %s/%s timer=%d\n",
1054 __func__
, _igmp_inet_buf
, if_name(inm
->inm_ifp
),
1057 INM_LOCK_ASSERT_HELD(inm
);
1059 switch (inm
->inm_state
) {
1060 case IGMP_NOT_MEMBER
:
1061 case IGMP_SILENT_MEMBER
:
1063 case IGMP_REPORTING_MEMBER
:
1064 if (inm
->inm_timer
!= 0 &&
1065 inm
->inm_timer
<= timer
) {
1066 IGMP_PRINTF(("%s: REPORTING and timer running, "
1067 "skipping.\n", __func__
));
1071 case IGMP_SG_QUERY_PENDING_MEMBER
:
1072 case IGMP_G_QUERY_PENDING_MEMBER
:
1073 case IGMP_IDLE_MEMBER
:
1074 case IGMP_LAZY_MEMBER
:
1075 case IGMP_AWAKENING_MEMBER
:
1076 IGMP_PRINTF(("%s: ->REPORTING\n", __func__
));
1077 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
1078 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1080 case IGMP_SLEEPING_MEMBER
:
1081 IGMP_PRINTF(("%s: ->AWAKENING\n", __func__
));
1082 inm
->inm_state
= IGMP_AWAKENING_MEMBER
;
1084 case IGMP_LEAVING_MEMBER
:
1088 return inm
->inm_timer
;
1092 * Process a received IGMPv3 general, group-specific or
1093 * group-and-source-specific query.
1094 * Assumes m has already been pulled up to the full IGMP message length.
1095 * Return 0 if successful, otherwise an appropriate error code is returned.
1098 igmp_input_v3_query(struct ifnet
*ifp
, const struct ip
*ip
,
1099 /*const*/ struct igmpv3
*igmpv3
)
1101 struct igmp_ifinfo
*igi
;
1102 struct in_multi
*inm
;
1103 int is_general_query
;
1104 uint32_t maxresp
, nsrc
, qqi
;
1107 struct igmp_tparams itp
= { .qpt
= 0, .it
= 0, .cst
= 0, .sct
= 0 };
1109 IGMP_LOCK_ASSERT_NOTHELD();
1111 is_general_query
= 0;
1113 IGMP_PRINTF(("%s: process v3 query on ifp 0x%llx(%s)\n", __func__
,
1114 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1116 maxresp
= igmpv3
->igmp_code
; /* in 1/10ths of a second */
1117 if (maxresp
>= 128) {
1118 maxresp
= IGMP_MANT(igmpv3
->igmp_code
) <<
1119 (IGMP_EXP(igmpv3
->igmp_code
) + 3);
1123 * Robustness must never be less than 2 for on-wire IGMPv3.
1124 * FUTURE: Check if ifp has IGIF_LOOPBACK set, as we will make
1125 * an exception for interfaces whose IGMPv3 state changes
1126 * are redirected to loopback (e.g. MANET).
1128 qrv
= IGMP_QRV(igmpv3
->igmp_misc
);
1130 IGMP_PRINTF(("%s: clamping qrv %d to %d\n", __func__
,
1131 qrv
, IGMP_RV_INIT
));
1135 qqi
= igmpv3
->igmp_qqi
;
1137 qqi
= IGMP_MANT(igmpv3
->igmp_qqi
) <<
1138 (IGMP_EXP(igmpv3
->igmp_qqi
) + 3);
1141 timer
= maxresp
/ IGMP_TIMER_SCALE
;
1146 nsrc
= ntohs(igmpv3
->igmp_numsrc
);
1149 * Validate address fields and versions upfront before
1150 * accepting v3 query.
1152 if (in_nullhost(igmpv3
->igmp_group
)) {
1154 * IGMPv3 General Query.
1156 * General Queries SHOULD be directed to 224.0.0.1.
1157 * A general query with a source list has undefined
1158 * behaviour; discard it.
1160 IGMPSTAT_INC(igps_rcv_gen_queries
);
1161 if (!in_allhosts(ip
->ip_dst
) || nsrc
> 0) {
1162 IGMPSTAT_INC(igps_rcv_badqueries
);
1163 OIGMPSTAT_INC(igps_rcv_badqueries
);
1166 is_general_query
= 1;
1168 /* Group or group-source specific query. */
1170 IGMPSTAT_INC(igps_rcv_group_queries
);
1172 IGMPSTAT_INC(igps_rcv_gsr_queries
);
1176 igi
= IGMP_IFINFO(ifp
);
1177 VERIFY(igi
!= NULL
);
1180 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
1181 IGMP_PRINTF(("%s: ignore v3 query on IGIF_LOOPBACK "
1182 "ifp 0x%llx(%s)\n", __func__
,
1183 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1189 * Discard the v3 query if we're in Compatibility Mode.
1190 * The RFC is not obviously worded that hosts need to stay in
1191 * compatibility mode until the Old Version Querier Present
1194 if (igi
->igi_version
!= IGMP_VERSION_3
) {
1195 IGMP_PRINTF(("%s: ignore v3 query in v%d mode on "
1196 "ifp 0x%llx(%s)\n", __func__
, igi
->igi_version
,
1197 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1202 itp
.qpt
= igmp_set_version(igi
, IGMP_VERSION_3
);
1205 igi
->igi_qri
= MAX(timer
, IGMP_QRI_MIN
);
1207 IGMP_PRINTF(("%s: qrv %d qi %d qri %d\n", __func__
, igi
->igi_rv
,
1208 igi
->igi_qi
, igi
->igi_qri
));
1210 if (is_general_query
) {
1212 * Schedule a current-state report on this ifp for
1213 * all groups, possibly containing source lists.
1214 * If there is a pending General Query response
1215 * scheduled earlier than the selected delay, do
1216 * not schedule any other reports.
1217 * Otherwise, reset the interface timer.
1219 IGMP_PRINTF(("%s: process v3 general query on ifp 0x%llx(%s)\n",
1220 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1221 if (igi
->igi_v3_timer
== 0 || igi
->igi_v3_timer
>= timer
) {
1222 itp
.it
= igi
->igi_v3_timer
= IGMP_RANDOM_DELAY(timer
);
1228 * Group-source-specific queries are throttled on
1229 * a per-group basis to defeat denial-of-service attempts.
1230 * Queries for groups we are not a member of on this
1231 * link are simply ignored.
1233 in_multihead_lock_shared();
1234 IN_LOOKUP_MULTI(&igmpv3
->igmp_group
, ifp
, inm
);
1235 in_multihead_lock_done();
1242 if (!ratecheck(&inm
->inm_lastgsrtv
,
1244 IGMP_PRINTF(("%s: GS query throttled.\n",
1246 IGMPSTAT_INC(igps_drop_gsr_queries
);
1248 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1252 IGMP_INET_PRINTF(igmpv3
->igmp_group
,
1253 ("process v3 %s query on ifp 0x%llx(%s)\n", _igmp_inet_buf
,
1254 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1256 * If there is a pending General Query response
1257 * scheduled sooner than the selected delay, no
1258 * further report need be scheduled.
1259 * Otherwise, prepare to respond to the
1260 * group-specific or group-and-source query.
1263 itp
.it
= igi
->igi_v3_timer
;
1265 if (itp
.it
== 0 || itp
.it
>= timer
) {
1266 (void) igmp_input_v3_group_query(inm
, timer
, igmpv3
);
1267 itp
.cst
= inm
->inm_timer
;
1270 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1274 IGMP_PRINTF(("%s: v3 general query response scheduled in "
1275 "T+%d seconds on ifp 0x%llx(%s)\n", __func__
, itp
.it
,
1276 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1278 igmp_set_timeout(&itp
);
1284 * Process a recieved IGMPv3 group-specific or group-and-source-specific
1286 * Return <0 if any error occured. Currently this is ignored.
1289 igmp_input_v3_group_query(struct in_multi
*inm
,
1290 int timer
, /*const*/ struct igmpv3
*igmpv3
)
1295 INM_LOCK_ASSERT_HELD(inm
);
1299 switch (inm
->inm_state
) {
1300 case IGMP_NOT_MEMBER
:
1301 case IGMP_SILENT_MEMBER
:
1302 case IGMP_SLEEPING_MEMBER
:
1303 case IGMP_LAZY_MEMBER
:
1304 case IGMP_AWAKENING_MEMBER
:
1305 case IGMP_IDLE_MEMBER
:
1306 case IGMP_LEAVING_MEMBER
:
1308 case IGMP_REPORTING_MEMBER
:
1309 case IGMP_G_QUERY_PENDING_MEMBER
:
1310 case IGMP_SG_QUERY_PENDING_MEMBER
:
1314 nsrc
= ntohs(igmpv3
->igmp_numsrc
);
1317 * Deal with group-specific queries upfront.
1318 * If any group query is already pending, purge any recorded
1319 * source-list state if it exists, and schedule a query response
1320 * for this group-specific query.
1323 if (inm
->inm_state
== IGMP_G_QUERY_PENDING_MEMBER
||
1324 inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
) {
1325 inm_clear_recorded(inm
);
1326 timer
= min(inm
->inm_timer
, timer
);
1328 inm
->inm_state
= IGMP_G_QUERY_PENDING_MEMBER
;
1329 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1334 * Deal with the case where a group-and-source-specific query has
1335 * been received but a group-specific query is already pending.
1337 if (inm
->inm_state
== IGMP_G_QUERY_PENDING_MEMBER
) {
1338 timer
= min(inm
->inm_timer
, timer
);
1339 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1344 * Finally, deal with the case where a group-and-source-specific
1345 * query has been received, where a response to a previous g-s-r
1346 * query exists, or none exists.
1347 * In this case, we need to parse the source-list which the Querier
1348 * has provided us with and check if we have any source list filter
1349 * entries at T1 for these sources. If we do not, there is no need
1350 * schedule a report and the query may be dropped.
1351 * If we do, we must record them and schedule a current-state
1352 * report for those sources.
1353 * FIXME: Handling source lists larger than 1 mbuf requires that
1354 * we pass the mbuf chain pointer down to this function, and use
1355 * m_getptr() to walk the chain.
1357 if (inm
->inm_nsrc
> 0) {
1358 const struct in_addr
*ap
;
1361 ap
= (const struct in_addr
*)(igmpv3
+ 1);
1363 for (i
= 0; i
< nsrc
; i
++, ap
++) {
1364 retval
= inm_record_source(inm
, ap
->s_addr
);
1368 nrecorded
+= retval
;
1370 if (nrecorded
> 0) {
1371 IGMP_PRINTF(("%s: schedule response to SG query\n",
1373 inm
->inm_state
= IGMP_SG_QUERY_PENDING_MEMBER
;
1374 inm
->inm_timer
= IGMP_RANDOM_DELAY(timer
);
1382 * Process a received IGMPv1 host membership report.
1384 * NOTE: 0.0.0.0 workaround breaks const correctness.
1387 igmp_input_v1_report(struct ifnet
*ifp
, struct mbuf
*m
, /*const*/ struct ip
*ip
,
1388 /*const*/ struct igmp
*igmp
)
1390 struct in_ifaddr
*ia
;
1391 struct in_multi
*inm
;
1393 IGMPSTAT_INC(igps_rcv_reports
);
1394 OIGMPSTAT_INC(igps_rcv_reports
);
1396 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
1397 (m
->m_pkthdr
.pkt_flags
& PKTF_LOOP
)) {
1401 if (!IN_MULTICAST(ntohl(igmp
->igmp_group
.s_addr
) ||
1402 !in_hosteq(igmp
->igmp_group
, ip
->ip_dst
))) {
1403 IGMPSTAT_INC(igps_rcv_badreports
);
1404 OIGMPSTAT_INC(igps_rcv_badreports
);
1409 * RFC 3376, Section 4.2.13, 9.2, 9.3:
1410 * Booting clients may use the source address 0.0.0.0. Some
1411 * IGMP daemons may not know how to use IP_RECVIF to determine
1412 * the interface upon which this message was received.
1413 * Replace 0.0.0.0 with the subnet address if told to do so.
1415 if (igmp_recvifkludge
&& in_nullhost(ip
->ip_src
)) {
1418 IFA_LOCK(&ia
->ia_ifa
);
1419 ip
->ip_src
.s_addr
= htonl(ia
->ia_subnet
);
1420 IFA_UNLOCK(&ia
->ia_ifa
);
1421 IFA_REMREF(&ia
->ia_ifa
);
1425 IGMP_INET_PRINTF(igmp
->igmp_group
,
1426 ("process v1 report %s on ifp 0x%llx(%s)\n", _igmp_inet_buf
,
1427 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1430 * IGMPv1 report suppression.
1431 * If we are a member of this group, and our membership should be
1432 * reported, stop our group timer and transition to the 'lazy' state.
1434 in_multihead_lock_shared();
1435 IN_LOOKUP_MULTI(&igmp
->igmp_group
, ifp
, inm
);
1436 in_multihead_lock_done();
1438 struct igmp_ifinfo
*igi
;
1443 VERIFY(igi
!= NULL
);
1445 IGMPSTAT_INC(igps_rcv_ourreports
);
1446 OIGMPSTAT_INC(igps_rcv_ourreports
);
1449 * If we are in IGMPv3 host mode, do not allow the
1450 * other host's IGMPv1 report to suppress our reports
1451 * unless explicitly configured to do so.
1454 if (igi
->igi_version
== IGMP_VERSION_3
) {
1455 if (igmp_legacysupp
) {
1456 igmp_v3_suppress_group_record(inm
);
1460 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1464 INM_LOCK_ASSERT_HELD(inm
);
1467 switch (inm
->inm_state
) {
1468 case IGMP_NOT_MEMBER
:
1469 case IGMP_SILENT_MEMBER
:
1471 case IGMP_IDLE_MEMBER
:
1472 case IGMP_LAZY_MEMBER
:
1473 case IGMP_AWAKENING_MEMBER
:
1474 IGMP_INET_PRINTF(igmp
->igmp_group
,
1475 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1477 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1478 case IGMP_SLEEPING_MEMBER
:
1479 inm
->inm_state
= IGMP_SLEEPING_MEMBER
;
1481 case IGMP_REPORTING_MEMBER
:
1482 IGMP_INET_PRINTF(igmp
->igmp_group
,
1483 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1485 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1486 if (igi
->igi_version
== IGMP_VERSION_1
) {
1487 inm
->inm_state
= IGMP_LAZY_MEMBER
;
1488 } else if (igi
->igi_version
== IGMP_VERSION_2
) {
1489 inm
->inm_state
= IGMP_SLEEPING_MEMBER
;
1492 case IGMP_G_QUERY_PENDING_MEMBER
:
1493 case IGMP_SG_QUERY_PENDING_MEMBER
:
1494 case IGMP_LEAVING_MEMBER
:
1499 INM_REMREF(inm
); /* from IN_LOOKUP_MULTI */
1506 * Process a received IGMPv2 host membership report.
1508 * NOTE: 0.0.0.0 workaround breaks const correctness.
1511 igmp_input_v2_report(struct ifnet
*ifp
, struct mbuf
*m
, /*const*/ struct ip
*ip
,
1512 /*const*/ struct igmp
*igmp
)
1514 struct in_ifaddr
*ia
;
1515 struct in_multi
*inm
;
1518 * Make sure we don't hear our own membership report. Fast
1519 * leave requires knowing that we are the only member of a
1524 IFA_LOCK(&ia
->ia_ifa
);
1525 if (in_hosteq(ip
->ip_src
, IA_SIN(ia
)->sin_addr
)) {
1526 IFA_UNLOCK(&ia
->ia_ifa
);
1527 IFA_REMREF(&ia
->ia_ifa
);
1530 IFA_UNLOCK(&ia
->ia_ifa
);
1533 IGMPSTAT_INC(igps_rcv_reports
);
1534 OIGMPSTAT_INC(igps_rcv_reports
);
1536 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
1537 (m
->m_pkthdr
.pkt_flags
& PKTF_LOOP
)) {
1539 IFA_REMREF(&ia
->ia_ifa
);
1544 if (!IN_MULTICAST(ntohl(igmp
->igmp_group
.s_addr
)) ||
1545 !in_hosteq(igmp
->igmp_group
, ip
->ip_dst
)) {
1547 IFA_REMREF(&ia
->ia_ifa
);
1549 IGMPSTAT_INC(igps_rcv_badreports
);
1550 OIGMPSTAT_INC(igps_rcv_badreports
);
1555 * RFC 3376, Section 4.2.13, 9.2, 9.3:
1556 * Booting clients may use the source address 0.0.0.0. Some
1557 * IGMP daemons may not know how to use IP_RECVIF to determine
1558 * the interface upon which this message was received.
1559 * Replace 0.0.0.0 with the subnet address if told to do so.
1561 if (igmp_recvifkludge
&& in_nullhost(ip
->ip_src
)) {
1563 IFA_LOCK(&ia
->ia_ifa
);
1564 ip
->ip_src
.s_addr
= htonl(ia
->ia_subnet
);
1565 IFA_UNLOCK(&ia
->ia_ifa
);
1569 IFA_REMREF(&ia
->ia_ifa
);
1572 IGMP_INET_PRINTF(igmp
->igmp_group
,
1573 ("process v2 report %s on ifp 0x%llx(%s)\n", _igmp_inet_buf
,
1574 (uint64_t)VM_KERNEL_ADDRPERM(ifp
), if_name(ifp
)));
1577 * IGMPv2 report suppression.
1578 * If we are a member of this group, and our membership should be
1579 * reported, and our group timer is pending or about to be reset,
1580 * stop our group timer by transitioning to the 'lazy' state.
1582 in_multihead_lock_shared();
1583 IN_LOOKUP_MULTI(&igmp
->igmp_group
, ifp
, inm
);
1584 in_multihead_lock_done();
1586 struct igmp_ifinfo
*igi
;
1590 VERIFY(igi
!= NULL
);
1592 IGMPSTAT_INC(igps_rcv_ourreports
);
1593 OIGMPSTAT_INC(igps_rcv_ourreports
);
1596 * If we are in IGMPv3 host mode, do not allow the
1597 * other host's IGMPv1 report to suppress our reports
1598 * unless explicitly configured to do so.
1601 if (igi
->igi_version
== IGMP_VERSION_3
) {
1602 if (igmp_legacysupp
) {
1603 igmp_v3_suppress_group_record(inm
);
1613 switch (inm
->inm_state
) {
1614 case IGMP_NOT_MEMBER
:
1615 case IGMP_SILENT_MEMBER
:
1616 case IGMP_SLEEPING_MEMBER
:
1618 case IGMP_REPORTING_MEMBER
:
1619 case IGMP_IDLE_MEMBER
:
1620 case IGMP_AWAKENING_MEMBER
:
1621 IGMP_INET_PRINTF(igmp
->igmp_group
,
1622 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1623 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(ifp
),
1625 case IGMP_LAZY_MEMBER
:
1626 inm
->inm_state
= IGMP_LAZY_MEMBER
;
1628 case IGMP_G_QUERY_PENDING_MEMBER
:
1629 case IGMP_SG_QUERY_PENDING_MEMBER
:
1630 case IGMP_LEAVING_MEMBER
:
1642 igmp_input(struct mbuf
*m
, int off
)
1652 IGMP_PRINTF(("%s: called w/mbuf (0x%llx,%d)\n", __func__
,
1653 (uint64_t)VM_KERNEL_ADDRPERM(m
), off
));
1655 ifp
= m
->m_pkthdr
.rcvif
;
1657 IGMPSTAT_INC(igps_rcv_total
);
1658 OIGMPSTAT_INC(igps_rcv_total
);
1660 /* Expect 32-bit aligned data pointer on strict-align platforms */
1661 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m
);
1663 ip
= mtod(m
, struct ip
*);
1666 /* By now, ip_len no longer contains the length of IP header */
1667 igmplen
= ip
->ip_len
;
1672 if (igmplen
< IGMP_MINLEN
) {
1673 IGMPSTAT_INC(igps_rcv_tooshort
);
1674 OIGMPSTAT_INC(igps_rcv_tooshort
);
1680 * Always pullup to the minimum size for v1/v2 or v3
1681 * to amortize calls to m_pulldown().
1683 if (igmplen
>= IGMP_V3_QUERY_MINLEN
) {
1684 minlen
= IGMP_V3_QUERY_MINLEN
;
1686 minlen
= IGMP_MINLEN
;
1689 /* A bit more expensive than M_STRUCT_GET, but ensures alignment */
1690 M_STRUCT_GET0(igmp
, struct igmp
*, m
, off
, minlen
);
1692 IGMPSTAT_INC(igps_rcv_tooshort
);
1693 OIGMPSTAT_INC(igps_rcv_tooshort
);
1696 /* N.B.: we assume the packet was correctly aligned in ip_input. */
1699 * Validate checksum.
1701 m
->m_data
+= iphlen
;
1703 if (in_cksum(m
, igmplen
)) {
1704 IGMPSTAT_INC(igps_rcv_badsum
);
1705 OIGMPSTAT_INC(igps_rcv_badsum
);
1709 m
->m_data
-= iphlen
;
1713 * IGMP control traffic is link-scope, and must have a TTL of 1.
1714 * DVMRP traffic (e.g. mrinfo, mtrace) is an exception;
1715 * probe packets may come from beyond the LAN.
1717 if (igmp
->igmp_type
!= IGMP_DVMRP
&& ip
->ip_ttl
!= 1) {
1718 IGMPSTAT_INC(igps_rcv_badttl
);
1723 switch (igmp
->igmp_type
) {
1724 case IGMP_HOST_MEMBERSHIP_QUERY
:
1725 if (igmplen
== IGMP_MINLEN
) {
1726 if (igmp
->igmp_code
== 0) {
1727 queryver
= IGMP_VERSION_1
;
1729 queryver
= IGMP_VERSION_2
;
1731 } else if (igmplen
>= IGMP_V3_QUERY_MINLEN
) {
1732 queryver
= IGMP_VERSION_3
;
1734 IGMPSTAT_INC(igps_rcv_tooshort
);
1735 OIGMPSTAT_INC(igps_rcv_tooshort
);
1740 OIGMPSTAT_INC(igps_rcv_queries
);
1743 case IGMP_VERSION_1
:
1744 IGMPSTAT_INC(igps_rcv_v1v2_queries
);
1745 if (!igmp_v1enable
) {
1748 if (igmp_input_v1_query(ifp
, ip
, igmp
) != 0) {
1754 case IGMP_VERSION_2
:
1755 IGMPSTAT_INC(igps_rcv_v1v2_queries
);
1756 if (!igmp_v2enable
) {
1759 if (igmp_input_v2_query(ifp
, ip
, igmp
) != 0) {
1765 case IGMP_VERSION_3
: {
1766 struct igmpv3
*igmpv3
;
1771 IGMPSTAT_INC(igps_rcv_v3_queries
);
1772 igmpv3
= (struct igmpv3
*)igmp
;
1774 * Validate length based on source count.
1776 nsrc
= ntohs(igmpv3
->igmp_numsrc
);
1778 * The max vaue of nsrc is limited by the
1779 * MTU of the network on which the datagram
1782 if (nsrc
< 0 || nsrc
> IGMP_V3_QUERY_MAX_SRCS
) {
1783 IGMPSTAT_INC(igps_rcv_tooshort
);
1784 OIGMPSTAT_INC(igps_rcv_tooshort
);
1788 srclen
= sizeof(struct in_addr
) * nsrc
;
1789 if (igmplen
< (IGMP_V3_QUERY_MINLEN
+ srclen
)) {
1790 IGMPSTAT_INC(igps_rcv_tooshort
);
1791 OIGMPSTAT_INC(igps_rcv_tooshort
);
1795 igmpv3len
= IGMP_V3_QUERY_MINLEN
+ srclen
;
1797 * A bit more expensive than M_STRUCT_GET,
1798 * but ensures alignment.
1800 M_STRUCT_GET0(igmpv3
, struct igmpv3
*, m
,
1802 if (igmpv3
== NULL
) {
1803 IGMPSTAT_INC(igps_rcv_tooshort
);
1804 OIGMPSTAT_INC(igps_rcv_tooshort
);
1808 * N.B.: we assume the packet was correctly
1809 * aligned in ip_input.
1811 if (igmp_input_v3_query(ifp
, ip
, igmpv3
) != 0) {
1820 case IGMP_v1_HOST_MEMBERSHIP_REPORT
:
1821 if (!igmp_v1enable
) {
1824 if (igmp_input_v1_report(ifp
, m
, ip
, igmp
) != 0) {
1830 case IGMP_v2_HOST_MEMBERSHIP_REPORT
:
1831 if (!igmp_v2enable
) {
1834 if (!ip_checkrouteralert(m
)) {
1835 IGMPSTAT_INC(igps_rcv_nora
);
1837 if (igmp_input_v2_report(ifp
, m
, ip
, igmp
) != 0) {
1843 case IGMP_v3_HOST_MEMBERSHIP_REPORT
:
1845 * Hosts do not need to process IGMPv3 membership reports,
1846 * as report suppression is no longer required.
1848 if (!ip_checkrouteralert(m
)) {
1849 IGMPSTAT_INC(igps_rcv_nora
);
1857 IGMP_LOCK_ASSERT_NOTHELD();
1859 * Pass all valid IGMP packets up to any process(es) listening on a
1866 * Schedule IGMP timer based on various parameters; caller must ensure that
1867 * lock ordering is maintained as this routine acquires IGMP global lock.
1870 igmp_set_timeout(struct igmp_tparams
*itp
)
1872 IGMP_LOCK_ASSERT_NOTHELD();
1873 VERIFY(itp
!= NULL
);
1875 if (itp
->qpt
!= 0 || itp
->it
!= 0 || itp
->cst
!= 0 || itp
->sct
!= 0) {
1877 if (itp
->qpt
!= 0) {
1878 querier_present_timers_running
= 1;
1881 interface_timers_running
= 1;
1883 if (itp
->cst
!= 0) {
1884 current_state_timers_running
= 1;
1886 if (itp
->sct
!= 0) {
1887 state_change_timers_running
= 1;
1889 igmp_sched_timeout();
1895 * IGMP timer handler (per 1 second).
1898 igmp_timeout(void *arg
)
1901 struct ifqueue scq
; /* State-change packets */
1902 struct ifqueue qrq
; /* Query response packets */
1904 struct igmp_ifinfo
*igi
;
1905 struct in_multi
*inm
;
1906 int loop
= 0, uri_sec
= 0;
1907 SLIST_HEAD(, in_multi
) inm_dthead
;
1909 SLIST_INIT(&inm_dthead
);
1912 * Update coarse-grained networking timestamp (in sec.); the idea
1913 * is to piggy-back on the timeout callout to update the counter
1914 * returnable via net_uptime().
1916 net_update_uptime();
1920 IGMP_PRINTF(("%s: qpt %d, it %d, cst %d, sct %d\n", __func__
,
1921 querier_present_timers_running
, interface_timers_running
,
1922 current_state_timers_running
, state_change_timers_running
));
1925 * IGMPv1/v2 querier present timer processing.
1927 if (querier_present_timers_running
) {
1928 querier_present_timers_running
= 0;
1929 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
1931 igmp_v1v2_process_querier_timers(igi
);
1932 if (igi
->igi_v1_timer
> 0 || igi
->igi_v2_timer
> 0) {
1933 querier_present_timers_running
= 1;
1940 * IGMPv3 General Query response timer processing.
1942 if (interface_timers_running
) {
1943 IGMP_PRINTF(("%s: interface timers running\n", __func__
));
1944 interface_timers_running
= 0;
1945 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
1947 if (igi
->igi_version
!= IGMP_VERSION_3
) {
1951 if (igi
->igi_v3_timer
== 0) {
1953 } else if (--igi
->igi_v3_timer
== 0) {
1954 if (igmp_v3_dispatch_general_query(igi
) > 0) {
1955 interface_timers_running
= 1;
1958 interface_timers_running
= 1;
1964 if (!current_state_timers_running
&&
1965 !state_change_timers_running
) {
1969 current_state_timers_running
= 0;
1970 state_change_timers_running
= 0;
1972 memset(&qrq
, 0, sizeof(struct ifqueue
));
1973 qrq
.ifq_maxlen
= IGMP_MAX_G_GS_PACKETS
;
1975 memset(&scq
, 0, sizeof(struct ifqueue
));
1976 scq
.ifq_maxlen
= IGMP_MAX_STATE_CHANGE_PACKETS
;
1978 IGMP_PRINTF(("%s: state change timers running\n", __func__
));
1981 * IGMPv1/v2/v3 host report and state-change timer processing.
1982 * Note: Processing a v3 group timer may remove a node.
1984 LIST_FOREACH(igi
, &igi_head
, igi_link
) {
1985 struct in_multistep step
;
1989 loop
= (igi
->igi_flags
& IGIF_LOOPBACK
) ? 1 : 0;
1990 uri_sec
= IGMP_RANDOM_DELAY(igi
->igi_uri
);
1993 in_multihead_lock_shared();
1994 IN_FIRST_MULTI(step
, inm
);
1995 while (inm
!= NULL
) {
1997 if (inm
->inm_ifp
!= ifp
) {
2002 switch (igi
->igi_version
) {
2003 case IGMP_VERSION_1
:
2004 case IGMP_VERSION_2
:
2005 igmp_v1v2_process_group_timer(inm
,
2008 case IGMP_VERSION_3
:
2009 igmp_v3_process_group_timers(igi
, &qrq
,
2010 &scq
, inm
, uri_sec
);
2016 IN_NEXT_MULTI(step
, inm
);
2018 in_multihead_lock_done();
2021 if (igi
->igi_version
== IGMP_VERSION_1
||
2022 igi
->igi_version
== IGMP_VERSION_2
) {
2023 igmp_dispatch_queue(igi
, &igi
->igi_v2q
, 0, loop
);
2024 } else if (igi
->igi_version
== IGMP_VERSION_3
) {
2026 igmp_dispatch_queue(NULL
, &qrq
, 0, loop
);
2027 igmp_dispatch_queue(NULL
, &scq
, 0, loop
);
2028 VERIFY(qrq
.ifq_len
== 0);
2029 VERIFY(scq
.ifq_len
== 0);
2033 * In case there are still any pending membership reports
2034 * which didn't get drained at version change time.
2036 IF_DRAIN(&igi
->igi_v2q
);
2038 * Release all deferred inm records, and drain any locally
2039 * enqueued packets; do it even if the current IGMP version
2040 * for the link is no longer IGMPv3, in order to handle the
2041 * version change case.
2043 igmp_flush_relq(igi
, (struct igmp_inm_relhead
*)&inm_dthead
);
2044 VERIFY(SLIST_EMPTY(&igi
->igi_relinmhead
));
2052 /* re-arm the timer if there's work to do */
2053 igmp_timeout_run
= 0;
2054 igmp_sched_timeout();
2057 /* Now that we're dropped all locks, release detached records */
2058 IGMP_REMOVE_DETACHED_INM(&inm_dthead
);
2062 igmp_sched_timeout(void)
2064 IGMP_LOCK_ASSERT_HELD();
2066 if (!igmp_timeout_run
&&
2067 (querier_present_timers_running
|| current_state_timers_running
||
2068 interface_timers_running
|| state_change_timers_running
)) {
2069 igmp_timeout_run
= 1;
2070 timeout(igmp_timeout
, NULL
, hz
);
2075 * Free the in_multi reference(s) for this IGMP lifecycle.
2077 * Caller must be holding igi_lock.
2080 igmp_flush_relq(struct igmp_ifinfo
*igi
, struct igmp_inm_relhead
*inm_dthead
)
2082 struct in_multi
*inm
;
2085 IGI_LOCK_ASSERT_HELD(igi
);
2086 inm
= SLIST_FIRST(&igi
->igi_relinmhead
);
2090 SLIST_REMOVE_HEAD(&igi
->igi_relinmhead
, inm_nrele
);
2093 in_multihead_lock_exclusive();
2095 VERIFY(inm
->inm_nrelecnt
!= 0);
2096 inm
->inm_nrelecnt
--;
2097 lastref
= in_multi_detach(inm
);
2098 VERIFY(!lastref
|| (!(inm
->inm_debug
& IFD_ATTACHED
) &&
2099 inm
->inm_reqcnt
== 0));
2101 in_multihead_lock_done();
2102 /* from igi_relinmhead */
2104 /* from in_multihead list */
2107 * Defer releasing our final reference, as we
2108 * are holding the IGMP lock at this point, and
2109 * we could end up with locking issues later on
2110 * (while issuing SIOCDELMULTI) when this is the
2111 * final reference count. Let the caller do it
2114 IGMP_ADD_DETACHED_INM(inm_dthead
, inm
);
2122 * Update host report group timer for IGMPv1/v2.
2123 * Will update the global pending timer flags.
2126 igmp_v1v2_process_group_timer(struct in_multi
*inm
, const int igmp_version
)
2128 int report_timer_expired
;
2130 IGMP_LOCK_ASSERT_HELD();
2131 INM_LOCK_ASSERT_HELD(inm
);
2132 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2134 if (inm
->inm_timer
== 0) {
2135 report_timer_expired
= 0;
2136 } else if (--inm
->inm_timer
== 0) {
2137 report_timer_expired
= 1;
2139 current_state_timers_running
= 1;
2140 /* caller will schedule timer */
2144 switch (inm
->inm_state
) {
2145 case IGMP_NOT_MEMBER
:
2146 case IGMP_SILENT_MEMBER
:
2147 case IGMP_IDLE_MEMBER
:
2148 case IGMP_LAZY_MEMBER
:
2149 case IGMP_SLEEPING_MEMBER
:
2150 case IGMP_AWAKENING_MEMBER
:
2152 case IGMP_REPORTING_MEMBER
:
2153 if (report_timer_expired
) {
2154 inm
->inm_state
= IGMP_IDLE_MEMBER
;
2155 (void) igmp_v1v2_queue_report(inm
,
2156 (igmp_version
== IGMP_VERSION_2
) ?
2157 IGMP_v2_HOST_MEMBERSHIP_REPORT
:
2158 IGMP_v1_HOST_MEMBERSHIP_REPORT
);
2159 INM_LOCK_ASSERT_HELD(inm
);
2160 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2163 case IGMP_G_QUERY_PENDING_MEMBER
:
2164 case IGMP_SG_QUERY_PENDING_MEMBER
:
2165 case IGMP_LEAVING_MEMBER
:
2171 * Update a group's timers for IGMPv3.
2172 * Will update the global pending timer flags.
2173 * Note: Unlocked read from igi.
2176 igmp_v3_process_group_timers(struct igmp_ifinfo
*igi
,
2177 struct ifqueue
*qrq
, struct ifqueue
*scq
,
2178 struct in_multi
*inm
, const int uri_sec
)
2180 int query_response_timer_expired
;
2181 int state_change_retransmit_timer_expired
;
2183 IGMP_LOCK_ASSERT_HELD();
2184 INM_LOCK_ASSERT_HELD(inm
);
2185 IGI_LOCK_ASSERT_HELD(igi
);
2186 VERIFY(igi
== inm
->inm_igi
);
2188 query_response_timer_expired
= 0;
2189 state_change_retransmit_timer_expired
= 0;
2192 * During a transition from v1/v2 compatibility mode back to v3,
2193 * a group record in REPORTING state may still have its group
2194 * timer active. This is a no-op in this function; it is easier
2195 * to deal with it here than to complicate the timeout path.
2197 if (inm
->inm_timer
== 0) {
2198 query_response_timer_expired
= 0;
2199 } else if (--inm
->inm_timer
== 0) {
2200 query_response_timer_expired
= 1;
2202 current_state_timers_running
= 1;
2203 /* caller will schedule timer */
2206 if (inm
->inm_sctimer
== 0) {
2207 state_change_retransmit_timer_expired
= 0;
2208 } else if (--inm
->inm_sctimer
== 0) {
2209 state_change_retransmit_timer_expired
= 1;
2211 state_change_timers_running
= 1;
2212 /* caller will schedule timer */
2215 /* We are in timer callback, so be quick about it. */
2216 if (!state_change_retransmit_timer_expired
&&
2217 !query_response_timer_expired
) {
2221 switch (inm
->inm_state
) {
2222 case IGMP_NOT_MEMBER
:
2223 case IGMP_SILENT_MEMBER
:
2224 case IGMP_SLEEPING_MEMBER
:
2225 case IGMP_LAZY_MEMBER
:
2226 case IGMP_AWAKENING_MEMBER
:
2227 case IGMP_IDLE_MEMBER
:
2229 case IGMP_G_QUERY_PENDING_MEMBER
:
2230 case IGMP_SG_QUERY_PENDING_MEMBER
:
2232 * Respond to a previously pending Group-Specific
2233 * or Group-and-Source-Specific query by enqueueing
2234 * the appropriate Current-State report for
2235 * immediate transmission.
2237 if (query_response_timer_expired
) {
2240 retval
= igmp_v3_enqueue_group_record(qrq
, inm
, 0, 1,
2241 (inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
));
2242 IGMP_PRINTF(("%s: enqueue record = %d\n",
2244 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2245 /* XXX Clear recorded sources for next time. */
2246 inm_clear_recorded(inm
);
2249 case IGMP_REPORTING_MEMBER
:
2250 case IGMP_LEAVING_MEMBER
:
2251 if (state_change_retransmit_timer_expired
) {
2253 * State-change retransmission timer fired.
2254 * If there are any further pending retransmissions,
2255 * set the global pending state-change flag, and
2258 if (--inm
->inm_scrv
> 0) {
2259 inm
->inm_sctimer
= uri_sec
;
2260 state_change_timers_running
= 1;
2261 /* caller will schedule timer */
2264 * Retransmit the previously computed state-change
2265 * report. If there are no further pending
2266 * retransmissions, the mbuf queue will be consumed.
2267 * Update T0 state to T1 as we have now sent
2270 (void) igmp_v3_merge_state_changes(inm
, scq
);
2273 IGMP_INET_PRINTF(inm
->inm_addr
,
2274 ("%s: T1 -> T0 for %s/%s\n", __func__
,
2275 _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
2278 * If we are leaving the group for good, make sure
2279 * we release IGMP's reference to it.
2280 * This release must be deferred using a SLIST,
2281 * as we are called from a loop which traverses
2282 * the in_multihead list.
2284 if (inm
->inm_state
== IGMP_LEAVING_MEMBER
&&
2285 inm
->inm_scrv
== 0) {
2286 inm
->inm_state
= IGMP_NOT_MEMBER
;
2288 * A reference has already been held in
2289 * igmp_final_leave() for this inm, so
2290 * no need to hold another one. We also
2291 * bumped up its request count then, so
2292 * that it stays in in_multihead. Both
2293 * of them will be released when it is
2294 * dequeued later on.
2296 VERIFY(inm
->inm_nrelecnt
!= 0);
2297 SLIST_INSERT_HEAD(&igi
->igi_relinmhead
,
2306 * Suppress a group's pending response to a group or source/group query.
2308 * Do NOT suppress state changes. This leads to IGMPv3 inconsistency.
2309 * Do NOT update ST1/ST0 as this operation merely suppresses
2310 * the currently pending group record.
2311 * Do NOT suppress the response to a general query. It is possible but
2312 * it would require adding another state or flag.
2315 igmp_v3_suppress_group_record(struct in_multi
*inm
)
2317 INM_LOCK_ASSERT_HELD(inm
);
2318 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2320 VERIFY(inm
->inm_igi
->igi_version
== IGMP_VERSION_3
);
2322 if (inm
->inm_state
!= IGMP_G_QUERY_PENDING_MEMBER
||
2323 inm
->inm_state
!= IGMP_SG_QUERY_PENDING_MEMBER
) {
2327 if (inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
) {
2328 inm_clear_recorded(inm
);
2332 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2336 * Switch to a different IGMP version on the given interface,
2337 * as per Section 7.2.1.
2340 igmp_set_version(struct igmp_ifinfo
*igi
, const int igmp_version
)
2342 int old_version_timer
;
2344 IGI_LOCK_ASSERT_HELD(igi
);
2346 IGMP_PRINTF(("%s: switching to v%d on ifp 0x%llx(%s)\n", __func__
,
2347 igmp_version
, (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2348 if_name(igi
->igi_ifp
)));
2350 if (igmp_version
== IGMP_VERSION_1
|| igmp_version
== IGMP_VERSION_2
) {
2352 * Compute the "Older Version Querier Present" timer as per
2353 * Section 8.12, in seconds.
2355 old_version_timer
= igi
->igi_rv
* igi
->igi_qi
+ igi
->igi_qri
;
2357 if (igmp_version
== IGMP_VERSION_1
) {
2358 igi
->igi_v1_timer
= old_version_timer
;
2359 igi
->igi_v2_timer
= 0;
2360 } else if (igmp_version
== IGMP_VERSION_2
) {
2361 igi
->igi_v1_timer
= 0;
2362 igi
->igi_v2_timer
= old_version_timer
;
2366 if (igi
->igi_v1_timer
== 0 && igi
->igi_v2_timer
> 0) {
2367 if (igi
->igi_version
!= IGMP_VERSION_2
) {
2368 igi
->igi_version
= IGMP_VERSION_2
;
2369 igmp_v3_cancel_link_timers(igi
);
2371 } else if (igi
->igi_v1_timer
> 0) {
2372 if (igi
->igi_version
!= IGMP_VERSION_1
) {
2373 igi
->igi_version
= IGMP_VERSION_1
;
2374 igmp_v3_cancel_link_timers(igi
);
2378 IGI_LOCK_ASSERT_HELD(igi
);
2380 return MAX(igi
->igi_v1_timer
, igi
->igi_v2_timer
);
2384 * Cancel pending IGMPv3 timers for the given link and all groups
2385 * joined on it; state-change, general-query, and group-query timers.
2387 * Only ever called on a transition from v3 to Compatibility mode. Kill
2388 * the timers stone dead (this may be expensive for large N groups), they
2389 * will be restarted if Compatibility Mode deems that they must be due to
2393 igmp_v3_cancel_link_timers(struct igmp_ifinfo
*igi
)
2396 struct in_multi
*inm
;
2397 struct in_multistep step
;
2399 IGI_LOCK_ASSERT_HELD(igi
);
2401 IGMP_PRINTF(("%s: cancel v3 timers on ifp 0x%llx(%s)\n", __func__
,
2402 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
), if_name(igi
->igi_ifp
)));
2405 * Stop the v3 General Query Response on this link stone dead.
2406 * If timer is woken up due to interface_timers_running,
2407 * the flag will be cleared if there are no pending link timers.
2409 igi
->igi_v3_timer
= 0;
2412 * Now clear the current-state and state-change report timers
2413 * for all memberships scoped to this link.
2418 in_multihead_lock_shared();
2419 IN_FIRST_MULTI(step
, inm
);
2420 while (inm
!= NULL
) {
2422 if (inm
->inm_ifp
!= ifp
) {
2426 switch (inm
->inm_state
) {
2427 case IGMP_NOT_MEMBER
:
2428 case IGMP_SILENT_MEMBER
:
2429 case IGMP_IDLE_MEMBER
:
2430 case IGMP_LAZY_MEMBER
:
2431 case IGMP_SLEEPING_MEMBER
:
2432 case IGMP_AWAKENING_MEMBER
:
2434 * These states are either not relevant in v3 mode,
2435 * or are unreported. Do nothing.
2438 case IGMP_LEAVING_MEMBER
:
2440 * If we are leaving the group and switching to
2441 * compatibility mode, we need to release the final
2442 * reference held for issuing the INCLUDE {}, and
2443 * transition to REPORTING to ensure the host leave
2444 * message is sent upstream to the old querier --
2445 * transition to NOT would lose the leave and race.
2446 * During igmp_final_leave(), we bumped up both the
2447 * request and reference counts. Since we cannot
2448 * call in_multi_detach() here, defer this task to
2449 * the timer routine.
2451 VERIFY(inm
->inm_nrelecnt
!= 0);
2453 SLIST_INSERT_HEAD(&igi
->igi_relinmhead
, inm
, inm_nrele
);
2456 case IGMP_G_QUERY_PENDING_MEMBER
:
2457 case IGMP_SG_QUERY_PENDING_MEMBER
:
2458 inm_clear_recorded(inm
);
2460 case IGMP_REPORTING_MEMBER
:
2461 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2465 * Always clear state-change and group report timers.
2466 * Free any pending IGMPv3 state-change records.
2468 inm
->inm_sctimer
= 0;
2470 IF_DRAIN(&inm
->inm_scq
);
2473 IN_NEXT_MULTI(step
, inm
);
2475 in_multihead_lock_done();
2481 * Update the Older Version Querier Present timers for a link.
2482 * See Section 7.2.1 of RFC 3376.
2485 igmp_v1v2_process_querier_timers(struct igmp_ifinfo
*igi
)
2487 IGI_LOCK_ASSERT_HELD(igi
);
2489 if (igi
->igi_v1_timer
== 0 && igi
->igi_v2_timer
== 0) {
2491 * IGMPv1 and IGMPv2 Querier Present timers expired.
2495 if (igi
->igi_version
!= IGMP_VERSION_3
) {
2496 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2497 "on 0x%llx(%s)\n", __func__
,
2498 igi
->igi_version
, IGMP_VERSION_3
,
2499 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2500 if_name(igi
->igi_ifp
)));
2501 igi
->igi_version
= IGMP_VERSION_3
;
2502 IF_DRAIN(&igi
->igi_v2q
);
2504 } else if (igi
->igi_v1_timer
== 0 && igi
->igi_v2_timer
> 0) {
2506 * IGMPv1 Querier Present timer expired,
2507 * IGMPv2 Querier Present timer running.
2508 * If IGMPv2 was disabled since last timeout,
2510 * If IGMPv2 is enabled, revert to IGMPv2.
2512 if (!igmp_v2enable
) {
2513 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2514 "on 0x%llx(%s%d)\n", __func__
,
2515 igi
->igi_version
, IGMP_VERSION_3
,
2516 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2517 igi
->igi_ifp
->if_name
, igi
->igi_ifp
->if_unit
));
2518 igi
->igi_v2_timer
= 0;
2519 igi
->igi_version
= IGMP_VERSION_3
;
2520 IF_DRAIN(&igi
->igi_v2q
);
2522 --igi
->igi_v2_timer
;
2523 if (igi
->igi_version
!= IGMP_VERSION_2
) {
2524 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2525 "on 0x%llx(%s)\n", __func__
,
2526 igi
->igi_version
, IGMP_VERSION_2
,
2527 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2528 if_name(igi
->igi_ifp
)));
2529 igi
->igi_version
= IGMP_VERSION_2
;
2530 IF_DRAIN(&igi
->igi_gq
);
2531 igmp_v3_cancel_link_timers(igi
);
2534 } else if (igi
->igi_v1_timer
> 0) {
2536 * IGMPv1 Querier Present timer running.
2537 * Stop IGMPv2 timer if running.
2539 * If IGMPv1 was disabled since last timeout,
2541 * If IGMPv1 is enabled, reset IGMPv2 timer if running.
2543 if (!igmp_v1enable
) {
2544 IGMP_PRINTF(("%s: transition from v%d -> v%d "
2545 "on 0x%llx(%s%d)\n", __func__
,
2546 igi
->igi_version
, IGMP_VERSION_3
,
2547 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2548 igi
->igi_ifp
->if_name
, igi
->igi_ifp
->if_unit
));
2549 igi
->igi_v1_timer
= 0;
2550 igi
->igi_version
= IGMP_VERSION_3
;
2551 IF_DRAIN(&igi
->igi_v2q
);
2553 --igi
->igi_v1_timer
;
2555 if (igi
->igi_v2_timer
> 0) {
2556 IGMP_PRINTF(("%s: cancel v2 timer on 0x%llx(%s%d)\n",
2558 (uint64_t)VM_KERNEL_ADDRPERM(igi
->igi_ifp
),
2559 igi
->igi_ifp
->if_name
, igi
->igi_ifp
->if_unit
));
2560 igi
->igi_v2_timer
= 0;
2566 * Dispatch an IGMPv1/v2 host report or leave message.
2567 * These are always small enough to fit inside a single mbuf.
2570 igmp_v1v2_queue_report(struct in_multi
*inm
, const int type
)
2578 INM_LOCK_ASSERT_HELD(inm
);
2579 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
2583 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
2587 MH_ALIGN(m
, sizeof(struct ip
) + sizeof(struct igmp
));
2589 m
->m_pkthdr
.len
= sizeof(struct ip
) + sizeof(struct igmp
);
2591 m
->m_data
+= sizeof(struct ip
);
2592 m
->m_len
= sizeof(struct igmp
);
2594 igmp
= mtod(m
, struct igmp
*);
2595 igmp
->igmp_type
= type
;
2596 igmp
->igmp_code
= 0;
2597 igmp
->igmp_group
= inm
->inm_addr
;
2598 igmp
->igmp_cksum
= 0;
2599 igmp
->igmp_cksum
= in_cksum(m
, sizeof(struct igmp
));
2601 m
->m_data
-= sizeof(struct ip
);
2602 m
->m_len
+= sizeof(struct ip
);
2604 ip
= mtod(m
, struct ip
*);
2606 ip
->ip_len
= sizeof(struct ip
) + sizeof(struct igmp
);
2608 ip
->ip_p
= IPPROTO_IGMP
;
2609 ip
->ip_src
.s_addr
= INADDR_ANY
;
2611 if (type
== IGMP_HOST_LEAVE_MESSAGE
) {
2612 ip
->ip_dst
.s_addr
= htonl(INADDR_ALLRTRS_GROUP
);
2614 ip
->ip_dst
= inm
->inm_addr
;
2617 igmp_save_context(m
, ifp
);
2619 m
->m_flags
|= M_IGMPV2
;
2620 if (inm
->inm_igi
->igi_flags
& IGIF_LOOPBACK
) {
2621 m
->m_flags
|= M_IGMP_LOOP
;
2625 * Due to the fact that at this point we are possibly holding
2626 * in_multihead_lock in shared or exclusive mode, we can't call
2627 * igmp_sendpkt() here since that will eventually call ip_output(),
2628 * which will try to lock in_multihead_lock and cause a deadlock.
2629 * Instead we defer the work to the igmp_timeout() thread, thus
2630 * avoiding unlocking in_multihead_lock here.
2632 if (IF_QFULL(&inm
->inm_igi
->igi_v2q
)) {
2633 IGMP_PRINTF(("%s: v1/v2 outbound queue full\n", __func__
));
2637 IF_ENQUEUE(&inm
->inm_igi
->igi_v2q
, m
);
2644 * Process a state change from the upper layer for the given IPv4 group.
2646 * Each socket holds a reference on the in_multi in its own ip_moptions.
2647 * The socket layer will have made the necessary updates to the group
2648 * state, it is now up to IGMP to issue a state change report if there
2649 * has been any change between T0 (when the last state-change was issued)
2652 * We use the IGMPv3 state machine at group level. The IGMP module
2653 * however makes the decision as to which IGMP protocol version to speak.
2654 * A state change *from* INCLUDE {} always means an initial join.
2655 * A state change *to* INCLUDE {} always means a final leave.
2657 * FUTURE: If IGIF_V3LITE is enabled for this interface, then we can
2658 * save ourselves a bunch of work; any exclusive mode groups need not
2659 * compute source filter lists.
2662 igmp_change_state(struct in_multi
*inm
, struct igmp_tparams
*itp
)
2664 struct igmp_ifinfo
*igi
;
2668 VERIFY(itp
!= NULL
);
2669 bzero(itp
, sizeof(*itp
));
2671 INM_LOCK_ASSERT_HELD(inm
);
2672 VERIFY(inm
->inm_igi
!= NULL
);
2673 IGI_LOCK_ASSERT_NOTHELD(inm
->inm_igi
);
2676 * Try to detect if the upper layer just asked us to change state
2677 * for an interface which has now gone away.
2679 VERIFY(inm
->inm_ifma
!= NULL
);
2680 ifp
= inm
->inm_ifma
->ifma_ifp
;
2682 * Sanity check that netinet's notion of ifp is the same as net's.
2684 VERIFY(inm
->inm_ifp
== ifp
);
2686 igi
= IGMP_IFINFO(ifp
);
2687 VERIFY(igi
!= NULL
);
2690 * If we detect a state transition to or from MCAST_UNDEFINED
2691 * for this group, then we are starting or finishing an IGMP
2692 * life cycle for this group.
2694 if (inm
->inm_st
[1].iss_fmode
!= inm
->inm_st
[0].iss_fmode
) {
2695 IGMP_PRINTF(("%s: inm transition %d -> %d\n", __func__
,
2696 inm
->inm_st
[0].iss_fmode
, inm
->inm_st
[1].iss_fmode
));
2697 if (inm
->inm_st
[0].iss_fmode
== MCAST_UNDEFINED
) {
2698 IGMP_PRINTF(("%s: initial join\n", __func__
));
2699 error
= igmp_initial_join(inm
, igi
, itp
);
2701 } else if (inm
->inm_st
[1].iss_fmode
== MCAST_UNDEFINED
) {
2702 IGMP_PRINTF(("%s: final leave\n", __func__
));
2703 igmp_final_leave(inm
, igi
, itp
);
2707 IGMP_PRINTF(("%s: filter set change\n", __func__
));
2710 error
= igmp_handle_state_change(inm
, igi
, itp
);
2716 * Perform the initial join for an IGMP group.
2718 * When joining a group:
2719 * If the group should have its IGMP traffic suppressed, do nothing.
2720 * IGMPv1 starts sending IGMPv1 host membership reports.
2721 * IGMPv2 starts sending IGMPv2 host membership reports.
2722 * IGMPv3 will schedule an IGMPv3 state-change report containing the
2723 * initial state of the membership.
2726 igmp_initial_join(struct in_multi
*inm
, struct igmp_ifinfo
*igi
,
2727 struct igmp_tparams
*itp
)
2730 struct ifqueue
*ifq
;
2731 int error
, retval
, syncstates
;
2733 INM_LOCK_ASSERT_HELD(inm
);
2734 IGI_LOCK_ASSERT_NOTHELD(igi
);
2735 VERIFY(itp
!= NULL
);
2737 IGMP_INET_PRINTF(inm
->inm_addr
,
2738 ("%s: initial join %s on ifp 0x%llx(%s)\n", __func__
,
2739 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
),
2740 if_name(inm
->inm_ifp
)));
2748 VERIFY(igi
->igi_ifp
== ifp
);
2751 * Groups joined on loopback or marked as 'not reported',
2752 * e.g. 224.0.0.1, enter the IGMP_SILENT_MEMBER state and
2753 * are never reported in any IGMP protocol exchanges.
2754 * All other groups enter the appropriate IGMP state machine
2755 * for the version in use on this link.
2756 * A link marked as IGIF_SILENT causes IGMP to be completely
2757 * disabled for the link.
2759 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
2760 (igi
->igi_flags
& IGIF_SILENT
) ||
2761 !igmp_isgroupreported(inm
->inm_addr
)) {
2762 IGMP_PRINTF(("%s: not kicking state machine for silent group\n",
2764 inm
->inm_state
= IGMP_SILENT_MEMBER
;
2768 * Deal with overlapping in_multi lifecycle.
2769 * If this group was LEAVING, then make sure
2770 * we drop the reference we picked up to keep the
2771 * group around for the final INCLUDE {} enqueue.
2772 * Since we cannot call in_multi_detach() here,
2773 * defer this task to the timer routine.
2775 if (igi
->igi_version
== IGMP_VERSION_3
&&
2776 inm
->inm_state
== IGMP_LEAVING_MEMBER
) {
2777 VERIFY(inm
->inm_nrelecnt
!= 0);
2778 SLIST_INSERT_HEAD(&igi
->igi_relinmhead
, inm
, inm_nrele
);
2781 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
2783 switch (igi
->igi_version
) {
2784 case IGMP_VERSION_1
:
2785 case IGMP_VERSION_2
:
2786 inm
->inm_state
= IGMP_IDLE_MEMBER
;
2787 error
= igmp_v1v2_queue_report(inm
,
2788 (igi
->igi_version
== IGMP_VERSION_2
) ?
2789 IGMP_v2_HOST_MEMBERSHIP_REPORT
:
2790 IGMP_v1_HOST_MEMBERSHIP_REPORT
);
2792 INM_LOCK_ASSERT_HELD(inm
);
2793 IGI_LOCK_ASSERT_HELD(igi
);
2797 IGMP_RANDOM_DELAY(IGMP_V1V2_MAX_RI
);
2802 case IGMP_VERSION_3
:
2804 * Defer update of T0 to T1, until the first copy
2805 * of the state change has been transmitted.
2810 * Immediately enqueue a State-Change Report for
2811 * this interface, freeing any previous reports.
2812 * Don't kick the timers if there is nothing to do,
2813 * or if an error occurred.
2815 ifq
= &inm
->inm_scq
;
2817 retval
= igmp_v3_enqueue_group_record(ifq
, inm
, 1,
2819 itp
->cst
= (ifq
->ifq_len
> 0);
2820 IGMP_PRINTF(("%s: enqueue record = %d\n",
2823 error
= retval
* -1;
2828 * Schedule transmission of pending state-change
2829 * report up to RV times for this link. The timer
2830 * will fire at the next igmp_timeout (1 second),
2831 * giving us an opportunity to merge the reports.
2833 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
2836 VERIFY(igi
->igi_rv
> 1);
2837 inm
->inm_scrv
= igi
->igi_rv
;
2839 inm
->inm_sctimer
= 1;
2849 * Only update the T0 state if state change is atomic,
2850 * i.e. we don't need to wait for a timer to fire before we
2851 * can consider the state change to have been communicated.
2855 IGMP_INET_PRINTF(inm
->inm_addr
,
2856 ("%s: T1 -> T0 for %s/%s\n", __func__
,
2857 _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
2864 * Issue an intermediate state change during the IGMP life-cycle.
2867 igmp_handle_state_change(struct in_multi
*inm
, struct igmp_ifinfo
*igi
,
2868 struct igmp_tparams
*itp
)
2873 INM_LOCK_ASSERT_HELD(inm
);
2874 IGI_LOCK_ASSERT_NOTHELD(igi
);
2875 VERIFY(itp
!= NULL
);
2877 IGMP_INET_PRINTF(inm
->inm_addr
,
2878 ("%s: state change for %s on ifp 0x%llx(%s)\n", __func__
,
2879 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
),
2880 if_name(inm
->inm_ifp
)));
2885 VERIFY(igi
->igi_ifp
== ifp
);
2887 if ((ifp
->if_flags
& IFF_LOOPBACK
) ||
2888 (igi
->igi_flags
& IGIF_SILENT
) ||
2889 !igmp_isgroupreported(inm
->inm_addr
) ||
2890 (igi
->igi_version
!= IGMP_VERSION_3
)) {
2892 if (!igmp_isgroupreported(inm
->inm_addr
)) {
2893 IGMP_PRINTF(("%s: not kicking state "
2894 "machine for silent group\n", __func__
));
2896 IGMP_PRINTF(("%s: nothing to do\n", __func__
));
2898 IGMP_INET_PRINTF(inm
->inm_addr
,
2899 ("%s: T1 -> T0 for %s/%s\n", __func__
,
2900 _igmp_inet_buf
, inm
->inm_ifp
->if_name
));
2904 IF_DRAIN(&inm
->inm_scq
);
2906 retval
= igmp_v3_enqueue_group_record(&inm
->inm_scq
, inm
, 1, 0, 0);
2907 itp
->cst
= (inm
->inm_scq
.ifq_len
> 0);
2908 IGMP_PRINTF(("%s: enqueue record = %d\n", __func__
, retval
));
2915 * If record(s) were enqueued, start the state-change
2916 * report timer for this group.
2918 inm
->inm_scrv
= ((igi
->igi_flags
& IGIF_LOOPBACK
) ? 1 : igi
->igi_rv
);
2919 inm
->inm_sctimer
= 1;
2927 * Perform the final leave for an IGMP group.
2929 * When leaving a group:
2930 * IGMPv1 does nothing.
2931 * IGMPv2 sends a host leave message, if and only if we are the reporter.
2932 * IGMPv3 enqueues a state-change report containing a transition
2933 * to INCLUDE {} for immediate transmission.
2936 igmp_final_leave(struct in_multi
*inm
, struct igmp_ifinfo
*igi
,
2937 struct igmp_tparams
*itp
)
2941 INM_LOCK_ASSERT_HELD(inm
);
2942 IGI_LOCK_ASSERT_NOTHELD(igi
);
2943 VERIFY(itp
!= NULL
);
2945 IGMP_INET_PRINTF(inm
->inm_addr
,
2946 ("%s: final leave %s on ifp 0x%llx(%s)\n", __func__
,
2947 _igmp_inet_buf
, (uint64_t)VM_KERNEL_ADDRPERM(inm
->inm_ifp
),
2948 if_name(inm
->inm_ifp
)));
2950 switch (inm
->inm_state
) {
2951 case IGMP_NOT_MEMBER
:
2952 case IGMP_SILENT_MEMBER
:
2953 case IGMP_LEAVING_MEMBER
:
2954 /* Already leaving or left; do nothing. */
2955 IGMP_PRINTF(("%s: not kicking state machine for silent group\n",
2958 case IGMP_REPORTING_MEMBER
:
2959 case IGMP_IDLE_MEMBER
:
2960 case IGMP_G_QUERY_PENDING_MEMBER
:
2961 case IGMP_SG_QUERY_PENDING_MEMBER
:
2963 if (igi
->igi_version
== IGMP_VERSION_2
) {
2964 if (inm
->inm_state
== IGMP_G_QUERY_PENDING_MEMBER
||
2965 inm
->inm_state
== IGMP_SG_QUERY_PENDING_MEMBER
) {
2966 panic("%s: IGMPv3 state reached, not IGMPv3 "
2967 "mode\n", __func__
);
2970 /* scheduler timer if enqueue is successful */
2971 itp
->cst
= (igmp_v1v2_queue_report(inm
,
2972 IGMP_HOST_LEAVE_MESSAGE
) == 0);
2974 INM_LOCK_ASSERT_HELD(inm
);
2975 IGI_LOCK_ASSERT_HELD(igi
);
2977 inm
->inm_state
= IGMP_NOT_MEMBER
;
2978 } else if (igi
->igi_version
== IGMP_VERSION_3
) {
2980 * Stop group timer and all pending reports.
2981 * Immediately enqueue a state-change report
2982 * TO_IN {} to be sent on the next timeout,
2983 * giving us an opportunity to merge reports.
2985 IF_DRAIN(&inm
->inm_scq
);
2987 if (igi
->igi_flags
& IGIF_LOOPBACK
) {
2990 inm
->inm_scrv
= igi
->igi_rv
;
2992 IGMP_INET_PRINTF(inm
->inm_addr
,
2993 ("%s: Leaving %s/%s with %d "
2994 "pending retransmissions.\n", __func__
,
2995 _igmp_inet_buf
, if_name(inm
->inm_ifp
),
2997 if (inm
->inm_scrv
== 0) {
2998 inm
->inm_state
= IGMP_NOT_MEMBER
;
2999 inm
->inm_sctimer
= 0;
3003 * Stick around in the in_multihead list;
3004 * the final detach will be issued by
3005 * igmp_v3_process_group_timers() when
3006 * the retransmit timer expires.
3008 INM_ADDREF_LOCKED(inm
);
3009 VERIFY(inm
->inm_debug
& IFD_ATTACHED
);
3011 VERIFY(inm
->inm_reqcnt
>= 1);
3012 inm
->inm_nrelecnt
++;
3013 VERIFY(inm
->inm_nrelecnt
!= 0);
3015 retval
= igmp_v3_enqueue_group_record(
3016 &inm
->inm_scq
, inm
, 1, 0, 0);
3017 itp
->cst
= (inm
->inm_scq
.ifq_len
> 0);
3018 KASSERT(retval
!= 0,
3019 ("%s: enqueue record = %d\n", __func__
,
3022 inm
->inm_state
= IGMP_LEAVING_MEMBER
;
3023 inm
->inm_sctimer
= 1;
3030 case IGMP_LAZY_MEMBER
:
3031 case IGMP_SLEEPING_MEMBER
:
3032 case IGMP_AWAKENING_MEMBER
:
3033 /* Our reports are suppressed; do nothing. */
3039 IGMP_INET_PRINTF(inm
->inm_addr
,
3040 ("%s: T1 -> T0 for %s/%s\n", __func__
,
3041 _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
3042 inm
->inm_st
[1].iss_fmode
= MCAST_UNDEFINED
;
3043 IGMP_INET_PRINTF(inm
->inm_addr
,
3044 ("%s: T1 now MCAST_UNDEFINED for %s/%s\n",
3045 __func__
, _igmp_inet_buf
, if_name(inm
->inm_ifp
)));
3050 * Enqueue an IGMPv3 group record to the given output queue.
3052 * XXX This function could do with having the allocation code
3053 * split out, and the multiple-tree-walks coalesced into a single
3054 * routine as has been done in igmp_v3_enqueue_filter_change().
3056 * If is_state_change is zero, a current-state record is appended.
3057 * If is_state_change is non-zero, a state-change report is appended.
3059 * If is_group_query is non-zero, an mbuf packet chain is allocated.
3060 * If is_group_query is zero, and if there is a packet with free space
3061 * at the tail of the queue, it will be appended to providing there
3062 * is enough free space.
3063 * Otherwise a new mbuf packet chain is allocated.
3065 * If is_source_query is non-zero, each source is checked to see if
3066 * it was recorded for a Group-Source query, and will be omitted if
3067 * it is not both in-mode and recorded.
3069 * The function will attempt to allocate leading space in the packet
3070 * for the IP/IGMP header to be prepended without fragmenting the chain.
3072 * If successful the size of all data appended to the queue is returned,
3073 * otherwise an error code less than zero is returned, or zero if
3074 * no record(s) were appended.
3077 igmp_v3_enqueue_group_record(struct ifqueue
*ifq
, struct in_multi
*inm
,
3078 const int is_state_change
, const int is_group_query
,
3079 const int is_source_query
)
3081 struct igmp_grouprec ig
;
3082 struct igmp_grouprec
*pig
;
3084 struct ip_msource
*ims
, *nims
;
3085 struct mbuf
*m0
, *m
, *md
;
3086 int error
, is_filter_list_change
;
3087 int minrec0len
, m0srcs
, msrcs
, nbytes
, off
;
3088 int record_has_sources
;
3093 u_int16_t ig_numsrc
;
3095 INM_LOCK_ASSERT_HELD(inm
);
3096 IGI_LOCK_ASSERT_HELD(inm
->inm_igi
);
3100 is_filter_list_change
= 0;
3107 record_has_sources
= 1;
3109 type
= IGMP_DO_NOTHING
;
3110 mode
= inm
->inm_st
[1].iss_fmode
;
3113 * If we did not transition out of ASM mode during t0->t1,
3114 * and there are no source nodes to process, we can skip
3115 * the generation of source records.
3117 if (inm
->inm_st
[0].iss_asm
> 0 && inm
->inm_st
[1].iss_asm
> 0 &&
3118 inm
->inm_nsrc
== 0) {
3119 record_has_sources
= 0;
3122 if (is_state_change
) {
3124 * Queue a state change record.
3125 * If the mode did not change, and there are non-ASM
3126 * listeners or source filters present,
3127 * we potentially need to issue two records for the group.
3128 * If we are transitioning to MCAST_UNDEFINED, we need
3129 * not send any sources.
3130 * If there are ASM listeners, and there was no filter
3131 * mode transition of any kind, do nothing.
3133 if (mode
!= inm
->inm_st
[0].iss_fmode
) {
3134 if (mode
== MCAST_EXCLUDE
) {
3135 IGMP_PRINTF(("%s: change to EXCLUDE\n",
3137 type
= IGMP_CHANGE_TO_EXCLUDE_MODE
;
3139 IGMP_PRINTF(("%s: change to INCLUDE\n",
3141 type
= IGMP_CHANGE_TO_INCLUDE_MODE
;
3142 if (mode
== MCAST_UNDEFINED
) {
3143 record_has_sources
= 0;
3147 if (record_has_sources
) {
3148 is_filter_list_change
= 1;
3150 type
= IGMP_DO_NOTHING
;
3155 * Queue a current state record.
3157 if (mode
== MCAST_EXCLUDE
) {
3158 type
= IGMP_MODE_IS_EXCLUDE
;
3159 } else if (mode
== MCAST_INCLUDE
) {
3160 type
= IGMP_MODE_IS_INCLUDE
;
3161 VERIFY(inm
->inm_st
[1].iss_asm
== 0);
3166 * Generate the filter list changes using a separate function.
3168 if (is_filter_list_change
) {
3169 return igmp_v3_enqueue_filter_change(ifq
, inm
);
3172 if (type
== IGMP_DO_NOTHING
) {
3173 IGMP_INET_PRINTF(inm
->inm_addr
,
3174 ("%s: nothing to do for %s/%s\n",
3175 __func__
, _igmp_inet_buf
,
3176 if_name(inm
->inm_ifp
)));
3181 * If any sources are present, we must be able to fit at least
3182 * one in the trailing space of the tail packet's mbuf,
3185 minrec0len
= sizeof(struct igmp_grouprec
);
3186 if (record_has_sources
) {
3187 minrec0len
+= sizeof(in_addr_t
);
3190 IGMP_INET_PRINTF(inm
->inm_addr
,
3191 ("%s: queueing %s for %s/%s\n", __func__
,
3192 igmp_rec_type_to_str(type
), _igmp_inet_buf
,
3193 if_name(inm
->inm_ifp
)));
3196 * Check if we have a packet in the tail of the queue for this
3197 * group into which the first group record for this group will fit.
3198 * Otherwise allocate a new packet.
3199 * Always allocate leading space for IP+RA_OPT+IGMP+REPORT.
3200 * Note: Group records for G/GSR query responses MUST be sent
3201 * in their own packet.
3204 if (!is_group_query
&&
3206 (m0
->m_pkthdr
.vt_nrecs
+ 1 <= IGMP_V3_REPORT_MAXRECS
) &&
3207 (m0
->m_pkthdr
.len
+ minrec0len
) <
3208 (ifp
->if_mtu
- IGMP_LEADINGSPACE
)) {
3209 m0srcs
= (ifp
->if_mtu
- m0
->m_pkthdr
.len
-
3210 sizeof(struct igmp_grouprec
)) / sizeof(in_addr_t
);
3212 IGMP_PRINTF(("%s: use existing packet\n", __func__
));
3214 if (IF_QFULL(ifq
)) {
3215 IGMP_PRINTF(("%s: outbound queue full\n", __func__
));
3219 m0srcs
= (ifp
->if_mtu
- IGMP_LEADINGSPACE
-
3220 sizeof(struct igmp_grouprec
)) / sizeof(in_addr_t
);
3221 if (!is_state_change
&& !is_group_query
) {
3222 m
= m_getcl(M_DONTWAIT
, MT_DATA
, M_PKTHDR
);
3224 m
->m_data
+= IGMP_LEADINGSPACE
;
3228 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
3230 MH_ALIGN(m
, IGMP_LEADINGSPACE
);
3237 igmp_save_context(m
, ifp
);
3239 IGMP_PRINTF(("%s: allocated first packet\n", __func__
));
3243 * Append group record.
3244 * If we have sources, we don't know how many yet.
3249 ig
.ig_group
= inm
->inm_addr
;
3250 if (!m_append(m
, sizeof(struct igmp_grouprec
), (void *)&ig
)) {
3254 IGMP_PRINTF(("%s: m_append() failed.\n", __func__
));
3257 nbytes
+= sizeof(struct igmp_grouprec
);
3260 * Append as many sources as will fit in the first packet.
3261 * If we are appending to a new packet, the chain allocation
3262 * may potentially use clusters; use m_getptr() in this case.
3263 * If we are appending to an existing packet, we need to obtain
3264 * a pointer to the group record after m_append(), in case a new
3265 * mbuf was allocated.
3266 * Only append sources which are in-mode at t1. If we are
3267 * transitioning to MCAST_UNDEFINED state on the group, do not
3268 * include source entries.
3269 * Only report recorded sources in our filter set when responding
3270 * to a group-source query.
3272 if (record_has_sources
) {
3275 pig
= (struct igmp_grouprec
*)(void *)
3276 (mtod(md
, uint8_t *) + md
->m_len
- nbytes
);
3278 md
= m_getptr(m
, 0, &off
);
3279 pig
= (struct igmp_grouprec
*)(void *)
3280 (mtod(md
, uint8_t *) + off
);
3283 RB_FOREACH_SAFE(ims
, ip_msource_tree
, &inm
->inm_srcs
, nims
) {
3285 char buf
[MAX_IPv4_STR_LEN
];
3287 inet_ntop_haddr(ims
->ims_haddr
, buf
, sizeof(buf
));
3288 IGMP_PRINTF(("%s: visit node %s\n", __func__
, buf
));
3290 now
= ims_get_mode(inm
, ims
, 1);
3291 IGMP_PRINTF(("%s: node is %d\n", __func__
, now
));
3292 if ((now
!= mode
) ||
3293 (now
== mode
&& mode
== MCAST_UNDEFINED
)) {
3294 IGMP_PRINTF(("%s: skip node\n", __func__
));
3297 if (is_source_query
&& ims
->ims_stp
== 0) {
3298 IGMP_PRINTF(("%s: skip unrecorded node\n",
3302 IGMP_PRINTF(("%s: append node\n", __func__
));
3303 naddr
= htonl(ims
->ims_haddr
);
3304 if (!m_append(m
, sizeof(in_addr_t
), (void *)&naddr
)) {
3308 IGMP_PRINTF(("%s: m_append() failed.\n",
3312 nbytes
+= sizeof(in_addr_t
);
3314 if (msrcs
== m0srcs
) {
3318 IGMP_PRINTF(("%s: msrcs is %d this packet\n", __func__
,
3320 ig_numsrc
= htons(msrcs
);
3321 bcopy(&ig_numsrc
, &pig
->ig_numsrc
, sizeof(ig_numsrc
));
3322 nbytes
+= (msrcs
* sizeof(in_addr_t
));
3325 if (is_source_query
&& msrcs
== 0) {
3326 IGMP_PRINTF(("%s: no recorded sources to report\n", __func__
));
3334 * We are good to go with first packet.
3337 IGMP_PRINTF(("%s: enqueueing first packet\n", __func__
));
3338 m
->m_pkthdr
.vt_nrecs
= 1;
3341 m
->m_pkthdr
.vt_nrecs
++;
3344 * No further work needed if no source list in packet(s).
3346 if (!record_has_sources
) {
3351 * Whilst sources remain to be announced, we need to allocate
3352 * a new packet and fill out as many sources as will fit.
3353 * Always try for a cluster first.
3355 while (nims
!= NULL
) {
3356 if (IF_QFULL(ifq
)) {
3357 IGMP_PRINTF(("%s: outbound queue full\n", __func__
));
3360 m
= m_getcl(M_DONTWAIT
, MT_DATA
, M_PKTHDR
);
3362 m
->m_data
+= IGMP_LEADINGSPACE
;
3365 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
3367 MH_ALIGN(m
, IGMP_LEADINGSPACE
);
3373 igmp_save_context(m
, ifp
);
3374 md
= m_getptr(m
, 0, &off
);
3375 pig
= (struct igmp_grouprec
*)(void *)
3376 (mtod(md
, uint8_t *) + off
);
3377 IGMP_PRINTF(("%s: allocated next packet\n", __func__
));
3379 if (!m_append(m
, sizeof(struct igmp_grouprec
), (void *)&ig
)) {
3383 IGMP_PRINTF(("%s: m_append() failed.\n", __func__
));
3386 m
->m_pkthdr
.vt_nrecs
= 1;
3387 nbytes
+= sizeof(struct igmp_grouprec
);
3389 m0srcs
= (ifp
->if_mtu
- IGMP_LEADINGSPACE
-
3390 sizeof(struct igmp_grouprec
)) / sizeof(in_addr_t
);
3393 RB_FOREACH_FROM(ims
, ip_msource_tree
, nims
) {
3395 char buf
[MAX_IPv4_STR_LEN
];
3397 inet_ntop_haddr(ims
->ims_haddr
, buf
, sizeof(buf
));
3398 IGMP_PRINTF(("%s: visit node %s\n", __func__
, buf
));
3400 now
= ims_get_mode(inm
, ims
, 1);
3401 if ((now
!= mode
) ||
3402 (now
== mode
&& mode
== MCAST_UNDEFINED
)) {
3403 IGMP_PRINTF(("%s: skip node\n", __func__
));
3406 if (is_source_query
&& ims
->ims_stp
== 0) {
3407 IGMP_PRINTF(("%s: skip unrecorded node\n",
3411 IGMP_PRINTF(("%s: append node\n", __func__
));
3412 naddr
= htonl(ims
->ims_haddr
);
3413 if (!m_append(m
, sizeof(in_addr_t
), (void *)&naddr
)) {
3417 IGMP_PRINTF(("%s: m_append() failed.\n",
3422 if (msrcs
== m0srcs
) {
3426 ig_numsrc
= htons(msrcs
);
3427 bcopy(&ig_numsrc
, &pig
->ig_numsrc
, sizeof(ig_numsrc
));
3428 nbytes
+= (msrcs
* sizeof(in_addr_t
));
3430 IGMP_PRINTF(("%s: enqueueing next packet\n", __func__
));
3438 * Type used to mark record pass completion.
3439 * We exploit the fact we can cast to this easily from the
3440 * current filter modes on each ip_msource node.
3443 REC_NONE
= 0x00, /* MCAST_UNDEFINED */
3444 REC_ALLOW
= 0x01, /* MCAST_INCLUDE */
3445 REC_BLOCK
= 0x02, /* MCAST_EXCLUDE */
3446 REC_FULL
= REC_ALLOW
| REC_BLOCK
3450 * Enqueue an IGMPv3 filter list change to the given output queue.
3452 * Source list filter state is held in an RB-tree. When the filter list
3453 * for a group is changed without changing its mode, we need to compute
3454 * the deltas between T0 and T1 for each source in the filter set,
3455 * and enqueue the appropriate ALLOW_NEW/BLOCK_OLD records.
3457 * As we may potentially queue two record types, and the entire R-B tree
3458 * needs to be walked at once, we break this out into its own function
3459 * so we can generate a tightly packed queue of packets.
3461 * XXX This could be written to only use one tree walk, although that makes
3462 * serializing into the mbuf chains a bit harder. For now we do two walks
3463 * which makes things easier on us, and it may or may not be harder on
3466 * If successful the size of all data appended to the queue is returned,
3467 * otherwise an error code less than zero is returned, or zero if
3468 * no record(s) were appended.
3471 igmp_v3_enqueue_filter_change(struct ifqueue
*ifq
, struct in_multi
*inm
)
3473 static const int MINRECLEN
=
3474 sizeof(struct igmp_grouprec
) + sizeof(in_addr_t
);
3476 struct igmp_grouprec ig
;
3477 struct igmp_grouprec
*pig
;
3478 struct ip_msource
*ims
, *nims
;
3479 struct mbuf
*m
, *m0
, *md
;
3481 int m0srcs
, nbytes
, npbytes
, off
, rsrcs
, schanged
;
3483 uint8_t mode
, now
, then
;
3484 rectype_t crt
, drt
, nrt
;
3485 u_int16_t ig_numsrc
;
3487 INM_LOCK_ASSERT_HELD(inm
);
3489 if (inm
->inm_nsrc
== 0 ||
3490 (inm
->inm_st
[0].iss_asm
> 0 && inm
->inm_st
[1].iss_asm
> 0)) {
3494 ifp
= inm
->inm_ifp
; /* interface */
3495 mode
= inm
->inm_st
[1].iss_fmode
; /* filter mode at t1 */
3496 crt
= REC_NONE
; /* current group record type */
3497 drt
= REC_NONE
; /* mask of completed group record types */
3498 nrt
= REC_NONE
; /* record type for current node */
3499 m0srcs
= 0; /* # source which will fit in current mbuf chain */
3500 nbytes
= 0; /* # of bytes appended to group's state-change queue */
3501 npbytes
= 0; /* # of bytes appended this packet */
3502 rsrcs
= 0; /* # sources encoded in current record */
3503 schanged
= 0; /* # nodes encoded in overall filter change */
3504 nallow
= 0; /* # of source entries in ALLOW_NEW */
3505 nblock
= 0; /* # of source entries in BLOCK_OLD */
3506 nims
= NULL
; /* next tree node pointer */
3509 * For each possible filter record mode.
3510 * The first kind of source we encounter tells us which
3511 * is the first kind of record we start appending.
3512 * If a node transitioned to UNDEFINED at t1, its mode is treated
3513 * as the inverse of the group's filter mode.
3515 while (drt
!= REC_FULL
) {
3519 (m0
->m_pkthdr
.vt_nrecs
+ 1 <=
3520 IGMP_V3_REPORT_MAXRECS
) &&
3521 (m0
->m_pkthdr
.len
+ MINRECLEN
) <
3522 (ifp
->if_mtu
- IGMP_LEADINGSPACE
)) {
3524 m0srcs
= (ifp
->if_mtu
- m0
->m_pkthdr
.len
-
3525 sizeof(struct igmp_grouprec
)) /
3527 IGMP_PRINTF(("%s: use previous packet\n",
3530 m
= m_getcl(M_DONTWAIT
, MT_DATA
, M_PKTHDR
);
3532 m
->m_data
+= IGMP_LEADINGSPACE
;
3535 m
= m_gethdr(M_DONTWAIT
, MT_DATA
);
3537 MH_ALIGN(m
, IGMP_LEADINGSPACE
);
3541 IGMP_PRINTF(("%s: m_get*() failed\n",
3545 m
->m_pkthdr
.vt_nrecs
= 0;
3546 igmp_save_context(m
, ifp
);
3547 m0srcs
= (ifp
->if_mtu
- IGMP_LEADINGSPACE
-
3548 sizeof(struct igmp_grouprec
)) /
3551 IGMP_PRINTF(("%s: allocated new packet\n",
3555 * Append the IGMP group record header to the
3556 * current packet's data area.
3557 * Recalculate pointer to free space for next
3558 * group record, in case m_append() allocated
3559 * a new mbuf or cluster.
3561 memset(&ig
, 0, sizeof(ig
));
3562 ig
.ig_group
= inm
->inm_addr
;
3563 if (!m_append(m
, sizeof(ig
), (void *)&ig
)) {
3567 IGMP_PRINTF(("%s: m_append() failed\n",
3571 npbytes
+= sizeof(struct igmp_grouprec
);
3573 /* new packet; offset in c hain */
3574 md
= m_getptr(m
, npbytes
-
3575 sizeof(struct igmp_grouprec
), &off
);
3576 pig
= (struct igmp_grouprec
*)(void *)(mtod(md
,
3579 /* current packet; offset from last append */
3581 pig
= (struct igmp_grouprec
*)(void *)(mtod(md
,
3582 uint8_t *) + md
->m_len
-
3583 sizeof(struct igmp_grouprec
));
3586 * Begin walking the tree for this record type
3587 * pass, or continue from where we left off
3588 * previously if we had to allocate a new packet.
3589 * Only report deltas in-mode at t1.
3590 * We need not report included sources as allowed
3591 * if we are in inclusive mode on the group,
3592 * however the converse is not true.
3596 nims
= RB_MIN(ip_msource_tree
, &inm
->inm_srcs
);
3598 RB_FOREACH_FROM(ims
, ip_msource_tree
, nims
) {
3600 char buf
[MAX_IPv4_STR_LEN
];
3602 inet_ntop_haddr(ims
->ims_haddr
, buf
, sizeof(buf
));
3603 IGMP_PRINTF(("%s: visit node %s\n", __func__
, buf
));
3605 now
= ims_get_mode(inm
, ims
, 1);
3606 then
= ims_get_mode(inm
, ims
, 0);
3607 IGMP_PRINTF(("%s: mode: t0 %d, t1 %d\n",
3608 __func__
, then
, now
));
3610 IGMP_PRINTF(("%s: skip unchanged\n",
3614 if (mode
== MCAST_EXCLUDE
&&
3615 now
== MCAST_INCLUDE
) {
3616 IGMP_PRINTF(("%s: skip IN src on EX "
3617 "group\n", __func__
));
3620 nrt
= (rectype_t
)now
;
3621 if (nrt
== REC_NONE
) {
3622 nrt
= (rectype_t
)(~mode
& REC_FULL
);
3624 if (schanged
++ == 0) {
3626 } else if (crt
!= nrt
) {
3629 naddr
= htonl(ims
->ims_haddr
);
3630 if (!m_append(m
, sizeof(in_addr_t
),
3635 IGMP_PRINTF(("%s: m_append() failed\n",
3639 nallow
+= !!(crt
== REC_ALLOW
);
3640 nblock
+= !!(crt
== REC_BLOCK
);
3641 if (++rsrcs
== m0srcs
) {
3646 * If we did not append any tree nodes on this
3647 * pass, back out of allocations.
3650 npbytes
-= sizeof(struct igmp_grouprec
);
3652 IGMP_PRINTF(("%s: m_free(m)\n",
3656 IGMP_PRINTF(("%s: m_adj(m, -ig)\n",
3658 m_adj(m
, -((int)sizeof(
3659 struct igmp_grouprec
)));
3663 npbytes
+= (rsrcs
* sizeof(in_addr_t
));
3664 if (crt
== REC_ALLOW
) {
3665 pig
->ig_type
= IGMP_ALLOW_NEW_SOURCES
;
3666 } else if (crt
== REC_BLOCK
) {
3667 pig
->ig_type
= IGMP_BLOCK_OLD_SOURCES
;
3669 ig_numsrc
= htons(rsrcs
);
3670 bcopy(&ig_numsrc
, &pig
->ig_numsrc
, sizeof(ig_numsrc
));
3672 * Count the new group record, and enqueue this
3673 * packet if it wasn't already queued.
3675 m
->m_pkthdr
.vt_nrecs
++;
3680 } while (nims
!= NULL
);
3682 crt
= (~crt
& REC_FULL
);
3685 IGMP_PRINTF(("%s: queued %d ALLOW_NEW, %d BLOCK_OLD\n", __func__
,
3692 igmp_v3_merge_state_changes(struct in_multi
*inm
, struct ifqueue
*ifscq
)
3695 struct mbuf
*m
; /* pending state-change */
3696 struct mbuf
*m0
; /* copy of pending state-change */
3697 struct mbuf
*mt
; /* last state-change in packet */
3699 int docopy
, domerge
;
3702 INM_LOCK_ASSERT_HELD(inm
);
3709 * If there are further pending retransmissions, make a writable
3710 * copy of each queued state-change message before merging.
3712 if (inm
->inm_scrv
> 0) {
3718 if (gq
->ifq_head
== NULL
) {
3719 IGMP_PRINTF(("%s: WARNING: queue for inm 0x%llx is empty\n",
3720 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(inm
)));
3725 * Use IF_REMQUEUE() instead of IF_DEQUEUE() below, since the
3726 * packet might not always be at the head of the ifqueue.
3731 * Only merge the report into the current packet if
3732 * there is sufficient space to do so; an IGMPv3 report
3733 * packet may only contain 65,535 group records.
3734 * Always use a simple mbuf chain concatentation to do this,
3735 * as large state changes for single groups may have
3736 * allocated clusters.
3739 mt
= ifscq
->ifq_tail
;
3741 recslen
= m_length(m
);
3743 if ((mt
->m_pkthdr
.vt_nrecs
+
3744 m
->m_pkthdr
.vt_nrecs
<=
3745 IGMP_V3_REPORT_MAXRECS
) &&
3746 (mt
->m_pkthdr
.len
+ recslen
<=
3747 (inm
->inm_ifp
->if_mtu
- IGMP_LEADINGSPACE
))) {
3752 if (!domerge
&& IF_QFULL(gq
)) {
3753 IGMP_PRINTF(("%s: outbound queue full, skipping whole "
3754 "packet 0x%llx\n", __func__
,
3755 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3766 IGMP_PRINTF(("%s: dequeueing 0x%llx\n", __func__
,
3767 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3773 IGMP_PRINTF(("%s: copying 0x%llx\n", __func__
,
3774 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3775 m0
= m_dup(m
, M_NOWAIT
);
3779 m0
->m_nextpkt
= NULL
;
3784 IGMP_PRINTF(("%s: queueing 0x%llx to ifscq 0x%llx)\n",
3785 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(m0
),
3786 (uint64_t)VM_KERNEL_ADDRPERM(ifscq
)));
3787 IF_ENQUEUE(ifscq
, m0
);
3789 struct mbuf
*mtl
; /* last mbuf of packet mt */
3791 IGMP_PRINTF(("%s: merging 0x%llx with ifscq tail "
3792 "0x%llx)\n", __func__
,
3793 (uint64_t)VM_KERNEL_ADDRPERM(m0
),
3794 (uint64_t)VM_KERNEL_ADDRPERM(mt
)));
3797 m0
->m_flags
&= ~M_PKTHDR
;
3798 mt
->m_pkthdr
.len
+= recslen
;
3799 mt
->m_pkthdr
.vt_nrecs
+=
3800 m0
->m_pkthdr
.vt_nrecs
;
3810 * Respond to a pending IGMPv3 General Query.
3813 igmp_v3_dispatch_general_query(struct igmp_ifinfo
*igi
)
3816 struct in_multi
*inm
;
3817 struct in_multistep step
;
3820 IGI_LOCK_ASSERT_HELD(igi
);
3822 VERIFY(igi
->igi_version
== IGMP_VERSION_3
);
3827 in_multihead_lock_shared();
3828 IN_FIRST_MULTI(step
, inm
);
3829 while (inm
!= NULL
) {
3831 if (inm
->inm_ifp
!= ifp
) {
3835 switch (inm
->inm_state
) {
3836 case IGMP_NOT_MEMBER
:
3837 case IGMP_SILENT_MEMBER
:
3839 case IGMP_REPORTING_MEMBER
:
3840 case IGMP_IDLE_MEMBER
:
3841 case IGMP_LAZY_MEMBER
:
3842 case IGMP_SLEEPING_MEMBER
:
3843 case IGMP_AWAKENING_MEMBER
:
3844 inm
->inm_state
= IGMP_REPORTING_MEMBER
;
3846 retval
= igmp_v3_enqueue_group_record(&igi
->igi_gq
,
3849 IGMP_PRINTF(("%s: enqueue record = %d\n",
3852 case IGMP_G_QUERY_PENDING_MEMBER
:
3853 case IGMP_SG_QUERY_PENDING_MEMBER
:
3854 case IGMP_LEAVING_MEMBER
:
3859 IN_NEXT_MULTI(step
, inm
);
3861 in_multihead_lock_done();
3864 loop
= (igi
->igi_flags
& IGIF_LOOPBACK
) ? 1 : 0;
3865 igmp_dispatch_queue(igi
, &igi
->igi_gq
, IGMP_MAX_RESPONSE_BURST
,
3867 IGI_LOCK_ASSERT_HELD(igi
);
3869 * Slew transmission of bursts over 1 second intervals.
3871 if (igi
->igi_gq
.ifq_head
!= NULL
) {
3872 igi
->igi_v3_timer
= 1 + IGMP_RANDOM_DELAY(
3873 IGMP_RESPONSE_BURST_INTERVAL
);
3876 return igi
->igi_v3_timer
;
3880 * Transmit the next pending IGMP message in the output queue.
3882 * Must not be called with inm_lock or igi_lock held.
3885 igmp_sendpkt(struct mbuf
*m
)
3887 struct ip_moptions
*imo
;
3888 struct mbuf
*ipopts
, *m0
;
3893 IGMP_PRINTF(("%s: transmit 0x%llx\n", __func__
,
3894 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3896 ifp
= igmp_restore_context(m
);
3898 * Check if the ifnet is still attached.
3900 if (ifp
== NULL
|| !ifnet_is_attached(ifp
, 0)) {
3901 IGMP_PRINTF(("%s: dropped 0x%llx as ifp went away.\n",
3902 __func__
, (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3904 OSAddAtomic(1, &ipstat
.ips_noroute
);
3908 ipopts
= igmp_sendra
? m_raopt
: NULL
;
3910 imo
= ip_allocmoptions(M_WAITOK
);
3916 imo
->imo_multicast_ttl
= 1;
3917 imo
->imo_multicast_vif
= -1;
3918 imo
->imo_multicast_loop
= 0;
3921 * If the user requested that IGMP traffic be explicitly
3922 * redirected to the loopback interface (e.g. they are running a
3923 * MANET interface and the routing protocol needs to see the
3924 * updates), handle this now.
3926 if (m
->m_flags
& M_IGMP_LOOP
) {
3927 imo
->imo_multicast_ifp
= lo_ifp
;
3929 imo
->imo_multicast_ifp
= ifp
;
3932 if (m
->m_flags
& M_IGMPV2
) {
3935 m0
= igmp_v3_encap_report(ifp
, m
);
3938 * If igmp_v3_encap_report() failed, then M_PREPEND()
3939 * already freed the original mbuf chain.
3940 * This means that we don't have to m_freem(m) here.
3942 IGMP_PRINTF(("%s: dropped 0x%llx\n", __func__
,
3943 (uint64_t)VM_KERNEL_ADDRPERM(m
)));
3945 atomic_add_32(&ipstat
.ips_odropped
, 1);
3950 igmp_scrub_context(m0
);
3951 m
->m_flags
&= ~(M_PROTOFLAGS
| M_IGMP_LOOP
);
3952 m0
->m_pkthdr
.rcvif
= lo_ifp
;
3954 mac_netinet_igmp_send(ifp
, m0
);
3957 if (ifp
->if_eflags
& IFEF_TXSTART
) {
3959 * Use control service class if the interface supports
3960 * transmit-start model.
3962 (void) m_set_service_class(m0
, MBUF_SC_CTL
);
3964 bzero(&ro
, sizeof(ro
));
3965 error
= ip_output(m0
, ipopts
, &ro
, 0, imo
, NULL
);
3971 IGMP_PRINTF(("%s: ip_output(0x%llx) = %d\n", __func__
,
3972 (uint64_t)VM_KERNEL_ADDRPERM(m0
), error
));
3976 IGMPSTAT_INC(igps_snd_reports
);
3977 OIGMPSTAT_INC(igps_snd_reports
);
3980 * Encapsulate an IGMPv3 report.
3982 * The internal mbuf flag M_IGMPV3_HDR is used to indicate that the mbuf
3983 * chain has already had its IP/IGMPv3 header prepended. In this case
3984 * the function will not attempt to prepend; the lengths and checksums
3985 * will however be re-computed.
3987 * Returns a pointer to the new mbuf chain head, or NULL if the
3988 * allocation failed.
3990 static struct mbuf
*
3991 igmp_v3_encap_report(struct ifnet
*ifp
, struct mbuf
*m
)
3993 struct igmp_report
*igmp
;
3995 int hdrlen
, igmpreclen
;
3997 VERIFY((m
->m_flags
& M_PKTHDR
));
3999 igmpreclen
= m_length(m
);
4000 hdrlen
= sizeof(struct ip
) + sizeof(struct igmp_report
);
4002 if (m
->m_flags
& M_IGMPV3_HDR
) {
4003 igmpreclen
-= hdrlen
;
4005 M_PREPEND(m
, hdrlen
, M_DONTWAIT
, 1);
4009 m
->m_flags
|= M_IGMPV3_HDR
;
4012 IGMP_PRINTF(("%s: igmpreclen is %d\n", __func__
, igmpreclen
));
4014 m
->m_data
+= sizeof(struct ip
);
4015 m
->m_len
-= sizeof(struct ip
);
4017 igmp
= mtod(m
, struct igmp_report
*);
4018 igmp
->ir_type
= IGMP_v3_HOST_MEMBERSHIP_REPORT
;
4021 igmp
->ir_numgrps
= htons(m
->m_pkthdr
.vt_nrecs
);
4023 igmp
->ir_cksum
= in_cksum(m
, sizeof(struct igmp_report
) + igmpreclen
);
4024 m
->m_pkthdr
.vt_nrecs
= 0;
4026 m
->m_data
-= sizeof(struct ip
);
4027 m
->m_len
+= sizeof(struct ip
);
4029 ip
= mtod(m
, struct ip
*);
4030 ip
->ip_tos
= IPTOS_PREC_INTERNETCONTROL
;
4031 ip
->ip_len
= hdrlen
+ igmpreclen
;
4033 ip
->ip_p
= IPPROTO_IGMP
;
4036 ip
->ip_src
.s_addr
= INADDR_ANY
;
4038 if (m
->m_flags
& M_IGMP_LOOP
) {
4039 struct in_ifaddr
*ia
;
4043 IFA_LOCK(&ia
->ia_ifa
);
4044 ip
->ip_src
= ia
->ia_addr
.sin_addr
;
4045 IFA_UNLOCK(&ia
->ia_ifa
);
4046 IFA_REMREF(&ia
->ia_ifa
);
4050 ip
->ip_dst
.s_addr
= htonl(INADDR_ALLRPTS_GROUP
);
4057 igmp_rec_type_to_str(const int type
)
4060 case IGMP_CHANGE_TO_EXCLUDE_MODE
:
4062 case IGMP_CHANGE_TO_INCLUDE_MODE
:
4064 case IGMP_MODE_IS_EXCLUDE
:
4066 case IGMP_MODE_IS_INCLUDE
:
4068 case IGMP_ALLOW_NEW_SOURCES
:
4070 case IGMP_BLOCK_OLD_SOURCES
:
4080 igmp_init(struct protosw
*pp
, struct domain
*dp
)
4083 static int igmp_initialized
= 0;
4085 VERIFY((pp
->pr_flags
& (PR_INITIALIZED
| PR_ATTACHED
)) == PR_ATTACHED
);
4087 if (igmp_initialized
) {
4090 igmp_initialized
= 1;
4092 IGMP_PRINTF(("%s: initializing\n", __func__
));
4094 igmp_timers_are_running
= 0;
4096 /* Setup lock group and attribute for igmp_mtx */
4097 igmp_mtx_grp_attr
= lck_grp_attr_alloc_init();
4098 igmp_mtx_grp
= lck_grp_alloc_init("igmp_mtx", igmp_mtx_grp_attr
);
4099 igmp_mtx_attr
= lck_attr_alloc_init();
4100 lck_mtx_init(&igmp_mtx
, igmp_mtx_grp
, igmp_mtx_attr
);
4102 LIST_INIT(&igi_head
);
4103 m_raopt
= igmp_ra_alloc();
4105 igi_size
= sizeof(struct igmp_ifinfo
);
4106 igi_zone
= zinit(igi_size
, IGI_ZONE_MAX
* igi_size
,
4108 if (igi_zone
== NULL
) {
4109 panic("%s: failed allocating %s", __func__
, IGI_ZONE_NAME
);
4112 zone_change(igi_zone
, Z_EXPAND
, TRUE
);
4113 zone_change(igi_zone
, Z_CALLERACCT
, FALSE
);