summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1995-10-26 21:28:30 +0000
committerjulian <julian@FreeBSD.org>1995-10-26 21:28:30 +0000
commit08d0610487a6192a11d0803de49d2ed6e9dd16f7 (patch)
treeb6b74427d5d1f5b58e8bf31836a53d1e4cf3c2c2
parent90ae06d6ac1d2da3758389a70a20c91f3e9fd1dc (diff)
downloadFreeBSD-src-08d0610487a6192a11d0803de49d2ed6e9dd16f7.zip
FreeBSD-src-08d0610487a6192a11d0803de49d2ed6e9dd16f7.tar.gz
Reviewed by: julian and Mike Mitchel
Submitted by: john Hay (John.Hay@csir.co.za) John's IPXrouted.. this has not yet been seen to run correctly with Mike's IPX/SPX code (he has his own) bringing them both in is the first step in merging the two packages for 2.2
-rw-r--r--usr.sbin/IPXrouted/IPXrouted.8184
-rw-r--r--usr.sbin/IPXrouted/Makefile11
-rw-r--r--usr.sbin/IPXrouted/af.c278
-rw-r--r--usr.sbin/IPXrouted/af.h77
-rw-r--r--usr.sbin/IPXrouted/defs.h107
-rw-r--r--usr.sbin/IPXrouted/if.c151
-rw-r--r--usr.sbin/IPXrouted/input.c282
-rw-r--r--usr.sbin/IPXrouted/interface.h95
-rw-r--r--usr.sbin/IPXrouted/main.c345
-rw-r--r--usr.sbin/IPXrouted/output.c224
-rw-r--r--usr.sbin/IPXrouted/protocol.h91
-rw-r--r--usr.sbin/IPXrouted/sap.h106
-rw-r--r--usr.sbin/IPXrouted/sap_input.c180
-rw-r--r--usr.sbin/IPXrouted/sap_output.c182
-rw-r--r--usr.sbin/IPXrouted/sap_tables.c326
-rw-r--r--usr.sbin/IPXrouted/startup.c277
-rw-r--r--usr.sbin/IPXrouted/table.h116
-rw-r--r--usr.sbin/IPXrouted/tables.c466
-rw-r--r--usr.sbin/IPXrouted/timer.c234
-rw-r--r--usr.sbin/IPXrouted/trace.c410
-rw-r--r--usr.sbin/IPXrouted/trace.h123
21 files changed, 4265 insertions, 0 deletions
diff --git a/usr.sbin/IPXrouted/IPXrouted.8 b/usr.sbin/IPXrouted/IPXrouted.8
new file mode 100644
index 0000000..e43055e
--- /dev/null
+++ b/usr.sbin/IPXrouted/IPXrouted.8
@@ -0,0 +1,184 @@
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Copyright (c) 1995 John Hay. 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.
+.\"
+.Dd Oct 11, 1995
+.Dt IPXROUTED 8
+.Os FreeBSD
+.Sh NAME
+.Nm IPXrouted
+.Nd IPX Routing Information Protocol daemon
+.Sh SYNOPSIS
+.Nm IPXrouted
+.Op Fl q
+.Op Fl s
+.Op Fl S
+.Op Fl t
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm IPXrouted
+is invoked at boot time to manage the IPX routing tables.
+The IPX routing daemon uses the Novell IPX 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 IPXrouted
+to supply routing information whether it is acting as an internetwork
+router or not.
+.It Fl S
+Do not supply Service Advertizing Protocol
+.Nm (SAP)
+information. The default is to supply
+.Nm SAP
+information.
+.It Fl t
+All packets sent or received are
+printed on the standard output. In addition,
+.Nm IPXrouted
+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 IPXrouted 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 IPXrouted
+listens
+for routing information packets. If the host is connected to
+multiple IPX networks, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm IPXrouted
+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 IPXrouted
+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 IPXrouted
+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 IPXrouted
+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 IPXrouted
+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 IPXrouted
+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 ipx 4
+.Sh HISTORY
diff --git a/usr.sbin/IPXrouted/Makefile b/usr.sbin/IPXrouted/Makefile
new file mode 100644
index 0000000..7d4e41c
--- /dev/null
+++ b/usr.sbin/IPXrouted/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+# $Id: Makefile,v 1.4 1995/03/15 08:44:14 jhay Exp $
+
+PROG= IPXrouted
+MAN8= IPXrouted.8
+SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c trace.c
+SRCS+= sap_input.c sap_tables.c sap_output.c
+DPADD= ${LIBCOMPAT} ${LIBIPX}
+LDADD= -lcompat -lipx
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/IPXrouted/af.c b/usr.sbin/IPXrouted/af.c
new file mode 100644
index 0000000..28c231c
--- /dev/null
+++ b/usr.sbin/IPXrouted/af.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: af.c,v 1.4 1995/10/11 18:57:05 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)af.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include "defs.h"
+
+/*
+ * Address family support routines
+ */
+af_hash_t null_hash;
+af_netmatch_t null_netmatch;
+af_output_t null_output;
+af_portmatch_t null_portmatch;
+af_portcheck_t null_portcheck;
+af_checkhost_t null_checkhost;
+af_ishost_t null_ishost;
+af_canon_t null_canon;
+
+void ipxnet_hash(struct sockaddr_ipx *, struct afhash *);
+int ipxnet_netmatch(struct sockaddr_ipx *, struct sockaddr_ipx *);
+void ipxnet_output(int, int, struct sockaddr_ipx *, int);
+int ipxnet_portmatch(struct sockaddr_ipx *);
+int ipxnet_checkhost(struct sockaddr_ipx *);
+int ipxnet_ishost(struct sockaddr_ipx *);
+void ipxnet_canon(struct sockaddr_ipx *);
+
+#define NIL \
+ { null_hash, null_netmatch, null_output, \
+ null_portmatch, null_portcheck, null_checkhost, \
+ null_ishost, null_canon }
+#define IPXNET \
+ { (af_hash_t *)ipxnet_hash, \
+ (af_netmatch_t *)ipxnet_netmatch, \
+ (af_output_t *)ipxnet_output, \
+ (af_portmatch_t *)ipxnet_portmatch, \
+ (af_portcheck_t *)ipxnet_portmatch, \
+ (af_checkhost_t *)ipxnet_checkhost, \
+ (af_ishost_t *)ipxnet_ishost, \
+ (af_canon_t *)ipxnet_canon }
+
+struct afswitch afswitch[AF_MAX] =
+ { NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL,
+ NIL, NIL, NIL, IPXNET, NIL, NIL };
+
+struct sockaddr_ipx ipxnet_default = { sizeof(struct sockaddr_ipx), AF_IPX };
+
+union ipx_net ipx_anynet;
+union ipx_net ipx_zeronet;
+
+void
+ipxnet_hash(sipx, hp)
+ register struct sockaddr_ipx *sipx;
+ struct afhash *hp;
+{
+ register long hash = 0;
+ register u_short *s = sipx->sipx_addr.x_host.s_host;
+ union ipx_net_u net;
+
+ net.net_e = sipx->sipx_addr.x_net;
+ hp->afh_nethash = net.long_e;
+ hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
+ hp->afh_hosthash = hash;
+}
+
+int
+ipxnet_netmatch(sxn1, sxn2)
+ struct sockaddr_ipx *sxn1, *sxn2;
+{
+ return (ipx_neteq(sxn1->sipx_addr, sxn2->sipx_addr));
+}
+
+/*
+ * Verify the message is from the right port.
+ */
+int
+ipxnet_portmatch(sipx)
+ register struct sockaddr_ipx *sipx;
+{
+
+ return (ntohs(sipx->sipx_addr.x_port) == IPXPORT_RIP );
+}
+
+
+/*
+ * ipx output routine.
+ */
+#ifdef DEBUG
+int do_output = 0;
+#endif
+void
+ipxnet_output(s, flags, sipx, size)
+ int s;
+ int flags;
+ struct sockaddr_ipx *sipx;
+ int size;
+{
+ struct sockaddr_ipx dst;
+
+ dst = *sipx;
+ sipx = &dst;
+ if (sipx->sipx_addr.x_port == 0)
+ sipx->sipx_addr.x_port = htons(IPXPORT_RIP);
+#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 (ipx_neteqnn(sipx->sipx_addr.x_net, ipx_zeronet)) {
+ extern struct interface *ifnet;
+ register struct interface *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ sipx->sipx_addr.x_net =
+ satoipx_addr(ifp->int_addr).x_net;
+ (void) sendto(s, msg, size, flags,
+ (struct sockaddr *)sipx, sizeof (*sipx));
+ }
+ return;
+ }
+
+ (void) sendto(s, msg, size, flags,
+ (struct sockaddr *)sipx, sizeof (*sipx));
+}
+
+/*
+ * Return 1 if we want this route.
+ * We use this to disallow route net G entries for one for multiple
+ * point to point links.
+ */
+int
+ipxnet_checkhost(sipx)
+ struct sockaddr_ipx *sipx;
+{
+ register struct interface *ifp = if_ifwithnet((struct sockaddr *)sipx);
+ /*
+ * 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.
+ */
+int
+ipxnet_ishost(sipx)
+struct sockaddr_ipx *sipx;
+{
+ register u_short *s = sipx->sipx_addr.x_host.s_host;
+
+ if ((s[0]==0xffff) && (s[1]==0xffff) && (s[2]==0xffff))
+ return (0);
+ else
+ return (1);
+}
+
+void
+ipxnet_canon(sipx)
+ struct sockaddr_ipx *sipx;
+{
+
+ sipx->sipx_addr.x_port = 0;
+}
+
+void
+null_hash(addr, hp)
+ struct sockaddr *addr;
+ struct afhash *hp;
+{
+
+ hp->afh_nethash = hp->afh_hosthash = 0;
+}
+
+int
+null_netmatch(a1, a2)
+ struct sockaddr *a1, *a2;
+{
+
+ return (0);
+}
+
+void
+null_output(s, f, a1, n)
+ int s;
+ int f;
+ struct sockaddr *a1;
+ int n;
+{
+
+ ;
+}
+
+int
+null_portmatch(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+int
+null_portcheck(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+int
+null_ishost(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+int
+null_checkhost(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+void
+null_canon(a1)
+ struct sockaddr *a1;
+{
+
+ ;
+}
+
diff --git a/usr.sbin/IPXrouted/af.h b/usr.sbin/IPXrouted/af.h
new file mode 100644
index 0000000..2781cef
--- /dev/null
+++ b/usr.sbin/IPXrouted/af.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: af.h,v 1.3 1995/10/11 18:57:09 jhay Exp $
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Structure returned by af_hash routines.
+ */
+struct afhash {
+ u_int afh_hosthash; /* host based hash */
+ u_int afh_nethash; /* network based hash */
+};
+
+/*
+ * Per address family routines.
+ */
+typedef void af_hash_t(struct sockaddr *, struct afhash *);
+typedef int af_netmatch_t(struct sockaddr *, struct sockaddr *);
+typedef void af_output_t(int, int, struct sockaddr *, int);
+typedef int af_portmatch_t(struct sockaddr *);
+typedef int af_portcheck_t(struct sockaddr *);
+typedef int af_checkhost_t(struct sockaddr *);
+typedef int af_ishost_t(struct sockaddr *);
+typedef void af_canon_t(struct sockaddr *);
+
+struct afswitch {
+ af_hash_t *af_hash; /* returns keys based on address */
+ af_netmatch_t *af_netmatch; /* verifies net # matching */
+ af_output_t *af_output; /* interprets address for sending */
+ af_portmatch_t *af_portmatch; /* packet from some other router? */
+ af_portcheck_t *af_portcheck; /* packet from privileged peer? */
+ af_checkhost_t *af_checkhost; /* tells if address for host or net */
+ af_ishost_t *af_ishost; /* tells if address is valid */
+ af_canon_t *af_canon; /* canonicalize address for compares */
+};
+
+struct afswitch afswitch[AF_MAX]; /* table proper */
diff --git a/usr.sbin/IPXrouted/defs.h b/usr.sbin/IPXrouted/defs.h
new file mode 100644
index 0000000..810bd7c
--- /dev/null
+++ b/usr.sbin/IPXrouted/defs.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: defs.h,v 1.5 1995/10/11 18:57:12 jhay Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/route.h>
+#include <netipx/ipx.h>
+#include <netipx/ipxdp.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
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "protocol.h"
+#include "sap.h"
+#include "table.h"
+#include "trace.h"
+#include "interface.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))
+#define max(a,b) ((a)<(b)?(b):(a))
+
+extern int ripsock; /* Socket to listen on */
+extern int sapsock; /* Socket to listen on */
+extern int kmem;
+extern int supplier; /* process should supply updates */
+extern int dosap; /* SAP is enabled */
+extern int install; /* if 1 call kernel */
+extern int lookforinterfaces; /* if 1 probe kernel for new up ifs */
+extern int performnlist; /* if 1 check if /kernel has changed */
+extern int externalinterfaces; /* # of remote and local interfaces */
+extern int timeval; /* local idea of time */
+extern int noteremoterequests; /* squawk on requests from non-local nets */
+extern int r; /* Routing socket to install updates with */
+extern int gateway;
+extern struct sockaddr_ipx ipx_netmask; /* Used in installing routes */
+
+extern char packet[MAXPACKETSIZE+sizeof(struct ipxdp)+1];
+extern struct rip *msg;
+
+extern char **argv0;
+
+#define ADD 1
+#define DELETE 2
+#define CHANGE 3
+
+void sndmsg(struct sockaddr *, int, struct interface *);
+void supply(struct sockaddr *, int, struct interface *);
+void addrouteforif(struct interface *);
+void ifinit(void);
+void toall(void (*f)(struct sockaddr *, int, struct interface *),
+ struct rt_entry *);
+void rip_input(struct sockaddr *, int);
+
diff --git a/usr.sbin/IPXrouted/if.c b/usr.sbin/IPXrouted/if.c
new file mode 100644
index 0000000..3ea0d51
--- /dev/null
+++ b/usr.sbin/IPXrouted/if.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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)
+ *
+ * $Id: if.c,v 1.2 1995/10/11 18:57:14 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
+#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/IPXrouted/input.c b/usr.sbin/IPXrouted/input.c
new file mode 100644
index 0000000..0aec53a
--- /dev/null
+++ b/usr.sbin/IPXrouted/input.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: input.c,v 1.9 1995/10/11 18:57:17 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * IPX Routing Table Management Daemon
+ */
+#include "defs.h"
+
+struct sockaddr *
+ipx_nettosa(net)
+union ipx_net net;
+{
+ static struct sockaddr_ipx sxn;
+ extern char ether_broadcast_addr[6];
+
+ bzero(&sxn, sizeof (struct sockaddr_ipx));
+ sxn.sipx_family = AF_IPX;
+ sxn.sipx_len = sizeof (sxn);
+ sxn.sipx_addr.x_net = net;
+ sxn.sipx_addr.x_host = *(union ipx_host *)ether_broadcast_addr;
+ return( (struct sockaddr *)&sxn);
+
+}
+
+/*
+ * Process a newly received packet.
+ */
+void
+rip_input(from, size)
+ struct sockaddr *from;
+ int size;
+{
+ struct rt_entry *rt;
+ struct netinfo *n;
+ struct interface *ifp = 0;
+ int newsize;
+ struct afswitch *afp;
+ struct sockaddr_ipx *ipxp;
+
+ ifp = if_ifwithnet(from);
+ ipxp = (struct sockaddr_ipx *)from;
+ if (ifp == 0) {
+ if(ftrace) {
+ fprintf(ftrace, "Received bogus packet from %s\n",
+ ipxdp_ntoa(&ipxp->sipx_addr));
+ }
+ return;
+ }
+
+ 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:
+ if (ipx_hosteq(satoipx_addr(ifp->int_addr), ipxp->sipx_addr))
+ return;
+ 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''.
+ *
+ * XXX According to the IPX RIP spec the metric
+ * and tick fields can be anything. So maybe we
+ * should not check the metric???
+ */
+ if (ipx_neteqnn(n->rip_dst, ipx_anynet) &&
+ ntohs(n->rip_metric) == HOPCNT_INFINITY &&
+ size == 0) {
+ supply(from, 0, ifp);
+ return;
+ }
+ /*
+ * request for specific nets
+ */
+ rt = rtlookup(ipx_nettosa(n->rip_dst));
+ if (ftrace) {
+ fprintf(ftrace,
+ "specific request for %s",
+ ipxdp_nettoa(n->rip_dst));
+ fprintf(ftrace,
+ " yields route %x\n",
+ (u_int)rt);
+ }
+ /*
+ * XXX We break out on the first net that isn't
+ * found. The specs is a bit vague here. I'm not
+ * sure what we should do.
+ */
+ if (rt == 0)
+ return;
+ /* XXX
+ * According to the spec we should not include
+ * information about networks for which the number
+ * of hops is 16.
+ */
+ if (rt->rt_metric == (HOPCNT_INFINITY-1))
+ return;
+ n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY :
+ min(rt->rt_metric+1, HOPCNT_INFINITY));
+ n->rip_ticks = htons(rt->rt_ticks+1);
+
+ /*
+ * We use split horizon with a twist. If the requested
+ * net is the directly connected net we supply an
+ * answer. This is so that the host can learn about
+ * the routers on its net.
+ */
+ {
+ register struct rt_entry *trt = rt;
+
+ while (trt) {
+ if ((trt->rt_ifp == ifp) &&
+ !ipx_neteqnn(n->rip_dst,
+ satoipx_addr(ifp->int_addr).x_net))
+ return;
+ trt = trt->rt_clone;
+ }
+ 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)(ripsock, 0, from, newsize);
+ TRACE_OUTPUT(ifp, from, newsize);
+ if (ftrace) {
+ /* XXX This should not happen anymore. */
+ if(ifp == 0)
+ fprintf(ftrace, "--- ifp = 0\n");
+ else
+ 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)) != 0) {
+ 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)) != 0) {
+ 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 = ipx_nettosa(n->rip_dst));
+ if (rt == 0) {
+ rtadd(sa, from, ntohs(n->rip_metric),
+ ntohs(n->rip_ticks), 0);
+ continue;
+ }
+
+ /*
+ * A clone is a different route to the same net
+ * with exactly the same cost (ticks and metric).
+ * They must all be recorded because those interfaces
+ * must be handled in the same way as the first route
+ * to that net. ie When using the split horizon
+ * algorithm we must look at these interfaces also.
+ *
+ * Update if from gateway and different,
+ * from anywhere and less ticks or
+ * if same ticks and shorter,
+ * or getting stale and equivalent.
+ *
+ * XXX I don't think this is quite right.
+ */
+ if (!equal(from, &rt->rt_router) &&
+ ntohs(n->rip_ticks == rt->rt_ticks) &&
+ ntohs(n->rip_metric == rt->rt_metric)) {
+ register struct rt_entry *trt = rt->rt_clone;
+
+ while (trt) {
+ if (equal(from, &trt->rt_router)) {
+ trt->rt_timer = 0;
+ break;
+ }
+ }
+ if (trt == NULL) {
+ rtadd_clone(rt, sa, from,
+ ntohs(n->rip_metric),
+ ntohs(n->rip_ticks), 0);
+ }
+ continue;
+ }
+ if ((equal(from, &rt->rt_router) &&
+ ((ntohs(n->rip_ticks) != rt->rt_ticks) ||
+ (ntohs(n->rip_metric) != rt->rt_metric))) ||
+ (ntohs(n->rip_ticks) < rt->rt_ticks) ||
+ ((ntohs(n->rip_ticks) == rt->rt_ticks) &&
+ (ntohs(n->rip_metric) < rt->rt_metric)) ||
+ (rt->rt_timer > (EXPIRE_TIME*2/3) &&
+ rt->rt_metric == ntohs(n->rip_metric))) {
+ rtchange(rt, from, ntohs(n->rip_metric),
+ ntohs(n->rip_ticks));
+ rt->rt_timer = 0;
+ } else if (equal(from, &rt->rt_router) &&
+ (ntohs(n->rip_ticks) == rt->rt_ticks) &&
+ (ntohs(n->rip_metric) == rt->rt_metric)) {
+ rt->rt_timer = 0;
+ }
+ }
+ return;
+ }
+}
diff --git a/usr.sbin/IPXrouted/interface.h b/usr.sbin/IPXrouted/interface.h
new file mode 100644
index 0000000..f80ced8
--- /dev/null
+++ b/usr.sbin/IPXrouted/interface.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: interface.h,v 1.3 1995/10/11 18:57:19 jhay Exp $
+ */
+
+/*
+ * 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_IPX one.
+ */
+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 */
+
+ /* XXX IPX 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 0x200000 /* can't tell if up/down */
+#define IFF_INTERFACE 0x400000 /* hardware interface */
+#define IFF_REMOTE 0x800000 /* interface isn't on this machine */
+
+struct interface *if_ifwithaddr(struct sockaddr *);
+struct interface *if_ifwithdstaddr(struct sockaddr *);
+struct interface *if_ifwithnet(struct sockaddr *);
+struct interface *if_iflookup(struct sockaddr *);
+
diff --git a/usr.sbin/IPXrouted/main.c b/usr.sbin/IPXrouted/main.c
new file mode 100644
index 0000000..9a0a6ab
--- /dev/null
+++ b/usr.sbin/IPXrouted/main.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: main.c,v 1.6 1995/10/11 18:57:21 jhay Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * IPX 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>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define SAP_PKT 0
+#define RIP_PKT 1
+
+struct sockaddr_ipx addr; /* Daemon's Address */
+int ripsock; /* RIP Socket to listen on */
+int sapsock; /* SAP Socket to listen on */
+int kmem;
+int install; /* if 1 call kernel */
+int lookforinterfaces; /* if 1 probe kernel for new up interfaces */
+int performnlist; /* if 1 check if /kernel has changed */
+int externalinterfaces; /* # of remote and local interfaces */
+int timeval; /* local idea of time */
+int noteremoterequests; /* squawk on requests from non-local nets */
+int r; /* Routing socket to install updates with */
+struct sockaddr_ipx ipx_netmask; /* Used in installing routes */
+
+char packet[MAXPACKETSIZE+sizeof(struct ipxdp)+1];
+
+char **argv0;
+
+int supplier = -1; /* process should supply updates */
+int dosap = 1; /* By default do SAP services. */
+
+struct rip *msg = (struct rip *) &packet[sizeof (struct ipxdp)];
+struct sap_packet *sap_msg =
+ (struct sap_packet *) &packet[sizeof (struct ipxdp)];
+void hup(), fkexit(), timer();
+void process(int fd, int pkt_type);
+int getsocket(int type, int proto, struct sockaddr_ipx *sipx);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int nfds;
+ fd_set fdvar;
+
+ 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, "-S") == 0) {
+ dosap = 0;
+ 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: ipxrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ]\n");
+ exit(1);
+ }
+
+
+#ifndef DEBUG
+ if (!tracepackets)
+ daemon(0, 0);
+#endif
+ openlog("IPXrouted", LOG_PID, LOG_DAEMON);
+
+ addr.sipx_family = AF_IPX;
+ addr.sipx_len = sizeof(addr);
+ addr.sipx_port = htons(IPXPORT_RIP);
+ ipx_anynet.s_net[0] = ipx_anynet.s_net[1] = -1;
+ ipx_netmask.sipx_addr.x_net = ipx_anynet;
+ ipx_netmask.sipx_len = 6;
+ ipx_netmask.sipx_family = AF_IPX;
+ r = socket(AF_ROUTE, SOCK_RAW, 0);
+ /* later, get smart about lookingforinterfaces */
+ if (r)
+ shutdown(r, 0); /* for now, don't want reponses */
+ else {
+ fprintf(stderr, "IPXrouted: no routing socket\n");
+ exit(1);
+ }
+ ripsock = getsocket(SOCK_DGRAM, 0, &addr);
+ if (ripsock < 0)
+ exit(1);
+
+ if (dosap) {
+ addr.sipx_port = htons(IPXPORT_SAP);
+ sapsock = getsocket(SOCK_DGRAM, 0, &addr);
+ if (sapsock < 0)
+ exit(1);
+ } else
+ sapsock = -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();
+ sapinit();
+ ifinit();
+ if (supplier < 0)
+ supplier = 0;
+ /* request the state of the world */
+ msg->rip_cmd = htons(RIPCMD_REQUEST);
+ msg->rip_nets[0].rip_dst = ipx_anynet;
+ msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY);
+ msg->rip_nets[0].rip_ticks = htons(-1);
+ toall(sndmsg, NULL);
+
+ if (dosap) {
+ sap_msg->sap_cmd = htons(SAP_REQ);
+ sap_msg->sap[0].ServType = htons(SAP_WILDCARD);
+ toall(sapsndmsg, NULL);
+ }
+
+ signal(SIGALRM, timer);
+ signal(SIGHUP, hup);
+ signal(SIGINT, hup);
+ signal(SIGEMT, fkexit);
+ timer();
+
+ nfds = 1 + max(sapsock, ripsock);
+
+ for (;;) {
+ FD_ZERO(&fdvar);
+ if (dosap) {
+ FD_SET(sapsock, &fdvar);
+ }
+ FD_SET(ripsock, &fdvar);
+
+ if(select(nfds, &fdvar, (fd_set *)NULL, (fd_set *)NULL,
+ (struct timeval *)NULL) < 0) {
+ if(errno != EINTR) {
+ perror("during select");
+ exit(1);
+ }
+ }
+
+ if(FD_ISSET(ripsock, &fdvar))
+ process(ripsock, RIP_PKT);
+
+ if(dosap && FD_ISSET(sapsock, &fdvar))
+ process(sapsock, SAP_PKT);
+ }
+}
+
+void
+process(fd, pkt_type)
+ int fd;
+ int pkt_type;
+{
+ struct sockaddr from;
+ int fromlen = sizeof (from), cc, omask;
+ struct ipxdp *ipxdp = (struct ipxdp *)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, ipxdp_ntoa(&ipxdp->ipxdp_dna));
+ fprintf(ftrace," from %s\n", ipxdp_ntoa(&ipxdp->ipxdp_sna));
+ }
+
+ if (noteremoterequests &&
+ !ipx_neteqnn(ipxdp->ipxdp_sna.x_net, ipx_zeronet) &&
+ !ipx_neteq(ipxdp->ipxdp_sna, ipxdp->ipxdp_dna))
+ {
+ syslog(LOG_ERR,
+ "net of interface (%s) != net on ether (%s)!\n",
+ ipxdp_nettoa(ipxdp->ipxdp_dna.x_net),
+ ipxdp_nettoa(ipxdp->ipxdp_sna.x_net));
+ }
+
+ /* We get the IPX header in front of the RIF packet*/
+ cc -= sizeof (struct ipxdp);
+#define mask(s) (1<<((s)-1))
+ omask = sigblock(mask(SIGALRM));
+ switch(pkt_type) {
+ case SAP_PKT: sap_input(&from, cc);
+ break;
+ case RIP_PKT: rip_input(&from, cc);
+ break;
+ }
+ sigsetmask(omask);
+}
+
+int
+getsocket(type, proto, sipx)
+ int type, proto;
+ struct sockaddr_ipx *sipx;
+{
+ int domain = sipx->sipx_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 *)sipx, sizeof (*sipx)) < 0 && retry) {
+ syslog(LOG_ERR, "bind: %m");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ if (domain==AF_IPX) {
+ struct ipxdp ipxdp;
+ if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
+ syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
+ exit(1);
+ }
+ if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_RIP)
+ ipxdp.ipxdp_pt = IPXPROTO_RI;
+ else if (ntohs(sipx->sipx_addr.x_port) == IPXPORT_SAP)
+ ipxdp.ipxdp_pt = IPXPROTO_SAP;
+ else {
+ syslog(LOG_ERR, "port should be either RIP or SAP");
+ exit(1);
+ }
+ if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &ipxdp, sizeof(ipxdp))) {
+ 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/IPXrouted/output.c b/usr.sbin/IPXrouted/output.c
new file mode 100644
index 0000000..e2dcb56
--- /dev/null
+++ b/usr.sbin/IPXrouted/output.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: output.c,v 1.6 1995/10/11 18:57:22 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
+#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.
+ */
+void
+toall(f, except)
+ void (*f)(struct sockaddr *, int, struct interface *);
+ struct rt_entry *except;
+{
+ register struct interface *ifp;
+ register struct sockaddr *dst;
+ register int flags;
+ register struct rt_entry *trt;
+ int onlist;
+ extern struct interface *ifnet;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_PASSIVE)
+ continue;
+
+ /*
+ * Don't send it on interfaces in the except list.
+ */
+ onlist = 0;
+ trt = except;
+ while(trt) {
+ if (ifp == trt->rt_ifp) {
+ onlist = 1;
+ break;
+ }
+ trt = trt->rt_clone;
+ }
+ if (onlist)
+ 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.
+ */
+void
+sndmsg(dst, flags, ifp)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+
+ (*afswitch[dst->sa_family].af_output)
+ (ripsock, 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.
+ *
+ * This must be done using the split horizon algorithm.
+ * 1. Don't send routing info to the interface from where it was received.
+ * 2. Don't publish an interface to itself.
+ * 3. If a route is received from more than one interface and the cost is
+ * the same, don't publish it on either interface. I am calling this
+ * clones.
+ */
+void
+supply(dst, flags, ifp)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+ register struct rt_entry *rt;
+ register struct rt_entry *crt; /* Clone route */
+ register struct rthash *rh;
+ register struct netinfo *nn;
+ register struct netinfo *n = msg->rip_nets;
+ struct rthash *base = hosthash;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) dst;
+ af_output_t *output = afswitch[dst->sa_family].af_output;
+ int doinghost = 1, size, metric, ticks;
+ union ipx_net net;
+
+ if (sipx->sipx_port == 0)
+ sipx->sipx_port = htons(IPXPORT_RIP);
+
+ 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)(ripsock, flags, dst, size);
+ TRACE_OUTPUT(ifp, dst, size);
+ n = msg->rip_nets;
+ }
+
+ /*
+ * This should do rule one and two of the split horizon
+ * algorithm.
+ */
+ if (rt->rt_ifp == ifp)
+ continue;
+
+ /*
+ * Rule 3.
+ * Look if we have clones (different routes to the same
+ * place with exactly the same cost).
+ *
+ * We should not publish on any of the clone interfaces.
+ */
+ crt = rt->rt_clone;
+ while (crt) {
+ if (crt->rt_ifp == ifp)
+ continue;
+ crt = crt->rt_clone;
+ }
+
+ sipx = (struct sockaddr_ipx *)&rt->rt_dst;
+ if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
+ sipx = (struct sockaddr_ipx *)&rt->rt_router;
+ if (rt->rt_metric == HOPCNT_INFINITY)
+ metric = HOPCNT_INFINITY;
+ else {
+ metric = rt->rt_metric + 1;
+ /*
+ * We don't advertize routes with more than 15 hops.
+ */
+ if (metric >= HOPCNT_INFINITY)
+ continue;
+ }
+ /* XXX One day we should cater for slow interfaces also. */
+ ticks = rt->rt_ticks + 1;
+ net = sipx->sipx_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 (ipx_neteqnn(net, nn->rip_dst)) {
+ if (ticks < ntohs(nn->rip_ticks)) {
+ nn->rip_metric = htons(metric);
+ nn->rip_ticks = htons(ticks);
+ } else if ((ticks == ntohs(nn->rip_ticks)) &&
+ (metric < ntohs(nn->rip_metric))) {
+ nn->rip_metric = htons(metric);
+ nn->rip_ticks = htons(ticks);
+ }
+ goto next;
+ }
+ }
+ n->rip_dst = net;
+ n->rip_metric = htons(metric);
+ n->rip_ticks = htons(ticks);
+ n++;
+ next:;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (n != msg->rip_nets) {
+ size = (char *)n - (char *)msg;
+ (*output)(ripsock, flags, dst, size);
+ TRACE_OUTPUT(ifp, dst, size);
+ }
+}
diff --git a/usr.sbin/IPXrouted/protocol.h b/usr.sbin/IPXrouted/protocol.h
new file mode 100644
index 0000000..e41f5c7
--- /dev/null
+++ b/usr.sbin/IPXrouted/protocol.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: protocol.h,v 1.4 1995/10/11 18:57:24 jhay Exp $
+ */
+
+/*
+ * IPX Routing Information Protocol
+ *
+ */
+
+struct netinfo {
+ union ipx_net rip_dst; /* destination net */
+ u_short rip_metric; /* cost of route */
+ u_short rip_ticks; /* 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 IPX */
+#define DSTNETS_ALL 0xffffffff /* per IPX */
+#define MAXPACKETSIZE 512 /* max broadcast size */
+
+extern union ipx_net ipx_anynet;
+extern union ipx_net ipx_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 RIP_INTERVAL 60 /* time to supply rip tables */
+
+#define EXPIRE_TIME 180 /* time to mark entry invalid */
+#define GARBAGE_TIME 240 /* time to garbage collect */
diff --git a/usr.sbin/IPXrouted/sap.h b/usr.sbin/IPXrouted/sap.h
new file mode 100644
index 0000000..9b7cb53
--- /dev/null
+++ b/usr.sbin/IPXrouted/sap.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1995 John Hay. 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 John Hay.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY John Hay 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 John Hay 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.
+ *
+ * $Id: sap.h,v 1.5 1995/10/11 18:57:26 jhay Exp $
+ */
+#ifndef _SAP_H_
+#define _SAP_H_
+
+#define SAP_REQ 1
+#define SAP_RESP 2
+#define SAP_REQ_NEAR 3
+#define SAP_RESP_NEAR 4
+
+#define SAPCMD_MAX 5
+#ifdef SAPCMDS
+char *sapcmds[SAPCMD_MAX] =
+ { "#0", "REQUEST", "RESPONSE", "REQ NEAREST", "RESP NEAREST"};
+#endif
+
+#define SAP_WILDCARD 0xFFFF
+#define SERVNAMELEN 48
+typedef struct sap_info {
+ u_short ServType;
+ char ServName[SERVNAMELEN];
+ struct ipx_addr ipx;
+ u_short hops;
+ }sap_info;
+
+typedef struct sap_packet {
+ u_short sap_cmd;
+ sap_info sap[0]; /* Variable length. */
+ }sap_packet;
+
+typedef struct sap_entry {
+ struct sap_entry *forw;
+ struct sap_entry *back;
+ struct sap_entry *clone;
+ struct interface *ifp;
+ struct sap_info sap;
+ struct sockaddr source;
+ int hash;
+ int state;
+ int timer;
+ int metric;
+ }sap_entry;
+
+#define SAPHASHSIZ 32 /* Should be a power of 2 */
+#define SAPHASHMASK (SAPHASHSIZ-1)
+typedef struct sap_hash {
+ struct sap_entry *forw;
+ struct sap_entry *back;
+ }sap_hash;
+
+extern sap_hash sap_head[SAPHASHSIZ];
+
+extern struct sap_packet *sap_msg;
+
+void sapinit(void);
+void sap_input(struct sockaddr *from, int size);
+void sapsndmsg(struct sockaddr *dst, int flags, struct interface *ifp);
+void sap_supply_toall(void);
+void sap_supply(struct sockaddr *dst,
+ int flags,
+ struct interface *ifp,
+ int ServType);
+
+struct sap_entry *sap_lookup(u_short ServType, char *ServName);
+struct sap_entry *sap_nearestserver(ushort ServType, struct interface *ifp);
+void sap_add(struct sap_info *si, struct sockaddr *from);
+void sap_change(struct sap_entry *sap,
+ struct sap_info *si,
+ struct sockaddr *from);
+void sap_add_clone(struct sap_entry *sap,
+ struct sap_info *clone,
+ struct sockaddr *from);
+void sap_delete(struct sap_entry *sap);
+
+#endif /*_SAP_H_*/
+
diff --git a/usr.sbin/IPXrouted/sap_input.c b/usr.sbin/IPXrouted/sap_input.c
new file mode 100644
index 0000000..44b6290
--- /dev/null
+++ b/usr.sbin/IPXrouted/sap_input.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1995 John Hay. 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 John Hay.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY John Hay 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 John Hay 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.
+ *
+ * $Id: sap_input.c,v 1.6 1995/10/11 18:57:27 jhay Exp $
+ */
+
+/*
+ * IPX Routing Table Management Daemon
+ */
+#include "defs.h"
+
+
+/*
+ * Process a newly received packet.
+ */
+void
+sap_input(from, size)
+ struct sockaddr *from;
+ int size;
+{
+ struct sap_entry *sap;
+ struct sap_info *n;
+ struct interface *ifp = 0;
+ int newsize;
+ struct afswitch *afp;
+ struct sockaddr_ipx *ipxp;
+
+ ifp = if_ifwithnet(from);
+ ipxp = (struct sockaddr_ipx *)from;
+ if (ifp == 0) {
+ if(ftrace) {
+ fprintf(ftrace, "Received bogus packet from %s\n",
+ ipxdp_ntoa(&ipxp->sipx_addr));
+ }
+ return;
+ }
+
+ if (ftrace)
+ dumpsappacket(ftrace, "received", from, (char *)sap_msg , size);
+
+ if (from->sa_family >= AF_MAX)
+ return;
+ afp = &afswitch[from->sa_family];
+
+ size -= sizeof (u_short) /* command */;
+ n = sap_msg->sap;
+
+ switch (ntohs(sap_msg->sap_cmd)) {
+
+ case SAP_REQ_NEAR:
+ if (ftrace)
+ fprintf(ftrace, "Received a sap REQ_NEAR packet.\n");
+ sap = sap_nearestserver(n->ServType, ifp);
+ if (sap == NULL)
+ return;
+ sap_msg->sap_cmd = htons(SAP_RESP_NEAR);
+ *n = sap->sap;
+ n->hops = htons(ntohs(n->hops) + 1);
+ if (ntohs(n->hops) >= HOPCNT_INFINITY)
+ return;
+
+ newsize = sizeof(struct sap_info) + sizeof(struct sap_packet);
+ (*afp->af_output)(sapsock, 0, from, newsize);
+ if (ftrace) {
+ fprintf(ftrace, "sap_nearestserver %X %s returned:\n",
+ ntohs(n->ServType),
+ ifp->int_name);
+ fprintf(ftrace, " service %04X %-20.20s "
+ "addr %s.%04X metric %d\n",
+ ntohs(sap->sap.ServType),
+ sap->sap.ServName,
+ ipxdp_ntoa(&sap->sap.ipx),
+ ntohs(sap->sap.ipx.x_port),
+ ntohs(sap->sap.hops));
+ }
+ return;
+
+ case SAP_REQ:
+ if (ftrace)
+ fprintf(ftrace, "Received a sap REQ packet.\n");
+
+ sap_supply(from, 0, ifp, n->ServType);
+ return;
+
+ case SAP_RESP_NEAR:
+ /* XXX We do nothing here, for the moment.
+ * Maybe we should check if the service is in our table?
+ *
+ */
+ if (ftrace)
+ fprintf(ftrace, "Received a sap RESP_NEAR packet.\n");
+
+ return;
+
+ case SAP_RESP:
+ if (ftrace)
+ fprintf(ftrace, "Received a sap RESP packet.\n");
+
+ (*afp->af_canon)(from);
+
+ for (; size > 0; size -= sizeof (struct sap_info), n++) {
+ if (size < sizeof (struct netinfo))
+ break;
+ sap = sap_lookup(n->ServType, n->ServName);
+ if (sap == 0) {
+ sap_add(n, from);
+ continue;
+ }
+
+ /*
+ * A clone is a different route to the same service
+ * with exactly the same cost (metric).
+ * They must all be recorded because those interfaces
+ * must be handled in the same way as the first route
+ * to that service. ie When using the split horizon
+ * algorithm we must look at these interfaces also.
+ *
+ * Update if from gateway and different,
+ * from anywhere and less hops or
+ * getting stale and equivalent.
+ *
+ * XXX I don't think this is quite right yet.
+ */
+ if (((ifp != sap->ifp) ||
+ !equal(&sap->source, from)) &&
+ (n->hops == sap->sap.hops) &&
+ (ntohs(n->hops) != HOPCNT_INFINITY)) {
+ register struct sap_entry *tsap = sap->clone;
+
+ while (tsap) {
+ if ((ifp == tsap->ifp) &&
+ equal(&tsap->source, from)) {
+ tsap->timer = 0;
+ break;
+ }
+ }
+ if (tsap == NULL) {
+ sap_add_clone(sap, n, from);
+ }
+ continue;
+ }
+ if (((ifp == sap->ifp) &&
+ equal(&sap->source, from) &&
+ (n->hops != sap->sap.hops)) ||
+ (ntohs(n->hops) < ntohs(sap->sap.hops)) ||
+ (sap->timer > (EXPIRE_TIME*2/3) &&
+ ntohs(sap->sap.hops) == ntohs(n->hops))) {
+ sap_change(sap, n, from);
+ }
+ }
+ return;
+ }
+}
diff --git a/usr.sbin/IPXrouted/sap_output.c b/usr.sbin/IPXrouted/sap_output.c
new file mode 100644
index 0000000..e074c3a
--- /dev/null
+++ b/usr.sbin/IPXrouted/sap_output.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1995 John Hay. 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 John Hay.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY John Hay 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 John Hay 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.
+ *
+ * $Id: sap_output.c,v 1.4 1995/10/11 18:57:28 jhay Exp $
+ */
+
+/*
+ * 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.
+ */
+void
+sap_supply_toall(void)
+{
+ register struct interface *ifp;
+ struct sockaddr dst;
+ register struct sockaddr_ipx *ipx_dst;
+ register int flags;
+ extern struct interface *ifnet;
+
+ ipx_dst = (struct sockaddr_ipx *)&dst;
+
+ 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;
+ if (ipx_dst->sipx_addr.x_port == 0)
+ ipx_dst->sipx_addr.x_port = htons(IPXPORT_SAP);
+
+ flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
+ sap_supply(&dst, flags, ifp, SAP_WILDCARD);
+ }
+}
+
+void
+sapsndmsg(dst, flags, ifp)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+ struct sockaddr t_dst;
+ struct sockaddr_ipx *ipx_dst;
+
+ t_dst = *dst;
+ ipx_dst = (struct sockaddr_ipx *)&t_dst;
+
+ if (ipx_dst->sipx_addr.x_port == 0)
+ ipx_dst->sipx_addr.x_port = htons(IPXPORT_SAP);
+
+ (*afswitch[dst->sa_family].af_output)
+ (sapsock, flags, &t_dst,
+ sizeof (struct sap_packet) + sizeof(u_short));
+ TRACE_SAP_OUTPUT(ifp, &t_dst,
+ sizeof (struct sap_packet) + sizeof(u_short));
+}
+
+/*
+ * Supply dst with the contents of the SAP tables. If the ServType ==
+ * SAP_WILDCARD (0xFFFF) supply the whole table, otherwise only the
+ * services that are of ServType. If this won't fit in one packet, chop
+ * it up into several.
+ *
+ * This must be done using the split horizon algorithm.
+ * 1. Don't send SAP info to the interface from where it was received.
+ * 2. If a service is received from more than one interface and the cost is
+ * the same, don't publish it on either interface. I am calling this
+ * clones.
+ */
+void
+sap_supply(dst, flags, ifp, ServType)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+ int ServType;
+{
+ register struct sap_entry *sap;
+ register struct sap_entry *csap; /* Clone route */
+ register struct sap_hash *sh;
+ register struct sap_info *n = sap_msg->sap;
+ struct sap_hash *base = sap_head;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) dst;
+ af_output_t *output = afswitch[dst->sa_family].af_output;
+ int size, metric;
+
+ if (sipx->sipx_port == 0)
+ sipx->sipx_port = htons(IPXPORT_SAP);
+
+ sap_msg->sap_cmd = ntohs(SAP_RESP);
+
+ for (sh = base; sh < &base[SAPHASHSIZ]; sh++)
+ for (sap = sh->forw; sap != (struct sap_entry *)sh; sap = sap->forw) {
+ size = (char *)n - (char *)sap_msg;
+ if (size > MAXPACKETSIZE - sizeof (struct sap_info)) {
+ (*output)(sapsock, flags, dst, size);
+ TRACE_SAP_OUTPUT(ifp, dst, size);
+ n = sap_msg->sap;
+ }
+
+ /*
+ * Check for the servicetype except if the ServType is
+ * a wildcard (0xFFFF).
+ */
+ if ((ServType != SAP_WILDCARD) &&
+ (ServType != sap->sap.ServType))
+ continue;
+
+ /*
+ * This should do rule one and two of the split horizon
+ * algorithm.
+ */
+ if (sap->ifp == ifp)
+ continue;
+
+ /*
+ * Rule 2.
+ * Look if we have clones (different routes to the same
+ * place with exactly the same cost).
+ *
+ * We should not publish on any of the clone interfaces.
+ */
+ csap = sap->clone;
+ while (csap) {
+ if (csap->ifp == ifp)
+ continue;
+ csap = csap->clone;
+ }
+
+ /*
+ * Don't advertise services with more than 15 hops. It
+ * will be confused with a service that has gone down.
+ */
+ if (ntohs(sap->sap.hops) == (HOPCNT_INFINITY - 1))
+ continue;
+ metric = min(ntohs(sap->sap.hops) + 1, HOPCNT_INFINITY);
+
+ *n = sap->sap;
+ n->hops = htons(metric);
+ n++;
+ }
+ if (n != sap_msg->sap) {
+ size = (char *)n - (char *)sap_msg;
+ (*output)(sapsock, flags, dst, size);
+ TRACE_SAP_OUTPUT(ifp, dst, size);
+ }
+}
+
diff --git a/usr.sbin/IPXrouted/sap_tables.c b/usr.sbin/IPXrouted/sap_tables.c
new file mode 100644
index 0000000..4f64a4c
--- /dev/null
+++ b/usr.sbin/IPXrouted/sap_tables.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 1995 John Hay. 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 John Hay.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY John Hay 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 John Hay 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.
+ *
+ * $Id: sap_tables.c,v 1.9 1995/10/11 18:57:29 jhay Exp $
+ */
+
+#include "defs.h"
+#include <string.h>
+#include <stdlib.h>
+/* XXX I thought that this should work! #include <sys/systm.h> */
+#include <machine/cpufunc.h>
+
+#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
+
+sap_hash sap_head[SAPHASHSIZ];
+
+void
+sapinit(void)
+{
+ int i;
+
+ for (i=0; i<SAPHASHSIZ; i++)
+ sap_head[i].forw = sap_head[i].back =
+ (struct sap_entry *)&sap_head[i];
+}
+
+/*
+ * XXX Make sure that this hash is good enough.
+ *
+ * This hash use the first 8 letters of the ServName and the ServType
+ * to create a 32 bit hash value.
+ *
+ * NOTE: The first two letters of ServName will be used to generate
+ * the lower bits of the hash. This is used to index into the hash table.
+ */
+#define rol(x) (((x * 2) & 0xFFFF) + ((x & 0x8000) != 0))
+
+int
+saphash(u_short ServType, char *ServName)
+{
+ int hsh, i;
+ char name[SERVNAMELEN];
+
+ bzero(name, SERVNAMELEN);
+ strncpy(name, ServName, SERVNAMELEN);
+ ServName = name;
+
+ hsh = 0;
+
+ for (i=0;i<8;i++) {
+ hsh = rol(hsh) + *ServName;
+ ServName++;
+ }
+
+ hsh = rol(hsh) + (ServType >> 8);
+ hsh = rol(hsh) + (ServType & 0xff);
+ hsh = (hsh >> 7) ^ hsh;
+ return hsh;
+}
+
+/*
+ * Look for an exact match on ServType and ServName. It is
+ * mostly used by the function that process SAP RESPONSE packets.
+ *
+ * A hash is created and used to index into the hash table. Then
+ * that list is walk through searching for a match.
+ *
+ * If no match is found NULL is returned.
+ */
+struct sap_entry *
+sap_lookup(u_short ServType, char *ServName)
+{
+ register struct sap_entry *sap;
+ register struct sap_hash *sh;
+ int hsh;
+
+ hsh = saphash(ServType, ServName);
+ sh = &sap_head[hsh & SAPHASHMASK];
+
+ for(sap = sh->forw; sap != (sap_entry *)sh; sap = sap->forw) {
+ if ((hsh == sap->hash) &&
+ (ServType == sap->sap.ServType) &&
+ (strncmp(ServName, sap->sap.ServName, SERVNAMELEN) == 0)) {
+ return sap;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * This returns the nearest service of the specified type. If no
+ * suitable service is found or if that service is on the interface
+ * where the request came from, NULL is returned.
+ *
+ * When checking interfaces clones must be considered also.
+ *
+ * XXX TODO:
+ * Maybe we can use RIP tables to get the fastest service (ticks).
+ */
+struct sap_entry *
+sap_nearestserver(ushort ServType, struct interface *ifp)
+{
+ register struct sap_entry *sap;
+ register struct sap_entry *csap;
+ struct sap_hash *sh;
+ register struct sap_entry *best = NULL;
+ register int besthops = HOPCNT_INFINITY;
+
+ sh = sap_head;
+
+ for (; sh < &sap_head[SAPHASHSIZ]; sh++)
+ for(sap = sh->forw; sap != (sap_entry *)sh; sap = sap->forw) {
+ if (ServType != sap->sap.ServType)
+ continue;
+ if (ifp == sap->ifp)
+ continue;
+
+ csap = sap->clone;
+ while (csap) {
+ if (ifp == csap->ifp)
+ /*
+ * I would have loved to use
+ * something else here.
+ */
+ goto next;
+ csap = csap->clone;
+ }
+
+ if (ntohs(sap->sap.hops) < besthops) {
+ best = sap;
+ besthops = ntohs(best->sap.hops);
+ }
+next:;
+ }
+ return best;
+}
+
+/*
+ * Add a entry to the SAP table.
+ *
+ * If the malloc fail, the entry will silently be thrown away.
+ */
+void
+sap_add(struct sap_info *si, struct sockaddr *from)
+{
+ register struct sap_entry *nsap;
+ register struct sap_hash *sh;
+
+ FIXLEN(from);
+ nsap = malloc(sizeof(struct sap_entry));
+ if (nsap == NULL)
+ return;
+
+ nsap->sap = *si;
+ nsap->source = *from;
+ nsap->clone = NULL;
+ nsap->ifp = if_ifwithnet(from);
+ nsap->state = RTS_CHANGED;
+ nsap->timer = 0;
+ nsap->hash = saphash(si->ServType, si->ServName);
+
+ sh = &sap_head[nsap->hash & SAPHASHMASK];
+
+ insque(nsap, sh);
+}
+
+/*
+ * Change an existing SAP entry. If a clone exist for the old one,
+ * check if it is cheaper. If it is change tothe clone, otherwise
+ * delete all the clones.
+ */
+void
+sap_change(struct sap_entry *sap,
+ struct sap_info *si,
+ struct sockaddr *from)
+{
+ struct sap_entry *osap = NULL;
+
+ FIXLEN(from);
+ /*
+ * If the hopcount (metric) is HOPCNT_INFINITY (16) it means that
+ * a service has gone down. We should keep it like that for 30
+ * seconds, so that it will get broadcast and then change to a
+ * clone if one exist.
+ */
+ if (sap->clone && (ntohs(si->hops) != HOPCNT_INFINITY)) {
+ /*
+ * There are three possibilities:
+ * 1. The new path is cheaper than the old one.
+ * Free all the clones.
+ *
+ * 2. The new path is the same cost as the old ones.
+ * If it is on the list of clones remove it
+ * from the clone list and free it.
+ *
+ * 3. The new path is more expensive than the old one.
+ * Use the values of the first clone and take it
+ * out of the list, to be freed at the end.
+ */
+ osap = sap->clone;
+ if (ntohs(osap->sap.hops) > ntohs(si->hops)) {
+ struct sap_entry *nsap;
+
+ while (osap) {
+ nsap = osap->clone;
+ free(osap);
+ osap = nsap;
+ }
+ sap->clone = NULL;
+ } else if (ntohs(osap->sap.hops) == ntohs(si->hops)) {
+ struct sap_entry *psap;
+
+ psap = sap;
+ while (osap) {
+ if (equal(&osap->source, from)) {
+ psap->clone = osap->clone;
+ free(osap);
+ osap = psap->clone;
+ } else {
+ psap = osap;
+ osap = osap->clone;
+ }
+ }
+ } else {
+ from = &osap->source;
+ si = &osap->sap;
+ sap->clone = osap->clone;
+ }
+ }
+ sap->sap = *si;
+ sap->source = *from;
+ sap->ifp = if_ifwithnet(from);
+ sap->state = RTS_CHANGED;
+ if (ntohs(si->hops) == HOPCNT_INFINITY)
+ sap->timer = EXPIRE_TIME;
+ else
+ sap->timer = 0;
+
+ if (osap)
+ free(osap);
+}
+
+/*
+ * Add a clone to the specified SAP entry. A clone is a different
+ * route to the same service. We must know about them when we use
+ * the split horizon algorithm.
+ *
+ * If the malloc fail, the entry will silently be thrown away.
+ */
+void
+sap_add_clone(struct sap_entry *sap,
+ struct sap_info *clone,
+ struct sockaddr *from)
+{
+ register struct sap_entry *nsap;
+ register struct sap_entry *csap;
+
+ FIXLEN(from);
+ nsap = malloc(sizeof(struct sap_entry));
+ if (nsap == NULL)
+ return;
+
+ if (ftrace)
+ fprintf(ftrace, "CLONE ADD %04.4X %s.\n",
+ ntohs(clone->ServType),
+ clone->ServName);
+
+ nsap->sap = *clone;
+ nsap->source = *from;
+ nsap->clone = NULL;
+ nsap->ifp = if_ifwithnet(from);
+ nsap->state = RTS_CHANGED;
+ nsap->timer = 0;
+ nsap->hash = saphash(clone->ServType, clone->ServName);
+
+ csap = sap;
+ while (csap->clone)
+ csap = csap->clone;
+ csap->clone = nsap;
+}
+
+/*
+ * Remove a SAP entry from the table and free the memory
+ * used by it.
+ *
+ * If the service have clone, do a sap_change to it and free
+ * the clone.
+ */
+void
+sap_delete(struct sap_entry *sap)
+{
+ if (sap->clone) {
+ sap_change(sap, &sap->clone->sap, &sap->clone->source);
+ return;
+ }
+ remque(sap);
+ free(sap);
+}
+
diff --git a/usr.sbin/IPXrouted/startup.c b/usr.sbin/IPXrouted/startup.c
new file mode 100644
index 0000000..c3b3e05
--- /dev/null
+++ b/usr.sbin/IPXrouted/startup.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: startup.c,v 1.3 1995/10/11 18:57:30 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)startup.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.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};
+
+
+void
+quit(s)
+ char *s;
+{
+ extern int errno;
+ int sverrno = errno;
+
+ (void) fprintf(stderr, "IPXroute: ");
+ if (s)
+ (void) fprintf(stderr, "%s: ", s);
+ (void) fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(1);
+ /* NOTREACHED */
+}
+
+struct rt_addrinfo info;
+/* Sleazy use of local variables throughout file, warning!!!! */
+#define netmask info.rti_info[RTAX_NETMASK]
+#define ifaaddr info.rti_info[RTAX_IFA]
+#define brdaddr info.rti_info[RTAX_BRD]
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+void
+rt_xaddrs(cp, cplim, rtinfo)
+ register caddr_t cp, cplim;
+ register struct rt_addrinfo *rtinfo;
+{
+ register struct sockaddr *sa;
+ register int i;
+
+ bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
+ for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
+ if ((rtinfo->rti_addrs & (1 << i)) == 0)
+ continue;
+ rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
+ ADVANCE(cp, sa);
+ }
+}
+
+/*
+ * 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.
+ */
+void
+ifinit(void)
+{
+ struct interface ifs, *ifp;
+ size_t needed;
+ int mib[6], no_ipxaddr = 0, flags = 0;
+ char *buf, *cplim, *cp;
+ register struct if_msghdr *ifm;
+ register struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl = 0;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_IPX;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ quit("route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ quit("malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ lookforinterfaces = 0;
+ cplim = buf + needed;
+ for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)cp;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ bzero(&ifs, sizeof(ifs));
+ ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE;
+ if ((flags & IFF_UP) == 0 || no_ipxaddr)
+ lookforinterfaces = 1;
+ sdl = (struct sockaddr_dl *) (ifm + 1);
+ sdl->sdl_data[sdl->sdl_nlen] = 0;
+ no_ipxaddr = 1;
+ continue;
+ }
+ if (ifm->ifm_type != RTM_NEWADDR)
+ quit("ifinit: out of sync");
+ if ((flags & IFF_UP) == 0)
+ continue;
+ ifam = (struct ifa_msghdr *)ifm;
+ info.rti_addrs = ifam->ifam_addrs;
+ rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
+ if (ifaaddr == 0) {
+ syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
+ continue;
+ }
+ ifs.int_addr = *ifaaddr;
+ if (ifs.int_addr.sa_family != AF_IPX)
+ continue;
+ no_ipxaddr = 0;
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get dstaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ if (brdaddr->sa_family == AF_UNSPEC) {
+ lookforinterfaces = 1;
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ if (ifs.int_flags & IFF_BROADCAST) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get broadaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ /*
+ * 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 (ifs.int_flags & IFF_LOOPBACK)
+ continue;
+ ifp = (struct interface *)
+ malloc(sdl->sdl_nlen + 1 + sizeof(ifs));
+ if (ifp == 0) {
+ syslog(LOG_ERR, "IPXrouted: out of memory\n");
+ lookforinterfaces = 1;
+ 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 = (char *)(ifp + 1);
+ strcpy(ifp->int_name, sdl->sdl_data);
+
+ ifp->int_metric = ifam->ifam_metric;
+ ifp->int_next = ifnet;
+ ifnet = ifp;
+ traceinit(ifp);
+ addrouteforif(ifp);
+ }
+ if (externalinterfaces > 1 && supplier < 0)
+ supplier = 1;
+ free(buf);
+}
+
+void
+addrouteforif(ifp)
+ struct interface *ifp;
+{
+ struct sockaddr *dst;
+ struct rt_entry *rt;
+
+ if (ifp->int_flags & IFF_POINTOPOINT) {
+ int (*match)();
+ register struct interface *ifp2 = 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, 0,
+ ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
+}
+
diff --git a/usr.sbin/IPXrouted/table.h b/usr.sbin/IPXrouted/table.h
new file mode 100644
index 0000000..b029dcc
--- /dev/null
+++ b/usr.sbin/IPXrouted/table.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: table.h,v 1.4 1995/10/11 18:57:30 jhay Exp $
+ */
+
+/*
+ * 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 rtuentry {
+ u_long rtu_hash;
+ struct sockaddr rtu_dst;
+ struct sockaddr rtu_router;
+ short rtu_rtflags; /* used by old rtioctl */
+ short rtu_wasted; /* XXX routed does it this way. */
+ int rtu_flags;
+ int rtu_state;
+ int rtu_timer;
+ int rtu_metric;
+ int rtu_ticks;
+ struct interface *rtu_ifp;
+ } rtu_entry;
+ } rt_rtu;
+ struct rt_entry *rt_clone;
+};
+
+#define rt_rt rt_rtu.rtu_entry /* 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_ticks rt_rtu.rtu_entry.rtu_ticks /* time 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 sockaddr *);
+struct rt_entry *rtfind(struct sockaddr *);
+void rtadd(struct sockaddr *, struct sockaddr *, short, short, int);
+void rtadd_clone(struct rt_entry *, struct sockaddr *, struct sockaddr *,
+ short, short, int);
+void rtchange(struct rt_entry *, struct sockaddr *, short, short);
+void rtdelete(struct rt_entry *);
+int rtioctl(int, struct rtuentry *);
+void rtinit(void);
+
diff --git a/usr.sbin/IPXrouted/tables.c b/usr.sbin/IPXrouted/tables.c
new file mode 100644
index 0000000..2faf523
--- /dev/null
+++ b/usr.sbin/IPXrouted/tables.c
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: tables.c,v 1.6 1995/10/11 18:57:31 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+/* XXX I thought that this should work! #include <sys/systm.h> */
+#include <machine/cpufunc.h>
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#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)() = 0;
+
+ 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 != 0) &&
+ (*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);
+}
+
+void
+rtadd(dst, gate, metric, ticks, state)
+ struct sockaddr *dst, *gate;
+ short metric, ticks;
+ int 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_ticks = ticks;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ rt->rt_clone = NULL;
+ 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 && rtioctl(ADD, &rt->rt_rt) < 0) {
+ if (errno != EEXIST)
+ perror("SIOCADDRT");
+ if (errno == ENETUNREACH) {
+ TRACE_ACTION(DELETE, rt);
+ remque(rt);
+ free((char *)rt);
+ }
+ }
+}
+
+void
+rtadd_clone(ort, dst, gate, metric, ticks, state)
+ struct rt_entry *ort;
+ struct sockaddr *dst, *gate;
+ short metric, ticks;
+ int 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_ticks = ticks;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ rt->rt_clone = NULL;
+ rt->rt_forw = NULL;
+ rt->rt_back = NULL;
+ if (metric)
+ rt->rt_flags |= RTF_GATEWAY;
+
+ while(ort->rt_clone != NULL)
+ ort = ort->rt_clone;
+ ort->rt_clone = rt;
+ TRACE_ACTION(ADD_CLONE, rt);
+}
+
+void
+rtchange(rt, gate, metric, ticks)
+ struct rt_entry *rt;
+ struct sockaddr *gate;
+ short metric, ticks;
+{
+ int doioctl = 0, metricchanged = 0;
+ struct rtuentry oldroute;
+
+ FIXLEN(gate);
+ /*
+ * Handling of clones.
+ * When the route changed and it had clones, handle it special.
+ * 1. If the new route is cheaper than the clone(s), free the clones.
+ * 2. If the new route is the same cost, it may be one of the clones,
+ * search for it and free it.
+ * 3. If the new route is more expensive than the clone(s), use the
+ * values of the clone(s).
+ */
+ if (rt->rt_clone) {
+ if ((ticks < rt->rt_clone->rt_ticks) ||
+ ((ticks == rt->rt_clone->rt_ticks) &&
+ (metric < rt->rt_clone->rt_metric))) {
+ /*
+ * Free all clones.
+ */
+ struct rt_entry *trt, *nrt;
+
+ trt = rt->rt_clone;
+ rt->rt_clone = NULL;
+ while(trt) {
+ nrt = trt->rt_clone;
+ free((char *)trt);
+ trt = nrt;
+ }
+ } else if ((ticks == rt->rt_clone->rt_ticks) &&
+ (metric == rt->rt_clone->rt_metric)) {
+ struct rt_entry *prt, *trt;
+
+ prt = rt;
+ trt = rt->rt_clone;
+
+ while(trt) {
+ if (equal(&trt->rt_router, gate)) {
+ prt->rt_clone = trt->rt_clone;
+ free(trt);
+ trt = prt->rt_clone;
+ } else {
+ prt = trt;
+ trt = trt->rt_clone;
+ }
+ }
+ } else {
+ /*
+ * Use the values of the first clone.
+ * Delete the corresponding clone.
+ */
+ struct rt_entry *trt;
+
+ trt = rt->rt_clone;
+ rt->rt_clone = rt->rt_clone->rt_clone;
+ metric = trt->rt_metric;
+ ticks = trt->rt_ticks;
+ *gate = trt->rt_router;
+ free((char *)trt);
+ }
+ }
+
+ if (!equal(&rt->rt_router, gate))
+ doioctl++;
+ if ((metric != rt->rt_metric) || (ticks != rt->rt_ticks))
+ metricchanged++;
+ if (doioctl || metricchanged) {
+ TRACE_ACTION(CHANGE FROM, rt);
+ if (doioctl) {
+ oldroute = rt->rt_rt;
+ rt->rt_router = *gate;
+ }
+ rt->rt_metric = metric;
+ rt->rt_ticks = ticks;
+ if ((rt->rt_state & RTS_INTERFACE) && metric) {
+ rt->rt_state &= ~RTS_INTERFACE;
+ if(rt->rt_ifp)
+ syslog(LOG_ERR,
+ "changing route from interface %s (timed out)",
+ rt->rt_ifp->int_name);
+ else
+ syslog(LOG_ERR,
+ "changing route from interface ??? (timed out)");
+ }
+ 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 (rtioctl(ADD, &rt->rt_rt) < 0)
+ syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+ if (delete && rtioctl(DELETE, &oldroute) < 0)
+ perror("rtioctl DELETE");
+#else
+ if (delete == 0) {
+ if (rtioctl(ADD, &rt->rt_rt) >= 0)
+ return;
+ } else {
+ if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
+ return;
+ }
+ syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
+ ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_dst)->sipx_addr),
+ ipxdp_ntoa(&((struct sockaddr_ipx *)&rt->rt_router)->sipx_addr));
+#endif
+ }
+}
+
+void
+rtdelete(rt)
+ struct rt_entry *rt;
+{
+
+ struct sockaddr *sa = &(rt->rt_router);
+ FIXLEN(sa);
+ sa = &(rt->rt_dst);
+ FIXLEN(sa);
+ if (rt->rt_clone) {
+ /*
+ * If there is a clone we just do a rt_change to it.
+ */
+ struct rt_entry *trt = rt->rt_clone;
+ rtchange(rt, &trt->rt_router, trt->rt_metric, trt->rt_ticks);
+ return;
+ }
+ if (rt->rt_state & RTS_INTERFACE) {
+ if (rt->rt_ifp)
+ syslog(LOG_ERR,
+ "deleting route to interface %s (timed out)",
+ rt->rt_ifp->int_name);
+ else
+ syslog(LOG_ERR,
+ "deleting route to interface ??? (timed out)");
+ }
+ TRACE_ACTION(DELETE, rt);
+ if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
+ perror("rtioctl DELETE");
+ remque(rt);
+ free((char *)rt);
+}
+
+void
+rtinit(void)
+{
+ 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;
+}
+int seqno;
+
+int
+rtioctl(action, ort)
+ int action;
+ struct rtuentry *ort;
+{
+#ifndef RTM_ADD
+ if (install == 0)
+ return (errno = 0);
+
+ ort->rtu_rtflags = ort->rtu_flags;
+
+ switch (action) {
+
+ case ADD:
+ return (ioctl(s, SIOCADDRT, (char *)ort));
+
+ case DELETE:
+ return (ioctl(s, SIOCDELRT, (char *)ort));
+
+ default:
+ return (-1);
+ }
+#else /* RTM_ADD */
+ struct {
+ struct rt_msghdr w_rtm;
+ struct sockaddr w_dst;
+ struct sockaddr w_gate;
+ struct sockaddr_ipx w_netmask;
+ } w;
+#define rtm w.w_rtm
+
+ bzero((char *)&w, sizeof(w));
+ rtm.rtm_msglen = sizeof(w);
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = (action == ADD ? RTM_ADD :
+ (action == DELETE ? RTM_DELETE : RTM_CHANGE));
+ rtm.rtm_flags = ort->rtu_flags;
+ rtm.rtm_seq = ++seqno;
+ rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+ bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
+ bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
+ w.w_gate.sa_family = w.w_dst.sa_family = AF_IPX;
+ w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
+ if (rtm.rtm_flags & RTF_HOST) {
+ rtm.rtm_msglen -= sizeof(w.w_netmask);
+ } else {
+ rtm.rtm_addrs |= RTA_NETMASK;
+ w.w_netmask = ipx_netmask;
+ rtm.rtm_msglen -= sizeof(w.w_netmask) - ipx_netmask.sipx_len;
+ }
+ errno = 0;
+ return write(r, (char *)&w, rtm.rtm_msglen);
+#endif /* RTM_ADD */
+}
+
diff --git a/usr.sbin/IPXrouted/timer.c b/usr.sbin/IPXrouted/timer.c
new file mode 100644
index 0000000..d7e8124
--- /dev/null
+++ b/usr.sbin/IPXrouted/timer.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: timer.c,v 1.8 1995/10/11 18:57:32 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)timer.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <unistd.h>
+#include <stdlib.h>
+
+int timeval = -TIMER_RATE;
+
+/*
+ * Timer routine. Performs routing information supply
+ * duties and manages timers on routing and SAP table entries.
+ */
+void
+timer()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ register struct sap_hash *sh;
+ register struct sap_entry *sap;
+ struct sap_hash *sap_base = sap_head;
+ int doinghost = 1, timetobroadcast, ripbroadcast, sapbroadcast;
+
+ timeval += TIMER_RATE;
+ if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
+ ifinit();
+ timetobroadcast = supplier && (timeval % SUPPLY_INTERVAL) == 0;
+ ripbroadcast = supplier && timetobroadcast &&
+ (timeval % RIP_INTERVAL) == 0;
+ sapbroadcast = timetobroadcast && dosap && !ripbroadcast;
+
+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_clone) {
+ struct rt_entry *trt, *prt;
+ /*
+ * If a clone expire free it and mark the
+ * main route RTS_CHANGED.
+ */
+ prt = rt;
+ trt = rt->rt_clone;
+ while (trt) {
+ trt->rt_timer += TIMER_RATE;
+ if (trt->rt_timer >= EXPIRE_TIME) {
+ prt->rt_clone = trt->rt_clone;
+ free((char *)trt);
+ trt = prt->rt_clone;
+ rt->rt_state |= RTS_CHANGED;
+ } else {
+ prt = trt;
+ trt = prt->rt_clone;
+ }
+ }
+ }
+ /*
+ * 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) &&
+ !(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 || ripbroadcast)
+ continue;
+ msg->rip_cmd = htons(RIPCMD_RESPONSE);
+ msg->rip_nets[0].rip_dst =
+ (satoipx_addr(rt->rt_dst)).x_net;
+ msg->rip_nets[0].rip_metric =
+ htons(min(rt->rt_metric+1, HOPCNT_INFINITY));
+ msg->rip_nets[0].rip_ticks =
+ htons(rt->rt_ticks + 1);
+ toall(sndmsg, rt);
+ }
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (ripbroadcast)
+ toall(supply, NULL);
+
+ /*
+ * Now do the SAP stuff.
+ */
+ for (sh = sap_base; sh < &sap_base[SAPHASHSIZ]; sh++) {
+ sap = sh->forw;
+ for (; sap != (struct sap_entry *)sh; sap = sap->forw) {
+ if (sap->clone) {
+ struct sap_entry *tsap, *psap;
+ /*
+ * If a clone expire free it and mark the
+ * main sap entry RTS_CHANGED.
+ */
+ psap = sap;
+ tsap = sap->clone;
+ while (tsap) {
+ tsap->timer += TIMER_RATE;
+ if (tsap->timer >= EXPIRE_TIME) {
+ psap->clone = tsap->clone;
+ free((char *)tsap);
+ tsap = psap->clone;
+ sap->state |= RTS_CHANGED;
+ } else {
+ psap = tsap;
+ tsap = psap->clone;
+ }
+ }
+ }
+ sap->timer += TIMER_RATE;
+ if (sap->timer >= EXPIRE_TIME)
+ sap->metric = HOPCNT_INFINITY;
+ if (sap->timer >= GARBAGE_TIME) {
+ sap = sap->back;
+ /* Perhaps we should send a REQUEST for this route? */
+ sap_delete(sap->forw);
+ continue;
+ }
+ /*
+ * XXX sap_sndmsg on RTS_CHANGED
+ */
+ }
+ }
+ if (sapbroadcast)
+ sap_supply_toall();
+ if (ftrace && sapbroadcast)
+ dumpsaptable(ftrace, sap_head);
+ 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;
+ register struct sap_hash *sh;
+ register struct sap_entry *sap;
+ 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, NULL);
+
+ /*
+ * Now for SAP.
+ */
+ for (sh = sap_head; sh < &sap_head[SAPHASHSIZ]; sh++) {
+ sap = sh->forw;
+ for (; sap != (struct sap_entry *)sh; sap = sap->forw)
+ sap->sap.hops = htons(HOPCNT_INFINITY);
+ }
+ if (dosap)
+ sap_supply_toall();
+ }
+ exit(1);
+}
diff --git a/usr.sbin/IPXrouted/trace.c b/usr.sbin/IPXrouted/trace.c
new file mode 100644
index 0000000..bf51116
--- /dev/null
+++ b/usr.sbin/IPXrouted/trace.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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.
+ *
+ * $Id: trace.c,v 1.6 1995/10/11 18:57:33 jhay Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#define RIPCMDS
+#define SAPCMDS
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <time.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
+
+void dumpif(FILE *fd, struct interface *ifp);
+void dumptrace(FILE *fd, char *dir, struct ifdebug *ifd);
+
+void
+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 int
+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);
+}
+
+void
+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;
+}
+
+void
+traceoff(void)
+{
+ if (!tracing)
+ return;
+ if (ftrace != NULL)
+ fclose(ftrace);
+ ftrace = NULL;
+ tracing = 0;
+}
+
+void
+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;
+}
+
+void
+traceaction(fd, action, rt)
+ FILE *fd;
+ char *action;
+ struct rt_entry *rt;
+{
+ struct sockaddr_ipx *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;
+
+ if (fd == NULL)
+ return;
+ fprintf(fd, "%s ", action);
+ dst = (struct sockaddr_ipx *)&rt->rt_dst;
+ gate = (struct sockaddr_ipx *)&rt->rt_router;
+ fprintf(fd, "dst %s, ", ipxdp_ntoa(&dst->sipx_addr));
+ fprintf(fd, "router %s, metric %d, ticks %d, flags",
+ ipxdp_ntoa(&gate->sipx_addr), rt->rt_metric, rt->rt_ticks);
+ 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);
+}
+
+void
+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");
+ }
+}
+
+void
+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);
+ }
+}
+
+void
+dumppacket(fd, dir, source, cp, size)
+ FILE *fd;
+ char *dir;
+ struct sockaddr *source;
+ char *cp;
+ register int size;
+{
+ register struct rip *msg = (struct rip *)cp;
+ register struct netinfo *n;
+ struct sockaddr_ipx *who = (struct sockaddr_ipx *)source;
+
+ if (msg->rip_cmd && ntohs(msg->rip_cmd) < RIPCMD_MAX)
+ fprintf(fd, "%s %s %s#%x", ripcmds[ntohs(msg->rip_cmd)],
+ dir, ipxdp_ntoa(&who->sipx_addr),
+ ntohs(who->sipx_addr.x_port));
+ else {
+ fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->rip_cmd),
+ dir, ipxdp_ntoa(&who->sipx_addr),
+ ntohs(who->sipx_addr.x_port));
+ fprintf(fd, "size=%d cp=%x packet=%x\n", size,
+ (u_int)cp, (u_int)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 ticks %d\n",
+ ipxdp_nettoa(n->rip_dst),
+ ntohs(n->rip_metric),
+ ntohs(n->rip_ticks));
+ }
+ break;
+
+ }
+}
+
+void
+dumpsappacket(fd, dir, source, cp, size)
+ FILE *fd;
+ char *dir;
+ struct sockaddr *source;
+ char *cp;
+ register int size;
+{
+ register struct sap_packet *msg = (struct sap_packet *)cp;
+ register struct sap_info *n;
+ struct sockaddr_ipx *who = (struct sockaddr_ipx *)source;
+
+ if (msg->sap_cmd && ntohs(msg->sap_cmd) < SAPCMD_MAX)
+ fprintf(fd, "%s %s %s#%x", sapcmds[ntohs(msg->sap_cmd)],
+ dir, ipxdp_ntoa(&who->sipx_addr),
+ ntohs(who->sipx_addr.x_port));
+ else {
+ fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->sap_cmd),
+ dir, ipxdp_ntoa(&who->sipx_addr),
+ ntohs(who->sipx_addr.x_port));
+ fprintf(fd, "size=%d cp=%x packet=%x\n", size,
+ (u_int)cp, (u_int)packet);
+ return;
+ }
+ switch (ntohs(msg->sap_cmd)) {
+
+ case SAP_REQ:
+ case SAP_RESP:
+ case SAP_REQ_NEAR:
+ case SAP_RESP_NEAR:
+ fprintf(fd, ":\n");
+ size -= sizeof (u_short);
+ n = msg->sap;
+ for (; size > 0; n++, size -= sizeof (struct sap_info)) {
+ if (size < sizeof (struct sap_info))
+ break;
+ fprintf(fd, " service %04X %-20.20s "
+ "addr %s.%04X metric %d\n",
+ ntohs(n->ServType),
+ n->ServName,
+ ipxdp_ntoa(&n->ipx),
+ ntohs(n->ipx.x_port),
+ ntohs(n->hops));
+ }
+ break;
+
+ }
+}
+
+void
+dumpsaptable(fd, sh)
+ FILE *fd;
+ struct sap_hash *sh;
+{
+ register struct sap_entry *sap;
+ struct sap_hash *hash;
+ int x = 0;
+
+ fprintf(fd, "------- SAP table dump. -------\n");
+ for (hash = sh; hash < &sh[SAPHASHSIZ]; hash++, x++) {
+ fprintf(fd, "HASH %d\n", x);
+ sap = hash->forw;
+ for (; sap != (struct sap_entry *)hash; sap = sap->forw) {
+ fprintf(fd, " service %04X %-20.20s "
+ "addr %s.%04X %c metric %d\n",
+ ntohs(sap->sap.ServType),
+ sap->sap.ServName,
+ ipxdp_ntoa(&sap->sap.ipx),
+ ntohs(sap->sap.ipx.x_port),
+ (sap->clone ? 'C' : ' '),
+ ntohs(sap->sap.hops));
+ }
+ }
+ fprintf(fd, "\n");
+}
+
+union ipx_net_u net;
+
+char *
+ipxdp_nettoa(val)
+union ipx_net val;
+{
+ static char buf[100];
+ net.net_e = val;
+ (void)sprintf(buf, "%lx", ntohl(net.long_e));
+ return (buf);
+}
+
+
+char *
+ipxdp_ntoa(addr)
+struct ipx_addr *addr;
+{
+ static char buf[100];
+
+ (void)sprintf(buf, "%s#%x:%x:%x:%x:%x:%x",
+ ipxdp_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/IPXrouted/trace.h b/usr.sbin/IPXrouted/trace.h
new file mode 100644
index 0000000..41d21ae
--- /dev/null
+++ b/usr.sbin/IPXrouted/trace.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Copyright (c) 1995 John Hay. 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 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: trace.h,v 1.4 1995/10/11 18:57:34 jhay Exp $
+ */
+
+/*
+ * IPX 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 ipxdp)], size, \
+ ntohl(ifp->int_metric)); \
+ } \
+ if (tracepackets && ftrace) \
+ dumppacket(ftrace, "from", src, &packet[sizeof(struct ipxdp)], size); \
+ }
+#define TRACE_OUTPUT(ifp, dst, size) { \
+ if (tracing) { \
+ ifp = if_iflookup(dst); \
+ if (ifp) \
+ trace(&ifp->int_output, dst, &packet[sizeof(struct ipxdp)], size, ifp->int_metric); \
+ } \
+ if (tracepackets && ftrace) \
+ dumppacket(ftrace, "to", dst, &packet[sizeof(struct ipxdp)], size); \
+ }
+
+#define TRACE_SAP_OUTPUT(ifp, dst, size) { \
+ if (tracing) { \
+ ifp = if_iflookup(dst); \
+ if (ifp) \
+ trace(&ifp->int_output, dst, &packet[sizeof(struct ipxdp)], size, ifp->int_metric); \
+ } \
+ if (tracepackets && ftrace) \
+ dumpsappacket(ftrace, "to", dst, &packet[sizeof(struct ipxdp)], size); \
+ }
+
+void traceinit(struct interface *);
+void traceon(char *file);
+void traceoff(void);
+void traceaction(FILE *, char *, struct rt_entry *);
+void trace(struct ifdebug *, struct sockaddr *, char *, int, int);
+void dumppacket(FILE *, char *, struct sockaddr *, char *, int);
+void dumpsappacket(FILE *, char *, struct sockaddr *, char *, int);
+void dumpsaptable(FILE *fd, struct sap_hash *sh);
+
+char *ipxdp_nettoa(union ipx_net);
+char *ipxdp_ntoa(struct ipx_addr *);
+
OpenPOWER on IntegriCloud