umount -> unmount
[unix-history] / usr / src / sbin / routed / routed.c
index cdad938..46e8264 100644 (file)
@@ -1,5 +1,5 @@
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)routed.c   4.8 %G%";
+static char sccsid[] = "@(#)routed.c   4.25 %G%";
 #endif
 
 /*
 #endif
 
 /*
@@ -14,6 +14,9 @@ static char sccsid[] = "@(#)routed.c  4.8 %G%";
 #include <stdio.h>
 #include <nlist.h>
 #include <signal.h>
 #include <stdio.h>
 #include <nlist.h>
 #include <signal.h>
+#include <time.h>
+#include <netdb.h>
+#define        RIPCMDS
 #include "rip.h"
 #include "router.h"
 
 #include "rip.h"
 #include "router.h"
 
@@ -31,26 +34,35 @@ struct nlist nl[] = {
        0,
 };
 
        0,
 };
 
-struct sockaddr_in myaddr = { AF_INET, IPPORT_ROUTESERVER };
+struct sockaddr_in routingaddr = { AF_INET };
+struct sockaddr_in noroutingaddr = { AF_INET };
 
 int    s;
 
 int    s;
+int    snoroute;               /* socket with no routing */
 int    kmem = -1;
 int    kmem = -1;
-int    supplier;               /* process should supply updates */
-int    initializing;           /* stem off broadcast() calls */
-int    install = 0;            /* if 1 call kernel */
+int    supplier = -1;          /* process should supply updates */
+int    install = 1;            /* if 1 call kernel */
 int    lookforinterfaces = 1;
 int    performnlist = 1;
 int    lookforinterfaces = 1;
 int    performnlist = 1;
-int    timeval;
+int    externalinterfaces = 0; /* # of remote and local interfaces */
+int    timeval = -TIMER_RATE;
 int    timer();
 int    cleanup();
 int    timer();
 int    cleanup();
+
+#define tprintf if (trace) printf
 int    trace = 0;
 int    trace = 0;
+FILE   *ftrace;
 
 
-char   packet[MAXPACKETSIZE];
+char   packet[MAXPACKETSIZE+1];
+struct rip *msg = (struct rip *)packet;
 
 
-struct in_addr if_makeaddr();
-struct ifnet *if_ifwithaddr(), *if_ifwithnet();
-extern char *malloc();
+struct in_addr inet_makeaddr();
+struct interface *if_ifwithaddr(), *if_ifwithnet();
+extern char *malloc(), *sys_errlist[];
 extern int errno, exit();
 extern int errno, exit();
+char   **argv0;
+
+int    sendmsg(), supply();
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
@@ -58,49 +70,100 @@ main(argc, argv)
 {
        int cc;
        struct sockaddr from;
 {
        int cc;
        struct sockaddr from;
+       struct servent *sp;
        
        
-       {   int t = open("/dev/tty", 2);
-           if (t >= 0) {
-               ioctl(t, TIOCNOTTY, 0);
-               close(t);
-           }
+       argv0 = argv;
+#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) freopen("/etc/routerlog", "a", stdout);
-               (void) dup2(fileno(stdout), 2);
-               setbuf(stdout, NULL);
+               ftrace = fopen("/etc/routerlog", "w");
+               dup2(fileno(ftrace), 1);
+               dup2(fileno(ftrace), 2);
        }
        }
-#ifdef vax || pdp11
-       myaddr.sin_port = htons(myaddr.sin_port);
-#endif
+
+       /*
+        * We use two sockets.  One for which outgoing
+        * packets are routed and for which they're not.
+        * The latter allows us to delete routing table
+        * entries in the kernel for network interfaces
+        * attached to our host which we believe are down
+        * while still polling it to see when/if it comes
+        * back up.  With the new ipc interface we'll be
+        * able to specify ``don't route'' as an option
+        * to send, but until then we utilize a second port.
+        */
+       sp = getservbyname("router", "udp");
+       if (sp == 0) {
+               fprintf(stderr, "routed: udp/router: unknown service\n");
+               exit(1);
+       }
+       routingaddr.sin_port = htons(sp->s_port);
+       noroutingaddr.sin_port = htons(sp->s_port + 1);
 again:
 again:
-       s = socket(SOCK_DGRAM, 0, &myaddr, 0);
+       s = socket(SOCK_DGRAM, 0, &routingaddr, 0);
        if (s < 0) {
                perror("socket");
                sleep(30);
                goto again;
        }
        if (s < 0) {
                perror("socket");
                sleep(30);
                goto again;
        }
-       rtinit();
-       getothers();
-       initializing = 1;
-       getinterfaces();
-       initializing = 0;
-       request();
-
+again2:
+       snoroute = socket(SOCK_DGRAM, 0, &noroutingaddr, SO_DONTROUTE);
+       if (snoroute < 0) {
+               perror("socket");
+               sleep(30);
+               goto again2;
+       }
        argv++, argc--;
        argv++, argc--;
-       while (argc > 0) {
-               if (strcmp(*argv, "-s") == 0)
+       while (argc > 0 && **argv == '-') {
+               if (!strcmp(*argv, "-s") == 0) {
                        supplier = 1;
                        supplier = 1;
-               else if (strcmp(*argv, "-q") == 0)
+                       argv++, argc--;
+                       continue;
+               }
+               if (!strcmp(*argv, "-q") == 0) {
                        supplier = 0;
                        supplier = 0;
-               argv++, argc--;
+                       argv++, argc--;
+                       continue;
+               }
+               goto usage;
        }
        }
+       if (argc > 0) {
+usage:
+               fprintf(stderr, "usage: routed [ -sq ]\n");
+               exit(1);
+       }
+       /*
+        * Collect an initial view of the world by
+        * snooping in the kernel and the gateway kludge
+        * file.  Then, send a request packet on all
+        * directly connected networks to find out what
+        * everyone else thinks.
+        */
+       rtinit();
+       gwkludge();
+       ifinit();
+       if (supplier < 0)
+               supplier = 0;
+       msg->rip_cmd = RIPCMD_REQUEST;
+       msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
+       msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
+       toall(sendmsg);
        sigset(SIGALRM, timer);
        timer();
 
        sigset(SIGALRM, timer);
        timer();
 
-       /*
-        * Listen for routing packets
-        */
        for (;;) {
                cc = receive(s, &from, packet, sizeof (packet));
                if (cc <= 0) {
        for (;;) {
                cc = receive(s, &from, packet, sizeof (packet));
                if (cc <= 0) {
@@ -114,167 +177,35 @@ 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.
- *
- * 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 = fopen("/etc/gateways", "r");
-       struct rt_entry *rt;
-
-       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_state |= RTS_SILENT;
-       }
-       fclose(fp);
-}
-
-/*
- * 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()
+rtinit()
 {
        register struct rthash *rh;
 {
        register struct rthash *rh;
-       register struct rt_entry *rt;
-       struct rthash *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 one we got
-                        * from the initialization file),
-                        * don't time out it's entry.
-                        */
-                       if ((rt->rt_state & RTS_SILENT) == 0)
-                               rt->rt_timer += TIMER_RATE;
-                       log("", rt);
-
-                       /*
-                        * 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;
-                       }
-
-                       /*
-                        * 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 (rt->rt_state & RTS_CHGRT)
-                               if (!ioctl(s, SIOCCHGRT,(char *)&rt->rt_rt) ||
-                                 --rt->rt_retry == 0)
-                                       rt->rt_state &= ~RTS_CHGRT;
-
-                       /*
-                        * Try to add the route to the kernel tables.
-                        * If this fails because the entry already exists
-                        * (perhaps because someone manually added it)
-                        * change the add to a change.  If the operation
-                        * fails otherwise (likely because the entry is
-                        * in use), retry the operation a few more times.
-                        */
-                       if (rt->rt_state & RTS_ADDRT) {
-                               if (!ioctl(s, SIOCADDRT,(char *)&rt->rt_rt)) {
-                                       if (errno == EEXIST) {
-                                               rt->rt_state &= ~RTS_ADDRT;
-                                               rt->rt_state |= RTS_CHGRT;
-                                               rt->rt_retry =
-                                                   (EXPIRE_TIME/TIMER_RATE);
-                                               continue;
-                                       }
-                                       if (--rt->rt_retry)
-                                               continue;
-                               }
-                               rt->rt_state &= ~RTS_ADDRT;
-                       }
-               }
-       }
-       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);
+       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;
 }
 
 }
 
-struct ifnet *ifnet;
+struct interface *ifnet;
+
 /*
 /*
- * Find the network interfaces attached to this machine.
- * The info is used to:
- *
- * (1) initialize the routing tables, as done by the kernel.
- * (2) ignore incoming packets we send.
- * (3) figure out broadcast capability and 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).
+ * Probe the kernel through /dev/kmem to find the network
+ * interfaces which have configured themselves.  If the
+ * interface is present but not yet up (for example an
+ * ARPANET IMP), set the lookforinterfaces flag so we'll
+ * come back later and look again.
  */
  */
-getinterfaces()
+ifinit()
 {
 {
-       struct ifnet *ifp;
-       struct ifnet ifstruct, *next;
-       struct sockaddr_in net;
-       register struct sockaddr *dst;
-       int nets;
+       struct interface *ifp;
+       struct ifnet ifs, *next;
 
        if (performnlist) {
                nlist("/vmunix", nl);
                if (nl[N_IFNET].n_value == 0) {
 
        if (performnlist) {
                nlist("/vmunix", nl);
                if (nl[N_IFNET].n_value == 0) {
-                       performnlist++;
                        printf("ifnet: not in namelist\n");
                        printf("ifnet: not in namelist\n");
-                       return;
+                       goto bad;
                }
                performnlist = 0;
        }
                }
                performnlist = 0;
        }
@@ -282,192 +213,285 @@ getinterfaces()
                kmem = open("/dev/kmem", 0);
                if (kmem < 0) {
                        perror("/dev/kmem");
                kmem = open("/dev/kmem", 0);
                if (kmem < 0) {
                        perror("/dev/kmem");
-                       return;
+                       goto bad;
                }
        }
        if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
                }
        }
        if (lseek(kmem, (long)nl[N_IFNET].n_value, 0) == -1 ||
-           read(kmem, (char *)&ifp, sizeof (ifp)) != sizeof (ifp)) {
-               performnlist = 1;
-               return;
+           read(kmem, (char *)&next, sizeof (next)) != sizeof (next)) {
+               printf("ifnet: error reading kmem\n");
+               goto bad;
        }
        }
-       bzero((char *)&net, sizeof (net));
-       net.sin_family = AF_INET;
        lookforinterfaces = 0;
        lookforinterfaces = 0;
-       nets = 0;
-       while (ifp) {
-               if (lseek(kmem, (long)ifp, 0) == -1 ||
-                 read(kmem, (char *)&ifstruct, sizeof (ifstruct)) !=
-                 sizeof (ifstruct)) {
+       while (next) {
+               if (lseek(kmem, (long)next, 0) == -1 ||
+                   read(kmem, (char *)&ifs, sizeof (ifs)) != sizeof (ifs)) {
                        perror("read");
                        perror("read");
-                       lookforinterfaces = performnlist = 1;
-                       break;
+                       goto bad;
                }
                }
-               ifp = &ifstruct;
-               if ((ifp->if_flags & IFF_UP) == 0) {
+               next = ifs.if_next;
+               if ((ifs.if_flags & IFF_UP) == 0) {
                        lookforinterfaces = 1;
                        lookforinterfaces = 1;
-       skip:
-                       ifp = ifp->if_next;
                        continue;
                }
                        continue;
                }
-               if (ifp->if_addr.sa_family != AF_INET)
-                       goto skip;
-               /* ignore software loopback networks. */
-               if (ifp->if_net == LOOPBACKNET)
-                       goto skip;
-               /* check if we already know about this one */
-               if (if_ifwithaddr(&ifstruct.if_addr)) {
-                       nets++;
-                       goto skip;
-               }
-               ifp = (struct ifnet *)malloc(sizeof (struct ifnet));
+               /* already known to us? */
+               if (if_ifwithaddr(&ifs.if_addr))
+                       continue;
+               /* argh, this'll have to change sometime */
+               if (ifs.if_addr.sa_family != AF_INET)
+                       continue;
+               /* no one cares about software loopback interfaces */
+               if (ifs.if_net == LOOPBACKNET)
+                       continue;
+               ifp = (struct interface *)malloc(sizeof (struct interface));
                if (ifp == 0) {
                        printf("routed: out of memory\n");
                        break;
                }
                if (ifp == 0) {
                        printf("routed: out of memory\n");
                        break;
                }
-               bcopy((char *)&ifstruct, (char *)ifp, sizeof (struct ifnet));
-
                /*
                 * Count the # of directly connected networks
                 * and point to point links which aren't looped
                 * back to ourself.  This is used below to
                /*
                 * 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".
+                * decide if we should be a routing ``supplier''.
                 */
                 */
-               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;
+               if ((ifs.if_flags & IFF_POINTOPOINT) == 0 ||
+                   if_ifwithaddr(&ifs.if_dstaddr) == 0)
+                       externalinterfaces++;
+               ifp->int_addr = ifs.if_addr;
+               ifp->int_flags = ifs.if_flags | IFF_INTERFACE;
+               /* this works because broadaddr overlaps dstaddr */
+               ifp->int_broadaddr = ifs.if_broadaddr;
+               ifp->int_net = ifs.if_net;
+               ifp->int_metric = 0;
+               ifp->int_next = ifnet;
                ifnet = ifp;
                ifnet = ifp;
-               if (rtlookup(dst) == 0)
-                       rtadd(dst, &ifp->if_addr, 0);
-               ifp = next;
-       }
-       supplier = nets > 1;
+               addrouteforif(ifp);
+       }
+       if (externalinterfaces > 1 && supplier < 0)
+               supplier = 1;
+       return;
+bad:
+       sleep(60);
+       close(kmem), close(s), close(snoroute);
+       execv("/etc/routed", argv0);
+       _exit(0177);
 }
 
 }
 
-/*
- * Send a request message to all directly
- * connected hosts and networks.
- */
-request()
+addrouteforif(ifp)
+       struct interface *ifp;
 {
 {
-       register struct rip *msg = (struct rip *)packet;
+       struct sockaddr_in net;
+       struct sockaddr *dst;
+       int state, metric;
+       struct rt_entry *rt;
 
 
-       msg->rip_cmd = RIPCMD_REQUEST;
-       msg->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
-       msg->rip_nets[0].rip_metric = HOPCNT_INFINITY;
-       sendall();
+       if (ifp->int_flags & IFF_POINTOPOINT)
+               dst = &ifp->int_dstaddr;
+       else {
+               bzero((char *)&net, sizeof (net));
+               net.sin_family = AF_INET;
+               net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+               dst = (struct sockaddr *)&net;
+       }
+       rt = rtlookup(dst);
+       rtadd(dst, &ifp->int_addr, ifp->int_metric,
+               ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
+       if (rt)
+               rtdelete(rt);
 }
 
 /*
 }
 
 /*
- * Broadcast a new, or modified, routing table entry
- * to all directly connected hosts and networks.
+ * As a concession to the ARPANET we read a list of gateways
+ * from /etc/gateways and add them to our tables.  This file
+ * exists at each ARPANET gateway and indicates a set of ``remote''
+ * gateways (i.e. a gateway which we can't immediately determine
+ * if it's present or not as we can do for those directly connected
+ * at the hardware level).  If a gateway is marked ``passive''
+ * in the file, then we assume it doesn't have a routing process
+ * of our design and simply assume it's always present.  Those
+ * not marked passive are treated as if they were directly
+ * connected -- they're added into the interface list so we'll
+ * send them routing updates.
  */
  */
-broadcast(entry)
-       struct rt_entry *entry;
+gwkludge()
 {
 {
-       struct rip *msg = (struct rip *)packet;
+       struct sockaddr_in dst, gate;
+       FILE *fp;
+       char *type, *dname, *gname, *qual, buf[BUFSIZ];
+       struct interface *ifp;
+       int metric;
 
 
-       log("broadcast", entry);
-       msg->rip_cmd = RIPCMD_RESPONSE;
-       msg->rip_nets[0].rip_dst = entry->rt_dst;
-       msg->rip_nets[0].rip_metric = min(entry->rt_metric+1, HOPCNT_INFINITY);
-       sendall();
+       fp = fopen("/etc/gateways", "r");
+       if (fp == NULL)
+               return;
+       qual = buf;
+       dname = buf + 64;
+       gname = buf + ((BUFSIZ - 64) / 3);
+       type = buf + (((BUFSIZ - 64) * 2) / 3);
+       bzero((char *)&dst, sizeof (dst));
+       bzero((char *)&gate, sizeof (gate));
+       dst.sin_family = gate.sin_family = AF_INET;
+       /* format: {net | host} XX gateway XX metric DD [passive]\n */
+#define        readentry(fp) \
+       fscanf((fp), "%s %s gateway %s metric %d %s\n", \
+               type, dname, gname, &metric, qual)
+       for (;;) {
+               struct hostent *host;
+               struct netent *net;
+
+               if (readentry(fp) == EOF)
+                       break;
+               if (strcmp(type, "net") == 0) {
+                       net = getnetbyname(dname);
+                       if (net == 0 || net->n_addrtype != AF_INET)
+                               continue;
+                       dst.sin_addr = inet_makeaddr(net->n_net, INADDR_ANY);
+               } else if (strcmp(type, "host") == 0) {
+                       host = gethostbyname(dname);
+                       if (host == 0)
+                               continue;
+                       bcopy(host->h_addr, &dst.sin_addr, host->h_length);
+               } else
+                       continue;
+               host = gethostbyname(gname);
+               if (host == 0)
+                       continue;
+               bcopy(host->h_addr, &gate.sin_addr, host->h_length);
+               ifp = (struct interface *)malloc(sizeof (*ifp));
+               bzero((char *)ifp, sizeof (*ifp));
+               ifp->int_flags = IFF_REMOTE;
+               /* can't identify broadcast capability */
+               ifp->int_net = inet_netof(dst.sin_addr);
+               if (strcmp(type, "host") == 0) {
+                       ifp->int_flags |= IFF_POINTOPOINT;
+                       ifp->int_dstaddr = *((struct sockaddr *)&dst);
+               }
+               if (strcmp(qual, "passive") == 0)
+                       ifp->int_flags |= IFF_PASSIVE;
+               else
+                       /* assume no duplicate entries */
+                       externalinterfaces++;
+               ifp->int_addr = *((struct sockaddr *)&gate);
+               ifp->int_metric = metric;
+               ifp->int_next = ifnet;
+               ifnet = ifp;
+               addrouteforif(ifp);
+       }
+       fclose(fp);
 }
 
 /*
 }
 
 /*
- * Send "packet" to all neighbors.
+ * Timer routine.  Performs routing information supply
+ * duties and manages timers on routing table entries.
  */
  */
-sendall()
+timer()
 {
        register struct rthash *rh;
        register struct rt_entry *rt;
 {
        register struct rthash *rh;
        register struct rt_entry *rt;
-       register struct sockaddr *dst;
        struct rthash *base = hosthash;
        struct rthash *base = hosthash;
-       int doinghost = 1;
+       int doinghost = 1, timetobroadcast;
 
 
+       timeval += TIMER_RATE;
+       if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
+               ifinit();
+       timetobroadcast = supplier && (timeval % SUPPLY_INTERVAL) == 0;
+       tprintf(">>> time %d >>>\n", timeval);
 again:
 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_state & RTS_SILENT) || rt->rt_metric > 0)
-                       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));
+       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+               rt = rh->rt_forw;
+               for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+                       /*
+                        * We don't advance time on a routing entry for
+                        * a passive gateway or that for our only interface. 
+                        * The latter is excused because we don't act as
+                        * a routing information supplier and hence would
+                        * time it out.  This is fair as if it's down
+                        * we're cut off from the world anyway and it's
+                        * not likely we'll grow any new hardware in
+                        * the mean time.
+                        */
+                       if (!(rt->rt_state & RTS_PASSIVE) &&
+                           (supplier || !(rt->rt_state & RTS_INTERFACE)))
+                               rt->rt_timer += TIMER_RATE;
+                       if (rt->rt_timer >= EXPIRE_TIME)
+                               rt->rt_metric = HOPCNT_INFINITY;
+                       log("", rt);
+                       if (rt->rt_timer >= GARBAGE_TIME) {
+                               rt = rt->rt_back;
+                               rtdelete(rt->rt_forw);
+                               continue;
+                       }
+                       if (rt->rt_state & RTS_CHANGED) {
+                               rt->rt_state &= ~RTS_CHANGED;
+                               /* don't send extraneous packets */
+                               if (!supplier || timetobroadcast)
+                                       continue;
+                               log("broadcast", rt);
+                               msg->rip_cmd = RIPCMD_RESPONSE;
+                               msg->rip_nets[0].rip_dst = rt->rt_dst;
+                               msg->rip_nets[0].rip_metric =
+                                   min(rt->rt_metric+1, HOPCNT_INFINITY);
+                               toall(sendmsg);
+                       }
+               }
        }
        if (doinghost) {
        }
        if (doinghost) {
-               base = nethash;
                doinghost = 0;
                doinghost = 0;
+               base = nethash;
                goto again;
        }
                goto again;
        }
+       if (timetobroadcast)
+               toall(supply);
+       tprintf("<<< time %d <<<\n", timeval);
+       alarm(TIMER_RATE);
 }
 
 }
 
-/*
- * Supply all directly connected neighbors with the
- * current state of the routing tables.
- */
-supplyall()
+toall(f)
+       int (*f)();
 {
 {
-       register struct rt_entry *rt;
-       register struct rthash *rh;
+       register struct interface *ifp;
        register struct sockaddr *dst;
        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) {
-               if ((rt->rt_state & RTS_SILENT) || rt->rt_metric > 0)
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               if (ifp->int_flags & IFF_PASSIVE)
                        continue;
                        continue;
-               if (rt->rt_ifp && (rt->rt_ifp->if_flags & IFF_BROADCAST))
-                       dst = &rt->rt_ifp->if_broadaddr;
-               else
-                       dst = &rt->rt_gateway;
-               log("supply", rt);
-               supply(dst);
-       }
-       if (doinghost) {
-               base = nethash;
-               doinghost = 0;
-               goto again;
+               dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
+                     ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
+                     &ifp->int_addr;
+               (*f)(dst, ifp->int_flags & IFF_INTERFACE);
        }
 }
 
        }
 }
 
+/*ARGSUSED*/
+sendmsg(dst, dontroute)
+       struct sockaddr *dst;
+       int dontroute;
+{
+       (*afswitch[dst->sa_family].af_output)(s, dst, sizeof (struct rip));
+}
+
 /*
 /*
- * Supply routing information to target "sa".
+ * Supply dst with the contents of the routing tables.
+ * If this won't fit in one packet, chop it up into several.
  */
  */
-supply(sa)
-       struct sockaddr *sa;
+supply(dst, dontroute)
+       struct sockaddr *dst;
+       int dontroute;
 {
 {
-       struct rip *msg = (struct rip *)packet;
+       register struct rt_entry *rt;
        struct netinfo *n = msg->rip_nets;
        register struct rthash *rh;
        struct netinfo *n = msg->rip_nets;
        register struct rthash *rh;
-       register struct rt_entry *rt;
        struct rthash *base = hosthash;
        int doinghost = 1, size;
        struct rthash *base = hosthash;
        int doinghost = 1, size;
-       int (*output)() = afswitch[sa->sa_family].af_output;
+       int (*output)() = afswitch[dst->sa_family].af_output;
+       int sto = dontroute ? snoroute : s;
 
        msg->rip_cmd = RIPCMD_RESPONSE;
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
 
        msg->rip_cmd = RIPCMD_RESPONSE;
 again:
        for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
        for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
-
-               /*
-                * Flush packet out if not enough room for
-                * another routing table entry.
-                */
                size = (char *)n - packet;
                if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
                size = (char *)n - packet;
                if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
-                       (*output)(sa, size);
+                       (*output)(sto, dst, size);
                        n = msg->rip_nets;
                }
                n->rip_dst = rt->rt_dst;
                        n = msg->rip_nets;
                }
                n->rip_dst = rt->rt_dst;
@@ -480,41 +504,7 @@ again:
                goto again;
        }
        if (n != msg->rip_nets)
                goto again;
        }
        if (n != msg->rip_nets)
-               (*output)(sa, (char *)n - packet);
-}
-
-/*
- * Respond to a routing info request.
- */
-rip_respond(from, size)
-       struct sockaddr *from;
-       int size;
-{
-       register struct rip *msg = (struct rip *)packet;
-       struct netinfo *np = msg->rip_nets;
-       struct rt_entry *rt;
-       int newsize = 0;
-       
-       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) {
-                       supply(from);
-                       return;
-               }
-               rt = rtlookup(&np->rip_dst);
-               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);
-               (*afswitch[from->sa_family].af_output)(from, newsize);
-       }
+               (*output)(sto, dst, (char *)n - packet);
 }
 
 /*
 }
 
 /*
@@ -524,120 +514,185 @@ rip_input(from, size)
        struct sockaddr *from;
        int size;
 {
        struct sockaddr *from;
        int size;
 {
-       register struct rip *msg = (struct rip *)packet;
        struct rt_entry *rt;
        struct netinfo *n;
        struct rt_entry *rt;
        struct netinfo *n;
+       struct interface *ifp;
+       time_t t;
+       int newsize;
+       struct afswitch *afp;
 
 
+       if (trace) {
+               if (msg->rip_cmd < RIPCMD_MAX)
+                       printf("%s from %x\n", ripcmds[msg->rip_cmd], 
+                           ((struct sockaddr_in *)from)->sin_addr);
+               else
+                       printf("%x from %x\n", msg->rip_cmd,
+                           ((struct sockaddr_in *)from)->sin_addr);
+       }
+       if (from->sa_family >= AF_MAX)
+               return;
+       afp = &afswitch[from->sa_family];
        switch (msg->rip_cmd) {
 
        switch (msg->rip_cmd) {
 
-       default:
+       case RIPCMD_REQUEST:
+               newsize = 0;
+               size -= 4 * sizeof (char);
+               n = msg->rip_nets;
+               while (size > 0) {
+                       if (size < sizeof (struct netinfo))
+                               break;
+                       size -= sizeof (struct netinfo);
+
+                       /* 
+                        * A single entry with sa_family == AF_UNSPEC and
+                        * metric ``infinity'' means ``all routes''.
+                        */
+                       if (n->rip_dst.sa_family == AF_UNSPEC &&
+                           n->rip_metric == HOPCNT_INFINITY && size == 0) {
+                               supply(from, 0);
+                               return;
+                       }
+                       rt = rtlookup(&n->rip_dst);
+                       n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
+                               min(rt->rt_metric+1, HOPCNT_INFINITY);
+                       n++, newsize += sizeof (struct netinfo);
+               }
+               if (newsize > 0) {
+                       msg->rip_cmd = RIPCMD_RESPONSE;
+                       newsize += sizeof (int);
+                       (*afp->af_output)(s, from, newsize);
+               }
                return;
 
                return;
 
-       case RIPCMD_REQUEST:
-               rip_respond(from, size);
+       case RIPCMD_TRACEON:
+               if ((*afp->af_portcheck)(from) == 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));
                return;
 
                return;
 
-       case RIPCMD_RESPONSE:
+       case RIPCMD_TRACEOFF:
                /* verify message came from a priviledged port */
                /* verify message came from a priviledged port */
-               if ((*afswitch[from->sa_family].af_portmatch)(from) == 0)
+               if ((*afp->af_portcheck)(from) == 0)
                        return;
                        return;
-               break;
-       }
-
-       /*
-        * Process updates.
-        * Extraneous information like Internet ports
-        * must first be purged from the sender's address for
-        * pattern matching below.
-        */
-       (*afswitch[from->sa_family].af_canon)(from);
-       if (trace)
-               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
-        * it as gospel (since it comes from the router) and
-        * unknowingly update the metric to show the outgoing
-        * cost (higher than our real cost).  I guess the protocol
-        * spec doesn't address this because Xerox Ethernets
-        * don't hear their own broadcasts?
-        */
-       if (if_ifwithaddr(from)) {
-               rt = rtlookup(from);
-               if (rt)
-                       rt->rt_timer = 0;
+               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;
                return;
-       }
-       size -= 4 * sizeof (char);
-       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...",
-                               ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
-                               n->rip_metric);
-               rt = rtlookup(&n->rip_dst);
 
 
-               /*
-                * Unknown entry, add it to the tables only if
-                * its interesting.
-                */
-               if (rt == 0) {
-                       if (n->rip_metric < HOPCNT_INFINITY)
-                               rtadd(&n->rip_dst, from, n->rip_metric);
-                       if (trace)
-                               printf("new\n");
-                       continue;
+       case RIPCMD_RESPONSE:
+               /* verify message came from a router */
+               if ((*afp->af_portmatch)(from) == 0)
+                       return;
+               (*afp->af_canon)(from);
+               /* are we talking to ourselves? */
+               ifp = if_ifwithaddr(from);
+               if (ifp) {
+                       rt = rtfind(from);
+                       if (rt == 0)
+                               addrouteforif(ifp);
+                       else
+                               rt->rt_timer = 0;
+                       return;
                }
                }
-
-               if (trace)
-                       printf("ours: gate %x hc %d timer %d\n",
-                         ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr,
+               size -= 4 * sizeof (char);
+               n = msg->rip_nets;
+               for (; size > 0; size -= sizeof (struct netinfo), n++) {
+                       if (size < sizeof (struct netinfo))
+                               break;
+                       if (n->rip_metric >= HOPCNT_INFINITY)
+                               continue;
+                       tprintf("dst %x hc %d...",
+                           ((struct sockaddr_in *)&n->rip_dst)->sin_addr,
+                           n->rip_metric);
+                       rt = rtlookup(&n->rip_dst);
+                       if (rt == 0) {
+                               rtadd(&n->rip_dst, from, n->rip_metric, 0);
+                               continue;
+                       }
+                       tprintf("ours: gate %x hc %d timer %d\n",
+                         ((struct sockaddr_in *)&rt->rt_router)->sin_addr,
                          rt->rt_metric, rt->rt_timer);
                          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
-                *     and a path of equivalent cost is offered
-                *     (with the cost finite).
-                */
-               if (equal(from, &rt->rt_gateway) ||
-                   rt->rt_metric > n->rip_metric ||
-                   (rt->rt_timer > (EXPIRE_TIME/2) &&
-                   rt->rt_metric == n->rip_metric &&
-                   rt->rt_metric < HOPCNT_INFINITY)) {
-                       rtchange(rt, from, n->rip_metric);
-                       rt->rt_timer = 0;
+
+                       /*
+                        * Update if from gateway, shorter, or getting
+                        * stale and equivalent.
+                        */
+                       if (equal(from, &rt->rt_router) ||
+                           n->rip_metric < rt->rt_metric ||
+                           (rt->rt_timer > (EXPIRE_TIME/2) &&
+                           rt->rt_metric == n->rip_metric)) {
+                               rtchange(rt, from, n->rip_metric);
+                               rt->rt_timer = 0;
+                       }
                }
                }
+               return;
        }
        }
+       tprintf("bad packet, cmd=%x\n", msg->rip_cmd);
 }
 
 }
 
-rtinit()
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *
+rtlookup(dst)
+       struct sockaddr *dst;
 {
 {
+       register struct rt_entry *rt;
        register struct rthash *rh;
        register struct rthash *rh;
+       register int hash;
+       struct afhash h;
+       int doinghost = 1;
 
 
-       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;
+       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);
 }
 
 /*
 }
 
 /*
- * Lookup an entry to the appropriate dstination.
+ * Find a route to dst as the kernel would.
  */
 struct rt_entry *
  */
 struct rt_entry *
-rtlookup(dst)
+rtfind(dst)
        struct sockaddr *dst;
 {
        register struct rt_entry *rt;
        register struct rthash *rh;
        struct sockaddr *dst;
 {
        register struct rt_entry *rt;
        register struct rthash *rh;
-       register int hash, (*match)();
+       register int hash;
        struct afhash h;
        struct afhash h;
-       int af = dst->sa_family, doinghost = 1;
+       int af = dst->sa_family;
+       int doinghost = 1, (*match)();
 
        if (af >= AF_MAX)
                return (0);
 
        if (af >= AF_MAX)
                return (0);
@@ -661,19 +716,16 @@ 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);
 }
 
-/*
- * Add a new entry.
- */
-rtadd(dst, gate, metric)
+rtadd(dst, gate, metric, state)
        struct sockaddr *dst, *gate;
        struct sockaddr *dst, *gate;
-       short metric;
+       int metric, state;
 {
        struct afhash h;
        register struct rt_entry *rt;
 {
        struct afhash h;
        register struct rt_entry *rt;
@@ -696,79 +748,56 @@ 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_state = 0;
-       rt->rt_ifp = if_ifwithnet(&rt->rt_gateway);
-       if (metric == 0)
-               rt->rt_flags |= RTF_DIRECT;
+       rt->rt_state = state | RTS_CHANGED;
+       rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+       if (metric)
+               rt->rt_flags |= RTF_GATEWAY;
        insque(rt, rh);
        log("add", rt);
        insque(rt, rh);
        log("add", rt);
-       if (initializing)
-               return;
-       if (supplier)
-               broadcast(rt);
-       if (install) {
-               rt->rt_state |= RTS_ADDRT;
-               rt->rt_retry = EXPIRE_TIME/TIMER_RATE;
-       }
+       if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+               tprintf("SIOCADDRT: %s\n", sys_errlist[errno]);
 }
 
 }
 
-/*
- * Look to see if a change to an existing entry
- * is warranted; if so, make it.
- */
 rtchange(rt, gate, metric)
        struct rt_entry *rt;
        struct sockaddr *gate;
        short metric;
 {
 rtchange(rt, gate, metric)
        struct rt_entry *rt;
        struct sockaddr *gate;
        short metric;
 {
-       int change = 0;
+       int doioctl = 0, metricchanged = 0;
+       struct rtentry oldroute;
 
 
-       if (!equal(&rt->rt_gateway, gate)) {
-               rt->rt_gateway = *gate;
-               change++;
-       }
-
-       /*
-        * If the hop count has changed, adjust
-        * the flags in the routing table entry accordingly.
-        */
+       if (!equal(&rt->rt_router, gate))
+               doioctl++;
        if (metric != rt->rt_metric) {
        if (metric != rt->rt_metric) {
-               if (rt->rt_metric == 0)
-                       rt->rt_flags &= ~RTF_DIRECT;
+               metricchanged++;
                rt->rt_metric = metric;
                rt->rt_metric = metric;
-               if (metric >= HOPCNT_INFINITY)
-                       rt->rt_flags &= ~RTF_UP;
-               else
-                       rt->rt_flags |= RTF_UP;
-               change++;
        }
        }
-
-       if (!change)
-               return;
-       if (supplier)
-               broadcast(rt);
-       log("change", rt);
-       if (install) {
-               rt->rt_state |= RTS_CHGRT;
-               rt->rt_retry = EXPIRE_TIME/TIMER_RATE;
+       if (doioctl || metricchanged) {
+               log("change", rt);
+               rt->rt_state |= RTS_CHANGED;
+       }
+       if (doioctl) {
+               oldroute = rt->rt_rt;
+               rt->rt_router = *gate;
+               if (install) {
+                       if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+                               tprintf("SIOCADDRT: %s\n", sys_errlist[errno]);
+                       if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+                               tprintf("SIOCDELRT: %s\n", sys_errlist[errno]);
+               }
        }
 }
 
        }
 }
 
-/*
- * Delete a routing table entry.
- */
 rtdelete(rt)
        struct rt_entry *rt;
 {
        log("delete", rt);
 rtdelete(rt)
        struct rt_entry *rt;
 {
        log("delete", rt);
-       if (install)
-               if (ioctl(s, SIOCDELRT, (char *)&rt->rt_rt) &&
-                 errno == EBUSY)
-                       rt->rt_state |= RTS_DELRT;
+       if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+               tprintf("SIOCDELRT: %s\n", sys_errlist[errno]);
        remque(rt);
        free((char *)rt);
 }
        remque(rt);
        free((char *)rt);
 }
@@ -777,20 +806,20 @@ log(operation, rt)
        char *operation;
        struct rt_entry *rt;
 {
        char *operation;
        struct rt_entry *rt;
 {
-       time_t t = time(0);
        struct sockaddr_in *dst, *gate;
        static struct bits {
                int     t_bits;
                char    *t_name;
        } flagbits[] = {
                { RTF_UP,       "UP" },
        struct sockaddr_in *dst, *gate;
        static struct bits {
                int     t_bits;
                char    *t_name;
        } flagbits[] = {
                { RTF_UP,       "UP" },
-               { RTF_DIRECT,   "DIRECT" },
+               { RTF_GATEWAY,  "GATEWAY" },
                { RTF_HOST,     "HOST" },
                { 0 }
        }, statebits[] = {
                { RTF_HOST,     "HOST" },
                { 0 }
        }, statebits[] = {
-               { RTS_DELRT,    "DELETE" },
-               { RTS_CHGRT,    "CHANGE" },
-               { RTS_SILENT,   "SILENT" },
+               { RTS_PASSIVE,  "PASSIVE" },
+               { RTS_REMOTE,   "REMOTE" },
+               { RTS_INTERFACE,"INTERFACE" },
+               { RTS_CHANGED,  "CHANGED" },
                { 0 }
        };
        register struct bits *p;
                { 0 }
        };
        register struct bits *p;
@@ -801,9 +830,9 @@ log(operation, rt)
                return;
        printf("%s ", operation);
        dst = (struct sockaddr_in *)&rt->rt_dst;
                return;
        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",
-               dst->sin_addr, gate->sin_addr, rt->rt_metric);
+       gate = (struct sockaddr_in *)&rt->rt_router;
+       printf("dst %x, router %x, metric %d, flags", dst->sin_addr,
+               gate->sin_addr, rt->rt_metric);
        cp = " %s";
        for (first = 1, p = flagbits; p->t_bits > 0; p++) {
                if ((rt->rt_flags & p->t_bits) == 0)
        cp = " %s";
        for (first = 1, p = flagbits; p->t_bits > 0; p++) {
                if ((rt->rt_flags & p->t_bits) == 0)
@@ -828,72 +857,47 @@ log(operation, rt)
        putchar('\n');
 }
 
        putchar('\n');
 }
 
-/*
- * Find the interface with address "addr".
- */
-struct ifnet *
+struct interface *
 if_ifwithaddr(addr)
        struct sockaddr *addr;
 {
 if_ifwithaddr(addr)
        struct sockaddr *addr;
 {
-       register struct ifnet *ifp;
+       register struct interface *ifp;
 
 #define        same(a1, a2) \
        (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
 
 #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)
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               if (ifp->int_flags & IFF_REMOTE)
+                       continue;
+               if (ifp->int_addr.sa_family != addr->sa_family)
                        continue;
                        continue;
-               if (same(&ifp->if_addr, addr))
+               if (same(&ifp->int_addr, addr))
                        break;
                        break;
-               if ((ifp->if_flags & IFF_BROADCAST) &&
-                   same(&ifp->if_broadaddr, addr))
+               if ((ifp->int_flags & IFF_BROADCAST) &&
+                   same(&ifp->int_broadaddr, addr))
                        break;
        }
        return (ifp);
 #undef same
 }
 
                        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 *
+struct interface *
 if_ifwithnet(addr)
        register struct sockaddr *addr;
 {
 if_ifwithnet(addr)
        register struct sockaddr *addr;
 {
-       register struct ifnet *ifp;
+       register struct interface *ifp;
        register int af = addr->sa_family;
        register int (*netmatch)();
 
        if (af >= AF_MAX)
                return (0);
        netmatch = afswitch[af].af_netmatch;
        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)
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               if (ifp->int_flags & IFF_REMOTE)
+                       continue;
+               if (af != ifp->int_addr.sa_family)
                        continue;
                        continue;
-               if ((*netmatch)(addr, &ifp->if_addr))
+               if ((*netmatch)(addr, &ifp->int_addr))
                        break;
        }
        return (ifp);
 }
                        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);
-}