diff -u --recursive --new-file v1.1.55/linux/Makefile linux/Makefile
--- v1.1.55/linux/Makefile	Fri Oct 21 10:15:03 1994
+++ linux/Makefile	Thu Oct 20 17:32:00 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 55
+SUBLEVEL = 56
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.55/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.1.55/linux/drivers/block/ll_rw_blk.c	Fri Sep  9 05:33:47 1994
+++ linux/drivers/block/ll_rw_blk.c	Fri Oct 21 10:04:10 1994
@@ -1,7 +1,8 @@
 /*
- *  linux/kernel/blk_dev/ll_rw.c
+ *  linux/drivers/block/ll_rw_blk.c
  *
  * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
  */
 
 /*
@@ -149,6 +150,20 @@
 static void add_request(struct blk_dev_struct * dev, struct request * req)
 {
 	struct request * tmp;
+	short		 disk_index;
+
+	switch (MAJOR(req->dev)) {
+		case SCSI_DISK_MAJOR:	disk_index = (MINOR(req->dev) & 0x0070) >> 4;
+					if (disk_index < 4)
+						kstat.dk_drive[disk_index]++;
+					break;
+		case HD_MAJOR:
+		case XT_DISK_MAJOR:	disk_index = (MINOR(req->dev) & 0x00C0) >> 6;
+					if (disk_index < 4)
+						kstat.dk_drive[disk_index]++;
+					break;
+		default:		break;
+	}
 
 	req->next = NULL;
 	cli();
diff -u --recursive --new-file v1.1.55/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.1.55/linux/drivers/char/ChangeLog	Thu Oct 20 09:37:28 1994
+++ linux/drivers/char/ChangeLog	Thu Oct 20 17:31:37 1994
@@ -1,3 +1,11 @@
+Tue Oct 18 10:02:43 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (rs_start): Removed an incorrect '!' that was
+		preventing transmit interrupts from being re-enabled in
+		rs_start().  Fortunately in most cases it would be
+		re-enabled elsewhere, but this still should be fixed
+		corectly.
+
 Sun Oct  9 23:46:03 1994  Theodore Y. Ts'o  (tytso@rt-11)
 
 	* tty_io.c (do_tty_hangup): If the tty driver flags
diff -u --recursive --new-file v1.1.55/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.1.55/linux/drivers/char/keyboard.c	Thu Oct 20 09:37:30 1994
+++ linux/drivers/char/keyboard.c	Fri Oct 21 17:04:12 1994
@@ -305,7 +305,7 @@
 		}
 		/* strange ... */
 		reply_expected = 1;
-#ifdef KBD_REPORT_ERR
+#if 0
 		printk("keyboard reply expected - got %02x\n", scancode);
 #endif
 	}
diff -u --recursive --new-file v1.1.55/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.1.55/linux/drivers/char/serial.c	Thu Oct 20 09:37:30 1994
+++ linux/drivers/char/serial.c	Thu Oct 20 17:31:37 1994
@@ -313,8 +313,7 @@
 		return;
 	
 	save_flags(flags); cli();
-	if (info->xmit_cnt && !info->xmit_buf &&
-	    !(info->IER & UART_IER_THRI)) {
+	if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
 		info->IER |= UART_IER_THRI;
 		serial_out(info, UART_IER, info->IER);
 	}
diff -u --recursive --new-file v1.1.55/linux/fs/exec.c linux/fs/exec.c
--- v1.1.55/linux/fs/exec.c	Thu Oct 20 09:37:35 1994
+++ linux/fs/exec.c	Fri Oct 21 09:54:09 1994
@@ -631,12 +631,8 @@
 		bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid;
 		bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid;
 	}
-	if (current->euid == bprm.inode->i_uid)
-		i >>= 6;
-	else if (in_group_p(bprm.inode->i_gid))
-		i >>= 3;
-	if (!(i & 1) &&
-	    !((bprm.inode->i_mode & 0111) && suser())) {
+	if (!permission(bprm.inode, MAY_EXEC) ||
+	    (!(bprm.inode->i_mode & 0111) && fsuser())) {
 		retval = -EACCES;
 		goto exec_error2;
 	}
diff -u --recursive --new-file v1.1.55/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v1.1.55/linux/fs/ext2/dir.c	Fri Oct 21 10:15:04 1994
+++ linux/fs/ext2/dir.c	Fri Oct 21 09:39:35 1994
@@ -144,29 +144,36 @@
 		
 revalidate:
 		/* If the dir block has changed since the last call to
-		   readdir(2), then we might be pointing to an invalid dirent
-		   right now.  Scan from the start of the block to make
-		   sure. */
-		for (i = 0; i < sb->s_blocksize && i < offset; ) {
-			de = (struct ext2_dir_entry *) (bh->b_data + i);
-			/* It's too expensive to do a full dirent test
-			 * each time round this loop, but we do have
-			 * to test at least that it is non-zero.  A
-			 * failure will be detected in the dirent test
-			 * below. */
-			if (de->rec_len < EXT2_DIR_REC_LEN(1))
-				break;
-			i += de->rec_len;
+		 * readdir(2), then we might be pointing to an invalid
+		 * dirent right now.  Scan from the start of the block
+		 * to make sure. */
+		if (filp->f_version != inode->i_version) {
+			for (i = 0; i < sb->s_blocksize && i < offset; ) {
+				de = (struct ext2_dir_entry *) 
+					(bh->b_data + i);
+				/* It's too expensive to do a full
+				 * dirent test each time round this
+				 * loop, but we do have to test at
+				 * least that it is non-zero.  A
+				 * failure will be detected in the
+				 * dirent test below. */
+				if (de->rec_len < EXT2_DIR_REC_LEN(1))
+					break;
+				i += de->rec_len;
+			}
+			offset = i;
+			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+				| offset;
+			filp->f_version = inode->i_version;
 		}
-		offset = i;
-		filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset;
 		
 		while (count > 0 && filp->f_pos < inode->i_size 
 		       && offset < sb->s_blocksize) {
 			de = (struct ext2_dir_entry *) (bh->b_data + offset);
 			if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
 						   bh, offset)) {
-				/* On error, skip the f_pos to the next block. */
+				/* On error, skip the f_pos to the
+                                   next block. */
 				filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
 					      + sb->s_blocksize;
 				brelse (bh);
@@ -175,7 +182,8 @@
 			if (de->inode) {
 				dlen = ROUND_UP(NAME_OFFSET(dirent) 
 						+ de->name_len + 1);
-				/* Old libc libraries always use a count of 1. */
+				/* Old libc libraries always use a
+                                   count of 1. */
 				if (count == 1 && !stored)
 					count = dlen;
 				if (count < dlen) {
@@ -184,11 +192,11 @@
 				}
 
 				/* We might block in the next section
-                               * if the data destination is
-                               * currently swapped out.  So, use a
-                               * version stamp to detect whether or
-                               * not the directory has been modified
-                               * during the copy operation. */
+				 * if the data destination is
+				 * currently swapped out.  So, use a
+				 * version stamp to detect whether or
+				 * not the directory has been modified
+				 * during the copy operation. */
 				version = inode->i_version;
 				i = de->name_len;
 				memcpy_tofs (dirent->d_name, de->name, i);
diff -u --recursive --new-file v1.1.55/linux/fs/fcntl.c linux/fs/fcntl.c
--- v1.1.55/linux/fs/fcntl.c	Sun Aug 21 17:48:36 1994
+++ linux/fs/fcntl.c	Fri Oct 21 09:39:32 1994
@@ -115,7 +115,24 @@
 			 */
 			return filp->f_owner;
 		case F_SETOWN:
-			filp->f_owner = arg; /* XXX security implications? */
+			/*
+			 *	Add the security checks - AC. Without this there is a massive
+			 *	Linux security hole here - consider what happens if you do 
+			 *	something like 
+			 *		fcntl(0,F_SETOWN,some_root_process);
+			 *		getchar();
+			 *	and input a line!
+			 *
+			 *	BTW: Don't try this for fun. Several Unix systems I tried this on
+			 *	fall for the trick!
+			 *
+			 *	I had to fix this botch job as Linux kill_fasync asserts
+			 *	priv making it a free all user process killer!
+			 */
+			if(!suser() && current->pgrp != -arg &&
+				current->pid != arg)
+					return -EPERM;
+			filp->f_owner = arg;
 			if (S_ISSOCK (filp->f_inode->i_mode))
 				sock_fcntl (filp, F_SETOWN, arg);
 			return 0;
diff -u --recursive --new-file v1.1.55/linux/fs/file_table.c linux/fs/file_table.c
--- v1.1.55/linux/fs/file_table.c	Tue Feb  8 12:52:14 1994
+++ linux/fs/file_table.c	Fri Oct 21 09:39:35 1994
@@ -79,6 +79,7 @@
 			memset(f,0,sizeof(*f));
 			put_last_free(f);
 			f->f_count = 1;
+			f->f_version = ++event;
 			return f;
 		}
 	if (nr_files < NR_FILE) {
diff -u --recursive --new-file v1.1.55/linux/fs/read_write.c linux/fs/read_write.c
--- v1.1.55/linux/fs/read_write.c	Fri Oct 21 10:15:05 1994
+++ linux/fs/read_write.c	Fri Oct 21 09:45:50 1994
@@ -71,6 +71,7 @@
 	if (tmp != file->f_pos) {
 		file->f_pos = tmp;
 		file->f_reada = 0;
+		file->f_version = ++event;
 	}
 	return file->f_pos;
 }
@@ -109,6 +110,7 @@
 		return -EINVAL;
 	file->f_pos = tmp;
 	file->f_reada = 0;
+	file->f_version = ++event;
 	memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
 	return 0;
 }
diff -u --recursive --new-file v1.1.55/linux/fs/xiafs/dir.c linux/fs/xiafs/dir.c
--- v1.1.55/linux/fs/xiafs/dir.c	Fri Oct 21 10:15:06 1994
+++ linux/fs/xiafs/dir.c	Fri Oct 21 08:04:25 1994
@@ -131,5 +131,5 @@
 	inode->i_atime=CURRENT_TIME;		    
 	inode->i_dirt=1;
     }
-    return 0;
+    return ret;
 }
diff -u --recursive --new-file v1.1.55/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.55/linux/include/linux/fs.h	Sun Aug 21 17:48:38 1994
+++ linux/include/linux/fs.h	Fri Oct 21 09:39:35 1994
@@ -233,6 +233,7 @@
 	int f_owner;		/* pid or -pgrp where SIGIO should be sent */
 	struct inode * f_inode;
 	struct file_operations * f_op;
+	unsigned long f_version;
 	void *private_data;	/* needed for tty driver, and maybe others */
 };
 
diff -u --recursive --new-file v1.1.55/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v1.1.55/linux/include/linux/if_arp.h	Fri Sep  9 05:33:49 1994
+++ linux/include/linux/if_arp.h	Fri Oct 21 09:39:32 1994
@@ -52,6 +52,7 @@
   struct sockaddr	arp_pa;		/* protocol address		*/
   struct sockaddr	arp_ha;		/* hardware address		*/
   int			arp_flags;	/* flags			*/
+  struct sockaddr       arp_netmask;    /* netmask (only for proxy arps) */
 };
 
 /* ARP Flag values. */
@@ -59,6 +60,8 @@
 #define	ATF_PERM	0x04		/* permanent entry		*/
 #define	ATF_PUBL	0x08		/* publish entry		*/
 #define	ATF_USETRAILERS	0x10		/* has requested trailers	*/
+#define ATF_NETMASK     0x20            /* want to use a netmask (only
+					   for proxy entries) */
 
 /*
  *	This structure defines an ethernet arp header.
diff -u --recursive --new-file v1.1.55/linux/include/linux/net.h linux/include/linux/net.h
--- v1.1.55/linux/include/linux/net.h	Mon Jul 25 17:56:43 1994
+++ linux/include/linux/net.h	Fri Oct 21 09:41:17 1994
@@ -77,6 +77,7 @@
   struct socket		*next;
   struct wait_queue	**wait;		/* ptr to place to wait on	*/
   struct inode		*inode;
+  struct fasync_struct  *fasync_list;	/* Asynchronous wake up list	*/
 };
 
 #define SOCK_INODE(S)	((S)->inode)
@@ -128,7 +129,9 @@
 };
 
 extern int	sock_awaitconn(struct socket *mysock, struct socket *servsock);
+extern int	sock_wake_async(struct socket *sock);
 extern int	sock_register(int family, struct proto_ops *ops);
+extern int	sock_unregister(int family);
 
 #endif /* __KERNEL__ */
 #endif	/* _LINUX_NET_H */
diff -u --recursive --new-file v1.1.55/linux/include/linux/socket.h linux/include/linux/socket.h
--- v1.1.55/linux/include/linux/socket.h	Fri Aug 26 14:44:44 1994
+++ linux/include/linux/socket.h	Fri Oct 21 09:39:32 1994
@@ -81,9 +81,6 @@
 /* IPX options */
 #define IPX_TYPE	1
 
-/* AX.25 options */
-#define AX25_WINDOW	1
-
 /* TCP options - this way around because someone left a set in the c library includes */
 #define TCP_NODELAY	1
 #define TCP_MAXSEG	2
diff -u --recursive --new-file v1.1.55/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.55/linux/kernel/ksyms.c	Fri Oct 21 10:15:06 1994
+++ linux/kernel/ksyms.c	Fri Oct 21 09:39:32 1994
@@ -28,6 +28,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #ifdef CONFIG_INET
+#include <linux/net.h>
 #include <linux/netdevice.h>
 #endif
 
@@ -169,6 +170,10 @@
 	/* Miscellaneous access points */
 	X(si_meminfo),
 
+	/* socket layer registration */
+	X(sock_register),
+	X(sock_unregister),
+
 #ifdef CONFIG_FTAPE
 	/* The next labels are needed for ftape driver.  */
 	X(ftape_big_buffer),
@@ -187,6 +192,12 @@
 	X(dev_rint),
 	X(dev_tint),
 	X(irq2dev_map),
+	X(dev_add_pack),
+	X(dev_remove_pack),
+	X(dev_get),
+	X(dev_ioctl),
+	X(dev_queue_xmit),
+	X(dev_base),
 #endif
 
 	/********************************************************
diff -u --recursive --new-file v1.1.55/linux/kernel/sys.c linux/kernel/sys.c
--- v1.1.55/linux/kernel/sys.c	Sun Oct  9 12:00:29 1994
+++ linux/kernel/sys.c	Fri Oct 21 16:49:14 1994
@@ -322,7 +322,7 @@
 	if (ruid != (uid_t) -1 ||
 	    (euid != (uid_t) -1 && euid != old_ruid))
 		current->suid = current->euid;
-	current->fsuid = euid;
+	current->fsuid = current->euid;
 	return 0;
 }
 
diff -u --recursive --new-file v1.1.55/linux/net/inet/README linux/net/inet/README
--- v1.1.55/linux/net/inet/README	Sun Aug 21 17:48:41 1994
+++ linux/net/inet/README	Fri Oct 21 09:39:35 1994
@@ -1,155 +1,16 @@
-Changes for 1.1.21
+Changes for NET3.017
 
-o	Small bug fix in the apricot xen-ii driver code (Mark Evans)
-o	DE600 changes + DE620 driver (Bj0rn Eckwall)
-o	WWW error return bug fixed (Everyone!)
-o	SLIP default address is now better
-o	Small changes to PLIP (Niibe)
-o	Added PF_UNSPEC	(Dominic Kubla)
-o	TCP fastpath for receive.
-o	Turbo charged tcp checksum routine (Arnt Gulbrandsen)
-o	PPP locking bug fixes (Florian La Roche)
+This is mostly small stuff as follows:
 
-To Do
+o	accept()ed socket don't end up with an invalid sk->socket and give bogus
+	netstat output.
+o	FASYNC/SIGIO now works with sockets.
+o	Fixed the permissions on F_SETOWN for all. Its now as broken/working
+	as other systems. Really we need something like a 32bit generation
+	number on processes.
+o	ARP allows proxy for whole networks (a la cisco routers)
+o	TCP sendto() reports ENOTCONN in the right cases
+o	Removed some surplus uncommented code from tcp.c
+o	Fixed protocol violation during closedown in tcp.c
+	[Still not got the window < MSS bug fix included]
 
-o	Include the HP onboard lance fixes.
-o	Fix Unix domain sockets.
-o	Fix the _SLOW_ TCP window calculation junk in tcp_data/tcp_ack.
-o	Make the dev_add_proto() list hashed by protocol type.
-o	Remove the call to dev->header_type - load it into the skbuff.
-	instead to avoid the extra calls and cache misses.
-o	Include new sk_buff skb_push() code and move toward using it.
-o	Fix the PI driver so pi0a can be down when pi0b is up without getting
-	crashes. Also fix the stuff to allow piconfig to set the parameters.
-o	Make AX.25 set the packet type - certainly before it hits IP.
-o	sk_buff building at the top level - pure kernel interfaces to the
-	protocol layers
-o	Clean up NFS, merge NFS/TCP code.
-o	SIGIO
-o	IP forwarding use of options properly (needs new sk_buff code)
-o	Reroute TCP retransmits if needed (needs new sk_buffs)
-
-
-Changes for 1.1.20
-
-o	All read/write buffers are validated at the top level _only_
-o	All address structures are moved to and from user mode at the top
-	level. Thus you can now issue proto->bind(....) calls and related
-	functions such as connect from another kernel task. All thats left
-	to fix now is a kernel alloc_socket()/free_socket() and accompanying
-	proto->make_kernel(socket)
-o	Small fixes to address behaviour caused by the above
-o	Max NFS size of 16K bytes
-o	Added the apricot driver as a test (#'ed out in config.in)
-o	Fixed a missing function definition in net_init.c
-o	Added G4KLX ax25_router code
-o	Added Niibe's PLIP driver and altered it to support timer
-	configuration and IRQ/port setting. Added if_plip.h. Comments and
-	feedback appreciated on this (both to Niibe and me).
-o	Added AF_MAX/PF_MAX defines
-o	Added a note that the DE600 driver also works for a noname 'PE1200'.
-o	Network buffer statistics on shift-scroll_lock
-o	Fixed a serious race in the device driver code. This was causing odd
-	crashes with the Lance drivers, lockups with the ne2000 cards and
-	a few other 'bad' goings on. All drivers are effected. See
-	README.DEV if porting a driver to this revision.
-
-	If you see entries in your 'free while locked' count, those would
-	typically have crashed a pre 1.20 kernel.
-
-o	TCP keeps the timers above 0.2sec round-trip time because of the use of
-	delayed ACK's by BSD style kernels.
-o	Fixed a small BSD error in the return from datagram socket
-	recv/recvfrom() calls when data is truncated. BSD returns the true
-	length of the message, Linux returned the amount copied which broke
-	programs that did a MSG_PEEK with a small buffer and grew it if need
-	be (some of the AV/RTP stuff notably).
-o	Added TIOCINQ/OUTQ to AX.25 and IPX.
-o	Added driver ioctl() calls to IPX.
-o	Corrected the skb->len==0 in the tcp_data reset on shutdown to check
-	skb->copied_seq.
-o	IP options reflect onto SO_PRIORITY.
-o	When a driver is downed its ARP entries are flushed. Should solve
-	the occasional crash when taking out a modular driver.
-o	Added Donald's multicast reception while promiscuous fix for the
-	8390 drivers.
-o	Potential ARP TCP-retransmit clear race fixed. Incredibly
-	unlikely to occur but no doubt it will 8(.
-
-
-Fixes added for 1.1.19
-
-o	Unix domain bind error code.
-o	skb->localroute starts cleared.
-o	Compiles with networking disabled
-
-Fixes added for 1.1.18
-
-o	Dummy driver includes correctly.
-o	PPP fixes from A.L.
-o	ifslave fixes
-o	Small error causing nfsd to coredump fixed by Linus.
-
-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).
-o	Integrated new AX.25 - this will be ready for the big time in a few
-	releases.
-
-Fixes added for 1.1.14
-
-o	Compiles properly on the whole 8)
-o	Yet more Unix /proc protection.
-o	Modular PLIP and 3c501 drivers. Now you -can- have multiple 3c501's
-	(sort of).
-
-This fixes the following from the 1.1.12 release (see the relevant files
-for the credits to authors).
-
-o	RARP compiles in properly
-o	Using new Tytso TTY drivers
-o	IP forwarding is configurable
-o	PC/TCP support
-o	AX.25 builds fine without SLIP driver (just PI)
-o	MTU recognized in routing table (but only by TCP currently)
-o	AX.25 PI driver merged into AX.25 code and kernel stubs
-o	UNIX /proc trap hopefully fixed
-o	DDI removed totally ready to use the PCMCIA people's stuff
-o	Unix domain lock/unlock now static (needlessly visible before)
-o	Split net/inet/sock.c into generic and IP components
-o	NFS client works correctly with 8K NFS
-o	Non IP builds work correctly
-o	Renamed inet_bh etc to net_bh to reflect true nature
-o	TCP handling of poor routes much improved
-o	TCP connect timing fixed
-o	Incredibly unlikely SLIP memory leak removed
-o	Loopback maintains IFF_LOOPBACK flag
-o	Johnathon Naylor(G4KLX) AX.25 changes
-o	Out of sync bug in lance driver fixed.
-o	First cut at ethernet loadable modules
-o	PCMCIA people have ifmap stuff. Will extend this to other drivers.
-o	New de600.c
-o	Clean up of IP layer - sorted a lot of redundant and duplicated code
-	out.
-o	Removed all the old non working debugging junk from the kernel.
-o	Removed all the devices the kernel used to use as a legacy from
-	FvK's days writing the linux networking.
-o	Greg Page's latest and greatest IPX fixes (including 802.2). Now
-	I've got the stuff to write a free Netware client too and some
-	volunteers to do it.
-o	Fixed the 1.1.12 ARP fragment bug.
diff -u --recursive --new-file v1.1.55/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.55/linux/net/inet/af_inet.c	Sun Aug 21 17:48:41 1994
+++ linux/net/inet/af_inet.c	Fri Oct 21 09:39:33 1994
@@ -15,6 +15,12 @@
  * Changes (see also sock.c)
  *
  *		A.N.Kuznetsov	:	Socket death error in accept().
+ *		John Richardson :	Fix non blocking error in connect()
+ *					so sockets that fail to connect
+ *					don't return -EINPROGRESS.
+ *		Alan Cox	:	Asynchronous I/O support
+ *		Alan Cox	:	Keep correct socket pointer on sock structures
+ *					when accept() ed
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -461,7 +467,10 @@
 static void def_callback2(struct sock *sk,int len)
 {
 	if(!sk->dead)
+	{
 		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket);
+	}
 }
 
 
@@ -875,6 +884,12 @@
 			return(err);
   		sock->state = SS_CONNECTING;
 	}
+	
+	if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING)
+	{
+		sock->state=SS_UNCONNECTED;
+		return -ETIMEDOUT;
+	}
 
 	if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) 
 	  	return(-EINPROGRESS);
@@ -966,6 +981,7 @@
 	}
 	newsock->data = (void *)sk2;
 	sk2->sleep = newsock->wait;
+	sk2->socket = newsock;
 	newsock->conn = NULL;
 	if (flags & O_NONBLOCK) 
 		return(0);
@@ -979,6 +995,7 @@
 			sti();
 			sk1->pair = sk2;
 			sk2->sleep = NULL;
+			sk2->socket=NULL;
 			newsock->data = NULL;
 			return(-ERESTARTSYS);
 		}
@@ -1318,7 +1335,7 @@
 	int i;
 
 
-	printk("NET3 TCP/IP protocols stack v016\n");
+	printk("Swansea University Computer Society TCP/IP for NET3.017\n");
 
 	/*
 	 *	Tell SOCKET that we are alive... 
diff -u --recursive --new-file v1.1.55/linux/net/inet/arp.c linux/net/inet/arp.c
--- v1.1.55/linux/net/inet/arp.c	Fri Sep  9 05:33:49 1994
+++ linux/net/inet/arp.c	Fri Oct 21 09:39:33 1994
@@ -33,6 +33,8 @@
  *		Martin Seine	:	Move the arphdr structure
  *					to if_arp.h for compatibility
  *					with BSD based programs.
+ *              Andrew Tridgell :       Added ARP netmask code and
+ *                                      re-arranged proxy handling
  */
 
 #include <linux/types.h>
@@ -62,6 +64,7 @@
 #include "ax25.h"
 #endif
 
+
 /*
  *	This structure defines the ARP mapping cache. As long as we make changes
  *	in this structure, we keep interrupts of. But normally we can copy the
@@ -75,6 +78,7 @@
 	unsigned long			last_used;		/* For expiry 			*/
 	unsigned int			flags;			/* Control status 		*/
 	unsigned long			ip;			/* ip address of entry 		*/
+	unsigned long			mask;			/* netmask - used for generalised proxy arps (tridge) 		*/
 	unsigned char			ha[MAX_ADDR_LEN];	/* Hardware address		*/
 	unsigned char			hlen;			/* Length of hardware address 	*/
 	unsigned short			htype;			/* Type of hardware in use	*/
@@ -122,40 +126,53 @@
 
 #define ARP_CHECK_INTERVAL	(60 * HZ)
 
-
-static void arp_check_expire (unsigned long);  /* Forward declaration. */
+/* Forward declarations. */
+static void arp_check_expire (unsigned long);  
+static struct arp_table *arp_lookup(unsigned long paddr, int exact);
 
 
 static struct timer_list arp_timer =
 	{ NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire };
 
 /*
+ * The default arp netmask is just 255.255.255.255 which means it's
+ * a single machine entry. Only proxy entries can have other netmasks
+ *
+*/
+
+#define DEF_ARP_NETMASK (~0)
+
+
+/*
  * 	The size of the hash table. Must be a power of two.
  * 	Maybe we should remove hashing in the future for arp and concentrate
  * 	on Patrick Schaaf's Host-Cache-Lookup...
  */
 
+
 #define ARP_TABLE_SIZE  16
 
-struct arp_table *arp_tables[ARP_TABLE_SIZE] =
+/* The ugly +1 here is to cater for proxy entries. They are put in their 
+   own list for efficiency of lookup. If you don't want to find a proxy
+   entry then don't look in the last entry, otherwise do 
+*/
+
+#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1)
+
+struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] =
 {
 	NULL,
 };
 
+
 /*
  *	The last bits in the IP address are used for the cache lookup.
+ *      A special entry is used for proxy arp entries
  */
 
 #define HASH(paddr) 		(htonl(paddr) & (ARP_TABLE_SIZE - 1))
-
-/*
- *	Number of proxy arp entries. This is normally zero and we use it to do
- *	some optimizing for normal uses.
- */
+#define PROXY_HASH ARP_TABLE_SIZE
 
-static int proxies = 0;
-
-
 /*
  *	Check if there are too old entries and remove them. If the ATF_PERM
  *	flag is set, they are always left in the arp cache (permanent entry).
@@ -172,7 +189,7 @@
 	save_flags(flags);
 	cli();
 
-	for (i = 0; i < ARP_TABLE_SIZE; i++)
+	for (i = 0; i < FULL_ARP_TABLE_SIZE; i++)
 	{
 		struct arp_table *entry;
 		struct arp_table **pentry = &arp_tables[i];
@@ -183,8 +200,6 @@
 				&& !(entry->flags & ATF_PERM))
 			{
 				*pentry = entry->next;	/* remove from list */
-				if (entry->flags & ATF_PUBL)
-					proxies--;
 				del_timer(&entry->timer);	/* Paranoia */
 				kfree_s(entry, sizeof(struct arp_table));
 			}
@@ -213,9 +228,6 @@
 	struct sk_buff *skb;
 	unsigned long flags;
 
-	if (entry->flags & ATF_PUBL)
-		proxies--;
-		
 	save_flags(flags);
 	cli();
 	/* Release the list of `skb' pointers. */
@@ -234,7 +246,7 @@
 /*
  *	Purge a device from the ARP queue
  */
- 
+
 void arp_device_down(struct device *dev)
 {
 	int i;
@@ -245,7 +257,7 @@
 	 */
 	save_flags(flags);
 	cli();
-	for (i = 0; i < ARP_TABLE_SIZE; i++)
+	for (i = 0; i < FULL_ARP_TABLE_SIZE; i++)
 	{
 		struct arp_table *entry;
 		struct arp_table **pentry = &arp_tables[i];
@@ -255,8 +267,6 @@
 			if(entry->dev==dev)
 			{
 				*pentry = entry->next;	/* remove from list */
-				if (entry->flags & ATF_PUBL)
-					proxies--;
 				del_timer(&entry->timer);	/* Paranoia */
 				kfree_s(entry, sizeof(struct arp_table));
 			}
@@ -387,9 +397,16 @@
 	 *	loop through everything again. Maybe hash is good enough, but
 	 *	I will look at it later.
 	 */
-	
+
 	hash = HASH(entry->ip);
-	pentry = &arp_tables[hash];
+
+	/* proxy entries shouldn't really time out so this is really
+	   only here for completeness
+	*/
+	if (entry->flags & ATF_PUBL)
+	  pentry = &arp_tables[PROXY_HASH];
+	else
+	  pentry = &arp_tables[hash];
 	while (*pentry != NULL)
 	{
 		if (*pentry == entry)
@@ -466,12 +483,16 @@
 
 void arp_destroy(unsigned long ip_addr, int force)
 {
+        int checked_proxies = 0;
 	struct arp_table *entry;
 	struct arp_table **pentry;
 	unsigned long hash = HASH(ip_addr);
 
 	cli();
 	pentry = &arp_tables[hash];
+	if (! *pentry) /* also check proxy entries */
+	  pentry = &arp_tables[PROXY_HASH];
+
 	while ((entry = *pentry) != NULL)
 	{
 		if (entry->ip == ip_addr)
@@ -485,6 +506,12 @@
 			return;
 		}
 		pentry = &entry->next;
+		if (!checked_proxies && ! *pentry)
+		  { /* ugly. we have to make sure we check proxy
+		       entries as well */
+		    checked_proxies = 1;
+		    pentry = &arp_tables[PROXY_HASH];
+		  }
 	}
 	sti();
 }
@@ -507,7 +534,7 @@
 	struct arp_table *entry;
 	struct arp_table *proxy_entry;
 	int addr_hint,hlen,htype;
-	unsigned long hash,dest_hash;
+	unsigned long hash;
 	unsigned char ha[MAX_ADDR_LEN];	/* So we can enable ints again. */
 	long sip,tip;
 	unsigned char *sha,*tha;
@@ -546,6 +573,7 @@
 			break;
 #endif
 		case ARPHRD_ETHER:
+		case ARPHRD_ARCNET:
 			if(arp->ar_pro != htons(ETH_P_IP))
 			{
 				kfree_skb(skb, FREE_READ);
@@ -628,22 +656,25 @@
  * 	check if that someone else is one of our proxies.  If it isn't,
  * 	we can toss it.
  */
-			if (proxies == 0)
-			{
-				kfree_skb(skb, FREE_READ);
-				return 0;
-			}
-	
-			dest_hash = HASH(tip);
 			cli();
-			for(proxy_entry=arp_tables[dest_hash];
-				proxy_entry;
-				proxy_entry = proxy_entry->next)
+			for(proxy_entry=arp_tables[PROXY_HASH];
+			    proxy_entry;
+			    proxy_entry = proxy_entry->next)
 			{
-				if(proxy_entry->ip == tip && proxy_entry->htype==htype)
-					break;
+			  /* we will respond to a proxy arp request
+			     if the masked arp table ip matches the masked
+			     tip. This allows a single proxy arp table
+			     entry to be used on a gateway machine to handle
+			     all requests for a whole network, rather than
+			     having to use a huge number of proxy arp entries
+			     and having to keep them uptodate.
+			     */
+			  if (proxy_entry->htype == htype && 
+			      !((proxy_entry->ip^tip)&proxy_entry->mask))
+			    break;
+
 			}
-			if (proxy_entry && (proxy_entry->flags & ATF_PUBL))
+			if (proxy_entry)
 			{
 				memcpy(ha, proxy_entry->ha, hlen);
 				sti();
@@ -724,6 +755,7 @@
 			return 0;
 		}
 
+                entry->mask = DEF_ARP_NETMASK;
 		entry->ip = sip;
 		entry->hlen = hlen;
 		entry->htype = htype;
@@ -774,11 +806,8 @@
 	/*
 	 *	Find an entry
 	 */
-	for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
-		if (entry->ip == paddr)
-			break;
+	entry = arp_lookup(paddr, 0);
 
-
 	if (entry != NULL) 	/* It exists */
 	{
 	        if (!(entry->flags & ATF_COM))
@@ -817,6 +846,7 @@
 					GFP_ATOMIC);
 	if (entry != NULL)
 	{
+	        entry->mask = DEF_ARP_NETMASK;
 		entry->ip = paddr;
 		entry->hlen = dev->addr_len;
 		entry->htype = dev->type;
@@ -874,12 +904,13 @@
 	int i,j,k;
 	const char hexbuf[] =  "0123456789ABCDEF";
 
-	size = sprintf(buffer,"IP address       HW type     Flags       HW address\n");
+	size = sprintf(buffer,"IP address       HW type     Flags       HW address            Mask\n");
+
 	pos+=size;
 	len+=size;
 	  
 	cli();
-	for(i=0; i<ARP_TABLE_SIZE; i++)
+	for(i=0; i<FULL_ARP_TABLE_SIZE; i++)
 	{
 		for(entry=arp_tables[i]; entry!=NULL; entry=entry->next)
 		{
@@ -905,11 +936,15 @@
 			}
 #endif
 			size = sprintf(buffer+len,
-				"%-17s0x%-10x0x%-10x%s\n",
+				"%-17s0x%-10x0x%-10x%s",
 				in_ntoa(entry->ip),
 				(unsigned int)entry->htype,
 				entry->flags,
 				hbuffer);
+			size += sprintf(buffer+len+size,
+				 "     %-17s\n",
+				  entry->mask==DEF_ARP_NETMASK?
+				   "*":in_ntoa(entry->mask));
 	
 			len+=size;
 			pos=begin+len;
@@ -935,17 +970,24 @@
 
 /*
  *	This will find an entry in the ARP table by looking at the IP address.
- *	Be careful, interrupts are turned off on exit!!!
+ *      If exact is true then only exact IP matches will be allowed
+ *      for proxy entries, otherwise the netmask will be used
  */
 
-static struct arp_table *arp_lookup(unsigned long paddr)
+static struct arp_table *arp_lookup(unsigned long paddr, int exact)
 {
 	struct arp_table *entry;
 	unsigned long hash = HASH(paddr);
-
-	cli();
+	
 	for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
 		if (entry->ip == paddr) break;
+
+	/* it's possibly a proxy entry (with a netmask) */
+	if (!entry)
+	for (entry=arp_tables[PROXY_HASH]; entry != NULL; entry = entry->next)
+	  if (exact? (entry->ip==paddr) : !((entry->ip^paddr)&entry->mask)) 
+	    break;	  
+
 	return entry;
 }
 
@@ -960,7 +1002,7 @@
 	struct arp_table *entry;
 	struct sockaddr_in *si;
 	int htype, hlen;
-	unsigned long ip, hash;
+	unsigned long ip;
 	struct rtable *rt;
 
 	memcpy_fromfs(&r, req, sizeof(r));
@@ -980,6 +1022,10 @@
 			htype = ARPHRD_ETHER;
 			hlen = ETH_ALEN;
 			break;
+		case ARPHRD_ARCNET:
+			htype = ARPHRD_ARCNET;
+			hlen = 1;	/* length of arcnet addresses */
+			break;
 #ifdef CONFIG_AX25
 		case ARPHRD_AX25:
 			htype = ARPHRD_AX25;
@@ -1010,15 +1056,12 @@
 	 *	Is there an existing entry for this address?
 	 */
 	
-	hash = HASH(ip);
 	cli();
 
 	/*
 	 *	Find the entry
 	 */
-	for (entry = arp_tables[hash]; entry != NULL; entry = entry->next)
-		if (entry->ip == ip)
-			break;
+	entry = arp_lookup(ip, 1);
 
 	/*
 	 *	Do we need to create a new entry
@@ -1026,6 +1069,10 @@
 	
 	if (entry == NULL)
 	{
+	        unsigned long hash = HASH(ip);
+		if (r.arp_flags & ATF_PUBL)
+		  hash = PROXY_HASH;
+
 		entry = (struct arp_table *) kmalloc(sizeof(struct arp_table),
 					GFP_ATOMIC);
 		if (entry == NULL)
@@ -1041,9 +1088,6 @@
 		arp_tables[hash] = entry;
 		skb_queue_head_init(&entry->skb);
 	}
-	else
-		if (entry->flags & ATF_PUBL)
-			proxies--;
 	/*
 	 *	We now have a pointer to an ARP entry.  Update it!
 	 */
@@ -1051,8 +1095,13 @@
 	memcpy(&entry->ha, &r.arp_ha.sa_data, hlen);
 	entry->last_used = jiffies;
 	entry->flags = r.arp_flags | ATF_COM;
-	if (entry->flags & ATF_PUBL)
-		proxies++;
+	if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK))
+	  {
+	    si = (struct sockaddr_in *) &r.arp_netmask;
+	    entry->mask = si->sin_addr.s_addr;
+	  }
+	else
+	  entry->mask = DEF_ARP_NETMASK;
 	entry->dev = rt->rt_dev;
 	sti();
 
@@ -1084,7 +1133,8 @@
 	 */
 	
 	si = (struct sockaddr_in *) &r.arp_pa;
-	entry = arp_lookup(si->sin_addr.s_addr);
+	cli();
+	entry = arp_lookup(si->sin_addr.s_addr,0);
 
 	if (entry == NULL)
 	{
diff -u --recursive --new-file v1.1.55/linux/net/inet/dev.c linux/net/inet/dev.c
--- v1.1.55/linux/net/inet/dev.c	Sun Aug 21 17:48:41 1994
+++ linux/net/inet/dev.c	Fri Oct 21 09:39:34 1994
@@ -21,6 +21,7 @@
  *		Alan Cox	:	Transmit queue code does relevant stunts to
  *					keep the queue safe.
  *		Alan Cox	:	Fixed double lock.
+ *		Alan Cox	:	Fixed promisc NULL pointer trap
  *
  *	Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have
  *	the rest as well commented in the end.
@@ -439,9 +440,6 @@
 		/*
 		 *	Packet is now solely the responsibility of the driver
 		 */
-#ifdef CONFIG_SLAVE_BALANCING	
-		dev->pkt_queue--;
-#endif
 		return;
 	}
 
@@ -1080,19 +1078,24 @@
 					dev->slave=NULL;
 				}
 #endif				
+
+				if( dev->set_multicast_list!=NULL)
+				{
 				
-				/*
-				 *	Has promiscuous mode been turned off
-				 */	
-				if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
-			 		dev->set_multicast_list(dev,0,NULL);
+					/*
+					 *	Has promiscuous mode been turned off
+					 */	
+				
+					if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
+			 			dev->set_multicast_list(dev,0,NULL);
 			 		
-			 	/*
-			 	 *	Has it been turned on
-			 	 */
+			 		/*
+			 		 *	Has it been turned on
+			 		 */
 	
-				if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
-			  		dev->set_multicast_list(dev,-1,NULL);
+					if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
+			  			dev->set_multicast_list(dev,-1,NULL);
+			  	}
 			  		
 			  	/*
 			  	 *	Have we downed the interface
@@ -1364,11 +1367,6 @@
 {
 	switch(cmd) 
 	{
-		/*
-		 *	The old old setup ioctl. Even its name and this entry will soon be
-		 *	just so much ionization on a backup tape.
-		 */
-
 		case SIOCGIFCONF:
 			(void) dev_ifconf((char *) arg);
 			return 0;
diff -u --recursive --new-file v1.1.55/linux/net/inet/ipx.c linux/net/inet/ipx.c
--- v1.1.55/linux/net/inet/ipx.c	Thu Oct 20 09:37:37 1994
+++ linux/net/inet/ipx.c	Fri Oct 21 09:39:33 1994
@@ -28,6 +28,9 @@
  *	Revision 0.26:  Device drop kills IPX routes via it. (needed for modules)
  *	Revision 0.27:  Autobind <Mark Evans>
  *	Revision 0.28:  Small fix for multiple local networks <Thomas Winder>
+ *	Revision 0.29:  Assorted major errors removed <Mark Evans>
+ *			Small correction to promisc mode error fix <Alan Cox>
+ *			Asynchronous I/O support.
  *
  *			
  *
@@ -563,7 +566,10 @@
 static void def_callback2(struct sock *sk, int len)
 {
 	if(!sk->dead)
+	{
 		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket);
+	}
 }
 
 static int ipx_create(struct socket *sock, int protocol)
@@ -861,7 +867,7 @@
 		int free_it=0;
 		
 		/* Rule: Don't forward packets that have exceeded the hop limit. This is fixed at 16 in IPX */
-		if((ipx->ipx_tctrl==16) || (dev->flags & IFF_PROMISC))
+		if((ipx->ipx_tctrl==16) || (skb->pkt_type!=PACKET_HOST))
 		{
 			kfree_skb(skb,FREE_READ);
 			return(0);
@@ -1354,7 +1360,7 @@
 	if ((p8022_datalink = register_8022_client(val, ipx_rcv)) == NULL)
 		printk("IPX: Unable to register with 802.2\n");
 	
-	printk("Swansea University Computer Society IPX 0.28 BETA for NET3.016\n");
+	printk("Swansea University Computer Society IPX 0.29 BETA for NET3.017\n");
 	
 }
 #endif
diff -u --recursive --new-file v1.1.55/linux/net/inet/skbuff.c linux/net/inet/skbuff.c
--- v1.1.55/linux/net/inet/skbuff.c	Wed Aug 31 10:14:12 1994
+++ linux/net/inet/skbuff.c	Fri Oct 21 09:39:34 1994
@@ -4,6 +4,9 @@
  *	Authors:	Alan Cox <iiitac@pyr.swan.ac.uk>
  *			Florian La Roche <rzsfl@rz.uni-sb.de>
  *
+ *	Fixes:	
+ *		Alan Cox	:	Fixed the worst of the load balancer bugs.
+ *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
  *	as published by the Free Software Foundation; either version
@@ -373,21 +376,10 @@
 				skb->sk->wmem_alloc-=skb->mem_len;
 			if(!skb->sk->dead)
 				skb->sk->write_space(skb->sk);
-#ifdef CONFIG_SLAVE_BALANCING
-			if(skb->in_dev_queue && skb->dev!=NULL)
-				skb->dev->pkt_queue--;
-#endif
-			kfree_skbmem(skb,skb->mem_len);
 		}
 	}
 	else
-	{
-#ifdef CONFIG_SLAVE_BALANCING
-		if(skb->in_dev_queue && skb->dev!=NULL)
-			skb->dev->pkt_queue--;
-#endif
 		kfree_skbmem(skb, skb->mem_len);
-	}
 }
 
 /*
diff -u --recursive --new-file v1.1.55/linux/net/inet/sock.h linux/net/inet/sock.h
--- v1.1.55/linux/net/inet/sock.h	Fri Aug 26 14:44:46 1994
+++ linux/net/inet/sock.h	Fri Oct 21 09:39:33 1994
@@ -150,7 +150,7 @@
   char				ax25_rrtimer;
   char				ax25_timer;
   unsigned char			ax25_n2;
-  unsigned short		ax25_t1,ax25_t3;
+  unsigned short		ax25_t1,ax25_t2,ax25_t3;
   ax25_digi			*ax25_digipeat;
 #endif  
 /* IP 'private area' or will be eventually */
diff -u --recursive --new-file v1.1.55/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.55/linux/net/inet/tcp.c	Fri Oct 21 10:15:07 1994
+++ linux/net/inet/tcp.c	Fri Oct 21 09:44:13 1994
@@ -83,6 +83,7 @@
  *		Matt Dillon	:	Yet more small nasties remove from the TCP code
  *					(Be very nice to this man if tcp finally works 100%) 8)
  *		Alan Cox	:	BSD accept semantics. 
+ *		Alan Cox	:	Reset on closedown bug.
  *	Peter De Schrijver	:	ENOTCONN check missing in tcp_sendto().
  *
  *
@@ -316,7 +317,7 @@
    
 
 	th =(struct tcphdr *)header;
-	sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr);
+	sk = get_sock(&tcp_prot, th->source, daddr, th->dest, saddr);
 
 	if (sk == NULL) 
 		return;
@@ -880,7 +881,7 @@
 	sk->bytes_rcv = 0;
 	sk->ack_timed = 0;
 	th->ack_seq = htonl(sk->acked_seq);
-	sk->window = tcp_select_window(sk)/*sk->prot->rspace(sk)*/;
+	sk->window = tcp_select_window(sk);
 	th->window = htons(sk->window);
 
 	return(sizeof(*th));
@@ -1098,7 +1099,7 @@
 
 		if (skb == NULL) 
 		{
-			if (nonblock /* || copied */) 
+			if (nonblock) 
 			{
 				release_sock(sk);
 				if (copied) 
@@ -1296,7 +1297,7 @@
 	t1->psh = 0;
 	sk->ack_backlog = 0;
 	sk->bytes_rcv = 0;
-	sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/
+	sk->window = tcp_select_window(sk);
 	t1->window = ntohs(sk->window);
 	t1->ack_seq = ntohl(sk->acked_seq);
 	t1->doff = sizeof(*t1)/4;
@@ -1715,7 +1716,7 @@
 	buff->h.seq = sk->write_seq;
 	t1->ack = 1;
 	t1->ack_seq = ntohl(sk->acked_seq);
-	t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
+	t1->window = ntohs(sk->window=tcp_select_window(sk));
 	t1->fin = 1;
 	t1->rst = 0;
 	t1->doff = sizeof(*t1)/4;
@@ -2166,7 +2167,7 @@
 	t1->source = newsk->dummy_th.source;
 	t1->seq = ntohl(newsk->write_seq++);
 	t1->ack = 1;
-	newsk->window = tcp_select_window(newsk);/*newsk->prot->rspace(newsk);*/
+	newsk->window = tcp_select_window(newsk);
 	newsk->sent_seq = newsk->write_seq;
 	t1->window = ntohs(newsk->window);
 	t1->res1 = 0;
@@ -2186,7 +2187,7 @@
 	tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
 	newsk->prot->queue_xmit(newsk, dev, buff, 0);
 
-	reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_TIMEOUT_INIT);
+	reset_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT);
 	skb->sk = newsk;
 
 	/*
@@ -2206,7 +2207,6 @@
 static void tcp_close(struct sock *sk, int timeout)
 {
   	struct sk_buff *buff;
-	int need_reset = 0;
 	struct tcphdr *t1, *th;
 	struct proto *prot;
 	struct device *dev=NULL;
@@ -2236,14 +2236,8 @@
 			struct sk_buff *skb;
 			if(sk->debug)
         			printk("Clean rcv queue\n");
-			while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
-			{
-				/* The +1 is not needed because the FIN takes up seq
-				   is not read!!! */
-				if(skb->len > 0 && after(skb->h.th->seq + skb->len , sk->copied_seq))
-					need_reset = 0;
-				kfree_skb(skb, FREE_READ);
-			}
+  			while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
+  				kfree_skb(skb, FREE_READ);
 			if(sk->debug)
 				printk("Cleaned.\n");
 		}
@@ -2282,15 +2276,6 @@
 				else
 					reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
 			}
-#ifdef NOTDEF
-			/* 
-			 *	Start a timer.
-			 * original code was 4 * sk->rtt.  In converting to the
-			 * new rtt representation, we can't quite use that.
-			 * it seems to make most sense to  use the backed off value
-			 */
-			reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
-#endif
 			if (timeout) 
 				tcp_time_wait(sk);
 			release_sock(sk);
@@ -2380,9 +2365,9 @@
 
 			sk->delay_acks = 0;
 			t1->ack_seq = ntohl(sk->acked_seq);
-			t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
+			t1->window = ntohs(sk->window=tcp_select_window(sk));
 			t1->fin = 1;
-			t1->rst = need_reset;
+			t1->rst = 0;
 			t1->doff = sizeof(*t1)/4;
 			tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
 
@@ -2486,45 +2471,6 @@
 
 
 /*
- *	This routine sorts the send list, and resets the
- *	sk->send_head and sk->send_tail pointers.
- */
-
-static void sort_send(struct sock *sk)
-{
-	struct sk_buff *list = NULL;
-	struct sk_buff *skb,*skb2,*skb3;
-
-	for (skb = sk->send_head; skb != NULL; skb = skb2) 
-	{
-		skb2 = skb->link3;
-		if (list == NULL || before (skb2->h.seq, list->h.seq)) 
-		{
-			skb->link3 = list;
-			sk->send_tail = skb;
-			list = skb;
-		}
-		else
-		{
-			for (skb3 = list; ; skb3 = skb3->link3) 
-			{
-				if (skb3->link3 == NULL ||
-				    before(skb->h.seq, skb3->link3->h.seq))
-				{
-					skb->link3 = skb3->link3;
-					skb3->link3 = skb;
-					if (skb->link3 == NULL) 
-						sk->send_tail = skb;
-					break;
-				}
-			}
-		}
-	}
-	sk->send_head = list;
-}
-  
-
-/*
  *	This routine deals with incoming acks, but not outgoing ones.
  */
 
@@ -2724,11 +2670,7 @@
 		/* Check for a bug. */
 		if (sk->send_head->link3 &&
 		    after(sk->send_head->h.seq, sk->send_head->link3->h.seq)) 
-		{
 			printk("INET: tcp.c: *** bug send_list out of order.\n");
-			sort_send(sk);
-		}
-
 		if (before(sk->send_head->h.seq, ack+1)) 
 		{
 			struct sk_buff *oskb;	
@@ -2979,17 +2921,8 @@
 		if (sk->rcv_ack_seq == sk->write_seq) 
 		{
 			flag |= 1;
-#ifdef THIS_BIT_IS_WRONG			
-			if (sk->acked_seq != sk->fin_seq) 
-			{
-				tcp_time_wait(sk);
-			}
-			else
-#endif			
-			{
-				sk->shutdown |= SEND_SHUTDOWN;
-				tcp_set_state(sk,TCP_FIN_WAIT2);
-			}
+			sk->shutdown |= SEND_SHUTDOWN;
+			tcp_set_state(sk,TCP_FIN_WAIT2);
 		}
 	}
 
@@ -3094,7 +3027,7 @@
 	{
 		new_seq= th->seq + skb->len + th->syn;	/* Right edge of _data_ part of frame */
 		
-		if(after(new_seq,sk->/*copied*/acked_seq+1))	/* If the right edge of this frame is after the last copied byte
+		if(after(new_seq,sk->acked_seq+1))	/* If the right edge of this frame is after the last copied byte
 							   then it contains data we will never touch. We send an RST to 
 							   ensure the far end knows it never got to the application */
 		{
@@ -3110,12 +3043,6 @@
 				sk->state_change(sk);
 			return(0);
 		}
-#if 0		
-		/* Discard the frame here - we've already proved its a duplicate */
-		
-		kfree_skb(skb, FREE_READ);
-		return(0);				
-#endif		
 	}
 	/*
 	 * 	Now we have to walk the chain, and figure out where this one
@@ -3438,7 +3365,6 @@
 			 * sending the ack.
 			 */
 			reset_timer(sk, TIME_CLOSE, TCP_TIMEOUT_LEN);
-			/*sk->fin_seq = th->seq+1;*/
 			tcp_set_state(sk,TCP_CLOSE_WAIT);
 			if (th->rst)
 				sk->shutdown = SHUTDOWN_MASK;
@@ -3468,7 +3394,6 @@
 			 */
 
 			reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-			/*sk->fin_seq = th->seq+1;*/
 			tcp_set_state(sk,TCP_CLOSING);
 			break;
 		case TCP_FIN_WAIT2:
@@ -3476,7 +3401,6 @@
 			 * received a FIN -- send ACK and enter TIME_WAIT
 			 */
 			reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
-			/*sk->fin_seq = th->seq+1;*/
 			sk->shutdown|=SHUTDOWN_MASK;
 			tcp_set_state(sk,TCP_TIME_WAIT);
 			break;
@@ -3707,7 +3631,6 @@
 	 */
 
 	tcp_set_state(sk,TCP_SYN_SENT);
-/*	sk->rtt = TCP_CONNECT_TIME;*/
 	sk->rto = TCP_TIMEOUT_INIT;
 	reset_timer(sk, TIME_WRITE, sk->rto);	/* Timer for repeating the SYN until an answer */
 	sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
@@ -4376,7 +4299,7 @@
 	t1->fin = 0;
 	t1->syn = 0;
 	t1->ack_seq = ntohl(sk->acked_seq);
-	t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/);
+	t1->window = ntohs(tcp_select_window(sk));
 	t1->doff = sizeof(*t1)/4;
 	tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
 
@@ -4425,7 +4348,6 @@
 	switch(optname)
 	{
 		case TCP_MAXSEG:
-/*			if(val<200||val>2048 || val>sk->mtu) */
 /*
  * values greater than interface MTU won't take effect.  however at
  * the point when this call is done we typically don't yet know
diff -u --recursive --new-file v1.1.55/linux/net/inet/timer.c linux/net/inet/timer.c
--- v1.1.55/linux/net/inet/timer.c	Thu Aug 11 20:43:41 1994
+++ linux/net/inet/timer.c	Fri Oct 21 09:39:34 1994
@@ -24,6 +24,7 @@
  *					of inet_bh() with this socket being handled it goes
  *					BOOM! Have to stop timer going off if net_bh is
  *					active or the destroy causes crashes.
+ *		Alan Cox	:	Cleaned up unused code.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -103,26 +104,9 @@
 	sk->inuse = 1;
 	sti();
 
-#ifdef NOTDEF
-	/* 
-	 * what the hell is this doing here?  this belongs in tcp.c.
-	 * I believe that this code is the cause of a lot of timer
-	 * screwups, especially during close (like FIN_WAIT1 states
-	 * with a KEEPOPEN timeout rather then a WRITE timeout).
-	 */
-	if (skb_peek(&sk->write_queue) && 
-	      before(sk->window_seq, sk->write_queue.next->h.seq) &&
-	      sk->send_head == NULL &&
-	      sk->ack_backlog == 0 &&
-	      sk->state != TCP_TIME_WAIT)
-		reset_timer(sk, TIME_PROBE0, sk->rto);
-	else if (sk->keepopen)
-		reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
-#endif
-
 	/* Always see if we need to send an ack. */
 
-	if (sk->ack_backlog) 
+	if (sk->ack_backlog && !sk->zapped) 
 	{
 		sk->prot->read_wakeup (sk);
 		if (! sk->dead)
diff -u --recursive --new-file v1.1.55/linux/net/socket.c linux/net/socket.c
--- v1.1.55/linux/net/socket.c	Fri Sep  9 05:33:50 1994
+++ linux/net/socket.c	Fri Oct 21 10:07:50 1994
@@ -17,7 +17,9 @@
  *					top level.
  *		Alan Cox	:	Move address structures to/from user
  *					mode above the protocol layers.
- *		Rob Janssen	:	Allow 0 length sends
+ *		Rob Janssen	:	Allow 0 length sends.
+ *		Alan Cox	:	Asynchronous I/O support (cribbed from the
+ *					tty drivers).
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -62,6 +64,8 @@
 static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
 static int sock_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg);
+static int sock_fasync(struct inode *inode, struct file *filp, int on);
+		   
 
 
 /*
@@ -78,7 +82,9 @@
 	sock_ioctl,
 	NULL,			/* mmap */
 	NULL,			/* no special open code... */
-	sock_close
+	sock_close,
+	NULL,			/* no fsync */
+	sock_fasync
 };
 
 /*
@@ -256,6 +262,7 @@
 				sock->data = NULL;
 				sock->conn = NULL;
 				sock->iconn = NULL;
+				sock->fasync_list = NULL;
 			/*
 			 * This really shouldn't be necessary, but everything
 			 * else depends on inodes, so we grab it.
@@ -467,7 +474,7 @@
 }
 
 
-void sock_close(struct inode *inode, struct file *file)
+void sock_close(struct inode *inode, struct file *filp)
 {
 	struct socket *sock;
 
@@ -483,11 +490,73 @@
 		printk("NET: sock_close: can't find socket for inode!\n");
 		return;
 	}
-
+	sock_fasync(inode, filp, 0);
 	sock_release(sock);
 }
 
 /*
+ *	Update the socket async list
+ */
+ 
+static int sock_fasync(struct inode *inode, struct file *filp, int on)
+{
+	struct fasync_struct *fa, *fna=NULL, **prev;
+	struct socket *sock;
+	unsigned long flags;
+	
+	if (on)
+	{
+		fna=(struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
+		if(fna==NULL)
+			return -ENOMEM;
+	}
+
+	sock = socki_lookup(inode);
+	
+	prev=&(sock->fasync_list);
+	
+	save_flags(flags);
+	cli();
+	
+	for(fa=*prev; fa!=NULL; prev=&fa->fa_next,fa=*prev)
+		if(fa->fa_file==filp)
+			break;
+	
+	if(on)
+	{
+		if(fa!=NULL)
+		{
+			kfree_s(fna,sizeof(struct fasync_struct));
+			restore_flags(flags);
+			return 0;
+		}
+		fna->fa_file=filp;
+		fna->magic=FASYNC_MAGIC;
+		fna->fa_next=sock->fasync_list;
+		sock->fasync_list=fna;
+	}
+	else
+	{
+		if(fa!=NULL)
+		{
+			*prev=fa->fa_next;
+			kfree_s(fa,sizeof(struct fasync_struct));
+		}
+	}
+	restore_flags(flags);
+	return 0;
+}
+
+int sock_wake_async(struct socket *sock)
+{
+	if(sock->fasync_list==NULL)
+		return -1;
+	kill_fasync(sock->fasync_list, SIGIO);
+	return 0;
+}
+
+	
+/*
  *	Wait for a connection.
  */
 
@@ -1265,6 +1334,32 @@
 	return(-ENOMEM);
 }
 
+/*
+ *	This function is called by a protocol handler that wants to
+ *	remove its address family, and have it unlinked from the
+ *	SOCKET module.
+ */
+ 
+int sock_unregister(int family)
+{
+	int i;
+
+	cli();
+	for(i = 0; i < NPROTO; i++) 
+	{
+		if (pops[i] == NULL) 
+			continue;
+		if(pops[i]->family == family)
+		{
+			pops[i]=NULL;
+			sti();
+			return(i);
+		}
+	}
+	sti();
+	return(-ENOENT);
+}
+
 void proto_init(void)
 {
 	extern struct net_proto protocols[];	/* Network protocols */
@@ -1286,7 +1381,7 @@
 	struct socket *sock;
 	int i;
 
-	printk("Swansea University Computer Society NET3.016\n");
+	printk("Swansea University Computer Society NET3.017\n");
 
 	/*
 	 *	Release all sockets. 
