The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/igmp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: igmp.c,v 1.49 2008/05/04 07:22:14 thorpej Exp $        */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Internet Group Management Protocol (IGMP) routines.
   34  *
   35  * Written by Steve Deering, Stanford, May 1988.
   36  * Modified by Rosen Sharma, Stanford, Aug 1994.
   37  * Modified by Bill Fenner, Xerox PARC, Feb 1995.
   38  *
   39  * MULTICAST Revision: 1.3
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.49 2008/05/04 07:22:14 thorpej Exp $");
   44 
   45 #include "opt_mrouting.h"
   46 
   47 #include <sys/param.h>
   48 #include <sys/mbuf.h>
   49 #include <sys/socket.h>
   50 #include <sys/socketvar.h>
   51 #include <sys/protosw.h>
   52 #include <sys/systm.h>
   53 #include <sys/sysctl.h>
   54 
   55 #include <net/if.h>
   56 #include <net/route.h>
   57 #include <net/net_stats.h>
   58 
   59 #include <netinet/in.h>
   60 #include <netinet/in_var.h>
   61 #include <netinet/in_systm.h>
   62 #include <netinet/ip.h>
   63 #include <netinet/ip_var.h>
   64 #include <netinet/igmp.h>
   65 #include <netinet/igmp_var.h>
   66 
   67 #include <machine/stdarg.h>
   68 
   69 #define IP_MULTICASTOPTS        0
   70 
   71 POOL_INIT(igmp_rti_pool, sizeof(struct router_info), 0, 0, 0, "igmppl", NULL,
   72     IPL_SOFTNET);
   73 
   74 static percpu_t *igmpstat_percpu;
   75 
   76 #define IGMP_STATINC(x)         _NET_STATINC(igmpstat_percpu, x)
   77 
   78 int igmp_timers_are_running;
   79 static LIST_HEAD(, router_info) rti_head = LIST_HEAD_INITIALIZER(rti_head);
   80 
   81 void igmp_sendpkt(struct in_multi *, int);
   82 static int rti_fill(struct in_multi *);
   83 static struct router_info *rti_find(struct ifnet *);
   84 static void rti_delete(struct ifnet *);
   85 
   86 static int
   87 rti_fill(struct in_multi *inm)
   88 {
   89         struct router_info *rti;
   90 
   91         /* this function is called at splsoftnet() */
   92         LIST_FOREACH(rti, &rti_head, rti_link) {
   93                 if (rti->rti_ifp == inm->inm_ifp) {
   94                         inm->inm_rti = rti;
   95                         if (rti->rti_type == IGMP_v1_ROUTER)
   96                                 return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
   97                         else
   98                                 return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
   99                 }
  100         }
  101 
  102         rti = pool_get(&igmp_rti_pool, PR_NOWAIT);
  103         if (rti == NULL)
  104                 return 0;
  105         rti->rti_ifp = inm->inm_ifp;
  106         rti->rti_type = IGMP_v2_ROUTER;
  107         LIST_INSERT_HEAD(&rti_head, rti, rti_link);
  108         inm->inm_rti = rti;
  109         return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
  110 }
  111 
  112 static struct router_info *
  113 rti_find(struct ifnet *ifp)
  114 {
  115         struct router_info *rti;
  116         int s = splsoftnet();
  117 
  118         LIST_FOREACH(rti, &rti_head, rti_link) {
  119                 if (rti->rti_ifp == ifp)
  120                         return (rti);
  121         }
  122 
  123         rti = pool_get(&igmp_rti_pool, PR_NOWAIT);
  124         if (rti == NULL) {
  125                 splx(s);
  126                 return NULL;
  127         }
  128         rti->rti_ifp = ifp;
  129         rti->rti_type = IGMP_v2_ROUTER;
  130         LIST_INSERT_HEAD(&rti_head, rti, rti_link);
  131         splx(s);
  132         return (rti);
  133 }
  134 
  135 static void
  136 rti_delete(struct ifnet *ifp)   /* MUST be called at splsoftnet */
  137 {
  138         struct router_info *rti;
  139 
  140         LIST_FOREACH(rti, &rti_head, rti_link) {
  141                 if (rti->rti_ifp == ifp) {
  142                         LIST_REMOVE(rti, rti_link);
  143                         pool_put(&igmp_rti_pool, rti);
  144                         return;
  145                 }
  146         }
  147 }
  148 
  149 void
  150 igmp_init(void)
  151 {
  152 
  153         igmpstat_percpu = percpu_alloc(sizeof(uint64_t) * IGMP_NSTATS);
  154 }
  155 
  156 void
  157 igmp_input(struct mbuf *m, ...)
  158 {
  159         int proto;
  160         int iphlen;
  161         struct ifnet *ifp = m->m_pkthdr.rcvif;
  162         struct ip *ip = mtod(m, struct ip *);
  163         struct igmp *igmp;
  164         u_int minlen;
  165         struct in_multi *inm;
  166         struct in_multistep step;
  167         struct router_info *rti;
  168         struct in_ifaddr *ia;
  169         u_int timer;
  170         va_list ap;
  171         u_int16_t ip_len;
  172 
  173         va_start(ap, m);
  174         iphlen = va_arg(ap, int);
  175         proto = va_arg(ap, int);
  176         va_end(ap);
  177 
  178         IGMP_STATINC(IGMP_STAT_RCV_TOTAL);
  179 
  180         /*
  181          * Validate lengths
  182          */
  183         minlen = iphlen + IGMP_MINLEN;
  184         ip_len = ntohs(ip->ip_len);
  185         if (ip_len < minlen) {
  186                 IGMP_STATINC(IGMP_STAT_RCV_TOOSHORT);
  187                 m_freem(m);
  188                 return;
  189         }
  190         if (((m->m_flags & M_EXT) && (ip->ip_src.s_addr & IN_CLASSA_NET) == 0)
  191             || m->m_len < minlen) {
  192                 if ((m = m_pullup(m, minlen)) == 0) {
  193                         IGMP_STATINC(IGMP_STAT_RCV_TOOSHORT);
  194                         return;
  195                 }
  196                 ip = mtod(m, struct ip *);
  197         }
  198 
  199         /*
  200          * Validate checksum
  201          */
  202         m->m_data += iphlen;
  203         m->m_len -= iphlen;
  204         igmp = mtod(m, struct igmp *);
  205         /* No need to assert alignment here. */
  206         if (in_cksum(m, ip_len - iphlen)) {
  207                 IGMP_STATINC(IGMP_STAT_RCV_BADSUM);
  208                 m_freem(m);
  209                 return;
  210         }
  211         m->m_data -= iphlen;
  212         m->m_len += iphlen;
  213 
  214         switch (igmp->igmp_type) {
  215 
  216         case IGMP_HOST_MEMBERSHIP_QUERY:
  217                 IGMP_STATINC(IGMP_STAT_RCV_QUERIES);
  218 
  219                 if (ifp->if_flags & IFF_LOOPBACK)
  220                         break;
  221 
  222                 if (igmp->igmp_code == 0) {
  223                         rti = rti_find(ifp);
  224                         if (rti == NULL)
  225                                 break;
  226                         rti->rti_type = IGMP_v1_ROUTER;
  227                         rti->rti_age = 0;
  228 
  229                         if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
  230                                 IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES);
  231                                 m_freem(m);
  232                                 return;
  233                         }
  234 
  235                         /*
  236                          * Start the timers in all of our membership records
  237                          * for the interface on which the query arrived,
  238                          * except those that are already running and those
  239                          * that belong to a "local" group (224.0.0.X).
  240                          */
  241                         IN_FIRST_MULTI(step, inm);
  242                         while (inm != NULL) {
  243                                 if (inm->inm_ifp == ifp &&
  244                                     inm->inm_timer == 0 &&
  245                                     !IN_LOCAL_GROUP(inm->inm_addr.s_addr)) {
  246                                         inm->inm_state = IGMP_DELAYING_MEMBER;
  247                                         inm->inm_timer = IGMP_RANDOM_DELAY(
  248                                             IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
  249                                         igmp_timers_are_running = 1;
  250                                 }
  251                                 IN_NEXT_MULTI(step, inm);
  252                         }
  253                 } else {
  254                         if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
  255                                 IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES);
  256                                 m_freem(m);
  257                                 return;
  258                         }
  259 
  260                         timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
  261                         if (timer == 0)
  262                                 timer =1;
  263 
  264                         /*
  265                          * Start the timers in all of our membership records
  266                          * for the interface on which the query arrived,
  267                          * except those that are already running and those
  268                          * that belong to a "local" group (224.0.0.X).  For
  269                          * timers already running, check if they need to be
  270                          * reset.
  271                          */
  272                         IN_FIRST_MULTI(step, inm);
  273                         while (inm != NULL) {
  274                                 if (inm->inm_ifp == ifp &&
  275                                     !IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
  276                                     (ip->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP ||
  277                                      in_hosteq(ip->ip_dst, inm->inm_addr))) {
  278                                         switch (inm->inm_state) {
  279                                         case IGMP_DELAYING_MEMBER:
  280                                                 if (inm->inm_timer <= timer)
  281                                                         break;
  282                                                 /* FALLTHROUGH */
  283                                         case IGMP_IDLE_MEMBER:
  284                                         case IGMP_LAZY_MEMBER:
  285                                         case IGMP_AWAKENING_MEMBER:
  286                                                 inm->inm_state =
  287                                                     IGMP_DELAYING_MEMBER;
  288                                                 inm->inm_timer =
  289                                                     IGMP_RANDOM_DELAY(timer);
  290                                                 igmp_timers_are_running = 1;
  291                                                 break;
  292                                         case IGMP_SLEEPING_MEMBER:
  293                                                 inm->inm_state =
  294                                                     IGMP_AWAKENING_MEMBER;
  295                                                 break;
  296                                         }
  297                                 }
  298                                 IN_NEXT_MULTI(step, inm);
  299                         }
  300                 }
  301 
  302                 break;
  303 
  304         case IGMP_v1_HOST_MEMBERSHIP_REPORT:
  305                 IGMP_STATINC(IGMP_STAT_RCV_REPORTS);
  306 
  307                 if (ifp->if_flags & IFF_LOOPBACK)
  308                         break;
  309 
  310                 if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
  311                     !in_hosteq(igmp->igmp_group, ip->ip_dst)) {
  312                         IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS);
  313                         m_freem(m);
  314                         return;
  315                 }
  316 
  317                 /*
  318                  * KLUDGE: if the IP source address of the report has an
  319                  * unspecified (i.e., zero) subnet number, as is allowed for
  320                  * a booting host, replace it with the correct subnet number
  321                  * so that a process-level multicast routing daemon can
  322                  * determine which subnet it arrived from.  This is necessary
  323                  * to compensate for the lack of any way for a process to
  324                  * determine the arrival interface of an incoming packet.
  325                  */
  326                 if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
  327                         IFP_TO_IA(ifp, ia);             /* XXX */
  328                         if (ia)
  329                                 ip->ip_src.s_addr = ia->ia_subnet;
  330                 }
  331 
  332                 /*
  333                  * If we belong to the group being reported, stop
  334                  * our timer for that group.
  335                  */
  336                 IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
  337                 if (inm != NULL) {
  338                         inm->inm_timer = 0;
  339                         IGMP_STATINC(IGMP_STAT_RCV_OURREPORTS);
  340 
  341                         switch (inm->inm_state) {
  342                         case IGMP_IDLE_MEMBER:
  343                         case IGMP_LAZY_MEMBER:
  344                         case IGMP_AWAKENING_MEMBER:
  345                         case IGMP_SLEEPING_MEMBER:
  346                                 inm->inm_state = IGMP_SLEEPING_MEMBER;
  347                                 break;
  348                         case IGMP_DELAYING_MEMBER:
  349                                 if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
  350                                         inm->inm_state = IGMP_LAZY_MEMBER;
  351                                 else
  352                                         inm->inm_state = IGMP_SLEEPING_MEMBER;
  353                                 break;
  354                         }
  355                 }
  356 
  357                 break;
  358 
  359         case IGMP_v2_HOST_MEMBERSHIP_REPORT:
  360 #ifdef MROUTING
  361                 /*
  362                  * Make sure we don't hear our own membership report.  Fast
  363                  * leave requires knowing that we are the only member of a
  364                  * group.
  365                  */
  366                 IFP_TO_IA(ifp, ia);                     /* XXX */
  367                 if (ia && in_hosteq(ip->ip_src, ia->ia_addr.sin_addr))
  368                         break;
  369 #endif
  370 
  371                 IGMP_STATINC(IGMP_STAT_RCV_REPORTS);
  372 
  373                 if (ifp->if_flags & IFF_LOOPBACK)
  374                         break;
  375 
  376                 if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
  377                     !in_hosteq(igmp->igmp_group, ip->ip_dst)) {
  378                         IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS);
  379                         m_freem(m);
  380                         return;
  381                 }
  382 
  383                 /*
  384                  * KLUDGE: if the IP source address of the report has an
  385                  * unspecified (i.e., zero) subnet number, as is allowed for
  386                  * a booting host, replace it with the correct subnet number
  387                  * so that a process-level multicast routing daemon can
  388                  * determine which subnet it arrived from.  This is necessary
  389                  * to compensate for the lack of any way for a process to
  390                  * determine the arrival interface of an incoming packet.
  391                  */
  392                 if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
  393 #ifndef MROUTING
  394                         IFP_TO_IA(ifp, ia);             /* XXX */
  395 #endif
  396                         if (ia)
  397                                 ip->ip_src.s_addr = ia->ia_subnet;
  398                 }
  399 
  400                 /*
  401                  * If we belong to the group being reported, stop
  402                  * our timer for that group.
  403                  */
  404                 IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
  405                 if (inm != NULL) {
  406                         inm->inm_timer = 0;
  407                         IGMP_STATINC(IGMP_STAT_RCV_OURREPORTS);
  408 
  409                         switch (inm->inm_state) {
  410                         case IGMP_DELAYING_MEMBER:
  411                         case IGMP_IDLE_MEMBER:
  412                         case IGMP_AWAKENING_MEMBER:
  413                                 inm->inm_state = IGMP_LAZY_MEMBER;
  414                                 break;
  415                         case IGMP_LAZY_MEMBER:
  416                         case IGMP_SLEEPING_MEMBER:
  417                                 break;
  418                         }
  419                 }
  420 
  421                 break;
  422 
  423         }
  424 
  425         /*
  426          * Pass all valid IGMP packets up to any process(es) listening
  427          * on a raw IGMP socket.
  428          */
  429         rip_input(m, iphlen, proto);
  430         return;
  431 }
  432 
  433 int
  434 igmp_joingroup(struct in_multi *inm)
  435 {
  436         int report_type;
  437         int s = splsoftnet();
  438 
  439         inm->inm_state = IGMP_IDLE_MEMBER;
  440 
  441         if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
  442             (inm->inm_ifp->if_flags & IFF_LOOPBACK) == 0) {
  443                 report_type = rti_fill(inm);
  444                 if (report_type == 0) {
  445                         splx(s);
  446                         return ENOMEM;
  447                 }
  448                 igmp_sendpkt(inm, report_type);
  449                 inm->inm_state = IGMP_DELAYING_MEMBER;
  450                 inm->inm_timer = IGMP_RANDOM_DELAY(
  451                     IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
  452                 igmp_timers_are_running = 1;
  453         } else
  454                 inm->inm_timer = 0;
  455         splx(s);
  456         return 0;
  457 }
  458 
  459 void
  460 igmp_leavegroup(struct in_multi *inm)
  461 {
  462 
  463         switch (inm->inm_state) {
  464         case IGMP_DELAYING_MEMBER:
  465         case IGMP_IDLE_MEMBER:
  466                 if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
  467                     (inm->inm_ifp->if_flags & IFF_LOOPBACK) == 0)
  468                         if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
  469                                 igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE);
  470                 break;
  471         case IGMP_LAZY_MEMBER:
  472         case IGMP_AWAKENING_MEMBER:
  473         case IGMP_SLEEPING_MEMBER:
  474                 break;
  475         }
  476 }
  477 
  478 void
  479 igmp_fasttimo(void)
  480 {
  481         struct in_multi *inm;
  482         struct in_multistep step;
  483 
  484         /*
  485          * Quick check to see if any work needs to be done, in order
  486          * to minimize the overhead of fasttimo processing.
  487          */
  488         if (!igmp_timers_are_running)
  489                 return;
  490 
  491         mutex_enter(softnet_lock);
  492         KERNEL_LOCK(1, NULL);
  493 
  494         igmp_timers_are_running = 0;
  495         IN_FIRST_MULTI(step, inm);
  496         while (inm != NULL) {
  497                 if (inm->inm_timer == 0) {
  498                         /* do nothing */
  499                 } else if (--inm->inm_timer == 0) {
  500                         if (inm->inm_state == IGMP_DELAYING_MEMBER) {
  501                                 if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
  502                                         igmp_sendpkt(inm,
  503                                             IGMP_v1_HOST_MEMBERSHIP_REPORT);
  504                                 else
  505                                         igmp_sendpkt(inm,
  506                                             IGMP_v2_HOST_MEMBERSHIP_REPORT);
  507                                 inm->inm_state = IGMP_IDLE_MEMBER;
  508                         }
  509                 } else {
  510                         igmp_timers_are_running = 1;
  511                 }
  512                 IN_NEXT_MULTI(step, inm);
  513         }
  514 
  515         KERNEL_UNLOCK_ONE(NULL);
  516         mutex_exit(softnet_lock);
  517 }
  518 
  519 void
  520 igmp_slowtimo(void)
  521 {
  522         struct router_info *rti;
  523 
  524         mutex_enter(softnet_lock);
  525         KERNEL_LOCK(1, NULL);
  526         LIST_FOREACH(rti, &rti_head, rti_link) {
  527                 if (rti->rti_type == IGMP_v1_ROUTER &&
  528                     ++rti->rti_age >= IGMP_AGE_THRESHOLD) {
  529                         rti->rti_type = IGMP_v2_ROUTER;
  530                 }
  531         }
  532         KERNEL_UNLOCK_ONE(NULL);
  533         mutex_exit(softnet_lock);
  534 }
  535 
  536 void
  537 igmp_sendpkt(struct in_multi *inm, int type)
  538 {
  539         struct mbuf *m;
  540         struct igmp *igmp;
  541         struct ip *ip;
  542         struct ip_moptions imo;
  543 #ifdef MROUTING
  544         extern struct socket *ip_mrouter;
  545 #endif /* MROUTING */
  546 
  547         MGETHDR(m, M_DONTWAIT, MT_HEADER);
  548         if (m == NULL)
  549                 return;
  550         /*
  551          * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
  552          * is smaller than mbuf size returned by MGETHDR.
  553          */
  554         m->m_data += max_linkhdr;
  555         m->m_len = sizeof(struct ip) + IGMP_MINLEN;
  556         m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
  557 
  558         ip = mtod(m, struct ip *);
  559         ip->ip_tos = 0;
  560         ip->ip_len = htons(sizeof(struct ip) + IGMP_MINLEN);
  561         ip->ip_off = htons(0);
  562         ip->ip_p = IPPROTO_IGMP;
  563         ip->ip_src = zeroin_addr;
  564         ip->ip_dst = inm->inm_addr;
  565 
  566         m->m_data += sizeof(struct ip);
  567         m->m_len -= sizeof(struct ip);
  568         igmp = mtod(m, struct igmp *);
  569         igmp->igmp_type = type;
  570         igmp->igmp_code = 0;
  571         igmp->igmp_group = inm->inm_addr;
  572         igmp->igmp_cksum = 0;
  573         igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
  574         m->m_data -= sizeof(struct ip);
  575         m->m_len += sizeof(struct ip);
  576 
  577         imo.imo_multicast_ifp = inm->inm_ifp;
  578         imo.imo_multicast_ttl = 1;
  579 #ifdef RSVP_ISI
  580         imo.imo_multicast_vif = -1;
  581 #endif
  582         /*
  583          * Request loopback of the report if we are acting as a multicast
  584          * router, so that the process-level routing demon can hear it.
  585          */
  586 #ifdef MROUTING
  587         imo.imo_multicast_loop = (ip_mrouter != NULL);
  588 #else
  589         imo.imo_multicast_loop = 0;
  590 #endif /* MROUTING */
  591 
  592         ip_output(m, NULL, NULL, IP_MULTICASTOPTS, &imo, NULL);
  593 
  594         IGMP_STATINC(IGMP_STAT_SND_REPORTS);
  595 }
  596 
  597 void
  598 igmp_purgeif(struct ifnet *ifp) /* MUST be called at splsoftnet() */
  599 {
  600         rti_delete(ifp);        /* manipulates pools */
  601 }
  602 
  603 static int
  604 sysctl_net_inet_igmp_stats(SYSCTLFN_ARGS)
  605 {
  606 
  607         return (NETSTAT_SYSCTL(igmpstat_percpu, IGMP_NSTATS));
  608 }
  609 
  610 SYSCTL_SETUP(sysctl_net_inet_igmp_setup, "sysctl net.inet.igmp subtree setup")
  611 {
  612 
  613         sysctl_createv(clog, 0, NULL, NULL,
  614                         CTLFLAG_PERMANENT,
  615                         CTLTYPE_NODE, "net", NULL,
  616                         NULL, 0, NULL, 0,
  617                         CTL_NET, CTL_EOL);
  618         sysctl_createv(clog, 0, NULL, NULL,
  619                         CTLFLAG_PERMANENT,
  620                         CTLTYPE_NODE, "inet", NULL,
  621                         NULL, 0, NULL, 0,
  622                         CTL_NET, PF_INET, CTL_EOL);
  623         sysctl_createv(clog, 0, NULL, NULL,
  624                         CTLFLAG_PERMANENT,
  625                         CTLTYPE_NODE, "igmp",
  626                         SYSCTL_DESCR("Internet Group Management Protocol"),
  627                         NULL, 0, NULL, 0,
  628                         CTL_NET, PF_INET, IPPROTO_IGMP, CTL_EOL);
  629         
  630         sysctl_createv(clog, 0, NULL, NULL,
  631                         CTLFLAG_PERMANENT,
  632                         CTLTYPE_STRUCT, "stats",
  633                         SYSCTL_DESCR("IGMP statistics"),
  634                         sysctl_net_inet_igmp_stats, 0, NULL, 0,
  635                         CTL_NET, PF_INET, IPPROTO_IGMP, CTL_CREATE, CTL_EOL);
  636 }

Cache object: cff6f9d2e49cf62ff6272449e30073a5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.