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/net/route.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 /*      $NetBSD: route.c,v 1.65 2005/02/26 22:45:09 perry Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Kevin M. Lahey of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
   42  * All rights reserved.
   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 project 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 PROJECT 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 PROJECT 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 
   69 /*
   70  * Copyright (c) 1980, 1986, 1991, 1993
   71  *      The Regents of the University of California.  All rights reserved.
   72  *
   73  * Redistribution and use in source and binary forms, with or without
   74  * modification, are permitted provided that the following conditions
   75  * are met:
   76  * 1. Redistributions of source code must retain the above copyright
   77  *    notice, this list of conditions and the following disclaimer.
   78  * 2. Redistributions in binary form must reproduce the above copyright
   79  *    notice, this list of conditions and the following disclaimer in the
   80  *    documentation and/or other materials provided with the distribution.
   81  * 3. Neither the name of the University nor the names of its contributors
   82  *    may be used to endorse or promote products derived from this software
   83  *    without specific prior written permission.
   84  *
   85  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   86  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   87  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   88  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   89  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   90  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   91  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   92  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   93  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   94  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   95  * SUCH DAMAGE.
   96  *
   97  *      @(#)route.c     8.3 (Berkeley) 1/9/95
   98  */
   99 
  100 #include <sys/cdefs.h>
  101 __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.65 2005/02/26 22:45:09 perry Exp $");
  102 
  103 #include "opt_ns.h"
  104 
  105 #include <sys/param.h>
  106 #include <sys/systm.h>
  107 #include <sys/callout.h>
  108 #include <sys/proc.h>
  109 #include <sys/mbuf.h>
  110 #include <sys/socket.h>
  111 #include <sys/socketvar.h>
  112 #include <sys/domain.h>
  113 #include <sys/protosw.h>
  114 #include <sys/kernel.h>
  115 #include <sys/ioctl.h>
  116 #include <sys/pool.h>
  117 
  118 #include <net/if.h>
  119 #include <net/route.h>
  120 #include <net/raw_cb.h>
  121 
  122 #include <netinet/in.h>
  123 #include <netinet/in_var.h>
  124 
  125 #ifdef NS
  126 #include <netns/ns.h>
  127 #endif
  128 
  129 #define SA(p) ((struct sockaddr *)(p))
  130 
  131 struct  route_cb route_cb;
  132 struct  rtstat  rtstat;
  133 struct  radix_node_head *rt_tables[AF_MAX+1];
  134 
  135 int     rttrash;                /* routes not in table but not freed */
  136 struct  sockaddr wildcard;      /* zero valued cookie for wildcard searches */
  137 
  138 POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL);
  139 POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL);
  140 
  141 struct callout rt_timer_ch; /* callout for rt_timer_timer() */
  142 
  143 static int rtdeletemsg(struct rtentry *);
  144 static int rtflushclone1(struct radix_node *, void *);
  145 static void rtflushclone(struct radix_node_head *, struct rtentry *);
  146 
  147 void
  148 rtable_init(void **table)
  149 {
  150         struct domain *dom;
  151         DOMAIN_FOREACH(dom)
  152                 if (dom->dom_rtattach)
  153                         dom->dom_rtattach(&table[dom->dom_family],
  154                             dom->dom_rtoffset);
  155 }
  156 
  157 void
  158 route_init(void)
  159 {
  160 
  161         rn_init();      /* initialize all zeroes, all ones, mask table */
  162         rtable_init((void **)rt_tables);
  163 }
  164 
  165 /*
  166  * Packet routing routines.
  167  */
  168 void
  169 rtalloc(struct route *ro)
  170 {
  171         if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
  172                 return;                          /* XXX */
  173         ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
  174 }
  175 
  176 struct rtentry *
  177 rtalloc1(const struct sockaddr *dst, int report)
  178 {
  179         struct radix_node_head *rnh = rt_tables[dst->sa_family];
  180         struct rtentry *rt;
  181         struct radix_node *rn;
  182         struct rtentry *newrt = 0;
  183         struct rt_addrinfo info;
  184         int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;
  185 
  186         if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
  187             ((rn->rn_flags & RNF_ROOT) == 0)) {
  188                 newrt = rt = (struct rtentry *)rn;
  189                 if (report && (rt->rt_flags & RTF_CLONING)) {
  190                         err = rtrequest(RTM_RESOLVE, dst, SA(0),
  191                                               SA(0), 0, &newrt);
  192                         if (err) {
  193                                 newrt = rt;
  194                                 rt->rt_refcnt++;
  195                                 goto miss;
  196                         }
  197                         if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
  198                                 msgtype = RTM_RESOLVE;
  199                                 goto miss;
  200                         }
  201                         /* Inform listeners of the new route */
  202                         memset(&info, 0, sizeof(info));
  203                         info.rti_info[RTAX_DST] = rt_key(rt);
  204                         info.rti_info[RTAX_NETMASK] = rt_mask(rt);
  205                         info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
  206                         if (rt->rt_ifp != NULL) {
  207                                 info.rti_info[RTAX_IFP] =
  208                                     TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
  209                                 info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
  210                         }
  211                         rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0);
  212                 } else
  213                         rt->rt_refcnt++;
  214         } else {
  215                 rtstat.rts_unreach++;
  216         miss:   if (report) {
  217                         memset((caddr_t)&info, 0, sizeof(info));
  218                         info.rti_info[RTAX_DST] = dst;
  219                         rt_missmsg(msgtype, &info, 0, err);
  220                 }
  221         }
  222         splx(s);
  223         return (newrt);
  224 }
  225 
  226 void
  227 rtfree(struct rtentry *rt)
  228 {
  229         struct ifaddr *ifa;
  230 
  231         if (rt == 0)
  232                 panic("rtfree");
  233         rt->rt_refcnt--;
  234         if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
  235                 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
  236                         panic ("rtfree 2");
  237                 rttrash--;
  238                 if (rt->rt_refcnt < 0) {
  239                         printf("rtfree: %p not freed (neg refs)\n", rt);
  240                         return;
  241                 }
  242                 rt_timer_remove_all(rt, 0);
  243                 ifa = rt->rt_ifa;
  244                 IFAFREE(ifa);
  245                 Free(rt_key(rt));
  246                 pool_put(&rtentry_pool, rt);
  247         }
  248 }
  249 
  250 void
  251 ifafree(struct ifaddr *ifa)
  252 {
  253 
  254 #ifdef DIAGNOSTIC
  255         if (ifa == NULL)
  256                 panic("ifafree: null ifa");
  257         if (ifa->ifa_refcnt != 0)
  258                 panic("ifafree: ifa_refcnt != 0 (%d)", ifa->ifa_refcnt);
  259 #endif
  260 #ifdef IFAREF_DEBUG
  261         printf("ifafree: freeing ifaddr %p\n", ifa);
  262 #endif
  263         free(ifa, M_IFADDR);
  264 }
  265 
  266 /*
  267  * Force a routing table entry to the specified
  268  * destination to go through the given gateway.
  269  * Normally called as a result of a routing redirect
  270  * message from the network layer.
  271  *
  272  * N.B.: must be called at splsoftnet
  273  */
  274 void
  275 rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway,
  276         const struct sockaddr *netmask, int flags, const struct sockaddr *src,
  277         struct rtentry **rtp)
  278 {
  279         struct rtentry *rt;
  280         int error = 0;
  281         u_quad_t *stat = 0;
  282         struct rt_addrinfo info;
  283         struct ifaddr *ifa;
  284 
  285         /* verify the gateway is directly reachable */
  286         if ((ifa = ifa_ifwithnet(gateway)) == 0) {
  287                 error = ENETUNREACH;
  288                 goto out;
  289         }
  290         rt = rtalloc1(dst, 0);
  291         /*
  292          * If the redirect isn't from our current router for this dst,
  293          * it's either old or wrong.  If it redirects us to ourselves,
  294          * we have a routing loop, perhaps as a result of an interface
  295          * going down recently.
  296          */
  297 #define equal(a1, a2) \
  298         ((a1)->sa_len == (a2)->sa_len && \
  299          bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
  300         if (!(flags & RTF_DONE) && rt &&
  301              (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
  302                 error = EINVAL;
  303         else if (ifa_ifwithaddr(gateway))
  304                 error = EHOSTUNREACH;
  305         if (error)
  306                 goto done;
  307         /*
  308          * Create a new entry if we just got back a wildcard entry
  309          * or the lookup failed.  This is necessary for hosts
  310          * which use routing redirects generated by smart gateways
  311          * to dynamically build the routing tables.
  312          */
  313         if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
  314                 goto create;
  315         /*
  316          * Don't listen to the redirect if it's
  317          * for a route to an interface.
  318          */
  319         if (rt->rt_flags & RTF_GATEWAY) {
  320                 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
  321                         /*
  322                          * Changing from route to net => route to host.
  323                          * Create new route, rather than smashing route to net.
  324                          */
  325                 create:
  326                         if (rt)
  327                                 rtfree(rt);
  328                         flags |=  RTF_GATEWAY | RTF_DYNAMIC;
  329                         info.rti_info[RTAX_DST] = dst;
  330                         info.rti_info[RTAX_GATEWAY] = gateway;
  331                         info.rti_info[RTAX_NETMASK] = netmask;
  332                         info.rti_ifa = ifa;
  333                         info.rti_flags = flags;
  334                         rt = NULL;
  335                         error = rtrequest1(RTM_ADD, &info, &rt);
  336                         if (rt != NULL)
  337                                 flags = rt->rt_flags;
  338                         stat = &rtstat.rts_dynamic;
  339                 } else {
  340                         /*
  341                          * Smash the current notion of the gateway to
  342                          * this destination.  Should check about netmask!!!
  343                          */
  344                         rt->rt_flags |= RTF_MODIFIED;
  345                         flags |= RTF_MODIFIED;
  346                         stat = &rtstat.rts_newgateway;
  347                         rt_setgate(rt, rt_key(rt), gateway);
  348                 }
  349         } else
  350                 error = EHOSTUNREACH;
  351 done:
  352         if (rt) {
  353                 if (rtp && !error)
  354                         *rtp = rt;
  355                 else
  356                         rtfree(rt);
  357         }
  358 out:
  359         if (error)
  360                 rtstat.rts_badredirect++;
  361         else if (stat != NULL)
  362                 (*stat)++;
  363         memset((caddr_t)&info, 0, sizeof(info));
  364         info.rti_info[RTAX_DST] = dst;
  365         info.rti_info[RTAX_GATEWAY] = gateway;
  366         info.rti_info[RTAX_NETMASK] = netmask;
  367         info.rti_info[RTAX_AUTHOR] = src;
  368         rt_missmsg(RTM_REDIRECT, &info, flags, error);
  369 }
  370 
  371 /*
  372  * Delete a route and generate a message
  373  */
  374 static int
  375 rtdeletemsg(struct rtentry *rt)
  376 {
  377         int error;
  378         struct rt_addrinfo info;
  379 
  380         /*
  381          * Request the new route so that the entry is not actually
  382          * deleted.  That will allow the information being reported to
  383          * be accurate (and consistent with route_output()).
  384          */
  385         memset((caddr_t)&info, 0, sizeof(info));
  386         info.rti_info[RTAX_DST] = rt_key(rt);
  387         info.rti_info[RTAX_NETMASK] = rt_mask(rt);
  388         info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
  389         info.rti_flags = rt->rt_flags;
  390         error = rtrequest1(RTM_DELETE, &info, &rt);
  391 
  392         rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
  393 
  394         /* Adjust the refcount */
  395         if (error == 0 && rt->rt_refcnt <= 0) {
  396                 rt->rt_refcnt++;
  397                 rtfree(rt);
  398         }
  399         return (error);
  400 }
  401 
  402 static int
  403 rtflushclone1(struct radix_node *rn, void *arg)
  404 {
  405         struct rtentry *rt, *parent;
  406 
  407         rt = (struct rtentry *)rn;
  408         parent = (struct rtentry *)arg;
  409         if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)
  410                 rtdeletemsg(rt);
  411         return 0;
  412 }
  413 
  414 static void
  415 rtflushclone(struct radix_node_head *rnh, struct rtentry *parent)
  416 {
  417 
  418 #ifdef DIAGNOSTIC
  419         if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
  420                 panic("rtflushclone: called with a non-cloning route");
  421         if (!rnh->rnh_walktree)
  422                 panic("rtflushclone: no rnh_walktree");
  423 #endif
  424         rnh->rnh_walktree(rnh, rtflushclone1, (void *)parent);
  425 }
  426 
  427 /*
  428  * Routing table ioctl interface.
  429  */
  430 int
  431 rtioctl(u_long req, caddr_t data, struct proc *p)
  432 {
  433         return (EOPNOTSUPP);
  434 }
  435 
  436 struct ifaddr *
  437 ifa_ifwithroute(int flags, const struct sockaddr *dst,
  438         const struct sockaddr *gateway)
  439 {
  440         struct ifaddr *ifa;
  441         if ((flags & RTF_GATEWAY) == 0) {
  442                 /*
  443                  * If we are adding a route to an interface,
  444                  * and the interface is a pt to pt link
  445                  * we should search for the destination
  446                  * as our clue to the interface.  Otherwise
  447                  * we can use the local address.
  448                  */
  449                 ifa = 0;
  450                 if (flags & RTF_HOST)
  451                         ifa = ifa_ifwithdstaddr(dst);
  452                 if (ifa == 0)
  453                         ifa = ifa_ifwithaddr(gateway);
  454         } else {
  455                 /*
  456                  * If we are adding a route to a remote net
  457                  * or host, the gateway may still be on the
  458                  * other end of a pt to pt link.
  459                  */
  460                 ifa = ifa_ifwithdstaddr(gateway);
  461         }
  462         if (ifa == 0)
  463                 ifa = ifa_ifwithnet(gateway);
  464         if (ifa == 0) {
  465                 struct rtentry *rt = rtalloc1(dst, 0);
  466                 if (rt == 0)
  467                         return (0);
  468                 rt->rt_refcnt--;
  469                 if ((ifa = rt->rt_ifa) == 0)
  470                         return (0);
  471         }
  472         if (ifa->ifa_addr->sa_family != dst->sa_family) {
  473                 struct ifaddr *oifa = ifa;
  474                 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
  475                 if (ifa == 0)
  476                         ifa = oifa;
  477         }
  478         return (ifa);
  479 }
  480 
  481 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  482 
  483 int
  484 rtrequest(int req, const struct sockaddr *dst, const struct sockaddr *gateway,
  485         const struct sockaddr *netmask, int flags, struct rtentry **ret_nrt)
  486 {
  487         struct rt_addrinfo info;
  488 
  489         memset(&info, 0, sizeof(info));
  490         info.rti_flags = flags;
  491         info.rti_info[RTAX_DST] = dst;
  492         info.rti_info[RTAX_GATEWAY] = gateway;
  493         info.rti_info[RTAX_NETMASK] = netmask;
  494         return rtrequest1(req, &info, ret_nrt);
  495 }
  496 
  497 /*
  498  * These (questionable) definitions of apparent local variables apply
  499  * to the next function.  XXXXXX!!!
  500  */
  501 #define dst     info->rti_info[RTAX_DST]
  502 #define gateway info->rti_info[RTAX_GATEWAY]
  503 #define netmask info->rti_info[RTAX_NETMASK]
  504 #define ifaaddr info->rti_info[RTAX_IFA]
  505 #define ifpaddr info->rti_info[RTAX_IFP]
  506 #define flags   info->rti_flags
  507 
  508 int
  509 rt_getifa(struct rt_addrinfo *info)
  510 {
  511         struct ifaddr *ifa;
  512         int error = 0;
  513 
  514         /*
  515          * ifp may be specified by sockaddr_dl when protocol address
  516          * is ambiguous
  517          */
  518         if (info->rti_ifp == NULL && ifpaddr != NULL
  519             && ifpaddr->sa_family == AF_LINK &&
  520             (ifa = ifa_ifwithnet((const struct sockaddr *)ifpaddr)) != NULL)
  521                 info->rti_ifp = ifa->ifa_ifp;
  522         if (info->rti_ifa == NULL && ifaaddr != NULL)
  523                 info->rti_ifa = ifa_ifwithaddr(ifaaddr);
  524         if (info->rti_ifa == NULL) {
  525                 const struct sockaddr *sa;
  526 
  527                 sa = ifaaddr != NULL ? ifaaddr :
  528                     (gateway != NULL ? gateway : dst);
  529                 if (sa != NULL && info->rti_ifp != NULL)
  530                         info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
  531                 else if (dst != NULL && gateway != NULL)
  532                         info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
  533                 else if (sa != NULL)
  534                         info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
  535         }
  536         if ((ifa = info->rti_ifa) != NULL) {
  537                 if (info->rti_ifp == NULL)
  538                         info->rti_ifp = ifa->ifa_ifp;
  539         } else
  540                 error = ENETUNREACH;
  541         return (error);
  542 }
  543 
  544 int
  545 rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
  546 {
  547         int s = splsoftnet();
  548         int error = 0;
  549         struct rtentry *rt, *crt;
  550         struct radix_node *rn;
  551         struct radix_node_head *rnh;
  552         struct ifaddr *ifa;
  553         struct sockaddr *ndst;
  554         struct sockaddr_storage deldst;
  555 #define senderr(x) { error = x ; goto bad; }
  556 
  557         if ((rnh = rt_tables[dst->sa_family]) == 0)
  558                 senderr(ESRCH);
  559         if (flags & RTF_HOST)
  560                 netmask = 0;
  561         switch (req) {
  562         case RTM_DELETE:
  563                 if (netmask) {
  564                         rt_maskedcopy(dst, (struct sockaddr *)&deldst, netmask);
  565                         dst = (struct sockaddr *)&deldst;
  566                 }
  567                 if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == 0)
  568                         senderr(ESRCH);
  569                 rt = (struct rtentry *)rn;
  570                 if ((rt->rt_flags & RTF_CLONING) != 0) {
  571                         /* clean up any cloned children */
  572                         rtflushclone(rnh, rt);
  573                 }
  574                 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
  575                         senderr(ESRCH);
  576                 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
  577                         panic ("rtrequest delete");
  578                 rt = (struct rtentry *)rn;
  579                 if (rt->rt_gwroute) {
  580                         rt = rt->rt_gwroute; RTFREE(rt);
  581                         (rt = (struct rtentry *)rn)->rt_gwroute = 0;
  582                 }
  583                 if (rt->rt_parent) {
  584                         rt->rt_parent->rt_refcnt--;
  585                         rt->rt_parent = NULL;
  586                 }
  587                 rt->rt_flags &= ~RTF_UP;
  588                 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
  589                         ifa->ifa_rtrequest(RTM_DELETE, rt, info);
  590                 rttrash++;
  591                 if (ret_nrt)
  592                         *ret_nrt = rt;
  593                 else if (rt->rt_refcnt <= 0) {
  594                         rt->rt_refcnt++;
  595                         rtfree(rt);
  596                 }
  597                 break;
  598 
  599         case RTM_RESOLVE:
  600                 if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
  601                         senderr(EINVAL);
  602                 if ((rt->rt_flags & RTF_CLONING) == 0)
  603                         senderr(EINVAL);
  604                 ifa = rt->rt_ifa;
  605                 flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
  606                 flags |= RTF_CLONED;
  607                 gateway = rt->rt_gateway;
  608                 if ((netmask = rt->rt_genmask) == 0)
  609                         flags |= RTF_HOST;
  610                 goto makeroute;
  611 
  612         case RTM_ADD:
  613                 if (info->rti_ifa == 0 && (error = rt_getifa(info)))
  614                         senderr(error);
  615                 ifa = info->rti_ifa;
  616         makeroute:
  617                 rt = pool_get(&rtentry_pool, PR_NOWAIT);
  618                 if (rt == 0)
  619                         senderr(ENOBUFS);
  620                 Bzero(rt, sizeof(*rt));
  621                 rt->rt_flags = RTF_UP | flags;
  622                 LIST_INIT(&rt->rt_timer);
  623                 if (rt_setgate(rt, dst, gateway)) {
  624                         pool_put(&rtentry_pool, rt);
  625                         senderr(ENOBUFS);
  626                 }
  627                 ndst = rt_key(rt);
  628                 if (netmask) {
  629                         rt_maskedcopy(dst, ndst, netmask);
  630                 } else
  631                         Bcopy(dst, ndst, dst->sa_len);
  632                 IFAREF(ifa);
  633                 rt->rt_ifa = ifa;
  634                 rt->rt_ifp = ifa->ifa_ifp;
  635                 if (req == RTM_RESOLVE) {
  636                         rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
  637                         rt->rt_parent = *ret_nrt;
  638                         rt->rt_parent->rt_refcnt++;
  639                 }
  640                 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
  641                     rnh, rt->rt_nodes);
  642                 if (rn == NULL && (crt = rtalloc1(ndst, 0)) != NULL) {
  643                         /* overwrite cloned route */
  644                         if ((crt->rt_flags & RTF_CLONED) != 0) {
  645                                 rtdeletemsg(crt);
  646                                 rn = rnh->rnh_addaddr((caddr_t)ndst,
  647                                     (caddr_t)netmask, rnh, rt->rt_nodes);
  648                         }
  649                         RTFREE(crt);
  650                 }
  651                 if (rn == 0) {
  652                         IFAFREE(ifa);
  653                         if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)
  654                                 rtfree(rt->rt_parent);
  655                         if (rt->rt_gwroute)
  656                                 rtfree(rt->rt_gwroute);
  657                         Free(rt_key(rt));
  658                         pool_put(&rtentry_pool, rt);
  659                         senderr(EEXIST);
  660                 }
  661                 if (ifa->ifa_rtrequest)
  662                         ifa->ifa_rtrequest(req, rt, info);
  663                 if (ret_nrt) {
  664                         *ret_nrt = rt;
  665                         rt->rt_refcnt++;
  666                 }
  667                 if ((rt->rt_flags & RTF_CLONING) != 0) {
  668                         /* clean up any cloned children */
  669                         rtflushclone(rnh, rt);
  670                 }
  671                 break;
  672         }
  673 bad:
  674         splx(s);
  675         return (error);
  676 }
  677 
  678 #undef dst
  679 #undef gateway
  680 #undef netmask
  681 #undef ifaaddr
  682 #undef ifpaddr
  683 #undef flags
  684 
  685 int
  686 rt_setgate( struct rtentry *rt0, const struct sockaddr *dst,
  687         const struct sockaddr *gate)
  688 {
  689         char *new, *old;
  690         u_int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
  691         struct rtentry *rt = rt0;
  692 
  693         if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
  694                 old = (caddr_t)rt_key(rt);
  695                 R_Malloc(new, caddr_t, dlen + glen);
  696                 if (new == 0)
  697                         return 1;
  698                 Bzero(new, dlen + glen);
  699                 rt->rt_nodes->rn_key = new;
  700         } else {
  701                 new = (void *)rt->rt_nodes->rn_key;
  702                 old = 0;
  703         }
  704         Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
  705         if (old) {
  706                 Bcopy(dst, new, dlen);
  707                 Free(old);
  708         }
  709         if (rt->rt_gwroute) {
  710                 rt = rt->rt_gwroute; RTFREE(rt);
  711                 rt = rt0; rt->rt_gwroute = 0;
  712         }
  713         if (rt->rt_flags & RTF_GATEWAY) {
  714                 rt->rt_gwroute = rtalloc1(gate, 1);
  715                 /*
  716                  * If we switched gateways, grab the MTU from the new
  717                  * gateway route if the current MTU, if the current MTU is
  718                  * greater than the MTU of gateway.
  719                  * Note that, if the MTU of gateway is 0, we will reset the
  720                  * MTU of the route to run PMTUD again from scratch. XXX
  721                  */
  722                 if (rt->rt_gwroute
  723                     && !(rt->rt_rmx.rmx_locks & RTV_MTU)
  724                     && rt->rt_rmx.rmx_mtu
  725                     && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) {
  726                         rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
  727                 }
  728         }
  729         return 0;
  730 }
  731 
  732 void
  733 rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
  734         const struct sockaddr *netmask)
  735 {
  736         const u_char *cp1 = (u_char *)src;
  737         u_char *cp2 = (u_char *)dst;
  738         const u_char *cp3 = (u_char *)netmask;
  739         u_char *cplim = cp2 + *cp3;
  740         u_char *cplim2 = cp2 + *cp1;
  741 
  742         *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
  743         cp3 += 2;
  744         if (cplim > cplim2)
  745                 cplim = cplim2;
  746         while (cp2 < cplim)
  747                 *cp2++ = *cp1++ & *cp3++;
  748         if (cp2 < cplim2)
  749                 memset((caddr_t)cp2, 0, (unsigned)(cplim2 - cp2));
  750 }
  751 
  752 /*
  753  * Set up or tear down a routing table entry, normally
  754  * for an interface.
  755  */
  756 int
  757 rtinit(struct ifaddr *ifa, int cmd, int flags)
  758 {
  759         struct rtentry *rt;
  760         struct sockaddr *dst, *odst;
  761         struct sockaddr_storage deldst;
  762         struct rtentry *nrt = 0;
  763         int error;
  764         struct rt_addrinfo info;
  765 
  766         dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
  767         if (cmd == RTM_DELETE) {
  768                 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
  769                         /* Delete subnet route for this interface */
  770                         odst = dst;
  771                         dst = (struct sockaddr *)&deldst;
  772                         rt_maskedcopy(odst, dst, ifa->ifa_netmask);
  773                 }
  774                 if ((rt = rtalloc1(dst, 0)) != NULL) {
  775                         rt->rt_refcnt--;
  776                         if (rt->rt_ifa != ifa)
  777                                 return (flags & RTF_HOST ? EHOSTUNREACH
  778                                                         : ENETUNREACH);
  779                 }
  780         }
  781         memset(&info, 0, sizeof(info));
  782         info.rti_ifa = ifa;
  783         info.rti_flags = flags | ifa->ifa_flags;
  784         info.rti_info[RTAX_DST] = dst;
  785         info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
  786         /*
  787          * XXX here, it seems that we are assuming that ifa_netmask is NULL
  788          * for RTF_HOST.  bsdi4 passes NULL explicitly (via intermediate
  789          * variable) when RTF_HOST is 1.  still not sure if i can safely
  790          * change it to meet bsdi4 behavior.
  791          */
  792         info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
  793         error = rtrequest1(cmd, &info, &nrt);
  794         if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
  795                 rt_newaddrmsg(cmd, ifa, error, nrt);
  796                 if (rt->rt_refcnt <= 0) {
  797                         rt->rt_refcnt++;
  798                         rtfree(rt);
  799                 }
  800         }
  801         if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
  802                 rt->rt_refcnt--;
  803                 if (rt->rt_ifa != ifa) {
  804                         printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
  805                                 rt->rt_ifa);
  806                         if (rt->rt_ifa->ifa_rtrequest)
  807                                 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL);
  808                         IFAFREE(rt->rt_ifa);
  809                         rt->rt_ifa = ifa;
  810                         rt->rt_ifp = ifa->ifa_ifp;
  811                         IFAREF(ifa);
  812                         if (ifa->ifa_rtrequest)
  813                                 ifa->ifa_rtrequest(RTM_ADD, rt, NULL);
  814                 }
  815                 rt_newaddrmsg(cmd, ifa, error, nrt);
  816         }
  817         return (error);
  818 }
  819 
  820 /*
  821  * Route timer routines.  These routes allow functions to be called
  822  * for various routes at any time.  This is useful in supporting
  823  * path MTU discovery and redirect route deletion.
  824  *
  825  * This is similar to some BSDI internal functions, but it provides
  826  * for multiple queues for efficiency's sake...
  827  */
  828 
  829 LIST_HEAD(, rttimer_queue) rttimer_queue_head;
  830 static int rt_init_done = 0;
  831 
  832 #define RTTIMER_CALLOUT(r)      do {                                    \
  833                 if (r->rtt_func != NULL) {                              \
  834                         (*r->rtt_func)(r->rtt_rt, r);                   \
  835                 } else {                                                \
  836                         rtrequest((int) RTM_DELETE,                     \
  837                                   (struct sockaddr *)rt_key(r->rtt_rt), \
  838                                   0, 0, 0, 0);                          \
  839                 }                                                       \
  840         } while (/*CONSTCOND*/0)
  841 
  842 /*
  843  * Some subtle order problems with domain initialization mean that
  844  * we cannot count on this being run from rt_init before various
  845  * protocol initializations are done.  Therefore, we make sure
  846  * that this is run when the first queue is added...
  847  */
  848 
  849 void
  850 rt_timer_init(void)
  851 {
  852         assert(rt_init_done == 0);
  853 
  854         LIST_INIT(&rttimer_queue_head);
  855         callout_init(&rt_timer_ch);
  856         callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
  857         rt_init_done = 1;
  858 }
  859 
  860 struct rttimer_queue *
  861 rt_timer_queue_create(u_int timeout)
  862 {
  863         struct rttimer_queue *rtq;
  864 
  865         if (rt_init_done == 0)
  866                 rt_timer_init();
  867 
  868         R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
  869         if (rtq == NULL)
  870                 return (NULL);
  871         Bzero(rtq, sizeof *rtq);
  872 
  873         rtq->rtq_timeout = timeout;
  874         rtq->rtq_count = 0;
  875         TAILQ_INIT(&rtq->rtq_head);
  876         LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
  877 
  878         return (rtq);
  879 }
  880 
  881 void
  882 rt_timer_queue_change(struct rttimer_queue *rtq, long timeout)
  883 {
  884 
  885         rtq->rtq_timeout = timeout;
  886 }
  887 
  888 void
  889 rt_timer_queue_remove_all(struct rttimer_queue *rtq, int destroy)
  890 {
  891         struct rttimer *r;
  892 
  893         while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
  894                 LIST_REMOVE(r, rtt_link);
  895                 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
  896                 if (destroy)
  897                         RTTIMER_CALLOUT(r);
  898                 pool_put(&rttimer_pool, r);
  899                 if (rtq->rtq_count > 0)
  900                         rtq->rtq_count--;
  901                 else
  902                         printf("rt_timer_queue_remove_all: "
  903                             "rtq_count reached 0\n");
  904         }
  905 }
  906 
  907 void
  908 rt_timer_queue_destroy(struct rttimer_queue *rtq, int destroy)
  909 {
  910 
  911         rt_timer_queue_remove_all(rtq, destroy);
  912 
  913         LIST_REMOVE(rtq, rtq_link);
  914 
  915         /*
  916          * Caller is responsible for freeing the rttimer_queue structure.
  917          */
  918 }
  919 
  920 unsigned long
  921 rt_timer_count(struct rttimer_queue *rtq)
  922 {
  923         return rtq->rtq_count;
  924 }
  925 
  926 void
  927 rt_timer_remove_all(struct rtentry *rt, int destroy)
  928 {
  929         struct rttimer *r;
  930 
  931         while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
  932                 LIST_REMOVE(r, rtt_link);
  933                 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
  934                 if (destroy)
  935                         RTTIMER_CALLOUT(r);
  936                 if (r->rtt_queue->rtq_count > 0)
  937                         r->rtt_queue->rtq_count--;
  938                 else
  939                         printf("rt_timer_remove_all: rtq_count reached 0\n");
  940                 pool_put(&rttimer_pool, r);
  941         }
  942 }
  943 
  944 int
  945 rt_timer_add(struct rtentry *rt,
  946         void (*func)(struct rtentry *, struct rttimer *),
  947         struct rttimer_queue *queue)
  948 {
  949         struct rttimer *r;
  950         long current_time;
  951         int s;
  952 
  953         s = splclock();
  954         current_time = mono_time.tv_sec;
  955         splx(s);
  956 
  957         /*
  958          * If there's already a timer with this action, destroy it before
  959          * we add a new one.
  960          */
  961         for (r = LIST_FIRST(&rt->rt_timer); r != NULL;
  962              r = LIST_NEXT(r, rtt_link)) {
  963                 if (r->rtt_func == func) {
  964                         LIST_REMOVE(r, rtt_link);
  965                         TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
  966                         if (r->rtt_queue->rtq_count > 0)
  967                                 r->rtt_queue->rtq_count--;
  968                         else
  969                                 printf("rt_timer_add: rtq_count reached 0\n");
  970                         pool_put(&rttimer_pool, r);
  971                         break;  /* only one per list, so we can quit... */
  972                 }
  973         }
  974 
  975         r = pool_get(&rttimer_pool, PR_NOWAIT);
  976         if (r == NULL)
  977                 return (ENOBUFS);
  978         Bzero(r, sizeof(*r));
  979 
  980         r->rtt_rt = rt;
  981         r->rtt_time = current_time;
  982         r->rtt_func = func;
  983         r->rtt_queue = queue;
  984         LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
  985         TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
  986         r->rtt_queue->rtq_count++;
  987 
  988         return (0);
  989 }
  990 
  991 /* ARGSUSED */
  992 void
  993 rt_timer_timer(void *arg)
  994 {
  995         struct rttimer_queue *rtq;
  996         struct rttimer *r;
  997         long current_time;
  998         int s;
  999 
 1000         s = splclock();
 1001         current_time = mono_time.tv_sec;
 1002         splx(s);
 1003 
 1004         s = splsoftnet();
 1005         for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
 1006              rtq = LIST_NEXT(rtq, rtq_link)) {
 1007                 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
 1008                     (r->rtt_time + rtq->rtq_timeout) < current_time) {
 1009                         LIST_REMOVE(r, rtt_link);
 1010                         TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
 1011                         RTTIMER_CALLOUT(r);
 1012                         pool_put(&rttimer_pool, r);
 1013                         if (rtq->rtq_count > 0)
 1014                                 rtq->rtq_count--;
 1015                         else
 1016                                 printf("rt_timer_timer: rtq_count reached 0\n");
 1017                 }
 1018         }
 1019         splx(s);
 1020 
 1021         callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
 1022 }

Cache object: 6df74227e42b9374d9e9f0b0d0fef257


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