xref: /openbsd-src/sys/netinet/igmp.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: igmp.c,v 1.42 2014/07/12 18:44:23 tedu Exp $	*/
2 /*	$NetBSD: igmp.c,v 1.15 1996/02/13 23:41:25 christos Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1988 Stephen Deering.
35  * Copyright (c) 1992, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Stephen Deering of Stanford University.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. 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.2 (Berkeley) 5/3/95
66  */
67 
68 /*
69  * Internet Group Management Protocol (IGMP) routines.
70  *
71  * Written by Steve Deering, Stanford, May 1988.
72  * Modified by Rosen Sharma, Stanford, Aug 1994.
73  * Modified by Bill Fenner, Xerox PARC, Feb 1995.
74  *
75  * MULTICAST Revision: 1.3
76  */
77 
78 #include <sys/param.h>
79 #include <sys/mbuf.h>
80 #include <sys/systm.h>
81 #include <sys/socket.h>
82 #include <sys/protosw.h>
83 #include <sys/proc.h>
84 #include <sys/sysctl.h>
85 
86 #include <net/if.h>
87 #include <net/if_var.h>
88 #include <net/route.h>
89 
90 #include <netinet/in.h>
91 #include <netinet/in_var.h>
92 #include <netinet/in_systm.h>
93 #include <netinet/ip.h>
94 #include <netinet/ip_var.h>
95 #include <netinet/igmp.h>
96 #include <netinet/igmp_var.h>
97 #include <dev/rndvar.h>
98 
99 #include <sys/stdarg.h>
100 
101 #define IP_MULTICASTOPTS	0
102 
103 int *igmpctl_vars[IGMPCTL_MAXID] = IGMPCTL_VARS;
104 
105 int		igmp_timers_are_running;
106 static struct router_info *rti_head;
107 static struct mbuf *router_alert;
108 struct igmpstat igmpstat;
109 
110 void igmp_checktimer(struct ifnet *);
111 void igmp_sendpkt(struct in_multi *, int, in_addr_t);
112 int rti_fill(struct in_multi *);
113 struct router_info * rti_find(struct ifnet *);
114 
115 void
116 igmp_init(void)
117 {
118 	struct ipoption *ra;
119 
120 	igmp_timers_are_running = 0;
121 	rti_head = 0;
122 
123 	router_alert = m_get(M_DONTWAIT, MT_DATA);
124 	if (router_alert == NULL) {
125 		printf("%s: no mbuf\n", __func__);
126 		return;
127 	}
128 
129 	/*
130 	 * Construct a Router Alert option (RAO) to use in report
131 	 * messages as required by RFC2236.  This option has the
132 	 * following format:
133 	 *
134 	 *	| 10010100 | 00000100 |  2 octet value  |
135 	 *
136 	 * where a value of "0" indicates that routers shall examine
137 	 * the packet.
138 	 */
139 	ra = mtod(router_alert, struct ipoption *);
140 	ra->ipopt_dst.s_addr = INADDR_ANY;
141 	ra->ipopt_list[0] = IPOPT_RA;
142 	ra->ipopt_list[1] = 0x04;
143 	ra->ipopt_list[2] = 0x00;
144 	ra->ipopt_list[3] = 0x00;
145 	router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1];
146 }
147 
148 /* Return -1 for error. */
149 int
150 rti_fill(struct in_multi *inm)
151 {
152 	struct router_info *rti;
153 
154 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
155 		if (rti->rti_ifp->if_index == inm->inm_ifidx) {
156 			inm->inm_rti = rti;
157 			if (rti->rti_type == IGMP_v1_ROUTER)
158 				return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
159 			else
160 				return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
161 		}
162 	}
163 
164 	rti = (struct router_info *)malloc(sizeof(struct router_info),
165 					   M_MRTABLE, M_NOWAIT);
166 	if (rti == NULL)
167 		return (-1);
168 	rti->rti_ifp = if_get(inm->inm_ifidx);
169 	rti->rti_type = IGMP_v2_ROUTER;
170 	rti->rti_next = rti_head;
171 	rti_head = rti;
172 	inm->inm_rti = rti;
173 	return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
174 }
175 
176 struct router_info *
177 rti_find(struct ifnet *ifp)
178 {
179 	struct router_info *rti;
180 
181 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
182 		if (rti->rti_ifp == ifp)
183 			return (rti);
184 	}
185 
186 	rti = (struct router_info *)malloc(sizeof(struct router_info),
187 					   M_MRTABLE, M_NOWAIT);
188 	if (rti == NULL)
189 		return (NULL);
190 	rti->rti_ifp = ifp;
191 	rti->rti_type = IGMP_v2_ROUTER;
192 	rti->rti_next = rti_head;
193 	rti_head = rti;
194 	return (rti);
195 }
196 
197 void
198 rti_delete(struct ifnet *ifp)
199 {
200 	struct router_info *rti, **prti = &rti_head;
201 
202 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
203 		if (rti->rti_ifp == ifp) {
204 			*prti = rti->rti_next;
205 			free(rti, M_MRTABLE, 0);
206 			break;
207 		}
208 		prti = &rti->rti_next;
209 	}
210 }
211 
212 void
213 igmp_input(struct mbuf *m, ...)
214 {
215 	int iphlen;
216 	struct ifnet *ifp = m->m_pkthdr.rcvif;
217 	struct ip *ip = mtod(m, struct ip *);
218 	struct igmp *igmp;
219 	int igmplen;
220 	int minlen;
221 	struct ifmaddr *ifma;
222 	struct in_multi *inm;
223 	struct router_info *rti;
224 	struct in_ifaddr *ia;
225 	int timer;
226 	va_list ap;
227 
228 	va_start(ap, m);
229 	iphlen = va_arg(ap, int);
230 	va_end(ap);
231 
232 	++igmpstat.igps_rcv_total;
233 
234 	igmplen = ntohs(ip->ip_len) - iphlen;
235 
236 	/*
237 	 * Validate lengths
238 	 */
239 	if (igmplen < IGMP_MINLEN) {
240 		++igmpstat.igps_rcv_tooshort;
241 		m_freem(m);
242 		return;
243 	}
244 	minlen = iphlen + IGMP_MINLEN;
245 	if ((m->m_flags & M_EXT || m->m_len < minlen) &&
246 	    (m = m_pullup(m, minlen)) == NULL) {
247 		++igmpstat.igps_rcv_tooshort;
248 		return;
249 	}
250 
251 	/*
252 	 * Validate checksum
253 	 */
254 	m->m_data += iphlen;
255 	m->m_len -= iphlen;
256 	igmp = mtod(m, struct igmp *);
257 	if (in_cksum(m, igmplen)) {
258 		++igmpstat.igps_rcv_badsum;
259 		m_freem(m);
260 		return;
261 	}
262 	m->m_data -= iphlen;
263 	m->m_len += iphlen;
264 	ip = mtod(m, struct ip *);
265 
266 	switch (igmp->igmp_type) {
267 
268 	case IGMP_HOST_MEMBERSHIP_QUERY:
269 		++igmpstat.igps_rcv_queries;
270 
271 		if (ifp->if_flags & IFF_LOOPBACK)
272 			break;
273 
274 		if (igmp->igmp_code == 0) {
275 			rti = rti_find(ifp);
276 			if (rti == NULL) {
277 				m_freem(m);
278 				return;
279 			}
280 			rti->rti_type = IGMP_v1_ROUTER;
281 			rti->rti_age = 0;
282 
283 			if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
284 				++igmpstat.igps_rcv_badqueries;
285 				m_freem(m);
286 				return;
287 			}
288 
289 			/*
290 			 * Start the timers in all of our membership records
291 			 * for the interface on which the query arrived,
292 			 * except those that are already running and those
293 			 * that belong to a "local" group (224.0.0.X).
294 			 */
295 			TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
296 				if (ifma->ifma_addr->sa_family != AF_INET)
297 					continue;
298 				inm = ifmatoinm(ifma);
299 				if (inm->inm_timer == 0 &&
300 				    !IN_LOCAL_GROUP(inm->inm_addr.s_addr)) {
301 					inm->inm_state = IGMP_DELAYING_MEMBER;
302 					inm->inm_timer = IGMP_RANDOM_DELAY(
303 					    IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
304 					igmp_timers_are_running = 1;
305 				}
306 			}
307 		} else {
308 			if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
309 				++igmpstat.igps_rcv_badqueries;
310 				m_freem(m);
311 				return;
312 			}
313 
314 			timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
315 			if (timer == 0)
316 				timer = 1;
317 
318 			/*
319 			 * Start the timers in all of our membership records
320 			 * for the interface on which the query arrived,
321 			 * except those that are already running and those
322 			 * that belong to a "local" group (224.0.0.X).  For
323 			 * timers already running, check if they need to be
324 			 * reset.
325 			 */
326 			TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
327 				if (ifma->ifma_addr->sa_family != AF_INET)
328 					continue;
329 				inm = ifmatoinm(ifma);
330 				if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
331 				    (ip->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP ||
332 				     ip->ip_dst.s_addr == inm->inm_addr.s_addr)) {
333 					switch (inm->inm_state) {
334 					case IGMP_DELAYING_MEMBER:
335 						if (inm->inm_timer <= timer)
336 							break;
337 						/* FALLTHROUGH */
338 					case IGMP_IDLE_MEMBER:
339 					case IGMP_LAZY_MEMBER:
340 					case IGMP_AWAKENING_MEMBER:
341 						inm->inm_state =
342 						    IGMP_DELAYING_MEMBER;
343 						inm->inm_timer =
344 						    IGMP_RANDOM_DELAY(timer);
345 						igmp_timers_are_running = 1;
346 						break;
347 					case IGMP_SLEEPING_MEMBER:
348 						inm->inm_state =
349 						    IGMP_AWAKENING_MEMBER;
350 						break;
351 					}
352 				}
353 			}
354 		}
355 
356 		break;
357 
358 	case IGMP_v1_HOST_MEMBERSHIP_REPORT:
359 		++igmpstat.igps_rcv_reports;
360 
361 		if (ifp->if_flags & IFF_LOOPBACK)
362 			break;
363 
364 		if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
365 		    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
366 			++igmpstat.igps_rcv_badreports;
367 			m_freem(m);
368 			return;
369 		}
370 
371 		/*
372 		 * KLUDGE: if the IP source address of the report has an
373 		 * unspecified (i.e., zero) subnet number, as is allowed for
374 		 * a booting host, replace it with the correct subnet number
375 		 * so that a process-level multicast routing daemon can
376 		 * determine which subnet it arrived from.  This is necessary
377 		 * to compensate for the lack of any way for a process to
378 		 * determine the arrival interface of an incoming packet.
379 		 */
380 		if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
381 			IFP_TO_IA(ifp, ia);
382 			if (ia)
383 				ip->ip_src.s_addr = ia->ia_net;
384 		}
385 
386 		/*
387 		 * If we belong to the group being reported, stop
388 		 * our timer for that group.
389 		 */
390 		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
391 		if (inm != NULL) {
392 			inm->inm_timer = 0;
393 			++igmpstat.igps_rcv_ourreports;
394 
395 			switch (inm->inm_state) {
396 			case IGMP_IDLE_MEMBER:
397 			case IGMP_LAZY_MEMBER:
398 			case IGMP_AWAKENING_MEMBER:
399 			case IGMP_SLEEPING_MEMBER:
400 				inm->inm_state = IGMP_SLEEPING_MEMBER;
401 				break;
402 			case IGMP_DELAYING_MEMBER:
403 				if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
404 					inm->inm_state = IGMP_LAZY_MEMBER;
405 				else
406 					inm->inm_state = IGMP_SLEEPING_MEMBER;
407 				break;
408 			}
409 		}
410 
411 		break;
412 
413 	case IGMP_v2_HOST_MEMBERSHIP_REPORT:
414 #ifdef MROUTING
415 		/*
416 		 * Make sure we don't hear our own membership report.  Fast
417 		 * leave requires knowing that we are the only member of a
418 		 * group.
419 		 */
420 		IFP_TO_IA(ifp, ia);
421 		if (ia && ip->ip_src.s_addr == ia->ia_addr.sin_addr.s_addr)
422 			break;
423 #endif
424 
425 		++igmpstat.igps_rcv_reports;
426 
427 		if (ifp->if_flags & IFF_LOOPBACK)
428 			break;
429 
430 		if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
431 		    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
432 			++igmpstat.igps_rcv_badreports;
433 			m_freem(m);
434 			return;
435 		}
436 
437 		/*
438 		 * KLUDGE: if the IP source address of the report has an
439 		 * unspecified (i.e., zero) subnet number, as is allowed for
440 		 * a booting host, replace it with the correct subnet number
441 		 * so that a process-level multicast routing daemon can
442 		 * determine which subnet it arrived from.  This is necessary
443 		 * to compensate for the lack of any way for a process to
444 		 * determine the arrival interface of an incoming packet.
445 		 */
446 		if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
447 #ifndef MROUTING
448 			IFP_TO_IA(ifp, ia);
449 #endif
450 			if (ia)
451 				ip->ip_src.s_addr = ia->ia_net;
452 		}
453 
454 		/*
455 		 * If we belong to the group being reported, stop
456 		 * our timer for that group.
457 		 */
458 		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
459 		if (inm != NULL) {
460 			inm->inm_timer = 0;
461 			++igmpstat.igps_rcv_ourreports;
462 
463 			switch (inm->inm_state) {
464 			case IGMP_DELAYING_MEMBER:
465 			case IGMP_IDLE_MEMBER:
466 			case IGMP_AWAKENING_MEMBER:
467 				inm->inm_state = IGMP_LAZY_MEMBER;
468 				break;
469 			case IGMP_LAZY_MEMBER:
470 			case IGMP_SLEEPING_MEMBER:
471 				break;
472 			}
473 		}
474 
475 		break;
476 
477 	}
478 
479 	/*
480 	 * Pass all valid IGMP packets up to any process(es) listening
481 	 * on a raw IGMP socket.
482 	 */
483 	rip_input(m);
484 }
485 
486 void
487 igmp_joingroup(struct in_multi *inm)
488 {
489 	struct ifnet* ifp;
490 	int i, s;
491 
492 	ifp = if_get(inm->inm_ifidx);
493 	s = splsoftnet();
494 
495 	inm->inm_state = IGMP_IDLE_MEMBER;
496 
497 	if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
498 	    ifp && (ifp->if_flags & IFF_LOOPBACK) == 0) {
499 		if ((i = rti_fill(inm)) == -1) {
500 			splx(s);
501 			return;
502 		}
503 		igmp_sendpkt(inm, i, 0);
504 		inm->inm_state = IGMP_DELAYING_MEMBER;
505 		inm->inm_timer = IGMP_RANDOM_DELAY(
506 		    IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
507 		igmp_timers_are_running = 1;
508 	} else
509 		inm->inm_timer = 0;
510 	splx(s);
511 }
512 
513 void
514 igmp_leavegroup(struct in_multi *inm)
515 {
516 	struct ifnet* ifp;
517 	int s;
518 
519 	ifp = if_get(inm->inm_ifidx);
520 	s = splsoftnet();
521 
522 	switch (inm->inm_state) {
523 	case IGMP_DELAYING_MEMBER:
524 	case IGMP_IDLE_MEMBER:
525 		if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
526 		    ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)
527 			if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
528 				igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE,
529 				    INADDR_ALLROUTERS_GROUP);
530 		break;
531 	case IGMP_LAZY_MEMBER:
532 	case IGMP_AWAKENING_MEMBER:
533 	case IGMP_SLEEPING_MEMBER:
534 		break;
535 	}
536 	splx(s);
537 }
538 
539 void
540 igmp_fasttimo(void)
541 {
542 	struct ifnet *ifp;
543 	int s;
544 
545 	/*
546 	 * Quick check to see if any work needs to be done, in order
547 	 * to minimize the overhead of fasttimo processing.
548 	 */
549 	if (!igmp_timers_are_running)
550 		return;
551 
552 	s = splsoftnet();
553 	igmp_timers_are_running = 0;
554 	TAILQ_FOREACH(ifp, &ifnet, if_list)
555 		igmp_checktimer(ifp);
556 	splx(s);
557 }
558 
559 
560 void
561 igmp_checktimer(struct ifnet *ifp)
562 {
563 	struct in_multi *inm;
564 	struct ifmaddr *ifma;
565 
566 	splsoftassert(IPL_SOFTNET);
567 
568 	TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
569 		if (ifma->ifma_addr->sa_family != AF_INET)
570 			continue;
571 		inm = ifmatoinm(ifma);
572 		if (inm->inm_timer == 0) {
573 			/* do nothing */
574 		} else if (--inm->inm_timer == 0) {
575 			if (inm->inm_state == IGMP_DELAYING_MEMBER) {
576 				if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
577 					igmp_sendpkt(inm,
578 					    IGMP_v1_HOST_MEMBERSHIP_REPORT, 0);
579 				else
580 					igmp_sendpkt(inm,
581 					    IGMP_v2_HOST_MEMBERSHIP_REPORT, 0);
582 				inm->inm_state = IGMP_IDLE_MEMBER;
583 			}
584 		} else {
585 			igmp_timers_are_running = 1;
586 		}
587 	}
588 }
589 
590 void
591 igmp_slowtimo(void)
592 {
593 	struct router_info *rti;
594 	int s;
595 
596 	s = splsoftnet();
597 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
598 		if (rti->rti_type == IGMP_v1_ROUTER &&
599 		    ++rti->rti_age >= IGMP_AGE_THRESHOLD) {
600 			rti->rti_type = IGMP_v2_ROUTER;
601 		}
602 	}
603 	splx(s);
604 }
605 
606 void
607 igmp_sendpkt(struct in_multi *inm, int type, in_addr_t addr)
608 {
609 	struct mbuf *m;
610 	struct igmp *igmp;
611 	struct ip *ip;
612 	struct ip_moptions imo;
613 
614 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
615 	if (m == NULL)
616 		return;
617 	/*
618 	 * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
619 	 * is smaller than mbuf size returned by MGETHDR.
620 	 */
621 	m->m_data += max_linkhdr;
622 	m->m_len = sizeof(struct ip) + IGMP_MINLEN;
623 	m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
624 
625 	ip = mtod(m, struct ip *);
626 	ip->ip_tos = 0;
627 	ip->ip_len = htons(sizeof(struct ip) + IGMP_MINLEN);
628 	ip->ip_off = 0;
629 	ip->ip_p = IPPROTO_IGMP;
630 	ip->ip_src.s_addr = INADDR_ANY;
631 	if (addr) {
632 		ip->ip_dst.s_addr = addr;
633 	} else {
634 		ip->ip_dst = inm->inm_addr;
635 	}
636 
637 	m->m_data += sizeof(struct ip);
638 	m->m_len -= sizeof(struct ip);
639 	igmp = mtod(m, struct igmp *);
640 	igmp->igmp_type = type;
641 	igmp->igmp_code = 0;
642 	igmp->igmp_group = inm->inm_addr;
643 	igmp->igmp_cksum = 0;
644 	igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
645 	m->m_data -= sizeof(struct ip);
646 	m->m_len += sizeof(struct ip);
647 
648 	imo.imo_multicast_ifp = if_get(inm->inm_ifidx);
649 	imo.imo_multicast_ttl = 1;
650 
651 	/*
652 	 * Request loopback of the report if we are acting as a multicast
653 	 * router, so that the process-level routing daemon can hear it.
654 	 */
655 #ifdef MROUTING
656 	imo.imo_multicast_loop = (ip_mrouter != NULL);
657 #else
658 	imo.imo_multicast_loop = 0;
659 #endif /* MROUTING */
660 
661 	ip_output(m, router_alert, NULL, IP_MULTICASTOPTS, &imo, NULL, 0);
662 
663 	++igmpstat.igps_snd_reports;
664 }
665 
666 /*
667  * Sysctl for igmp variables.
668  */
669 int
670 igmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
671     void *newp, size_t newlen)
672 {
673 	/* All sysctl names at this level are terminal. */
674 	if (namelen != 1)
675 		return (ENOTDIR);
676 
677 	switch (name[0]) {
678 	case IGMPCTL_STATS:
679 		if (newp != NULL)
680 			return (EPERM);
681 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
682 		    &igmpstat, sizeof(igmpstat)));
683 	default:
684 		if (name[0] < IGMPCTL_MAXID)
685 			return (sysctl_int_arr(igmpctl_vars, name, namelen,
686 			    oldp, oldlenp, newp, newlen));
687 		return (ENOPROTOOPT);
688 	}
689 	/* NOTREACHED */
690 }
691