BSD 4_4 release
[unix-history] / usr / src / sbin / XNSrouted / tables.c
index 755519f..4b00dc5 100644 (file)
@@ -1,6 +1,39 @@
+/*
+ * Copyright (c) 1985, 1993
+ *     The 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 rcsid[] = "$Header$";
-#endif
+static char sccsid[] = "@(#)tables.c   8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
 
 /*
  * Routing Table Management Daemon
 
 /*
  * Routing Table Management Daemon
@@ -13,8 +46,11 @@ static char rcsid[] = "$Header$";
 #define        DEBUG   0
 #endif
 
 #define        DEBUG   0
 #endif
 
+extern char *xns_ntoa();
+#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
+
 int    install = !DEBUG;               /* if 1 call kernel */
 int    install = !DEBUG;               /* if 1 call kernel */
-static  int    s;                      /* for routing table ioctl's */
+int    delete = 1;
 /*
  * Lookup dst in the tables for an exact match.
  */
 /*
  * Lookup dst in the tables for an exact match.
  */
@@ -102,6 +138,8 @@ rtadd(dst, gate, metric, state)
        int af = dst->sa_family, flags;
        u_int hash;
 
        int af = dst->sa_family, flags;
        u_int hash;
 
+       FIXLEN(dst);
+       FIXLEN(gate);
        if (af >= AF_MAX)
                return;
        (*afswitch[af].af_hash)(dst, &h);
        if (af >= AF_MAX)
                return;
        (*afswitch[af].af_hash)(dst, &h);
@@ -133,8 +171,9 @@ rtadd(dst, gate, metric, state)
         * from this host, discard the entry.  This should only
         * occur because of an incorrect entry in /etc/gateways.
         */
         * from this host, discard the entry.  This should only
         * occur because of an incorrect entry in /etc/gateways.
         */
-       if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
-               perror("SIOCADDRT");
+       if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
+               if (errno != EEXIST)
+                       perror("SIOCADDRT");
                if (errno == ENETUNREACH) {
                        TRACE_ACTION(DELETE, rt);
                        remque(rt);
                if (errno == ENETUNREACH) {
                        TRACE_ACTION(DELETE, rt);
                        remque(rt);
@@ -151,6 +190,7 @@ rtchange(rt, gate, metric)
        int doioctl = 0, metricchanged = 0;
        struct rtentry oldroute;
 
        int doioctl = 0, metricchanged = 0;
        struct rtentry oldroute;
 
+       FIXLEN(gate);
        if (!equal(&rt->rt_router, gate))
                doioctl++;
        if (metric != rt->rt_metric)
        if (!equal(&rt->rt_router, gate))
                doioctl++;
        if (metric != rt->rt_metric)
@@ -162,17 +202,39 @@ rtchange(rt, gate, metric)
                        rt->rt_router = *gate;
                }
                rt->rt_metric = metric;
                        rt->rt_router = *gate;
                }
                rt->rt_metric = metric;
-               rt->rt_state &= ~RTS_INTERFACE;
+               if ((rt->rt_state & RTS_INTERFACE) && metric) {
+                       rt->rt_state &= ~RTS_INTERFACE;
+                       syslog(LOG_ERR,
+                               "changing route from interface %s (timed out)",
+                               rt->rt_ifp->int_name);
+               }
                if (metric)
                if (metric)
-                       rt->rt_state |= RTF_GATEWAY;
+                       rt->rt_flags |= RTF_GATEWAY;
+               else
+                       rt->rt_flags &= ~RTF_GATEWAY;
                rt->rt_state |= RTS_CHANGED;
                TRACE_ACTION(CHANGE TO, rt);
        }
        if (doioctl && install) {
                rt->rt_state |= RTS_CHANGED;
                TRACE_ACTION(CHANGE TO, rt);
        }
        if (doioctl && install) {
-               if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
-                       perror("SIOCADDRT");
-               if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
-                       perror("SIOCDELRT");
+#ifndef RTM_ADD
+               if (rtioctl(ADD, &rt->rt_rt) < 0)
+                 syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
+                  xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+                  xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+               if (delete && rtioctl(DELETE, &oldroute) < 0)
+                       perror("rtioctl DELETE");
+#else
+               if (delete == 0) {
+                       if (rtioctl(ADD, &rt->rt_rt) >= 0)
+                               return;
+               } else {
+                       if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
+                               return;
+               }
+               syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
+                  xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+                  xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+#endif
        }
 }
 
        }
 }
 
@@ -180,9 +242,18 @@ rtdelete(rt)
        struct rt_entry *rt;
 {
 
        struct rt_entry *rt;
 {
 
+       struct sockaddr *sa = &(rt->rt_rt.rt_gateway);
+       FIXLEN(sa);
+#undef rt_dst
+       sa = &(rt->rt_rt.rt_dst);
+       FIXLEN(sa);
+       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);
        TRACE_ACTION(DELETE, rt);
-       if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
-               perror("SIOCDELRT");
+       if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
+               perror("rtioctl DELETE");
        remque(rt);
        free((char *)rt);
 }
        remque(rt);
        free((char *)rt);
 }
@@ -195,9 +266,54 @@ rtinit()
                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;
                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;
-               
-       if ((s = socket(AF_XNS, SOCK_RAW, IDPPROTO_RAW)) < 0) {
-               perror("socket");
-               exit(1);
+}
+int seqno;
+
+rtioctl(action, ort)
+       int action;
+       struct ortentry *ort;
+{
+#ifndef RTM_ADD
+       switch (action) {
+
+       case ADD:
+               return (ioctl(s, SIOCADDRT, (char *)ort));
+
+       case DELETE:
+               return (ioctl(s, SIOCDELRT, (char *)ort));
+
+       default:
+               return (-1);
+       }
+#else /* RTM_ADD */
+       struct {
+               struct rt_msghdr w_rtm;
+               struct sockaddr w_dst;
+               struct sockaddr w_gate;
+               struct sockaddr_ns w_netmask;
+       } w;
+#define rtm w.w_rtm
+
+       bzero((char *)&w, sizeof(w));
+       rtm.rtm_msglen = sizeof(w);
+       rtm.rtm_version = RTM_VERSION;
+       rtm.rtm_type = (action == ADD ? RTM_ADD :
+                               (action == DELETE ? RTM_DELETE : RTM_CHANGE));
+#undef rt_flags
+       rtm.rtm_flags = ort->rt_flags;
+       rtm.rtm_seq = ++seqno;
+       rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+       bcopy((char *)&ort->rt_dst, (char *)&w.w_dst, sizeof(w.w_dst));
+       bcopy((char *)&ort->rt_gateway, (char *)&w.w_gate, sizeof(w.w_gate));
+       w.w_gate.sa_family = w.w_dst.sa_family = AF_NS;
+       w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
+       if (rtm.rtm_flags & RTF_HOST) {
+               rtm.rtm_msglen -= sizeof(w.w_netmask);
+       } else {
+               w.w_netmask = ns_netmask;
+               rtm.rtm_msglen -= 8;
        }
        }
+       errno = 0;
+       return write(r, (char *)&w, rtm.rtm_msglen);
+#endif  /* RTM_ADD */
 }
 }