diff -u --recursive --new-file v1.1.16/linux/Makefile linux/Makefile
--- v1.1.16/linux/Makefile	Tue May 31 12:48:14 1994
+++ linux/Makefile	Tue May 31 12:38:53 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 16
+SUBLEVEL = 17
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.16/linux/config.in linux/config.in
--- v1.1.16/linux/config.in	Fri May 27 10:49:05 1994
+++ linux/config.in	Tue May 31 12:43:17 1994
@@ -73,6 +73,7 @@
 comment 'Skipping ethercard configuration options...'
 
 else
+bool 'Dummy net driver support' CONFIG_DUMMY y
 bool 'SLIP (serial line) support' CONFIG_SLIP n
 if [ "$CONFIG_SLIP" = "y" ]; then
   bool ' CSLIP compressed headers' SL_COMPRESSED y
@@ -98,7 +99,7 @@
 #bool 'NI52EE support' CONFIG_NI52 n
 #bool 'NI65EE support' CONFIG_NI65 n
 #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
-#bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n
+#bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
 bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
 bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
 fi
diff -u --recursive --new-file v1.1.16/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.1.16/linux/drivers/net/Makefile	Tue May 31 12:48:17 1994
+++ linux/drivers/net/Makefile	Tue May 31 12:32:57 1994
@@ -82,6 +82,12 @@
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c589.o)
 endif
 
+ifdef CONFIG_DUMMY
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(dummy.o)
+dummy.o: dummy.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+endif
+
 ifdef CONFIG_DE600
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(de600.o)
 endif
Only in v1.1.16/linux/drivers/net: d_link.c
diff -u --recursive --new-file v1.1.16/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v1.1.16/linux/drivers/net/dummy.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/dummy.c	Tue May 31 12:33:04 1994
@@ -0,0 +1,110 @@
+/* dummy.c: a dummy net driver
+
+	The purpose of this driver is to provide a device to point a
+	route through, but not to actually transmit packets.
+
+	Why?  If you have a machine whose only connection is an occasional
+	PPP/SLIP/PLIP link, you can only connect to your own hostname
+	when the link is up.  Otherwise you have to use localhost.
+	This isn't very consistent.
+
+	One solution is to set up a dummy link using PPP/SLIP/PLIP,
+	but this seems (to me) too much overhead for too little gain.
+	This driver provides a small alternative. Thus you can do
+	
+	[when not running slip]
+		ifconfig dummy slip.addr.ess.here up
+	[to go to slip]
+		ifconfig dummy down
+		dip whatever
+
+	This was written by looking at Donald Becker's skeleton driver
+	and the loopback driver.  I then threw away anything that didn't
+	apply!	Thanks to Alan Cox for the key clue on what to do with
+	misguided packets.
+
+			Nick Holloway, 27th May 1994
+	[I tweaked this explanation a little but thats all]
+			Alan Cox, 30th May 1994
+*/
+
+/* To have statistics (just packets sent) define this */
+#undef DUMMY_STATS
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+static int dummy_xmit(struct sk_buff *skb, struct device *dev);
+#ifdef DUMMY_STATS
+static struct enet_statistics *dummy_get_stats(struct device *dev);
+#endif
+
+int
+dummy_init(struct device *dev)
+{
+/* I commented this out as bootup is noisy enough anyway and this driver
+   seems pretty reliable 8) 8) 8) */
+/*	printk ( KERN_INFO "Dummy net driver (94/05/27 v1.0)\n" ); */
+
+	/* Initialize the device structure. */
+	dev->hard_start_xmit	= dummy_xmit;
+
+#if DUMMY_STATS
+	dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct enet_statistics));
+	dev->get_stats		= dummy_get_stats;
+#endif
+
+	/* Fill in the fields of the device structure with ethernet-generic values. */
+	ether_setup(dev);
+
+	return 0;
+}
+
+static int
+dummy_xmit(struct sk_buff *skb, struct device *dev)
+{
+#if DUMMY_STATS
+	struct enet_statistics *stats;
+#endif
+
+	if (skb == NULL || dev == NULL)
+		return 0;
+
+	if (skb->free)
+		kfree_skb(skb, FREE_WRITE);
+
+#if DUMMY_STATS
+	stats = (struct enet_statistics *)dev->priv;
+	stats->tx_packets++;
+#endif
+
+	return 0;
+}
+
+#if DUMMY_STATS
+static struct enet_statistics *
+dummy_get_stats(struct device *dev)
+{
+	struct enet_statistics *stats = (struct enet_statistics*) dev->priv;
+	return stats;
+}
+#endif
diff -u --recursive --new-file v1.1.16/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v1.1.16/linux/drivers/net/net_init.c	Tue May 31 12:48:17 1994
+++ linux/drivers/net/net_init.c	Tue May 31 12:33:05 1994
@@ -15,7 +15,9 @@
 	A secondary advantage is that the dangerous NE*000 netcards can reserve
 	their I/O port region before the SCSI probes start.
 
-	register_netdev()/unregister_netdev() by Bjorn Ekwall <bj0rn@blox.se>
+	Modifications/additions by Bjorn Ekwall <bj0rn@blox.se>:
+		ethdev_index[MAX_ETH_CARDS]
+		register_netdev() / unregister_netdev()
 */
 
 #include <linux/config.h>
@@ -45,8 +47,9 @@
     by magic we get them, but otherwise they are un-needed and a space waste]
 */
 
-/* The next device number/name to assign: "eth0", "eth1", etc. */
-static int next_ethdev_number = 0;
+/* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
+#define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
+static struct device *ethdev_index[MAX_ETH_CARDS];
 
 unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
 
@@ -78,11 +81,11 @@
    long.
  */
 
-struct device *init_etherdev(struct device *dev, int sizeof_private,
-							 unsigned long *mem_startp)
+struct device *
+init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
 {
-	int i;
 	int new_device = 0;
+	int i;
 
 	if (dev == NULL) {
 		int alloc_size = sizeof(struct device) + sizeof("eth%d ")
@@ -99,31 +102,17 @@
 		new_device = 1;
 	}
 
-	if (dev->name  &&  dev->name[0] == '\0')
-		sprintf(dev->name, "eth%d", next_ethdev_number++);
-
-	for (i = 0; i < DEV_NUMBUFFS; i++)
-		skb_queue_head_init(&dev->buffs[i]);
-	
-	dev->hard_header	= eth_header;
-	dev->rebuild_header	= eth_rebuild_header;
-	dev->type_trans		= eth_type_trans;
-	
-	dev->type			= ARPHRD_ETHER;
-	dev->hard_header_len = ETH_HLEN;
-	dev->mtu			= 1500; /* eth_mtu */
-	dev->addr_len		= ETH_ALEN;
-	for (i = 0; i < ETH_ALEN; i++) {
-		dev->broadcast[i]=0xff;
+	if (dev->name &&
+		((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
+		for (i = 0; i < MAX_ETH_CARDS; ++i)
+			if (ethdev_index[i] == NULL) {
+				sprintf(dev->name, "eth%d", i);
+				ethdev_index[i] = dev;
+				break;
+			}
 	}
-	
-	/* New-style flags. */
-	dev->flags			= IFF_BROADCAST;
-	dev->family			= AF_INET;
-	dev->pa_addr		= 0;
-	dev->pa_brdaddr		= 0;
-	dev->pa_mask		= 0;
-	dev->pa_alen		= sizeof(unsigned long);
+
+	ether_setup(dev); /* should this be called here? */
 	
 	if (new_device) {
 		/* Append the device to the device queue. */
@@ -144,6 +133,19 @@
 	for (i = 0; i < DEV_NUMBUFFS; i++)
 		skb_queue_head_init(&dev->buffs[i]);
 
+	/* register boot-defined "eth" devices */
+	if (dev->name && (strncmp(dev->name, "eth", 3) == 0)) {
+		i = simple_strtoul(dev->name + 3, NULL, 0);
+		if (ethdev_index[i] == NULL) {
+			ethdev_index[i] = dev;
+		}
+		else if (dev != ethdev_index[i]) {
+			/* Really shouldn't happen! */
+			printk("ether_setup: Ouch! Someone else took %s\n",
+				dev->name);
+		}
+	}
+
 	dev->hard_header	= eth_header;
 	dev->rebuild_header = eth_rebuild_header;
 	dev->type_trans = eth_type_trans;
@@ -186,24 +188,30 @@
 {
 	struct device *d = dev_base;
 	unsigned long flags;
-	
+	int i;
+
 	save_flags(flags);
 	cli();
 
-	if (dev && dev->init) 
-	{
-		if (dev->init(dev) != 0)
-		{
+	if (dev && dev->init) {
+		if (dev->init(dev) != 0) {
 			restore_flags(flags);
 			return -EIO;
 		}
-		
-		if (dev->name  &&  dev->name[0] == '\0')
-			sprintf(dev->name, "eth%d", next_ethdev_number++);
+
+		if (dev->name &&
+			((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
+			for (i = 0; i < MAX_ETH_CARDS; ++i)
+				if (ethdev_index[i] == NULL) {
+					sprintf(dev->name, "eth%d", i);
+					printk("device '%s' loaded\n", dev->name);
+					ethdev_index[i] = dev;
+					break;
+				}
+		}
 
 		/* Add device to end of chain */
-		if (dev_base) 
-		{
+		if (dev_base) {
 			while (d->next)
 				d = d->next;
 			d->next = dev;
@@ -220,35 +228,48 @@
 {
 	struct device *d = dev_base;
 	unsigned long flags;
-	
+	int i;
+
 	save_flags(flags);
 	cli();
 
 	printk("unregister_netdev: device ");
-	if (dev) {
-		if (dev->start)
-			printk("'%s' busy", dev->name);
+
+	if (dev == NULL) {
+		printk("was NULL\n");
+		restore_flags(flags);
+		return;
+	}
+	/* else */
+	if (dev->start)
+		printk("'%s' busy\n", dev->name);
+	else {
+		if (dev_base == dev)
+			dev_base = dev->next;
 		else {
-			if (dev_base == dev)
-				dev_base = dev->next;
-			else {
-				while (d && (d->next != dev))
-					d = d->next;
+			while (d && (d->next != dev))
+				d = d->next;
 
-				if (d && (d->next == dev)) {
-					d->next = dev->next;
-					printk("'%s' unlinked", dev->name);
-				}
-				else
-					printk("'%s' not found", dev->name);
+			if (d && (d->next == dev)) {
+				d->next = dev->next;
+				printk("'%s' unlinked\n", dev->name);
+			}
+			else {
+				printk("'%s' not found\n", dev->name);
+				restore_flags(flags);
+				return;
+			}
+		}
+		for (i = 0; i < MAX_ETH_CARDS; ++i) {
+			if (ethdev_index[i] == dev) {
+				ethdev_index[i] = NULL;
+				break;
 			}
 		}
 	}
-	else
-		printk("was NULL");
-	printk("\n");
 	restore_flags(flags);
 }
+
 
 
 /*
diff -u --recursive --new-file v1.1.16/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.1.16/linux/drivers/net/plip.c	Tue May 31 12:48:18 1994
+++ linux/drivers/net/plip.c	Tue May 31 12:33:05 1994
@@ -45,6 +45,12 @@
  *
  ***** So we can all compare loads of different PLIP drivers for a bit I've modularised this beastie too.
  ***** In addition a seperate bidirectional plip module can be done.
+ *
+ *	WARNING: The PRE 1.1.16 plip will NOT work with this PLIP driver. We
+ *	can't avoid this due to an error in the old plip module. If you must
+ *	mix PLIP's you'll need to fix the _OLD_ one to use 0xFC 0xFC as its
+ *	MAC header not 0xFD.
+ *
  */
 
 static char *version =
@@ -703,7 +709,7 @@
 {
     /*
      * set physical address to
-     *  0xfd.0xfd.ipaddr
+     *  0xfc.0xfc.ipaddr
      */
 
     unsigned char *addr = dev->dev_addr;
diff -u --recursive --new-file v1.1.16/linux/net/inet/README linux/net/inet/README
--- v1.1.16/linux/net/inet/README	Tue May 31 12:48:19 1994
+++ linux/net/inet/README	Tue May 31 12:33:05 1994
@@ -1,5 +1,18 @@
 This is snapshot 014
 
+Fixes added for 1.1.17
+
+o	Charles Hedrick's fixes broken fragmentation totally. Mended.
+o	Contributed 'dummy' device added. Apparently some slip people want it.
+o	Tried to kill the memory problems with fragments by setting things
+	up more carefully and guarding them.
+o	Module fixes by Bj0rn.
+o	PLIP fix by Tanabe.
+
+Fixes added for 1.1.16
+o	Charles Hedricks fixes to TCP.
+o	Small fixes all over the place.
+
 Fixes added for 1.1.15
 o	Modular PLIP and 3c501 drivers. Now you -can- have multiple 3c501's
 	(sort of).
diff -u --recursive --new-file v1.1.16/linux/net/inet/arp.c linux/net/inet/arp.c
--- v1.1.16/linux/net/inet/arp.c	Tue May 24 00:35:00 1994
+++ linux/net/inet/arp.c	Tue May 31 12:33:05 1994
@@ -722,17 +722,6 @@
 {
 	struct arp_table *entry;
 	unsigned long hash;
-/* SHOULD BE FIXED NOW */	
-	if(paddr==0)
-	{
-		printk("ADDRESS BOTCH 0\n");
-		if(skb)
-		{
-			printk("skb(saddr=%lx, daddr=%lx, raddr=%lx)\n",
-				skb->saddr,skb->daddr,skb->raddr);
-		}
-	}	
-/* ------------- */
 	switch (ip_chk_addr(paddr))
 	{
 		case IS_MYADDR:
diff -u --recursive --new-file v1.1.16/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.16/linux/net/inet/ip.c	Tue May 31 12:48:20 1994
+++ linux/net/inet/ip.c	Tue May 31 12:33:05 1994
@@ -171,7 +171,7 @@
 		{
 			mac = -mac;
 			skb->arp = 0;
-			skb->raddr = daddr;	/* next routing address */
+			skb->raddr = daddr;	/* next routing address */			
 		}	
 	}
 	return mac;
@@ -226,7 +226,7 @@
 		 *	If the frame is from us and going off machine it MUST MUST MUST
 		 *	have the output device ip address and never the loopback
 		 */
-		if (saddr == 0x0100007FL && daddr != 0x0100007FL) 
+		if (saddr == htonl(0x7F000001L) && daddr != htonl(0x7F000001L))
 			saddr = src;/*rt->rt_dev->pa_addr;*/
 		raddr = rt->rt_gateway;
 
@@ -665,7 +665,6 @@
  
    	/* Finally, release the queue descriptor itself. */
    	kfree_s(qp, sizeof(struct ipq));
-/*   	printk("ip_free:done\n");*/
    	sti();
  }
  
@@ -716,7 +715,7 @@
   	{
 		printk("IP: create: no memory left !\n");
 		return(NULL);
-   	skb->dev = qp->dev;
+	   	skb->dev = qp->dev;
   	}
  	memset(qp, 0, sizeof(struct ipq));
 
@@ -949,7 +948,7 @@
    	 
    	ihl = (iph->ihl * sizeof(unsigned long));
    	end = offset + ntohs(iph->tot_len) - ihl;
- 
+
    	/*
    	 *	Point into the IP datagram 'data' part. 
    	 */
@@ -1088,6 +1087,7 @@
    	struct sk_buff *skb2;
    	int left, mtu, hlen, len;
    	int offset;
+   	unsigned long flags;
  
    	/* 
    	 *	Point into the IP datagram header. 
@@ -1180,19 +1180,27 @@
  		 *	Set up data on packet
  		 */
 
- 		skb2->arp = 0;/*skb->arp;*/
- 		skb2->free = skb->free;
+ 		skb2->arp = skb->arp;
+ 		if(skb->free==0)
+ 			printk("IP fragmenter: BUG free!=1 in fragmenter\n");
+ 		skb2->free = 1;
  		skb2->len = len + hlen;
  		skb2->h.raw=(char *) skb2->data;
- 		skb2->raddr = skb->raddr;	/* For rebuild_header */
 		/*
 		 *	Charge the memory for the fragment to any owner
 		 *	it might posess
 		 */
 		 
+		save_flags(flags);
  		if (sk) 
+ 		{
+ 			cli();
  			sk->wmem_alloc += skb2->mem_len;
- 
+ 			skb2->sk=sk;
+ 		}
+ 		restore_flags(flags);
+ 		skb2->raddr = skb->raddr;	/* For rebuild_header - must be here */ 
+
  		/* 
  		 *	Copy the packet header into the new buffer. 
  		 */
@@ -1227,7 +1235,7 @@
  		 
  		ip_statistics.IpFragCreates++;
  		
- 		ip_queue_xmit(sk, dev, skb2, 1);
+ 		ip_queue_xmit(sk, dev, skb2, 2);
    	}
    	ip_statistics.IpFragOKs++;
 }
@@ -1236,7 +1244,7 @@
 
 #ifdef CONFIG_IP_FORWARD
 
-/* 
+/* 	
  *	Forward an IP datagram to its next destination. 
  */
 
@@ -1627,7 +1635,8 @@
 /*
  * Queues a packet to be sent, and starts the transmitter
  * if necessary.  if free = 1 then we free the block after
- * transmit, otherwise we don't.
+ * transmit, otherwise we don't. If free==2 we not only
+ * free the block but also dont assign a new ip seq number.
  * This routine also needs to put in the total length,
  * and compute the checksum
  */
@@ -1655,7 +1664,7 @@
   	 *	Do some book-keeping in the packet for later
   	 */
 
-  	skb->free = free;
+
   	skb->dev = dev;
   	skb->when = jiffies;
   
@@ -1672,7 +1681,17 @@
 	iph = (struct iphdr *)ptr;
 	skb->ip_hdr = iph;
 	iph->tot_len = ntohs(skb->len-dev->hard_header_len);
-	iph->id      = htons(ip_id_count++);
+
+	/*
+	 *	No reassigning numbers to fragments...
+	 */
+	 
+	if(free!=2)
+		iph->id      = htons(ip_id_count++);
+	else
+		free=1;
+		
+  	skb->free = free;		
 
 	/*
 	 *	Do we need to fragment. Again this is inefficient. 
diff -u --recursive --new-file v1.1.16/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.16/linux/net/inet/tcp.c	Tue May 31 12:48:21 1994
+++ linux/net/inet/tcp.c	Tue May 31 12:33:06 1994
@@ -71,6 +71,7 @@
  *		Matthew Dillon  :	Reworked TCP machine states as per RFC
  *		Gerhard Koerting:	PC/TCP workarounds
  *		Adam Caldwell	:	Assorted timer/timing errors
+ *		Matthew Dillon	:	Fixed another RST bug
  *
  *
  * To Fix:
@@ -78,7 +79,6 @@
  *		it causes a select. Linux can - given the official select semantics I
  *		feel that _really_ its the BSD network programs that are bust (notably
  *		inetd, which hangs occasionally because of this).
- *			Protocol closedown badly messed up.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -2044,7 +2044,9 @@
 			printk("Clean rcv queue\n");
 		while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
 		{
-			if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
+			/* The +1 is not needed because the FIN takes up sequence space and
+			   is not read!!! */
+			if(skb->len > 0 && after(skb->h.th->seq + skb->len/* + 1 */ , sk->copied_seq))
 				need_reset = 1;
 			kfree_skb(skb, FREE_READ);
 		}
diff -u --recursive --new-file v1.1.16/linux/net/inet/udp.c linux/net/inet/udp.c
--- v1.1.16/linux/net/inet/udp.c	Tue May 24 00:35:06 1994
+++ linux/net/inet/udp.c	Tue May 31 12:35:36 1994
@@ -119,6 +119,15 @@
 	}
 
 	/*
+	 *	Various people wanted BSD UDP semantics. Well they've come 
+	 *	back out because they slow down response to stuff like dead
+	 *	or unreachable name servers and they screw term users something
+	 *	chronic. Oh and it violates RFC1122. So basically fix your 
+	 *	client code people.
+	 */
+	 
+#ifdef CONFIG_I_AM_A_BROKEN_BSD_WEENIE
+	/*
 	 *	It's only fatal if we have connected to them. I'm not happy
 	 *	with this code. Some BSD comparisons need doing.
 	 */
@@ -126,10 +135,15 @@
 	if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) 
 	{
 		sk->err = icmp_err_convert[err & 0xff].errno;
-/*		sk->err=ECONNREFUSED;*/
+		sk->error_report(sk);
  	}
-	
-	sk->error_report(sk);
+#else
+	if (icmp_err_convert[err & 0xff].fatal)
+	{
+		sk->err = icmp_err_convert[err & 0xff].errno;
+		sk->error_report(sk);
+	}
+#endif
 }
 
 
