xref: /openbsd-src/sys/netinet/igmp.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: igmp.c,v 1.54 2015/11/11 10:01:46 mpi 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/sysctl.h>
84 
85 #include <net/if.h>
86 #include <net/if_var.h>
87 
88 #include <netinet/in.h>
89 #include <netinet/in_var.h>
90 #include <netinet/ip.h>
91 #include <netinet/ip_var.h>
92 #include <netinet/igmp.h>
93 #include <netinet/igmp_var.h>
94 
95 #include <sys/stdarg.h>
96 
97 #define IP_MULTICASTOPTS	0
98 
99 int *igmpctl_vars[IGMPCTL_MAXID] = IGMPCTL_VARS;
100 
101 int		igmp_timers_are_running;
102 static struct router_info *rti_head;
103 static struct mbuf *router_alert;
104 struct igmpstat igmpstat;
105 
106 void igmp_checktimer(struct ifnet *);
107 void igmp_sendpkt(struct in_multi *, int, in_addr_t);
108 int rti_fill(struct in_multi *);
109 struct router_info * rti_find(struct ifnet *);
110 void igmp_input_if(struct ifnet *, struct mbuf *, int);
111 
112 void
113 igmp_init(void)
114 {
115 	struct ipoption *ra;
116 
117 	igmp_timers_are_running = 0;
118 	rti_head = 0;
119 
120 	router_alert = m_get(M_DONTWAIT, MT_DATA);
121 	if (router_alert == NULL) {
122 		printf("%s: no mbuf\n", __func__);
123 		return;
124 	}
125 
126 	/*
127 	 * Construct a Router Alert option (RAO) to use in report
128 	 * messages as required by RFC2236.  This option has the
129 	 * following format:
130 	 *
131 	 *	| 10010100 | 00000100 |  2 octet value  |
132 	 *
133 	 * where a value of "0" indicates that routers shall examine
134 	 * the packet.
135 	 */
136 	ra = mtod(router_alert, struct ipoption *);
137 	ra->ipopt_dst.s_addr = INADDR_ANY;
138 	ra->ipopt_list[0] = IPOPT_RA;
139 	ra->ipopt_list[1] = 0x04;
140 	ra->ipopt_list[2] = 0x00;
141 	ra->ipopt_list[3] = 0x00;
142 	router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1];
143 }
144 
145 /* Return -1 for error. */
146 int
147 rti_fill(struct in_multi *inm)
148 {
149 	struct router_info *rti;
150 
151 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
152 		if (rti->rti_ifidx == inm->inm_ifidx) {
153 			inm->inm_rti = rti;
154 			if (rti->rti_type == IGMP_v1_ROUTER)
155 				return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
156 			else
157 				return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
158 		}
159 	}
160 
161 	rti = (struct router_info *)malloc(sizeof(struct router_info),
162 					   M_MRTABLE, M_NOWAIT);
163 	if (rti == NULL)
164 		return (-1);
165 	rti->rti_ifidx = inm->inm_ifidx;
166 	rti->rti_type = IGMP_v2_ROUTER;
167 	rti->rti_next = rti_head;
168 	rti_head = rti;
169 	inm->inm_rti = rti;
170 	return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
171 }
172 
173 struct router_info *
174 rti_find(struct ifnet *ifp)
175 {
176 	struct router_info *rti;
177 
178 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
179 		if (rti->rti_ifidx == ifp->if_index)
180 			return (rti);
181 	}
182 
183 	rti = (struct router_info *)malloc(sizeof(struct router_info),
184 					   M_MRTABLE, M_NOWAIT);
185 	if (rti == NULL)
186 		return (NULL);
187 	rti->rti_ifidx = ifp->if_index;
188 	rti->rti_type = IGMP_v2_ROUTER;
189 	rti->rti_next = rti_head;
190 	rti_head = rti;
191 	return (rti);
192 }
193 
194 void
195 rti_delete(struct ifnet *ifp)
196 {
197 	struct router_info *rti, **prti = &rti_head;
198 
199 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
200 		if (rti->rti_ifidx == ifp->if_index) {
201 			*prti = rti->rti_next;
202 			free(rti, M_MRTABLE, sizeof(*rti));
203 			break;
204 		}
205 		prti = &rti->rti_next;
206 	}
207 }
208 
209 void
210 igmp_input(struct mbuf *m, ...)
211 {
212 	int iphlen;
213 	struct ifnet *ifp;
214 	va_list ap;
215 
216 	va_start(ap, m);
217 	iphlen = va_arg(ap, int);
218 	va_end(ap);
219 
220 	++igmpstat.igps_rcv_total;
221 
222 	ifp = if_get(m->m_pkthdr.ph_ifidx);
223 	if (ifp == NULL) {
224 		m_freem(m);
225 		return;
226 	}
227 
228 	igmp_input_if(ifp, m, iphlen);
229 	if_put(ifp);
230 }
231 
232 void
233 igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
234 {
235 	struct ip *ip = mtod(m, struct ip *);
236 	struct igmp *igmp;
237 	int igmplen;
238 	int minlen;
239 	struct ifmaddr *ifma;
240 	struct in_multi *inm;
241 	struct router_info *rti;
242 	struct in_ifaddr *ia;
243 	int timer;
244 
245 	igmplen = ntohs(ip->ip_len) - iphlen;
246 
247 	/*
248 	 * Validate lengths
249 	 */
250 	if (igmplen < IGMP_MINLEN) {
251 		++igmpstat.igps_rcv_tooshort;
252 		m_freem(m);
253 		return;
254 	}
255 	minlen = iphlen + IGMP_MINLEN;
256 	if ((m->m_flags & M_EXT || m->m_len < minlen) &&
257 	    (m = m_pullup(m, minlen)) == NULL) {
258 		++igmpstat.igps_rcv_tooshort;
259 		return;
260 	}
261 
262 	/*
263 	 * Validate checksum
264 	 */
265 	m->m_data += iphlen;
266 	m->m_len -= iphlen;
267 	igmp = mtod(m, struct igmp *);
268 	if (in_cksum(m, igmplen)) {
269 		++igmpstat.igps_rcv_badsum;
270 		m_freem(m);
271 		return;
272 	}
273 	m->m_data -= iphlen;
274 	m->m_len += iphlen;
275 	ip = mtod(m, struct ip *);
276 
277 	switch (igmp->igmp_type) {
278 
279 	case IGMP_HOST_MEMBERSHIP_QUERY:
280 		++igmpstat.igps_rcv_queries;
281 
282 		if (ifp->if_flags & IFF_LOOPBACK)
283 			break;
284 
285 		if (igmp->igmp_code == 0) {
286 			rti = rti_find(ifp);
287 			if (rti == NULL) {
288 				m_freem(m);
289 				return;
290 			}
291 			rti->rti_type = IGMP_v1_ROUTER;
292 			rti->rti_age = 0;
293 
294 			if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
295 				++igmpstat.igps_rcv_badqueries;
296 				m_freem(m);
297 				return;
298 			}
299 
300 			/*
301 			 * Start the timers in all of our membership records
302 			 * for the interface on which the query arrived,
303 			 * except those that are already running and those
304 			 * that belong to a "local" group (224.0.0.X).
305 			 */
306 			TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
307 				if (ifma->ifma_addr->sa_family != AF_INET)
308 					continue;
309 				inm = ifmatoinm(ifma);
310 				if (inm->inm_timer == 0 &&
311 				    !IN_LOCAL_GROUP(inm->inm_addr.s_addr)) {
312 					inm->inm_state = IGMP_DELAYING_MEMBER;
313 					inm->inm_timer = IGMP_RANDOM_DELAY(
314 					    IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
315 					igmp_timers_are_running = 1;
316 				}
317 			}
318 		} else {
319 			if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
320 				++igmpstat.igps_rcv_badqueries;
321 				m_freem(m);
322 				return;
323 			}
324 
325 			timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
326 			if (timer == 0)
327 				timer = 1;
328 
329 			/*
330 			 * Start the timers in all of our membership records
331 			 * for the interface on which the query arrived,
332 			 * except those that are already running and those
333 			 * that belong to a "local" group (224.0.0.X).  For
334 			 * timers already running, check if they need to be
335 			 * reset.
336 			 */
337 			TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
338 				if (ifma->ifma_addr->sa_family != AF_INET)
339 					continue;
340 				inm = ifmatoinm(ifma);
341 				if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
342 				    (ip->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP ||
343 				     ip->ip_dst.s_addr == inm->inm_addr.s_addr)) {
344 					switch (inm->inm_state) {
345 					case IGMP_DELAYING_MEMBER:
346 						if (inm->inm_timer <= timer)
347 							break;
348 						/* FALLTHROUGH */
349 					case IGMP_IDLE_MEMBER:
350 					case IGMP_LAZY_MEMBER:
351 					case IGMP_AWAKENING_MEMBER:
352 						inm->inm_state =
353 						    IGMP_DELAYING_MEMBER;
354 						inm->inm_timer =
355 						    IGMP_RANDOM_DELAY(timer);
356 						igmp_timers_are_running = 1;
357 						break;
358 					case IGMP_SLEEPING_MEMBER:
359 						inm->inm_state =
360 						    IGMP_AWAKENING_MEMBER;
361 						break;
362 					}
363 				}
364 			}
365 		}
366 
367 		break;
368 
369 	case IGMP_v1_HOST_MEMBERSHIP_REPORT:
370 		++igmpstat.igps_rcv_reports;
371 
372 		if (ifp->if_flags & IFF_LOOPBACK)
373 			break;
374 
375 		if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
376 		    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
377 			++igmpstat.igps_rcv_badreports;
378 			m_freem(m);
379 			return;
380 		}
381 
382 		/*
383 		 * KLUDGE: if the IP source address of the report has an
384 		 * unspecified (i.e., zero) subnet number, as is allowed for
385 		 * a booting host, replace it with the correct subnet number
386 		 * so that a process-level multicast routing daemon can
387 		 * determine which subnet it arrived from.  This is necessary
388 		 * to compensate for the lack of any way for a process to
389 		 * determine the arrival interface of an incoming packet.
390 		 */
391 		if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
392 			IFP_TO_IA(ifp, ia);
393 			if (ia)
394 				ip->ip_src.s_addr = ia->ia_net;
395 		}
396 
397 		/*
398 		 * If we belong to the group being reported, stop
399 		 * our timer for that group.
400 		 */
401 		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
402 		if (inm != NULL) {
403 			inm->inm_timer = 0;
404 			++igmpstat.igps_rcv_ourreports;
405 
406 			switch (inm->inm_state) {
407 			case IGMP_IDLE_MEMBER:
408 			case IGMP_LAZY_MEMBER:
409 			case IGMP_AWAKENING_MEMBER:
410 			case IGMP_SLEEPING_MEMBER:
411 				inm->inm_state = IGMP_SLEEPING_MEMBER;
412 				break;
413 			case IGMP_DELAYING_MEMBER:
414 				if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
415 					inm->inm_state = IGMP_LAZY_MEMBER;
416 				else
417 					inm->inm_state = IGMP_SLEEPING_MEMBER;
418 				break;
419 			}
420 		}
421 
422 		break;
423 
424 	case IGMP_v2_HOST_MEMBERSHIP_REPORT:
425 #ifdef MROUTING
426 		/*
427 		 * Make sure we don't hear our own membership report.  Fast
428 		 * leave requires knowing that we are the only member of a
429 		 * group.
430 		 */
431 		IFP_TO_IA(ifp, ia);
432 		if (ia && ip->ip_src.s_addr == ia->ia_addr.sin_addr.s_addr)
433 			break;
434 #endif
435 
436 		++igmpstat.igps_rcv_reports;
437 
438 		if (ifp->if_flags & IFF_LOOPBACK)
439 			break;
440 
441 		if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
442 		    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
443 			++igmpstat.igps_rcv_badreports;
444 			m_freem(m);
445 			return;
446 		}
447 
448 		/*
449 		 * KLUDGE: if the IP source address of the report has an
450 		 * unspecified (i.e., zero) subnet number, as is allowed for
451 		 * a booting host, replace it with the correct subnet number
452 		 * so that a process-level multicast routing daemon can
453 		 * determine which subnet it arrived from.  This is necessary
454 		 * to compensate for the lack of any way for a process to
455 		 * determine the arrival interface of an incoming packet.
456 		 */
457 		if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
458 #ifndef MROUTING
459 			IFP_TO_IA(ifp, ia);
460 #endif
461 			if (ia)
462 				ip->ip_src.s_addr = ia->ia_net;
463 		}
464 
465 		/*
466 		 * If we belong to the group being reported, stop
467 		 * our timer for that group.
468 		 */
469 		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
470 		if (inm != NULL) {
471 			inm->inm_timer = 0;
472 			++igmpstat.igps_rcv_ourreports;
473 
474 			switch (inm->inm_state) {
475 			case IGMP_DELAYING_MEMBER:
476 			case IGMP_IDLE_MEMBER:
477 			case IGMP_AWAKENING_MEMBER:
478 				inm->inm_state = IGMP_LAZY_MEMBER;
479 				break;
480 			case IGMP_LAZY_MEMBER:
481 			case IGMP_SLEEPING_MEMBER:
482 				break;
483 			}
484 		}
485 
486 		break;
487 
488 	}
489 
490 	/*
491 	 * Pass all valid IGMP packets up to any process(es) listening
492 	 * on a raw IGMP socket.
493 	 */
494 	rip_input(m);
495 }
496 
497 void
498 igmp_joingroup(struct in_multi *inm)
499 {
500 	struct ifnet* ifp;
501 	int i, s;
502 
503 	ifp = if_get(inm->inm_ifidx);
504 	s = splsoftnet();
505 
506 	inm->inm_state = IGMP_IDLE_MEMBER;
507 
508 	if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
509 	    ifp && (ifp->if_flags & IFF_LOOPBACK) == 0) {
510 		if ((i = rti_fill(inm)) == -1)
511 			goto out;
512 
513 		igmp_sendpkt(inm, i, 0);
514 		inm->inm_state = IGMP_DELAYING_MEMBER;
515 		inm->inm_timer = IGMP_RANDOM_DELAY(
516 		    IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
517 		igmp_timers_are_running = 1;
518 	} else
519 		inm->inm_timer = 0;
520 
521 out:
522 	splx(s);
523 	if_put(ifp);
524 }
525 
526 void
527 igmp_leavegroup(struct in_multi *inm)
528 {
529 	struct ifnet* ifp;
530 	int s;
531 
532 	ifp = if_get(inm->inm_ifidx);
533 	s = splsoftnet();
534 
535 	switch (inm->inm_state) {
536 	case IGMP_DELAYING_MEMBER:
537 	case IGMP_IDLE_MEMBER:
538 		if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
539 		    ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)
540 			if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
541 				igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE,
542 				    INADDR_ALLROUTERS_GROUP);
543 		break;
544 	case IGMP_LAZY_MEMBER:
545 	case IGMP_AWAKENING_MEMBER:
546 	case IGMP_SLEEPING_MEMBER:
547 		break;
548 	}
549 	splx(s);
550 	if_put(ifp);
551 }
552 
553 void
554 igmp_fasttimo(void)
555 {
556 	struct ifnet *ifp;
557 	int s;
558 
559 	/*
560 	 * Quick check to see if any work needs to be done, in order
561 	 * to minimize the overhead of fasttimo processing.
562 	 */
563 	if (!igmp_timers_are_running)
564 		return;
565 
566 	s = splsoftnet();
567 	igmp_timers_are_running = 0;
568 	TAILQ_FOREACH(ifp, &ifnet, if_list)
569 		igmp_checktimer(ifp);
570 	splx(s);
571 }
572 
573 
574 void
575 igmp_checktimer(struct ifnet *ifp)
576 {
577 	struct in_multi *inm;
578 	struct ifmaddr *ifma;
579 
580 	splsoftassert(IPL_SOFTNET);
581 
582 	TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
583 		if (ifma->ifma_addr->sa_family != AF_INET)
584 			continue;
585 		inm = ifmatoinm(ifma);
586 		if (inm->inm_timer == 0) {
587 			/* do nothing */
588 		} else if (--inm->inm_timer == 0) {
589 			if (inm->inm_state == IGMP_DELAYING_MEMBER) {
590 				if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
591 					igmp_sendpkt(inm,
592 					    IGMP_v1_HOST_MEMBERSHIP_REPORT, 0);
593 				else
594 					igmp_sendpkt(inm,
595 					    IGMP_v2_HOST_MEMBERSHIP_REPORT, 0);
596 				inm->inm_state = IGMP_IDLE_MEMBER;
597 			}
598 		} else {
599 			igmp_timers_are_running = 1;
600 		}
601 	}
602 }
603 
604 void
605 igmp_slowtimo(void)
606 {
607 	struct router_info *rti;
608 	int s;
609 
610 	s = splsoftnet();
611 	for (rti = rti_head; rti != 0; rti = rti->rti_next) {
612 		if (rti->rti_type == IGMP_v1_ROUTER &&
613 		    ++rti->rti_age >= IGMP_AGE_THRESHOLD) {
614 			rti->rti_type = IGMP_v2_ROUTER;
615 		}
616 	}
617 	splx(s);
618 }
619 
620 void
621 igmp_sendpkt(struct in_multi *inm, int type, in_addr_t addr)
622 {
623 	struct mbuf *m;
624 	struct igmp *igmp;
625 	struct ip *ip;
626 	struct ip_moptions imo;
627 
628 	MGETHDR(m, M_DONTWAIT, MT_HEADER);
629 	if (m == NULL)
630 		return;
631 	/*
632 	 * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
633 	 * is smaller than mbuf size returned by MGETHDR.
634 	 */
635 	m->m_data += max_linkhdr;
636 	m->m_len = sizeof(struct ip) + IGMP_MINLEN;
637 	m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
638 
639 	ip = mtod(m, struct ip *);
640 	ip->ip_tos = 0;
641 	ip->ip_len = htons(sizeof(struct ip) + IGMP_MINLEN);
642 	ip->ip_off = 0;
643 	ip->ip_p = IPPROTO_IGMP;
644 	ip->ip_src.s_addr = INADDR_ANY;
645 	if (addr) {
646 		ip->ip_dst.s_addr = addr;
647 	} else {
648 		ip->ip_dst = inm->inm_addr;
649 	}
650 
651 	m->m_data += sizeof(struct ip);
652 	m->m_len -= sizeof(struct ip);
653 	igmp = mtod(m, struct igmp *);
654 	igmp->igmp_type = type;
655 	igmp->igmp_code = 0;
656 	igmp->igmp_group = inm->inm_addr;
657 	igmp->igmp_cksum = 0;
658 	igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
659 	m->m_data -= sizeof(struct ip);
660 	m->m_len += sizeof(struct ip);
661 
662 	imo.imo_ifidx = inm->inm_ifidx;
663 	imo.imo_ttl = 1;
664 
665 	/*
666 	 * Request loopback of the report if we are acting as a multicast
667 	 * router, so that the process-level routing daemon can hear it.
668 	 */
669 #ifdef MROUTING
670 	imo.imo_loop = (ip_mrouter != NULL);
671 #else
672 	imo.imo_loop = 0;
673 #endif /* MROUTING */
674 
675 	ip_output(m, router_alert, NULL, IP_MULTICASTOPTS, &imo, NULL, 0);
676 
677 	++igmpstat.igps_snd_reports;
678 }
679 
680 /*
681  * Sysctl for igmp variables.
682  */
683 int
684 igmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
685     void *newp, size_t newlen)
686 {
687 	/* All sysctl names at this level are terminal. */
688 	if (namelen != 1)
689 		return (ENOTDIR);
690 
691 	switch (name[0]) {
692 	case IGMPCTL_STATS:
693 		if (newp != NULL)
694 			return (EPERM);
695 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
696 		    &igmpstat, sizeof(igmpstat)));
697 	default:
698 		if (name[0] < IGMPCTL_MAXID)
699 			return (sysctl_int_arr(igmpctl_vars, name, namelen,
700 			    oldp, oldlenp, newp, newlen));
701 		return (ENOPROTOOPT);
702 	}
703 	/* NOTREACHED */
704 }
705