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

          Line data    Source code
       1             : /*      $OpenBSD: ip_mroute.c,v 1.122 2018/04/30 19:07:44 tb Exp $      */
       2             : /*      $NetBSD: ip_mroute.c,v 1.85 2004/04/26 01:31:57 matt Exp $      */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1989 Stephen Deering
       6             :  * Copyright (c) 1992, 1993
       7             :  *      The Regents of the University of California.  All rights reserved.
       8             :  *
       9             :  * This code is derived from software contributed to Berkeley by
      10             :  * Stephen Deering of Stanford University.
      11             :  *
      12             :  * Redistribution and use in source and binary forms, with or without
      13             :  * modification, are permitted provided that the following conditions
      14             :  * are met:
      15             :  * 1. Redistributions of source code must retain the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer.
      17             :  * 2. Redistributions in binary form must reproduce the above copyright
      18             :  *    notice, this list of conditions and the following disclaimer in the
      19             :  *    documentation and/or other materials provided with the distribution.
      20             :  * 3. Neither the name of the University nor the names of its contributors
      21             :  *    may be used to endorse or promote products derived from this software
      22             :  *    without specific prior written permission.
      23             :  *
      24             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      25             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      26             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      27             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      28             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      29             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      30             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      31             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      32             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      33             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      34             :  * SUCH DAMAGE.
      35             :  *
      36             :  *      @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
      37             :  */
      38             : 
      39             : /*
      40             :  * IP multicast forwarding procedures
      41             :  *
      42             :  * Written by David Waitzman, BBN Labs, August 1988.
      43             :  * Modified by Steve Deering, Stanford, February 1989.
      44             :  * Modified by Mark J. Steiglitz, Stanford, May, 1991
      45             :  * Modified by Van Jacobson, LBL, January 1993
      46             :  * Modified by Ajit Thyagarajan, PARC, August 1993
      47             :  * Modified by Bill Fenner, PARC, April 1994
      48             :  * Modified by Charles M. Hannum, NetBSD, May 1995.
      49             :  * Modified by Ahmed Helmy, SGI, June 1996
      50             :  * Modified by George Edmond Eddy (Rusty), ISI, February 1998
      51             :  * Modified by Pavlin Radoslavov, USC/ISI, May 1998, August 1999, October 2000
      52             :  * Modified by Hitoshi Asaeda, WIDE, August 2000
      53             :  * Modified by Pavlin Radoslavov, ICSI, October 2002
      54             :  *
      55             :  * MROUTING Revision: 1.2
      56             :  * advanced API support, bandwidth metering and signaling
      57             :  */
      58             : 
      59             : #include <sys/param.h>
      60             : #include <sys/systm.h>
      61             : #include <sys/mbuf.h>
      62             : #include <sys/socket.h>
      63             : #include <sys/socketvar.h>
      64             : #include <sys/protosw.h>
      65             : #include <sys/ioctl.h>
      66             : #include <sys/syslog.h>
      67             : 
      68             : #include <net/if.h>
      69             : #include <net/if_var.h>
      70             : #include <net/route.h>
      71             : 
      72             : #include <netinet/in.h>
      73             : #include <netinet/ip.h>
      74             : #include <netinet/ip_var.h>
      75             : #include <netinet/in_pcb.h>
      76             : #include <netinet/igmp.h>
      77             : #include <netinet/ip_mroute.h>
      78             : 
      79             : /* #define MCAST_DEBUG */
      80             : 
      81             : #ifdef MCAST_DEBUG
      82             : int mcast_debug = 1;
      83             : #define DPRINTF(fmt, args...)                                           \
      84             :         do {                                                            \
      85             :                 if (mcast_debug)                                        \
      86             :                         printf("%s:%d " fmt "\n",                   \
      87             :                             __func__, __LINE__, ## args);               \
      88             :         } while (0)
      89             : #else
      90             : #define DPRINTF(fmt, args...)                   \
      91             :         do { } while (0)
      92             : #endif
      93             : 
      94             : /*
      95             :  * Globals.  All but ip_mrouter and ip_mrtproto could be static,
      96             :  * except for netstat or debugging purposes.
      97             :  */
      98             : struct socket   *ip_mrouter[RT_TABLEID_MAX];
      99             : struct rttimer_queue *mrouterq[RT_TABLEID_MAX];
     100             : uint64_t         mrt_count[RT_TABLEID_MAX];
     101             : int             ip_mrtproto = IGMP_DVMRP;    /* for netstat only */
     102             : 
     103             : struct mrtstat  mrtstat;
     104             : 
     105             : struct rtentry  *mfc_find(struct ifnet *, struct in_addr *,
     106             :     struct in_addr *, unsigned int);
     107             : int get_sg_cnt(unsigned int, struct sioc_sg_req *);
     108             : int get_vif_cnt(unsigned int, struct sioc_vif_req *);
     109             : int mrt_rtwalk_mfcsysctl(struct rtentry *, void *, unsigned int);
     110             : int ip_mrouter_init(struct socket *, struct mbuf *);
     111             : int mrouter_rtwalk_delete(struct rtentry *, void *, unsigned int);
     112             : int get_version(struct mbuf *);
     113             : int add_vif(struct socket *, struct mbuf *);
     114             : int del_vif(struct socket *, struct mbuf *);
     115             : void update_mfc_params(struct mfcctl2 *, int, unsigned int);
     116             : void mfc_expire_route(struct rtentry *, struct rttimer *);
     117             : int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
     118             :     int, unsigned int, int);
     119             : int add_mfc(struct socket *, struct mbuf *);
     120             : int del_mfc(struct socket *, struct mbuf *);
     121             : int set_api_config(struct socket *, struct mbuf *); /* chose API capabilities */
     122             : int get_api_support(struct mbuf *);
     123             : int get_api_config(struct mbuf *);
     124             : int socket_send(struct socket *, struct mbuf *,
     125             :                             struct sockaddr_in *);
     126             : int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
     127             : struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
     128             : struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
     129             :     struct sockaddr *);
     130             : int rt_mcast_del(struct rtentry *, unsigned int);
     131             : 
     132             : /*
     133             :  * Kernel multicast routing API capabilities and setup.
     134             :  * If more API capabilities are added to the kernel, they should be
     135             :  * recorded in `mrt_api_support'.
     136             :  */
     137             : static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF |
     138             :                                           MRT_MFC_RP);
     139             : static u_int32_t mrt_api_config = 0;
     140             : 
     141             : /*
     142             :  * Find a route for a given origin IP address and Multicast group address
     143             :  * Type of service parameter to be added in the future!!!
     144             :  * Statistics are updated by the caller if needed
     145             :  * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
     146             :  */
     147             : struct rtentry *
     148           0 : mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group,
     149             :     unsigned int rtableid)
     150             : {
     151             :         struct rtentry          *rt;
     152           0 :         struct sockaddr_in       msin;
     153             : 
     154           0 :         memset(&msin, 0, sizeof(msin));
     155           0 :         msin.sin_len = sizeof(msin);
     156           0 :         msin.sin_family = AF_INET;
     157           0 :         msin.sin_addr = *group;
     158             : 
     159           0 :         rt = rtalloc(sintosa(&msin), 0, rtableid);
     160           0 :         do {
     161           0 :                 if (!rtisvalid(rt)) {
     162           0 :                         rtfree(rt);
     163           0 :                         return NULL;
     164             :                 }
     165             :                 /* Don't consider non multicast routes. */
     166           0 :                 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
     167             :                     (RTF_HOST | RTF_MULTICAST))
     168             :                         continue;
     169             :                 /* Return first occurrence if interface is not specified. */
     170           0 :                 if (ifp == NULL)
     171           0 :                         return (rt);
     172           0 :                 if (rt->rt_ifidx == ifp->if_index)
     173           0 :                         return (rt);
     174           0 :         } while ((rt = rtable_iterate(rt)) != NULL);
     175             : 
     176           0 :         return (NULL);
     177           0 : }
     178             : 
     179             : /*
     180             :  * Handle MRT setsockopt commands to modify the multicast routing tables.
     181             :  */
     182             : int
     183           0 : ip_mrouter_set(struct socket *so, int optname, struct mbuf *m)
     184             : {
     185           0 :         struct inpcb *inp = sotoinpcb(so);
     186             :         int error;
     187             : 
     188           0 :         if (optname != MRT_INIT &&
     189           0 :             so != ip_mrouter[inp->inp_rtableid])
     190           0 :                 error = ENOPROTOOPT;
     191             :         else
     192           0 :                 switch (optname) {
     193             :                 case MRT_INIT:
     194           0 :                         error = ip_mrouter_init(so, m);
     195           0 :                         break;
     196             :                 case MRT_DONE:
     197           0 :                         error = ip_mrouter_done(so);
     198           0 :                         break;
     199             :                 case MRT_ADD_VIF:
     200           0 :                         error = add_vif(so, m);
     201           0 :                         break;
     202             :                 case MRT_DEL_VIF:
     203           0 :                         error = del_vif(so, m);
     204           0 :                         break;
     205             :                 case MRT_ADD_MFC:
     206           0 :                         error = add_mfc(so, m);
     207           0 :                         break;
     208             :                 case MRT_DEL_MFC:
     209           0 :                         error = del_mfc(so, m);
     210           0 :                         break;
     211             :                 case MRT_API_CONFIG:
     212           0 :                         error = set_api_config(so, m);
     213           0 :                         break;
     214             :                 default:
     215             :                         error = ENOPROTOOPT;
     216           0 :                         break;
     217             :                 }
     218             : 
     219           0 :         return (error);
     220             : }
     221             : 
     222             : /*
     223             :  * Handle MRT getsockopt commands
     224             :  */
     225             : int
     226           0 : ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
     227             : {
     228           0 :         struct inpcb *inp = sotoinpcb(so);
     229             :         int error;
     230             : 
     231           0 :         if (so != ip_mrouter[inp->inp_rtableid])
     232           0 :                 error = ENOPROTOOPT;
     233             :         else {
     234           0 :                 switch (optname) {
     235             :                 case MRT_VERSION:
     236           0 :                         error = get_version(m);
     237           0 :                         break;
     238             :                 case MRT_API_SUPPORT:
     239           0 :                         error = get_api_support(m);
     240           0 :                         break;
     241             :                 case MRT_API_CONFIG:
     242           0 :                         error = get_api_config(m);
     243           0 :                         break;
     244             :                 default:
     245             :                         error = ENOPROTOOPT;
     246           0 :                         break;
     247             :                 }
     248             :         }
     249             : 
     250           0 :         return (error);
     251             : }
     252             : 
     253             : /*
     254             :  * Handle ioctl commands to obtain information from the cache
     255             :  */
     256             : int
     257           0 : mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
     258             : {
     259           0 :         struct inpcb *inp = sotoinpcb(so);
     260             :         int error;
     261             : 
     262           0 :         if (so != ip_mrouter[inp->inp_rtableid])
     263           0 :                 error = EINVAL;
     264             :         else
     265           0 :                 switch (cmd) {
     266             :                 case SIOCGETVIFCNT:
     267           0 :                         NET_RLOCK();
     268           0 :                         error = get_vif_cnt(inp->inp_rtableid,
     269           0 :                             (struct sioc_vif_req *)data);
     270           0 :                         NET_RUNLOCK();
     271           0 :                         break;
     272             :                 case SIOCGETSGCNT:
     273           0 :                         NET_RLOCK();
     274           0 :                         error = get_sg_cnt(inp->inp_rtableid,
     275           0 :                             (struct sioc_sg_req *)data);
     276           0 :                         NET_RUNLOCK();
     277           0 :                         break;
     278             :                 default:
     279             :                         error = ENOTTY;
     280           0 :                         break;
     281             :                 }
     282             : 
     283           0 :         return (error);
     284             : }
     285             : 
     286             : /*
     287             :  * returns the packet, byte, rpf-failure count for the source group provided
     288             :  */
     289             : int
     290           0 : get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
     291             : {
     292             :         struct rtentry *rt;
     293             :         struct mfc *mfc;
     294             : 
     295           0 :         rt = mfc_find(NULL, &req->src, &req->grp, rtableid);
     296           0 :         if (rt == NULL) {
     297           0 :                 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
     298           0 :                 return (EADDRNOTAVAIL);
     299             :         }
     300             : 
     301           0 :         req->pktcnt = req->bytecnt = req->wrong_if = 0;
     302           0 :         do {
     303             :                 /* Don't consider non multicast routes. */
     304           0 :                 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
     305             :                     (RTF_HOST | RTF_MULTICAST))
     306             :                         continue;
     307             : 
     308           0 :                 mfc = (struct mfc *)rt->rt_llinfo;
     309           0 :                 if (mfc == NULL)
     310             :                         continue;
     311             : 
     312           0 :                 req->pktcnt += mfc->mfc_pkt_cnt;
     313           0 :                 req->bytecnt += mfc->mfc_byte_cnt;
     314           0 :                 req->wrong_if += mfc->mfc_wrong_if;
     315           0 :         } while ((rt = rtable_iterate(rt)) != NULL);
     316             : 
     317           0 :         return (0);
     318           0 : }
     319             : 
     320             : /*
     321             :  * returns the input and output packet and byte counts on the vif provided
     322             :  */
     323             : int
     324           0 : get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
     325             : {
     326             :         struct ifnet    *ifp;
     327             :         struct vif      *v;
     328           0 :         vifi_t           vifi = req->vifi;
     329             : 
     330           0 :         if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL)
     331           0 :                 return (EINVAL);
     332             : 
     333           0 :         v = (struct vif *)ifp->if_mcast;
     334           0 :         req->icount = v->v_pkt_in;
     335           0 :         req->ocount = v->v_pkt_out;
     336           0 :         req->ibytes = v->v_bytes_in;
     337           0 :         req->obytes = v->v_bytes_out;
     338             : 
     339           0 :         return (0);
     340           0 : }
     341             : 
     342             : int
     343           0 : mrt_sysctl_vif(void *oldp, size_t *oldlenp)
     344             : {
     345             :         caddr_t where = oldp;
     346             :         size_t needed, given;
     347             :         struct ifnet *ifp;
     348             :         struct vif *vifp;
     349           0 :         struct vifinfo vinfo;
     350             : 
     351           0 :         given = *oldlenp;
     352             :         needed = 0;
     353           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
     354           0 :                 if ((vifp = (struct vif *)ifp->if_mcast) == NULL)
     355             :                         continue;
     356             : 
     357           0 :                 vinfo.v_vifi = vifp->v_id;
     358           0 :                 vinfo.v_flags = vifp->v_flags;
     359           0 :                 vinfo.v_threshold = vifp->v_threshold;
     360           0 :                 vinfo.v_lcl_addr = vifp->v_lcl_addr;
     361           0 :                 vinfo.v_rmt_addr = vifp->v_rmt_addr;
     362           0 :                 vinfo.v_pkt_in = vifp->v_pkt_in;
     363           0 :                 vinfo.v_pkt_out = vifp->v_pkt_out;
     364           0 :                 vinfo.v_bytes_in = vifp->v_bytes_in;
     365           0 :                 vinfo.v_bytes_out = vifp->v_bytes_out;
     366             : 
     367           0 :                 needed += sizeof(vinfo);
     368           0 :                 if (where && needed <= given) {
     369             :                         int error;
     370             : 
     371           0 :                         error = copyout(&vinfo, where, sizeof(vinfo));
     372           0 :                         if (error)
     373           0 :                                 return (error);
     374           0 :                         where += sizeof(vinfo);
     375           0 :                 }
     376             :         }
     377           0 :         if (where) {
     378           0 :                 *oldlenp = needed;
     379           0 :                 if (given < needed)
     380           0 :                         return (ENOMEM);
     381             :         } else
     382           0 :                 *oldlenp = (11 * needed) / 10;
     383             : 
     384           0 :         return (0);
     385           0 : }
     386             : 
     387             : struct mfcsysctlarg {
     388             :         struct mfcinfo  *msa_minfos;
     389             :         size_t           msa_len;
     390             :         size_t           msa_needed;
     391             : };
     392             : 
     393             : int
     394           0 : mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
     395             : {
     396           0 :         struct mfc              *mfc = (struct mfc *)rt->rt_llinfo;
     397           0 :         struct mfcsysctlarg     *msa = (struct mfcsysctlarg *)arg;
     398             :         struct ifnet            *ifp;
     399             :         struct vif              *v;
     400             :         struct mfcinfo          *minfo;
     401             :         int                      new = 0;
     402             : 
     403             :         /* Skip entries being removed. */
     404           0 :         if (mfc == NULL)
     405           0 :                 return (0);
     406             : 
     407             :         /* Skip non-multicast routes. */
     408           0 :         if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
     409             :             (RTF_HOST | RTF_MULTICAST))
     410           0 :                 return (0);
     411             : 
     412             :         /* User just asked for the output size. */
     413           0 :         if (msa->msa_minfos == NULL) {
     414           0 :                 msa->msa_needed += sizeof(*minfo);
     415           0 :                 return (0);
     416             :         }
     417             : 
     418             :         /* Skip route with invalid interfaces. */
     419           0 :         if ((ifp = if_get(rt->rt_ifidx)) == NULL)
     420           0 :                 return (0);
     421           0 :         if ((v = (struct vif *)ifp->if_mcast) == NULL) {
     422           0 :                 if_put(ifp);
     423           0 :                 return (0);
     424             :         }
     425             : 
     426           0 :         for (minfo = msa->msa_minfos;
     427           0 :              (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len);
     428           0 :              minfo++) {
     429             :                 /* Find a new entry or update old entry. */
     430           0 :                 if (minfo->mfc_origin.s_addr !=
     431           0 :                     satosin(rt->rt_gateway)->sin_addr.s_addr ||
     432           0 :                     minfo->mfc_mcastgrp.s_addr !=
     433           0 :                     satosin(rt_key(rt))->sin_addr.s_addr) {
     434           0 :                         if (minfo->mfc_origin.s_addr != 0 ||
     435           0 :                             minfo->mfc_mcastgrp.s_addr != 0)
     436             :                                 continue;
     437             : 
     438             :                         new = 1;
     439           0 :                 }
     440             : 
     441           0 :                 minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
     442           0 :                 minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
     443           0 :                 minfo->mfc_parent = mfc->mfc_parent;
     444           0 :                 minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
     445           0 :                 minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
     446           0 :                 minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
     447           0 :                 break;
     448             :         }
     449             : 
     450           0 :         if (new != 0)
     451           0 :                 msa->msa_needed += sizeof(*minfo);
     452             : 
     453           0 :         if_put(ifp);
     454             : 
     455           0 :         return (0);
     456           0 : }
     457             : 
     458             : int
     459           0 : mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
     460             : {
     461             :         unsigned int             rtableid;
     462             :         int                      error;
     463           0 :         struct mfcsysctlarg      msa;
     464             : 
     465           0 :         if (oldp != NULL && *oldlenp > MAXPHYS)
     466           0 :                 return (EINVAL);
     467             : 
     468           0 :         if (oldp != NULL)
     469           0 :                 msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
     470             :         else
     471           0 :                 msa.msa_minfos = NULL;
     472             : 
     473           0 :         msa.msa_len = *oldlenp;
     474           0 :         msa.msa_needed = 0;
     475             : 
     476           0 :         for (rtableid = 0; rtableid < RT_TABLEID_MAX; rtableid++)
     477           0 :                 rtable_walk(rtableid, AF_INET, mrt_rtwalk_mfcsysctl, &msa);
     478             : 
     479           0 :         if (msa.msa_minfos != NULL && msa.msa_needed > 0 &&
     480           0 :             (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
     481           0 :                 free(msa.msa_minfos, M_TEMP, *oldlenp);
     482           0 :                 return (error);
     483             :         }
     484             : 
     485           0 :         free(msa.msa_minfos, M_TEMP, *oldlenp);
     486           0 :         *oldlenp = msa.msa_needed;
     487             : 
     488           0 :         return (0);
     489           0 : }
     490             : 
     491             : /*
     492             :  * Enable multicast routing
     493             :  */
     494             : int
     495           0 : ip_mrouter_init(struct socket *so, struct mbuf *m)
     496             : {
     497           0 :         struct inpcb *inp = sotoinpcb(so);
     498           0 :         unsigned int rtableid = inp->inp_rtableid;
     499             :         int *v;
     500             : 
     501           0 :         if (so->so_type != SOCK_RAW ||
     502           0 :             so->so_proto->pr_protocol != IPPROTO_IGMP)
     503           0 :                 return (EOPNOTSUPP);
     504             : 
     505           0 :         if (m == NULL || m->m_len < sizeof(int))
     506           0 :                 return (EINVAL);
     507             : 
     508           0 :         v = mtod(m, int *);
     509           0 :         if (*v != 1)
     510           0 :                 return (EINVAL);
     511             : 
     512           0 :         if (ip_mrouter[rtableid] != NULL ||
     513           0 :             mrouterq[rtableid] != NULL)
     514           0 :                 return (EADDRINUSE);
     515             : 
     516           0 :         ip_mrouter[rtableid] = so;
     517           0 :         mrouterq[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_FREQUENCY);
     518             : 
     519           0 :         return (0);
     520           0 : }
     521             : 
     522             : int
     523           0 : mrouter_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
     524             : {
     525             :         /* Skip non-multicast routes. */
     526           0 :         if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
     527             :             (RTF_HOST | RTF_MULTICAST))
     528           0 :                 return (0);
     529             : 
     530             :         /* Remove all timers related to this route. */
     531           0 :         rt_timer_remove_all(rt);
     532           0 :         rt_mcast_del(rt, rtableid);
     533           0 :         return (0);
     534           0 : }
     535             : 
     536             : /*
     537             :  * Disable multicast routing
     538             :  */
     539             : int
     540           0 : ip_mrouter_done(struct socket *so)
     541             : {
     542           0 :         struct inpcb *inp = sotoinpcb(so);
     543             :         struct ifnet *ifp;
     544           0 :         unsigned int rtableid = inp->inp_rtableid;
     545             : 
     546           0 :         NET_ASSERT_LOCKED();
     547             : 
     548             :         /* Delete all remaining installed multicast routes. */
     549           0 :         rtable_walk(rtableid, AF_INET, mrouter_rtwalk_delete, NULL);
     550             : 
     551           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
     552           0 :                 if (ifp->if_rdomain != rtableid)
     553             :                         continue;
     554             : 
     555           0 :                 vif_delete(ifp);
     556           0 :         }
     557             : 
     558           0 :         mrt_api_config = 0;
     559             : 
     560           0 :         rt_timer_queue_destroy(mrouterq[rtableid]);
     561           0 :         mrouterq[rtableid] = NULL;
     562           0 :         ip_mrouter[rtableid] = NULL;
     563           0 :         mrt_count[rtableid] = 0;
     564             : 
     565           0 :         return (0);
     566             : }
     567             : 
     568             : int
     569           0 : get_version(struct mbuf *m)
     570             : {
     571           0 :         int *v = mtod(m, int *);
     572             : 
     573           0 :         *v = 0x0305;    /* XXX !!!! */
     574           0 :         m->m_len = sizeof(int);
     575           0 :         return (0);
     576             : }
     577             : 
     578             : /*
     579             :  * Configure API capabilities
     580             :  */
     581             : int
     582           0 : set_api_config(struct socket *so, struct mbuf *m)
     583             : {
     584           0 :         struct inpcb *inp = sotoinpcb(so);
     585             :         struct ifnet *ifp;
     586             :         u_int32_t *apival;
     587           0 :         unsigned int rtableid = inp->inp_rtableid;
     588             : 
     589           0 :         if (m == NULL || m->m_len < sizeof(u_int32_t))
     590           0 :                 return (EINVAL);
     591             : 
     592           0 :         apival = mtod(m, u_int32_t *);
     593             : 
     594             :         /*
     595             :          * We can set the API capabilities only if it is the first operation
     596             :          * after MRT_INIT. I.e.:
     597             :          *  - there are no vifs installed
     598             :          *  - the MFC table is empty
     599             :          */
     600           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
     601           0 :                 if (ifp->if_rdomain != rtableid)
     602             :                         continue;
     603           0 :                 if (ifp->if_mcast == NULL)
     604             :                         continue;
     605             : 
     606           0 :                 *apival = 0;
     607           0 :                 return (EPERM);
     608             :         }
     609           0 :         if (mrt_count[rtableid] > 0) {
     610           0 :                 *apival = 0;
     611           0 :                 return (EPERM);
     612             :         }
     613             : 
     614           0 :         mrt_api_config = *apival & mrt_api_support;
     615           0 :         *apival = mrt_api_config;
     616             : 
     617           0 :         return (0);
     618           0 : }
     619             : 
     620             : /*
     621             :  * Get API capabilities
     622             :  */
     623             : int
     624           0 : get_api_support(struct mbuf *m)
     625             : {
     626             :         u_int32_t *apival;
     627             : 
     628           0 :         if (m == NULL || m->m_len < sizeof(u_int32_t))
     629           0 :                 return (EINVAL);
     630             : 
     631           0 :         apival = mtod(m, u_int32_t *);
     632             : 
     633           0 :         *apival = mrt_api_support;
     634             : 
     635           0 :         return (0);
     636           0 : }
     637             : 
     638             : /*
     639             :  * Get API configured capabilities
     640             :  */
     641             : int
     642           0 : get_api_config(struct mbuf *m)
     643             : {
     644             :         u_int32_t *apival;
     645             : 
     646           0 :         if (m == NULL || m->m_len < sizeof(u_int32_t))
     647           0 :                 return (EINVAL);
     648             : 
     649           0 :         apival = mtod(m, u_int32_t *);
     650             : 
     651           0 :         *apival = mrt_api_config;
     652             : 
     653           0 :         return (0);
     654           0 : }
     655             : 
     656             : static struct sockaddr_in sin = { sizeof(sin), AF_INET };
     657             : 
     658             : int
     659           0 : add_vif(struct socket *so, struct mbuf *m)
     660             : {
     661           0 :         struct inpcb *inp = sotoinpcb(so);
     662             :         struct vifctl *vifcp;
     663             :         struct vif *vifp;
     664             :         struct ifaddr *ifa;
     665             :         struct ifnet *ifp;
     666           0 :         struct ifreq ifr;
     667             :         int error;
     668           0 :         unsigned int rtableid = inp->inp_rtableid;
     669             : 
     670           0 :         NET_ASSERT_LOCKED();
     671             : 
     672           0 :         if (m == NULL || m->m_len < sizeof(struct vifctl))
     673           0 :                 return (EINVAL);
     674             : 
     675           0 :         vifcp = mtod(m, struct vifctl *);
     676           0 :         if (vifcp->vifc_vifi >= MAXVIFS)
     677           0 :                 return (EINVAL);
     678           0 :         if (in_nullhost(vifcp->vifc_lcl_addr))
     679           0 :                 return (EADDRNOTAVAIL);
     680           0 :         if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL)
     681           0 :                 return (EADDRINUSE);
     682             : 
     683             :         /* Tunnels are no longer supported use gif(4) instead. */
     684           0 :         if (vifcp->vifc_flags & VIFF_TUNNEL)
     685           0 :                 return (EOPNOTSUPP);
     686             :         {
     687           0 :                 sin.sin_addr = vifcp->vifc_lcl_addr;
     688           0 :                 ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
     689           0 :                 if (ifa == NULL)
     690           0 :                         return (EADDRNOTAVAIL);
     691             :         }
     692             : 
     693             :         /* Use the physical interface associated with the address. */
     694           0 :         ifp = ifa->ifa_ifp;
     695           0 :         if (ifp->if_mcast != NULL)
     696           0 :                 return (EADDRINUSE);
     697             : 
     698             :         {
     699             :                 /* Make sure the interface supports multicast. */
     700           0 :                 if ((ifp->if_flags & IFF_MULTICAST) == 0)
     701           0 :                         return (EOPNOTSUPP);
     702             : 
     703             :                 /* Enable promiscuous reception of all IP multicasts. */
     704           0 :                 memset(&ifr, 0, sizeof(ifr));
     705           0 :                 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
     706           0 :                 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
     707           0 :                 satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
     708           0 :                 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
     709           0 :                 if (error)
     710           0 :                         return (error);
     711             :         }
     712             : 
     713           0 :         vifp = malloc(sizeof(*vifp), M_MRTABLE, M_WAITOK | M_ZERO);
     714           0 :         ifp->if_mcast = (caddr_t)vifp;
     715             : 
     716           0 :         vifp->v_id = vifcp->vifc_vifi;
     717           0 :         vifp->v_flags = vifcp->vifc_flags;
     718           0 :         vifp->v_threshold = vifcp->vifc_threshold;
     719           0 :         vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
     720           0 :         vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
     721             : 
     722           0 :         return (0);
     723           0 : }
     724             : 
     725             : int
     726           0 : del_vif(struct socket *so, struct mbuf *m)
     727             : {
     728           0 :         struct inpcb *inp = sotoinpcb(so);
     729             :         struct ifnet *ifp;
     730             :         vifi_t *vifip;
     731           0 :         unsigned int rtableid = inp->inp_rtableid;
     732             : 
     733           0 :         NET_ASSERT_LOCKED();
     734             : 
     735           0 :         if (m == NULL || m->m_len < sizeof(vifi_t))
     736           0 :                 return (EINVAL);
     737             : 
     738           0 :         vifip = mtod(m, vifi_t *);
     739           0 :         if ((ifp = if_lookupbyvif(*vifip, rtableid)) == NULL)
     740           0 :                 return (EADDRNOTAVAIL);
     741             : 
     742           0 :         vif_delete(ifp);
     743           0 :         return (0);
     744           0 : }
     745             : 
     746             : void
     747           0 : vif_delete(struct ifnet *ifp)
     748             : {
     749             :         struct vif      *v;
     750           0 :         struct ifreq     ifr;
     751             : 
     752           0 :         if ((v = (struct vif *)ifp->if_mcast) == NULL)
     753           0 :                 return;
     754             : 
     755           0 :         ifp->if_mcast = NULL;
     756             : 
     757           0 :         memset(&ifr, 0, sizeof(ifr));
     758           0 :         satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
     759           0 :         satosin(&ifr.ifr_addr)->sin_family = AF_INET;
     760           0 :         satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
     761           0 :         (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
     762             : 
     763           0 :         free(v, M_MRTABLE, sizeof(*v));
     764           0 : }
     765             : 
     766             : void
     767           0 : mfc_expire_route(struct rtentry *rt, struct rttimer *rtt)
     768             : {
     769           0 :         struct mfc      *mfc = (struct mfc *)rt->rt_llinfo;
     770           0 :         unsigned int     rtableid = rtt->rtt_tableid;
     771             : 
     772             :         /* Skip entry being deleted. */
     773           0 :         if (mfc == NULL)
     774           0 :                 return;
     775             : 
     776             :         DPRINTF("Route domain %d origin %#08X group %#08x interface %d "
     777             :             "expire %s", rtt->rtt_tableid,
     778             :             satosin(rt->rt_gateway)->sin_addr.s_addr,
     779             :             satosin(rt_key(rt))->sin_addr.s_addr,
     780             :             rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no");
     781             : 
     782             :         /* Not expired, add it back to the queue. */
     783           0 :         if (mfc->mfc_expire == 0) {
     784           0 :                 mfc->mfc_expire = 1;
     785           0 :                 rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
     786             :                     rtableid);
     787           0 :                 return;
     788             :         }
     789             : 
     790             :         /* Remove all timers related to this route. */
     791           0 :         rt_timer_remove_all(rt);
     792           0 :         rt_mcast_del(rt, rtableid);
     793           0 : }
     794             : 
     795             : int
     796           0 : mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
     797             :     struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
     798             : {
     799           0 :         struct vif              *v = (struct vif *)ifp->if_mcast;
     800             :         struct rtentry          *rt;
     801             :         struct mfc              *mfc;
     802           0 :         unsigned int             rtableid = ifp->if_rdomain;
     803             : 
     804           0 :         rt = rt_mcast_add(ifp, origin, group);
     805           0 :         if (rt == NULL)
     806           0 :                 return (EHOSTUNREACH);
     807             : 
     808           0 :         mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
     809           0 :         if (mfc == NULL) {
     810             :                 DPRINTF("origin %#08X group %#08X parent %d (%s) "
     811             :                     "malloc failed",
     812             :                     satosin(origin)->sin_addr.s_addr,
     813             :                     satosin(group)->sin_addr.s_addr,
     814             :                     mfccp->mfcc_parent, ifp->if_xname);
     815           0 :                 rt_mcast_del(rt, rtableid);
     816           0 :                 return (ENOMEM);
     817             :         }
     818             : 
     819           0 :         rt->rt_llinfo = (caddr_t)mfc;
     820             : 
     821           0 :         rt_timer_add(rt, mfc_expire_route, mrouterq[rtableid],
     822             :             rtableid);
     823             : 
     824           0 :         mfc->mfc_parent = mfccp->mfcc_parent;
     825           0 :         mfc->mfc_pkt_cnt = 0;
     826           0 :         mfc->mfc_byte_cnt = 0;
     827           0 :         mfc->mfc_wrong_if = 0;
     828           0 :         mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
     829           0 :         mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
     830             :             MRT_MFC_FLAGS_ALL;
     831           0 :         mfc->mfc_expire = 0;
     832             : 
     833             :         /* set the RP address */
     834           0 :         if (mrt_api_config & MRT_MFC_RP)
     835           0 :                 mfc->mfc_rp = mfccp->mfcc_rp;
     836             :         else
     837           0 :                 mfc->mfc_rp = zeroin_addr;
     838             : 
     839           0 :         rtfree(rt);
     840             : 
     841           0 :         return (0);
     842           0 : }
     843             : 
     844             : void
     845           0 : update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
     846             : {
     847             :         struct rtentry          *rt;
     848             :         struct mfc              *mfc;
     849             :         struct ifnet            *ifp;
     850             :         int                      i;
     851           0 :         struct sockaddr_in       osin, msin;
     852             : 
     853           0 :         memset(&osin, 0, sizeof(osin));
     854           0 :         osin.sin_len = sizeof(osin);
     855           0 :         osin.sin_family = AF_INET;
     856           0 :         osin.sin_addr = mfccp->mfcc_origin;
     857             : 
     858           0 :         memset(&msin, 0, sizeof(msin));
     859           0 :         msin.sin_len = sizeof(msin);
     860           0 :         msin.sin_family = AF_INET;
     861           0 :         msin.sin_addr = mfccp->mfcc_mcastgrp;
     862             : 
     863           0 :         for (i = 0; i < MAXVIFS; i++) {
     864             :                 /* Don't add/del upstream routes here. */
     865           0 :                 if (i == mfccp->mfcc_parent)
     866             :                         continue;
     867             : 
     868             :                 /* Test for vif existence and then update the entry. */
     869           0 :                 if ((ifp = if_lookupbyvif(i, rtableid)) == NULL)
     870             :                         continue;
     871             : 
     872           0 :                 rt = mfc_find(ifp, &mfccp->mfcc_origin,
     873             :                     &mfccp->mfcc_mcastgrp, rtableid);
     874             : 
     875             :                 /* vif not configured or removed. */
     876           0 :                 if (mfccp->mfcc_ttls[i] == 0) {
     877             :                         /* Route doesn't exist, nothing to do. */
     878           0 :                         if (rt == NULL)
     879             :                                 continue;
     880             : 
     881             :                         DPRINTF("del route (group %#08X) for vif %d (%s)",
     882             :                             mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
     883           0 :                         rt_timer_remove_all(rt);
     884           0 :                         rt_mcast_del(rt, rtableid);
     885           0 :                         continue;
     886             :                 }
     887             : 
     888             :                 /* Route exists, look for changes. */
     889           0 :                 if (rt != NULL) {
     890           0 :                         mfc = (struct mfc *)rt->rt_llinfo;
     891             :                         /* Skip route being deleted. */
     892           0 :                         if (mfc == NULL) {
     893           0 :                                 rtfree(rt);
     894           0 :                                 continue;
     895             :                         }
     896             : 
     897             :                         /* No new changes to apply. */
     898           0 :                         if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
     899           0 :                             mfccp->mfcc_parent == mfc->mfc_parent) {
     900           0 :                                 rtfree(rt);
     901           0 :                                 continue;
     902             :                         }
     903             : 
     904             :                         DPRINTF("update route (group %#08X) for vif %d (%s)",
     905             :                             mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
     906           0 :                         mfc->mfc_ttl = mfccp->mfcc_ttls[i];
     907           0 :                         mfc->mfc_parent = mfccp->mfcc_parent;
     908           0 :                         rtfree(rt);
     909           0 :                         continue;
     910             :                 }
     911             : 
     912             :                 DPRINTF("add route (group %#08X) for vif %d (%s)",
     913             :                     mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
     914             : 
     915           0 :                 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
     916             :                     mfccp, wait);
     917           0 :         }
     918             : 
     919             :         /* Create route for the parent interface. */
     920           0 :         if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL) {
     921             :                 DPRINTF("failed to find upstream interface %d",
     922             :                     mfccp->mfcc_parent);
     923           0 :                 return;
     924             :         }
     925             : 
     926             :         /* We already have a route, nothing to do here. */
     927           0 :         if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
     928           0 :             &mfccp->mfcc_mcastgrp, rtableid)) != NULL) {
     929           0 :                 rtfree(rt);
     930           0 :                 return;
     931             :         }
     932             : 
     933             :         DPRINTF("add upstream route (group %#08X) for if %s",
     934             :             mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname);
     935           0 :         mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
     936           0 : }
     937             : 
     938             : int
     939           0 : mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
     940             :     struct in_addr *group, int vidx, unsigned int rtableid, int wait)
     941             : {
     942             :         struct ifnet            *ifp;
     943             :         struct vif              *v;
     944           0 :         struct mfcctl2           mfcctl;
     945             : 
     946           0 :         ifp = if_lookupbyvif(vidx, rtableid);
     947           0 :         if (ifp == NULL ||
     948           0 :             (v = (struct vif *)ifp->if_mcast) == NULL)
     949           0 :                 return (EHOSTUNREACH);
     950             : 
     951           0 :         memset(&mfcctl, 0, sizeof(mfcctl));
     952           0 :         if (mfcctl2 == NULL) {
     953           0 :                 mfcctl.mfcc_origin = *origin;
     954           0 :                 mfcctl.mfcc_mcastgrp = *group;
     955           0 :                 mfcctl.mfcc_parent = vidx;
     956           0 :         } else
     957           0 :                 memcpy(&mfcctl, mfcctl2, sizeof(mfcctl));
     958             : 
     959           0 :         update_mfc_params(&mfcctl, wait, rtableid);
     960             : 
     961           0 :         return (0);
     962           0 : }
     963             : 
     964             : int
     965           0 : add_mfc(struct socket *so, struct mbuf *m)
     966             : {
     967           0 :         struct inpcb *inp = sotoinpcb(so);
     968           0 :         struct mfcctl2 mfcctl2;
     969             :         int mfcctl_size = sizeof(struct mfcctl);
     970           0 :         unsigned int rtableid = inp->inp_rtableid;
     971             : 
     972           0 :         NET_ASSERT_LOCKED();
     973             : 
     974           0 :         if (mrt_api_config & MRT_API_FLAGS_ALL)
     975           0 :                 mfcctl_size = sizeof(struct mfcctl2);
     976             : 
     977           0 :         if (m == NULL || m->m_len < mfcctl_size)
     978           0 :                 return (EINVAL);
     979             : 
     980             :         /*
     981             :          * select data size depending on API version.
     982             :          */
     983           0 :         if (mrt_api_config & MRT_API_FLAGS_ALL) {
     984           0 :                 struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
     985           0 :                 memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2));
     986           0 :         } else {
     987           0 :                 struct mfcctl *mp = mtod(m, struct mfcctl *);
     988           0 :                 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
     989           0 :                 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
     990             :                     sizeof(mfcctl2) - sizeof(struct mfcctl));
     991             :         }
     992             : 
     993           0 :         if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
     994           0 :             mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
     995           0 :                 return (EINVAL);
     996             : 
     997           0 :         return (0);
     998           0 : }
     999             : 
    1000             : int
    1001           0 : del_mfc(struct socket *so, struct mbuf *m)
    1002             : {
    1003           0 :         struct inpcb *inp = sotoinpcb(so);
    1004             :         struct rtentry *rt;
    1005           0 :         struct mfcctl2 mfcctl2;
    1006             :         int mfcctl_size = sizeof(struct mfcctl);
    1007             :         struct mfcctl *mp;
    1008           0 :         unsigned int rtableid = inp->inp_rtableid;
    1009             : 
    1010           0 :         NET_ASSERT_LOCKED();
    1011             : 
    1012             :         /*
    1013             :          * XXX: for deleting MFC entries the information in entries
    1014             :          * of size "struct mfcctl" is sufficient.
    1015             :          */
    1016             : 
    1017           0 :         if (m == NULL || m->m_len < mfcctl_size)
    1018           0 :                 return (EINVAL);
    1019             : 
    1020           0 :         mp = mtod(m, struct mfcctl *);
    1021             : 
    1022           0 :         memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
    1023           0 :         memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
    1024             :             sizeof(mfcctl2) - sizeof(struct mfcctl));
    1025             : 
    1026             :         DPRINTF("origin %#08X group %#08X rtableid %d",
    1027             :             mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
    1028             : 
    1029           0 :         while ((rt = mfc_find(NULL, &mfcctl2.mfcc_origin,
    1030           0 :             &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
    1031             :                 /* Remove all timers related to this route. */
    1032           0 :                 rt_timer_remove_all(rt);
    1033           0 :                 rt_mcast_del(rt, rtableid);
    1034             :         }
    1035             : 
    1036           0 :         return (0);
    1037           0 : }
    1038             : 
    1039             : int
    1040           0 : socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src)
    1041             : {
    1042           0 :         if (s != NULL) {
    1043           0 :                 if (sbappendaddr(s, &s->so_rcv, sintosa(src), mm, NULL) != 0) {
    1044           0 :                         sorwakeup(s);
    1045           0 :                         return (0);
    1046             :                 }
    1047             :         }
    1048           0 :         m_freem(mm);
    1049           0 :         return (-1);
    1050           0 : }
    1051             : 
    1052             : /*
    1053             :  * IP multicast forwarding function. This function assumes that the packet
    1054             :  * pointed to by "ip" has arrived on (or is about to be sent to) the interface
    1055             :  * pointed to by "ifp", and the packet is to be relayed to other networks
    1056             :  * that have members of the packet's destination IP multicast group.
    1057             :  *
    1058             :  * The packet is returned unscathed to the caller, unless it is
    1059             :  * erroneous, in which case a non-zero return value tells the caller to
    1060             :  * discard it.
    1061             :  */
    1062             : 
    1063             : #define IP_HDR_LEN  20  /* # bytes of fixed IP header (excluding options) */
    1064             : #define TUNNEL_LEN  12  /* # bytes of IP option for tunnel encapsulation  */
    1065             : 
    1066             : int
    1067           0 : ip_mforward(struct mbuf *m, struct ifnet *ifp)
    1068             : {
    1069           0 :         struct ip *ip = mtod(m, struct ip *);
    1070             :         struct vif *v;
    1071             :         struct rtentry *rt;
    1072             :         static int srctun = 0;
    1073             :         struct mbuf *mm;
    1074           0 :         unsigned int rtableid = ifp->if_rdomain;
    1075             : 
    1076           0 :         if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
    1077           0 :             ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
    1078             :                 /*
    1079             :                  * Packet arrived via a physical interface or
    1080             :                  * an encapsulated tunnel or a register_vif.
    1081             :                  */
    1082             :         } else {
    1083             :                 /*
    1084             :                  * Packet arrived through a source-route tunnel.
    1085             :                  * Source-route tunnels are no longer supported.
    1086             :                  */
    1087           0 :                 if ((srctun++ % 1000) == 0)
    1088           0 :                         log(LOG_ERR, "ip_mforward: received source-routed "
    1089           0 :                             "packet from %x\n", ntohl(ip->ip_src.s_addr));
    1090           0 :                 return (EOPNOTSUPP);
    1091             :         }
    1092             : 
    1093             :         /*
    1094             :          * Don't forward a packet with time-to-live of zero or one,
    1095             :          * or a packet destined to a local-only group.
    1096             :          */
    1097           0 :         if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
    1098           0 :                 return (0);
    1099             : 
    1100             :         /*
    1101             :          * Determine forwarding vifs from the forwarding cache table
    1102             :          */
    1103           0 :         ++mrtstat.mrts_mfc_lookups;
    1104           0 :         rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid);
    1105             : 
    1106             :         /* Entry exists, so forward if necessary */
    1107           0 :         if (rt != NULL) {
    1108           0 :                 return (ip_mdq(m, ifp, rt));
    1109             :         } else {
    1110             :                 /*
    1111             :                  * If we don't have a route for packet's origin,
    1112             :                  * Make a copy of the packet & send message to routing daemon
    1113             :                  */
    1114           0 :                 int hlen = ip->ip_hl << 2;
    1115             : 
    1116           0 :                 ++mrtstat.mrts_mfc_misses;
    1117           0 :                 mrtstat.mrts_no_route++;
    1118             : 
    1119             :                 {
    1120             :                         struct igmpmsg *im;
    1121             : 
    1122             :                         /*
    1123             :                          * Locate the vifi for the incoming interface for
    1124             :                          * this packet.
    1125             :                          * If none found, drop packet.
    1126             :                          */
    1127           0 :                         if ((v = (struct vif *)ifp->if_mcast) == NULL)
    1128           0 :                                 return (EHOSTUNREACH);
    1129             :                         /*
    1130             :                          * Make a copy of the header to send to the user level
    1131             :                          * process
    1132             :                          */
    1133           0 :                         mm = m_copym(m, 0, hlen, M_NOWAIT);
    1134           0 :                         if (mm == NULL ||
    1135           0 :                             (mm = m_pullup(mm, hlen)) == NULL)
    1136           0 :                                 return (ENOBUFS);
    1137             : 
    1138             :                         /*
    1139             :                          * Send message to routing daemon to install
    1140             :                          * a route into the kernel table
    1141             :                          */
    1142             : 
    1143           0 :                         im = mtod(mm, struct igmpmsg *);
    1144           0 :                         im->im_msgtype = IGMPMSG_NOCACHE;
    1145           0 :                         im->im_mbz = 0;
    1146           0 :                         im->im_vif = v->v_id;
    1147             : 
    1148           0 :                         mrtstat.mrts_upcalls++;
    1149             : 
    1150           0 :                         sin.sin_addr = ip->ip_src;
    1151           0 :                         if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
    1152           0 :                                 log(LOG_WARNING, "ip_mforward: ip_mrouter "
    1153             :                                     "socket queue full\n");
    1154           0 :                                 ++mrtstat.mrts_upq_sockfull;
    1155           0 :                                 return (ENOBUFS);
    1156             :                         }
    1157             : 
    1158           0 :                         mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
    1159             :                             rtableid, M_NOWAIT);
    1160           0 :                 }
    1161             : 
    1162           0 :                 return (0);
    1163             :         }
    1164           0 : }
    1165             : 
    1166             : /*
    1167             :  * Packet forwarding routine once entry in the cache is made
    1168             :  */
    1169             : int
    1170           0 : ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
    1171             : {
    1172           0 :         struct ip  *ip = mtod(m, struct ip *);
    1173           0 :         struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
    1174           0 :         struct vif *v = (struct vif *)ifp0->if_mcast;
    1175             :         struct ifnet *ifp;
    1176             :         struct mbuf *mc;
    1177           0 :         struct ip_moptions imo;
    1178             : 
    1179             :         /* Sanity check: we have all promised pointers. */
    1180           0 :         if (v == NULL || mfc == NULL) {
    1181           0 :                 rtfree(rt);
    1182           0 :                 return (EHOSTUNREACH);
    1183             :         }
    1184             : 
    1185             :         /*
    1186             :          * Don't forward if it didn't arrive from the parent vif for its origin.
    1187             :          */
    1188           0 :         if (mfc->mfc_parent != v->v_id) {
    1189             :                 /* came in the wrong interface */
    1190           0 :                 ++mrtstat.mrts_wrong_if;
    1191           0 :                 mfc->mfc_wrong_if++;
    1192           0 :                 rtfree(rt);
    1193           0 :                 return (0);
    1194             :         }
    1195             : 
    1196             :         /* If I sourced this packet, it counts as output, else it was input. */
    1197           0 :         if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
    1198           0 :                 v->v_pkt_out++;
    1199           0 :                 v->v_bytes_out += m->m_pkthdr.len;
    1200           0 :         } else {
    1201           0 :                 v->v_pkt_in++;
    1202           0 :                 v->v_bytes_in += m->m_pkthdr.len;
    1203             :         }
    1204             : 
    1205             :         /*
    1206             :          * For each vif, decide if a copy of the packet should be forwarded.
    1207             :          * Forward if:
    1208             :          *              - the ttl exceeds the vif's threshold
    1209             :          *              - there are group members downstream on interface
    1210             :          */
    1211           0 :         do {
    1212             :                 /* Don't consider non multicast routes. */
    1213           0 :                 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
    1214             :                     (RTF_HOST | RTF_MULTICAST))
    1215             :                         continue;
    1216             : 
    1217           0 :                 mfc = (struct mfc *)rt->rt_llinfo;
    1218           0 :                 if (mfc == NULL)
    1219             :                         continue;
    1220             : 
    1221           0 :                 mfc->mfc_pkt_cnt++;
    1222           0 :                 mfc->mfc_byte_cnt += m->m_pkthdr.len;
    1223             : 
    1224             :                 /* Don't let this route expire. */
    1225           0 :                 mfc->mfc_expire = 0;
    1226             : 
    1227           0 :                 if (ip->ip_ttl <= mfc->mfc_ttl)
    1228             :                         continue;
    1229           0 :                 if ((ifp = if_get(rt->rt_ifidx)) == NULL)
    1230             :                         continue;
    1231             : 
    1232             :                 /* Sanity check: did we configure this? */
    1233           0 :                 if ((v = (struct vif *)ifp->if_mcast) == NULL) {
    1234           0 :                         if_put(ifp);
    1235           0 :                         continue;
    1236             :                 }
    1237             : 
    1238             :                 /* Don't send in the upstream interface. */
    1239           0 :                 if (mfc->mfc_parent == v->v_id) {
    1240           0 :                         if_put(ifp);
    1241           0 :                         continue;
    1242             :                 }
    1243             : 
    1244           0 :                 v->v_pkt_out++;
    1245           0 :                 v->v_bytes_out += m->m_pkthdr.len;
    1246             : 
    1247             :                 /*
    1248             :                  * Make a new reference to the packet; make sure
    1249             :                  * that the IP header is actually copied, not
    1250             :                  * just referenced, so that ip_output() only
    1251             :                  * scribbles on the copy.
    1252             :                  */
    1253           0 :                 mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
    1254           0 :                 if (mc == NULL) {
    1255           0 :                         if_put(ifp);
    1256           0 :                         rtfree(rt);
    1257           0 :                         return (ENOBUFS);
    1258             :                 }
    1259             : 
    1260             :                 /*
    1261             :                  * if physical interface option, extract the options
    1262             :                  * and then send
    1263             :                  */
    1264           0 :                 imo.imo_ifidx = rt->rt_ifidx;
    1265           0 :                 imo.imo_ttl = ip->ip_ttl - IPTTLDEC;
    1266           0 :                 imo.imo_loop = 1;
    1267             : 
    1268           0 :                 ip_output(mc, NULL, NULL, IP_FORWARDING, &imo, NULL, 0);
    1269           0 :                 if_put(ifp);
    1270           0 :         } while ((rt = rtable_iterate(rt)) != NULL);
    1271             : 
    1272           0 :         return (0);
    1273           0 : }
    1274             : 
    1275             : struct ifnet *
    1276           0 : if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
    1277             : {
    1278             :         struct vif      *v;
    1279             :         struct ifnet    *ifp;
    1280             : 
    1281           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
    1282           0 :                 if (ifp->if_rdomain != rtableid)
    1283             :                         continue;
    1284           0 :                 if ((v = (struct vif *)ifp->if_mcast) == NULL)
    1285             :                         continue;
    1286           0 :                 if (v->v_id != vifi)
    1287             :                         continue;
    1288             : 
    1289           0 :                 return (ifp);
    1290             :         }
    1291             : 
    1292           0 :         return (NULL);
    1293           0 : }
    1294             : 
    1295             : struct rtentry *
    1296           0 : rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
    1297             : {
    1298             :         struct ifaddr           *ifa;
    1299             :         int                      rv;
    1300           0 :         unsigned int             rtableid = ifp->if_rdomain;
    1301             : 
    1302           0 :         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
    1303           0 :                 if (ifa->ifa_addr->sa_family == AF_INET)
    1304             :                         break;
    1305             :         }
    1306           0 :         if (ifa == NULL) {
    1307             :                 DPRINTF("ifa == NULL");
    1308           0 :                 return (NULL);
    1309             :         }
    1310             : 
    1311           0 :         rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST, group);
    1312           0 :         if (rv != 0) {
    1313             :                 DPRINTF("rt_ifa_add failed (%d)", rv);
    1314           0 :                 return (NULL);
    1315             :         }
    1316             : 
    1317           0 :         mrt_count[rtableid]++;
    1318             : 
    1319           0 :         return (mfc_find(ifp, NULL, &satosin(group)->sin_addr, rtableid));
    1320           0 : }
    1321             : 
    1322             : int
    1323           0 : rt_mcast_del(struct rtentry *rt, unsigned int rtableid)
    1324             : {
    1325             :         struct ifnet            *ifp;
    1326             :         int                      rv;
    1327             : 
    1328           0 :         free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
    1329           0 :         rt->rt_llinfo = NULL;
    1330             : 
    1331           0 :         if ((ifp = if_get(rt->rt_ifidx)) == NULL) {
    1332             :                 DPRINTF("if_get(%d) failed", rt->rt_ifidx);
    1333           0 :                 rtfree(rt);
    1334           0 :                 return (ENOENT);
    1335             :         }
    1336             : 
    1337           0 :         rv = rtdeletemsg(rt, ifp, rtableid);
    1338           0 :         if_put(ifp);
    1339           0 :         if (rv != 0) {
    1340             :                 DPRINTF("rtdeletemsg failed (%d)", rv);
    1341           0 :                 rtfree(rt);
    1342           0 :                 return (rv);
    1343             :         }
    1344             : 
    1345           0 :         mrt_count[rtableid]--;
    1346             : 
    1347           0 :         return (0);
    1348           0 : }

Generated by: LCOV version 1.13