]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/igmp.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / bsd / netinet / igmp.c
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
6d2010ae
A
28/*-
29 * Copyright (c) 2007-2009 Bruce Simpson.
1c79356b
A
30 * Copyright (c) 1988 Stephen Deering.
31 * Copyright (c) 1992, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * This code is derived from software contributed to Berkeley by
35 * Stephen Deering of Stanford University.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
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.
52 *
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
63 * SUCH DAMAGE.
64 *
65 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
66 */
2d21ac55
A
67/*
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,
71 * Version 2.0.
72 */
1c79356b
A
73
74/*
75 * Internet Group Management Protocol (IGMP) routines.
6d2010ae 76 * [RFC1112, RFC2236, RFC3376]
1c79356b
A
77 *
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.
6d2010ae 82 * Significantly rewritten for IGMPv3, VIMAGE, and SMP by Bruce Simpson.
1c79356b
A
83 *
84 * MULTICAST Revision: 3.5.1.4
85 */
86
6d2010ae
A
87#include <sys/cdefs.h>
88
1c79356b
A
89#include <sys/param.h>
90#include <sys/systm.h>
91#include <sys/malloc.h>
92#include <sys/mbuf.h>
93#include <sys/socket.h>
94#include <sys/protosw.h>
95#include <sys/kernel.h>
96#include <sys/sysctl.h>
6d2010ae
A
97#include <sys/mcache.h>
98
99#include <libkern/libkern.h>
100#include <kern/zalloc.h>
1c79356b
A
101
102#include <net/if.h>
103#include <net/route.h>
104
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>
6d2010ae
A
112#include <netinet/kpi_ipfilter_var.h>
113
13f56ec4
A
114SLIST_HEAD(igmp_inm_relhead, in_multi);
115
0a7de745 116static void igi_initvar(struct igmp_ifinfo *, struct ifnet *, int);
6d2010ae 117static struct igmp_ifinfo *igi_alloc(int);
0a7de745
A
118static void igi_free(struct igmp_ifinfo *);
119static void igi_delete(const struct ifnet *, struct igmp_inm_relhead *);
120static void igmp_dispatch_queue(struct igmp_ifinfo *, struct ifqueue *,
39236c6e 121 int, const int);
0a7de745
A
122static void igmp_final_leave(struct in_multi *, struct igmp_ifinfo *,
123 struct igmp_tparams *);
124static int igmp_handle_state_change(struct in_multi *,
125 struct igmp_ifinfo *, struct igmp_tparams *);
126static int igmp_initial_join(struct in_multi *, struct igmp_ifinfo *,
127 struct igmp_tparams *);
128static int igmp_input_v1_query(struct ifnet *, const struct ip *,
129 const struct igmp *);
130static int igmp_input_v2_query(struct ifnet *, const struct ip *,
131 const struct igmp *);
132static int igmp_input_v3_query(struct ifnet *, const struct ip *,
133 /*const*/ struct igmpv3 *);
134static int igmp_input_v3_group_query(struct in_multi *,
135 int, /*const*/ struct igmpv3 *);
136static int igmp_input_v1_report(struct ifnet *, struct mbuf *,
137 /*const*/ struct ip *, /*const*/ struct igmp *);
138static int igmp_input_v2_report(struct ifnet *, struct mbuf *,
139 /*const*/ struct ip *, /*const*/ struct igmp *);
140static void igmp_sendpkt(struct mbuf *);
141static __inline__ int igmp_isgroupreported(const struct in_addr);
39236c6e 142static struct mbuf *igmp_ra_alloc(void);
6d2010ae 143#ifdef IGMP_DEBUG
39236c6e 144static const char *igmp_rec_type_to_str(const int);
9bccf70c 145#endif
0a7de745
A
146static uint32_t igmp_set_version(struct igmp_ifinfo *, const int);
147static void igmp_flush_relq(struct igmp_ifinfo *,
13f56ec4 148 struct igmp_inm_relhead *);
0a7de745
A
149static int igmp_v1v2_queue_report(struct in_multi *, const int);
150static void igmp_v1v2_process_group_timer(struct in_multi *, const int);
151static void igmp_v1v2_process_querier_timers(struct igmp_ifinfo *);
152static uint32_t igmp_v2_update_group(struct in_multi *, const int);
153static void igmp_v3_cancel_link_timers(struct igmp_ifinfo *);
154static uint32_t igmp_v3_dispatch_general_query(struct igmp_ifinfo *);
6d2010ae 155static struct mbuf *
0a7de745
A
156igmp_v3_encap_report(struct ifnet *, struct mbuf *);
157static int igmp_v3_enqueue_group_record(struct ifqueue *,
158 struct in_multi *, const int, const int, const int);
159static int igmp_v3_enqueue_filter_change(struct ifqueue *,
160 struct in_multi *);
161static void igmp_v3_process_group_timers(struct igmp_ifinfo *,
162 struct ifqueue *, struct ifqueue *, struct in_multi *,
163 const int);
164static int igmp_v3_merge_state_changes(struct in_multi *,
165 struct ifqueue *);
166static void igmp_v3_suppress_group_record(struct in_multi *);
167static int sysctl_igmp_ifinfo SYSCTL_HANDLER_ARGS;
168static int sysctl_igmp_gsr SYSCTL_HANDLER_ARGS;
169static int sysctl_igmp_default_version SYSCTL_HANDLER_ARGS;
170
171static int igmp_timeout_run; /* IGMP timer is scheduled to run */
39236c6e
A
172static void igmp_timeout(void *);
173static void igmp_sched_timeout(void);
1c79356b 174
0a7de745 175static struct mbuf *m_raopt; /* Router Alert option */
39236c6e 176
0a7de745
A
177static int querier_present_timers_running; /* IGMPv1/v2 older version
178 * querier present */
179static int interface_timers_running; /* IGMPv3 general
180 * query response */
181static int state_change_timers_running; /* IGMPv3 state-change
182 * retransmit */
183static int current_state_timers_running; /* IGMPv1/v2 host
184 * report; IGMPv3 g/sg
185 * query response */
1c79356b 186
39236c6e
A
187/*
188 * Subsystem lock macros.
189 */
0a7de745 190#define IGMP_LOCK() \
39236c6e 191 lck_mtx_lock(&igmp_mtx)
0a7de745 192#define IGMP_LOCK_ASSERT_HELD() \
5ba3f43e 193 LCK_MTX_ASSERT(&igmp_mtx, LCK_MTX_ASSERT_OWNED)
0a7de745 194#define IGMP_LOCK_ASSERT_NOTHELD() \
5ba3f43e 195 LCK_MTX_ASSERT(&igmp_mtx, LCK_MTX_ASSERT_NOTOWNED)
0a7de745 196#define IGMP_UNLOCK() \
39236c6e
A
197 lck_mtx_unlock(&igmp_mtx)
198
6d2010ae
A
199static LIST_HEAD(, igmp_ifinfo) igi_head;
200static struct igmpstat_v3 igmpstat_v3 = {
201 .igps_version = IGPS_VERSION_3,
202 .igps_len = sizeof(struct igmpstat_v3),
203};
204static struct igmpstat igmpstat; /* old IGMPv2 stats structure */
cb323159 205static struct timeval igmp_gsrdelay = {.tv_sec = 10, .tv_usec = 0};
1c79356b 206
6d2010ae
A
207static int igmp_recvifkludge = 1;
208static int igmp_sendra = 1;
209static int igmp_sendlocal = 1;
210static int igmp_v1enable = 1;
211static int igmp_v2enable = 1;
212static int igmp_legacysupp = 0;
213static int igmp_default_version = IGMP_VERSION_3;
1c79356b 214
6d2010ae
A
215SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_RD | CTLFLAG_LOCKED,
216 &igmpstat, igmpstat, "");
217SYSCTL_STRUCT(_net_inet_igmp, OID_AUTO, v3stats,
218 CTLFLAG_RD | CTLFLAG_LOCKED, &igmpstat_v3, igmpstat_v3, "");
219SYSCTL_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");
222SYSCTL_INT(_net_inet_igmp, OID_AUTO, sendra, CTLFLAG_RW | CTLFLAG_LOCKED,
223 &igmp_sendra, 0,
224 "Send IP Router Alert option in IGMPv2/v3 messages");
225SYSCTL_INT(_net_inet_igmp, OID_AUTO, sendlocal, CTLFLAG_RW | CTLFLAG_LOCKED,
226 &igmp_sendlocal, 0,
227 "Send IGMP membership reports for 224.0.0.0/24 groups");
228SYSCTL_INT(_net_inet_igmp, OID_AUTO, v1enable, CTLFLAG_RW | CTLFLAG_LOCKED,
229 &igmp_v1enable, 0,
230 "Enable backwards compatibility with IGMPv1");
231SYSCTL_INT(_net_inet_igmp, OID_AUTO, v2enable, CTLFLAG_RW | CTLFLAG_LOCKED,
232 &igmp_v2enable, 0,
233 "Enable backwards compatibility with IGMPv2");
234SYSCTL_INT(_net_inet_igmp, OID_AUTO, legacysupp, CTLFLAG_RW | CTLFLAG_LOCKED,
235 &igmp_legacysupp, 0,
236 "Allow v1/v2 reports to suppress v3 group responses");
237SYSCTL_PROC(_net_inet_igmp, OID_AUTO, default_version,
0a7de745
A
238 CTLTYPE_INT | CTLFLAG_RW,
239 &igmp_default_version, 0, sysctl_igmp_default_version, "I",
6d2010ae
A
240 "Default version of IGMP to run on each interface");
241SYSCTL_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");
245#ifdef IGMP_DEBUG
246int igmp_debug = 0;
247SYSCTL_INT(_net_inet_igmp, OID_AUTO,
0a7de745 248 debug, CTLFLAG_RW | CTLFLAG_LOCKED, &igmp_debug, 0, "");
6d2010ae 249#endif
1c79356b 250
6d2010ae
A
251SYSCTL_NODE(_net_inet_igmp, OID_AUTO, ifinfo, CTLFLAG_RD | CTLFLAG_LOCKED,
252 sysctl_igmp_ifinfo, "Per-interface IGMPv3 state");
1c79356b 253
6d2010ae 254/* Lock group and attribute for igmp_mtx */
0a7de745
A
255static lck_attr_t *igmp_mtx_attr;
256static lck_grp_t *igmp_mtx_grp;
257static lck_grp_attr_t *igmp_mtx_grp_attr;
1c79356b 258
6d2010ae
A
259/*
260 * Locking and reference counting:
261 *
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.
267 *
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.)
274 *
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.
281 *
282 * Thus, the permitted lock oder is:
283 *
284 * igmp_mtx, in_multihead_lock, inm_lock, igi_lock
285 *
286 * Any may be taken independently, but if any are held at the same time,
287 * the above lock order must be followed.
288 */
289static decl_lck_mtx_data(, igmp_mtx);
290static int igmp_timers_are_running;
1c79356b 291
0a7de745
A
292#define IGMP_ADD_DETACHED_INM(_head, _inm) { \
293 SLIST_INSERT_HEAD(_head, _inm, inm_dtle); \
13f56ec4
A
294}
295
0a7de745
A
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); \
300 INM_REMREF(_inm); \
301 } \
302 VERIFY(SLIST_EMPTY(_head)); \
13f56ec4
A
303}
304
0a7de745
A
305#define IGI_ZONE_MAX 64 /* maximum elements in zone */
306#define IGI_ZONE_NAME "igmp_ifinfo" /* zone name */
1c79356b 307
0a7de745
A
308static unsigned int igi_size; /* size of zone element */
309static struct zone *igi_zone; /* zone for igmp_ifinfo */
1c79356b 310
39236c6e 311/* Store IGMPv3 record count in the module private scratch space */
0a7de745 312#define vt_nrecs pkt_mpriv.__mpriv_u.__mpriv32[0].__mpriv32_u.__val16[0]
39236c6e
A
313
314static __inline void
315igmp_save_context(struct mbuf *m, struct ifnet *ifp)
316{
0a7de745 317 m->m_pkthdr.rcvif = ifp;
39236c6e
A
318}
319
320static __inline void
321igmp_scrub_context(struct mbuf *m)
322{
0a7de745 323 m->m_pkthdr.rcvif = NULL;
39236c6e
A
324}
325
6d2010ae 326#ifdef IGMP_DEBUG
39236c6e
A
327static __inline const char *
328inet_ntop_haddr(in_addr_t haddr, char *buf, socklen_t size)
1c79356b 329{
6d2010ae
A
330 struct in_addr ia;
331
332 ia.s_addr = htonl(haddr);
0a7de745 333 return inet_ntop(AF_INET, &ia, buf, size);
6d2010ae 334}
1c79356b 335#endif
39236c6e
A
336
337/*
338 * Restore context from a queued IGMP output chain.
339 * Return saved ifp.
340 */
341static __inline struct ifnet *
342igmp_restore_context(struct mbuf *m)
343{
0a7de745 344 return m->m_pkthdr.rcvif;
39236c6e
A
345}
346
6d2010ae
A
347/*
348 * Retrieve or set default IGMP version.
349 */
350static int
351sysctl_igmp_default_version SYSCTL_HANDLER_ARGS
352{
353#pragma unused(oidp, arg2)
0a7de745
A
354 int error;
355 int new;
6d2010ae 356
39236c6e 357 IGMP_LOCK();
6d2010ae
A
358
359 error = SYSCTL_OUT(req, arg1, sizeof(int));
0a7de745 360 if (error || !req->newptr) {
6d2010ae 361 goto out_locked;
0a7de745 362 }
6d2010ae
A
363
364 new = igmp_default_version;
365
366 error = SYSCTL_IN(req, &new, sizeof(int));
0a7de745 367 if (error) {
6d2010ae 368 goto out_locked;
0a7de745 369 }
6d2010ae
A
370
371 if (new < IGMP_VERSION_1 || new > IGMP_VERSION_3) {
372 error = EINVAL;
373 goto out_locked;
374 }
375
39236c6e
A
376 IGMP_PRINTF(("%s: change igmp_default_version from %d to %d\n",
377 __func__, igmp_default_version, new));
6d2010ae
A
378
379 igmp_default_version = new;
380
381out_locked:
39236c6e 382 IGMP_UNLOCK();
0a7de745 383 return error;
1c79356b
A
384}
385
6d2010ae
A
386/*
387 * Retrieve or set threshold between group-source queries in seconds.
388 *
389 */
390static int
391sysctl_igmp_gsr SYSCTL_HANDLER_ARGS
1c79356b 392{
6d2010ae
A
393#pragma unused(arg1, arg2)
394 int error;
395 int i;
1c79356b 396
39236c6e 397 IGMP_LOCK();
1c79356b 398
6d2010ae 399 i = igmp_gsrdelay.tv_sec;
1c79356b 400
6d2010ae 401 error = sysctl_handle_int(oidp, &i, 0, req);
0a7de745 402 if (error || !req->newptr) {
6d2010ae 403 goto out_locked;
0a7de745 404 }
1c79356b 405
6d2010ae
A
406 if (i < -1 || i >= 60) {
407 error = EINVAL;
408 goto out_locked;
1c79356b 409 }
1c79356b 410
6d2010ae 411 igmp_gsrdelay.tv_sec = i;
1c79356b 412
6d2010ae 413out_locked:
39236c6e 414 IGMP_UNLOCK();
0a7de745 415 return error;
6d2010ae 416}
1c79356b 417
6d2010ae
A
418/*
419 * Expose struct igmp_ifinfo to userland, keyed by ifindex.
420 * For use by ifmcstat(8).
421 *
422 */
423static int
424sysctl_igmp_ifinfo SYSCTL_HANDLER_ARGS
425{
426#pragma unused(oidp)
0a7de745
A
427 int *name;
428 int error;
429 u_int namelen;
430 struct ifnet *ifp;
431 struct igmp_ifinfo *igi;
432 struct igmp_ifinfo_u igi_u;
1c79356b 433
6d2010ae
A
434 name = (int *)arg1;
435 namelen = arg2;
1c79356b 436
0a7de745
A
437 if (req->newptr != USER_ADDR_NULL) {
438 return EPERM;
439 }
1c79356b 440
0a7de745
A
441 if (namelen != 1) {
442 return EINVAL;
443 }
1c79356b 444
39236c6e 445 IGMP_LOCK();
1c79356b 446
6d2010ae
A
447 if (name[0] <= 0 || name[0] > (u_int)if_index) {
448 error = ENOENT;
449 goto out_locked;
450 }
1c79356b 451
6d2010ae
A
452 error = ENOENT;
453
454 ifnet_head_lock_shared();
455 ifp = ifindex2ifnet[name[0]];
456 ifnet_head_done();
0a7de745 457 if (ifp == NULL) {
6d2010ae 458 goto out_locked;
0a7de745 459 }
6d2010ae 460
0a7de745 461 bzero(&igi_u, sizeof(igi_u));
6d2010ae
A
462
463 LIST_FOREACH(igi, &igi_head, igi_link) {
464 IGI_LOCK(igi);
465 if (ifp != igi->igi_ifp) {
466 IGI_UNLOCK(igi);
467 continue;
1c79356b 468 }
6d2010ae
A
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;
479 IGI_UNLOCK(igi);
1c79356b 480
0a7de745 481 error = SYSCTL_OUT(req, &igi_u, sizeof(igi_u));
1c79356b 482 break;
6d2010ae 483 }
1c79356b 484
6d2010ae 485out_locked:
39236c6e 486 IGMP_UNLOCK();
0a7de745 487 return error;
6d2010ae 488}
1c79356b 489
6d2010ae
A
490/*
491 * Dispatch an entire queue of pending packet chains
492 *
493 * Must not be called with inm_lock held.
494 */
495static void
496igmp_dispatch_queue(struct igmp_ifinfo *igi, struct ifqueue *ifq, int limit,
39236c6e 497 const int loop)
6d2010ae
A
498{
499 struct mbuf *m;
500 struct ip *ip;
1c79356b 501
0a7de745 502 if (igi != NULL) {
6d2010ae 503 IGI_LOCK_ASSERT_HELD(igi);
0a7de745 504 }
6d2010ae
A
505
506 for (;;) {
507 IF_DEQUEUE(ifq, m);
0a7de745 508 if (m == NULL) {
1c79356b 509 break;
0a7de745 510 }
39236c6e
A
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)));
6d2010ae 514 ip = mtod(m, struct ip *);
0a7de745 515 if (loop) {
6d2010ae 516 m->m_flags |= M_IGMP_LOOP;
0a7de745
A
517 }
518 if (igi != NULL) {
6d2010ae 519 IGI_UNLOCK(igi);
0a7de745 520 }
39236c6e 521 igmp_sendpkt(m);
0a7de745 522 if (igi != NULL) {
6d2010ae 523 IGI_LOCK(igi);
0a7de745
A
524 }
525 if (--limit == 0) {
6d2010ae 526 break;
0a7de745 527 }
6d2010ae 528 }
1c79356b 529
0a7de745 530 if (igi != NULL) {
6d2010ae 531 IGI_LOCK_ASSERT_HELD(igi);
0a7de745 532 }
6d2010ae 533}
1c79356b 534
6d2010ae
A
535/*
536 * Filter outgoing IGMP report state by group.
537 *
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
542 * report behaviour.
543 *
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.
546 */
1c79356b 547
6d2010ae 548static __inline__
0a7de745
A
549int
550igmp_isgroupreported(const struct in_addr addr)
6d2010ae 551{
6d2010ae 552 if (in_allhosts(addr) ||
0a7de745
A
553 ((!igmp_sendlocal && IN_LOCAL_GROUP(ntohl(addr.s_addr))))) {
554 return 0;
555 }
1c79356b 556
0a7de745 557 return 1;
6d2010ae 558}
1c79356b 559
6d2010ae
A
560/*
561 * Construct a Router Alert option to use in outgoing packets.
562 */
563static struct mbuf *
564igmp_ra_alloc(void)
565{
0a7de745
A
566 struct mbuf *m;
567 struct ipoption *p;
1c79356b 568
6d2010ae
A
569 MGET(m, M_WAITOK, MT_DATA);
570 p = mtod(m, struct ipoption *);
571 p->ipopt_dst.s_addr = INADDR_ANY;
0a7de745
A
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 */
6d2010ae
A
576 m->m_len = sizeof(p->ipopt_dst) + p->ipopt_list[1];
577
0a7de745 578 return m;
1c79356b
A
579}
580
6d2010ae
A
581/*
582 * Attach IGMP when PF_INET is attached to an interface.
583 */
584struct igmp_ifinfo *
585igmp_domifattach(struct ifnet *ifp, int how)
1c79356b 586{
6d2010ae 587 struct igmp_ifinfo *igi;
1c79356b 588
39236c6e
A
589 IGMP_PRINTF(("%s: called for ifp 0x%llx(%s)\n",
590 __func__, (uint64_t)VM_KERNEL_ADDRPERM(ifp), ifp->if_name));
6d2010ae
A
591
592 igi = igi_alloc(how);
0a7de745
A
593 if (igi == NULL) {
594 return NULL;
595 }
6d2010ae 596
39236c6e 597 IGMP_LOCK();
6d2010ae
A
598
599 IGI_LOCK(igi);
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 */
604 IGI_UNLOCK(igi);
316670eb
A
605 ifnet_lock_shared(ifp);
606 igmp_initsilent(ifp, igi);
607 ifnet_lock_done(ifp);
6d2010ae
A
608
609 LIST_INSERT_HEAD(&igi_head, igi, igi_link);
610
39236c6e 611 IGMP_UNLOCK();
6d2010ae 612
39236c6e 613 IGMP_PRINTF(("%s: allocate igmp_ifinfo for ifp 0x%llx(%s)\n", __func__,
0a7de745 614 (uint64_t)VM_KERNEL_ADDRPERM(ifp), ifp->if_name));
6d2010ae 615
0a7de745 616 return igi;
1c79356b
A
617}
618
6d2010ae
A
619/*
620 * Attach IGMP when PF_INET is reattached to an interface. Caller is
621 * expected to have an outstanding reference to the igi.
622 */
1c79356b 623void
6d2010ae 624igmp_domifreattach(struct igmp_ifinfo *igi)
1c79356b 625{
6d2010ae
A
626 struct ifnet *ifp;
627
39236c6e 628 IGMP_LOCK();
6d2010ae
A
629
630 IGI_LOCK(igi);
631 VERIFY(!(igi->igi_debug & IFD_ATTACHED));
632 ifp = igi->igi_ifp;
633 VERIFY(ifp != NULL);
634 igi_initvar(igi, ifp, 1);
635 igi->igi_debug |= IFD_ATTACHED;
636 IGI_ADDREF_LOCKED(igi); /* hold a reference for igi_head */
637 IGI_UNLOCK(igi);
316670eb
A
638 ifnet_lock_shared(ifp);
639 igmp_initsilent(ifp, igi);
640 ifnet_lock_done(ifp);
6d2010ae
A
641
642 LIST_INSERT_HEAD(&igi_head, igi, igi_link);
643
39236c6e 644 IGMP_UNLOCK();
6d2010ae 645
39236c6e
A
646 IGMP_PRINTF(("%s: reattached igmp_ifinfo for ifp 0x%llx(%s)\n",
647 __func__, (uint64_t)VM_KERNEL_ADDRPERM(ifp), ifp->if_name));
1c79356b
A
648}
649
6d2010ae
A
650/*
651 * Hook for domifdetach.
652 */
1c79356b 653void
6d2010ae 654igmp_domifdetach(struct ifnet *ifp)
1c79356b 655{
13f56ec4
A
656 SLIST_HEAD(, in_multi) inm_dthead;
657
658 SLIST_INIT(&inm_dthead);
659
39236c6e
A
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));
6d2010ae 662
39236c6e 663 IGMP_LOCK();
13f56ec4 664 igi_delete(ifp, (struct igmp_inm_relhead *)&inm_dthead);
39236c6e 665 IGMP_UNLOCK();
13f56ec4
A
666
667 /* Now that we're dropped all locks, release detached records */
668 IGMP_REMOVE_DETACHED_INM(&inm_dthead);
6d2010ae
A
669}
670
671/*
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
675 * the reattach case.
676 */
677static void
13f56ec4 678igi_delete(const struct ifnet *ifp, struct igmp_inm_relhead *inm_dthead)
6d2010ae
A
679{
680 struct igmp_ifinfo *igi, *tigi;
681
39236c6e 682 IGMP_LOCK_ASSERT_HELD();
6d2010ae
A
683
684 LIST_FOREACH_SAFE(igi, &igi_head, igi_link, tigi) {
685 IGI_LOCK(igi);
686 if (igi->igi_ifp == ifp) {
687 /*
688 * Free deferred General Query responses.
689 */
690 IF_DRAIN(&igi->igi_gq);
691 IF_DRAIN(&igi->igi_v2q);
13f56ec4 692 igmp_flush_relq(igi, inm_dthead);
6d2010ae
A
693 VERIFY(SLIST_EMPTY(&igi->igi_relinmhead));
694 igi->igi_debug &= ~IFD_ATTACHED;
695 IGI_UNLOCK(igi);
696
697 LIST_REMOVE(igi, igi_link);
698 IGI_REMREF(igi); /* release igi_head reference */
699 return;
700 }
701 IGI_UNLOCK(igi);
702 }
39236c6e
A
703 panic("%s: igmp_ifinfo not found for ifp %p(%s)\n", __func__,
704 ifp, ifp->if_xname);
6d2010ae
A
705}
706
316670eb
A
707__private_extern__ void
708igmp_initsilent(struct ifnet *ifp, struct igmp_ifinfo *igi)
709{
710 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_OWNED);
711
712 IGI_LOCK_ASSERT_NOTHELD(igi);
713 IGI_LOCK(igi);
0a7de745 714 if (!(ifp->if_flags & IFF_MULTICAST)) {
316670eb 715 igi->igi_flags |= IGIF_SILENT;
0a7de745 716 } else {
316670eb 717 igi->igi_flags &= ~IGIF_SILENT;
0a7de745 718 }
316670eb
A
719 IGI_UNLOCK(igi);
720}
721
6d2010ae
A
722static void
723igi_initvar(struct igmp_ifinfo *igi, struct ifnet *ifp, int reattach)
724{
725 IGI_LOCK_ASSERT_HELD(igi);
726
727 igi->igi_ifp = ifp;
728 igi->igi_version = igmp_default_version;
729 igi->igi_flags = 0;
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;
734
0a7de745 735 if (!reattach) {
6d2010ae 736 SLIST_INIT(&igi->igi_relinmhead);
0a7de745 737 }
1c79356b
A
738
739 /*
6d2010ae 740 * Responses to general queries are subject to bounds.
1c79356b 741 */
6d2010ae
A
742 igi->igi_gq.ifq_maxlen = IGMP_MAX_RESPONSE_PACKETS;
743 igi->igi_v2q.ifq_maxlen = IGMP_MAX_RESPONSE_PACKETS;
744}
1c79356b 745
6d2010ae
A
746static struct igmp_ifinfo *
747igi_alloc(int how)
748{
749 struct igmp_ifinfo *igi;
1c79356b 750
6d2010ae
A
751 igi = (how == M_WAITOK) ? zalloc(igi_zone) : zalloc_noblock(igi_zone);
752 if (igi != NULL) {
753 bzero(igi, igi_size);
754 lck_mtx_init(&igi->igi_lock, igmp_mtx_grp, igmp_mtx_attr);
755 igi->igi_debug |= IFD_ALLOC;
756 }
0a7de745 757 return igi;
6d2010ae
A
758}
759
760static void
761igi_free(struct igmp_ifinfo *igi)
762{
763 IGI_LOCK(igi);
764 if (igi->igi_debug & IFD_ATTACHED) {
765 panic("%s: attached igi=%p is being freed", __func__, igi);
766 /* NOTREACHED */
767 } else if (igi->igi_ifp != NULL) {
768 panic("%s: ifp not NULL for igi=%p", __func__, igi);
769 /* NOTREACHED */
770 } else if (!(igi->igi_debug & IFD_ALLOC)) {
771 panic("%s: igi %p cannot be freed", __func__, igi);
772 /* NOTREACHED */
773 } else if (igi->igi_refcnt != 0) {
774 panic("%s: non-zero refcnt igi=%p", __func__, igi);
775 /* NOTREACHED */
1c79356b 776 }
6d2010ae
A
777 igi->igi_debug &= ~IFD_ALLOC;
778 IGI_UNLOCK(igi);
779
780 lck_mtx_destroy(&igi->igi_lock, igmp_mtx_grp);
781 zfree(igi_zone, igi);
1c79356b
A
782}
783
784void
6d2010ae 785igi_addref(struct igmp_ifinfo *igi, int locked)
1c79356b 786{
0a7de745 787 if (!locked) {
6d2010ae 788 IGI_LOCK_SPIN(igi);
0a7de745 789 } else {
6d2010ae 790 IGI_LOCK_ASSERT_HELD(igi);
0a7de745 791 }
1c79356b 792
6d2010ae
A
793 if (++igi->igi_refcnt == 0) {
794 panic("%s: igi=%p wraparound refcnt", __func__, igi);
795 /* NOTREACHED */
1c79356b 796 }
0a7de745 797 if (!locked) {
6d2010ae 798 IGI_UNLOCK(igi);
0a7de745 799 }
1c79356b
A
800}
801
6d2010ae
A
802void
803igi_remref(struct igmp_ifinfo *igi)
1c79356b 804{
13f56ec4 805 SLIST_HEAD(, in_multi) inm_dthead;
6d2010ae 806 struct ifnet *ifp;
1c79356b 807
6d2010ae 808 IGI_LOCK_SPIN(igi);
1c79356b 809
6d2010ae
A
810 if (igi->igi_refcnt == 0) {
811 panic("%s: igi=%p negative refcnt", __func__, igi);
812 /* NOTREACHED */
813 }
814
815 --igi->igi_refcnt;
816 if (igi->igi_refcnt > 0) {
817 IGI_UNLOCK(igi);
818 return;
819 }
820
821 ifp = igi->igi_ifp;
822 igi->igi_ifp = NULL;
823 IF_DRAIN(&igi->igi_gq);
824 IF_DRAIN(&igi->igi_v2q);
13f56ec4
A
825 SLIST_INIT(&inm_dthead);
826 igmp_flush_relq(igi, (struct igmp_inm_relhead *)&inm_dthead);
6d2010ae
A
827 VERIFY(SLIST_EMPTY(&igi->igi_relinmhead));
828 IGI_UNLOCK(igi);
829
13f56ec4
A
830 /* Now that we're dropped all locks, release detached records */
831 IGMP_REMOVE_DETACHED_INM(&inm_dthead);
832
39236c6e
A
833 IGMP_PRINTF(("%s: freeing igmp_ifinfo for ifp 0x%llx(%s)\n",
834 __func__, (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
6d2010ae
A
835
836 igi_free(igi);
837}
838
839/*
840 * Process a received IGMPv1 query.
841 * Return non-zero if the message should be dropped.
842 */
843static int
844igmp_input_v1_query(struct ifnet *ifp, const struct ip *ip,
845 const struct igmp *igmp)
846{
0a7de745
A
847 struct igmp_ifinfo *igi;
848 struct in_multi *inm;
849 struct in_multistep step;
cb323159 850 struct igmp_tparams itp = { .qpt = 0, .it = 0, .cst = 0, .sct = 0 };
39236c6e
A
851
852 IGMP_LOCK_ASSERT_NOTHELD();
1c79356b
A
853
854 /*
6d2010ae
A
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.
1c79356b 859 */
6d2010ae
A
860 if (!in_allhosts(ip->ip_dst) || !in_nullhost(igmp->igmp_group)) {
861 IGMPSTAT_INC(igps_rcv_badqueries);
862 OIGMPSTAT_INC(igps_rcv_badqueries);
39236c6e 863 goto done;
d1ecb069 864 }
6d2010ae 865 IGMPSTAT_INC(igps_rcv_gen_queries);
1c79356b 866
6d2010ae
A
867 igi = IGMP_IFINFO(ifp);
868 VERIFY(igi != NULL);
869
870 IGI_LOCK(igi);
871 if (igi->igi_flags & IGIF_LOOPBACK) {
39236c6e
A
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)));
6d2010ae 875 IGI_UNLOCK(igi);
39236c6e 876 goto done;
6d2010ae
A
877 }
878 /*
879 * Switch to IGMPv1 host compatibility mode.
880 */
39236c6e 881 itp.qpt = igmp_set_version(igi, IGMP_VERSION_1);
6d2010ae 882 IGI_UNLOCK(igi);
2d21ac55 883
39236c6e
A
884 IGMP_PRINTF(("%s: process v1 query on ifp 0x%llx(%s)\n", __func__,
885 (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
6d2010ae
A
886
887 /*
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.
891 */
892 in_multihead_lock_shared();
893 IN_FIRST_MULTI(step, inm);
894 while (inm != NULL) {
895 INM_LOCK(inm);
0a7de745 896 if (inm->inm_ifp != ifp || inm->inm_timer != 0) {
6d2010ae 897 goto next;
0a7de745 898 }
6d2010ae
A
899
900 switch (inm->inm_state) {
901 case IGMP_NOT_MEMBER:
902 case IGMP_SILENT_MEMBER:
903 break;
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;
39236c6e
A
912 inm->inm_timer = IGMP_RANDOM_DELAY(IGMP_V1V2_MAX_RI);
913 itp.cst = 1;
6d2010ae
A
914 break;
915 case IGMP_LEAVING_MEMBER:
916 break;
917 }
918next:
919 INM_UNLOCK(inm);
920 IN_NEXT_MULTI(step, inm);
921 }
922 in_multihead_lock_done();
39236c6e
A
923done:
924 igmp_set_timeout(&itp);
6d2010ae 925
0a7de745 926 return 0;
6d2010ae
A
927}
928
929/*
930 * Process a received IGMPv2 general or group-specific query.
931 */
932static int
933igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip,
934 const struct igmp *igmp)
935{
0a7de745
A
936 struct igmp_ifinfo *igi;
937 struct in_multi *inm;
938 int is_general_query;
939 uint16_t timer;
cb323159 940 struct igmp_tparams itp = { .qpt = 0, .it = 0, .cst = 0, .sct = 0 };
39236c6e
A
941
942 IGMP_LOCK_ASSERT_NOTHELD();
6d2010ae
A
943
944 is_general_query = 0;
945
946 /*
947 * Validate address fields upfront.
948 */
949 if (in_nullhost(igmp->igmp_group)) {
950 /*
951 * IGMPv2 General Query.
952 * If this was not sent to the all-hosts group, ignore it.
953 */
0a7de745 954 if (!in_allhosts(ip->ip_dst)) {
39236c6e 955 goto done;
0a7de745 956 }
6d2010ae
A
957 IGMPSTAT_INC(igps_rcv_gen_queries);
958 is_general_query = 1;
959 } else {
960 /* IGMPv2 Group-Specific Query. */
961 IGMPSTAT_INC(igps_rcv_group_queries);
962 }
963
964 igi = IGMP_IFINFO(ifp);
965 VERIFY(igi != NULL);
966
967 IGI_LOCK(igi);
968 if (igi->igi_flags & IGIF_LOOPBACK) {
39236c6e
A
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)));
6d2010ae 972 IGI_UNLOCK(igi);
39236c6e 973 goto done;
6d2010ae
A
974 }
975 /*
976 * Ignore v2 query if in v1 Compatibility Mode.
977 */
978 if (igi->igi_version == IGMP_VERSION_1) {
979 IGI_UNLOCK(igi);
39236c6e 980 goto done;
6d2010ae 981 }
39236c6e 982 itp.qpt = igmp_set_version(igi, IGMP_VERSION_2);
6d2010ae
A
983 IGI_UNLOCK(igi);
984
39236c6e 985 timer = igmp->igmp_code / IGMP_TIMER_SCALE;
0a7de745 986 if (timer == 0) {
6d2010ae 987 timer = 1;
0a7de745 988 }
6d2010ae
A
989
990 if (is_general_query) {
991 struct in_multistep step;
992
39236c6e
A
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)));
6d2010ae
A
995 /*
996 * For each reporting group joined on this
997 * interface, kick the report timer.
998 */
999 in_multihead_lock_shared();
1000 IN_FIRST_MULTI(step, inm);
1001 while (inm != NULL) {
1002 INM_LOCK(inm);
0a7de745 1003 if (inm->inm_ifp == ifp) {
39236c6e 1004 itp.cst += igmp_v2_update_group(inm, timer);
0a7de745 1005 }
6d2010ae
A
1006 INM_UNLOCK(inm);
1007 IN_NEXT_MULTI(step, inm);
1008 }
1009 in_multihead_lock_done();
1010 } else {
1011 /*
1012 * Group-specific IGMPv2 query, we need only
1013 * look up the single group to process it.
1014 */
1015 in_multihead_lock_shared();
1016 IN_LOOKUP_MULTI(&igmp->igmp_group, ifp, inm);
1017 in_multihead_lock_done();
1018 if (inm != NULL) {
1019 INM_LOCK(inm);
39236c6e
A
1020 IGMP_INET_PRINTF(igmp->igmp_group,
1021 ("process v2 query %s on ifp 0x%llx(%s)\n",
1022 _igmp_inet_buf,
1023 (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
1024 itp.cst = igmp_v2_update_group(inm, timer);
6d2010ae
A
1025 INM_UNLOCK(inm);
1026 INM_REMREF(inm); /* from IN_LOOKUP_MULTI */
1027 }
1028 }
39236c6e
A
1029done:
1030 igmp_set_timeout(&itp);
6d2010ae 1031
0a7de745 1032 return 0;
6d2010ae
A
1033}
1034
1035/*
1036 * Update the report timer on a group in response to an IGMPv2 query.
1037 *
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.
1041 *
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
0a7de745 1045 * for group and group-source query responses.
6d2010ae
A
1046 *
1047 * Unlike IGMPv3, the delay per group should be jittered
1048 * to avoid bursts of IGMPv2 reports.
1049 */
39236c6e 1050static uint32_t
6d2010ae
A
1051igmp_v2_update_group(struct in_multi *inm, const int timer)
1052{
39236c6e
A
1053 IGMP_INET_PRINTF(inm->inm_addr, ("%s: %s/%s timer=%d\n",
1054 __func__, _igmp_inet_buf, if_name(inm->inm_ifp),
1055 timer));
6d2010ae
A
1056
1057 INM_LOCK_ASSERT_HELD(inm);
1058
1059 switch (inm->inm_state) {
1060 case IGMP_NOT_MEMBER:
1061 case IGMP_SILENT_MEMBER:
1062 break;
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__));
1068 break;
1069 }
0a7de745 1070 /* FALLTHROUGH */
6d2010ae
A
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);
6d2010ae
A
1079 break;
1080 case IGMP_SLEEPING_MEMBER:
1081 IGMP_PRINTF(("%s: ->AWAKENING\n", __func__));
1082 inm->inm_state = IGMP_AWAKENING_MEMBER;
1083 break;
1084 case IGMP_LEAVING_MEMBER:
1085 break;
1086 }
39236c6e 1087
0a7de745 1088 return inm->inm_timer;
6d2010ae
A
1089}
1090
1091/*
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.
1096 */
1097static int
1098igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip,
1099 /*const*/ struct igmpv3 *igmpv3)
1100{
0a7de745
A
1101 struct igmp_ifinfo *igi;
1102 struct in_multi *inm;
1103 int is_general_query;
1104 uint32_t maxresp, nsrc, qqi;
1105 uint16_t timer;
1106 uint8_t qrv;
cb323159 1107 struct igmp_tparams itp = { .qpt = 0, .it = 0, .cst = 0, .sct = 0 };
39236c6e
A
1108
1109 IGMP_LOCK_ASSERT_NOTHELD();
6d2010ae
A
1110
1111 is_general_query = 0;
1112
39236c6e
A
1113 IGMP_PRINTF(("%s: process v3 query on ifp 0x%llx(%s)\n", __func__,
1114 (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
6d2010ae 1115
0a7de745 1116 maxresp = igmpv3->igmp_code; /* in 1/10ths of a second */
6d2010ae
A
1117 if (maxresp >= 128) {
1118 maxresp = IGMP_MANT(igmpv3->igmp_code) <<
0a7de745 1119 (IGMP_EXP(igmpv3->igmp_code) + 3);
6d2010ae
A
1120 }
1121
1122 /*
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).
1127 */
1128 qrv = IGMP_QRV(igmpv3->igmp_misc);
1129 if (qrv < 2) {
1130 IGMP_PRINTF(("%s: clamping qrv %d to %d\n", __func__,
1131 qrv, IGMP_RV_INIT));
1132 qrv = IGMP_RV_INIT;
1133 }
1134
1135 qqi = igmpv3->igmp_qqi;
1136 if (qqi >= 128) {
1137 qqi = IGMP_MANT(igmpv3->igmp_qqi) <<
0a7de745 1138 (IGMP_EXP(igmpv3->igmp_qqi) + 3);
6d2010ae
A
1139 }
1140
39236c6e 1141 timer = maxresp / IGMP_TIMER_SCALE;
0a7de745 1142 if (timer == 0) {
6d2010ae 1143 timer = 1;
0a7de745 1144 }
6d2010ae
A
1145
1146 nsrc = ntohs(igmpv3->igmp_numsrc);
1147
1148 /*
1149 * Validate address fields and versions upfront before
1150 * accepting v3 query.
1151 */
1152 if (in_nullhost(igmpv3->igmp_group)) {
1153 /*
1154 * IGMPv3 General Query.
1155 *
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.
1159 */
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);
39236c6e 1164 goto done;
6d2010ae
A
1165 }
1166 is_general_query = 1;
1167 } else {
1168 /* Group or group-source specific query. */
0a7de745 1169 if (nsrc == 0) {
6d2010ae 1170 IGMPSTAT_INC(igps_rcv_group_queries);
0a7de745 1171 } else {
6d2010ae 1172 IGMPSTAT_INC(igps_rcv_gsr_queries);
0a7de745 1173 }
6d2010ae
A
1174 }
1175
1176 igi = IGMP_IFINFO(ifp);
1177 VERIFY(igi != NULL);
1178
1179 IGI_LOCK(igi);
1180 if (igi->igi_flags & IGIF_LOOPBACK) {
39236c6e
A
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)));
6d2010ae 1184 IGI_UNLOCK(igi);
39236c6e 1185 goto done;
6d2010ae
A
1186 }
1187
1188 /*
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
1192 * timer expires.
1193 */
1194 if (igi->igi_version != IGMP_VERSION_3) {
39236c6e
A
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)));
6d2010ae 1198 IGI_UNLOCK(igi);
39236c6e 1199 goto done;
6d2010ae
A
1200 }
1201
39236c6e 1202 itp.qpt = igmp_set_version(igi, IGMP_VERSION_3);
6d2010ae
A
1203 igi->igi_rv = qrv;
1204 igi->igi_qi = qqi;
39236c6e 1205 igi->igi_qri = MAX(timer, IGMP_QRI_MIN);
6d2010ae 1206
39236c6e
A
1207 IGMP_PRINTF(("%s: qrv %d qi %d qri %d\n", __func__, igi->igi_rv,
1208 igi->igi_qi, igi->igi_qri));
6d2010ae
A
1209
1210 if (is_general_query) {
1211 /*
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.
1218 */
39236c6e
A
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)));
6d2010ae 1221 if (igi->igi_v3_timer == 0 || igi->igi_v3_timer >= timer) {
39236c6e 1222 itp.it = igi->igi_v3_timer = IGMP_RANDOM_DELAY(timer);
6d2010ae
A
1223 }
1224 IGI_UNLOCK(igi);
1225 } else {
1226 IGI_UNLOCK(igi);
1227 /*
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.
1232 */
1233 in_multihead_lock_shared();
1234 IN_LOOKUP_MULTI(&igmpv3->igmp_group, ifp, inm);
1235 in_multihead_lock_done();
0a7de745 1236 if (inm == NULL) {
39236c6e 1237 goto done;
0a7de745 1238 }
6d2010ae
A
1239
1240 INM_LOCK(inm);
6d2010ae
A
1241 if (nsrc > 0) {
1242 if (!ratecheck(&inm->inm_lastgsrtv,
1243 &igmp_gsrdelay)) {
1244 IGMP_PRINTF(("%s: GS query throttled.\n",
1245 __func__));
1246 IGMPSTAT_INC(igps_drop_gsr_queries);
1247 INM_UNLOCK(inm);
1248 INM_REMREF(inm); /* from IN_LOOKUP_MULTI */
39236c6e 1249 goto done;
6d2010ae
A
1250 }
1251 }
39236c6e
A
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)));
6d2010ae
A
1255 /*
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.
1261 */
1262 IGI_LOCK(igi);
39236c6e
A
1263 itp.it = igi->igi_v3_timer;
1264 IGI_UNLOCK(igi);
1265 if (itp.it == 0 || itp.it >= timer) {
1266 (void) igmp_input_v3_group_query(inm, timer, igmpv3);
1267 itp.cst = inm->inm_timer;
6d2010ae
A
1268 }
1269 INM_UNLOCK(inm);
1270 INM_REMREF(inm); /* from IN_LOOKUP_MULTI */
1271 }
39236c6e
A
1272done:
1273 if (itp.it > 0) {
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)));
1277 }
1278 igmp_set_timeout(&itp);
6d2010ae 1279
0a7de745 1280 return 0;
6d2010ae
A
1281}
1282
1283/*
1284 * Process a recieved IGMPv3 group-specific or group-and-source-specific
1285 * query.
1286 * Return <0 if any error occured. Currently this is ignored.
1287 */
1288static int
39236c6e 1289igmp_input_v3_group_query(struct in_multi *inm,
6d2010ae
A
1290 int timer, /*const*/ struct igmpv3 *igmpv3)
1291{
0a7de745
A
1292 int retval;
1293 uint16_t nsrc;
6d2010ae
A
1294
1295 INM_LOCK_ASSERT_HELD(inm);
1296
1297 retval = 0;
1298
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:
0a7de745 1307 return retval;
6d2010ae
A
1308 case IGMP_REPORTING_MEMBER:
1309 case IGMP_G_QUERY_PENDING_MEMBER:
1310 case IGMP_SG_QUERY_PENDING_MEMBER:
1311 break;
1312 }
1313
1314 nsrc = ntohs(igmpv3->igmp_numsrc);
1315
1316 /*
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.
1321 */
1322 if (nsrc == 0) {
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);
1327 }
1328 inm->inm_state = IGMP_G_QUERY_PENDING_MEMBER;
1329 inm->inm_timer = IGMP_RANDOM_DELAY(timer);
0a7de745 1330 return retval;
6d2010ae
A
1331 }
1332
1333 /*
1334 * Deal with the case where a group-and-source-specific query has
1335 * been received but a group-specific query is already pending.
1336 */
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);
0a7de745 1340 return retval;
6d2010ae
A
1341 }
1342
1343 /*
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.
1356 */
1357 if (inm->inm_nsrc > 0) {
0a7de745
A
1358 const struct in_addr *ap;
1359 int i, nrecorded;
6d2010ae
A
1360
1361 ap = (const struct in_addr *)(igmpv3 + 1);
1362 nrecorded = 0;
1363 for (i = 0; i < nsrc; i++, ap++) {
1364 retval = inm_record_source(inm, ap->s_addr);
0a7de745 1365 if (retval < 0) {
6d2010ae 1366 break;
0a7de745 1367 }
6d2010ae
A
1368 nrecorded += retval;
1369 }
1370 if (nrecorded > 0) {
1371 IGMP_PRINTF(("%s: schedule response to SG query\n",
1372 __func__));
1373 inm->inm_state = IGMP_SG_QUERY_PENDING_MEMBER;
1374 inm->inm_timer = IGMP_RANDOM_DELAY(timer);
6d2010ae
A
1375 }
1376 }
1377
0a7de745 1378 return retval;
6d2010ae
A
1379}
1380
1381/*
1382 * Process a received IGMPv1 host membership report.
1383 *
1384 * NOTE: 0.0.0.0 workaround breaks const correctness.
1385 */
1386static int
39236c6e 1387igmp_input_v1_report(struct ifnet *ifp, struct mbuf *m, /*const*/ struct ip *ip,
6d2010ae
A
1388 /*const*/ struct igmp *igmp)
1389{
1390 struct in_ifaddr *ia;
1391 struct in_multi *inm;
1392
1393 IGMPSTAT_INC(igps_rcv_reports);
1394 OIGMPSTAT_INC(igps_rcv_reports);
1395
39236c6e 1396 if ((ifp->if_flags & IFF_LOOPBACK) ||
0a7de745
A
1397 (m->m_pkthdr.pkt_flags & PKTF_LOOP)) {
1398 return 0;
1399 }
6d2010ae
A
1400
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);
0a7de745 1405 return EINVAL;
6d2010ae
A
1406 }
1407
1408 /*
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.
1414 */
1415 if (igmp_recvifkludge && in_nullhost(ip->ip_src)) {
1416 IFP_TO_IA(ifp, ia);
1417 if (ia != NULL) {
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);
1422 }
1423 }
1424
39236c6e
A
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)));
6d2010ae
A
1428
1429 /*
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.
1433 */
1434 in_multihead_lock_shared();
1435 IN_LOOKUP_MULTI(&igmp->igmp_group, ifp, inm);
1436 in_multihead_lock_done();
1437 if (inm != NULL) {
1438 struct igmp_ifinfo *igi;
1439
1440 INM_LOCK(inm);
1441
1442 igi = inm->inm_igi;
1443 VERIFY(igi != NULL);
1444
1445 IGMPSTAT_INC(igps_rcv_ourreports);
1446 OIGMPSTAT_INC(igps_rcv_ourreports);
1447
1448 /*
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.
1452 */
1453 IGI_LOCK(igi);
1454 if (igi->igi_version == IGMP_VERSION_3) {
0a7de745 1455 if (igmp_legacysupp) {
6d2010ae 1456 igmp_v3_suppress_group_record(inm);
0a7de745 1457 }
6d2010ae
A
1458 IGI_UNLOCK(igi);
1459 INM_UNLOCK(inm);
1460 INM_REMREF(inm); /* from IN_LOOKUP_MULTI */
0a7de745 1461 return 0;
6d2010ae
A
1462 }
1463
1464 INM_LOCK_ASSERT_HELD(inm);
1465 inm->inm_timer = 0;
1466
1467 switch (inm->inm_state) {
1468 case IGMP_NOT_MEMBER:
1469 case IGMP_SILENT_MEMBER:
1470 break;
1471 case IGMP_IDLE_MEMBER:
1472 case IGMP_LAZY_MEMBER:
1473 case IGMP_AWAKENING_MEMBER:
39236c6e
A
1474 IGMP_INET_PRINTF(igmp->igmp_group,
1475 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1476 _igmp_inet_buf,
1477 (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
6d2010ae
A
1478 case IGMP_SLEEPING_MEMBER:
1479 inm->inm_state = IGMP_SLEEPING_MEMBER;
1480 break;
1481 case IGMP_REPORTING_MEMBER:
39236c6e
A
1482 IGMP_INET_PRINTF(igmp->igmp_group,
1483 ("report suppressed for %s on ifp 0x%llx(%s)\n",
1484 _igmp_inet_buf,
1485 (uint64_t)VM_KERNEL_ADDRPERM(ifp), if_name(ifp)));
0a7de745 1486 if (igi->igi_version == IGMP_VERSION_1) {
6d2010ae 1487 inm->inm_state = IGMP_LAZY_MEMBER;
0a7de745 1488 } else if (igi->igi_version == IGMP_VERSION_2) {
6d2010ae 1489 inm->inm_state = IGMP_SLEEPING_MEMBER;
0a7de745 1490 }
6d2010ae
A
1491 break;
1492 case IGMP_G_QUERY_PENDING_MEMBER:
1493 case IGMP_SG_QUERY_PENDING_MEMBER:
1494 case IGMP_LEAVING_MEMBER:
1495 break;
1496 }
1497 IGI_UNLOCK(igi);
1498 INM_UNLOCK(inm);
1499 INM_REMREF(inm); /* from IN_LOOKUP_MULTI */
1500 }
1501
0a7de745 1502 return 0;
6d2010ae
A
1503}
1504
1505/*
1506 * Process a received IGMPv2 host membership report.
1507 *
1508 * NOTE: 0.0.0.0 workaround breaks const correctness.
1509 */
1510static int
39236c6e 1511igmp_input_v2_report(struct ifnet *ifp, struct mbuf *m, /*const*/ struct ip *ip,
6d2010ae
A
1512 /*const*/ struct igmp *igmp)
1513{
1514 struct in_ifaddr *ia;
1515 struct in_multi *inm;
1516
1517 /*
1518 * Make sure we don't hear our own membership report. Fast
1519 * leave requires knowing that we are the only member of a
1520 * group.
1521 */
1522 IFP_TO_IA(ifp, ia);
1523 if (ia != NULL) {
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);
0a7de745 1528 return 0;
6d2010ae
A
1529 }
1530 IFA_UNLOCK(&ia->ia_ifa);
1531 }
1532
1533 IGMPSTAT_INC(igps_rcv_reports);
1534 OIGMPSTAT_INC(igps_rcv_reports);
1535
39236c6e
A
1536 if ((ifp->if_flags & IFF_LOOPBACK) ||
1537 (m->m_pkthdr.pkt_flags & PKTF_LOOP)) {
0a7de745 1538 if (ia != NULL) {
6d2010ae 1539 IFA_REMREF(&ia->ia_ifa);
0a7de745
A
1540 }
1541 return 0;
6d2010ae
A
1542 }
1543
1544 if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
1545 !in_hosteq(igmp->igmp_group, ip->ip_dst)) {
0a7de745 1546 if (ia != NULL) {
6d2010ae 1547 IFA_REMREF(&ia->ia_ifa);
0a7de745 1548 }
6d2010ae
A
1549 IGMPSTAT_INC(igps_rcv_badreports);
1550 OIGMPSTAT_INC(igps_rcv_badreports);
0a7de745 1551 return EINVAL;
6d2010ae
A
1552 }
1553
1554 /*
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.
1560 */
1561 if (igmp_recvifkludge && in_nullhost(ip->ip_src)) {
1562 if (ia != NULL) {
1563 IFA_LOCK(&ia->ia_ifa);
1564 ip->ip_src.s_addr = htonl(ia->ia_subnet);
1565 IFA_UNLOCK(&ia->ia_ifa);
1566 }
1567 }
0a7de745 1568 if (ia != NULL) {
6d2010ae 1569 IFA_REMREF(&ia->ia_ifa);
0a7de745 1570 }
6d2010ae 1571
39236c6e
A
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)));
6d2010ae
A
1575
1576 /*
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.
1581 */
1582 in_multihead_lock_shared();
1583 IN_LOOKUP_MULTI(&igmp->igmp_group, ifp, inm);
1584 in_multihead_lock_done();
1585 if (inm != NULL) {
1586 struct igmp_ifinfo *igi;
1587
1588 INM_LOCK(inm);
1589 igi = inm->inm_igi;
1590 VERIFY(igi != NULL);
1591
1592 IGMPSTAT_INC(igps_rcv_ourreports);
1593 OIGMPSTAT_INC(igps_rcv_ourreports);
1594
1595 /*
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.
1599 */
1600 IGI_LOCK(igi);
1601 if (igi->igi_version == IGMP_VERSION_3) {
0a7de745 1602 if (igmp_legacysupp) {
6d2010ae 1603 igmp_v3_suppress_group_record(inm);
0a7de745 1604 }
6d2010ae
A
1605 IGI_UNLOCK(igi);
1606 INM_UNLOCK(inm);
1607 INM_REMREF(inm);
0a7de745 1608 return 0;
6d2010ae
A
1609 }
1610
1611 inm->inm_timer = 0;
1612
1613 switch (inm->inm_state) {
1614 case IGMP_NOT_MEMBER:
1615 case IGMP_SILENT_MEMBER:
1616 case IGMP_SLEEPING_MEMBER:
1617 break;
1618 case IGMP_REPORTING_MEMBER:
1619 case IGMP_IDLE_MEMBER:
1620 case IGMP_AWAKENING_MEMBER:
39236c6e
A
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),
1624 if_name(ifp)));
6d2010ae
A
1625 case IGMP_LAZY_MEMBER:
1626 inm->inm_state = IGMP_LAZY_MEMBER;
1627 break;
1628 case IGMP_G_QUERY_PENDING_MEMBER:
1629 case IGMP_SG_QUERY_PENDING_MEMBER:
1630 case IGMP_LEAVING_MEMBER:
1631 break;
1632 }
1633 IGI_UNLOCK(igi);
1634 INM_UNLOCK(inm);
1635 INM_REMREF(inm);
1636 }
1637
0a7de745 1638 return 0;
6d2010ae
A
1639}
1640
1641void
1642igmp_input(struct mbuf *m, int off)
1643{
1644 int iphlen;
1645 struct ifnet *ifp;
1646 struct igmp *igmp;
1647 struct ip *ip;
1648 int igmplen;
1649 int minlen;
1650 int queryver;
1651
39236c6e
A
1652 IGMP_PRINTF(("%s: called w/mbuf (0x%llx,%d)\n", __func__,
1653 (uint64_t)VM_KERNEL_ADDRPERM(m), off));
6d2010ae
A
1654
1655 ifp = m->m_pkthdr.rcvif;
1656
1657 IGMPSTAT_INC(igps_rcv_total);
1658 OIGMPSTAT_INC(igps_rcv_total);
1659
316670eb
A
1660 /* Expect 32-bit aligned data pointer on strict-align platforms */
1661 MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
1662
6d2010ae
A
1663 ip = mtod(m, struct ip *);
1664 iphlen = off;
1665
1666 /* By now, ip_len no longer contains the length of IP header */
1667 igmplen = ip->ip_len;
1668
1669 /*
1670 * Validate lengths.
1671 */
1672 if (igmplen < IGMP_MINLEN) {
1673 IGMPSTAT_INC(igps_rcv_tooshort);
1674 OIGMPSTAT_INC(igps_rcv_tooshort);
1675 m_freem(m);
1676 return;
1677 }
1678
1679 /*
1680 * Always pullup to the minimum size for v1/v2 or v3
1681 * to amortize calls to m_pulldown().
1682 */
0a7de745 1683 if (igmplen >= IGMP_V3_QUERY_MINLEN) {
6d2010ae 1684 minlen = IGMP_V3_QUERY_MINLEN;
0a7de745 1685 } else {
6d2010ae 1686 minlen = IGMP_MINLEN;
0a7de745 1687 }
6d2010ae 1688
316670eb
A
1689 /* A bit more expensive than M_STRUCT_GET, but ensures alignment */
1690 M_STRUCT_GET0(igmp, struct igmp *, m, off, minlen);
6d2010ae
A
1691 if (igmp == NULL) {
1692 IGMPSTAT_INC(igps_rcv_tooshort);
1693 OIGMPSTAT_INC(igps_rcv_tooshort);
1694 return;
1695 }
bd504ef0 1696 /* N.B.: we assume the packet was correctly aligned in ip_input. */
6d2010ae
A
1697
1698 /*
1699 * Validate checksum.
1700 */
1701 m->m_data += iphlen;
1702 m->m_len -= iphlen;
1703 if (in_cksum(m, igmplen)) {
1704 IGMPSTAT_INC(igps_rcv_badsum);
1705 OIGMPSTAT_INC(igps_rcv_badsum);
1706 m_freem(m);
1707 return;
1708 }
1709 m->m_data -= iphlen;
1710 m->m_len += iphlen;
1711
1712 /*
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.
1716 */
1717 if (igmp->igmp_type != IGMP_DVMRP && ip->ip_ttl != 1) {
1718 IGMPSTAT_INC(igps_rcv_badttl);
1719 m_freem(m);
1720 return;
1721 }
1722
1723 switch (igmp->igmp_type) {
1724 case IGMP_HOST_MEMBERSHIP_QUERY:
1725 if (igmplen == IGMP_MINLEN) {
0a7de745 1726 if (igmp->igmp_code == 0) {
6d2010ae 1727 queryver = IGMP_VERSION_1;
0a7de745 1728 } else {
6d2010ae 1729 queryver = IGMP_VERSION_2;
0a7de745 1730 }
6d2010ae
A
1731 } else if (igmplen >= IGMP_V3_QUERY_MINLEN) {
1732 queryver = IGMP_VERSION_3;
1733 } else {
1734 IGMPSTAT_INC(igps_rcv_tooshort);
1735 OIGMPSTAT_INC(igps_rcv_tooshort);
1736 m_freem(m);
1737 return;
1738 }
1739
1740 OIGMPSTAT_INC(igps_rcv_queries);
1741
1742 switch (queryver) {
1743 case IGMP_VERSION_1:
1744 IGMPSTAT_INC(igps_rcv_v1v2_queries);
0a7de745 1745 if (!igmp_v1enable) {
6d2010ae 1746 break;
0a7de745 1747 }
6d2010ae
A
1748 if (igmp_input_v1_query(ifp, ip, igmp) != 0) {
1749 m_freem(m);
1750 return;
1751 }
1752 break;
1753
1754 case IGMP_VERSION_2:
1755 IGMPSTAT_INC(igps_rcv_v1v2_queries);
0a7de745 1756 if (!igmp_v2enable) {
6d2010ae 1757 break;
0a7de745 1758 }
6d2010ae
A
1759 if (igmp_input_v2_query(ifp, ip, igmp) != 0) {
1760 m_freem(m);
1761 return;
1762 }
1763 break;
1764
1765 case IGMP_VERSION_3: {
0a7de745
A
1766 struct igmpv3 *igmpv3;
1767 uint16_t igmpv3len;
1768 uint16_t srclen;
1769 int nsrc;
6d2010ae 1770
0a7de745
A
1771 IGMPSTAT_INC(igps_rcv_v3_queries);
1772 igmpv3 = (struct igmpv3 *)igmp;
1773 /*
1774 * Validate length based on source count.
1775 */
1776 nsrc = ntohs(igmpv3->igmp_numsrc);
1777 /*
1778 * The max vaue of nsrc is limited by the
1779 * MTU of the network on which the datagram
1780 * is received
1781 */
1782 if (nsrc < 0 || nsrc > IGMP_V3_QUERY_MAX_SRCS) {
1783 IGMPSTAT_INC(igps_rcv_tooshort);
1784 OIGMPSTAT_INC(igps_rcv_tooshort);
1785 m_freem(m);
1786 return;
6d2010ae 1787 }
0a7de745
A
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);
1792 m_freem(m);
1793 return;
1794 }
1795 igmpv3len = IGMP_V3_QUERY_MINLEN + srclen;
1796 /*
1797 * A bit more expensive than M_STRUCT_GET,
1798 * but ensures alignment.
1799 */
1800 M_STRUCT_GET0(igmpv3, struct igmpv3 *, m,
1801 off, igmpv3len);
1802 if (igmpv3 == NULL) {
1803 IGMPSTAT_INC(igps_rcv_tooshort);
1804 OIGMPSTAT_INC(igps_rcv_tooshort);
1805 return;
1806 }
1807 /*
1808 * N.B.: we assume the packet was correctly
1809 * aligned in ip_input.
1810 */
1811 if (igmp_input_v3_query(ifp, ip, igmpv3) != 0) {
1812 m_freem(m);
1813 return;
1814 }
1815 }
1816 break;
6d2010ae
A
1817 }
1818 break;
1819
1820 case IGMP_v1_HOST_MEMBERSHIP_REPORT:
0a7de745 1821 if (!igmp_v1enable) {
6d2010ae 1822 break;
0a7de745 1823 }
39236c6e 1824 if (igmp_input_v1_report(ifp, m, ip, igmp) != 0) {
6d2010ae
A
1825 m_freem(m);
1826 return;
1827 }
1828 break;
1829
1830 case IGMP_v2_HOST_MEMBERSHIP_REPORT:
0a7de745 1831 if (!igmp_v2enable) {
6d2010ae 1832 break;
0a7de745
A
1833 }
1834 if (!ip_checkrouteralert(m)) {
6d2010ae 1835 IGMPSTAT_INC(igps_rcv_nora);
0a7de745 1836 }
39236c6e 1837 if (igmp_input_v2_report(ifp, m, ip, igmp) != 0) {
6d2010ae
A
1838 m_freem(m);
1839 return;
1840 }
1841 break;
1842
1843 case IGMP_v3_HOST_MEMBERSHIP_REPORT:
1844 /*
1845 * Hosts do not need to process IGMPv3 membership reports,
1846 * as report suppression is no longer required.
1847 */
0a7de745 1848 if (!ip_checkrouteralert(m)) {
6d2010ae 1849 IGMPSTAT_INC(igps_rcv_nora);
0a7de745 1850 }
6d2010ae
A
1851 break;
1852
1853 default:
1854 break;
1855 }
1856
39236c6e 1857 IGMP_LOCK_ASSERT_NOTHELD();
6d2010ae
A
1858 /*
1859 * Pass all valid IGMP packets up to any process(es) listening on a
1860 * raw IGMP socket.
1861 */
1862 rip_input(m, off);
1863}
1864
6d2010ae 1865/*
39236c6e
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.
6d2010ae
A
1868 */
1869void
39236c6e
A
1870igmp_set_timeout(struct igmp_tparams *itp)
1871{
1872 IGMP_LOCK_ASSERT_NOTHELD();
1873 VERIFY(itp != NULL);
1874
1875 if (itp->qpt != 0 || itp->it != 0 || itp->cst != 0 || itp->sct != 0) {
1876 IGMP_LOCK();
0a7de745 1877 if (itp->qpt != 0) {
39236c6e 1878 querier_present_timers_running = 1;
0a7de745
A
1879 }
1880 if (itp->it != 0) {
39236c6e 1881 interface_timers_running = 1;
0a7de745
A
1882 }
1883 if (itp->cst != 0) {
39236c6e 1884 current_state_timers_running = 1;
0a7de745
A
1885 }
1886 if (itp->sct != 0) {
39236c6e 1887 state_change_timers_running = 1;
0a7de745 1888 }
39236c6e
A
1889 igmp_sched_timeout();
1890 IGMP_UNLOCK();
1891 }
1892}
1893
1894/*
1895 * IGMP timer handler (per 1 second).
1896 */
1897static void
1898igmp_timeout(void *arg)
6d2010ae 1899{
39236c6e 1900#pragma unused(arg)
0a7de745
A
1901 struct ifqueue scq; /* State-change packets */
1902 struct ifqueue qrq; /* Query response packets */
1903 struct ifnet *ifp;
1904 struct igmp_ifinfo *igi;
1905 struct in_multi *inm;
1906 int loop = 0, uri_sec = 0;
1907 SLIST_HEAD(, in_multi) inm_dthead;
13f56ec4
A
1908
1909 SLIST_INIT(&inm_dthead);
6d2010ae 1910
39236c6e
A
1911 /*
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().
1915 */
1916 net_update_uptime();
1917
1918 IGMP_LOCK();
6d2010ae 1919
39236c6e
A
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));
6d2010ae
A
1923
1924 /*
39236c6e 1925 * IGMPv1/v2 querier present timer processing.
6d2010ae 1926 */
39236c6e
A
1927 if (querier_present_timers_running) {
1928 querier_present_timers_running = 0;
1929 LIST_FOREACH(igi, &igi_head, igi_link) {
1930 IGI_LOCK(igi);
1931 igmp_v1v2_process_querier_timers(igi);
0a7de745 1932 if (igi->igi_v1_timer > 0 || igi->igi_v2_timer > 0) {
39236c6e 1933 querier_present_timers_running = 1;
0a7de745 1934 }
39236c6e
A
1935 IGI_UNLOCK(igi);
1936 }
6d2010ae
A
1937 }
1938
1939 /*
1940 * IGMPv3 General Query response timer processing.
1941 */
1942 if (interface_timers_running) {
39236c6e 1943 IGMP_PRINTF(("%s: interface timers running\n", __func__));
6d2010ae
A
1944 interface_timers_running = 0;
1945 LIST_FOREACH(igi, &igi_head, igi_link) {
1946 IGI_LOCK(igi);
fe8ab488
A
1947 if (igi->igi_version != IGMP_VERSION_3) {
1948 IGI_UNLOCK(igi);
1949 continue;
1950 }
6d2010ae
A
1951 if (igi->igi_v3_timer == 0) {
1952 /* Do nothing. */
1953 } else if (--igi->igi_v3_timer == 0) {
0a7de745 1954 if (igmp_v3_dispatch_general_query(igi) > 0) {
39236c6e 1955 interface_timers_running = 1;
0a7de745 1956 }
6d2010ae
A
1957 } else {
1958 interface_timers_running = 1;
1959 }
1960 IGI_UNLOCK(igi);
1961 }
1962 }
1963
1964 if (!current_state_timers_running &&
0a7de745 1965 !state_change_timers_running) {
6d2010ae 1966 goto out_locked;
0a7de745 1967 }
6d2010ae
A
1968
1969 current_state_timers_running = 0;
1970 state_change_timers_running = 0;
1971
1972 memset(&qrq, 0, sizeof(struct ifqueue));
1973 qrq.ifq_maxlen = IGMP_MAX_G_GS_PACKETS;
1974
1975 memset(&scq, 0, sizeof(struct ifqueue));
1976 scq.ifq_maxlen = IGMP_MAX_STATE_CHANGE_PACKETS;
1977
39236c6e
A
1978 IGMP_PRINTF(("%s: state change timers running\n", __func__));
1979
6d2010ae
A
1980 /*
1981 * IGMPv1/v2/v3 host report and state-change timer processing.
1982 * Note: Processing a v3 group timer may remove a node.
1983 */
1984 LIST_FOREACH(igi, &igi_head, igi_link) {
1985 struct in_multistep step;
1986
1987 IGI_LOCK(igi);
1988 ifp = igi->igi_ifp;
1989 loop = (igi->igi_flags & IGIF_LOOPBACK) ? 1 : 0;
39236c6e 1990 uri_sec = IGMP_RANDOM_DELAY(igi->igi_uri);
6d2010ae
A
1991 IGI_UNLOCK(igi);
1992
1993 in_multihead_lock_shared();
1994 IN_FIRST_MULTI(step, inm);
1995 while (inm != NULL) {
1996 INM_LOCK(inm);
0a7de745 1997 if (inm->inm_ifp != ifp) {
6d2010ae 1998 goto next;
0a7de745 1999 }
6d2010ae
A
2000
2001 IGI_LOCK(igi);
2002 switch (igi->igi_version) {
0a7de745
A
2003 case IGMP_VERSION_1:
2004 case IGMP_VERSION_2:
2005 igmp_v1v2_process_group_timer(inm,
2006 igi->igi_version);
2007 break;
2008 case IGMP_VERSION_3:
2009 igmp_v3_process_group_timers(igi, &qrq,
2010 &scq, inm, uri_sec);
2011 break;
6d2010ae
A
2012 }
2013 IGI_UNLOCK(igi);
2014next:
2015 INM_UNLOCK(inm);
2016 IN_NEXT_MULTI(step, inm);
2017 }
2018 in_multihead_lock_done();
2019
2020 IGI_LOCK(igi);
2021 if (igi->igi_version == IGMP_VERSION_1 ||
2022 igi->igi_version == IGMP_VERSION_2) {
39236c6e 2023 igmp_dispatch_queue(igi, &igi->igi_v2q, 0, loop);
6d2010ae
A
2024 } else if (igi->igi_version == IGMP_VERSION_3) {
2025 IGI_UNLOCK(igi);
39236c6e
A
2026 igmp_dispatch_queue(NULL, &qrq, 0, loop);
2027 igmp_dispatch_queue(NULL, &scq, 0, loop);
6d2010ae
A
2028 VERIFY(qrq.ifq_len == 0);
2029 VERIFY(scq.ifq_len == 0);
2030 IGI_LOCK(igi);
2031 }
2032 /*
2033 * In case there are still any pending membership reports
2034 * which didn't get drained at version change time.
2035 */
2036 IF_DRAIN(&igi->igi_v2q);
2037 /*
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.
2042 */
13f56ec4 2043 igmp_flush_relq(igi, (struct igmp_inm_relhead *)&inm_dthead);
6d2010ae
A
2044 VERIFY(SLIST_EMPTY(&igi->igi_relinmhead));
2045 IGI_UNLOCK(igi);
2046
2047 IF_DRAIN(&qrq);
2048 IF_DRAIN(&scq);
2049 }
2050
2051out_locked:
39236c6e
A
2052 /* re-arm the timer if there's work to do */
2053 igmp_timeout_run = 0;
2054 igmp_sched_timeout();
2055 IGMP_UNLOCK();
13f56ec4
A
2056
2057 /* Now that we're dropped all locks, release detached records */
2058 IGMP_REMOVE_DETACHED_INM(&inm_dthead);
6d2010ae
A
2059}
2060
39236c6e
A
2061static void
2062igmp_sched_timeout(void)
2063{
2064 IGMP_LOCK_ASSERT_HELD();
2065
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);
2071 }
2072}
2073
6d2010ae
A
2074/*
2075 * Free the in_multi reference(s) for this IGMP lifecycle.
2076 *
2077 * Caller must be holding igi_lock.
2078 */
2079static void
13f56ec4 2080igmp_flush_relq(struct igmp_ifinfo *igi, struct igmp_inm_relhead *inm_dthead)
6d2010ae
A
2081{
2082 struct in_multi *inm;
2083
2084again:
2085 IGI_LOCK_ASSERT_HELD(igi);
2086 inm = SLIST_FIRST(&igi->igi_relinmhead);
2087 if (inm != NULL) {
2088 int lastref;
2089
2090 SLIST_REMOVE_HEAD(&igi->igi_relinmhead, inm_nrele);
2091 IGI_UNLOCK(igi);
2092
2093 in_multihead_lock_exclusive();
2094 INM_LOCK(inm);
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));
2100 INM_UNLOCK(inm);
2101 in_multihead_lock_done();
2102 /* from igi_relinmhead */
2103 INM_REMREF(inm);
2104 /* from in_multihead list */
13f56ec4
A
2105 if (lastref) {
2106 /*
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
2112 * when it is safe.
2113 */
2114 IGMP_ADD_DETACHED_INM(inm_dthead, inm);
2115 }
6d2010ae
A
2116 IGI_LOCK(igi);
2117 goto again;
2118 }
2119}
2120
2121/*
2122 * Update host report group timer for IGMPv1/v2.
2123 * Will update the global pending timer flags.
2124 */
2125static void
2126igmp_v1v2_process_group_timer(struct in_multi *inm, const int igmp_version)
2127{
2128 int report_timer_expired;
2129
39236c6e 2130 IGMP_LOCK_ASSERT_HELD();
6d2010ae
A
2131 INM_LOCK_ASSERT_HELD(inm);
2132 IGI_LOCK_ASSERT_HELD(inm->inm_igi);
2133
2134 if (inm->inm_timer == 0) {
2135 report_timer_expired = 0;
2136 } else if (--inm->inm_timer == 0) {
2137 report_timer_expired = 1;
2138 } else {
2139 current_state_timers_running = 1;
39236c6e 2140 /* caller will schedule timer */
6d2010ae
A
2141 return;
2142 }
2143
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:
2151 break;
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) ?
0a7de745
A
2157 IGMP_v2_HOST_MEMBERSHIP_REPORT :
2158 IGMP_v1_HOST_MEMBERSHIP_REPORT);
6d2010ae
A
2159 INM_LOCK_ASSERT_HELD(inm);
2160 IGI_LOCK_ASSERT_HELD(inm->inm_igi);
2161 }
2162 break;
2163 case IGMP_G_QUERY_PENDING_MEMBER:
2164 case IGMP_SG_QUERY_PENDING_MEMBER:
2165 case IGMP_LEAVING_MEMBER:
2166 break;
2167 }
2168}
2169
2170/*
2171 * Update a group's timers for IGMPv3.
2172 * Will update the global pending timer flags.
2173 * Note: Unlocked read from igi.
2174 */
2175static void
2176igmp_v3_process_group_timers(struct igmp_ifinfo *igi,
2177 struct ifqueue *qrq, struct ifqueue *scq,
39236c6e 2178 struct in_multi *inm, const int uri_sec)
6d2010ae
A
2179{
2180 int query_response_timer_expired;
2181 int state_change_retransmit_timer_expired;
2182
39236c6e 2183 IGMP_LOCK_ASSERT_HELD();
6d2010ae
A
2184 INM_LOCK_ASSERT_HELD(inm);
2185 IGI_LOCK_ASSERT_HELD(igi);
2186 VERIFY(igi == inm->inm_igi);
2187
2188 query_response_timer_expired = 0;
2189 state_change_retransmit_timer_expired = 0;
2190
2191 /*
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
39236c6e 2195 * to deal with it here than to complicate the timeout path.
6d2010ae
A
2196 */
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;
2201 } else {
2202 current_state_timers_running = 1;
39236c6e 2203 /* caller will schedule timer */
6d2010ae
A
2204 }
2205
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;
2210 } else {
2211 state_change_timers_running = 1;
39236c6e 2212 /* caller will schedule timer */
6d2010ae
A
2213 }
2214
39236c6e 2215 /* We are in timer callback, so be quick about it. */
6d2010ae 2216 if (!state_change_retransmit_timer_expired &&
0a7de745 2217 !query_response_timer_expired) {
6d2010ae 2218 return;
0a7de745 2219 }
6d2010ae
A
2220
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:
2228 break;
2229 case IGMP_G_QUERY_PENDING_MEMBER:
2230 case IGMP_SG_QUERY_PENDING_MEMBER:
2231 /*
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.
2236 */
2237 if (query_response_timer_expired) {
2238 int retval;
2239
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",
2243 __func__, retval));
2244 inm->inm_state = IGMP_REPORTING_MEMBER;
2245 /* XXX Clear recorded sources for next time. */
2246 inm_clear_recorded(inm);
2247 }
0a7de745 2248 /* FALLTHROUGH */
6d2010ae
A
2249 case IGMP_REPORTING_MEMBER:
2250 case IGMP_LEAVING_MEMBER:
2251 if (state_change_retransmit_timer_expired) {
2252 /*
2253 * State-change retransmission timer fired.
2254 * If there are any further pending retransmissions,
2255 * set the global pending state-change flag, and
2256 * reset the timer.
2257 */
2258 if (--inm->inm_scrv > 0) {
39236c6e 2259 inm->inm_sctimer = uri_sec;
6d2010ae 2260 state_change_timers_running = 1;
39236c6e 2261 /* caller will schedule timer */
6d2010ae
A
2262 }
2263 /*
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
2268 * a state-change.
2269 */
2270 (void) igmp_v3_merge_state_changes(inm, scq);
2271
2272 inm_commit(inm);
39236c6e
A
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)));
6d2010ae
A
2276
2277 /*
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.
2283 */
2284 if (inm->inm_state == IGMP_LEAVING_MEMBER &&
2285 inm->inm_scrv == 0) {
2286 inm->inm_state = IGMP_NOT_MEMBER;
2287 /*
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.
2295 */
2296 VERIFY(inm->inm_nrelecnt != 0);
2297 SLIST_INSERT_HEAD(&igi->igi_relinmhead,
2298 inm, inm_nrele);
2299 }
2300 }
2301 break;
2302 }
2303}
2304
2305/*
2306 * Suppress a group's pending response to a group or source/group query.
2307 *
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.
2313 */
2314static void
2315igmp_v3_suppress_group_record(struct in_multi *inm)
2316{
6d2010ae
A
2317 INM_LOCK_ASSERT_HELD(inm);
2318 IGI_LOCK_ASSERT_HELD(inm->inm_igi);
2319
2320 VERIFY(inm->inm_igi->igi_version == IGMP_VERSION_3);
2321
2322 if (inm->inm_state != IGMP_G_QUERY_PENDING_MEMBER ||
0a7de745 2323 inm->inm_state != IGMP_SG_QUERY_PENDING_MEMBER) {
6d2010ae 2324 return;
0a7de745 2325 }
6d2010ae 2326
0a7de745 2327 if (inm->inm_state == IGMP_SG_QUERY_PENDING_MEMBER) {
6d2010ae 2328 inm_clear_recorded(inm);
0a7de745 2329 }
6d2010ae
A
2330
2331 inm->inm_timer = 0;
2332 inm->inm_state = IGMP_REPORTING_MEMBER;
2333}
2334
2335/*
2336 * Switch to a different IGMP version on the given interface,
2337 * as per Section 7.2.1.
2338 */
39236c6e 2339static uint32_t
6d2010ae
A
2340igmp_set_version(struct igmp_ifinfo *igi, const int igmp_version)
2341{
2342 int old_version_timer;
2343
2344 IGI_LOCK_ASSERT_HELD(igi);
2345
39236c6e
A
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)));
6d2010ae
A
2349
2350 if (igmp_version == IGMP_VERSION_1 || igmp_version == IGMP_VERSION_2) {
2351 /*
2352 * Compute the "Older Version Querier Present" timer as per
39236c6e 2353 * Section 8.12, in seconds.
6d2010ae
A
2354 */
2355 old_version_timer = igi->igi_rv * igi->igi_qi + igi->igi_qri;
6d2010ae
A
2356
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;
2363 }
2364 }
2365
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);
2370 }
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);
2375 }
2376 }
2377
2378 IGI_LOCK_ASSERT_HELD(igi);
39236c6e 2379
0a7de745 2380 return MAX(igi->igi_v1_timer, igi->igi_v2_timer);
6d2010ae
A
2381}
2382
2383/*
2384 * Cancel pending IGMPv3 timers for the given link and all groups
2385 * joined on it; state-change, general-query, and group-query timers.
2386 *
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
2390 * query processing.
2391 */
2392static void
2393igmp_v3_cancel_link_timers(struct igmp_ifinfo *igi)
2394{
0a7de745
A
2395 struct ifnet *ifp;
2396 struct in_multi *inm;
2397 struct in_multistep step;
6d2010ae
A
2398
2399 IGI_LOCK_ASSERT_HELD(igi);
2400
39236c6e
A
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)));
6d2010ae
A
2403
2404 /*
2405 * Stop the v3 General Query Response on this link stone dead.
39236c6e 2406 * If timer is woken up due to interface_timers_running,
6d2010ae
A
2407 * the flag will be cleared if there are no pending link timers.
2408 */
2409 igi->igi_v3_timer = 0;
2410
2411 /*
2412 * Now clear the current-state and state-change report timers
2413 * for all memberships scoped to this link.
2414 */
2415 ifp = igi->igi_ifp;
2416 IGI_UNLOCK(igi);
2417
2418 in_multihead_lock_shared();
2419 IN_FIRST_MULTI(step, inm);
2420 while (inm != NULL) {
2421 INM_LOCK(inm);
0a7de745 2422 if (inm->inm_ifp != ifp) {
6d2010ae 2423 goto next;
0a7de745 2424 }
6d2010ae
A
2425
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:
2433 /*
2434 * These states are either not relevant in v3 mode,
2435 * or are unreported. Do nothing.
2436 */
2437 break;
2438 case IGMP_LEAVING_MEMBER:
2439 /*
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.
2450 */
2451 VERIFY(inm->inm_nrelecnt != 0);
2452 IGI_LOCK(igi);
2453 SLIST_INSERT_HEAD(&igi->igi_relinmhead, inm, inm_nrele);
2454 IGI_UNLOCK(igi);
0a7de745 2455 /* FALLTHROUGH */
6d2010ae
A
2456 case IGMP_G_QUERY_PENDING_MEMBER:
2457 case IGMP_SG_QUERY_PENDING_MEMBER:
2458 inm_clear_recorded(inm);
0a7de745 2459 /* FALLTHROUGH */
6d2010ae
A
2460 case IGMP_REPORTING_MEMBER:
2461 inm->inm_state = IGMP_REPORTING_MEMBER;
2462 break;
2463 }
2464 /*
2465 * Always clear state-change and group report timers.
2466 * Free any pending IGMPv3 state-change records.
2467 */
2468 inm->inm_sctimer = 0;
2469 inm->inm_timer = 0;
2470 IF_DRAIN(&inm->inm_scq);
2471next:
2472 INM_UNLOCK(inm);
2473 IN_NEXT_MULTI(step, inm);
2474 }
2475 in_multihead_lock_done();
2476
2477 IGI_LOCK(igi);
2478}
2479
2480/*
2481 * Update the Older Version Querier Present timers for a link.
2482 * See Section 7.2.1 of RFC 3376.
2483 */
2484static void
2485igmp_v1v2_process_querier_timers(struct igmp_ifinfo *igi)
2486{
2487 IGI_LOCK_ASSERT_HELD(igi);
2488
2489 if (igi->igi_v1_timer == 0 && igi->igi_v2_timer == 0) {
2490 /*
2491 * IGMPv1 and IGMPv2 Querier Present timers expired.
2492 *
2493 * Revert to IGMPv3.
2494 */
2495 if (igi->igi_version != IGMP_VERSION_3) {
39236c6e
A
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)));
6d2010ae
A
2501 igi->igi_version = IGMP_VERSION_3;
2502 IF_DRAIN(&igi->igi_v2q);
2503 }
2504 } else if (igi->igi_v1_timer == 0 && igi->igi_v2_timer > 0) {
2505 /*
2506 * IGMPv1 Querier Present timer expired,
2507 * IGMPv2 Querier Present timer running.
2508 * If IGMPv2 was disabled since last timeout,
2509 * revert to IGMPv3.
2510 * If IGMPv2 is enabled, revert to IGMPv2.
2511 */
2512 if (!igmp_v2enable) {
39236c6e
A
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));
6d2010ae
A
2518 igi->igi_v2_timer = 0;
2519 igi->igi_version = IGMP_VERSION_3;
2520 IF_DRAIN(&igi->igi_v2q);
2521 } else {
2522 --igi->igi_v2_timer;
2523 if (igi->igi_version != IGMP_VERSION_2) {
39236c6e
A
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)));
6d2010ae
A
2529 igi->igi_version = IGMP_VERSION_2;
2530 IF_DRAIN(&igi->igi_gq);
39236c6e 2531 igmp_v3_cancel_link_timers(igi);
6d2010ae
A
2532 }
2533 }
2534 } else if (igi->igi_v1_timer > 0) {
2535 /*
2536 * IGMPv1 Querier Present timer running.
2537 * Stop IGMPv2 timer if running.
2538 *
2539 * If IGMPv1 was disabled since last timeout,
2540 * revert to IGMPv3.
2541 * If IGMPv1 is enabled, reset IGMPv2 timer if running.
2542 */
2543 if (!igmp_v1enable) {
39236c6e
A
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));
6d2010ae
A
2549 igi->igi_v1_timer = 0;
2550 igi->igi_version = IGMP_VERSION_3;
2551 IF_DRAIN(&igi->igi_v2q);
2552 } else {
2553 --igi->igi_v1_timer;
2554 }
2555 if (igi->igi_v2_timer > 0) {
39236c6e
A
2556 IGMP_PRINTF(("%s: cancel v2 timer on 0x%llx(%s%d)\n",
2557 __func__,
2558 (uint64_t)VM_KERNEL_ADDRPERM(igi->igi_ifp),
2559 igi->igi_ifp->if_name, igi->igi_ifp->if_unit));
6d2010ae
A
2560 igi->igi_v2_timer = 0;
2561 }
2562 }
2563}
2564
2565/*
2566 * Dispatch an IGMPv1/v2 host report or leave message.
2567 * These are always small enough to fit inside a single mbuf.
2568 */
2569static int
2570igmp_v1v2_queue_report(struct in_multi *inm, const int type)
2571{
0a7de745
A
2572 struct ifnet *ifp;
2573 struct igmp *igmp;
2574 struct ip *ip;
2575 struct mbuf *m;
2576 int error = 0;
6d2010ae
A
2577
2578 INM_LOCK_ASSERT_HELD(inm);
2579 IGI_LOCK_ASSERT_HELD(inm->inm_igi);
2580
2581 ifp = inm->inm_ifp;
2582
2583 MGETHDR(m, M_DONTWAIT, MT_DATA);
0a7de745
A
2584 if (m == NULL) {
2585 return ENOMEM;
2586 }
6d2010ae
A
2587 MH_ALIGN(m, sizeof(struct ip) + sizeof(struct igmp));
2588
2589 m->m_pkthdr.len = sizeof(struct ip) + sizeof(struct igmp);
2590
2591 m->m_data += sizeof(struct ip);
2592 m->m_len = sizeof(struct igmp);
2593
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));
2600
2601 m->m_data -= sizeof(struct ip);
2602 m->m_len += sizeof(struct ip);
2603
2604 ip = mtod(m, struct ip *);
2605 ip->ip_tos = 0;
2606 ip->ip_len = sizeof(struct ip) + sizeof(struct igmp);
2607 ip->ip_off = 0;
2608 ip->ip_p = IPPROTO_IGMP;
2609 ip->ip_src.s_addr = INADDR_ANY;
2610
0a7de745 2611 if (type == IGMP_HOST_LEAVE_MESSAGE) {
6d2010ae 2612 ip->ip_dst.s_addr = htonl(INADDR_ALLRTRS_GROUP);
0a7de745 2613 } else {
6d2010ae 2614 ip->ip_dst = inm->inm_addr;
0a7de745 2615 }
6d2010ae 2616
39236c6e
A
2617 igmp_save_context(m, ifp);
2618
6d2010ae 2619 m->m_flags |= M_IGMPV2;
0a7de745 2620 if (inm->inm_igi->igi_flags & IGIF_LOOPBACK) {
6d2010ae 2621 m->m_flags |= M_IGMP_LOOP;
0a7de745 2622 }
6d2010ae
A
2623
2624 /*
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.
39236c6e 2629 * Instead we defer the work to the igmp_timeout() thread, thus
6d2010ae
A
2630 * avoiding unlocking in_multihead_lock here.
2631 */
2632 if (IF_QFULL(&inm->inm_igi->igi_v2q)) {
2633 IGMP_PRINTF(("%s: v1/v2 outbound queue full\n", __func__));
2634 error = ENOMEM;
2635 m_freem(m);
39236c6e 2636 } else {
6d2010ae 2637 IF_ENQUEUE(&inm->inm_igi->igi_v2q, m);
39236c6e
A
2638 VERIFY(error == 0);
2639 }
0a7de745 2640 return error;
6d2010ae
A
2641}
2642
2643/*
2644 * Process a state change from the upper layer for the given IPv4 group.
2645 *
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)
2650 * and T1 (now).
2651 *
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.
2656 *
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.
2660 */
2661int
39236c6e 2662igmp_change_state(struct in_multi *inm, struct igmp_tparams *itp)
6d2010ae
A
2663{
2664 struct igmp_ifinfo *igi;
2665 struct ifnet *ifp;
2666 int error = 0;
2667
39236c6e 2668 VERIFY(itp != NULL);
0a7de745 2669 bzero(itp, sizeof(*itp));
39236c6e 2670
6d2010ae
A
2671 INM_LOCK_ASSERT_HELD(inm);
2672 VERIFY(inm->inm_igi != NULL);
2673 IGI_LOCK_ASSERT_NOTHELD(inm->inm_igi);
2674
2675 /*
2676 * Try to detect if the upper layer just asked us to change state
2677 * for an interface which has now gone away.
2678 */
2679 VERIFY(inm->inm_ifma != NULL);
2680 ifp = inm->inm_ifma->ifma_ifp;
2681 /*
2682 * Sanity check that netinet's notion of ifp is the same as net's.
2683 */
2684 VERIFY(inm->inm_ifp == ifp);
2685
2686 igi = IGMP_IFINFO(ifp);
2687 VERIFY(igi != NULL);
2688
2689 /*
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.
2693 */
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__));
39236c6e 2699 error = igmp_initial_join(inm, igi, itp);
6d2010ae
A
2700 goto out;
2701 } else if (inm->inm_st[1].iss_fmode == MCAST_UNDEFINED) {
2702 IGMP_PRINTF(("%s: final leave\n", __func__));
39236c6e 2703 igmp_final_leave(inm, igi, itp);
6d2010ae
A
2704 goto out;
2705 }
2706 } else {
2707 IGMP_PRINTF(("%s: filter set change\n", __func__));
2708 }
2709
39236c6e 2710 error = igmp_handle_state_change(inm, igi, itp);
6d2010ae 2711out:
0a7de745 2712 return error;
6d2010ae
A
2713}
2714
2715/*
2716 * Perform the initial join for an IGMP group.
2717 *
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.
2724 */
2725static int
39236c6e
A
2726igmp_initial_join(struct in_multi *inm, struct igmp_ifinfo *igi,
2727 struct igmp_tparams *itp)
6d2010ae 2728{
0a7de745
A
2729 struct ifnet *ifp;
2730 struct ifqueue *ifq;
2731 int error, retval, syncstates;
6d2010ae
A
2732
2733 INM_LOCK_ASSERT_HELD(inm);
2734 IGI_LOCK_ASSERT_NOTHELD(igi);
39236c6e 2735 VERIFY(itp != NULL);
6d2010ae 2736
39236c6e
A
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)));
6d2010ae
A
2741
2742 error = 0;
2743 syncstates = 1;
2744
2745 ifp = inm->inm_ifp;
2746
2747 IGI_LOCK(igi);
2748 VERIFY(igi->igi_ifp == ifp);
2749
2750 /*
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.
2758 */
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",
2763 __func__));
2764 inm->inm_state = IGMP_SILENT_MEMBER;
2765 inm->inm_timer = 0;
2766 } else {
2767 /*
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.
2774 */
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);
2779 }
2780
2781 inm->inm_state = IGMP_REPORTING_MEMBER;
2782
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) ?
0a7de745
A
2789 IGMP_v2_HOST_MEMBERSHIP_REPORT :
2790 IGMP_v1_HOST_MEMBERSHIP_REPORT);
6d2010ae
A
2791
2792 INM_LOCK_ASSERT_HELD(inm);
2793 IGI_LOCK_ASSERT_HELD(igi);
2794
2795 if (error == 0) {
39236c6e
A
2796 inm->inm_timer =
2797 IGMP_RANDOM_DELAY(IGMP_V1V2_MAX_RI);
2798 itp->cst = 1;
6d2010ae
A
2799 }
2800 break;
2801
2802 case IGMP_VERSION_3:
2803 /*
2804 * Defer update of T0 to T1, until the first copy
2805 * of the state change has been transmitted.
2806 */
2807 syncstates = 0;
2808
2809 /*
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.
2814 */
2815 ifq = &inm->inm_scq;
2816 IF_DRAIN(ifq);
2817 retval = igmp_v3_enqueue_group_record(ifq, inm, 1,
2818 0, 0);
39236c6e 2819 itp->cst = (ifq->ifq_len > 0);
6d2010ae
A
2820 IGMP_PRINTF(("%s: enqueue record = %d\n",
2821 __func__, retval));
2822 if (retval <= 0) {
2823 error = retval * -1;
2824 break;
2825 }
2826
2827 /*
2828 * Schedule transmission of pending state-change
2829 * report up to RV times for this link. The timer
39236c6e 2830 * will fire at the next igmp_timeout (1 second),
6d2010ae
A
2831 * giving us an opportunity to merge the reports.
2832 */
2833 if (igi->igi_flags & IGIF_LOOPBACK) {
2834 inm->inm_scrv = 1;
2835 } else {
2836 VERIFY(igi->igi_rv > 1);
2837 inm->inm_scrv = igi->igi_rv;
2838 }
2839 inm->inm_sctimer = 1;
39236c6e 2840 itp->sct = 1;
6d2010ae
A
2841
2842 error = 0;
2843 break;
2844 }
2845 }
2846 IGI_UNLOCK(igi);
2847
2848 /*
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.
2852 */
2853 if (syncstates) {
2854 inm_commit(inm);
39236c6e
A
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)));
6d2010ae
A
2858 }
2859
0a7de745 2860 return error;
6d2010ae
A
2861}
2862
2863/*
2864 * Issue an intermediate state change during the IGMP life-cycle.
2865 */
2866static int
39236c6e
A
2867igmp_handle_state_change(struct in_multi *inm, struct igmp_ifinfo *igi,
2868 struct igmp_tparams *itp)
6d2010ae 2869{
0a7de745
A
2870 struct ifnet *ifp;
2871 int retval = 0;
6d2010ae
A
2872
2873 INM_LOCK_ASSERT_HELD(inm);
2874 IGI_LOCK_ASSERT_NOTHELD(igi);
39236c6e 2875 VERIFY(itp != NULL);
6d2010ae 2876
39236c6e
A
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)));
6d2010ae
A
2881
2882 ifp = inm->inm_ifp;
2883
2884 IGI_LOCK(igi);
2885 VERIFY(igi->igi_ifp == ifp);
2886
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)) {
2891 IGI_UNLOCK(igi);
2892 if (!igmp_isgroupreported(inm->inm_addr)) {
2893 IGMP_PRINTF(("%s: not kicking state "
2894 "machine for silent group\n", __func__));
2895 }
2896 IGMP_PRINTF(("%s: nothing to do\n", __func__));
2897 inm_commit(inm);
39236c6e
A
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));
2901 goto done;
6d2010ae
A
2902 }
2903
2904 IF_DRAIN(&inm->inm_scq);
2905
2906 retval = igmp_v3_enqueue_group_record(&inm->inm_scq, inm, 1, 0, 0);
39236c6e 2907 itp->cst = (inm->inm_scq.ifq_len > 0);
6d2010ae
A
2908 IGMP_PRINTF(("%s: enqueue record = %d\n", __func__, retval));
2909 if (retval <= 0) {
2910 IGI_UNLOCK(igi);
39236c6e
A
2911 retval *= -1;
2912 goto done;
6d2010ae
A
2913 }
2914 /*
2915 * If record(s) were enqueued, start the state-change
2916 * report timer for this group.
2917 */
2918 inm->inm_scrv = ((igi->igi_flags & IGIF_LOOPBACK) ? 1 : igi->igi_rv);
2919 inm->inm_sctimer = 1;
39236c6e 2920 itp->sct = 1;
6d2010ae 2921 IGI_UNLOCK(igi);
39236c6e 2922done:
0a7de745 2923 return retval;
6d2010ae
A
2924}
2925
2926/*
2927 * Perform the final leave for an IGMP group.
2928 *
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.
2934 */
2935static void
39236c6e
A
2936igmp_final_leave(struct in_multi *inm, struct igmp_ifinfo *igi,
2937 struct igmp_tparams *itp)
6d2010ae
A
2938{
2939 int syncstates = 1;
2940
2941 INM_LOCK_ASSERT_HELD(inm);
2942 IGI_LOCK_ASSERT_NOTHELD(igi);
39236c6e 2943 VERIFY(itp != NULL);
6d2010ae 2944
39236c6e
A
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)));
6d2010ae
A
2949
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",
2956 __func__));
2957 break;
2958 case IGMP_REPORTING_MEMBER:
2959 case IGMP_IDLE_MEMBER:
2960 case IGMP_G_QUERY_PENDING_MEMBER:
2961 case IGMP_SG_QUERY_PENDING_MEMBER:
2962 IGI_LOCK(igi);
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__);
2968 /* NOTREACHED */
2969 }
39236c6e
A
2970 /* scheduler timer if enqueue is successful */
2971 itp->cst = (igmp_v1v2_queue_report(inm,
2972 IGMP_HOST_LEAVE_MESSAGE) == 0);
6d2010ae
A
2973
2974 INM_LOCK_ASSERT_HELD(inm);
2975 IGI_LOCK_ASSERT_HELD(igi);
2976
2977 inm->inm_state = IGMP_NOT_MEMBER;
2978 } else if (igi->igi_version == IGMP_VERSION_3) {
2979 /*
2980 * Stop group timer and all pending reports.
2981 * Immediately enqueue a state-change report
39236c6e 2982 * TO_IN {} to be sent on the next timeout,
6d2010ae
A
2983 * giving us an opportunity to merge reports.
2984 */
2985 IF_DRAIN(&inm->inm_scq);
2986 inm->inm_timer = 0;
2987 if (igi->igi_flags & IGIF_LOOPBACK) {
2988 inm->inm_scrv = 1;
2989 } else {
2990 inm->inm_scrv = igi->igi_rv;
2991 }
39236c6e
A
2992 IGMP_INET_PRINTF(inm->inm_addr,
2993 ("%s: Leaving %s/%s with %d "
6d2010ae 2994 "pending retransmissions.\n", __func__,
39236c6e 2995 _igmp_inet_buf, if_name(inm->inm_ifp),
6d2010ae
A
2996 inm->inm_scrv));
2997 if (inm->inm_scrv == 0) {
2998 inm->inm_state = IGMP_NOT_MEMBER;
2999 inm->inm_sctimer = 0;
3000 } else {
3001 int retval;
3002 /*
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.
3007 */
3008 INM_ADDREF_LOCKED(inm);
3009 VERIFY(inm->inm_debug & IFD_ATTACHED);
3010 inm->inm_reqcnt++;
3011 VERIFY(inm->inm_reqcnt >= 1);
3012 inm->inm_nrelecnt++;
3013 VERIFY(inm->inm_nrelecnt != 0);
3014
3015 retval = igmp_v3_enqueue_group_record(
0a7de745 3016 &inm->inm_scq, inm, 1, 0, 0);
39236c6e 3017 itp->cst = (inm->inm_scq.ifq_len > 0);
6d2010ae
A
3018 KASSERT(retval != 0,
3019 ("%s: enqueue record = %d\n", __func__,
0a7de745 3020 retval));
6d2010ae
A
3021
3022 inm->inm_state = IGMP_LEAVING_MEMBER;
3023 inm->inm_sctimer = 1;
39236c6e 3024 itp->sct = 1;
6d2010ae
A
3025 syncstates = 0;
3026 }
3027 }
3028 IGI_UNLOCK(igi);
3029 break;
3030 case IGMP_LAZY_MEMBER:
3031 case IGMP_SLEEPING_MEMBER:
3032 case IGMP_AWAKENING_MEMBER:
3033 /* Our reports are suppressed; do nothing. */
3034 break;
3035 }
3036
3037 if (syncstates) {
3038 inm_commit(inm);
39236c6e
A
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)));
6d2010ae 3042 inm->inm_st[1].iss_fmode = MCAST_UNDEFINED;
39236c6e
A
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)));
6d2010ae
A
3046 }
3047}
3048
3049/*
3050 * Enqueue an IGMPv3 group record to the given output queue.
3051 *
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().
3055 *
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.
3058 *
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.
3064 *
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.
3068 *
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.
3071 *
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.
3075 */
3076static int
3077igmp_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)
3080{
0a7de745
A
3081 struct igmp_grouprec ig;
3082 struct igmp_grouprec *pig;
3083 struct ifnet *ifp;
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;
3089 int now;
3090 int type;
3091 in_addr_t naddr;
3092 uint8_t mode;
3093 u_int16_t ig_numsrc;
6d2010ae
A
3094
3095 INM_LOCK_ASSERT_HELD(inm);
3096 IGI_LOCK_ASSERT_HELD(inm->inm_igi);
3097
3098 error = 0;
3099 ifp = inm->inm_ifp;
3100 is_filter_list_change = 0;
3101 m = NULL;
3102 m0 = NULL;
3103 m0srcs = 0;
3104 msrcs = 0;
3105 nbytes = 0;
3106 nims = NULL;
3107 record_has_sources = 1;
3108 pig = NULL;
3109 type = IGMP_DO_NOTHING;
3110 mode = inm->inm_st[1].iss_fmode;
3111
3112 /*
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.
3116 */
3117 if (inm->inm_st[0].iss_asm > 0 && inm->inm_st[1].iss_asm > 0 &&
0a7de745 3118 inm->inm_nsrc == 0) {
6d2010ae 3119 record_has_sources = 0;
0a7de745 3120 }
6d2010ae
A
3121
3122 if (is_state_change) {
3123 /*
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.
3132 */
3133 if (mode != inm->inm_st[0].iss_fmode) {
3134 if (mode == MCAST_EXCLUDE) {
3135 IGMP_PRINTF(("%s: change to EXCLUDE\n",
3136 __func__));
3137 type = IGMP_CHANGE_TO_EXCLUDE_MODE;
3138 } else {
3139 IGMP_PRINTF(("%s: change to INCLUDE\n",
3140 __func__));
3141 type = IGMP_CHANGE_TO_INCLUDE_MODE;
0a7de745 3142 if (mode == MCAST_UNDEFINED) {
6d2010ae 3143 record_has_sources = 0;
0a7de745 3144 }
6d2010ae
A
3145 }
3146 } else {
3147 if (record_has_sources) {
3148 is_filter_list_change = 1;
3149 } else {
3150 type = IGMP_DO_NOTHING;
3151 }
3152 }
3153 } else {
3154 /*
3155 * Queue a current state record.
3156 */
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);
3162 }
3163 }
3164
3165 /*
3166 * Generate the filter list changes using a separate function.
3167 */
0a7de745
A
3168 if (is_filter_list_change) {
3169 return igmp_v3_enqueue_filter_change(ifq, inm);
3170 }
6d2010ae
A
3171
3172 if (type == IGMP_DO_NOTHING) {
39236c6e
A
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)));
0a7de745 3177 return 0;
6d2010ae
A
3178 }
3179
3180 /*
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,
3183 * ideally more.
3184 */
3185 minrec0len = sizeof(struct igmp_grouprec);
0a7de745 3186 if (record_has_sources) {
6d2010ae 3187 minrec0len += sizeof(in_addr_t);
0a7de745 3188 }
6d2010ae 3189
39236c6e
A
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)));
6d2010ae
A
3194
3195 /*
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.
3202 */
3203 m0 = ifq->ifq_tail;
3204 if (!is_group_query &&
3205 m0 != NULL &&
3206 (m0->m_pkthdr.vt_nrecs + 1 <= IGMP_V3_REPORT_MAXRECS) &&
3207 (m0->m_pkthdr.len + minrec0len) <
0a7de745 3208 (ifp->if_mtu - IGMP_LEADINGSPACE)) {
6d2010ae 3209 m0srcs = (ifp->if_mtu - m0->m_pkthdr.len -
0a7de745 3210 sizeof(struct igmp_grouprec)) / sizeof(in_addr_t);
6d2010ae
A
3211 m = m0;
3212 IGMP_PRINTF(("%s: use existing packet\n", __func__));
3213 } else {
3214 if (IF_QFULL(ifq)) {
3215 IGMP_PRINTF(("%s: outbound queue full\n", __func__));
0a7de745 3216 return -ENOMEM;
6d2010ae
A
3217 }
3218 m = NULL;
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);
0a7de745 3223 if (m) {
6d2010ae 3224 m->m_data += IGMP_LEADINGSPACE;
0a7de745 3225 }
6d2010ae
A
3226 }
3227 if (m == NULL) {
3228 m = m_gethdr(M_DONTWAIT, MT_DATA);
0a7de745 3229 if (m) {
6d2010ae 3230 MH_ALIGN(m, IGMP_LEADINGSPACE);
0a7de745
A
3231 }
3232 }
3233 if (m == NULL) {
3234 return -ENOMEM;
6d2010ae 3235 }
6d2010ae 3236
39236c6e
A
3237 igmp_save_context(m, ifp);
3238
6d2010ae
A
3239 IGMP_PRINTF(("%s: allocated first packet\n", __func__));
3240 }
3241
3242 /*
3243 * Append group record.
3244 * If we have sources, we don't know how many yet.
3245 */
3246 ig.ig_type = type;
3247 ig.ig_datalen = 0;
3248 ig.ig_numsrc = 0;
3249 ig.ig_group = inm->inm_addr;
3250 if (!m_append(m, sizeof(struct igmp_grouprec), (void *)&ig)) {
0a7de745 3251 if (m != m0) {
6d2010ae 3252 m_freem(m);
0a7de745 3253 }
6d2010ae 3254 IGMP_PRINTF(("%s: m_append() failed.\n", __func__));
0a7de745 3255 return -ENOMEM;
6d2010ae
A
3256 }
3257 nbytes += sizeof(struct igmp_grouprec);
3258
3259 /*
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.
3271 */
3272 if (record_has_sources) {
3273 if (m == m0) {
3274 md = m_last(m);
316670eb
A
3275 pig = (struct igmp_grouprec *)(void *)
3276 (mtod(md, uint8_t *) + md->m_len - nbytes);
6d2010ae
A
3277 } else {
3278 md = m_getptr(m, 0, &off);
316670eb
A
3279 pig = (struct igmp_grouprec *)(void *)
3280 (mtod(md, uint8_t *) + off);
6d2010ae
A
3281 }
3282 msrcs = 0;
3283 RB_FOREACH_SAFE(ims, ip_msource_tree, &inm->inm_srcs, nims) {
39236c6e
A
3284#ifdef IGMP_DEBUG
3285 char buf[MAX_IPv4_STR_LEN];
3286
3287 inet_ntop_haddr(ims->ims_haddr, buf, sizeof(buf));
3288 IGMP_PRINTF(("%s: visit node %s\n", __func__, buf));
3289#endif
6d2010ae
A
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__));
3295 continue;
3296 }
3297 if (is_source_query && ims->ims_stp == 0) {
3298 IGMP_PRINTF(("%s: skip unrecorded node\n",
3299 __func__));
3300 continue;
3301 }
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)) {
0a7de745 3305 if (m != m0) {
6d2010ae 3306 m_freem(m);
0a7de745 3307 }
6d2010ae
A
3308 IGMP_PRINTF(("%s: m_append() failed.\n",
3309 __func__));
0a7de745 3310 return -ENOMEM;
6d2010ae
A
3311 }
3312 nbytes += sizeof(in_addr_t);
3313 ++msrcs;
0a7de745 3314 if (msrcs == m0srcs) {
6d2010ae 3315 break;
0a7de745 3316 }
6d2010ae
A
3317 }
3318 IGMP_PRINTF(("%s: msrcs is %d this packet\n", __func__,
3319 msrcs));
316670eb 3320 ig_numsrc = htons(msrcs);
0a7de745 3321 bcopy(&ig_numsrc, &pig->ig_numsrc, sizeof(ig_numsrc));
6d2010ae
A
3322 nbytes += (msrcs * sizeof(in_addr_t));
3323 }
3324
3325 if (is_source_query && msrcs == 0) {
3326 IGMP_PRINTF(("%s: no recorded sources to report\n", __func__));
0a7de745 3327 if (m != m0) {
6d2010ae 3328 m_freem(m);
0a7de745
A
3329 }
3330 return 0;
6d2010ae
A
3331 }
3332
3333 /*
3334 * We are good to go with first packet.
3335 */
3336 if (m != m0) {
3337 IGMP_PRINTF(("%s: enqueueing first packet\n", __func__));
3338 m->m_pkthdr.vt_nrecs = 1;
6d2010ae
A
3339 IF_ENQUEUE(ifq, m);
3340 } else {
3341 m->m_pkthdr.vt_nrecs++;
3342 }
3343 /*
3344 * No further work needed if no source list in packet(s).
3345 */
0a7de745
A
3346 if (!record_has_sources) {
3347 return nbytes;
3348 }
6d2010ae
A
3349
3350 /*
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.
3354 */
3355 while (nims != NULL) {
3356 if (IF_QFULL(ifq)) {
3357 IGMP_PRINTF(("%s: outbound queue full\n", __func__));
0a7de745 3358 return -ENOMEM;
6d2010ae
A
3359 }
3360 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
0a7de745 3361 if (m) {
6d2010ae 3362 m->m_data += IGMP_LEADINGSPACE;
0a7de745 3363 }
6d2010ae
A
3364 if (m == NULL) {
3365 m = m_gethdr(M_DONTWAIT, MT_DATA);
0a7de745 3366 if (m) {
6d2010ae 3367 MH_ALIGN(m, IGMP_LEADINGSPACE);
0a7de745
A
3368 }
3369 }
3370 if (m == NULL) {
3371 return -ENOMEM;
6d2010ae 3372 }
39236c6e 3373 igmp_save_context(m, ifp);
6d2010ae 3374 md = m_getptr(m, 0, &off);
316670eb
A
3375 pig = (struct igmp_grouprec *)(void *)
3376 (mtod(md, uint8_t *) + off);
6d2010ae
A
3377 IGMP_PRINTF(("%s: allocated next packet\n", __func__));
3378
3379 if (!m_append(m, sizeof(struct igmp_grouprec), (void *)&ig)) {
0a7de745 3380 if (m != m0) {
6d2010ae 3381 m_freem(m);
0a7de745 3382 }
6d2010ae 3383 IGMP_PRINTF(("%s: m_append() failed.\n", __func__));
0a7de745 3384 return -ENOMEM;
6d2010ae
A
3385 }
3386 m->m_pkthdr.vt_nrecs = 1;
3387 nbytes += sizeof(struct igmp_grouprec);
3388
3389 m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE -
3390 sizeof(struct igmp_grouprec)) / sizeof(in_addr_t);
3391
3392 msrcs = 0;
3393 RB_FOREACH_FROM(ims, ip_msource_tree, nims) {
39236c6e
A
3394#ifdef IGMP_DEBUG
3395 char buf[MAX_IPv4_STR_LEN];
3396
3397 inet_ntop_haddr(ims->ims_haddr, buf, sizeof(buf));
3398 IGMP_PRINTF(("%s: visit node %s\n", __func__, buf));
3399#endif
6d2010ae
A
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__));
3404 continue;
3405 }
3406 if (is_source_query && ims->ims_stp == 0) {
3407 IGMP_PRINTF(("%s: skip unrecorded node\n",
3408 __func__));
3409 continue;
3410 }
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)) {
0a7de745 3414 if (m != m0) {
6d2010ae 3415 m_freem(m);
0a7de745 3416 }
6d2010ae
A
3417 IGMP_PRINTF(("%s: m_append() failed.\n",
3418 __func__));
0a7de745 3419 return -ENOMEM;
6d2010ae
A
3420 }
3421 ++msrcs;
0a7de745 3422 if (msrcs == m0srcs) {
6d2010ae 3423 break;
0a7de745 3424 }
6d2010ae 3425 }
316670eb 3426 ig_numsrc = htons(msrcs);
0a7de745 3427 bcopy(&ig_numsrc, &pig->ig_numsrc, sizeof(ig_numsrc));
6d2010ae
A
3428 nbytes += (msrcs * sizeof(in_addr_t));
3429
3430 IGMP_PRINTF(("%s: enqueueing next packet\n", __func__));
6d2010ae
A
3431 IF_ENQUEUE(ifq, m);
3432 }
3433
0a7de745 3434 return nbytes;
6d2010ae
A
3435}
3436
3437/*
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.
3441 */
3442typedef enum {
0a7de745
A
3443 REC_NONE = 0x00, /* MCAST_UNDEFINED */
3444 REC_ALLOW = 0x01, /* MCAST_INCLUDE */
3445 REC_BLOCK = 0x02, /* MCAST_EXCLUDE */
6d2010ae
A
3446 REC_FULL = REC_ALLOW | REC_BLOCK
3447} rectype_t;
3448
3449/*
3450 * Enqueue an IGMPv3 filter list change to the given output queue.
3451 *
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.
3456 *
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.
3460 *
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
3464 * the L2 cache.
3465 *
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.
3469 */
3470static int
3471igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm)
3472{
3473 static const int MINRECLEN =
3474 sizeof(struct igmp_grouprec) + sizeof(in_addr_t);
0a7de745
A
3475 struct ifnet *ifp;
3476 struct igmp_grouprec ig;
3477 struct igmp_grouprec *pig;
3478 struct ip_msource *ims, *nims;
3479 struct mbuf *m, *m0, *md;
3480 in_addr_t naddr;
3481 int m0srcs, nbytes, npbytes, off, rsrcs, schanged;
3482 int nallow, nblock;
3483 uint8_t mode, now, then;
3484 rectype_t crt, drt, nrt;
3485 u_int16_t ig_numsrc;
6d2010ae
A
3486
3487 INM_LOCK_ASSERT_HELD(inm);
3488
3489 if (inm->inm_nsrc == 0 ||
0a7de745
A
3490 (inm->inm_st[0].iss_asm > 0 && inm->inm_st[1].iss_asm > 0)) {
3491 return 0;
3492 }
3493
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 */
6d2010ae
A
3507
3508 /*
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.
3514 */
3515 while (drt != REC_FULL) {
3516 do {
3517 m0 = ifq->ifq_tail;
3518 if (m0 != NULL &&
3519 (m0->m_pkthdr.vt_nrecs + 1 <=
0a7de745 3520 IGMP_V3_REPORT_MAXRECS) &&
6d2010ae 3521 (m0->m_pkthdr.len + MINRECLEN) <
0a7de745 3522 (ifp->if_mtu - IGMP_LEADINGSPACE)) {
6d2010ae
A
3523 m = m0;
3524 m0srcs = (ifp->if_mtu - m0->m_pkthdr.len -
0a7de745 3525 sizeof(struct igmp_grouprec)) /
6d2010ae
A
3526 sizeof(in_addr_t);
3527 IGMP_PRINTF(("%s: use previous packet\n",
3528 __func__));
3529 } else {
3530 m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
0a7de745 3531 if (m) {
6d2010ae 3532 m->m_data += IGMP_LEADINGSPACE;
0a7de745 3533 }
6d2010ae
A
3534 if (m == NULL) {
3535 m = m_gethdr(M_DONTWAIT, MT_DATA);
0a7de745 3536 if (m) {
6d2010ae 3537 MH_ALIGN(m, IGMP_LEADINGSPACE);
0a7de745 3538 }
6d2010ae
A
3539 }
3540 if (m == NULL) {
3541 IGMP_PRINTF(("%s: m_get*() failed\n",
3542 __func__));
0a7de745 3543 return -ENOMEM;
6d2010ae
A
3544 }
3545 m->m_pkthdr.vt_nrecs = 0;
39236c6e 3546 igmp_save_context(m, ifp);
6d2010ae
A
3547 m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE -
3548 sizeof(struct igmp_grouprec)) /
3549 sizeof(in_addr_t);
3550 npbytes = 0;
3551 IGMP_PRINTF(("%s: allocated new packet\n",
3552 __func__));
3553 }
3554 /*
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.
3560 */
3561 memset(&ig, 0, sizeof(ig));
3562 ig.ig_group = inm->inm_addr;
3563 if (!m_append(m, sizeof(ig), (void *)&ig)) {
0a7de745 3564 if (m != m0) {
6d2010ae 3565 m_freem(m);
0a7de745 3566 }
6d2010ae
A
3567 IGMP_PRINTF(("%s: m_append() failed\n",
3568 __func__));
0a7de745 3569 return -ENOMEM;
6d2010ae
A
3570 }
3571 npbytes += sizeof(struct igmp_grouprec);
3572 if (m != m0) {
3573 /* new packet; offset in c hain */
3574 md = m_getptr(m, npbytes -
3575 sizeof(struct igmp_grouprec), &off);
316670eb 3576 pig = (struct igmp_grouprec *)(void *)(mtod(md,
6d2010ae
A
3577 uint8_t *) + off);
3578 } else {
3579 /* current packet; offset from last append */
3580 md = m_last(m);
316670eb 3581 pig = (struct igmp_grouprec *)(void *)(mtod(md,
6d2010ae
A
3582 uint8_t *) + md->m_len -
3583 sizeof(struct igmp_grouprec));
3584 }
3585 /*
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.
3593 */
3594 rsrcs = 0;
0a7de745 3595 if (nims == NULL) {
6d2010ae 3596 nims = RB_MIN(ip_msource_tree, &inm->inm_srcs);
0a7de745 3597 }
6d2010ae 3598 RB_FOREACH_FROM(ims, ip_msource_tree, nims) {
39236c6e
A
3599#ifdef IGMP_DEBUG
3600 char buf[MAX_IPv4_STR_LEN];
3601
3602 inet_ntop_haddr(ims->ims_haddr, buf, sizeof(buf));
3603 IGMP_PRINTF(("%s: visit node %s\n", __func__, buf));
3604#endif
6d2010ae
A
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));
3609 if (now == then) {
3610 IGMP_PRINTF(("%s: skip unchanged\n",
3611 __func__));
3612 continue;
3613 }
3614 if (mode == MCAST_EXCLUDE &&
3615 now == MCAST_INCLUDE) {
3616 IGMP_PRINTF(("%s: skip IN src on EX "
3617 "group\n", __func__));
3618 continue;
3619 }
3620 nrt = (rectype_t)now;
0a7de745 3621 if (nrt == REC_NONE) {
6d2010ae 3622 nrt = (rectype_t)(~mode & REC_FULL);
0a7de745 3623 }
6d2010ae
A
3624 if (schanged++ == 0) {
3625 crt = nrt;
0a7de745 3626 } else if (crt != nrt) {
6d2010ae 3627 continue;
0a7de745 3628 }
6d2010ae
A
3629 naddr = htonl(ims->ims_haddr);
3630 if (!m_append(m, sizeof(in_addr_t),
3631 (void *)&naddr)) {
0a7de745 3632 if (m != m0) {
6d2010ae 3633 m_freem(m);
0a7de745 3634 }
6d2010ae
A
3635 IGMP_PRINTF(("%s: m_append() failed\n",
3636 __func__));
0a7de745 3637 return -ENOMEM;
6d2010ae
A
3638 }
3639 nallow += !!(crt == REC_ALLOW);
3640 nblock += !!(crt == REC_BLOCK);
0a7de745 3641 if (++rsrcs == m0srcs) {
6d2010ae 3642 break;
0a7de745 3643 }
6d2010ae
A
3644 }
3645 /*
3646 * If we did not append any tree nodes on this
3647 * pass, back out of allocations.
3648 */
3649 if (rsrcs == 0) {
3650 npbytes -= sizeof(struct igmp_grouprec);
3651 if (m != m0) {
3652 IGMP_PRINTF(("%s: m_free(m)\n",
3653 __func__));
3654 m_freem(m);
3655 } else {
3656 IGMP_PRINTF(("%s: m_adj(m, -ig)\n",
3657 __func__));
3658 m_adj(m, -((int)sizeof(
0a7de745 3659 struct igmp_grouprec)));
6d2010ae
A
3660 }
3661 continue;
3662 }
3663 npbytes += (rsrcs * sizeof(in_addr_t));
0a7de745 3664 if (crt == REC_ALLOW) {
6d2010ae 3665 pig->ig_type = IGMP_ALLOW_NEW_SOURCES;
0a7de745 3666 } else if (crt == REC_BLOCK) {
6d2010ae 3667 pig->ig_type = IGMP_BLOCK_OLD_SOURCES;
0a7de745 3668 }
316670eb 3669 ig_numsrc = htons(rsrcs);
0a7de745 3670 bcopy(&ig_numsrc, &pig->ig_numsrc, sizeof(ig_numsrc));
6d2010ae
A
3671 /*
3672 * Count the new group record, and enqueue this
3673 * packet if it wasn't already queued.
3674 */
3675 m->m_pkthdr.vt_nrecs++;
0a7de745 3676 if (m != m0) {
6d2010ae 3677 IF_ENQUEUE(ifq, m);
0a7de745 3678 }
6d2010ae
A
3679 nbytes += npbytes;
3680 } while (nims != NULL);
3681 drt |= crt;
3682 crt = (~crt & REC_FULL);
3683 }
3684
3685 IGMP_PRINTF(("%s: queued %d ALLOW_NEW, %d BLOCK_OLD\n", __func__,
3686 nallow, nblock));
3687
0a7de745 3688 return nbytes;
6d2010ae
A
3689}
3690
3691static int
3692igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq)
3693{
0a7de745
A
3694 struct ifqueue *gq;
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 */
3698 struct mbuf *n;
3699 int docopy, domerge;
3700 u_int recslen;
6d2010ae
A
3701
3702 INM_LOCK_ASSERT_HELD(inm);
3703
3704 docopy = 0;
3705 domerge = 0;
3706 recslen = 0;
3707
3708 /*
3709 * If there are further pending retransmissions, make a writable
3710 * copy of each queued state-change message before merging.
3711 */
0a7de745 3712 if (inm->inm_scrv > 0) {
6d2010ae 3713 docopy = 1;
0a7de745 3714 }
6d2010ae
A
3715
3716 gq = &inm->inm_scq;
3717#ifdef IGMP_DEBUG
3718 if (gq->ifq_head == NULL) {
39236c6e
A
3719 IGMP_PRINTF(("%s: WARNING: queue for inm 0x%llx is empty\n",
3720 __func__, (uint64_t)VM_KERNEL_ADDRPERM(inm)));
6d2010ae
A
3721 }
3722#endif
3723
3724 /*
3725 * Use IF_REMQUEUE() instead of IF_DEQUEUE() below, since the
3726 * packet might not always be at the head of the ifqueue.
3727 */
3728 m = gq->ifq_head;
3729 while (m != NULL) {
3730 /*
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.
3737 */
3738 domerge = 0;
3739 mt = ifscq->ifq_tail;
3740 if (mt != NULL) {
3741 recslen = m_length(m);
3742
3743 if ((mt->m_pkthdr.vt_nrecs +
3744 m->m_pkthdr.vt_nrecs <=
3745 IGMP_V3_REPORT_MAXRECS) &&
3746 (mt->m_pkthdr.len + recslen <=
0a7de745 3747 (inm->inm_ifp->if_mtu - IGMP_LEADINGSPACE))) {
6d2010ae 3748 domerge = 1;
0a7de745 3749 }
6d2010ae
A
3750 }
3751
3752 if (!domerge && IF_QFULL(gq)) {
3753 IGMP_PRINTF(("%s: outbound queue full, skipping whole "
39236c6e
A
3754 "packet 0x%llx\n", __func__,
3755 (uint64_t)VM_KERNEL_ADDRPERM(m)));
6d2010ae
A
3756 n = m->m_nextpkt;
3757 if (!docopy) {
3758 IF_REMQUEUE(gq, m);
3759 m_freem(m);
3760 }
3761 m = n;
3762 continue;
3763 }
3764
3765 if (!docopy) {
39236c6e
A
3766 IGMP_PRINTF(("%s: dequeueing 0x%llx\n", __func__,
3767 (uint64_t)VM_KERNEL_ADDRPERM(m)));
6d2010ae
A
3768 n = m->m_nextpkt;
3769 IF_REMQUEUE(gq, m);
3770 m0 = m;
3771 m = n;
3772 } else {
39236c6e
A
3773 IGMP_PRINTF(("%s: copying 0x%llx\n", __func__,
3774 (uint64_t)VM_KERNEL_ADDRPERM(m)));
6d2010ae 3775 m0 = m_dup(m, M_NOWAIT);
0a7de745
A
3776 if (m0 == NULL) {
3777 return ENOMEM;
3778 }
6d2010ae
A
3779 m0->m_nextpkt = NULL;
3780 m = m->m_nextpkt;
3781 }
3782
3783 if (!domerge) {
39236c6e
A
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)));
6d2010ae
A
3787 IF_ENQUEUE(ifscq, m0);
3788 } else {
0a7de745 3789 struct mbuf *mtl; /* last mbuf of packet mt */
6d2010ae 3790
39236c6e
A
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)));
6d2010ae
A
3795
3796 mtl = m_last(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;
3801
3802 mtl->m_next = m0;
3803 }
3804 }
3805
0a7de745 3806 return 0;
6d2010ae
A
3807}
3808
3809/*
3810 * Respond to a pending IGMPv3 General Query.
3811 */
39236c6e 3812static uint32_t
6d2010ae
A
3813igmp_v3_dispatch_general_query(struct igmp_ifinfo *igi)
3814{
0a7de745
A
3815 struct ifnet *ifp;
3816 struct in_multi *inm;
3817 struct in_multistep step;
3818 int retval, loop;
6d2010ae
A
3819
3820 IGI_LOCK_ASSERT_HELD(igi);
3821
3822 VERIFY(igi->igi_version == IGMP_VERSION_3);
3823
3824 ifp = igi->igi_ifp;
3825 IGI_UNLOCK(igi);
3826
3827 in_multihead_lock_shared();
3828 IN_FIRST_MULTI(step, inm);
3829 while (inm != NULL) {
3830 INM_LOCK(inm);
0a7de745 3831 if (inm->inm_ifp != ifp) {
6d2010ae 3832 goto next;
0a7de745 3833 }
6d2010ae
A
3834
3835 switch (inm->inm_state) {
3836 case IGMP_NOT_MEMBER:
3837 case IGMP_SILENT_MEMBER:
3838 break;
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;
3845 IGI_LOCK(igi);
3846 retval = igmp_v3_enqueue_group_record(&igi->igi_gq,
3847 inm, 0, 0, 0);
3848 IGI_UNLOCK(igi);
3849 IGMP_PRINTF(("%s: enqueue record = %d\n",
3850 __func__, retval));
3851 break;
3852 case IGMP_G_QUERY_PENDING_MEMBER:
3853 case IGMP_SG_QUERY_PENDING_MEMBER:
3854 case IGMP_LEAVING_MEMBER:
3855 break;
3856 }
3857next:
3858 INM_UNLOCK(inm);
3859 IN_NEXT_MULTI(step, inm);
3860 }
3861 in_multihead_lock_done();
3862
3863 IGI_LOCK(igi);
3864 loop = (igi->igi_flags & IGIF_LOOPBACK) ? 1 : 0;
3865 igmp_dispatch_queue(igi, &igi->igi_gq, IGMP_MAX_RESPONSE_BURST,
39236c6e 3866 loop);
6d2010ae
A
3867 IGI_LOCK_ASSERT_HELD(igi);
3868 /*
39236c6e 3869 * Slew transmission of bursts over 1 second intervals.
6d2010ae
A
3870 */
3871 if (igi->igi_gq.ifq_head != NULL) {
3872 igi->igi_v3_timer = 1 + IGMP_RANDOM_DELAY(
0a7de745 3873 IGMP_RESPONSE_BURST_INTERVAL);
6d2010ae 3874 }
39236c6e 3875
0a7de745 3876 return igi->igi_v3_timer;
6d2010ae
A
3877}
3878
3879/*
3880 * Transmit the next pending IGMP message in the output queue.
3881 *
3882 * Must not be called with inm_lock or igi_lock held.
3883 */
39236c6e
A
3884static void
3885igmp_sendpkt(struct mbuf *m)
6d2010ae 3886{
0a7de745
A
3887 struct ip_moptions *imo;
3888 struct mbuf *ipopts, *m0;
3889 int error;
3890 struct route ro;
3891 struct ifnet *ifp;
6d2010ae 3892
39236c6e
A
3893 IGMP_PRINTF(("%s: transmit 0x%llx\n", __func__,
3894 (uint64_t)VM_KERNEL_ADDRPERM(m)));
6d2010ae 3895
39236c6e 3896 ifp = igmp_restore_context(m);
6d2010ae
A
3897 /*
3898 * Check if the ifnet is still attached.
3899 */
3900 if (ifp == NULL || !ifnet_is_attached(ifp, 0)) {
39236c6e
A
3901 IGMP_PRINTF(("%s: dropped 0x%llx as ifp went away.\n",
3902 __func__, (uint64_t)VM_KERNEL_ADDRPERM(m)));
6d2010ae
A
3903 m_freem(m);
3904 OSAddAtomic(1, &ipstat.ips_noroute);
3905 return;
3906 }
3907
3908 ipopts = igmp_sendra ? m_raopt : NULL;
3909
3910 imo = ip_allocmoptions(M_WAITOK);
3911 if (imo == NULL) {
3912 m_freem(m);
3913 return;
3914 }
3915
3916 imo->imo_multicast_ttl = 1;
3917 imo->imo_multicast_vif = -1;
6d2010ae 3918 imo->imo_multicast_loop = 0;
6d2010ae
A
3919
3920 /*
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.
3925 */
0a7de745 3926 if (m->m_flags & M_IGMP_LOOP) {
6d2010ae 3927 imo->imo_multicast_ifp = lo_ifp;
0a7de745 3928 } else {
6d2010ae 3929 imo->imo_multicast_ifp = ifp;
0a7de745 3930 }
6d2010ae
A
3931
3932 if (m->m_flags & M_IGMPV2) {
3933 m0 = m;
3934 } else {
3935 m0 = igmp_v3_encap_report(ifp, m);
3936 if (m0 == NULL) {
3937 /*
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.
3941 */
39236c6e
A
3942 IGMP_PRINTF(("%s: dropped 0x%llx\n", __func__,
3943 (uint64_t)VM_KERNEL_ADDRPERM(m)));
6d2010ae
A
3944 IMO_REMREF(imo);
3945 atomic_add_32(&ipstat.ips_odropped, 1);
3946 return;
3947 }
3948 }
3949
39236c6e 3950 igmp_scrub_context(m0);
6d2010ae
A
3951 m->m_flags &= ~(M_PROTOFLAGS | M_IGMP_LOOP);
3952 m0->m_pkthdr.rcvif = lo_ifp;
3953#ifdef MAC
3954 mac_netinet_igmp_send(ifp, m0);
3955#endif
316670eb
A
3956
3957 if (ifp->if_eflags & IFEF_TXSTART) {
39236c6e
A
3958 /*
3959 * Use control service class if the interface supports
316670eb
A
3960 * transmit-start model.
3961 */
3962 (void) m_set_service_class(m0, MBUF_SC_CTL);
3963 }
0a7de745 3964 bzero(&ro, sizeof(ro));
6d2010ae 3965 error = ip_output(m0, ipopts, &ro, 0, imo, NULL);
39236c6e 3966 ROUTE_RELEASE(&ro);
6d2010ae
A
3967
3968 IMO_REMREF(imo);
3969
3970 if (error) {
39236c6e
A
3971 IGMP_PRINTF(("%s: ip_output(0x%llx) = %d\n", __func__,
3972 (uint64_t)VM_KERNEL_ADDRPERM(m0), error));
6d2010ae
A
3973 return;
3974 }
3975
3976 IGMPSTAT_INC(igps_snd_reports);
3977 OIGMPSTAT_INC(igps_snd_reports);
3978}
3979/*
3980 * Encapsulate an IGMPv3 report.
3981 *
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.
3986 *
3987 * Returns a pointer to the new mbuf chain head, or NULL if the
3988 * allocation failed.
3989 */
3990static struct mbuf *
3991igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m)
3992{
0a7de745
A
3993 struct igmp_report *igmp;
3994 struct ip *ip;
3995 int hdrlen, igmpreclen;
6d2010ae
A
3996
3997 VERIFY((m->m_flags & M_PKTHDR));
3998
3999 igmpreclen = m_length(m);
4000 hdrlen = sizeof(struct ip) + sizeof(struct igmp_report);
4001
4002 if (m->m_flags & M_IGMPV3_HDR) {
4003 igmpreclen -= hdrlen;
4004 } else {
3e170ce0 4005 M_PREPEND(m, hdrlen, M_DONTWAIT, 1);
0a7de745
A
4006 if (m == NULL) {
4007 return NULL;
4008 }
6d2010ae
A
4009 m->m_flags |= M_IGMPV3_HDR;
4010 }
4011
4012 IGMP_PRINTF(("%s: igmpreclen is %d\n", __func__, igmpreclen));
4013
4014 m->m_data += sizeof(struct ip);
4015 m->m_len -= sizeof(struct ip);
4016
4017 igmp = mtod(m, struct igmp_report *);
4018 igmp->ir_type = IGMP_v3_HOST_MEMBERSHIP_REPORT;
4019 igmp->ir_rsv1 = 0;
4020 igmp->ir_rsv2 = 0;
4021 igmp->ir_numgrps = htons(m->m_pkthdr.vt_nrecs);
4022 igmp->ir_cksum = 0;
4023 igmp->ir_cksum = in_cksum(m, sizeof(struct igmp_report) + igmpreclen);
4024 m->m_pkthdr.vt_nrecs = 0;
4025
4026 m->m_data -= sizeof(struct ip);
4027 m->m_len += sizeof(struct ip);
4028
4029 ip = mtod(m, struct ip *);
4030 ip->ip_tos = IPTOS_PREC_INTERNETCONTROL;
4031 ip->ip_len = hdrlen + igmpreclen;
4032 ip->ip_off = IP_DF;
4033 ip->ip_p = IPPROTO_IGMP;
4034 ip->ip_sum = 0;
4035
4036 ip->ip_src.s_addr = INADDR_ANY;
4037
4038 if (m->m_flags & M_IGMP_LOOP) {
4039 struct in_ifaddr *ia;
4040
4041 IFP_TO_IA(ifp, ia);
4042 if (ia != NULL) {
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);
4047 }
4048 }
4049
4050 ip->ip_dst.s_addr = htonl(INADDR_ALLRPTS_GROUP);
4051
0a7de745 4052 return m;
6d2010ae
A
4053}
4054
4055#ifdef IGMP_DEBUG
4056static const char *
4057igmp_rec_type_to_str(const int type)
4058{
4059 switch (type) {
0a7de745
A
4060 case IGMP_CHANGE_TO_EXCLUDE_MODE:
4061 return "TO_EX";
4062 case IGMP_CHANGE_TO_INCLUDE_MODE:
4063 return "TO_IN";
4064 case IGMP_MODE_IS_EXCLUDE:
4065 return "MODE_EX";
4066 case IGMP_MODE_IS_INCLUDE:
4067 return "MODE_IN";
4068 case IGMP_ALLOW_NEW_SOURCES:
4069 return "ALLOW_NEW";
4070 case IGMP_BLOCK_OLD_SOURCES:
4071 return "BLOCK_OLD";
4072 default:
4073 break;
6d2010ae
A
4074 }
4075 return "unknown";
4076}
4077#endif
4078
4079void
39236c6e 4080igmp_init(struct protosw *pp, struct domain *dp)
6d2010ae 4081{
39236c6e
A
4082#pragma unused(dp)
4083 static int igmp_initialized = 0;
4084
0a7de745 4085 VERIFY((pp->pr_flags & (PR_INITIALIZED | PR_ATTACHED)) == PR_ATTACHED);
39236c6e 4086
0a7de745 4087 if (igmp_initialized) {
39236c6e 4088 return;
0a7de745 4089 }
39236c6e 4090 igmp_initialized = 1;
6d2010ae
A
4091
4092 IGMP_PRINTF(("%s: initializing\n", __func__));
4093
4094 igmp_timers_are_running = 0;
4095
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);
4101
4102 LIST_INIT(&igi_head);
4103 m_raopt = igmp_ra_alloc();
4104
0a7de745 4105 igi_size = sizeof(struct igmp_ifinfo);
6d2010ae
A
4106 igi_zone = zinit(igi_size, IGI_ZONE_MAX * igi_size,
4107 0, IGI_ZONE_NAME);
4108 if (igi_zone == NULL) {
4109 panic("%s: failed allocating %s", __func__, IGI_ZONE_NAME);
4110 /* NOTREACHED */
4111 }
4112 zone_change(igi_zone, Z_EXPAND, TRUE);
4113 zone_change(igi_zone, Z_CALLERACCT, FALSE);
4114}