386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Wed, 17 Apr 1991 00:31:38 +0000 (16:31 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Wed, 17 Apr 1991 00:31:38 +0000 (16:31 -0800)
Work on file usr/src/sbin/routed/af.c
Work on file usr/src/sbin/routed/if.c
Work on file usr/src/sbin/routed/af.h
Work on file usr/src/sbin/routed/defs.h
Work on file usr/src/sbin/routed/inet.c
Work on file usr/src/sbin/routed/input.c
Work on file usr/src/sbin/routed/interface.h
Work on file usr/src/sbin/routed/pathnames.h
Work on file usr/src/sbin/routed/routed.8
Work on file usr/src/sbin/routed/startup.c
Work on file usr/src/sbin/routed/output.c
Work on file usr/src/sbin/routed/timer.c
Work on file usr/src/sbin/routed/table.h
Work on file usr/src/sbin/routed/trace.h
Work on file usr/src/sbin/routed/trace.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

15 files changed:
usr/src/sbin/routed/af.c [new file with mode: 0644]
usr/src/sbin/routed/af.h [new file with mode: 0644]
usr/src/sbin/routed/defs.h [new file with mode: 0644]
usr/src/sbin/routed/if.c [new file with mode: 0644]
usr/src/sbin/routed/inet.c [new file with mode: 0644]
usr/src/sbin/routed/input.c [new file with mode: 0644]
usr/src/sbin/routed/interface.h [new file with mode: 0644]
usr/src/sbin/routed/output.c [new file with mode: 0644]
usr/src/sbin/routed/pathnames.h [new file with mode: 0644]
usr/src/sbin/routed/routed.8 [new file with mode: 0644]
usr/src/sbin/routed/startup.c [new file with mode: 0644]
usr/src/sbin/routed/table.h [new file with mode: 0644]
usr/src/sbin/routed/timer.c [new file with mode: 0644]
usr/src/sbin/routed/trace.c [new file with mode: 0644]
usr/src/sbin/routed/trace.h [new file with mode: 0644]

diff --git a/usr/src/sbin/routed/af.c b/usr/src/sbin/routed/af.c
new file mode 100644 (file)
index 0000000..19807b7
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)af.c       5.11 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+#include "defs.h"
+
+/*
+ * Address family support routines
+ */
+int    inet_hash(), inet_netmatch(), inet_output(),
+       inet_portmatch(), inet_portcheck(),
+       inet_checkhost(), inet_rtflags(), inet_sendroute(), inet_canon();
+char   *inet_format();
+
+#define NIL    { 0 }
+#define        INET \
+       { inet_hash,            inet_netmatch,          inet_output, \
+         inet_portmatch,       inet_portcheck,         inet_checkhost, \
+         inet_rtflags,         inet_sendroute,         inet_canon, \
+         inet_format \
+       }
+
+struct afswitch afswitch[AF_MAX] = {
+       NIL,            /* 0- unused */
+       NIL,            /* 1- Unix domain, unused */
+       INET,           /* Internet */
+};
+
+int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
+
+struct sockaddr_in inet_default = {
+#ifdef RTM_ADD
+       sizeof (inet_default),
+#endif
+       AF_INET, INADDR_ANY };
+
+inet_hash(sin, hp)
+       register struct sockaddr_in *sin;
+       struct afhash *hp;
+{
+       register u_long n;
+
+       n = inet_netof(sin->sin_addr);
+       if (n)
+           while ((n & 0xff) == 0)
+               n >>= 8;
+       hp->afh_nethash = n;
+       hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
+       hp->afh_hosthash &= 0x7fffffff;
+}
+
+inet_netmatch(sin1, sin2)
+       struct sockaddr_in *sin1, *sin2;
+{
+
+       return (inet_netof(sin1->sin_addr) == inet_netof(sin2->sin_addr));
+}
+
+/*
+ * Verify the message is from the right port.
+ */
+inet_portmatch(sin)
+       register struct sockaddr_in *sin;
+{
+       
+       return (sin->sin_port == sp->s_port);
+}
+
+/*
+ * Verify the message is from a "trusted" port.
+ */
+inet_portcheck(sin)
+       struct sockaddr_in *sin;
+{
+
+       return (ntohs(sin->sin_port) <= IPPORT_RESERVED);
+}
+
+/*
+ * Internet output routine.
+ */
+inet_output(s, flags, sin, size)
+       int s, flags;
+       struct sockaddr_in *sin;
+       int size;
+{
+       struct sockaddr_in dst;
+
+       dst = *sin;
+       sin = &dst;
+       if (sin->sin_port == 0)
+               sin->sin_port = sp->s_port;
+       if (sin->sin_len == 0)
+               sin->sin_len = sizeof (*sin);
+       if (sendto(s, packet, size, flags,
+           (struct sockaddr *)sin, sizeof (*sin)) < 0)
+               perror("sendto");
+}
+
+/*
+ * Return 1 if the address is believed
+ * for an Internet host -- THIS IS A KLUDGE.
+ */
+inet_checkhost(sin)
+       struct sockaddr_in *sin;
+{
+       u_long i = ntohl(sin->sin_addr.s_addr);
+
+#ifndef IN_EXPERIMENTAL
+#define        IN_EXPERIMENTAL(i)      (((long) (i) & 0xe0000000) == 0xe0000000)
+#endif
+
+       if (IN_EXPERIMENTAL(i) || sin->sin_port != 0)
+               return (0);
+       if (i != 0 && (i & 0xff000000) == 0)
+               return (0);
+       for (i = 0; i < sizeof(sin->sin_zero)/sizeof(sin->sin_zero[0]); i++)
+               if (sin->sin_zero[i])
+                       return (0);
+       return (1);
+}
+
+inet_canon(sin)
+       struct sockaddr_in *sin;
+{
+
+       sin->sin_port = 0;
+       sin->sin_len = sizeof(*sin);
+}
+
+char *
+inet_format(sin)
+       struct sockaddr_in *sin;
+{
+       char *inet_ntoa();
+
+       return (inet_ntoa(sin->sin_addr));
+}
diff --git a/usr/src/sbin/routed/af.h b/usr/src/sbin/routed/af.h
new file mode 100644 (file)
index 0000000..2d1bf29
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)af.h        5.7 (Berkeley) 6/1/90
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Per address family routines.
+ */
+struct afswitch {
+       int     (*af_hash)();           /* returns keys based on address */
+       int     (*af_netmatch)();       /* verifies net # matching */
+       int     (*af_output)();         /* interprets address for sending */
+       int     (*af_portmatch)();      /* packet from some other router? */
+       int     (*af_portcheck)();      /* packet from privileged peer? */
+       int     (*af_checkhost)();      /* tells if address is valid */
+       int     (*af_rtflags)();        /* get flags for route (host or net) */
+       int     (*af_sendroute)();      /* check bounds of subnet broadcast */
+       int     (*af_canon)();          /* canonicalize address for compares */
+       char    *(*af_format)();        /* convert address to string */
+};
+
+/*
+ * Structure returned by af_hash routines.
+ */
+struct afhash {
+       u_int   afh_hosthash;           /* host based hash */
+       u_int   afh_nethash;            /* network based hash */
+};
+
+struct afswitch afswitch[];            /* table proper */
+int    af_max;                         /* number of entries in table */
diff --git a/usr/src/sbin/routed/defs.h b/usr/src/sbin/routed/defs.h
new file mode 100644 (file)
index 0000000..f4fdf7a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)defs.h      5.10 (Berkeley) 2/28/91
+ */
+
+/*
+ * Internal data structure definitions for
+ * user routing process.  Based on Xerox NS
+ * protocol specs with mods relevant to more
+ * general addressing scheme.
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+
+#include <stdio.h>
+#include <netdb.h>
+
+#include "trace.h"
+#include "interface.h"
+#include "table.h"
+#include "af.h"
+
+/*
+ * When we find any interfaces marked down we rescan the
+ * kernel every CHECK_INTERVAL seconds to see if they've
+ * come up.
+ */
+#define        CHECK_INTERVAL  (1*60)
+
+#define equal(a1, a2) \
+       (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
+
+struct sockaddr_in addr;       /* address of daemon's socket */
+
+int    s;                      /* source and sink of all data */
+int    kmem;
+int    supplier;               /* process should supply updates */
+int    install;                /* if 1 call kernel */
+int    lookforinterfaces;      /* if 1 probe kernel for new up interfaces */
+int    performnlist;           /* if 1 check if /vmunix has changed */
+int    externalinterfaces;     /* # of remote and local interfaces */
+struct timeval now;            /* current idea of time */
+struct timeval lastbcast;      /* last time all/changes broadcast */
+struct timeval lastfullupdate; /* last time full table broadcast */
+struct timeval nextbcast;      /* time to wait before changes broadcast */
+int    needupdate;             /* true if we need update at nextbcast */
+
+char   packet[MAXPACKETSIZE+1];
+struct rip *msg;
+
+char   **argv0;
+struct servent *sp;
+
+struct in_addr inet_makeaddr();
+int    inet_addr();
+int    sndmsg();
+int    supply();
+int    cleanup();
diff --git a/usr/src/sbin/routed/if.c b/usr/src/sbin/routed/if.c
new file mode 100644 (file)
index 0000000..4871c9d
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)if.c       5.6 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Find the interface with address addr.
+ */
+struct interface *
+if_ifwithaddr(addr)
+       struct sockaddr *addr;
+{
+       register struct interface *ifp;
+
+#define        same(a1, a2) \
+       (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
+       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;
+               if (same(&ifp->int_addr, addr))
+                       break;
+               if ((ifp->int_flags & IFF_BROADCAST) &&
+                   same(&ifp->int_broadaddr, addr))
+                       break;
+       }
+       return (ifp);
+}
+
+/*
+ * Find the point-to-point interface with destination address addr.
+ */
+struct interface *
+if_ifwithdstaddr(addr)
+       struct sockaddr *addr;
+{
+       register struct interface *ifp;
+
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               if ((ifp->int_flags & IFF_POINTOPOINT) == 0)
+                       continue;
+               if (same(&ifp->int_dstaddr, addr))
+                       break;
+       }
+       return (ifp);
+}
+
+/*
+ * Find the interface on the network 
+ * of the specified address.
+ */
+struct interface *
+if_ifwithnet(addr)
+       register struct sockaddr *addr;
+{
+       register struct interface *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->int_next) {
+               if (ifp->int_flags & IFF_REMOTE)
+                       continue;
+               if (af != ifp->int_addr.sa_family)
+                       continue;
+               if ((*netmatch)(addr, &ifp->int_addr))
+                       break;
+       }
+       return (ifp);
+}
+
+/*
+ * Find an interface from which the specified address
+ * should have come from.  Used for figuring out which
+ * interface a packet came in on -- for tracing.
+ */
+struct interface *
+if_iflookup(addr)
+       struct sockaddr *addr;
+{
+       register struct interface *ifp, *maybe;
+       register int af = addr->sa_family;
+       register int (*netmatch)();
+
+       if (af >= af_max)
+               return (0);
+       maybe = 0;
+       netmatch = afswitch[af].af_netmatch;
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               if (ifp->int_addr.sa_family != af)
+                       continue;
+               if (same(&ifp->int_addr, addr))
+                       break;
+               if ((ifp->int_flags & IFF_BROADCAST) &&
+                   same(&ifp->int_broadaddr, addr))
+                       break;
+               if ((ifp->int_flags & IFF_POINTOPOINT) &&
+                   same(&ifp->int_dstaddr, addr))
+                       break;
+               if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
+                       maybe = ifp;
+       }
+       if (ifp == 0)
+               ifp = maybe;
+       return (ifp);
+}
diff --git a/usr/src/sbin/routed/inet.c b/usr/src/sbin/routed/inet.c
new file mode 100644 (file)
index 0000000..a465ac7
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)inet.c     5.8 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * Temporarily, copy these routines from the kernel,
+ * as we need to know about subnets.
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Formulate an Internet address from network + host.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+       u_long net, host;
+{
+       register struct interface *ifp;
+       register u_long mask;
+       u_long addr;
+
+       if (IN_CLASSA(net))
+               mask = IN_CLASSA_HOST;
+       else if (IN_CLASSB(net))
+               mask = IN_CLASSB_HOST;
+       else
+               mask = IN_CLASSC_HOST;
+       for (ifp = ifnet; ifp; ifp = ifp->int_next)
+               if ((ifp->int_netmask & net) == ifp->int_net) {
+                       mask = ~ifp->int_subnetmask;
+                       break;
+               }
+       addr = net | (host & mask);
+       addr = htonl(addr);
+       return (*(struct in_addr *)&addr);
+}
+
+/*
+ * Return the network number from an internet address.
+ */
+inet_netof(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+       register u_long net;
+       register struct interface *ifp;
+
+       if (IN_CLASSA(i))
+               net = i & IN_CLASSA_NET;
+       else if (IN_CLASSB(i))
+               net = i & IN_CLASSB_NET;
+       else
+               net = i & IN_CLASSC_NET;
+
+       /*
+        * Check whether network is a subnet;
+        * if so, return subnet number.
+        */
+       for (ifp = ifnet; ifp; ifp = ifp->int_next)
+               if ((ifp->int_netmask & net) == ifp->int_net)
+                       return (i & ifp->int_subnetmask);
+       return (net);
+}
+
+/*
+ * Return the host portion of an internet address.
+ */
+inet_lnaof(in)
+       struct in_addr in;
+{
+       register u_long i = ntohl(in.s_addr);
+       register u_long net, host;
+       register struct interface *ifp;
+
+       if (IN_CLASSA(i)) {
+               net = i & IN_CLASSA_NET;
+               host = i & IN_CLASSA_HOST;
+       } else if (IN_CLASSB(i)) {
+               net = i & IN_CLASSB_NET;
+               host = i & IN_CLASSB_HOST;
+       } else {
+               net = i & IN_CLASSC_NET;
+               host = i & IN_CLASSC_HOST;
+       }
+
+       /*
+        * Check whether network is a subnet;
+        * if so, use the modified interpretation of `host'.
+        */
+       for (ifp = ifnet; ifp; ifp = ifp->int_next)
+               if ((ifp->int_netmask & net) == ifp->int_net)
+                       return (host &~ ifp->int_subnetmask);
+       return (host);
+}
+
+/*
+ * Return RTF_HOST if the address is
+ * for an Internet host, RTF_SUBNET for a subnet,
+ * 0 for a network.
+ */
+inet_rtflags(sin)
+       struct sockaddr_in *sin;
+{
+       register u_long i = ntohl(sin->sin_addr.s_addr);
+       register u_long net, host;
+       register struct interface *ifp;
+
+       if (IN_CLASSA(i)) {
+               net = i & IN_CLASSA_NET;
+               host = i & IN_CLASSA_HOST;
+       } else if (IN_CLASSB(i)) {
+               net = i & IN_CLASSB_NET;
+               host = i & IN_CLASSB_HOST;
+       } else {
+               net = i & IN_CLASSC_NET;
+               host = i & IN_CLASSC_HOST;
+       }
+
+       /*
+        * Check whether this network is subnetted;
+        * if so, check whether this is a subnet or a host.
+        */
+       for (ifp = ifnet; ifp; ifp = ifp->int_next)
+               if (net == ifp->int_net) {
+                       if (host &~ ifp->int_subnetmask)
+                               return (RTF_HOST);
+                       else if (ifp->int_subnetmask != ifp->int_netmask)
+                               return (RTF_SUBNET);
+                       else
+                               return (0);             /* network */
+               }
+       if (host == 0)
+               return (0);     /* network */
+       else
+               return (RTF_HOST);
+}
+
+/*
+ * Return true if a route to subnet/host of route rt should be sent to dst.
+ * Send it only if dst is on the same logical network if not "internal",
+ * otherwise only if the route is the "internal" route for the logical net.
+ */
+inet_sendroute(rt, dst)
+       struct rt_entry *rt;
+       struct sockaddr_in *dst;
+{
+       register u_long r =
+           ntohl(((struct sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr);
+       register u_long d = ntohl(dst->sin_addr.s_addr);
+
+       if (IN_CLASSA(r)) {
+               if ((r & IN_CLASSA_NET) == (d & IN_CLASSA_NET)) {
+                       if ((r & IN_CLASSA_HOST) == 0)
+                               return ((rt->rt_state & RTS_INTERNAL) == 0);
+                       return (1);
+               }
+               if (r & IN_CLASSA_HOST)
+                       return (0);
+               return ((rt->rt_state & RTS_INTERNAL) != 0);
+       } else if (IN_CLASSB(r)) {
+               if ((r & IN_CLASSB_NET) == (d & IN_CLASSB_NET)) {
+                       if ((r & IN_CLASSB_HOST) == 0)
+                               return ((rt->rt_state & RTS_INTERNAL) == 0);
+                       return (1);
+               }
+               if (r & IN_CLASSB_HOST)
+                       return (0);
+               return ((rt->rt_state & RTS_INTERNAL) != 0);
+       } else {
+               if ((r & IN_CLASSC_NET) == (d & IN_CLASSC_NET)) {
+                       if ((r & IN_CLASSC_HOST) == 0)
+                               return ((rt->rt_state & RTS_INTERNAL) == 0);
+                       return (1);
+               }
+               if (r & IN_CLASSC_HOST)
+                       return (0);
+               return ((rt->rt_state & RTS_INTERNAL) != 0);
+       }
+}
diff --git a/usr/src/sbin/routed/input.c b/usr/src/sbin/routed/input.c
new file mode 100644 (file)
index 0000000..ec8c9d7
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)input.c    5.22 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/syslog.h>
+
+/*
+ * Process a newly received packet.
+ */
+rip_input(from, rip, size)
+       struct sockaddr *from;
+       register struct rip *rip;
+       int size;
+{
+       register struct rt_entry *rt;
+       register struct netinfo *n;
+       register struct interface *ifp;
+       struct interface *if_ifwithdstaddr();
+       int count, changes = 0;
+       register struct afswitch *afp;
+       static struct sockaddr badfrom, badfrom2;
+
+       ifp = 0;
+       TRACE_INPUT(ifp, from, (char *)rip, size);
+       if (from->sa_family >= af_max ||
+           (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) {
+               syslog(LOG_INFO,
+        "\"from\" address in unsupported address family (%d), cmd %d\n",
+                   from->sa_family, rip->rip_cmd);
+               return;
+       }
+       if (rip->rip_vers == 0) {
+               syslog(LOG_ERR,
+                   "RIP version 0 packet received from %s! (cmd %d)",
+                   (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd);
+               return;
+       }
+       switch (rip->rip_cmd) {
+
+       case RIPCMD_REQUEST:
+               n = rip->rip_nets;
+               count = size - ((char *)n - (char *)rip);
+               if (count < sizeof (struct netinfo))
+                       return;
+               for (; count > 0; n++) {
+                       if (count < sizeof (struct netinfo))
+                               break;
+                       count -= sizeof (struct netinfo);
+
+#if BSD < 198810
+                       if (sizeof(n->rip_dst.sa_family) > 1)   /* XXX */
+                           n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+#else
+#define osa(x) ((struct osockaddr *)(&(x)))
+                           n->rip_dst.sa_family =
+                                       ntohs(osa(n->rip_dst)->sa_family);
+                           n->rip_dst.sa_len = sizeof(n->rip_dst);
+#endif
+                       n->rip_metric = ntohl(n->rip_metric);
+                       /* 
+                        * A single entry with sa_family == AF_UNSPEC and
+                        * metric ``infinity'' means ``all routes''.
+                        * We respond to routers only if we are acting
+                        * as a supplier, or to anyone other than a router
+                        * (eg, query).
+                        */
+                       if (n->rip_dst.sa_family == AF_UNSPEC &&
+                           n->rip_metric == HOPCNT_INFINITY && count == 0) {
+                               if (supplier || (*afp->af_portmatch)(from) == 0)
+                                       supply(from, 0, 0, 0);
+                               return;
+                       }
+                       if (n->rip_dst.sa_family < af_max &&
+                           afswitch[n->rip_dst.sa_family].af_hash)
+                               rt = rtlookup(&n->rip_dst);
+                       else
+                               rt = 0;
+#define min(a, b) (a < b ? a : b)
+                       n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
+                               min(rt->rt_metric + 1, HOPCNT_INFINITY);
+#if BSD < 198810
+                       if (sizeof(n->rip_dst.sa_family) > 1)   /* XXX */
+                           n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
+#else
+                           osa(n->rip_dst)->sa_family =
+                                               htons(n->rip_dst.sa_family);
+#endif
+                       n->rip_metric = htonl(n->rip_metric);
+               }
+               rip->rip_cmd = RIPCMD_RESPONSE;
+               bcopy((char *)rip, packet, size);
+               (*afp->af_output)(s, 0, from, size);
+               return;
+
+       case RIPCMD_TRACEON:
+       case RIPCMD_TRACEOFF:
+               /* verify message came from a privileged port */
+               if ((*afp->af_portcheck)(from) == 0)
+                       return;
+               if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
+                   (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
+                   ifp->int_flags & IFF_PASSIVE) {
+                       syslog(LOG_ERR, "trace command from unknown router, %s",
+                           (*afswitch[from->sa_family].af_format)(from));
+                       return;
+               }
+               ((char *)rip)[size] = '\0';
+               if (rip->rip_cmd == RIPCMD_TRACEON)
+                       traceon(rip->rip_tracefile);
+               else
+                       traceoff();
+               return;
+
+       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) {
+                       if (ifp->int_flags & IFF_PASSIVE) {
+                               syslog(LOG_ERR,
+                                 "bogus input (from passive interface, %s)",
+                                 (*afswitch[from->sa_family].af_format)(from));
+                               return;
+                       }
+                       rt = rtfind(from);
+                       if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) &&
+                           rt->rt_metric >= ifp->int_metric) 
+                               addrouteforif(ifp);
+                       else
+                               rt->rt_timer = 0;
+                       return;
+               }
+               /*
+                * Update timer for interface on which the packet arrived.
+                * If from other end of a point-to-point link that isn't
+                * in the routing tables, (re-)add the route.
+                */
+               if ((rt = rtfind(from)) &&
+                   (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
+                       rt->rt_timer = 0;
+               else if ((ifp = if_ifwithdstaddr(from)) &&
+                   (rt == 0 || rt->rt_metric >= ifp->int_metric))
+                       addrouteforif(ifp);
+               /*
+                * "Authenticate" router from which message originated.
+                * We accept routing packets from routers directly connected
+                * via broadcast or point-to-point networks,
+                * and from those listed in /etc/gateways.
+                */
+               if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
+                   (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
+                   ifp->int_flags & IFF_PASSIVE) {
+                       if (bcmp((char *)from, (char *)&badfrom,
+                           sizeof(badfrom)) != 0) {
+                               syslog(LOG_ERR,
+                                 "packet from unknown router, %s",
+                                 (*afswitch[from->sa_family].af_format)(from));
+                               badfrom = *from;
+                       }
+                       return;
+               }
+               size -= 4 * sizeof (char);
+               n = rip->rip_nets;
+               for (; size > 0; size -= sizeof (struct netinfo), n++) {
+                       if (size < sizeof (struct netinfo))
+                               break;
+#if BSD < 198810
+                       if (sizeof(n->rip_dst.sa_family) > 1)   /* XXX */
+                               n->rip_dst.sa_family =
+                                       ntohs(n->rip_dst.sa_family);
+#else
+                           n->rip_dst.sa_family =
+                                       ntohs(osa(n->rip_dst)->sa_family);
+                           n->rip_dst.sa_len = sizeof(n->rip_dst);
+#endif
+                       n->rip_metric = ntohl(n->rip_metric);
+                       if (n->rip_dst.sa_family >= af_max ||
+                           (afp = &afswitch[n->rip_dst.sa_family])->af_hash ==
+                           (int (*)())0) {
+                               syslog(LOG_INFO,
+               "route in unsupported address family (%d), from %s (af %d)\n",
+                                  n->rip_dst.sa_family,
+                                  (*afswitch[from->sa_family].af_format)(from),
+                                  from->sa_family);
+                               continue;
+                       }
+                       if (((*afp->af_checkhost)(&n->rip_dst)) == 0) {
+                               syslog(LOG_DEBUG,
+                                   "bad host in route from %s (af %d)\n",
+                                  (*afswitch[from->sa_family].af_format)(from),
+                                  from->sa_family);
+                               continue;
+                       }
+                       if (n->rip_metric == 0 ||
+                           (unsigned) n->rip_metric > HOPCNT_INFINITY) {
+                               if (bcmp((char *)from, (char *)&badfrom2,
+                                   sizeof(badfrom2)) != 0) {
+                                       syslog(LOG_ERR,
+                                           "bad metric (%d) from %s\n",
+                                           n->rip_metric,
+                                 (*afswitch[from->sa_family].af_format)(from));
+                                       badfrom2 = *from;
+                               }
+                               continue;
+                       }
+                       /*
+                        * Adjust metric according to incoming interface.
+                        */
+                       if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
+                               n->rip_metric += ifp->int_metric;
+                       if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
+                               n->rip_metric = HOPCNT_INFINITY;
+                       rt = rtlookup(&n->rip_dst);
+                       if (rt == 0 ||
+                           (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
+                           (RTS_INTERNAL|RTS_INTERFACE)) {
+                               /*
+                                * If we're hearing a logical network route
+                                * back from a peer to which we sent it,
+                                * ignore it.
+                                */
+                               if (rt && rt->rt_state & RTS_SUBNET &&
+                                   (*afp->af_sendroute)(rt, from))
+                                       continue;
+                               if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
+                                   /*
+                                    * Look for an equivalent route that
+                                    * includes this one before adding
+                                    * this route.
+                                    */
+                                   rt = rtfind(&n->rip_dst);
+                                   if (rt && equal(from, &rt->rt_router))
+                                           continue;
+                                   rtadd(&n->rip_dst, from, n->rip_metric, 0);
+                                   changes++;
+                               }
+                               continue;
+                       }
+
+                       /*
+                        * Update if from gateway and different,
+                        * shorter, or equivalent but old route
+                        * is getting stale.
+                        */
+                       if (equal(from, &rt->rt_router)) {
+                               if (n->rip_metric != rt->rt_metric) {
+                                       rtchange(rt, from, n->rip_metric);
+                                       changes++;
+                                       rt->rt_timer = 0;
+                                       if (rt->rt_metric >= HOPCNT_INFINITY)
+                                               rt->rt_timer =
+                                                   GARBAGE_TIME - EXPIRE_TIME;
+                               } else if (rt->rt_metric < HOPCNT_INFINITY)
+                                       rt->rt_timer = 0;
+                       } else if ((unsigned) n->rip_metric < rt->rt_metric ||
+                           (rt->rt_metric == n->rip_metric &&
+                           rt->rt_timer > (EXPIRE_TIME/2) &&
+                           (unsigned) n->rip_metric < HOPCNT_INFINITY)) {
+                               rtchange(rt, from, n->rip_metric);
+                               changes++;
+                               rt->rt_timer = 0;
+                       }
+               }
+               break;
+       }
+
+       /*
+        * If changes have occurred, and if we have not sent a broadcast
+        * recently, send a dynamic update.  This update is sent only
+        * on interfaces other than the one on which we received notice
+        * of the change.  If we are within MIN_WAITTIME of a full update,
+        * don't bother sending; if we just sent a dynamic update
+        * and set a timer (nextbcast), delay until that time.
+        * If we just sent a full update, delay the dynamic update.
+        * Set a timer for a randomized value to suppress additional
+        * dynamic updates until it expires; if we delayed sending
+        * the current changes, set needupdate.
+        */
+       if (changes && supplier &&
+          now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
+               u_long delay;
+               extern long random();
+
+               if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
+                   timercmp(&nextbcast, &now, <)) {
+                       if (traceactions)
+                               fprintf(ftrace, "send dynamic update\n");
+                       toall(supply, RTS_CHANGED, ifp);
+                       lastbcast = now;
+                       needupdate = 0;
+                       nextbcast.tv_sec = 0;
+               } else {
+                       needupdate++;
+                       if (traceactions)
+                               fprintf(ftrace, "delay dynamic update\n");
+               }
+#define RANDOMDELAY()  (MIN_WAITTIME * 1000000 + \
+               (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
+
+               if (nextbcast.tv_sec == 0) {
+                       delay = RANDOMDELAY();
+                       if (traceactions)
+                               fprintf(ftrace,
+                                   "inhibit dynamic update for %d usec\n",
+                                   delay);
+                       nextbcast.tv_sec = delay / 1000000;
+                       nextbcast.tv_usec = delay % 1000000;
+                       timevaladd(&nextbcast, &now);
+                       /*
+                        * If the next possibly dynamic update
+                        * is within MIN_WAITTIME of the next full update,
+                        * force the delay past the full update,
+                        * or we might send a dynamic update just before
+                        * the full update.
+                        */
+                       if (nextbcast.tv_sec > lastfullupdate.tv_sec +
+                           SUPPLY_INTERVAL - MIN_WAITTIME)
+                               nextbcast.tv_sec = lastfullupdate.tv_sec +
+                                   SUPPLY_INTERVAL + 1;
+               }
+       }
+}
diff --git a/usr/src/sbin/routed/interface.h b/usr/src/sbin/routed/interface.h
new file mode 100644 (file)
index 0000000..6e555cb
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)interface.h 5.6 (Berkeley) 6/1/90
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * An ``interface'' is similar to an ifnet structure,
+ * except it doesn't contain q'ing info, and it also
+ * handles ``logical'' interfaces (remote gateways
+ * that we want to keep polling even if they go down).
+ * The list of interfaces which we maintain is used
+ * in supplying the gratuitous routing table updates.
+ */
+struct interface {
+       struct  interface *int_next;
+       struct  sockaddr int_addr;              /* address on this host */
+       union {
+               struct  sockaddr intu_broadaddr;
+               struct  sockaddr intu_dstaddr;
+       } int_intu;
+#define        int_broadaddr   int_intu.intu_broadaddr /* broadcast address */
+#define        int_dstaddr     int_intu.intu_dstaddr   /* other end of p-to-p link */
+       int     int_metric;                     /* init's routing entry */
+       int     int_flags;                      /* see below */
+       /* START INTERNET SPECIFIC */
+       u_long  int_net;                        /* network # */
+       u_long  int_netmask;                    /* net mask for addr */
+       u_long  int_subnet;                     /* subnet # */
+       u_long  int_subnetmask;                 /* subnet mask for addr */
+       /* END INTERNET SPECIFIC */
+       struct  ifdebug int_input, int_output;  /* packet tracing stuff */
+       int     int_ipackets;                   /* input packets received */
+       int     int_opackets;                   /* output packets sent */
+       char    *int_name;                      /* from kernel if structure */
+       u_short int_transitions;                /* times gone up-down */
+};
+
+/*
+ * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
+ * the others agree with the RTS_ flags defined elsewhere.
+ */
+#define        IFF_UP          0x1             /* interface is up */
+#define        IFF_BROADCAST   0x2             /* broadcast address valid */
+#define        IFF_DEBUG       0x4             /* turn on debugging */
+#define        IFF_LOOPBACK    0x8             /* software loopback net */
+#define        IFF_POINTOPOINT 0x10            /* interface is point-to-point link */
+
+#define        IFF_SUBNET      0x1000          /* interface on subnetted network */
+#define        IFF_PASSIVE     0x2000          /* can't tell if up/down */
+#define        IFF_INTERFACE   0x4000          /* hardware interface */
+#define        IFF_REMOTE      0x8000          /* interface isn't on this machine */
+
+struct interface *if_ifwithaddr();
+struct interface *if_ifwithdstaddr();
+struct interface *if_ifwithnet();
+struct interface *if_iflookup();
diff --git a/usr/src/sbin/routed/output.c b/usr/src/sbin/routed/output.c
new file mode 100644 (file)
index 0000000..10c81b1
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)output.c   5.15 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+/*
+ * Apply the function "f" to all non-passive
+ * interfaces.  If the interface supports the
+ * use of broadcasting use it, otherwise address
+ * the output to the known router.
+ */
+toall(f, rtstate, skipif)
+       int (*f)();
+       int rtstate;
+       struct interface *skipif;
+{
+       register struct interface *ifp;
+       register struct sockaddr *dst;
+       register int flags;
+       extern struct interface *ifnet;
+
+       for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+               if (ifp->int_flags & IFF_PASSIVE || ifp == skipif)
+                       continue;
+               dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
+                     ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
+                     &ifp->int_addr;
+               flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
+               (*f)(dst, flags, ifp, rtstate);
+       }
+}
+
+/*
+ * Output a preformed packet.
+ */
+/*ARGSUSED*/
+sndmsg(dst, flags, ifp, rtstate)
+       struct sockaddr *dst;
+       int flags;
+       struct interface *ifp;
+       int rtstate;
+{
+
+       (*afswitch[dst->sa_family].af_output)(s, flags,
+               dst, sizeof (struct rip));
+       TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
+}
+
+/*
+ * Supply dst with the contents of the routing tables.
+ * If this won't fit in one packet, chop it up into several.
+ */
+supply(dst, flags, ifp, rtstate)
+       struct sockaddr *dst;
+       int flags;
+       register struct interface *ifp;
+       int rtstate;
+{
+       register struct rt_entry *rt;
+       register struct netinfo *n = msg->rip_nets;
+       register struct rthash *rh;
+       struct rthash *base = hosthash;
+       int doinghost = 1, size;
+       int (*output)() = afswitch[dst->sa_family].af_output;
+       int (*sendroute)() = afswitch[dst->sa_family].af_sendroute;
+       int npackets = 0;
+
+       msg->rip_cmd = RIPCMD_RESPONSE;
+       msg->rip_vers = RIPVERSION;
+       bzero(msg->rip_res1, sizeof(msg->rip_res1));
+again:
+       for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
+       for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+               /*
+                * Don't resend the information on the network
+                * from which it was received (unless sending
+                * in response to a query).
+                */
+               if (ifp && rt->rt_ifp == ifp &&
+                   (rt->rt_state & RTS_INTERFACE) == 0)
+                       continue;
+               if (rt->rt_state & RTS_EXTERNAL)
+                       continue;
+               /*
+                * For dynamic updates, limit update to routes
+                * with the specified state.
+                */
+               if (rtstate && (rt->rt_state & rtstate) == 0)
+                       continue;
+               /*
+                * Limit the spread of subnet information
+                * to those who are interested.
+                */
+               if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
+                       if (rt->rt_dst.sa_family != dst->sa_family)
+                               continue;
+                       if ((*sendroute)(rt, dst) == 0)
+                               continue;
+               }
+               size = (char *)n - packet;
+               if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
+                       TRACE_OUTPUT(ifp, dst, size);
+                       (*output)(s, flags, dst, size);
+                       /*
+                        * If only sending to ourselves,
+                        * one packet is enough to monitor interface.
+                        */
+                       if (ifp && (ifp->int_flags &
+                          (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0)
+                               return;
+                       n = msg->rip_nets;
+                       npackets++;
+               }
+               n->rip_dst = rt->rt_dst;
+#if BSD < 198810
+               if (sizeof(n->rip_dst.sa_family) > 1)   /* XXX */
+               n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
+#else
+#define osa(x) ((struct osockaddr *)(&(x)))
+               osa(n->rip_dst)->sa_family = htons(n->rip_dst.sa_family);
+#endif
+               n->rip_metric = htonl(rt->rt_metric);
+               n++;
+       }
+       if (doinghost) {
+               doinghost = 0;
+               base = nethash;
+               goto again;
+       }
+       if (n != msg->rip_nets || (npackets == 0 && rtstate == 0)) {
+               size = (char *)n - packet;
+               TRACE_OUTPUT(ifp, dst, size);
+               (*output)(s, flags, dst, size);
+       }
+}
diff --git a/usr/src/sbin/routed/pathnames.h b/usr/src/sbin/routed/pathnames.h
new file mode 100644 (file)
index 0000000..54bac27
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)pathnames.h 5.3 (Berkeley) 6/1/90
+ */
+
+#include <paths.h>
+
+#define        _PATH_GATEWAYS  "/etc/gateways"
diff --git a/usr/src/sbin/routed/routed.8 b/usr/src/sbin/routed/routed.8
new file mode 100644 (file)
index 0000000..1d428a7
--- /dev/null
@@ -0,0 +1,360 @@
+.\" Copyright (c) 1983, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)routed.8   6.6 (Berkeley) 3/16/91
+.\"
+.Dd March 16, 1991
+.Dt ROUTED 8
+.Os BSD 4.2
+.Sh NAME
+.Nm routed
+.Nd network routing daemon
+.Sh SYNOPSIS
+.Nm routed
+.Op Fl d
+.Op Fl g
+.Op Fl q
+.Op Fl s
+.Op Fl t
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm Routed
+is invoked at boot time to manage the network routing tables.
+The routing daemon uses a variant of the Xerox NS Routing
+Information Protocol in maintaining up to date kernel routing
+table entries.
+It used a generalized protocol capable of use with multiple
+address types, but is currently used only for Internet routing
+within a cluster of networks.
+.Pp
+In normal operation
+.Nm routed
+listens on the
+.Xr udp 4
+socket for the
+.Xr route 8
+service (see
+.Xr services 5 )
+for routing information packets.  If the host is an
+internetwork router, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm routed
+is started, it uses the
+.Dv SIOCGIFCONF
+.Xr ioctl 2
+to find those
+directly connected interfaces configured into the
+system and marked ``up'' (the software loopback interface
+is ignored).  If multiple interfaces
+are present, it is assumed that the host will forward packets
+between networks.
+.Nm Routed
+then transmits a 
+.Em request
+packet on each interface (using a broadcast packet if
+the interface supports it) and enters a loop, listening
+for
+.Em request
+and
+.Em response
+packets from other hosts.
+.Pp
+When a
+.Em request
+packet is received, 
+.Nm routed
+formulates a reply based on the information maintained in its
+internal tables.  The
+.Em response
+packet generated contains a list of known routes, each marked
+with a ``hop count'' metric (a count of 16, or greater, is
+considered ``infinite'').  The metric associated with each
+route returned provides a metric
+.Em relative to the sender .
+.Pp
+.Em Response
+packets received by
+.Nm routed
+are used to update the routing tables if one of the following
+conditions is satisfied:
+.Bl -enum
+.It
+No routing table entry exists for the destination network
+or host, and the metric indicates the destination is ``reachable''
+(i.e. the hop count is not infinite).
+.It
+The source host of the packet is the same as the router in the
+existing routing table entry.  That is, updated information is
+being received from the very internetwork router through which
+packets for the destination are being routed.
+.It
+The existing entry in the routing table has not been updated for
+some time (defined to be 90 seconds) and the route is at least
+as cost effective as the current route.
+.It
+The new route describes a shorter route to the destination than
+the one currently stored in the routing tables; the metric of
+the new route is compared against the one stored in the table
+to decide this.
+.El
+.Pp
+When an update is applied,
+.Nm routed
+records the change in its internal tables and updates the kernel
+routing table.
+The change is reflected in the next
+.Em response
+packet sent.
+.Pp
+In addition to processing incoming packets,
+.Nm routed
+also periodically checks the routing table entries.
+If an entry has not been updated for 3 minutes, the entry's metric
+is set to infinity and marked for deletion.  Deletions are delayed
+an additional 60 seconds to insure the invalidation is propagated
+throughout the local internet.
+.Pp
+Hosts acting as internetwork routers gratuitously supply their
+routing tables every 30 seconds to all directly connected hosts
+and networks.
+The response is sent to the broadcast address on nets capable of that function,
+to the destination address on point-to-point links, and to the router's
+own address on other networks.
+The normal routing tables are bypassed when sending gratuitous responses.
+The reception of responses on each network is used to determine that the
+network and interface are functioning correctly.
+If no response is received on an interface, another route may be chosen
+to route around the interface, or the route may be dropped if no alternative
+is available.
+.Pp
+Options supported by
+.Nm routed :
+.Bl -tag -width Ds
+.It Fl d
+Enable additional debugging information to be logged,
+such as bad packets received.
+.It Fl g
+This flag is used on internetwork routers to offer a route
+to the ``default'' destination.
+This is typically used on a gateway to the Internet,
+or on a gateway that uses another routing protocol whose routes
+are not reported to other local routers.
+.It Fl s
+Supplying this
+option forces 
+.Nm routed
+to supply routing information whether it is acting as an internetwork
+router or not.
+This is the default if multiple network interfaces are present,
+or if a point-to-point link is in use.
+.It Fl q
+This
+is the opposite of the
+.Fl s
+option.
+.It Fl t
+If the
+.Fl t
+option is specified, all packets sent or received are
+printed on the standard output.  In addition,
+.Nm routed
+will not divorce itself from the controlling terminal
+so that interrupts from the keyboard will kill the process.
+.El
+.Pp
+Any other argument supplied is interpreted as the name
+of file in which 
+.Nm routed Ns \'s
+actions should be logged.  This log contains information
+about any changes to the routing tables and, if not tracing all packets,
+a history of recent messages sent and received which are related to
+the changed route.
+.Pp
+In addition to the facilities described above, 
+.Nm routed
+supports the notion of ``distant''
+.Em passive
+and 
+.Em active
+gateways.  When 
+.Nm routed
+is started up, it reads the file
+.Pa /etc/gateways
+to find gateways which may not be located using
+only information from the
+.Dv SIOGIFCONF
+.Xr ioctl 2 .
+Gateways specified in this manner should be marked passive
+if they are not expected to exchange routing information,
+while gateways marked active
+should be willing to exchange routing information (i.e.
+they should have a
+.Nm routed
+process running on the machine).
+Routes through passive gateways are installed in the
+kernel's routing tables once upon startup.
+Such routes are not included in
+any routing information transmitted.
+Active gateways are treated equally to network
+interfaces.  Routing information is distributed
+to the gateway and if no routing information is
+received for a period of the time, the associated
+route is deleted.
+Gateways marked
+.Em external
+are also passive, but are not placed in the kernel
+routing table nor are they included in routing updates.
+The function of external entries is to inform
+.Nm routed
+that another routing process
+will install such a route, and that alternate routes to that destination
+should not be installed.
+Such entries are only required when both routers may learn of routes
+to the same destination.
+.Pp
+The 
+.Pa /etc/gateways
+is comprised of a series of lines, each in
+the following format:
+.Bd -ragged
+.Pf < Cm net No \&|
+.Cm host Ns >
+.Ar name1
+.Cm gateway
+.Ar name2
+.Cm metric
+.Ar value
+.Pf < Cm passive No \&|
+.Cm active No \&|
+.Cm external Ns >
+.Ed
+.Pp
+The 
+.Cm net
+or
+.Cm host
+keyword indicates if the route is to a network or specific host.
+.Pp
+.Ar Name1
+is the name of the destination network or host.  This may be a
+symbolic name located in
+.Pa /etc/networks
+or
+.Pa /etc/hosts
+(or, if started after
+.Xr named 8 ,
+known to the name server), 
+or an Internet address specified in ``dot'' notation; see
+.Xr inet 3 .
+.Pp
+.Ar Name2
+is the name or address of the gateway to which messages should
+be forwarded.
+.Pp
+.Ar Value
+is a metric indicating the hop count to the destination host
+or network.
+.Pp
+One of the keywords
+.Cm passive ,
+.Cm active
+or
+.Cm external
+indicates if the gateway should be treated as 
+.Em passive
+or
+.Em active
+(as described above),
+or whether the gateway is
+.Em external
+to the scope of the
+.Nm routed
+protocol.
+.Pp
+Internetwork routers that are directly attached to the Arpanet or Milnet
+should use the Exterior Gateway Protocol
+.Pq Tn EGP
+to gather routing information
+rather then using a static routing table of passive gateways.
+.Tn EGP
+is required in order to provide routes for local networks to the rest
+of the Internet system.
+Sites needing assistance with such configurations
+should contact the Computer Systems Research Group at Berkeley.
+.Sh FILES
+.Bl -tag -width /etc/gateways -compact
+.It Pa /etc/gateways
+for distant gateways
+.El
+.Sh SEE ALSO
+.Xr udp 4 ,
+.Xr icmp 4 ,
+.Xr XNSrouted 8 ,
+.Xr htable 8
+.Rs
+.%T Internet Transport Protocols
+.%R XSIS 028112
+.%Q Xerox System Integration Standard
+.Re
+.Sh BUGS
+The kernel's routing tables may not correspond to those of
+.Nm routed
+when redirects change or add routes.
+.Nm Routed
+should note any redirects received by reading
+the
+.Tn ICMP
+packets received via a raw socket.
+.Pp
+.Nm Routed
+should incorporate other routing protocols,
+such as Xerox
+.Tn \&NS
+.Pq Xr XNSrouted 8
+and
+.Tn EGP .
+Using separate processes for each requires configuration options
+to avoid redundant or competing routes.
+.Pp
+.Nm Routed
+should listen to intelligent interfaces, such as an
+.Tn IMP ,
+to gather more information.
+It does not always detect unidirectional failures in network interfaces
+(e.g., when the output side fails).
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr/src/sbin/routed/startup.c b/usr/src/sbin/routed/startup.c
new file mode 100644 (file)
index 0000000..f88d593
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)startup.c  5.19 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+struct interface *ifnet;
+struct interface **ifnext = &ifnet;
+int    lookforinterfaces = 1;
+int    externalinterfaces = 0;         /* # of remote and local interfaces */
+int    foundloopback;                  /* valid flag for loopaddr */
+struct sockaddr loopaddr;              /* our address on loopback */
+
+/*
+ * 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.
+ */
+ifinit()
+{
+       struct interface ifs, *ifp;
+       int s;
+       char buf[BUFSIZ], *cp, *cplim;
+        struct ifconf ifc;
+        struct ifreq ifreq, *ifr;
+        struct sockaddr_in *sin;
+       u_long i;
+
+       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+               syslog(LOG_ERR, "socket: %m");
+               close(s);
+                return;
+       }
+        ifc.ifc_len = sizeof (buf);
+        ifc.ifc_buf = buf;
+        if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+                syslog(LOG_ERR, "ioctl (get interface configuration)");
+               close(s);
+                return;
+        }
+        ifr = ifc.ifc_req;
+       lookforinterfaces = 0;
+#ifdef RTM_ADD
+#define max(a, b) (a > b ? a : b)
+#define size(p)        max((p).sa_len, sizeof(p))
+#else
+#define size(p) (sizeof (p))
+#endif
+       cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+       for (cp = buf; cp < cplim;
+                       cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+               ifr = (struct ifreq *)cp;
+               bzero((char *)&ifs, sizeof(ifs));
+               ifs.int_addr = ifr->ifr_addr;
+               ifreq = *ifr;
+                if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
+                        syslog(LOG_ERR, "%s: ioctl (get interface flags)",
+                           ifr->ifr_name);
+                        continue;
+                }
+               ifs.int_flags = ifreq.ifr_flags | IFF_INTERFACE;
+               if ((ifs.int_flags & IFF_UP) == 0 ||
+                   ifr->ifr_addr.sa_family == AF_UNSPEC) {
+                       lookforinterfaces = 1;
+                       continue;
+               }
+               /* argh, this'll have to change sometime */
+               if (ifs.int_addr.sa_family != AF_INET)
+                       continue;
+                if (ifs.int_flags & IFF_POINTOPOINT) {
+                        if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+                                syslog(LOG_ERR, "%s: ioctl (get dstaddr)",
+                                   ifr->ifr_name);
+                                continue;
+                       }
+                       if (ifr->ifr_addr.sa_family == AF_UNSPEC) {
+                               lookforinterfaces = 1;
+                               continue;
+                       }
+                       ifs.int_dstaddr = ifreq.ifr_dstaddr;
+               }
+               /*
+                * already known to us?
+                * This allows multiple point-to-point links
+                * to share a source address (possibly with one
+                * other link), but assumes that there will not be
+                * multiple links with the same destination address.
+                */
+               if (ifs.int_flags & IFF_POINTOPOINT) {
+                       if (if_ifwithdstaddr(&ifs.int_dstaddr))
+                               continue;
+               } else if (if_ifwithaddr(&ifs.int_addr))
+                       continue;
+               if (ifs.int_flags & IFF_LOOPBACK) {
+                       ifs.int_flags |= IFF_PASSIVE;
+                       foundloopback = 1;
+                       loopaddr = ifs.int_addr;
+                       for (ifp = ifnet; ifp; ifp = ifp->int_next)
+                           if (ifp->int_flags & IFF_POINTOPOINT)
+                               add_ptopt_localrt(ifp);
+               }
+                if (ifs.int_flags & IFF_BROADCAST) {
+                        if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+                                syslog(LOG_ERR, "%s: ioctl (get broadaddr)",
+                                   ifr->ifr_name);
+                                continue;
+                        }
+#ifndef sun
+                       ifs.int_broadaddr = ifreq.ifr_broadaddr;
+#else
+                       ifs.int_broadaddr = ifreq.ifr_addr;
+#endif
+               }
+#ifdef SIOCGIFMETRIC
+               if (ioctl(s, SIOCGIFMETRIC, (char *)&ifreq) < 0) {
+                       syslog(LOG_ERR, "%s: ioctl (get metric)",
+                           ifr->ifr_name);
+                       ifs.int_metric = 0;
+               } else
+                       ifs.int_metric = ifreq.ifr_metric;
+#else
+               ifs.int_metric = 0;
+#endif
+               /*
+                * Use a minimum metric of one;
+                * treat the interface metric (default 0)
+                * as an increment to the hop count of one.
+                */
+               ifs.int_metric++;
+               if (ioctl(s, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
+                       syslog(LOG_ERR, "%s: ioctl (get netmask)",
+                           ifr->ifr_name);
+                       continue;
+               }
+               sin = (struct sockaddr_in *)&ifreq.ifr_addr;
+               ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
+               sin = (struct sockaddr_in *)&ifs.int_addr;
+               i = ntohl(sin->sin_addr.s_addr);
+               if (IN_CLASSA(i))
+                       ifs.int_netmask = IN_CLASSA_NET;
+               else if (IN_CLASSB(i))
+                       ifs.int_netmask = IN_CLASSB_NET;
+               else
+                       ifs.int_netmask = IN_CLASSC_NET;
+               ifs.int_net = i & ifs.int_netmask;
+               ifs.int_subnet = i & ifs.int_subnetmask;
+               if (ifs.int_subnetmask != ifs.int_netmask)
+                       ifs.int_flags |= IFF_SUBNET;
+               ifp = (struct interface *)malloc(sizeof (struct interface));
+               if (ifp == 0) {
+                       printf("routed: out of memory\n");
+                       break;
+               }
+               *ifp = ifs;
+               /*
+                * 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''.
+                */
+               if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
+                   ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
+                   if_ifwithaddr(&ifs.int_dstaddr) == 0))
+                       externalinterfaces++;
+               /*
+                * If we have a point-to-point link, we want to act
+                * as a supplier even if it's our only interface,
+                * as that's the only way our peer on the other end
+                * can tell that the link is up.
+                */
+               if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
+                       supplier = 1;
+               ifp->int_name = malloc(strlen(ifr->ifr_name) + 1);
+               if (ifp->int_name == 0) {
+                       fprintf(stderr, "routed: ifinit: out of memory\n");
+                       syslog(LOG_ERR, "routed: ifinit: out of memory\n");
+                       close(s);
+                       return;
+               }
+               strcpy(ifp->int_name, ifr->ifr_name);
+               *ifnext = ifp;
+               ifnext = &ifp->int_next;
+               traceinit(ifp);
+               addrouteforif(ifp);
+       }
+       if (externalinterfaces > 1 && supplier < 0)
+               supplier = 1;
+       close(s);
+}
+
+/*
+ * Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ * INTERNET SPECIFIC.
+ */
+addrouteforif(ifp)
+       register struct interface *ifp;
+{
+       struct sockaddr_in net;
+       struct sockaddr *dst;
+       int state;
+       register struct rt_entry *rt;
+
+       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_subnet, INADDR_ANY);
+               dst = (struct sockaddr *)&net;
+       }
+       rt = rtfind(dst);
+       if (rt &&
+           (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
+               return;
+       if (rt)
+               rtdelete(rt);
+       /*
+        * If interface on subnetted network,
+        * install route to network as well.
+        * This is meant for external viewers.
+        */
+       if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
+               struct in_addr subnet;
+
+               subnet = net.sin_addr;
+               net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+               rt = rtfind(dst);
+               if (rt == 0)
+                       rtadd(dst, &ifp->int_addr, ifp->int_metric,
+                           ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
+                           RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
+               else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) == 
+                   (RTS_INTERNAL|RTS_SUBNET) &&
+                   ifp->int_metric < rt->rt_metric)
+                       rtchange(rt, &rt->rt_router, ifp->int_metric);
+               net.sin_addr = subnet;
+       }
+       if (ifp->int_transitions++ > 0)
+               syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+       state = ifp->int_flags &
+           (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
+       if (ifp->int_flags & IFF_POINTOPOINT &&
+           (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
+           ifp->int_netmask) != ifp->int_net)
+               state &= ~RTS_SUBNET;
+       if (ifp->int_flags & IFF_LOOPBACK)
+               state |= RTS_EXTERNAL;
+       rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
+       if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
+               add_ptopt_localrt(ifp);
+}
+
+/*
+ * Add route to local end of point-to-point using loopback.
+ * If a route to this network is being sent to neighbors on other nets,
+ * mark this route as subnet so we don't have to propagate it too.
+ */
+add_ptopt_localrt(ifp)
+       register struct interface *ifp;
+{
+       struct rt_entry *rt;
+       struct sockaddr *dst;
+       struct sockaddr_in net;
+       int state;
+
+       state = RTS_INTERFACE | RTS_PASSIVE;
+
+       /* look for route to logical network */
+       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 = rtfind(dst);
+       if (rt && rt->rt_state & RTS_INTERNAL)
+               state |= RTS_SUBNET;
+
+       dst = &ifp->int_addr;
+       if (rt = rtfind(dst)) {
+               if (rt && rt->rt_state & RTS_INTERFACE)
+                       return;
+               rtdelete(rt);
+       }
+       rtadd(dst, &loopaddr, 1, state);
+}
+
+/*
+ * 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.
+ *
+ * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
+ */
+gwkludge()
+{
+       struct sockaddr_in dst, gate;
+       FILE *fp;
+       char *type, *dname, *gname, *qual, buf[BUFSIZ];
+       struct interface *ifp;
+       int metric, n;
+       struct rt_entry route;
+
+       fp = fopen(_PATH_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));
+       bzero((char *)&route, sizeof(route));
+/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
+#define        readentry(fp) \
+       fscanf((fp), "%s %s gateway %s metric %d %s\n", \
+               type, dname, gname, &metric, qual)
+       for (;;) {
+               if ((n = readentry(fp)) == EOF)
+                       break;
+               if (!getnetorhostname(type, dname, &dst))
+                       continue;
+               if (!gethostnameornumber(gname, &gate))
+                       continue;
+               if (metric == 0)                        /* XXX */
+                       metric = 1;
+               if (strcmp(qual, "passive") == 0) {
+                       /*
+                        * Passive entries aren't placed in our tables,
+                        * only the kernel's, so we don't copy all of the
+                        * external routing information within a net.
+                        * Internal machines should use the default
+                        * route to a suitable gateway (like us).
+                        */
+                       route.rt_dst = *(struct sockaddr *) &dst;
+                       route.rt_router = *(struct sockaddr *) &gate;
+                       route.rt_flags = RTF_UP;
+                       if (strcmp(type, "host") == 0)
+                               route.rt_flags |= RTF_HOST;
+                       if (metric)
+                               route.rt_flags |= RTF_GATEWAY;
+                       (void) ioctl(s, SIOCADDRT, (char *)&route.rt_rt);
+                       continue;
+               }
+               if (strcmp(qual, "external") == 0) {
+                       /*
+                        * Entries marked external are handled
+                        * by other means, e.g. EGP,
+                        * and are placed in our tables only
+                        * to prevent overriding them
+                        * with something else.
+                        */
+                       rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
+                       continue;
+               }
+               /* assume no duplicate entries */
+               externalinterfaces++;
+               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);
+               }
+               ifp->int_addr = *((struct sockaddr *)&gate);
+               ifp->int_metric = metric;
+               ifp->int_next = ifnet;
+               ifnet = ifp;
+               addrouteforif(ifp);
+       }
+       fclose(fp);
+}
+
+getnetorhostname(type, name, sin)
+       char *type, *name;
+       struct sockaddr_in *sin;
+{
+
+       if (strcmp(type, "net") == 0) {
+               struct netent *np = getnetbyname(name);
+               int n;
+
+               if (np == 0)
+                       n = inet_network(name);
+               else {
+                       if (np->n_addrtype != AF_INET)
+                               return (0);
+                       n = np->n_net;
+                       /*
+                        * getnetbyname returns right-adjusted value.
+                        */
+                       if (n < 128)
+                               n <<= IN_CLASSA_NSHIFT;
+                       else if (n < 65536)
+                               n <<= IN_CLASSB_NSHIFT;
+                       else
+                               n <<= IN_CLASSC_NSHIFT;
+               }
+               sin->sin_family = AF_INET;
+               sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
+               return (1);
+       }
+       if (strcmp(type, "host") == 0) {
+               struct hostent *hp = gethostbyname(name);
+
+               if (hp == 0)
+                       sin->sin_addr.s_addr = inet_addr(name);
+               else {
+                       if (hp->h_addrtype != AF_INET)
+                               return (0);
+                       bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+               }
+               sin->sin_family = AF_INET;
+               return (1);
+       }
+       return (0);
+}
+
+gethostnameornumber(name, sin)
+       char *name;
+       struct sockaddr_in *sin;
+{
+       struct hostent *hp;
+
+       hp = gethostbyname(name);
+       if (hp) {
+               bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+               sin->sin_family = hp->h_addrtype;
+               return (1);
+       }
+       sin->sin_addr.s_addr = inet_addr(name);
+       sin->sin_family = AF_INET;
+       return (sin->sin_addr.s_addr != -1);
+}
diff --git a/usr/src/sbin/routed/table.h b/usr/src/sbin/routed/table.h
new file mode 100644 (file)
index 0000000..124e098
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)table.h     5.8 (Berkeley) 6/1/90
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Routing table structure; differs a bit from kernel tables.
+ *
+ * Note: the union below must agree in the first 4 members
+ * so the ioctl's will work.
+ */
+struct rthash {
+       struct  rt_entry *rt_forw;
+       struct  rt_entry *rt_back;
+};
+#ifdef RTM_ADD
+#define rtentry ortentry
+#endif
+
+struct rt_entry {
+       struct  rt_entry *rt_forw;
+       struct  rt_entry *rt_back;
+       union {
+               struct  rtentry rtu_rt;
+               struct {
+                       u_long  rtu_hash;
+                       struct  sockaddr rtu_dst;
+                       struct  sockaddr rtu_router;
+                       short   rtu_flags;
+                       short   rtu_state;
+                       int     rtu_timer;
+                       int     rtu_metric;
+                       int     rtu_ifmetric;
+                       struct  interface *rtu_ifp;
+               } rtu_entry;
+       } rt_rtu;
+};
+
+#define        rt_rt           rt_rtu.rtu_rt                   /* pass to ioctl */
+#define        rt_hash         rt_rtu.rtu_entry.rtu_hash       /* for net or host */
+#define        rt_dst          rt_rtu.rtu_entry.rtu_dst        /* match value */
+#define        rt_router       rt_rtu.rtu_entry.rtu_router     /* who to forward to */
+#define        rt_flags        rt_rtu.rtu_entry.rtu_flags      /* kernel flags */
+#define        rt_timer        rt_rtu.rtu_entry.rtu_timer      /* for invalidation */
+#define        rt_state        rt_rtu.rtu_entry.rtu_state      /* see below */
+#define        rt_metric       rt_rtu.rtu_entry.rtu_metric     /* cost of route */
+#define        rt_ifmetric     rt_rtu.rtu_entry.rtu_ifmetric   /* cost of route if */
+#define        rt_ifp          rt_rtu.rtu_entry.rtu_ifp        /* interface to take */
+
+#define        ROUTEHASHSIZ    32              /* must be a power of 2 */
+#define        ROUTEHASHMASK   (ROUTEHASHSIZ - 1)
+
+/*
+ * "State" of routing table entry.
+ */
+#define        RTS_CHANGED     0x1             /* route has been altered recently */
+#define        RTS_EXTERNAL    0x2             /* extern info, not installed or sent */
+#define        RTS_INTERNAL    0x4             /* internal route, not installed */
+#define        RTS_PASSIVE     IFF_PASSIVE     /* don't time out route */
+#define        RTS_INTERFACE   IFF_INTERFACE   /* route is for network interface */
+#define        RTS_REMOTE      IFF_REMOTE      /* route is for ``remote'' entity */
+#define        RTS_SUBNET      IFF_SUBNET      /* route is for network subnet */
+
+/*
+ * Flags are same as kernel, with this addition for af_rtflags:
+ */
+#define        RTF_SUBNET      0x8000          /* pseudo: route to subnet */
+
+struct rthash nethash[ROUTEHASHSIZ];
+struct rthash hosthash[ROUTEHASHSIZ];
+struct rt_entry *rtlookup();
+struct rt_entry *rtfind();
diff --git a/usr/src/sbin/routed/timer.c b/usr/src/sbin/routed/timer.c
new file mode 100644 (file)
index 0000000..fd0851d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)timer.c    5.10 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+int    faketime;
+
+/*
+ * Timer routine.  Performs routing information supply
+ * duties and manages timers on routing table entries.
+ * Management of the RTS_CHANGED bit assumes that we broadcast
+ * each time called.
+ */
+void
+timer()
+{
+       register struct rthash *rh;
+       register struct rt_entry *rt;
+       struct rthash *base = hosthash;
+       int doinghost = 1, timetobroadcast;
+       extern int externalinterfaces;
+
+       (void) gettimeofday(&now, (struct timezone *)NULL);
+       faketime += TIMER_RATE;
+       if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
+               ifinit();
+       timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
+again:
+       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 any interface if we're
+                        * not acting as supplier.
+                        */
+                       if (!(rt->rt_state & RTS_PASSIVE) &&
+                           (supplier || !(rt->rt_state & RTS_INTERFACE)))
+                               rt->rt_timer += TIMER_RATE;
+                       if (rt->rt_timer >= GARBAGE_TIME) {
+                               rt = rt->rt_back;
+                               rtdelete(rt->rt_forw);
+                               continue;
+                       }
+                       if (rt->rt_timer >= EXPIRE_TIME &&
+                           rt->rt_metric < HOPCNT_INFINITY)
+                               rtchange(rt, &rt->rt_router, HOPCNT_INFINITY);
+                       rt->rt_state &= ~RTS_CHANGED;
+               }
+       }
+       if (doinghost) {
+               doinghost = 0;
+               base = nethash;
+               goto again;
+       }
+       if (timetobroadcast) {
+               toall(supply, 0, (struct interface *)NULL);
+               lastbcast = now;
+               lastfullupdate = now;
+               needupdate = 0;         /* cancel any pending dynamic update */
+               nextbcast.tv_sec = 0;
+       }
+}
+
+/*
+ * On hangup, let everyone know we're going away.
+ */
+hup()
+{
+       register struct rthash *rh;
+       register struct rt_entry *rt;
+       struct rthash *base = hosthash;
+       int doinghost = 1;
+
+       if (supplier) {
+again:
+               for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+                       rt = rh->rt_forw;
+                       for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
+                               rt->rt_metric = HOPCNT_INFINITY;
+               }
+               if (doinghost) {
+                       doinghost = 0;
+                       base = nethash;
+                       goto again;
+               }
+               toall(supply, 0, (struct interface *)NULL);
+       }
+       exit(1);
+}
diff --git a/usr/src/sbin/routed/trace.c b/usr/src/sbin/routed/trace.c
new file mode 100644 (file)
index 0000000..6e0b478
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)trace.c    5.11 (Berkeley) 2/28/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#define        RIPCMDS
+#include "defs.h"
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+#define        NRECORDS        50              /* size of circular trace buffer */
+#ifdef DEBUG
+FILE   *ftrace = stdout;
+int    traceactions = 0;
+#endif
+static struct timeval lastlog;
+static char *savetracename;
+
+traceinit(ifp)
+       register struct interface *ifp;
+{
+       static int iftraceinit();
+
+       if (iftraceinit(ifp, &ifp->int_input) &&
+           iftraceinit(ifp, &ifp->int_output))
+               return;
+       tracehistory = 0;
+       fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
+}
+
+static
+iftraceinit(ifp, ifd)
+       struct interface *ifp;
+       register struct ifdebug *ifd;
+{
+       register struct iftrace *t;
+
+       ifd->ifd_records =
+         (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
+       if (ifd->ifd_records == 0)
+               return (0);
+       ifd->ifd_front = ifd->ifd_records;
+       ifd->ifd_count = 0;
+       for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
+               t->ift_size = 0;
+               t->ift_packet = 0;
+       }
+       ifd->ifd_if = ifp;
+       return (1);
+}
+
+traceon(file)
+       char *file;
+{
+       struct stat stbuf;
+
+       if (ftrace != NULL)
+               return;
+       if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
+               return;
+       savetracename = file;
+       (void) gettimeofday(&now, (struct timezone *)NULL);
+       ftrace = fopen(file, "a");
+       if (ftrace == NULL)
+               return;
+       dup2(fileno(ftrace), 1);
+       dup2(fileno(ftrace), 2);
+       traceactions = 1;
+       fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
+}
+
+traceoff()
+{
+       if (!traceactions)
+               return;
+       if (ftrace != NULL) {
+               int fd = open(_PATH_DEVNULL, O_RDWR);
+
+               fprintf(ftrace, "Tracing disabled %s\n",
+                   ctime((time_t *)&now.tv_sec));
+               fflush(ftrace);
+               (void) dup2(fd, 1);
+               (void) dup2(fd, 2);
+               (void) close(fd);
+               fclose(ftrace);
+               ftrace = NULL;
+       }
+       traceactions = 0;
+       tracehistory = 0;
+       tracepackets = 0;
+       tracecontents = 0;
+}
+
+void
+sigtrace(s)
+       int s;
+{
+
+       if (s == SIGUSR2)
+               traceoff();
+       else if (ftrace == NULL && savetracename)
+               traceon(savetracename);
+       else
+               bumploglevel();
+}
+
+/*
+ * Move to next higher level of tracing when -t option processed or
+ * SIGUSR1 is received.  Successive levels are:
+ *     traceactions
+ *     traceactions + tracepackets
+ *     traceactions + tracehistory (packets and contents after change)
+ *     traceactions + tracepackets + tracecontents
+ */
+bumploglevel()
+{
+
+       (void) gettimeofday(&now, (struct timezone *)NULL);
+       if (traceactions == 0) {
+               traceactions++;
+               if (ftrace)
+                       fprintf(ftrace, "Tracing actions started %s\n",
+                           ctime((time_t *)&now.tv_sec));
+       } else if (tracepackets == 0) {
+               tracepackets++;
+               tracehistory = 0;
+               tracecontents = 0;
+               if (ftrace)
+                       fprintf(ftrace, "Tracing packets started %s\n",
+                           ctime((time_t *)&now.tv_sec));
+       } else if (tracehistory == 0) {
+               tracehistory++;
+               if (ftrace)
+                       fprintf(ftrace, "Tracing history started %s\n",
+                           ctime((time_t *)&now.tv_sec));
+       } else {
+               tracepackets++;
+               tracecontents++;
+               tracehistory = 0;
+               if (ftrace)
+                       fprintf(ftrace, "Tracing packet contents started %s\n",
+                           ctime((time_t *)&now.tv_sec));
+       }
+       if (ftrace)
+               fflush(ftrace);
+}
+
+trace(ifd, who, p, len, m)
+       register struct ifdebug *ifd;
+       struct sockaddr *who;
+       char *p;
+       int len, m;
+{
+       register struct iftrace *t;
+
+       if (ifd->ifd_records == 0)
+               return;
+       t = ifd->ifd_front++;
+       if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
+               ifd->ifd_front = ifd->ifd_records;
+       if (ifd->ifd_count < NRECORDS)
+               ifd->ifd_count++;
+       if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
+               free(t->ift_packet);
+               t->ift_packet = 0;
+       }
+       t->ift_stamp = now;
+       t->ift_who = *who;
+       if (len > 0 && t->ift_packet == 0) {
+               t->ift_packet = malloc(len);
+               if (t->ift_packet == 0)
+                       len = 0;
+       }
+       if (len > 0)
+               bcopy(p, t->ift_packet, len);
+       t->ift_size = len;
+       t->ift_metric = m;
+}
+
+traceaction(fd, action, rt)
+       FILE *fd;
+       char *action;
+       struct rt_entry *rt;
+{
+       struct sockaddr_in *dst, *gate;
+       static struct bits {
+               int     t_bits;
+               char    *t_name;
+       } flagbits[] = {
+               { RTF_UP,       "UP" },
+               { RTF_GATEWAY,  "GATEWAY" },
+               { RTF_HOST,     "HOST" },
+               { 0 }
+       }, statebits[] = {
+               { RTS_PASSIVE,  "PASSIVE" },
+               { RTS_REMOTE,   "REMOTE" },
+               { RTS_INTERFACE,"INTERFACE" },
+               { RTS_CHANGED,  "CHANGED" },
+               { RTS_INTERNAL, "INTERNAL" },
+               { RTS_EXTERNAL, "EXTERNAL" },
+               { RTS_SUBNET,   "SUBNET" },
+               { 0 }
+       };
+       register struct bits *p;
+       register int first;
+       char *cp;
+       struct interface *ifp;
+
+       if (fd == NULL)
+               return;
+       if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+               fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
+               lastlog = now;
+       }
+       fprintf(fd, "%s ", action);
+       dst = (struct sockaddr_in *)&rt->rt_dst;
+       gate = (struct sockaddr_in *)&rt->rt_router;
+       fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
+       fprintf(fd, "router %s, metric %d, flags",
+            inet_ntoa(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)
+                       continue;
+               fprintf(fd, cp, p->t_name);
+               if (first) {
+                       cp = "|%s";
+                       first = 0;
+               }
+       }
+       fprintf(fd, " state");
+       cp = " %s";
+       for (first = 1, p = statebits; p->t_bits > 0; p++) {
+               if ((rt->rt_state & p->t_bits) == 0)
+                       continue;
+               fprintf(fd, cp, p->t_name);
+               if (first) {
+                       cp = "|%s";
+                       first = 0;
+               }
+       }
+       fprintf(fd, " timer %d\n", rt->rt_timer);
+       if (tracehistory && !tracepackets &&
+           (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
+               dumpif(fd, rt->rt_ifp);
+       fflush(fd);
+       if (ferror(fd))
+               traceoff();
+}
+
+tracenewmetric(fd, rt, newmetric)
+       FILE *fd;
+       struct rt_entry *rt;
+       int newmetric;
+{
+       struct sockaddr_in *dst, *gate;
+
+       if (fd == NULL)
+               return;
+       if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+               fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
+               lastlog = now;
+       }
+       dst = (struct sockaddr_in *)&rt->rt_dst;
+       gate = (struct sockaddr_in *)&rt->rt_router;
+       fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
+       fprintf(fd, "router %s, from %d to %d\n",
+            inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
+       fflush(fd);
+       if (ferror(fd))
+               traceoff();
+}
+
+dumpif(fd, ifp)
+       FILE *fd;
+       register struct interface *ifp;
+{
+       if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
+               fprintf(fd, "*** Packet history for interface %s ***\n",
+                       ifp->int_name);
+#ifdef notneeded
+               dumptrace(fd, "to", &ifp->int_output);
+#endif
+               dumptrace(fd, "from", &ifp->int_input);
+               fprintf(fd, "*** end packet history ***\n");
+       }
+}
+
+dumptrace(fd, dir, ifd)
+       FILE *fd;
+       char *dir;
+       register struct ifdebug *ifd;
+{
+       register struct iftrace *t;
+       char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+
+       if (ifd->ifd_front == ifd->ifd_records &&
+           ifd->ifd_front->ift_size == 0) {
+               fprintf(fd, "%s: no packets.\n", cp);
+               fflush(fd);
+               return;
+       }
+       fprintf(fd, "%s trace:\n", cp);
+       t = ifd->ifd_front - ifd->ifd_count;
+       if (t < ifd->ifd_records)
+               t += NRECORDS;
+       for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
+               if (t >= ifd->ifd_records + NRECORDS)
+                       t = ifd->ifd_records;
+               if (t->ift_size == 0)
+                       continue;
+               dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
+                   &t->ift_stamp);
+       }
+}
+
+dumppacket(fd, dir, who, cp, size, stamp)
+       FILE *fd;
+       struct sockaddr_in *who;                /* should be sockaddr */
+       char *dir, *cp;
+       register int size;
+       struct timeval *stamp;
+{
+       register struct rip *msg = (struct rip *)cp;
+       register struct netinfo *n;
+
+       if (fd == NULL)
+               return;
+       if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
+               fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
+                   dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
+                   ctime((time_t *)&stamp->tv_sec));
+       else {
+               fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd,
+                   dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
+               fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet,
+                   ctime((time_t *)&stamp->tv_sec));
+               fflush(fd);
+               return;
+       }
+       if (tracepackets && tracecontents == 0) {
+               fflush(fd);
+               return;
+       }
+       switch (msg->rip_cmd) {
+
+       case RIPCMD_REQUEST:
+       case RIPCMD_RESPONSE:
+               size -= 4 * sizeof (char);
+               n = msg->rip_nets;
+               for (; size > 0; n++, size -= sizeof (struct netinfo)) {
+                       if (size < sizeof (struct netinfo)) {
+                               fprintf(fd, "(truncated record, len %d)\n",
+                                   size);
+                               break;
+                       }
+                       if (sizeof(n->rip_dst.sa_family) > 1)
+                           n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+
+                       switch ((int)n->rip_dst.sa_family) {
+
+                       case AF_INET:
+                               fprintf(fd, "\tdst %s metric %d\n",
+#define        satosin(sa)     ((struct sockaddr_in *)&sa)
+                                    inet_ntoa(satosin(n->rip_dst)->sin_addr),
+                                    ntohl(n->rip_metric));
+                               break;
+
+                       default:
+                               fprintf(fd, "\taf %d? metric %d\n",
+                                    n->rip_dst.sa_family,
+                                    ntohl(n->rip_metric));
+                               break;
+                       }
+               }
+               break;
+
+       case RIPCMD_TRACEON:
+               fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
+               break;
+
+       case RIPCMD_TRACEOFF:
+               break;
+       }
+       fflush(fd);
+       if (ferror(fd))
+               traceoff();
+}
diff --git a/usr/src/sbin/routed/trace.h b/usr/src/sbin/routed/trace.h
new file mode 100644 (file)
index 0000000..741de72
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)trace.h     5.8 (Berkeley) 6/1/90
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Trace record format.
+ */
+struct iftrace {
+       struct  timeval ift_stamp;      /* time stamp */
+       struct  sockaddr ift_who;       /* from/to */
+       char    *ift_packet;            /* pointer to packet */
+       short   ift_size;               /* size of packet */
+       short   ift_metric;             /* metric on associated metric */
+};
+
+/*
+ * Per interface packet tracing buffers.  An incoming and
+ * outgoing circular buffer of packets is maintained, per
+ * interface, for debugging.  Buffers are dumped whenever
+ * an interface is marked down.
+ */
+struct ifdebug {
+       struct  iftrace *ifd_records;   /* array of trace records */
+       struct  iftrace *ifd_front;     /* next empty trace record */
+       int     ifd_count;              /* number of unprinted records */
+       struct  interface *ifd_if;      /* for locating stuff */
+};
+
+/*
+ * Packet tracing stuff.
+ */
+int    tracepackets;           /* watch packets as they go by */
+int    tracecontents;          /* watch packet contents as they go by */
+int    traceactions;           /* on/off */
+int    tracehistory;           /* on/off */
+FILE   *ftrace;                /* output trace file */
+
+#define        TRACE_ACTION(action, route) { \
+         if (traceactions) \
+               traceaction(ftrace, action, route); \
+       }
+#define        TRACE_NEWMETRIC(route, newmetric) { \
+         if (traceactions) \
+               tracenewmetric(ftrace, route, newmetric); \
+       }
+#define        TRACE_INPUT(ifp, src, pack, size) { \
+         if (tracehistory) { \
+               ifp = if_iflookup(src); \
+               if (ifp) \
+                       trace(&ifp->int_input, src, pack, size, \
+                               ntohl(ifp->int_metric)); \
+         } \
+         if (tracepackets) \
+               dumppacket(ftrace, "from", src, pack, size, &now); \
+       }
+#define        TRACE_OUTPUT(ifp, dst, size) { \
+         if (tracehistory && ifp) \
+               trace(&ifp->int_output, dst, packet, size, ifp->int_metric); \
+         if (tracepackets) \
+               dumppacket(ftrace, "to", dst, packet, size, &now); \
+       }