igmp.c revision 183550
1139823Simp/*- 21541Srgrimes * Copyright (c) 1988 Stephen Deering. 31541Srgrimes * Copyright (c) 1992, 1993 41541Srgrimes * The Regents of the University of California. All rights reserved. 51541Srgrimes * 61541Srgrimes * This code is derived from software contributed to Berkeley by 71541Srgrimes * Stephen Deering of Stanford University. 81541Srgrimes * 91541Srgrimes * Redistribution and use in source and binary forms, with or without 101541Srgrimes * modification, are permitted provided that the following conditions 111541Srgrimes * are met: 121541Srgrimes * 1. Redistributions of source code must retain the above copyright 131541Srgrimes * notice, this list of conditions and the following disclaimer. 141541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151541Srgrimes * notice, this list of conditions and the following disclaimer in the 161541Srgrimes * documentation and/or other materials provided with the distribution. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)igmp.c 8.1 (Berkeley) 7/19/93 341541Srgrimes */ 351541Srgrimes 362531Swollman/* 372531Swollman * Internet Group Management Protocol (IGMP) routines. 382531Swollman * 392531Swollman * Written by Steve Deering, Stanford, May 1988. 402531Swollman * Modified by Rosen Sharma, Stanford, Aug 1994. 419209Swollman * Modified by Bill Fenner, Xerox PARC, Feb 1995. 4214622Sfenner * Modified to fully comply to IGMPv2 by Bill Fenner, Oct 1995. 432531Swollman * 4414622Sfenner * MULTICAST Revision: 3.5.1.4 452531Swollman */ 461541Srgrimes 47172467Ssilby#include <sys/cdefs.h> 48172467Ssilby__FBSDID("$FreeBSD: head/sys/netinet/igmp.c 183550 2008-10-02 15:37:58Z zec $"); 49172467Ssilby 50101091Srwatson#include "opt_mac.h" 51101091Srwatson 521541Srgrimes#include <sys/param.h> 531549Srgrimes#include <sys/systm.h> 5429024Sbde#include <sys/malloc.h> 551541Srgrimes#include <sys/mbuf.h> 561541Srgrimes#include <sys/socket.h> 571541Srgrimes#include <sys/protosw.h> 5812296Sphk#include <sys/kernel.h> 596472Swollman#include <sys/sysctl.h> 60181803Sbz#include <sys/vimage.h> 611541Srgrimes 621541Srgrimes#include <net/if.h> 631541Srgrimes#include <net/route.h> 641541Srgrimes 651541Srgrimes#include <netinet/in.h> 661541Srgrimes#include <netinet/in_var.h> 671541Srgrimes#include <netinet/in_systm.h> 681541Srgrimes#include <netinet/ip.h> 691541Srgrimes#include <netinet/ip_var.h> 70152592Sandre#include <netinet/ip_options.h> 711541Srgrimes#include <netinet/igmp.h> 721541Srgrimes#include <netinet/igmp_var.h> 731541Srgrimes 7460105Sjlemon#include <machine/in_cksum.h> 7560105Sjlemon 76163606Srwatson#include <security/mac/mac_framework.h> 77163606Srwatson 7842776Sfennerstatic MALLOC_DEFINE(M_IGMP, "igmp", "igmp state"); 7930309Sphk 80119181Srwatsonstatic struct router_info *find_rti(struct ifnet *ifp); 81119181Srwatsonstatic void igmp_sendpkt(struct in_multi *, int, unsigned long); 8212579Sbde 8312704Sphkstatic struct igmpstat igmpstat; 842531Swollman 85183550SzecSYSCTL_V_STRUCT(V_NET, vnet_inet, _net_inet_igmp, IGMPCTL_STATS, 86183550Szec stats, CTLFLAG_RW, igmpstat, igmpstat, ""); 8712296Sphk 88130333Srwatson/* 89164863Srwatson * igmp_mtx protects all mutable global variables in igmp.c, as well as the 90164863Srwatson * data fields in struct router_info. In general, a router_info structure 91164863Srwatson * will be valid as long as the referencing struct in_multi is valid, so no 92164863Srwatson * reference counting is used. We allow unlocked reads of router_info data 93164863Srwatson * when accessed via an in_multi read-only. 94130333Srwatson */ 95130333Srwatsonstatic struct mtx igmp_mtx; 96119181Srwatsonstatic SLIST_HEAD(, router_info) router_info_head; 979209Swollmanstatic int igmp_timers_are_running; 98130333Srwatson 99130333Srwatson/* 100130333Srwatson * XXXRW: can we define these such that these can be made const? In any 101130333Srwatson * case, these shouldn't be changed after igmp_init() and therefore don't 102130333Srwatson * need locking. 103130333Srwatson */ 1041541Srgrimesstatic u_long igmp_all_hosts_group; 10514622Sfennerstatic u_long igmp_all_rtrs_group; 106130333Srwatson 10714622Sfennerstatic struct mbuf *router_alert; 108119181Srwatsonstatic struct route igmprt; 1091541Srgrimes 110119180Srwatson#ifdef IGMP_DEBUG 111119180Srwatson#define IGMP_PRINTF(x) printf(x) 112119180Srwatson#else 113119180Srwatson#define IGMP_PRINTF(x) 114119180Srwatson#endif 115119180Srwatson 1161541Srgrimesvoid 117119181Srwatsonigmp_init(void) 1181541Srgrimes{ 119183550Szec INIT_VNET_INET(curvnet); 12014622Sfenner struct ipoption *ra; 12114622Sfenner 1221541Srgrimes /* 1231541Srgrimes * To avoid byte-swapping the same value over and over again. 1241541Srgrimes */ 1251541Srgrimes igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP); 12614622Sfenner igmp_all_rtrs_group = htonl(INADDR_ALLRTRS_GROUP); 1279209Swollman 1289209Swollman igmp_timers_are_running = 0; 1299209Swollman 13014622Sfenner /* 131164863Srwatson * Construct a Router Alert option to use in outgoing packets. 13214622Sfenner */ 133111119Simp MGET(router_alert, M_DONTWAIT, MT_DATA); 13414622Sfenner ra = mtod(router_alert, struct ipoption *); 13514622Sfenner ra->ipopt_dst.s_addr = 0; 13614622Sfenner ra->ipopt_list[0] = IPOPT_RA; /* Router Alert Option */ 13714622Sfenner ra->ipopt_list[1] = 0x04; /* 4 bytes long */ 13814622Sfenner ra->ipopt_list[2] = 0x00; 13914622Sfenner ra->ipopt_list[3] = 0x00; 14014622Sfenner router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1]; 14114622Sfenner 142130333Srwatson mtx_init(&igmp_mtx, "igmp_mtx", NULL, MTX_DEF); 143181803Sbz SLIST_INIT(&V_router_info_head); 1441541Srgrimes} 1451541Srgrimes 14612704Sphkstatic struct router_info * 147119181Srwatsonfind_rti(struct ifnet *ifp) 1482531Swollman{ 149183550Szec INIT_VNET_INET(ifp->if_vnet); 150119180Srwatson struct router_info *rti; 1512531Swollman 152130333Srwatson mtx_assert(&igmp_mtx, MA_OWNED); 153119180Srwatson IGMP_PRINTF("[igmp.c, _find_rti] --> entering \n"); 154181803Sbz SLIST_FOREACH(rti, &V_router_info_head, rti_list) { 155119180Srwatson if (rti->rti_ifp == ifp) { 156119180Srwatson IGMP_PRINTF( 157119180Srwatson "[igmp.c, _find_rti] --> found old entry \n"); 158164863Srwatson return (rti); 159119181Srwatson } 160119181Srwatson } 16142776Sfenner MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, M_NOWAIT); 162144163Ssam if (rti == NULL) { 163164863Srwatson IGMP_PRINTF("[igmp.c, _find_rti] --> no memory for entry\n"); 164164863Srwatson return (NULL); 165144163Ssam } 166119181Srwatson rti->rti_ifp = ifp; 167119181Srwatson rti->rti_type = IGMP_V2_ROUTER; 168119181Srwatson rti->rti_time = 0; 169181803Sbz SLIST_INSERT_HEAD(&V_router_info_head, rti, rti_list); 170119180Srwatson IGMP_PRINTF("[igmp.c, _find_rti] --> created an entry \n"); 171164863Srwatson return (rti); 1722531Swollman} 1732531Swollman 1741541Srgrimesvoid 175119181Srwatsonigmp_input(register struct mbuf *m, int off) 1761541Srgrimes{ 177107113Sluigi register int iphlen = off; 178107113Sluigi register struct igmp *igmp; 179107113Sluigi register struct ip *ip; 180107113Sluigi register int igmplen; 181107113Sluigi register struct ifnet *ifp = m->m_pkthdr.rcvif; 182107113Sluigi register int minlen; 183107113Sluigi register struct in_multi *inm; 184107113Sluigi register struct in_ifaddr *ia; 1851541Srgrimes struct in_multistep step; 1862531Swollman struct router_info *rti; 1878546Sdg int timer; /** timer value in the igmp query header **/ 188183550Szec INIT_VNET_INET(ifp->if_vnet); 1891541Srgrimes 190181803Sbz ++V_igmpstat.igps_rcv_total; 1911541Srgrimes 1921541Srgrimes ip = mtod(m, struct ip *); 1931541Srgrimes igmplen = ip->ip_len; 1941541Srgrimes 1951541Srgrimes /* 196164863Srwatson * Validate lengths. 1971541Srgrimes */ 1981541Srgrimes if (igmplen < IGMP_MINLEN) { 199181803Sbz ++V_igmpstat.igps_rcv_tooshort; 2001541Srgrimes m_freem(m); 2011541Srgrimes return; 2021541Srgrimes } 2031541Srgrimes minlen = iphlen + IGMP_MINLEN; 2041541Srgrimes if ((m->m_flags & M_EXT || m->m_len < minlen) && 2051541Srgrimes (m = m_pullup(m, minlen)) == 0) { 206181803Sbz ++V_igmpstat.igps_rcv_tooshort; 2071541Srgrimes return; 2081541Srgrimes } 2091541Srgrimes 2101541Srgrimes /* 211164863Srwatson * Validate checksum. 2121541Srgrimes */ 2131541Srgrimes m->m_data += iphlen; 2141541Srgrimes m->m_len -= iphlen; 2151541Srgrimes igmp = mtod(m, struct igmp *); 2161541Srgrimes if (in_cksum(m, igmplen)) { 217181803Sbz ++V_igmpstat.igps_rcv_badsum; 2181541Srgrimes m_freem(m); 2191541Srgrimes return; 2201541Srgrimes } 2211541Srgrimes m->m_data -= iphlen; 2221541Srgrimes m->m_len += iphlen; 2232531Swollman 2241541Srgrimes ip = mtod(m, struct ip *); 2258546Sdg timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE; 22641702Sdillon if (timer == 0) 22741702Sdillon timer = 1; 2281541Srgrimes 22914622Sfenner /* 23014622Sfenner * In the IGMPv2 specification, there are 3 states and a flag. 23114622Sfenner * 23214622Sfenner * In Non-Member state, we simply don't have a membership record. 233164863Srwatson * In Delaying Member state, our timer is running (inm->inm_timer). 234164863Srwatson * In Idle Member state, our timer is not running (inm->inm_timer==0). 23514622Sfenner * 236164863Srwatson * The flag is inm->inm_state, it is set to IGMP_OTHERMEMBER if we 237164863Srwatson * have heard a report from another member, or IGMP_IREPORTEDLAST if 238164863Srwatson * I sent the last report. 23914622Sfenner */ 2401541Srgrimes switch (igmp->igmp_type) { 24114622Sfenner case IGMP_MEMBERSHIP_QUERY: 242181803Sbz ++V_igmpstat.igps_rcv_queries; 2431541Srgrimes 2448090Spst if (ifp->if_flags & IFF_LOOPBACK) 2451541Srgrimes break; 2461541Srgrimes 2472531Swollman if (igmp->igmp_code == 0) { 24814622Sfenner /* 24914622Sfenner * Old router. Remember that the querier on this 250164863Srwatson * interface is old, and set the timer to the value 251164863Srwatson * in RFC 1112. 25214622Sfenner */ 2534028Spst 254130333Srwatson mtx_lock(&igmp_mtx); 255130333Srwatson rti = find_rti(ifp); 256144163Ssam if (rti == NULL) { 257144163Ssam mtx_unlock(&igmp_mtx); 258144163Ssam m_freem(m); 259144163Ssam return; 260144163Ssam } 26114622Sfenner rti->rti_type = IGMP_V1_ROUTER; 26214622Sfenner rti->rti_time = 0; 263130333Srwatson mtx_unlock(&igmp_mtx); 2644028Spst 26514622Sfenner timer = IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ; 2664028Spst 26714622Sfenner if (ip->ip_dst.s_addr != igmp_all_hosts_group || 26814622Sfenner igmp->igmp_group.s_addr != 0) { 269181803Sbz ++V_igmpstat.igps_rcv_badqueries; 2702531Swollman m_freem(m); 2712531Swollman return; 2722531Swollman } 27314622Sfenner } else { 2742531Swollman /* 27514622Sfenner * New router. Simply do the new validity check. 2762531Swollman */ 27714622Sfenner 27814622Sfenner if (igmp->igmp_group.s_addr != 0 && 27914622Sfenner !IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) { 280181803Sbz ++V_igmpstat.igps_rcv_badqueries; 28114622Sfenner m_freem(m); 28214622Sfenner return; 28314622Sfenner } 28414622Sfenner } 2852531Swollman 28614622Sfenner /* 287164863Srwatson * - Start the timers in all of our membership records that 288164863Srwatson * the query applies to for the interface on which the 289164863Srwatson * query arrived excl. those that belong to the "all-hosts" 290164863Srwatson * group (224.0.0.1). 291164863Srwatson * - Restart any timer that is already running but has a 292164863Srwatson * value longer than the requested timeout. 293164863Srwatson * - Use the value specified in the query message as the 294164863Srwatson * maximum timeout. 29514622Sfenner */ 296148682Srwatson IN_MULTI_LOCK(); 29714622Sfenner IN_FIRST_MULTI(step, inm); 29814622Sfenner while (inm != NULL) { 29914622Sfenner if (inm->inm_ifp == ifp && 30014622Sfenner inm->inm_addr.s_addr != igmp_all_hosts_group && 30114622Sfenner (igmp->igmp_group.s_addr == 0 || 30214622Sfenner igmp->igmp_group.s_addr == inm->inm_addr.s_addr)) { 30314622Sfenner if (inm->inm_timer == 0 || 30414622Sfenner inm->inm_timer > timer) { 30514622Sfenner inm->inm_timer = 30614622Sfenner IGMP_RANDOM_DELAY(timer); 3072531Swollman igmp_timers_are_running = 1; 3082531Swollman } 3091541Srgrimes } 3101541Srgrimes IN_NEXT_MULTI(step, inm); 3111541Srgrimes } 312148682Srwatson IN_MULTI_UNLOCK(); 3131541Srgrimes break; 3141541Srgrimes 31514622Sfenner case IGMP_V1_MEMBERSHIP_REPORT: 31614622Sfenner case IGMP_V2_MEMBERSHIP_REPORT: 3179209Swollman /* 31814622Sfenner * For fast leave to work, we have to know that we are the 319164863Srwatson * last person to send a report for this group. Reports can 320164863Srwatson * potentially get looped back if we are a multicast router, 321164863Srwatson * so discard reports sourced by me. 3229209Swollman */ 32314622Sfenner IFP_TO_IA(ifp, ia); 324164863Srwatson if (ia != NULL && 325164863Srwatson ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr) 32614622Sfenner break; 32714622Sfenner 328181803Sbz ++V_igmpstat.igps_rcv_reports; 3291541Srgrimes 3308090Spst if (ifp->if_flags & IFF_LOOPBACK) 3311541Srgrimes break; 3321541Srgrimes 33314622Sfenner if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) { 334181803Sbz ++V_igmpstat.igps_rcv_badreports; 3351541Srgrimes m_freem(m); 3361541Srgrimes return; 3371541Srgrimes } 3381541Srgrimes 3391541Srgrimes /* 3401541Srgrimes * KLUDGE: if the IP source address of the report has an 3411541Srgrimes * unspecified (i.e., zero) subnet number, as is allowed for 3421541Srgrimes * a booting host, replace it with the correct subnet number 34396432Sdd * so that a process-level multicast routing daemon can 3441541Srgrimes * determine which subnet it arrived from. This is necessary 3451541Srgrimes * to compensate for the lack of any way for a process to 3461541Srgrimes * determine the arrival interface of an incoming packet. 3471541Srgrimes */ 348164863Srwatson if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) { 349164863Srwatson if (ia != NULL) 350164863Srwatson ip->ip_src.s_addr = htonl(ia->ia_subnet); 351164863Srwatson } 3521541Srgrimes 3531541Srgrimes /* 354164863Srwatson * If we belong to the group being reported, stop our timer 355164863Srwatson * for that group. 3561541Srgrimes */ 357148682Srwatson IN_MULTI_LOCK(); 3581541Srgrimes IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm); 3592531Swollman if (inm != NULL) { 36014622Sfenner inm->inm_timer = 0; 361181803Sbz ++V_igmpstat.igps_rcv_ourreports; 36214622Sfenner inm->inm_state = IGMP_OTHERMEMBER; 3632531Swollman } 364148682Srwatson IN_MULTI_UNLOCK(); 3651541Srgrimes break; 3661541Srgrimes } 3671541Srgrimes 3681541Srgrimes /* 369164863Srwatson * Pass all valid IGMP packets up to any process(es) listening on a 370164863Srwatson * raw IGMP socket. 3711541Srgrimes */ 37282890Sjulian rip_input(m, off); 3731541Srgrimes} 3741541Srgrimes 3751541Srgrimesvoid 376119181Srwatsonigmp_joingroup(struct in_multi *inm) 3771541Srgrimes{ 3781541Srgrimes 379148682Srwatson IN_MULTI_LOCK_ASSERT(); 380148682Srwatson 38114622Sfenner if (inm->inm_addr.s_addr == igmp_all_hosts_group 38214622Sfenner || inm->inm_ifp->if_flags & IFF_LOOPBACK) { 3831541Srgrimes inm->inm_timer = 0; 38414622Sfenner inm->inm_state = IGMP_OTHERMEMBER; 38514622Sfenner } else { 386130333Srwatson mtx_lock(&igmp_mtx); 38714622Sfenner inm->inm_rti = find_rti(inm->inm_ifp); 388130333Srwatson mtx_unlock(&igmp_mtx); 389144163Ssam if (inm->inm_rti != NULL) { 390144163Ssam igmp_sendpkt(inm, inm->inm_rti->rti_type, 0); 391144163Ssam inm->inm_timer = IGMP_RANDOM_DELAY( 3922531Swollman IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ); 393144163Ssam inm->inm_state = IGMP_IREPORTEDLAST; 394144163Ssam igmp_timers_are_running = 1; 395144163Ssam } 396144163Ssam /* XXX handling of failure case? */ 3971541Srgrimes } 3981541Srgrimes} 3991541Srgrimes 4001541Srgrimesvoid 401119181Srwatsonigmp_leavegroup(struct in_multi *inm) 4021541Srgrimes{ 403119181Srwatson 404148682Srwatson IN_MULTI_LOCK_ASSERT(); 405148682Srwatson 40614622Sfenner if (inm->inm_state == IGMP_IREPORTEDLAST && 40714622Sfenner inm->inm_addr.s_addr != igmp_all_hosts_group && 40814622Sfenner !(inm->inm_ifp->if_flags & IFF_LOOPBACK) && 40914622Sfenner inm->inm_rti->rti_type != IGMP_V1_ROUTER) 41014622Sfenner igmp_sendpkt(inm, IGMP_V2_LEAVE_GROUP, igmp_all_rtrs_group); 4111541Srgrimes} 4121541Srgrimes 4131541Srgrimesvoid 414119181Srwatsonigmp_fasttimo(void) 4151541Srgrimes{ 416183550Szec VNET_ITERATOR_DECL(vnet_iter); 417107113Sluigi register struct in_multi *inm; 4181541Srgrimes struct in_multistep step; 4191541Srgrimes 4201541Srgrimes /* 421164863Srwatson * Quick check to see if any work needs to be done, in order to 422164863Srwatson * minimize the overhead of fasttimo processing. 4231541Srgrimes */ 4249209Swollman 4251541Srgrimes if (!igmp_timers_are_running) 4261541Srgrimes return; 4271541Srgrimes 428148682Srwatson IN_MULTI_LOCK(); 4291541Srgrimes igmp_timers_are_running = 0; 430183550Szec VNET_LIST_RLOCK(); 431183550Szec VNET_FOREACH(vnet_iter) { 432183550Szec CURVNET_SET(vnet_iter); 433183550Szec INIT_VNET_INET(vnet_iter); 434183550Szec IN_FIRST_MULTI(step, inm); 435183550Szec while (inm != NULL) { 436183550Szec if (inm->inm_timer == 0) { 437183550Szec /* do nothing */ 438183550Szec } else if (--inm->inm_timer == 0) { 439183550Szec igmp_sendpkt(inm, inm->inm_rti->rti_type, 0); 440183550Szec inm->inm_state = IGMP_IREPORTEDLAST; 441183550Szec } else { 442183550Szec igmp_timers_are_running = 1; 443183550Szec } 444183550Szec IN_NEXT_MULTI(step, inm); 4451541Srgrimes } 446183550Szec CURVNET_RESTORE(); 4471541Srgrimes } 448183550Szec VNET_LIST_RUNLOCK(); 449148682Srwatson IN_MULTI_UNLOCK(); 4501541Srgrimes} 4511541Srgrimes 4522531Swollmanvoid 453119181Srwatsonigmp_slowtimo(void) 4542531Swollman{ 455183550Szec VNET_ITERATOR_DECL(vnet_iter); 456119180Srwatson struct router_info *rti; 4572531Swollman 458119180Srwatson IGMP_PRINTF("[igmp.c,_slowtimo] -- > entering \n"); 459130333Srwatson mtx_lock(&igmp_mtx); 460183550Szec VNET_LIST_RLOCK(); 461183550Szec VNET_FOREACH(vnet_iter) { 462183550Szec CURVNET_SET(vnet_iter); 463183550Szec INIT_VNET_INET(vnet_iter); 464183550Szec SLIST_FOREACH(rti, &V_router_info_head, rti_list) { 465183550Szec if (rti->rti_type == IGMP_V1_ROUTER) { 466183550Szec rti->rti_time++; 467183550Szec if (rti->rti_time >= IGMP_AGE_THRESHOLD) 468183550Szec rti->rti_type = IGMP_V2_ROUTER; 469183550Szec } 4702531Swollman } 471183550Szec CURVNET_RESTORE(); 4722531Swollman } 473183550Szec VNET_LIST_RUNLOCK(); 474130333Srwatson mtx_unlock(&igmp_mtx); 475119180Srwatson IGMP_PRINTF("[igmp.c,_slowtimo] -- > exiting \n"); 4762531Swollman} 4772531Swollman 4781541Srgrimesstatic void 479119181Srwatsonigmp_sendpkt(struct in_multi *inm, int type, unsigned long addr) 4801541Srgrimes{ 481183550Szec INIT_VNET_NET(curvnet); 482183550Szec INIT_VNET_INET(curvnet); 483119181Srwatson struct mbuf *m; 484119181Srwatson struct igmp *igmp; 485119181Srwatson struct ip *ip; 486119181Srwatson struct ip_moptions imo; 4871541Srgrimes 488148682Srwatson IN_MULTI_LOCK_ASSERT(); 489148682Srwatson 490151967Sandre MGETHDR(m, M_DONTWAIT, MT_DATA); 491119181Srwatson if (m == NULL) 492119181Srwatson return; 4932531Swollman 494181803Sbz m->m_pkthdr.rcvif = V_loif; 495101091Srwatson#ifdef MAC 496173095Srwatson mac_netinet_igmp_send(inm->inm_ifp, m); 497101091Srwatson#endif 4981541Srgrimes m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN; 4992531Swollman MH_ALIGN(m, IGMP_MINLEN + sizeof(struct ip)); 5002531Swollman m->m_data += sizeof(struct ip); 501119181Srwatson m->m_len = IGMP_MINLEN; 502119181Srwatson igmp = mtod(m, struct igmp *); 503119181Srwatson igmp->igmp_type = type; 504119181Srwatson igmp->igmp_code = 0; 505119181Srwatson igmp->igmp_group = inm->inm_addr; 506119181Srwatson igmp->igmp_cksum = 0; 507119181Srwatson igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN); 5081541Srgrimes 509119181Srwatson m->m_data -= sizeof(struct ip); 510119181Srwatson m->m_len += sizeof(struct ip); 511119181Srwatson ip = mtod(m, struct ip *); 512119181Srwatson ip->ip_tos = 0; 513119181Srwatson ip->ip_len = sizeof(struct ip) + IGMP_MINLEN; 514119181Srwatson ip->ip_off = 0; 515119181Srwatson ip->ip_p = IPPROTO_IGMP; 516119181Srwatson ip->ip_src.s_addr = INADDR_ANY; 517119181Srwatson ip->ip_dst.s_addr = addr ? addr : igmp->igmp_group.s_addr; 5181541Srgrimes 519119181Srwatson imo.imo_multicast_ifp = inm->inm_ifp; 520119181Srwatson imo.imo_multicast_ttl = 1; 52115292Swollman imo.imo_multicast_vif = -1; 522119181Srwatson /* 523119181Srwatson * Request loopback of the report if we are acting as a multicast 524119181Srwatson * router, so that the process-level routing daemon can hear it. 525119181Srwatson */ 526181803Sbz imo.imo_multicast_loop = (V_ip_mrouter != NULL); 5271541Srgrimes 52815292Swollman /* 529164863Srwatson * XXX: Do we have to worry about reentrancy here? Don't think so. 53015292Swollman */ 531119181Srwatson ip_output(m, router_alert, &igmprt, 0, &imo, NULL); 5322531Swollman 533181803Sbz ++V_igmpstat.igps_snd_reports; 5341541Srgrimes} 535