home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / routed / tables.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-23  |  10.1 KB  |  390 lines

  1. /*
  2.  * Copyright (c) 1983, 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. /*static char sccsid[] = "from: @(#)tables.c    5.17 (Berkeley) 6/1/90";*/
  36. static char rcsid[] = "$Id: tables.c,v 1.1 1994/05/23 09:08:12 rzsfl Exp rzsfl $";
  37. #endif /* not lint */
  38.  
  39. /*
  40.  * Routing Table Management Daemon
  41.  */
  42. #include "defs.h"
  43. #include <sys/ioctl.h>
  44. #include <errno.h>
  45. #include <sys/syslog.h>
  46.  
  47. #ifndef DEBUG
  48. #define    DEBUG    0
  49. #endif
  50.  
  51. #ifdef RTM_ADD
  52. #define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
  53. #else
  54. #define FIXLEN(s) { }
  55. #endif
  56.  
  57. int    install = !DEBUG;        /* if 1 call kernel */
  58.  
  59. /*
  60.  * Lookup dst in the tables for an exact match.
  61.  */
  62. struct rt_entry *
  63. rtlookup(dst)
  64.     struct sockaddr *dst;
  65. {
  66.     register struct rt_entry *rt;
  67.     register struct rthash *rh;
  68.     register u_int hash;
  69.     struct afhash h;
  70.     int doinghost = 1;
  71.  
  72.     if (dst->sa_family >= af_max)
  73.         return (0);
  74.     (*afswitch[dst->sa_family].af_hash)(dst, &h);
  75.     hash = h.afh_hosthash;
  76.     rh = &hosthash[hash & ROUTEHASHMASK];
  77. again:
  78.     for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
  79.         if (rt->rt_hash != hash)
  80.             continue;
  81.         if (equal(&rt->rt_dst, dst))
  82.             return (rt);
  83.     }
  84.     if (doinghost) {
  85.         doinghost = 0;
  86.         hash = h.afh_nethash;
  87.         rh = &nethash[hash & ROUTEHASHMASK];
  88.         goto again;
  89.     }
  90.     return (0);
  91. }
  92.  
  93. struct sockaddr wildcard;    /* zero valued cookie for wildcard searches */
  94.  
  95. /*
  96.  * Find a route to dst as the kernel would.
  97.  */
  98. struct rt_entry *
  99. rtfind(dst)
  100.     struct sockaddr *dst;
  101. {
  102.     register struct rt_entry *rt;
  103.     register struct rthash *rh;
  104.     register u_int hash;
  105.     struct afhash h;
  106.     int af = dst->sa_family;
  107.     int doinghost = 1, (*match)();
  108.  
  109.     if (af >= af_max)
  110.         return (0);
  111.     (*afswitch[af].af_hash)(dst, &h);
  112.     hash = h.afh_hosthash;
  113.     rh = &hosthash[hash & ROUTEHASHMASK];
  114.  
  115. again:
  116.     for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
  117.         if (rt->rt_hash != hash)
  118.             continue;
  119.         if (doinghost) {
  120.             if (equal(&rt->rt_dst, dst))
  121.                 return (rt);
  122.         } else {
  123.             if (rt->rt_dst.sa_family == af &&
  124.                 (*match)(&rt->rt_dst, dst))
  125.                 return (rt);
  126.         }
  127.     }
  128.     if (doinghost) {
  129.         doinghost = 0;
  130.         hash = h.afh_nethash;
  131.         rh = &nethash[hash & ROUTEHASHMASK];
  132.         match = afswitch[af].af_netmatch;
  133.         goto again;
  134.     }
  135. #ifdef notyet
  136.     /*
  137.      * Check for wildcard gateway, by convention network 0.
  138.      */
  139.     if (dst != &wildcard) {
  140.         dst = &wildcard, hash = 0;
  141.         goto again;
  142.     }
  143. #endif
  144.     return (0);
  145. }
  146.  
  147. rtadd(dst, gate, metric, state)
  148.     struct sockaddr *dst, *gate;
  149.     int metric, state;
  150. {
  151.     struct afhash h;
  152.     register struct rt_entry *rt;
  153.     struct rthash *rh;
  154.     int af = dst->sa_family, flags;
  155.     u_int hash;
  156.  
  157.     if (af >= af_max)
  158.         return;
  159.     (*afswitch[af].af_hash)(dst, &h);
  160.     flags = (*afswitch[af].af_rtflags)(dst);
  161.     /*
  162.      * Subnet flag isn't visible to kernel, move to state.    XXX
  163.      */
  164.     FIXLEN(dst);
  165.     FIXLEN(gate);
  166.     if (flags & RTF_SUBNET) {
  167.         state |= RTS_SUBNET;
  168.         flags &= ~RTF_SUBNET;
  169.     }
  170.     if (flags & RTF_HOST) {
  171.         hash = h.afh_hosthash;
  172.         rh = &hosthash[hash & ROUTEHASHMASK];
  173.     } else {
  174.         hash = h.afh_nethash;
  175.         rh = &nethash[hash & ROUTEHASHMASK];
  176.     }
  177.     rt = (struct rt_entry *)malloc(sizeof (*rt));
  178.     if (rt == 0)
  179.         return;
  180.     rt->rt_hash = hash;
  181.     rt->rt_dst = *dst;
  182.     rt->rt_router = *gate;
  183.     rt->rt_timer = 0;
  184.     rt->rt_flags = RTF_UP | flags;
  185.     rt->rt_state = state | RTS_CHANGED;
  186.     rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
  187.     if (rt->rt_ifp == 0)
  188.         rt->rt_ifp = if_ifwithnet(&rt->rt_router);
  189.     if ((state & RTS_INTERFACE) == 0)
  190.         rt->rt_flags |= RTF_GATEWAY;
  191.     rt->rt_metric = metric;
  192.     rt->rt_dev = NULL;
  193.     insque(rt, rh);
  194.     TRACE_ACTION("ADD", rt);
  195.     /*
  196.      * If the ioctl fails because the gateway is unreachable
  197.      * from this host, discard the entry.  This should only
  198.      * occur because of an incorrect entry in /etc/gateways.
  199.      */
  200.     if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
  201.         ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
  202.         if (errno != EEXIST && gate->sa_family < af_max)
  203.             syslog(LOG_ERR,
  204.             "adding route to net/host %s through gateway %s: %m\n",
  205.                (*afswitch[dst->sa_family].af_format)(dst),
  206.                (*afswitch[gate->sa_family].af_format)(gate));
  207.         perror("SIOCADDRT");
  208.         if (errno == ENETUNREACH) {
  209.             TRACE_ACTION("DELETE", rt);
  210.             remque(rt);
  211.             free((char *)rt);
  212.         }
  213.     }
  214. }
  215.  
  216. rtchange(rt, gate, metric)
  217.     struct rt_entry *rt;
  218.     struct sockaddr *gate;
  219.     short metric;
  220. {
  221.     int add = 0, delete = 0, newgateway = 0;
  222.     struct rtentry oldroute;
  223.  
  224.     FIXLEN(gate);
  225.     FIXLEN(&(rt->rt_router));
  226.     FIXLEN(&(rt->rt_dst));
  227.     if (!equal(&rt->rt_router, gate)) {
  228.         newgateway++;
  229.         TRACE_ACTION("CHANGE FROM ", rt);
  230.     } else if (metric != rt->rt_metric)
  231.         TRACE_NEWMETRIC(rt, metric);
  232.     if ((rt->rt_state & RTS_INTERNAL) == 0) {
  233.         /*
  234.          * If changing to different router, we need to add
  235.          * new route and delete old one if in the kernel.
  236.          * If the router is the same, we need to delete
  237.          * the route if has become unreachable, or re-add
  238.          * it if it had been unreachable.
  239.          */
  240.         if (newgateway) {
  241.             add++;
  242.             if (rt->rt_metric != HOPCNT_INFINITY)
  243.                 delete++;
  244.         } else if (metric == HOPCNT_INFINITY)
  245.             delete++;
  246.         else if (rt->rt_metric == HOPCNT_INFINITY)
  247.             add++;
  248.     }
  249.     if (delete)
  250.         oldroute = rt->rt_rt;
  251.     if ((rt->rt_state & RTS_INTERFACE) && delete) {
  252.         rt->rt_state &= ~RTS_INTERFACE;
  253.         rt->rt_flags |= RTF_GATEWAY;
  254.         if (metric > rt->rt_metric && delete)
  255.             syslog(LOG_ERR, "%s route to interface %s (timed out)",
  256.                 add? "changing" : "deleting",
  257.                 rt->rt_ifp->int_name);
  258.     }
  259.     if (add) {
  260.         rt->rt_router = *gate;
  261.         rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
  262.         if (rt->rt_ifp == 0)
  263.             rt->rt_ifp = if_ifwithnet(&rt->rt_router);
  264.     }
  265.     rt->rt_metric = metric;
  266.     rt->rt_state |= RTS_CHANGED;
  267.     if (newgateway)
  268.         TRACE_ACTION("CHANGE TO   ", rt);
  269. #ifndef RTM_ADD
  270.     if (add && install)
  271.         if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
  272.             perror("SIOCADDRT");
  273.     if (delete && install)
  274.         if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
  275.             perror("SIOCDELRT");
  276. #else
  277.     if (delete && install)
  278.         if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
  279.             perror("SIOCDELRT");
  280.     if (add && install) {
  281.         if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
  282.             perror("SIOCADDRT");
  283.     }
  284. #endif
  285. }
  286.  
  287. rtdelete(rt)
  288.     struct rt_entry *rt;
  289. {
  290.  
  291.     TRACE_ACTION("DELETE", rt);
  292.     FIXLEN(&(rt->rt_router));
  293.     FIXLEN(&(rt->rt_dst));
  294.     if (rt->rt_metric < HOPCNT_INFINITY) {
  295.         if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
  296.         syslog(LOG_ERR,
  297.             "deleting route to interface %s? (timed out?)",
  298.             rt->rt_ifp->int_name);
  299.         if (install &&
  300.         (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
  301.         ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
  302.             perror("SIOCDELRT");
  303.     }
  304.     remque(rt);
  305.     free((char *)rt);
  306. }
  307.  
  308. rtdeleteall(sig)
  309.     int sig;
  310. {
  311.     register struct rthash *rh;
  312.     register struct rt_entry *rt;
  313.     struct rthash *base = hosthash;
  314.     int doinghost = 1;
  315.  
  316.     (void) signal(sig, rtdeleteall);
  317.  
  318. again:
  319.     for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
  320.         rt = rh->rt_forw;
  321.         for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
  322.             if (rt->rt_state & RTS_INTERFACE ||
  323.                 rt->rt_metric >= HOPCNT_INFINITY)
  324.                 continue;
  325.             TRACE_ACTION("DELETE", rt);
  326.             if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
  327.                 ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
  328.                 perror("SIOCDELRT");
  329.         }
  330.     }
  331.     if (doinghost) {
  332.         doinghost = 0;
  333.         base = nethash;
  334.         goto again;
  335.     }
  336.     exit(sig);
  337. }
  338.  
  339. /*
  340.  * If we have an interface to the wide, wide world,
  341.  * add an entry for an Internet default route (wildcard) to the internal
  342.  * tables and advertise it.  This route is not added to the kernel routes,
  343.  * but this entry prevents us from listening to other people's defaults
  344.  * and installing them in the kernel here.
  345.  */
  346. rtdefault()
  347. {
  348.     extern struct sockaddr inet_default;
  349.  
  350.     rtadd(&inet_default, &inet_default, 1,
  351.         RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
  352. }
  353.  
  354. rtinit()
  355. {
  356.     register struct rthash *rh;
  357.  
  358.     for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
  359.         rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
  360.     for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
  361.         rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
  362. }
  363.  
  364.  
  365. #ifndef __linux__
  366. /* ffrom /sys/i386/i386/machdep.c */
  367. /*
  368.  * insert an element into a queue 
  369.  */
  370. insque(element, head)
  371.     register struct rthash *element, *head;
  372. {
  373.     element->rt_forw = head->rt_forw;
  374.     head->rt_forw = (struct rt_entry *)element;
  375.     element->rt_back = (struct rt_entry *)head;
  376.     ((struct rthash *)(element->rt_forw))->rt_back=(struct rt_entry *)element;
  377. }
  378.  
  379. /*
  380.  * remove an element from a queue
  381.  */
  382. remque(element)
  383.     register struct rthash *element;
  384. {
  385.     ((struct rthash *)(element->rt_forw))->rt_back = element->rt_back;
  386.     ((struct rthash *)(element->rt_back))->rt_forw = element->rt_forw;
  387.     element->rt_back = (struct rt_entry *)0;
  388. }
  389. #endif
  390.