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


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

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

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

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

Cache object: 77aa143c9dc41654eb2d5b4830e31142


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


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