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

          Line data    Source code
       1             : /*      $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $   */
       2             : /*      $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 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             : /*      BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp     */
      34             : 
      35             : /*
      36             :  * Copyright (c) 1989 Stephen Deering
      37             :  * Copyright (c) 1992, 1993
      38             :  *      The Regents of the University of California.  All rights reserved.
      39             :  *
      40             :  * This code is derived from software contributed to Berkeley by
      41             :  * Stephen Deering of Stanford University.
      42             :  *
      43             :  * Redistribution and use in source and binary forms, with or without
      44             :  * modification, are permitted provided that the following conditions
      45             :  * are met:
      46             :  * 1. Redistributions of source code must retain the above copyright
      47             :  *    notice, this list of conditions and the following disclaimer.
      48             :  * 2. Redistributions in binary form must reproduce the above copyright
      49             :  *    notice, this list of conditions and the following disclaimer in the
      50             :  *    documentation and/or other materials provided with the distribution.
      51             :  * 3. Neither the name of the University nor the names of its contributors
      52             :  *    may be used to endorse or promote products derived from this software
      53             :  *    without specific prior written permission.
      54             :  *
      55             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      56             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      57             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      58             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      59             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      60             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      61             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      62             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      63             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      64             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      65             :  * SUCH DAMAGE.
      66             :  *
      67             :  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
      68             :  */
      69             : 
      70             : /*
      71             :  * IP multicast forwarding procedures
      72             :  *
      73             :  * Written by David Waitzman, BBN Labs, August 1988.
      74             :  * Modified by Steve Deering, Stanford, February 1989.
      75             :  * Modified by Mark J. Steiglitz, Stanford, May, 1991
      76             :  * Modified by Van Jacobson, LBL, January 1993
      77             :  * Modified by Ajit Thyagarajan, PARC, August 1993
      78             :  * Modified by Bill Fenner, PARC, April 1994
      79             :  *
      80             :  * MROUTING Revision: 3.5.1.2
      81             :  */
      82             : 
      83             : #include <sys/param.h>
      84             : #include <sys/malloc.h>
      85             : #include <sys/systm.h>
      86             : #include <sys/timeout.h>
      87             : #include <sys/mbuf.h>
      88             : #include <sys/socket.h>
      89             : #include <sys/socketvar.h>
      90             : #include <sys/protosw.h>
      91             : #include <sys/kernel.h>
      92             : #include <sys/ioctl.h>
      93             : #include <sys/syslog.h>
      94             : #include <sys/sysctl.h>
      95             : 
      96             : #include <net/if.h>
      97             : #include <net/if_var.h>
      98             : #include <net/route.h>
      99             : 
     100             : #include <netinet/in.h>
     101             : #include <netinet6/in6_var.h>
     102             : #include <netinet/ip.h>
     103             : #include <netinet/ip6.h>
     104             : #include <netinet/icmp6.h>
     105             : #include <netinet6/ip6_var.h>
     106             : #include <netinet6/ip6_mroute.h>
     107             : #include <netinet/in_pcb.h>
     108             : 
     109             : /* #define MCAST_DEBUG */
     110             : 
     111             : #ifdef MCAST_DEBUG
     112             : int mcast6_debug = 1;
     113             : #define DPRINTF(fmt, args...)                                           \
     114             :         do {                                                            \
     115             :                 if (mcast6_debug)                                       \
     116             :                         printf("%s:%d " fmt "\n",                   \
     117             :                             __func__, __LINE__, ## args);               \
     118             :         } while (0)
     119             : #else
     120             : #define DPRINTF(fmt, args...)                   \
     121             :         do { } while (0)
     122             : #endif
     123             : 
     124             : int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
     125             : void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *);
     126             : 
     127             : /*
     128             :  * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
     129             :  * except for netstat or debugging purposes.
     130             :  */
     131             : struct socket  *ip6_mrouter[RT_TABLEID_MAX];
     132             : struct rttimer_queue *mrouter6q[RT_TABLEID_MAX];
     133             : int             ip6_mrouter_ver = 0;
     134             : int             ip6_mrtproto;    /* for netstat only */
     135             : struct mrt6stat mrt6stat;
     136             : 
     137             : #define NO_RTE_FOUND    0x1
     138             : #define RTE_FOUND       0x2
     139             : 
     140             : #define         MCAST_EXPIRE_TIMEOUT 30         /* seconds */
     141             : 
     142             : /*
     143             :  * Macros to compute elapsed time efficiently
     144             :  * Borrowed from Van Jacobson's scheduling code
     145             :  */
     146             : #define TV_DELTA(a, b, delta) do { \
     147             :             int xxs; \
     148             :                 \
     149             :             delta = (a).tv_usec - (b).tv_usec; \
     150             :             if ((xxs = (a).tv_sec - (b).tv_sec)) { \
     151             :                switch (xxs) { \
     152             :                       case 2: \
     153             :                           delta += 1000000; \
     154             :                               /* FALLTHROUGH */ \
     155             :                       case 1: \
     156             :                           delta += 1000000; \
     157             :                           break; \
     158             :                       default: \
     159             :                           delta += (1000000 * xxs); \
     160             :                } \
     161             :             } \
     162             : } while (0)
     163             : 
     164             : #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
     165             :               (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
     166             : 
     167             : int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int);
     168             : int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int);
     169             : int ip6_mrouter_init(struct socket *, int, int);
     170             : int add_m6if(struct socket *, struct mif6ctl *);
     171             : int del_m6if(struct socket *, mifi_t *);
     172             : int add_m6fc(struct socket *, struct mf6cctl *);
     173             : int del_m6fc(struct socket *, struct mf6cctl *);
     174             : struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int);
     175             : struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *,
     176             :     struct in6_addr *, unsigned int);
     177             : struct rtentry *mrt6_mcast6_add(struct ifnet *, struct sockaddr *,
     178             :     struct sockaddr *);
     179             : int mrt6_mcast6_del(struct rtentry *, unsigned int);
     180             : void mf6c_expire_route(struct rtentry *, struct rttimer *);
     181             : 
     182             : /*
     183             :  * Handle MRT setsockopt commands to modify the multicast routing tables.
     184             :  */
     185             : int
     186           0 : ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m)
     187             : {
     188           0 :         struct inpcb    *inp = sotoinpcb(so);
     189             : 
     190           0 :         if (cmd != MRT6_INIT && so != ip6_mrouter[inp->inp_rtableid])
     191           0 :                 return (EPERM);
     192             : 
     193           0 :         switch (cmd) {
     194             :         case MRT6_INIT:
     195           0 :                 if (m == NULL || m->m_len < sizeof(int))
     196           0 :                         return (EINVAL);
     197           0 :                 return (ip6_mrouter_init(so, *mtod(m, int *), cmd));
     198             :         case MRT6_DONE:
     199           0 :                 return (ip6_mrouter_done(so));
     200             :         case MRT6_ADD_MIF:
     201           0 :                 if (m == NULL || m->m_len < sizeof(struct mif6ctl))
     202           0 :                         return (EINVAL);
     203           0 :                 return (add_m6if(so, mtod(m, struct mif6ctl *)));
     204             :         case MRT6_DEL_MIF:
     205           0 :                 if (m == NULL || m->m_len < sizeof(mifi_t))
     206           0 :                         return (EINVAL);
     207           0 :                 return (del_m6if(so, mtod(m, mifi_t *)));
     208             :         case MRT6_ADD_MFC:
     209           0 :                 if (m == NULL || m->m_len < sizeof(struct mf6cctl))
     210           0 :                         return (EINVAL);
     211           0 :                 return (add_m6fc(so, mtod(m, struct mf6cctl *)));
     212             :         case MRT6_DEL_MFC:
     213           0 :                 if (m == NULL || m->m_len < sizeof(struct mf6cctl))
     214           0 :                         return (EINVAL);
     215           0 :                 return (del_m6fc(so, mtod(m,  struct mf6cctl *)));
     216             :         default:
     217           0 :                 return (EOPNOTSUPP);
     218             :         }
     219           0 : }
     220             : 
     221             : /*
     222             :  * Handle MRT getsockopt commands
     223             :  */
     224             : int
     225           0 : ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m)
     226             : {
     227           0 :         struct inpcb    *inp = sotoinpcb(so);
     228             : 
     229           0 :         if (so != ip6_mrouter[inp->inp_rtableid])
     230           0 :                 return (EPERM);
     231             : 
     232             :         switch (cmd) {
     233             :         default:
     234           0 :                 return EOPNOTSUPP;
     235             :         }
     236           0 : }
     237             : 
     238             : /*
     239             :  * Handle ioctl commands to obtain information from the cache
     240             :  */
     241             : int
     242           0 : mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data)
     243             : {
     244           0 :         struct inpcb *inp = sotoinpcb(so);
     245             :         int error;
     246             : 
     247           0 :         switch (cmd) {
     248             :         case SIOCGETSGCNT_IN6:
     249           0 :                 NET_RLOCK();
     250           0 :                 error = get_sg6_cnt((struct sioc_sg_req6 *)data,
     251           0 :                     inp->inp_rtableid);
     252           0 :                 NET_RUNLOCK();
     253           0 :                 break;
     254             :         case SIOCGETMIFCNT_IN6:
     255           0 :                 NET_RLOCK();
     256           0 :                 error = get_mif6_cnt((struct sioc_mif_req6 *)data,
     257           0 :                     inp->inp_rtableid);
     258           0 :                 NET_RUNLOCK();
     259           0 :                 break;
     260             :         default:
     261             :                 error = ENOTTY;
     262           0 :                 break;
     263             :         }
     264           0 :         return error;
     265             : }
     266             : 
     267             : /*
     268             :  * returns the packet, byte, rpf-failure count for the source group provided
     269             :  */
     270             : int
     271           0 : get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid)
     272             : {
     273             :         struct rtentry *rt;
     274             :         struct mf6c *mf6c;
     275             : 
     276           0 :         rt = mf6c_find(NULL, &req->src.sin6_addr, &req->grp.sin6_addr,
     277             :             rtableid);
     278           0 :         if (rt == NULL) {
     279           0 :                 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
     280           0 :                 return EADDRNOTAVAIL;
     281             :         }
     282             : 
     283           0 :         req->pktcnt = req->bytecnt = req->wrong_if = 0;
     284           0 :         do {
     285           0 :                 mf6c = (struct mf6c *)rt->rt_llinfo;
     286           0 :                 if (mf6c == NULL)
     287             :                         continue;
     288             : 
     289           0 :                 req->pktcnt += mf6c->mf6c_pkt_cnt;
     290           0 :                 req->bytecnt += mf6c->mf6c_byte_cnt;
     291           0 :                 req->wrong_if += mf6c->mf6c_wrong_if;
     292           0 :         } while ((rt = rtable_iterate(rt)) != NULL);
     293             : 
     294           0 :         return 0;
     295           0 : }
     296             : 
     297             : /*
     298             :  * returns the input and output packet and byte counts on the mif provided
     299             :  */
     300             : int
     301           0 : get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid)
     302             : {
     303             :         struct ifnet *ifp;
     304             :         struct mif6 *m6;
     305             : 
     306           0 :         if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL)
     307           0 :                 return EINVAL;
     308             : 
     309           0 :         m6 = (struct mif6 *)ifp->if_mcast6;
     310           0 :         req->icount = m6->m6_pkt_in;
     311           0 :         req->ocount = m6->m6_pkt_out;
     312           0 :         req->ibytes = m6->m6_bytes_in;
     313           0 :         req->obytes = m6->m6_bytes_out;
     314             : 
     315           0 :         return 0;
     316           0 : }
     317             : 
     318             : int
     319           0 : mrt6_sysctl_mif(void *oldp, size_t *oldlenp)
     320             : {
     321             :         struct ifnet *ifp;
     322             :         caddr_t where = oldp;
     323             :         size_t needed, given;
     324             :         struct mif6 *mifp;
     325           0 :         struct mif6info minfo;
     326             : 
     327           0 :         given = *oldlenp;
     328             :         needed = 0;
     329           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
     330           0 :                 if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
     331             :                         continue;
     332             : 
     333           0 :                 minfo.m6_mifi = mifp->m6_mifi;
     334           0 :                 minfo.m6_flags = mifp->m6_flags;
     335           0 :                 minfo.m6_lcl_addr = mifp->m6_lcl_addr;
     336           0 :                 minfo.m6_ifindex = ifp->if_index;
     337           0 :                 minfo.m6_pkt_in = mifp->m6_pkt_in;
     338           0 :                 minfo.m6_pkt_out = mifp->m6_pkt_out;
     339           0 :                 minfo.m6_bytes_in = mifp->m6_bytes_in;
     340           0 :                 minfo.m6_bytes_out = mifp->m6_bytes_out;
     341           0 :                 minfo.m6_rate_limit = mifp->m6_rate_limit;
     342             : 
     343           0 :                 needed += sizeof(minfo);
     344           0 :                 if (where && needed <= given) {
     345             :                         int error;
     346             : 
     347           0 :                         error = copyout(&minfo, where, sizeof(minfo));
     348           0 :                         if (error)
     349           0 :                                 return (error);
     350           0 :                         where += sizeof(minfo);
     351           0 :                 }
     352             :         }
     353           0 :         if (where) {
     354           0 :                 *oldlenp = needed;
     355           0 :                 if (given < needed)
     356           0 :                         return (ENOMEM);
     357             :         } else
     358           0 :                 *oldlenp = (11 * needed) / 10;
     359             : 
     360           0 :         return (0);
     361           0 : }
     362             : 
     363             : struct mf6csysctlarg {
     364             :         struct mf6cinfo *ms6a_minfos;
     365             :         size_t           ms6a_len;
     366             :         size_t           ms6a_needed;
     367             : };
     368             : 
     369             : int
     370           0 : mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
     371             : {
     372           0 :         struct mf6c             *mf6c = (struct mf6c *)rt->rt_llinfo;
     373           0 :         struct mf6csysctlarg    *msa = arg;
     374             :         struct ifnet            *ifp;
     375             :         struct mif6             *m6;
     376             :         struct mf6cinfo         *minfo;
     377             :         int                      new = 0;
     378             : 
     379             :         /* Skip entries being removed. */
     380           0 :         if (mf6c == NULL)
     381           0 :                 return 0;
     382             : 
     383             :         /* Skip non-multicast routes. */
     384           0 :         if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
     385             :             (RTF_HOST | RTF_MULTICAST))
     386           0 :                 return 0;
     387             : 
     388             :         /* User just asked for the output size. */
     389           0 :         if (msa->ms6a_minfos == NULL) {
     390           0 :                 msa->ms6a_needed += sizeof(*minfo);
     391           0 :                 return 0;
     392             :         }
     393             : 
     394             :         /* Skip route with invalid interfaces. */
     395           0 :         if ((ifp = if_get(rt->rt_ifidx)) == NULL)
     396           0 :                 return 0;
     397           0 :         if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL) {
     398           0 :                 if_put(ifp);
     399           0 :                 return 0;
     400             :         }
     401             : 
     402           0 :         for (minfo = msa->ms6a_minfos;
     403           0 :              (uint8_t *)minfo < ((uint8_t *)msa->ms6a_minfos + msa->ms6a_len);
     404           0 :              minfo++) {
     405             :                 /* Find a new entry or update old entry. */
     406           0 :                 if (!IN6_ARE_ADDR_EQUAL(&minfo->mf6c_origin.sin6_addr,
     407           0 :                     &satosin6(rt->rt_gateway)->sin6_addr) ||
     408           0 :                     !IN6_ARE_ADDR_EQUAL(&minfo->mf6c_mcastgrp.sin6_addr,
     409             :                     &satosin6(rt_key(rt))->sin6_addr)) {
     410           0 :                         if (!IN6_IS_ADDR_UNSPECIFIED(
     411           0 :                             &minfo->mf6c_origin.sin6_addr) ||
     412           0 :                             !IN6_IS_ADDR_UNSPECIFIED(
     413             :                             &minfo->mf6c_mcastgrp.sin6_addr))
     414             :                                 continue;
     415             : 
     416             :                         new = 1;
     417           0 :                 }
     418             : 
     419           0 :                 minfo->mf6c_origin = *satosin6(rt->rt_gateway);
     420           0 :                 minfo->mf6c_mcastgrp = *satosin6(rt_key(rt));
     421           0 :                 minfo->mf6c_parent = mf6c->mf6c_parent;
     422           0 :                 minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt;
     423           0 :                 minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt;
     424           0 :                 IF_SET(m6->m6_mifi, &minfo->mf6c_ifset);
     425           0 :                 break;
     426             :         }
     427             : 
     428           0 :         if (new != 0)
     429           0 :                 msa->ms6a_needed += sizeof(*minfo);
     430             : 
     431           0 :         if_put(ifp);
     432             : 
     433           0 :         return 0;
     434           0 : }
     435             : 
     436             : int
     437           0 : mrt6_sysctl_mfc(void *oldp, size_t *oldlenp)
     438             : {
     439             :         unsigned int             rtableid;
     440             :         int                      error;
     441           0 :         struct mf6csysctlarg     msa;
     442             : 
     443           0 :         if (oldp != NULL && *oldlenp > MAXPHYS)
     444           0 :                 return EINVAL;
     445             : 
     446           0 :         if (oldp != NULL)
     447           0 :                 msa.ms6a_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
     448             :         else
     449           0 :                 msa.ms6a_minfos = NULL;
     450             : 
     451           0 :         msa.ms6a_len = *oldlenp;
     452           0 :         msa.ms6a_needed = 0;
     453             : 
     454           0 :         for (rtableid = 0; rtableid < RT_TABLEID_MAX; rtableid++)
     455           0 :                 rtable_walk(rtableid, AF_INET6, mrt6_rtwalk_mf6csysctl, &msa);
     456             : 
     457           0 :         if (msa.ms6a_minfos != NULL && msa.ms6a_needed > 0 &&
     458           0 :             (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) {
     459           0 :                 free(msa.ms6a_minfos, M_TEMP, *oldlenp);
     460           0 :                 return error;
     461             :         }
     462             : 
     463           0 :         free(msa.ms6a_minfos, M_TEMP, *oldlenp);
     464           0 :         *oldlenp = msa.ms6a_needed;
     465             : 
     466           0 :         return 0;
     467           0 : }
     468             : 
     469             : /*
     470             :  * Enable multicast routing
     471             :  */
     472             : int
     473           0 : ip6_mrouter_init(struct socket *so, int v, int cmd)
     474             : {
     475           0 :         struct inpcb *inp = sotoinpcb(so);
     476           0 :         unsigned int rtableid = inp->inp_rtableid;
     477             : 
     478           0 :         if (so->so_type != SOCK_RAW ||
     479           0 :             so->so_proto->pr_protocol != IPPROTO_ICMPV6)
     480           0 :                 return (EOPNOTSUPP);
     481             : 
     482           0 :         if (v != 1)
     483           0 :                 return (ENOPROTOOPT);
     484             : 
     485           0 :         if (ip6_mrouter[rtableid] != NULL)
     486           0 :                 return (EADDRINUSE);
     487             : 
     488           0 :         ip6_mrouter[rtableid] = so;
     489           0 :         ip6_mrouter_ver = cmd;
     490           0 :         mrouter6q[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_TIMEOUT);
     491             : 
     492           0 :         return (0);
     493           0 : }
     494             : 
     495             : int
     496           0 : mrouter6_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
     497             : {
     498             :         /* Skip non-multicast routes. */
     499           0 :         if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
     500             :             (RTF_HOST | RTF_MULTICAST))
     501           0 :                 return 0;
     502             : 
     503             :         /* Remove all timers related to this route. */
     504           0 :         rt_timer_remove_all(rt);
     505           0 :         mrt6_mcast6_del(rt, rtableid);
     506             : 
     507           0 :         return 0;
     508           0 : }
     509             : 
     510             : /*
     511             :  * Disable multicast routing
     512             :  */
     513             : int
     514           0 : ip6_mrouter_done(struct socket *so)
     515             : {
     516           0 :         struct inpcb *inp = sotoinpcb(so);
     517             :         struct ifnet *ifp;
     518           0 :         unsigned int rtableid = inp->inp_rtableid;
     519             : 
     520           0 :         NET_ASSERT_LOCKED();
     521             : 
     522             :         /* Delete all remaining installed multicast routes. */
     523           0 :         rtable_walk(rtableid, AF_INET6, mrouter6_rtwalk_delete, NULL);
     524             : 
     525             :         /* Unregister all interfaces in the domain. */
     526           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
     527           0 :                 if (ifp->if_rdomain != rtableid)
     528             :                         continue;
     529             : 
     530           0 :                 ip6_mrouter_detach(ifp);
     531           0 :         }
     532             : 
     533           0 :         rt_timer_queue_destroy(mrouter6q[rtableid]);
     534           0 :         ip6_mrouter[inp->inp_rtableid] = NULL;
     535           0 :         ip6_mrouter_ver = 0;
     536           0 :         mrouter6q[rtableid] = NULL;
     537             : 
     538           0 :         return 0;
     539             : }
     540             : 
     541             : void
     542           0 : ip6_mrouter_detach(struct ifnet *ifp)
     543             : {
     544           0 :         struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6;
     545           0 :         struct in6_ifreq ifr;
     546             : 
     547           0 :         if (m6 == NULL)
     548           0 :                 return;
     549             : 
     550           0 :         ifp->if_mcast6 = NULL;
     551             : 
     552           0 :         memset(&ifr, 0, sizeof(ifr));
     553           0 :         ifr.ifr_addr.sin6_family = AF_INET6;
     554           0 :         ifr.ifr_addr.sin6_addr = in6addr_any;
     555           0 :         (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
     556             : 
     557           0 :         free(m6, M_MRTABLE, sizeof(*m6));
     558           0 : }
     559             : 
     560             : /*
     561             :  * Add a mif to the mif table
     562             :  */
     563             : int
     564           0 : add_m6if(struct socket *so, struct mif6ctl *mifcp)
     565             : {
     566           0 :         struct inpcb *inp = sotoinpcb(so);
     567             :         struct mif6 *mifp;
     568             :         struct ifnet *ifp;
     569           0 :         struct in6_ifreq ifr;
     570             :         int error;
     571           0 :         unsigned int rtableid = inp->inp_rtableid;
     572             : 
     573           0 :         NET_ASSERT_LOCKED();
     574             : 
     575           0 :         if (mifcp->mif6c_mifi >= MAXMIFS)
     576           0 :                 return EINVAL;
     577             : 
     578           0 :         if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL)
     579           0 :                 return EADDRINUSE; /* XXX: is it appropriate? */
     580             : 
     581             :         {
     582           0 :                 ifp = if_get(mifcp->mif6c_pifi);
     583           0 :                 if (ifp == NULL)
     584           0 :                         return ENXIO;
     585             : 
     586             :                 /* Make sure the interface supports multicast */
     587           0 :                 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
     588           0 :                         if_put(ifp);
     589           0 :                         return EOPNOTSUPP;
     590             :                 }
     591             : 
     592             :                 /*
     593             :                  * Enable promiscuous reception of all IPv6 multicasts
     594             :                  * from the interface.
     595             :                  */
     596           0 :                 memset(&ifr, 0, sizeof(ifr));
     597           0 :                 ifr.ifr_addr.sin6_family = AF_INET6;
     598           0 :                 ifr.ifr_addr.sin6_addr = in6addr_any;
     599           0 :                 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
     600             : 
     601           0 :                 if (error) {
     602           0 :                         if_put(ifp);
     603           0 :                         return error;
     604             :                 }
     605             :         }
     606             : 
     607           0 :         mifp = malloc(sizeof(*mifp), M_MRTABLE, M_WAITOK | M_ZERO);
     608           0 :         ifp->if_mcast6          = (caddr_t)mifp;
     609           0 :         mifp->m6_mifi           = mifcp->mif6c_mifi;
     610           0 :         mifp->m6_flags     = mifcp->mif6c_flags;
     611             : #ifdef notyet
     612             :         /* scaling up here allows division by 1024 in critical code */
     613             :         mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
     614             : #endif
     615             : 
     616           0 :         if_put(ifp);
     617             : 
     618           0 :         return 0;
     619           0 : }
     620             : 
     621             : /*
     622             :  * Delete a mif from the mif table
     623             :  */
     624             : int
     625           0 : del_m6if(struct socket *so, mifi_t *mifip)
     626             : {
     627           0 :         struct inpcb *inp = sotoinpcb(so);
     628             :         struct ifnet *ifp;
     629             : 
     630           0 :         NET_ASSERT_LOCKED();
     631             : 
     632           0 :         if (*mifip >= MAXMIFS)
     633           0 :                 return EINVAL;
     634           0 :         if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL)
     635           0 :                 return EINVAL;
     636             : 
     637           0 :         ip6_mrouter_detach(ifp);
     638             : 
     639           0 :         return 0;
     640           0 : }
     641             : 
     642             : int
     643           0 : mf6c_add_route(struct ifnet *ifp, struct sockaddr *origin,
     644             :     struct sockaddr *group, struct mf6cctl *mf6cc, int wait)
     645             : {
     646             :         struct rtentry *rt;
     647             :         struct mf6c *mf6c;
     648           0 :         unsigned int rtableid = ifp->if_rdomain;
     649             : #ifdef MCAST_DEBUG
     650             :         char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
     651             : #endif /* MCAST_DEBUG */
     652             : 
     653           0 :         rt = mrt6_mcast6_add(ifp, origin, group);
     654           0 :         if (rt == NULL)
     655           0 :                 return ENOENT;
     656             : 
     657           0 :         mf6c = malloc(sizeof(*mf6c), M_MRTABLE, wait | M_ZERO);
     658           0 :         if (mf6c == NULL) {
     659             :                 DPRINTF("origin %s group %s parent %d (%s) malloc failed",
     660             :                     inet_ntop(AF_INET6, origin, bsrc, sizeof(bsrc)),
     661             :                     inet_ntop(AF_INET6, group, bdst, sizeof(bdst)),
     662             :                     mf6cc->mf6cc_parent, ifp->if_xname);
     663           0 :                 mrt6_mcast6_del(rt, rtableid);
     664           0 :                 return ENOMEM;
     665             :         }
     666             : 
     667           0 :         rt->rt_llinfo = (caddr_t)mf6c;
     668           0 :         rt_timer_add(rt, mf6c_expire_route, mrouter6q[rtableid], rtableid);
     669           0 :         mf6c->mf6c_parent = mf6cc->mf6cc_parent;
     670           0 :         rtfree(rt);
     671             : 
     672           0 :         return 0;
     673           0 : }
     674             : 
     675             : void
     676           0 : mf6c_update(struct mf6cctl *mf6cc, int wait, unsigned int rtableid)
     677             : {
     678             :         struct rtentry *rt;
     679             :         struct mf6c *mf6c;
     680             :         struct ifnet *ifp;
     681           0 :         struct sockaddr_in6 osin6, gsin6;
     682             :         mifi_t mifi;
     683             : #ifdef MCAST_DEBUG
     684             :         char bdst[INET6_ADDRSTRLEN];
     685             : #endif /* MCAST_DEBUG */
     686             : 
     687           0 :         memset(&osin6, 0, sizeof(osin6));
     688           0 :         osin6.sin6_family = AF_INET6;
     689           0 :         osin6.sin6_len = sizeof(osin6);
     690           0 :         osin6.sin6_addr = mf6cc->mf6cc_origin.sin6_addr;
     691             : 
     692           0 :         memset(&gsin6, 0, sizeof(gsin6));
     693           0 :         gsin6.sin6_family = AF_INET6;
     694           0 :         gsin6.sin6_len = sizeof(gsin6);
     695           0 :         gsin6.sin6_addr = mf6cc->mf6cc_mcastgrp.sin6_addr;
     696             : 
     697           0 :         for (mifi = 0; mifi < MAXMIFS; mifi++) {
     698           0 :                 if (mifi == mf6cc->mf6cc_parent)
     699             :                         continue;
     700             : 
     701             :                 /* Test for mif existence and then update the entry. */
     702           0 :                 if ((ifp = mrt6_iflookupbymif(mifi, rtableid)) == NULL)
     703             :                         continue;
     704             : 
     705           0 :                 rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
     706             :                     &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid);
     707             : 
     708             :                 /* mif not configured or removed. */
     709           0 :                 if (!IF_ISSET(mifi, &mf6cc->mf6cc_ifset)) {
     710             :                         /* Route doesn't exist, nothing to do. */
     711           0 :                         if (rt == NULL)
     712             :                                 continue;
     713             : 
     714             :                         DPRINTF("del route (group %s) for mif %d (%s)",
     715             :                             inet_ntop(AF_INET6,
     716             :                             &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
     717             :                             sizeof(bdst)), mifi, ifp->if_xname);
     718             : 
     719           0 :                         rt_timer_remove_all(rt);
     720           0 :                         mrt6_mcast6_del(rt, rtableid);
     721           0 :                         continue;
     722             :                 }
     723             : 
     724             :                 /* Route exists, look for changes. */
     725           0 :                 if (rt != NULL) {
     726           0 :                         mf6c = (struct mf6c *)rt->rt_llinfo;
     727             :                         /* Skip route being deleted. */
     728           0 :                         if (mf6c == NULL) {
     729           0 :                                 rtfree(rt);
     730           0 :                                 continue;
     731             :                         }
     732             : 
     733             :                         /* No new changes to apply. */
     734           0 :                         if (mf6cc->mf6cc_parent == mf6c->mf6c_parent) {
     735           0 :                                 rtfree(rt);
     736           0 :                                 continue;
     737             :                         }
     738             : 
     739             :                         DPRINTF("update route (group %s) for mif %d (%s)",
     740             :                             inet_ntop(AF_INET6,
     741             :                             &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
     742             :                             sizeof(bdst)), mifi, ifp->if_xname);
     743             : 
     744           0 :                         mf6c->mf6c_parent = mf6cc->mf6cc_parent;
     745           0 :                         rtfree(rt);
     746           0 :                         continue;
     747             :                 }
     748             : 
     749             :                 DPRINTF("add route (group %s) for mif %d (%s)",
     750             :                     inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
     751             :                     bdst, sizeof(bdst)), mifi, ifp->if_xname);
     752             : 
     753           0 :                 mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6),
     754             :                     mf6cc, wait);
     755           0 :         }
     756             : 
     757             :         /* Create route for the parent interface. */
     758           0 :         if ((ifp = mrt6_iflookupbymif(mf6cc->mf6cc_parent,
     759           0 :             rtableid)) == NULL) {
     760             :                 DPRINTF("failed to find upstream interface %d",
     761             :                     mf6cc->mf6cc_parent);
     762           0 :                 return;
     763             :         }
     764             : 
     765             :         /* We already have a route, nothing to do here. */
     766           0 :         if ((rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
     767           0 :             &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
     768           0 :                 rtfree(rt);
     769           0 :                 return;
     770             :         }
     771             : 
     772             :         DPRINTF("add upstream route (group %s) for if %s",
     773             :             inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
     774             :             bdst, sizeof(bdst)), ifp->if_xname);
     775           0 :         mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), mf6cc, wait);
     776           0 : }
     777             : 
     778             : int
     779           0 : mf6c_add(struct mf6cctl *mfccp, struct in6_addr *origin,
     780             :     struct in6_addr *group, int vidx, unsigned int rtableid, int wait)
     781             : {
     782             :         struct ifnet *ifp;
     783             :         struct mif6 *m6;
     784           0 :         struct mf6cctl mf6cc;
     785             : 
     786           0 :         ifp = mrt6_iflookupbymif(vidx, rtableid);
     787           0 :         if (ifp == NULL ||
     788           0 :             (m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
     789           0 :                 return ENOENT;
     790             : 
     791           0 :         memset(&mf6cc, 0, sizeof(mf6cc));
     792           0 :         if (mfccp == NULL) {
     793           0 :                 mf6cc.mf6cc_origin.sin6_family = AF_INET6;
     794           0 :                 mf6cc.mf6cc_origin.sin6_len = sizeof(mf6cc.mf6cc_origin);
     795           0 :                 mf6cc.mf6cc_origin.sin6_addr = *origin;
     796           0 :                 mf6cc.mf6cc_mcastgrp.sin6_family = AF_INET6;
     797           0 :                 mf6cc.mf6cc_mcastgrp.sin6_len = sizeof(mf6cc.mf6cc_mcastgrp);
     798           0 :                 mf6cc.mf6cc_mcastgrp.sin6_addr = *group;
     799           0 :                 mf6cc.mf6cc_parent = vidx;
     800           0 :         } else
     801           0 :                 memcpy(&mf6cc, mfccp, sizeof(mf6cc));
     802             : 
     803           0 :         mf6c_update(&mf6cc, wait, rtableid);
     804             : 
     805           0 :         return 0;
     806           0 : }
     807             : 
     808             : int
     809           0 : add_m6fc(struct socket *so, struct mf6cctl *mfccp)
     810             : {
     811           0 :         struct inpcb *inp = sotoinpcb(so);
     812           0 :         unsigned int rtableid = inp->inp_rtableid;
     813             : 
     814           0 :         NET_ASSERT_LOCKED();
     815             : 
     816           0 :         return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr,
     817           0 :             &mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent,
     818             :             rtableid, M_WAITOK);
     819             : }
     820             : 
     821             : int
     822           0 : del_m6fc(struct socket *so, struct mf6cctl *mfccp)
     823             : {
     824           0 :         struct inpcb *inp = sotoinpcb(so);
     825             :         struct rtentry *rt;
     826           0 :         unsigned int rtableid = inp->inp_rtableid;
     827             : 
     828           0 :         NET_ASSERT_LOCKED();
     829             : 
     830           0 :         while ((rt = mf6c_find(NULL, &mfccp->mf6cc_origin.sin6_addr,
     831           0 :             &mfccp->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
     832             :                 /* Remove all timers related to this route. */
     833           0 :                 rt_timer_remove_all(rt);
     834           0 :                 mrt6_mcast6_del(rt, rtableid);
     835             :         }
     836             : 
     837           0 :         return 0;
     838             : }
     839             : 
     840             : int
     841           0 : socket6_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
     842             : {
     843           0 :         if (s) {
     844           0 :                 if (sbappendaddr(s, &s->so_rcv, sin6tosa(src), mm, NULL) != 0) {
     845           0 :                         sorwakeup(s);
     846           0 :                         return 0;
     847             :                 }
     848             :         }
     849           0 :         m_freem(mm);
     850           0 :         return -1;
     851           0 : }
     852             : 
     853             : /*
     854             :  * IPv6 multicast forwarding function. This function assumes that the packet
     855             :  * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
     856             :  * pointed to by "ifp", and the packet is to be relayed to other networks
     857             :  * that have members of the packet's destination IPv6 multicast group.
     858             :  *
     859             :  * The packet is returned unscathed to the caller, unless it is
     860             :  * erroneous, in which case a non-zero return value tells the caller to
     861             :  * discard it.
     862             :  */
     863             : int
     864           0 : ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
     865             : {
     866             :         struct rtentry *rt;
     867             :         struct mif6 *mifp;
     868             :         struct mbuf *mm;
     869           0 :         struct sockaddr_in6 sin6;
     870           0 :         unsigned int rtableid = ifp->if_rdomain;
     871             : 
     872           0 :         NET_ASSERT_LOCKED();
     873             : 
     874             :         /*
     875             :          * Don't forward a packet with Hop limit of zero or one,
     876             :          * or a packet destined to a local-only group.
     877             :          */
     878           0 :         if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
     879           0 :             IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
     880           0 :                 return 0;
     881           0 :         ip6->ip6_hlim--;
     882             : 
     883             :         /*
     884             :          * Source address check: do not forward packets with unspecified
     885             :          * source. It was discussed in July 2000, on ipngwg mailing list.
     886             :          * This is rather more serious than unicast cases, because some
     887             :          * MLD packets can be sent with the unspecified source address
     888             :          * (although such packets must normally set 1 to the hop limit field).
     889             :          */
     890           0 :         if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
     891           0 :                 ip6stat_inc(ip6s_cantforward);
     892           0 :                 if (ip6_log_time + ip6_log_interval < time_uptime) {
     893           0 :                         char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
     894             : 
     895           0 :                         ip6_log_time = time_uptime;
     896             : 
     897           0 :                         inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src));
     898           0 :                         inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst));
     899           0 :                         log(LOG_DEBUG, "cannot forward "
     900             :                             "from %s to %s nxt %d received on interface %u\n",
     901           0 :                             src, dst, ip6->ip6_nxt, m->m_pkthdr.ph_ifidx);
     902           0 :                 }
     903           0 :                 return 0;
     904             :         }
     905             : 
     906             :         /*
     907             :          * Determine forwarding mifs from the forwarding cache table
     908             :          */
     909           0 :         rt = mf6c_find(NULL, &ip6->ip6_src, &ip6->ip6_dst, rtableid);
     910             : 
     911             :         /* Entry exists, so forward if necessary */
     912           0 :         if (rt) {
     913           0 :                 return (ip6_mdq(m, ifp, rt));
     914             :         } else {
     915             :                 /*
     916             :                  * If we don't have a route for packet's origin,
     917             :                  * Make a copy of the packet &
     918             :                  * send message to routing daemon
     919             :                  */
     920             : 
     921           0 :                 mrt6stat.mrt6s_no_route++;
     922             : 
     923             :                 {
     924             :                         struct mrt6msg *im;
     925             : 
     926           0 :                         if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
     927           0 :                                 return EHOSTUNREACH;
     928             : 
     929             :                         /*
     930             :                          * Make a copy of the header to send to the user
     931             :                          * level process
     932             :                          */
     933           0 :                         mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT);
     934           0 :                         if (mm == NULL)
     935           0 :                                 return ENOBUFS;
     936             : 
     937             :                         /*
     938             :                          * Send message to routing daemon
     939             :                          */
     940           0 :                         (void)memset(&sin6, 0, sizeof(sin6));
     941           0 :                         sin6.sin6_len = sizeof(sin6);
     942           0 :                         sin6.sin6_family = AF_INET6;
     943           0 :                         sin6.sin6_addr = ip6->ip6_src;
     944             : 
     945             :                         im = NULL;
     946           0 :                         switch (ip6_mrouter_ver) {
     947             :                         case MRT6_INIT:
     948           0 :                                 im = mtod(mm, struct mrt6msg *);
     949           0 :                                 im->im6_msgtype = MRT6MSG_NOCACHE;
     950           0 :                                 im->im6_mbz = 0;
     951           0 :                                 im->im6_mif = mifp->m6_mifi;
     952             :                                 break;
     953             :                         default:
     954           0 :                                 m_freem(mm);
     955           0 :                                 return EINVAL;
     956             :                         }
     957             : 
     958           0 :                         if (socket6_send(ip6_mrouter[rtableid], mm,
     959           0 :                             &sin6) < 0) {
     960           0 :                                 log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
     961             :                                     "socket queue full\n");
     962           0 :                                 mrt6stat.mrt6s_upq_sockfull++;
     963           0 :                                 return ENOBUFS;
     964             :                         }
     965             : 
     966           0 :                         mrt6stat.mrt6s_upcalls++;
     967             : 
     968           0 :                         mf6c_add(NULL, &ip6->ip6_src, &ip6->ip6_dst,
     969           0 :                             mifp->m6_mifi, rtableid, M_NOWAIT);
     970           0 :                 }
     971             : 
     972           0 :                 return 0;
     973             :         }
     974           0 : }
     975             : 
     976             : void
     977           0 : mf6c_expire_route(struct rtentry *rt, struct rttimer *rtt)
     978             : {
     979           0 :         struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
     980           0 :         unsigned int rtableid = rtt->rtt_tableid;
     981             : #ifdef MCAST_DEBUG
     982             :         char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
     983             : #endif /* MCAST_DEBUG */
     984             : 
     985             :         /* Skip entry being deleted. */
     986           0 :         if (mf6c == NULL)
     987           0 :                 return;
     988             : 
     989             :         DPRINTF("origin %s group %s interface %d expire %s",
     990             :             inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr,
     991             :             bsrc, sizeof(bsrc)),
     992             :             inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr,
     993             :             bdst, sizeof(bdst)), rt->rt_ifidx,
     994             :             mf6c->mf6c_expire ? "yes" : "no");
     995             : 
     996           0 :         if (mf6c->mf6c_expire == 0) {
     997           0 :                 mf6c->mf6c_expire = 1;
     998           0 :                 rt_timer_add(rt, mf6c_expire_route, mrouter6q[rtableid],
     999             :                     rtableid);
    1000           0 :                 return;
    1001             :         }
    1002             : 
    1003           0 :         rt_timer_remove_all(rt);
    1004           0 :         mrt6_mcast6_del(rt, rtableid);
    1005           0 : }
    1006             : 
    1007             : /*
    1008             :  * Packet forwarding routine once entry in the cache is made
    1009             :  */
    1010             : int
    1011           0 : ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
    1012             : {
    1013           0 :         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
    1014           0 :         struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6;
    1015           0 :         struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
    1016             :         struct ifnet *ifn;
    1017           0 :         int plen = m->m_pkthdr.len;
    1018             : 
    1019           0 :         if (mifp == NULL || mf6c == NULL) {
    1020           0 :                 rtfree(rt);
    1021           0 :                 return EHOSTUNREACH;
    1022             :         }
    1023             : 
    1024             :         /*
    1025             :          * Don't forward if it didn't arrive from the parent mif
    1026             :          * for its origin.
    1027             :          */
    1028           0 :         if (mifp->m6_mifi != mf6c->mf6c_parent) {
    1029             :                 /* came in the wrong interface */
    1030           0 :                 mrt6stat.mrt6s_wrong_if++;
    1031           0 :                 mf6c->mf6c_wrong_if++;
    1032           0 :                 rtfree(rt);
    1033           0 :                 return 0;
    1034             :         }                       /* if wrong iif */
    1035             : 
    1036             :         /* If I sourced this packet, it counts as output, else it was input. */
    1037           0 :         if (m->m_pkthdr.ph_ifidx == 0) {
    1038             :                 /* XXX: is ph_ifidx really 0 when output?? */
    1039           0 :                 mifp->m6_pkt_out++;
    1040           0 :                 mifp->m6_bytes_out += plen;
    1041           0 :         } else {
    1042           0 :                 mifp->m6_pkt_in++;
    1043           0 :                 mifp->m6_bytes_in += plen;
    1044             :         }
    1045             : 
    1046             :         /*
    1047             :          * For each mif, forward a copy of the packet if there are group
    1048             :          * members downstream on the interface.
    1049             :          */
    1050           0 :         do {
    1051             :                 /* Don't consider non multicast routes. */
    1052           0 :                 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
    1053             :                     (RTF_HOST | RTF_MULTICAST))
    1054             :                         continue;
    1055             : 
    1056           0 :                 mf6c = (struct mf6c *)rt->rt_llinfo;
    1057           0 :                 if (mf6c == NULL)
    1058             :                         continue;
    1059             : 
    1060           0 :                 mf6c->mf6c_pkt_cnt++;
    1061           0 :                 mf6c->mf6c_byte_cnt += m->m_pkthdr.len;
    1062             : 
    1063             :                 /* Don't let this route expire. */
    1064           0 :                 mf6c->mf6c_expire = 0;
    1065             : 
    1066           0 :                 if ((ifn = if_get(rt->rt_ifidx)) == NULL)
    1067             :                         continue;
    1068             : 
    1069             :                 /* Sanity check: did we configure this? */
    1070           0 :                 if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL) {
    1071           0 :                         if_put(ifn);
    1072           0 :                         continue;
    1073             :                 }
    1074             : 
    1075             :                 /* Don't send in the upstream interface. */
    1076           0 :                 if (mf6c->mf6c_parent == m6->m6_mifi) {
    1077           0 :                         if_put(ifn);
    1078           0 :                         continue;
    1079             :                 }
    1080             : 
    1081             :                 /*
    1082             :                  * check if the outgoing packet is going to break
    1083             :                  * a scope boundary.
    1084             :                  */
    1085           0 :                 if ((mifp->m6_flags & MIFF_REGISTER) == 0 &&
    1086           0 :                     (m6->m6_flags & MIFF_REGISTER) == 0 &&
    1087           0 :                     (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) !=
    1088           0 :                     in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) ||
    1089           0 :                     in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) !=
    1090           0 :                     in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) {
    1091           0 :                         if_put(ifn);
    1092           0 :                         ip6stat_inc(ip6s_badscope);
    1093           0 :                         continue;
    1094             :                 }
    1095             : 
    1096           0 :                 m6->m6_pkt_out++;
    1097           0 :                 m6->m6_bytes_out += plen;
    1098             : 
    1099           0 :                 phyint_send6(ifn, ip6, m);
    1100           0 :                 if_put(ifn);
    1101           0 :         } while ((rt = rtable_iterate(rt)) != NULL);
    1102             : 
    1103           0 :         return 0;
    1104           0 : }
    1105             : 
    1106             : void
    1107           0 : phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m)
    1108             : {
    1109             :         struct mbuf *mb_copy;
    1110           0 :         struct sockaddr_in6 *dst6, sin6;
    1111             :         int error = 0;
    1112             : 
    1113           0 :         NET_ASSERT_LOCKED();
    1114             : 
    1115             :         /*
    1116             :          * Make a new reference to the packet; make sure that
    1117             :          * the IPv6 header is actually copied, not just referenced,
    1118             :          * so that ip6_output() only scribbles on the copy.
    1119             :          */
    1120           0 :         mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
    1121           0 :         if (mb_copy == NULL)
    1122           0 :                 return;
    1123             :         /* set MCAST flag to the outgoing packet */
    1124           0 :         mb_copy->m_flags |= M_MCAST;
    1125             : 
    1126             :         /*
    1127             :          * If we sourced the packet, call ip6_output since we may devide
    1128             :          * the packet into fragments when the packet is too big for the
    1129             :          * outgoing interface.
    1130             :          * Otherwise, we can simply send the packet to the interface
    1131             :          * sending queue.
    1132             :          */
    1133           0 :         if (m->m_pkthdr.ph_ifidx == 0) {
    1134           0 :                 struct ip6_moptions im6o;
    1135             : 
    1136           0 :                 im6o.im6o_ifidx = ifp->if_index;
    1137             :                 /* XXX: ip6_output will override ip6->ip6_hlim */
    1138           0 :                 im6o.im6o_hlim = ip6->ip6_hlim;
    1139           0 :                 im6o.im6o_loop = 1;
    1140           0 :                 error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
    1141             :                     NULL);
    1142             :                 return;
    1143           0 :         }
    1144             : 
    1145             :         /*
    1146             :          * If we belong to the destination multicast group
    1147             :          * on the outgoing interface, loop back a copy.
    1148             :          */
    1149             :         dst6 = &sin6;
    1150           0 :         memset(&sin6, 0, sizeof(sin6));
    1151           0 :         if (in6_hasmulti(&ip6->ip6_dst, ifp)) {
    1152           0 :                 dst6->sin6_len = sizeof(struct sockaddr_in6);
    1153           0 :                 dst6->sin6_family = AF_INET6;
    1154           0 :                 dst6->sin6_addr = ip6->ip6_dst;
    1155           0 :                 ip6_mloopback(ifp, m, dst6);
    1156           0 :         }
    1157             :         /*
    1158             :          * Put the packet into the sending queue of the outgoing interface
    1159             :          * if it would fit in the MTU of the interface.
    1160             :          */
    1161           0 :         if (mb_copy->m_pkthdr.len <= ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
    1162           0 :                 dst6->sin6_len = sizeof(struct sockaddr_in6);
    1163           0 :                 dst6->sin6_family = AF_INET6;
    1164           0 :                 dst6->sin6_addr = ip6->ip6_dst;
    1165           0 :                 error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL);
    1166           0 :         } else {
    1167           0 :                 if (ip6_mcast_pmtu)
    1168           0 :                         icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0,
    1169             :                             ifp->if_mtu);
    1170             :                 else {
    1171           0 :                         m_freem(mb_copy); /* simply discard the packet */
    1172             :                 }
    1173             :         }
    1174           0 : }
    1175             : 
    1176             : struct ifnet *
    1177           0 : mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid)
    1178             : {
    1179             :         struct mif6     *m6;
    1180             :         struct ifnet    *ifp;
    1181             : 
    1182           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
    1183           0 :                 if (ifp->if_rdomain != rtableid)
    1184             :                         continue;
    1185           0 :                 if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
    1186             :                         continue;
    1187           0 :                 if (m6->m6_mifi != mifi)
    1188             :                         continue;
    1189             : 
    1190           0 :                 return ifp;
    1191             :         }
    1192             : 
    1193           0 :         return NULL;
    1194           0 : }
    1195             : 
    1196             : struct rtentry *
    1197           0 : mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group,
    1198             :     unsigned int rtableid)
    1199             : {
    1200             :         struct rtentry *rt;
    1201           0 :         struct sockaddr_in6 msin6;
    1202             : 
    1203           0 :         memset(&msin6, 0, sizeof(msin6));
    1204           0 :         msin6.sin6_family = AF_INET6;
    1205           0 :         msin6.sin6_len = sizeof(msin6);
    1206           0 :         msin6.sin6_addr = *group;
    1207             : 
    1208           0 :         rt = rtalloc(sin6tosa(&msin6), 0, rtableid);
    1209           0 :         do {
    1210           0 :                 if (!rtisvalid(rt)) {
    1211           0 :                         rtfree(rt);
    1212           0 :                         return NULL;
    1213             :                 }
    1214           0 :                 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
    1215             :                     (RTF_HOST | RTF_MULTICAST))
    1216             :                         continue;
    1217             :                 /* Return first occurrence if interface is not specified. */
    1218           0 :                 if (ifp == NULL)
    1219           0 :                         return rt;
    1220           0 :                 if (rt->rt_ifidx == ifp->if_index)
    1221           0 :                         return rt;
    1222           0 :         } while ((rt = rtable_iterate(rt)) != NULL);
    1223             : 
    1224           0 :         return NULL;
    1225           0 : }
    1226             : 
    1227             : struct rtentry *
    1228           0 : mrt6_mcast6_add(struct ifnet *ifp, struct sockaddr *origin,
    1229             :     struct sockaddr *group)
    1230             : {
    1231             :         struct ifaddr *ifa;
    1232             :         int rv;
    1233           0 :         unsigned int rtableid = ifp->if_rdomain;
    1234             : 
    1235           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
    1236           0 :                 if (ifa->ifa_addr->sa_family == AF_INET6)
    1237             :                         break;
    1238             :         }
    1239           0 :         if (ifa == NULL) {
    1240             :                 DPRINTF("ifa == NULL");
    1241           0 :                 return NULL;
    1242             :         }
    1243             : 
    1244           0 :         rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST, group);
    1245           0 :         if (rv != 0) {
    1246             :                 DPRINTF("rt_ifa_add failed %d", rv);
    1247           0 :                 return NULL;
    1248             :         }
    1249             : 
    1250           0 :         return mf6c_find(ifp, NULL, &satosin6(group)->sin6_addr, rtableid);
    1251           0 : }
    1252             : 
    1253             : int
    1254           0 : mrt6_mcast6_del(struct rtentry *rt, unsigned int rtableid)
    1255             : {
    1256             :         struct ifnet *ifp;
    1257             :         int rv;
    1258             : 
    1259           0 :         free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mf6c));
    1260           0 :         rt->rt_llinfo = NULL;
    1261             : 
    1262           0 :         if ((ifp = if_get(rt->rt_ifidx)) == NULL) {
    1263             :                 DPRINTF("if_get(%d) failed", rt->rt_ifidx);
    1264           0 :                 rtfree(rt);
    1265           0 :                 return ENOENT;
    1266             :         }
    1267             : 
    1268           0 :         rv = rtdeletemsg(rt, ifp, rtableid);
    1269           0 :         if_put(ifp);
    1270           0 :         if (rv != 0) {
    1271             :                 DPRINTF("rtdeletemsg failed %d", rv);
    1272           0 :                 rtfree(rt);
    1273           0 :                 return rv;
    1274             :         }
    1275             : 
    1276           0 :         return 0;
    1277           0 : }

Generated by: LCOV version 1.13