LCOV - code coverage report
Current view: top level - netinet6 - mld6.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 164 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: mld6.c,v 1.55 2017/10/29 14:56:36 florian Exp $       */
       2             : /*      $KAME: mld6.c,v 1.26 2001/02/16 14:50:35 itojun Exp $   */
       3             : 
       4             : /*
       5             :  * Copyright (C) 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.1 (Berkeley) 7/19/93
      66             :  */
      67             : 
      68             : #include <sys/param.h>
      69             : #include <sys/systm.h>
      70             : #include <sys/mbuf.h>
      71             : #include <sys/socket.h>
      72             : #include <sys/protosw.h>
      73             : #include <sys/syslog.h>
      74             : 
      75             : #include <net/if.h>
      76             : #include <net/if_var.h>
      77             : 
      78             : #include <netinet/in.h>
      79             : #include <netinet6/in6_var.h>
      80             : #include <netinet/ip6.h>
      81             : #include <netinet6/ip6_var.h>
      82             : #include <netinet/icmp6.h>
      83             : #include <netinet6/mld6.h>
      84             : #include <netinet6/mld6_var.h>
      85             : 
      86             : static struct ip6_pktopts ip6_opts;
      87             : static int mld_timers_are_running;
      88             : /* XXX: These are necessary for KAME's link-local hack */
      89             : static struct in6_addr mld_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
      90             : static struct in6_addr mld_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
      91             : 
      92             : void mld6_checktimer(struct ifnet *);
      93             : static void mld6_sendpkt(struct in6_multi *, int, const struct in6_addr *);
      94             : 
      95             : void
      96           0 : mld6_init(void)
      97             : {
      98             :         static u_int8_t hbh_buf[8];
      99             :         struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf;
     100             :         u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD);
     101             : 
     102           0 :         mld_timers_are_running = 0;
     103             : 
     104             :         /* ip6h_nxt will be fill in later */
     105           0 :         hbh->ip6h_len = 0;   /* (8 >> 3) - 1 */
     106             : 
     107             :         /* XXX: grotty hard coding... */
     108           0 :         hbh_buf[2] = IP6OPT_PADN;       /* 2 byte padding */
     109           0 :         hbh_buf[3] = 0;
     110           0 :         hbh_buf[4] = IP6OPT_ROUTER_ALERT;
     111           0 :         hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
     112           0 :         memcpy(&hbh_buf[6], (caddr_t)&rtalert_code, sizeof(u_int16_t));
     113             : 
     114           0 :         ip6_initpktopts(&ip6_opts);
     115           0 :         ip6_opts.ip6po_hbh = hbh;
     116           0 : }
     117             : 
     118             : void
     119           0 : mld6_start_listening(struct in6_multi *in6m)
     120             : {
     121             :         /*
     122             :          * RFC2710 page 10:
     123             :          * The node never sends a Report or Done for the link-scope all-nodes
     124             :          * address.
     125             :          * MLD messages are never sent for multicast addresses whose scope is 0
     126             :          * (reserved) or 1 (node-local).
     127             :          */
     128           0 :         mld_all_nodes_linklocal.s6_addr16[1] = htons(in6m->in6m_ifidx);/* XXX */
     129           0 :         if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal) ||
     130           0 :             __IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < __IPV6_ADDR_SCOPE_LINKLOCAL) {
     131           0 :                 in6m->in6m_timer = 0;
     132           0 :                 in6m->in6m_state = MLD_OTHERLISTENER;
     133           0 :         } else {
     134           0 :                 mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
     135           0 :                 in6m->in6m_timer =
     136           0 :                     MLD_RANDOM_DELAY(MLD_V1_MAX_RI *
     137             :                     PR_FASTHZ);
     138           0 :                 in6m->in6m_state = MLD_IREPORTEDLAST;
     139           0 :                 mld_timers_are_running = 1;
     140             :         }
     141           0 : }
     142             : 
     143             : void
     144           0 : mld6_stop_listening(struct in6_multi *in6m)
     145             : {
     146           0 :         mld_all_nodes_linklocal.s6_addr16[1] = htons(in6m->in6m_ifidx);/* XXX */
     147           0 :         mld_all_routers_linklocal.s6_addr16[1] =
     148           0 :             htons(in6m->in6m_ifidx); /* XXX: necessary when mrouting */
     149             : 
     150           0 :         if (in6m->in6m_state == MLD_IREPORTEDLAST &&
     151           0 :             (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal)) &&
     152           0 :             __IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > __IPV6_ADDR_SCOPE_INTFACELOCAL)
     153           0 :                 mld6_sendpkt(in6m, MLD_LISTENER_DONE,
     154             :                     &mld_all_routers_linklocal);
     155           0 : }
     156             : 
     157             : void
     158           0 : mld6_input(struct mbuf *m, int off)
     159             : {
     160             :         struct ip6_hdr *ip6;
     161             :         struct mld_hdr *mldh;
     162             :         struct ifnet *ifp;
     163             :         struct in6_multi *in6m;
     164             :         struct ifmaddr *ifma;
     165             :         int timer;              /* timer value in the MLD query header */
     166             : 
     167           0 :         IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
     168           0 :         if (mldh == NULL) {
     169           0 :                 icmp6stat_inc(icp6s_tooshort);
     170           0 :                 return;
     171             :         }
     172             : 
     173             :         /* source address validation */
     174           0 :         ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */
     175           0 :         if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
     176             : #if 0
     177             :                 char src[INET6_ADDRSTRLEN], grp[INET6_ADDRSTRLEN];
     178             : 
     179             :                 log(LOG_ERR,
     180             :                     "mld_input: src %s is not link-local (grp=%s)\n",
     181             :                     inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src)),
     182             :                     inet_ntop(AF_INET6, &mldh->mld_addr, grp, sizeof(grp)));
     183             : #endif
     184             :                 /*
     185             :                  * spec (RFC2710) does not explicitly
     186             :                  * specify to discard the packet from a non link-local
     187             :                  * source address. But we believe it's expected to do so.
     188             :                  */
     189           0 :                 m_freem(m);
     190           0 :                 return;
     191             :         }
     192             : 
     193           0 :         ifp = if_get(m->m_pkthdr.ph_ifidx);
     194           0 :         if (ifp == NULL) {
     195           0 :                 m_freem(m);
     196           0 :                 return;
     197             :         }
     198             : 
     199             :         /*
     200             :          * In the MLD6 specification, there are 3 states and a flag.
     201             :          *
     202             :          * In Non-Listener state, we simply don't have a membership record.
     203             :          * In Delaying Listener state, our timer is running (in6m->in6m_timer)
     204             :          * In Idle Listener state, our timer is not running (in6m->in6m_timer==0)
     205             :          *
     206             :          * The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if
     207             :          * we have heard a report from another member, or MLD_IREPORTEDLAST
     208             :          * if we sent the last report.
     209             :          */
     210           0 :         switch(mldh->mld_type) {
     211             :         case MLD_LISTENER_QUERY:
     212           0 :                 if (ifp->if_flags & IFF_LOOPBACK)
     213             :                         break;
     214             : 
     215           0 :                 if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) &&
     216           0 :                     !IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
     217             :                         break;  /* print error or log stat? */
     218           0 :                 if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
     219           0 :                         mldh->mld_addr.s6_addr16[1] =
     220           0 :                             htons(ifp->if_index); /* XXX */
     221             : 
     222             :                 /*
     223             :                  * - Start the timers in all of our membership records
     224             :                  *   that the query applies to for the interface on
     225             :                  *   which the query arrived excl. those that belong
     226             :                  *   to the "all-nodes" group (ff02::1).
     227             :                  * - Restart any timer that is already running but has
     228             :                  *   A value longer than the requested timeout.
     229             :                  * - Use the value specified in the query message as
     230             :                  *   the maximum timeout.
     231             :                  */
     232             : 
     233             :                 /*
     234             :                  * XXX: System timer resolution is too low to handle Max
     235             :                  * Response Delay, so set 1 to the internal timer even if
     236             :                  * the calculated value equals to zero when Max Response
     237             :                  * Delay is positive.
     238             :                  */
     239           0 :                 timer = ntohs(mldh->mld_maxdelay)*PR_FASTHZ/MLD_TIMER_SCALE;
     240           0 :                 if (timer == 0 && mldh->mld_maxdelay)
     241           0 :                         timer = 1;
     242           0 :                 mld_all_nodes_linklocal.s6_addr16[1] =
     243           0 :                         htons(ifp->if_index); /* XXX */
     244             : 
     245           0 :                 TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
     246           0 :                         if (ifma->ifma_addr->sa_family != AF_INET6)
     247             :                                 continue;
     248           0 :                         in6m = ifmatoin6m(ifma);
     249           0 :                         if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr,
     250           0 :                                                 &mld_all_nodes_linklocal) ||
     251           0 :                             __IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
     252             :                             __IPV6_ADDR_SCOPE_LINKLOCAL)
     253             :                                 continue;
     254             : 
     255           0 :                         if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) ||
     256           0 :                             IN6_ARE_ADDR_EQUAL(&mldh->mld_addr,
     257             :                                                 &in6m->in6m_addr))
     258             :                         {
     259           0 :                                 if (timer == 0) {
     260             :                                         /* send a report immediately */
     261           0 :                                         mld6_sendpkt(in6m, MLD_LISTENER_REPORT,
     262             :                                             NULL);
     263           0 :                                         in6m->in6m_timer = 0; /* reset timer */
     264           0 :                                         in6m->in6m_state = MLD_IREPORTEDLAST;
     265           0 :                                 } else if (in6m->in6m_timer == 0 || /* idle */
     266           0 :                                         in6m->in6m_timer > timer) {
     267           0 :                                         in6m->in6m_timer =
     268           0 :                                             MLD_RANDOM_DELAY(timer);
     269           0 :                                         mld_timers_are_running = 1;
     270           0 :                                 }
     271             :                         }
     272             :                 }
     273             : 
     274           0 :                 if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
     275           0 :                         mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
     276             :                 break;
     277             :         case MLD_LISTENER_REPORT:
     278             :                 /*
     279             :                  * For fast leave to work, we have to know that we are the
     280             :                  * last person to send a report for this group.  Reports
     281             :                  * can potentially get looped back if we are a multicast
     282             :                  * router, so discard reports sourced by me.
     283             :                  * Note that it is impossible to check IFF_LOOPBACK flag of
     284             :                  * ifp for this purpose, since ip6_mloopback pass the physical
     285             :                  * interface to if_input_local().
     286             :                  */
     287           0 :                 if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
     288             :                         break;
     289             : 
     290           0 :                 if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
     291             :                         break;
     292             : 
     293           0 :                 if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
     294           0 :                         mldh->mld_addr.s6_addr16[1] =
     295           0 :                                 htons(ifp->if_index); /* XXX */
     296             :                 /*
     297             :                  * If we belong to the group being reported, stop
     298             :                  * our timer for that group.
     299             :                  */
     300           0 :                 IN6_LOOKUP_MULTI(mldh->mld_addr, ifp, in6m);
     301           0 :                 if (in6m) {
     302           0 :                         in6m->in6m_timer = 0; /* transit to idle state */
     303           0 :                         in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */
     304           0 :                 }
     305             : 
     306           0 :                 if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
     307           0 :                         mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
     308             :                 break;
     309             :         default:                /* this is impossible */
     310             : #if 0
     311             :                 /*
     312             :                  * this case should be impossible because of filtering in
     313             :                  * icmp6_input().  But we explicitly disabled this part
     314             :                  * just in case.
     315             :                  */
     316             :                 log(LOG_ERR, "mld_input: illegal type(%d)", mldh->mld_type);
     317             : #endif
     318             :                 break;
     319             :         }
     320           0 :         if_put(ifp);
     321             : 
     322           0 :         m_freem(m);
     323           0 : }
     324             : 
     325             : void
     326           0 : mld6_fasttimeo(void)
     327             : {
     328             :         struct ifnet *ifp;
     329             : 
     330           0 :         NET_LOCK();
     331             : 
     332             :         /*
     333             :          * Quick check to see if any work needs to be done, in order
     334             :          * to minimize the overhead of fasttimo processing.
     335             :          */
     336           0 :         if (!mld_timers_are_running)
     337             :                 goto out;
     338             : 
     339           0 :         mld_timers_are_running = 0;
     340           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list)
     341           0 :                 mld6_checktimer(ifp);
     342             : 
     343             : out:
     344           0 :         NET_UNLOCK();
     345           0 : }
     346             : 
     347             : void
     348           0 : mld6_checktimer(struct ifnet *ifp)
     349             : {
     350             :         struct in6_multi *in6m;
     351             :         struct ifmaddr *ifma;
     352             : 
     353           0 :         NET_ASSERT_LOCKED();
     354             : 
     355           0 :         TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
     356           0 :                 if (ifma->ifma_addr->sa_family != AF_INET6)
     357             :                         continue;
     358           0 :                 in6m = ifmatoin6m(ifma);
     359           0 :                 if (in6m->in6m_timer == 0) {
     360             :                         /* do nothing */
     361           0 :                 } else if (--in6m->in6m_timer == 0) {
     362           0 :                         mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
     363           0 :                         in6m->in6m_state = MLD_IREPORTEDLAST;
     364           0 :                 } else {
     365           0 :                         mld_timers_are_running = 1;
     366             :                 }
     367             :         }
     368           0 : }
     369             : 
     370             : static void
     371           0 : mld6_sendpkt(struct in6_multi *in6m, int type, const struct in6_addr *dst)
     372             : {
     373             :         struct mbuf *mh, *md;
     374             :         struct mld_hdr *mldh;
     375             :         struct ip6_hdr *ip6;
     376           0 :         struct ip6_moptions im6o;
     377             :         struct in6_ifaddr *ia6;
     378             :         struct ifnet *ifp;
     379             :         int ignflags;
     380             : 
     381           0 :         ifp = if_get(in6m->in6m_ifidx);
     382           0 :         if (ifp == NULL)
     383           0 :                 return;
     384             : 
     385             :         /*
     386             :          * At first, find a link local address on the outgoing interface
     387             :          * to use as the source address of the MLD packet.
     388             :          * We do not reject tentative addresses for MLD report to deal with
     389             :          * the case where we first join a link-local address.
     390             :          */
     391             :         ignflags = IN6_IFF_DUPLICATED|IN6_IFF_ANYCAST;
     392           0 :         if ((ia6 = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL) {
     393           0 :                 if_put(ifp);
     394           0 :                 return;
     395             :         }
     396           0 :         if ((ia6->ia6_flags & IN6_IFF_TENTATIVE))
     397           0 :                 ia6 = NULL;
     398             : 
     399             :         /*
     400             :          * Allocate mbufs to store ip6 header and MLD header.
     401             :          * We allocate 2 mbufs and make chain in advance because
     402             :          * it is more convenient when inserting the hop-by-hop option later.
     403             :          */
     404           0 :         MGETHDR(mh, M_DONTWAIT, MT_HEADER);
     405           0 :         if (mh == NULL) {
     406           0 :                 if_put(ifp);
     407           0 :                 return;
     408             :         }
     409           0 :         MGET(md, M_DONTWAIT, MT_DATA);
     410           0 :         if (md == NULL) {
     411           0 :                 m_free(mh);
     412           0 :                 if_put(ifp);
     413           0 :                 return;
     414             :         }
     415           0 :         mh->m_next = md;
     416             : 
     417           0 :         mh->m_pkthdr.ph_ifidx = 0;
     418           0 :         mh->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     419           0 :         mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr);
     420           0 :         mh->m_len = sizeof(struct ip6_hdr);
     421           0 :         MH_ALIGN(mh, sizeof(struct ip6_hdr));
     422             : 
     423             :         /* fill in the ip6 header */
     424           0 :         ip6 = mtod(mh, struct ip6_hdr *);
     425           0 :         ip6->ip6_flow = 0;
     426           0 :         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
     427           0 :         ip6->ip6_vfc |= IPV6_VERSION;
     428             :         /* ip6_plen will be set later */
     429           0 :         ip6->ip6_nxt = IPPROTO_ICMPV6;
     430             :         /* ip6_hlim will be set by im6o.im6o_hlim */
     431           0 :         ip6->ip6_src = ia6 ? ia6->ia_addr.sin6_addr : in6addr_any;
     432           0 :         ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
     433             : 
     434             :         /* fill in the MLD header */
     435           0 :         md->m_len = sizeof(struct mld_hdr);
     436           0 :         mldh = mtod(md, struct mld_hdr *);
     437           0 :         mldh->mld_type = type;
     438           0 :         mldh->mld_code = 0;
     439           0 :         mldh->mld_cksum = 0;
     440             :         /* XXX: we assume the function will not be called for query messages */
     441           0 :         mldh->mld_maxdelay = 0;
     442           0 :         mldh->mld_reserved = 0;
     443           0 :         mldh->mld_addr = in6m->in6m_addr;
     444           0 :         if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
     445           0 :                 mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
     446           0 :         mh->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
     447             : 
     448             :         /* construct multicast option */
     449           0 :         bzero(&im6o, sizeof(im6o));
     450           0 :         im6o.im6o_ifidx = ifp->if_index;
     451           0 :         im6o.im6o_hlim = 1;
     452             : 
     453             :         /*
     454             :          * Request loopback of the report if we are acting as a multicast
     455             :          * router, so that the process-level routing daemon can hear it.
     456             :          */
     457             : #ifdef MROUTING
     458           0 :         im6o.im6o_loop = (ip6_mrouter[ifp->if_rdomain] != NULL);
     459             : #endif
     460           0 :         if_put(ifp);
     461             : 
     462           0 :         icmp6stat_inc(icp6s_outhist + type);
     463           0 :         ip6_output(mh, &ip6_opts, NULL, ia6 ? 0 : IPV6_UNSPECSRC, &im6o,
     464             :             NULL);
     465           0 : }

Generated by: LCOV version 1.13