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

Cache object: 7e4ccf8f07c79126d4a328385056de40


[ 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.