changes per sam
[unix-history] / usr / src / sbin / routed / routed.c
index 14dfb96..3bb1f0e 100644 (file)
@@ -1,19 +1,20 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)routed.c   4.1 %G%";
+static char sccsid[] = "@(#)routed.c   4.13 %G%";
 #endif
 
 #endif
 
-#include <sys/param.h>
-#include <sys/protosw.h>
+/*
+ * Routing Table Management Daemon
+ */
+#include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/in.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <net/in.h>
-#define        KERNEL
-#include <net/route.h>
 #include <net/if.h>
 #include <errno.h>
 #include <stdio.h>
 #include <nlist.h>
 #include <signal.h>
 #include <net/if.h>
 #include <errno.h>
 #include <stdio.h>
 #include <nlist.h>
 #include <signal.h>
+#include <time.h>
 #include "rip.h"
 #include "router.h"
 
 #include "rip.h"
 #include "router.h"
 
@@ -23,6 +24,7 @@ static char sccsid[] = "@(#)routed.c  4.1 %G%";
 #define        remque(q)       _remque((caddr_t)q)
 #define equal(a1, a2) \
        (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
 #define        remque(q)       _remque((caddr_t)q)
 #define equal(a1, a2) \
        (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
+#define        min(a,b)        ((a)>(b)?(b):(a))
 
 struct nlist nl[] = {
 #define        N_IFNET         0
 
 struct nlist nl[] = {
 #define        N_IFNET         0
@@ -33,19 +35,24 @@ struct nlist nl[] = {
 struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER };
 
 int    s;
 struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER };
 
 int    s;
-int    kmem;
+int    snoroute;               /* socket with no routing */
+int    kmem = -1;
 int    supplier;               /* process should supply updates */
 int    supplier;               /* process should supply updates */
-int    initializing;           /* stem off broadcast() calls */
-int    install = 0;            /* if 1 call kernel */
+int    install = 1;            /* if 1 call kernel */
+int    lookforinterfaces = 1;
+int    performnlist = 1;
 int    timeval;
 int    timer();
 int    cleanup();
 int    trace = 0;
 int    timeval;
 int    timer();
 int    cleanup();
 int    trace = 0;
+FILE   *ftrace;
 
 char   packet[MAXPACKETSIZE];
 
 
 char   packet[MAXPACKETSIZE];
 
+struct in_addr if_makeaddr();
+struct ifnet *if_ifwithaddr(), *if_ifwithnet();
 extern char *malloc();
 extern char *malloc();
-extern int errno;
+extern int errno, exit();
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
@@ -54,21 +61,27 @@ main(argc, argv)
        int cc;
        struct sockaddr from;
        
        int cc;
        struct sockaddr from;
        
-       {   int t = open("/dev/tty", 2);
-           if (t >= 0) {
-               ioctl(t, TIOCNOTTY, 0);
-               close(t);
-           }
+#ifndef DEBUG
+       if (fork())
+               exit(0);
+       for (cc = 0; cc < 10; cc++)
+               (void) close(cc);
+       (void) open("/", 0);
+       (void) dup2(0, 1);
+       (void) dup2(0, 2);
+       { int t = open("/dev/tty", 2);
+         if (t >= 0) {
+               ioctl(t, TIOCNOTTY, (char *)0);
+               (void) close(t);
+         }
        }
        }
+#endif
        if (trace) {
        if (trace) {
-               (void) fclose(stdout);
-               (void) fclose(stderr);
-               (void) fopen("trace", "a");
-               (void) dup(fileno(stdout));
-               setbuf(stdout, NULL);
-
+               ftrace = fopen("/etc/routerlog", "w");
+               dup2(fileno(ftrace), 1);
+               dup2(fileno(ftrace), 2);
        }
        }
-#ifdef vax
+#ifdef vax || pdp11
        myaddr.sin_port = htons(myaddr.sin_port);
 #endif
 again:
        myaddr.sin_port = htons(myaddr.sin_port);
 #endif
 again:
@@ -78,21 +91,27 @@ again:
                sleep(30);
                goto again;
        }
                sleep(30);
                goto again;
        }
+again2:
+       snoroute = socket(SOCK_DGRAM, 0, 0, SO_DONTROUTE);
+       if (snoroute < 0) {
+               perror("socket");
+               sleep(30);
+               goto again2;
+       }
        rtinit();
        rtinit();
-       getothers();
        getinterfaces();
        request();
 
        argv++, argc--;
        while (argc > 0) {
                if (strcmp(*argv, "-s") == 0)
        getinterfaces();
        request();
 
        argv++, argc--;
        while (argc > 0) {
                if (strcmp(*argv, "-s") == 0)
-                       supplier++;
+                       supplier = 1;
                else if (strcmp(*argv, "-q") == 0)
                        supplier = 0;
                argv++, argc--;
        }
        sigset(SIGALRM, timer);
                else if (strcmp(*argv, "-q") == 0)
                        supplier = 0;
                argv++, argc--;
        }
        sigset(SIGALRM, timer);
-       alarm(TIMER_RATE);
+       timer();
 
        /*
         * Listen for routing packets
 
        /*
         * Listen for routing packets
@@ -111,98 +130,104 @@ again:
 }
 
 /*
 }
 
 /*
- * Look in a file for any gateways we should configure
- * outside the directly connected ones.  This is a kludge,
- * but until we can find out about gateways on the "other side"
- * of the ARPANET using GGP, it's a must.
+ * Timer routine:
  *
  *
- * We don't really know the distance to the gateway, so we
- * assume it's a neighbor.
+ * o handle timers on table entries,
+ * o invalidate entries which haven't been updated in a while,
+ * o delete entries which are too old,
+ * o if we're an internetwork router, supply routing updates
+ *   periodically
  */
  */
-getothers()
+timer()
 {
 {
-       struct sockaddr_in dst, gate;
-       FILE *fp = fopen("/etc/gateways", "r");
-       struct rt_entry *rt;
+       register struct rthash *rh;
+       register struct rt_entry *rt;
+       struct rthash *base = hosthash;
+       int doinghost = 1;
 
 
-       if (fp == NULL)
-               return;
-       bzero((char *)&dst, sizeof (dst));
-       bzero((char *)&gate, sizeof (gate));
-       dst.sin_family = AF_INET;
-       gate.sin_family = AF_INET;
-       while (fscanf(fp, "%x %x", &dst.sin_addr.s_addr, 
-          &gate.sin_addr.s_addr) != EOF) {
-               rtadd((struct sockaddr *)&dst, (struct sockaddr *)&gate, 1);
-               rt = rtlookup((struct sockaddr *)&dst);
-               if (rt)
-                       rt->rt_flags |= RTF_SILENT;
-       }
-       fclose(fp);
-}
+       if (trace)
+               printf(">>> time %d >>>\n", timeval);
+again:
+       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+               rt = rh->rt_forw;
+               for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
 
 
-struct ifnet *
-if_ifwithaddr(addr)
-       struct sockaddr *addr;
-{
-       register struct ifnet *ifp;
+                       /*
+                        * If the host is indicated to be
+                        * "hidden" (i.e. it's one we got
+                        * from the initialization file),
+                        * don't time out it's entry.
+                        */
+                       if ((rt->rt_state & RTS_PASSIVE) == 0)
+                               rt->rt_timer += TIMER_RATE;
+                       log("", rt);
 
 
-#define        same(a1, a2) \
-       (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
-       for (ifp = ifnet; ifp; ifp = ifp->if_next) {
-               if (ifp->if_addr.sa_family != addr->sa_family)
-                       continue;
-               if (same(&ifp->if_addr, addr))
-                       break;
-               if ((ifp->if_flags & IFF_BROADCAST) &&
-                   same(&ifp->if_broadaddr, addr))
-                       break;
-       }
-       return (ifp);
-#undef same
-}
+                       /*
+                        * If the entry should be deleted
+                        * attempt to do so and reclaim space.
+                        */
+                       if (rt->rt_timer >= GARBAGE_TIME ||
+                         (rt->rt_state & RTS_DELRT)) {
+                               rt = rt->rt_back;
+                               rtdelete(rt->rt_forw);
+                               continue;
+                       }
 
 
-struct ifnet *
-if_ifwithnet(addr)
-       register struct sockaddr *addr;
-{
-       register struct ifnet *ifp;
-       register int af = addr->sa_family;
-       register int (*netmatch)();
+                       /*
+                        * If we haven't heard from the router
+                        * in a long time indicate the route is
+                        * hard to reach.
+                        */
+                       if (rt->rt_timer >= EXPIRE_TIME)
+                               rt->rt_metric = HOPCNT_INFINITY;
 
 
-       if (af >= AF_MAX)
-               return (0);
-       netmatch = afswitch[af].af_netmatch;
-       for (ifp = ifnet; ifp; ifp = ifp->if_next) {
-               if (af != ifp->if_addr.sa_family)
-                       continue;
-               if ((*netmatch)(addr, &ifp->if_addr))
-                       break;
+                       /*
+                        * If a change or addition is to be made
+                        * and this isn't time to broadcast an
+                        * update, then broadcast the change.
+                        */
+                       if ((rt->rt_state & (RTS_CHGRT|RTS_ADDRT)) &&
+                           supplier &&
+                           (timeval + TIMER_RATE) % SUPPLY_INTERVAL)
+                               broadcast(rt);
+
+                       if (rt->rt_state & RTS_CHGRT) {
+                               struct rtentry oldroute;
+
+                               oldroute = rt->rt_rt;
+                               rt->rt_router = rt->rt_newrouter;
+                               if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+                                       perror("SIOCADDRT");
+                               if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+                                       perror("SIOCDELRT");
+                               rt->rt_state &= ~RTS_CHGRT;
+                       }
+                       if (rt->rt_state & RTS_ADDRT) {
+                               if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+                                       perror("SIOCADDRT");
+                               rt->rt_state &= ~RTS_ADDRT;
+                       }
+               }
        }
        }
-       return (ifp);
-}
-
-struct in_addr
-if_makeaddr(net, host)
-       int net, host;
-{
-       u_long addr;
-
-       if (net < 128)
-               addr = (net << 24) | host;
-       else if (net < 65536)
-               addr = (net << 16) | host;
-       else
-               addr = (net << 8) | host;
-#ifdef vax
-       addr = htonl(addr);
-#endif
-       return (*(struct in_addr *)&addr);
+       if (doinghost) {
+               doinghost = 0;
+               base = nethash;
+               goto again;
+       }
+       timeval += TIMER_RATE;
+       if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
+               getinterfaces();
+       if (supplier && (timeval % SUPPLY_INTERVAL) == 0)
+               supplyall();
+       if (trace)
+               printf("<<< time %d <<<\n", timeval);
+       alarm(TIMER_RATE);
 }
 
 }
 
+struct ifnet *ifnet;
 /*
  * Find the network interfaces attached to this machine.
 /*
  * Find the network interfaces attached to this machine.
- * The info is used to::
+ * The info is used to:
  *
  * (1) initialize the routing tables, as done by the kernel.
  * (2) ignore incoming packets we send.
  *
  * (1) initialize the routing tables, as done by the kernel.
  * (2) ignore incoming packets we send.
@@ -210,87 +235,152 @@ if_makeaddr(net, host)
  * (4) figure out if we're an internetwork gateway.
  *
  * We don't handle anything but Internet addresses.
  * (4) figure out if we're an internetwork gateway.
  *
  * We don't handle anything but Internet addresses.
+ *
+ * Note: this routine may be called periodically to
+ * scan for new interfaces.  In fact, the timer routine
+ * does so based on the flag lookforinterfaces.  The
+ * flag performnlist is set whenever something odd occurs
+ * while scanning the kernel; this is likely to occur
+ * if /vmunix isn't up to date (e.g. someone booted /ovmunix).
  */
 getinterfaces()
 {
  */
 getinterfaces()
 {
-       register struct ifnet **pifp, *ifp;
+       struct ifnet *ifp;
+       struct ifnet ifstruct, *next;
        struct sockaddr_in net;
        struct sockaddr_in net;
-       struct in_addr logicaladdr;
+       register struct sockaddr *dst;
        int nets;
 
        int nets;
 
-       nlist("/vmunix", nl);
-       if (nl[N_IFNET].n_value == 0) {
-               printf("ifnet: symbol not in namelist\n");
-               exit(1);
+       if (performnlist) {
+               nlist("/vmunix", nl);
+               if (nl[N_IFNET].n_value == 0) {
+                       performnlist++;
+                       printf("ifnet: not in namelist\n");
+                       return;
+               }
+               performnlist = 0;
        }
        }
-       kmem = open("/dev/kmem", 0);
        if (kmem < 0) {
        if (kmem < 0) {
-               perror("/dev/kmem");
-               exit(1);
+               kmem = open("/dev/kmem", 0);
+               if (kmem < 0) {
+                       perror("/dev/kmem");
+                       return;
+               }
+       }
+       if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
+           read(kmem, (char *)&ifp, sizeof (ifp)) != sizeof (ifp)) {
+               performnlist = 1;
+               return;
        }
        }
-       (void) lseek(kmem, (long)nl[N_IFNET].n_value, 0);
-       (void) read(kmem, (char *)&ifnet, sizeof (ifnet));
        bzero((char *)&net, sizeof (net));
        net.sin_family = AF_INET;
        bzero((char *)&net, sizeof (net));
        net.sin_family = AF_INET;
-       logicaladdr.s_addr = 0;
+       lookforinterfaces = 0;
        nets = 0;
        nets = 0;
-       pifp = &ifnet;
-       initializing = 1;
-       while (*pifp) {
-               struct sockaddr_in *sin;
-
-               (void) lseek(kmem, (long)*pifp, 0);
-               ifp = *pifp = (struct ifnet *)malloc(sizeof (struct ifnet));
-               if (ifp == 0) {
-                       printf("routed: out of memory\n");
-                       break;
-               }
-               if (read(kmem, (char *)ifp, sizeof (*ifp)) != sizeof (*ifp)) {
+       while (ifp) {
+               if (lseek(kmem, (long)ifp, 0) == -1 ||
+                 read(kmem, (char *)&ifstruct, sizeof (ifstruct)) !=
+                 sizeof (ifstruct)) {
                        perror("read");
                        perror("read");
+                       lookforinterfaces = performnlist = 1;
                        break;
                }
                        break;
                }
-               if (ifp->if_net == LOOPBACKNET)
+               ifp = &ifstruct;
+               if ((ifp->if_flags & IFF_UP) == 0) {
+                       lookforinterfaces = 1;
+       skip:
+                       ifp = ifp->if_next;
+                       continue;
+               }
+               if (ifp->if_addr.sa_family != AF_INET)
                        goto skip;
                        goto skip;
-               nets++;
-               if ((ifp->if_flags & IFF_UP) == 0)
+               /* ignore software loopback networks. */
+               if (ifp->if_net == LOOPBACKNET)
                        goto skip;
                        goto skip;
-
-               /*
-                * Kludge: don't treat logical host pseudo-interface
-                *         as a net route, instead fabricate route
-                *         to get packets back from the gateway.
-                */
-               sin = (struct sockaddr_in *)&ifp->if_addr;
-               if (sin->sin_family == AF_INET && ifp->if_net == 10 &&
-                   sin->sin_addr.s_lh) {
-                       logicaladdr = sin->sin_addr;
+               /* check if we already know about this one */
+               if (if_ifwithaddr(&ifstruct.if_addr)) {
+                       nets++;
                        goto skip;
                }
                        goto skip;
                }
+               ifp = (struct ifnet *)malloc(sizeof (struct ifnet));
+               if (ifp == 0) {
+                       printf("routed: out of memory\n");
+                       break;
+               }
+               bcopy((char *)&ifstruct, (char *)ifp, sizeof (struct ifnet));
 
                /*
 
                /*
-                * Before we can handle point-point links, the interface
-                * structure will have to include an indicator to allow
-                * us to distinguish entries from "network" entries.
+                * Count the # of directly connected networks
+                * and point to point links which aren't looped
+                * back to ourself.  This is used below to
+                * decide if we should be a routing "supplier".
                 */
                 */
-               net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
-               rtadd((struct sockaddr *)&net, (struct sockaddr *)sin, 0);
-       skip:
-               pifp = &ifp->if_next;
+               if ((ifp->if_flags & IFF_POINTOPOINT) == 0 ||
+                   if_ifwithaddr(&ifp->if_dstaddr) == 0)
+                       nets++;
+
+               if (ifp->if_flags & IFF_POINTOPOINT)
+                       dst = &ifp->if_dstaddr;
+               else {
+                       net.sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
+                       dst = (struct sockaddr *)&net;
+               }
+               next = ifp->if_next;
+               ifp->if_next = ifnet;
+               ifnet = ifp;
+               if (rtlookup(dst) == 0) {
+                       struct rt_entry *rt;
+
+                       rtadd(dst, &ifp->if_addr, 0);
+                       rt = rtlookup(dst);
+                       if (rt)
+                               rt->rt_state |= RTS_INTERFACE;
+               }
+               ifp = next;
        }
        }
-       if (logicaladdr.s_addr) {
-               struct rt_entry *rt;
+       supplier = nets > 1;
+       getothers();
+}
 
 
-               net.sin_addr = logicaladdr;
-               if (ifnet)
-                       rtadd((struct sockaddr *)&net, &ifnet->if_addr, 0);
-               /* yech...yet another logical host kludge */
-               rt = rtlookup((struct sockaddr *)&net);
-               if (rt)
-                       rt->rt_flags |= RTF_SILENT;
+/*
+ * Look in a file for any gateways we should configure
+ * outside the directly connected ones.  This is a kludge,
+ * but until we can find out about gateways on the "other side"
+ * of the ARPANET using GGP, it's a must.
+ *
+ * File format is one entry per line, 
+ *     destination gateway flags       (all hex #'s)
+ *
+ * We don't really know the distance to the gateway, so we
+ * assume it's a neighbor.
+ */
+getothers()
+{
+       struct sockaddr_in dst, gate;
+       FILE *fp;
+       struct rt_entry *rt;
+       char flags[132];
+
+       fp = fopen("/etc/gateways", "r");
+       if (fp == NULL)
+               return;
+       bzero((char *)&dst, sizeof (dst));
+       bzero((char *)&gate, sizeof (gate));
+       dst.sin_family = AF_INET;
+       gate.sin_family = AF_INET;
+       flags[0] = '\0';
+       while (fscanf(fp, "dst %x gateway %x %s\n", &dst.sin_addr.s_addr, 
+          &gate.sin_addr.s_addr, flags) != EOF) {
+               if (rt = rtlookup((struct sockaddr *)&dst)) {
+                       flags[0] = '\0';
+                       continue;
+               }
+               rtadd((struct sockaddr *)&dst,(struct sockaddr *)&gate,1);
+               rt = rtlookup(&dst);
+               if (strcmp(flags, "passive") == 0)
+                       rt->rt_state |= RTS_PASSIVE;
+               flags[0] = '\0';
        }
        }
-       (void) close(kmem);
-       initializing = 0;
-       supplier = nets > 1;
+       fclose(fp);
 }
 
 /*
 }
 
 /*
@@ -299,23 +389,12 @@ getinterfaces()
  */
 request()
 {
  */
 request()
 {
-       register struct rt_entry *rt;
-       register struct rt_hash *rh;
-       struct rt_hash *base = hosthash;
-       int doinghost = 1;
+       register struct rip *msg = (struct rip *)packet;
 
 
-again:
-       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
-       for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
-               if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0)
-                       continue;
-               getall(rt);
-       }
-       if (doinghost) {
-               base = nethash;
-               doinghost = 0;
-               goto again;
-       }
+       msg->rip_cmd = RIPCMD_REQUEST;
+       msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
+       msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
+       sendall();
 }
 
 /*
 }
 
 /*
@@ -325,33 +404,41 @@ again:
 broadcast(entry)
        struct rt_entry *entry;
 {
 broadcast(entry)
        struct rt_entry *entry;
 {
-       register struct rt_hash *rh;
-       register struct rt_entry *rt;
-       register struct sockaddr *dst;
-       struct rt_hash *base = hosthash;
-       int doinghost = 1;
        struct rip *msg = (struct rip *)packet;
 
        struct rip *msg = (struct rip *)packet;
 
-       if (trace)
-               log("broadcast", entry);
+       log("broadcast", entry);
        msg->rip_cmd = RIPCMD_RESPONSE;
        msg->rip_nets[0].rip_dst = entry->rt_dst;
        msg->rip_cmd = RIPCMD_RESPONSE;
        msg->rip_nets[0].rip_dst = entry->rt_dst;
-       msg->rip_nets[0].rip_metric = entry->rt_metric + 1;
+       msg->rip_nets[0].rip_metric = min(entry->rt_metric+1, HOPCNT_INFINITY);
+       sendall();
+}
+
+/*
+ * Send "packet" to all neighbors.
+ */
+sendall()
+{
+       register struct rthash *rh;
+       register struct rt_entry *rt;
+       register struct sockaddr *dst;
+       struct rthash *base = hosthash;
+       int doinghost = 1;
 
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
 
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
-               if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0)
+               if ((rt->rt_state&RTS_PASSIVE) || rt->rt_metric > 0)
                        continue;
                if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
                        dst = &rt->rt_ifp->if_broadaddr;
                else
                        continue;
                if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
                        dst = &rt->rt_ifp->if_broadaddr;
                else
-                       dst = &rt->rt_gateway;
-               (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip));
+                       dst = &rt->rt_router;
+               (*afswitch[dst->sa_family].af_output)
+                       (s, dst, sizeof (struct rip));
        }
        if (doinghost) {
        }
        if (doinghost) {
-               doinghost = 0;
                base = nethash;
                base = nethash;
+               doinghost = 0;
                goto again;
        }
 }
                goto again;
        }
 }
@@ -363,23 +450,23 @@ again:
 supplyall()
 {
        register struct rt_entry *rt;
 supplyall()
 {
        register struct rt_entry *rt;
-       register struct rt_hash *rh;
+       register struct rthash *rh;
        register struct sockaddr *dst;
        register struct sockaddr *dst;
-       struct rt_hash *base = hosthash;
+       struct rthash *base = hosthash;
        int doinghost = 1;
 
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
        int doinghost = 1;
 
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
-               if ((rt->rt_flags & RTF_SILENT) || rt->rt_metric > 0)
+               if ((rt->rt_state&RTS_PASSIVE) ||
+                   (!(rt->rt_state&RTS_INTERFACE) && rt->rt_metric > 0))
                        continue;
                if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
                        dst = &rt->rt_ifp->if_broadaddr;
                else
                        continue;
                if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
                        dst = &rt->rt_ifp->if_broadaddr;
                else
-                       dst = &rt->rt_gateway;
-               if (trace)
-                       log("supply", rt);
-               supply(dst);
+                       dst = &rt->rt_router;
+               log("supply", rt);
+               supply(rt->rt_state&RTS_INTERFACE ? snoroute : s, dst);
        }
        if (doinghost) {
                base = nethash;
        }
        if (doinghost) {
                base = nethash;
@@ -391,15 +478,16 @@ again:
 /*
  * Supply routing information to target "sa".
  */
 /*
  * Supply routing information to target "sa".
  */
-supply(sa)
+supply(s, sa)
+       int s;
        struct sockaddr *sa;
 {
        struct rip *msg = (struct rip *)packet;
        struct netinfo *n = msg->rip_nets;
        struct sockaddr *sa;
 {
        struct rip *msg = (struct rip *)packet;
        struct netinfo *n = msg->rip_nets;
-       register struct rt_hash *rh;
+       register struct rthash *rh;
        register struct rt_entry *rt;
        register struct rt_entry *rt;
-       struct rt_hash *base = hosthash;
-       int space = MAXPACKETSIZE - sizeof (int), doinghost = 1;
+       struct rthash *base = hosthash;
+       int doinghost = 1, size;
        int (*output)() = afswitch[sa->sa_family].af_output;
 
        msg->rip_cmd = RIPCMD_RESPONSE;
        int (*output)() = afswitch[sa->sa_family].af_output;
 
        msg->rip_cmd = RIPCMD_RESPONSE;
@@ -411,39 +499,22 @@ again:
                 * Flush packet out if not enough room for
                 * another routing table entry.
                 */
                 * Flush packet out if not enough room for
                 * another routing table entry.
                 */
-               if (space < sizeof (struct netinfo)) {
-                       (*output)(sa, MAXPACKETSIZE - space);
-                       space = MAXPACKETSIZE - sizeof (int);
+               size = (char *)n - packet;
+               if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
+                       (*output)(s, sa, size);
                        n = msg->rip_nets;
                }
                n->rip_dst = rt->rt_dst;
                        n = msg->rip_nets;
                }
                n->rip_dst = rt->rt_dst;
-               n->rip_metric = rt->rt_metric + 1;
-               n++, space -= sizeof (struct netinfo);
+               n->rip_metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
+               n++;
        }
        if (doinghost) {
                doinghost = 0;
                base = nethash;
                goto again;
        }
        }
        if (doinghost) {
                doinghost = 0;
                base = nethash;
                goto again;
        }
-
-       if (space < MAXPACKETSIZE - sizeof (int))
-               (*output)(sa, MAXPACKETSIZE - space);
-}
-
-getall(rt)
-       struct rt_entry *rt;
-{
-       register struct rip *msg = (struct rip *)packet;
-       struct sockaddr *dst;
-
-       msg->rip_cmd = RIPCMD_REQUEST;
-       msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
-       msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
-       if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
-               dst = &rt->rt_ifp->if_broadaddr;
-       else
-               dst = &rt->rt_gateway;
-       (*afswitch[dst->sa_family].af_output)(dst, sizeof (struct rip));
+       if (n != msg->rip_nets)
+               (*output)(s, sa, (char *)n - packet);
 }
 
 /*
 }
 
 /*
@@ -458,24 +529,25 @@ rip_respond(from, size)
        struct rt_entry *rt;
        int newsize = 0;
        
        struct rt_entry *rt;
        int newsize = 0;
        
-       size -= sizeof (int);
+       size -= 4 * sizeof (char);
        while (size > 0) {
                if (size < sizeof (struct netinfo))
                        break;
                size -= sizeof (struct netinfo);
                if (np->rip_dst.sa_family == AF_UNSPEC &&
                    np->rip_metric == HOPCNT_INFINITY && size == 0) {
        while (size > 0) {
                if (size < sizeof (struct netinfo))
                        break;
                size -= sizeof (struct netinfo);
                if (np->rip_dst.sa_family == AF_UNSPEC &&
                    np->rip_metric == HOPCNT_INFINITY && size == 0) {
-                       supply(from);
+                       supply(s, from);
                        return;
                }
                rt = rtlookup(&np->rip_dst);
                        return;
                }
                rt = rtlookup(&np->rip_dst);
-               np->rip_metric = rt == 0 ? HOPCNT_INFINITY : rt->rt_metric + 1;
+               np->rip_metric = rt == 0 ?
+                       HOPCNT_INFINITY : min(rt->rt_metric+1, HOPCNT_INFINITY);
                np++, newsize += sizeof (struct netinfo);
        }
        if (newsize > 0) {
                msg->rip_cmd = RIPCMD_RESPONSE;
                newsize += sizeof (int);
                np++, newsize += sizeof (struct netinfo);
        }
        if (newsize > 0) {
                msg->rip_cmd = RIPCMD_RESPONSE;
                newsize += sizeof (int);
-               (*afswitch[from->sa_family].af_output)(from, newsize);
+               (*afswitch[from->sa_family].af_output)(s, from, newsize);
        }
 }
 
        }
 }
 
@@ -490,21 +562,28 @@ rip_input(from, size)
        struct rt_entry *rt;
        struct netinfo *n;
 
        struct rt_entry *rt;
        struct netinfo *n;
 
-       if (msg->rip_cmd != RIPCMD_RESPONSE &&
-           msg->rip_cmd != RIPCMD_REQUEST)
-               return;
+       switch (msg->rip_cmd) {
 
 
-       /*
-        * The router port is in the lower 1K of the UDP port space,
-        * and so is priviledged.  Hence we can "authenticate" incoming
-        * updates simply by checking the source port.
-        */
-       if (msg->rip_cmd == RIPCMD_RESPONSE &&
-           (*afswitch[from->sa_family].af_portmatch)(from) == 0)
+       default:
                return;
                return;
-       if (msg->rip_cmd == RIPCMD_REQUEST) {
+
+       case RIPCMD_REQUEST:
                rip_respond(from, size);
                return;
                rip_respond(from, size);
                return;
+
+       case RIPCMD_TRACEON:
+       case RIPCMD_TRACEOFF:
+               /* verify message came from a priviledged port */
+               if ((*afswitch[from->sa_family].af_portcheck)(from) == 0)
+                       return;
+               tracecmd(msg->rip_cmd, msg, size);
+               return;
+
+       case RIPCMD_RESPONSE:
+               /* verify message came from a router */
+               if ((*afswitch[from->sa_family].af_portmatch)(from) == 0)
+                       return;
+               break;
        }
 
        /*
        }
 
        /*
@@ -515,7 +594,8 @@ rip_input(from, size)
         */
        (*afswitch[from->sa_family].af_canon)(from);
        if (trace)
         */
        (*afswitch[from->sa_family].af_canon)(from);
        if (trace)
-               printf("input from %x\n", from->sin_addr);
+               printf("input from %x\n",
+                       ((struct sockaddr_in *)from)->sin_addr);
        /*
         * If response packet is from ourselves, use it only
         * to reset timer on entry.  Otherwise, we'd believe
        /*
         * If response packet is from ourselves, use it only
         * to reset timer on entry.  Otherwise, we'd believe
@@ -526,18 +606,19 @@ rip_input(from, size)
         * don't hear their own broadcasts?
         */
        if (if_ifwithaddr(from)) {
         * don't hear their own broadcasts?
         */
        if (if_ifwithaddr(from)) {
-               rt = rtlookup(from);
+               rt = rtfind(from);
                if (rt)
                        rt->rt_timer = 0;
                return;
        }
                if (rt)
                        rt->rt_timer = 0;
                return;
        }
-       size -= sizeof (int);
+       size -= 4 * sizeof (char);
        n = msg->rip_nets;
        for (; size > 0; size -= sizeof (struct netinfo), n++) {
                if (size < sizeof (struct netinfo))
                        break;
                if (trace)
        n = msg->rip_nets;
        for (; size > 0; size -= sizeof (struct netinfo), n++) {
                if (size < sizeof (struct netinfo))
                        break;
                if (trace)
-                       printf("dst %x hc %d...", n->rip_dst.sin_addr,
+                       printf("dst %x hc %d...",
+                               ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
                                n->rip_metric);
                rt = rtlookup(&n->rip_dst);
 
                                n->rip_metric);
                rt = rtlookup(&n->rip_dst);
 
@@ -555,26 +636,72 @@ rip_input(from, size)
 
                if (trace)
                        printf("ours: gate %x hc %d timer %d\n",
 
                if (trace)
                        printf("ours: gate %x hc %d timer %d\n",
-                       rt->rt_gateway.sin_addr,
-                       rt->rt_metric, rt->rt_timer);
+                         ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
+                         rt->rt_metric, rt->rt_timer);
                /*
                 * Update the entry if one of the following is true:
                 *
                 * (1) The update came directly from the gateway.
                 * (2) A shorter path is provided.
                 * (3) The entry hasn't been updated in a while
                /*
                 * Update the entry if one of the following is true:
                 *
                 * (1) The update came directly from the gateway.
                 * (2) A shorter path is provided.
                 * (3) The entry hasn't been updated in a while
-                *     and a path of equivalent cost is offered.
+                *     and a path of equivalent cost is offered
+                *     (with the cost finite).
                 */
                 */
-               if (equal(from, &rt->rt_gateway) ||
+               if (equal(from, &rt->rt_router) ||
                    rt->rt_metric > n->rip_metric ||
                    (rt->rt_timer > (EXPIRE_TIME/2) &&
                    rt->rt_metric > n->rip_metric ||
                    (rt->rt_timer > (EXPIRE_TIME/2) &&
-                   rt->rt_metric == n->rip_metric)) {
+                   rt->rt_metric == n->rip_metric &&
+                   rt->rt_metric < HOPCNT_INFINITY)) {
                        rtchange(rt, from, n->rip_metric);
                        rt->rt_timer = 0;
                }
        }
 }
 
                        rtchange(rt, from, n->rip_metric);
                        rt->rt_timer = 0;
                }
        }
 }
 
+/*
+ * Handle tracing requests.
+ */
+tracecmd(cmd, msg, size)
+       int cmd, size;
+       struct rip *msg;
+{
+       time_t t;
+
+       if (cmd == RIPCMD_TRACEOFF) {
+               if (!trace)
+                       return;
+               t = time(0);
+               printf("*** Tracing turned off at %.24s ***\n", ctime(&t));
+               fflush(stdout), fflush(stderr);
+               if (ftrace)
+                       fclose(ftrace);
+               (void) close(1), (void) close(2);
+               trace = 0;
+               return;
+       }
+       if (trace)
+               return;
+       packet[size] = '\0';
+       ftrace = fopen(msg->rip_tracefile, "a");
+       if (ftrace == NULL)
+               return;
+       (void) dup2(fileno(ftrace), 1);
+       (void) dup2(fileno(ftrace), 2);
+       trace = 1;
+       t = time(0);
+       printf("*** Tracing turned on at %.24s ***\n", ctime(&t));
+}
+
+rtinit()
+{
+       register struct rthash *rh;
+
+       for (rh = nethash; rh < &nethash[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;
+}
+
 /*
  * Lookup an entry to the appropriate dstination.
  */
 /*
  * Lookup an entry to the appropriate dstination.
  */
@@ -583,10 +710,48 @@ rtlookup(dst)
        struct sockaddr *dst;
 {
        register struct rt_entry *rt;
        struct sockaddr *dst;
 {
        register struct rt_entry *rt;
-       register struct rt_hash *rh;
-       register int hash, (*match)();
+       register struct rthash *rh;
+       register int hash;
        struct afhash h;
        struct afhash h;
-       int af = dst->sa_family, doinghost = 1;
+       int doinghost = 1;
+
+       if (dst->sa_family >= AF_MAX)
+               return (0);
+       (*afswitch[dst->sa_family].af_hash)(dst, &h);
+       hash = h.afh_hosthash;
+       rh = &hosthash[hash % ROUTEHASHSIZ];
+again:
+       for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+               if (rt->rt_hash != hash)
+                       continue;
+               if (equal(&rt->rt_dst, dst))
+                       return (rt);
+       }
+       if (doinghost) {
+               doinghost = 0;
+               hash = h.afh_nethash;
+               rh = &nethash[hash % ROUTEHASHSIZ];
+               goto again;
+       }
+       return (0);
+}
+
+/*
+ * Find an entry based on address "dst", as the kernel
+ * does in selecting routes.  This means we look first
+ * for a point to point link, settling for a route to
+ * the destination network if the former fails.
+ */
+struct rt_entry *
+rtfind(dst)
+       struct sockaddr *dst;
+{
+       register struct rt_entry *rt;
+       register struct rthash *rh;
+       register int hash;
+       struct afhash h;
+       int af = dst->sa_family;
+       int doinghost = 1, (*match)();
 
        if (af >= AF_MAX)
                return (0);
 
        if (af >= AF_MAX)
                return (0);
@@ -610,23 +775,13 @@ again:
        if (doinghost) {
                doinghost = 0;
                hash = h.afh_nethash;
        if (doinghost) {
                doinghost = 0;
                hash = h.afh_nethash;
-               match = afswitch[af].af_netmatch;
                rh = &nethash[hash % ROUTEHASHSIZ];
                rh = &nethash[hash % ROUTEHASHSIZ];
+               match = afswitch[af].af_netmatch;
                goto again;
        }
        return (0);
 }
 
                goto again;
        }
        return (0);
 }
 
-rtinit()
-{
-       register struct rt_hash *rh;
-
-       for (rh = nethash; rh < &nethash[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;
-}
-
 /*
  * Add a new entry.
  */
 /*
  * Add a new entry.
  */
@@ -636,7 +791,7 @@ rtadd(dst, gate, metric)
 {
        struct afhash h;
        register struct rt_entry *rt;
 {
        struct afhash h;
        register struct rt_entry *rt;
-       struct rt_hash *rh;
+       struct rthash *rh;
        int af = dst->sa_family, flags, hash;
 
        if (af >= AF_MAX)
        int af = dst->sa_family, flags, hash;
 
        if (af >= AF_MAX)
@@ -655,24 +810,18 @@ rtadd(dst, gate, metric)
                return;
        rt->rt_hash = hash;
        rt->rt_dst = *dst;
                return;
        rt->rt_hash = hash;
        rt->rt_dst = *dst;
-       rt->rt_gateway = *gate;
+       rt->rt_router = *gate;
        rt->rt_metric = metric;
        rt->rt_timer = 0;
        rt->rt_flags = RTF_UP | flags;
        rt->rt_metric = metric;
        rt->rt_timer = 0;
        rt->rt_flags = RTF_UP | flags;
-       rt->rt_ifp = if_ifwithnet(&rt->rt_gateway);
-       if (metric == 0)
-               rt->rt_flags |= RTF_DIRECT;
+       rt->rt_state = 0;
+       rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+       if (metric)
+               rt->rt_flags |= RTF_GATEWAY;
        insque(rt, rh);
        insque(rt, rh);
-       if (trace)
-               log("add", rt);
-       if (initializing)
-               return;
-       if (supplier)
-               broadcast(rt);
-       if (install) {
-               rt->rt_flags |= RTF_ADDRT;
-               rt->rt_retry = EXPIRE_TIME/TIMER_RATE;
-       }
+       log("add", rt);
+       if (install)
+               rt->rt_state |= RTS_ADDRT;
 }
 
 /*
 }
 
 /*
@@ -686,36 +835,21 @@ rtchange(rt, gate, metric)
 {
        int change = 0;
 
 {
        int change = 0;
 
-       if (!equal(&rt->rt_gateway, gate)) {
-               rt->rt_gateway = *gate;
+       if (!equal(&rt->rt_router, gate)) {
+               rt->rt_newrouter = *gate;
                change++;
        }
                change++;
        }
-
-       /*
-        * If the hop count has changed, adjust
-        * the flags in the routing table entry accordingly.
-        */
        if (metric != rt->rt_metric) {
        if (metric != rt->rt_metric) {
-               if (rt->rt_metric == 0)
-                       rt->rt_flags &= ~RTF_DIRECT;
+               if (metric == 0)
+                       rt->rt_flags |= RTF_GATEWAY;
                rt->rt_metric = metric;
                rt->rt_metric = metric;
-               if (metric >= HOPCNT_INFINITY)
-                       rt->rt_flags &= ~RTF_UP;
-               else
-                       rt->rt_flags |= RTF_UP;
                change++;
        }
                change++;
        }
-
        if (!change)
                return;
        if (!change)
                return;
-       if (supplier)
-               broadcast(rt);
-       if (trace)
-               log("change", rt);
-       if (install) {
-               rt->rt_flags |= RTF_CHGRT;
-               rt->rt_retry = EXPIRE_TIME/TIMER_RATE;
-       }
+       log("change", rt);
+       if (install)
+               rt->rt_state |= RTS_CHGRT;
 }
 
 /*
 }
 
 /*
@@ -724,113 +858,50 @@ rtchange(rt, gate, metric)
 rtdelete(rt)
        struct rt_entry *rt;
 {
 rtdelete(rt)
        struct rt_entry *rt;
 {
-       if (trace)
-               log("delete", rt);
-       if (install)
-               if (ioctl(s, SIOCDELRT, (char *)&rt->rt_hash) &&
-                 errno == EBUSY)
-                       rt->rt_flags |= RTF_DELRT;
+       log("delete", rt);
+       if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+               perror("SIOCDELRT");
+       /* don't delete interface entries so we can poll them later */
+       if (rt->rt_state & RTS_INTERFACE)
+               return;
        remque(rt);
        free((char *)rt);
 }
 
        remque(rt);
        free((char *)rt);
 }
 
-/*
- * Timer routine:
- *
- * o handle timers on table entries,
- * o invalidate entries which haven't been updated in a while,
- * o delete entries which are too old,
- * o retry ioctl's which weren't successful the first
- *   time due to the kernel entry being busy
- * o if we're an internetwork router, supply routing updates
- *   periodically
- */
-timer()
-{
-       register struct rt_hash *rh;
-       register struct rt_entry *rt;
-       struct rt_hash *base = hosthash;
-       int doinghost = 1;
-
-       if (trace)
-               printf(">>> time %d >>>\n", timeval);
-again:
-       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
-               rt = rh->rt_forw;
-               for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
-
-                       /*
-                        * If the host is indicated to be
-                        * "silent" (i.e. it's a logical host,
-                        * or one we got from the initialization
-                        * file), don't time out it's entry.
-                        */
-                       if (rt->rt_flags & RTF_SILENT)
-                               continue;
-                       if (trace)
-                               log("", rt);
-                       rt->rt_timer += TIMER_RATE;
-                       if (rt->rt_timer >= GARBAGE_TIME ||
-                         (rt->rt_flags & RTF_DELRT)) {
-                               rt = rt->rt_forw;
-                               rtdelete(rt->rt_back);
-                               rt = rt->rt_back;
-                               continue;
-                       }
-                       if (rt->rt_timer >= EXPIRE_TIME)
-                               rt->rt_metric = HOPCNT_INFINITY;
-                       if (rt->rt_flags & RTF_CHGRT)
-                               if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_hash) ||
-                                 --rt->rt_retry == 0)
-                                       rt->rt_flags &= ~RTF_CHGRT;
-                       if (rt->rt_flags & RTF_ADDRT)
-                               if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_hash) ||
-                                 --rt->rt_retry == 0)
-                                       rt->rt_flags &= ~RTF_ADDRT;
-               }
-       }
-       if (doinghost) {
-               doinghost = 0;
-               base = nethash;
-               goto again;
-       }
-       timeval += TIMER_RATE;
-       if (supplier && (timeval % SUPPLY_INTERVAL) == 0)
-               supplyall();
-       if (trace)
-               printf("<<< time %d <<<\n", timeval);
-       alarm(TIMER_RATE);
-}
-
 log(operation, rt)
        char *operation;
        struct rt_entry *rt;
 {
        time_t t = time(0);
        struct sockaddr_in *dst, *gate;
 log(operation, rt)
        char *operation;
        struct rt_entry *rt;
 {
        time_t t = time(0);
        struct sockaddr_in *dst, *gate;
-       static struct flagbits {
+       static struct bits {
                int     t_bits;
                char    *t_name;
                int     t_bits;
                char    *t_name;
-       } bits[] = {
+       } flagbits[] = {
                { RTF_UP,       "UP" },
                { RTF_UP,       "UP" },
-               { RTF_DIRECT,   "DIRECT" },
+               { RTF_GATEWAY,  "GATEWAY" },
                { RTF_HOST,     "HOST" },
                { RTF_HOST,     "HOST" },
-               { RTF_DELRT,    "DELETE" },
-               { RTF_CHGRT,    "CHANGE" },
-               { RTF_SILENT,   "SILENT" },
+               { 0 }
+       }, statebits[] = {
+               { RTS_DELRT,    "DELETE" },
+               { RTS_CHGRT,    "CHANGE" },
+               { RTS_PASSIVE,  "PASSIVE" },
+               { RTS_INTERFACE,"INTERFACE" },
                { 0 }
        };
                { 0 }
        };
-       register struct flagbits *p;
+       register struct bits *p;
        register int first;
        char *cp;
 
        register int first;
        char *cp;
 
+       if (trace == 0)
+               return;
        printf("%s ", operation);
        dst = (struct sockaddr_in *)&rt->rt_dst;
        printf("%s ", operation);
        dst = (struct sockaddr_in *)&rt->rt_dst;
-       gate = (struct sockaddr_in *)&rt->rt_gateway;
-       printf("dst %x, router %x, metric %d, flags ",
+       gate = (struct sockaddr_in *)&rt->rt_router;
+       printf("dst %x, router %x, metric %d, flags",
                dst->sin_addr, gate->sin_addr, rt->rt_metric);
                dst->sin_addr, gate->sin_addr, rt->rt_metric);
-       cp = "%s";
-       for (first = 1, p = bits; p->t_bits > 0; p++) {
+       cp = " %s";
+       for (first = 1, p = flagbits; p->t_bits > 0; p++) {
                if ((rt->rt_flags & p->t_bits) == 0)
                        continue;
                printf(cp, p->t_name);
                if ((rt->rt_flags & p->t_bits) == 0)
                        continue;
                printf(cp, p->t_name);
@@ -839,5 +910,86 @@ log(operation, rt)
                        first = 0;
                }
        }
                        first = 0;
                }
        }
+       printf(" state");
+       cp = " %s";
+       for (first = 1, p = statebits; p->t_bits > 0; p++) {
+               if ((rt->rt_state & p->t_bits) == 0)
+                       continue;
+               printf(cp, p->t_name);
+               if (first) {
+                       cp = "|%s";
+                       first = 0;
+               }
+       }
        putchar('\n');
 }
        putchar('\n');
 }
+
+/*
+ * Find the interface with address "addr".
+ */
+struct ifnet *
+if_ifwithaddr(addr)
+       struct sockaddr *addr;
+{
+       register struct ifnet *ifp;
+
+#define        same(a1, a2) \
+       (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
+       for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+               if (ifp->if_addr.sa_family != addr->sa_family)
+                       continue;
+               if (same(&ifp->if_addr, addr))
+                       break;
+               if ((ifp->if_flags & IFF_BROADCAST) &&
+                   same(&ifp->if_broadaddr, addr))
+                       break;
+       }
+       return (ifp);
+#undef same
+}
+
+/*
+ * Find the interface with network imbedded in
+ * the sockaddr "addr".  Must use per-af routine
+ * look for match.
+ */
+struct ifnet *
+if_ifwithnet(addr)
+       register struct sockaddr *addr;
+{
+       register struct ifnet *ifp;
+       register int af = addr->sa_family;
+       register int (*netmatch)();
+
+       if (af >= AF_MAX)
+               return (0);
+       netmatch = afswitch[af].af_netmatch;
+       for (ifp = ifnet; ifp; ifp = ifp->if_next) {
+               if (af != ifp->if_addr.sa_family)
+                       continue;
+               if ((*netmatch)(addr, &ifp->if_addr))
+                       break;
+       }
+       return (ifp);
+}
+
+/*
+ * Formulate an Internet address.
+ */
+struct in_addr
+if_makeaddr(net, host)
+       int net, host;
+{
+       u_long addr;
+
+       if (net < 128)
+               addr = (net << 24) | host;
+       else if (net < 65536)
+               addr = (net << 16) | host;
+       else
+               addr = (net << 8) | host;
+#ifdef vax
+       addr = htonl(addr);
+#endif
+       return (*(struct in_addr *)&addr);
+}