aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-07-01 08:00:00 +0000
committersvn2git <svn2git@FreeBSD.org>1994-07-01 08:00:00 +0000
commit5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch)
treee779b5a6edddbb949b7990751b12d6f25304ba86 /usr.sbin
parenta16f65c7d117419bd266c28a1901ef129a337569 (diff)
This commit was manufactured to restore the state of the 1.1.5.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile11
-rw-r--r--usr.sbin/XNSrouted/Makefile10
-rw-r--r--usr.sbin/XNSrouted/XNSrouted.8186
-rw-r--r--usr.sbin/XNSrouted/af.c246
-rw-r--r--usr.sbin/XNSrouted/af.h64
-rw-r--r--usr.sbin/XNSrouted/defs.h88
-rw-r--r--usr.sbin/XNSrouted/if.c147
-rw-r--r--usr.sbin/XNSrouted/input.c189
-rw-r--r--usr.sbin/XNSrouted/interface.h90
-rw-r--r--usr.sbin/XNSrouted/main.c245
-rw-r--r--usr.sbin/XNSrouted/output.c147
-rw-r--r--usr.sbin/XNSrouted/protocol.h85
-rw-r--r--usr.sbin/XNSrouted/startup.c218
-rw-r--r--usr.sbin/XNSrouted/table.h99
-rw-r--r--usr.sbin/XNSrouted/tables.c265
-rw-r--r--usr.sbin/XNSrouted/timer.c139
-rw-r--r--usr.sbin/XNSrouted/tools/query.c232
-rw-r--r--usr.sbin/XNSrouted/trace.c313
-rw-r--r--usr.sbin/XNSrouted/trace.h96
-rw-r--r--usr.sbin/ac/Makefile18
-rw-r--r--usr.sbin/ac/ac.8165
-rw-r--r--usr.sbin/ac/ac.c557
-rw-r--r--usr.sbin/config/config.86
-rw-r--r--usr.sbin/config/main.c37
-rw-r--r--usr.sbin/config/mkglue.c6
-rw-r--r--usr.sbin/config/mkmakefile.c4
-rw-r--r--usr.sbin/cron/cron.82
-rw-r--r--usr.sbin/diskless_cfg/diskless.h2
-rw-r--r--usr.sbin/diskless_cfg/diskless_cfg.c86
-rw-r--r--usr.sbin/fdcontrol/Makefile4
-rw-r--r--usr.sbin/fdcontrol/fdcontrol.877
-rw-r--r--usr.sbin/fdcontrol/fdcontrol.c100
-rw-r--r--usr.sbin/fdformat/Makefile25
-rw-r--r--usr.sbin/fdformat/fdformat.126
-rw-r--r--usr.sbin/fdformat/fdformat.c66
-rw-r--r--usr.sbin/flcopy/Makefile7
-rw-r--r--usr.sbin/flcopy/flcopy.883
-rw-r--r--usr.sbin/flcopy/flcopy.c201
-rw-r--r--usr.sbin/kbdcontrol/Makefile4
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.177
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.c566
-rw-r--r--usr.sbin/kbdcontrol/lex.h55
-rw-r--r--usr.sbin/kbdcontrol/lex.l114
-rw-r--r--usr.sbin/kbdcontrol/path.h4
-rw-r--r--usr.sbin/kvm_mkdb/nlist.c52
-rw-r--r--usr.sbin/lpr/common_source/common.c2
-rw-r--r--usr.sbin/lpr/lpr/lpr.c2
-rw-r--r--usr.sbin/lptcontrol/Makefile4
-rw-r--r--usr.sbin/lptcontrol/lptcontrol.167
-rw-r--r--usr.sbin/lptcontrol/lptcontrol.c93
-rw-r--r--usr.sbin/mrouted/LICENSE48
-rw-r--r--usr.sbin/mrouted/Makefile44
-rw-r--r--usr.sbin/mrouted/config.c528
-rw-r--r--usr.sbin/mrouted/defs.h129
-rw-r--r--usr.sbin/mrouted/dvmrp.h141
-rw-r--r--usr.sbin/mrouted/igmp.c217
-rw-r--r--usr.sbin/mrouted/inet.c187
-rw-r--r--usr.sbin/mrouted/kern.c213
-rw-r--r--usr.sbin/mrouted/main.c322
-rw-r--r--usr.sbin/mrouted/mapper.c932
-rw-r--r--usr.sbin/mrouted/mrinfo.c469
-rw-r--r--usr.sbin/mrouted/mrouted.8242
-rw-r--r--usr.sbin/mrouted/mrouted.conf15
-rw-r--r--usr.sbin/mrouted/route.c900
-rw-r--r--usr.sbin/mrouted/route.h50
-rw-r--r--usr.sbin/mrouted/vif.c782
-rw-r--r--usr.sbin/mrouted/vif.h47
-rw-r--r--usr.sbin/mtree/verify.c5
-rw-r--r--usr.sbin/named/named.restart2
-rw-r--r--usr.sbin/pwd_mkdb/Makefile3
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.814
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c126
-rw-r--r--usr.sbin/routed/Makefile22
-rw-r--r--usr.sbin/routed/af.c171
-rw-r--r--usr.sbin/routed/af.h65
-rw-r--r--usr.sbin/routed/defs.h93
-rw-r--r--usr.sbin/routed/if.c148
-rw-r--r--usr.sbin/routed/inet.c214
-rw-r--r--usr.sbin/routed/input.c362
-rw-r--r--usr.sbin/routed/interface.h91
-rw-r--r--usr.sbin/routed/main.c343
-rw-r--r--usr.sbin/routed/output.c172
-rw-r--r--usr.sbin/routed/pathnames.h (renamed from usr.sbin/flcopy/pathnames.h)10
-rw-r--r--usr.sbin/routed/query/Makefile7
-rw-r--r--usr.sbin/routed/query/query.c289
-rw-r--r--usr.sbin/routed/routed.8360
-rw-r--r--usr.sbin/routed/startup.c486
-rw-r--r--usr.sbin/routed/table.h106
-rw-r--r--usr.sbin/routed/tables.c410
-rw-r--r--usr.sbin/routed/timer.c127
-rw-r--r--usr.sbin/routed/trace.c426
-rw-r--r--usr.sbin/routed/trace.h96
-rw-r--r--usr.sbin/routed/trace/Makefile7
-rw-r--r--usr.sbin/routed/trace/trace.c125
-rw-r--r--usr.sbin/sa/Makefile8
-rw-r--r--usr.sbin/sa/extern.h100
-rw-r--r--usr.sbin/sa/main.c542
-rw-r--r--usr.sbin/sa/pathnames.h35
-rw-r--r--usr.sbin/sa/pdb.c418
-rw-r--r--usr.sbin/sa/sa.8246
-rw-r--r--usr.sbin/sa/usrdb.c282
-rw-r--r--usr.sbin/sendmail/cf/README2
-rw-r--r--usr.sbin/sendmail/contrib/expn.pl2
-rw-r--r--usr.sbin/sendmail/src/conf.c2
-rw-r--r--usr.sbin/sliplogin/slip.hosts2
-rw-r--r--usr.sbin/sliplogin/sliplogin.c7
-rw-r--r--usr.sbin/slstat/Makefile11
-rw-r--r--usr.sbin/slstat/slstat.8141
-rw-r--r--usr.sbin/slstat/slstat.c287
-rw-r--r--usr.sbin/vidcontrol/Makefile4
-rw-r--r--usr.sbin/vidcontrol/decode.c74
-rw-r--r--usr.sbin/vidcontrol/path.h4
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.1112
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.c472
-rw-r--r--usr.sbin/xten/Install.notes222
-rw-r--r--usr.sbin/xten/Makefile10
-rw-r--r--usr.sbin/xten/xten.1110
-rw-r--r--usr.sbin/xten/xten.c164
118 files changed, 17702 insertions, 483 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index c625fea95cad..e189ba5ccfaa 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -1,10 +1,11 @@
# @(#)Makefile 5.6.1.2 (Berkeley) 5/8/91
-SUBDIR= accton arp chown chroot config cron dbsym dev_mkdb diskpart \
- edquota fdformat flcopy ftinfo gettable htable inetd iostat kgmon \
- kvm_mkdb lpr mtree named portmap pppstats pwd_mkdb quotaon repquota \
- rmt rwhod sendmail sliplogin spkrtest swapinfo syslogd timed \
- traceroute trpt trsp vipw yp
+SUBDIR= XNSrouted ac accton arp chown chroot config cron dbsym dev_mkdb \
+ diskpart edquota fdcontrol fdformat ftinfo gettable htable \
+ inetd iostat kbdcontrol kgmon kvm_mkdb lpr lptcontrol mrouted \
+ mtree named portmap pppstats pwd_mkdb quotaon repquota rmt \
+ routed rwhod sa sendmail sliplogin slstat spkrtest swapinfo \
+ syslogd timed traceroute trpt trsp vidcontrol vipw xten yp
.if make(clean) || make(cleandir)
SUBDIR+=bad144
diff --git a/usr.sbin/XNSrouted/Makefile b/usr.sbin/XNSrouted/Makefile
new file mode 100644
index 000000000000..9f6583f8ee56
--- /dev/null
+++ b/usr.sbin/XNSrouted/Makefile
@@ -0,0 +1,10 @@
+# From: @(#)Makefile 5.14 (Berkeley) 2/26/91
+# $Id: Makefile,v 1.1 1993/09/07 14:13:06 rgrimes Exp $
+
+PROG= XNSrouted
+MAN8= XNSrouted.8
+SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c trace.c
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/XNSrouted/XNSrouted.8 b/usr.sbin/XNSrouted/XNSrouted.8
new file mode 100644
index 000000000000..144cb1d40453
--- /dev/null
+++ b/usr.sbin/XNSrouted/XNSrouted.8
@@ -0,0 +1,186 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)XNSrouted.8 6.4 (Berkeley) 3/16/91
+.\"
+.Dd March 16, 1991
+.Dt XNSROUTED 8
+.Os BSD 4.3
+.Sh NAME
+.Nm XNSrouted
+.Nd NS Routing Information Protocol daemon
+.Sh SYNOPSIS
+.Nm XNSrouted
+.Op Fl q
+.Op Fl s
+.Op Fl t
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm XNSrouted
+is invoked at boot time to manage the Xerox NS routing tables.
+The NS routing daemon uses the Xerox NS Routing
+Information Protocol in maintaining up to date kernel routing
+table entries.
+.Pp
+Available options:
+.Bl -tag -width logfile
+.It Fl q
+Do not supply routing information (opposite of
+.Fl s
+option below).
+.It Fl s
+Forces
+.Nm XNSrouted
+to supply routing information whether it is acting as an internetwork
+router or not.
+.It Fl t
+All packets sent or received are
+printed on the standard output. In addition,
+.Nm XNSrouted
+will not divorce itself from the controlling terminal
+so that interrupts from the keyboard will kill the process.
+.It Ar logfile
+Name of file in which
+.Nm XNSrouted Ns 's
+actions should be logged. This log contains information
+about any changes to the routing tables and a history of
+recent messages sent and received which are related to
+the changed route.
+.El
+.Pp
+In normal operation
+.Nm XNSrouted
+listens
+for routing information packets. If the host is connected to
+multiple NS networks, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm XNSrouted
+is started, it uses the
+.Dv SIOCGIFCONF
+.Xr ioctl 2
+to find those
+directly connected interfaces configured into the
+system and marked
+.Dq up
+(the software loopback interface
+is ignored). If multiple interfaces
+are present, it is assumed the host will forward packets
+between networks.
+.Nm XNSrouted
+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 XNSrouted
+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
+.Dq hop count
+metric (a count of 16, or greater, is
+considered
+.Dq infinite ) .
+The metric associated with each
+route returned provides a metric
+.Em relative to the sender .
+.Pp
+.Em Response
+packets received by
+.Nm XNSrouted
+are used to update the routing tables if one of the following
+conditions is satisfied:
+.Bl -bullet
+.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 XNSrouted
+records the change in its internal tables and generates a
+.Em response
+packet to all directly connected hosts and networks.
+.Xr Routed 8
+waits a short period
+of time (no more than 30 seconds) before modifying the kernel's
+routing tables to allow possible unstable situations to settle.
+.Pp
+In addition to processing incoming packets,
+.Nm XNSrouted
+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
+to other routers.
+.Pp
+Hosts acting as internetwork routers gratuitously supply their
+routing tables every 30 seconds to all directly connected hosts
+and networks.
+.Sh SEE ALSO
+.Xr idp 4
+.Rs
+.%T "Internet Transport Protocols"
+.%R "XSIS 028112"
+.%Q "Xerox System Integration Standard"
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/XNSrouted/af.c b/usr.sbin/XNSrouted/af.c
new file mode 100644
index 000000000000..d131e8773992
--- /dev/null
+++ b/usr.sbin/XNSrouted/af.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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/26/91";
+#endif /* not lint */
+
+#include "defs.h"
+
+/*
+ * Address family support routines
+ */
+int null_hash(), null_netmatch(), null_output(),
+ null_portmatch(), null_portcheck(),
+ null_checkhost(), null_ishost(), null_canon();
+int xnnet_hash(), xnnet_netmatch(), xnnet_output(),
+ xnnet_portmatch(),
+ xnnet_checkhost(), xnnet_ishost(), xnnet_canon();
+#define NIL \
+ { null_hash, null_netmatch, null_output, \
+ null_portmatch, null_portcheck, null_checkhost, \
+ null_ishost, null_canon }
+#define XNSNET \
+ { xnnet_hash, xnnet_netmatch, xnnet_output, \
+ xnnet_portmatch, xnnet_portmatch, xnnet_checkhost, \
+ xnnet_ishost, xnnet_canon }
+
+struct afswitch afswitch[AF_MAX] =
+ { NIL, NIL, NIL, NIL, NIL, NIL, XNSNET, NIL, NIL, NIL, NIL };
+
+struct sockaddr_ns xnnet_default = { sizeof(struct sockaddr_ns), AF_NS };
+
+union ns_net ns_anynet;
+union ns_net ns_zeronet;
+
+xnnet_hash(sns, hp)
+ register struct sockaddr_ns *sns;
+ struct afhash *hp;
+{
+ register long hash = 0;
+ register u_short *s = sns->sns_addr.x_host.s_host;
+ union ns_net_u net;
+
+ net.net_e = sns->sns_addr.x_net;
+ hp->afh_nethash = net.long_e;
+ hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
+ hp->afh_hosthash = hash;
+}
+
+xnnet_netmatch(sxn1, sxn2)
+ struct sockaddr_ns *sxn1, *sxn2;
+{
+ return (ns_neteq(sxn1->sns_addr, sxn2->sns_addr));
+}
+
+/*
+ * Verify the message is from the right port.
+ */
+xnnet_portmatch(sns)
+ register struct sockaddr_ns *sns;
+{
+
+ return (ntohs(sns->sns_addr.x_port) == IDPPORT_RIF );
+}
+
+
+/*
+ * xns output routine.
+ */
+#ifdef DEBUG
+int do_output = 0;
+#endif
+xnnet_output(flags, sns, size)
+ int flags;
+ struct sockaddr_ns *sns;
+ int size;
+{
+ struct sockaddr_ns dst;
+
+ dst = *sns;
+ sns = &dst;
+ if (sns->sns_addr.x_port == 0)
+ sns->sns_addr.x_port = htons(IDPPORT_RIF);
+#ifdef DEBUG
+ if(do_output || ntohs(msg->rip_cmd) == RIPCMD_REQUEST)
+#endif
+ /*
+ * Kludge to allow us to get routes out to machines that
+ * don't know their addresses yet; send to that address on
+ * ALL connected nets
+ */
+ if (ns_neteqnn(sns->sns_addr.x_net, ns_zeronet)) {
+ extern struct interface *ifnet;
+ register struct interface *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ sns->sns_addr.x_net =
+ satons_addr(ifp->int_addr).x_net;
+ (void) sendto(s, msg, size, flags,
+ (struct sockaddr *)sns, sizeof (*sns));
+ }
+ return;
+ }
+
+ (void) sendto(s, msg, size, flags,
+ (struct sockaddr *)sns, sizeof (*sns));
+}
+
+/*
+ * Return 1 if we want this route.
+ * We use this to disallow route net G entries for one for multiple
+ * point to point links.
+ */
+xnnet_checkhost(sns)
+ struct sockaddr_ns *sns;
+{
+ register struct interface *ifp = if_ifwithnet(sns);
+ /*
+ * We want this route if there is no more than one
+ * point to point interface with this network.
+ */
+ if (ifp == 0 || (ifp->int_flags & IFF_POINTOPOINT)==0) return (1);
+ return (ifp->int_sq.n == ifp->int_sq.p);
+}
+
+/*
+ * Return 1 if the address is
+ * for a host, 0 for a network.
+ */
+xnnet_ishost(sns)
+struct sockaddr_ns *sns;
+{
+ register u_short *s = sns->sns_addr.x_host.s_host;
+
+ if ((s[0]==0xffff) && (s[1]==0xffff) && (s[2]==0xffff))
+ return (0);
+ else
+ return (1);
+}
+
+xnnet_canon(sns)
+ struct sockaddr_ns *sns;
+{
+
+ sns->sns_addr.x_port = 0;
+}
+
+/*ARGSUSED*/
+null_hash(addr, hp)
+ struct sockaddr *addr;
+ struct afhash *hp;
+{
+
+ hp->afh_nethash = hp->afh_hosthash = 0;
+}
+
+/*ARGSUSED*/
+null_netmatch(a1, a2)
+ struct sockaddr *a1, *a2;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_output(s, f, a1, n)
+ int s, f;
+ struct sockaddr *a1;
+ int n;
+{
+
+ ;
+}
+
+/*ARGSUSED*/
+null_portmatch(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_portcheck(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_ishost(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_checkhost(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_canon(a1)
+ struct sockaddr *a1;
+{
+
+ ;
+}
diff --git a/usr.sbin/XNSrouted/af.h b/usr.sbin/XNSrouted/af.h
new file mode 100644
index 000000000000..d2b27c531380
--- /dev/null
+++ b/usr.sbin/XNSrouted/af.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * @(#)af.h 5.1 (Berkeley) 6/4/85 (routed/af.h)
+ *
+ * @(#)af.h 5.2 (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 for host or net */
+ int (*af_ishost)(); /* tells if address is valid */
+ int (*af_canon)(); /* canonicalize address for compares */
+};
+
+/*
+ * 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[AF_MAX]; /* table proper */
diff --git a/usr.sbin/XNSrouted/defs.h b/usr.sbin/XNSrouted/defs.h
new file mode 100644
index 000000000000..5414d8c08ca3
--- /dev/null
+++ b/usr.sbin/XNSrouted/defs.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * @(#)defs.h 5.9 (Berkeley) 2/26/91
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/route.h>
+#include <netns/ns.h>
+#include <netns/idp.h>
+#if defined(vax) || defined(pdp11)
+#define xnnet(x) ((u_long) (x)->rip_dst[1] << 16 | (u_long) (x)->rip_dst[0] )
+#else
+#define xnnet(x) ((u_long) (x)->rip_dst[0] << 16 | (u_long) (x)->rip_dst[1] )
+#endif
+#define IDPPORT_RIF 1
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "protocol.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 (5*60)
+
+#define equal(a1, a2) \
+ (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
+#define min(a,b) ((a)>(b)?(b):(a))
+
+struct sockaddr_ns addr; /* Daemon's Address */
+int s; /* Socket to listen on */
+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 */
+int timeval; /* local idea of time */
+int noteremoterequests; /* squawk on requests from non-local nets */
+
+char packet[MAXPACKETSIZE+sizeof(struct idp)+1];
+struct rip *msg;
+
+char **argv0;
+
+int sndmsg();
+int supply();
+int cleanup();
diff --git a/usr.sbin/XNSrouted/if.c b/usr.sbin/XNSrouted/if.c
new file mode 100644
index 000000000000..0f597a66fac3
--- /dev/null
+++ b/usr.sbin/XNSrouted/if.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * static char sccsid[] = "@(#)if.c 5.1 (Berkeley) 6/4/85"; (routed/if.c)
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)if.c 5.2 (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 (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
+ maybe = ifp;
+ }
+ if (ifp == 0)
+ ifp = maybe;
+ return (ifp);
+}
diff --git a/usr.sbin/XNSrouted/input.c b/usr.sbin/XNSrouted/input.c
new file mode 100644
index 000000000000..7dc64fa5cc9c
--- /dev/null
+++ b/usr.sbin/XNSrouted/input.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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.9 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * XNS Routing Table Management Daemon
+ */
+#include "defs.h"
+
+struct sockaddr *
+xns_nettosa(net)
+union ns_net net;
+{
+ static struct sockaddr_ns sxn;
+ extern char ether_broadcast_addr[6];
+
+ bzero(&sxn, sizeof (struct sockaddr_ns));
+ sxn.sns_family = AF_NS;
+ sxn.sns_len = sizeof (sxn);
+ sxn.sns_addr.x_net = net;
+ sxn.sns_addr.x_host = *(union ns_host *)ether_broadcast_addr;
+ return( (struct sockaddr *)&sxn);
+
+}
+
+/*
+ * Process a newly received packet.
+ */
+rip_input(from, size)
+ struct sockaddr *from;
+ int size;
+{
+ struct rt_entry *rt;
+ struct netinfo *n;
+ struct interface *ifp;
+ int newsize;
+ struct afswitch *afp;
+
+
+ ifp = 0;
+ TRACE_INPUT(ifp, from, size);
+ if (from->sa_family >= AF_MAX)
+ return;
+ afp = &afswitch[from->sa_family];
+
+ size -= sizeof (u_short) /* command */;
+ n = msg->rip_nets;
+
+ switch (ntohs(msg->rip_cmd)) {
+
+ case RIPCMD_REQUEST:
+ newsize = 0;
+ while (size > 0) {
+ if (size < sizeof (struct netinfo))
+ break;
+ size -= sizeof (struct netinfo);
+
+ /*
+ * A single entry with rip_dst == DSTNETS_ALL and
+ * metric ``infinity'' means ``all routes''.
+ */
+ if (ns_neteqnn(n->rip_dst, ns_anynet) &&
+ ntohs(n->rip_metric) == HOPCNT_INFINITY &&
+ size == 0) {
+ ifp = if_ifwithnet(from);
+ supply(from, 0, ifp);
+ return;
+ }
+ /*
+ * request for specific nets
+ */
+ rt = rtlookup(xns_nettosa(n->rip_dst));
+ if (ftrace) {
+ fprintf(ftrace,
+ "specific request for %s",
+ xns_nettoa(n->rip_dst));
+ fprintf(ftrace,
+ " yields route %x\n",
+ rt);
+ }
+ n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY :
+ min(rt->rt_metric+1, HOPCNT_INFINITY));
+ n++;
+ newsize += sizeof (struct netinfo);
+ }
+ if (newsize > 0) {
+ msg->rip_cmd = htons(RIPCMD_RESPONSE);
+ newsize += sizeof (u_short);
+ /* should check for if with dstaddr(from) first */
+ (*afp->af_output)(0, from, newsize);
+ ifp = if_ifwithnet(from);
+ TRACE_OUTPUT(ifp, from, newsize);
+ if (ftrace) {
+ fprintf(ftrace,
+ "request arrived on interface %s\n",
+ ifp->int_name);
+ }
+ }
+ 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? */
+ if (ifp = if_ifwithaddr(from)) {
+ rt = rtfind(from);
+ if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0)
+ 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)) {
+ if(ftrace) fprintf(ftrace, "Got route\n");
+ rt->rt_timer = 0;
+ } else if (ifp = if_ifwithdstaddr(from)) {
+ if(ftrace) fprintf(ftrace, "Got partner\n");
+ addrouteforif(ifp);
+ }
+ for (; size > 0; size -= sizeof (struct netinfo), n++) {
+ struct sockaddr *sa;
+ if (size < sizeof (struct netinfo))
+ break;
+ if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY)
+ continue;
+ rt = rtfind(sa = xns_nettosa(n->rip_dst));
+ if (rt == 0) {
+ rtadd(sa, from, ntohs(n->rip_metric), 0);
+ continue;
+ }
+
+ /*
+ * Update if from gateway and different,
+ * from anywhere and shorter, or getting stale and equivalent.
+ */
+ if ((equal(from, &rt->rt_router) &&
+ ntohs(n->rip_metric) != rt->rt_metric ) ||
+ (unsigned) ntohs(n->rip_metric) < rt->rt_metric ||
+ (rt->rt_timer > (EXPIRE_TIME/2) &&
+ rt->rt_metric == ntohs(n->rip_metric))) {
+ rtchange(rt, from, ntohs(n->rip_metric));
+ rt->rt_timer = 0;
+ }
+ }
+ return;
+ }
+}
diff --git a/usr.sbin/XNSrouted/interface.h b/usr.sbin/XNSrouted/interface.h
new file mode 100644
index 000000000000..7cb416699a1b
--- /dev/null
+++ b/usr.sbin/XNSrouted/interface.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * @(#)interface.h 5.5 (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.
+ * We list only one address for each interface, the AF_XNS one.
+ */
+#define NIFADDR 3
+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 */
+ 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 */
+/*XNS Specific entry */
+ struct sameq {
+ struct sameq *n; /* q of other pt-to-pt links */
+ struct sameq *p; /* with same net # */
+ } int_sq;
+};
+
+/*
+ * 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_ROUTE 0x8 /* routing entry installed */
+#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
+
+#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.sbin/XNSrouted/main.c b/usr.sbin/XNSrouted/main.c
new file mode 100644
index 000000000000..f4ddf285839c
--- /dev/null
+++ b/usr.sbin/XNSrouted/main.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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
+char copyright[] =
+"@(#) Copyright (c) 1985 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 5.11 (Berkeley) 2/26/91";
+#endif /* not lint */
+
+/*
+ * XNS Routing Information Protocol Daemon
+ */
+#include "defs.h"
+#include <sys/time.h>
+
+#include <net/if.h>
+
+#include <errno.h>
+#include <nlist.h>
+#include <signal.h>
+#include <paths.h>
+
+int supplier = -1; /* process should supply updates */
+extern int gateway;
+
+struct rip *msg = (struct rip *) &packet[sizeof (struct idp)];
+void hup(), fkexit(), timer();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int cc;
+ struct sockaddr from;
+ u_char retry;
+
+ argv0 = argv;
+ argv++, argc--;
+ while (argc > 0 && **argv == '-') {
+ if (strcmp(*argv, "-s") == 0) {
+ supplier = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-q") == 0) {
+ supplier = 0;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-R") == 0) {
+ noteremoterequests++;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-t") == 0) {
+ tracepackets++;
+ argv++, argc--;
+ ftrace = stderr;
+ tracing = 1;
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ gateway = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-l") == 0) {
+ gateway = -1;
+ argv++, argc--;
+ continue;
+ }
+ fprintf(stderr,
+ "usage: xnsrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ]\n");
+ exit(1);
+ }
+
+
+#ifndef DEBUG
+ if (!tracepackets)
+ daemon(0, 0);
+#endif
+ openlog("XNSrouted", LOG_PID, LOG_DAEMON);
+
+ ns_anynet.s_net[0] = -1; ns_anynet.s_net[1] = -1;
+ addr.sns_family = AF_NS;
+ addr.sns_len = sizeof(addr);
+ addr.sns_port = htons(IDPPORT_RIF);
+ s = getsocket(SOCK_DGRAM, 0, &addr);
+ if (s < 0)
+ exit(1);
+ /*
+ * Any extra argument is considered
+ * a tracing log file.
+ */
+ if (argc > 0)
+ traceon(*argv);
+ /*
+ * Collect an initial view of the world by
+ * snooping in the kernel. Then, send a request packet on all
+ * directly connected networks to find out what
+ * everyone else thinks.
+ */
+ rtinit();
+ ifinit();
+ if (supplier < 0)
+ supplier = 0;
+ /* request the state of the world */
+ msg->rip_cmd = htons(RIPCMD_REQUEST);
+ msg->rip_nets[0].rip_dst = ns_anynet;
+ msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY);
+ toall(sndmsg);
+ signal(SIGALRM, timer);
+ signal(SIGHUP, hup);
+ signal(SIGINT, hup);
+ signal(SIGEMT, fkexit);
+ timer();
+
+
+ for (;;)
+ process(s);
+
+}
+
+process(fd)
+ int fd;
+{
+ struct sockaddr from;
+ int fromlen = sizeof (from), cc, omask;
+ struct idp *idp = (struct idp *)packet;
+
+ cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EINTR)
+ syslog(LOG_ERR, "recvfrom: %m");
+ return;
+ }
+ if (tracepackets > 1 && ftrace) {
+ fprintf(ftrace,"rcv %d bytes on %s ", cc, xns_ntoa(&idp->idp_dna));
+ fprintf(ftrace," from %s\n", xns_ntoa(&idp->idp_sna));
+ }
+
+ if (noteremoterequests && !ns_neteqnn(idp->idp_sna.x_net, ns_zeronet)
+ && !ns_neteq(idp->idp_sna, idp->idp_dna))
+ {
+ syslog(LOG_ERR,
+ "net of interface (%s) != net on ether (%s)!\n",
+ xns_nettoa(idp->idp_dna.x_net),
+ xns_nettoa(idp->idp_sna.x_net));
+ }
+
+ /* We get the IDP header in front of the RIF packet*/
+ cc -= sizeof (struct idp);
+#define mask(s) (1<<((s)-1))
+ omask = sigblock(mask(SIGALRM));
+ rip_input(&from, cc);
+ sigsetmask(omask);
+}
+
+getsocket(type, proto, sns)
+ int type, proto;
+ struct sockaddr_ns *sns;
+{
+ int domain = sns->sns_family;
+ int retry, s, on = 1;
+
+ retry = 1;
+ while ((s = socket(domain, type, proto)) < 0 && retry) {
+ syslog(LOG_ERR, "socket: %m");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ while (bind(s, (struct sockaddr *)sns, sizeof (*sns)) < 0 && retry) {
+ syslog(LOG_ERR, "bind: %m");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ if (domain==AF_NS) {
+ struct idp idp;
+ if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
+ syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
+ exit(1);
+ }
+ idp.idp_pt = NSPROTO_RI;
+ if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &idp, sizeof(idp))) {
+ syslog(LOG_ERR, "setsockopt SET HEADER: %m");
+ exit(1);
+ }
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ exit(1);
+ }
+ return (s);
+}
+
+/*
+ * Fork and exit on EMT-- for profiling.
+ */
+void
+fkexit()
+{
+ if (fork() == 0)
+ exit(0);
+}
diff --git a/usr.sbin/XNSrouted/output.c b/usr.sbin/XNSrouted/output.c
new file mode 100644
index 000000000000..cdea11f2b73f
--- /dev/null
+++ b/usr.sbin/XNSrouted/output.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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.8 (Berkeley) 2/26/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)
+ int (*f)();
+{
+ 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)
+ 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);
+ }
+}
+
+/*
+ * Output a preformed packet.
+ */
+/*ARGSUSED*/
+sndmsg(dst, flags, ifp)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+
+ (*afswitch[dst->sa_family].af_output)
+ (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)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register struct netinfo *nn;
+ register struct netinfo *n = msg->rip_nets;
+ struct rthash *base = hosthash;
+ struct sockaddr_ns *sns = (struct sockaddr_ns *) dst;
+ int (*output)() = afswitch[dst->sa_family].af_output;
+ int doinghost = 1, size, metric;
+ union ns_net net;
+
+ msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ size = (char *)n - (char *)msg;
+ if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
+ (*output)(flags, dst, size);
+ TRACE_OUTPUT(ifp, dst, size);
+ n = msg->rip_nets;
+ }
+ sns = (struct sockaddr_ns *)&rt->rt_dst;
+ if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
+ sns = (struct sockaddr_ns *)&rt->rt_router;
+ metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
+ net = sns->sns_addr.x_net;
+ /*
+ * Make sure that we don't put out a two net entries
+ * for a pt to pt link (one for the G route, one for the if)
+ * This is a kludge, and won't work if there are lots of nets.
+ */
+ for (nn = msg->rip_nets; nn < n; nn++) {
+ if (ns_neteqnn(net, nn->rip_dst)) {
+ if (metric < ntohs(nn->rip_metric))
+ nn->rip_metric = htons(metric);
+ goto next;
+ }
+ }
+ n->rip_dst = net;
+ n->rip_metric = htons(metric);
+ n++;
+ next:;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (n != msg->rip_nets) {
+ size = (char *)n - (char *)msg;
+ (*output)(flags, dst, size);
+ TRACE_OUTPUT(ifp, dst, size);
+ }
+}
diff --git a/usr.sbin/XNSrouted/protocol.h b/usr.sbin/XNSrouted/protocol.h
new file mode 100644
index 000000000000..9bf422b60625
--- /dev/null
+++ b/usr.sbin/XNSrouted/protocol.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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.
+ *
+ * @(#)protocol.h 5.6 (Berkeley) 6/1/90
+ */
+
+/*
+ * Xerox Routing Information Protocol
+ *
+ */
+
+struct netinfo {
+ union ns_net rip_dst; /* destination net */
+ u_short rip_metric; /* cost of route */
+};
+
+struct rip {
+ u_short rip_cmd; /* request/response */
+ struct netinfo rip_nets[1]; /* variable length */
+};
+
+/*
+ * Packet types.
+ */
+#define RIPCMD_REQUEST 1 /* want info */
+#define RIPCMD_RESPONSE 2 /* responding to request */
+
+#define RIPCMD_MAX 3
+#ifdef RIPCMDS
+char *ripcmds[RIPCMD_MAX] =
+ { "#0", "REQUEST", "RESPONSE" };
+#endif
+
+#define HOPCNT_INFINITY 16 /* per Xerox NS */
+#define DSTNETS_ALL 0xffffffff /* per Xerox NS */
+#define MAXPACKETSIZE 512 /* max broadcast size */
+
+extern union ns_net ns_anynet;
+extern union ns_net ns_zeronet;
+
+/*
+ * Timer values used in managing the routing table.
+ * Every update forces an entry's timer to be reset. After
+ * EXPIRE_TIME without updates, the entry is marked invalid,
+ * but held onto until GARBAGE_TIME so that others may
+ * see it "be deleted".
+ */
+#define TIMER_RATE 30 /* alarm clocks every 30 seconds */
+
+#define SUPPLY_INTERVAL 30 /* time to supply tables */
+
+#define EXPIRE_TIME 180 /* time to mark entry invalid */
+#define GARBAGE_TIME 240 /* time to garbage collect */
diff --git a/usr.sbin/XNSrouted/startup.c b/usr.sbin/XNSrouted/startup.c
new file mode 100644
index 000000000000..8887c1fc474a
--- /dev/null
+++ b/usr.sbin/XNSrouted/startup.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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.11 (Berkeley) 2/26/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <nlist.h>
+#include <stdlib.h>
+
+struct interface *ifnet;
+int lookforinterfaces = 1;
+int performnlist = 1;
+int gateway = 0;
+int externalinterfaces = 0; /* # of remote and local interfaces */
+char ether_broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+
+/*
+ * 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;
+ struct ifconf ifc;
+ char buf[BUFSIZ], *cp, *cplim;
+ struct ifreq ifreq, *ifr;
+ u_long i;
+
+ if ((s = socket(AF_NS, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+ 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);
+ exit(1);
+ }
+ 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, "ioctl (get interface flags)");
+ 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;
+ }
+ if (ifs.int_addr.sa_family != AF_NS)
+ continue;
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "ioctl (get dstaddr): %m");
+ continue;
+ }
+ ifs.int_dstaddr = ifreq.ifr_dstaddr;
+ }
+ if (ifs.int_flags & IFF_BROADCAST) {
+ if (ioctl(s, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "ioctl (get broadaddr: %m");
+ continue;
+ }
+ ifs.int_broadaddr = ifreq.ifr_broadaddr;
+ }
+ /*
+ * already known to us?
+ * what makes a POINTOPOINT if unique is its dst addr,
+ * NOT its source address
+ */
+ if ( ((ifs.int_flags & IFF_POINTOPOINT) &&
+ if_ifwithdstaddr(&ifs.int_dstaddr)) ||
+ ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) &&
+ if_ifwithaddr(&ifs.int_addr)))
+ continue;
+ /* no one cares about software loopback interfaces */
+ if (strncmp(ifr->ifr_name,"lo", 2)==0)
+ continue;
+ ifp = (struct interface *)malloc(sizeof (struct interface));
+ if (ifp == 0) {
+ syslog(LOG_ERR,"XNSrouted: 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_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) {
+ syslog(LOG_ERR,"XNSrouted: out of memory\n");
+ exit(1);
+ }
+ strcpy(ifp->int_name, ifr->ifr_name);
+ ifp->int_metric = 0;
+ ifp->int_next = ifnet;
+ ifnet = ifp;
+ traceinit(ifp);
+ addrouteforif(ifp);
+ }
+ if (externalinterfaces > 1 && supplier < 0)
+ supplier = 1;
+ close(s);
+}
+
+addrouteforif(ifp)
+ struct interface *ifp;
+{
+ struct sockaddr_ns net;
+ struct sockaddr *dst;
+ int state, metric;
+ struct rt_entry *rt;
+
+ if (ifp->int_flags & IFF_POINTOPOINT) {
+ int (*match)();
+ register struct interface *ifp2 = ifnet;
+ register struct interface *ifprev = ifnet;
+
+ dst = &ifp->int_dstaddr;
+
+ /* Search for interfaces with the same net */
+ ifp->int_sq.n = ifp->int_sq.p = &(ifp->int_sq);
+ match = afswitch[dst->sa_family].af_netmatch;
+ if (match)
+ for (ifp2 = ifnet; ifp2; ifp2 =ifp2->int_next) {
+ if (ifp->int_flags & IFF_POINTOPOINT == 0)
+ continue;
+ if ((*match)(&ifp2->int_dstaddr,&ifp->int_dstaddr)) {
+ insque(&ifp2->int_sq,&ifp->int_sq);
+ break;
+ }
+ }
+ } else {
+ dst = &ifp->int_broadaddr;
+ }
+ rt = rtlookup(dst);
+ if (rt)
+ rtdelete(rt);
+ if (tracing)
+ fprintf(stderr, "Adding route to interface %s\n", ifp->int_name);
+ if (ifp->int_transitions++ > 0)
+ syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+ rtadd(dst, &ifp->int_addr, ifp->int_metric,
+ ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
+}
+
diff --git a/usr.sbin/XNSrouted/table.h b/usr.sbin/XNSrouted/table.h
new file mode 100644
index 000000000000..159dc4e64252
--- /dev/null
+++ b/usr.sbin/XNSrouted/table.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1983 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.
+ *
+ * @(#)table.h 5.1 (Berkeley) 6/4/85 (routed/table.h)
+ *
+ * @(#)table.h 5.3 (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;
+ 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_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_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 */
+
+struct rthash nethash[ROUTEHASHSIZ];
+struct rthash hosthash[ROUTEHASHSIZ];
+struct rt_entry *rtlookup();
+struct rt_entry *rtfind();
diff --git a/usr.sbin/XNSrouted/tables.c b/usr.sbin/XNSrouted/tables.c
new file mode 100644
index 000000000000..38ce4386fe25
--- /dev/null
+++ b/usr.sbin/XNSrouted/tables.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tables.c 5.9 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+extern char *xns_ntoa();
+#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
+
+int install = !DEBUG; /* if 1 call kernel */
+int delete = 1;
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *
+rtlookup(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int doinghost = 1;
+
+ if (dst->sa_family >= AF_MAX)
+ return (0);
+ (*afswitch[dst->sa_family].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ goto again;
+ }
+ return (0);
+}
+
+/*
+ * Find a route to dst as the kernel would.
+ */
+struct rt_entry *
+rtfind(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int af = dst->sa_family;
+ int doinghost = 1, (*match)();
+
+ if (af >= AF_MAX)
+ return (0);
+ (*afswitch[af].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (doinghost) {
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ } else {
+ if (rt->rt_dst.sa_family == af &&
+ (*match)(&rt->rt_dst, dst))
+ return (rt);
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ match = afswitch[af].af_netmatch;
+ goto again;
+ }
+ return (0);
+}
+
+rtadd(dst, gate, metric, state)
+ struct sockaddr *dst, *gate;
+ int metric, state;
+{
+ struct afhash h;
+ register struct rt_entry *rt;
+ struct rthash *rh;
+ int af = dst->sa_family, flags;
+ u_int hash;
+
+ FIXLEN(dst);
+ FIXLEN(gate);
+ if (af >= AF_MAX)
+ return;
+ (*afswitch[af].af_hash)(dst, &h);
+ flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
+ if (flags & RTF_HOST) {
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+ } else {
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ }
+ rt = (struct rt_entry *)malloc(sizeof (*rt));
+ if (rt == 0)
+ return;
+ rt->rt_hash = hash;
+ rt->rt_dst = *dst;
+ rt->rt_router = *gate;
+ rt->rt_metric = metric;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ if (metric)
+ rt->rt_flags |= RTF_GATEWAY;
+ insque(rt, rh);
+ TRACE_ACTION(ADD, rt);
+ /*
+ * If the ioctl fails because the gateway is unreachable
+ * from this host, discard the entry. This should only
+ * occur because of an incorrect entry in /etc/gateways.
+ */
+ if (install && ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
+ if (errno != EEXIST)
+ perror("SIOCADDRT");
+ if (errno == ENETUNREACH) {
+ TRACE_ACTION(DELETE, rt);
+ remque(rt);
+ free((char *)rt);
+ }
+ }
+}
+
+rtchange(rt, gate, metric)
+ struct rt_entry *rt;
+ struct sockaddr *gate;
+ short metric;
+{
+ int doioctl = 0, metricchanged = 0;
+ struct rtentry oldroute;
+
+ FIXLEN(gate);
+ if (!equal(&rt->rt_router, gate))
+ doioctl++;
+ if (metric != rt->rt_metric)
+ metricchanged++;
+ if (doioctl || metricchanged) {
+ TRACE_ACTION(CHANGE FROM, rt);
+ if (doioctl) {
+ oldroute = rt->rt_rt;
+ rt->rt_router = *gate;
+ }
+ rt->rt_metric = metric;
+ if ((rt->rt_state & RTS_INTERFACE) && metric) {
+ rt->rt_state &= ~RTS_INTERFACE;
+ syslog(LOG_ERR,
+ "changing route from interface %s (timed out)",
+ rt->rt_ifp->int_name);
+ }
+ if (metric)
+ rt->rt_flags |= RTF_GATEWAY;
+ else
+ rt->rt_flags &= ~RTF_GATEWAY;
+ rt->rt_state |= RTS_CHANGED;
+ TRACE_ACTION(CHANGE TO, rt);
+ }
+ if (doioctl && install) {
+#ifndef RTM_ADD
+ if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+ syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+ if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+ perror("SIOCDELRT");
+#else
+ if (delete && ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+ perror("SIOCDELRT");
+ if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+ syslog(LOG_ERR, "SIOCADDRT dst %s, gw %s: %m",
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+#endif
+ }
+}
+
+rtdelete(rt)
+ struct rt_entry *rt;
+{
+
+ struct sockaddr *sa = &(rt->rt_rt.rt_gateway);
+ FIXLEN(sa);
+#undef rt_dst
+ sa = &(rt->rt_rt.rt_dst);
+ FIXLEN(sa);
+ if (rt->rt_state & RTS_INTERFACE) {
+ syslog(LOG_ERR, "deleting route to interface %s (timed out)",
+ rt->rt_ifp->int_name);
+ }
+ TRACE_ACTION(DELETE, rt);
+ if (install && ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+ perror("SIOCDELRT");
+ remque(rt);
+ free((char *)rt);
+}
+
+rtinit()
+{
+ register struct rthash *rh;
+
+ for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+ for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+}
diff --git a/usr.sbin/XNSrouted/timer.c b/usr.sbin/XNSrouted/timer.c
new file mode 100644
index 000000000000..f420bc074e00
--- /dev/null
+++ b/usr.sbin/XNSrouted/timer.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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.7 (Berkeley) 2/26/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+int timeval = -TIMER_RATE;
+
+/*
+ * Timer routine. Performs routing information supply
+ * duties and manages timers on routing table entries.
+ */
+void
+timer()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1, timetobroadcast;
+
+ timeval += TIMER_RATE;
+ if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
+ ifinit();
+ timetobroadcast = supplier && (timeval % 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 that for our only interface.
+ * The latter is excused because we don't act as
+ * a routing information supplier and hence would
+ * time it out. This is fair as if it's down
+ * we're cut off from the world anyway and it's
+ * not likely we'll grow any new hardware in
+ * the mean time.
+ */
+ if (!(rt->rt_state & RTS_PASSIVE) &&
+ (supplier || !(rt->rt_state & RTS_INTERFACE)))
+ rt->rt_timer += TIMER_RATE;
+ if (rt->rt_timer >= EXPIRE_TIME)
+ rt->rt_metric = HOPCNT_INFINITY;
+ if (rt->rt_timer >= GARBAGE_TIME) {
+ rt = rt->rt_back;
+ /* Perhaps we should send a REQUEST for this route? */
+ rtdelete(rt->rt_forw);
+ continue;
+ }
+ if (rt->rt_state & RTS_CHANGED) {
+ rt->rt_state &= ~RTS_CHANGED;
+ /* don't send extraneous packets */
+ if (!supplier || timetobroadcast)
+ continue;
+ msg->rip_cmd = htons(RIPCMD_RESPONSE);
+ msg->rip_nets[0].rip_dst =
+ (satons_addr(rt->rt_dst)).x_net;
+ msg->rip_nets[0].rip_metric =
+ htons(min(rt->rt_metric+1, HOPCNT_INFINITY));
+ toall(sndmsg);
+ }
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (timetobroadcast)
+ toall(supply);
+ alarm(TIMER_RATE);
+}
+
+/*
+ * On hangup, let everyone know we're going away.
+ */
+void
+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);
+ }
+ exit(1);
+}
diff --git a/usr.sbin/XNSrouted/tools/query.c b/usr.sbin/XNSrouted/tools/query.c
new file mode 100644
index 000000000000..2e6374d1f63f
--- /dev/null
+++ b/usr.sbin/XNSrouted/tools/query.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 1983, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code includes software contributed to Berkeley by
+ * Bill Nesheim at Cornell University.
+ *
+ * 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
+char copyright[] =
+"@(#) Copyright (c) 1983, 1986 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)query.c 5.8 (Berkeley) 4/16/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netns/ns.h>
+#include <netns/idp.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netdb.h>
+#include "../protocol.h"
+#define IDPPORT_RIF 1
+
+#define WTIME 5 /* Time to wait for responses */
+
+int s;
+int timedout, timeout();
+char packet[MAXPACKETSIZE];
+extern int errno;
+struct sockaddr_ns myaddr = {sizeof(myaddr), AF_NS};
+char *ns_ntoa();
+struct ns_addr ns_addr();
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int cc, count, bits;
+ struct sockaddr from;
+ int fromlen = sizeof(from);
+ struct timeval notime;
+
+ if (argc < 2) {
+ printf("usage: query hosts...\n");
+ exit(1);
+ }
+ s = getsocket(SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+
+ argv++, argc--;
+ query(argv,argc);
+
+ /*
+ * Listen for returning packets;
+ * may be more than one packet per host.
+ */
+ bits = 1 << s;
+ bzero(&notime, sizeof(notime));
+ signal(SIGALRM, timeout);
+ alarm(WTIME);
+ while (!timedout ||
+ select(20, &bits, 0, 0, &notime) > 0) {
+ struct nspacket {
+ struct idp hdr;
+ char data[512];
+ } response;
+ cc = recvfrom(s, &response, sizeof (response), 0,
+ &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("recvfrom");
+ (void) close(s);
+ exit(1);
+ }
+ continue;
+ }
+ rip_input(&from, response.data, cc);
+ count--;
+ }
+}
+static struct sockaddr_ns router = {sizeof(myaddr), AF_NS};
+static struct ns_addr zero_addr;
+static short allones[] = {-1, -1, -1};
+
+query(argv,argc)
+char **argv;
+{
+ register struct rip *msg = (struct rip *)packet;
+ char *host = *argv;
+ int flags = 0;
+ struct ns_addr specific;
+
+ if (bcmp(*argv, "-r", 3) == 0) {
+ flags = MSG_DONTROUTE; argv++; argc--;
+ }
+ host = *argv;
+ router.sns_addr = ns_addr(host);
+ router.sns_addr.x_port = htons(IDPPORT_RIF);
+ if (ns_hosteq(zero_addr, router.sns_addr)) {
+ router.sns_addr.x_host = *(union ns_host *) allones;
+ }
+ msg->rip_cmd = htons(RIPCMD_REQUEST);
+ msg->rip_nets[0].rip_dst = *(union ns_net *) allones;
+ msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY);
+ if (argc > 0) {
+ specific = ns_addr(*argv);
+ msg->rip_nets[0].rip_dst = specific.x_net;
+ specific.x_host = zero_addr.x_host;
+ specific.x_port = zero_addr.x_port;
+ printf("Net asked for was %s\n", ns_ntoa(specific));
+ }
+ if (sendto(s, packet, sizeof (struct rip), flags,
+ &router, sizeof(router)) < 0)
+ perror(host);
+}
+
+/*
+ * Handle an incoming routing packet.
+ */
+rip_input(from, msg, size)
+ struct sockaddr_ns *from;
+ register struct rip *msg;
+ int size;
+{
+ struct netinfo *n;
+ char *name;
+ int lna, net, subnet;
+ struct hostent *hp;
+ struct netent *np;
+ static struct ns_addr work;
+
+ if (htons(msg->rip_cmd) != RIPCMD_RESPONSE)
+ return;
+ printf("from %s\n", ns_ntoa(from->sns_addr));
+ size -= sizeof (struct idp);
+ size -= sizeof (short);
+ n = msg->rip_nets;
+ while (size > 0) {
+ union ns_net_u net;
+ if (size < sizeof (struct netinfo))
+ break;
+ net.net_e = n->rip_dst;
+ printf("\t%d, metric %d\n", ntohl(net.long_e),
+ ntohs(n->rip_metric));
+ size -= sizeof (struct netinfo), n++;
+ }
+}
+
+timeout()
+{
+ timedout = 1;
+}
+getsocket(type, proto)
+ int type, proto;
+{
+ struct sockaddr_ns *sns = &myaddr;
+ int domain = sns->sns_family;
+ int retry, s, on = 1;
+
+ retry = 1;
+ while ((s = socket(domain, type, proto)) < 0 && retry) {
+ perror("socket");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ while (bind(s, sns, sizeof (*sns), 0) < 0 && retry) {
+ perror("bind");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ if (domain==AF_NS) {
+ struct idp idp;
+ if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
+ perror("setsockopt SEE HEADERS");
+ exit(1);
+ }
+ idp.idp_pt = NSPROTO_RI;
+ if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &idp, sizeof(idp))) {
+ perror("setsockopt SET HEADERS");
+ exit(1);
+ }
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ perror("setsockopt SO_BROADCAST");
+ exit(1);
+ }
+ return (s);
+}
diff --git a/usr.sbin/XNSrouted/trace.c b/usr.sbin/XNSrouted/trace.c
new file mode 100644
index 000000000000..51728733a387
--- /dev/null
+++ b/usr.sbin/XNSrouted/trace.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 1985 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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/26/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#define RIPCMDS
+#include <stdlib.h>
+#include "defs.h"
+
+#define NRECORDS 50 /* size of circular trace buffer */
+#ifdef DEBUG
+FILE *ftrace = stdout;
+int tracing = 1;
+#else DEBUG
+FILE *ftrace = NULL;
+int tracing = 0;
+#endif
+
+char *xns_ntoa();
+
+traceinit(ifp)
+ register struct interface *ifp;
+{
+ static int iftraceinit();
+
+ if (iftraceinit(ifp, &ifp->int_input) &&
+ iftraceinit(ifp, &ifp->int_output))
+ return;
+ tracing = 0;
+ syslog(LOG_ERR, "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;
+{
+
+ if (ftrace != NULL)
+ return;
+ ftrace = fopen(file, "a");
+ if (ftrace == NULL)
+ return;
+ dup2(fileno(ftrace), 1);
+ dup2(fileno(ftrace), 2);
+ tracing = 1;
+}
+
+traceoff()
+{
+ if (!tracing)
+ return;
+ if (ftrace != NULL)
+ fclose(ftrace);
+ ftrace = NULL;
+ tracing = 0;
+}
+
+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_packet)
+ free(t->ift_packet);
+ t->ift_packet = 0;
+ t->ift_stamp = time(0);
+ t->ift_who = *who;
+ if (len > 0) {
+ t->ift_packet = malloc(len);
+ if (t->ift_packet)
+ bcopy(p, t->ift_packet, len);
+ else
+ len = 0;
+ }
+ t->ift_size = len;
+ t->ift_metric = m;
+}
+
+traceaction(fd, action, rt)
+ FILE *fd;
+ char *action;
+ struct rt_entry *rt;
+{
+ struct sockaddr_ns *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" },
+ { 0 }
+ };
+ register struct bits *p;
+ register int first;
+ char *cp;
+ struct interface *ifp;
+
+ if (fd == NULL)
+ return;
+ fprintf(fd, "%s ", action);
+ dst = (struct sockaddr_ns *)&rt->rt_dst;
+ gate = (struct sockaddr_ns *)&rt->rt_router;
+ fprintf(fd, "dst %s, ", xns_ntoa(&dst->sns_addr));
+ fprintf(fd, "router %s, metric %d, flags",
+ xns_ntoa(&gate->sns_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;
+ }
+ }
+ putc('\n', fd);
+ if (!tracepackets && (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
+ dumpif(fd, rt->rt_ifp);
+ fflush(fd);
+}
+
+dumpif(fd, ifp)
+ register struct interface *ifp;
+ FILE *fd;
+{
+ if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
+ fprintf(fd, "*** Packet history for interface %s ***\n",
+ ifp->int_name);
+ dumptrace(fd, "to", &ifp->int_output);
+ 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);
+ 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;
+ fprintf(fd, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
+ t->ift_metric);
+ dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size);
+ }
+}
+
+dumppacket(fd, dir, who, cp, size)
+ FILE *fd;
+ struct sockaddr_ns *who; /* should be sockaddr */
+ char *dir, *cp;
+ register int size;
+{
+ register struct rip *msg = (struct rip *)cp;
+ register struct netinfo *n;
+ char *xns_nettoa();
+
+ if (msg->rip_cmd && ntohs(msg->rip_cmd) < RIPCMD_MAX)
+ fprintf(fd, "%s %s %s#%x", ripcmds[ntohs(msg->rip_cmd)],
+ dir, xns_ntoa(&who->sns_addr), ntohs(who->sns_addr.x_port));
+ else {
+ fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->rip_cmd),
+ dir, xns_ntoa(&who->sns_addr), ntohs(who->sns_addr.x_port));
+ fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet);
+ return;
+ }
+ switch (ntohs(msg->rip_cmd)) {
+
+ case RIPCMD_REQUEST:
+ case RIPCMD_RESPONSE:
+ fprintf(fd, ":\n");
+ size -= sizeof (u_short);
+ n = msg->rip_nets;
+ for (; size > 0; n++, size -= sizeof (struct netinfo)) {
+ if (size < sizeof (struct netinfo))
+ break;
+ fprintf(fd, "\tnet %s metric %d\n",
+ xns_nettoa(n->rip_dst),
+ ntohs(n->rip_metric));
+ }
+ break;
+
+ }
+}
+
+union ns_net_u net;
+
+char *
+xns_nettoa(val)
+union ns_net val;
+{
+ static char buf[100];
+ net.net_e = val;
+ (void)sprintf(buf, "%lx", ntohl(net.long_e));
+ return (buf);
+}
+
+
+char *
+xns_ntoa(addr)
+struct ns_addr *addr;
+{
+ static char buf[100];
+
+ (void)sprintf(buf, "%s#%x:%x:%x:%x:%x:%x",
+ xns_nettoa(addr->x_net),
+ addr->x_host.c_host[0], addr->x_host.c_host[1],
+ addr->x_host.c_host[2], addr->x_host.c_host[3],
+ addr->x_host.c_host[4], addr->x_host.c_host[5]);
+
+ return(buf);
+}
diff --git a/usr.sbin/XNSrouted/trace.h b/usr.sbin/XNSrouted/trace.h
new file mode 100644
index 000000000000..be48553d6c13
--- /dev/null
+++ b/usr.sbin/XNSrouted/trace.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * 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.6 (Berkeley) 6/1/90
+ */
+
+/*
+ * Xerox Routing Information Protocol.
+ */
+
+/*
+ * Trace record format.
+ */
+struct iftrace {
+ time_t 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 */
+};
+
+/*
+ * 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 tracing; /* on/off */
+FILE *ftrace; /* output trace file */
+
+#define TRACE_ACTION(action, route) { \
+ if (tracing) \
+ traceaction(ftrace, "action", route); \
+ }
+#define TRACE_INPUT(ifp, src, size) { \
+ if (tracing) { \
+ ifp = if_iflookup(src); \
+ if (ifp) \
+ trace(&ifp->int_input, src, &packet[sizeof(struct idp)], size, \
+ ntohl(ifp->int_metric)); \
+ } \
+ if (tracepackets && ftrace) \
+ dumppacket(ftrace, "from", src, &packet[sizeof(struct idp)], size); \
+ }
+#define TRACE_OUTPUT(ifp, dst, size) { \
+ if (tracing) { \
+ ifp = if_iflookup(dst); \
+ if (ifp) \
+ trace(&ifp->int_output, dst, &packet[sizeof(struct idp)], size, ifp->int_metric); \
+ } \
+ if (tracepackets && ftrace) \
+ dumppacket(ftrace, "to", dst, &packet[sizeof(struct idp)], size); \
+ }
diff --git a/usr.sbin/ac/Makefile b/usr.sbin/ac/Makefile
new file mode 100644
index 000000000000..349e9ce83e78
--- /dev/null
+++ b/usr.sbin/ac/Makefile
@@ -0,0 +1,18 @@
+# $Id: Makefile,v 1.1.1.1 1994/05/18 08:00:44 csgr Exp $
+
+PROG= ac
+MAN8= ac.8
+
+# If "CONSOLE_TTY" is not defined, this program is compatible with the
+# traditional implementation (using SunOS 4.x as the sample traditional
+# implementation). This is the default.
+#
+# If "CONSOLE_TTY" is defined, it must be defined to the appropriate
+# console name, e.g. "vga". Additionally, the various commented-out
+# sections of the man page should be uncommented. This is not the
+# default because of the inability to detect the proper console name
+# easily, especially on m68k systems, which can share binaries.
+#
+#CFLAGS+=-DCONSOLE_TTY=\"vga\"
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ac/ac.8 b/usr.sbin/ac/ac.8
new file mode 100644
index 000000000000..86f05bb51279
--- /dev/null
+++ b/usr.sbin/ac/ac.8
@@ -0,0 +1,165 @@
+.\"
+.\" Copyright (c) 1994 Simon J. Gerraty
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $Id: ac.8,v 1.1.1.1 1994/05/18 08:00:45 csgr Exp $
+.\"
+.Dd March 15, 1994
+.Dt AC 8
+.Os NetBSD 0.9a
+.Sh NAME
+.Nm ac
+.Nd connect time accounting
+.Sh SYNOPSIS
+.Nm ac
+.Op Fl dp
+.\".Op Fl c Ar console
+.Op Fl t Ar tty
+.Op Fl w Ar wtmp
+.Op Ar users ...
+.Sh DESCRIPTION
+If the file
+.Pa /var/log/wtmp
+exists, a record of individual login and logout
+times are written to it by
+.Xr login 8
+and
+.Xr init 8 ,
+respectively.
+.Nm \&Ac
+examines these records and writes the accumulated connect time
+for all logins to the standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width indentXXX
+.It Fl d
+Display the connect times in 24 hour chunks.
+.\" .It Fl c Ar console
+.\" Use
+.\" .Ar console
+.\" as the name of the device that local X sessions (ut_host of ":0.0")
+.\" originate from. If any login has been recorded on
+.\" .Ar console
+.\" then these X sessions are ignored unless COMPAT_SUNOS was defined at
+.\" compile time.
+.It Fl p
+Print individual users' totals.
+.It Fl t Ar tty
+Only do accounting logins on certain ttys. The
+.Ar tty
+specification can start with '!' to indicate not this
+.Ar tty
+and end with '*' to indicate all similarly named ttys.
+Multiple
+.Fl t
+flags may be specified.
+.It Fl w Ar wtmp
+Read connect time data from
+.Ar wtmp
+instead of the default file,
+.Pa /var/log/wtmp .
+.It Ar users ...
+Display totals for the given individuals only.
+.El
+.Pp
+If no arguments are given,
+.Nm ac
+displays the total connect time for all
+accounts with login sessions recorded in
+.Pa wtmp .
+.Pp
+The default
+.Pa wtmp
+file will increase without bound unless it is truncated.
+It is normally truncated by the daily scripts run
+by
+.Xr cron 8 ,
+which rename and rotate the
+.Pa wtmp
+files, keeping a week's worth of data on
+hand. No login or connect time accounting is performed if
+.Pa /var/log/wtmp
+does not exist.
+.Pp
+For example,
+.Bd -literal -offset
+ac -p -t "ttyd*" > modems
+ac -p -t "!ttyd*" > other
+.Ed
+.Pp
+allows times recorded in
+.Pa modems
+to be charged out at a different rate than
+.Pa other .
+.Pp
+The
+.Nm ac
+utility exits 0 on success, and >0 if a fatal error occurs.
+.Sh FILES
+.Bl -tag -width /var/log/wtmp.[0-7] -compact
+.It Pa /var/log/wtmp
+connect time accounting file
+.It Pa /var/log/wtmp.[0-7]
+rotated files
+.El
+.Sh SEE ALSO
+.Xr init 8 ,
+.Xr sa 8 ,
+.Xr login 1 ,
+.Xr utmp
+.Sh HISTORY
+An
+.Nm ac
+command appeard in
+.At v6 .
+This version of
+.Nm ac
+was written for
+.Nx 0.9a
+from the specification provided by various systems' manual pages.
+.\" .Sh NOTES
+.\" If COMPAT_SUNOS is defined
+.\" .Nm ac
+.\" ignores the fact that entries with ut_host of ":0.0" are not real
+.\" login sessions. Normally such entries are ignored except in the case
+.\" of a user being logged in when the
+.\" .Pa wtmp
+.\" file was rotated, in which case a login with ut_host of ":0.0" may
+.\" appear without any preceeding console logins.
+.\" If no one is logged in on the console, the user is deemed to have
+.\" logged in on at the earliest time stamp found in
+.\" .Pa wtmp .
+.\" Use of
+.\" .Pa console
+.\" allows
+.\" .Nm ac
+.\" to identify and correcty process a logout for the user. The default
+.\" value for
+.\" .Pa console
+.\" is usually correct at compile time.
diff --git a/usr.sbin/ac/ac.c b/usr.sbin/ac/ac.c
new file mode 100644
index 000000000000..2d6831511217
--- /dev/null
+++ b/usr.sbin/ac/ac.c
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou.
+ * @(#)Copyright (c) 1994, Simon J. Gerraty.
+ *
+ * This is free software. It comes with NO WARRANTY.
+ * Permission to use, modify and distribute this source code
+ * is granted subject to the following conditions.
+ * 1/ that the above copyright notice and this notice
+ * are preserved in all copies and that due credit be given
+ * to the author.
+ * 2/ that any changes to this code are clearly commented
+ * as such so that the author does not get blamed for bugs
+ * other than his own.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: ac.c,v 1.1.1.1 1994/05/18 08:00:45 csgr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+#include <unistd.h>
+
+/*
+ * this is for our list of currently logged in sessions
+ */
+struct utmp_list {
+ struct utmp_list *next;
+ struct utmp usr;
+};
+
+/*
+ * this is for our list of users that are accumulating time.
+ */
+struct user_list {
+ struct user_list *next;
+ char name[UT_NAMESIZE+1];
+ time_t secs;
+};
+
+/*
+ * this is for chosing whether to ignore a login
+ */
+struct tty_list {
+ struct tty_list *next;
+ char name[UT_LINESIZE+3];
+ int len;
+ int ret;
+};
+
+/*
+ * globals - yes yuk
+ */
+#ifdef CONSOLE_TTY
+static char *Console = CONSOLE_TTY;
+#endif
+static time_t Total = 0;
+static time_t FirstTime = 0;
+static int Flags = 0;
+static struct user_list *Users = NULL;
+static struct tty_list *Ttys = NULL;
+
+#define NEW(type) (type *)malloc(sizeof (type))
+
+#define AC_W 1 /* not _PATH_WTMP */
+#define AC_D 2 /* daily totals (ignore -p) */
+#define AC_P 4 /* per-user totals */
+#define AC_U 8 /* specified users only */
+#define AC_T 16 /* specified ttys only */
+
+#ifdef DEBUG
+static int Debug = 0;
+#endif
+
+int main __P((int, char **));
+int ac __P((FILE *));
+struct tty_list *add_tty __P((char *));
+int do_tty __P((char *));
+FILE *file __P((char *));
+struct utmp_list *log_in __P((struct utmp_list *, struct utmp *));
+struct utmp_list *log_out __P((struct utmp_list *, struct utmp *));
+int on_console __P((struct utmp_list *));
+void show __P((char *, time_t));
+void show_today __P((struct user_list *, struct utmp_list *,
+ time_t));
+void show_users __P((struct user_list *));
+struct user_list *update_user __P((struct user_list *, char *, time_t));
+void usage __P((void));
+
+/*
+ * open wtmp or die
+ */
+FILE *
+file(name)
+ char *name;
+{
+ FILE *fp;
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "%s", name);
+ /* in case we want to discriminate */
+ if (strcmp(_PATH_WTMP, name))
+ Flags |= AC_W;
+ return fp;
+}
+
+struct tty_list *
+add_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ register char *rcp;
+
+ Flags |= AC_T;
+
+ if ((tp = NEW(struct tty_list)) == NULL)
+ err(1, "malloc");
+ tp->len = 0; /* full match */
+ tp->ret = 1; /* do if match */
+ if (*name == '!') { /* don't do if match */
+ tp->ret = 0;
+ name++;
+ }
+ (void)strncpy(tp->name, name, sizeof (tp->name) - 1);
+ tp->name[sizeof (tp->name) - 1] = '\0';
+ if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */
+ *rcp = '\0';
+ tp->len = strlen(tp->name); /* match len bytes only */
+ }
+ tp->next = Ttys;
+ Ttys = tp;
+ return Ttys;
+}
+
+/*
+ * should we process the named tty?
+ */
+int
+do_tty(name)
+ char *name;
+{
+ struct tty_list *tp;
+ int def_ret = 0;
+
+ for (tp = Ttys; tp != NULL; tp = tp->next) {
+ if (tp->ret == 0) /* specific don't */
+ def_ret = 1; /* default do */
+ if (tp->len != 0) {
+ if (strncmp(name, tp->name, tp->len) == 0)
+ return tp->ret;
+ } else {
+ if (strncmp(name, tp->name, sizeof (tp->name)) == 0)
+ return tp->ret;
+ }
+ }
+ return def_ret;
+}
+
+#ifdef CONSOLE_TTY
+/*
+ * is someone logged in on Console?
+ */
+int
+on_console(head)
+ struct utmp_list *head;
+{
+ struct utmp_list *up;
+
+ for (up = head; up; up = up->next) {
+ if (strncmp(up->usr.ut_line, Console,
+ sizeof (up->usr.ut_line)) == 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * update user's login time
+ */
+struct user_list *
+update_user(head, name, secs)
+ struct user_list *head;
+ char *name;
+ time_t secs;
+{
+ struct user_list *up;
+
+ for (up = head; up != NULL; up = up->next) {
+ if (strncmp(up->name, name, sizeof (up->name)) == 0) {
+ up->secs += secs;
+ Total += secs;
+ return head;
+ }
+ }
+ /*
+ * not found so add new user unless specified users only
+ */
+ if (Flags & AC_U)
+ return head;
+
+ if ((up = NEW(struct user_list)) == NULL)
+ err(1, "malloc");
+ up->next = head;
+ (void)strncpy(up->name, name, sizeof (up->name) - 1);
+ up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */
+ up->secs = secs;
+ Total += secs;
+ return up;
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *fp;
+ int c;
+
+ fp = NULL;
+ while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) {
+ switch (c) {
+#ifdef DEBUG
+ case 'D':
+ Debug++;
+ break;
+#endif
+ case 'c':
+#ifdef CONSOLE_TTY
+ Console = optarg;
+#else
+ usage(); /* XXX */
+#endif
+ break;
+ case 'd':
+ Flags |= AC_D;
+ break;
+ case 'p':
+ Flags |= AC_P;
+ break;
+ case 't': /* only do specified ttys */
+ add_tty(optarg);
+ break;
+ case 'w':
+ fp = file(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ if (optind < argc) {
+ /*
+ * initialize user list
+ */
+ for (; optind < argc; optind++) {
+ Users = update_user(Users, argv[optind], 0L);
+ }
+ Flags |= AC_U; /* freeze user list */
+ }
+ if (Flags & AC_D)
+ Flags &= ~AC_P;
+ if (fp == NULL) {
+ /*
+ * if _PATH_WTMP does not exist, exit quietly
+ */
+ if (access(_PATH_WTMP, 0) != 0 && errno == ENOENT)
+ return 0;
+
+ fp = file(_PATH_WTMP);
+ }
+ ac(fp);
+
+ return 0;
+}
+
+/*
+ * print login time in decimal hours
+ */
+void
+show(name, secs)
+ char *name;
+ time_t secs;
+{
+ (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name,
+ ((double)secs / 3600));
+}
+
+void
+show_users(list)
+ struct user_list *list;
+{
+ struct user_list *lp;
+
+ for (lp = list; lp; lp = lp->next)
+ show(lp->name, lp->secs);
+}
+
+/*
+ * print total login time for 24hr period in decimal hours
+ */
+void
+show_today(users, logins, secs)
+ struct user_list *users;
+ struct utmp_list *logins;
+ time_t secs;
+{
+ struct user_list *up;
+ struct utmp_list *lp;
+ char date[64];
+ time_t yesterday = secs - 1;
+
+ (void)strftime(date, sizeof (date), "%b %e total",
+ localtime(&yesterday));
+
+ /* restore the missing second */
+ yesterday++;
+
+ for (lp = logins; lp != NULL; lp = lp->next) {
+ secs = yesterday - lp->usr.ut_time;
+ Users = update_user(Users, lp->usr.ut_name, secs);
+ lp->usr.ut_time = yesterday; /* as if they just logged in */
+ }
+ secs = 0;
+ for (up = users; up != NULL; up = up->next) {
+ secs += up->secs;
+ up->secs = 0; /* for next day */
+ }
+ if (secs)
+ (void)printf("%s %11.2f\n", date, ((double)secs / 3600));
+}
+
+/*
+ * log a user out and update their times.
+ * if ut_line is "~", we log all users out as the system has
+ * been shut down.
+ */
+struct utmp_list *
+log_out(head, up)
+ struct utmp_list *head;
+ struct utmp *up;
+{
+ struct utmp_list *lp, *lp2, *tlp;
+ time_t secs;
+
+ for (lp = head, lp2 = NULL; lp != NULL; )
+ if (*up->ut_line == '~' || strncmp(lp->usr.ut_line, up->ut_line,
+ sizeof (up->ut_line)) == 0) {
+ secs = up->ut_time - lp->usr.ut_time;
+ Users = update_user(Users, lp->usr.ut_name, secs);
+#ifdef DEBUG
+ if (Debug)
+ printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
+ 19, ctime(&up->ut_time),
+ sizeof (lp->usr.ut_line), lp->usr.ut_line,
+ sizeof (lp->usr.ut_name), lp->usr.ut_name,
+ secs / 3600, (secs % 3600) / 60, secs % 60);
+#endif
+ /*
+ * now lose it
+ */
+ tlp = lp;
+ lp = lp->next;
+ if (tlp == head)
+ head = lp;
+ else if (lp2 != NULL)
+ lp2->next = lp;
+ free(tlp);
+ } else {
+ lp2 = lp;
+ lp = lp->next;
+ }
+ return head;
+}
+
+
+/*
+ * if do_tty says ok, login a user
+ */
+struct utmp_list *
+log_in(head, up)
+ struct utmp_list *head;
+ struct utmp *up;
+{
+ struct utmp_list *lp;
+
+ /*
+ * this could be a login. if we're not dealing with
+ * the console name, say it is.
+ *
+ * If we are, and if ut_host==":0.0" we know that it
+ * isn't a real login. _But_ if we have not yet recorded
+ * someone being logged in on Console - due to the wtmp
+ * file starting after they logged in, we'll pretend they
+ * logged in, at the start of the wtmp file.
+ */
+
+#ifdef CONSOLE_TTY
+ if (up->ut_host[0] == ':') {
+ /*
+ * SunOS 4.0.2 does not treat ":0.0" as special but we
+ * do.
+ */
+ if (on_console(head))
+ return head;
+ /*
+ * ok, no recorded login, so they were here when wtmp
+ * started! Adjust ut_time!
+ */
+ up->ut_time = FirstTime;
+ /*
+ * this allows us to pick the right logout
+ */
+ (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1);
+ up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */
+ }
+#endif
+ /*
+ * If we are doing specified ttys only, we ignore
+ * anything else.
+ */
+ if (Flags & AC_T)
+ if (!do_tty(up->ut_line))
+ return head;
+
+ /*
+ * go ahead and log them in
+ */
+ if ((lp = NEW(struct utmp_list)) == NULL)
+ err(1, "malloc");
+ lp->next = head;
+ head = lp;
+ memmove((char *)&lp->usr, (char *)up, sizeof (struct utmp));
+#ifdef DEBUG
+ if (Debug) {
+ printf("%-.*s %-.*s: %-.*s logged in", 19,
+ ctime(&lp->usr.ut_time), sizeof (up->ut_line),
+ up->ut_line, sizeof (up->ut_name), up->ut_name);
+ if (*up->ut_host)
+ printf(" (%-.*s)", sizeof (up->ut_host), up->ut_host);
+ putchar('\n');
+ }
+#endif
+ return head;
+}
+
+int
+ac(fp)
+ FILE *fp;
+{
+ struct utmp_list *lp, *head = NULL;
+ struct utmp usr;
+ struct tm *ltm;
+ time_t secs;
+ int day = -1;
+
+ while (fread((char *)&usr, sizeof(usr), 1, fp) == 1) {
+ if (!FirstTime)
+ FirstTime = usr.ut_time;
+ if (Flags & AC_D) {
+ ltm = localtime(&usr.ut_time);
+ if (day >= 0 && day != ltm->tm_yday) {
+ day = ltm->tm_yday;
+ /*
+ * print yesterday's total
+ */
+ secs = usr.ut_time;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ } else
+ day = ltm->tm_yday;
+ }
+ switch(*usr.ut_line) {
+ case '|':
+ secs = usr.ut_time;
+ break;
+ case '{':
+ secs -= usr.ut_time;
+ /*
+ * adjust time for those logged in
+ */
+ for (lp = head; lp != NULL; lp = lp->next)
+ lp->usr.ut_time -= secs;
+ break;
+ case '~': /* reboot or shutdown */
+ head = log_out(head, &usr);
+ FirstTime = usr.ut_time; /* shouldn't be needed */
+ break;
+ default:
+ /*
+ * if they came in on tty[p-y]*, then it is only
+ * a login session if the ut_host field is non-empty
+ */
+ if (*usr.ut_name) {
+ if (strncmp(usr.ut_line, "tty", 3) != 0 ||
+ strchr("pqrstuvwxy", usr.ut_line[3]) == 0 ||
+ *usr.ut_host != '\0')
+ head = log_in(head, &usr);
+ } else
+ head = log_out(head, &usr);
+ break;
+ }
+ }
+ (void)fclose(fp);
+ usr.ut_time = time((time_t *)0);
+ (void)strcpy(usr.ut_line, "~");
+
+ if (Flags & AC_D) {
+ ltm = localtime(&usr.ut_time);
+ if (day >= 0 && day != ltm->tm_yday) {
+ /*
+ * print yesterday's total
+ */
+ secs = usr.ut_time;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ }
+ }
+ /*
+ * anyone still logged in gets time up to now
+ */
+ head = log_out(head, &usr);
+
+ if (Flags & AC_D)
+ show_today(Users, head, time((time_t *)0));
+ else {
+ if (Flags & AC_P)
+ show_users(Users);
+ show("total", Total);
+ }
+ return 0;
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+#ifdef CONSOLE_TTY
+ "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
+#else
+ "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");
+#endif
+ exit(1);
+}
diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8
index f5c07b672c49..abf6ced7654d 100644
--- a/usr.sbin/config/config.8
+++ b/usr.sbin/config/config.8
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)config.8 6.5 (Berkeley) 3/16/91
-.\" $Id: config.8,v 1.2 1993/09/26 23:11:06 rgrimes Exp $
+.\" $Id: config.8,v 1.3 1994/06/01 09:50:08 phk Exp $
.\"
.Dd March 16, 1991
.Dt CONFIG 8
@@ -133,6 +133,10 @@ the problems in the configuration file should be corrected and
should be run again.
Attempts to compile a system that had configuration errors
are likely to fail.
+.Pp
+The entire input file is embedded in the new kernel. This means that
+.Xr strings 1
+can be used to extract it from a kernel.
.Sh FILES
.Bl -tag -width /sys/i386/conf/Makefile.i386 -compact
.It Pa /sys/conf/files
diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c
index 2ea5c3d7ec32..93c089b18dde 100644
--- a/usr.sbin/config/main.c
+++ b/usr.sbin/config/main.c
@@ -146,6 +146,7 @@ usage: fputs("usage: config [-gp] sysname\n", stderr);
makefile(); /* build Makefile */
headers(); /* make a lot of .h files */
swapconf(); /* swap config files */
+ configfile(); /* add config file into kernel */
printf("Don't forget to run \"make depend\"\n");
exit(0);
}
@@ -256,3 +257,39 @@ path(file)
}
return (cp);
}
+
+
+configfile()
+{
+ FILE *fi, *fo;
+ char *p;
+ int i;
+
+ fi = fopen(PREFIX,"r");
+ if(!fi) {
+ perror(PREFIX);
+ exit(2);
+ }
+ fo = fopen(p=path("config.c"),"w");
+ if(!fo) {
+ perror(p);
+ exit(2);
+ }
+ fprintf(fo,"static char *config = \"\n");
+ fprintf(fo,"START CONFIG FILE %s\n___",PREFIX);
+ while (EOF != (i=getc(fi))) {
+ if(i == '\n') {
+ fprintf(fo,"\n___");
+ } else if(i == '\"') {
+ fprintf(fo,"\\\"");
+ } else if(i == '\\') {
+ fprintf(fo,"\\\\");
+ } else {
+ putc(i,fo);
+ }
+ }
+ fprintf(fo,"\nEND CONFIG FILE %s\n",PREFIX);
+ fprintf(fo,"\";\n");
+ fclose(fi);
+ fclose(fo);
+}
diff --git a/usr.sbin/config/mkglue.c b/usr.sbin/config/mkglue.c
index 8702448d6254..381f7bca0366 100644
--- a/usr.sbin/config/mkglue.c
+++ b/usr.sbin/config/mkglue.c
@@ -353,7 +353,7 @@ vector() {
fprintf(fp, "\
#define BUILD_VECTORS \\\n\
- BUILD_VECTOR(clk, 0,0,0, _highmask, _hardclock,1,1, al);\\\n");
+ BUILD_VECTOR(clk, 0,0,0, _high_imask, _timerintr,1,1, al);\\\n");
count=1;
for (dp = dtab; dp != 0; dp = dp->d_next) {
@@ -388,9 +388,9 @@ build_vector(fp, dp, id, offset)
strcmp(dp->d_name, "sio") == 0 ? "FAST_" : "",
dp->d_name, dp->d_unit, dp->d_unit, dp->d_irq, offset);
if (eq(dp->d_mask, "null"))
- fprintf(fp, ", _%s%dmask,", dp->d_name, dp->d_unit);
+ fprintf(fp, ", _%s%d_imask,", dp->d_name, dp->d_unit);
else
- fprintf(fp, ", _%smask, ", dp->d_mask);
+ fprintf(fp, ", _%s_imask, ", dp->d_mask);
fprintf(fp, " _%s,%d,1", id->id, 1 + dp->d_irq / 8);
if (dp->d_irq < 8)
fprintf(fp, ", al");
diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c
index 86654bfc104f..e135fc30736a 100644
--- a/usr.sbin/config/mkmakefile.c
+++ b/usr.sbin/config/mkmakefile.c
@@ -244,6 +244,10 @@ openit:
perror(fname);
exit(1);
}
+ if(ident == NULL) {
+ printf("no ident line specified\n");
+ exit(1);
+ }
next:
/*
* filename [ standard | optional ] [ config-dependent ]
diff --git a/usr.sbin/cron/cron.8 b/usr.sbin/cron/cron.8
index c89398663e0c..d96755ad0309 100644
--- a/usr.sbin/cron/cron.8
+++ b/usr.sbin/cron/cron.8
@@ -15,7 +15,7 @@
.\" * Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
.\" */
.\"
-.\" $Header: /home/cvs/386BSD/src/usr.sbin/cron/cron.8,v 1.1.2.1 1994/05/01 16:09:33 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/usr.sbin/cron/cron.8,v 1.1 1994/01/22 20:38:58 guido Exp $
.\"
.\" From Id: cron.8,v 2.2 1993/12/28 08:34:43 vixie Exp
.\"
diff --git a/usr.sbin/diskless_cfg/diskless.h b/usr.sbin/diskless_cfg/diskless.h
index 96d2a2d043e5..ef037279d5da 100644
--- a/usr.sbin/diskless_cfg/diskless.h
+++ b/usr.sbin/diskless_cfg/diskless.h
@@ -136,7 +136,7 @@ struct ifaliasreq {
*/
#define NFS_FHSIZE 32
-typedef struct { u_char f[NFS_FHSIZE] } nfsv2fh_t;
+typedef struct { u_char f[NFS_FHSIZE]; } nfsv2fh_t;
/*
* Arguments to mount NFS
*/
diff --git a/usr.sbin/diskless_cfg/diskless_cfg.c b/usr.sbin/diskless_cfg/diskless_cfg.c
index 3cf21379470f..7678ff54675f 100644
--- a/usr.sbin/diskless_cfg/diskless_cfg.c
+++ b/usr.sbin/diskless_cfg/diskless_cfg.c
@@ -18,6 +18,11 @@ Based loosely on the 4.4BSD diskless setup code
#include <rpc/types.h>
#include <sys/errno.h>
#include <nfs/nfs.h>
+#ifdef __SVR4
+/* Solaris: compile with -lbsm -lnsl -lsocket */
+#define getfh nfs_getfh
+#define bcopy(a,b,c) memcpy(b,a,c)
+#endif
#endif
#ifdef i386 /* Native 386bsd system */
@@ -50,6 +55,7 @@ struct nfs_diskless nfs_diskless;
#define KW_HOSTNAME 7
#define KW_KERNEL 8
#define KW_GATEWAY 9
+#define KW_SERVER 10
struct {
char *name;
@@ -63,11 +69,12 @@ struct {
{ "-wsize", KW_WSIZE },
{ "-hostname", KW_HOSTNAME },
{ "-gateway", KW_GATEWAY },
+ { "-server", KW_SERVER },
{ NULL, KW_HELP }
};
char *hostname = "386bsd";
-char *gateway = NULL;
+char gateway[256];
char cfg[64];
char *rootpath = "/var/386bsd";
char *swappath = "/var/swap/386bsd";
@@ -86,7 +93,7 @@ main(argc, argv)
char *p, *q;
netmask = 0;
- bzero(&nfs_diskless, 0, sizeof(struct nfs_diskless));
+ memset(&nfs_diskless, 0, sizeof(struct nfs_diskless));
strcpy(nfs_diskless.myif.ifra_name,"ed0");
nfs_diskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
nfs_diskless.myif.ifra_addr.sa_family = AF_INET;
@@ -107,24 +114,6 @@ main(argc, argv)
nfs_diskless.root_saddr.sa_len = sizeof(struct sockaddr);
nfs_diskless.root_saddr.sa_family = AF_INET;
- if (gethostname(servername, 256) < 0) {
- fprintf(stderr,"%s: unable to get host server name\n",argv[0]);
- exit(2);
- }
- if ((hp = gethostbyname(servername)) == NULL) {
- fprintf(stderr,"%s: unable to get host address\n",argv[0]);
- exit(2);
- }
- p = servername;
- while (*p && (*p != '.')) p++;
- *p = 0;
- nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0]
- = NFS_SOCKET >> 8;
- nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1]
- = NFS_SOCKET & 0x00FF;
- bcopy(*hp->h_addr_list, &nfs_diskless.swap_saddr.sa_data[2], 4);
- bcopy(*hp->h_addr_list, &nfs_diskless.root_saddr.sa_data[2], 4);
-
i = 1;
while (i < argc) {
cmd = KW_HELP;
@@ -174,28 +163,49 @@ main(argc, argv)
hostname = argv[i+1];
i += 2;
break;
+ case KW_SERVER:
+ strcpy(servername,argv[i+1]);
+ i += 2;
+ break;
case KW_GATEWAY:
- gateway = argv[i+1];
+ strcpy(gateway,argv[i+1]);
i += 2;
break;
}
}
- if(gateway)
- {
- if (gethostname(gateway, 256) < 0) {
- fprintf(stderr,"%s: unable to get gateway host name\n",argv[0]);
- exit(2);
- }
- if ((hp = gethostbyname(gateway)) == NULL) {
- fprintf(stderr,"%s: unable to get gateway host address\n",argv[0]);
- exit(2);
- }
- nfs_diskless.mygateway.sa_len = sizeof(struct sockaddr);
- nfs_diskless.mygateway.sa_family = AF_INET;
- nfs_diskless.mygateway.sa_data[0] = NFS_SOCKET >> 8;
- nfs_diskless.mygateway.sa_data[1] = NFS_SOCKET & 0x00FF;
- bcopy(*hp->h_addr_list, &nfs_diskless.mygateway.sa_data[2], 4);
+
+ if (!*servername && gethostname(servername, sizeof servername) < 0) {
+ fprintf(stderr,"%s: unable to get host server name\n",argv[0]);
+ exit(2);
+ }
+ if ((hp = gethostbyname(servername)) == NULL) {
+ fprintf(stderr,"%s: unable to get host address\n",argv[0]);
+ exit(2);
+ }
+ p = servername;
+ while (*p && (*p != '.')) p++;
+ *p = 0;
+ nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0]
+ = NFS_SOCKET >> 8;
+ nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1]
+ = NFS_SOCKET & 0x00FF;
+ bcopy(*hp->h_addr_list, &nfs_diskless.swap_saddr.sa_data[2], 4);
+ bcopy(*hp->h_addr_list, &nfs_diskless.root_saddr.sa_data[2], 4);
+
+ if (!*gateway && gethostname(gateway, sizeof gateway) < 0) {
+ fprintf(stderr,"%s: unable to get gateway host name\n",argv[0]);
+ exit(2);
}
+ if ((hp = gethostbyname(gateway)) == NULL) {
+ fprintf(stderr,"%s: unable to get gateway host address\n",argv[0]);
+ exit(2);
+ }
+ nfs_diskless.mygateway.sa_len = sizeof(struct sockaddr);
+ nfs_diskless.mygateway.sa_family = AF_INET;
+ nfs_diskless.mygateway.sa_data[0] = NFS_SOCKET >> 8;
+ nfs_diskless.mygateway.sa_data[1] = NFS_SOCKET & 0x00FF;
+ bcopy(*hp->h_addr_list, &nfs_diskless.mygateway.sa_data[2], 4);
+
nfs_diskless.swap_args.rsize = i386order(rsize);
nfs_diskless.swap_args.wsize = i386order(wsize);
nfs_diskless.root_args.rsize = i386order(rsize);
@@ -219,7 +229,7 @@ main(argc, argv)
bcopy(&broadcast, &nfs_diskless.myif.ifra_broadaddr.sa_data[2], 4);
bcopy(&netmask, &nfs_diskless.myif.ifra_mask.sa_data[2], 4);
if (stat(rootpath, &statbuf) < 0) {
- fprintf(stderr,"%s: unable to stat '%s'\n",
+ fprintf(stderr,"%s: unable to stat root '%s'\n",
argv[0],rootpath);
exit(2);
}
@@ -238,7 +248,7 @@ main(argc, argv)
strcpy(nfs_diskless.root_hostnam,buf);
printf("root is on %s\n",nfs_diskless.root_hostnam);
if (stat(swappath, &statbuf) < 0) {
- fprintf(stderr,"%s: unable to stat '%s'\n",
+ fprintf(stderr,"%s: unable to stat swap '%s'\n",
argv[0],swappath);
exit(2);
}
diff --git a/usr.sbin/fdcontrol/Makefile b/usr.sbin/fdcontrol/Makefile
new file mode 100644
index 000000000000..068cadeb782a
--- /dev/null
+++ b/usr.sbin/fdcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG = fdcontrol
+MAN8 = fdcontrol.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fdcontrol/fdcontrol.8 b/usr.sbin/fdcontrol/fdcontrol.8
new file mode 100644
index 000000000000..4c9f2872118c
--- /dev/null
+++ b/usr.sbin/fdcontrol/fdcontrol.8
@@ -0,0 +1,77 @@
+.\"
+.\" Copyright (C) 1994 by Joerg Wunsch, Dresden
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+.\"
+.Dd May 22, 1994
+.Os
+.Dt FDCONTROL 8
+.Sh NAME
+.Nm fdcontrol
+.Nd modify floppy disk parameters
+.Sh SYNOPSIS
+.Nm fdcontrol
+.Ar device
+.Sh DESCRIPTION
+.Nm Fdcontrol
+allows the specification of device parameters for the floppy disk at
+.Ar device .
+.Ar Device
+should be a character device.
+
+Since the implications of such a specification are considered harmful,
+the underlying
+.Xr ioctl 2
+command is restricted to the super-user.
+
+The command asks the user for each individual tunable parameter,
+defaulting to the currently used value.
+
+.Sh DIAGNOSTICS
+Error codes for the underlying
+.Xr ioctl 2
+commands are printed by the
+.Xr perror 3
+facility.
+
+.Sh BUGS
+The
+.Nm
+command is currently under development. It's user interface is rather
+silly and likely to change in future, options should be provided to
+allow anything being modified from the command line.
+
+.Sh SEE ALSO
+.Xr fd 4 ,
+.Xr ioctl 2 ,
+.Xr perror 3 .
+.Sh HISTORY
+.Nm Fdcontrol
+is currently under development. It's user interface and overall
+functionality are subjects to future improvements and changes.
+.Sh AUTHOR
+The program has been contributed by
+.if n Joerg Wunsch,
+.if t J\(:org Wunsch,
+Dresden.
diff --git a/usr.sbin/fdcontrol/fdcontrol.c b/usr.sbin/fdcontrol/fdcontrol.c
new file mode 100644
index 000000000000..91011a4a67f6
--- /dev/null
+++ b/usr.sbin/fdcontrol/fdcontrol.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1994 by Joerg Wunsch, Dresden
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <machine/ioctl_fd.h>
+#include <sys/file.h>
+
+int
+getnumber(void)
+{
+ int i;
+ char b[80];
+
+ fgets(b, 80, stdin);
+ if(b[0] == '\n') return -1;
+
+ sscanf(b, " %i", &i);
+ return i;
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: fdcontrol device-node\n");
+ exit(2);
+}
+
+
+#define ask(name, fmt) \
+printf(#name "? [" fmt "]: ", ft.name); fflush(stdout); \
+if((i = getnumber()) != -1) ft.name = i
+
+int
+main(int argc, char **argv)
+{
+ struct fd_type ft;
+ int fd, i;
+
+ if(argc != 2)
+ usage();
+
+ if((fd = open(argv[1], 0)) < 0)
+ {
+ perror("open(floppy)");
+ return 1;
+ }
+
+ if(ioctl(fd, FD_GTYPE, &ft) < 0)
+ {
+ perror("ioctl(FD_GTYPE)");
+ return 1;
+ }
+
+ ask(sectrac, "%d");
+ ask(secsize, "%d");
+ ask(datalen, "0x%x");
+ ask(gap, "0x%x");
+ ask(tracks, "%d");
+ ask(size, "%d");
+ ask(steptrac, "%d");
+ ask(trans, "%d");
+ ask(heads, "%d");
+ ask(f_gap, "0x%x");
+ ask(f_inter, "%d");
+
+ if(ioctl(fd, FD_STYPE, &ft) < 0)
+ {
+ perror("ioctl(FD_STYPE)");
+ return 1;
+ }
+ return 0;
+}
+
+
+
diff --git a/usr.sbin/fdformat/Makefile b/usr.sbin/fdformat/Makefile
index 209af72d124d..3ee3b4debeec 100644
--- a/usr.sbin/fdformat/Makefile
+++ b/usr.sbin/fdformat/Makefile
@@ -1,32 +1,9 @@
-# Copyright (C) 1993 by Joerg Wunsch, Dresden
-# 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.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
#
PROG = fdformat
# the -I's seem to be confusing, but necessery this way
# (so the right <unistd.h> will be found in /usr/include, and the
# "../i386/isa/ic/nec765.h" included from fdreg.h is accessible, too)
-CFLAGS+=-Wall -I/usr/include -I/sys/sys
+CFLAGS+= -Wall -I/usr/include -I/sys/sys
.include <bsd.prog.mk>
diff --git a/usr.sbin/fdformat/fdformat.1 b/usr.sbin/fdformat/fdformat.1
index 78a6b133340c..2b27f7f5ead7 100644
--- a/usr.sbin/fdformat/fdformat.1
+++ b/usr.sbin/fdformat/fdformat.1
@@ -10,20 +10,20 @@
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
.\"
.Dd September 16, 1993
-.Os FreeBSD
+.Os
.Dt FDFORMAT 1
.Sh NAME
.Nm fdformat
@@ -57,7 +57,7 @@ or default name in an abbreviated form
.Pq e.\ g. Em fd0 .
In the latter case, the name is constructed by prepending
.Pa /dev/r
-and appending an
+and appending a
.Em .capacity
to the
.Ar device_name .
diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c
index b88a8ea7618d..6ab7d94ff96f 100644
--- a/usr.sbin/fdformat/fdformat.c
+++ b/usr.sbin/fdformat/fdformat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1992-1993 by Joerg Wunsch, Dresden
+ * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,17 +11,17 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
*/
/*
@@ -90,7 +90,16 @@ verify_track(int fd, int track, int tracksize)
{
static char *buf = 0;
static int bufsz = 0;
-
+ int fdopts = -1, ofdopts, rv = 0;
+
+ if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
+ perror("warning: ioctl(FD_GOPTS)");
+ else {
+ ofdopts = fdopts;
+ fdopts |= FDOPT_NORETRY;
+ (void)ioctl(fd, FD_SOPTS, &fdopts);
+ }
+
if (bufsz < tracksize) {
if (buf)
free (buf);
@@ -104,10 +113,14 @@ verify_track(int fd, int track, int tracksize)
exit (2);
}
if (lseek (fd, (long) track*tracksize, 0) < 0)
- return (-1);
- if (read (fd, buf, tracksize) != tracksize)
- return (-1);
- return (0);
+ rv = -1;
+ /* try twice reading it, without using the normal retrier */
+ else if (read (fd, buf, tracksize) != tracksize
+ && read (fd, buf, tracksize) != tracksize)
+ rv = -1;
+ if(fdopts != -1)
+ (void)ioctl(fd, FD_SOPTS, &ofdopts);
+ return (rv);
}
static const char *
@@ -127,7 +140,7 @@ makename(const char *arg, const char *suffix)
}
static void
-usage ()
+usage (void)
{
printf("Usage:\n\tfdformat [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]\n");
printf("\t\t [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname\n");
@@ -152,7 +165,7 @@ usage ()
}
static int
-yes ()
+yes (void)
{
char reply [256], *p;
@@ -353,3 +366,18 @@ main(int argc, char **argv)
return errs;
}
+/*
+ * Local Variables:
+ * c-indent-level: 8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * c-brace-offset: -8
+ * c-brace-imaginary-offset: 0
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c++-hanging-braces: 1
+ * c++-access-specifier-offset: -8
+ * c++-empty-arglist-indent: 8
+ * c++-friend-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/flcopy/Makefile b/usr.sbin/flcopy/Makefile
deleted file mode 100644
index 2cfc59848c66..000000000000
--- a/usr.sbin/flcopy/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# @(#)Makefile 5.2 (Berkeley) 1/20/91
-
-PROG= flcopy
-MANSUBDIR=/vax
-MAN8= flcopy.8
-
-.include <bsd.prog.mk>
diff --git a/usr.sbin/flcopy/flcopy.8 b/usr.sbin/flcopy/flcopy.8
deleted file mode 100644
index 1cc14ccd9c80..000000000000
--- a/usr.sbin/flcopy/flcopy.8
+++ /dev/null
@@ -1,83 +0,0 @@
-.\" Copyright (c) 1980 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.
-.\"
-.\" @(#)flcopy.8 5.2 (Berkeley) 4/20/91
-.\"
-.TH FLCOPY 8 "April 20, 1991"
-.UC 4
-.SH NAME
-flcopy \- floppy copy
-.SH SYNOPSIS
-.nf
-.ft B
-flcopy [ \-hr ] [ \-f file ] [ \-t ntracks ]
-.ft R
-.fi
-.SH DESCRIPTION
-.I Flcopy
-copies the console floppy disk (``/dev/floppy'') to a file in the
-current directory, named ``floppy''.
-The user is then prompted to change the floppy, and enter a carriage
-return when done.
-When a carriage return is entered,
-.I flcopy
-copies the file out to the floppy disk.
-.PP
-The options are as follows:
-.TP
-\-f
-Use
-.I file
-instead of ``/dev/floppy''.
-.TP
--h
-Cause
-.I flcopy
-to copy a file named ``floppy'' in the current directory to
-the console floppy disk.
-.TP
-\-r
-Cause
-.I flcopy
-to copy the floppy to the current directory and then quit.
-.TP
-\-t
-Copy only the first
-.I ntracks
-tracks.
-.SH FILES
-floppy temporary file name
-.br
-/dev/floppy default floppy device
-.SH SEE ALSO
-crl(4), fl(4), rx(4), tu(4), arff(8), rxformat(8)
-.SH BUGS
-Device errors are handled ungracefully.
diff --git a/usr.sbin/flcopy/flcopy.c b/usr.sbin/flcopy/flcopy.c
deleted file mode 100644
index d1a2e35ff043..000000000000
--- a/usr.sbin/flcopy/flcopy.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
- All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)flcopy.c 5.4 (Berkeley) 1/20/91";
-#endif /* not lint */
-
-#include <sys/file.h>
-#include <stdio.h>
-#include "pathnames.h"
-
-int floppydes;
-char *flopname = _PATH_FLOPPY;
-long dsize = 77 * 26 * 128;
-int hflag;
-int rflag;
-
-main(argc, argv)
- register char **argv;
-{
- extern char *optarg;
- extern int optind;
- static char buff[512];
- register long count;
- register startad = -26 * 128;
- register int n, file;
- register char *cp;
- int ch;
-
- while ((ch = getopt(argc, argv, "f:hrt:")) != EOF)
- switch(ch) {
- case 'f':
- flopname = optarg;
- break;
- case 'h':
- hflag = 1;
- printf("Halftime!\n");
- if ((file = open("floppy", 0)) < 0) {
- printf("can't open \"floppy\"\n");
- exit(1);
- }
- break;
- case 'r':
- rflag = 1;
- break;
- case 't':
- dsize = atoi(optarg);
- if (dsize <= 0 || dsize > 77) {
- (void)fprintf(stderr,
- "flcopy: bad number of tracks (0 - 77).\n");
- exit(2);
- }
- dsize *= 26 * 128;
- break;
- case '?':
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (!hflag) {
- file = open("floppy", O_RDWR|O_CREAT|O_TRUNC, 0666);
- if (file < 0) {
- printf("can't open \"floppy\"\n");
- exit(1);
- }
- for (count = dsize; count > 0 ; count -= 512) {
- n = count > 512 ? 512 : count;
- lread(startad, n, buff);
- write(file, buff, n);
- startad += 512;
- }
- }
- if (rflag)
- exit(0);
- printf("Change Floppy, Hit return when done.\n");
- gets(buff);
- lseek(file, 0, 0);
- count = dsize;
- startad = -26 * 128;
- for ( ; count > 0 ; count -= 512) {
- n = count > 512 ? 512 : count;
- read(file, buff, n);
- lwrite(startad, n, buff);
- startad += 512;
- }
- exit(0);
-}
-
-rt_init()
-{
- static initized = 0;
- int mode = 2;
-
- if (initized)
- return;
- if (rflag)
- mode = 0;
- initized = 1;
- if ((floppydes = open(flopname, mode)) < 0) {
- printf("Floppy open failed\n");
- exit(1);
- }
-}
-
-/*
- * Logical to physical adress translation
- */
-long
-trans(logical)
- register int logical;
-{
- register int sector, bytes, track;
-
- logical += 26 * 128;
- bytes = (logical & 127);
- logical >>= 7;
- sector = logical % 26;
- if (sector >= 13)
- sector = sector*2 +1;
- else
- sector *= 2;
- sector += 26 + ((track = (logical / 26)) - 1) * 6;
- sector %= 26;
- return ((((track *26) + sector) << 7) + bytes);
-}
-
-lread(startad, count, obuff)
- register startad, count;
- register char *obuff;
-{
- long trans();
- extern floppydes;
-
- rt_init();
- while ((count -= 128) >= 0) {
- lseek(floppydes, trans(startad), 0);
- read(floppydes, obuff, 128);
- obuff += 128;
- startad += 128;
- }
-}
-
-lwrite(startad, count, obuff)
- register startad, count;
- register char *obuff;
-{
- long trans();
- extern floppydes;
-
- rt_init();
- while ((count -= 128) >= 0) {
- lseek(floppydes, trans(startad), 0);
- write(floppydes, obuff, 128);
- obuff += 128;
- startad += 128;
- }
-}
-
-usage()
-{
- (void)fprintf(stderr, "usage: flcopy [-hr] [-f file] [-t ntracks]\n");
- exit(1);
-}
diff --git a/usr.sbin/kbdcontrol/Makefile b/usr.sbin/kbdcontrol/Makefile
new file mode 100644
index 000000000000..da1a23380674
--- /dev/null
+++ b/usr.sbin/kbdcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG= kbdcontrol
+SRCS= kbdcontrol.c lex.l
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.1 b/usr.sbin/kbdcontrol/kbdcontrol.1
new file mode 100644
index 000000000000..645103675f4e
--- /dev/null
+++ b/usr.sbin/kbdcontrol/kbdcontrol.1
@@ -0,0 +1,77 @@
+.\"
+.\" kbdcontrol - a utility for manipulating the syscons keyboard driver section
+.\"
+.\" 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.
+.\"
+.\" @(#)kbdcontrol.1
+.\"
+.TH kbdcontrol 1 "May 22, 1994" "" "FreeBSD"
+
+.SH NAME
+kbdcontrol - a utility for manipulating the syscons keyboard driver section.
+.SH SYNOPSIS
+.na
+.B kbdcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B kbdcontrol
+command is used to set various keyboard related options for the syscons
+console driver, such as keymap, keyboard repeat & delay rates, bell
+characteristics etc.
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.BI "\-b\ " [ duration.pitch ]
+Set the bell duration and pitch values.
+.TP
+.BI "\-r\ " [ delay.repeat | slow | fast | normal ]
+Set keyboard
+.I delay
+and
+.I repeat
+rates, or use presets for
+.I slow,
+.I fast
+or
+.I normal.
+.TP
+.BI "\-l\ " mapfile
+Install keyboard map file from
+.I mapfile
+.TP
+.BI "\-d\ "
+Dump the current keyboard map onto stdout
+.TP
+.BI "\-f\ " #\ string
+Set function key number
+.I #
+to send
+.I string
+.
+.TP
+.BI "\-F\ "
+Set function keys back to the standard definitions.
+.TP
+.B \-v
+Turns on verbose output.
+.PP
+.SH FILES
+/usr/share/syscons/keymaps
+.SH "BUGS"
+Report when found.
+.SH "SEE ALSO"
+.BR vidcontrol (1) ,
+.BR keyboard (4) ,
+.BR screen (4) ,
+.BR /sys/i386/conf/SYSCONS
+.SH AUTHORS
+Søren Schmidt (sos@login.dkuug.dk)
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c
new file mode 100644
index 000000000000..cda976b203c2
--- /dev/null
+++ b/usr.sbin/kbdcontrol/kbdcontrol.c
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: kbdcontrol.c,v 1.1 1994/05/20 12:18:05 sos Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include "path.h"
+#include "lex.h"
+
+char ctrl_names[32][4] = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns "
+ };
+
+char fkey_table[60][MAXFK] = {
+/* 00-03 */ "\033[M", "\033[N", "\033[O", "\033[P",
+/* 04-07 */ "\033[Q", "\033[R", "\033[S", "\033[T",
+/* 08-0B */ "\033[U", "\033[V", "\033[W", "\033[X",
+/* 0C-0F */ "\033[W", "\033[X", "\033[Y", "\033[Z",
+/* 10-13 */ "\033[a", "\033[b", "\033[c", "\033[d",
+/* 14-17 */ "\033[e", "\033[f", "\033[g", "\033[h",
+/* 18-1B */ "\033[g", "\033[h", "\033[i", "\033[j",
+/* 1C-1F */ "\033[k", "\033[l", "\033[m", "\033[n",
+/* 20-23 */ "\033[o", "\033[p", "\033[q", "\033[r",
+/* 24-27 */ "\033[g", "\033[h", "\033[i", "\033[j",
+/* 28-2B */ "\033[k", "\033[l", "\033[m", "\033[n",
+/* 2C-2F */ "\033[o", "\033[p", "\033[q", "\033[r",
+/* 30-33 */ "\033[H", "\033[A", "\033[I", "-" ,
+/* 34-37 */ "\033[D", "\177" , "\033[C", "+" ,
+/* 38-3B */ "\033[F", "\033[B", "\033[G", "\033[L"
+ };
+
+const int delays[] = {250, 500, 750, 1000};
+const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63,
+ 68, 76, 84, 92, 100, 110, 118, 126,
+ 136, 152, 168, 184, 200, 220, 236, 252,
+ 272, 304, 336, 368, 400, 440, 472, 504};
+const int ndelays = (sizeof(delays) / sizeof(int));
+const int nrepeats = (sizeof(repeats) / sizeof(int));
+int hex = 0;
+int number, verbose = 0;
+char letter;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+ if (*indp < ac)
+ return(av[(*indp)++]);
+ fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+ usage();
+ exit(1);
+ return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char *buf = NULL;
+static int bufl = 0;
+int f;
+
+
+ f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+ if (f > bufl)
+ if (buf)
+ buf = (char *)realloc(buf, f);
+ else
+ buf = (char *)malloc(f);
+ if (!buf) {
+ bufl = 0;
+ return(NULL);
+ }
+
+ bufl = f;
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ strcat(buf, s3);
+ return(buf);
+}
+
+
+int
+get_entry()
+{
+ switch (yylex()) {
+ case TNOP:
+ return NOP | 0x100;
+ case TLSH:
+ return LSH | 0x100;
+ case TRSH:
+ return RSH | 0x100;
+ case TCLK:
+ return CLK | 0x100;
+ case TNLK:
+ return NLK | 0x100;
+ case TSLK:
+ return SLK | 0x100;
+ case TBTAB:
+ return BTAB | 0x100;
+ case TLALT:
+ return LALT | 0x100;
+ case TLCTR:
+ return LCTR | 0x100;
+ case TNEXT:
+ return NEXT | 0x100;
+ case TRCTR:
+ return RCTR | 0x100;
+ case TRALT:
+ return RALT | 0x100;
+ case TALK:
+ return ALK | 0x100;
+ case TASH:
+ return ASH | 0x100;
+ case TMETA:
+ return META | 0x100;
+ case TRBT:
+ return RBT | 0x100;
+ case TDBG:
+ return DBG | 0x100;
+ case TFUNC:
+ if (F(number) > L_FN)
+ return -1;
+ return F(number) | 0x100;
+ case TSCRN:
+ if (S(number) > L_SCR)
+ return -1;
+ return S(number) | 0x100;
+ case TLET:
+ return (unsigned char)letter;
+ case TNUM:
+ if (number < 0 || number > 255)
+ return -1;
+ return number;
+ default:
+ return -1;
+ }
+}
+
+
+int
+get_key_definition_line(FILE* fd, keymap_t *map)
+{
+ int i, def, scancode;
+
+ yyin = fd;
+
+ /* get scancode number */
+ if (yylex() != TNUM)
+ return -1;
+ if (number < 0 || number >= NUM_KEYS)
+ return -1;
+ scancode = number;
+
+ /* get key definitions */
+ map->key[scancode].spcl = 0;
+ for (i=0; i<NUM_STATES; i++) {
+ if ((def = get_entry()) == -1)
+ return -1;
+ if (def & 0x100)
+ map->key[scancode].spcl |= (0x80 >> i);
+ map->key[scancode].map[i] = def & 0xFF;
+ }
+ /* get lock state key def */
+ if (yylex() != TFLAG)
+ return -1;
+ map->key[scancode].flgs = number;
+ return scancode;
+}
+
+
+int
+print_entry(FILE *fp, int value)
+{
+ int val = value & 0xFF;
+
+ switch (value) {
+ case NOP | 0x100:
+ fprintf(fp, " nop ");
+ break;
+ case LSH | 0x100:
+ fprintf(fp, " lshift");
+ break;
+ case RSH | 0x100:
+ fprintf(fp, " rshift");
+ break;
+ case CLK | 0x100:
+ fprintf(fp, " clock ");
+ break;
+ case NLK | 0x100:
+ fprintf(fp, " nlock ");
+ break;
+ case SLK | 0x100:
+ fprintf(fp, " slock ");
+ break;
+ case BTAB | 0x100:
+ fprintf(fp, " btab ");
+ break;
+ case LALT | 0x100:
+ fprintf(fp, " lalt ");
+ break;
+ case LCTR | 0x100:
+ fprintf(fp, " lctrl ");
+ break;
+ case NEXT | 0x100:
+ fprintf(fp, " nscr ");
+ break;
+ case RCTR | 0x100:
+ fprintf(fp, " rctrl ");
+ break;
+ case RALT | 0x100:
+ fprintf(fp, " ralt ");
+ break;
+ case ALK | 0x100:
+ fprintf(fp, " alock ");
+ break;
+ case ASH | 0x100:
+ fprintf(fp, " ashift");
+ break;
+ case META | 0x100:
+ fprintf(fp, " meta ");
+ break;
+ case RBT | 0x100:
+ fprintf(fp, " boot ");
+ break;
+ case DBG | 0x100:
+ fprintf(fp, " debug ");
+ break;
+ default:
+ if (value & 0x100) {
+ if (val >= F_FN && val <= L_FN)
+ fprintf(fp, " fkey%02d", val - F_FN + 1);
+ else if (val >= F_SCR && val <= L_SCR)
+ fprintf(fp, " scr%02d ", val - F_SCR + 1);
+ else if (hex)
+ fprintf(fp, " 0x%02x ", val);
+ else
+ fprintf(fp, " %3d ", val);
+ }
+ else {
+ if (val < ' ')
+ fprintf(fp, " %s ", ctrl_names[val]);
+ else if (val == 127)
+ fprintf(fp, " del ");
+ else if (isprint(val))
+ fprintf(fp, " '%c' ", val);
+ else if (hex)
+ fprintf(fp, " 0x%02x ", val);
+ else
+ fprintf(fp, " %3d ", val);
+ }
+ }
+}
+
+
+void
+print_key_definition_line(FILE *fp, int scancode, struct key_t *key)
+{
+ int i, value;
+
+ /* print scancode number */
+ if (hex)
+ fprintf(fp, " 0x%02x ", scancode);
+ else
+ fprintf(fp, " %03d ", scancode);
+
+ /* print key definitions */
+ for (i=0; i<NUM_STATES; i++) {
+ if (key->spcl & (0x80 >> i))
+ print_entry(fp, key->map[i] | 0x100);
+ else
+ print_entry(fp, key->map[i]);
+ }
+
+ /* print lock state key def */
+ switch (key->flgs) {
+ case 0:
+ fprintf(fp, " O\n");
+ break;
+ case 1:
+ fprintf(fp, " C\n");
+ break;
+ case 2:
+ fprintf(fp, " N\n");
+ break;
+ }
+}
+
+
+void
+load_keymap(char *opt)
+{
+ keymap_t map;
+ FILE *fd;
+ int scancode, i;
+ char *name;
+ char *prefix[] = {"", "", KEYMAP_PATH, NULL};
+ char *postfix[] = {"", ".kbd", ".kbd"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], opt, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("keymap file not found");
+ return;
+ }
+ memset(map, 0, sizeof(map));
+ while (1) {
+ if ((scancode = get_key_definition_line(fd, &map)) < 0)
+ break;
+ if (scancode > map.n_keys) map.n_keys = scancode;
+ }
+ if (ioctl(0, PIO_KEYMAP, &map) < 0) {
+ perror("setting keymap");
+ fclose(fd);
+ return;
+ }
+}
+
+
+void
+print_keymap()
+{
+ keymap_t map;
+ int i;
+
+ if (ioctl(0, GIO_KEYMAP, &map) < 0) {
+ perror("getting keymap");
+ exit(1);
+ }
+ printf(
+"# alt\n"
+"# scan cntrl alt alt cntrl lock\n"
+"# code base shift cntrl shift alt shift cntrl shift state\n"
+"# ------------------------------------------------------------------\n"
+ );
+ for (i=0; i<map.n_keys; i++)
+ print_key_definition_line(stdout, i, &map.key[i]);
+}
+
+
+void
+load_default_functionkeys()
+{
+ fkeyarg_t fkey;
+ int i;
+
+ for (i=0; i<NUM_FKEYS; i++) {
+ fkey.keynum = i;
+ strcpy(fkey.keydef, fkey_table[i]);
+ fkey.flen = strlen(fkey_table[i]);
+ if (ioctl(0, SETFKEY, &fkey) < 0)
+ perror("setting function key");
+ }
+}
+
+void
+set_functionkey(char *keynumstr, char *string)
+{
+ fkeyarg_t fkey;
+ int keynum;
+
+ if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
+ load_default_functionkeys();
+ return;
+ }
+ fkey.keynum = atoi(keynumstr);
+ if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
+ fprintf(stderr,
+ "function key number must be between 1 and %d\n",
+ NUM_FKEYS);
+ return;
+ }
+ if ((fkey.flen = strlen(string)) > MAXFK) {
+ fprintf(stderr, "function key string too long (%d > %d)\n",
+ fkey.flen, MAXFK);
+ return;
+ }
+ strcpy(fkey.keydef, string);
+ if (verbose)
+ fprintf(stderr, "setting function key %d to <%s>\n",
+ fkey.keynum, fkey.keydef);
+ fkey.keynum -= 1;
+ if (ioctl(0, SETFKEY, &fkey) < 0)
+ perror("setting function key");
+}
+
+
+void
+set_bell_values(char *opt)
+{
+ int duration, pitch;
+
+ if (!strcmp(opt, "normal"))
+ duration = 1, pitch = 15;
+ else {
+ int n;
+ char *v1;
+
+ duration = strtol(opt, &v1, 0);
+ if ((duration < 0) || (*v1 != '.'))
+ goto badopt;
+ opt = ++v1;
+ pitch = strtol(opt, &v1, 0);
+ if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -b must be DURATION.PITCH\n");
+ return;
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "setting bell values to %d.%d\n",
+ duration, pitch);
+ fprintf(stderr, "[=%d;%dB", pitch, duration);
+}
+
+
+void
+set_keyrates(char *opt)
+{
+struct {
+ int rep:5;
+ int del:2;
+ int pad:1;
+ }rate;
+
+ if (!strcmp(opt, "slow"))
+ rate.del = 3, rate.rep = 31;
+ else if (!strcmp(opt, "normal"))
+ rate.del = 1, rate.rep = 15;
+ else if (!strcmp(opt, "fast"))
+ rate.del = rate.rep = 0;
+ else {
+ int n;
+ int delay, repeat;
+ char *v1;
+
+ delay = strtol(opt, &v1, 0);
+ if ((delay < 0) || (*v1 != '.'))
+ goto badopt;
+ opt = ++v1;
+ repeat = strtol(opt, &v1, 0);
+ if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -r must be delay.repeat\n");
+ return;
+ }
+ for (n = 0; n < ndelays - 1; n++)
+ if (delay <= delays[n])
+ break;
+ rate.del = n;
+ for (n = 0; n < nrepeats - 1; n++)
+ if (repeat <= repeats[n])
+ break;
+ rate.rep = n;
+ }
+
+ if (verbose)
+ fprintf(stderr, "setting keyboard rate to %d.%d\n",
+ delays[rate.del], repeats[rate.rep]);
+ if (ioctl(0, KDSETRAD, rate) < 0)
+ perror("setting keyboard rate");
+}
+
+
+usage()
+{
+ fprintf(stderr,
+"Usage: kbdcontrol -b duration.pitch (set bell duration & pitch)\n"
+" -d (dump keyboard map to stdout)\n"
+" -l filename (load keyboard map file)\n"
+" -f <N> string (set function key N to send <string>)\n"
+" -F (set function keys back to default)\n"
+" -r delay.repeat (set keyboard delay & repeat rate)\n"
+" -r slow (set keyboard delay & repeat to slow)\n"
+" -r normal (set keyboard delay & repeat to normal)\n"
+" -r fast (set keyboard delay & repeat to fast)\n"
+" -v (verbose)\n"
+ );
+}
+
+
+void
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+
+ /*
+ if (!is_syscons(0))
+ exit(1);
+ */
+ while((opt = getopt(argc, argv, "b:df:Fl:r:vx")) != -1)
+ switch(opt) {
+ case 'b':
+ set_bell_values(optarg);
+ break;
+ case 'd':
+ print_keymap();
+ break;
+ case 'l':
+ load_keymap(optarg);
+ break;
+ case 'f':
+ set_functionkey(optarg,
+ nextarg(argc, argv, &optind, 'f'));
+ break;
+ case 'F':
+ load_default_functionkeys();
+ break;
+ case 'r':
+ set_keyrates(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ hex = 1;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ if ((optind != argc) || (argc == 1)) {
+ usage();
+ exit(1);
+ }
+ exit(0);
+}
+
+
diff --git a/usr.sbin/kbdcontrol/lex.h b/usr.sbin/kbdcontrol/lex.h
new file mode 100644
index 000000000000..feff74009f95
--- /dev/null
+++ b/usr.sbin/kbdcontrol/lex.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: lex.h,v 1.1 1994/05/20 12:18:06 sos Exp $
+ */
+
+#define TNOP 256
+#define TLSH 257
+#define TRSH 258
+#define TCLK 259
+#define TNLK 260
+#define TSLK 261
+#define TLALT 262
+#define TLCTR 263
+#define TNEXT 264
+#define TRCTR 265
+#define TRALT 266
+#define TALK 267
+#define TASH 268
+#define TMETA 269
+#define TRBT 270
+#define TDBG 271
+#define TFUNC 272
+#define TSCRN 273
+#define TLET 274
+#define TNUM 275
+#define TFLAG 276
+#define TBTAB 277
+
+extern int number;
+extern char letter;
+extern FILE *yyin;
diff --git a/usr.sbin/kbdcontrol/lex.l b/usr.sbin/kbdcontrol/lex.l
new file mode 100644
index 000000000000..0729af70f161
--- /dev/null
+++ b/usr.sbin/kbdcontrol/lex.l
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: lex.l,v 1.1 1994/05/20 12:18:08 sos Exp $
+ */
+
+%{
+
+#include "lex.h"
+
+%}
+
+D [0-9]
+X [0-9a-fA-F]
+A .
+L [OCN]
+
+%%
+
+nop { return TNOP; }
+lshift { return TLSH; }
+rshift { return TRSH; }
+clock { return TCLK; }
+nlock { return TNLK; }
+slock { return TSLK; }
+lalt|alt { return TLALT; }
+btab { return TBTAB; }
+lctrl|ctrl { return TLCTR; }
+nscr { return TNEXT; }
+rctrl { return TRCTR; }
+ralt { return TRALT; }
+alock { return TALK; }
+ashift { return TASH; }
+meta { return TMETA; }
+boot { return TRBT; }
+debug { return TDBG; }
+
+NUL|nul { number = 0; return TNUM; }
+SOH|soh { number = 1; return TNUM; }
+STX|stx { number = 2; return TNUM; }
+ETX|etx { number = 3; return TNUM; }
+EOT|eot { number = 4; return TNUM; }
+ENQ|enq { number = 5; return TNUM; }
+ACK|ack { number = 6; return TNUM; }
+BEL|bel { number = 7; return TNUM; }
+BS|bs { number = 8; return TNUM; }
+HT|ht { number = 9; return TNUM; }
+LF|lf|NL|nl { number = 10; return TNUM; }
+VT|vt { number = 11; return TNUM; }
+FF|ff|NP|np { number = 12; return TNUM; }
+CR|cr { number = 13; return TNUM; }
+SO|so { number = 14; return TNUM; }
+SI|si { number = 15; return TNUM; }
+DLE|dle { number = 16; return TNUM; }
+DC1|dc1 { number = 17; return TNUM; }
+DC2|dc2 { number = 18; return TNUM; }
+DC3|dc3 { number = 19; return TNUM; }
+DC4|dc4 { number = 20; return TNUM; }
+NAK|nak { number = 21; return TNUM; }
+SYN|syn { number = 22; return TNUM; }
+ETB|etb { number = 23; return TNUM; }
+CAN|can { number = 24; return TNUM; }
+EM|em { number = 25; return TNUM; }
+SUB|sub { number = 26; return TNUM; }
+ESC|esc { number = 27; return TNUM; }
+FS|fs { number = 28; return TNUM; }
+GS|gs { number = 29; return TNUM; }
+RS|rs { number = 30; return TNUM; }
+NS|ns { number = 31; return TNUM; }
+SP|sp { number = 32; return TNUM; }
+DEL|del { number = 127; return TNUM; }
+
+fkey{D}({D}*) {
+ sscanf(yytext+4, "%d", &number);
+ return TFUNC;
+ }
+scr{D}({D}*) {
+ sscanf(yytext+3, "%d", &number);
+ return TSCRN;
+ }
+'{A}' { letter = *(yytext+1); return TLET; }
+#({A}*) { /* ignore */ }
+0x{X}({X}*) { sscanf(yytext, "%x", &number); return TNUM; }
+{D}({D}*) { sscanf(yytext, "%d", &number); return TNUM; }
+{L} {
+ if (*yytext == 'O') number = 0;
+ if (*yytext == 'C') number = 1;
+ if (*yytext == 'N') number = 2;
+ return TFLAG;
+ }
+[ \t\n] { /* ignore */ }
diff --git a/usr.sbin/kbdcontrol/path.h b/usr.sbin/kbdcontrol/path.h
new file mode 100644
index 000000000000..709acbc375dc
--- /dev/null
+++ b/usr.sbin/kbdcontrol/path.h
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
+#define FONT_PATH "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/kvm_mkdb/nlist.c b/usr.sbin/kvm_mkdb/nlist.c
index f2ee8a1999b1..622e0d99edf0 100644
--- a/usr.sbin/kvm_mkdb/nlist.c
+++ b/usr.sbin/kvm_mkdb/nlist.c
@@ -122,58 +122,6 @@ create_knlist(name, db)
if ((db->put)(db, &key, &data, 0))
error("put");
- if (!strncmp((char *)key.data, VRS_SYM, sizeof(VRS_SYM) - 1)) {
- off_t cur_off, rel_off, vers_off;
-
- /* Offset relative to start of text image in VM. */
-#ifdef hp300
- rel_off = nbuf.n_value;
-#endif
-#ifdef tahoe
- /*
- * On tahoe, first 0x800 is reserved for communication
- * with the console processor.
- */
- rel_off = ((nbuf.n_value & ~KERNBASE) - 0x800);
-#endif
-#ifdef vax
- rel_off = nbuf.n_value & ~KERNBASE;
-#endif
-#ifdef i386
- rel_off = nbuf.n_value - ebuf.a_entry + CLBYTES;
-#endif
- /*
- * When loaded, data is rounded to next page cluster
- * after text, but not in file.
- */
- rel_off -= CLBYTES - (ebuf.a_text % CLBYTES);
- vers_off = N_TXTOFF(ebuf) + rel_off;
-
- cur_off = ftell(fp);
- if (fseek(fp, vers_off, SEEK_SET) == -1)
- badfmt("corrupted string table");
-
- /*
- * Read version string up to, and including newline.
- * This code assumes that a newline terminates the
- * version line.
- */
- if (fgets(buf, sizeof(buf), fp) == NULL)
- badfmt("corrupted string table");
-
- key.data = (u_char *)VRS_KEY;
- key.size = sizeof(VRS_KEY) - 1;
- data.data = (u_char *)buf;
- data.size = strlen(buf);
- if ((db->put)(db, &key, &data, 0))
- error("put");
-
- /* Restore to original values. */
- data.data = (u_char *)&nbuf;
- data.size = sizeof(NLIST);
- if (fseek(fp, cur_off, SEEK_SET) == -1)
- badfmt("corrupted string table");
- }
}
(void)fclose(fp);
}
diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c
index 0fe755dec16f..05339b640e16 100644
--- a/usr.sbin/lpr/common_source/common.c
+++ b/usr.sbin/lpr/common_source/common.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: common.c,v 1.1.1.1.2.1 1994/05/04 08:01:55 rgrimes Exp $
+ * $Id: common.c,v 1.2 1994/05/04 08:37:15 rgrimes Exp $
*/
/*
* Copyright (c) 1983 Regents of the University of California.
diff --git a/usr.sbin/lpr/lpr/lpr.c b/usr.sbin/lpr/lpr/lpr.c
index eca1fb43e2db..9abe1c980bc9 100644
--- a/usr.sbin/lpr/lpr/lpr.c
+++ b/usr.sbin/lpr/lpr/lpr.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: lpr.c,v 1.1.1.1.2.2 1994/05/04 08:02:12 rgrimes Exp $
+ * $Id: lpr.c,v 1.3 1994/05/04 08:37:28 rgrimes Exp $
*/
/*
* Copyright (c) 1983 Regents of the University of California.
diff --git a/usr.sbin/lptcontrol/Makefile b/usr.sbin/lptcontrol/Makefile
new file mode 100644
index 000000000000..e685c02febc4
--- /dev/null
+++ b/usr.sbin/lptcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG = lptcontrol
+CFLAGS += -Wall
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lptcontrol/lptcontrol.1 b/usr.sbin/lptcontrol/lptcontrol.1
new file mode 100644
index 000000000000..52c34a68a725
--- /dev/null
+++ b/usr.sbin/lptcontrol/lptcontrol.1
@@ -0,0 +1,67 @@
+.\"
+.\" lptcontrol - a utility for manipulating the lpt driver
+.\"
+.\" 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.
+.\"
+.\"
+.\" $Id: lptcontrol.1,v 1.3 1994/05/22 12:31:54 csgr Exp $
+.TH lptcontrol 1 "March 12, 1994" "" "FreeBSD"
+
+.SH NAME
+lptcontrol - a utility for manipulating the lpt printer driver.
+.SH SYNOPSIS
+.na
+.B lptcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B lptcontrol
+command is used to set either the interrupt-driven or polling mode
+of individual lpt devices. When a printer is switched between
+interrupt-driven and polled mode, this change will only take effect
+the next time the device is opened.
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.B \-i
+Turns on interrupt-driven mode.
+.TP
+.B \-p
+Turns on polled mode.
+.TP
+.BI "\-f\ " file
+Sets the mode of the printer device specified by
+.I file.
+The default value for
+.I file
+is
+.I /dev/lpt0
+.TP
+One of
+.B \-i
+or
+.B \-p
+must be specified.
+.PP
+.SH FILES
+/dev/lpt?
+.PP
+.SH BUGS
+If the port to be controlled does not have a printer connected and
+on-line, then lptcontrol will not be able to open the port in question
+for performing ioctl's and will fail.
+.sp
+Sure to be others.
+.SH "SEE ALSO"
+.BR lpt (4) ,
+.BR /sys/i386/conf/GENERICAH
+.SH AUTHOR
+Geoffrey M. Rehmet
diff --git a/usr.sbin/lptcontrol/lptcontrol.c b/usr.sbin/lptcontrol/lptcontrol.c
new file mode 100644
index 000000000000..bcb3ad303569
--- /dev/null
+++ b/usr.sbin/lptcontrol/lptcontrol.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1994 Geoffrey M. Rehmet
+ * 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 Geoffrey M. Rehmet
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: lptcontrol.c,v 1.2 1994/04/08 22:23:39 csgr Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/lpt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+
+
+#define DEFAULT_LPT "/dev/lpt0"
+#define IRQ_INVALID -1
+#define DO_POLL 0
+#define USE_IRQ 1
+
+static char default_printer[] = DEFAULT_LPT;
+
+static void usage(const char * progname)
+{
+ fprintf(stderr, "usage: %s -i | -p [-f <file name>]\n", progname);
+ exit(1);
+}
+
+static void set_interrupt_status(int irq_status, const char * file)
+{
+ int fd;
+
+ if((fd = open(file, O_WRONLY, 0660)) < 0) {
+ perror("open");
+ exit(1);
+ }
+ if(ioctl(fd, LPT_IRQ, &irq_status) < 0) {
+ perror("ioctl");
+ exit(1);
+ }
+ close(fd);
+}
+
+
+int main (int argc, char * argv[])
+{
+ int opt;
+ int irq_status = -1;
+ char * file = default_printer;
+
+ while((opt = getopt(argc, argv, "pif:")) != -1)
+ switch(opt) {
+ case 'i': irq_status = USE_IRQ; break;
+ case 'p': irq_status = DO_POLL; break;
+ case 'f': file = optarg; break;
+ default : usage(argv[0]);
+ }
+ if(irq_status == IRQ_INVALID) usage(argv[0]);
+
+ set_interrupt_status(irq_status, file);
+
+ exit(0);
+}
+
+
diff --git a/usr.sbin/mrouted/LICENSE b/usr.sbin/mrouted/LICENSE
new file mode 100644
index 000000000000..ef7da470b117
--- /dev/null
+++ b/usr.sbin/mrouted/LICENSE
@@ -0,0 +1,48 @@
+
+The mrouted program is covered by the following license. Use of the
+mrouted program represents acceptance of these terms and conditions.
+
+1. STANFORD grants to LICENSEE a nonexclusive and nontransferable license
+to use, copy and modify the computer software ``mrouted'' (hereinafter
+called the ``Program''), upon the terms and conditions hereinafter set
+out and until Licensee discontinues use of the Licensed Program.
+
+2. LICENSEE acknowledges that the Program is a research tool still in
+the development state, that it is being supplied ``as is,'' without any
+accompanying services from STANFORD, and that this license is entered
+into in order to encourage scientific collaboration aimed at further
+development and application of the Program.
+
+3. LICENSEE may copy the Program and may sublicense others to use object
+code copies of the Program or any derivative version of the Program.
+All copies must contain all copyright and other proprietary notices found
+in the Program as provided by STANFORD. Title to copyright to the
+Program remains with STANFORD.
+
+4. LICENSEE may create derivative versions of the Program. LICENSEE
+hereby grants STANFORD a royalty-free license to use, copy, modify,
+distribute and sublicense any such derivative works. At the time
+LICENSEE provides a copy of a derivative version of the Program to a
+third party, LICENSEE shall provide STANFORD with one copy of the source
+code of the derivative version at no charge to STANFORD.
+
+5. STANFORD MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
+By way of example, but not limitation, STANFORD MAKES NO REPRESENTATION
+OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+THAT THE USE OF THE LICENSED PROGRAM WILL NOT INFRINGE ANY PATENTS,
+COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. STANFORD shall not be held liable
+for any liability nor for any direct, indirect or consequential damages
+with respect to any claim by LICENSEE or any third party on account of or
+arising from this Agreement or use of the Program.
+
+6. This agreement shall be construed, interpreted and applied in
+accordance with the State of California and any legal action arising
+out of this Agreement or use of the Program shall be filed in a court
+in the State of California.
+
+7. Nothing in this Agreement shall be construed as conferring rights to
+use in advertising, publicity or otherwise any trademark or the name
+of ``Stanford''.
+
+The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+Leland Stanford Junior University.
diff --git a/usr.sbin/mrouted/Makefile b/usr.sbin/mrouted/Makefile
new file mode 100644
index 000000000000..06b9e28be6c4
--- /dev/null
+++ b/usr.sbin/mrouted/Makefile
@@ -0,0 +1,44 @@
+#
+# Makefile for mrouted, a multicast router, and its auxiliary programs,
+# map-mbone and mrinfo.
+#
+# $Id: Makefile,v 1.3 1994/06/15 11:28:38 jkh Exp $
+#
+# Modified by: Jim Lowe for FreeBSD 5/17/94
+#
+
+IGMP_SRCS= igmp.c inet.c kern.c
+IGMP_OBJS= igmp.o inet.o kern.o
+ROUTER_SRCS= config.c main.c route.c vif.c
+ROUTER_OBJS= config.o main.o route.o vif.o
+MAPPER_SRCS= mapper.c
+MAPPER_OBJS= mapper.o
+MRINFO_SRCS= mrinfo.c
+MRINFO_OBJS= mrinfo.o
+HDRS= defs.h dvmrp.h route.h vif.h
+SRCS= ${IGMP_SRCS} ${ROUTER_SRCS} ${MAPPER_SRCS} ${MRINFO_SRCS}
+OBJS= ${IGMP_OBJS} ${ROUTER_OBJS} ${MAPPER_OBJS} ${MRINFO_OBJS}
+CLEANFILES+=mrouted map-mbone mrinfo
+
+MAN8= mrouted.8
+
+all: mrouted map-mbone mrinfo
+
+mrouted: ${IGMP_OBJS} ${ROUTER_OBJS}
+ rm -f $@
+ ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${ROUTER_OBJS}
+
+map-mbone: ${IGMP_OBJS} ${MAPPER_OBJS}
+ rm -f $@
+ ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${MAPPER_OBJS}
+
+mrinfo: ${IGMP_OBJS} ${MRINFO_OBJS}
+ rm -f $@
+ ${CC} ${LDFLAGS} -o $@ ${CFLAGS} ${IGMP_OBJS} ${MRINFO_OBJS}
+
+install: mrouted mrinfo map-mbone
+ install -c mrouted ${DESTDIR}${BINDIR}
+ install -c -o root -m 500 mrinfo ${DESTDIR}${BINDIR}
+ install -c -o root -m 500 map-mbone ${DESTDIR}${BINDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c
new file mode 100644
index 000000000000..089b7098f335
--- /dev/null
+++ b/usr.sbin/mrouted/config.c
@@ -0,0 +1,528 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: config.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+char *configfilename = "/etc/mrouted.conf";
+
+
+/*
+ * Forward declarations.
+ */
+static char *next_word();
+
+
+/*
+ * Query the kernel to find network interfaces that are multicast-capable
+ * and install them in the uvifs array.
+ */
+void config_vifs_from_kernel()
+{
+ struct ifreq ifbuf[32];
+ struct ifreq *ifrp, *ifend, *mp;
+ struct ifconf ifc;
+ register struct uvif *v;
+ register vifi_t vifi;
+ int i, n;
+ u_long addr, mask, subnet;
+ u_int flags;
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ ifrp = (struct ifreq *)ifbuf;
+ ifend = (struct ifreq *)((char *)ifbuf + ifc.ifc_len);
+ /*
+ * Loop through all of the interfaces.
+ */
+ for (; ifrp < ifend; ifrp = (struct ifreq *)((char *)ifrp + n)) {
+ struct ifreq ifr;
+#if BSD >= 199006
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ n = sizeof(*ifrp);
+#else
+ n = sizeof(*ifrp);
+#endif
+ /*
+ * Ignore any interface for an address family other than IP.
+ */
+ addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+
+ /*
+ * Ignore loopback interfaces and interfaces that do not support
+ * multicast.
+ */
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
+ flags = ifr.ifr_flags;
+ if ((flags & (IFF_LOOPBACK|IFF_MULTICAST)) != IFF_MULTICAST) continue;
+
+ /*
+ * Ignore any interface whose address and mask do not define a
+ * valid subnet number, or whose address is of the form {subnet,0}
+ * or {subnet,-1}.
+ */
+ if (ioctl(udp_socket, SIOCGIFNETMASK, (char *)&ifr) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", ifr.ifr_name);
+ mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ subnet = addr & mask;
+ if (!inet_valid_subnet(subnet, mask) ||
+ addr == subnet ||
+ addr == (subnet | ~mask)) {
+ log(LOG_WARNING, 0,
+ "ignoring %s, has invalid address (%s) and/or mask (%08x)",
+ ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
+ continue;
+ }
+
+ /*
+ * Ignore any interface that is connected to the same subnet as
+ * one already installed in the uvifs array.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if ((addr & v->uv_subnetmask) == v->uv_subnet ||
+ (v->uv_subnet & mask) == subnet) {
+ log(LOG_WARNING, 0, "ignoring %s, same subnet as %s",
+ ifr.ifr_name, v->uv_name);
+ break;
+ }
+ }
+ if (vifi != numvifs) continue;
+
+ /*
+ * If there is room in the uvifs array, install this interface.
+ */
+ if (numvifs == MAXVIFS) {
+ log(LOG_WARNING, 0, "too many vifs, ignoring %s", ifr.ifr_name);
+ continue;
+ }
+ v = &uvifs[numvifs];
+ v->uv_flags = 0;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = addr;
+ v->uv_rmt_addr = 0;
+ v->uv_subnet = subnet;
+ v->uv_subnetmask = mask;
+ v->uv_subnetbcast = subnet | ~mask;
+ strncpy(v->uv_name, ifr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+
+ log(LOG_INFO, 0, "installing %s (%s on subnet %s) as vif #%u",
+ v->uv_name, inet_fmt(addr, s1), inet_fmts(subnet, mask, s2),
+ numvifs);
+
+ ++numvifs;
+
+ /*
+ * If the interface is not yet up, set the vifs_down flag to
+ * remind us to check again later.
+ */
+ if (!(flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ }
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_long a;
+{
+ int n;
+ struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf;
+ struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len);
+
+ while (ifrp < ifend) {
+ if (ifrp->ifr_addr.sa_family == AF_INET &&
+ ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a)
+ return (ifrp);
+#if BSD >= 199006
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ++ifrp;
+ else
+ ifrp = (struct ifreq *)((char *)ifrp + n);
+#else
+ ++ifrp;
+#endif
+ }
+ return (0);
+}
+/*
+ * Read the config file to learn about tunnel vifs and
+ * non-default phyint parameters.
+ */
+void config_vifs_from_file()
+{
+ FILE *f;
+ char linebuf[100];
+ char *w, *s, c;
+ u_long lcl_addr, rmt_addr;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ int i;
+ u_int n;
+ struct ifreq ifbuf[32];
+ vifi_t vifi;
+ struct uvif *v;
+
+ f = fopen(configfilename, "r");
+ if (f == NULL) {
+ if (errno != ENOENT)
+ log(LOG_WARNING, errno, "can't open %s", configfilename);
+ return;
+ }
+
+ ifc.ifc_buf = (char *)ifbuf;
+ ifc.ifc_len = sizeof(ifbuf);
+ if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0)
+ log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
+
+ while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
+
+ s = linebuf;
+ if (EQUAL((w = next_word(&s)), "")) {
+ /*
+ * blank or comment line; ignore
+ */
+ }
+
+ else if (EQUAL(w, "phyint")) {
+ /*
+ * phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+ */
+
+ /*
+ * Parse the local address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing phyint address in %s",
+ configfilename);
+ continue;
+ }
+ if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(lcl_addr)) {
+ log(LOG_WARNING, 0,
+ "invalid phyint address '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Look up the vif with the specified local address.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ lcl_addr == v->uv_lcl_addr) {
+ break;
+ }
+ }
+ if (vifi == numvifs) {
+ log(LOG_WARNING, 0,
+ "phyint %s in %s is not a configured interface",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Look for "disable", "metric" and "threshold" options.
+ */
+ while (!EQUAL((w = next_word(&s)), "")) {
+ if (EQUAL(w, "disable")) {
+ v->uv_flags |= VIFF_DISABLED;
+ }
+ else if (EQUAL(w, "metric")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing metric for phyint %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n >= UNREACHABLE ) {
+ log(LOG_WARNING, 0,
+ "invalid metric '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_metric = n;
+ }
+ else if (EQUAL(w, "threshold")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing threshold for phyint %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n > 255 ) {
+ log(LOG_WARNING, 0,
+ "invalid threshold '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_threshold = n;
+ }
+ else break;
+ }
+ if (!EQUAL(w, "")) continue;
+ }
+
+ else if (EQUAL(w, "tunnel")) {
+ /*
+ * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>]
+ */
+
+ /*
+ * Parse the local address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing tunnel local address in %s",
+ configfilename);
+ continue;
+ }
+ if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(lcl_addr)) {
+ log(LOG_WARNING, 0,
+ "invalid tunnel local address '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the local address is one of ours.
+ */
+ ifr = ifconfaddr(&ifc, lcl_addr);
+ if (ifr == 0) {
+ log(LOG_WARNING, 0,
+ "tunnel local address %s in %s is not one of ours",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the local address doesn't name a loopback interface..
+ */
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
+ log(LOG_ERR, errno,
+ "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
+ }
+ if (ffr.ifr_flags & IFF_LOOPBACK) {
+ log(LOG_WARNING, 0,
+ "tunnel local address %s in %s is a loopback interface",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Parse the remote address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing tunnel remote address in %s",
+ configfilename);
+ continue;
+ }
+ if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(rmt_addr)) {
+ log(LOG_WARNING, 0,
+ "invalid tunnel remote address %s in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the remote address is not one of ours.
+ */
+ if (ifconfaddr(&ifc, rmt_addr) != 0) {
+ log(LOG_WARNING, 0,
+ "tunnel remote address %s in %s is one of ours",
+ inet_fmt(rmt_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the remote address has not been used for another
+ * tunnel and does not belong to a subnet to which we have direct
+ * access on an enabled phyint.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if (rmt_addr == v->uv_rmt_addr) {
+ log(LOG_WARNING, 0,
+ "duplicate tunnel remote address %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ }
+ else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
+ log(LOG_WARNING, 0,
+ "unnecessary tunnel remote address %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ }
+ }
+ if (vifi != numvifs) continue;
+
+ /*
+ * OK, let's initialize a uvif structure for the tunnel.
+ */
+ if (numvifs == MAXVIFS) {
+ log(LOG_WARNING, 0, "too many vifs, ignoring tunnel to %s",
+ inet_fmt(rmt_addr, s1));
+ continue;
+ }
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = lcl_addr;
+ v->uv_rmt_addr = rmt_addr;
+ v->uv_subnet = 0;
+ v->uv_subnetmask = 0;
+ v->uv_subnetbcast = 0;
+ strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ);
+ v->uv_groups = NULL;
+ v->uv_neighbors = NULL;
+
+ /*
+ * Look for "metric" and "threshold" options.
+ */
+ while (!EQUAL((w = next_word(&s)), "")) {
+ if (EQUAL(w, "metric")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing metric for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n >= UNREACHABLE ) {
+ log(LOG_WARNING, 0,
+ "invalid metric '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_metric = n;
+ }
+ else if (EQUAL(w, "threshold")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_WARNING, 0,
+ "missing threshold for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n > 255 ) {
+ log(LOG_WARNING, 0,
+ "invalid threshold '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_threshold = n;
+ }
+ else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
+ v->uv_flags |= VIFF_SRCRT;
+ }
+ else break;
+ }
+ if (!EQUAL(w, "")) continue;
+
+ log(LOG_INFO, 0,
+ "installing %stunnel from %s to %s as vif #%u",
+ v->uv_flags & VIFF_SRCRT? "srcrt " : "",
+ inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2), numvifs);
+
+ ++numvifs;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ }
+
+ else {
+ log(LOG_WARNING, 0,
+ "unknown command '%s' in %s", w, configfilename);
+ }
+ }
+
+ close(f);
+}
+
+
+/*
+ * Return a pointer to the next "word" in the string to which '*s' points,
+ * lower-cased and null terminated, and advance '*s' to point beyond the word.
+ * Words are separated by blanks and/or tabs, and the input string is
+ * considered to terminate at a newline, '#' (comment), or null character.
+ * If no words remain, a pointer to a null string ("") is returned.
+ * Warning: This function clobbers the input string.
+ */
+static char *next_word(s)
+ char **s;
+{
+ char *w;
+
+ w = *s;
+ while (*w == ' ' || *w == '\t')
+ ++w;
+
+ *s = w;
+ for(;;) {
+ switch (**s) {
+
+ case ' ' :
+ case '\t' : **s = '\0';
+ ++*s;
+ return (w);
+
+ case '\n' :
+ case '#' : **s = '\0';
+ return (w);
+
+ case '\0' : return (w);
+
+ default : if (isascii(**s) && isupper(**s))
+ **s = tolower(**s);
+ ++*s;
+ }
+ }
+}
diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h
new file mode 100644
index 000000000000..ebaec8e5abff
--- /dev/null
+++ b/usr.sbin/mrouted/defs.h
@@ -0,0 +1,129 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: defs.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/igmp.h>
+#include <netinet/ip_mroute.h>
+
+#include "dvmrp.h"
+#include "vif.h"
+#include "route.h"
+
+
+/*
+ * Miscellaneous constants and macros.
+ */
+#define FALSE 0
+#define TRUE 1
+
+#define EQUAL(s1, s2) (strcmp((s1), (s2)) == 0)
+
+#define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
+
+#define PROTOCOL_VERSION 2 /* increment when packet format/content changes */
+
+#define MROUTED_VERSION 0 /* increment on local changes or bug fixes, */
+ /* reset to 0 whever PROTOCOL_VERSION increments */
+
+#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
+ /* for IGMP 'group' field of DVMRP messages */
+
+/*
+ * External declarations for global variables and functions.
+ */
+extern char recv_buf[MAX_IP_PACKET_LEN];
+extern char send_buf[MAX_IP_PACKET_LEN];
+extern int igmp_socket;
+extern u_long allhosts_group;
+extern u_long dvmrp_group;
+
+#define DEFAULT_DEBUG 2 /* default if "-d" given without value */
+
+extern int debug;
+
+extern int routes_changed;
+extern int delay_change_reports;
+
+extern struct uvif uvifs[MAXVIFS];
+extern vifi_t numvifs;
+extern int vifs_down;
+extern int udp_socket;
+
+extern char s1[];
+extern char s2[];
+extern char s3[];
+
+extern int errno;
+extern int sys_nerr;
+extern char * sys_errlist[];
+
+extern void log();
+
+extern void init_igmp();
+extern void accept_igmp();
+extern void send_igmp();
+
+extern void init_routes();
+extern void start_route_updates();
+extern void update_route();
+extern void age_routes();
+extern void expire_all_routes();
+extern void accept_probe();
+extern void accept_report();
+extern void report();
+extern void report_to_all_neighbors();
+extern void add_vif_to_routes();
+extern void delete_vif_from_routes();
+extern void delete_neighbor_from_routes();
+extern void dump_routes();
+
+extern void init_vifs();
+extern void check_vif_state();
+extern vifi_t find_vif();
+extern void age_vifs();
+extern void dump_vifs();
+extern void accept_group_report();
+extern void query_groups();
+extern void probe_for_neighbors();
+extern int update_neighbor();
+extern void accept_neighbor_request();
+
+extern void config_vifs_from_kernel();
+extern void config_vifs_from_file();
+
+extern int inet_valid_host();
+extern int inet_valid_subnet();
+extern char * inet_fmt();
+extern char * inet_fmts();
+extern u_long inet_parse();
+extern int inet_cksum();
+
+extern char * malloc();
+extern char * fgets();
+extern FILE * fopen();
+
+#ifndef htonl
+extern u_long htonl();
+extern u_long ntohl();
+#endif
diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h
new file mode 100644
index 000000000000..6928fe82bb9e
--- /dev/null
+++ b/usr.sbin/mrouted/dvmrp.h
@@ -0,0 +1,141 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: dvmrp.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+/*
+ * A DVMRP message consists of an IP header + an IGMP header + (for some types)
+ * zero or more bytes of data.
+ *
+ * For REPORT messages, the data is route information; the route information
+ * consists of one or more lists of the following form:
+ *
+ * (mask, (origin, metric), (origin, metric), ...)
+ *
+ * where:
+ *
+ * "mask" is the subnet mask for all the origins in the list.
+ * It is always THREE bytes long, containing the low-order
+ * three bytes of the mask (the high-order byte is always
+ * 0xff and therefore need not be transmitted).
+ *
+ * "origin" is the number of a subnet from which multicast datagrams
+ * may originate. It is from one to four bytes long,
+ * depending on the value of "mask":
+ * if all bytes of the mask are zero
+ * the subnet number is one byte long
+ * else if the low-order two bytes of the mask are zero
+ * the subnet number is two bytes long
+ * else if the lowest-order byte of the mask is zero
+ * the subnet number is three bytes long,
+ * else
+ * the subnet number is four bytes long.
+ *
+ * "metric" is a one-byte value consisting of two subfields:
+ * - the high-order bit is a flag which, when set, indicates
+ * the last (origin, metric) pair of a list.
+ * - the low-order seven bits contain the routing metric for
+ * the corresponding origin, relative to the sender of the
+ * DVMRP report. The metric may have the value of UNREACHABLE
+ * added to it as a "split horizon" indication (so called
+ * "poisoned reverse").
+ *
+ * Within a list, the origin subnet numbers must be in ascending order, and
+ * the lists themselves are in order of increasing mask value. A message may
+ * not exceed 576 bytes, the default maximum IP reassembly size, including
+ * the IP and IGMP headers; the route information may be split across more
+ * than one message if necessary, by terminating a list in one message and
+ * starting a new list in the next message (repeating the same mask value,
+ * if necessary).
+ *
+ * For NEIGHBORS messages, the data is neighboring-router information
+ * consisting of one or more lists of the following form:
+ *
+ * (local-addr, metric, threshold, ncount, neighbor, neighbor, ...)
+ *
+ * where:
+ *
+ * "local-addr" is the sending router's address as seen by the neighbors
+ * in this list; it is always four bytes long.
+ * "metric" is a one-byte unsigned value, the TTL `cost' of forwarding
+ * packets to any of the neighbors on this list.
+ * "threshold" is a one-byte unsigned value, a lower bound on the TTL a
+ * packet must have to be forwarded to any of the neighbors on
+ * this list.
+ * "ncount" is the number of neighbors in this list.
+ * "neighbor" is the address of a neighboring router, four bytes long.
+ *
+ * As with REPORT messages, NEIGHBORS messages should not exceed 576 bytes,
+ * including the IP and IGMP headers; split longer messages by terminating the
+ * list in one and continuing in another, repeating the local-addr, etc., if
+ * necessary.
+ *
+ * For NEIGHBORS2 messages, the data is identical to NEIGHBORS except
+ * there is a flags byte before the neighbor count:
+ *
+ * (local-addr, metric, threshold, flags, ncount, neighbor, neighbor, ...)
+ */
+
+/*
+ * DVMRP message types (carried in the "code" field of an IGMP header)
+ */
+#define DVMRP_PROBE 1 /* for finding neighbors */
+#define DVMRP_REPORT 2 /* for reporting some or all routes */
+#define DVMRP_ASK_NEIGHBORS 3 /* sent by mapper, asking for a list */
+ /* of this router's neighbors. */
+#define DVMRP_NEIGHBORS 4 /* response to such a request */
+#define DVMRP_ASK_NEIGHBORS2 5 /* as above, want new format reply */
+#define DVMRP_NEIGHBORS2 6
+
+/*
+ * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
+ */
+#define DVMRP_NF_TUNNEL 0x01 /* neighbors reached via tunnel */
+#define DVMRP_NF_SRCRT 0x02 /* tunnel uses IP source routing */
+#define DVMRP_NF_DOWN 0x10 /* kernel state of interface */
+#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
+#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
+
+/*
+ * Limit on length of route data
+ */
+#define MAX_IP_PACKET_LEN 576
+#define MIN_IP_HEADER_LEN 20
+#define MAX_IP_HEADER_LEN 60
+#define MAX_DVMRP_DATA_LEN \
+ ( MAX_IP_PACKET_LEN - MAX_IP_HEADER_LEN - IGMP_MINLEN )
+
+/*
+ * Various protocol constants (all times in seconds)
+ */
+ /* address for multicast DVMRP msgs */
+#define INADDR_DVMRP_GROUP (u_long)0xe0000004 /* 224.0.0.4 */
+
+#define ROUTE_MAX_REPORT_DELAY 5 /* max delay for reporting changes */
+ /* (This is the timer interrupt */
+ /* interval; all times must be */
+ /* multiples of this value.) */
+
+#define ROUTE_REPORT_INTERVAL 60 /* periodic route report interval */
+#define ROUTE_SWITCH_TIME 140 /* time to switch to equivalent gw */
+#define ROUTE_EXPIRE_TIME 200 /* time to mark route invalid */
+#define ROUTE_DISCARD_TIME 340 /* time to garbage collect route */
+
+#define LEAF_CONFIRMATION_TIME 200 /* time to consider subnet a leaf */
+
+#define NEIGHBOR_PROBE_INTERVAL 190 /* periodic neighbor probe interval */
+#define NEIGHBOR_EXPIRE_TIME 140 /* time to consider neighbor gone */
+
+#define GROUP_QUERY_INTERVAL 125 /* periodic group query interval */
+#define GROUP_EXPIRE_TIME 270 /* time to consider group gone */
+
+#define UNREACHABLE 32 /* "infinity" metric, must be <= 64 */
+#define DEFAULT_METRIC 1 /* default subnet/tunnel metric */
+#define DEFAULT_THRESHOLD 1 /* default subnet/tunnel threshold */
diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c
new file mode 100644
index 000000000000..cfd874e611b9
--- /dev/null
+++ b/usr.sbin/mrouted/igmp.c
@@ -0,0 +1,217 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: igmp.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
+char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
+int igmp_socket; /* socket for all network I/O */
+u_long allhosts_group; /* allhosts addr in net order */
+u_long dvmrp_group; /* DVMRP grp addr in net order */
+
+
+/*
+ * Open and initialize the igmp socket, and fill in the non-changing
+ * IP header fields in the output packet buffer.
+ */
+void init_igmp()
+{
+ struct ip *ip;
+
+ if ((igmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0)
+ log(LOG_ERR, errno, "IGMP socket");
+
+ k_hdr_include(TRUE); /* include IP header when sending */
+ k_set_rcvbuf(48*1024); /* lots of input buffering */
+ k_set_ttl(1); /* restrict multicasts to one hop */
+ k_set_loop(FALSE); /* disable multicast loopback */
+
+ ip = (struct ip *)send_buf;
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = IPPROTO_IGMP;
+ ip->ip_ttl = MAXTTL; /* applies to unicasts only */
+
+ allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
+ dvmrp_group = htonl(INADDR_DVMRP_GROUP);
+}
+
+static char *packet_kind(type, code)
+ u_char type, code;
+{
+ switch (type) {
+ case IGMP_HOST_MEMBERSHIP_QUERY: return "membership query ";
+ case IGMP_HOST_MEMBERSHIP_REPORT: return "membership report ";
+ case IGMP_DVMRP:
+ switch (code) {
+ case DVMRP_PROBE: return "neighbor probe ";
+ case DVMRP_REPORT: return "route report ";
+ case DVMRP_ASK_NEIGHBORS: return "neighbor request ";
+ case DVMRP_NEIGHBORS: return "neighbor list ";
+ case DVMRP_ASK_NEIGHBORS2: return "neighbor request 2";
+ case DVMRP_NEIGHBORS2: return "neighbor list 2 ";
+ default: return "unknown DVMRP msg ";
+ }
+ default: return "unknown IGMP msg ";
+ }
+}
+
+/*
+ * Process a newly received IGMP packet that is sitting in the input
+ * packet buffer.
+ */
+void accept_igmp(recvlen)
+ int recvlen;
+{
+ register vifi_t vifi;
+ register u_long src, dst, group;
+ struct ip *ip;
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+ if (recvlen < sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "received packet too short (%u bytes) for IP header", recvlen);
+ return;
+ }
+
+ ip = (struct ip *)recv_buf;
+ src = ip->ip_src.s_addr;
+ dst = ip->ip_dst.s_addr;
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+ "received packet shorter (%u bytes) than hdr+data length (%u+%u)",
+ recvlen, iphdrlen, ipdatalen);
+ return;
+ }
+
+ igmp = (struct igmp *)(recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ log(LOG_WARNING, 0,
+ "received IP data field too short (%u bytes) for IGMP, from %s",
+ ipdatalen, inet_fmt(src, s1));
+ return;
+ }
+
+ log(LOG_DEBUG, 0, "RECV %s from %-15s to %s",
+ packet_kind(igmp->igmp_type, igmp->igmp_code),
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+
+ switch (igmp->igmp_type) {
+
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ return; /* Answered automatically by the kernel. */
+
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ accept_group_report(src, dst, group);
+ return;
+
+ case IGMP_DVMRP:
+ switch (igmp->igmp_code) {
+
+ case DVMRP_PROBE:
+ accept_probe(src, dst);
+ return;
+
+ case DVMRP_REPORT:
+ accept_report(src, dst,
+ (char *)(igmp+1), igmpdatalen);
+ return;
+
+ case DVMRP_ASK_NEIGHBORS:
+ accept_neighbor_request(src, dst);
+ return;
+
+ case DVMRP_ASK_NEIGHBORS2:
+ accept_neighbor_request2(src, dst);
+ return;
+
+ case DVMRP_NEIGHBORS:
+ accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
+ group);
+ return;
+
+ case DVMRP_NEIGHBORS2:
+ accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
+ group);
+ return;
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown DVMRP message code %u from %s to %s",
+ igmp->igmp_code, inet_fmt(src, s1),
+ inet_fmt(dst, s2));
+ return;
+ }
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown IGMP message type %u from %s to %s",
+ igmp->igmp_type, inet_fmt(src, s1),
+ inet_fmt(dst, s2));
+ return;
+ }
+}
+
+
+/*
+ * Construct an IGMP message in the output packet buffer. The caller may
+ * have already placed data in that buffer, of length 'datalen'. Then send
+ * the message from the interface with IP address 'src' to destination 'dst'.
+ */
+void send_igmp(src, dst, type, code, group, datalen)
+ u_long src, dst;
+ int type, code;
+ u_long group;
+ int datalen;
+{
+ static struct sockaddr_in sdst = {AF_INET};
+ struct ip *ip;
+ struct igmp *igmp;
+
+ ip = (struct ip *)send_buf;
+ ip->ip_src.s_addr = src;
+ ip->ip_dst.s_addr = dst;
+ ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
+
+ igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
+ igmp->igmp_type = type;
+ igmp->igmp_code = code;
+ igmp->igmp_group.s_addr = group;
+ igmp->igmp_cksum = 0;
+ igmp->igmp_cksum = inet_cksum((u_short *)igmp,
+ IGMP_MINLEN + datalen);
+
+ if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
+ if (dst == allhosts_group) k_set_loop(TRUE);
+
+ sdst.sin_addr.s_addr = dst;
+ if (sendto(igmp_socket, send_buf, ip->ip_len, 0,
+ (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
+ if (errno == ENETDOWN) check_vif_state();
+ else log(LOG_WARNING, errno, "sendto on %s", inet_fmt(src, s1));
+ }
+
+ if (dst == allhosts_group) k_set_loop(FALSE);
+
+ log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
+ packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
+}
diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c
new file mode 100644
index 000000000000..02b187a85a39
--- /dev/null
+++ b/usr.sbin/mrouted/inet.c
@@ -0,0 +1,187 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: inet.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char s1[16]; /* buffers to hold the string representations */
+char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
+char s3[16]; /* or inet_fmts(). */
+
+
+/*
+ * Verify that a given IP address is credible as a host address.
+ * (Without a mask, cannot detect addresses of the form {subnet,0} or
+ * {subnet,-1}.)
+ */
+int inet_valid_host(naddr)
+ u_long naddr;
+{
+ register u_long addr;
+
+ addr = ntohl(naddr);
+
+ return (!(IN_MULTICAST(addr) ||
+ IN_BADCLASS (addr) ||
+ (addr & 0xff000000) == 0));
+}
+
+
+/*
+ * Verify that a given subnet number and mask pair are credible.
+ */
+int inet_valid_subnet(nsubnet, nmask)
+ u_long nsubnet, nmask;
+{
+ register u_long subnet, mask;
+
+ subnet = ntohl(nsubnet);
+ mask = ntohl(nmask);
+
+ if ((subnet & mask) != subnet) return (FALSE);
+
+ if (IN_CLASSA(subnet)) {
+ if (mask < 0xff000000 ||
+ (subnet & 0xff000000) == 0 ||
+ (subnet & 0xff000000) == 0x7f000000) return (FALSE);
+ }
+ else if (IN_CLASSB(subnet)) {
+ if (mask < 0xffff0000) return (FALSE);
+ }
+ else if (IN_CLASSC(subnet)) {
+ if (mask < 0xffffff00) return (FALSE);
+ }
+ else return (FALSE);
+
+ return (TRUE);
+}
+
+
+/*
+ * Convert an IP address in u_long (network) format into a printable string.
+ */
+char *inet_fmt(addr, s)
+ u_long addr;
+ char *s;
+{
+ register u_char *a;
+
+ a = (u_char *)&addr;
+ sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
+ return (s);
+}
+
+
+/*
+ * Convert an IP subnet number in u_long (network) format into a printable
+ * string.
+ */
+char *inet_fmts(addr, mask, s)
+ u_long addr, mask;
+ char *s;
+{
+ register u_char *a, *m;
+
+ a = (u_char *)&addr;
+ m = (u_char *)&mask;
+
+ if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
+ else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
+ else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
+ else sprintf(s, "%u", a[0]);
+
+ return (s);
+}
+
+
+/*
+ * Convert the printable string representation of an IP address into the
+ * u_long (network) format. Return 0xffffffff on error. (To detect the
+ * legal address with that value, you must explicitly compare the string
+ * with "255.255.255.255".)
+ */
+u_long inet_parse(s)
+ char *s;
+{
+ u_long a;
+ u_int a0, a1, a2, a3;
+ char c;
+
+ if (sscanf(s, "%u.%u.%u.%u%c", &a0, &a1, &a2, &a3, &c) != 4 ||
+ a0 > 255 || a1 > 255 || a2 > 255 || a3 > 255)
+ return (0xffffffff);
+
+ ((u_char *)&a)[0] = a0;
+ ((u_char *)&a)[1] = a1;
+ ((u_char *)&a)[2] = a2;
+ ((u_char *)&a)[3] = a3;
+
+ return (a);
+}
+
+
+/*
+ * inet_cksum extracted from:
+ * P I N G . C
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ * Modified at Uc Berkeley
+ *
+ * (ping.c) Status -
+ * Public Domain. Distribution Unlimited.
+ *
+ * I N _ C K S U M
+ *
+ * Checksum routine for Internet Protocol family headers (C Version)
+ *
+ */
+int inet_cksum(addr, len)
+ u_short *addr;
+ u_int len;
+{
+ register int nleft = (int)len;
+ register u_short *w = addr;
+ u_short answer = 0;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while( nleft > 1 ) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if( nleft == 1 ) {
+ *(u_char *) (&answer) = *(u_char *)w ;
+ sum += answer;
+ }
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c
new file mode 100644
index 000000000000..08c934982ebb
--- /dev/null
+++ b/usr.sbin/mrouted/kern.c
@@ -0,0 +1,213 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: kern.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+void k_set_rcvbuf(bufsize)
+ int bufsize;
+{
+ if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
+ (char *)&bufsize, sizeof(bufsize)) < 0)
+ log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);
+}
+
+
+void k_hdr_include(bool)
+ int bool;
+{
+#ifdef IP_HDRINCL
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&bool, sizeof(bool)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
+#endif
+}
+
+
+void k_set_ttl(t)
+ int t;
+{
+ u_char ttl;
+
+ ttl = t;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
+}
+
+
+void k_set_loop(l)
+ int l;
+{
+ u_char loop;
+
+ loop = l;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
+ (char *)&loop, sizeof(loop)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
+}
+
+
+void k_set_if(ifa)
+ u_long ifa;
+{
+ struct in_addr adr;
+
+ adr.s_addr = ifa;
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
+ (char *)&adr, sizeof(adr)) < 0)
+ log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
+ inet_fmt(ifa, s1));
+}
+
+
+void k_join(grp, ifa)
+ u_long grp;
+ u_long ifa;
+{
+ struct ip_mreq mreq;
+
+ mreq.imr_multiaddr.s_addr = grp;
+ mreq.imr_interface.s_addr = ifa;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) < 0)
+ log(LOG_WARNING, errno, "can't join group %s on interface %s",
+ inet_fmt(grp, s1), inet_fmt(ifa, s2));
+}
+
+
+void k_leave(grp, ifa)
+ u_long grp;
+ u_long ifa;
+{
+ struct ip_mreq mreq;
+
+ mreq.imr_multiaddr.s_addr = grp;
+ mreq.imr_interface.s_addr = ifa;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) < 0)
+ log(LOG_WARNING, errno, "can't leave group %s on interface %s",
+ inet_fmt(grp, s1), inet_fmt(ifa, s2));
+}
+
+
+void k_init_dvmrp()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT,
+ (char *)NULL, 0) < 0)
+ log(LOG_ERR, errno, "can't enable DVMRP routing in kernel");
+}
+
+
+void k_stop_dvmrp()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE,
+ (char *)NULL, 0) < 0)
+ log(LOG_WARNING, errno, "can't disable DVMRP routing in kernel");
+}
+
+
+void k_add_vif(vifi, v)
+ vifi_t vifi;
+ struct uvif *v;
+{
+ struct vifctl vc;
+
+ vc.vifc_vifi = vifi;
+ vc.vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
+ vc.vifc_threshold = v->uv_threshold;
+ vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
+ vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_VIF,
+ (char *)&vc, sizeof(vc)) < 0)
+ log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF");
+}
+
+
+void k_del_vif(vifi)
+ vifi_t vifi;
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF,
+ (char *)&vifi, sizeof(vifi)) < 0)
+ log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF");
+}
+
+
+void k_add_group(vifi, group)
+ vifi_t vifi;
+ u_long group;
+{
+ struct lgrplctl lc;
+
+ lc.lgc_vifi = vifi;
+ lc.lgc_gaddr.s_addr = group;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_LGRP,
+ (char *)&lc, sizeof(lc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_LGRP");
+}
+
+
+void k_del_group(vifi, group)
+ vifi_t vifi;
+ u_long group;
+{
+ struct lgrplctl lc;
+
+ lc.lgc_vifi = vifi;
+ lc.lgc_gaddr.s_addr = group;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_LGRP,
+ (char *)&lc, sizeof(lc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_LGRP");
+}
+
+
+void k_add_route(r)
+ struct rtentry *r;
+{
+ struct mrtctl mc;
+
+ mc.mrtc_origin.s_addr = r->rt_origin;
+ mc.mrtc_originmask.s_addr = r->rt_originmask;
+ mc.mrtc_parent = r->rt_parent;
+ VIFM_COPY(r->rt_children, mc.mrtc_children);
+ VIFM_COPY(r->rt_leaves, mc.mrtc_leaves);
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MRT,
+ (char *)&mc, sizeof(mc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MRT");
+}
+
+
+void k_update_route(r)
+ struct rtentry *r;
+{
+ k_add_route(r);
+}
+
+
+void k_del_route(r)
+ struct rtentry *r;
+{
+ struct in_addr orig;
+
+ orig.s_addr = r->rt_origin;
+
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MRT,
+ (char *)&orig, sizeof(orig)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MRT");
+}
diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c
new file mode 100644
index 000000000000..75809dc478e3
--- /dev/null
+++ b/usr.sbin/mrouted/main.c
@@ -0,0 +1,322 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: main.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+/*
+ * Written by Steve Deering, Stanford University, February 1989.
+ *
+ * (An earlier version of DVMRP was implemented by David Waitzman of
+ * BBN STC by extending Berkeley's routed program. Some of Waitzman's
+ * extensions have been incorporated into mrouted, but none of the
+ * original routed code has been adopted.)
+ */
+
+
+#include "defs.h"
+
+extern char *configfilename;
+
+static char pidfilename[] = "/etc/mrouted.pid";
+static char dumpfilename[] = "/usr/tmp/mrouted.dump";
+
+static int debug = 0;
+
+
+/*
+ * Forward declarations.
+ */
+static void timer();
+static void hup();
+static void dump();
+static void fdump();
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int recvlen;
+ register int omask;
+ int dummy;
+ FILE *fp;
+ extern uid_t geteuid();
+
+ setlinebuf(stderr);
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "mrouted: must be root\n");
+ exit(1);
+ }
+
+ argv++, argc--;
+ while (argc > 0 && *argv[0] == '-') {
+ if (strcmp(*argv, "-d") == 0) {
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ debug = atoi(*argv);
+ } else
+ debug = DEFAULT_DEBUG;
+ } else if (strcmp(*argv, "-c") == 0) {
+ if (argc > 1) {
+ argv++, argc--;
+ configfilename = *argv;
+ } else
+ goto usage;
+ } else
+ goto usage;
+ argv++, argc--;
+ }
+
+ if (argc > 0) {
+usage: fprintf(stderr, "usage: mrouted [-c configfile] [-d [debug_level]]\n");
+ exit(1);
+ }
+
+ if (debug == 0) {
+ /*
+ * Detach from the terminal
+ */
+ int t;
+
+ if (fork()) exit(0);
+ (void)close(0);
+ (void)close(1);
+ (void)close(2);
+ (void)open("/", 0);
+ (void)dup2(0, 1);
+ (void)dup2(0, 2);
+ t = open("/dev/tty", 2);
+ if (t >= 0) {
+ (void)ioctl(t, TIOCNOTTY, (char *)0);
+ (void)close(t);
+ }
+ }
+ else fprintf(stderr, "debug level %u\n", debug);
+
+#ifdef LOG_DAEMON
+ (void)openlog("mrouted", LOG_PID, LOG_DAEMON);
+ (void)setlogmask(LOG_UPTO(LOG_NOTICE));
+#else
+ (void)openlog("mrouted", LOG_PID);
+#endif
+ log(LOG_NOTICE, 0, "mrouted version %d.%d",
+ PROTOCOL_VERSION, MROUTED_VERSION);
+
+ fp = fopen(pidfilename, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) fclose(fp);
+ }
+
+ srandom(gethostid());
+
+ init_igmp();
+ k_init_dvmrp(); /* enable DVMRP routing in kernel */
+ init_routes();
+ init_vifs();
+
+ if (debug >= 2) dump();
+
+ (void)signal(SIGALRM, timer);
+ (void)signal(SIGHUP, hup);
+ (void)signal(SIGTERM, hup);
+ (void)signal(SIGINT, hup);
+ (void)signal(SIGUSR1, fdump);
+ if (debug != 0)
+ (void)signal(SIGQUIT, dump);
+
+ (void)alarm(TIMER_INTERVAL); /* schedule first timer interrupt */
+
+ /*
+ * Main receive loop.
+ */
+ dummy = 0;
+ for(;;) {
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 0, NULL, &dummy);
+ if (recvlen < 0) {
+ if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
+ continue;
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ accept_igmp(recvlen);
+ (void)sigsetmask(omask);
+ }
+}
+
+
+/*
+ * The 'virtual_time' variable is initialized to a value that will cause the
+ * first invocation of timer() to send a probe or route report to all vifs
+ * and send group membership queries to all subnets for which this router is
+ * querier. This first invocation occurs approximately TIMER_INTERVAL seconds
+ * after the router starts up. Note that probes for neighbors and queries
+ * for group memberships are also sent at start-up time, as part of initial-
+ * ization. This repetition after a short interval is desirable for quickly
+ * building up topology and membership information in the presence of possible
+ * packet loss.
+ *
+ * 'virtual_time' advances at a rate that is only a crude approximation of
+ * real time, because it does not take into account any time spent processing,
+ * and because the timer intervals are sometimes shrunk by a random amount to
+ * avoid unwanted synchronization with other routers.
+ */
+
+static u_long virtual_time = 0;
+
+
+/*
+ * Timer routine. Performs periodic neighbor probing, route reporting, and
+ * group querying duties, and drives various timers in routing entries and
+ * virtual interface data structures.
+ */
+static void timer()
+{
+ int next_interval;
+
+ age_routes(); /* Advance the timers in the route entries */
+ age_vifs(); /* Advance the timers for neighbors and groups */
+
+ if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
+ /*
+ * Time to query the local group memberships on all subnets
+ * for which this router is the elected querier.
+ */
+ query_groups();
+ }
+
+ if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
+ /*
+ * Time to send a probe on all vifs from which no neighbors have
+ * been heard. Also, check if any inoperative interfaces have now
+ * come up. (If they have, they will also be probed as part of
+ * their initialization.)
+ */
+ probe_for_neighbors();
+
+ if (vifs_down)
+ check_vif_state();
+ }
+
+ delay_change_reports = FALSE;
+ next_interval = TIMER_INTERVAL;
+
+ if (virtual_time % ROUTE_REPORT_INTERVAL == 0) {
+ /*
+ * Time for the periodic report of all routes to all neighbors.
+ */
+ report_to_all_neighbors(ALL_ROUTES);
+
+ /*
+ * Schedule the next timer interrupt for a random time between
+ * 1 and TIMER_INTERVAL seconds from now. This randomization is
+ * intended to counteract the undesirable synchronizing tendency
+ * of periodic transmissions from multiple sources.
+ */
+ next_interval = (random() % TIMER_INTERVAL) + 1;
+ }
+ else if (routes_changed) {
+ /*
+ * Some routes have changed since the last timer interrupt, but
+ * have not been reported yet. Report the changed routes to all
+ * neighbors.
+ */
+ report_to_all_neighbors(CHANGED_ROUTES);
+ }
+
+ /*
+ * Advance virtual time and schedule the next timer interrupt.
+ */
+ virtual_time += TIMER_INTERVAL;
+ (void)alarm(next_interval);
+}
+
+
+/*
+ * On hangup signal, let everyone know we're going away.
+ */
+static void hup()
+{
+ log(LOG_INFO, 0, "hup");
+ expire_all_routes();
+ report_to_all_neighbors(ALL_ROUTES);
+ exit(1);
+}
+
+
+/*
+ * Dump internal data structures to stderr.
+ */
+static void dump()
+{
+ dump_vifs(stderr);
+ dump_routes(stderr);
+}
+
+
+/*
+ * Dump internal data structures to a file.
+ */
+static void fdump()
+{
+ FILE *fp;
+
+ fp = fopen(dumpfilename, "w");
+ if (fp != NULL) {
+ dump_vifs(fp);
+ dump_routes(fp);
+ (void) fclose(fp);
+ }
+}
+
+
+/*
+ * Log errors and other messages to the system log daemon and to stderr,
+ * according to the severity of the message and the current debug level.
+ * For errors of severity LOG_ERR or worse, terminate the program.
+ */
+void log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0: break;
+ case 1: if (severity > LOG_NOTICE) break;
+ case 2: if (severity > LOG_INFO ) break;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if(syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_NOTICE) {
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ if (syserr != 0) {
+ strcat(fmt, ": %m");
+ errno = syserr;
+ }
+ syslog(severity, fmt, a, b, c, d, e);
+
+ if (severity <= LOG_ERR) exit(-1);
+ }
+}
diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c
new file mode 100644
index 000000000000..cdc2e875611b
--- /dev/null
+++ b/usr.sbin/mrouted/mapper.c
@@ -0,0 +1,932 @@
+/* Mapper for connections between MRouteD multicast routers.
+ * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
+ *
+ * $Id: mapper.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $
+ */
+
+/*
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative
+ * works for research and evaluation purposes, provided that Xerox is
+ * acknowledged in all documentation pertaining to any such copy or derivative
+ * work. Xerox grants no other licenses expressed or implied. The Xerox trade
+ * name should not be used in any advertising without its written permission.
+ *
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
+ * FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without
+ * express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 2 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 1 /* How many times to ask each router */
+
+
+/* All IP addresses are stored in the data structure in NET order. */
+
+typedef struct neighbor {
+ struct neighbor *next;
+ u_long addr; /* IP address in NET order */
+ u_char metric; /* TTL cost of forwarding */
+ u_char threshold; /* TTL threshold to forward */
+ u_short flags; /* flags on connection */
+#define NF_PRESENT 0x8000 /* True if flags are meaningful */
+} Neighbor;
+
+typedef struct interface {
+ struct interface *next;
+ u_long addr; /* IP address of the interface in NET order */
+ Neighbor *neighbors; /* List of neighbors' IP addresses */
+} Interface;
+
+typedef struct node {
+ u_long addr; /* IP address of this entry in NET order */
+ u_long version; /* which mrouted version is running */
+ int tries; /* How many requests sent? -1 for aliases */
+ union {
+ struct node *alias; /* If alias, to what? */
+ struct interface *interfaces; /* Else, neighbor data */
+ } u;
+ struct node *left, *right;
+} Node;
+
+
+Node *routers = 0;
+u_long our_addr, target_addr = 0; /* in NET order */
+int debug = 0;
+int retries = DEFAULT_RETRIES;
+int timeout = DEFAULT_TIMEOUT;
+int show_names = TRUE;
+
+
+Node *find_node(addr, ptr)
+ u_long addr;
+ Node **ptr;
+{
+ Node *n = *ptr;
+
+ if (!n) {
+ *ptr = n = (Node *) malloc(sizeof(Node));
+ n->addr = addr;
+ n->version = 0;
+ n->tries = 0;
+ n->u.interfaces = 0;
+ n->left = n->right = 0;
+ return n;
+ } else if (addr == n->addr)
+ return n;
+ else if (addr < n->addr)
+ return find_node(addr, &(n->left));
+ else
+ return find_node(addr, &(n->right));
+}
+
+
+Interface *find_interface(addr, node)
+ u_long addr;
+ Node *node;
+{
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
+ if (ifc->addr == addr)
+ return ifc;
+
+ ifc = (Interface *) malloc(sizeof(Interface));
+ ifc->addr = addr;
+ ifc->next = node->u.interfaces;
+ node->u.interfaces = ifc;
+ ifc->neighbors = 0;
+
+ return ifc;
+}
+
+
+Neighbor *find_neighbor(addr, node)
+ u_long addr;
+ Node *node;
+{
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+
+ for (nb = ifc->neighbors; nb; nb = nb->next)
+ if (nb->addr == addr)
+ return nb;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Log errors and other messages to stderr, according to the severity of the
+ * message and the current debug level. For errors of severity LOG_ERR or
+ * worse, terminate the program.
+ */
+void log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0: if (severity > LOG_WARNING) return;
+ case 1: if (severity > LOG_NOTICE ) return;
+ case 2: if (severity > LOG_INFO ) return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING)
+ strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if (syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+
+/*
+ * Send a neighbors-list request.
+ */
+void ask(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void ask2(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+
+/*
+ * Process an incoming group membership report.
+ */
+void accept_group_report(src, dst, group)
+ u_long src, dst, group;
+{
+ log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void accept_probe(src, dst)
+ u_long src, dst;
+{
+ log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming route report message.
+ */
+void accept_report(src, dst, p, datalen)
+ u_long src, dst;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring DVMRP routing report from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list request message.
+ */
+void accept_neighbor_request(src, dst)
+ u_long src, dst;
+{
+ if (src != our_addr)
+ log(LOG_INFO, 0,
+ "ignoring spurious DVMRP neighbor request from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+void accept_neighbor_request2(src, dst)
+ u_long src, dst;
+{
+ if (src != our_addr)
+ log(LOG_INFO, 0,
+ "ignoring spurious DVMRP neighbor request2 from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors(src, dst, p, datalen, level)
+ u_long src, dst, level;
+ u_char *p;
+ int datalen;
+{
+ Node *node = find_node(src, &routers);
+
+ if (node->tries == 0) /* Never heard of 'em; must have hit them at */
+ node->tries = 1; /* least once, though...*/
+ else if (node->tries == -1) /* follow alias link */
+ node = node->u.alias;
+
+#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
+ a += ((u_long)*p++ << 8), a += *p++)
+
+ /* if node is running a recent mrouted, ask for additional info */
+ if (level != 0) {
+ node->version = ntohl(level);
+ node->tries = 0;
+ ask2(src);
+ return;
+ }
+
+ if (debug > 3) {
+ int i;
+
+ fprintf(stderr, " datalen = %d\n", datalen);
+ for (i = 0; i < datalen; i++) {
+ if ((i & 0xF) == 0)
+ fprintf(stderr, " ");
+ fprintf(stderr, " %02x", p[i]);
+ if ((i & 0xF) == 0xF)
+ fprintf(stderr, "\n");
+ }
+ if ((datalen & 0xF) != 0xF)
+ fprintf(stderr, "\n");
+ }
+
+ while (datalen > 0) { /* loop through interfaces */
+ u_long ifc_addr;
+ u_char metric, threshold, ncount;
+ Node *ifc_node;
+ Interface *ifc;
+ Neighbor *old_neighbors;
+
+ if (datalen < 4 + 3) {
+ log(LOG_WARNING, 0, "received truncated interface record from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ GET_ADDR(ifc_addr);
+ ifc_addr = htonl(ifc_addr);
+ metric = *p++;
+ threshold = *p++;
+ ncount = *p++;
+ datalen -= 4 + 3;
+
+ /* Fix up any alias information */
+ ifc_node = find_node(ifc_addr, &routers);
+ if (ifc_node->tries == 0) { /* new node */
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ } else if (ifc_node != node
+ && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
+ /* must merge two hosts' nodes */
+ Interface *ifc_i, *next_ifc_i;
+
+ if (ifc_node->tries == -1) {
+ Node *tmp = ifc_node->u.alias;
+
+ ifc_node->u.alias = node;
+ ifc_node = tmp;
+ }
+
+ /* Merge ifc_node (foo_i) into node (foo_n) */
+
+ if (ifc_node->tries > node->tries)
+ node->tries = ifc_node->tries;
+
+ for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
+ Neighbor *nb_i, *next_nb_i, *nb_n;
+ Interface *ifc_n = find_interface(ifc_i->addr, node);
+
+ old_neighbors = ifc_n->neighbors;
+ for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
+ next_nb_i = nb_i->next;
+ for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
+ if (nb_i->addr == nb_n->addr) {
+ if (nb_i->metric != nb_n->metric
+ || nb_i->threshold != nb_i->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb_i->addr, s1),
+ inet_fmt(node->addr, s2));
+ free(nb_i);
+ break;
+ }
+ if (!nb_n) { /* no match for this neighbor yet */
+ nb_i->next = ifc_n->neighbors;
+ ifc_n->neighbors = nb_i;
+ }
+ }
+
+ next_ifc_i = ifc_i->next;
+ free(ifc_i);
+ }
+
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ }
+
+ ifc = find_interface(ifc_addr, node);
+ old_neighbors = ifc->neighbors;
+
+ /* Add the neighbors for this interface */
+ while (ncount--) {
+ u_long neighbor;
+ Neighbor *nb;
+ Node *n_node;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0, "received truncated neighbor list from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ GET_ADDR(neighbor);
+ neighbor = htonl(neighbor);
+ datalen -= 4;
+
+ for (nb = old_neighbors; nb; nb = nb->next)
+ if (nb->addr == neighbor) {
+ if (metric != nb->metric || threshold != nb->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
+ goto next_neighbor;
+ }
+
+ nb = (Neighbor *) malloc(sizeof(Neighbor));
+ nb->next = ifc->neighbors;
+ ifc->neighbors = nb;
+ nb->addr = neighbor;
+ nb->metric = metric;
+ nb->threshold = threshold;
+ nb->flags = 0;
+
+ n_node = find_node(neighbor, &routers);
+ if (n_node->tries == 0 && !target_addr) { /* it's a new router */
+ ask(neighbor);
+ n_node->tries = 1;
+ }
+
+ next_neighbor: ;
+ }
+ }
+}
+
+void accept_neighbors2(src, dst, p, datalen)
+ u_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ Node *node = find_node(src, &routers);
+
+ if (node->tries == 0) /* Never heard of 'em; must have hit them at */
+ node->tries = 1; /* least once, though...*/
+ else if (node->tries == -1) /* follow alias link */
+ node = node->u.alias;
+
+ while (datalen > 0) { /* loop through interfaces */
+ u_long ifc_addr;
+ u_char metric, threshold, ncount, flags;
+ Node *ifc_node;
+ Interface *ifc;
+ Neighbor *old_neighbors;
+
+ if (datalen < 4 + 4) {
+ log(LOG_WARNING, 0, "received truncated interface record from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ ifc_addr = *(u_long*)p;
+ p += 4;
+ metric = *p++;
+ threshold = *p++;
+ flags = *p++;
+ ncount = *p++;
+ datalen -= 4 + 4;
+
+ /* Fix up any alias information */
+ ifc_node = find_node(ifc_addr, &routers);
+ if (ifc_node->tries == 0) { /* new node */
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ } else if (ifc_node != node
+ && (ifc_node->tries > 0 || ifc_node->u.alias != node)) {
+ /* must merge two hosts' nodes */
+ Interface *ifc_i, *next_ifc_i;
+
+ if (ifc_node->tries == -1) {
+ Node *tmp = ifc_node->u.alias;
+
+ ifc_node->u.alias = node;
+ ifc_node = tmp;
+ }
+
+ /* Merge ifc_node (foo_i) into node (foo_n) */
+
+ if (ifc_node->tries > node->tries)
+ node->tries = ifc_node->tries;
+
+ for (ifc_i = ifc_node->u.interfaces; ifc_i; ifc_i = next_ifc_i) {
+ Neighbor *nb_i, *next_nb_i, *nb_n;
+ Interface *ifc_n = find_interface(ifc_i->addr, node);
+
+ old_neighbors = ifc_n->neighbors;
+ for (nb_i = ifc_i->neighbors; nb_i; nb_i = next_nb_i) {
+ next_nb_i = nb_i->next;
+ for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
+ if (nb_i->addr == nb_n->addr) {
+ if (nb_i->metric != nb_n->metric
+ || nb_i->threshold != nb_i->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb_i->addr, s1),
+ inet_fmt(node->addr, s2));
+ free(nb_i);
+ break;
+ }
+ if (!nb_n) { /* no match for this neighbor yet */
+ nb_i->next = ifc_n->neighbors;
+ ifc_n->neighbors = nb_i;
+ }
+ }
+
+ next_ifc_i = ifc_i->next;
+ free(ifc_i);
+ }
+
+ ifc_node->tries = -1;
+ ifc_node->u.alias = node;
+ }
+
+ ifc = find_interface(ifc_addr, node);
+ old_neighbors = ifc->neighbors;
+
+ /* Add the neighbors for this interface */
+ while (ncount--) {
+ u_long neighbor;
+ Neighbor *nb;
+ Node *n_node;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0, "received truncated neighbor list from %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ neighbor = *(u_long*)p;
+ p += 4;
+ datalen -= 4;
+ if (neighbor == 0)
+ /* make leaf nets point to themselves */
+ neighbor = ifc_addr;
+
+ for (nb = old_neighbors; nb; nb = nb->next)
+ if (nb->addr == neighbor) {
+ if (metric != nb->metric || threshold != nb->threshold)
+ log(LOG_WARNING, 0,
+ "inconsistent %s for neighbor %s of %s",
+ "metric/threshold",
+ inet_fmt(nb->addr, s1), inet_fmt(node->addr, s2));
+ goto next_neighbor;
+ }
+
+ nb = (Neighbor *) malloc(sizeof(Neighbor));
+ nb->next = ifc->neighbors;
+ ifc->neighbors = nb;
+ nb->addr = neighbor;
+ nb->metric = metric;
+ nb->threshold = threshold;
+ nb->flags = flags | NF_PRESENT;
+
+ n_node = find_node(neighbor, &routers);
+ if (n_node->tries == 0 && !target_addr) { /* it's a new router */
+ ask(neighbor);
+ n_node->tries = 1;
+ }
+
+ next_neighbor: ;
+ }
+ }
+}
+
+
+void check_vif_state()
+{
+ log(LOG_NOTICE, 0, "network marked down...");
+}
+
+
+int retry_requests(node)
+ Node *node;
+{
+ int result;
+
+ if (node) {
+ result = retry_requests(node->left);
+ if (node->tries > 0 && node->tries < retries) {
+ if (node->version)
+ ask2(node->addr);
+ else
+ ask(node->addr);
+ node->tries++;
+ result = 1;
+ }
+ return retry_requests(node->right) || result;
+ } else
+ return 0;
+}
+
+
+char *inet_name(addr)
+ u_long addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : 0;
+}
+
+
+void print_map(node)
+ Node *node;
+{
+ if (node) {
+ char *name, *addr;
+
+ print_map(node->left);
+
+ addr = inet_fmt(node->addr, s1);
+ if (!target_addr
+ || (node->tries >= 0 && node->u.interfaces)
+ || (node->tries == -1
+ && node->u.alias->tries >= 0
+ && node->u.alias->u.interfaces)) {
+ if (show_names && (name = inet_name(node->addr)))
+ printf("%s (%s):", addr, name);
+ else
+ printf("%s:", addr);
+ if (node->tries < 0)
+ printf(" alias for %s\n\n", inet_fmt(node->u.alias->addr, s1));
+ else if (!node->u.interfaces)
+ printf(" no response to query\n\n");
+ else {
+ Interface *ifc;
+
+ if (node->version)
+ printf(" <v%d.%d>", node->version & 0xff,
+ (node->version >> 8) & 0xff);
+ printf("\n");
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+ char *ifc_name = inet_fmt(ifc->addr, s1);
+ int ifc_len = strlen(ifc_name);
+ int count = 0;
+
+ printf(" %s:", ifc_name);
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ if (count > 0)
+ printf("%*s", ifc_len + 5, "");
+ printf(" %s", inet_fmt(nb->addr, s1));
+ if (show_names && (name = inet_name(nb->addr)))
+ printf(" (%s)", name);
+ printf(" [%d/%d", nb->metric, nb->threshold);
+ if (nb->flags) {
+ u_short flags = nb->flags;
+ if (flags & DVMRP_NF_TUNNEL)
+ printf("/tunnel");
+ if (flags & DVMRP_NF_SRCRT)
+ printf("/srcrt");
+ if (flags & DVMRP_NF_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ }
+ printf("]\n");
+ count++;
+ }
+ }
+ printf("\n");
+ }
+ }
+ print_map(node->right);
+ }
+}
+
+
+char *graph_name(addr, buf)
+ u_long addr;
+ char *buf;
+{
+ char *name;
+
+ if (show_names && (name = inet_name(addr)))
+ strcpy(buf, name);
+ else
+ inet_fmt(addr, buf);
+
+ return buf;
+}
+
+
+void graph_edges(node)
+ Node *node;
+{
+ Interface *ifc;
+ Neighbor *nb;
+ char name[100];
+
+ if (node) {
+ graph_edges(node->left);
+ if (node->tries >= 0) {
+ printf(" %d {$ NP %d0 %d0 $} \"%s%s\" \n",
+ (int) node->addr,
+ node->addr & 0xFF, (node->addr >> 8) & 0xFF,
+ graph_name(node->addr, name),
+ node->u.interfaces ? "" : "*");
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next)
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ Node *nb_node = find_node(nb->addr, &routers);
+ Neighbor *nb2;
+
+ if (nb_node->tries < 0)
+ nb_node = nb_node->u.alias;
+
+ if (node != nb_node &&
+ (!(nb2 = find_neighbor(node->addr, nb_node))
+ || node->addr < nb_node->addr)) {
+ printf(" %d \"%d/%d",
+ nb_node->addr, nb->metric, nb->threshold);
+ if (nb2 && (nb2->metric != nb->metric
+ || nb2->threshold != nb->threshold))
+ printf(",%d/%d", nb2->metric, nb2->threshold);
+ if (nb->flags & NF_PRESENT)
+ printf("%s%s",
+ nb->flags & DVMRP_NF_SRCRT ? "" :
+ nb->flags & DVMRP_NF_TUNNEL ? "E" : "P",
+ nb->flags & DVMRP_NF_DOWN ? "D" : "");
+ printf("\"\n");
+ }
+ }
+ printf(" ;\n");
+ }
+ graph_edges(node->right);
+ }
+}
+
+void elide_aliases(node)
+ Node *node;
+{
+ if (node) {
+ elide_aliases(node->left);
+ if (node->tries >= 0) {
+ Interface *ifc;
+
+ for (ifc = node->u.interfaces; ifc; ifc = ifc->next) {
+ Neighbor *nb;
+
+ for (nb = ifc->neighbors; nb; nb = nb->next) {
+ Node *nb_node = find_node(nb->addr, &routers);
+
+ if (nb_node->tries < 0)
+ nb->addr = nb_node->u.alias->addr;
+ }
+ }
+ }
+ elide_aliases(node->right);
+ }
+}
+
+void graph_map()
+{
+ time_t now = time(0);
+ char *nowstr = ctime(&now);
+
+ nowstr[24] = '\0'; /* Kill the newline at the end */
+ elide_aliases(routers);
+ printf("GRAPH \"Multicast Router Connectivity: %s\" = UNDIRECTED\n",
+ nowstr);
+ graph_edges(routers);
+ printf("END\n");
+}
+
+
+int get_number(var, deflt, pargv, pargc)
+ int *var, *pargc, deflt;
+ char ***pargv;
+{
+ if ((*pargv)[0][2] == '\0') { /* Get the value from the next argument */
+ if (*pargc > 1 && isdigit((*pargv)[1][0])) {
+ (*pargv)++, (*pargc)--;
+ *var = atoi((*pargv)[0]);
+ return 1;
+ } else if (deflt >= 0) {
+ *var = deflt;
+ return 1;
+ } else
+ return 0;
+ } else { /* Get value from the rest of this argument */
+ if (isdigit((*pargv)[0][2])) {
+ *var = atoi((*pargv)[0] + 2);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+u_long host_addr(name)
+ char *name;
+{
+ struct hostent *e = gethostbyname(name);
+ int addr;
+
+ if (e)
+ memcpy(&addr, e->h_addr_list[0], e->h_length);
+ else {
+ addr = inet_addr(name);
+ if (addr == -1)
+ addr = 0;
+ }
+
+ return addr;
+}
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int flood = FALSE, graph = FALSE;
+
+#ifdef SYSV
+ setvbuf(stderr, NULL, _IOLBF, 0);
+#else
+ setlinebuf(stderr);
+#endif
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "must be root\n");
+ exit(1);
+ }
+
+ argv++, argc--;
+ while (argc > 0 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'd':
+ if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
+ goto usage;
+ break;
+ case 'f':
+ flood = TRUE;
+ break;
+ case 'g':
+ graph = TRUE;
+ break;
+ case 'n':
+ show_names = FALSE;
+ break;
+ case 'r':
+ if (!get_number(&retries, -1, &argv, &argc))
+ goto usage;
+ break;
+ case 't':
+ if (!get_number(&timeout, -1, &argv, &argc))
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ argv++, argc--;
+ }
+
+ if (argc > 1) {
+ usage:
+ fprintf(stderr,
+ "Usage: map-mbone [-f] [-g] [-n] [-t timeout] %s\n\n",
+ "[-r retries] [-d [debug-level]] [router]");
+ fprintf(stderr, "\t-f Flood the routing graph with queries\n");
+ fprintf(stderr, "\t (True by default unless `router' is given)\n");
+ fprintf(stderr, "\t-g Generate output in GraphEd format\n");
+ fprintf(stderr, "\t-n Don't look up DNS names for routers\n");
+ exit(1);
+ } else if (argc == 1 && !(target_addr = host_addr(argv[0]))) {
+ fprintf(stderr, "Unknown host: %s\n", argv[0]);
+ exit(2);
+ }
+
+ if (debug)
+ fprintf(stderr, "Debug level %u\n", debug);
+
+ init_igmp();
+
+ { /* Find a good local address for us. */
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = dvmrp_group;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+ close(udp);
+ our_addr = addr.sin_addr.s_addr;
+ }
+
+ /* Send initial seed message to all local routers */
+ ask(target_addr ? target_addr : allhosts_group);
+
+ if (target_addr) {
+ Node *n = find_node(target_addr, &routers);
+
+ n->tries = 1;
+
+ if (flood)
+ target_addr = 0;
+ }
+
+ /* Main receive loop */
+ for(;;) {
+ fd_set fds;
+ struct timeval tv;
+ int count, recvlen, dummy = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, 0, 0, &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
+ if (retry_requests(routers))
+ continue;
+ else
+ break;
+ }
+
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 0, NULL, &dummy);
+ if (recvlen >= 0)
+ accept_igmp(recvlen);
+ else if (errno != EINTR)
+ perror("recvfrom");
+ }
+
+ printf("\n");
+
+ if (graph)
+ graph_map();
+ else {
+ if (!target_addr)
+ printf("Multicast Router Connectivity:\n\n");
+ print_map(routers);
+ }
+
+ exit(0);
+}
diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c
new file mode 100644
index 000000000000..c9451348c09e
--- /dev/null
+++ b/usr.sbin/mrouted/mrinfo.c
@@ -0,0 +1,469 @@
+/*
+ * This tool requests configuration info from a multicast router
+ * and prints the reply (if any). Invoke it as:
+ *
+ * mrinfo router-name-or-address
+ *
+ * Written Wed Mar 24 1993 by Van Jacobson (adapted from the
+ * multicast mapper written by Pavel Curtis).
+ *
+ * The lawyers insist we include the following UC copyright notice.
+ * The mapper from which this is derived contained a Xerox copyright
+ * notice which follows the UC one. Try not to get depressed noting
+ * that the legal gibberish is larger than the program.
+ *
+ * Copyright (c) 1993 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 Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory 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.
+ * ---------------------------------
+ * Copyright (c) Xerox Corporation 1992. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Xerox is acknowledged
+ * in all documentation pertaining to any such copy or derivative work. Xerox
+ * grants no other licenses expressed or implied. The Xerox trade name should
+ * not be used in any advertising without its written permission.
+ *
+ * XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE FOR
+ * ANY PARTICULAR PURPOSE. The software is provided "as is" without express
+ * or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Id: mrinfo.c,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $";
+/* original rcsid:
+ "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
+*/
+#endif
+
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 3 /* How many times to ask each router */
+
+u_long our_addr, target_addr = 0; /* in NET order */
+int debug = 0;
+int retries = DEFAULT_RETRIES;
+int timeout = DEFAULT_TIMEOUT;
+int target_level;
+
+char *
+inet_name(addr)
+ u_long addr;
+{
+ struct hostent *e;
+
+ if (addr == 0)
+ return "local";
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : "?";
+}
+
+/*
+ * Log errors and other messages to stderr, according to the severity of the
+ * message and the current debug level. For errors of severity LOG_ERR or
+ * worse, terminate the program.
+ */
+void
+log(severity, syserr, format, a, b, c, d, e)
+ int severity, syserr;
+ char *format;
+ int a, b, c, d, e;
+{
+ char fmt[100];
+
+ switch (debug) {
+ case 0:
+ if (severity > LOG_WARNING)
+ return;
+ case 1:
+ if (severity > LOG_NOTICE)
+ return;
+ case 2:
+ if (severity > LOG_INFO)
+ return;
+ default:
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING)
+ strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ fprintf(stderr, fmt, a, b, c, d, e);
+ if (syserr == 0)
+ fprintf(stderr, "\n");
+ else if (syserr < sys_nerr)
+ fprintf(stderr, ": %s\n", sys_errlist[syserr]);
+ else
+ fprintf(stderr, ": errno %d\n", syserr);
+ }
+
+ if (severity <= LOG_ERR)
+ exit(-1);
+}
+
+/*
+ * Send a neighbors-list request.
+ */
+void
+ask(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void
+ask2(dst)
+ u_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void
+accept_neighbors(src, dst, p, datalen)
+ u_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
+ a += ((u_long)*p++ << 8), a += *p++)
+
+ printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
+ while (p < ep) {
+ register u_long laddr;
+ register u_char metric;
+ register u_char thresh;
+ register int ncount;
+
+ GET_ADDR(laddr);
+ laddr = htonl(laddr);
+ metric = *p++;
+ thresh = *p++;
+ ncount = *p++;
+ while (--ncount >= 0) {
+ register u_long neighbor;
+ GET_ADDR(neighbor);
+ neighbor = htonl(neighbor);
+ printf(" %s -> ", inet_fmt(laddr, s1));
+ printf("%s (%s) [%d/%d]\n", inet_fmt(neighbor, s1),
+ inet_name(neighbor), metric, thresh);
+ }
+ }
+}
+
+void
+accept_neighbors2(src, dst, p, datalen)
+ u_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+
+ printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
+ target_level & 0xff, (target_level >> 8) & 0xff);
+ while (p < ep) {
+ register u_char metric;
+ register u_char thresh;
+ register u_char flags;
+ register int ncount;
+ register u_long laddr = *(u_long*)p;
+
+ p += 4;
+ metric = *p++;
+ thresh = *p++;
+ flags = *p++;
+ ncount = *p++;
+ while (--ncount >= 0) {
+ register u_long neighbor = *(u_long*)p;
+ p += 4;
+ printf(" %s -> ", inet_fmt(laddr, s1));
+ printf("%s (%s) [%d/%d", inet_fmt(neighbor, s1),
+ inet_name(neighbor), metric, thresh);
+ if (flags & DVMRP_NF_TUNNEL)
+ printf("/tunnel");
+ if (flags & DVMRP_NF_SRCRT)
+ printf("/srcrt");
+ if (flags & DVMRP_NF_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ printf("]\n");
+ }
+ }
+}
+
+int
+get_number(var, deflt, pargv, pargc)
+ int *var, *pargc, deflt;
+ char ***pargv;
+{
+ if ((*pargv)[0][2] == '\0') { /* Get the value from the next
+ * argument */
+ if (*pargc > 1 && isdigit((*pargv)[1][0])) {
+ (*pargv)++, (*pargc)--;
+ *var = atoi((*pargv)[0]);
+ return 1;
+ } else if (deflt >= 0) {
+ *var = deflt;
+ return 1;
+ } else
+ return 0;
+ } else { /* Get value from the rest of this argument */
+ if (isdigit((*pargv)[0][2])) {
+ *var = atoi((*pargv)[0] + 2);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+u_long
+host_addr(name)
+ char *name;
+{
+ struct hostent *e = gethostbyname(name);
+ int addr;
+
+ if (e)
+ memcpy(&addr, e->h_addr_list[0], e->h_length);
+ else {
+ addr = inet_addr(name);
+ if (addr == -1)
+ addr = 0;
+ }
+
+ return addr;
+}
+
+void
+usage()
+{
+ fprintf(stderr, "Usage: mrinfo [-t timeout] [-r retries] router\n");
+ exit(1);
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ setlinebuf(stderr);
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "mrinfo: must be root\n");
+ exit(1);
+ }
+ argv++, argc--;
+ while (argc > 0 && argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'd':
+ if (!get_number(&debug, DEFAULT_DEBUG, &argv, &argc))
+ usage();
+ break;
+ case 'r':
+ if (!get_number(&retries, -1, &argv, &argc))
+ usage();
+ break;
+ case 't':
+ if (!get_number(&timeout, -1, &argv, &argc))
+ usage();
+ break;
+ default:
+ usage();
+ }
+ argv++, argc--;
+ }
+ if (argc != 1)
+ usage();
+
+ target_addr = host_addr(argv[0]);
+ if (target_addr == 0) {
+ fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
+ exit(1);
+ }
+ if (debug)
+ fprintf(stderr, "Debug level %u\n", debug);
+
+ init_igmp();
+
+ { /* Find a good local address for us. */
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = target_addr;
+ addr.sin_port = htons(2000); /* any port over 1024 will
+ * do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) & addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) & addr, &addrlen) < 0) {
+ perror("Determining local address");
+ exit(-1);
+ }
+ close(udp);
+ our_addr = addr.sin_addr.s_addr;
+ }
+
+ ask(target_addr);
+
+ /* Main receive loop */
+ for (;;) {
+ fd_set fds;
+ struct timeval tv;
+ int count, recvlen, dummy = 0;
+ register u_long src, dst, group;
+ struct ip *ip;
+ struct igmp *igmp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ count = select(igmp_socket + 1, &fds, 0, 0, &tv);
+
+ if (count < 0) {
+ if (errno != EINTR)
+ perror("select");
+ continue;
+ } else if (count == 0) {
+ log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
+ if (--retries < 0)
+ exit(1);
+ if (target_level == 0)
+ ask(target_addr);
+ else
+ ask2(target_addr);
+ continue;
+ }
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 0, NULL, &dummy);
+ if (recvlen <= 0) {
+ if (recvlen && errno != EINTR)
+ perror("recvfrom");
+ continue;
+ }
+
+ if (recvlen < sizeof(struct ip)) {
+ log(LOG_WARNING, 0,
+ "packet too short (%u bytes) for IP header",
+ recvlen);
+ continue;
+ }
+ ip = (struct ip *) recv_buf;
+ src = ip->ip_src.s_addr;
+ if (src != target_addr) {
+ fprintf(stderr, "mrinfo: got reply from %s",
+ inet_fmt(src, s1));
+ fprintf(stderr, " instead of %s\n",
+ inet_fmt(target_addr, s1));
+ continue;
+ }
+ dst = ip->ip_dst.s_addr;
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ log(LOG_WARNING, 0,
+ "packet shorter (%u bytes) than hdr+data length (%u+%u)",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ log(LOG_WARNING, 0,
+ "IP data field too short (%u bytes) for IGMP, from %s",
+ ipdatalen, inet_fmt(src, s1));
+ continue;
+ }
+ if (igmp->igmp_type != IGMP_DVMRP)
+ continue;
+
+ switch (igmp->igmp_code) {
+
+ case DVMRP_NEIGHBORS:
+ if (group) {
+ /* knows about DVMRP_NEIGHBORS2 msg */
+ if (target_level == 0) {
+ target_level = ntohl(group);
+ ask2(target_addr);
+ }
+ } else {
+ accept_neighbors(src, dst, (char *)(igmp + 1),
+ igmpdatalen);
+ exit(0);
+ }
+ break;
+
+ case DVMRP_NEIGHBORS2:
+ accept_neighbors2(src, dst, (char *)(igmp + 1),
+ igmpdatalen);
+ exit(0);
+ }
+ }
+}
+
+/* dummies */
+void accept_probe()
+{
+}
+void accept_group_report()
+{
+}
+void accept_neighbor_request2()
+{
+}
+void accept_report()
+{
+}
+void accept_neighbor_request()
+{
+}
+void check_vif_state()
+{
+}
diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8
new file mode 100644
index 000000000000..5013bc7c9e5b
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.8
@@ -0,0 +1,242 @@
+'\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
+.TH MROUTED 8
+.UC 5
+.SH NAME
+mrouted \- IP multicast routing daemon
+.SH SYNOPSIS
+.B /etc/mrouted
+[
+.B \-c
+.I config_file
+] [
+.B \-d
+[
+.I debug_level
+] ]
+.SH DESCRIPTION
+.I Mrouted
+is an implementation of the Distance-Vector Multicast Routing
+Protocol (DVMRP), an earlier version of which is specified in RFC-1075.
+It maintains topological knowledge via a distance-vector routing protocol
+(like RIP, described in RFC-1058), upon which it implements a multicast
+forwarding algorithm called Truncated Reverse Path Broadcasting (TRPB).
+.PP
+.I Mrouted
+forwards a multicast datagram along a shortest (reverse) path tree
+rooted at the subnet on which the datagram originates. It is a
+.I broadcast
+tree, which means it includes
+.I all
+subnets reachable by a cooperating set of
+.I mrouted
+routers. However, the datagram will not be forwarded onto
+.I leaf
+subnets of the tree if those subnets do not have members of the destination
+group. Furthermore, the IP time-to-live of a multicast datagram may prevent
+it from being forwarded along the entire tree.
+.PP
+In order to support multicasting among subnets that are separated by (unicast)
+routers that do not support IP multicasting,
+.I mrouted
+includes support for
+"tunnels", which are virtual point-to-point links between pairs of
+.IR mrouted s
+located anywhere in an internet. IP multicast packets are encapsulated for
+transmission through tunnels, so that they look like normal unicast datagrams
+to intervening routers and subnets. The encapsulation
+is inserted on entry to a tunnel, and stripped out
+on exit from a tunnel.
+By default, the packets are encapsulated using the IP-in-IP protocol
+(IP protocol number 4).
+Older versions of
+.I mrouted
+encapsulate using IP source routing, which puts a heavy load on some
+types of routers.
+This version supports IP source route encapsulation only for backwards
+compatibility.
+.PP
+The tunnel mechanism allows
+.I mrouted
+to establish a virtual internet, for
+the purpose of multicasting only, which is independent of the physical
+internet, and which may span multiple Autonomous Systems. This capability
+is intended for experimental support of internet multicasting only, pending
+widespread support for multicast routing by the regular (unicast) routers.
+.I Mrouted
+suffers from the well-known scaling problems of any distance-vector
+routing protocol, and does not (yet) support hierarchical multicast routing
+or inter-operation with other multicast routing protocols.
+.PP
+.I Mrouted
+handles multicast routing only; there may or may not be a unicast
+router running on the same host as
+.IR mrouted .
+With the use of tunnels, it
+is not necessary for
+.I mrouted
+to have access to more than one physical subnet
+in order to perform multicast forwarding.
+.br
+.ne 5
+.SH INVOCATION
+.PP
+If no "\-d" option is given, or if the debug level is specified as 0,
+.I mrouted
+detaches from the invoking terminal. Otherwise, it remains attached to the
+invoking terminal and responsive to signals from that terminal. If "\-d" is
+given with no argument, the debug level defaults to 2. Regardless of the
+debug level,
+.I mrouted
+always writes warning and error messages to the system
+log demon. Non-zero debug levels have the following effects:
+.IP "level 1"
+all syslog'ed messages are also printed to stderr.
+.IP "level 2"
+all level 1 messages plus notifications of "significant"
+events are printed to stderr.
+.IP "level 3"
+all level 2 messages plus notifications of all packet
+arrivals and departures are printed to stderr.
+.SH CONFIGURATION
+.PP
+.I Mrouted
+automatically configures itself to forward on all multicast-capable
+interfaces, i.e., interfaces that have the IFF_MULTICAST flag set (excluding
+the loopback "interface"), and it finds other
+.IR mrouted s
+directly reachable
+via those interfaces. To override the default configuration, or to add
+tunnel links to other
+.IR mrouted s,
+configuration commands may be placed in
+/etc/mrouted.conf (or an alternative file, specified by the "\-c" option).
+There are two types of configuration command:
+.nf
+
+ phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+
+ tunnel <local-addr> <remote-addr> [metric <m>] [threshold <t>] [srcrt]
+
+.fi
+The phyint command can be used to disable multicast routing on the physical
+interface identified by local IP address <local-addr>, or to associate a
+non-default metric or threshold with the specified physical interface.
+Phyint commands must precede tunnel commands.
+.PP
+The tunnel command can be used to establish a tunnel link between local
+IP address <local-addr> and remote IP address <remote-addr>, and to associate
+a non-default metric or threshold with that tunnel. The tunnel must be set
+up in the mrouted.conf files of both ends before it will be used.
+For backwards compatibility with older
+.IR mrouted s,
+the srcrt keyword specifies
+encapsulation using IP source routing.
+.PP
+The metric is the "cost" associated with sending a datagram on the given
+interface or tunnel; it may be used to influence the choice of routes.
+The metric defaults to 1. Metrics should be kept as small as possible,
+because
+.I mrouted
+cannot route along paths with a sum of metrics greater
+than 31. When in doubt, the following metrics are recommended:
+.ne 5
+.IP 1
+LAN, or tunnel across a single LAN
+.IP 2
+serial link, or tunnel across a single serial link
+.IP 3
+multi-hop tunnel
+.LP
+The threshold is the minimum IP time-to-live required for a multicast datagram
+to be forwarded to the given interface or tunnel. It is used to control the
+scope of multicast datagrams. (The TTL of forwarded packets is only compared
+to the threshold, it is not decremented by the threshold. Every multicast
+router decrements the TTL by 1.) The default threshold is 1.
+Suggested thresholds:
+.IP 32
+for links that separate sites,
+.IP 64
+for links that separate regions,
+.IP 128
+for links that separate continents.
+.LP
+In general, all
+.IR mrouted s
+connected to a particular subnet or tunnel should
+use the same metric and threshold for that subnet or tunnel.
+.PP
+.I Mrouted
+will not initiate execution if it has fewer than two enabled vifs,
+where a vif (virtual interface) is either a physical multicast-capable
+interface or a tunnel. It will log a warning if all of its vifs are
+tunnels; such an
+.I mrouted
+configuration would be better replaced by more
+direct tunnels (i.e., eliminate the middle man).
+.SH SIGNALS
+.PP
+.I Mrouted
+responds to the following signals:
+.IP HUP
+.sp -.5v
+.IP TERM
+.sp -.5v
+.IP INT
+terminates execution gracefully (i.e., by sending
+good-bye messages to all neighboring routers).
+.IP USR1
+dumps the internal routing tables to /usr/tmp/mrouted.dump.
+.IP QUIT
+dumps the internal routing tables to stderr (only if
+.I mrouted
+was invoked with a non-zero debug level).
+.bp
+.SH EXAMPLE
+.PP
+The routing tables look like this:
+.nf
+
+Virtual Interface Table
+ Vif Local-Address Metric Thresh Flags
+ 0 36.2.0.8 subnet: 36.2 1 1 querier
+ groups: 224.0.2.1
+ 224.0.0.4
+ 1 36.11.0.1 subnet: 36.11 1 1 querier
+ groups: 224.0.2.1
+ 224.0.1.0
+ 224.0.0.4
+ 2 36.2.0.8 tunnel: 36.8.0.77 3 1
+ peers : 36.8.0.77
+ 3 36.2.0.8 tunnel: 36.8.0.110 3 1
+
+Multicast Routing Table
+ Origin-Subnet From-Gateway Metric In-Vif Out-Vifs
+ 36.2 1 0 1* 2 3*
+ 36.8 36.8.0.77 4 2 0* 1* 3*
+ 36.11 1 1 0* 2 3*
+
+.fi
+In this example, there are four vifs connecting to two subnets and two
+tunnels. The vif 3 tunnel is not in use (no peer address). The vif 0 and
+vif 1 subnets have some groups present; tunnels never have any groups. This
+instance of
+.I mrouted
+is the one responsible for sending periodic group
+membership queries on the vif 0 and vif 1 subnets, as indicated by the
+"querier" flags.
+.PP
+Associated with each subnet from which a multicast datagram can originate
+is the address of the previous hop gateway (unless the subnet is directly-
+connected), the metric of the path back to the origin, the incoming vif for
+multicasts from that origin, and a list of outgoing vifs. "*" means that
+the outgoing vif is connected to a leaf of the broadcast tree rooted at the
+origin, and a multicast datagram from that origin will be forwarded on that
+outgoing vif only if there are members of the destination group on that leaf.
+.SH FILES
+/etc/mrouted.conf
+.SH SEE ALSO
+TRPB is described, along with other multicast routing algorithms, in the
+paper "Multicast Routing in Internetworks and Extended LANs" by S. Deering,
+in the Proceedings of the ACM SIGCOMM '88 Conference.
+.SH AUTHOR
+Steve Deering
diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf
new file mode 100644
index 000000000000..6629d4d1a8f8
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.conf
@@ -0,0 +1,15 @@
+# $Id: mrouted.conf,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+#
+# This is the configuration file for "mrouted", an IP multicast router.
+# mrouted looks for it in "/etc/mrouted.conf".
+#
+# Command formats:
+#
+# phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>]
+#
+# any phyint commands MUST precede any tunnel commands
+#
+# See the Mbone FAQ on ftp.isi.edu for metric, thresholds and connection info.
+#
+tunnel 129.89.9.63 129.89.9.50 metric 3 threshold 64 # <-- EXAMPLE; REPLACE OR DELETE
diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c
new file mode 100644
index 000000000000..d31165b1becd
--- /dev/null
+++ b/usr.sbin/mrouted/route.c
@@ -0,0 +1,900 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: route.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+int routes_changed; /* 1=>some routes have changed */
+int delay_change_reports; /* 1=>postpone change reports */
+
+
+/*
+ * Private variables.
+ */
+static struct rtentry *routing_table; /* pointer to list of route entries */
+static struct rtentry *rtp; /* pointer to a route entry */
+static unsigned nroutes; /* current number of route entries */
+
+
+/*
+ * Initialize the routing table and associated variables.
+ */
+void init_routes()
+{
+ routing_table = NULL;
+ nroutes = 0;
+ routes_changed = FALSE;
+ delay_change_reports = FALSE;
+}
+
+
+/*
+ * Initialize the children and leaf bits for route 'r', along with the
+ * associated dominant, subordinate, and leaf timing data structures.
+ * Return TRUE if this changes the value of either the children or
+ * leaf bitmaps for 'r'.
+ */
+static int init_children_and_leaves(r, parent)
+ register struct rtentry *r;
+ register vifi_t parent;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ vifbitmap_t old_children, old_leaves;
+
+ VIFM_COPY(r->rt_children, old_children);
+ VIFM_COPY(r->rt_leaves, old_leaves );
+
+ VIFM_CLRALL(r->rt_children);
+ VIFM_CLRALL(r->rt_leaves);
+ r->rt_flags &= ~RTF_LEAF_TIMING;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+
+ if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ VIFM_SET(vifi, r->rt_children);
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ else {
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ }
+
+ return (!VIFM_SAME(r->rt_children, old_children) ||
+ !VIFM_SAME(r->rt_leaves, old_leaves));
+}
+
+
+/*
+ * A new vif has come up -- update the children and leaf bitmaps in all route
+ * entries to take that into account.
+ */
+void add_vif_to_routes(vifi)
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE &&
+ !VIFM_ISSET(vifi, r->rt_children)) {
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ k_update_route(r);
+ }
+ }
+}
+
+
+/*
+ * A vif has gone down -- expire all routes that have that vif as parent,
+ * and update the children bitmaps in all other route entries to take into
+ * account the failed vif.
+ */
+void delete_vif_from_routes(vifi)
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE) {
+ if (vifi == r->rt_parent) {
+ k_del_route(r);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (VIFM_ISSET(vifi, r->rt_children)) {
+ VIFM_CLR(vifi, r->rt_children);
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_subordinates[vifi] = 0;
+ r->rt_leaf_timers [vifi] = 0;
+ k_update_route(r);
+ }
+ else {
+ r->rt_dominants[vifi] = 0;
+ }
+ }
+ }
+}
+
+
+/*
+ * A neighbor has failed or become unreachable. If that neighbor was
+ * considered a dominant or subordinate router in any route entries,
+ * take appropriate action.
+ */
+void delete_neighbor_from_routes(addr, vifi)
+ register u_long addr;
+ register vifi_t vifi;
+{
+ register struct rtentry *r;
+ register struct uvif *v;
+
+ v = &uvifs[vifi];
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ if (r->rt_metric != UNREACHABLE) {
+ if (r->rt_dominants[vifi] == addr) {
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ }
+ else {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ k_update_route(r);
+ }
+ else if (r->rt_subordinates[vifi] == addr) {
+ r->rt_subordinates[vifi] = 0;
+ if (v->uv_neighbors == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ k_update_route(r);
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ else if (v->uv_neighbors == NULL &&
+ r->rt_leaf_timers[vifi] != 0) {
+ VIFM_SET(vifi, r->rt_leaves);
+ r->rt_leaf_timers[vifi] = 0;
+ k_update_route(r);
+ }
+ }
+ }
+}
+
+
+/*
+ * Prepare for a sequence of ordered route updates by initializing a pointer
+ * to the start of the routing table. The pointer is used to remember our
+ * position in the routing table in order to avoid searching from the
+ * beginning for each update; this relies on having the route reports in
+ * a single message be in the same order as the route entries in the routing
+ * table.
+ */
+void start_route_updates()
+{
+ rtp = (struct rtentry *)&routing_table;
+}
+
+
+/*
+ * Starting at the route entry following the one to which 'rtp' points,
+ * look for a route entry matching the specified origin and mask. If a
+ * match is found, return TRUE and leave 'rtp' pointing at the found entry.
+ * If no match is found, return FALSE and leave 'rtp' pointing to the route
+ * entry preceding the point at which the new origin should be inserted.
+ * This code is optimized for the normal case in which the first entry to
+ * be examined is the matching entry.
+ */
+static int find_route(origin, mask)
+ register u_long origin, mask;
+{
+ register struct rtentry *r;
+
+ r = rtp->rt_next;
+ while (r != NULL) {
+ if (origin == r->rt_origin && mask == r->rt_originmask) {
+ rtp = r;
+ return (TRUE);
+ }
+ if (ntohl(mask) > ntohl(r->rt_originmask) ||
+ (mask == r->rt_originmask &&
+ ntohl(origin) > ntohl(r->rt_origin))) {
+ rtp = r;
+ r = r->rt_next;
+ }
+ else break;
+ }
+ return (FALSE);
+}
+
+
+/*
+ * Search the entire routing table, looking for an entry which conflicts
+ * with the given origin and mask, for example, an entry which has the same
+ * origin under a different mask. If a conflicting entry is found, return
+ * a pointer to the entry preceding it (to facilitate deletion); if no
+ * conflict is found, return NULL.
+ */
+static struct rtentry *find_conflicting_route(origin, mask)
+ register u_long origin, mask;
+{
+ register struct rtentry *r, *prev_r;
+
+ for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
+ r != NULL;
+ prev_r = r, r = r->rt_next ) {
+ if ((origin & r->rt_originmask) == r->rt_origin ||
+ (r->rt_origin & mask) == origin) {
+ return (prev_r);
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * Create a new routing table entry for the specified origin and link it into
+ * the routing table. The shared variable 'rtp' is assumed to point to the
+ * routing entry after which the new one should be inserted. It is left
+ * pointing to the new entry.
+ *
+ * Only the origin, originmask, originwidth and flags fields are initialized
+ * in the new route entry; the caller is responsible for filling in the the
+ * rest.
+ */
+static void create_route(origin, mask)
+ u_long origin, mask;
+{
+ register struct rtentry *r;
+
+ if ((r = (struct rtentry *) malloc(sizeof(struct rtentry)
+ + (3 * numvifs * sizeof(u_long)))) == NULL) {
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+ }
+ r->rt_origin = origin;
+ r->rt_originmask = mask;
+ if (((char *)&mask)[3] != 0) r->rt_originwidth = 4;
+ else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3;
+ else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
+ else r->rt_originwidth = 1;
+ r->rt_flags = 0;
+ r->rt_dominants = (u_long *)(r + 1);
+ r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs);
+ r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
+
+ r->rt_next = rtp->rt_next;
+ rtp->rt_next = r;
+ rtp = r;
+ ++nroutes;
+}
+
+
+/*
+ * Discard the routing table entry following the one to which 'prev_r' points.
+ */
+static void discard_route(prev_r)
+ register struct rtentry *prev_r;
+{
+ register struct rtentry *r;
+
+ r = prev_r->rt_next;
+ prev_r->rt_next = r->rt_next;
+ free((char *)r);
+ --nroutes;
+}
+
+
+/*
+ * Process a route report for a single origin, creating or updating the
+ * corresponding routing table entry if necessary. 'src' is either the
+ * address of a neighboring router from which the report arrived, or zero
+ * to indicate a change of status of one of our own interfaces.
+ */
+void update_route(origin, mask, metric, src, vifi)
+ u_long origin, mask;
+ int metric;
+ u_long src;
+ vifi_t vifi;
+{
+ register struct rtentry *r;
+ struct rtentry *prev_r;
+ int adj_metric;
+
+ /*
+ * Compute an adjusted metric, taking into account the cost of the
+ * subnet or tunnel over which the report arrived, and normalizing
+ * all unreachable/poisoned metrics into a single value.
+ */
+ if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) {
+ log(LOG_WARNING, 0,
+ "%s reports out-of-range metric %u for origin %s",
+ inet_fmt(src, s1), metric, inet_fmts(origin, mask, s2));
+ return;
+ }
+ adj_metric = metric + uvifs[vifi].uv_metric;
+ if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE;
+
+ /*
+ * Look up the reported origin in the routing table.
+ */
+ if (!find_route(origin, mask)) {
+ /*
+ * Not found.
+ * Don't create a new entry if the report says it's unreachable,
+ * or if the reported origin and mask are invalid.
+ */
+ if (adj_metric == UNREACHABLE) {
+ return;
+ }
+ if (src != 0 && !inet_valid_subnet(origin, mask)) {
+ log(LOG_WARNING, 0,
+ "%s reports an invalid origin (%s) and/or mask (%08x)",
+ inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
+ return;
+ }
+
+ /*
+ * If the new origin and mask are inconsistent with an entry
+ * already in the routing table, either ignore this update
+ * (if it came from another router), or delete the conflicting
+ * entry (if the update is for a directly-connected subnet).
+ */
+ if ((prev_r = find_conflicting_route(origin, mask)) != NULL ) {
+ if (src != 0) {
+ log(LOG_WARNING, 0,
+ "%s reports a conflicting origin (%s) and mask (%08x)",
+ inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
+ return;
+ }
+ else {
+ r = prev_r->rt_next;
+ log(LOG_WARNING, 0,
+ "deleting route with conflicting origin (%s), mask (%08x)",
+ inet_fmt(r->rt_origin, s1), ntohl(r->rt_originmask));
+
+ if (r->rt_metric != UNREACHABLE) {
+ k_del_route(r);
+ }
+ discard_route(prev_r);
+ if (rtp == r) rtp = prev_r;
+ }
+ }
+
+ /*
+ * OK, create the new routing entry. 'rtp' will be left pointing
+ * to the new entry.
+ */
+ create_route(origin, mask);
+
+ rtp->rt_metric = UNREACHABLE; /* temporary; updated below */
+ }
+
+ /*
+ * We now have a routing entry for the reported origin. Update it?
+ */
+ r = rtp;
+ if (r->rt_metric == UNREACHABLE) {
+ /*
+ * The routing entry is for a formerly-unreachable or new origin.
+ * If the report claims reachability, update the entry to use
+ * the reported route.
+ */
+ if (adj_metric == UNREACHABLE)
+ return;
+
+ r->rt_parent = vifi;
+ init_children_and_leaves(r, vifi);
+ k_add_route(r);
+ r->rt_gateway = src;
+ r->rt_timer = 0;
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (src == r->rt_gateway) {
+ /*
+ * The report has come either from the interface directly-connected
+ * to the origin subnet (src and r->rt_gateway both equal zero) or
+ * from the gateway we have chosen as the best first-hop gateway back
+ * towards the origin (src and r->rt_gateway not equal zero). Reset
+ * the route timer and, if the reported metric has changed, update
+ * our entry accordingly.
+ */
+ r->rt_timer = 0;
+ if (adj_metric == r->rt_metric)
+ return;
+
+ if (adj_metric == UNREACHABLE) {
+ k_del_route(r);
+ r->rt_timer = ROUTE_EXPIRE_TIME;
+ }
+ else if (adj_metric < r->rt_metric) {
+ if (init_children_and_leaves(r, vifi)) {
+ k_update_route(r);
+ }
+ }
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (src == 0 ||
+ (r->rt_gateway != 0 &&
+ (adj_metric < r->rt_metric ||
+ (adj_metric == r->rt_metric &&
+ r->rt_timer >= ROUTE_SWITCH_TIME)))) {
+ /*
+ * The report is for an origin we consider reachable; the report
+ * comes either from one of our own interfaces or from a gateway
+ * other than the one we have chosen as the best first-hop gateway
+ * back towards the origin. If the source of the update is one of
+ * our own interfaces, or if the origin is not a directly-connected
+ * subnet and the reported metric for that origin is better than
+ * what our routing entry says, update the entry to use the new
+ * gateway and metric. We also switch gateways if the reported
+ * metric is the same as the one in the route entry and the gateway
+ * associated with the route entry has not been heard from recently.
+ * Did you get all that?
+ */
+ if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
+ r->rt_parent = vifi;
+ if (init_children_and_leaves(r, vifi)) {
+ k_update_route(r);
+ }
+ }
+ r->rt_gateway = src;
+ r->rt_timer = 0;
+ r->rt_metric = adj_metric;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ else if (vifi != r->rt_parent) {
+ /*
+ * The report came from a vif other than the route's parent vif.
+ * Update the children and leaf info, if necessary.
+ */
+ if (VIFM_ISSET(vifi, r->rt_children)) {
+ /*
+ * Vif is a child vif for this route.
+ */
+ if (metric < r->rt_metric ||
+ (metric == r->rt_metric &&
+ ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) {
+ /*
+ * Neighbor has lower metric to origin (or has same metric
+ * and lower IP address) -- it becomes the dominant router,
+ * and vif is no longer a child for me.
+ */
+ VIFM_CLR(vifi, r->rt_children);
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_dominants [vifi] = src;
+ r->rt_subordinates[vifi] = 0;
+ r->rt_leaf_timers [vifi] = 0;
+ k_update_route(r);
+ }
+ else if (metric > UNREACHABLE) { /* "poisoned reverse" */
+ /*
+ * Neighbor considers this vif to be on path to route's
+ * origin; if no subordinate recorded, record this neighbor
+ * as subordinate and clear the leaf flag.
+ */
+ if (r->rt_subordinates[vifi] == 0) {
+ VIFM_CLR(vifi, r->rt_leaves);
+ r->rt_subordinates[vifi] = src;
+ r->rt_leaf_timers [vifi] = 0;
+ k_update_route(r);
+ }
+ }
+ else if (src == r->rt_subordinates[vifi]) {
+ /*
+ * Current subordinate no longer considers this vif to be on
+ * path to route's origin; it is no longer a subordinate
+ * router, and we set the leaf confirmation timer to give
+ * us time to hear from other subordinates.
+ */
+ r->rt_subordinates[vifi] = 0;
+ if (uvifs[vifi].uv_neighbors == NULL ||
+ uvifs[vifi].uv_neighbors->al_next == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ k_update_route(r);
+ }
+ else {
+ r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+
+ }
+ else if (src == r->rt_dominants[vifi] &&
+ (metric > r->rt_metric ||
+ (metric == r->rt_metric &&
+ ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) {
+ /*
+ * Current dominant no longer has a lower metric to origin
+ * (or same metric and lower IP address); we adopt the vif
+ * as our own child.
+ */
+ VIFM_SET(vifi, r->rt_children);
+ r->rt_dominants [vifi] = 0;
+ if (metric > UNREACHABLE) {
+ r->rt_subordinates[vifi] = src;
+ }
+ else if (uvifs[vifi].uv_neighbors == NULL ||
+ uvifs[vifi].uv_neighbors->al_next == NULL) {
+ VIFM_SET(vifi, r->rt_leaves);
+ }
+ else {
+ r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ k_update_route(r);
+ }
+ }
+}
+
+
+/*
+ * On every timer interrupt, advance the timer in each routing entry.
+ */
+void age_routes()
+{
+ register struct rtentry *r;
+ register struct rtentry *prev_r;
+ register vifi_t vifi;
+
+ for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
+ r != NULL;
+ prev_r = r, r = r->rt_next) {
+
+ if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) {
+ /*
+ * Route is still good; see if any leaf timers need to be
+ * advanced.
+ */
+ if (r->rt_flags & RTF_LEAF_TIMING) {
+ r->rt_flags &= ~RTF_LEAF_TIMING;
+ for (vifi = 0; vifi < numvifs; ++vifi) {
+ if (r->rt_leaf_timers[vifi] != 0) {
+ /*
+ * Unlike other timers, leaf timers decrement.
+ */
+ if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
+ VIFM_SET(vifi, r->rt_leaves);
+ k_update_route(r);
+ }
+ else {
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ }
+ }
+ }
+ else if (r->rt_timer >= ROUTE_DISCARD_TIME) {
+ /*
+ * Time to garbage-collect the route entry.
+ */
+ discard_route(prev_r);
+ r = prev_r;
+ }
+ else if (r->rt_metric != UNREACHABLE) {
+ /*
+ * Time to expire the route entry. If the gateway is zero,
+ * i.e., it is a route to a directly-connected subnet, just
+ * set the timer back to zero; such routes expire only when
+ * the interface to the subnet goes down.
+ */
+ if (r->rt_gateway == 0) {
+ r->rt_timer = 0;
+ }
+ else {
+ k_del_route(r);
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Mark all routes as unreachable. This function is called only from
+ * hup() in preparation for informing all neighbors that we are going
+ * off the air. For consistency, we ought also to delete all reachable
+ * route entries from the kernel, but since we are about to exit we rely
+ * on the kernel to do its own cleanup -- no point in making all those
+ * expensive kernel calls now.
+ */
+void expire_all_routes()
+{
+ register struct rtentry *r;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ r->rt_metric = UNREACHABLE;
+ r->rt_flags |= RTF_CHANGED;
+ routes_changed = TRUE;
+ }
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void accept_probe(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring probe from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (!update_neighbor(vifi, src, DVMRP_PROBE))
+ return;
+
+ report(ALL_ROUTES, vifi, src);
+}
+
+
+/*
+ * Process an incoming route report message.
+ */
+void accept_report(src, dst, p, datalen)
+ u_long src, dst;
+ register char *p;
+ register int datalen;
+{
+ vifi_t vifi;
+ register int width, i;
+ int metric;
+ u_long mask;
+ u_long origin;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring route report from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (!update_neighbor(vifi, src, DVMRP_REPORT))
+ return;
+
+ start_route_updates();
+
+ while (datalen > 0) { /* Loop through per-mask lists. */
+
+ if (datalen < 3) {
+ log(LOG_WARNING, 0,
+ "received truncated route report from %s", inet_fmt(src, s1));
+ return;
+ }
+ ((char *)&mask)[0] = 0xff; width = 1;
+ if ((((char *)&mask)[1] = *p++) != 0) width = 2;
+ if ((((char *)&mask)[2] = *p++) != 0) width = 3;
+ if ((((char *)&mask)[3] = *p++) != 0) width = 4;
+ datalen -= 3;
+
+ do { /* Loop through (origin, metric) pairs */
+
+ if (datalen < width + 1) {
+ log(LOG_WARNING, 0,
+ "received truncated route report from %s", inet_fmt(src, s1));
+ return;
+ }
+ origin = 0;
+ for (i = 0; i < width; ++i)
+ ((char *)&origin)[i] = *p++;
+ metric = *p++;
+ datalen -= width + 1;
+
+ update_route(origin, mask, (metric & 0x7f), src, vifi);
+
+ } while (!(metric & 0x80));
+ }
+
+ if (routes_changed && !delay_change_reports)
+ report_to_all_neighbors(CHANGED_ROUTES);
+}
+
+
+/*
+ * Send a route report message to destination 'dst', via virtual interface
+ * 'vifi'. 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+void report(which_routes, vifi, dst)
+ int which_routes;
+ vifi_t vifi;
+ u_long dst;
+{
+ register struct rtentry *r;
+ register char *p;
+ register int i;
+ int datalen;
+ int width;
+ u_long mask;
+ u_long src;
+
+ src = uvifs[vifi].uv_lcl_addr;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
+ continue;
+
+ /*
+ * If there is no room for this route in the current message,
+ * send the message and start a new one.
+ */
+ if (datalen + ((r->rt_originmask == mask) ?
+ (width + 1) :
+ (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL), datalen);
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+ }
+
+ if(r->rt_originmask != mask) {
+ mask = r->rt_originmask;
+ width = r->rt_originwidth;
+ if (datalen != 0) *(p-1) |= 0x80;
+ *p++ = ((char *)&mask)[1];
+ *p++ = ((char *)&mask)[2];
+ *p++ = ((char *)&mask)[3];
+ datalen += 3;
+ }
+
+ for (i = 0; i < width; ++i)
+ *p++ = ((char *)&(r->rt_origin))[i];
+
+ *p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
+ (char)(r->rt_metric + UNREACHABLE) : /* "poisoned reverse" */
+ (char)(r->rt_metric);
+
+ datalen += width + 1;
+ }
+
+ if (datalen != 0) {
+ *(p-1) |= 0x80;
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
+ htonl(MROUTED_LEVEL), datalen);
+ }
+}
+
+
+/*
+ * Send a route report message to all neighboring routers.
+ * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
+ */
+void report_to_all_neighbors(which_routes)
+ int which_routes;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct rtentry *r;
+ int routes_changed_before;
+
+ /*
+ * Remember the state of the global routes_changed flag before
+ * generating the reports, and clear the flag.
+ */
+ routes_changed_before = routes_changed;
+ routes_changed = FALSE;
+
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (v->uv_neighbors != NULL) {
+ report(which_routes, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group);
+ }
+ }
+
+ /*
+ * If there were changed routes before we sent the reports AND
+ * if no new changes occurred while sending the reports, clear
+ * the change flags in the individual route entries. If changes
+ * did occur while sending the reports, new reports will be
+ * generated at the next timer interrupt.
+ */
+ if (routes_changed_before && !routes_changed) {
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+ r->rt_flags &= ~RTF_CHANGED;
+ }
+ }
+
+ /*
+ * Set a flag to inhibit further reports of changed routes until the
+ * next timer interrupt. This is to alleviate update storms.
+ */
+ delay_change_reports = TRUE;
+}
+
+
+/*
+ * Print the contents of the routing table on file 'fp'.
+ */
+void dump_routes(fp)
+ FILE *fp;
+{
+ register struct rtentry *r;
+ register int i;
+
+ fprintf(fp,
+ "Multicast Routing Table (%u %s)\n%s",
+ nroutes, (nroutes == 1) ? "entry" : "entries",
+ " Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n");
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ fprintf(fp, " %-15s %-15s ",
+ inet_fmts(r->rt_origin, r->rt_originmask, s1),
+ (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2));
+
+ fprintf(fp, (r->rt_metric == UNREACHABLE) ? " NR " : "%4u ",
+ r->rt_metric);
+
+ fprintf(fp, "%7u ",
+ r->rt_parent);
+
+ for (i = 0; i < numvifs; ++i) {
+ if (VIFM_ISSET(i, r->rt_children)) {
+ fprintf(fp, " %u%c",
+ i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' ');
+ }
+ }
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, "\n");
+}
diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h
new file mode 100644
index 000000000000..03ee8c656cfe
--- /dev/null
+++ b/usr.sbin/mrouted/route.h
@@ -0,0 +1,50 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: route.h,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+/*
+ * Routing Table Entry, one per subnet from which a multicast could originate.
+ * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
+ *
+ * The Routing Table is stored as a singly-linked list of these structures,
+ * ordered by increasing value of rt_originmask and, secondarily, by
+ * increasing value of rt_origin within each rt_originmask value.
+ * This data structure is efficient for generating route reports, whether
+ * full or partial, for processing received full reports, for clearing the
+ * CHANGED flags, and for periodically advancing the timers in all routes.
+ * It is not so efficient for updating a small number of routes in response
+ * to a partial report. In a stable topology, the latter are rare; if they
+ * turn out to be costing a lot, we can add an auxiliary hash table for
+ * faster access to arbitrary route entries.
+ */
+struct rtentry {
+ struct rtentry *rt_next; /* link to next entry MUST BE FIRST */
+ u_long rt_origin; /* subnet origin of multicasts */
+ u_long rt_originmask; /* subnet mask for origin */
+ short rt_originwidth; /* # bytes of origin subnet number */
+ u_char rt_metric; /* cost of route back to origin */
+ u_char rt_flags; /* RTF_ flags defined below */
+ u_long rt_gateway; /* first-hop gateway back to origin */
+ vifi_t rt_parent; /* incoming vif (ie towards origin) */
+ vifbitmap_t rt_children; /* outgoing children vifs */
+ vifbitmap_t rt_leaves; /* subset of outgoing children vifs */
+ u_long *rt_dominants; /* per vif dominant gateways */
+ u_long *rt_subordinates; /* per vif subordinate gateways */
+ u_long *rt_leaf_timers; /* per vif leaf confirmation timers */
+ u_long rt_timer; /* for timing out the route entry */
+};
+
+#define RTF_CHANGED 0x01 /* route changed but not reported */
+#define RTF_LEAF_TIMING 0x02 /* some leaf timers are running */
+
+
+#define ALL_ROUTES 0 /* possible arguments to report() */
+#define CHANGED_ROUTES 1 /* and report_to_all_neighbors() */
diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c
new file mode 100644
index 000000000000..5a55dd41654b
--- /dev/null
+++ b/usr.sbin/mrouted/vif.c
@@ -0,0 +1,782 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: vif.c,v 1.1.1.1 1994/05/17 20:59:33 jkh Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+struct uvif uvifs[MAXVIFS]; /* array of virtual interfaces */
+vifi_t numvifs; /* number of vifs in use */
+int vifs_down; /* 1=>some interfaces are down */
+int udp_socket; /* Since the honkin' kernel doesn't support */
+ /* ioctls on raw IP sockets, we need a UDP */
+ /* socket as well as our IGMP (raw) socket. */
+ /* How dumb. */
+
+/*
+ * Forward declarations.
+ */
+static void start_vif();
+static void stop_vif();
+
+
+/*
+ * Initialize the virtual interfaces.
+ */
+void init_vifs()
+{
+ vifi_t vifi;
+ struct uvif *v;
+ int enabled_vifs, enabled_phyints;
+
+ numvifs = 0;
+ vifs_down = FALSE;
+
+ /*
+ * Configure the vifs based on the interface configuration of the
+ * the kernel and the contents of the configuration file.
+ * (Open a UDP socket for ioctl use in the config procedures.)
+ */
+ if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ log(LOG_ERR, errno, "UDP socket");
+ config_vifs_from_kernel();
+ config_vifs_from_file();
+
+ /*
+ * Quit if there are fewer than two enabled vifs.
+ */
+ enabled_vifs = 0;
+ enabled_phyints = 0;
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ ++enabled_vifs;
+ if (!(v->uv_flags & VIFF_TUNNEL))
+ ++enabled_phyints;
+ }
+ }
+ if (enabled_vifs < 2)
+ log(LOG_ERR, 0, "can't forward: %s",
+ enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
+
+ if (enabled_phyints == 0)
+ log(LOG_WARNING, 0,
+ "no enabled interfaces, forwarding via tunnels only");
+
+ /*
+ * Start routing on all virtual interfaces that are not down or
+ * administratively disabled.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (!(v->uv_flags & VIFF_DOWN))
+ start_vif(vifi);
+ else log(LOG_INFO, 0,
+ "%s is not yet up; vif #%u not in service",
+ v->uv_name, vifi);
+ }
+ }
+}
+
+
+/*
+ * See if any interfaces have changed from up state to down, or vice versa,
+ * including any non-multicast-capable interfaces that are in use as local
+ * tunnel end-points. Ignore interfaces that have been administratively
+ * disabled.
+ */
+void check_vif_state()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ struct ifreq ifr;
+
+ vifs_down = FALSE;
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+
+ if (v->uv_flags & VIFF_DISABLED) continue;
+
+ strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
+ log(LOG_ERR, errno,
+ "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
+
+ if (v->uv_flags & VIFF_DOWN) {
+ if (ifr.ifr_flags & IFF_UP) {
+ v->uv_flags &= ~VIFF_DOWN;
+ start_vif(vifi);
+ log(LOG_INFO, 0,
+ "%s has come up; vif #%u now in service",
+ v->uv_name, vifi);
+ }
+ else vifs_down = TRUE;
+ }
+ else {
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ stop_vif(vifi);
+ v->uv_flags |= VIFF_DOWN;
+ log(LOG_INFO, 0,
+ "%s has gone down; vif #%u taken out of service",
+ v->uv_name, vifi);
+ vifs_down = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Start routing on the specified virtual interface.
+ */
+static void start_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ u_long src, dst;
+
+ v = &uvifs[vifi];
+ src = v->uv_lcl_addr;
+ dst = (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr : dvmrp_group;
+
+ /*
+ * Install the interface in the kernel's vif structure.
+ */
+ k_add_vif(vifi, &uvifs[vifi]);
+
+ /*
+ * Update the existing route entries to take into account the new vif.
+ */
+ add_vif_to_routes(vifi);
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ /*
+ * Join the DVMRP multicast group on the interface.
+ * (This is not strictly necessary, since the kernel promiscuously
+ * receives IGMP packets addressed to ANY IP multicast group while
+ * multicast routing is enabled. However, joining the group allows
+ * this host to receive non-IGMP packets as well, such as 'pings'.)
+ */
+ k_join(dvmrp_group, src);
+
+ /*
+ * Install an entry in the routing table for the subnet to which
+ * the interface is connected.
+ */
+ start_route_updates();
+ update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
+
+ /*
+ * Until neighbors are discovered, assume responsibility for sending
+ * periodic group membership queries to the subnet. Send the first
+ * query.
+ */
+ v->uv_flags |= VIFF_QUERIER;
+ send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY, 0, 0, 0);
+ }
+
+ /*
+ * Send a probe via the new vif to look for neighbors.
+ */
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), 0);
+}
+
+
+/*
+ * Stop routing on the specified virtual interface.
+ */
+static void stop_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ struct listaddr *a;
+
+ v = &uvifs[vifi];
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ /*
+ * Depart from the DVMRP multicast group on the interface.
+ */
+ k_leave(dvmrp_group, v->uv_lcl_addr);
+
+ /*
+ * Update the entry in the routing table for the subnet to which
+ * the interface is connected, to take into account the interface
+ * failure.
+ */
+ start_route_updates();
+ update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
+
+ /*
+ * Discard all group addresses. (No need to tell kernel;
+ * the k_del_vif() call, below, will clean up kernel state.)
+ */
+ while (v->uv_groups != NULL) {
+ a = v->uv_groups;
+ v->uv_groups = a->al_next;
+ free((char *)a);
+ }
+
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ /*
+ * Update the existing route entries to take into account the vif failure.
+ */
+ delete_vif_from_routes(vifi);
+
+ /*
+ * Delete the interface from the kernel's vif structure.
+ */
+ k_del_vif(vifi);
+
+ /*
+ * Discard all neighbor addresses.
+ */
+ while (v->uv_neighbors != NULL) {
+ a = v->uv_neighbors;
+ v->uv_neighbors = a->al_next;
+ free((char *)a);
+ }
+}
+
+
+/*
+ * Find the virtual interface from which an incoming packet arrived,
+ * based on the packet's source and destination IP addresses.
+ */
+vifi_t find_vif(src, dst)
+ register u_long src;
+ register u_long dst;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr)
+ return(vifi);
+ }
+ else {
+ if ((src & v->uv_subnetmask) == v->uv_subnet &&
+ src != v->uv_subnetbcast)
+ return(vifi);
+ }
+ }
+ }
+ return (NO_VIF);
+}
+
+
+/*
+ * Send group membership queries to all subnets for which I am querier.
+ */
+void query_groups()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (v->uv_flags & VIFF_QUERIER) {
+ send_igmp(v->uv_lcl_addr, allhosts_group,
+ IGMP_HOST_MEMBERSHIP_QUERY, 0, 0, 0);
+ }
+ }
+}
+
+
+/*
+ * Process an incoming group membership report.
+ */
+void accept_group_report(src, dst, group)
+ u_long src, dst, group;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *g;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF ||
+ (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
+ log(LOG_INFO, 0,
+ "ignoring group membership report from non-adjacent host %s",
+ inet_fmt(src, s1));
+ return;
+ }
+
+ v = &uvifs[vifi];
+
+ /*
+ * Look for the group in our group list; if found, reset its timer.
+ */
+ for (g = v->uv_groups; g != NULL; g = g->al_next) {
+ if (group == g->al_addr) {
+ g->al_timer = 0;
+ break;
+ }
+ }
+
+ /*
+ * If not found, add it to the list and tell the kernel.
+ */
+ if (g == NULL) {
+ g = (struct listaddr *)malloc(sizeof(struct listaddr));
+ if (g == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ g->al_addr = group;
+ g->al_timer = 0;
+ g->al_next = v->uv_groups;
+ v->uv_groups = g;
+
+ k_add_group(vifi, group);
+ }
+}
+
+
+/*
+ * Send a probe on all vifs from which no neighbors have been heard recently.
+ */
+void probe_for_neighbors()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED)) &&
+ v->uv_neighbors == NULL) {
+ send_igmp(v->uv_lcl_addr,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group,
+ IGMP_DVMRP, DVMRP_PROBE, htonl(MROUTED_LEVEL), 0);
+ }
+ }
+}
+
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void accept_neighbor_request(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_long temp_addr, us, them = src;
+
+ /* Determine which of our addresses to use as the source of our response
+ * to this query.
+ */
+ if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
+ int udp; /* find best interface to reply on */
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = dst;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ log(LOG_WARNING, errno, "Determining local address");
+ close(udp);
+ return;
+ }
+ close(udp);
+ us = addr.sin_addr.s_addr;
+ } else /* query sent to us alone */
+ us = dst;
+
+#define PUT_ADDR(a) temp_addr = ntohl(a); \
+ *p++ = temp_addr >> 24; \
+ *p++ = (temp_addr >> 16) & 0xFF; \
+ *p++ = (temp_addr >> 8) & 0xFF; \
+ *p++ = temp_addr & 0xFF;
+
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (v->uv_flags & VIFF_DISABLED)
+ continue;
+
+ ncount = 0;
+
+ for (la = v->uv_neighbors; la; la = la->al_next) {
+
+ /* Make sure that there's room for this neighbor... */
+ if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ ncount = 0;
+ }
+
+ /* Put out the header for this neighbor list... */
+ if (ncount == 0) {
+ PUT_ADDR(v->uv_lcl_addr);
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ ncount = p;
+ *p++ = 0;
+ datalen += 4 + 3;
+ }
+
+ PUT_ADDR(la->al_addr);
+ datalen += 4;
+ (*ncount)++;
+ }
+ }
+
+ if (datalen != 0)
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL),
+ datalen);
+}
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void accept_neighbor_request2(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_long temp_addr, us, them = src;
+
+ /* Determine which of our addresses to use as the source of our response
+ * to this query.
+ */
+ if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
+ int udp; /* find best interface to reply on */
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = dst;
+ addr.sin_port = htons(2000); /* any port over 1024 will do... */
+ if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
+ || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
+ || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
+ log(LOG_WARNING, errno, "Determining local address");
+ close(udp);
+ return;
+ }
+ close(udp);
+ us = addr.sin_addr.s_addr;
+ } else /* query sent to us alone */
+ us = dst;
+
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ register u_short vflags = v->uv_flags;
+ register u_char rflags = 0;
+ if (vflags & VIFF_TUNNEL)
+ rflags |= DVMRP_NF_TUNNEL;
+ if (vflags & VIFF_SRCRT)
+ rflags |= DVMRP_NF_SRCRT;
+ if (vflags & VIFF_DOWN)
+ rflags |= DVMRP_NF_DOWN;
+ if (vflags & VIFF_DISABLED)
+ rflags |= DVMRP_NF_DISABLED;
+ if (vflags & VIFF_QUERIER)
+ rflags |= DVMRP_NF_QUERIER;
+ ncount = 0;
+ la = v->uv_neighbors;
+ if (la == NULL) {
+ /*
+ * include down & disabled interfaces and interfaces on
+ * leaf nets.
+ */
+ if (rflags & DVMRP_NF_TUNNEL)
+ rflags |= DVMRP_NF_DOWN;
+ if (datalen > MAX_DVMRP_DATA_LEN - 12) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ }
+ *(u_int*)p = v->uv_lcl_addr;
+ p += 4;
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ *p++ = rflags;
+ *p++ = 1;
+ *(u_int*)p = v->uv_rmt_addr;
+ p += 4;
+ datalen += 12;
+ } else {
+ for ( ; la; la = la->al_next) {
+ /* Make sure that there's room for this neighbor... */
+ if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
+ htonl(MROUTED_LEVEL), datalen);
+ p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+ datalen = 0;
+ ncount = 0;
+ }
+ /* Put out the header for this neighbor list... */
+ if (ncount == 0) {
+ *(u_int*)p = v->uv_lcl_addr;
+ p += 4;
+ *p++ = v->uv_metric;
+ *p++ = v->uv_threshold;
+ *p++ = rflags;
+ ncount = p;
+ *p++ = 0;
+ datalen += 4 + 4;
+ }
+ *(u_int*)p = la->al_addr;
+ p += 4;
+ datalen += 4;
+ (*ncount)++;
+ }
+ }
+ }
+ if (datalen != 0)
+ send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL),
+ datalen);
+}
+
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors(src, dst, p, datalen, level)
+ u_long src, dst, level;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+/*
+ * Process an incoming neighbor-list message.
+ */
+void accept_neighbors2(src, dst, p, datalen, level)
+ u_long src, dst, level;
+ char *p;
+ int datalen;
+{
+ log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
+ inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
+
+/*
+ * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
+ * 'msgtype' is the type of DVMRP message received from the neighbor.
+ * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise.
+ */
+int update_neighbor(vifi, addr, msgtype)
+ vifi_t vifi;
+ u_long addr;
+ int msgtype;
+{
+ register struct uvif *v;
+ register struct listaddr *n;
+
+ v = &uvifs[vifi];
+
+ /*
+ * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
+ * IT IS ASSUMED that this was preceded by a call to find_vif(), which
+ * checks that 'addr' is either a valid remote tunnel endpoint or a
+ * non-broadcast address belonging to a directly-connected subnet.
+ * Therefore, here we check only that 'addr' is not our own address
+ * (due to an impostor or erroneous loopback) or an address of the form
+ * {subnet,0} ("the unknown host"). These checks are not performed in
+ * find_vif() because those types of address are acceptable for some
+ * types of IGMP message (such as group membership reports).
+ */
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ (addr == v->uv_lcl_addr ||
+ addr == v->uv_subnet )) {
+ log(LOG_WARNING, 0,
+ "received DVMRP message from 'the unknown host' or self: %s",
+ inet_fmt(addr, s1));
+ return (FALSE);
+ }
+
+ /*
+ * If we have received a route report from a neighbor, and we believed
+ * that we had no neighbors on this vif, send a full route report to
+ * all neighbors on the vif.
+ */
+
+ if (msgtype == DVMRP_REPORT && v->uv_neighbors == NULL)
+ report(ALL_ROUTES, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group);
+
+ /*
+ * Look for addr in list of neighbors; if found, reset its timer.
+ */
+ for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+ if (addr == n->al_addr) {
+ n->al_timer = 0;
+ break;
+ }
+ }
+
+ /*
+ * If not found, add it to the list. If the neighbor has a lower
+ * IP address than me, yield querier duties to it.
+ */
+ if (n == NULL) {
+ n = (struct listaddr *)malloc(sizeof(struct listaddr));
+ if (n == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ n->al_addr = addr;
+ n->al_timer = 0;
+ n->al_next = v->uv_neighbors;
+ v->uv_neighbors = n;
+
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ ntohl(addr) < ntohl(v->uv_lcl_addr))
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ return (TRUE);
+}
+
+
+/*
+ * On every timer interrupt, advance the timer in each neighbor and
+ * group entry on every vif.
+ */
+void age_vifs()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *a, *prev_a, *n;
+ register u_long addr;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
+
+ for (prev_a = (struct listaddr *)&(v->uv_neighbors),
+ a = v->uv_neighbors;
+ a != NULL;
+ prev_a = a, a = a->al_next) {
+
+ if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME)
+ continue;
+
+ /*
+ * Neighbor has expired; delete it from the neighbor list,
+ * delete it from the 'dominants' and 'subordinates arrays of
+ * any route entries and assume querier duties unless there is
+ * another neighbor with a lower IP address than mine.
+ */
+ addr = a->al_addr;
+ prev_a->al_next = a->al_next;
+ free((char *)a);
+ a = prev_a;
+
+ delete_neighbor_from_routes(addr, vifi);
+
+ if (!(v->uv_flags & VIFF_TUNNEL)) {
+ v->uv_flags |= VIFF_QUERIER;
+ for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+ if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) {
+ v->uv_flags &= ~VIFF_QUERIER;
+ break;
+ }
+ }
+ }
+ }
+
+ for (prev_a = (struct listaddr *)&(v->uv_groups),
+ a = v->uv_groups;
+ a != NULL;
+ prev_a = a, a = a->al_next) {
+
+ if ((a->al_timer += TIMER_INTERVAL) < GROUP_EXPIRE_TIME)
+ continue;
+
+ /*
+ * Group has expired; tell kernel and delete from group list.
+ */
+ k_del_group(vifi, a->al_addr);
+
+ prev_a->al_next = a->al_next;
+ free((char *)a);
+ a = prev_a;
+ }
+ }
+}
+
+
+/*
+ * Print the contents of the uvifs array on file 'fp'.
+ */
+void dump_vifs(fp)
+ FILE *fp;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct listaddr *a;
+
+ fprintf(fp,
+ "\nVirtual Interface Table\n%s",
+ " Vif Local-Address Metric Thresh Flags\n");
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+
+ fprintf(fp, " %2u %-15s %6s: %-15s %4u %7u ",
+ vifi,
+ inet_fmt(v->uv_lcl_addr, s1),
+ (v->uv_flags & VIFF_TUNNEL) ?
+ "tunnel":
+ "subnet",
+ (v->uv_flags & VIFF_TUNNEL) ?
+ inet_fmt(v->uv_rmt_addr, s2) :
+ inet_fmts(v->uv_subnet, v->uv_subnetmask, s3),
+ v->uv_metric,
+ v->uv_threshold);
+
+ if (v->uv_flags & VIFF_DOWN) fprintf(fp, " down");
+ if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled");
+ if (v->uv_flags & VIFF_QUERIER) fprintf(fp, " querier");
+ if (v->uv_flags & VIFF_SRCRT) fprintf(fp, " src-rt");
+ fprintf(fp, "\n");
+
+ if (v->uv_neighbors != NULL) {
+ fprintf(fp, " peers : %-15s\n",
+ inet_fmt(v->uv_neighbors->al_addr, s1));
+ for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %-15s\n",
+ inet_fmt(a->al_addr, s1));
+ }
+ }
+
+ if (v->uv_groups != NULL) {
+ fprintf(fp, " groups: %-15s\n",
+ inet_fmt(v->uv_groups->al_addr, s1));
+ for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %-15s\n",
+ inet_fmt(a->al_addr, s1));
+ }
+ }
+ }
+ fprintf(fp, "\n");
+}
diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h
new file mode 100644
index 000000000000..4af87c5ae805
--- /dev/null
+++ b/usr.sbin/mrouted/vif.h
@@ -0,0 +1,47 @@
+/*
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE". Use of the mrouted program represents acceptance of
+ * the terms and conditions listed in that file.
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ *
+ * $Id: vif.h,v 1.1.1.1 1994/05/17 20:59:34 jkh Exp $
+ */
+
+/*
+ * User level Virtual Interface structure
+ *
+ * A "virtual interface" is either a physical, multicast-capable interface
+ * (called a "phyint") or a virtual point-to-point link (called a "tunnel").
+ * (Note: all addresses, subnet numbers and masks are kept in NETWORK order.)
+ */
+struct uvif {
+ u_short uv_flags; /* VIFF_ flags defined below */
+ u_char uv_metric; /* cost of this vif */
+ u_char uv_threshold; /* min ttl required to forward on vif */
+ u_long uv_lcl_addr; /* local address of this vif */
+ u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */
+ u_long uv_subnet; /* subnet number (phyints only) */
+ u_long uv_subnetmask; /* subnet mask (phyints only) */
+ u_long uv_subnetbcast;/* subnet broadcast addr (phyints only) */
+ char uv_name[IFNAMSIZ]; /* interface name */
+ struct listaddr *uv_groups; /* list of local groups (phyints only) */
+ struct listaddr *uv_neighbors; /* list of neighboring routers */
+};
+
+#define VIFF_KERNEL_FLAGS (VIFF_TUNNEL|VIFF_SRCRT)
+#define VIFF_DOWN 0x0100 /* kernel state of interface */
+#define VIFF_DISABLED 0x0200 /* administratively disabled */
+#define VIFF_QUERIER 0x0400 /* I am the subnet's querier */
+
+
+struct listaddr {
+ struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
+ u_long al_addr; /* local group or neighbor address */
+ u_long al_timer; /* for timing out group or neighbor */
+};
+
+
+#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/mtree/verify.c
index d09312622265..c50611de4a4a 100644
--- a/usr.sbin/mtree/verify.c
+++ b/usr.sbin/mtree/verify.c
@@ -172,10 +172,11 @@ miss(p, tail)
(void)printf(" (not created: group not specified)");
else if (!(p->flags & F_MODE))
(void)printf(" (not created: mode not specified)");
- else if (mkdir(path, S_IRWXU))
+ else if (mkdir(path, S_IRWXU)) {
+ create = 1;
(void)printf(" (not created: %s)",
strerror(errno));
- else {
+ } else {
create = 1;
(void)printf(" (created)");
}
diff --git a/usr.sbin/named/named.restart b/usr.sbin/named/named.restart
index 6159a605cebe..19a2590e1b96 100644
--- a/usr.sbin/named/named.restart
+++ b/usr.sbin/named/named.restart
@@ -5,5 +5,5 @@
PATH=/bin:/sbin:/usr/sbin:/usr/bin
-kill -9 `cat /var/run/named.pid`
+kill -TERM `cat /var/run/named.pid`
named
diff --git a/usr.sbin/pwd_mkdb/Makefile b/usr.sbin/pwd_mkdb/Makefile
index 645728b3505c..616f10514dae 100644
--- a/usr.sbin/pwd_mkdb/Makefile
+++ b/usr.sbin/pwd_mkdb/Makefile
@@ -3,5 +3,8 @@
PROG= pwd_mkdb
SRCS= pw_scan.c pwd_mkdb.c
MAN8= pwd_mkdb.8
+.if defined (PW_COMPACT)
+CFLAGS+=-DPW_COMPACT
+.endif
.include <bsd.prog.mk>
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8
index 2ab2cee6ca5f..845662dc233c 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.8
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8
@@ -99,6 +99,20 @@ The front-ends to
and
.IR vipw (8),
handle the locking necessary to avoid this problem.
+.PP
+Standard database make routines are slow especially for big passwd
+files. Moreover, *pwd.db bases are too big and waste root space.
+You can have much faster routines with small *pwd.db,
+but loose binary compatibility
+with previous versions and with other BSD-like systems.
+If you want to setup much faster routines, define
+.B PW_COMPACT
+envirnoment variable (f.e. 'setenv PW_COMPACT' in csh) and use
+.I bootstrappwd
+target into /usr/src/Makefile.
+If you will want to return this changes back, use the same target
+without defining
+.BR PW_COMPACT .
.SH COMPATIBILITY
Previous versions of the system had a program similar to
.I pwd_mkdb,
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c
index b90daee24884..ffad7ed3158e 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.c
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -53,11 +53,42 @@ static char sccsid[] = "@(#)pwd_mkdb.c 5.5 (Berkeley) 5/6/91";
#include <string.h>
#include <stdlib.h>
+/* #define PW_COMPACT */
+/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */
+#ifdef PW_COMPACT
+# define HI_BSIZE 1024
+# define HI_CACHE (512 * 1024)
+# define HI_SCACHE (128 * 1024)
+#else
+# define HI_BSIZE 4096
+# define HI_CACHE (2048 * 1024)
+#endif
+
#define INSECURE 1
#define SECURE 2
#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#define PERM_SECURE (S_IRUSR|S_IWUSR)
+HASHINFO openinfo = {
+ HI_BSIZE, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ HI_CACHE, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+#ifdef PW_COMPACT
+HASHINFO sopeninfo = {
+ HI_BSIZE, /* bsize */
+ 32, /* ffactor */
+ 256, /* nelem */
+ HI_SCACHE, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+#endif
+
char *progname = "pwd_mkdb";
static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
@@ -76,10 +107,14 @@ main(argc, argv)
DB *dp, *edp;
sigset_t set;
DBT data, key;
+#ifdef PW_COMPACT
+ DBT pdata, sdata;
+#endif
int ch, cnt, tfd;
char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
char buf2[MAXPATHLEN];
+ umask(022);
strcpy(prefix, _PATH_PWD);
makeold = 0;
while ((ch = getopt(argc, argv, "d:pv")) != EOF)
@@ -121,17 +156,21 @@ main(argc, argv)
/* Open the temporary insecure password database. */
(void)sprintf(buf, "%s/%s.tmp", prefix, _MP_DB);
- dp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, NULL);
+ dp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
if (!dp)
error(buf);
clean = FILE_INSECURE;
+#ifdef PW_COMPACT
/* Open the temporary encrypted password database. */
(void)sprintf(buf, "%s/%s.tmp", prefix, _SMP_DB);
- edp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, NULL);
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &sopeninfo);
if (!edp)
error(buf);
clean = FILE_SECURE;
+#endif
/*
* Open file for old password file. Minor trickiness -- don't want to
@@ -163,11 +202,19 @@ main(argc, argv)
data.data = (u_char *)buf;
key.data = (u_char *)tbuf;
for (cnt = 1; scan(fp, &pwd); ++cnt) {
+#ifdef PW_COMPACT
+ pdata.data = (u_char *)&cnt;
+ pdata.size = sizeof(int);
+ sdata.data = (u_char *)pwd.pw_passwd;
+ sdata.size = strlen(pwd.pw_passwd) + 1;
+#endif
#define COMPACT(e) t = e; while (*p++ = *t++);
/* Create insecure data. */
p = buf;
COMPACT(pwd.pw_name);
+#ifndef PW_COMPACT
COMPACT("*");
+#endif
bcopy((char *)&pwd.pw_uid, p, sizeof(int));
p += sizeof(int);
bcopy((char *)&pwd.pw_gid, p, sizeof(int));
@@ -187,7 +234,22 @@ main(argc, argv)
len = strlen(pwd.pw_name);
bcopy(pwd.pw_name, tbuf + 1, len);
key.size = len + 1;
+#ifdef PW_COMPACT
+ if ((dp->put)(dp, &key, &pdata, R_NOOVERWRITE) == -1)
+#else
+ if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#endif
+ error("put");
+
+ /* Store insecure by uid. */
+ tbuf[0] = _PW_KEYBYUID;
+ bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
+ key.size = sizeof(pwd.pw_uid) + 1;
+#ifdef PW_COMPACT
+ if ((dp->put)(dp, &key, &pdata, R_NOOVERWRITE) == -1)
+#else
if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#endif
error("put");
/* Store insecure by number. */
@@ -197,12 +259,41 @@ main(argc, argv)
if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
- /* Store insecure by uid. */
- tbuf[0] = _PW_KEYBYUID;
- bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
- key.size = sizeof(pwd.pw_uid) + 1;
- if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+#ifdef PW_COMPACT
+ /* Store secure. */
+ if ((edp->put)(edp, &key, &sdata, R_NOOVERWRITE) == -1)
error("put");
+#endif
+
+ /* Create original format password file entry */
+ if (makeold)
+ (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
+ pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
+ pwd.pw_dir, pwd.pw_shell);
+
+ }
+ (void)(dp->close)(dp);
+#ifdef PW_COMPACT
+ (void)(edp->close)(edp);
+#endif
+
+ if (makeold) {
+ (void)fflush(oldfp);
+ (void)fsync(fileno(oldfp));
+ (void)fclose(oldfp);
+ }
+
+#ifndef PW_COMPACT
+ /* Open the temporary encrypted password database. */
+ (void)sprintf(buf, "%s/%s.tmp", prefix, _SMP_DB);
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+ if (!edp)
+ error(buf);
+ clean = FILE_SECURE;
+
+ rewind(fp);
+ for (cnt = 1; scan(fp, &pwd); ++cnt) {
/* Create secure data. */
p = buf;
@@ -227,35 +318,27 @@ main(argc, argv)
len = strlen(pwd.pw_name);
bcopy(pwd.pw_name, tbuf + 1, len);
key.size = len + 1;
- if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
/* Store secure by number. */
tbuf[0] = _PW_KEYBYNUM;
bcopy((char *)&cnt, tbuf + 1, sizeof(cnt));
key.size = sizeof(cnt) + 1;
- if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
/* Store secure by uid. */
tbuf[0] = _PW_KEYBYUID;
bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid));
key.size = sizeof(pwd.pw_uid) + 1;
- if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
error("put");
- /* Create original format password file entry */
- if (makeold)
- (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
- pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
- pwd.pw_dir, pwd.pw_shell);
}
- (void)(dp->close)(dp);
+
(void)(edp->close)(edp);
- if (makeold) {
- (void)fsync(oldfp);
- (void)fclose(oldfp);
- }
+#endif
/* Set master.passwd permissions, in case caller forgot. */
(void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
@@ -284,6 +367,7 @@ main(argc, argv)
exit(0);
}
+int
scan(fp, pw)
FILE *fp;
struct passwd *pw;
@@ -310,8 +394,8 @@ scan(fp, pw)
(void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt);
fmt: errno = EFTYPE;
error(pname);
- exit(1);
}
+ return(1);
}
mv(from, to)
diff --git a/usr.sbin/routed/Makefile b/usr.sbin/routed/Makefile
new file mode 100644
index 000000000000..0fc8bc839cbf
--- /dev/null
+++ b/usr.sbin/routed/Makefile
@@ -0,0 +1,22 @@
+# @(#)Makefile 5.16 (Berkeley) 4/26/91
+
+PROG= routed
+SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c \
+ trace.c inet.c
+MAN8= routed.8
+SUBDIR= query trace
+DPADD= ${LIBUTIL} ${LIBCOMPAT}
+LDADD= -lutil
+
+.include <bsd.prog.mk>
+
+.if (${MACHINE} == "vax")
+# The following can be deleted where not appropriate to use the kernel's
+# inline code expansions.
+INLINE= /sys/vax/inline/obj/inline
+C2= /usr/libexec/c2
+.c.o:
+ ${CC} -S ${CFLAGS} ${.CURDIR}/${.PREFIX}.c
+ @${C2} ${.PREFIX}.s | ${INLINE} | ${AS} -o ${.PREFIX}.o
+ @rm -f ${.PREFIX}.s
+.endif
diff --git a/usr.sbin/routed/af.c b/usr.sbin/routed/af.c
new file mode 100644
index 000000000000..19807b71db41
--- /dev/null
+++ b/usr.sbin/routed/af.c
@@ -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.sbin/routed/af.h b/usr.sbin/routed/af.h
new file mode 100644
index 000000000000..2d1bf293d365
--- /dev/null
+++ b/usr.sbin/routed/af.h
@@ -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.sbin/routed/defs.h b/usr.sbin/routed/defs.h
new file mode 100644
index 000000000000..f4fdf7a68f29
--- /dev/null
+++ b/usr.sbin/routed/defs.h
@@ -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.sbin/routed/if.c b/usr.sbin/routed/if.c
new file mode 100644
index 000000000000..4871c9df32aa
--- /dev/null
+++ b/usr.sbin/routed/if.c
@@ -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.sbin/routed/inet.c b/usr.sbin/routed/inet.c
new file mode 100644
index 000000000000..a465ac7637c9
--- /dev/null
+++ b/usr.sbin/routed/inet.c
@@ -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.sbin/routed/input.c b/usr.sbin/routed/input.c
new file mode 100644
index 000000000000..ec8c9d76239b
--- /dev/null
+++ b/usr.sbin/routed/input.c
@@ -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.sbin/routed/interface.h b/usr.sbin/routed/interface.h
new file mode 100644
index 000000000000..c67f203e3f8c
--- /dev/null
+++ b/usr.sbin/routed/interface.h
@@ -0,0 +1,91 @@
+/*
+ * 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_KERNELPUN 0x1f /* mask for above */
+
+#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.sbin/routed/main.c b/usr.sbin/routed/main.c
new file mode 100644
index 000000000000..75ed82f58e56
--- /dev/null
+++ b/usr.sbin/routed/main.c
@@ -0,0 +1,343 @@
+/*
+ * 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
+char copyright[] =
+"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 5.23 (Berkeley) 7/1/91";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <net/if.h>
+
+#include <sys/errno.h>
+#include <sys/signal.h>
+#include <sys/syslog.h>
+#include "pathnames.h"
+
+int supplier = -1; /* process should supply updates */
+int gateway = 0; /* 1 if we are a gateway to parts beyond */
+int debug = 0;
+int bufspace = 127*1024; /* max. input buffer size to request */
+
+struct rip *msg = (struct rip *)packet;
+void hup(), rtdeleteall(), sigtrace(), timer();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int n, cc, nfd, omask, tflags = 0;
+ struct sockaddr from;
+ struct timeval *tvp, waittime;
+ struct itimerval itval;
+ register struct rip *query = msg;
+ fd_set ibits;
+ u_char retry;
+
+ argv0 = argv;
+#if BSD >= 43
+ openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ setlogmask(LOG_UPTO(LOG_WARNING));
+#else
+ openlog("routed", LOG_PID);
+#define LOG_UPTO(x) (x)
+#define setlogmask(x) (x)
+#endif
+ sp = getservbyname("router", "udp");
+ if (sp == NULL) {
+ fprintf(stderr, "routed: router/udp: unknown service\n");
+ exit(1);
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = sp->s_port;
+ s = getsocket(AF_INET, SOCK_DGRAM, &addr);
+ if (s < 0)
+ exit(1);
+ argv++, argc--;
+ while (argc > 0 && **argv == '-') {
+ if (strcmp(*argv, "-s") == 0) {
+ supplier = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-q") == 0) {
+ supplier = 0;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-t") == 0) {
+ tflags++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-d") == 0) {
+ debug++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ gateway = 1;
+ argv++, argc--;
+ continue;
+ }
+ fprintf(stderr,
+ "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n");
+ exit(1);
+ }
+
+ if (debug == 0)
+ daemon(0, 0);
+ /*
+ * Any extra argument is considered
+ * a tracing log file.
+ */
+ if (argc > 0)
+ traceon(*argv);
+ while (tflags-- > 0)
+ bumploglevel();
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ /*
+ * Collect an initial view of the world by
+ * checking the interface configuration and the gateway kludge
+ * file. Then, send a request packet on all
+ * directly connected networks to find out what
+ * everyone else thinks.
+ */
+ rtinit();
+ ifinit();
+ gwkludge();
+ if (gateway > 0)
+ rtdefault();
+ if (supplier < 0)
+ supplier = 0;
+ query->rip_cmd = RIPCMD_REQUEST;
+ query->rip_vers = RIPVERSION;
+ if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */
+ query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC);
+ else
+ query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
+ query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
+ toall(sndmsg);
+ signal(SIGALRM, timer);
+ signal(SIGHUP, hup);
+ signal(SIGTERM, hup);
+ signal(SIGINT, rtdeleteall);
+ signal(SIGUSR1, sigtrace);
+ signal(SIGUSR2, sigtrace);
+ itval.it_interval.tv_sec = TIMER_RATE;
+ itval.it_value.tv_sec = TIMER_RATE;
+ itval.it_interval.tv_usec = 0;
+ itval.it_value.tv_usec = 0;
+ srandom(getpid());
+ if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
+ syslog(LOG_ERR, "setitimer: %m\n");
+
+ FD_ZERO(&ibits);
+ nfd = s + 1; /* 1 + max(fd's) */
+ for (;;) {
+ FD_SET(s, &ibits);
+ /*
+ * If we need a dynamic update that was held off,
+ * needupdate will be set, and nextbcast is the time
+ * by which we want select to return. Compute time
+ * until dynamic update should be sent, and select only
+ * until then. If we have already passed nextbcast,
+ * just poll.
+ */
+ if (needupdate) {
+ waittime = nextbcast;
+ timevalsub(&waittime, &now);
+ if (waittime.tv_sec < 0) {
+ waittime.tv_sec = 0;
+ waittime.tv_usec = 0;
+ }
+ if (traceactions)
+ fprintf(ftrace,
+ "select until dynamic update %d/%d sec/usec\n",
+ waittime.tv_sec, waittime.tv_usec);
+ tvp = &waittime;
+ } else
+ tvp = (struct timeval *)NULL;
+ n = select(nfd, &ibits, 0, 0, tvp);
+ if (n <= 0) {
+ /*
+ * Need delayed dynamic update if select returned
+ * nothing and we timed out. Otherwise, ignore
+ * errors (e.g. EINTR).
+ */
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ if (n == 0 && needupdate) {
+ if (traceactions)
+ fprintf(ftrace,
+ "send delayed dynamic update\n");
+ (void) gettimeofday(&now,
+ (struct timezone *)NULL);
+ toall(supply, RTS_CHANGED,
+ (struct interface *)NULL);
+ lastbcast = now;
+ needupdate = 0;
+ nextbcast.tv_sec = 0;
+ }
+ sigsetmask(omask);
+ continue;
+ }
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ omask = sigblock(sigmask(SIGALRM));
+#ifdef doesntwork
+/*
+printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n",
+ s,
+ ibits.fds_bits[0],
+ (s)/(sizeof(fd_mask) * 8),
+ ((s) % (sizeof(fd_mask) * 8)),
+ (1 << ((s) % (sizeof(fd_mask) * 8))),
+ ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))),
+ &ibits
+ );
+*/
+ if (FD_ISSET(s, &ibits))
+#else
+ if (ibits.fds_bits[s/32] & (1 << s))
+#endif
+ process(s);
+ /* handle ICMP redirects */
+ sigsetmask(omask);
+ }
+}
+
+timevaladd(t1, t2)
+ struct timeval *t1, *t2;
+{
+
+ t1->tv_sec += t2->tv_sec;
+ if ((t1->tv_usec += t2->tv_usec) > 1000000) {
+ t1->tv_sec++;
+ t1->tv_usec -= 1000000;
+ }
+}
+
+timevalsub(t1, t2)
+ struct timeval *t1, *t2;
+{
+
+ t1->tv_sec -= t2->tv_sec;
+ if ((t1->tv_usec -= t2->tv_usec) < 0) {
+ t1->tv_sec--;
+ t1->tv_usec += 1000000;
+ }
+}
+
+process(fd)
+ int fd;
+{
+ struct sockaddr from;
+ int fromlen, cc;
+ union {
+ char buf[MAXPACKETSIZE+1];
+ struct rip rip;
+ } inbuf;
+
+ for (;;) {
+ fromlen = sizeof (from);
+ cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EWOULDBLOCK)
+ perror("recvfrom");
+ break;
+ }
+ if (fromlen != sizeof (struct sockaddr_in))
+ break;
+ rip_input(&from, &inbuf.rip, cc);
+ }
+}
+
+getsocket(domain, type, sin)
+ int domain, type;
+ struct sockaddr_in *sin;
+{
+ int sock, on = 1;
+
+ if ((sock = socket(domain, type, 0)) < 0) {
+ perror("socket");
+ syslog(LOG_ERR, "socket: %m");
+ return (-1);
+ }
+#ifdef SO_BROADCAST
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ close(sock);
+ return (-1);
+ }
+#endif
+#ifdef SO_RCVBUF
+ for (on = bufspace; ; on -= 1024) {
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ &on, sizeof (on)) == 0)
+ break;
+ if (on <= 8*1024) {
+ syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
+ break;
+ }
+ }
+ if (traceactions)
+ fprintf(ftrace, "recv buf %d\n", on);
+#endif
+ if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) {
+ perror("bind");
+ syslog(LOG_ERR, "bind: %m");
+ close(sock);
+ return (-1);
+ }
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
+ syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
+ return (sock);
+}
diff --git a/usr.sbin/routed/output.c b/usr.sbin/routed/output.c
new file mode 100644
index 000000000000..10c81b1a0ca0
--- /dev/null
+++ b/usr.sbin/routed/output.c
@@ -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.sbin/flcopy/pathnames.h b/usr.sbin/routed/pathnames.h
index 60b2df28a6b4..54bac2751e52 100644
--- a/usr.sbin/flcopy/pathnames.h
+++ b/usr.sbin/routed/pathnames.h
@@ -1,5 +1,5 @@
-/*-
- * Copyright (c) 1990 The Regents of the University of California.
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,9 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)pathnames.h 5.1 (Berkeley) 4/28/90
+ * @(#)pathnames.h 5.3 (Berkeley) 6/1/90
*/
-#define _PATH_FLOPPY "/dev/floppy"
+#include <paths.h>
+
+#define _PATH_GATEWAYS "/etc/gateways"
diff --git a/usr.sbin/routed/query/Makefile b/usr.sbin/routed/query/Makefile
new file mode 100644
index 000000000000..03746d30652d
--- /dev/null
+++ b/usr.sbin/routed/query/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 5.6 (Berkeley) 5/11/90
+
+PROG= query
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/routed/query/query.c b/usr.sbin/routed/query/query.c
new file mode 100644
index 000000000000..32c10c1e1a8b
--- /dev/null
+++ b/usr.sbin/routed/query/query.c
@@ -0,0 +1,289 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1982, 1986 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)query.c 5.13 (Berkeley) 4/16/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WTIME 5 /* Time to wait for all responses */
+#define STIME 500000 /* usec to wait for another response */
+
+int s;
+int timedout;
+void timeout();
+char packet[MAXPACKETSIZE];
+int nflag;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, cc, count, bits;
+ struct sockaddr from;
+ int fromlen = sizeof(from), size = 32*1024;
+ struct timeval shorttime;
+
+ while ((ch = getopt(argc, argv, "n")) != EOF)
+ switch((char)ch) {
+ case 'n':
+ nflag++;
+ break;
+ case '?':
+ default:
+ goto usage;
+ }
+ argv += optind;
+
+ if (!*argv) {
+usage: printf("usage: query [-n] hosts...\n");
+ exit(1);
+ }
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0)
+ perror("setsockopt SO_RCVBUF");
+
+ while (*argv) {
+ query(*argv++);
+ count++;
+ }
+
+ /*
+ * Listen for returning packets;
+ * may be more than one packet per host.
+ */
+ bits = 1 << s;
+ bzero(&shorttime, sizeof(shorttime));
+ shorttime.tv_usec = STIME;
+ signal(SIGALRM, timeout);
+ alarm(WTIME);
+ while ((count > 0 && !timedout) ||
+ select(20, (fd_set *)&bits, NULL, NULL, &shorttime) > 0) {
+ cc = recvfrom(s, packet, sizeof (packet), 0,
+ &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("recvfrom");
+ (void) close(s);
+ exit(1);
+ }
+ continue;
+ }
+ rip_input(&from, cc);
+ count--;
+ }
+ exit (count > 0 ? count : 0);
+}
+
+query(host)
+ char *host;
+{
+ struct sockaddr_in router;
+ register struct rip *msg = (struct rip *)packet;
+ struct hostent *hp;
+ struct servent *sp;
+
+ bzero((char *)&router, sizeof (router));
+ router.sin_family = AF_INET;
+ router.sin_addr.s_addr = inet_addr(host);
+ if (router.sin_addr.s_addr == -1) {
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "query: %s: ", host);
+ herror((char *)NULL);
+ exit(1);
+ }
+ bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
+ }
+ sp = getservbyname("router", "udp");
+ if (sp == 0) {
+ printf("udp/router: service unknown\n");
+ exit(1);
+ }
+ router.sin_port = sp->s_port;
+ msg->rip_cmd = RIPCMD_REQUEST;
+ msg->rip_vers = RIPVERSION;
+ msg->rip_nets[0].rip_dst.sa_family = htons(AF_UNSPEC);
+ msg->rip_nets[0].rip_metric = htonl(HOPCNT_INFINITY);
+ if (sendto(s, packet, sizeof (struct rip), 0,
+ (struct sockaddr *)&router, sizeof(router)) < 0)
+ perror(host);
+}
+
+/*
+ * Handle an incoming routing packet.
+ */
+rip_input(from, size)
+ struct sockaddr_in *from;
+ int size;
+{
+ register struct rip *msg = (struct rip *)packet;
+ register struct netinfo *n;
+ char *name;
+ int lna, net, subnet;
+ struct hostent *hp;
+ struct netent *np;
+
+ if (msg->rip_cmd != RIPCMD_RESPONSE)
+ return;
+ printf("%d bytes from ", size);
+ if (nflag)
+ printf("%s:\n", inet_ntoa(from->sin_addr));
+ else {
+ hp = gethostbyaddr((char *)&from->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ name = hp == 0 ? "???" : hp->h_name;
+ printf("%s(%s):\n", name, inet_ntoa(from->sin_addr));
+ }
+ size -= sizeof (int);
+ n = msg->rip_nets;
+ while (size > 0) {
+ if (size < sizeof (struct netinfo))
+ break;
+ if (msg->rip_vers > 0) {
+ n->rip_dst.sa_family =
+ ntohs(n->rip_dst.sa_family);
+ n->rip_metric = ntohl(n->rip_metric);
+ }
+ switch (n->rip_dst.sa_family) {
+
+ case AF_INET:
+ { register struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)&n->rip_dst;
+ net = inet_netof(sin->sin_addr);
+ subnet = inet_subnetof(sin->sin_addr);
+ lna = inet_lnaof(sin->sin_addr);
+ name = "???";
+ if (!nflag) {
+ if (sin->sin_addr.s_addr == 0)
+ name = "default";
+ else if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ name = np->n_name;
+ else if (net == 0)
+ name = "default";
+ } else if ((lna & 0xff) == 0 &&
+ (np = getnetbyaddr(subnet, AF_INET))) {
+ struct in_addr subnaddr, inet_makeaddr();
+
+ subnaddr = inet_makeaddr(subnet, INADDR_ANY);
+ if (bcmp(&sin->sin_addr, &subnaddr,
+ sizeof(subnaddr)) == 0)
+ name = np->n_name;
+ else
+ goto host;
+ } else {
+ host:
+ hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ if (hp)
+ name = hp->h_name;
+ }
+ printf("\t%-17s metric %2d name %s\n",
+ inet_ntoa(sin->sin_addr), n->rip_metric, name);
+ } else
+ printf("\t%-17s metric %2d\n",
+ inet_ntoa(sin->sin_addr), n->rip_metric);
+ break;
+ }
+
+ default:
+ { u_short *p = (u_short *)n->rip_dst.sa_data;
+
+ printf("\t(af %d) %x %x %x %x %x %x %x, metric %d\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6],
+ n->rip_dst.sa_family,
+ n->rip_metric);
+ break;
+ }
+
+ }
+ size -= sizeof (struct netinfo), n++;
+ }
+}
+
+void
+timeout()
+{
+ timedout = 1;
+}
+
+/*
+ * Return the possible subnetwork number from an internet address.
+ * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING
+ * INSIDE OF THE HOST PART. We can only believe this if we have other
+ * information (e.g., we can find a name for this number).
+ */
+inet_subnetof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else if (IN_CLASSB(i))
+ return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+ else
+ return ((i & 0xffffffc0) >> 28);
+}
diff --git a/usr.sbin/routed/routed.8 b/usr.sbin/routed/routed.8
new file mode 100644
index 000000000000..1d428a7b39b3
--- /dev/null
+++ b/usr.sbin/routed/routed.8
@@ -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.sbin/routed/startup.c b/usr.sbin/routed/startup.c
new file mode 100644
index 000000000000..de4d58da2f45
--- /dev/null
+++ b/usr.sbin/routed/startup.c
@@ -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_KERNELPUN) | 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.sbin/routed/table.h b/usr.sbin/routed/table.h
new file mode 100644
index 000000000000..124e098eb295
--- /dev/null
+++ b/usr.sbin/routed/table.h
@@ -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.sbin/routed/tables.c b/usr.sbin/routed/tables.c
new file mode 100644
index 000000000000..17a4fb7b966e
--- /dev/null
+++ b/usr.sbin/routed/tables.c
@@ -0,0 +1,410 @@
+/*
+ * 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[] = "@(#)tables.c 5.17 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/syslog.h>
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#ifdef RTM_ADD
+#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
+#else
+#define FIXLEN(s) { }
+#endif
+
+int install = !DEBUG; /* if 1 call kernel */
+
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *
+rtlookup(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int doinghost = 1;
+
+ if (dst->sa_family >= af_max)
+ return (0);
+ (*afswitch[dst->sa_family].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ goto again;
+ }
+ return (0);
+}
+
+struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
+
+/*
+ * Find a route to dst as the kernel would.
+ */
+struct rt_entry *
+rtfind(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int af = dst->sa_family;
+ int doinghost = 1, (*match)();
+
+ if (af >= af_max)
+ return (0);
+ (*afswitch[af].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (doinghost) {
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ } else {
+ if (rt->rt_dst.sa_family == af &&
+ (*match)(&rt->rt_dst, dst))
+ return (rt);
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ match = afswitch[af].af_netmatch;
+ goto again;
+ }
+#ifdef notyet
+ /*
+ * Check for wildcard gateway, by convention network 0.
+ */
+ if (dst != &wildcard) {
+ dst = &wildcard, hash = 0;
+ goto again;
+ }
+#endif
+ return (0);
+}
+
+rtadd(dst, gate, metric, state)
+ struct sockaddr *dst, *gate;
+ int metric, state;
+{
+ struct afhash h;
+ register struct rt_entry *rt;
+ struct rthash *rh;
+ int af = dst->sa_family, flags;
+ u_int hash;
+
+ if (af >= af_max)
+ return;
+ (*afswitch[af].af_hash)(dst, &h);
+ flags = (*afswitch[af].af_rtflags)(dst);
+ /*
+ * Subnet flag isn't visible to kernel, move to state. XXX
+ */
+ FIXLEN(dst);
+ FIXLEN(gate);
+ if (flags & RTF_SUBNET) {
+ state |= RTS_SUBNET;
+ flags &= ~RTF_SUBNET;
+ }
+ if (flags & RTF_HOST) {
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+ } else {
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ }
+ rt = (struct rt_entry *)malloc(sizeof (*rt));
+ if (rt == 0)
+ return;
+ rt->rt_hash = hash;
+ rt->rt_dst = *dst;
+ rt->rt_router = *gate;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
+ if (rt->rt_ifp == 0) {
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ /*
+ * seems like we can't figure out the interface for the
+ * IP address of the local side of a point to point
+ * connection, we just don't add that entry in the
+ * table. (it seems to already be there anyway)
+ */
+ if (rt->rt_ifp == 0) {
+ syslog(LOG_DEBUG,
+ "rtadd: can't get interface for %s",
+ (*afswitch[dst->sa_family].af_format)(dst));
+ return;
+ }
+ }
+ if ((state & RTS_INTERFACE) == 0)
+ rt->rt_flags |= RTF_GATEWAY;
+ rt->rt_metric = metric;
+ insque(rt, rh);
+ TRACE_ACTION("ADD", rt);
+ /*
+ * If the ioctl fails because the gateway is unreachable
+ * from this host, discard the entry. This should only
+ * occur because of an incorrect entry in /etc/gateways.
+ */
+ if (install && (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+ ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0) {
+ if (errno != EEXIST && gate->sa_family < af_max)
+ syslog(LOG_ERR,
+ "adding route to net/host %s through gateway %s: %m\n",
+ (*afswitch[dst->sa_family].af_format)(dst),
+ (*afswitch[gate->sa_family].af_format)(gate));
+ perror("SIOCADDRT");
+ if (errno == ENETUNREACH) {
+ TRACE_ACTION("DELETE", rt);
+ remque(rt);
+ free((char *)rt);
+ }
+ }
+}
+
+rtchange(rt, gate, metric)
+ struct rt_entry *rt;
+ struct sockaddr *gate;
+ short metric;
+{
+ int add = 0, delete = 0, newgateway = 0;
+ struct rtentry oldroute;
+
+ FIXLEN(gate);
+ FIXLEN(&(rt->rt_router));
+ FIXLEN(&(rt->rt_dst));
+ if (!equal(&rt->rt_router, gate)) {
+ newgateway++;
+ TRACE_ACTION("CHANGE FROM ", rt);
+ } else if (metric != rt->rt_metric)
+ TRACE_NEWMETRIC(rt, metric);
+ if ((rt->rt_state & RTS_INTERNAL) == 0) {
+ /*
+ * If changing to different router, we need to add
+ * new route and delete old one if in the kernel.
+ * If the router is the same, we need to delete
+ * the route if has become unreachable, or re-add
+ * it if it had been unreachable.
+ */
+ if (newgateway) {
+ add++;
+ if (rt->rt_metric != HOPCNT_INFINITY)
+ delete++;
+ } else if (metric == HOPCNT_INFINITY)
+ delete++;
+ else if (rt->rt_metric == HOPCNT_INFINITY)
+ add++;
+ }
+ if (delete)
+ oldroute = rt->rt_rt;
+ if ((rt->rt_state & RTS_INTERFACE) && delete) {
+ rt->rt_state &= ~RTS_INTERFACE;
+ rt->rt_flags |= RTF_GATEWAY;
+ if (metric > rt->rt_metric && delete)
+ syslog(LOG_ERR, "%s route to interface %s (timed out)",
+ add? "changing" : "deleting",
+ rt->rt_ifp->int_name);
+ }
+ if (add) {
+ rt->rt_router = *gate;
+ rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+ if (rt->rt_ifp == 0) {
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ /*
+ * seems like we can't figure out the interface for the
+ * IP address of the local side of a point to point
+ * connection, we just don't add that entry in the
+ * table. (it seems to already be there anyway)
+ */
+ if (rt->rt_ifp == 0) {
+ struct sockaddr *dst = &(rt->rt_dst);
+ syslog(LOG_DEBUG,
+ "rtchange: can't get interface for %s",
+ (*afswitch[dst->sa_family].af_format)(dst));
+ return;
+ }
+ }
+ }
+ rt->rt_metric = metric;
+ rt->rt_state |= RTS_CHANGED;
+ if (newgateway)
+ TRACE_ACTION("CHANGE TO ", rt);
+#ifndef RTM_ADD
+ if (add && install)
+ if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+ perror("SIOCADDRT");
+ if (delete && install)
+ if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+ perror("SIOCDELRT");
+#else
+ if (delete && install)
+ if (ioctl(s, SIOCDELRT, (char *)&oldroute) < 0)
+ perror("SIOCDELRT");
+ if (add && install) {
+ if (ioctl(s, SIOCADDRT, (char *)&rt->rt_rt) < 0)
+ perror("SIOCADDRT");
+ }
+#endif
+}
+
+rtdelete(rt)
+ struct rt_entry *rt;
+{
+
+ TRACE_ACTION("DELETE", rt);
+ FIXLEN(&(rt->rt_router));
+ FIXLEN(&(rt->rt_dst));
+ if (rt->rt_metric < HOPCNT_INFINITY) {
+ if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
+ syslog(LOG_ERR,
+ "deleting route to interface %s? (timed out?)",
+ rt->rt_ifp->int_name);
+ if (install &&
+ (rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+ ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+ perror("SIOCDELRT");
+ }
+ remque(rt);
+ free((char *)rt);
+}
+
+rtdeleteall(sig)
+ int sig;
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1;
+
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_state & RTS_INTERFACE ||
+ rt->rt_metric >= HOPCNT_INFINITY)
+ continue;
+ TRACE_ACTION("DELETE", rt);
+ if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
+ ioctl(s, SIOCDELRT, (char *)&rt->rt_rt))
+ perror("SIOCDELRT");
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ exit(sig);
+}
+
+/*
+ * If we have an interface to the wide, wide world,
+ * add an entry for an Internet default route (wildcard) to the internal
+ * tables and advertise it. This route is not added to the kernel routes,
+ * but this entry prevents us from listening to other people's defaults
+ * and installing them in the kernel here.
+ */
+rtdefault()
+{
+ extern struct sockaddr inet_default;
+
+ rtadd(&inet_default, &inet_default, 1,
+ RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
+}
+
+rtinit()
+{
+ register struct rthash *rh;
+
+ for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+ for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+}
+
+
+/* ffrom /sys/i386/i386/machdep.c */
+/*
+ * insert an element into a queue
+ */
+insque(element, head)
+ register struct rthash *element, *head;
+{
+ element->rt_forw = head->rt_forw;
+ head->rt_forw = (struct rt_entry *)element;
+ element->rt_back = (struct rt_entry *)head;
+ ((struct rthash *)(element->rt_forw))->rt_back=(struct rt_entry *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+remque(element)
+ register struct rthash *element;
+{
+ ((struct rthash *)(element->rt_forw))->rt_back = element->rt_back;
+ ((struct rthash *)(element->rt_back))->rt_forw = element->rt_forw;
+ element->rt_back = (struct rt_entry *)0;
+}
diff --git a/usr.sbin/routed/timer.c b/usr.sbin/routed/timer.c
new file mode 100644
index 000000000000..fd0851d20ad9
--- /dev/null
+++ b/usr.sbin/routed/timer.c
@@ -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.sbin/routed/trace.c b/usr.sbin/routed/trace.c
new file mode 100644
index 000000000000..6e0b478bc55d
--- /dev/null
+++ b/usr.sbin/routed/trace.c
@@ -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.sbin/routed/trace.h b/usr.sbin/routed/trace.h
new file mode 100644
index 000000000000..741de720ce20
--- /dev/null
+++ b/usr.sbin/routed/trace.h
@@ -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); \
+ }
diff --git a/usr.sbin/routed/trace/Makefile b/usr.sbin/routed/trace/Makefile
new file mode 100644
index 000000000000..85e405af1d50
--- /dev/null
+++ b/usr.sbin/routed/trace/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 5.1 (Berkeley) 5/11/90
+
+PROG= trace
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/routed/trace/trace.c b/usr.sbin/routed/trace/trace.c
new file mode 100644
index 000000000000..64d928db8f20
--- /dev/null
+++ b/usr.sbin/routed/trace/trace.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 1983, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983, 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)trace.c 5.9 (Berkeley) 4/16/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sockaddr_in myaddr;
+char packet[MAXPACKETSIZE];
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int size, s;
+ struct sockaddr from;
+ struct sockaddr_in router;
+ register struct rip *msg = (struct rip *)packet;
+ struct hostent *hp;
+ struct servent *sp;
+
+ if (argc < 3) {
+usage:
+ printf("usage: trace cmd machines,\n");
+ printf("cmd either \"on filename\", or \"off\"\n");
+ exit(1);
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_port = htons(IPPORT_RESERVED-1);
+ if (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
+ perror("bind");
+ exit(2);
+ }
+
+ argv++, argc--;
+ msg->rip_cmd = strcmp(*argv, "on") == 0 ?
+ RIPCMD_TRACEON : RIPCMD_TRACEOFF;
+ msg->rip_vers = RIPVERSION;
+ argv++, argc--;
+ size = sizeof (int);
+ if (msg->rip_cmd == RIPCMD_TRACEON) {
+ strcpy(msg->rip_tracefile, *argv);
+ size += strlen(*argv);
+ argv++, argc--;
+ }
+ if (argc == 0)
+ goto usage;
+ bzero((char *)&router, sizeof (router));
+ router.sin_family = AF_INET;
+ sp = getservbyname("router", "udp");
+ if (sp == 0) {
+ printf("udp/router: service unknown\n");
+ exit(1);
+ }
+ router.sin_port = sp->s_port;
+ while (argc > 0) {
+ router.sin_family = AF_INET;
+ router.sin_addr.s_addr = inet_addr(*argv);
+ if (router.sin_addr.s_addr == -1) {
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "trace: %s: ", *argv);
+ herror((char *)NULL);
+ continue;
+ }
+ bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
+ }
+ if (sendto(s, packet, size, 0,
+ (struct sockaddr *)&router, sizeof(router)) < 0)
+ perror(*argv);
+ argv++, argc--;
+ }
+}
diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile
new file mode 100644
index 000000000000..c0a7a2dc767b
--- /dev/null
+++ b/usr.sbin/sa/Makefile
@@ -0,0 +1,8 @@
+# $Id: Makefile,v 1.2 1994/05/18 12:21:31 csgr Exp $
+
+PROG= sa
+MAN8= sa.8
+SRCS= main.c pdb.c usrdb.c
+LDADD= -lutil
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sa/extern.h b/usr.sbin/sa/extern.h
new file mode 100644
index 000000000000..609752d2d0d2
--- /dev/null
+++ b/usr.sbin/sa/extern.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: extern.h,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <db.h>
+
+/* structures */
+
+struct cmdinfo {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ u_long ci_uid; /* user id */
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+ u_int ci_flags; /* flags; see below */
+};
+#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
+
+struct userinfo {
+ u_long ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+};
+
+/* typedefs */
+
+typedef int (*cmpf_t) __P((const DBT *, const DBT *));
+
+/* external functions in sa.c */
+int main __P((int, char **));
+
+/* external functions in pdb.c */
+int pacct_init __P((void));
+void pacct_destroy __P((void));
+int pacct_add __P((const struct cmdinfo *));
+int pacct_update __P((void));
+void pacct_print __P((void));
+
+/* external functions in usrdb.c */
+int usracct_init __P((void));
+void usracct_destroy __P((void));
+int usracct_add __P((const struct cmdinfo *));
+int usracct_update __P((void));
+void usracct_print __P((void));
+
+/* variables */
+
+extern int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+extern int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+extern int cutoff;
+extern cmpf_t sa_cmp;
+
+/* some #defines to help with db's stupidity */
+
+#define DB_CLOSE(db) \
+ ((*(db)->close)(db))
+#define DB_GET(db, key, data, flags) \
+ ((*(db)->get)((db), (key), (data), (flags)))
+#define DB_PUT(db, key, data, flags) \
+ ((*(db)->put)((db), (key), (data), (flags)))
+#define DB_SYNC(db, flags) \
+ ((*(db)->sync)((db), (flags)))
+#define DB_SEQ(db, key, data, flags) \
+ ((*(db)->seq)((db), (key), (data), (flags)))
diff --git a/usr.sbin/sa/main.c b/usr.sbin/sa/main.c
new file mode 100644
index 000000000000..65a0216e928a
--- /dev/null
+++ b/usr.sbin/sa/main.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 copright[] =
+"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
+ All rights reserved.\n";
+
+static char rcsid[] = "$Id: main.c,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $";
+#endif
+
+/*
+ * sa: system accounting
+ */
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int acct_load __P((char *, int));
+static u_quad_t decode_comp_t __P((comp_t));
+static int cmp_comm __P((const char *, const char *));
+static int cmp_usrsys __P((const DBT *, const DBT *));
+static int cmp_avgusrsys __P((const DBT *, const DBT *));
+static int cmp_dkio __P((const DBT *, const DBT *));
+static int cmp_avgdkio __P((const DBT *, const DBT *));
+static int cmp_cpumem __P((const DBT *, const DBT *));
+static int cmp_avgcpumem __P((const DBT *, const DBT *));
+static int cmp_calls __P((const DBT *, const DBT *));
+
+int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+int cutoff = 1;
+
+static char *dfltargv[] = { _PATH_ACCT };
+static int dfltargc = (sizeof dfltargv/sizeof(char *));
+
+/* default to comparing by sum of user + system time */
+cmpf_t sa_cmp = cmp_usrsys;
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char ch;
+ int error;
+
+ while ((ch = getopt(argc, argv, "abcdDfijkKlmnqrstuv:")) != -1)
+ switch (ch) {
+ case 'a':
+ /* print all commands */
+ aflag = 1;
+ break;
+ case 'b':
+ /* sort by per-call user/system time average */
+ bflag = 1;
+ sa_cmp = cmp_avgusrsys;
+ break;
+ case 'c':
+ /* print percentage total time */
+ cflag = 1;
+ break;
+ case 'd':
+ /* sort by averge number of disk I/O ops */
+ dflag = 1;
+ sa_cmp = cmp_avgdkio;
+ break;
+ case 'D':
+ /* print and sort by total disk I/O ops */
+ Dflag = 1;
+ sa_cmp = cmp_dkio;
+ break;
+ case 'f':
+ /* force no interactive threshold comprison */
+ fflag = 1;
+ break;
+ case 'i':
+ /* do not read in summary file */
+ iflag = 1;
+ break;
+ case 'j':
+ /* instead of total minutes, give sec/call */
+ jflag = 1;
+ break;
+ case 'k':
+ /* sort by cpu-time average memory usage */
+ kflag = 1;
+ sa_cmp = cmp_avgcpumem;
+ break;
+ case 'K':
+ /* print and sort by cpu-storage integral */
+ sa_cmp = cmp_cpumem;
+ Kflag = 1;
+ break;
+ case 'l':
+ /* seperate system and user time */
+ lflag = 1;
+ break;
+ case 'm':
+ /* print procs and time per-user */
+ mflag = 1;
+ break;
+ case 'n':
+ /* sort by number of calls */
+ sa_cmp = cmp_calls;
+ break;
+ case 'q':
+ /* quiet; error messages only */
+ qflag = 1;
+ break;
+ case 'r':
+ /* reverse order of sort */
+ rflag = 1;
+ break;
+ case 's':
+ /* merge accounting file into summaries */
+ sflag = 1;
+ break;
+ case 't':
+ /* report ratio of user and system times */
+ tflag = 1;
+ break;
+ case 'u':
+ /* first, print uid and command name */
+ uflag = 1;
+ break;
+ case 'v':
+ /* cull junk */
+ vflag = 1;
+ cutoff = atoi(optarg);
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr,
+ "usage: sa [-abcdDfijkKlmnqrstu] [-v cutoff] [file ...]\n");
+ exit(1);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* various argument checking */
+ if (fflag && !vflag)
+ errx(1, "only one of -f requires -v");
+ if (fflag && aflag)
+ errx(1, "only one of -a and -v may be specified");
+ /* XXX need more argument checking */
+
+ if (!uflag) {
+ /* initialize tables */
+ if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
+ errx(1, "process accounting initialization failed");
+ if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
+ errx(1, "user accounting initialization failed");
+ }
+
+ if (argc == 0) {
+ argc = dfltargc;
+ argv = dfltargv;
+ }
+
+ /* for each file specified */
+ for (; argc > 0; argc--, argv++) {
+ int fd;
+
+ /*
+ * load the accounting data from the file.
+ * if it fails, go on to the next file.
+ */
+ fd = acct_load(argv[0], sflag);
+ if (fd < 0)
+ continue;
+
+ if (!uflag && sflag) {
+#ifndef DEBUG
+ sigset_t nmask, omask;
+ int unmask = 1;
+
+ /*
+ * block most signals so we aren't interrupted during
+ * the update.
+ */
+ if (sigfillset(&nmask) == -1) {
+ warn("sigfillset");
+ unmask = 0;
+ error = 1;
+ }
+ if (unmask &&
+ (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
+ warn("couldn't set signal mask ");
+ unmask = 0;
+ error = 1;
+ }
+#endif /* DEBUG */
+
+ /*
+ * truncate the accounting data file ASAP, to avoid
+ * losing data. don't worry about errors in updating
+ * the saved stats; better to underbill than overbill,
+ * but we want every accounting record intact.
+ */
+ if (ftruncate(fd, 0) == -1) {
+ warn("couldn't truncate %s", argv);
+ error = 1;
+ }
+
+ /*
+ * update saved user and process accounting data.
+ * note errors for later.
+ */
+ if (pacct_update() != 0 || usracct_update() != 0)
+ error = 1;
+
+#ifndef DEBUG
+ /*
+ * restore signals
+ */
+ if (unmask &&
+ (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
+ warn("couldn't restore signal mask");
+ error = 1;
+ }
+#endif /* DEBUG */
+ }
+
+ /*
+ * close the opened accounting file
+ */
+ if (close(fd) == -1) {
+ warn("close %s", argv);
+ error = 1;
+ }
+ }
+
+ if (!uflag && !qflag) {
+ /* print any results we may have obtained. */
+ if (!mflag)
+ pacct_print();
+ else
+ usracct_print();
+ }
+
+ if (!uflag) {
+ /* finally, deallocate databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_destroy();
+ if (sflag || (mflag && !qflag))
+ usracct_destroy();
+ }
+
+ exit(error);
+}
+
+static int
+acct_load(pn, wr)
+ char *pn;
+ int wr;
+{
+ struct acct ac;
+ struct cmdinfo ci;
+ ssize_t rv;
+ int fd, i;
+
+ /*
+ * open the file
+ */
+ fd = open(pn, wr ? O_RDWR : O_RDONLY, 0);
+ if (fd == -1) {
+ warn("open %s %s", pn, wr ? "for read/write" : "read-only");
+ return (-1);
+ }
+
+ /*
+ * read all we can; don't stat and open because more processes
+ * could exit, and we'd miss them
+ */
+ while (1) {
+ /* get one accounting entry and punt if there's an error */
+ rv = read(fd, &ac, sizeof(struct acct));
+ if (rv == -1)
+ warn("error reading %s", pn);
+ else if (rv > 0 && rv < sizeof(struct acct))
+ warnx("short read of accounting data in %s", pn);
+ if (rv != sizeof(struct acct))
+ break;
+
+ /* decode it */
+ ci.ci_calls = 1;
+ for (i = 0; i < sizeof ac.ac_comm && ac.ac_comm[i] != '\0';
+ i++) {
+ char c = ac.ac_comm[i];
+
+ if (!isascii(c) || iscntrl(c)) {
+ ci.ci_comm[i] = '?';
+ ci.ci_flags |= CI_UNPRINTABLE;
+ } else
+ ci.ci_comm[i] = c;
+ }
+ if (ac.ac_flag & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = decode_comp_t(ac.ac_etime);
+ ci.ci_utime = decode_comp_t(ac.ac_utime);
+ ci.ci_stime = decode_comp_t(ac.ac_stime);
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
+
+ if (!uflag) {
+ /* and enter it into the usracct and pacct databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_add(&ci);
+ if (sflag || (mflag && !qflag))
+ usracct_add(&ci);
+ } else if (!qflag)
+ printf("%6u %12.2lf cpu %12quk mem %12qu io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / (double) AHZ,
+ ci.ci_mem, ci.ci_io, ci.ci_comm);
+ }
+
+ /* finally, return the file descriptor for possible truncation */
+ return (fd);
+}
+
+static u_quad_t
+decode_comp_t(comp)
+ comp_t comp;
+{
+ u_quad_t rv;
+
+ /*
+ * for more info on the comp_t format, see:
+ * /usr/src/sys/kern/kern_acct.c
+ * /usr/src/sys/sys/acct.h
+ * /usr/src/usr.bin/lastcomm/lastcomm.c
+ */
+ rv = comp & 0x1fff; /* 13 bit fraction */
+ comp >>= 13; /* 3 bit base-8 exponent */
+ while (comp--)
+ rv <<= 3;
+
+ return (rv);
+}
+
+/* sort commands, doing the right thing in terms of reversals */
+static int
+cmp_comm(s1, s2)
+ const char *s1, *s2;
+{
+ int rv;
+
+ rv = strcmp(s1, s2);
+ if (rv == 0)
+ rv = -1;
+ return (rflag ? rv : -rv);
+}
+
+/* sort by total user and system time */
+static int
+cmp_usrsys(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ u_quad_t t1, t2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ t1 = c1->ci_utime + c1->ci_stime;
+ t2 = c2->ci_utime + c2->ci_stime;
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average user and system time */
+static int
+cmp_avgusrsys(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ double t1, t2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ t1 = c1->ci_utime + c1->ci_stime;
+ t1 /= (double) (c1->ci_calls ? c1->ci_calls : 1);
+
+ t2 = c2->ci_utime + c2->ci_stime;
+ t2 /= (double) (c2->ci_calls ? c2->ci_calls : 1);
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by total number of disk I/O operations */
+static int
+cmp_dkio(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ if (c1->ci_io < c2->ci_io)
+ return -1;
+ else if (c1->ci_io == c2->ci_io)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average number of disk I/O operations */
+static int
+cmp_avgdkio(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ double n1, n2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ n1 = (double) c1->ci_io / (double) (c1->ci_calls ? c1->ci_calls : 1);
+ n2 = (double) c2->ci_io / (double) (c2->ci_calls ? c2->ci_calls : 1);
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-storage integral */
+static int
+cmp_cpumem(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ if (c1->ci_mem < c2->ci_mem)
+ return -1;
+ else if (c1->ci_mem == c2->ci_mem)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-time average memory usage */
+static int
+cmp_avgcpumem(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+ u_quad_t t1, t2;
+ double n1, n2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ t1 = c1->ci_utime + c1->ci_stime;
+ t2 = c2->ci_utime + c2->ci_stime;
+
+ n1 = (double) c1->ci_mem / (double) (t1 ? t1 : 1);
+ n2 = (double) c2->ci_mem / (double) (t2 ? t2 : 1);
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the number of invocations */
+static int
+cmp_calls(d1, d2)
+ const DBT *d1, *d2;
+{
+ struct cmdinfo *c1, *c2;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ if (c1->ci_calls < c2->ci_calls)
+ return -1;
+ else if (c1->ci_calls == c2->ci_calls)
+ return (cmp_comm(c1->ci_comm, c2->ci_comm));
+ else
+ return 1;
+}
diff --git a/usr.sbin/sa/pathnames.h b/usr.sbin/sa/pathnames.h
new file mode 100644
index 000000000000..3ed865785492
--- /dev/null
+++ b/usr.sbin/sa/pathnames.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: pathnames.h,v 1.1.1.1 1994/05/18 08:04:10 csgr Exp $
+ */
+
+#define _PATH_ACCT "/var/account/acct"
+#define _PATH_SAVACCT "/var/account/savacct"
+#define _PATH_USRACCT "/var/account/usracct"
diff --git a/usr.sbin/sa/pdb.c b/usr.sbin/sa/pdb.c
new file mode 100644
index 000000000000..25b0168ffa28
--- /dev/null
+++ b/usr.sbin/sa/pdb.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 rcsid[] = "$Id: pdb.c,v 1.1.1.1 1994/05/18 08:04:11 csgr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int check_junk __P((struct cmdinfo *));
+static void add_ci __P((const struct cmdinfo *, struct cmdinfo *));
+static void print_ci __P((const struct cmdinfo *, const struct cmdinfo *));
+
+static DB *pacct_db;
+
+int
+pacct_init()
+{
+ DB *saved_pacct_db;
+ int error;
+
+ pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL);
+ if (pacct_db == NULL)
+ return (-1);
+
+ error = 0;
+ if (!iflag) {
+ DBT key, data;
+ int serr, nerr;
+
+ saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDONLY, 0, DB_BTREE,
+ NULL);
+ if (saved_pacct_db == NULL) {
+ error = errno == ENOENT ? 0 : -1;
+ if (error)
+ warn("retrieving process accounting summary");
+ goto out;
+ }
+
+ serr = DB_SEQ(saved_pacct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving process accounting summary");
+ error = -1;
+ goto closeout;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(pacct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("initializing process accounting stats");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(saved_pacct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving process accounting summary");
+ error = -1;
+ break;
+ }
+ }
+
+closeout: if (DB_CLOSE(saved_pacct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ }
+
+out: if (error != 0)
+ pacct_destroy();
+ return (error);
+}
+
+void
+pacct_destroy()
+{
+ if (DB_CLOSE(pacct_db) < 0)
+ warn("destroying process accounting stats");
+}
+
+int
+pacct_add(ci)
+ const struct cmdinfo *ci;
+{
+ DBT key, data;
+ struct cmdinfo newci;
+ char keydata[sizeof ci->ci_comm];
+ int rv;
+
+ bcopy(ci->ci_comm, &keydata, sizeof keydata);
+ key.data = &keydata;
+ key.size = strlen(keydata);
+
+ rv = DB_GET(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %s from process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* XXX compare size if paranoid */
+ /* add the old data to the new data */
+ bcopy(data.data, &newci, data.size);
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newci, sizeof newci);
+ bcopy(key.data, newci.ci_comm, key.size);
+ }
+
+ add_ci(ci, &newci);
+
+ data.data = &newci;
+ data.size = sizeof newci;
+ rv = DB_PUT(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %s to process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 1) {
+ warnx("duplicate key %s in process accounting stats",
+ ci->ci_comm);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+pacct_update()
+{
+ DB *saved_pacct_db;
+ DBT key, data;
+ int error, serr, nerr;
+
+ saved_pacct_db = dbopen(_PATH_SAVACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, NULL);
+ if (saved_pacct_db == NULL) {
+ warn("creating process accounting summary");
+ return (-1);
+ }
+
+ error = 0;
+
+ serr = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving process accounting stats");
+ error = -1;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(saved_pacct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("saving process accounting summary");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving process accounting stats");
+ error = -1;
+ break;
+ }
+ }
+
+ if (DB_SYNC(saved_pacct_db, 0) < 0) {
+ warn("syncing process accounting summary");
+ error = -1;
+ }
+ if (DB_CLOSE(saved_pacct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ return error;
+}
+
+void
+pacct_print()
+{
+ BTREEINFO bti;
+ DBT key, data, ndata;
+ DB *output_pacct_db;
+ struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
+ int rv;
+
+ bzero(&ci_total, sizeof ci_total);
+ strcpy(ci_total.ci_comm, "");
+ bzero(&ci_other, sizeof ci_other);
+ strcpy(ci_other.ci_comm, "***other");
+ bzero(&ci_junk, sizeof ci_junk);
+ strcpy(ci_junk.ci_comm, "**junk**");
+
+ /*
+ * Retrieve them into new DB, sorted by appropriate key.
+ * At the same time, cull 'other' and 'junk'
+ */
+ bzero(&bti, sizeof bti);
+ bti.compare = sa_cmp;
+ output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (output_pacct_db == NULL) {
+ warn("couldn't sort process accounting stats");
+ return;
+ }
+
+ ndata.data = NULL;
+ ndata.size = 0;
+ rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ /* add to total */
+ add_ci(&ci, &ci_total);
+
+ if (vflag && ci.ci_calls <= cutoff &&
+ (fflag || check_junk(&ci))) {
+ /* put it into **junk** */
+ add_ci(&ci, &ci_junk);
+ goto next;
+ }
+ if (!aflag &&
+ ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
+ /* put into ***other */
+ add_ci(&ci, &ci_other);
+ goto next;
+ }
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+
+next: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ }
+
+ /* insert **junk** and ***other */
+ if (ci_junk.ci_calls != 0) {
+ data.data = &ci_junk;
+ data.size = sizeof ci_junk;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+ if (ci_other.ci_calls != 0) {
+ data.data = &ci_other;
+ data.size = sizeof ci_other;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+
+ /* print out the total */
+ print_ci(&ci_total, &ci_total);
+
+ /* print out; if reversed, print first (smallest) first */
+ rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ print_ci(&ci, &ci_total);
+
+ rv = DB_SEQ(output_pacct_db, &data, &ndata,
+ rflag ? R_NEXT : R_PREV);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ }
+ DB_CLOSE(output_pacct_db);
+}
+
+static int
+check_junk(cip)
+ struct cmdinfo *cip;
+{
+ char *cp;
+ size_t len;
+
+ fprintf(stderr, "%s (%qu) -- ", cip->ci_comm, cip->ci_calls);
+ cp = fgetln(stdin, &len);
+
+ return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
+}
+
+static void
+add_ci(fromcip, tocip)
+ const struct cmdinfo *fromcip;
+ struct cmdinfo *tocip;
+{
+ tocip->ci_calls += fromcip->ci_calls;
+ tocip->ci_etime += fromcip->ci_etime;
+ tocip->ci_utime += fromcip->ci_utime;
+ tocip->ci_stime += fromcip->ci_stime;
+ tocip->ci_mem += fromcip->ci_mem;
+ tocip->ci_io += fromcip->ci_io;
+}
+
+static void
+print_ci(cip, totalcip)
+ const struct cmdinfo *cip, *totalcip;
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8qu ", cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_calls / (double) totalcip->ci_calls);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
+ else
+ printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_etime / (double) totalcip->ci_etime);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.2fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ (cip->ci_utime + cip->ci_stime) / (double)
+ (totalcip->ci_utime + totalcip->ci_stime));
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag)
+ if (!uflow)
+ printf("%8.2fre/cp ", cip->ci_etime / (double) (cip->ci_utime + cip->ci_stime));
+ else
+ printf("%8 ", "*ignore*");
+
+ if (Dflag)
+ printf("%10qutio ", cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10quk*sec ", cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
diff --git a/usr.sbin/sa/sa.8 b/usr.sbin/sa/sa.8
new file mode 100644
index 000000000000..339ab55d29e1
--- /dev/null
+++ b/usr.sbin/sa/sa.8
@@ -0,0 +1,246 @@
+.\"
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $Id: sa.8,v 1.1.1.1 1994/05/18 08:04:11 csgr Exp $
+.\"
+.Dd February 25, 1994
+.Dt SA 8
+.Os NetBSD 0.9a
+.Sh NAME
+.Nm sa
+.Nd print system accounting statistics
+.Sh SYNOPSIS
+.Nm sa
+.Op Fl abcdDfijkKlmnqrstu
+.Op Fl v Ar cutoff
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm sa
+utility reports on, cleans up,
+and generally maintains system
+accounting files.
+.Pp
+.Nm Sa
+is able to condense the the information in
+.Pa /var/account/acct
+into the summary files
+.Pa /var/account/savacct
+and
+.Pa /var/account/usracct ,
+which contain system statistics according
+to command name and login id, respectively.
+This condensation is desirable because on a
+large system,
+.Pa /var/account/acct
+can grow by hundreds of blocks per day.
+The summary files are normally read before
+the accounting file, so that reports include
+all available information.
+.Pp
+If file names are supplied, they are read instead of
+.Pa /var/account/account .
+After each file is read, if the summary
+files are being updated, an updated summary will
+be saved to disk. Only one report is printed,
+after the last file is processed.
+.Pp
+The labels used in the output indicate the following, except
+where otherwise specified by individual options:
+.Bl -tag -width k*sec
+.It Dv avio
+Average number of I/O operations per execution
+.It Dv cp
+Sum of user and system time, in minutes
+.It Dv cpu
+Same as
+.Dv cp
+.It Dv k
+CPU-time averaged core usage, in 1k units
+.It Dv k*sec
+CPU storage integral, in 1k-core seconds
+.It Dv re
+Real time, in minutes
+.It Dv s
+System time, in minutes
+.It Dv tio
+Total number of I/O operations
+.It Dv u
+User time, in minutes
+.El
+.Pp
+The options to
+.Nm sa
+are:
+.Bl -tag -width Ds
+.It Fl a
+List all command names, including those containing unprintable
+characters and those used only once. By default,
+.Nm sa
+places all names containing unprintable characters and
+those used only once under the name ``***other''.
+.It Fl b
+If printing command statistics, sort output by the sum of user and system
+time divided by number of calls.
+.It Fl c
+In addition to the number of calls and the user, system and real times
+for each command, print their percentage of the total over all commands.
+.It Fl d
+If printing command statistics, sort by the average number of disk
+I/O operations. If printing user statistics, print the average number of
+disk I/O operations per user.
+.It Fl D
+If printing command statistics, sort and print by the total number
+of disk I/O operations.
+.It Fl f
+Force no interactive threshold comparison with the
+.Fl v
+option.
+.It Fl i
+Do not read in the summary files.
+.It Fl j
+Instead of the total minutes per category, give seconds per call.
+.It Fl k
+If printing command statistics, sort by the cpu-time average memory
+usage. If printing user statistics, print the cpu-time average
+memory usage.
+.It Fl K
+If printing command statistics, print and sort by the cpu-storage integral.
+.It Fl l
+Separate system and user time; normally they are combined.
+.It Fl m
+Print per-user statistics rather than per-command statistics.
+.It Fl n
+Sort by number of calls.
+.It Fl q
+Create no output other than error messages.
+.It Fl r
+Reverse order of sort.
+.It Fl s
+Truncate the accounting files when done and merge their data
+into the summary files.
+.It Fl t
+For each command, report the ratio of real time to the sum
+of user and system cpu times.
+If the cpu time is too small to report, ``*ignore*'' appears in
+this field.
+.It Fl u
+Superseding all other flags, for each entry
+in the accounting file, print the user ID, total seconds of cpu usage,
+total memory usage, number of I/O operations performed, and
+command name.
+.It Fl v Ar cutoff
+For each command used
+.Ar cutoff
+times or fewer, print the command name and await a reply
+from the terminal. If the reply begins with ``y'', add
+the command to the category ``**junk**''. This flag is
+used to strip garbage from the report.
+.El
+.Pp
+By default, per-command statistics will be printed. The number of
+calls, the total elapsed time in minutes, total cpu and user time
+in minutes, average number of I/O operations, and CPU-time
+averaged core usage will be printed. If the
+.Fl m
+option is specified, per-user statistics will be printed, including
+the user name, the number of commands invoked, total cpu time used
+(in minutes), total number of I/O operations, and CPU storage integral
+for each user. If the
+.Fl u
+option is specified, the uid, user and system time (in seconds),
+CPU storage integral, I/O usage, and command name will be printed
+for each entry in the accounting data file.
+.Pp
+If the
+.Fl u
+flag is specified, all flags other than
+.Fl q
+are ignored. If the
+.Fl m
+flag is specified, only the
+.Fl b ,
+.Fl d ,
+.Fl i ,
+.Fl k ,
+.Fl q ,
+and
+.Fl s
+flags are honored.
+.Pp
+The
+.Nm sa
+utility exits 0 on success, and >0 if an error occurs.
+.Sh FILES
+.Bl -tag -width /var/account/usracct -compact
+.It Pa /var/account/acct
+raw accounting data file
+.It Pa /var/account/savacct
+per-command accounting summary database
+.It Pa /var/account/usracct
+per-user accounting summary database
+.El
+.Sh SEE ALSO
+.Xr ac 8 ,
+.Xr acct 5 ,
+.Xr accton 8 ,
+.Xr lastcomm 1
+.Sh BUGS
+The number of options to this program is absurd, especially considering
+that there's not much logic behind their lettering.
+.Pp
+The field labels should be more consistent.
+.Pp
+NetBSD's VM system does not record the CPU storage integral.
+.Sh CAVEATS
+While the behavior of the options in this version of
+.Nm sa
+was modeled after the original version, there are some intentional
+differences and undoubtedly some unintentional ones as well. In
+particular, the
+.Fl q
+option has been added, and the
+.Fl m
+option now understands more options than it used to.
+.Pp
+The formats of the summary files created by this version of
+.Nm sa
+are very different than the those used by the original version.
+This is not considered a problem, however, because the accounting record
+format has changed as well (since user ids are now 32 bits).
+.Sh HISTORY
+.Nm Sa
+was written for
+.Nx 0.9a
+from the specification provided by various systems' manual pages.
+Its date of origin is unknown to the author.
+.Sh AUTHOR
+.Bl -tag
+Chris G. Demetriou, cgd@postgres.berkeley.edu
+.El
diff --git a/usr.sbin/sa/usrdb.c b/usr.sbin/sa/usrdb.c
new file mode 100644
index 000000000000..2e004731c1fe
--- /dev/null
+++ b/usr.sbin/sa/usrdb.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 rcsid[] = "$Id: usrdb.c,v 1.2 1994/05/18 12:21:33 csgr Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int uid_compare __P((const DBT *, const DBT *));
+
+static DB *usracct_db;
+
+int
+usracct_init()
+{
+ DB *saved_usracct_db;
+ BTREEINFO bti;
+ int error;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ usracct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (usracct_db == NULL)
+ return (-1);
+
+ error = 0;
+ if (!iflag) {
+ DBT key, data;
+ int serr, nerr;
+
+ saved_usracct_db = dbopen(_PATH_USRACCT, O_RDONLY, 0, DB_BTREE,
+ &bti);
+ if (saved_usracct_db == NULL) {
+ error = (errno == ENOENT) ? 0 : -1;
+ if (error)
+ warn("retrieving user accounting summary");
+ goto out;
+ }
+
+ serr = DB_SEQ(saved_usracct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving user accounting summary");
+ error = -1;
+ goto closeout;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(usracct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("initializing user accounting stats");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(saved_usracct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving user accounting summary");
+ error = -1;
+ break;
+ }
+ }
+
+closeout:
+ if (DB_CLOSE(saved_usracct_db) < 0) {
+ warn("closing user accounting summary");
+ error = -1;
+ }
+ }
+
+out:
+ if (error != 0)
+ usracct_destroy();
+ return (error);
+}
+
+void
+usracct_destroy()
+{
+ if (DB_CLOSE(usracct_db) < 0)
+ warn("destroying user accounting stats");
+}
+
+int
+usracct_add(ci)
+ const struct cmdinfo *ci;
+{
+ DBT key, data;
+ struct userinfo newui;
+ u_long uid;
+ int rv;
+
+ uid = ci->ci_uid;
+ key.data = &uid;
+ key.size = sizeof uid;
+
+ rv = DB_GET(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %d from user accounting stats", uid);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* add the old data to the new data */
+ bcopy(data.data, &newui, data.size);
+ if (newui.ui_uid != uid) {
+ warnx("key %d != expected record number %d",
+ newui.ui_uid, uid);
+ warnx("inconsistent user accounting stats");
+ return (-1);
+ }
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newui, sizeof newui);
+ newui.ui_uid = ci->ci_uid;
+ }
+
+ newui.ui_calls += ci->ci_calls;
+ newui.ui_utime += ci->ci_utime;
+ newui.ui_stime += ci->ci_stime;
+ newui.ui_mem += ci->ci_mem;
+ newui.ui_io += ci->ci_io;
+
+ data.data = &newui;
+ data.size = sizeof newui;
+ rv = DB_PUT(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %d to user accounting stats", uid);
+ return (-1);
+ } else if (rv != 0) {
+ warnx("DB_PUT returned 1");
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+usracct_update()
+{
+ DB *saved_usracct_db;
+ DBT key, data;
+ BTREEINFO bti;
+ u_long uid;
+ int error, serr, nerr;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ saved_usracct_db = dbopen(_PATH_USRACCT, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, &bti);
+ if (saved_usracct_db == NULL) {
+ warn("creating user accounting summary");
+ return (-1);
+ }
+
+ error = 0;
+
+ serr = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (serr < 0) {
+ warn("retrieving user accounting stats");
+ error = -1;
+ }
+ while (serr == 0) {
+ nerr = DB_PUT(saved_usracct_db, &key, &data, 0);
+ if (nerr < 0) {
+ warn("saving user accounting summary");
+ error = -1;
+ break;
+ }
+
+ serr = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (serr < 0) {
+ warn("retrieving user accounting stats");
+ error = -1;
+ break;
+ }
+ }
+
+ if (DB_SYNC(saved_usracct_db, 0) < 0) {
+ warn("syncing process accounting summary");
+ error = -1;
+ }
+out:
+ if (DB_CLOSE(saved_usracct_db) < 0) {
+ warn("closing process accounting summary");
+ error = -1;
+ }
+ return error;
+}
+
+void
+usracct_print()
+{
+ DBT key, data;
+ struct userinfo *ui;
+ double t;
+ int rv;
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+
+ while (rv == 0) {
+ ui = (struct userinfo *) data.data;
+
+ printf("%-8s %9qu ",
+ user_from_uid(ui->ui_uid, 0), ui->ui_calls);
+
+ t = (double) (ui->ui_utime + ui->ui_stime) /
+ (double) AHZ;
+ if (t < 0.0001) /* kill divide by zero */
+ t = 0.0001;
+
+ printf("%12.2lf%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
+ else
+ printf("%12qu%s", ui->ui_io, "tio");
+
+ /* t is always >= 0.0001; see above */
+ if (kflag)
+ printf("%12qu%s", ui->ui_mem / t, "k");
+ else
+ printf("%12qu%s", ui->ui_mem, "k*sec");
+
+ printf("\n");
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+ }
+}
+
+static int
+uid_compare(k1, k2)
+ const DBT *k1, *k2;
+{
+ u_long d1, d2;
+
+ bcopy(k1->data, &d1, sizeof d1);
+ bcopy(k2->data, &d2, sizeof d2);
+
+ if (d1 < d2)
+ return -1;
+ else if (d1 == d2)
+ return 0;
+ else
+ return 1;
+}
diff --git a/usr.sbin/sendmail/cf/README b/usr.sbin/sendmail/cf/README
index 53bc084bb88e..c026b141f242 100644
--- a/usr.sbin/sendmail/cf/README
+++ b/usr.sbin/sendmail/cf/README
@@ -813,7 +813,7 @@ Sam Leffler's FlexFAX software is still in beta test -- but he expects a
public version out "later this week" [as of 3/1/93]. The following
blurb is direct from Sam:
- $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/cf/README,v 1.7.2.1 1994/04/18 03:51:03 rgrimes Exp $
+ $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/cf/README,v 1.8 1994/03/19 07:35:36 alm Exp $
How To Obtain This Software (in case all you get is this file)
--------------------------------------------------------------
diff --git a/usr.sbin/sendmail/contrib/expn.pl b/usr.sbin/sendmail/contrib/expn.pl
index 15d287b5c650..b202fd738482 100644
--- a/usr.sbin/sendmail/contrib/expn.pl
+++ b/usr.sbin/sendmail/contrib/expn.pl
@@ -14,7 +14,7 @@ $sockaddr = 'S n a4 x8';
# system requirements:
# must have 'nslookup' and 'hostname' programs.
-# $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/contrib/expn.pl,v 1.1.2.1 1994/04/18 03:52:18 rgrimes Exp $
+# $Header: /home/cvs/386BSD/src/usr.sbin/sendmail/contrib/expn.pl,v 1.2 1994/03/19 07:36:03 alm Exp $
# TODO:
# less magic should apply to command-line addresses
diff --git a/usr.sbin/sendmail/src/conf.c b/usr.sbin/sendmail/src/conf.c
index 1a9646365b88..8fef644fc7a9 100644
--- a/usr.sbin/sendmail/src/conf.c
+++ b/usr.sbin/sendmail/src/conf.c
@@ -913,7 +913,7 @@ getla()
/* Non Apollo stuff removed by Don Lewis 11/15/93 */
#ifndef lint
-static char rcsid[] = "@(#)$Id: conf.c,v 1.5.2.1 1994/04/18 03:53:45 rgrimes Exp $";
+static char rcsid[] = "@(#)$Id: conf.c,v 1.6 1994/03/19 07:36:47 alm Exp $";
#endif /* !lint */
#ifdef apollo
diff --git a/usr.sbin/sliplogin/slip.hosts b/usr.sbin/sliplogin/slip.hosts
index 00c01e6e58da..16d22fbd43e0 100644
--- a/usr.sbin/sliplogin/slip.hosts
+++ b/usr.sbin/sliplogin/slip.hosts
@@ -1,6 +1,6 @@
#
# login local-addr remote-addr mask opt1 opt2
-# (normal,compress,noicmp)
+# (normal,compressautocomp,noicmp)
#
Shavoc okeeffe havoc 0xffffff00 normal
Soxford okeeffe oxford-gw 0xffffff00 compress
diff --git a/usr.sbin/sliplogin/sliplogin.c b/usr.sbin/sliplogin/sliplogin.c
index a4cf21491733..3ca006cd847e 100644
--- a/usr.sbin/sliplogin/sliplogin.c
+++ b/usr.sbin/sliplogin/sliplogin.c
@@ -280,7 +280,7 @@ main(argc, argv)
#ifdef POSIX
if (fork() > 0)
exit(0);
- if (setsid() != 0)
+ if (setsid() == -1)
perror("setsid");
#else
if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) {
@@ -318,6 +318,11 @@ main(argc, argv)
}
findid(name);
}
+ if (!isatty(0)) {
+ (void) fprintf(stderr, "access denied - stdin is not a tty\n");
+ syslog(LOG_ERR, "access denied - stdin is not a tty\n");
+ exit(1);
+ }
(void) fchmod(0, 0600);
(void) fprintf(stderr, "starting slip login for %s\n", loginname);
#ifdef POSIX
diff --git a/usr.sbin/slstat/Makefile b/usr.sbin/slstat/Makefile
new file mode 100644
index 000000000000..21309a612b45
--- /dev/null
+++ b/usr.sbin/slstat/Makefile
@@ -0,0 +1,11 @@
+# from: @(#)Makefile 5.6 (Berkeley) 4/23/91
+# $Id: Makefile,v 1.1.1.1 1994/06/17 06:42:36 rich Exp $
+
+PROG= slstat
+MAN8= slstat.8
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/slstat/slstat.8 b/usr.sbin/slstat/slstat.8
new file mode 100644
index 000000000000..0194cbf80e95
--- /dev/null
+++ b/usr.sbin/slstat/slstat.8
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1986 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.
+.\"
+.\" @(#)slstat.8 6.8 (Berkeley) 6/20/91
+.\"
+.TH SLSTAT 1 "June 20, 1991"
+.UC 4
+.SH NAME
+slstat \- report serial line IP statistics
+.SH SYNOPSIS
+.nf
+.ft B
+slstat [ \-i interval ] [ \-v ] [ \-r ] [ unit ] [ system ] [ core ]
+.ft R
+.fi
+.SH DESCRIPTION
+.I Slstat
+reports certain kernel statistics kept about serial line internet
+protocol traffic.
+.PP
+The options are as follows:
+.TP
+\-i
+Repeat the display indefinitely every
+.I interval
+seconds.
+If no
+.I interval
+is specified, the default is 5 seconds.
+.TP
+\-v
+Verbose display of extra fields of information.
+.TP
+\-r
+Display all values in rate per second that ammount per interval.
+.TP
+unit
+is a single digit specifying the slip interface. The default unit is
+.I 0
+for interface
+.I sl0.
+.TP
+system
+Extract the name list from the specified system instead of the default, /386bsd.
+.TP
+core
+Extract values associated with the name list from the specified
+core instead of the default, /dev/kmem.
+.PP
+By default,
+.I vmstat
+displays the following information:
+.PP
+.TP
+in
+bytes received
+.TP
+out
+bytes sent
+.TP
+pack
+packets received or sent
+.TP
+comp
+compressed packets received or sent
+.TP
+uncomp
+uncompressed packets received or sent
+.TP
+unknwn
+inbound packets of unknown type
+.TP
+toss
+inbound packets tossed because of error
+.TP
+other
+all other inbound or outbound ip packets
+.TP
+err
+input or output errors
+.TP
+search
+searches for connection state
+.TP
+miss
+times we could not find a connectoin state
+.TP
+coll
+collisions with end of clists.
+If you get many collisions (more than one or two
+a day) you probably do not have enough clists
+and you should increase "nclist" in param.c.
+.SH EXAMPLES
+The command ``slstat -i 5'' will print what the system is doing every five
+seconds.
+.SH FILES
+.ta \w'/dev/kmem 'u
+/386bsd default kernel namelist
+.br
+/dev/kmem default memory file
+.SH SEE ALSO
+.IR fstat (1),
+.IR netstat (1),
+.IR nfsstat (1),
+.IR ps (1),
+.IR systat (1),
+.IR iostat (8),
+.IR pstat (8)
+.sp
+The sections starting with ``Interpreting system activity'' in
+.IR "Installing and Operating 4.3BSD" .
+.SH BUGS
+
diff --git a/usr.sbin/slstat/slstat.c b/usr.sbin/slstat/slstat.c
new file mode 100644
index 000000000000..ddcee8b10f3e
--- /dev/null
+++ b/usr.sbin/slstat/slstat.c
@@ -0,0 +1,287 @@
+/*
+ * print serial line IP statistics:
+ * slstat [-i interval] [-v] [interface] [system] [core]
+ *
+ * Copyright (c) 1989, 1990, 1991, 1992 Regents of the University of
+ * California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Van Jacobson (van@ee.lbl.gov), Dec 31, 1989:
+ * - Initial distribution.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: slstat.c,v 1.1.1.1 1994/06/17 06:42:39 rich Exp $";
+#endif
+
+#include <stdio.h>
+#include <paths.h>
+#include <nlist.h>
+#include <kvm.h>
+
+#define INET
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+#include <signal.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <net/slcompress.h>
+#include <net/if_slvar.h>
+
+struct nlist nl[] = {
+#define N_SOFTC 0
+ { "_sl_softc" },
+ "",
+};
+
+char *system = _PATH_UNIX;
+char *kmemf = NULL;
+
+int kflag;
+int rflag;
+int vflag;
+unsigned interval = 5;
+int unit;
+
+extern char *malloc();
+extern off_t lseek();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ --argc; ++argv;
+ while (argc > 0) {
+ if (strcmp(argv[0], "-v") == 0) {
+ ++vflag;
+ ++argv, --argc;
+ continue;
+ }
+ if (strcmp(argv[0], "-r") == 0) {
+ ++rflag;
+ ++argv, --argc;
+ continue;
+ }
+ if (strcmp(argv[0], "-i") == 0 && argv[1] &&
+ isdigit(argv[1][0])) {
+ interval = atoi(argv[1]);
+ if (interval <= 0)
+ usage();
+ ++argv, --argc;
+ ++argv, --argc;
+ continue;
+ }
+ if (isdigit(argv[0][0])) {
+ unit = atoi(argv[0]);
+ if (unit < 0)
+ usage();
+ ++argv, --argc;
+ continue;
+ }
+ if (kflag)
+ usage();
+
+ system = *argv;
+ ++argv, --argc;
+ if (argc > 0) {
+ kmemf = *argv++;
+ --argc;
+ kflag++;
+ }
+ }
+ if (kvm_openfiles(system, kmemf, NULL) < 0) {
+ (void)fprintf(stderr,
+ "slstat: kvm_openfiles(%s,%s,0): %s\n",
+ system, kmemf, kvm_geterr());
+ exit(1);
+ }
+ if ((c = kvm_nlist(nl)) != 0) {
+ if (c > 0) {
+ (void)fprintf(stderr,
+ "slstat: undefined symbols in %s:", system);
+ for (c = 0; c < sizeof(nl)/sizeof(nl[0]); c++)
+ if (nl[c].n_type == 0)
+ fprintf(stderr, " %s", nl[c].n_name);
+ (void)fputc('\n', stderr);
+ } else
+ (void)fprintf(stderr, "slstat: kvm_nlist: %s\n",
+ kvm_geterr());
+ exit(1);
+ }
+ intpr();
+ exit(0);
+}
+
+#define V(offset) ((line % 20)? ((sc->offset - osc->offset) / (rflag ? interval : 1)) : sc->offset)
+#define AMT (sizeof(*sc) - 2 * sizeof(sc->sc_comp.tstate))
+
+usage()
+{
+ static char umsg[] =
+ "usage: slstat [-i interval] [-v] [unit] [system] [core]\n";
+
+ fprintf(stderr, umsg);
+ exit(1);
+}
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ */
+intpr()
+{
+ register int line = 0;
+ int oldmask;
+ void catchalarm();
+ struct sl_softc *sc, *osc;
+ off_t addr;
+
+ addr = nl[N_SOFTC].n_value + unit * sizeof(struct sl_softc);
+ sc = (struct sl_softc *)malloc(AMT);
+ osc = (struct sl_softc *)malloc(AMT);
+ bzero((char *)osc, AMT);
+
+ while (1) {
+ if (kread(addr, (char *)sc, AMT) < 0)
+ perror("kmem read");
+ (void)signal(SIGALRM, catchalarm);
+ signalled = 0;
+ (void)alarm(interval);
+
+ if ((line % 20) == 0) {
+ printf("%8.8s %6.6s %6.6s %6.6s %6.6s",
+ "in", "pack", "comp", "uncomp", "unknwn");
+ if (vflag)
+ printf(" %6.6s %6.6s %6.6s",
+ "toss", "other", "err");
+ printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s",
+ "out", "pack", "comp", "uncomp", "other");
+ if (vflag)
+ printf(" %6.6s %6.6s %6.6s %6.6s",
+ "search", "miss", "err", "coll");
+ putchar('\n');
+ }
+ printf("%8u %6d %6u %6u %6u",
+ V(sc_bytesrcvd),
+ V(sc_if.if_ipackets),
+ V(sc_comp.sls_compressedin),
+ V(sc_comp.sls_uncompressedin),
+ V(sc_comp.sls_errorin));
+ if (vflag)
+ printf(" %6u %6u %6u",
+ V(sc_comp.sls_tossed),
+ V(sc_if.if_ipackets) -
+ V(sc_comp.sls_compressedin) -
+ V(sc_comp.sls_uncompressedin) -
+ V(sc_comp.sls_errorin),
+ V(sc_if.if_ierrors));
+ printf(" | %8u %6d %6u %6u %6u",
+ V(sc_bytessent) / (rflag ? interval : 1),
+ V(sc_if.if_opackets),
+ V(sc_comp.sls_compressed),
+ V(sc_comp.sls_packets) - V(sc_comp.sls_compressed),
+ V(sc_if.if_opackets) - V(sc_comp.sls_packets));
+ if (vflag)
+ printf(" %6u %6u %6u %6u",
+ V(sc_comp.sls_searches),
+ V(sc_comp.sls_misses),
+ V(sc_if.if_oerrors),
+ V(sc_if.if_collisions));
+ putchar('\n');
+ fflush(stdout);
+ line++;
+ oldmask = sigblock(sigmask(SIGALRM));
+ if (! signalled) {
+ sigpause(0);
+ }
+ sigsetmask(oldmask);
+ signalled = 0;
+ (void)alarm(interval);
+ bcopy((char *)sc, (char *)osc, AMT);
+ }
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+void
+catchalarm()
+{
+ signalled = 1;
+}
+
+#include <kvm.h>
+#include <fcntl.h>
+
+int kd;
+
+kopen(system, kmemf, errstr)
+ char *system;
+ char *kmemf;
+ char *errstr;
+{
+ if (strcmp(system, _PATH_UNIX) == 0 &&
+ strcmp(kmemf, _PATH_KMEM) == 0) {
+ system = 0;
+ kmemf = 0;
+ }
+ kd = kvm_openfiles(system, kmemf, (void *)0);
+ if (kd == 0)
+ return -1;
+
+ return 0;
+}
+
+int
+knlist(system, nl, errstr)
+ char *system;
+ struct nlist *nl;
+ char *errstr;
+{
+ if (kd == 0)
+ /* kopen() must be called first */
+ abort();
+
+ if (kvm_nlist(nl) < 0 || nl[0].n_type == 0) {
+ fprintf(stderr, "%s: %s: no namelist\n", errstr, system);
+ return -1;
+ }
+ return 0;
+}
+
+int
+kread(addr, buf, size)
+ off_t addr;
+ char *buf;
+ int size;
+{
+ if (kvm_read((char *)addr, buf, size) != size)
+ return -1;
+ return 0;
+}
diff --git a/usr.sbin/vidcontrol/Makefile b/usr.sbin/vidcontrol/Makefile
new file mode 100644
index 000000000000..11636b96dba2
--- /dev/null
+++ b/usr.sbin/vidcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG= vidcontrol
+SRCS= vidcontrol.c decode.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/vidcontrol/decode.c b/usr.sbin/vidcontrol/decode.c
new file mode 100644
index 000000000000..88861db6e8f2
--- /dev/null
+++ b/usr.sbin/vidcontrol/decode.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: decode.c,v 1.1 1994/05/20 12:20:37 sos Exp $
+ */
+
+#include <stdio.h>
+
+int decode(FILE *fd, char *buffer)
+{
+ int n, pos = 0;
+ char *p;
+ char temp[128];
+
+#define DEC(c) (((c) - ' ') & 0x3f)
+
+ do {
+ if (!fgets(temp, sizeof(temp), fd))
+ return(0);
+ } while (strncmp(temp, "begin ", 6));
+ sscanf(temp, "begin %o %s", &n, temp);
+ for (;;) {
+ if (!fgets(p = temp, sizeof(temp), fd))
+ return(0);
+ if ((n = DEC(*p)) <= 0)
+ break;
+ for (++p; n > 0; p += 4, n -= 3)
+ if (n >= 3) {
+ buffer[pos++] = DEC(p[0])<<2 | DEC(p[1])>>4;
+ buffer[pos++] = DEC(p[1])<<4 | DEC(p[2])>>2;
+ buffer[pos++] = DEC(p[2])<<6 | DEC(p[3]);
+ }
+ else {
+ if (n >= 1) {
+ buffer[pos++] =
+ DEC(p[0])<<2 | DEC(p[1])>>4;
+ }
+ if (n >= 2) {
+ buffer[pos++] =
+ DEC(p[1])<<4 | DEC(p[2])>>2;
+ }
+ if (n >= 3) {
+ buffer[pos++] =
+ DEC(p[2])<<6 | DEC(p[3]);
+ }
+ }
+ }
+ if (!fgets(temp, sizeof(temp), fd) || strcmp(temp, "end\n"))
+ return(0);
+ return(pos);
+}
diff --git a/usr.sbin/vidcontrol/path.h b/usr.sbin/vidcontrol/path.h
new file mode 100644
index 000000000000..709acbc375dc
--- /dev/null
+++ b/usr.sbin/vidcontrol/path.h
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
+#define FONT_PATH "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.1 b/usr.sbin/vidcontrol/vidcontrol.1
new file mode 100644
index 000000000000..5bc0af0372fe
--- /dev/null
+++ b/usr.sbin/vidcontrol/vidcontrol.1
@@ -0,0 +1,112 @@
+.\"
+.\" vidcontrol - a utility for manipulating the syscons video driver
+.\"
+.\" 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.
+.\"
+.\" @(#)vidcontrol.1
+.\"
+.TH vidcontrol 1 "May 22, 1994" "" "FreeBSD"
+
+.SH NAME
+vidcontrol - a utility for manipulating the syscons video driver.
+.SH SYNOPSIS
+.na
+.B vidcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B vidcontrol
+command is used to set various options for the syscons video driver,
+such as video mode, colors, cursor, scrnmaps, font,
+screensaver type and timeout.
+
+A new video mode is selected by specifying its name as an argument to
+.B vidcontrol
+eg. "
+.B vidcontrol 80x25
+".
+
+The modes currently supported: 80x25 and 80x50 text.
+
+The colors used when displaying text can be changed by specifying the
+foreground color (eg. "
+.B vidcontrol white
+"), or both a foreground & background
+color (eg. "
+.B vidcontrol yellow blue
+").
+
+To see the supported colors on a given platform use "
+.B vidcontrol show
+".
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.BI "\-r\ " foreground\ background
+Change reverse mode colors to
+.B foreground
+and
+.B background
+.
+.TP
+.BI "\-b\ " color
+Set border color to
+.B color
+(only supported on VGA hardware):
+.TP
+.BI "\-c\ " start.end
+Change the cursor apperance. The cursor is changed to a shape that starts
+on scanline
+.B start
+and ends on scanline
+.B end
+.
+.TP
+.BI "\-l\ " scrmap
+Install screen output map file from
+.I scrmap
+.TP
+.BI "\-L\ "
+Install default screen output map.
+.TP
+.BI "\-f\ " size\ file
+Load font
+.I file
+for
+.I size
+(currently, only 8x8, 8x14 or 8x16).
+The fontfile can be either uuencoded or in raw binary format.
+.TP
+.BI "\-t\ " N|off
+Sets the screensaver timeout to
+.I N
+seconds, or turns it
+.I off
+.TP
+.BI "\-s\ " NAME|help
+Sets the screensaver appearance to
+.I NAME .
+Use \-s help to print a list of the available screen savers.
+.PP
+.SH FILES
+/usr/share/syscons/fonts
+/usr/share/syscons/scrnmaps
+.SH BUGS
+Report when found.
+.SH "SEE ALSO"
+.BR kbdcontrol(1) ,
+.BR keyboard (4) ,
+.BR screen (4) ,
+.BR /sys/i386/conf/SYSCONS
+.SH AUTHORS
+Søren Schmidt (sos@login.dkuug.dk)
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c
new file mode 100644
index 000000000000..3278f921092a
--- /dev/null
+++ b/usr.sbin/vidcontrol/vidcontrol.c
@@ -0,0 +1,472 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: vidcontrol.c,v 1.4 1994/05/26 04:13:59 jkh Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include <sys/errno.h>
+#include "path.h"
+
+
+char legal_colors[16][16] = {
+ "black", "blue", "green", "cyan",
+ "red", "magenta", "brown", "white",
+ "grey", "lightblue", "lightgreen", "lightcyan",
+ "lightred", "lightmagenta", "yellow", "lightwhite"
+ };
+int hex = 0;
+int number, verbose = 0;
+char letter;
+struct vid_info info;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+ if (*indp < ac)
+ return(av[(*indp)++]);
+ fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+ usage();
+ exit(1);
+ return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char *buf = NULL;
+static int bufl = 0;
+int f;
+
+
+ f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+ if (f > bufl)
+ if (buf)
+ buf = (char *)realloc(buf, f);
+ else
+ buf = (char *)malloc(f);
+ if (!buf) {
+ bufl = 0;
+ return(NULL);
+ }
+
+ bufl = f;
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ strcat(buf, s3);
+ return(buf);
+}
+
+
+void
+load_scrnmap(char *filename)
+{
+ FILE *fd;
+ int i, size;
+ char *name;
+ scrmap_t scrnmap;
+ char *prefix[] = {"", "", SCRNMAP_PATH, SCRNMAP_PATH, NULL};
+ char *postfix[] = {"", ".scm", "", ".scm"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], filename, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("screenmap file not found");
+ return;
+ }
+ size = sizeof(scrnmap);
+ if (decode(fd, &scrnmap) != size) {
+ rewind(fd);
+ if (fread(&scrnmap, 1, size, fd) != size) {
+ fprintf(stderr, "bad scrnmap file\n");
+ close(fd);
+ return;
+ }
+ }
+ if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
+ perror("can't load screenmap");
+ close(fd);
+}
+
+
+void
+load_default_scrnmap()
+{
+ int i;
+ scrmap_t scrnmap;
+
+ for (i=0; i<256; i++)
+ *((char*)&scrnmap + i) = i;
+ if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
+ perror("can't load default screenmap");
+}
+
+
+void
+print_scrnmap()
+{
+ unsigned char map[256];
+ int i;
+
+ if (ioctl(0, GIO_SCRNMAP, &map) < 0) {
+ perror("getting scrnmap");
+ return;
+ }
+ for (i=0; i<sizeof(map); i++) {
+ if (i > 0 && i % 16 == 0)
+ fprintf(stdout, "\n");
+ if (hex)
+ fprintf(stdout, " %02x", map[i]);
+ else
+ fprintf(stdout, " %03d", map[i]);
+ }
+ fprintf(stdout, "\n");
+
+}
+
+
+void
+load_font(char *type, char *filename)
+{
+ FILE *fd;
+ int i, io, size;
+ char *name, *fontmap;
+ char *prefix[] = {"", "", FONT_PATH, FONT_PATH, NULL};
+ char *postfix[] = {"", ".fnt", "", ".fnt"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], filename, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("font file not found");
+ return;
+ }
+ if (!strcmp(type, "8x8")) {
+ size = 8*256;
+ io = PIO_FONT8x8;
+ }
+ else if (!strcmp(type, "8x14")) {
+ size = 14*256;
+ io = PIO_FONT8x14;
+ }
+ else if (!strcmp(type, "8x16")) {
+ size = 16*256;
+ io = PIO_FONT8x16;
+ }
+ else {
+ perror("bad font size specification");
+ close(fd);
+ return;
+ }
+ fontmap = (char*) malloc(size);
+ if (decode(fd, fontmap) != size) {
+ rewind(fd);
+ if (fread(fontmap, 1, size, fd) != size) {
+ fprintf(stderr, "bad font file\n");
+ close(fd);
+ free(fontmap);
+ return;
+ }
+ }
+ if (ioctl(0, io, fontmap) < 0)
+ perror("can't load font");
+ close(fd);
+ free(fontmap);
+}
+
+
+void
+set_screensaver_timeout(char *arg)
+{
+ int nsec;
+
+ if (!strcmp(arg, "off"))
+ nsec = 0;
+ else {
+ nsec = atoi(arg);
+ if ((*arg == '\0') || (nsec < 1)) {
+ fprintf(stderr, "argument must be a positive number\n");
+ return;
+ }
+ }
+ if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
+ perror("setting screensaver period");
+}
+
+
+void
+set_screensaver_type(char *type)
+{
+ ssaver_t saver;
+ int i, e;
+
+ if (!strcmp(type, "help")) {
+ i = 0;
+ printf("available screen saver types:\n");
+ do {
+ saver.num = i;
+ e = ioctl(0, CONS_GSAVER, &saver);
+ i ++;
+ if (e == 0)
+ printf("\t%s\n", saver.name);
+ } while (e == 0);
+ if (e == -1 && errno != EIO)
+ perror("getting screensaver info");
+ } else {
+ i = 0;
+ do {
+ saver.num = i;
+ e = ioctl(0, CONS_GSAVER, &saver);
+ i ++;
+ if (e == 0 && !strcmp(type, saver.name)) {
+ if (ioctl(0, CONS_SSAVER, &saver) == -1)
+ perror("setting screensaver type");
+ return;
+ }
+ } while (e == 0);
+ if (e == -1 && errno != EIO)
+ perror("getting screensaver info");
+ else
+ fprintf(stderr, "%s: No such screensaver\n", type);
+ }
+}
+
+void
+set_cursor_values(char *size)
+{
+ int start, end;
+ int n;
+ char *v1;
+
+ start = strtol(size, &v1, 0);
+ if ((start < 0) || (*v1 != '.'))
+ goto badopt;
+ size = ++v1;
+ end = strtol(size, &v1, 0);
+ if ((end < 0) || (*size == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -c must be start.end\n");
+ return;
+ }
+ if (verbose)
+ fprintf(stderr, "setting cursor to %d.%d\n", start, end);
+ fprintf(stdout, "[=%d;%dC", start, end);
+}
+
+
+int
+video_mode(int argc, char **argv, int *index)
+{
+ int mode;
+
+ if (*index < argc) {
+ if (!strcmp(argv[*index], "80x25"))
+ mode = CONS_80x25TEXT;
+ else if (!strcmp(argv[*index], "80x50"))
+ mode = CONS_80x50TEXT;
+ else
+ return;
+ if (ioctl(0, mode, NULL) < 0)
+ perror("Cannot set videomode");
+ (*index)++;
+ }
+ return;
+}
+
+
+int
+get_color_number(char *color)
+{
+ int i;
+
+ for (i=0; i<16; i++)
+ if (!strcmp(color, legal_colors[i]))
+ return i;
+ return -1;
+}
+
+
+int
+set_normal_colors(int argc, char **argv, int *index)
+{
+ int color;
+
+ if (*index < argc && (color = get_color_number(argv[*index])) != -1) {
+ (*index)++;
+ fprintf(stderr, "[=%dF", color);
+ if (*index < argc
+ && (color = get_color_number(argv[*index])) != -1
+ && color < 8) {
+ (*index)++;
+ fprintf(stderr, "[=%dG", color);
+ }
+ }
+}
+
+
+set_reverse_colors(int argc, char **argv, int *index)
+{
+ int color;
+
+ if ((color = get_color_number(argv[*(index)-1])) != -1) {
+ fprintf(stderr, "[=%dH", color);
+ if (*index < argc
+ && (color = get_color_number(argv[*index])) != -1
+ && color < 8) {
+ (*index)++;
+ fprintf(stderr, "[=%dI", color);
+ }
+ }
+}
+
+
+set_border_color(char *arg)
+{
+ int color;
+
+ if ((color = get_color_number(arg)) != -1) {
+ fprintf(stderr, "[=%dA", color);
+ }
+ else
+ usage();
+}
+
+
+test_frame()
+{
+ int i;
+
+ fprintf(stdout, "[=0G\n\n");
+ for (i=0; i<8; i++) {
+ fprintf(stdout, "[=15F[=0G %2d [=%dF%-16s"
+ "[=15F[=0G %2d [=%dF%-16s "
+ "[=15F %2d [=%dGBACKGROUND[=0G\n",
+ i, i, legal_colors[i], i+8, i+8,
+ legal_colors[i+8], i, i);
+ }
+ fprintf(stdout, "[=%dF[=%dG[=%dH[=%dI\n",
+ info.mv_norm.fore, info.mv_norm.back,
+ info.mv_rev.fore, info.mv_rev.back);
+}
+
+
+usage()
+{
+ fprintf(stderr,
+"Usage: vidcontrol mode (available modes: 80x25, 80x50)\n"
+" show (show available colors)\n"
+" fgcol bgcol (set fore- & background colors)\n"
+" -r fgcol bgcol (set reverse fore- & background colors)\n"
+" -b color (set border color)\n"
+" -c n.m (set cursor start line n & end line m)\n"
+#if 0
+" -d (dump screenmap to stdout)\n"
+#endif
+" -l filename (load srceenmap file filename)\n"
+" -L (load default screenmap)\n"
+" -f DxL filename (load font, D dots wide & L lines high)\n"
+" -s saver | help (set screensaver type or help for a list)\n"
+" -t N (set screensaver timeout in seconds)\n"
+ );
+}
+
+
+void
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+
+
+ info.size = sizeof(info);
+ if (ioctl(0, CONS_GETINFO, &info) < 0) {
+ perror("Must be on a vty");
+ exit(1);
+ }
+ while((opt = getopt(argc, argv, "b:c:df:l:Lr:s:t:vx")) != -1)
+ switch(opt) {
+ case 'c':
+ set_cursor_values(optarg);
+ break;
+ case 'b':
+ set_border_color(optarg);
+ break;
+ case 'd':
+ print_scrnmap();
+ break;
+ case 'f':
+ load_font(optarg,
+ nextarg(argc, argv, &optind, 'f'));
+ break;
+ case 'l':
+ load_scrnmap(optarg);
+ break;
+ case 'L':
+ load_default_scrnmap();
+ break;
+ case 'r':
+ set_reverse_colors(argc, argv, &optind);
+ break;
+ case 's':
+ set_screensaver_type(optarg);
+ break;
+ case 't':
+ set_screensaver_timeout(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ hex = 1;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ if (video_mode(argc, argv, &optind)) ;
+ if (set_normal_colors(argc, argv, &optind)) ;
+ if (optind < argc && !strcmp(argv[optind], "show")) {
+ test_frame();
+ optind++;
+ }
+ if ((optind != argc) || (argc == 1)) {
+ usage();
+ exit(1);
+ }
+ exit(0);
+}
+
diff --git a/usr.sbin/xten/Install.notes b/usr.sbin/xten/Install.notes
new file mode 100644
index 000000000000..9725ba402b58
--- /dev/null
+++ b/usr.sbin/xten/Install.notes
@@ -0,0 +1,222 @@
+Installation Notes for X-10 software
+Eugene W. Stark (stark@cs.sunysb.edu)
+October 30, 1993
+
+The TW523 is a carrier-current modem for home control/automation purposes.
+It is made by:
+
+ X-10 Inc.
+ 185A LeGrand Ave.
+ Northvale, NJ 07647
+ USA
+ (201) 784-9700 or 1-800-526-0027
+
+ X-10 Home Controls Inc.
+ 1200 Aerowood Drive, Unit 20
+ Mississauga, Ontario
+ (416) 624-4446 or 1-800-387-3346
+
+The TW523 is designed for communications using the X-10 protocol,
+which is compatible with a number of home control systems, including
+Radio Shack "Plug 'n Power(tm)" and Stanley "Lightmaker(tm)."
+I bought my TW523 from:
+
+ Home Control Concepts
+ 9353-C Activity Road
+ San Diego, CA 92126
+ (619) 693-8887
+
+They supplied me with the TW523 (which has an RJ-11 four-wire modular
+telephone connector), a modular cable, an RJ-11 to DB-25 connector with
+internal wiring, documentation from X-10 on the TW523 (very good),
+an instruction manual by Home Control Concepts (not very informative),
+and a floppy disk containing binary object code of some demonstration/test
+programs and of a C function library suitable for controlling the TW523
+by an IBM PC under MS-DOS (not useful to me other than to verify that
+the unit worked). I suggest saving money and buying the bare TW523
+rather than the TW523 development kit (what I bought), because if you
+are running 386BSD you don't really care about the DOS binaries.
+For details on the X-10 protocol itself, refer to the documentation from
+X-10 Inc.
+
+The interface to the TW-523 consists of four wires on the RJ-11 connector,
+which are jumpered to somewhat more wires on the DB-25 connector, which
+in turn is intended to plug into the PC parallel printer port. I dismantled
+the DB-25 connector to find out what they had done:
+
+ Signal RJ-11 pin DB-25 pin(s) Parallel Port
+ Transmit TX 4 (Y) 2, 4, 6, 8 Data out
+ Receive RX 3 (G) 10, 14 -ACK, -AutoFeed
+ Common 2 (R) 25 Common
+ Zero crossing 1 (B) 17 -Select Input
+
+I use the TW-523 and this software in the USA with 120V/60Hz power.
+Phil Sampson (vk2jnt@gw.vk2jnt.ampr.org OR sampson@gidday.enet.dec.com)
+in Australia has reported success in using a TW-7223 (a local version
+of the TW-523) and Tandy modules with this software under 240V/50Hz power.
+For reasons explained in the comments in the driver, it will probably not
+work if you have three-phase power, but this is usually not the case for
+normal residences and offices.
+
+
+1. Installing the TW523 Device Driver
+
+I assume that you are running FreeBSD. If you are running some other
+system, you are more or less on your own, though I can try to help if you
+have problems.
+
+Check the configuration parameters at the beginning of the file
+
+ /sys/i386/isa/tw.c
+
+Probably the only thing you might need to change is to change the
+definition of HALFCYCLE from 8333 to 10000 if you are using 50Hz power.
+The driver assumes that the TW523 device is connected to a parallel port.
+See the comments near the beginning of the file to find out where to
+get a TW523 if you don't have one, and how to make a cable for it to
+connect to your parallel port.
+
+Add a line like the following
+
+ device tw0 at isa? port 0x278 tty irq 5 vector twintr
+
+to /sys/i386/conf/YOURSYSTEM, but make sure to change the I/O port and
+interrupt to match your hardware configuration.
+
+Cd to /sys/i386/conf and do "config YOURSYSTEM".
+Cd to /sys/compile/YOURSYSTEM and do "make depend", then "make".
+(If you have any troubles, I suggest starting fresh by doing a full
+"make clean; make depend; make".) Assuming the make works correctly, do
+
+ mv /386bsd /386bsd.old
+ mv 386bsd /386bsd
+
+(If you are not a trusting person, or you don't have any spare fixit
+floppies with working kernels lying around, don't do this without testing
+the kernel first by copying it to a fixit floppy and booting from that.)
+
+Reboot the system. You should see a line indicating that the TW523 has
+been configured as the system comes up. If you see this line, then probably
+everything is going to work OK, because the TW523 will only get configured
+if the driver is able to sync to the power line. If the TW523 is not plugged
+in, or the driver is not getting sync for some reason, then you won't see
+any message on bootup.
+
+NOTE: I have received a report that some multi IDE/SIO/PARALLEL cards
+"cheat" and use TTL outputs rather than pullup open collector outputs,
+and this can mess up the scheme by which sync gets to the driver.
+If you are having trouble getting the driver to work, you might want to
+look into this possibility.
+
+In directory /dev, execute the command
+
+ MAKEDEV tw0
+
+
+2. Installing the X-10 Daemon
+
+Go to the xten source directory (probably /usr/src/contrib/xten).
+Check over the file "paths.h", if desired, to make sure that the entries
+are reasonable for your system. On my system, I have a special UID "xten"
+for the daemon. If you want to do this, too, you will have to add this UID
+to your /etc/master.passwd in the usual way. Otherwise, use "root" or
+"daemon" or something. You should change the ownership of /dev/tw0 to
+match this UID, so that the daemon will be able to access the TW-523.
+Edit the file Makefile.inc in the source directory to specify this UID:
+
+ xtenuser= xten
+
+Then run "make". If everything is OK, run
+
+ make install
+
+This should install the daemon "xtend" and the command "xten".
+
+Make sure the directory /var/spool/xten exists and is owned by the UID
+you selected above. This directory is used by the daemon for its log and
+device status files. When it is run, the daemon will also create a socket
+/var/run/tw523 and it will put its pid in /var/run/xtend.pid so that it can
+be signalled from shell scripts.
+
+Add the following lines to your /etc/rc.local file:
+
+ if [ -x /usr/libexec/xtend ]; then
+ echo -n ' xtend'; /usr/libexec/xtend
+ fi
+
+This will cause the X-10 daemon to be invoked automatically when you boot
+the system. To test the installation, you can either reboot now, or
+you can just run "xtend" by hand. The daemon should start up, and it should
+create files in /var/spool/xten. Check the file /var/spool/xten/Log to
+make sure that the daemon started up without any errors.
+
+Now you are ready to start trying X-10 commands. Try doing
+
+ xten A 1 Off
+ xten A 1 On 1 Dim:10
+
+etc. The "xten" program expects a house code as its first argument, then
+a series of key codes, which are either unit names ("1" through "16") or
+else are command names. You can find the list of command names by looking
+at the table in the file "xten.c". Each key code can optionally be followed
+by a colon : then a number specifying the number of times that command is
+to be transmitted without gaps between packets. The default is 2, and this
+is the normal case, but some commands like Bright and Dim are designed to
+be transmitted with counts other than 2. See the X-10 documentation for
+more detail.
+
+The "xten" program works by connecting to "xtend" through a socket, and
+asking that the X-10 codes be transmitted over the TW523. All activity
+on the TW523 is logged by the daemon in /var/spool/xten/Log. The daemon
+also attempts to track the state of all devices. (Of course, most X-10
+devices do not transmit when they are operated manually, so if somebody
+operates a device manually there is no way the X-10 daemon will know
+about it.)
+
+3. Low-level Programming of the TW523 Driver
+
+Normally, you would never operate the TW523 directly, rather you would
+use the shell command "xten" or you would connect to "xtend" through its
+socket. However, if you don't want to run "xtend", you can manipulate
+the TW523 directly through the device /dev/tw0. Have a look at the
+xtend code for a programming example.
+
+The driver supports read(), write(), and select() system calls.
+The driver allows multiple processes to read and write simultaneously,
+but there is probably not much sense in having more than one reader or more
+than one writer at a time, and in fact there may currently be a race
+condition in the driver if two processes try to transmit simultaneously
+(due to unsynchronized access to the sc_pkt structure in tw_sc).
+
+Transmission is done by calling write() to send three byte packets of data.
+The first byte contains a four bit house code (0=A to 15=P). The second byte
+contains five bit unit/key code (0=unit 1 to 15=unit 16, 16=All Units Off
+to 31 = Status Request). The third byte specifies the number of times the
+packet is to be transmitted without any gaps between successive transmissions.
+Normally this is 2, as per the X-10 documentation, but sometimes (e.g. for
+bright and dim codes) it can be another value. Each call to write can specify
+an arbitrary number of data bytes, but at most one packet will actually be
+processed in any call. Any incomplete packet is buffered until a subsequent
+call to write() provides data to complete it. Successive calls to write()
+leave a three-cycle gap between transmissions, per the X-10 documentation.
+The driver transmits each bit only once per half cycle, not three times as
+the X-10 documentation states, because the TW523 only provides sync on
+each power line zero crossing. So, the driver will probably not work
+properly if you have three-phase service. Most residences use a two-wire
+system, for which the driver does work.
+
+Reception is done using read(). The driver produces a series of three
+character packets. In each packet, the first character consists of flags,
+the second character is a four bit house code (0-15), and the third character
+is a five bit key/function code (0-31). The flags are the following:
+
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+
+The select() system call can be used in the usual way to determine if there
+is data ready for reading.
+
+
+ Happy Controlling!
+ Gene Stark
+ stark@cs.sunysb.edu
diff --git a/usr.sbin/xten/Makefile b/usr.sbin/xten/Makefile
new file mode 100644
index 000000000000..6300ec9effed
--- /dev/null
+++ b/usr.sbin/xten/Makefile
@@ -0,0 +1,10 @@
+# Makefile for xten (Stark) 10/30/93
+
+PROG= xten
+SRCS= xten.c
+CFLAGS+=-I. -I/usr/src/libexec/xtend
+
+MAN1= xten.1
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/xten/xten.1 b/usr.sbin/xten/xten.1
new file mode 100644
index 000000000000..1c7d51de7963
--- /dev/null
+++ b/usr.sbin/xten/xten.1
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1992, 1993 Eugene W. Stark
+.\" 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 Eugene W. Stark.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+.\"
+.Th XTEN 8 "30 Oct 1993"
+.Dd Oct 30, 1993
+.Dt XTEN 1
+.Os BSD FreeBSD
+.Sh NAME
+xten \- transmit X-10 commands
+.Sh SYNOPSIS
+.Nm xten
+[ - ] house key[:cnt] [ [ house ] key[:cnt] .\|.\|. ]
+.Sh DESCRIPTION
+.Nm Xten
+is a command-line interface to the X-10 daemon.
+When invoked with a one-letter house code (A-P) and a series of key/unit
+codes as arguments, it requests the X-10 daemon to transmit a corresponding
+series of X-10 packets. The X-10 daemon makes its best effort to ensure
+that the packets are all transmitted correctly, though in general it is
+not possible to tell whether the commands were actually received and
+executed by the remote X-10 devices.
+.Pp
+When invoked with the single argument \-,
+.Nm xten
+enters an interactive mode in which a line is repeatedly read from the
+standard input, sent to the X-10 daemon, and the one-line response from
+the daemon printed on the standard output.
+.Sh OPTIONS
+The
+.I
+house
+argument is a one-letter house code in the range A-P.
+All the X-10 requests generated will refer to this house code.
+Each
+.I
+key
+is either a numeric unit code in the range 1-16, or else
+is a string that specifies an X-10 function. The possible
+function code strings are:
+.Bl -diag
+.It AllUnitsOff
+.It AllLightsOn
+.It On
+.It Off
+.It Dim
+.It Bright
+.It AllLightsOff
+.It ExtendedCode
+.It HailRequest
+.It HailAcknowledge
+.It PreSetDim0
+.It PreSetDim1
+.It ExtendedData
+.It StatusOn
+.It StatusOff
+.It StatusRequest
+.El
+.Pp
+Each
+.I
+key
+may be followed by an optional numeric
+.I
+cnt,
+which specifies the number of packets that are to be sent with that
+key code without gaps. If this argument is omitted, two packets
+are transmitted. The ability to specify numbers of packets other than
+two is used by the X-10
+.I
+Dim
+and
+.I
+Bright
+commands.
+.Sh SEE ALSO
+.Xr xtend 8
+.Xr tw 4
+.Sh FILES
+.Bl -tag -width /var/spool/xten/Status -compact
+.It Pa /dev/tw0
+the TW523 special file
+.El
+.Sh AUTHOR
+Eugene W. Stark (stark@cs.sunysb.edu)
diff --git a/usr.sbin/xten/xten.c b/usr.sbin/xten/xten.c
new file mode 100644
index 000000000000..dc8555675d4a
--- /dev/null
+++ b/usr.sbin/xten/xten.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * 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 Eugene W. Stark.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY EUGENE W. STARK (THE AUTHOR) ``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 AUTHOR 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.
+ */
+
+/*
+ * Xten - user command interface to X-10 daemon
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+#define RETRIES 10
+#define CMDLEN 512
+
+char *X10housenames[] = {
+ "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P",
+ NULL
+};
+
+char *X10cmdnames[] = {
+ "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
+ "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
+ "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
+ "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
+ NULL
+};
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int c, tmp, h, k, sock, error;
+ FILE *daemon;
+ struct sockaddr_un sa;
+ char *sockpath = SOCKPATH;
+ char reply[CMDLEN], cmd[CMDLEN], *cp;
+ int interactive = 0;
+
+ if(argc == 2 && !strcmp(argv[1], "-")) interactive++;
+ else if(argc < 3) {
+ fprintf(stderr, "Usage: %s house key[:cnt] [ [house] key[:cnt] ... ]\n", argv[0]);
+ exit(1);
+ }
+ if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ fprintf(stderr, "%s: Can't create socket\n", argv[0]);
+ exit(1);
+ }
+ strcpy(sa.sun_path, sockpath);
+ sa.sun_family = AF_UNIX;
+ if(connect(sock, (struct sockaddr *)(&sa), strlen(sa.sun_path) + 2) < 0) {
+ fprintf(stderr, "%s: Can't connect to X-10 daemon\n", argv[0]);
+ exit(1);
+ }
+ if((daemon = fdopen(sock, "w+")) == NULL) {
+ fprintf(stderr, "%s: Can't attach stream to socket\n", argv[0]);
+ exit(1);
+ }
+ /*
+ * If interactive, copy standard input to daemon and report results
+ * on standard output.
+ */
+ if(interactive) {
+ while(!feof(stdin)) {
+ if(fgets(cmd, CMDLEN, stdin) != NULL) {
+ fprintf(daemon, "%s", cmd);
+ fflush(daemon);
+ if(fgets(reply, CMDLEN, daemon) != NULL) {
+ fprintf(stdout, "%s", reply);
+ fflush(stdout);
+ }
+ }
+ }
+ exit(0);
+ }
+ /*
+ * Otherwise, interpret arguments and issue commands to daemon,
+ * handling retries in case of errors.
+ */
+ if((h = find(argv[1], X10housenames)) < 0) {
+ fprintf(stderr, "Invalid house code: %s\n", argv[1]);
+ exit(1);
+ }
+ argv++;
+ argv++;
+ while(argc >= 3) {
+ cp = argv[0];
+ if((tmp = find(cp, X10housenames)) >= 0) {
+ h = tmp;
+ argv++;
+ argc--;
+ continue;
+ }
+ while(*cp != '\0' && *cp != ':') cp++;
+ if(*cp == ':') c = atoi(cp+1);
+ else c = 2;
+ *cp = '\0';
+ if((k = find(argv[0], X10cmdnames)) < 0) {
+ fprintf(stderr, "Invalid key/unit code: %s\n", argv[0]);
+ error++;
+ }
+ error = 0;
+ while(error < RETRIES) {
+ fprintf(daemon, "send %s %s %d\n", X10housenames[h], X10cmdnames[k], c);
+ fflush(daemon);
+ fgets(reply, CMDLEN, daemon);
+ if(strncmp(reply, "ERROR", 5)) break;
+ error++;
+ usleep(200000);
+ }
+ if(error == RETRIES) {
+ fprintf(stderr, "Command failed: send %s %s %d\n",
+ X10housenames[h], X10cmdnames[k], c);
+ }
+ argc--;
+ argv++;
+ }
+ exit(0);
+}
+
+find(s, tab)
+char *s;
+char *tab[];
+{
+ int i;
+
+ for(i = 0; tab[i] != NULL; i++) {
+ if(strcmp(s, tab[i]) == 0) return(i);
+ }
+ return(-1);
+}