summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1995-10-26 20:31:59 +0000
committerjulian <julian@FreeBSD.org>1995-10-26 20:31:59 +0000
commit90ae06d6ac1d2da3758389a70a20c91f3e9fd1dc (patch)
treed823a4d0efac391c6dfad3ac2e27c0e984cea732 /sys
parent627b063e661d2c0187cf625f83db54c6aca0a0c1 (diff)
downloadFreeBSD-src-90ae06d6ac1d2da3758389a70a20c91f3e9fd1dc.zip
FreeBSD-src-90ae06d6ac1d2da3758389a70a20c91f3e9fd1dc.tar.gz
Reviewed by: julian and jhay@mikom.csir.co.za
Submitted by: Mike Mitchell, supervisor@alb.asctmd.com This is a bulk mport of Mike's IPX/SPX protocol stacks and all the related gunf that goes with it.. it is not guaranteed to work 100% correctly at this time but as we had several people trying to work on it I figured it would be better to get it checked in so they could all get teh same thing to work on.. Mikes been using it for a year or so but on 2.0 more changes and stuff will be merged in from other developers now that this is in. Mike Mitchell, Network Engineer AMTECH Systems Corporation, Technology and Manufacturing 8600 Jefferson Street, Albuquerque, New Mexico 87113 (505) 856-8000 supervisor@alb.asctmd.com
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES8
-rw-r--r--sys/conf/files12
-rw-r--r--sys/dev/ed/if_ed.c38
-rw-r--r--sys/dev/ep/if_ep.c25
-rw-r--r--sys/dev/fe/if_fe.c31
-rw-r--r--sys/dev/ie/if_ie.c29
-rw-r--r--sys/i386/conf/LINT8
-rw-r--r--sys/i386/conf/NOTES8
-rw-r--r--sys/i386/isa/if_ed.c38
-rw-r--r--sys/i386/isa/if_eg.c24
-rw-r--r--sys/i386/isa/if_el.c33
-rw-r--r--sys/i386/isa/if_ep.c25
-rw-r--r--sys/i386/isa/if_fe.c31
-rw-r--r--sys/i386/isa/if_ie.c29
-rw-r--r--sys/i386/isa/if_ix.c13
-rw-r--r--sys/i386/isa/if_le.c27
-rw-r--r--sys/i386/isa/if_ze.c33
-rw-r--r--sys/i386/isa/if_zp.c25
-rw-r--r--sys/net/if_ethersubr.c26
-rw-r--r--sys/net/if_fddisubr.c19
-rw-r--r--sys/net/if_loop.c13
-rw-r--r--sys/net/if_ppp.c7
-rw-r--r--sys/net/if_ppp.h4
-rw-r--r--sys/net/if_spppsubr.c11
-rw-r--r--sys/net/netisr.h3
-rw-r--r--sys/net/route.h3
-rw-r--r--sys/net/rtsock.c7
-rw-r--r--sys/netccitt/if_x25subr.c14
-rw-r--r--sys/netinet/in_proto.c13
-rw-r--r--sys/netipx/README21
-rw-r--r--sys/netipx/ipx.c372
-rw-r--r--sys/netipx/ipx.h196
-rw-r--r--sys/netipx/ipx_cksum.c205
-rw-r--r--sys/netipx/ipx_error.c378
-rw-r--r--sys/netipx/ipx_error.h98
-rw-r--r--sys/netipx/ipx_if.h90
-rw-r--r--sys/netipx/ipx_input.c523
-rw-r--r--sys/netipx/ipx_ip.c452
-rw-r--r--sys/netipx/ipx_outputfl.c159
-rw-r--r--sys/netipx/ipx_pcb.c373
-rw-r--r--sys/netipx/ipx_pcb.h88
-rw-r--r--sys/netipx/ipx_proto.c100
-rw-r--r--sys/netipx/ipx_tun.c67
-rw-r--r--sys/netipx/ipx_usrreq.c577
-rw-r--r--sys/netipx/ipx_var.h55
-rw-r--r--sys/netipx/spx.h97
-rw-r--r--sys/netipx/spx_debug.c168
-rw-r--r--sys/netipx/spx_debug.h75
-rw-r--r--sys/netipx/spx_timer.h128
-rw-r--r--sys/netipx/spx_usrreq.c1815
-rw-r--r--sys/netipx/spx_var.h211
-rw-r--r--sys/netns/ns.h3
52 files changed, 6770 insertions, 38 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index ae502aa..cd2ae49 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.205 1995/10/10 04:03:12 bde Exp $
+# $Id: LINT,v 1.206 1995/10/25 16:43:01 jkh Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -129,6 +129,12 @@ options INET #Internet communications protocols
options CCITT #X.25 network layer
options NS #Xerox NS communications protocols
+options IPX #IPX/SPX communications protocols
+options IPXIP #IPX in IP encapsulation (not available)
+options IPTUNNEL #IP in IPX encapsulation (not available)
+#options "IPXPRINTFS=0" #Console Debugging Information
+#options "IPX_ERRPRINTFS=0" #Console Debugging Information
+
# These are currently broken and don't compile
#options ISO
#options TPIP #ISO TP class 4 over IP
diff --git a/sys/conf/files b/sys/conf/files
index eab96e8..a23a1cf 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -208,6 +208,18 @@ netinet/tcp_subr.c optional inet
netinet/tcp_timer.c optional inet
netinet/tcp_usrreq.c optional inet
netinet/udp_usrreq.c optional inet
+netipx/ipx_usrreq.c optional ipx
+netipx/ipx.c optional ipx
+netipx/ipx_cksum.c optional ipx
+netipx/ipx_error.c optional ipx
+netipx/ipx_input.c optional ipx
+netipx/ipx_ip.c optional ipx
+netipx/ipx_outputfl.c optional ipx
+netipx/ipx_pcb.c optional ipx
+netipx/ipx_proto.c optional ipx
+netipx/ipx_tun.c optional ipx
+netipx/spx_debug.c optional ipx
+netipx/spx_usrreq.c optional ipx
netiso/clnp_debug.c optional iso
netiso/clnp_er.c optional iso
netiso/clnp_frag.c optional iso
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c
index e5c1771..9234fcf 100644
--- a/sys/dev/ed/if_ed.c
+++ b/sys/dev/ed/if_ed.c
@@ -13,7 +13,7 @@
* the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000,
* and a variety of similar clones.
*
- * $Id: if_ed.c,v 1.78 1995/10/13 19:47:40 wollman Exp $
+ * $Id: if_ed.c,v 1.79 1995/10/21 00:55:23 phk Exp $
*/
#include "ed.h"
@@ -40,6 +40,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -2256,11 +2261,34 @@ ed_ioctl(ifp, command, data)
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
-#ifdef NS
+#ifdef IPX
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
- /*
- * XXX - This code is probably wrong
- */
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->arpcom.ac_enaddr);
+ else {
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+
+ /*
+ * Set new address
+ */
+ ed_init(ifp->if_unit);
+ break;
+ }
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
case AF_NS:
{
register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c
index 6c940ff..0b5008d 100644
--- a/sys/dev/ep/if_ep.c
+++ b/sys/dev/ep/if_ep.c
@@ -38,7 +38,7 @@
*/
/*
- * $Id: if_ep.c,v 1.30 1995/08/28 12:01:17 guido Exp $
+ * $Id: if_ep.c,v 1.31 1995/10/13 19:47:44 wollman Exp $
*
* Promiscuous mode added and interrupt logic slightly changed
* to reduce the number of adapter failures. Transceiver select
@@ -82,6 +82,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1141,6 +1146,24 @@ epioctl(ifp, cmd, data)
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->arpcom.ac_enaddr);
+ else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ epinit(ifp->if_unit);
+ break;
+ }
+#endif
#ifdef NS
case AF_NS:
{
diff --git a/sys/dev/fe/if_fe.c b/sys/dev/fe/if_fe.c
index d6e9ca7..b17d4fb 100644
--- a/sys/dev/fe/if_fe.c
+++ b/sys/dev/fe/if_fe.c
@@ -72,6 +72,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -2017,6 +2022,32 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data )
arp_ifinit( &sc->arpcom, ifa );
break;
#endif
+#ifdef IPX
+
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina
+ = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->sc_enaddr);
+ else {
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->sc_enaddr,
+ sizeof(sc->sc_enaddr));
+ }
+
+ /*
+ * Set new address
+ */
+ fe_init(sc->sc_unit);
+ break;
+ }
+#endif
#ifdef NS
/*
diff --git a/sys/dev/ie/if_ie.c b/sys/dev/ie/if_ie.c
index c0465e9..46aa428 100644
--- a/sys/dev/ie/if_ie.c
+++ b/sys/dev/ie/if_ie.c
@@ -43,7 +43,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_ie.c,v 1.26 1995/09/19 18:55:09 bde Exp $
+ * $Id: if_ie.c,v 1.27 1995/10/13 19:47:47 wollman Exp $
*/
/*
@@ -133,6 +133,11 @@ iomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1891,6 +1896,28 @@ ieioctl(ifp, command, data)
break;
#endif /* INET */
+#ifdef IPX
+ /* This magic copied from if_is.c; I don't use XNS, so I have no
+ * way of telling if this actually works or not.
+ */
+ case AF_IPX:
+ {
+ struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if(ipx_nullhost(*ina)) {
+ ina->x_host = *(union ipx_host *)(ie->arpcom.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)ie->arpcom.ac_enaddr,
+ sizeof ie->arpcom.ac_enaddr);
+ }
+
+ ieinit(ifp->if_unit);
+ }
+ break;
+#endif /* IPX */
+
#ifdef NS
/* This magic copied from if_is.c; I don't use XNS, so I have no
* way of telling if this actually works or not.
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
index ae502aa..cd2ae49 100644
--- a/sys/i386/conf/LINT
+++ b/sys/i386/conf/LINT
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.205 1995/10/10 04:03:12 bde Exp $
+# $Id: LINT,v 1.206 1995/10/25 16:43:01 jkh Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -129,6 +129,12 @@ options INET #Internet communications protocols
options CCITT #X.25 network layer
options NS #Xerox NS communications protocols
+options IPX #IPX/SPX communications protocols
+options IPXIP #IPX in IP encapsulation (not available)
+options IPTUNNEL #IP in IPX encapsulation (not available)
+#options "IPXPRINTFS=0" #Console Debugging Information
+#options "IPX_ERRPRINTFS=0" #Console Debugging Information
+
# These are currently broken and don't compile
#options ISO
#options TPIP #ISO TP class 4 over IP
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index ae502aa..cd2ae49 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -2,7 +2,7 @@
# LINT -- config file for checking all the sources, tries to pull in
# as much of the source tree as it can.
#
-# $Id: LINT,v 1.205 1995/10/10 04:03:12 bde Exp $
+# $Id: LINT,v 1.206 1995/10/25 16:43:01 jkh Exp $
#
# NB: You probably don't want to try running a kernel built from this
# file. Instead, you should start from GENERIC, and add options from
@@ -129,6 +129,12 @@ options INET #Internet communications protocols
options CCITT #X.25 network layer
options NS #Xerox NS communications protocols
+options IPX #IPX/SPX communications protocols
+options IPXIP #IPX in IP encapsulation (not available)
+options IPTUNNEL #IP in IPX encapsulation (not available)
+#options "IPXPRINTFS=0" #Console Debugging Information
+#options "IPX_ERRPRINTFS=0" #Console Debugging Information
+
# These are currently broken and don't compile
#options ISO
#options TPIP #ISO TP class 4 over IP
diff --git a/sys/i386/isa/if_ed.c b/sys/i386/isa/if_ed.c
index e5c1771..9234fcf 100644
--- a/sys/i386/isa/if_ed.c
+++ b/sys/i386/isa/if_ed.c
@@ -13,7 +13,7 @@
* the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000,
* and a variety of similar clones.
*
- * $Id: if_ed.c,v 1.78 1995/10/13 19:47:40 wollman Exp $
+ * $Id: if_ed.c,v 1.79 1995/10/21 00:55:23 phk Exp $
*/
#include "ed.h"
@@ -40,6 +40,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -2256,11 +2261,34 @@ ed_ioctl(ifp, command, data)
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
-#ifdef NS
+#ifdef IPX
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
- /*
- * XXX - This code is probably wrong
- */
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->arpcom.ac_enaddr);
+ else {
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+
+ /*
+ * Set new address
+ */
+ ed_init(ifp->if_unit);
+ break;
+ }
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
case AF_NS:
{
register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
diff --git a/sys/i386/isa/if_eg.c b/sys/i386/isa/if_eg.c
index b345b19..f3db5b5 100644
--- a/sys/i386/isa/if_eg.c
+++ b/sys/i386/isa/if_eg.c
@@ -27,7 +27,7 @@
* (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: if_eg.c,v 1.4 1995/05/30 08:02:02 rgrimes Exp $
+ * $Id: if_eg.c,v 1.5 1995/10/13 19:47:42 wollman Exp $
*/
/* To do:
@@ -58,6 +58,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -725,6 +730,23 @@ egioctl(ifp, command, data)
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &IA_SIPX(ifa)->sipx_addr;
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *)(sc->sc_arpcom.ac_enaddr);
+ else
+ bcopy(ina->x_host.c_host,
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+ /* Set new address. */
+ eginit(sc);
+ break;
+ }
+#endif
#ifdef NS
case AF_NS:
{
diff --git a/sys/i386/isa/if_el.c b/sys/i386/isa/if_el.c
index 40f00a8..47d95d8 100644
--- a/sys/i386/isa/if_el.c
+++ b/sys/i386/isa/if_el.c
@@ -6,7 +6,7 @@
*
* Questions, comments, bug reports and fixes to kimmel@cs.umass.edu.
*
- * $Id: if_el.c,v 1.14 1995/06/11 19:31:25 rgrimes Exp $
+ * $Id: if_el.c,v 1.15 1995/10/13 19:47:43 wollman Exp $
*/
/* Except of course for the portions of code lifted from other FreeBSD
* drivers (mainly elread, elget and el_ioctl)
@@ -44,6 +44,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -711,6 +716,32 @@ el_ioctl(ifp, command, data)
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
+#ifdef IPX
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ el_init(ifp->if_unit);
+ break;
+ }
+#endif
#ifdef NS
/*
* XXX - This code is probably wrong
diff --git a/sys/i386/isa/if_ep.c b/sys/i386/isa/if_ep.c
index 6c940ff..0b5008d 100644
--- a/sys/i386/isa/if_ep.c
+++ b/sys/i386/isa/if_ep.c
@@ -38,7 +38,7 @@
*/
/*
- * $Id: if_ep.c,v 1.30 1995/08/28 12:01:17 guido Exp $
+ * $Id: if_ep.c,v 1.31 1995/10/13 19:47:44 wollman Exp $
*
* Promiscuous mode added and interrupt logic slightly changed
* to reduce the number of adapter failures. Transceiver select
@@ -82,6 +82,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1141,6 +1146,24 @@ epioctl(ifp, cmd, data)
arp_ifinit((struct arpcom *)ifp, ifa);
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->arpcom.ac_enaddr);
+ else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ epinit(ifp->if_unit);
+ break;
+ }
+#endif
#ifdef NS
case AF_NS:
{
diff --git a/sys/i386/isa/if_fe.c b/sys/i386/isa/if_fe.c
index d6e9ca7..b17d4fb 100644
--- a/sys/i386/isa/if_fe.c
+++ b/sys/i386/isa/if_fe.c
@@ -72,6 +72,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -2017,6 +2022,32 @@ fe_ioctl ( struct ifnet *ifp, int command, caddr_t data )
arp_ifinit( &sc->arpcom, ifa );
break;
#endif
+#ifdef IPX
+
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina
+ = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->sc_enaddr);
+ else {
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->sc_enaddr,
+ sizeof(sc->sc_enaddr));
+ }
+
+ /*
+ * Set new address
+ */
+ fe_init(sc->sc_unit);
+ break;
+ }
+#endif
#ifdef NS
/*
diff --git a/sys/i386/isa/if_ie.c b/sys/i386/isa/if_ie.c
index c0465e9..46aa428 100644
--- a/sys/i386/isa/if_ie.c
+++ b/sys/i386/isa/if_ie.c
@@ -43,7 +43,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: if_ie.c,v 1.26 1995/09/19 18:55:09 bde Exp $
+ * $Id: if_ie.c,v 1.27 1995/10/13 19:47:47 wollman Exp $
*/
/*
@@ -133,6 +133,11 @@ iomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1891,6 +1896,28 @@ ieioctl(ifp, command, data)
break;
#endif /* INET */
+#ifdef IPX
+ /* This magic copied from if_is.c; I don't use XNS, so I have no
+ * way of telling if this actually works or not.
+ */
+ case AF_IPX:
+ {
+ struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if(ipx_nullhost(*ina)) {
+ ina->x_host = *(union ipx_host *)(ie->arpcom.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)ie->arpcom.ac_enaddr,
+ sizeof ie->arpcom.ac_enaddr);
+ }
+
+ ieinit(ifp->if_unit);
+ }
+ break;
+#endif /* IPX */
+
#ifdef NS
/* This magic copied from if_is.c; I don't use XNS, so I have no
* way of telling if this actually works or not.
diff --git a/sys/i386/isa/if_ix.c b/sys/i386/isa/if_ix.c
index cdafd00..0dc4317 100644
--- a/sys/i386/isa/if_ix.c
+++ b/sys/i386/isa/if_ix.c
@@ -28,7 +28,7 @@
* (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: if_ix.c,v 1.9 1995/10/05 03:01:13 davidg Exp $
+ * $Id: if_ix.c,v 1.10 1995/10/13 19:47:48 wollman Exp $
*/
#include "ix.h"
@@ -56,6 +56,11 @@
#include <netinet/if_ether.h>
#endif /* INET */
+#ifdef IPX /*ZZZ no work done on this, this is just here to remind me*/
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif /* IPX */
+
#ifdef NS /*ZZZ no work done on this, this is just here to remind me*/
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1519,6 +1524,12 @@ ixioctl(struct ifnet *ifp, int cmd, caddr_t data) {
break;
}
#endif /* INET */
+#ifdef IPX
+ case AF_IPX: {
+ /*ZZZ*/printf("Address family IPX not supported by ixioctl\n");
+ break;
+ }
+#endif /* IPX */
#ifdef NS
case AF_NS: {
/*ZZZ*/printf("Address family NS not supported by ixioctl\n");
diff --git a/sys/i386/isa/if_le.c b/sys/i386/isa/if_le.c
index 6bfb08f..208f24a 100644
--- a/sys/i386/isa/if_le.c
+++ b/sys/i386/isa/if_le.c
@@ -21,7 +21,7 @@
* (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: if_le.c,v 1.19 1995/09/19 18:55:12 bde Exp $
+ * $Id: if_le.c,v 1.20 1995/10/13 19:47:49 wollman Exp $
*/
/*
@@ -65,6 +65,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -569,7 +574,26 @@ le_ioctl(
break;
}
#endif /* INET */
+#ifdef IPX
+ /* This magic copied from if_is.c; I don't use XNS,
+ * so I have no way of telling if this actually
+ * works or not.
+ */
+ case AF_IPX: {
+ struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+ if (ipx_nullhost(*ina)) {
+ ina->x_host = *(union ipx_host *)(sc->le_ac.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->le_ac.ac_enaddr,
+ sizeof sc->le_ac.ac_enaddr);
+ }
+ (*ifp->if_init)(ifp->if_unit);
+ break;
+ }
+#endif /* IPX */
#ifdef NS
/* This magic copied from if_is.c; I don't use XNS,
* so I have no way of telling if this actually
@@ -590,7 +614,6 @@ le_ioctl(
break;
}
#endif /* NS */
-
default: {
(*ifp->if_init)(ifp->if_unit);
break;
diff --git a/sys/i386/isa/if_ze.c b/sys/i386/isa/if_ze.c
index ac78d97..cad7fc8 100644
--- a/sys/i386/isa/if_ze.c
+++ b/sys/i386/isa/if_ze.c
@@ -47,7 +47,7 @@
*/
/*
- * $Id: if_ze.c,v 1.20 1995/09/26 08:57:47 phk Exp $
+ * $Id: if_ze.c,v 1.21 1995/10/13 19:47:52 wollman Exp $
*/
#include "ze.h"
@@ -75,6 +75,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1349,6 +1354,32 @@ ze_ioctl(ifp, command, data)
arp_ifinit((struct arpcom*) ifp, ifa);
break;
#endif
+#ifdef IPX
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ ze_init(ifp->if_unit);
+ break;
+ }
+#endif
#ifdef NS
/*
* XXX - This code is probably wrong
diff --git a/sys/i386/isa/if_zp.c b/sys/i386/isa/if_zp.c
index 3c19a4f..e1453f0 100644
--- a/sys/i386/isa/if_zp.c
+++ b/sys/i386/isa/if_zp.c
@@ -34,7 +34,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
- * $Id: if_zp.c,v 1.8 1995/08/16 23:34:28 nate Exp $
+ * $Id: if_zp.c,v 1.9 1995/10/13 19:47:53 wollman Exp $
*/
/*-
* TODO:
@@ -166,6 +166,11 @@ enum memtype {
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -1958,6 +1963,24 @@ zpioctl(ifp, cmd, data)
#endif
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ {
+ register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
+
+ if (ipx_nullhost(*ina))
+ ina->x_host =
+ *(union ipx_host *) (sc->arpcom.ac_enaddr);
+ else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t) sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ zpinit(ifp->if_unit);
+ break;
+ }
+#endif
#ifdef NS
case AF_NS:
{
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index ff63303..9da90b1 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93
- * $Id: if_ethersubr.c,v 1.8.2.1 1995/06/03 04:46:21 davidg Exp $
+ * $Id: if_ethersubr.c,v 1.9 1995/06/11 19:31:39 rgrimes Exp $
*/
#include <sys/param.h>
@@ -60,6 +60,11 @@
#endif
#include <netinet/if_ether.h>
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -147,6 +152,18 @@ ether_output(ifp, m0, dst, rt0)
type = ETHERTYPE_IP;
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ type = ETHERTYPE_IPX;
+ bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
+ (caddr_t)edst, sizeof (edst));
+ if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst)))
+ return (looutput(ifp, m, dst, rt));
+ /* If broadcasting on a simplex interface, loopback a copy */
+ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
+ mcopy = m_copy(m, 0, (int)M_COPYALL);
+ break;
+#endif
#ifdef NS
case AF_NS:
type = ETHERTYPE_NS;
@@ -342,12 +359,17 @@ ether_input(ifp, eh, m)
inq = &arpintrq;
break;
#endif
+#ifdef IPX
+ case ETHERTYPE_IPX:
+ schednetisr(NETISR_IPX);
+ inq = &ipxintrq;
+ break;
+#endif
#ifdef NS
case ETHERTYPE_NS:
schednetisr(NETISR_NS);
inq = &nsintrq;
break;
-
#endif
default:
#if defined (ISO) || defined (LLC)
diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c
index 41ea156..0824ede 100644
--- a/sys/net/if_fddisubr.c
+++ b/sys/net/if_fddisubr.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
- * $Id: if_fddisubr.c,v 1.4 1995/05/09 13:35:40 davidg Exp $
+ * $Id: if_fddisubr.c,v 1.5 1995/05/30 08:08:05 rgrimes Exp $
*/
#include <sys/param.h>
@@ -61,6 +61,11 @@
#include <netinet/if_ether.h>
#include <netinet/if_fddi.h>
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -164,6 +169,18 @@ fddi_output(ifp, m0, dst, rt0)
type = ETHERTYPE_IP;
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ type = ETHERTYPE_IPX;
+ bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
+ (caddr_t)edst, sizeof (edst));
+ if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst)))
+ return (looutput(ifp, m, dst, rt));
+ /* If broadcasting on a simplex interface, loopback a copy */
+ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
+ mcopy = m_copy(m, 0, (int)M_COPYALL);
+ break;
+#endif
#ifdef NS
case AF_NS:
type = ETHERTYPE_NS;
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index 5bf79ee..cf29912 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if_loop.c 8.1 (Berkeley) 6/10/93
- * $Id: if_loop.c,v 1.12 1995/09/09 18:10:22 davidg Exp $
+ * $Id: if_loop.c,v 1.13 1995/09/22 17:57:48 wollman Exp $
*/
/*
@@ -63,6 +63,11 @@
#include <netinet/ip.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -169,6 +174,12 @@ looutput(ifp, m, dst, rt)
isr = NETISR_IP;
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ ifq = &ipxintrq;
+ isr = NETISR_IPX;
+ break;
+#endif
#ifdef NS
case AF_NS:
ifq = &nsintrq;
diff --git a/sys/net/if_ppp.c b/sys/net/if_ppp.c
index 7e1a321..dab6370 100644
--- a/sys/net/if_ppp.c
+++ b/sys/net/if_ppp.c
@@ -69,7 +69,7 @@
* Paul Mackerras (paulus@cs.anu.edu.au).
*/
-/* $Id: if_ppp.c,v 1.21 1995/09/09 18:10:23 davidg Exp $ */
+/* $Id: if_ppp.c,v 1.22 1995/10/05 00:33:27 bde Exp $ */
/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
#include "ppp.h"
@@ -699,6 +699,11 @@ pppoutput(ifp, m0, dst, rt)
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ protocol = PPP_IPX;
+ break;
+#endif
#ifdef NS
case AF_NS:
protocol = PPP_XNS;
diff --git a/sys/net/if_ppp.h b/sys/net/if_ppp.h
index 97df728..099b9be 100644
--- a/sys/net/if_ppp.h
+++ b/sys/net/if_ppp.h
@@ -16,7 +16,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Id: if_ppp.h,v 1.2 1994/09/23 00:13:20 wollman Exp $
+ * $Id: if_ppp.h,v 1.3 1995/05/30 08:08:09 rgrimes Exp $
*/
#ifndef _IF_PPP_H_
@@ -45,10 +45,12 @@ struct ppp_header {
*/
#define PPP_IP 0x21 /* Internet Protocol */
#define PPP_XNS 0x25 /* Xerox NS */
+#define PPP_IPX 0x2b /* IPX Datagram (RFC1552) */
#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */
#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */
#define PPP_COMP 0xfd /* compressed packet */
#define PPP_LCP 0xc021 /* Link Control Protocol */
+#define PPP_IPXCP 0x802b /* IPX Control Protocol (RFC1552) */
#define PPP_CCP 0x80fd /* Compression Control Protocol */
/*
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index e8a9576..c26fddc 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -36,6 +36,11 @@
#include <netinet/if_ether.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -405,6 +410,12 @@ int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct
ETHERTYPE_NS : PPP_XNS);
break;
#endif
+#ifdef IPX
+ case AF_IPX: /* Xerox NS Protocol */
+ h->protocol = htons ((sp->pp_flags & PP_CISCO) ?
+ ETHERTYPE_IPX : PPP_XNS);
+ break;
+#endif
#ifdef ISO
case AF_ISO: /* ISO OSI Protocol */
if (sp->pp_flags & PP_CISCO)
diff --git a/sys/net/netisr.h b/sys/net/netisr.h
index 3558348..5dd9b87 100644
--- a/sys/net/netisr.h
+++ b/sys/net/netisr.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)netisr.h 8.1 (Berkeley) 6/10/93
- * $Id: netisr.h,v 1.5 1995/01/05 19:51:47 se Exp $
+ * $Id: netisr.h,v 1.6 1995/05/11 00:13:10 wollman Exp $
*/
#ifndef _NET_NETISR_H_
@@ -62,6 +62,7 @@
#define NETISR_ISO 7 /* same as AF_ISO */
#define NETISR_CCITT 10 /* same as AF_CCITT */
#define NETISR_ARP 18 /* same as AF_LINK */
+#define NETISR_IPX 23 /* same as AF_IPX */
#define NETISR_ISDN 26 /* same as AF_E164 */
#define schednetisr(anisr) { netisr |= 1<<(anisr); setsoftnet(); }
diff --git a/sys/net/route.h b/sys/net/route.h
index 894669c..6d26488 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)route.h 8.3 (Berkeley) 4/19/94
- * $Id: route.h,v 1.15 1995/07/29 11:41:03 bde Exp $
+ * $Id: route.h,v 1.16 1995/10/16 20:53:55 wollman Exp $
*/
#ifndef _NET_ROUTE_H_
@@ -242,6 +242,7 @@ struct rt_addrinfo {
struct route_cb {
int ip_count;
+ int ipx_count;
int ns_count;
int iso_count;
int any_count;
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 2601ad7..f24ac4e 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)rtsock.c 8.5 (Berkeley) 11/2/94
- * $Id: rtsock.c,v 1.14 1995/10/09 04:06:28 bde Exp $
+ * $Id: rtsock.c,v 1.15 1995/10/13 16:01:59 wollman Exp $
*/
#include <sys/param.h>
@@ -92,12 +92,13 @@ route_usrreq(so, req, m, nam, control)
so->so_pcb = (caddr_t)rp;
if (so->so_pcb)
bzero(so->so_pcb, sizeof(*rp));
-
}
if (req == PRU_DETACH && rp) {
int af = rp->rcb_proto.sp_protocol;
if (af == AF_INET)
route_cb.ip_count--;
+ else if (af == AF_IPX)
+ route_cb.ipx_count--;
else if (af == AF_NS)
route_cb.ns_count--;
else if (af == AF_ISO)
@@ -116,6 +117,8 @@ route_usrreq(so, req, m, nam, control)
}
if (af == AF_INET)
route_cb.ip_count++;
+ else if (af == AF_IPX)
+ route_cb.ipx_count++;
else if (af == AF_NS)
route_cb.ns_count++;
else if (af == AF_ISO)
diff --git a/sys/netccitt/if_x25subr.c b/sys/netccitt/if_x25subr.c
index 8cdc22e..f43b626 100644
--- a/sys/netccitt/if_x25subr.c
+++ b/sys/netccitt/if_x25subr.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)if_x25subr.c 8.1 (Berkeley) 6/10/93
- * $Id: if_x25subr.c,v 1.6 1995/05/30 08:08:46 rgrimes Exp $
+ * $Id: if_x25subr.c,v 1.7 1995/07/29 11:41:21 bde Exp $
*/
#include <sys/param.h>
@@ -62,6 +62,11 @@
#include <netinet/in_var.h>
#endif
+#ifdef IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
#ifdef NS
#include <netns/ns.h>
#include <netns/ns_if.h>
@@ -186,12 +191,17 @@ register struct mbuf *m;
break;
#endif
+#ifdef IPX
+ case AF_IPX:
+ isr = NETISR_IPX;
+ inq = &ipxintrq;
+ break;
+#endif
#ifdef NS
case AF_NS:
isr = NETISR_NS;
inq = &nsintrq;
break;
-
#endif
#ifdef ISO
case AF_ISO:
diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c
index e5cbcef..4e38754 100644
--- a/sys/netinet/in_proto.c
+++ b/sys/netinet/in_proto.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)in_proto.c 8.2 (Berkeley) 2/9/95
- * $Id: in_proto.c,v 1.17 1995/06/26 16:11:51 wollman Exp $
+ * $Id: in_proto.c,v 1.18 1995/09/21 17:58:07 wollman Exp $
*/
#include <sys/param.h>
@@ -68,6 +68,10 @@
* TCP/IP protocol family: IP, ICMP, UDP, TCP.
*/
+#ifdef IPXIP
+void ipxip_input(), ipxip_ctlinput();
+#endif
+
#ifdef NSIP
void idpip_input(), nsip_ctlinput();
#endif
@@ -143,6 +147,13 @@ struct protosw inetsw[] = {
eonprotoinit, 0, 0, 0,
},
#endif
+#ifdef IPXIP
+{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
+ ipxip_input, rip_output, ipxip_ctlinput, 0,
+ rip_usrreq,
+ 0, 0, 0, 0,
+},
+#endif
#ifdef NSIP
{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
idpip_input, rip_output, nsip_ctlinput, 0,
diff --git a/sys/netipx/README b/sys/netipx/README
new file mode 100644
index 0000000..87c1db9
--- /dev/null
+++ b/sys/netipx/README
@@ -0,0 +1,21 @@
+This protocol implements IPX/SPX over Ethernet_II frame type 0x8137.
+Please note: the SPX implementation may require further work and testing
+to insure proper operation.
+
+Mike Mitchell, Network Engineer
+AMTECH Systems Corporation, Technology and Manufacturing
+8600 Jefferson Street, Albuquerque, New Mexico 87113 (505) 856-8000
+supervisor@alb.asctmd.com
+
+John Hay
+Some Company
+Some Address
+jhay@mikom.csir.co.za
+
+--- Copyright Information ---
+
+Copyright (c) 1984, 1985, 1986, 1987, 1993
+The Regents of the University of California. All rights reserved.
+
+Modifications Copyright (c) 1995, Mike Mitchell
+Modifications Copyright (c) 1995, John Hay
diff --git a/sys/netipx/ipx.c b/sys/netipx/ipx.c
new file mode 100644
index 0000000..f04463e
--- /dev/null
+++ b/sys/netipx/ipx.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#ifdef IPX
+
+struct ipx_ifaddr *ipx_ifaddr;
+int ipx_interfaces;
+
+/*
+ * Generic internet control operations (ioctl's).
+ */
+/* ARGSUSED */
+int
+ipx_control(so, cmd, data, ifp)
+ struct socket *so;
+ int cmd;
+ caddr_t data;
+ register struct ifnet *ifp;
+{
+ register struct ifreq *ifr = (struct ifreq *)data;
+ register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
+ register struct ipx_ifaddr *ia;
+ struct ifaddr *ifa;
+ struct ipx_ifaddr *oia;
+ int dstIsNew, hostIsNew;
+ int error = 0;
+
+ /*
+ * Find address for this interface, if it exists.
+ */
+ if (ifp == 0)
+ return (EADDRNOTAVAIL);
+ for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+
+ switch (cmd) {
+
+ case SIOCGIFADDR:
+ if (ia == (struct ipx_ifaddr *)0)
+ return (EADDRNOTAVAIL);
+ *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
+ return (0);
+
+ case SIOCGIFBRDADDR:
+ if (ia == (struct ipx_ifaddr *)0)
+ return (EADDRNOTAVAIL);
+ if ((ifp->if_flags & IFF_BROADCAST) == 0)
+ return (EINVAL);
+ *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
+ return (0);
+
+ case SIOCGIFDSTADDR:
+ if (ia == (struct ipx_ifaddr *)0)
+ return (EADDRNOTAVAIL);
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ return (EINVAL);
+ *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
+ return (0);
+ }
+
+ if ((so->so_state & SS_PRIV) == 0)
+ return (EPERM);
+
+ switch (cmd) {
+ case SIOCAIFADDR:
+ case SIOCDIFADDR:
+ if (ifra->ifra_addr.sipx_family == AF_IPX)
+ for (oia = ia; ia; ia = ia->ia_next) {
+ if (ia->ia_ifp == ifp &&
+ ipx_neteq(ia->ia_addr.sipx_addr,
+ ifra->ifra_addr.sipx_addr))
+ break;
+ }
+ if (cmd == SIOCDIFADDR && ia == 0)
+ return (EADDRNOTAVAIL);
+ /* FALLTHROUGH */
+
+ case SIOCSIFADDR:
+ case SIOCSIFDSTADDR:
+ if (ia == (struct ipx_ifaddr *)0) {
+ oia = (struct ipx_ifaddr *)
+ malloc(sizeof *ia, M_IFADDR, M_WAITOK);
+ if (oia == (struct ipx_ifaddr *)NULL)
+ return (ENOBUFS);
+ bzero((caddr_t)oia, sizeof(*oia));
+ if ((ia = ipx_ifaddr)) {
+ for ( ; ia->ia_next; ia = ia->ia_next)
+ ;
+ ia->ia_next = oia;
+ } else
+ ipx_ifaddr = oia;
+ ia = oia;
+ if ((ifa = ifp->if_addrlist)) {
+ for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
+ ;
+ ifa->ifa_next = (struct ifaddr *) ia;
+ } else
+ ifp->if_addrlist = (struct ifaddr *) ia;
+ ia->ia_ifp = ifp;
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+
+ ia->ia_ifa.ifa_netmask =
+ (struct sockaddr *)&ipx_netmask;
+
+ ia->ia_ifa.ifa_dstaddr =
+ (struct sockaddr *)&ia->ia_dstaddr;
+ if (ifp->if_flags & IFF_BROADCAST) {
+ ia->ia_broadaddr.sipx_family = AF_IPX;
+ ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
+ ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
+ }
+ ipx_interfaces++;
+ }
+ }
+
+ switch (cmd) {
+
+ case SIOCSIFDSTADDR:
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+ return (EINVAL);
+ if (ia->ia_flags & IFA_ROUTE) {
+ rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+ ia->ia_flags &= ~IFA_ROUTE;
+ }
+ if (ifp->if_ioctl) {
+ error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
+ if (error)
+ return (error);
+ }
+ *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
+ return (0);
+
+ case SIOCSIFADDR:
+ return (ipx_ifinit(ifp, ia,
+ (struct sockaddr_ipx *)&ifr->ifr_addr, 1));
+
+ case SIOCDIFADDR:
+ ipx_ifscrub(ifp, ia);
+ if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
+ ifp->if_addrlist = ifa->ifa_next;
+ else {
+ while (ifa->ifa_next &&
+ (ifa->ifa_next != (struct ifaddr *)ia))
+ ifa = ifa->ifa_next;
+ if (ifa->ifa_next)
+ ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
+ else
+ printf("Couldn't unlink ipxifaddr from ifp\n");
+ }
+ oia = ia;
+ if (oia == (ia = ipx_ifaddr)) {
+ ipx_ifaddr = ia->ia_next;
+ } else {
+ while (ia->ia_next && (ia->ia_next != oia)) {
+ ia = ia->ia_next;
+ }
+ if (ia->ia_next)
+ ia->ia_next = oia->ia_next;
+ else
+ printf("Didn't unlink ipxifadr from list\n");
+ }
+ IFAFREE((&oia->ia_ifa));
+ if (0 == --ipx_interfaces) {
+ /*
+ * We reset to virginity and start all over again
+ */
+ ipx_thishost = ipx_zerohost;
+ }
+ return (0);
+
+ case SIOCAIFADDR:
+ dstIsNew = 0; hostIsNew = 1;
+ if (ia->ia_addr.sipx_family == AF_IPX) {
+ if (ifra->ifra_addr.sipx_len == 0) {
+ ifra->ifra_addr = ia->ia_addr;
+ hostIsNew = 0;
+ } else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
+ ia->ia_addr.sipx_addr))
+ hostIsNew = 0;
+ }
+ if ((ifp->if_flags & IFF_POINTOPOINT) &&
+ (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
+ if (hostIsNew == 0)
+ ipx_ifscrub(ifp, ia);
+ ia->ia_dstaddr = ifra->ifra_dstaddr;
+ dstIsNew = 1;
+ }
+ if (ifra->ifra_addr.sipx_family == AF_IPX &&
+ (hostIsNew || dstIsNew))
+ error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+ return (error);
+
+ default:
+ if (ifp->if_ioctl == 0)
+ return (EOPNOTSUPP);
+ return ((*ifp->if_ioctl)(ifp, cmd, data));
+ }
+}
+
+/*
+* Delete any previous route for an old address.
+*/
+void
+ipx_ifscrub(ifp, ia)
+ register struct ifnet *ifp;
+ register struct ipx_ifaddr *ia;
+{
+ if (ia->ia_flags & IFA_ROUTE) {
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+ } else
+ rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
+ ia->ia_flags &= ~IFA_ROUTE;
+ }
+}
+/*
+ * Initialize an interface's internet address
+ * and routing table entry.
+ */
+int
+ipx_ifinit(ifp, ia, sipx, scrub)
+ register struct ifnet *ifp;
+ register struct ipx_ifaddr *ia;
+ register struct sockaddr_ipx *sipx;
+ int scrub;
+{
+ struct sockaddr_ipx oldaddr;
+ register union ipx_host *h = &ia->ia_addr.sipx_addr.x_host;
+ int s = splimp(), error;
+
+ /*
+ * Set up new addresses.
+ */
+ oldaddr = ia->ia_addr;
+ ia->ia_addr = *sipx;
+ /*
+ * The convention we shall adopt for naming is that
+ * a supplied address of zero means that "we don't care".
+ * if there is a single interface, use the address of that
+ * interface as our 6 byte host address.
+ * if there are multiple interfaces, use any address already
+ * used.
+ *
+ * Give the interface a chance to initialize
+ * if this is its first address,
+ * and to validate the address if necessary.
+ */
+ if (ipx_hosteqnh(ipx_thishost, ipx_zerohost)) {
+ if (ifp->if_ioctl &&
+ (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
+ ia->ia_addr = oldaddr;
+ splx(s);
+ return (error);
+ }
+ ipx_thishost = *h;
+ } else if (ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_zerohost)
+ || ipx_hosteqnh(sipx->sipx_addr.x_host, ipx_thishost)) {
+ *h = ipx_thishost;
+ if (ifp->if_ioctl &&
+ (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
+ ia->ia_addr = oldaddr;
+ splx(s);
+ return (error);
+ }
+ if (!ipx_hosteqnh(ipx_thishost,*h)) {
+ ia->ia_addr = oldaddr;
+ splx(s);
+ return (EINVAL);
+ }
+ } else {
+ ia->ia_addr = oldaddr;
+ splx(s);
+ return (EINVAL);
+ }
+ ia->ia_ifa.ifa_metric = ifp->if_metric;
+ /*
+ * Add route for the network.
+ */
+ if (scrub) {
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
+ ipx_ifscrub(ifp, ia);
+ ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+ }
+ if (ifp->if_flags & IFF_POINTOPOINT)
+ rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
+ else {
+ ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
+ rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
+ }
+ ia->ia_flags |= IFA_ROUTE;
+ return (0);
+}
+
+/*
+ * Return address info for specified internet network.
+ */
+struct ipx_ifaddr *
+ipx_iaonnetof(dst)
+ register struct ipx_addr *dst;
+{
+ register struct ipx_ifaddr *ia;
+ register struct ipx_addr *compare;
+ register struct ifnet *ifp;
+ struct ipx_ifaddr *ia_maybe = 0;
+ union ipx_net net = dst->x_net;
+
+ for (ia = ipx_ifaddr; ia; ia = ia->ia_next) {
+ if ((ifp = ia->ia_ifp)) {
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ compare = &satoipx_addr(ia->ia_dstaddr);
+ if (ipx_hosteq(*dst, *compare))
+ return (ia);
+ if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
+ ia_maybe = ia;
+ } else {
+ if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
+ return (ia);
+ }
+ }
+ }
+ return (ia_maybe);
+}
+#endif
diff --git a/sys/netipx/ipx.h b/sys/netipx/ipx.h
new file mode 100644
index 0000000..e6dab3f
--- /dev/null
+++ b/sys/netipx/ipx.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx.h
+ */
+
+#ifndef _NETIPX_IPX_H_
+#define _NETIPX_IPX_H_
+
+/*
+ * Constants and Structures
+ */
+
+/*
+ * Protocols
+ */
+#define IPXPROTO_UNKWN 0 /* Unknown */
+#define IPXPROTO_RI 1 /* RIP Routing Information */
+#define IPXPROTO_ECHO 2 /* Echo Protocol */
+#define IPXPROTO_ERROR 3 /* Error Protocol */
+#define IPXPROTO_PXP 4 /* PXP Packet Exchange */
+#define IPXPROTO_SPX 5 /* SPX Sequenced Packet */
+#define IPXPROTO_NCP 17 /* NCP NetWare Core */
+#define IPXPROTO_RAW 255 /* Placemarker*/
+#define IPXPROTO_MAX 256 /* Placemarker*/
+
+/*
+ * Port/Socket numbers: network standard functions
+ */
+
+#define IPXPORT_RI 1 /* NS RIP Routing Information */
+#define IPXPORT_ECHO 2 /* NS Echo */
+#define IPXPORT_RE 3 /* NS Router Error */
+#define IPXPORT_FSP 0x0451 /* NW FSP File Service */
+#define IPXPORT_SAP 0x0452 /* NW SAP Service Advertising */
+#define IPXPORT_RIP 0x0453 /* NW RIP Routing Information */
+#define IPXPORT_NETBIOS 0x0455 /* NW NetBIOS */
+#define IPXPORT_DIAGS 0x0456 /* NW Diagnostics */
+#define IPXPORT_WDOG 0x4001 /* NW Watchdog Packets */
+#define IPXPORT_SHELL 0x4003 /* NW Shell Socket */
+#define IPXPORT_MAX 0x8000 /* Maximum User Addressable Port */
+
+/* flags passed to ipx_outputfl as last parameter */
+
+#define IPX_FORWARDING 0x1 /* most of ipx header exists */
+#define IPX_ROUTETOIF 0x10 /* same as SO_DONTROUTE */
+#define IPX_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */
+
+#define IPX_MAXHOPS 15
+
+/* flags passed to get/set socket option */
+#define SO_HEADERS_ON_INPUT 1
+#define SO_HEADERS_ON_OUTPUT 2
+#define SO_DEFAULT_HEADERS 3
+#define SO_LAST_HEADER 4
+#define SO_IPXIP_ROUTE 5
+#define SO_SEQNO 6
+#define SO_ALL_PACKETS 7
+#define SO_MTU 8
+#define SO_IPXTUN_ROUTE 9
+
+/*
+ * IPX addressing
+ */
+union ipx_host {
+ u_char c_host[6];
+ u_short s_host[3];
+};
+
+union ipx_net {
+ u_char c_net[4];
+ u_short s_net[2];
+};
+
+union ipx_net_u {
+ union ipx_net net_e;
+ u_long long_e;
+};
+
+struct ipx_addr {
+ union ipx_net x_net;
+ union ipx_host x_host;
+ u_short x_port;
+};
+
+/*
+ * Socket address
+ */
+struct sockaddr_ipx {
+ u_char sipx_len;
+ u_char sipx_family;
+ struct ipx_addr sipx_addr;
+ char sipx_zero[2];
+};
+#define sipx_port sipx_addr.x_port
+
+/*
+ * Definitions for IPX Internet Datagram Protocol
+ */
+struct ipx {
+ u_short ipx_sum; /* Checksum */
+ u_short ipx_len; /* Length, in bytes, including header */
+ u_char ipx_tc; /* Transport Crontrol (i.e. hop count) */
+ u_char ipx_pt; /* Packet Type (i.e. level 2 protocol) */
+ struct ipx_addr ipx_dna; /* Destination Network Address */
+ struct ipx_addr ipx_sna; /* Source Network Address */
+};
+
+#ifdef vax
+#define ipx_netof(a) (*(long *) & ((a).x_net)) /* XXX - not needed */
+#endif
+#define ipx_neteqnn(a,b) \
+ (((a).s_net[0]==(b).s_net[0]) && ((a).s_net[1]==(b).s_net[1]))
+#define ipx_neteq(a,b) ipx_neteqnn((a).x_net, (b).x_net)
+#define satoipx_addr(sa) (((struct sockaddr_ipx *)&(sa))->sipx_addr)
+#define ipx_hosteqnh(s,t) ((s).s_host[0] == (t).s_host[0] && \
+ (s).s_host[1] == (t).s_host[1] && (s).s_host[2] == (t).s_host[2])
+#define ipx_hosteq(s,t) (ipx_hosteqnh((s).x_host,(t).x_host))
+#define ipx_nullnet(x) (((x).x_net.s_net[0]==0) && ((x).x_net.s_net[1]==0))
+#define ipx_nullhost(x) (((x).x_host.s_host[0]==0) && \
+ ((x).x_host.s_host[1]==0) && ((x).x_host.s_host[2]==0))
+#define ipx_wildnet(x) (((x).x_net.s_net[0]==0xffff) && \
+ ((x).x_net.s_net[1]==0xffff))
+#define ipx_wildhost(x) (((x).x_host.s_host[0]==0xffff) && \
+ ((x).x_host.s_host[1]==0xffff) && ((x).x_host.s_host[2]==0xffff))
+
+#ifdef KERNEL
+
+extern int ipxcksum;
+extern struct domain ipxdomain;
+extern struct sockaddr_ipx ipx_netmask;
+extern struct sockaddr_ipx ipx_hostmask;
+
+extern union ipx_host ipx_thishost;
+extern union ipx_net ipx_zeronet;
+extern union ipx_host ipx_zerohost;
+extern union ipx_net ipx_broadnet;
+extern union ipx_host ipx_broadhost;
+
+extern long ipx_pexseq;
+extern u_char ipxctlerrmap[];
+extern struct ipxpcb ipxrawpcb;
+
+
+u_short ipx_cksum();
+void ipx_input(), ipx_abort(), ipx_drop();
+int ipx_output(), ipx_ctloutput(), ipx_usrreq();
+int ipx_raw_usrreq(), ipx_control(), ipx_do_route();
+void ipx_init(), ipxintr(), ipx_ctlinput(), ipx_forward();
+void ipx_undo_route(), ipx_watch_output();
+int ipx_outputfl();
+
+int ipxip_route();
+#else
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern struct ipx_addr ipx_addr __P((const char *));
+extern char *ipx_ntoa __P((struct ipx_addr));
+extern char *_ns_spectHex __P((const char *));
+__END_DECLS
+
+#endif
+
+#endif
diff --git a/sys/netipx/ipx_cksum.c b/sys/netipx/ipx_cksum.c
new file mode 100644
index 0000000..6db3c60
--- /dev/null
+++ b/sys/netipx/ipx_cksum.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1982, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_cksum.c
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+/*
+ * Checksum routine for Network Systems Protocol Packets (Big-Endian).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ */
+
+#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; }
+#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);}
+
+u_short
+ipx_cksum(m, len)
+ register struct mbuf *m;
+ register int len;
+{
+ register u_short *w;
+ register int sum = 0;
+ register int mlen = 0;
+ register int sum2;
+
+ union {
+ u_short s[2];
+ long l;
+ } l_util;
+
+ for (;m && len; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ /*
+ * Each trip around loop adds in
+ * word from one mbuf segment.
+ */
+ w = mtod(m, u_short *);
+ if (mlen == -1) {
+ /*
+ * There is a byte left from the last segment;
+ * ones-complement add it into the checksum.
+ */
+#if BYTE_ORDER == BIG_ENDIAN
+ sum += *(u_char *)w;
+#else
+ sum += *(u_char *)w << 8;
+#endif
+ sum += sum;
+ w = (u_short *)(1 + (char *)w);
+ mlen = m->m_len - 1;
+ len--;
+ FOLD(sum);
+ } else
+ mlen = m->m_len;
+ if (len < mlen)
+ mlen = len;
+ len -= mlen;
+ /*
+ * We can do a 16 bit ones complement sum using
+ * 32 bit arithmetic registers for adding,
+ * with carries from the low added
+ * into the high (by normal carry-chaining)
+ * so long as we fold back before 16 carries have occured.
+ */
+ if (1 & (int) w)
+ goto uuuuglyy;
+#ifndef TINY
+/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */
+ while ((mlen -= 32) >= 0) {
+ sum += w[0]; sum += sum; sum += w[1]; sum += sum;
+ sum += w[2]; sum += sum; sum += w[3]; sum += sum;
+ sum += w[4]; sum += sum; sum += w[5]; sum += sum;
+ sum += w[6]; sum += sum; sum += w[7]; sum += sum;
+ FOLD(sum);
+ sum += w[8]; sum += sum; sum += w[9]; sum += sum;
+ sum += w[10]; sum += sum; sum += w[11]; sum += sum;
+ sum += w[12]; sum += sum; sum += w[13]; sum += sum;
+ sum += w[14]; sum += sum; sum += w[15]; sum += sum;
+ FOLD(sum);
+ w += 16;
+ }
+ mlen += 32;
+#endif
+ while ((mlen -= 8) >= 0) {
+ sum += w[0]; sum += sum; sum += w[1]; sum += sum;
+ sum += w[2]; sum += sum; sum += w[3]; sum += sum;
+ FOLD(sum);
+ w += 4;
+ }
+ mlen += 8;
+ while ((mlen -= 2) >= 0) {
+ sum += *w++; sum += sum;
+ }
+ goto commoncase;
+uuuuglyy:
+#if BYTE_ORDER == BIG_ENDIAN
+#define ww(n) (((u_char *)w)[n + n + 1])
+#define vv(n) (((u_char *)w)[n + n])
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define vv(n) (((u_char *)w)[n + n + 1])
+#define ww(n) (((u_char *)w)[n + n])
+#endif
+#endif
+ sum2 = 0;
+#ifndef TINY
+ while ((mlen -= 32) >= 0) {
+ sum += ww(0); sum += sum; sum += ww(1); sum += sum;
+ sum += ww(2); sum += sum; sum += ww(3); sum += sum;
+ sum += ww(4); sum += sum; sum += ww(5); sum += sum;
+ sum += ww(6); sum += sum; sum += ww(7); sum += sum;
+ FOLD(sum);
+ sum += ww(8); sum += sum; sum += ww(9); sum += sum;
+ sum += ww(10); sum += sum; sum += ww(11); sum += sum;
+ sum += ww(12); sum += sum; sum += ww(13); sum += sum;
+ sum += ww(14); sum += sum; sum += ww(15); sum += sum;
+ FOLD(sum);
+ sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
+ sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
+ sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2;
+ sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2;
+ FOLD(sum2);
+ sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2;
+ sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2;
+ sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2;
+ sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2;
+ FOLD(sum2);
+ w += 16;
+ }
+ mlen += 32;
+#endif
+ while ((mlen -= 8) >= 0) {
+ sum += ww(0); sum += sum; sum += ww(1); sum += sum;
+ sum += ww(2); sum += sum; sum += ww(3); sum += sum;
+ FOLD(sum);
+ sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
+ sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
+ FOLD(sum2);
+ w += 4;
+ }
+ mlen += 8;
+ while ((mlen -= 2) >= 0) {
+ sum += ww(0); sum += sum;
+ sum2 += vv(0); sum2 += sum2;
+ w++;
+ }
+ sum += (sum2 << 8);
+commoncase:
+ if (mlen == -1) {
+#if BYTE_ORDER == BIG_ENDIAN
+ sum += *(u_char *)w << 8;
+#else
+ sum += *(u_char *)w;
+#endif
+ }
+ FOLD(sum);
+ }
+ if (mlen == -1) {
+ /* We had an odd number of bytes to sum; assume a garbage
+ byte of zero and clean up */
+ sum += sum;
+ FOLD(sum);
+ }
+ /*
+ * sum has already been kept to low sixteen bits.
+ * just examine result and exit.
+ */
+ if(sum==0xffff) sum = 0;
+ return (sum);
+}
diff --git a/sys/netipx/ipx_error.c b/sys/netipx/ipx_error.c
new file mode 100644
index 0000000..3c06e8e
--- /dev/null
+++ b/sys/netipx/ipx_error.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_error.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netipx/ipx.h>
+#include <netipx/spx.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx_error.h>
+
+/*
+ * IPX_ERR routines: error generation, receive packet processing, and
+ * routines to turnaround packets back to the originator.
+ */
+#ifndef IPX_ERRPRINTFS
+#define IPX_ERRPRINTFS 0
+#endif
+int ipx_errprintfs = IPX_ERRPRINTFS;
+
+struct ipx_errstat ipx_errstat;
+
+int
+ipx_err_x(c)
+int c;
+{
+ register u_short *w, *lim, *base = ipx_errstat.ipx_es_codes;
+ u_short x = c;
+
+ /*
+ * zero is a legit error code, handle specially
+ */
+ if (x == 0)
+ return (0);
+ lim = base + IPX_ERR_MAX - 1;
+ for (w = base + 1; w < lim; w++) {
+ if (*w == 0)
+ *w = x;
+ if (*w == x)
+ break;
+ }
+ return (w - base);
+}
+
+/*
+ * Generate an error packet of type error
+ * in response to bad packet.
+ */
+
+void
+ipx_error(om, type, param)
+ struct mbuf *om;
+ int type, param;
+{
+ register struct ipx_epipx *ep;
+ struct mbuf *m;
+ struct ipx *nip;
+ register struct ipx *oip = mtod(om, struct ipx *);
+
+ /*
+ * If this packet was sent to the echo port,
+ * and nobody was there, just echo it.
+ * (Yes, this is a wart!)
+ */
+ if (type == IPX_ERR_NOSOCK &&
+ oip->ipx_dna.x_port == htons(2) &&
+ (type = ipx_echo(om))==0)
+ return;
+
+ if (ipx_errprintfs)
+ printf("ipx_error(%x, %u, %d)\n", oip, type, param);
+
+ /*
+ * Don't Generate error packets in response to multicasts.
+ */
+ if (oip->ipx_dna.x_host.c_host[0] & 1)
+ goto freeit;
+
+ ipx_errstat.ipx_es_error++;
+ /*
+ * Make sure that the old IPX packet had 30 bytes of data to return;
+ * if not, don't bother. Also don't EVER error if the old
+ * packet protocol was IPX_ERR.
+ */
+ if (oip->ipx_len < sizeof(struct ipx)) {
+ ipx_errstat.ipx_es_oldshort++;
+ goto freeit;
+ }
+ if (oip->ipx_pt == IPXPROTO_ERROR) {
+ ipx_errstat.ipx_es_oldipx_err++;
+ goto freeit;
+ }
+
+ /*
+ * First, formulate ipx_err message
+ */
+ m = m_gethdr(M_DONTWAIT, MT_HEADER);
+ if (m == NULL)
+ goto freeit;
+ m->m_len = sizeof(*ep);
+ MH_ALIGN(m, m->m_len);
+ ep = mtod(m, struct ipx_epipx *);
+ if ((u_int)type > IPX_ERR_TOO_BIG)
+ panic("ipx_err_error");
+ ipx_errstat.ipx_es_outhist[ipx_err_x(type)]++;
+ ep->ipx_ep_errp.ipx_err_num = htons((u_short)type);
+ ep->ipx_ep_errp.ipx_err_param = htons((u_short)param);
+ bcopy((caddr_t)oip, (caddr_t)&ep->ipx_ep_errp.ipx_err_ipx, 42);
+ nip = &ep->ipx_ep_ipx;
+ nip->ipx_len = sizeof(*ep);
+ nip->ipx_len = htons((u_short)nip->ipx_len);
+ nip->ipx_pt = IPXPROTO_ERROR;
+ nip->ipx_tc = 0;
+ nip->ipx_dna = oip->ipx_sna;
+ nip->ipx_sna = oip->ipx_dna;
+ if (ipxcksum) {
+ nip->ipx_sum = 0;
+ nip->ipx_sum = ipx_cksum(m, sizeof(*ep));
+ } else
+ nip->ipx_sum = 0xffff;
+ (void) ipx_outputfl(m, (struct route *)0, 0);
+
+freeit:
+ m_freem(om);
+}
+
+void
+ipx_printhost(addr)
+register struct ipx_addr *addr;
+{
+ u_short port;
+ struct ipx_addr work = *addr;
+ register char *p; register u_char *q;
+ register char *net = "", *host = "";
+ char cport[10], chost[15], cnet[15];
+
+ port = ntohs(work.x_port);
+
+ if (ipx_nullnet(work) && ipx_nullhost(work)) {
+
+ if (port)
+ printf("*.%x", port);
+ else
+ printf("*.*");
+
+ return;
+ }
+
+ if (ipx_wildnet(work))
+ net = "any";
+ else if (ipx_nullnet(work))
+ net = "*";
+ else {
+ q = work.x_net.c_net;
+ sprintf(cnet, "%x%x%x%x",
+ q[0], q[1], q[2], q[3]);
+ for (p = cnet; *p == '0' && p < cnet + 8; p++)
+ continue;
+ net = p;
+ }
+
+ if (ipx_wildhost(work))
+ host = "any";
+ else if (ipx_nullhost(work))
+ host = "*";
+ else {
+ q = work.x_host.c_host;
+ sprintf(chost, "%x%x%x%x%x%x",
+ q[0], q[1], q[2], q[3], q[4], q[5]);
+ for (p = chost; *p == '0' && p < chost + 12; p++)
+ continue;
+ host = p;
+ }
+
+ if (port) {
+ if (strcmp(host, "*") == 0) {
+ host = "";
+ sprintf(cport, "%x", port);
+ } else
+ sprintf(cport, ".%x", port);
+ } else
+ *cport = 0;
+
+ printf("%s.%s%s", net, host, cport);
+}
+
+/*
+ * Process a received IPX_ERR message.
+ */
+void
+ipx_err_input(m)
+ struct mbuf *m;
+{
+ register struct ipx_errp *ep;
+ register struct ipx_epipx *epipx = mtod(m, struct ipx_epipx *);
+ register int i;
+ int type, code, param;
+
+ /*
+ * Locate ipx_err structure in mbuf, and check
+ * that not corrupted and of at least minimum length.
+ */
+
+ if (ipx_errprintfs) {
+ printf("ipx_err_input ");
+ ipx_printhost(&epipx->ipx_ep_ipx.ipx_sna);
+ printf("%d\n", ntohs(epipx->ipx_ep_ipx.ipx_len));
+ }
+
+ i = sizeof (struct ipx_epipx);
+ if (((m->m_flags & M_EXT) || m->m_len < i) &&
+ (m = m_pullup(m, i)) == 0) {
+ ipx_errstat.ipx_es_tooshort++;
+ return;
+ }
+ ep = &(mtod(m, struct ipx_epipx *)->ipx_ep_errp);
+ type = ntohs(ep->ipx_err_num);
+ param = ntohs(ep->ipx_err_param);
+ ipx_errstat.ipx_es_inhist[ipx_err_x(type)]++;
+
+ /*
+ * Message type specific processing.
+ */
+ if (ipx_errprintfs)
+ printf("ipx_err_input, type %d param %d\n", type, param);
+
+ if (type >= IPX_ERR_TOO_BIG) {
+ goto badcode;
+ }
+ ipx_errstat.ipx_es_outhist[ipx_err_x(type)]++;
+ switch (type) {
+
+ case IPX_ERR_UNREACH_HOST:
+ code = PRC_UNREACH_NET;
+ goto deliver;
+
+ case IPX_ERR_TOO_OLD:
+ code = PRC_TIMXCEED_INTRANS;
+ goto deliver;
+
+ case IPX_ERR_TOO_BIG:
+ code = PRC_MSGSIZE;
+ goto deliver;
+
+ case IPX_ERR_FULLUP:
+ code = PRC_QUENCH;
+ goto deliver;
+
+ case IPX_ERR_NOSOCK:
+ code = PRC_UNREACH_PORT;
+ goto deliver;
+
+ case IPX_ERR_UNSPEC_T:
+ case IPX_ERR_BADSUM_T:
+ case IPX_ERR_BADSUM:
+ case IPX_ERR_UNSPEC:
+ code = PRC_PARAMPROB;
+ goto deliver;
+
+ deliver:
+ /*
+ * Problem with datagram; advise higher level routines.
+ */
+
+ if (ipx_errprintfs)
+ printf("deliver to protocol %d\n",
+ ep->ipx_err_ipx.ipx_pt);
+
+ switch(ep->ipx_err_ipx.ipx_pt) {
+ case IPXPROTO_SPX:
+ spx_ctlinput(code, (caddr_t)ep);
+ break;
+
+ default:
+ ipx_ctlinput(code, (caddr_t)ep);
+ }
+
+ goto freeit;
+
+ default:
+ badcode:
+ ipx_errstat.ipx_es_badcode++;
+ goto freeit;
+
+ }
+freeit:
+ m_freem(m);
+}
+
+#ifdef notdef
+u_long
+ipxtime()
+{
+ int s = splclock();
+ u_long t;
+
+ t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
+ splx(s);
+ return (htonl(t));
+}
+#endif
+
+int
+ipx_echo(m)
+struct mbuf *m;
+{
+ register struct ipx *ipx = mtod(m, struct ipx *);
+ register struct echo {
+ struct ipx ec_ipx;
+ u_short ec_op; /* Operation, 1 = request, 2 = reply */
+ } *ec = (struct echo *)ipx;
+ struct ipx_addr temp;
+
+ if (ipx->ipx_pt!=IPXPROTO_ECHO)
+ return(IPX_ERR_NOSOCK);
+ if (ec->ec_op!=htons(1))
+ return(IPX_ERR_UNSPEC);
+
+ ec->ec_op = htons(2);
+
+ temp = ipx->ipx_dna;
+ ipx->ipx_dna = ipx->ipx_sna;
+ ipx->ipx_sna = temp;
+
+ if (ipxcksum && ipx->ipx_sum != 0xffff) {
+ ipx->ipx_sum = 0;
+ ipx->ipx_sum = ipx_cksum(m,
+ (int)(((ntohs(ipx->ipx_len) - 1)|1)+1));
+ }
+ else
+ ipx->ipx_sum = 0xffff;
+
+ (void) ipx_outputfl(m, (struct route *)0, IPX_FORWARDING);
+
+ return(0);
+}
diff --git a/sys/netipx/ipx_error.h b/sys/netipx/ipx_error.h
new file mode 100644
index 0000000..946438c
--- /dev/null
+++ b/sys/netipx/ipx_error.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_error.h
+ */
+
+#ifndef _NETIPX_IPX_ERROR_H_
+#define _NETIPX_IPX_ERROR_H_
+
+/*
+ * IPX error messages
+ */
+
+struct ipx_errp {
+ u_short ipx_err_num; /* Error Number */
+ u_short ipx_err_param; /* Error Parameter */
+ struct ipx ipx_err_ipx; /* Initial segment of offending
+ packet */
+ u_char ipx_err_lev2[12]; /* at least this much higher
+ level protocol */
+};
+struct ipx_epipx {
+ struct ipx ipx_ep_ipx;
+ struct ipx_errp ipx_ep_errp;
+};
+
+#define IPX_ERR_UNSPEC 0 /* Unspecified Error detected at dest. */
+#define IPX_ERR_BADSUM 1 /* Bad Checksum detected at dest */
+#define IPX_ERR_NOSOCK 2 /* Specified socket does not exist at dest*/
+#define IPX_ERR_FULLUP 3 /* Dest. refuses packet due to resource lim.*/
+#define IPX_ERR_UNSPEC_T 0x200 /* Unspec. Error occured before reaching dest*/
+#define IPX_ERR_BADSUM_T 0x201 /* Bad Checksum detected in transit */
+#define IPX_ERR_UNREACH_HOST 0x202 /* Dest cannot be reached from here*/
+#define IPX_ERR_TOO_OLD 0x203 /* Packet x'd 15 routers without delivery*/
+#define IPX_ERR_TOO_BIG 0x204 /* Packet too large to be forwarded through
+ some intermediate gateway. The error
+ parameter field contains the max packet
+ size that can be accommodated */
+#define IPX_ERR_MAX 20
+
+/*
+ * Variables related to this implementation
+ * of the network systems error message protocol.
+ */
+struct ipx_errstat {
+/* statistics related to ipx_err packets generated */
+ int ipx_es_error; /* # of calls to ipx_error */
+ int ipx_es_oldshort; /* no error 'cuz old ip too short */
+ int ipx_es_oldipx_err; /* no error 'cuz old was ipx_err */
+ int ipx_es_outhist[IPX_ERR_MAX];
+/* statistics related to input messages processed */
+ int ipx_es_badcode; /* ipx_err_code out of range */
+ int ipx_es_tooshort; /* packet < IPX_MINLEN */
+ int ipx_es_checksum; /* bad checksum */
+ int ipx_es_badlen; /* calculated bound mismatch */
+ int ipx_es_reflect; /* number of responses */
+ int ipx_es_inhist[IPX_ERR_MAX];
+ u_short ipx_es_codes[IPX_ERR_MAX];/* which error code for outhist
+ since we might not know all */
+};
+
+#ifdef KERNEL
+extern struct ipx_errstat ipx_errstat;
+int ipx_err_x(), ipx_echo();
+void ipx_error(), ipx_printhost(), ipx_err_input();
+#endif
+
+#endif
diff --git a/sys/netipx/ipx_if.h b/sys/netipx/ipx_if.h
new file mode 100644
index 0000000..f6e0f70
--- /dev/null
+++ b/sys/netipx/ipx_if.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_if.h
+ */
+
+#ifndef _NETIPX_IPX_IF_H_
+#define _NETIPX_IPX_IF_H_
+
+/*
+ * Interface address. One of these structures
+ * is allocated for each interface with an internet address.
+ * The ifaddr structure contains the protocol-independent part
+ * of the structure and is assumed to be first.
+ */
+
+struct ipx_ifaddr {
+ struct ifaddr ia_ifa; /* protocol-independent info */
+#define ia_ifp ia_ifa.ifa_ifp
+#define ia_flags ia_ifa.ifa_flags
+ struct ipx_ifaddr *ia_next; /* next in list of ipx addresses */
+ struct sockaddr_ipx ia_addr; /* reserve space for my address */
+ struct sockaddr_ipx ia_dstaddr; /* space for my broadcast address */
+#define ia_broadaddr ia_dstaddr
+ struct sockaddr_ipx ia_netmask; /* space for my network mask */
+};
+
+struct ipx_aliasreq {
+ char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ struct sockaddr_ipx ifra_addr;
+ struct sockaddr_ipx ifra_broadaddr;
+#define ifra_dstaddr ifra_broadaddr
+};
+/*
+ * Given a pointer to an ipx_ifaddr (ifaddr),
+ * return a pointer to the addr as a sockadd_ipx.
+ */
+
+#define IA_SIPX(ia) (&(((struct ipx_ifaddr *)(ia))->ia_addr))
+
+/* This is not the right place for this but where is? */
+#define ETHERTYPE_IPX 0x8137
+
+#ifdef IPXIP
+struct ipxip_req {
+ struct sockaddr rq_ipx; /* must be ipx format destination */
+ struct sockaddr rq_ip; /* must be ip format gateway */
+ short rq_flags;
+};
+#endif
+
+#ifdef KERNEL
+extern struct ifqueue ipxintrq; /* IPX input packet queue */
+extern struct ipx_ifaddr *ipx_ifaddr;
+int ipx_ifinit();
+void ipx_ifscrub();
+struct ipx_ifaddr *ipx_iaonnetof();
+#endif
+
+#endif
diff --git a/sys/netipx/ipx_input.c b/sys/netipx/ipx_input.c
new file mode 100644
index 0000000..6b8c5b5
--- /dev/null
+++ b/sys/netipx/ipx_input.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_input.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/raw_cb.h>
+
+#include <netipx/ipx.h>
+#include <netipx/spx.h>
+#include <netipx/ipx_if.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx_var.h>
+#include <netipx/ipx_error.h>
+
+#ifndef IPXFORWARDING
+#ifdef GATEWAY
+#define IPXFORWARDING 1 /* forward IPX packets not for us */
+#else
+#define IPXFORWARDING 0 /* don't forward IPX packets not for us */
+#endif
+#endif
+#ifndef IPXPRINTFS
+#define IPXPRINTFS 1 /* printing forwarding information */
+#endif
+
+#ifndef IPXCKSUM
+#define IPXCKSUM 0 /* perform IPX checksum */
+#endif
+
+#ifndef IXDONOSOCKS
+#define IPXDONOSOCKS 0 /* return no socket errors */
+#endif
+
+int ipxcksum = IPXCKSUM;
+int ipxprintfs = IPXPRINTFS;
+int ipxdonosocks = IPXDONOSOCKS;
+int ipxforwarding = IPXFORWARDING;
+
+union ipx_host ipx_thishost;
+union ipx_net ipx_zeronet;
+union ipx_host ipx_zerohost;
+
+union ipx_net ipx_broadnet;
+union ipx_host ipx_broadhost;
+
+struct ipxstat ipxstat;
+struct sockaddr_ipx ipx_netmask, ipx_hostmask;
+
+int ipxintr_getpck = 0;
+int ipxintr_swtch = 0;
+
+static u_short allones[] = {-1, -1, -1};
+
+struct ipxpcb ipxpcb;
+struct ipxpcb ipxrawpcb;
+
+struct ifqueue ipxintrq;
+int ipxqmaxlen = IFQ_MAXLEN;
+
+long ipx_pexseq;
+
+NETISR_SET(NETISR_IPX, ipxintr);
+
+/*
+ * IPX initialization.
+ */
+
+void
+ipx_init()
+{
+ ipx_broadnet = * (union ipx_net *) allones;
+ ipx_broadhost = * (union ipx_host *) allones;
+
+ ipx_pexseq = time.tv_usec;
+ ipxintrq.ifq_maxlen = ipxqmaxlen;
+ ipxpcb.ipxp_next = ipxpcb.ipxp_prev = &ipxpcb;
+ ipxrawpcb.ipxp_next = ipxrawpcb.ipxp_prev = &ipxrawpcb;
+
+ ipx_netmask.sipx_len = 6;
+ ipx_netmask.sipx_addr.x_net = ipx_broadnet;
+
+ ipx_hostmask.sipx_len = 12;
+ ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
+ ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
+}
+
+/*
+ * IPX input routine. Pass to next level.
+ */
+void
+ipxintr()
+{
+ register struct ipx *ipx;
+ register struct mbuf *m;
+ register struct ipxpcb *ipxp;
+ register int i;
+ int len, s, error;
+ char oddpacketp;
+
+next:
+ /*
+ * Get next datagram off input queue and get IPX header
+ * in first mbuf.
+ */
+ s = splimp();
+ IF_DEQUEUE(&ipxintrq, m);
+ splx(s);
+ ipxintr_getpck++;
+ if (m == 0)
+ return;
+ if ((m->m_flags & M_EXT || m->m_len < sizeof (struct ipx)) &&
+ (m = m_pullup(m, sizeof (struct ipx))) == 0) {
+ ipxstat.ipxs_toosmall++;
+ goto next;
+ }
+
+ /*
+ * Give any raw listeners a crack at the packet
+ */
+ for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) {
+ struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
+ if (m1) ipx_input(m1, ipxp);
+ }
+
+ ipx = mtod(m, struct ipx *);
+ len = ntohs(ipx->ipx_len);
+ if (oddpacketp = len & 1) {
+ len++; /* If this packet is of odd length,
+ preserve garbage byte for checksum */
+ }
+
+ /*
+ * Check that the amount of data in the buffers
+ * is as at least much as the IPX header would have us expect.
+ * Trim mbufs if longer than we expect.
+ * Drop packet if shorter than we expect.
+ */
+ if (m->m_pkthdr.len < len) {
+ ipxstat.ipxs_tooshort++;
+ goto bad;
+ }
+ if (m->m_pkthdr.len > len) {
+ if (m->m_len == m->m_pkthdr.len) {
+ m->m_len = len;
+ m->m_pkthdr.len = len;
+ } else
+ m_adj(m, len - m->m_pkthdr.len);
+ }
+ if (ipxcksum && ((i = ipx->ipx_sum)!=0xffff)) {
+ ipx->ipx_sum = 0;
+ if (i != (ipx->ipx_sum = ipx_cksum(m, len))) {
+ ipxstat.ipxs_badsum++;
+ ipx->ipx_sum = i;
+ if (ipx_hosteqnh(ipx_thishost, ipx->ipx_dna.x_host))
+ error = IPX_ERR_BADSUM;
+ else
+ error = IPX_ERR_BADSUM_T;
+ ipx_error(m, error, 0);
+ goto next;
+ }
+ }
+ /*
+ * Is this a directed broadcast?
+ */
+ if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
+ if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
+ (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
+ (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
+ (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
+ /*
+ * Look to see if I need to eat this packet.
+ * Algorithm is to forward all young packets
+ * and prematurely age any packets which will
+ * by physically broadcasted.
+ * Any very old packets eaten without forwarding
+ * would die anyway.
+ *
+ * Suggestion of Bill Nesheim, Cornell U.
+ */
+ if (ipx->ipx_tc < IPX_MAXHOPS) {
+ ipx_forward(m);
+ goto next;
+ }
+ }
+ /*
+ * Is this our packet? If not, forward.
+ */
+ } else if (!ipx_hosteqnh(ipx_thishost,ipx->ipx_dna.x_host)) {
+ ipx_forward(m);
+ goto next;
+ }
+ /*
+ * Locate pcb for datagram.
+ */
+ ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
+ /*
+ * Switch out to protocol's input routine.
+ */
+ ipxintr_swtch++;
+ if (ipxp) {
+ if (oddpacketp) {
+ m_adj(m, -1);
+ }
+ if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS)==0)
+ switch (ipx->ipx_pt) {
+
+ case IPXPROTO_SPX:
+ spx_input(m, ipxp);
+ goto next;
+
+ case IPXPROTO_ERROR:
+ ipx_err_input(m);
+ goto next;
+ }
+ ipx_input(m, ipxp);
+ } else {
+ ipx_error(m, IPX_ERR_NOSOCK, 0);
+ }
+ goto next;
+
+bad:
+ m_freem(m);
+ goto next;
+}
+
+u_char ipxctlerrmap[PRC_NCMDS] = {
+ ECONNABORTED, ECONNABORTED, 0, 0,
+ 0, 0, EHOSTDOWN, EHOSTUNREACH,
+ ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
+ EMSGSIZE, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+void
+ipx_ctlinput(cmd, arg)
+ int cmd;
+ caddr_t arg;
+{
+ struct ipx_addr *ipx;
+ struct ipxpcb *ipxp;
+ struct ipx_errp *errp;
+ int type;
+
+ if (cmd < 0 || cmd > PRC_NCMDS)
+ return;
+ if (ipxctlerrmap[cmd] == 0)
+ return; /* XXX */
+ type = IPX_ERR_UNREACH_HOST;
+ errp = (struct ipx_errp *)arg;
+ switch (cmd) {
+ struct sockaddr_ipx *sipx;
+
+ case PRC_IFDOWN:
+ case PRC_HOSTDEAD:
+ case PRC_HOSTUNREACH:
+ sipx = (struct sockaddr_ipx *)arg;
+ if (sipx->sipx_family != AF_IPX)
+ return;
+ ipx = &sipx->sipx_addr;
+ break;
+
+ default:
+ ipx = &errp->ipx_err_ipx.ipx_dna;
+ type = errp->ipx_err_num;
+ type = ntohs((u_short)type);
+ break;
+ }
+ switch (type) {
+
+ case IPX_ERR_UNREACH_HOST:
+ ipx_pcbnotify(ipx, (int)ipxctlerrmap[cmd], ipx_abort, (long)0);
+ break;
+
+ case IPX_ERR_NOSOCK:
+ ipxp = ipx_pcblookup(ipx, errp->ipx_err_ipx.ipx_sna.x_port,
+ IPX_WILDCARD);
+ if(ipxp && ipxdonosocks && ! ipx_nullhost(ipxp->ipxp_faddr))
+ (void) ipx_drop(ipxp, (int)ipxctlerrmap[cmd]);
+ }
+}
+
+/*
+ * Forward a packet. If some error occurs return the sender
+ * an error packet. Note we can't always generate a meaningful
+ * error message because the IPX errors don't have a large enough repetoire
+ * of codes and types.
+ */
+struct route ipx_droute;
+struct route ipx_sroute;
+
+void
+ipx_forward(m)
+struct mbuf *m;
+{
+ register struct ipx *ipx = mtod(m, struct ipx *);
+ register int error, type, code;
+ struct mbuf *mcopy = NULL;
+ int agedelta = 1;
+ int flags = IPX_FORWARDING;
+ int ok_there = 0;
+ int ok_back = 0;
+
+ if (ipxforwarding == 0) {
+ /* can't tell difference between net and host */
+ type = IPX_ERR_UNREACH_HOST, code = 0;
+ goto senderror;
+ }
+ ipx->ipx_tc++;
+ if (ipx->ipx_tc > IPX_MAXHOPS) {
+ type = IPX_ERR_TOO_OLD, code = 0;
+ goto senderror;
+ }
+ /*
+ * Save at most 42 bytes of the packet in case
+ * we need to generate an IPX error message to the src.
+ */
+ mcopy = m_copy(m, 0, imin((int)ntohs(ipx->ipx_len), 42));
+
+ if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute))==0) {
+ type = IPX_ERR_UNREACH_HOST, code = 0;
+ goto senderror;
+ }
+ /*
+ * Here we think about forwarding broadcast packets,
+ * so we try to insure that it doesn't go back out
+ * on the interface it came in on. Also, if we
+ * are going to physically broadcast this, let us
+ * age the packet so we can eat it safely the second time around.
+ */
+ if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
+ struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
+ struct ifnet *ifp;
+ if (ia) {
+ /* I'm gonna hafta eat this packet */
+ agedelta += IPX_MAXHOPS - ipx->ipx_tc;
+ ipx->ipx_tc = IPX_MAXHOPS;
+ }
+ if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute))==0) {
+ /* error = ENETUNREACH; He'll never get it! */
+ m_freem(m);
+ goto cleanup;
+ }
+ if (ipx_droute.ro_rt &&
+ (ifp=ipx_droute.ro_rt->rt_ifp) &&
+ ipx_sroute.ro_rt &&
+ (ifp!=ipx_sroute.ro_rt->rt_ifp)) {
+ flags |= IPX_ALLOWBROADCAST;
+ } else {
+ type = IPX_ERR_UNREACH_HOST, code = 0;
+ goto senderror;
+ }
+ }
+ /* need to adjust checksum */
+ if (ipxcksum && ipx->ipx_sum != 0xffff) {
+ union bytes {
+ u_char c[4];
+ u_short s[2];
+ long l;
+ } x;
+ register int shift;
+ x.l = 0; x.c[0] = agedelta;
+ shift = (((((int)ntohs(ipx->ipx_len))+1)>>1)-2) & 0xf;
+ x.l = ipx->ipx_sum + (x.s[0] << shift);
+ x.l = x.s[0] + x.s[1];
+ x.l = x.s[0] + x.s[1];
+ if (x.l==0xffff) ipx->ipx_sum = 0; else ipx->ipx_sum = x.l;
+ } else
+ ipx->ipx_sum = 0xffff;
+
+ error = ipx_outputfl(m, &ipx_droute, flags);
+
+ if (ipxprintfs && !error) {
+ printf("forward: ");
+ ipx_printhost(&ipx->ipx_sna);
+ printf(" to ");
+ ipx_printhost(&ipx->ipx_dna);
+ printf(" hops %d\n", ipx->ipx_tc);
+ }
+
+ if (error && mcopy != NULL) {
+ ipx = mtod(mcopy, struct ipx *);
+ type = IPX_ERR_UNSPEC_T, code = 0;
+ switch (error) {
+
+ case ENETUNREACH:
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ case ENETDOWN:
+ case EPERM:
+ type = IPX_ERR_UNREACH_HOST;
+ break;
+
+ case EMSGSIZE:
+ type = IPX_ERR_TOO_BIG;
+ code = 576; /* too hard to figure out mtu here */
+ break;
+
+ case ENOBUFS:
+ type = IPX_ERR_UNSPEC_T;
+ break;
+ }
+ mcopy = NULL;
+ senderror:
+ ipx_error(m, type, code);
+ }
+cleanup:
+ if (ok_there)
+ ipx_undo_route(&ipx_droute);
+ if (ok_back)
+ ipx_undo_route(&ipx_sroute);
+ if (mcopy != NULL)
+ m_freem(mcopy);
+}
+
+int
+ipx_do_route(src, ro)
+struct ipx_addr *src;
+struct route *ro;
+{
+ struct sockaddr_ipx *dst;
+
+ bzero((caddr_t)ro, sizeof (*ro));
+ dst = (struct sockaddr_ipx *)&ro->ro_dst;
+
+ dst->sipx_len = sizeof(*dst);
+ dst->sipx_family = AF_IPX;
+ dst->sipx_addr = *src;
+ dst->sipx_addr.x_port = 0;
+ rtalloc(ro);
+ if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {
+ return (0);
+ }
+ ro->ro_rt->rt_use++;
+ return (1);
+}
+
+void
+ipx_undo_route(ro)
+register struct route *ro;
+{
+ if (ro->ro_rt) {RTFREE(ro->ro_rt);}
+}
+
+void
+ipx_watch_output(m, ifp)
+struct mbuf *m;
+struct ifnet *ifp;
+{
+ register struct ipxpcb *ipxp;
+ register struct ifaddr *ifa;
+ /*
+ * Give any raw listeners a crack at the packet
+ */
+ for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb; ipxp = ipxp->ipxp_next) {
+ struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
+ if (m0) {
+ register struct ipx *ipx;
+
+ M_PREPEND(m0, sizeof (*ipx), M_DONTWAIT);
+ if (m0 == NULL)
+ continue;
+ ipx = mtod(m0, struct ipx *);
+ ipx->ipx_sna.x_net = ipx_zeronet;
+ ipx->ipx_sna.x_host = ipx_thishost;
+ if (ifp && (ifp->if_flags & IFF_POINTOPOINT))
+ for(ifa = ifp->if_addrlist; ifa;
+ ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family==AF_IPX) {
+ ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr;
+ break;
+ }
+ }
+ ipx->ipx_len = ntohl(m0->m_pkthdr.len);
+ ipx_input(m0, ipxp);
+ }
+ }
+}
diff --git a/sys/netipx/ipx_ip.c b/sys/netipx/ipx_ip.c
new file mode 100644
index 0000000..f5e4e92
--- /dev/null
+++ b/sys/netipx/ipx_ip.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_ip.c
+ */
+
+/*
+ * Software interface driver for encapsulating IPX in IP.
+ */
+
+#ifdef IPXIP
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <machine/mtpr.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+struct ifnet_en {
+ struct ifnet ifen_ifnet;
+ struct route ifen_route;
+ struct in_addr ifen_src;
+ struct in_addr ifen_dst;
+ struct ifnet_en *ifen_next;
+};
+
+void ipxipstart();
+int ipxipoutput(), ipxipioctl();
+void ipxip_input();
+int ipxip_free();
+void ipxip_ctlinput();
+void ipxip_rtchange();
+
+#define LOMTU (1024+512);
+
+struct ifnet ipxipif;
+struct ifnet_en *ipxip_list; /* list of all hosts and gateways or broadcast addrs */
+
+struct ifnet_en *
+ipxipattach()
+{
+ register struct ifnet_en *m;
+ register struct ifnet *ifp;
+
+ if (ipxipif.if_mtu == 0) {
+ ifp = &ipxipif;
+ ifp->if_name = "ipxip";
+ ifp->if_mtu = LOMTU;
+ ifp->if_ioctl = ipxipioctl;
+ ifp->if_output = ipxipoutput;
+ ifp->if_start = ipxipstart;
+ ifp->if_flags = IFF_POINTOPOINT;
+ }
+
+ MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT);
+ if (m == NULL) return (NULL);
+ m->ifen_next = ipxip_list;
+ ipxip_list = m;
+ ifp = &m->ifen_ifnet;
+
+ ifp->if_name = "ipxip";
+ ifp->if_mtu = LOMTU;
+ ifp->if_ioctl = ipxipioctl;
+ ifp->if_output = ipxipoutput;
+ ifp->if_start = ipxipstart;
+ ifp->if_flags = IFF_POINTOPOINT;
+ ifp->if_unit = ipxipif.if_unit++;
+ if_attach(ifp);
+
+ return (m);
+}
+
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+int
+ipxipioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ int error = 0;
+ struct ifreq *ifr;
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ /* fall into: */
+
+ case SIOCSIFDSTADDR:
+ /*
+ * Everything else is done at a higher level.
+ */
+ break;
+
+ case SIOCSIFFLAGS:
+ ifr = (struct ifreq *)data;
+ if ((ifr->ifr_flags & IFF_UP) == 0)
+ error = ipxip_free(ifp);
+
+
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+struct mbuf *ipxip_badlen;
+struct mbuf *ipxip_lastin;
+int ipxip_hold_input;
+
+void
+ipxip_input(m, ifp)
+ register struct mbuf *m;
+ struct ifnet *ifp;
+{
+ register struct ip *ip;
+ register struct ipx *ipx;
+ register struct ifqueue *ifq = &ipxintrq;
+ int len, s;
+
+ if (ipxip_hold_input) {
+ if (ipxip_lastin) {
+ m_freem(ipxip_lastin);
+ }
+ ipxip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT);
+ }
+ /*
+ * Get IP and IPX header together in first mbuf.
+ */
+ ipxipif.if_ipackets++;
+ s = sizeof (struct ip) + sizeof (struct ipx);
+ if (((m->m_flags & M_EXT) || m->m_len < s) &&
+ (m = m_pullup(m, s)) == 0) {
+ ipxipif.if_ierrors++;
+ return;
+ }
+ ip = mtod(m, struct ip *);
+ if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
+ ip_stripoptions(m, (struct mbuf *)0);
+ if (m->m_len < s) {
+ if ((m = m_pullup(m, s)) == 0) {
+ ipxipif.if_ierrors++;
+ return;
+ }
+ ip = mtod(m, struct ip *);
+ }
+ }
+
+ /*
+ * Make mbuf data length reflect IPX length.
+ * If not enough data to reflect IPX length, drop.
+ */
+ m->m_data += sizeof (struct ip);
+ m->m_len -= sizeof (struct ip);
+ m->m_pkthdr.len -= sizeof (struct ip);
+ ipx = mtod(m, struct ipx *);
+ len = ntohs(ipx->ipx_len);
+ if (len & 1) len++; /* Preserve Garbage Byte */
+ if (ip->ip_len != len) {
+ if (len > ip->ip_len) {
+ ipxipif.if_ierrors++;
+ if (ipxip_badlen) m_freem(ipxip_badlen);
+ ipxip_badlen = m;
+ return;
+ }
+ /* Any extra will be trimmed off by the IPX routines */
+ }
+
+ /*
+ * Place interface pointer before the data
+ * for the receiving protocol.
+ */
+ m->m_pkthdr.rcvif = ifp;
+ /*
+ * Deliver to IPX
+ */
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq);
+bad:
+ m_freem(m);
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(NETISR_IPX);
+ splx(s);
+ return;
+}
+
+/* ARGSUSED */
+int
+ipxipoutput(ifn, m, dst)
+ struct ifnet_en *ifn;
+ register struct mbuf *m;
+ struct sockaddr *dst;
+{
+
+ register struct ip *ip;
+ register struct route *ro = &(ifn->ifen_route);
+ register int len = 0;
+ register struct ipx *ipx = mtod(m, struct ipx *);
+ int error;
+
+ ifn->ifen_ifnet.if_opackets++;
+ ipxipif.if_opackets++;
+
+ /*
+ * Calculate data length and make space
+ * for IP header.
+ */
+ len = ntohs(ipx->ipx_len);
+ if (len & 1) len++; /* Preserve Garbage Byte */
+ /* following clause not necessary on vax */
+ if (3 & (int)m->m_data) {
+ /* force longword alignment of ip hdr */
+ struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT);
+ if (m0 == 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ MH_ALIGN(m0, sizeof (struct ip));
+ m0->m_flags = m->m_flags & M_COPYFLAGS;
+ m0->m_next = m;
+ m0->m_len = sizeof (struct ip);
+ m0->m_pkthdr.len = m0->m_len + m->m_len;
+ m->m_flags &= ~M_PKTHDR;
+ } else {
+ M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
+ if (m == 0)
+ return (ENOBUFS);
+ }
+ /*
+ * Fill in IP header.
+ */
+ ip = mtod(m, struct ip *);
+ *(long *)ip = 0;
+ ip->ip_p = IPPROTO_IDP;
+ ip->ip_src = ifn->ifen_src;
+ ip->ip_dst = ifn->ifen_dst;
+ ip->ip_len = (u_short)len + sizeof (struct ip);
+ ip->ip_ttl = MAXTTL;
+
+ /*
+ * Output final datagram.
+ */
+ error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST, NULL));
+ if (error) {
+ ifn->ifen_ifnet.if_oerrors++;
+ ifn->ifen_ifnet.if_ierrors = error;
+ }
+ return (error);
+bad:
+ m_freem(m);
+ return (ENETUNREACH);
+}
+
+void
+ipxipstart(ifp)
+struct ifnet *ifp;
+{
+ panic("ipxip_start called\n");
+}
+
+struct ifreq ifr_ipxip = {"ipxip0"};
+
+int
+ipxip_route(m)
+ register struct mbuf *m;
+{
+ register struct ipxip_req *rq = mtod(m, struct ipxip_req *);
+ struct sockaddr_ipx *ipx_dst = (struct sockaddr_ipx *)&rq->rq_ipx;
+ struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
+ struct route ro;
+ struct ifnet_en *ifn;
+ struct sockaddr_in *src;
+
+ /*
+ * First, make sure we already have an IPX address:
+ */
+ if (ipx_hosteqnh(ipx_thishost, ipx_zerohost))
+ return (EADDRNOTAVAIL);
+ /*
+ * Now, determine if we can get to the destination
+ */
+ bzero((caddr_t)&ro, sizeof (ro));
+ ro.ro_dst = *(struct sockaddr *)ip_dst;
+ rtalloc(&ro);
+ if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
+ return (ENETUNREACH);
+ }
+
+ /*
+ * And see how he's going to get back to us:
+ * i.e., what return ip address do we use?
+ */
+ {
+ register struct in_ifaddr *ia;
+ struct ifnet *ifp = ro.ro_rt->rt_ifp;
+
+ for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0)
+ ia = in_ifaddr;
+ if (ia == 0) {
+ RTFREE(ro.ro_rt);
+ return (EADDRNOTAVAIL);
+ }
+ src = (struct sockaddr_in *)&ia->ia_addr;
+ }
+
+ /*
+ * Is there a free (pseudo-)interface or space?
+ */
+ for (ifn = ipxip_list; ifn; ifn = ifn->ifen_next) {
+ if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0)
+ break;
+ }
+ if (ifn == NULL)
+ ifn = ipxipattach();
+ if (ifn == NULL) {
+ RTFREE(ro.ro_rt);
+ return (ENOBUFS);
+ }
+ ifn->ifen_route = ro;
+ ifn->ifen_dst = ip_dst->sin_addr;
+ ifn->ifen_src = src->sin_addr;
+
+ /*
+ * now configure this as a point to point link
+ */
+ ifr_ipxip.ifr_name[4] = '0' + ipxipif.if_unit - 1;
+ ifr_ipxip.ifr_dstaddr = * (struct sockaddr *) ipx_dst;
+ (void)ipx_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr_ipxip,
+ (struct ifnet *)ifn);
+ satoipx_addr(ifr_ipxip.ifr_addr).x_host = ipx_thishost;
+ return (ipx_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr_ipxip,
+ (struct ifnet *)ifn));
+}
+
+int
+ipxip_free(ifp)
+struct ifnet *ifp;
+{
+ register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
+ struct route *ro = & ifn->ifen_route;
+
+ if (ro->ro_rt) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = 0;
+ }
+ ifp->if_flags &= ~IFF_UP;
+ return (0);
+}
+
+void
+ipxip_ctlinput(cmd, sa)
+ int cmd;
+ struct sockaddr *sa;
+{
+ /*extern u_char inetctlerrmap[]; */ /*XXX*/ /*JRE*/
+ struct sockaddr_in *sin;
+ /* int in_rtchange(); */ /*XXX*/ /*JRE*/
+
+ if ((unsigned)cmd >= PRC_NCMDS)
+ return;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
+ return;
+ sin = (struct sockaddr_in *)sa;
+ if (sin->sin_addr.s_addr == INADDR_ANY)
+ return;
+
+ switch (cmd) {
+
+ case PRC_ROUTEDEAD:
+ case PRC_REDIRECT_NET:
+ case PRC_REDIRECT_HOST:
+ case PRC_REDIRECT_TOSNET:
+ case PRC_REDIRECT_TOSHOST:
+ ipxip_rtchange(&sin->sin_addr);
+ break;
+ }
+}
+
+void
+ipxip_rtchange(dst)
+ register struct in_addr *dst;
+{
+ register struct ifnet_en *ifn;
+
+ for (ifn = ipxip_list; ifn; ifn = ifn->ifen_next) {
+ if (ifn->ifen_dst.s_addr == dst->s_addr &&
+ ifn->ifen_route.ro_rt) {
+ RTFREE(ifn->ifen_route.ro_rt);
+ ifn->ifen_route.ro_rt = 0;
+ }
+ }
+}
+#endif
diff --git a/sys/netipx/ipx_outputfl.c b/sys/netipx/ipx_outputfl.c
new file mode 100644
index 0000000..74fa9b5
--- /dev/null
+++ b/sys/netipx/ipx_outputfl.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_outputfl.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#include <netipx/ipx_var.h>
+
+#ifdef vax
+#include <machine/mtpr.h>
+#endif
+
+int ipx_hold_output = 0;
+int ipx_copy_output = 0;
+int ipx_outputfl_cnt = 0;
+struct mbuf *ipx_lastout;
+
+int
+ipx_outputfl(m0, ro, flags)
+ struct mbuf *m0;
+ struct route *ro;
+ int flags;
+{
+ register struct ipx *ipx = mtod(m0, struct ipx *);
+ register struct ifnet *ifp = 0;
+ int error = 0;
+ struct sockaddr_ipx *dst;
+ struct route ipxroute;
+
+ if (ipx_hold_output) {
+ if (ipx_lastout) {
+ (void)m_free(ipx_lastout);
+ }
+ ipx_lastout = m_copy(m0, 0, (int)M_COPYALL);
+ }
+ /*
+ * Route packet.
+ */
+ if (ro == 0) {
+ ro = &ipxroute;
+ bzero((caddr_t)ro, sizeof (*ro));
+ }
+ dst = (struct sockaddr_ipx *)&ro->ro_dst;
+ if (ro->ro_rt == 0) {
+ dst->sipx_family = AF_IPX;
+ dst->sipx_len = sizeof (*dst);
+ dst->sipx_addr = ipx->ipx_dna;
+ dst->sipx_addr.x_port = 0;
+ /*
+ * If routing to interface only,
+ * short circuit routing lookup.
+ */
+ if (flags & IPX_ROUTETOIF) {
+ struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
+
+ if (ia == 0) {
+ error = ENETUNREACH;
+ goto bad;
+ }
+ ifp = ia->ia_ifp;
+ goto gotif;
+ }
+ rtalloc(ro);
+ } else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
+ /*
+ * The old route has gone away; try for a new one.
+ */
+ rtfree(ro->ro_rt);
+ ro->ro_rt = NULL;
+ rtalloc(ro);
+ }
+ if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
+ error = ENETUNREACH;
+ goto bad;
+ }
+ ro->ro_rt->rt_use++;
+ if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
+ dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
+gotif:
+ /*
+ * Look for multicast addresses and
+ * and verify user is allowed to send
+ * such a packet.
+ */
+ if (dst->sipx_addr.x_host.c_host[0]&1) {
+ if ((ifp->if_flags & IFF_BROADCAST) == 0) {
+ error = EADDRNOTAVAIL;
+ goto bad;
+ }
+ if ((flags & IPX_ALLOWBROADCAST) == 0) {
+ error = EACCES;
+ goto bad;
+ }
+ }
+
+ if (htons(ipx->ipx_len) <= ifp->if_mtu) {
+ ipx_outputfl_cnt++;
+ if (ipx_copy_output) {
+ ipx_watch_output(m0, ifp);
+ }
+ error = (*ifp->if_output)(ifp, m0,
+ (struct sockaddr *)dst, ro->ro_rt);
+ goto done;
+ } else error = EMSGSIZE;
+bad:
+ if (ipx_copy_output) {
+ ipx_watch_output(m0, ifp);
+ }
+ m_freem(m0);
+done:
+ if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 && ro->ro_rt) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = 0;
+ }
+ return (error);
+}
diff --git a/sys/netipx/ipx_pcb.c b/sys/netipx/ipx_pcb.c
new file mode 100644
index 0000000..d2d625c
--- /dev/null
+++ b/sys/netipx/ipx_pcb.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_pcb.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#include <netipx/ipx_pcb.h>
+
+struct ipx_addr zeroipx_addr;
+
+int
+ipx_pcballoc(so, head)
+ struct socket *so;
+ struct ipxpcb *head;
+{
+ struct mbuf *m;
+ register struct ipxpcb *ipxp;
+
+ m = m_getclr(M_DONTWAIT, MT_PCB);
+ if (m == NULL)
+ return (ENOBUFS);
+ ipxp = mtod(m, struct ipxpcb *);
+ ipxp->ipxp_socket = so;
+ insque(ipxp, head);
+ so->so_pcb = (caddr_t)ipxp;
+ return (0);
+}
+
+int
+ipx_pcbbind(ipxp, nam)
+ register struct ipxpcb *ipxp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_ipx *sipx;
+ u_short lport = 0;
+
+ if (ipxp->ipxp_lport || !ipx_nullhost(ipxp->ipxp_laddr))
+ return (EINVAL);
+ if (nam == 0)
+ goto noname;
+ sipx = mtod(nam, struct sockaddr_ipx *);
+ if (nam->m_len != sizeof (*sipx))
+ return (EINVAL);
+ if (!ipx_nullhost(sipx->sipx_addr)) {
+ int tport = sipx->sipx_port;
+
+ sipx->sipx_port = 0; /* yech... */
+ if (ifa_ifwithaddr((struct sockaddr *)sipx) == 0)
+ return (EADDRNOTAVAIL);
+ sipx->sipx_port = tport;
+ }
+ lport = sipx->sipx_port;
+ if (lport) {
+ u_short aport = ntohs(lport);
+
+ if (aport < IPXPORT_MAX &&
+ (ipxp->ipxp_socket->so_state & SS_PRIV) == 0)
+ return (EACCES);
+ if (ipx_pcblookup(&zeroipx_addr, lport, 0))
+ return (EADDRINUSE);
+ }
+ ipxp->ipxp_laddr = sipx->sipx_addr;
+noname:
+ if (lport == 0)
+ do {
+ if (ipxpcb.ipxp_lport++ < IPXPORT_MAX)
+ ipxpcb.ipxp_lport = IPXPORT_MAX;
+ lport = htons(ipxpcb.ipxp_lport);
+ } while (ipx_pcblookup(&zeroipx_addr, lport, 0));
+ ipxp->ipxp_lport = lport;
+ return (0);
+}
+
+/*
+ * Connect from a socket to a specified address.
+ * Both address and port must be specified in argument sipx.
+ * If don't have a local address for this socket yet,
+ * then pick one.
+ */
+int
+ipx_pcbconnect(ipxp, nam)
+ struct ipxpcb *ipxp;
+ struct mbuf *nam;
+{
+ struct ipx_ifaddr *ia;
+ register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
+ register struct ipx_addr *dst;
+ register struct route *ro;
+ struct ifnet *ifp;
+
+ if (nam->m_len != sizeof (*sipx))
+ return (EINVAL);
+ if (sipx->sipx_family != AF_IPX)
+ return (EAFNOSUPPORT);
+ if (sipx->sipx_port==0 || ipx_nullhost(sipx->sipx_addr))
+ return (EADDRNOTAVAIL);
+ /*
+ * If we haven't bound which network number to use as ours,
+ * we will use the number of the outgoing interface.
+ * This depends on having done a routing lookup, which
+ * we will probably have to do anyway, so we might
+ * as well do it now. On the other hand if we are
+ * sending to multiple destinations we may have already
+ * done the lookup, so see if we can use the route
+ * from before. In any case, we only
+ * chose a port number once, even if sending to multiple
+ * destinations.
+ */
+ ro = &ipxp->ipxp_route;
+ dst = &satoipx_addr(ro->ro_dst);
+ if (ipxp->ipxp_socket->so_options & SO_DONTROUTE)
+ goto flush;
+ if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr))
+ goto flush;
+ if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) {
+ if (ro->ro_rt && ! (ro->ro_rt->rt_flags & RTF_HOST)) {
+ /* can patch route to avoid rtalloc */
+ *dst = sipx->sipx_addr;
+ } else {
+ flush:
+ if (ro->ro_rt)
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ ipxp->ipxp_laddr.x_net = ipx_zeronet;
+ }
+ }/* else cached route is ok; do nothing */
+ ipxp->ipxp_lastdst = sipx->sipx_addr;
+ if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
+ (ro->ro_rt == (struct rtentry *)0 ||
+ ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
+ /* No route yet, so try to acquire one */
+ ro->ro_dst.sa_family = AF_IPX;
+ ro->ro_dst.sa_len = sizeof(ro->ro_dst);
+ *dst = sipx->sipx_addr;
+ dst->x_port = 0;
+ rtalloc(ro);
+ }
+ if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
+ /*
+ * If route is known or can be allocated now,
+ * our src addr is taken from the i/f, else punt.
+ */
+
+ ia = (struct ipx_ifaddr *)0;
+ /*
+ * If we found a route, use the address
+ * corresponding to the outgoing interface
+ */
+ if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp))
+ for (ia = ipx_ifaddr; ia; ia = ia->ia_next)
+ if (ia->ia_ifp == ifp)
+ break;
+ if (ia == 0) {
+ u_short fport = sipx->sipx_addr.x_port;
+ sipx->sipx_addr.x_port = 0;
+ ia = (struct ipx_ifaddr *)
+ ifa_ifwithdstaddr((struct sockaddr *)sipx);
+ sipx->sipx_addr.x_port = fport;
+ if (ia == 0)
+ ia = ipx_iaonnetof(&sipx->sipx_addr);
+ if (ia == 0)
+ ia = ipx_ifaddr;
+ if (ia == 0)
+ return (EADDRNOTAVAIL);
+ }
+ ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
+ }
+ if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
+ return (EADDRINUSE);
+ if (ipx_nullhost(ipxp->ipxp_laddr)) {
+ if (ipxp->ipxp_lport == 0)
+ (void) ipx_pcbbind(ipxp, (struct mbuf *)0);
+ ipxp->ipxp_laddr.x_host = ipx_thishost;
+ }
+ ipxp->ipxp_faddr = sipx->sipx_addr;
+ /* Includes ipxp->ipxp_fport = sipx->sipx_port; */
+ return (0);
+}
+
+void
+ipx_pcbdisconnect(ipxp)
+ struct ipxpcb *ipxp;
+{
+
+ ipxp->ipxp_faddr = zeroipx_addr;
+ if (ipxp->ipxp_socket->so_state & SS_NOFDREF)
+ ipx_pcbdetach(ipxp);
+}
+
+void
+ipx_pcbdetach(ipxp)
+ struct ipxpcb *ipxp;
+{
+ struct socket *so = ipxp->ipxp_socket;
+
+ so->so_pcb = 0;
+ sofree(so);
+ if (ipxp->ipxp_route.ro_rt)
+ rtfree(ipxp->ipxp_route.ro_rt);
+ remque(ipxp);
+ (void) m_free(dtom(ipxp));
+}
+
+void
+ipx_setsockaddr(ipxp, nam)
+ register struct ipxpcb *ipxp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
+
+ nam->m_len = sizeof (*sipx);
+ sipx = mtod(nam, struct sockaddr_ipx *);
+ bzero((caddr_t)sipx, sizeof (*sipx));
+ sipx->sipx_len = sizeof(*sipx);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_addr = ipxp->ipxp_laddr;
+}
+
+void
+ipx_setpeeraddr(ipxp, nam)
+ register struct ipxpcb *ipxp;
+ struct mbuf *nam;
+{
+ register struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
+
+ nam->m_len = sizeof (*sipx);
+ sipx = mtod(nam, struct sockaddr_ipx *);
+ bzero((caddr_t)sipx, sizeof (*sipx));
+ sipx->sipx_len = sizeof(*sipx);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_addr = ipxp->ipxp_faddr;
+}
+
+/*
+ * Pass some notification to all connections of a protocol
+ * associated with address dst. Call the
+ * protocol specific routine to handle each connection.
+ * Also pass an extra paramter via the ipxpcb. (which may in fact
+ * be a parameter list!)
+ */
+void
+ipx_pcbnotify(dst, errno, notify, param)
+ register struct ipx_addr *dst;
+ long param;
+ int errno, (*notify)();
+{
+ register struct ipxpcb *ipxp, *oinp;
+ int s = splimp();
+
+ for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb);) {
+ if (!ipx_hosteq(*dst,ipxp->ipxp_faddr)) {
+ next:
+ ipxp = ipxp->ipxp_next;
+ continue;
+ }
+ if (ipxp->ipxp_socket == 0)
+ goto next;
+ if (errno)
+ ipxp->ipxp_socket->so_error = errno;
+ oinp = ipxp;
+ ipxp = ipxp->ipxp_next;
+ oinp->ipxp_notify_param = param;
+ (*notify)(oinp);
+ }
+ splx(s);
+}
+
+#ifdef notdef
+/*
+ * After a routing change, flush old routing
+ * and allocate a (hopefully) better one.
+ */
+ipx_rtchange(ipxp)
+ struct ipxpcb *ipxp;
+{
+ if (ipxp->ipxp_route.ro_rt) {
+ rtfree(ipxp->ipxp_route.ro_rt);
+ ipxp->ipxp_route.ro_rt = 0;
+ /*
+ * A new route can be allocated the next time
+ * output is attempted.
+ */
+ }
+ /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
+}
+#endif
+
+struct ipxpcb *
+ipx_pcblookup(faddr, lport, wildp)
+ struct ipx_addr *faddr;
+ u_short lport;
+ int wildp;
+{
+ register struct ipxpcb *ipxp, *match = 0;
+ int matchwild = 3, wildcard;
+ u_short fport;
+
+ fport = faddr->x_port;
+ for (ipxp = (&ipxpcb)->ipxp_next; ipxp != (&ipxpcb); ipxp = ipxp->ipxp_next) {
+ if (ipxp->ipxp_lport != lport)
+ continue;
+ wildcard = 0;
+ if (ipx_nullhost(ipxp->ipxp_faddr)) {
+ if (!ipx_nullhost(*faddr))
+ wildcard++;
+ } else {
+ if (ipx_nullhost(*faddr))
+ wildcard++;
+ else {
+ if (!ipx_hosteq(ipxp->ipxp_faddr, *faddr))
+ continue;
+ if (ipxp->ipxp_fport != fport) {
+ if (ipxp->ipxp_fport != 0)
+ continue;
+ else
+ wildcard++;
+ }
+ }
+ }
+ if (wildcard && wildp==0)
+ continue;
+ if (wildcard < matchwild) {
+ match = ipxp;
+ matchwild = wildcard;
+ if (wildcard == 0)
+ break;
+ }
+ }
+ return (match);
+}
diff --git a/sys/netipx/ipx_pcb.h b/sys/netipx/ipx_pcb.h
new file mode 100644
index 0000000..69762cf
--- /dev/null
+++ b/sys/netipx/ipx_pcb.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_pcb.h
+ */
+
+#ifndef _NETIPX_IPX_PCB_H_
+#define _NETIPX_IPX_PCB_H_
+
+/*
+ * IPX protocol interface control block.
+ */
+struct ipxpcb {
+ struct ipxpcb *ipxp_next; /* doubly linked list */
+ struct ipxpcb *ipxp_prev;
+ struct ipxpcb *ipxp_head;
+ struct socket *ipxp_socket; /* back pointer to socket */
+ struct ipx_addr ipxp_faddr; /* destination address */
+ struct ipx_addr ipxp_laddr; /* socket's address */
+ caddr_t ipxp_pcb; /* protocol specific stuff */
+ struct route ipxp_route; /* routing information */
+ struct ipx_addr ipxp_lastdst; /* validate cached route for dg socks*/
+ long ipxp_notify_param; /* extra info passed via ipx_pcbnotify*/
+ short ipxp_flags;
+ u_char ipxp_dpt; /* default packet type for ipx_output */
+ u_char ipxp_rpt; /* last received packet type by ipx_input() */
+};
+
+/* possible flags */
+
+#define IPXP_IN_ABORT 0x1 /* calling abort through socket */
+#define IPXP_RAWIN 0x2 /* show headers on input */
+#define IPXP_RAWOUT 0x4 /* show header on output */
+#define IPXP_ALL_PACKETS 0x8 /* Turn off higher proto processing */
+
+#define IPX_WILDCARD 1
+
+#define ipxp_lport ipxp_laddr.x_port
+#define ipxp_fport ipxp_faddr.x_port
+
+#define sotoipxpcb(so) ((struct ipxpcb *)((so)->so_pcb))
+
+/*
+ * Nominal space allocated to a IPX socket.
+ */
+#define IPXSNDQ 2048
+#define IPXRCVQ 2048
+
+
+#ifdef KERNEL
+extern struct ipxpcb ipxpcb; /* head of list */
+int ipx_pcballoc(), ipx_pcbbind(), ipx_pcbconnect();
+void ipx_pcbdisconnect(), ipx_pcbdetach(), ipx_setsockaddr();
+void ipx_setpeeraddr(), ipx_pcbnotify();
+struct ipxpcb *ipx_pcblookup();
+#endif
+
+#endif
diff --git a/sys/netipx/ipx_proto.c b/sys/netipx/ipx_proto.c
new file mode 100644
index 0000000..6aa2d7f
--- /dev/null
+++ b/sys/netipx/ipx_proto.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_proto.c
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+
+#include <net/radix.h>
+
+#include <netipx/ipx.h>
+#include <netipx/spx.h>
+
+/*
+ * IPX protocol family: IPX, ERR, PXP, SPX, ROUTE.
+ */
+
+struct protosw ipxsw[] = {
+{ 0, &ipxdomain, 0, 0,
+ 0, ipx_output, 0, 0,
+ 0,
+ ipx_init, 0, 0, 0
+},
+{ SOCK_DGRAM, &ipxdomain, 0, PR_ATOMIC|PR_ADDR,
+ 0, 0, ipx_ctlinput, ipx_ctloutput,
+ ipx_usrreq,
+ 0, 0, 0, 0
+},
+{ SOCK_STREAM, &ipxdomain, IPXPROTO_SPX, PR_CONNREQUIRED|PR_WANTRCVD,
+ spx_input, 0, spx_ctlinput, spx_ctloutput,
+ spx_usrreq,
+ spx_init, spx_fasttimo, spx_slowtimo, 0
+},
+{ SOCK_SEQPACKET,&ipxdomain, IPXPROTO_SPX, PR_CONNREQUIRED|PR_WANTRCVD|PR_ATOMIC,
+ spx_input, 0, spx_ctlinput, spx_ctloutput,
+ spx_usrreq_sp,
+ 0, 0, 0, 0
+},
+{ SOCK_RAW, &ipxdomain, IPXPROTO_RAW, PR_ATOMIC|PR_ADDR,
+ ipx_input, ipx_output, 0, ipx_ctloutput,
+ ipx_raw_usrreq,
+ 0, 0, 0, 0
+},
+{ SOCK_RAW, &ipxdomain, IPXPROTO_ERROR, PR_ATOMIC|PR_ADDR,
+ ipx_ctlinput, ipx_output, 0, ipx_ctloutput,
+ ipx_raw_usrreq,
+ 0, 0, 0, 0
+},
+#ifdef IPTUNNEL
+#if 0
+{ SOCK_RAW, &ipxdomain, IPPROTO_IPX, PR_ATOMIC|PR_ADDR,
+ iptun_input, rip_output, iptun_ctlinput, 0,
+ rip_usrreq,
+ 0, 0, 0, 0,
+},
+#endif
+#endif
+};
+
+struct domain ipxdomain =
+ { AF_IPX, "network systems", 0, 0, 0,
+ ipxsw, &ipxsw[sizeof(ipxsw)/sizeof(ipxsw[0])], 0,
+ rn_inithead, 16, sizeof(struct sockaddr_ipx)};
+
+DOMAIN_SET(ipx);
diff --git a/sys/netipx/ipx_tun.c b/sys/netipx/ipx_tun.c
new file mode 100644
index 0000000..e04946c
--- /dev/null
+++ b/sys/netipx/ipx_tun.c
@@ -0,0 +1,67 @@
+/*
+ * Modifications Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_tun.c
+ */
+
+/*
+ * Software interface driver for encapsulating IP in IPX.
+ */
+
+#ifdef IPTUNNEL
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/netisr.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <machine/mtpr.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+
+#endif
diff --git a/sys/netipx/ipx_usrreq.c b/sys/netipx/ipx_usrreq.c
new file mode 100644
index 0000000..1434c74
--- /dev/null
+++ b/sys/netipx/ipx_usrreq.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_usrreq.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx_if.h>
+#include <netipx/ipx_var.h>
+#include <netipx/ipx_error.h>
+
+/*
+ * IPX protocol implementation.
+ */
+
+int noipxRoute;
+
+/*
+ * This may also be called for raw listeners.
+ */
+void
+ipx_input(m, ipxp)
+ struct mbuf *m;
+ register struct ipxpcb *ipxp;
+{
+ register struct ipx *ipx = mtod(m, struct ipx *);
+ struct ifnet *ifp = m->m_pkthdr.rcvif;
+ struct sockaddr_ipx ipx_ipx = { sizeof(ipx_ipx), AF_IPX };
+
+ if (ipxp==0)
+ panic("No ipxpcb");
+ /*
+ * Construct sockaddr format source address.
+ * Stuff source address and datagram in user buffer.
+ */
+ ipx_ipx.sipx_addr = ipx->ipx_sna;
+ if (ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet) && ifp) {
+ register struct ifaddr *ifa;
+
+ for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_IPX) {
+ ipx_ipx.sipx_addr.x_net =
+ IA_SIPX(ifa)->sipx_addr.x_net;
+ break;
+ }
+ }
+ }
+ ipxp->ipxp_rpt = ipx->ipx_pt;
+ if ( ! (ipxp->ipxp_flags & IPXP_RAWIN) ) {
+ m->m_len -= sizeof (struct ipx);
+ m->m_pkthdr.len -= sizeof (struct ipx);
+ m->m_data += sizeof (struct ipx);
+ }
+ if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx,
+ m, (struct mbuf *)0) == 0)
+ goto bad;
+ sorwakeup(ipxp->ipxp_socket);
+ return;
+bad:
+ m_freem(m);
+}
+
+void
+ipx_abort(ipxp)
+ struct ipxpcb *ipxp;
+{
+ struct socket *so = ipxp->ipxp_socket;
+
+ ipx_pcbdisconnect(ipxp);
+ soisdisconnected(so);
+}
+/*
+ * Drop connection, reporting
+ * the specified error.
+ */
+/* struct ipxpcb * DELETE THIS */
+void
+ipx_drop(ipxp, errno)
+ register struct ipxpcb *ipxp;
+ int errno;
+{
+ struct socket *so = ipxp->ipxp_socket;
+
+ /*
+ * someday, in the xerox world
+ * we will generate error protocol packets
+ * announcing that the socket has gone away.
+ */
+ /*if (TCPS_HAVERCVDSYN(tp->t_state)) {
+ tp->t_state = TCPS_CLOSED;
+ (void) tcp_output(tp);
+ }*/
+ so->so_error = errno;
+ ipx_pcbdisconnect(ipxp);
+ soisdisconnected(so);
+}
+
+int
+ipx_output(ipxp, m0)
+ struct ipxpcb *ipxp;
+ struct mbuf *m0;
+{
+ register struct mbuf *m;
+ register struct ipx *ipx;
+ register struct socket *so;
+ register int len = 0;
+ register struct route *ro;
+ struct mbuf *mprev = NULL;
+
+ /*
+ * Calculate data length.
+ */
+ for (m = m0; m; m = m->m_next) {
+ mprev = m;
+ len += m->m_len;
+ }
+ /*
+ * Make sure packet is actually of even length.
+ */
+
+ if (len & 1) {
+ m = mprev;
+ if ((m->m_flags & M_EXT) == 0 &&
+ (m->m_len + m->m_data < &m->m_dat[MLEN])) {
+ m->m_len++;
+ } else {
+ struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
+
+ if (m1 == 0) {
+ m_freem(m0);
+ return (ENOBUFS);
+ }
+ m1->m_len = 1;
+ * mtod(m1, char *) = 0;
+ m->m_next = m1;
+ }
+ m0->m_pkthdr.len++;
+ }
+
+ /*
+ * Fill in mbuf with extended IPX header
+ * and addresses and length put into network format.
+ */
+ m = m0;
+ if (ipxp->ipxp_flags & IPXP_RAWOUT) {
+ ipx = mtod(m, struct ipx *);
+ } else {
+ M_PREPEND(m, sizeof (struct ipx), M_DONTWAIT);
+ if (m == 0)
+ return (ENOBUFS);
+ ipx = mtod(m, struct ipx *);
+ ipx->ipx_tc = 0;
+ ipx->ipx_pt = ipxp->ipxp_dpt;
+ ipx->ipx_sna = ipxp->ipxp_laddr;
+ ipx->ipx_dna = ipxp->ipxp_faddr;
+ len += sizeof (struct ipx);
+ }
+
+ ipx->ipx_len = htons((u_short)len);
+
+ if (ipxcksum) {
+ ipx->ipx_sum = 0;
+ len = ((len - 1) | 1) + 1;
+ ipx->ipx_sum = ipx_cksum(m, len);
+ } else
+ ipx->ipx_sum = 0xffff;
+
+ /*
+ * Output datagram.
+ */
+ so = ipxp->ipxp_socket;
+ if (so->so_options & SO_DONTROUTE)
+ return (ipx_outputfl(m, (struct route *)0,
+ (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF));
+ /*
+ * Use cached route for previous datagram if
+ * possible. If the previous net was the same
+ * and the interface was a broadcast medium, or
+ * if the previous destination was identical,
+ * then we are ok.
+ *
+ * NB: We don't handle broadcasts because that
+ * would require 3 subroutine calls.
+ */
+ ro = &ipxp->ipxp_route;
+#ifdef ancient_history
+ /*
+ * I think that this will all be handled in ipx_pcbconnect!
+ */
+ if (ro->ro_rt) {
+ if(ipx_neteq(ipxp->ipxp_lastdst, ipx->ipx_dna)) {
+ /*
+ * This assumes we have no GH type routes
+ */
+ if (ro->ro_rt->rt_flags & RTF_HOST) {
+ if (!ipx_hosteq(ipxp->ipxp_lastdst, ipx->ipx_dna))
+ goto re_route;
+
+ }
+ if ((ro->ro_rt->rt_flags & RTF_GATEWAY) == 0) {
+ register struct ipx_addr *dst =
+ &satoipx_addr(ro->ro_dst);
+ dst->x_host = ipx->ipx_dna.x_host;
+ }
+ /*
+ * Otherwise, we go through the same gateway
+ * and dst is already set up.
+ */
+ } else {
+ re_route:
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ }
+ ipxp->ipxp_lastdst = ipx->ipx_dna;
+#endif /* ancient_history */
+ if (noipxRoute) ro = 0;
+ return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST));
+}
+/* ARGSUSED */
+int
+ipx_ctloutput(req, so, level, name, value)
+ int req, level;
+ struct socket *so;
+ int name;
+ struct mbuf **value;
+{
+ register struct mbuf *m;
+ struct ipxpcb *ipxp = sotoipxpcb(so);
+ int mask, error = 0;
+ /*extern long ipx_pexseq;*/ /*XXX*//*JRE*/
+
+ if (ipxp == NULL)
+ return (EINVAL);
+
+ switch (req) {
+
+ case PRCO_GETOPT:
+ if (value==NULL)
+ return (EINVAL);
+ m = m_get(M_DONTWAIT, MT_DATA);
+ if (m==NULL)
+ return (ENOBUFS);
+ switch (name) {
+
+ case SO_ALL_PACKETS:
+ mask = IPXP_ALL_PACKETS;
+ goto get_flags;
+
+ case SO_HEADERS_ON_INPUT:
+ mask = IPXP_RAWIN;
+ goto get_flags;
+
+ case SO_HEADERS_ON_OUTPUT:
+ mask = IPXP_RAWOUT;
+ get_flags:
+ m->m_len = sizeof(short);
+ *mtod(m, short *) = ipxp->ipxp_flags & mask;
+ break;
+
+ case SO_DEFAULT_HEADERS:
+ m->m_len = sizeof(struct ipx);
+ {
+ register struct ipx *ipx = mtod(m, struct ipx *);
+ ipx->ipx_len = 0;
+ ipx->ipx_sum = 0;
+ ipx->ipx_tc = 0;
+ ipx->ipx_pt = ipxp->ipxp_dpt;
+ ipx->ipx_dna = ipxp->ipxp_faddr;
+ ipx->ipx_sna = ipxp->ipxp_laddr;
+ }
+ break;
+
+ case SO_SEQNO:
+ m->m_len = sizeof(long);
+ *mtod(m, long *) = ipx_pexseq++;
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ *value = m;
+ break;
+
+ case PRCO_SETOPT:
+ switch (name) {
+ int *ok;
+
+ case SO_ALL_PACKETS:
+ mask = IPXP_ALL_PACKETS;
+ goto set_head;
+
+ case SO_HEADERS_ON_INPUT:
+ mask = IPXP_RAWIN;
+ goto set_head;
+
+ case SO_HEADERS_ON_OUTPUT:
+ mask = IPXP_RAWOUT;
+ set_head:
+ if (value && *value) {
+ ok = mtod(*value, int *);
+ if (*ok)
+ ipxp->ipxp_flags |= mask;
+ else
+ ipxp->ipxp_flags &= ~mask;
+ } else error = EINVAL;
+ break;
+
+ case SO_DEFAULT_HEADERS:
+ {
+ register struct ipx *ipx
+ = mtod(*value, struct ipx *);
+ ipxp->ipxp_dpt = ipx->ipx_pt;
+ }
+ break;
+#ifdef IPXIP
+ case SO_IPXIP_ROUTE:
+ error = ipxip_route(*value);
+ break;
+#endif /* IPXIP */
+#ifdef IPXTUNNEL
+ case SO_IPXTUNNEL_ROUTE
+ error = ipxtun_route(*value);
+ break;
+#endif
+ default:
+ error = EINVAL;
+ }
+ if (value && *value)
+ m_freem(*value);
+ break;
+ }
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+ipx_usrreq(so, req, m, nam, control)
+ struct socket *so;
+ int req;
+ struct mbuf *m, *nam, *control;
+{
+ struct ipxpcb *ipxp = sotoipxpcb(so);
+ int error = 0;
+
+ if (req == PRU_CONTROL)
+ return (ipx_control(so, (int)m, (caddr_t)nam,
+ (struct ifnet *)control));
+ if (control && control->m_len) {
+ error = EINVAL;
+ goto release;
+ }
+ if (ipxp == NULL && req != PRU_ATTACH) {
+ error = EINVAL;
+ goto release;
+ }
+ switch (req) {
+
+ case PRU_ATTACH:
+ if (ipxp != NULL) {
+ error = EINVAL;
+ break;
+ }
+ error = ipx_pcballoc(so, &ipxpcb);
+ if (error)
+ break;
+ error = soreserve(so, (u_long) 2048, (u_long) 2048);
+ if (error)
+ break;
+ break;
+
+ case PRU_DETACH:
+ if (ipxp == NULL) {
+ error = ENOTCONN;
+ break;
+ }
+ ipx_pcbdetach(ipxp);
+ break;
+
+ case PRU_BIND:
+ error = ipx_pcbbind(ipxp, nam);
+ break;
+
+ case PRU_LISTEN:
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_CONNECT:
+ if (!ipx_nullhost(ipxp->ipxp_faddr)) {
+ error = EISCONN;
+ break;
+ }
+ error = ipx_pcbconnect(ipxp, nam);
+ if (error == 0)
+ soisconnected(so);
+ break;
+
+ case PRU_CONNECT2:
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_ACCEPT:
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_DISCONNECT:
+ if (ipx_nullhost(ipxp->ipxp_faddr)) {
+ error = ENOTCONN;
+ break;
+ }
+ ipx_pcbdisconnect(ipxp);
+ soisdisconnected(so);
+ break;
+
+ case PRU_SHUTDOWN:
+ socantsendmore(so);
+ break;
+
+ case PRU_SEND:
+ {
+ struct ipx_addr laddr;
+ int s = 0;
+
+ if (nam) {
+ laddr = ipxp->ipxp_laddr;
+ if (!ipx_nullhost(ipxp->ipxp_faddr)) {
+ error = EISCONN;
+ break;
+ }
+ /*
+ * Must block input while temporarily connected.
+ */
+ s = splnet();
+ error = ipx_pcbconnect(ipxp, nam);
+ if (error) {
+ splx(s);
+ break;
+ }
+ } else {
+ if (ipx_nullhost(ipxp->ipxp_faddr)) {
+ error = ENOTCONN;
+ break;
+ }
+ }
+ error = ipx_output(ipxp, m);
+ m = NULL;
+ if (nam) {
+ ipx_pcbdisconnect(ipxp);
+ splx(s);
+ ipxp->ipxp_laddr.x_host = laddr.x_host;
+ ipxp->ipxp_laddr.x_port = laddr.x_port;
+ }
+ }
+ break;
+
+ case PRU_ABORT:
+ ipx_pcbdetach(ipxp);
+ sofree(so);
+ soisdisconnected(so);
+ break;
+
+ case PRU_SOCKADDR:
+ ipx_setsockaddr(ipxp, nam);
+ break;
+
+ case PRU_PEERADDR:
+ ipx_setpeeraddr(ipxp, nam);
+ break;
+
+ case PRU_SENSE:
+ /*
+ * stat: don't bother with a blocksize.
+ */
+ return (0);
+
+ case PRU_SENDOOB:
+ case PRU_FASTTIMO:
+ case PRU_SLOWTIMO:
+ case PRU_PROTORCV:
+ case PRU_PROTOSEND:
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_CONTROL:
+ case PRU_RCVD:
+ case PRU_RCVOOB:
+ return (EOPNOTSUPP); /* do not free mbuf's */
+
+ default:
+ panic("ipx_usrreq");
+ }
+release:
+ if (control != NULL)
+ m_freem(control);
+ if (m != NULL)
+ m_freem(m);
+ return (error);
+}
+/*ARGSUSED*/
+int
+ipx_raw_usrreq(so, req, m, nam, control)
+ struct socket *so;
+ int req;
+ struct mbuf *m, *nam, *control;
+{
+ int error = 0;
+ struct ipxpcb *ipxp = sotoipxpcb(so);
+ /*extern struct ipxpcb ipxrawpcb;*//*XXX*//*JRE*/
+
+ switch (req) {
+
+ case PRU_ATTACH:
+
+ if (!(so->so_state & SS_PRIV) || (ipxp != NULL)) {
+ error = EINVAL;
+ break;
+ }
+ error = ipx_pcballoc(so, &ipxrawpcb);
+ if (error)
+ break;
+ error = soreserve(so, (u_long) 2048, (u_long) 2048);
+ if (error)
+ break;
+ ipxp = sotoipxpcb(so);
+ ipxp->ipxp_faddr.x_host = ipx_broadhost;
+ ipxp->ipxp_flags = IPXP_RAWIN | IPXP_RAWOUT;
+ break;
+ default:
+ error = ipx_usrreq(so, req, m, nam, control);
+ }
+ return (error);
+}
+
diff --git a/sys/netipx/ipx_var.h b/sys/netipx/ipx_var.h
new file mode 100644
index 0000000..09fab3c
--- /dev/null
+++ b/sys/netipx/ipx_var.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ipx_var.h
+ */
+
+#ifndef _NETIPX_IPX_VAR_H_
+#define _NETIPX_IPX_VAR_H_
+
+/*
+ * IPX Kernel Structures and Variables
+ */
+struct ipxstat {
+ int ipxs_badsum; /* checksum bad */
+ int ipxs_tooshort; /* packet too short */
+ int ipxs_toosmall; /* not enough data */
+ int ipxs_badhlen; /* ip header length < data size */
+ int ipxs_badlen; /* ip length < ip header length */
+};
+
+#ifdef KERNEL
+extern struct ipxstat ipxstat;
+#endif
+
+#endif
diff --git a/sys/netipx/spx.h b/sys/netipx/spx.h
new file mode 100644
index 0000000..d40467f
--- /dev/null
+++ b/sys/netipx/spx.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)spx.h
+ */
+
+#ifndef _NETIPX_SPX_H_
+#define _NETIPX_SPX_H_
+
+/*
+ * Definitions for IPX style Sequenced Packet Protocol
+ */
+
+struct spxhdr {
+ u_char spx_cc; /* connection control */
+ u_char spx_dt; /* datastream type */
+#define SPX_SP 0x80 /* system packet */
+#define SPX_SA 0x40 /* send acknowledgement */
+#define SPX_OB 0x20 /* attention (out of band data) */
+#define SPX_EM 0x10 /* end of message */
+ u_short spx_sid; /* source connection identifier */
+ u_short spx_did; /* destination connection identifier */
+ u_short spx_seq; /* sequence number */
+ u_short spx_ack; /* acknowledge number */
+ u_short spx_alo; /* allocation number */
+};
+
+/*
+ * Definitions for NS(tm) Internet Datagram Protocol
+ * containing a Sequenced Packet Protocol packet.
+ */
+struct spx {
+ struct ipx si_i;
+ struct spxhdr si_s;
+};
+struct spx_q {
+ struct spx_q *si_next;
+ struct spx_q *si_prev;
+};
+#define SI(x) ((struct spx *)x)
+#define si_sum si_i.ipx_sum
+#define si_len si_i.ipx_len
+#define si_tc si_i.ipx_tc
+#define si_pt si_i.ipx_pt
+#define si_dna si_i.ipx_dna
+#define si_sna si_i.ipx_sna
+#define si_sport si_i.ipx_sna.x_port
+#define si_cc si_s.spx_cc
+#define si_dt si_s.spx_dt
+#define si_sid si_s.spx_sid
+#define si_did si_s.spx_did
+#define si_seq si_s.spx_seq
+#define si_ack si_s.spx_ack
+#define si_alo si_s.spx_alo
+
+#ifdef KERNEL
+int spx_reass(), spx_output();
+int spx_usrreq(), spx_usrreq_sp(), spx_ctloutput();
+void spx_input(), spx_ctlinput();
+void spx_init(), spx_fasttimo(), spx_slowtimo();
+void spx_quench(), spx_setpersist(), spx_template(), spx_abort();
+struct spxpcb *spx_close(), *spx_usrclosed();
+struct spxpcb *spx_disconnect(), *spx_drop();
+struct spxpcb *spx_timers();
+#endif
+
+#endif
diff --git a/sys/netipx/spx_debug.c b/sys/netipx/spx_debug.c
new file mode 100644
index 0000000..f392d41
--- /dev/null
+++ b/sys/netipx/spx_debug.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)spx_debug.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/errno.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/tcp_fsm.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_error.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx.h>
+#include <netipx/ipx_var.h>
+#include <netipx/spx.h>
+#define SPXTIMERS
+#include <netipx/spx_timer.h>
+#include <netipx/spx_var.h>
+#define SANAMES
+#include <netipx/spx_debug.h>
+
+int spxconsdebug = 0;
+/*
+ * spx debug routines
+ */
+void
+spx_trace(act, ostate, sp, si, req)
+ short act;
+ u_char ostate;
+ struct spxpcb *sp;
+ struct spx *si;
+ int req;
+{
+#ifdef INET
+#ifdef TCPDEBUG
+ u_short seq, ack, len, alo;
+ int flags;
+ struct spx_debug *sd = &spx_debug[spx_debx++];
+
+ if (spx_debx == SPX_NDEBUG)
+ spx_debx = 0;
+ sd->sd_time = iptime();
+ sd->sd_act = act;
+ sd->sd_ostate = ostate;
+ sd->sd_cb = (caddr_t)sp;
+ if (sp)
+ sd->sd_sp = *sp;
+ else
+ bzero((caddr_t)&sd->sd_sp, sizeof (*sp));
+ if (si)
+ sd->sd_si = *si;
+ else
+ bzero((caddr_t)&sd->sd_si, sizeof (*si));
+ sd->sd_req = req;
+ if (spxconsdebug == 0)
+ return;
+ if (ostate >= TCP_NSTATES) ostate = 0;
+ if (act >= SA_DROP) act = SA_DROP;
+ if (sp)
+ printf("%x %s:", sp, tcpstates[ostate]);
+ else
+ printf("???????? ");
+ printf("%s ", sanames[act]);
+ switch (act) {
+
+ case SA_RESPOND:
+ case SA_INPUT:
+ case SA_OUTPUT:
+ case SA_DROP:
+ if (si == 0)
+ break;
+ seq = si->si_seq;
+ ack = si->si_ack;
+ alo = si->si_alo;
+ len = si->si_len;
+ if (act == SA_OUTPUT) {
+ seq = ntohs(seq);
+ ack = ntohs(ack);
+ alo = ntohs(alo);
+ len = ntohs(len);
+ }
+#ifndef lint
+#define p1(f) { printf("%s = %x, ", "f", f); }
+ p1(seq); p1(ack); p1(alo); p1(len);
+#endif
+ flags = si->si_cc;
+ if (flags) {
+ char *cp = "<";
+#ifndef lint
+#define pf(f) { if (flags & SPX_ ## f) { printf("%s%s", cp, "f"); cp = ","; } }
+ pf(SP); pf(SA); pf(OB); pf(EM);
+#else
+ cp = cp;
+#endif
+ printf(">");
+ }
+#ifndef lint
+#define p2(f) { printf("%s = %x, ", "f", si->si_ ## f); }
+ p2(sid);p2(did);p2(dt);p2(pt);
+#endif
+ ipx_printhost(&si->si_sna);
+ ipx_printhost(&si->si_dna);
+
+ if (act==SA_RESPOND) {
+ printf("ipx_len = %x, ",
+ ((struct ipx *)si)->ipx_len);
+ }
+ break;
+
+ case SA_USER:
+ printf("%s", prurequests[req&0xff]);
+ if ((req & 0xff) == PRU_SLOWTIMO)
+ printf("<%s>", spxtimers[req>>8]);
+ break;
+ }
+ if (sp)
+ printf(" -> %s", tcpstates[sp->s_state]);
+ /* print out internal state of sp !?! */
+ printf("\n");
+ if (sp == 0)
+ return;
+#ifndef lint
+#define p3(f) { printf("%s = %x, ", "f", sp->s_ ## f); }
+ printf("\t"); p3(rack);p3(ralo);p3(smax);p3(flags); printf("\n");
+#endif
+#endif
+#endif
+}
diff --git a/sys/netipx/spx_debug.h b/sys/netipx/spx_debug.h
new file mode 100644
index 0000000..8a26918
--- /dev/null
+++ b/sys/netipx/spx_debug.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)spx_debug.h
+ */
+
+#ifndef _NETIPX_SPX_DEBUG_H_
+#define _NETIPX_SPX_DEBUG_H_
+
+struct spx_debug {
+ u_long sd_time;
+ short sd_act;
+ short sd_ostate;
+ caddr_t sd_cb;
+ short sd_req;
+ struct spx sd_si;
+ struct spxpcb sd_sp;
+};
+
+#define SA_INPUT 0
+#define SA_OUTPUT 1
+#define SA_USER 2
+#define SA_RESPOND 3
+#define SA_DROP 4
+
+#ifdef SANAMES
+char *spxnames[] =
+ { "input", "output", "user", "respond", "drop" };
+#endif
+
+#define SPX_NDEBUG 100
+struct spx_debug spx_debug[SPX_NDEBUG];
+int spx_debx;
+
+#ifdef KERNEL
+
+void spx_trace();
+
+extern char *prurequests[];
+extern char *sanames[];
+extern char *tcpstates[];
+
+#endif
+
+#endif
diff --git a/sys/netipx/spx_timer.h b/sys/netipx/spx_timer.h
new file mode 100644
index 0000000..ac88eb7
--- /dev/null
+++ b/sys/netipx/spx_timer.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1982, 1986, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)spx_timer.h
+ */
+
+#ifndef _NETIPX_SPX_TIMER_H_
+#define _NETIPX_SPX_TIMER_H_
+
+/*
+ * Definitions of the SPX timers. These timers are counted
+ * down PR_SLOWHZ times a second.
+ */
+#define SPXT_NTIMERS 4
+
+#define SPXT_REXMT 0 /* retransmit */
+#define SPXT_PERSIST 1 /* retransmit persistance */
+#define SPXT_KEEP 2 /* keep alive */
+#define SPXT_2MSL 3 /* 2*msl quiet time timer */
+
+/*
+ * The SPXT_REXMT timer is used to force retransmissions.
+ * The SPX has the SPXT_REXMT timer set whenever segments
+ * have been sent for which ACKs are expected but not yet
+ * received. If an ACK is received which advances tp->snd_una,
+ * then the retransmit timer is cleared (if there are no more
+ * outstanding segments) or reset to the base value (if there
+ * are more ACKs expected). Whenever the retransmit timer goes off,
+ * we retransmit one unacknowledged segment, and do a backoff
+ * on the retransmit timer.
+ *
+ * The SPXT_PERSIST timer is used to keep window size information
+ * flowing even if the window goes shut. If all previous transmissions
+ * have been acknowledged (so that there are no retransmissions in progress),
+ * and the window is too small to bother sending anything, then we start
+ * the SPXT_PERSIST timer. When it expires, if the window is nonzero,
+ * we go to transmit state. Otherwise, at intervals send a single byte
+ * into the peer's window to force him to update our window information.
+ * We do this at most as often as SPXT_PERSMIN time intervals,
+ * but no more frequently than the current estimate of round-trip
+ * packet time. The SPXT_PERSIST timer is cleared whenever we receive
+ * a window update from the peer.
+ *
+ * The SPXT_KEEP timer is used to keep connections alive. If an
+ * connection is idle (no segments received) for SPXTV_KEEP amount of time,
+ * but not yet established, then we drop the connection. If the connection
+ * is established, then we force the peer to send us a segment by sending:
+ * <SEQ=SND.UNA-1><ACK=RCV.NXT><CTL=ACK>
+ * This segment is (deliberately) outside the window, and should elicit
+ * an ack segment in response from the peer. If, despite the SPXT_KEEP
+ * initiated segments we cannot elicit a response from a peer in SPXT_MAXIDLE
+ * amount of time, then we drop the connection.
+ */
+
+#define SPX_TTL 30 /* default time to live for SPX segs */
+/*
+ * Time constants.
+ */
+#define SPXTV_MSL ( 15*PR_SLOWHZ) /* max seg lifetime */
+#define SPXTV_SRTTBASE 0 /* base roundtrip time;
+ if 0, no idea yet */
+#define SPXTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */
+
+#define SPXTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistance */
+#define SPXTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */
+
+#define SPXTV_KEEP ( 75*PR_SLOWHZ) /* keep alive - 75 secs */
+#define SPXTV_MAXIDLE ( 8*SPXTV_KEEP) /* maximum allowable idle
+ time before drop conn */
+
+#define SPXTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */
+#define SPXTV_REXMTMAX ( 64*PR_SLOWHZ) /* max allowable REXMT value */
+
+#define SPX_LINGERTIME 120 /* linger at most 2 minutes */
+
+#define SPX_MAXRXTSHIFT 12 /* maximum retransmits */
+
+#ifdef SPXTIMERS
+char *spxtimers[] =
+ { "REXMT", "PERSIST", "KEEP", "2MSL" };
+#endif
+
+/*
+ * Force a time value to be in a certain range.
+ */
+#define SPXT_RANGESET(tv, value, tvmin, tvmax) { \
+ (tv) = (value); \
+ if ((tv) < (tvmin)) \
+ (tv) = (tvmin); \
+ else if ((tv) > (tvmax)) \
+ (tv) = (tvmax); \
+}
+
+#ifdef KERNEL
+extern int spx_backoff[];
+#endif
+
+#endif
diff --git a/sys/netipx/spx_usrreq.c b/sys/netipx/spx_usrreq.c
new file mode 100644
index 0000000..9321236
--- /dev/null
+++ b/sys/netipx/spx_usrreq.c
@@ -0,0 +1,1815 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)spx_usrreq.h
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/tcp_fsm.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx_var.h>
+#include <netipx/ipx_error.h>
+#include <netipx/spx.h>
+#include <netipx/spx_timer.h>
+#include <netipx/spx_var.h>
+#include <netipx/spx_debug.h>
+
+/*
+ * SPX protocol implementation.
+ */
+
+struct spx spx_savesi;
+int traceallspxs = 0;
+extern int spxconsdebug;
+int spx_hardnosed;
+int spx_use_delack = 0;
+u_short spx_newchecks[50];
+
+struct spx_istat spx_istat;
+u_short spx_iss;
+
+void
+spx_init()
+{
+
+ spx_iss = 1; /* WRONG !! should fish it out of TODR */
+}
+
+/*ARGSUSED*/
+void
+spx_input(m, ipxp)
+ register struct mbuf *m;
+ register struct ipxpcb *ipxp;
+{
+ register struct spxpcb *cb;
+ register struct spx *si = mtod(m, struct spx *);
+ register struct socket *so;
+ int dropsocket = 0;
+ short ostate = 0;
+
+ spxstat.spxs_rcvtotal++;
+ if (ipxp == 0) {
+ panic("No ipxpcb in spx_input\n");
+ return;
+ }
+
+ cb = ipxtospxpcb(ipxp);
+ if (cb == 0) goto bad;
+
+ if (m->m_len < sizeof(*si)) {
+ if ((m = m_pullup(m, sizeof(*si))) == 0) {
+ spxstat.spxs_rcvshort++;
+ return;
+ }
+ si = mtod(m, struct spx *);
+ }
+ si->si_seq = ntohs(si->si_seq);
+ si->si_ack = ntohs(si->si_ack);
+ si->si_alo = ntohs(si->si_alo);
+
+ so = ipxp->ipxp_socket;
+
+ if (so->so_options & SO_DEBUG || traceallspxs) {
+ ostate = cb->s_state;
+ spx_savesi = *si;
+ }
+ if (so->so_options & SO_ACCEPTCONN) {
+ struct spxpcb *ocb = cb;
+
+ so = sonewconn(so, 0);
+ if (so == 0) {
+ goto drop;
+ }
+ /*
+ * This is ugly, but ....
+ *
+ * Mark socket as temporary until we're
+ * committed to keeping it. The code at
+ * ``drop'' and ``dropwithreset'' check the
+ * flag dropsocket to see if the temporary
+ * socket created here should be discarded.
+ * We mark the socket as discardable until
+ * we're committed to it below in TCPS_LISTEN.
+ */
+ dropsocket++;
+ ipxp = (struct ipxpcb *)so->so_pcb;
+ ipxp->ipxp_laddr = si->si_dna;
+ cb = ipxtospxpcb(ipxp);
+ cb->s_mtu = ocb->s_mtu; /* preserve sockopts */
+ cb->s_flags = ocb->s_flags; /* preserve sockopts */
+ cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */
+ cb->s_state = TCPS_LISTEN;
+ }
+
+ /*
+ * Packet received on connection.
+ * reset idle time and keep-alive timer;
+ */
+ cb->s_idle = 0;
+ cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
+
+ switch (cb->s_state) {
+
+ case TCPS_LISTEN:{
+ struct mbuf *am;
+ register struct sockaddr_ipx *sipx;
+ struct ipx_addr laddr;
+
+ /*
+ * If somebody here was carying on a conversation
+ * and went away, and his pen pal thinks he can
+ * still talk, we get the misdirected packet.
+ */
+ if (spx_hardnosed && (si->si_did != 0 || si->si_seq != 0)) {
+ spx_istat.gonawy++;
+ goto dropwithreset;
+ }
+ am = m_get(M_DONTWAIT, MT_SONAME);
+ if (am == NULL)
+ goto drop;
+ am->m_len = sizeof (struct sockaddr_ipx);
+ sipx = mtod(am, struct sockaddr_ipx *);
+ sipx->sipx_len = sizeof(*sipx);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_addr = si->si_sna;
+ laddr = ipxp->ipxp_laddr;
+ if (ipx_nullhost(laddr))
+ ipxp->ipxp_laddr = si->si_dna;
+ if (ipx_pcbconnect(ipxp, am)) {
+ ipxp->ipxp_laddr = laddr;
+ (void) m_free(am);
+ spx_istat.noconn++;
+ goto drop;
+ }
+ (void) m_free(am);
+ spx_template(cb);
+ dropsocket = 0; /* committed to socket */
+ cb->s_did = si->si_sid;
+ cb->s_rack = si->si_ack;
+ cb->s_ralo = si->si_alo;
+#define THREEWAYSHAKE
+#ifdef THREEWAYSHAKE
+ cb->s_state = TCPS_SYN_RECEIVED;
+ cb->s_force = 1 + SPXT_KEEP;
+ spxstat.spxs_accepts++;
+ cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
+ }
+ break;
+ /*
+ * This state means that we have heard a response
+ * to our acceptance of their connection
+ * It is probably logically unnecessary in this
+ * implementation.
+ */
+ case TCPS_SYN_RECEIVED: {
+ if (si->si_did!=cb->s_sid) {
+ spx_istat.wrncon++;
+ goto drop;
+ }
+#endif
+ ipxp->ipxp_fport = si->si_sport;
+ cb->s_timer[SPXT_REXMT] = 0;
+ cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
+ soisconnected(so);
+ cb->s_state = TCPS_ESTABLISHED;
+ spxstat.spxs_accepts++;
+ }
+ break;
+
+ /*
+ * This state means that we have gotten a response
+ * to our attempt to establish a connection.
+ * We fill in the data from the other side,
+ * telling us which port to respond to, instead of the well-
+ * known one we might have sent to in the first place.
+ * We also require that this is a response to our
+ * connection id.
+ */
+ case TCPS_SYN_SENT:
+ if (si->si_did!=cb->s_sid) {
+ spx_istat.notme++;
+ goto drop;
+ }
+ spxstat.spxs_connects++;
+ cb->s_did = si->si_sid;
+ cb->s_rack = si->si_ack;
+ cb->s_ralo = si->si_alo;
+ cb->s_dport = ipxp->ipxp_fport = si->si_sport;
+ cb->s_timer[SPXT_REXMT] = 0;
+ cb->s_flags |= SF_ACKNOW;
+ soisconnected(so);
+ cb->s_state = TCPS_ESTABLISHED;
+ /* Use roundtrip time of connection request for initial rtt */
+ if (cb->s_rtt) {
+ cb->s_srtt = cb->s_rtt << 3;
+ cb->s_rttvar = cb->s_rtt << 1;
+ SPXT_RANGESET(cb->s_rxtcur,
+ ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
+ SPXTV_MIN, SPXTV_REXMTMAX);
+ cb->s_rtt = 0;
+ }
+ }
+ if (so->so_options & SO_DEBUG || traceallspxs)
+ spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0);
+
+ m->m_len -= sizeof (struct ipx);
+ m->m_pkthdr.len -= sizeof (struct ipx);
+ m->m_data += sizeof (struct ipx);
+
+ if (spx_reass(cb, si)) {
+ (void) m_freem(m);
+ }
+ if (cb->s_force || (cb->s_flags & (SF_ACKNOW|SF_WIN|SF_RXT)))
+ (void) spx_output(cb, (struct mbuf *)0);
+ cb->s_flags &= ~(SF_WIN|SF_RXT);
+ return;
+
+dropwithreset:
+ if (dropsocket)
+ (void) soabort(so);
+ si->si_seq = ntohs(si->si_seq);
+ si->si_ack = ntohs(si->si_ack);
+ si->si_alo = ntohs(si->si_alo);
+ ipx_error(dtom(si), IPX_ERR_NOSOCK, 0);
+ if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs)
+ spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
+ return;
+
+drop:
+bad:
+ if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG ||
+ traceallspxs)
+ spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0);
+ m_freem(m);
+}
+
+int spxrexmtthresh = 3;
+
+/*
+ * This is structurally similar to the tcp reassembly routine
+ * but its function is somewhat different: It merely queues
+ * packets up, and suppresses duplicates.
+ */
+int
+spx_reass(cb, si)
+register struct spxpcb *cb;
+register struct spx *si;
+{
+ register struct spx_q *q;
+ register struct mbuf *m;
+ register struct socket *so = cb->s_ipxpcb->ipxp_socket;
+ char packetp = cb->s_flags & SF_HI;
+ int incr;
+ char wakeup = 0;
+
+ if (si == SI(0))
+ goto present;
+ /*
+ * Update our news from them.
+ */
+ if (si->si_cc & SPX_SA)
+ cb->s_flags |= (spx_use_delack ? SF_DELACK : SF_ACKNOW);
+ if (SSEQ_GT(si->si_alo, cb->s_ralo))
+ cb->s_flags |= SF_WIN;
+ if (SSEQ_LEQ(si->si_ack, cb->s_rack)) {
+ if ((si->si_cc & SPX_SP) && cb->s_rack != (cb->s_smax + 1)) {
+ spxstat.spxs_rcvdupack++;
+ /*
+ * If this is a completely duplicate ack
+ * and other conditions hold, we assume
+ * a packet has been dropped and retransmit
+ * it exactly as in tcp_input().
+ */
+ if (si->si_ack != cb->s_rack ||
+ si->si_alo != cb->s_ralo)
+ cb->s_dupacks = 0;
+ else if (++cb->s_dupacks == spxrexmtthresh) {
+ u_short onxt = cb->s_snxt;
+ int cwnd = cb->s_cwnd;
+
+ cb->s_snxt = si->si_ack;
+ cb->s_cwnd = CUNIT;
+ cb->s_force = 1 + SPXT_REXMT;
+ (void) spx_output(cb, (struct mbuf *)0);
+ cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
+ cb->s_rtt = 0;
+ if (cwnd >= 4 * CUNIT)
+ cb->s_cwnd = cwnd / 2;
+ if (SSEQ_GT(onxt, cb->s_snxt))
+ cb->s_snxt = onxt;
+ return (1);
+ }
+ } else
+ cb->s_dupacks = 0;
+ goto update_window;
+ }
+ cb->s_dupacks = 0;
+ /*
+ * If our correspondent acknowledges data we haven't sent
+ * TCP would drop the packet after acking. We'll be a little
+ * more permissive
+ */
+ if (SSEQ_GT(si->si_ack, (cb->s_smax + 1))) {
+ spxstat.spxs_rcvacktoomuch++;
+ si->si_ack = cb->s_smax + 1;
+ }
+ spxstat.spxs_rcvackpack++;
+ /*
+ * If transmit timer is running and timed sequence
+ * number was acked, update smoothed round trip time.
+ * See discussion of algorithm in tcp_input.c
+ */
+ if (cb->s_rtt && SSEQ_GT(si->si_ack, cb->s_rtseq)) {
+ spxstat.spxs_rttupdated++;
+ if (cb->s_srtt != 0) {
+ register short delta;
+ delta = cb->s_rtt - (cb->s_srtt >> 3);
+ if ((cb->s_srtt += delta) <= 0)
+ cb->s_srtt = 1;
+ if (delta < 0)
+ delta = -delta;
+ delta -= (cb->s_rttvar >> 2);
+ if ((cb->s_rttvar += delta) <= 0)
+ cb->s_rttvar = 1;
+ } else {
+ /*
+ * No rtt measurement yet
+ */
+ cb->s_srtt = cb->s_rtt << 3;
+ cb->s_rttvar = cb->s_rtt << 1;
+ }
+ cb->s_rtt = 0;
+ cb->s_rxtshift = 0;
+ SPXT_RANGESET(cb->s_rxtcur,
+ ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1,
+ SPXTV_MIN, SPXTV_REXMTMAX);
+ }
+ /*
+ * If all outstanding data is acked, stop retransmit
+ * timer and remember to restart (more output or persist).
+ * If there is more data to be acked, restart retransmit
+ * timer, using current (possibly backed-off) value;
+ */
+ if (si->si_ack == cb->s_smax + 1) {
+ cb->s_timer[SPXT_REXMT] = 0;
+ cb->s_flags |= SF_RXT;
+ } else if (cb->s_timer[SPXT_PERSIST] == 0)
+ cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
+ /*
+ * When new data is acked, open the congestion window.
+ * If the window gives us less than ssthresh packets
+ * in flight, open exponentially (maxseg at a time).
+ * Otherwise open linearly (maxseg^2 / cwnd at a time).
+ */
+ incr = CUNIT;
+ if (cb->s_cwnd > cb->s_ssthresh)
+ incr = max(incr * incr / cb->s_cwnd, 1);
+ cb->s_cwnd = min(cb->s_cwnd + incr, cb->s_cwmx);
+ /*
+ * Trim Acked data from output queue.
+ */
+ while ((m = so->so_snd.sb_mb) != NULL) {
+ if (SSEQ_LT((mtod(m, struct spx *))->si_seq, si->si_ack))
+ sbdroprecord(&so->so_snd);
+ else
+ break;
+ }
+ sowwakeup(so);
+ cb->s_rack = si->si_ack;
+update_window:
+ if (SSEQ_LT(cb->s_snxt, cb->s_rack))
+ cb->s_snxt = cb->s_rack;
+ if (SSEQ_LT(cb->s_swl1, si->si_seq) || cb->s_swl1 == si->si_seq &&
+ (SSEQ_LT(cb->s_swl2, si->si_ack) ||
+ cb->s_swl2 == si->si_ack && SSEQ_LT(cb->s_ralo, si->si_alo))) {
+ /* keep track of pure window updates */
+ if ((si->si_cc & SPX_SP) && cb->s_swl2 == si->si_ack
+ && SSEQ_LT(cb->s_ralo, si->si_alo)) {
+ spxstat.spxs_rcvwinupd++;
+ spxstat.spxs_rcvdupack--;
+ }
+ cb->s_ralo = si->si_alo;
+ cb->s_swl1 = si->si_seq;
+ cb->s_swl2 = si->si_ack;
+ cb->s_swnd = (1 + si->si_alo - si->si_ack);
+ if (cb->s_swnd > cb->s_smxw)
+ cb->s_smxw = cb->s_swnd;
+ cb->s_flags |= SF_WIN;
+ }
+ /*
+ * If this packet number is higher than that which
+ * we have allocated refuse it, unless urgent
+ */
+ if (SSEQ_GT(si->si_seq, cb->s_alo)) {
+ if (si->si_cc & SPX_SP) {
+ spxstat.spxs_rcvwinprobe++;
+ return (1);
+ } else
+ spxstat.spxs_rcvpackafterwin++;
+ if (si->si_cc & SPX_OB) {
+ if (SSEQ_GT(si->si_seq, cb->s_alo + 60)) {
+ ipx_error(dtom(si), IPX_ERR_FULLUP, 0);
+ return (0);
+ } /* else queue this packet; */
+ } else {
+ /*register struct socket *so = cb->s_ipxpcb->ipxp_socket;
+ if (so->so_state && SS_NOFDREF) {
+ ipx_error(dtom(si), IPX_ERR_NOSOCK, 0);
+ (void)spx_close(cb);
+ } else
+ would crash system*/
+ spx_istat.notyet++;
+ ipx_error(dtom(si), IPX_ERR_FULLUP, 0);
+ return (0);
+ }
+ }
+ /*
+ * If this is a system packet, we don't need to
+ * queue it up, and won't update acknowledge #
+ */
+ if (si->si_cc & SPX_SP) {
+ return (1);
+ }
+ /*
+ * We have already seen this packet, so drop.
+ */
+ if (SSEQ_LT(si->si_seq, cb->s_ack)) {
+ spx_istat.bdreas++;
+ spxstat.spxs_rcvduppack++;
+ if (si->si_seq == cb->s_ack - 1)
+ spx_istat.lstdup++;
+ return (1);
+ }
+ /*
+ * Loop through all packets queued up to insert in
+ * appropriate sequence.
+ */
+ for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
+ if (si->si_seq == SI(q)->si_seq) {
+ spxstat.spxs_rcvduppack++;
+ return (1);
+ }
+ if (SSEQ_LT(si->si_seq, SI(q)->si_seq)) {
+ spxstat.spxs_rcvoopack++;
+ break;
+ }
+ }
+ insque(si, q->si_prev);
+ /*
+ * If this packet is urgent, inform process
+ */
+ if (si->si_cc & SPX_OB) {
+ cb->s_iobc = ((char *)si)[1 + sizeof(*si)];
+ sohasoutofband(so);
+ cb->s_oobflags |= SF_IOOB;
+ }
+present:
+#define SPINC sizeof(struct spxhdr)
+ /*
+ * Loop through all packets queued up to update acknowledge
+ * number, and present all acknowledged data to user;
+ * If in packet interface mode, show packet headers.
+ */
+ for (q = cb->s_q.si_next; q!=&cb->s_q; q = q->si_next) {
+ if (SI(q)->si_seq == cb->s_ack) {
+ cb->s_ack++;
+ m = dtom(q);
+ if (SI(q)->si_cc & SPX_OB) {
+ cb->s_oobflags &= ~SF_IOOB;
+ if (so->so_rcv.sb_cc)
+ so->so_oobmark = so->so_rcv.sb_cc;
+ else
+ so->so_state |= SS_RCVATMARK;
+ }
+ q = q->si_prev;
+ remque(q->si_next);
+ wakeup = 1;
+ spxstat.spxs_rcvpack++;
+#ifdef SF_NEWCALL
+ if (cb->s_flags2 & SF_NEWCALL) {
+ struct spxhdr *sp = mtod(m, struct spxhdr *);
+ u_char dt = sp->spx_dt;
+ spx_newchecks[4]++;
+ if (dt != cb->s_rhdr.spx_dt) {
+ struct mbuf *mm =
+ m_getclr(M_DONTWAIT, MT_CONTROL);
+ spx_newchecks[0]++;
+ if (mm != NULL) {
+ u_short *s =
+ mtod(mm, u_short *);
+ cb->s_rhdr.spx_dt = dt;
+ mm->m_len = 5; /*XXX*/
+ s[0] = 5;
+ s[1] = 1;
+ *(u_char *)(&s[2]) = dt;
+ sbappend(&so->so_rcv, mm);
+ }
+ }
+ if (sp->spx_cc & SPX_OB) {
+ MCHTYPE(m, MT_OOBDATA);
+ spx_newchecks[1]++;
+ so->so_oobmark = 0;
+ so->so_state &= ~SS_RCVATMARK;
+ }
+ if (packetp == 0) {
+ m->m_data += SPINC;
+ m->m_len -= SPINC;
+ m->m_pkthdr.len -= SPINC;
+ }
+ if ((sp->spx_cc & SPX_EM) || packetp) {
+ sbappendrecord(&so->so_rcv, m);
+ spx_newchecks[9]++;
+ } else
+ sbappend(&so->so_rcv, m);
+ } else
+#endif
+ if (packetp) {
+ sbappendrecord(&so->so_rcv, m);
+ } else {
+ cb->s_rhdr = *mtod(m, struct spxhdr *);
+ m->m_data += SPINC;
+ m->m_len -= SPINC;
+ m->m_pkthdr.len -= SPINC;
+ sbappend(&so->so_rcv, m);
+ }
+ } else
+ break;
+ }
+ if (wakeup) sorwakeup(so);
+ return (0);
+}
+
+void
+spx_ctlinput(cmd, arg)
+ int cmd;
+ caddr_t arg;
+{
+ struct ipx_addr *na;
+ struct ipx_errp *errp = (struct ipx_errp *)arg;
+ struct ipxpcb *ipxp;
+ struct sockaddr_ipx *sipx;
+ int type;
+
+ if (cmd < 0 || cmd > PRC_NCMDS)
+ return;
+ type = IPX_ERR_UNREACH_HOST;
+
+ switch (cmd) {
+
+ case PRC_ROUTEDEAD:
+ return;
+
+ case PRC_IFDOWN:
+ case PRC_HOSTDEAD:
+ case PRC_HOSTUNREACH:
+ sipx = (struct sockaddr_ipx *)arg;
+ if (sipx->sipx_family != AF_IPX)
+ return;
+ na = &sipx->sipx_addr;
+ break;
+
+ default:
+ errp = (struct ipx_errp *)arg;
+ na = &errp->ipx_err_ipx.ipx_dna;
+ type = errp->ipx_err_num;
+ type = ntohs((u_short)type);
+ break;
+ }
+ switch (type) {
+
+ case IPX_ERR_UNREACH_HOST:
+ ipx_pcbnotify(na, (int)ipxctlerrmap[cmd], spx_abort, (long) 0);
+ break;
+
+ case IPX_ERR_TOO_BIG:
+ case IPX_ERR_NOSOCK:
+ ipxp = ipx_pcblookup(na, errp->ipx_err_ipx.ipx_sna.x_port,
+ IPX_WILDCARD);
+ if (ipxp) {
+ if(ipxp->ipxp_pcb)
+ (void) spx_drop((struct spxpcb *)ipxp->ipxp_pcb,
+ (int)ipxctlerrmap[cmd]);
+ else
+ (void) ipx_drop(ipxp, (int)ipxctlerrmap[cmd]);
+ }
+ break;
+
+ case IPX_ERR_FULLUP:
+ ipx_pcbnotify(na, 0, spx_quench, (long) 0);
+ break;
+ }
+}
+/*
+ * When a source quench is received, close congestion window
+ * to one packet. We will gradually open it again as we proceed.
+ */
+void
+spx_quench(ipxp)
+ struct ipxpcb *ipxp;
+{
+ struct spxpcb *cb = ipxtospxpcb(ipxp);
+
+ if (cb)
+ cb->s_cwnd = CUNIT;
+}
+
+#ifdef notdef
+int
+spx_fixmtu(ipxp)
+register struct ipxpcb *ipxp;
+{
+ register struct spxpcb *cb = (struct spxpcb *)(ipxp->ipxp_pcb);
+ register struct mbuf *m;
+ register struct spx *si;
+ struct ipx_errp *ep;
+ struct sockbuf *sb;
+ int badseq, len;
+ struct mbuf *firstbad, *m0;
+
+ if (cb) {
+ /*
+ * The notification that we have sent
+ * too much is bad news -- we will
+ * have to go through queued up so far
+ * splitting ones which are too big and
+ * reassigning sequence numbers and checksums.
+ * we should then retransmit all packets from
+ * one above the offending packet to the last one
+ * we had sent (or our allocation)
+ * then the offending one so that the any queued
+ * data at our destination will be discarded.
+ */
+ ep = (struct ipx_errp *)ipxp->ipxp_notify_param;
+ sb = &ipxp->ipxp_socket->so_snd;
+ cb->s_mtu = ep->ipx_err_param;
+ badseq = SI(&ep->ipx_err_ipx)->si_seq;
+ for (m = sb->sb_mb; m; m = m->m_act) {
+ si = mtod(m, struct spx *);
+ if (si->si_seq == badseq)
+ break;
+ }
+ if (m == 0) return;
+ firstbad = m;
+ /*for (;;) {*/
+ /* calculate length */
+ for (m0 = m, len = 0; m ; m = m->m_next)
+ len += m->m_len;
+ if (len > cb->s_mtu) {
+ }
+ /* FINISH THIS
+ } */
+ }
+}
+#endif
+
+int
+spx_output(cb, m0)
+ register struct spxpcb *cb;
+ struct mbuf *m0;
+{
+ struct socket *so = cb->s_ipxpcb->ipxp_socket;
+ register struct mbuf *m;
+ register struct spx *si = (struct spx *) 0;
+ register struct sockbuf *sb = &so->so_snd;
+ int len = 0, win, rcv_win;
+ short span, off, recordp = 0;
+ u_short alo;
+ int error = 0, sendalot;
+#ifdef notdef
+ int idle;
+#endif
+ struct mbuf *mprev;
+
+ if (m0) {
+ int mtu = cb->s_mtu;
+ int datalen;
+ /*
+ * Make sure that packet isn't too big.
+ */
+ for (m = m0; m ; m = m->m_next) {
+ mprev = m;
+ len += m->m_len;
+ if (m->m_flags & M_EOR)
+ recordp = 1;
+ }
+ datalen = (cb->s_flags & SF_HO) ?
+ len - sizeof (struct spxhdr) : len;
+ if (datalen > mtu) {
+ if (cb->s_flags & SF_PI) {
+ m_freem(m0);
+ return (EMSGSIZE);
+ } else {
+ int oldEM = cb->s_cc & SPX_EM;
+
+ cb->s_cc &= ~SPX_EM;
+ while (len > mtu) {
+ /*
+ * Here we are only being called
+ * from usrreq(), so it is OK to
+ * block.
+ */
+ m = m_copym(m0, 0, mtu, M_WAIT);
+ if (cb->s_flags & SF_NEWCALL) {
+ struct mbuf *mm = m;
+ spx_newchecks[7]++;
+ while (mm) {
+ mm->m_flags &= ~M_EOR;
+ mm = mm->m_next;
+ }
+ }
+ error = spx_output(cb, m);
+ if (error) {
+ cb->s_cc |= oldEM;
+ m_freem(m0);
+ return(error);
+ }
+ m_adj(m0, mtu);
+ len -= mtu;
+ }
+ cb->s_cc |= oldEM;
+ }
+ }
+ /*
+ * Force length even, by adding a "garbage byte" if
+ * necessary.
+ */
+ if (len & 1) {
+ m = mprev;
+ if (M_TRAILINGSPACE(m) >= 1)
+ m->m_len++;
+ else {
+ struct mbuf *m1 = m_get(M_DONTWAIT, MT_DATA);
+
+ if (m1 == 0) {
+ m_freem(m0);
+ return (ENOBUFS);
+ }
+ m1->m_len = 1;
+ *(mtod(m1, u_char *)) = 0;
+ m->m_next = m1;
+ }
+ }
+ m = m_gethdr(M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ m_freem(m0);
+ return (ENOBUFS);
+ }
+ /*
+ * Fill in mbuf with extended SP header
+ * and addresses and length put into network format.
+ */
+ MH_ALIGN(m, sizeof (struct spx));
+ m->m_len = sizeof (struct spx);
+ m->m_next = m0;
+ si = mtod(m, struct spx *);
+ si->si_i = *cb->s_ipx;
+ si->si_s = cb->s_shdr;
+ if ((cb->s_flags & SF_PI) && (cb->s_flags & SF_HO)) {
+ register struct spxhdr *sh;
+ if (m0->m_len < sizeof (*sh)) {
+ if((m0 = m_pullup(m0, sizeof(*sh))) == NULL) {
+ (void) m_free(m);
+ m_freem(m0);
+ return (EINVAL);
+ }
+ m->m_next = m0;
+ }
+ sh = mtod(m0, struct spxhdr *);
+ si->si_dt = sh->spx_dt;
+ si->si_cc |= sh->spx_cc & SPX_EM;
+ m0->m_len -= sizeof (*sh);
+ m0->m_data += sizeof (*sh);
+ len -= sizeof (*sh);
+ }
+ len += sizeof(*si);
+ if ((cb->s_flags2 & SF_NEWCALL) && recordp) {
+ si->si_cc |= SPX_EM;
+ spx_newchecks[8]++;
+ }
+ if (cb->s_oobflags & SF_SOOB) {
+ /*
+ * Per jqj@cornell:
+ * make sure OB packets convey exactly 1 byte.
+ * If the packet is 1 byte or larger, we
+ * have already guaranted there to be at least
+ * one garbage byte for the checksum, and
+ * extra bytes shouldn't hurt!
+ */
+ if (len > sizeof(*si)) {
+ si->si_cc |= SPX_OB;
+ len = (1 + sizeof(*si));
+ }
+ }
+ si->si_len = htons((u_short)len);
+ m->m_pkthdr.len = ((len - 1) | 1) + 1;
+ /*
+ * queue stuff up for output
+ */
+ sbappendrecord(sb, m);
+ cb->s_seq++;
+ }
+#ifdef notdef
+ idle = (cb->s_smax == (cb->s_rack - 1));
+#endif
+again:
+ sendalot = 0;
+ off = cb->s_snxt - cb->s_rack;
+ win = min(cb->s_swnd, (cb->s_cwnd/CUNIT));
+
+ /*
+ * If in persist timeout with window of 0, send a probe.
+ * Otherwise, if window is small but nonzero
+ * and timer expired, send what we can and go into
+ * transmit state.
+ */
+ if (cb->s_force == 1 + SPXT_PERSIST) {
+ if (win != 0) {
+ cb->s_timer[SPXT_PERSIST] = 0;
+ cb->s_rxtshift = 0;
+ }
+ }
+ span = cb->s_seq - cb->s_rack;
+ len = min(span, win) - off;
+
+ if (len < 0) {
+ /*
+ * Window shrank after we went into it.
+ * If window shrank to 0, cancel pending
+ * restransmission and pull s_snxt back
+ * to (closed) window. We will enter persist
+ * state below. If the widndow didn't close completely,
+ * just wait for an ACK.
+ */
+ len = 0;
+ if (win == 0) {
+ cb->s_timer[SPXT_REXMT] = 0;
+ cb->s_snxt = cb->s_rack;
+ }
+ }
+ if (len > 1)
+ sendalot = 1;
+ rcv_win = sbspace(&so->so_rcv);
+
+ /*
+ * Send if we owe peer an ACK.
+ */
+ if (cb->s_oobflags & SF_SOOB) {
+ /*
+ * must transmit this out of band packet
+ */
+ cb->s_oobflags &= ~ SF_SOOB;
+ sendalot = 1;
+ spxstat.spxs_sndurg++;
+ goto found;
+ }
+ if (cb->s_flags & SF_ACKNOW)
+ goto send;
+ if (cb->s_state < TCPS_ESTABLISHED)
+ goto send;
+ /*
+ * Silly window can't happen in spx.
+ * Code from tcp deleted.
+ */
+ if (len)
+ goto send;
+ /*
+ * Compare available window to amount of window
+ * known to peer (as advertised window less
+ * next expected input.) If the difference is at least two
+ * packets or at least 35% of the mximum possible window,
+ * then want to send a window update to peer.
+ */
+ if (rcv_win > 0) {
+ u_short delta = 1 + cb->s_alo - cb->s_ack;
+ int adv = rcv_win - (delta * cb->s_mtu);
+
+ if ((so->so_rcv.sb_cc == 0 && adv >= (2 * cb->s_mtu)) ||
+ (100 * adv / so->so_rcv.sb_hiwat >= 35)) {
+ spxstat.spxs_sndwinup++;
+ cb->s_flags |= SF_ACKNOW;
+ goto send;
+ }
+
+ }
+ /*
+ * Many comments from tcp_output.c are appropriate here
+ * including . . .
+ * If send window is too small, there is data to transmit, and no
+ * retransmit or persist is pending, then go to persist state.
+ * If nothing happens soon, send when timer expires:
+ * if window is nonzero, transmit what we can,
+ * otherwise send a probe.
+ */
+ if (so->so_snd.sb_cc && cb->s_timer[SPXT_REXMT] == 0 &&
+ cb->s_timer[SPXT_PERSIST] == 0) {
+ cb->s_rxtshift = 0;
+ spx_setpersist(cb);
+ }
+ /*
+ * No reason to send a packet, just return.
+ */
+ cb->s_outx = 1;
+ return (0);
+
+send:
+ /*
+ * Find requested packet.
+ */
+ si = 0;
+ if (len > 0) {
+ cb->s_want = cb->s_snxt;
+ for (m = sb->sb_mb; m; m = m->m_act) {
+ si = mtod(m, struct spx *);
+ if (SSEQ_LEQ(cb->s_snxt, si->si_seq))
+ break;
+ }
+ found:
+ if (si) {
+ if (si->si_seq == cb->s_snxt)
+ cb->s_snxt++;
+ else
+ spxstat.spxs_sndvoid++, si = 0;
+ }
+ }
+ /*
+ * update window
+ */
+ if (rcv_win < 0)
+ rcv_win = 0;
+ alo = cb->s_ack - 1 + (rcv_win / ((short)cb->s_mtu));
+ if (SSEQ_LT(alo, cb->s_alo))
+ alo = cb->s_alo;
+
+ if (si) {
+ /*
+ * must make a copy of this packet for
+ * ipx_output to monkey with
+ */
+ m = m_copy(dtom(si), 0, (int)M_COPYALL);
+ if (m == NULL) {
+ return (ENOBUFS);
+ }
+ si = mtod(m, struct spx *);
+ if (SSEQ_LT(si->si_seq, cb->s_smax))
+ spxstat.spxs_sndrexmitpack++;
+ else
+ spxstat.spxs_sndpack++;
+ } else if (cb->s_force || cb->s_flags & SF_ACKNOW) {
+ /*
+ * Must send an acknowledgement or a probe
+ */
+ if (cb->s_force)
+ spxstat.spxs_sndprobe++;
+ if (cb->s_flags & SF_ACKNOW)
+ spxstat.spxs_sndacks++;
+ m = m_gethdr(M_DONTWAIT, MT_HEADER);
+ if (m == 0)
+ return (ENOBUFS);
+ /*
+ * Fill in mbuf with extended SP header
+ * and addresses and length put into network format.
+ */
+ MH_ALIGN(m, sizeof (struct spx));
+ m->m_len = sizeof (*si);
+ m->m_pkthdr.len = sizeof (*si);
+ si = mtod(m, struct spx *);
+ si->si_i = *cb->s_ipx;
+ si->si_s = cb->s_shdr;
+ si->si_seq = cb->s_smax + 1;
+ si->si_len = htons(sizeof (*si));
+ si->si_cc |= SPX_SP;
+ } else {
+ cb->s_outx = 3;
+ if (so->so_options & SO_DEBUG || traceallspxs)
+ spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
+ return (0);
+ }
+ /*
+ * Stuff checksum and output datagram.
+ */
+ if ((si->si_cc & SPX_SP) == 0) {
+ if (cb->s_force != (1 + SPXT_PERSIST) ||
+ cb->s_timer[SPXT_PERSIST] == 0) {
+ /*
+ * If this is a new packet and we are not currently
+ * timing anything, time this one.
+ */
+ if (SSEQ_LT(cb->s_smax, si->si_seq)) {
+ cb->s_smax = si->si_seq;
+ if (cb->s_rtt == 0) {
+ spxstat.spxs_segstimed++;
+ cb->s_rtseq = si->si_seq;
+ cb->s_rtt = 1;
+ }
+ }
+ /*
+ * Set rexmt timer if not currently set,
+ * Initial value for retransmit timer is smoothed
+ * round-trip time + 2 * round-trip time variance.
+ * Initialize shift counter which is used for backoff
+ * of retransmit time.
+ */
+ if (cb->s_timer[SPXT_REXMT] == 0 &&
+ cb->s_snxt != cb->s_rack) {
+ cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
+ if (cb->s_timer[SPXT_PERSIST]) {
+ cb->s_timer[SPXT_PERSIST] = 0;
+ cb->s_rxtshift = 0;
+ }
+ }
+ } else if (SSEQ_LT(cb->s_smax, si->si_seq)) {
+ cb->s_smax = si->si_seq;
+ }
+ } else if (cb->s_state < TCPS_ESTABLISHED) {
+ if (cb->s_rtt == 0)
+ cb->s_rtt = 1; /* Time initial handshake */
+ if (cb->s_timer[SPXT_REXMT] == 0)
+ cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
+ }
+ {
+ /*
+ * Do not request acks when we ack their data packets or
+ * when we do a gratuitous window update.
+ */
+ if (((si->si_cc & SPX_SP) == 0) || cb->s_force)
+ si->si_cc |= SPX_SA;
+ si->si_seq = htons(si->si_seq);
+ si->si_alo = htons(alo);
+ si->si_ack = htons(cb->s_ack);
+
+ if (ipxcksum) {
+ si->si_sum = 0;
+ len = ntohs(si->si_len);
+ if (len & 1)
+ len++;
+ si->si_sum = ipx_cksum(m, len);
+ } else
+ si->si_sum = 0xffff;
+
+ cb->s_outx = 4;
+ if (so->so_options & SO_DEBUG || traceallspxs)
+ spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0);
+
+ if (so->so_options & SO_DONTROUTE)
+ error = ipx_outputfl(m, (struct route *)0, IPX_ROUTETOIF);
+ else
+ error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0);
+ }
+ if (error) {
+ return (error);
+ }
+ spxstat.spxs_sndtotal++;
+ /*
+ * Data sent (as far as we can tell).
+ * If this advertises a larger window than any other segment,
+ * then remember the size of the advertized window.
+ * Any pending ACK has now been sent.
+ */
+ cb->s_force = 0;
+ cb->s_flags &= ~(SF_ACKNOW|SF_DELACK);
+ if (SSEQ_GT(alo, cb->s_alo))
+ cb->s_alo = alo;
+ if (sendalot)
+ goto again;
+ cb->s_outx = 5;
+ return (0);
+}
+
+int spx_do_persist_panics = 0;
+
+void
+spx_setpersist(cb)
+ register struct spxpcb *cb;
+{
+ register t = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
+
+ if (cb->s_timer[SPXT_REXMT] && spx_do_persist_panics)
+ panic("spx_output REXMT");
+ /*
+ * Start/restart persistance timer.
+ */
+ SPXT_RANGESET(cb->s_timer[SPXT_PERSIST],
+ t*spx_backoff[cb->s_rxtshift],
+ SPXTV_PERSMIN, SPXTV_PERSMAX);
+ if (cb->s_rxtshift < SPX_MAXRXTSHIFT)
+ cb->s_rxtshift++;
+}
+/*ARGSUSED*/
+int
+spx_ctloutput(req, so, level, name, value)
+ int req;
+ struct socket *so;
+ int level, name;
+ struct mbuf **value;
+{
+ register struct mbuf *m;
+ struct ipxpcb *ipxp = sotoipxpcb(so);
+ register struct spxpcb *cb;
+ int mask, error = 0;
+
+ if (level != IPXPROTO_SPX) {
+ /* This will have to be changed when we do more general
+ stacking of protocols */
+ return (ipx_ctloutput(req, so, level, name, value));
+ }
+ if (ipxp == NULL) {
+ error = EINVAL;
+ goto release;
+ } else
+ cb = ipxtospxpcb(ipxp);
+
+ switch (req) {
+
+ case PRCO_GETOPT:
+ if (value == NULL)
+ return (EINVAL);
+ m = m_get(M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (ENOBUFS);
+ switch (name) {
+
+ case SO_HEADERS_ON_INPUT:
+ mask = SF_HI;
+ goto get_flags;
+
+ case SO_HEADERS_ON_OUTPUT:
+ mask = SF_HO;
+ get_flags:
+ m->m_len = sizeof(short);
+ *mtod(m, short *) = cb->s_flags & mask;
+ break;
+
+ case SO_MTU:
+ m->m_len = sizeof(u_short);
+ *mtod(m, short *) = cb->s_mtu;
+ break;
+
+ case SO_LAST_HEADER:
+ m->m_len = sizeof(struct spxhdr);
+ *mtod(m, struct spxhdr *) = cb->s_rhdr;
+ break;
+
+ case SO_DEFAULT_HEADERS:
+ m->m_len = sizeof(struct spx);
+ *mtod(m, struct spxhdr *) = cb->s_shdr;
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ *value = m;
+ break;
+
+ case PRCO_SETOPT:
+ if (value == 0 || *value == 0) {
+ error = EINVAL;
+ break;
+ }
+ switch (name) {
+ int *ok;
+
+ case SO_HEADERS_ON_INPUT:
+ mask = SF_HI;
+ goto set_head;
+
+ case SO_HEADERS_ON_OUTPUT:
+ mask = SF_HO;
+ set_head:
+ if (cb->s_flags & SF_PI) {
+ ok = mtod(*value, int *);
+ if (*ok)
+ cb->s_flags |= mask;
+ else
+ cb->s_flags &= ~mask;
+ } else error = EINVAL;
+ break;
+
+ case SO_MTU:
+ cb->s_mtu = *(mtod(*value, u_short *));
+ break;
+
+#ifdef SF_NEWCALL
+ case SO_NEWCALL:
+ ok = mtod(*value, int *);
+ if (*ok) {
+ cb->s_flags2 |= SF_NEWCALL;
+ spx_newchecks[5]++;
+ } else {
+ cb->s_flags2 &= ~SF_NEWCALL;
+ spx_newchecks[6]++;
+ }
+ break;
+#endif
+
+ case SO_DEFAULT_HEADERS:
+ {
+ register struct spxhdr *sp
+ = mtod(*value, struct spxhdr *);
+ cb->s_dt = sp->spx_dt;
+ cb->s_cc = sp->spx_cc & SPX_EM;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ m_freem(*value);
+ break;
+ }
+ release:
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+spx_usrreq(so, req, m, nam, controlp)
+ struct socket *so;
+ int req;
+ struct mbuf *m, *nam, *controlp;
+{
+ struct ipxpcb *ipxp = sotoipxpcb(so);
+ register struct spxpcb *cb = NULL;
+ int s = splnet();
+ int error = 0, ostate;
+ struct mbuf *mm;
+ register struct sockbuf *sb;
+
+ if (req == PRU_CONTROL)
+ return (ipx_control(so, (int)m, (caddr_t)nam,
+ (struct ifnet *)controlp));
+ if (ipxp == NULL) {
+ if (req != PRU_ATTACH) {
+ error = EINVAL;
+ goto release;
+ }
+ } else
+ cb = ipxtospxpcb(ipxp);
+
+ ostate = cb ? cb->s_state : 0;
+
+ switch (req) {
+
+ case PRU_ATTACH:
+ if (ipxp != NULL) {
+ error = EISCONN;
+ break;
+ }
+ error = ipx_pcballoc(so, &ipxpcb);
+ if (error)
+ break;
+ if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
+ error = soreserve(so, (u_long) 3072, (u_long) 3072);
+ if (error)
+ break;
+ }
+ ipxp = sotoipxpcb(so);
+
+ mm = m_getclr(M_DONTWAIT, MT_PCB);
+ sb = &so->so_snd;
+
+ if (mm == NULL) {
+ error = ENOBUFS;
+ break;
+ }
+ cb = mtod(mm, struct spxpcb *);
+ mm = m_getclr(M_DONTWAIT, MT_HEADER);
+ if (mm == NULL) {
+ (void) m_free(dtom(m));
+ error = ENOBUFS;
+ break;
+ }
+ cb->s_ipx = mtod(mm, struct ipx *);
+ cb->s_state = TCPS_LISTEN;
+ cb->s_smax = -1;
+ cb->s_swl1 = -1;
+ cb->s_q.si_next = cb->s_q.si_prev = &cb->s_q;
+ cb->s_ipxpcb = ipxp;
+ cb->s_mtu = 576 - sizeof (struct spx);
+ cb->s_cwnd = sbspace(sb) * CUNIT / cb->s_mtu;
+ cb->s_ssthresh = cb->s_cwnd;
+ cb->s_cwmx = sbspace(sb) * CUNIT /
+ (2 * sizeof (struct spx));
+ /* Above is recomputed when connecting to account
+ for changed buffering or mtu's */
+ cb->s_rtt = SPXTV_SRTTBASE;
+ cb->s_rttvar = SPXTV_SRTTDFLT << 2;
+ SPXT_RANGESET(cb->s_rxtcur,
+ ((SPXTV_SRTTBASE >> 2) + (SPXTV_SRTTDFLT << 2)) >> 1,
+ SPXTV_MIN, SPXTV_REXMTMAX);
+ ipxp->ipxp_pcb = (caddr_t) cb;
+ break;
+
+ case PRU_DETACH:
+ if (ipxp == NULL) {
+ error = ENOTCONN;
+ break;
+ }
+ if (cb->s_state > TCPS_LISTEN)
+ cb = spx_disconnect(cb);
+ else
+ cb = spx_close(cb);
+ break;
+
+ case PRU_BIND:
+ error = ipx_pcbbind(ipxp, nam);
+ break;
+
+ case PRU_LISTEN:
+ if (ipxp->ipxp_lport == 0)
+ error = ipx_pcbbind(ipxp, (struct mbuf *)0);
+ if (error == 0)
+ cb->s_state = TCPS_LISTEN;
+ break;
+
+ /*
+ * Initiate connection to peer.
+ * Enter SYN_SENT state, and mark socket as connecting.
+ * Start keep-alive timer, setup prototype header,
+ * Send initial system packet requesting connection.
+ */
+ case PRU_CONNECT:
+ if (ipxp->ipxp_lport == 0) {
+ error = ipx_pcbbind(ipxp, (struct mbuf *)0);
+ if (error)
+ break;
+ }
+ error = ipx_pcbconnect(ipxp, nam);
+ if (error)
+ break;
+ soisconnecting(so);
+ spxstat.spxs_connattempt++;
+ cb->s_state = TCPS_SYN_SENT;
+ cb->s_did = 0;
+ spx_template(cb);
+ cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
+ cb->s_force = 1 + SPXTV_KEEP;
+ /*
+ * Other party is required to respond to
+ * the port I send from, but he is not
+ * required to answer from where I am sending to,
+ * so allow wildcarding.
+ * original port I am sending to is still saved in
+ * cb->s_dport.
+ */
+ ipxp->ipxp_fport = 0;
+ error = spx_output(cb, (struct mbuf *) 0);
+ break;
+
+ case PRU_CONNECT2:
+ error = EOPNOTSUPP;
+ break;
+
+ /*
+ * We may decide later to implement connection closing
+ * handshaking at the spx level optionally.
+ * here is the hook to do it:
+ */
+ case PRU_DISCONNECT:
+ cb = spx_disconnect(cb);
+ break;
+
+ /*
+ * Accept a connection. Essentially all the work is
+ * done at higher levels; just return the address
+ * of the peer, storing through addr.
+ */
+ case PRU_ACCEPT: {
+ struct sockaddr_ipx *sipx = mtod(nam, struct sockaddr_ipx *);
+
+ nam->m_len = sizeof (struct sockaddr_ipx);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_addr = ipxp->ipxp_faddr;
+ break;
+ }
+
+ case PRU_SHUTDOWN:
+ socantsendmore(so);
+ cb = spx_usrclosed(cb);
+ if (cb)
+ error = spx_output(cb, (struct mbuf *) 0);
+ break;
+
+ /*
+ * After a receive, possibly send acknowledgment
+ * updating allocation.
+ */
+ case PRU_RCVD:
+ cb->s_flags |= SF_RVD;
+ (void) spx_output(cb, (struct mbuf *) 0);
+ cb->s_flags &= ~SF_RVD;
+ break;
+
+ case PRU_ABORT:
+ (void) spx_drop(cb, ECONNABORTED);
+ break;
+
+ case PRU_SENSE:
+ case PRU_CONTROL:
+ m = NULL;
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_RCVOOB:
+ if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark ||
+ (so->so_state & SS_RCVATMARK)) {
+ m->m_len = 1;
+ *mtod(m, caddr_t) = cb->s_iobc;
+ break;
+ }
+ error = EINVAL;
+ break;
+
+ case PRU_SENDOOB:
+ if (sbspace(&so->so_snd) < -512) {
+ error = ENOBUFS;
+ break;
+ }
+ cb->s_oobflags |= SF_SOOB;
+ /* fall into */
+ case PRU_SEND:
+ if (controlp) {
+ u_short *p = mtod(controlp, u_short *);
+ spx_newchecks[2]++;
+ if ((p[0] == 5) && p[1] == 1) { /* XXXX, for testing */
+ cb->s_shdr.spx_dt = *(u_char *)(&p[2]);
+ spx_newchecks[3]++;
+ }
+ m_freem(controlp);
+ }
+ controlp = NULL;
+ error = spx_output(cb, m);
+ m = NULL;
+ break;
+
+ case PRU_SOCKADDR:
+ ipx_setsockaddr(ipxp, nam);
+ break;
+
+ case PRU_PEERADDR:
+ ipx_setpeeraddr(ipxp, nam);
+ break;
+
+ case PRU_SLOWTIMO:
+ cb = spx_timers(cb, (int)nam);
+ req |= ((int)nam) << 8;
+ break;
+
+ case PRU_FASTTIMO:
+ case PRU_PROTORCV:
+ case PRU_PROTOSEND:
+ error = EOPNOTSUPP;
+ break;
+
+ default:
+ panic("spx_usrreq");
+ }
+ if (cb && (so->so_options & SO_DEBUG || traceallspxs))
+ spx_trace(SA_USER, (u_char)ostate, cb, (struct spx *)0, req);
+release:
+ if (controlp != NULL)
+ m_freem(controlp);
+ if (m != NULL)
+ m_freem(m);
+ splx(s);
+ return (error);
+}
+
+int
+spx_usrreq_sp(so, req, m, nam, controlp)
+ struct socket *so;
+ int req;
+ struct mbuf *m, *nam, *controlp;
+{
+ int error = spx_usrreq(so, req, m, nam, controlp);
+
+ if (req == PRU_ATTACH && error == 0) {
+ struct ipxpcb *ipxp = sotoipxpcb(so);
+ ((struct spxpcb *)ipxp->ipxp_pcb)->s_flags |=
+ (SF_HI | SF_HO | SF_PI);
+ }
+ return (error);
+}
+
+/*
+ * Create template to be used to send spx packets on a connection.
+ * Called after host entry created, fills
+ * in a skeletal spx header (choosing connection id),
+ * minimizing the amount of work necessary when the connection is used.
+ */
+void
+spx_template(cb)
+ register struct spxpcb *cb;
+{
+ register struct ipxpcb *ipxp = cb->s_ipxpcb;
+ register struct ipx *ipx = cb->s_ipx;
+ register struct sockbuf *sb = &(ipxp->ipxp_socket->so_snd);
+
+ ipx->ipx_pt = IPXPROTO_SPX;
+ ipx->ipx_sna = ipxp->ipxp_laddr;
+ ipx->ipx_dna = ipxp->ipxp_faddr;
+ cb->s_sid = htons(spx_iss);
+ spx_iss += SPX_ISSINCR/2;
+ cb->s_alo = 1;
+ cb->s_cwnd = (sbspace(sb) * CUNIT) / cb->s_mtu;
+ cb->s_ssthresh = cb->s_cwnd; /* Try to expand fast to full complement
+ of large packets */
+ cb->s_cwmx = (sbspace(sb) * CUNIT) / (2 * sizeof(struct spx));
+ cb->s_cwmx = max(cb->s_cwmx, cb->s_cwnd);
+ /* But allow for lots of little packets as well */
+}
+
+/*
+ * Close a SPIP control block:
+ * discard spx control block itself
+ * discard ipx protocol control block
+ * wake up any sleepers
+ */
+struct spxpcb *
+spx_close(cb)
+ register struct spxpcb *cb;
+{
+ register struct spx_q *s;
+ struct ipxpcb *ipxp = cb->s_ipxpcb;
+ struct socket *so = ipxp->ipxp_socket;
+ register struct mbuf *m;
+
+ s = cb->s_q.si_next;
+ while (s != &(cb->s_q)) {
+ s = s->si_next;
+ m = dtom(s->si_prev);
+ remque(s->si_prev);
+ m_freem(m);
+ }
+ (void) m_free(dtom(cb->s_ipx));
+ (void) m_free(dtom(cb));
+ ipxp->ipxp_pcb = 0;
+ soisdisconnected(so);
+ ipx_pcbdetach(ipxp);
+ spxstat.spxs_closed++;
+ return ((struct spxpcb *)0);
+}
+/*
+ * Someday we may do level 3 handshaking
+ * to close a connection or send a xerox style error.
+ * For now, just close.
+ */
+struct spxpcb *
+spx_usrclosed(cb)
+ register struct spxpcb *cb;
+{
+ return (spx_close(cb));
+}
+struct spxpcb *
+spx_disconnect(cb)
+ register struct spxpcb *cb;
+{
+ return (spx_close(cb));
+}
+/*
+ * Drop connection, reporting
+ * the specified error.
+ */
+struct spxpcb *
+spx_drop(cb, errno)
+ register struct spxpcb *cb;
+ int errno;
+{
+ struct socket *so = cb->s_ipxpcb->ipxp_socket;
+
+ /*
+ * someday, in the xerox world
+ * we will generate error protocol packets
+ * announcing that the socket has gone away.
+ */
+ if (TCPS_HAVERCVDSYN(cb->s_state)) {
+ spxstat.spxs_drops++;
+ cb->s_state = TCPS_CLOSED;
+ /*(void) tcp_output(cb);*/
+ } else
+ spxstat.spxs_conndrops++;
+ so->so_error = errno;
+ return (spx_close(cb));
+}
+
+void
+spx_abort(ipxp)
+ struct ipxpcb *ipxp;
+{
+
+ (void) spx_close((struct spxpcb *)ipxp->ipxp_pcb);
+}
+
+int spx_backoff[SPX_MAXRXTSHIFT+1] =
+ { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
+/*
+ * Fast timeout routine for processing delayed acks
+ */
+void
+spx_fasttimo()
+{
+ register struct ipxpcb *ipxp;
+ register struct spxpcb *cb;
+ int s = splnet();
+
+ ipxp = ipxpcb.ipxp_next;
+ if (ipxp)
+ for (; ipxp != &ipxpcb; ipxp = ipxp->ipxp_next)
+ if ((cb = (struct spxpcb *)ipxp->ipxp_pcb) &&
+ (cb->s_flags & SF_DELACK)) {
+ cb->s_flags &= ~SF_DELACK;
+ cb->s_flags |= SF_ACKNOW;
+ spxstat.spxs_delack++;
+ (void) spx_output(cb, (struct mbuf *) 0);
+ }
+ splx(s);
+}
+
+/*
+ * spx protocol timeout routine called every 500 ms.
+ * Updates the timers in all active pcb's and
+ * causes finite state machine actions if timers expire.
+ */
+void
+spx_slowtimo()
+{
+ register struct ipxpcb *ip, *ipnxt;
+ register struct spxpcb *cb;
+ int s = splnet();
+ register int i;
+
+ /*
+ * Search through tcb's and update active timers.
+ */
+ ip = ipxpcb.ipxp_next;
+ if (ip == 0) {
+ splx(s);
+ return;
+ }
+ while (ip != &ipxpcb) {
+ cb = ipxtospxpcb(ip);
+ ipnxt = ip->ipxp_next;
+ if (cb == 0)
+ goto tpgone;
+ for (i = 0; i < SPXT_NTIMERS; i++) {
+ if (cb->s_timer[i] && --cb->s_timer[i] == 0) {
+ (void) spx_usrreq(cb->s_ipxpcb->ipxp_socket,
+ PRU_SLOWTIMO, (struct mbuf *)0,
+ (struct mbuf *)i, (struct mbuf *)0,
+ (struct mbuf *)0);
+ if (ipnxt->ipxp_prev != ip)
+ goto tpgone;
+ }
+ }
+ cb->s_idle++;
+ if (cb->s_rtt)
+ cb->s_rtt++;
+tpgone:
+ ip = ipnxt;
+ }
+ spx_iss += SPX_ISSINCR/PR_SLOWHZ; /* increment iss */
+ splx(s);
+}
+/*
+ * SPX timer processing.
+ */
+struct spxpcb *
+spx_timers(cb, timer)
+ register struct spxpcb *cb;
+ int timer;
+{
+ long rexmt;
+ int win;
+
+ cb->s_force = 1 + timer;
+ switch (timer) {
+
+ /*
+ * 2 MSL timeout in shutdown went off. TCP deletes connection
+ * control block.
+ */
+ case SPXT_2MSL:
+ printf("spx: SPXT_2MSL went off for no reason\n");
+ cb->s_timer[timer] = 0;
+ break;
+
+ /*
+ * Retransmission timer went off. Message has not
+ * been acked within retransmit interval. Back off
+ * to a longer retransmit interval and retransmit one packet.
+ */
+ case SPXT_REXMT:
+ if (++cb->s_rxtshift > SPX_MAXRXTSHIFT) {
+ cb->s_rxtshift = SPX_MAXRXTSHIFT;
+ spxstat.spxs_timeoutdrop++;
+ cb = spx_drop(cb, ETIMEDOUT);
+ break;
+ }
+ spxstat.spxs_rexmttimeo++;
+ rexmt = ((cb->s_srtt >> 2) + cb->s_rttvar) >> 1;
+ rexmt *= spx_backoff[cb->s_rxtshift];
+ SPXT_RANGESET(cb->s_rxtcur, rexmt, SPXTV_MIN, SPXTV_REXMTMAX);
+ cb->s_timer[SPXT_REXMT] = cb->s_rxtcur;
+ /*
+ * If we have backed off fairly far, our srtt
+ * estimate is probably bogus. Clobber it
+ * so we'll take the next rtt measurement as our srtt;
+ * move the current srtt into rttvar to keep the current
+ * retransmit times until then.
+ */
+ if (cb->s_rxtshift > SPX_MAXRXTSHIFT / 4 ) {
+ cb->s_rttvar += (cb->s_srtt >> 2);
+ cb->s_srtt = 0;
+ }
+ cb->s_snxt = cb->s_rack;
+ /*
+ * If timing a packet, stop the timer.
+ */
+ cb->s_rtt = 0;
+ /*
+ * See very long discussion in tcp_timer.c about congestion
+ * window and sstrhesh
+ */
+ win = min(cb->s_swnd, (cb->s_cwnd/CUNIT)) / 2;
+ if (win < 2)
+ win = 2;
+ cb->s_cwnd = CUNIT;
+ cb->s_ssthresh = win * CUNIT;
+ (void) spx_output(cb, (struct mbuf *) 0);
+ break;
+
+ /*
+ * Persistance timer into zero window.
+ * Force a probe to be sent.
+ */
+ case SPXT_PERSIST:
+ spxstat.spxs_persisttimeo++;
+ spx_setpersist(cb);
+ (void) spx_output(cb, (struct mbuf *) 0);
+ break;
+
+ /*
+ * Keep-alive timer went off; send something
+ * or drop connection if idle for too long.
+ */
+ case SPXT_KEEP:
+ spxstat.spxs_keeptimeo++;
+ if (cb->s_state < TCPS_ESTABLISHED)
+ goto dropit;
+ if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) {
+ if (cb->s_idle >= SPXTV_MAXIDLE)
+ goto dropit;
+ spxstat.spxs_keepprobe++;
+ (void) spx_output(cb, (struct mbuf *) 0);
+ } else
+ cb->s_idle = 0;
+ cb->s_timer[SPXT_KEEP] = SPXTV_KEEP;
+ break;
+ dropit:
+ spxstat.spxs_keepdrops++;
+ cb = spx_drop(cb, ETIMEDOUT);
+ break;
+ }
+ return (cb);
+}
diff --git a/sys/netipx/spx_var.h b/sys/netipx/spx_var.h
new file mode 100644
index 0000000..2e87ee0
--- /dev/null
+++ b/sys/netipx/spx_var.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 1995, Mike Mitchell
+ * Copyright (c) 1984, 1985, 1986, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)spx_var.h
+ */
+
+#ifndef _NETIPX_SPX_VAR_H_
+#define _NETIPX_SPX_VAR_H_
+
+/*
+ * SPX control block, one per connection
+ */
+struct spxpcb {
+ struct spx_q s_q; /* queue for out-of-order receipt */
+ struct ipxpcb *s_ipxpcb; /* backpointer to internet pcb */
+ u_char s_state;
+ u_char s_flags;
+#define SF_ACKNOW 0x01 /* Ack peer immediately */
+#define SF_DELACK 0x02 /* Ack, but try to delay it */
+#define SF_HI 0x04 /* Show headers on input */
+#define SF_HO 0x08 /* Show headers on output */
+#define SF_PI 0x10 /* Packet (datagram) interface */
+#define SF_WIN 0x20 /* Window info changed */
+#define SF_RXT 0x40 /* Rxt info changed */
+#define SF_RVD 0x80 /* Calling from read usrreq routine */
+ u_short s_mtu; /* Max packet size for this stream */
+/* use sequence fields in headers to store sequence numbers for this
+ connection */
+ struct ipx *s_ipx;
+ struct spxhdr s_shdr; /* prototype header to transmit */
+#define s_cc s_shdr.spx_cc /* connection control (for EM bit) */
+#define s_dt s_shdr.spx_dt /* datastream type */
+#define s_sid s_shdr.spx_sid /* source connection identifier */
+#define s_did s_shdr.spx_did /* destination connection identifier */
+#define s_seq s_shdr.spx_seq /* sequence number */
+#define s_ack s_shdr.spx_ack /* acknowledge number */
+#define s_alo s_shdr.spx_alo /* allocation number */
+#define s_dport s_ipx->ipx_dna.x_port /* where we are sending */
+ struct spxhdr s_rhdr; /* last received header (in effect!)*/
+ u_short s_rack; /* their acknowledge number */
+ u_short s_ralo; /* their allocation number */
+ u_short s_smax; /* highest packet # we have sent */
+ u_short s_snxt; /* which packet to send next */
+
+/* congestion control */
+#define CUNIT 1024 /* scaling for ... */
+ int s_cwnd; /* Congestion-controlled window */
+ /* in packets * CUNIT */
+ short s_swnd; /* == tcp snd_wnd, in packets */
+ short s_smxw; /* == tcp max_sndwnd */
+ /* difference of two spx_seq's can be
+ no bigger than a short */
+ u_short s_swl1; /* == tcp snd_wl1 */
+ u_short s_swl2; /* == tcp snd_wl2 */
+ int s_cwmx; /* max allowable cwnd */
+ int s_ssthresh; /* s_cwnd size threshhold for
+ * slow start exponential-to-
+ * linear switch */
+/* transmit timing stuff
+ * srtt and rttvar are stored as fixed point, for convenience in smoothing.
+ * srtt has 3 bits to the right of the binary point, rttvar has 2.
+ */
+ short s_idle; /* time idle */
+ short s_timer[SPXT_NTIMERS]; /* timers */
+ short s_rxtshift; /* log(2) of rexmt exp. backoff */
+ short s_rxtcur; /* current retransmit value */
+ u_short s_rtseq; /* packet being timed */
+ short s_rtt; /* timer for round trips */
+ short s_srtt; /* averaged timer */
+ short s_rttvar; /* variance in round trip time */
+ char s_force; /* which timer expired */
+ char s_dupacks; /* counter to intuit xmt loss */
+
+/* out of band data */
+ char s_oobflags;
+#define SF_SOOB 0x08 /* sending out of band data */
+#define SF_IOOB 0x10 /* receiving out of band data */
+ char s_iobc; /* input characters */
+/* debug stuff */
+ u_short s_want; /* Last candidate for sending */
+ char s_outx; /* exit taken from spx_output */
+ char s_inx; /* exit taken from spx_input */
+ u_short s_flags2; /* more flags for testing */
+#define SF_NEWCALL 0x100 /* for new_recvmsg */
+#define SO_NEWCALL 10 /* for new_recvmsg */
+};
+
+#define ipxtospxpcb(np) ((struct spxpcb *)(np)->ipxp_pcb)
+#define sotospxpcb(so) (ipxtospxpcb(sotoipxpcb(so)))
+
+struct spxstat {
+ long spxs_connattempt; /* connections initiated */
+ long spxs_accepts; /* connections accepted */
+ long spxs_connects; /* connections established */
+ long spxs_drops; /* connections dropped */
+ long spxs_conndrops; /* embryonic connections dropped */
+ long spxs_closed; /* conn. closed (includes drops) */
+ long spxs_segstimed; /* segs where we tried to get rtt */
+ long spxs_rttupdated; /* times we succeeded */
+ long spxs_delack; /* delayed acks sent */
+ long spxs_timeoutdrop; /* conn. dropped in rxmt timeout */
+ long spxs_rexmttimeo; /* retransmit timeouts */
+ long spxs_persisttimeo; /* persist timeouts */
+ long spxs_keeptimeo; /* keepalive timeouts */
+ long spxs_keepprobe; /* keepalive probes sent */
+ long spxs_keepdrops; /* connections dropped in keepalive */
+
+ long spxs_sndtotal; /* total packets sent */
+ long spxs_sndpack; /* data packets sent */
+ long spxs_sndbyte; /* data bytes sent */
+ long spxs_sndrexmitpack; /* data packets retransmitted */
+ long spxs_sndrexmitbyte; /* data bytes retransmitted */
+ long spxs_sndacks; /* ack-only packets sent */
+ long spxs_sndprobe; /* window probes sent */
+ long spxs_sndurg; /* packets sent with URG only */
+ long spxs_sndwinup; /* window update-only packets sent */
+ long spxs_sndctrl; /* control (SYN|FIN|RST) packets sent */
+ long spxs_sndvoid; /* couldn't find requested packet*/
+
+ long spxs_rcvtotal; /* total packets received */
+ long spxs_rcvpack; /* packets received in sequence */
+ long spxs_rcvbyte; /* bytes received in sequence */
+ long spxs_rcvbadsum; /* packets received with ccksum errs */
+ long spxs_rcvbadoff; /* packets received with bad offset */
+ long spxs_rcvshort; /* packets received too short */
+ long spxs_rcvduppack; /* duplicate-only packets received */
+ long spxs_rcvdupbyte; /* duplicate-only bytes received */
+ long spxs_rcvpartduppack; /* packets with some duplicate data */
+ long spxs_rcvpartdupbyte; /* dup. bytes in part-dup. packets */
+ long spxs_rcvoopack; /* out-of-order packets received */
+ long spxs_rcvoobyte; /* out-of-order bytes received */
+ long spxs_rcvpackafterwin; /* packets with data after window */
+ long spxs_rcvbyteafterwin; /* bytes rcvd after window */
+ long spxs_rcvafterclose; /* packets rcvd after "close" */
+ long spxs_rcvwinprobe; /* rcvd window probe packets */
+ long spxs_rcvdupack; /* rcvd duplicate acks */
+ long spxs_rcvacktoomuch; /* rcvd acks for unsent data */
+ long spxs_rcvackpack; /* rcvd ack packets */
+ long spxs_rcvackbyte; /* bytes acked by rcvd acks */
+ long spxs_rcvwinupd; /* rcvd window update packets */
+};
+struct spx_istat {
+ short hdrops;
+ short badsum;
+ short badlen;
+ short slotim;
+ short fastim;
+ short nonucn;
+ short noconn;
+ short notme;
+ short wrncon;
+ short bdreas;
+ short gonawy;
+ short notyet;
+ short lstdup;
+ struct spxstat newstats;
+};
+
+#ifdef KERNEL
+extern struct spx_istat spx_istat;
+extern u_short spx_iss;
+
+/* Following was struct spxstat spxstat; */
+#ifndef spxstat
+#define spxstat spx_istat.newstats
+#endif
+
+#endif
+
+#define SPX_ISSINCR 128
+/*
+ * spx sequence numbers are 16 bit integers operated
+ * on with modular arithmetic. These macros can be
+ * used to compare such integers.
+ */
+#define SSEQ_LT(a,b) (((short)((a)-(b))) < 0)
+#define SSEQ_LEQ(a,b) (((short)((a)-(b))) <= 0)
+#define SSEQ_GT(a,b) (((short)((a)-(b))) > 0)
+#define SSEQ_GEQ(a,b) (((short)((a)-(b))) >= 0)
+
+#endif
diff --git a/sys/netns/ns.h b/sys/netns/ns.h
index 7dd35a6..c737600 100644
--- a/sys/netns/ns.h
+++ b/sys/netns/ns.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)ns.h 8.1 (Berkeley) 6/10/93
- * $Id: ns.h,v 1.3 1994/08/21 06:22:07 paul Exp $
+ * $Id: ns.h,v 1.4 1995/07/29 11:41:49 bde Exp $
*/
#ifndef _NETNS_NS_H_
@@ -150,6 +150,7 @@ u_short ns_cksum();
__BEGIN_DECLS
extern struct ns_addr ns_addr __P((const char *));
extern char *ns_ntoa __P((struct ns_addr));
+extern char *_ns_spectHex __P((const char *));
__END_DECLS
#endif
OpenPOWER on IntegriCloud