386BSD 0.1 development
[unix-history] / usr / src / sbin / routed / tables.c
index beed3a0..a05e023 100644 (file)
@@ -1,12 +1,39 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)tables.c   5.8 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)tables.c   5.17 (Berkeley) 6/1/90";
+#endif /* not lint */
 
 /*
  * Routing Table Management Daemon
 
 /*
  * Routing Table Management Daemon
@@ -14,12 +41,18 @@ static char sccsid[] = "@(#)tables.c        5.8 (Berkeley) %G%";
 #include "defs.h"
 #include <sys/ioctl.h>
 #include <errno.h>
 #include "defs.h"
 #include <sys/ioctl.h>
 #include <errno.h>
-#include <syslog.h>
+#include <sys/syslog.h>
 
 #ifndef DEBUG
 #define        DEBUG   0
 #endif
 
 
 #ifndef DEBUG
 #define        DEBUG   0
 #endif
 
+#ifdef RTM_ADD
+#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
+#else
+#define FIXLEN(s) { }
+#endif
+
 int    install = !DEBUG;               /* if 1 call kernel */
 
 /*
 int    install = !DEBUG;               /* if 1 call kernel */
 
 /*
@@ -56,6 +89,8 @@ again:
        return (0);
 }
 
        return (0);
 }
 
+struct sockaddr wildcard;      /* zero valued cookie for wildcard searches */
+
 /*
  * Find a route to dst as the kernel would.
  */
 /*
  * Find a route to dst as the kernel would.
  */
@@ -96,6 +131,15 @@ again:
                match = afswitch[af].af_netmatch;
                goto again;
        }
                match = afswitch[af].af_netmatch;
                goto again;
        }
+#ifdef notyet
+       /*
+        * Check for wildcard gateway, by convention network 0.
+        */
+       if (dst != &wildcard) {
+               dst = &wildcard, hash = 0;
+               goto again;
+       }
+#endif
        return (0);
 }
 
        return (0);
 }
 
@@ -106,7 +150,7 @@ rtadd(dst, gate, metric, state)
        struct afhash h;
        register struct rt_entry *rt;
        struct rthash *rh;
        struct afhash h;
        register struct rt_entry *rt;
        struct rthash *rh;
-       int af = dst->sa_family, flags, ifmetric;
+       int af = dst->sa_family, flags;
        u_int hash;
 
        if (af >= af_max)
        u_int hash;
 
        if (af >= af_max)
@@ -116,6 +160,8 @@ rtadd(dst, gate, metric, state)
        /*
         * Subnet flag isn't visible to kernel, move to state.  XXX
         */
        /*
         * Subnet flag isn't visible to kernel, move to state.  XXX
         */
+       FIXLEN(dst);
+       FIXLEN(gate);
        if (flags & RTF_SUBNET) {
                state |= RTS_SUBNET;
                flags &= ~RTF_SUBNET;
        if (flags & RTF_SUBNET) {
                state |= RTS_SUBNET;
                flags &= ~RTF_SUBNET;
@@ -136,28 +182,14 @@ rtadd(dst, gate, metric, state)
        rt->rt_timer = 0;
        rt->rt_flags = RTF_UP | flags;
        rt->rt_state = state | RTS_CHANGED;
        rt->rt_timer = 0;
        rt->rt_flags = RTF_UP | flags;
        rt->rt_state = state | RTS_CHANGED;
-       rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+       rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
        if (rt->rt_ifp == 0)
                rt->rt_ifp = if_ifwithnet(&rt->rt_router);
        if (rt->rt_ifp == 0)
                rt->rt_ifp = if_ifwithnet(&rt->rt_router);
-       if (rt->rt_ifp)
-               ifmetric = rt->rt_ifp->int_metric;
-       else
-               ifmetric = 0;
        if ((state & RTS_INTERFACE) == 0)
                rt->rt_flags |= RTF_GATEWAY;
        if ((state & RTS_INTERFACE) == 0)
                rt->rt_flags |= RTF_GATEWAY;
-       /*
-        * Set rt_ifmetric to the amount by which we
-        * increment the route when sending it to others.
-        */
-       if (state & RTS_INTERFACE) {
-               rt->rt_metric = 0;
-               rt->rt_ifmetric = metric + 1;
-       } else {
-               rt->rt_metric = metric;
-               rt->rt_ifmetric = ifmetric + 1;
-       }
+       rt->rt_metric = metric;
        insque(rt, rh);
        insque(rt, rh);
-       TRACE_ACTION(ADD, rt);
+       TRACE_ACTION("ADD", rt);
        /*
         * If the ioctl fails because the gateway is unreachable
         * from this host, discard the entry.  This should only
        /*
         * If the ioctl fails because the gateway is unreachable
         * from this host, discard the entry.  This should only
@@ -165,15 +197,14 @@ rtadd(dst, gate, metric, state)
         */
        if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
            ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
         */
        if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
            ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
-               if (errno != EEXIST &&
-                   dst->sa_family < af_max && gate->sa_family < af_max)
+               if (errno != EEXIST && gate->sa_family < af_max)
                        syslog(LOG_ERR,
                        "adding route to net/host %s through gateway %s: %m\n",
                           (*afswitch[dst->sa_family].af_format)(dst),
                           (*afswitch[gate->sa_family].af_format)(gate));
                perror("SIOCADDRT");
                if (errno == ENETUNREACH) {
                        syslog(LOG_ERR,
                        "adding route to net/host %s through gateway %s: %m\n",
                           (*afswitch[dst->sa_family].af_format)(dst),
                           (*afswitch[gate->sa_family].af_format)(gate));
                perror("SIOCADDRT");
                if (errno == ENETUNREACH) {
-                       TRACE_ACTION(DELETE, rt);
+                       TRACE_ACTION("DELETE", rt);
                        remque(rt);
                        free((char *)rt);
                }
                        remque(rt);
                        free((char *)rt);
                }
@@ -185,60 +216,122 @@ rtchange(rt, gate, metric)
        struct sockaddr *gate;
        short metric;
 {
        struct sockaddr *gate;
        short metric;
 {
-       int doioctl = 0, metricchanged = 0, delete = 0;
+       int add = 0, delete = 0, newgateway = 0;
        struct rtentry oldroute;
 
        struct rtentry oldroute;
 
-       if (!equal(&rt->rt_router, gate) && (rt->rt_state & RTS_INTERNAL) == 0)
-               doioctl++;
-       if (metric != rt->rt_metric) {
-               metricchanged++;
-               if (metric == HOPCNT_INFINITY)
+       FIXLEN(gate);
+       FIXLEN(&(rt->rt_router));
+       FIXLEN(&(rt->rt_dst));
+       if (!equal(&rt->rt_router, gate)) {
+               newgateway++;
+               TRACE_ACTION("CHANGE FROM ", rt);
+       } else if (metric != rt->rt_metric)
+               TRACE_NEWMETRIC(rt, metric);
+       if ((rt->rt_state & RTS_INTERNAL) == 0) {
+               /*
+                * If changing to different router, we need to add
+                * new route and delete old one if in the kernel.
+                * If the router is the same, we need to delete
+                * the route if has become unreachable, or re-add
+                * it if it had been unreachable.
+                */
+               if (newgateway) {
+                       add++;
+                       if (rt->rt_metric != HOPCNT_INFINITY)
+                               delete++;
+               } else if (metric == HOPCNT_INFINITY)
                        delete++;
                        delete++;
+               else if (rt->rt_metric == HOPCNT_INFINITY)
+                       add++;
        }
        }
-       if (doioctl || metricchanged) {
-               TRACE_ACTION(CHANGE FROM, rt);
-               if ((rt->rt_state & RTS_INTERFACE) &&
-                   metric > rt->rt_ifp->int_metric) {
-                       rt->rt_state &= ~RTS_INTERFACE;
-                       rt->rt_flags |= RTF_GATEWAY;
-                       syslog(LOG_ERR,
-                               "changing route from interface %s (timed out)",
-                               rt->rt_ifp->int_name);
-               }
-               if (doioctl || delete) {
-                       oldroute = rt->rt_rt;
-                       rt->rt_router = *gate;
-                       rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
-                       if (rt->rt_ifp == 0)
-                               rt->rt_ifp = if_ifwithnet(&rt->rt_router);
-               }
-               rt->rt_metric = metric;
-               rt->rt_state |= RTS_CHANGED;
-               TRACE_ACTION(CHANGE TO, rt);
+       if (delete)
+               oldroute = rt->rt_rt;
+       if ((rt->rt_state & RTS_INTERFACE) && delete) {
+               rt->rt_state &= ~RTS_INTERFACE;
+               rt->rt_flags |= RTF_GATEWAY;
+               if (metric > rt->rt_metric && delete)
+                       syslog(LOG_ERR, "%s route to interface %s (timed out)",
+                           add? "changing" : "deleting",
+                           rt->rt_ifp->int_name);
        }
        }
-       if (doioctl && install)
+       if (add) {
+               rt->rt_router = *gate;
+               rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+               if (rt->rt_ifp == 0)
+                       rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+       }
+       rt->rt_metric = metric;
+       rt->rt_state |= RTS_CHANGED;
+       if (newgateway)
+               TRACE_ACTION("CHANGE TO   ", rt);
+#ifndef RTM_ADD
+       if (add && install)
                if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
                        perror("SIOCADDRT");
                if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
                        perror("SIOCADDRT");
-       if ((doioctl || delete) && install)
+       if (delete && install)
+               if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+                       perror("SIOCDELRT");
+#else
+       if (delete && install)
                if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
                        perror("SIOCDELRT");
                if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
                        perror("SIOCDELRT");
+       if (add && install) {
+               if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+                       perror("SIOCADDRT");
+       }
+#endif
 }
 
 rtdelete(rt)
        struct rt_entry *rt;
 {
 
 }
 
 rtdelete(rt)
        struct rt_entry *rt;
 {
 
-       if (rt->rt_state & RTS_INTERFACE)
-               syslog(LOG_ERR, "deleting route to interface %s (timed out)",
-                       rt->rt_ifp->int_name);
-       TRACE_ACTION(DELETE, rt);
-       if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
-           ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
-               perror("SIOCDELRT");
+       TRACE_ACTION("DELETE", rt);
+       FIXLEN(&(rt->rt_router));
+       FIXLEN(&(rt->rt_dst));
+       if (rt->rt_metric < HOPCNT_INFINITY) {
+           if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
+               syslog(LOG_ERR,
+                   "deleting route to interface %s? (timed out?)",
+                   rt->rt_ifp->int_name);
+           if (install &&
+               (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+               ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+                   perror("SIOCDELRT");
+       }
        remque(rt);
        free((char *)rt);
 }
 
        remque(rt);
        free((char *)rt);
 }
 
+rtdeleteall(sig)
+       int sig;
+{
+       register struct rthash *rh;
+       register struct rt_entry *rt;
+       struct rthash *base = hosthash;
+       int doinghost = 1;
+
+again:
+       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+               rt = rh->rt_forw;
+               for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+                       if (rt->rt_state & RTS_INTERFACE ||
+                           rt->rt_metric >= HOPCNT_INFINITY)
+                               continue;
+                       TRACE_ACTION("DELETE", rt);
+                       if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
+                           ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+                               perror("SIOCDELRT");
+               }
+       }
+       if (doinghost) {
+               doinghost = 0;
+               base = nethash;
+               goto again;
+       }
+       exit(sig);
+}
+
 /*
  * If we have an interface to the wide, wide world,
  * add an entry for an Internet default route (wildcard) to the internal
 /*
  * If we have an interface to the wide, wide world,
  * add an entry for an Internet default route (wildcard) to the internal
@@ -250,7 +343,7 @@ rtdefault()
 {
        extern struct sockaddr inet_default;
 
 {
        extern struct sockaddr inet_default;
 
-       rtadd(&inet_default, &inet_default, 0,
+       rtadd(&inet_default, &inet_default, 1,
                RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
 }
 
                RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
 }
 
@@ -263,3 +356,28 @@ rtinit()
        for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
                rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
 }
        for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
                rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
 }
+
+
+/* ffrom /sys/i386/i386/machdep.c */
+/*
+ * insert an element into a queue 
+ */
+insque(element, head)
+       register struct rthash *element, *head;
+{
+       element->rt_forw = head->rt_forw;
+       head->rt_forw = (struct rt_entry *)element;
+       element->rt_back = (struct rt_entry *)head;
+       ((struct rthash *)(element->rt_forw))->rt_back=(struct rt_entry *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+remque(element)
+       register struct rthash *element;
+{
+       ((struct rthash *)(element->rt_forw))->rt_back = element->rt_back;
+       ((struct rthash *)(element->rt_back))->rt_forw = element->rt_forw;
+       element->rt_back = (struct rt_entry *)0;
+}