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

Cache object: c88598e7ef734e386a5cf110dadc9bbf


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