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

Cache object: c29405faca8a3d9cabc09747cbfcaa86


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