diff -u --recursive --new-file v1.3.25/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v1.3.25/linux/Documentation/devices.tex	Sun Sep  3 12:26:47 1995
+++ linux/Documentation/devices.tex	Sun Sep 10 10:30:32 1995
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$Peter.Anvin@linux.org$>$}
-\date{Last revised: August 28, 1995}
+\date{Last revised: September 6, 1995}
 \maketitle
 %
 \noindent
@@ -51,11 +51,11 @@
 registry of allocated major device numbers, as well as the recommended
 {\file /dev} directory nodes for these devices.
 
-This list is available via FTP from ftp.yggdrasil.com in the directory
-{\file /pub/device-list}; filename is {\file devices.{\it format\/}}
-where {\it format\/} is {\file txt} (ASCII), {\file tex} (\LaTeX),
-{\file dvi} (DVI) or {\file ps} (PostScript).  In cases of
-discrepancy, the \LaTeX\ version has priority.
+This list is now included with the Linux kernel sources in \LaTeX\ and
+ASCII form.  This list is also vailable via FTP from ftp.yggdrasil.com
+in the directory {\file /pub/device-list}; filename is {\file
+devices.{\it format\/}} where {\it format\/} is {\file txt} (ASCII),
+{\file tex} (\LaTeX), {\file dvi} (DVI) or {\file ps} (PostScript).
 
 This document is included by reference into the Linux Filesystem
 Standard (FSSTND).  The FSSTND is available via FTP from
@@ -69,6 +69,11 @@
 
 Allocations marked (68k) apply to Linux/68k only.
 
+This document is in the public domain.  The author requests, however,
+that semantically altered versions are not distributed without
+permission of the author, assuming the author can be contacted without
+an unreasonable effort.
+
 \section{Major numbers}
 
 \begin{devicelist}
@@ -130,9 +135,10 @@
 \major{32}{}{char }{Specialix serial card}
 \major{  }{}{block}{Philips LMS-206 CD-ROM}
 \major{33}{}{char }{Specialix serial card -- alternate devices}
-\major{  }{}{block}{Modular RAM disk}
-\major{34}{}{block}{Third IDE hard disk/CD-ROM interface}
-\major{35}{}{block}{Fourth IDE hard disk/CD-ROM interface}
+\major{  }{}{block}{Third IDE hard disk/CD-ROM interface}
+\major{34}{}{char }{Z8530 HDLC driver}
+\major{  }{}{block}{Fourth IDE hard disk/CD-ROM interface}
+\major{35}{}{block}{Modular RAM disk}
 \major{36--223}{}{}{Unallocated}
 \major{224--254}{}{}{Local use}
 \major{255}{}{}{Reserved}
@@ -705,31 +711,41 @@
 	\minor{0}{/dev/cux0}{Callout device corresponding to {\file ttyX0}}
 	\minor{1}{/dev/cux1}{Callout device corresponding to {\file ttyX1}}
 	\minordots
-\major{  }{}{block}{Modular RAM disk}
-	\minor{0}{/dev/ram0}{First modular RAM disk}
-	\minor{1}{/dev/ram1}{Second modular RAM disk}
-	\minordots
-	\minor{255}{/dev/ram255}{256th modular RAM disk}
-\end{devicelist}
-
-\begin{devicelist}
-\major{33}{}{block}{Third IDE hard disk/CD-ROM interface}
+\major{  }{}{block}{Third IDE hard disk/CD-ROM interface}
 	\minor{0}{/dev/hde}{Master: whole disk (or CD-ROM)}
 	\minor{64}{/dev/hdf}{Slave: whole disk (or CD-ROM)}
 \end{devicelist}
 
+\noindent
+Partitions are handled the same way as for the first interface (see
+major number 3).
+
 \begin{devicelist}
-\major{34}{}{block}{Fourth IDE hard disk/CD-ROM interface}
+\major{34}{}{char }{Z8530 HDLC driver}
+	\minor{0}{/dev/sc1}{First Z8530, first port}
+	\minor{1}{/dev/sc2}{First Z8530, second port}
+	\minor{2}{/dev/sc3}{Second Z8530, first port}
+	\minor{3}{/dev/sc4}{Second Z8530, second port}
+	\minordots
+\major{  }{}{block}{Fourth IDE hard disk/CD-ROM interface}
 	\minor{0}{/dev/hdg}{Master: whole disk (or CD-ROM)}
 	\minor{64}{/dev/hdh}{Slave: whole disk (or CD-ROM)}
 \end{devicelist}
 
 \noindent
-For both IDE interfaces: partitions are handled the same way as for
-the first interface (see major number 3).
+Partitions are handled the same way as for the first interface (see
+major number 3).
+
+\begin{devicelist}
+\major{35}{}{block}{Modular RAM disk}
+	\minor{0}{/dev/ram0}{First modular RAM disk}
+	\minor{1}{/dev/ram1}{Second modular RAM disk}
+	\minordots
+	\minor{255}{/dev/ram255}{256th modular RAM disk}
+\end{devicelist}
 
 \begin{devicelist}
-\major{35}{--223}{}{Unallocated}
+\major{36}{--223}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
diff -u --recursive --new-file v1.3.25/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v1.3.25/linux/Documentation/devices.txt	Sun Sep  3 12:26:47 1995
+++ linux/Documentation/devices.txt	Sun Sep 10 10:30:32 1995
@@ -2,17 +2,18 @@
 
 	 Maintained by H. Peter Anvin <Peter.Anvin@linux.org>
 
-		    Last revised: August 28, 1995
+		   Last revised: September 6, 1995
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he lost network access in 1993.  It is a
 registry of allocated major device numbers, as well as the recommended
 /dev directory nodes for these devices.
 
-This list is available via FTP from ftp.yggdrasil.com in the directory
-/pub/device-list; filename is devices.<format> where <format> is txt
-(ASCII), tex (LaTeX), dvi (DVI) or ps (PostScript).  In cases of
-discrepancy, the LaTeX version has priority.
+This list is now included with the Linux kernel sources in LaTeX and
+ASCII form.  This list is also available via FTP from
+ftp.yggdrasil.com in the directory /pub/device-list; filename is
+devices.<format> where <format> is txt (ASCII), tex (LaTeX), dvi (DVI)
+or ps (PostScript).
 
 This document is included by reference into the Linux Filesystem
 Standard (FSSTND).  The FSSTND is available via FTP from
@@ -25,6 +26,11 @@
 
 Allocations marked (68k) apply to Linux/68k only.
 
+This document is in the public domain.  The author requests, however,
+that semantically altered versions are not distributed without
+permission of the author, assuming the author can be contacted without
+an unreasonable effort.
+
   0 		Unnamed devices (NFS mounts, loopback devices)
 		  0 = reserved as null device number
 
@@ -477,25 +483,33 @@
 		  0 = /dev/cux0		Callout device corresponding to ttyX0
 		  1 = /dev/cux1		Callout device corresponding to ttyX1
 		      ...
-    block	Modular RAM disk device
-		  0 = /dev/ram0		First modular RAM disk
-		  1 = /dev/ram1		Second modular RAM disk
-		      ...
-		255 = /dev/ram255	256th modular RAM disk
-
- 33 block	Third IDE hard disk/CD-ROM interface
+    block	Third IDE hard disk/CD-ROM interface
     		  0 = /dev/hde		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdf		Slave: whole disk (or CD-ROM)
 
- 34 block	Fourth IDE hard disk/CD-ROM interface
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
+ 34 char	Z8530 HDLC driver
+		  0 = /dev/sc1		First Z8530, first port
+		  1 = /dev/sc2		First Z8530, second port
+		  2 = /dev/sc3		Second Z8530, first port
+		  3 = /dev/sc4		Second Z8530, second port
+		      ...
+    block	Fourth IDE hard disk/CD-ROM interface
     		  0 = /dev/hdg		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdh		Slave: whole disk (or CD-ROM)
 		
-		For both IDE interfaces: partitions are handled the
-		same way as for the first interface (see major number
-		3).
+		Partitions are handled the same way as for the first
+		interface (see major number 3).
+
+ 35 block	Modular RAM disk device
+		  0 = /dev/ram0		First modular RAM disk
+		  1 = /dev/ram1		Second modular RAM disk
+		      ...
+		255 = /dev/ram255	256th modular RAM disk
 
- 35-223		UNALLOCATED
+ 36-223		UNALLOCATED
 
 224-254		LOCAL USE
 		Allocated for local/experimental use
diff -u --recursive --new-file v1.3.25/linux/Makefile linux/Makefile
--- v1.3.25/linux/Makefile	Sat Sep  9 15:26:51 1995
+++ linux/Makefile	Mon Sep 11 20:56:37 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 25
+SUBLEVEL = 26
 
 ARCH = i386
 
@@ -21,6 +21,7 @@
 AR	=ar
 NM	=nm
 STRIP	=strip
+AWK	=awk
 
 all:	do-it-all
 
@@ -258,7 +259,7 @@
 
 #depend dep: .hdepend
 depend dep: archdep .hdepend include/linux/version.h
-	awk -f scripts/depend.awk init/*.c > .tmpdepend
+	$(AWK) -f scripts/depend.awk init/*.c > .tmpdepend
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep; done
 	mv .tmpdepend .depend
 ifdef CONFIG_MODVERSIONS
@@ -296,5 +297,5 @@
 
 .hdepend: dummy
 	rm -f $@
-	awk -f scripts/depend.awk `find $(HPATH) -name \*.h -print` > .$@
+	$(AWK) -f scripts/depend.awk `find $(HPATH) -name \*.h -print` > .$@
 	mv .$@ $@
diff -u --recursive --new-file v1.3.25/linux/README linux/README
--- v1.3.25/linux/README	Sun Sep  3 12:26:48 1995
+++ linux/README	Mon Sep 11 07:47:44 1995
@@ -199,6 +199,10 @@
    important: it tells something about why the kernel dumped code (in
    the above example it's due to a bad kernel pointer)
 
+ - You can use the "ksymoops" program to make sense of the dump.  Find
+   the C++ sources under the scripts/ directory to avoid having to do
+   the dump lookup by hand:
+
  - in debugging dumps like the above, it helps enormously if you can
    look up what the EIP value means.  The hex value as such doesn't help
    me or anybody else very much: it will depend on your particular
diff -u --recursive --new-file v1.3.25/linux/Rules.make linux/Rules.make
--- v1.3.25/linux/Rules.make	Sat Sep  9 15:26:51 1995
+++ linux/Rules.make	Mon Sep 11 20:57:04 1995
@@ -68,7 +68,7 @@
 #
 fastdep: dummy
 	if [ -n "$(wildcard *.[chS])" ]; then \
-	awk -f $(TOPDIR)/scripts/depend.awk *.[chS] > .depend; fi
+	$(AWK) -f $(TOPDIR)/scripts/depend.awk *.[chS] > .depend; fi
 ifdef ALL_SUB_DIRS
 	set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i fastdep; done
 endif
diff -u --recursive --new-file v1.3.25/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v1.3.25/linux/arch/alpha/config.in	Sat Sep  9 15:26:51 1995
+++ linux/arch/alpha/config.in	Mon Sep 11 20:54:50 1995
@@ -178,7 +178,6 @@
 fi
 bool 'Other ISA cards' CONFIG_NET_ISA y
 if [ "$CONFIG_NET_ISA" = "y" ]; then
-	tristate 'Arcnet support' CONFIG_ARCNET n
 	tristate 'Cabletron E21xx support' CONFIG_E2100 n
 	tristate 'DEPCA support' CONFIG_DEPCA y
 	tristate 'EtherWorks 3 support' CONFIG_EWRK3 n
@@ -225,6 +224,7 @@
 if [ "$CONFIG_TR" = "y" ]; then
 	tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR y
 fi
+tristate 'Arcnet support' CONFIG_ARCNET n
 fi
 fi
 
diff -u --recursive --new-file v1.3.25/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.3.25/linux/arch/alpha/kernel/entry.S	Sun Sep  3 12:26:48 1995
+++ linux/arch/alpha/kernel/entry.S	Wed Sep 13 10:08:38 1995
@@ -8,6 +8,7 @@
 
 #define halt	.long PAL_halt
 #define rti	.long PAL_rti
+#define SIGCHLD	20
 
 #define NR_SYSCALLS 320
 #define osf_vfork sys_fork
@@ -189,9 +190,9 @@
  * stack buildup, as we can't do system calls from kernel space.
  */
 .align 3
-.globl	kernel_fork
-.ent	kernel_fork
-kernel_fork:
+.globl	kernel_clone
+.ent	kernel_clone
+kernel_clone:
 	subq $30,6*8,$30
 	stq $31,0($30)
 	stq $26,8($30)
@@ -201,11 +202,11 @@
 	stq $18,40($30)
 	bis $31,2,$0	/* Register v0: syscall nr for fork() */
 	SAVE_ALL
-	lda $27,sys_fork
-	jsr $26,($27),sys_fork
+	lda $27,sys_clone
+	jsr $26,($27),sys_clone
 	stq $0,0($30)	
 	br ret_from_sys_call
-.end	kernel_fork
+.end	kernel_clone
 
 .align 3
 .ent	do_switch_stack
@@ -401,19 +402,37 @@
 
 .end	entUnaUser
 
+/*
+ * A fork is the same as clone(SIGCHLD, 0);
+*/
 .align 3
 .globl	sys_fork
 .ent	sys_fork
 sys_fork:
 	br $1,do_switch_stack
-	bis $30,$30,$16
-	lda $27,alpha_fork
-	jsr $26,($27),alpha_fork
+	bis $31,SIGCHLD,$16
+	bis $31,$31,$17
+	bis $30,$30,$18
+	lda $27,alpha_clone
+	jsr $26,($27),alpha_clone
 	br $1,undo_switch_stack
 	ret $31,($26),1
 .end	sys_fork
 
 .align 3
+.globl	sys_clone
+.ent	sys_clone
+sys_clone:
+	br $1,do_switch_stack
+	/* arg1 and arg2 come from the user */
+	bis $30,$30,$18
+	lda $27,alpha_clone
+	jsr $26,($27),alpha_clone
+	br $1,undo_switch_stack
+	ret $31,($26),1
+.end	sys_clone
+
+.align 3
 .globl  alpha_switch_to
 .ent    alpha_switch_to
 alpha_switch_to:
@@ -610,6 +629,6 @@
 /* linux-specific system calls start at 300 */
 /*300*/	.quad sys_bdflush, sys_sethae, sys_mount, sys_adjtimex, sys_swapoff
 	.quad sys_getdents, sys_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms
-	.quad sys_syslog, sys_reboot, do_entSys, do_entSys, do_entSys
+	.quad sys_syslog, sys_reboot, sys_clone, do_entSys, do_entSys
 	.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
 
diff -u --recursive --new-file v1.3.25/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v1.3.25/linux/arch/alpha/kernel/head.S	Thu Jun 29 19:02:38 1995
+++ linux/arch/alpha/kernel/head.S	Wed Sep 13 10:08:38 1995
@@ -14,11 +14,13 @@
 #define halt .long PAL_halt
 
 .globl swapper_pg_dir
+.globl _stext
 swapper_pg_dir=SWAPPER_PGD
 
 	.set noreorder
 	.globl	__start
 	.ent	__start
+_stext:
 __start:
 	br	$27,1f
 1:	ldgp	$29,0($27)
diff -u --recursive --new-file v1.3.25/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v1.3.25/linux/arch/alpha/kernel/irq.c	Sun Sep  3 12:26:48 1995
+++ linux/arch/alpha/kernel/irq.c	Wed Sep 13 10:08:38 1995
@@ -449,7 +449,6 @@
 static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq, ack;
-	struct irqaction * action;
 
 	ack = irq = (vector - 0x800) >> 4;
 
diff -u --recursive --new-file v1.3.25/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v1.3.25/linux/arch/alpha/kernel/process.c	Sun Sep  3 12:26:48 1995
+++ linux/arch/alpha/kernel/process.c	Wed Sep 13 10:08:38 1995
@@ -84,14 +84,20 @@
 }
 
 /*
- * "alpha_fork()".. By the time we get here, the
+ * "alpha_clone()".. By the time we get here, the
  * non-volatile registers have also been saved on the
  * stack. We do some ugly pointer stuff here.. (see
  * also copy_thread)
+ *
+ * Notice that "fork()" is implemented in terms of clone,
+ * with parameters (SIGCHLD, 0).
  */
-int alpha_fork(struct switch_stack * swstack)
+int alpha_clone(unsigned long clone_flags, unsigned long usp,
+	struct switch_stack * swstack)
 {
-	return do_fork(SIGCHLD, rdusp(), (struct pt_regs *) (swstack+1));
+	if (!usp)
+		usp = rdusp();
+	return do_fork(clone_flags, usp, (struct pt_regs *) (swstack+1));
 }
 
 extern void ret_from_sys_call(void);
diff -u --recursive --new-file v1.3.25/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
--- v1.3.25/linux/arch/alpha/kernel/signal.c	Sun Sep  3 12:26:49 1995
+++ linux/arch/alpha/kernel/signal.c	Wed Sep 13 10:08:38 1995
@@ -229,7 +229,7 @@
 	while ((signr = current->signal & mask) != 0) {
 		signr = ffz(~signr);
 		clear_bit(signr, &current->signal);
-		sa = current->sigaction + signr;
+		sa = current->sig->action + signr;
 		signr++;
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
@@ -246,7 +246,7 @@
 				current->signal |= _S(signr);
 				continue;
 			}
-			sa = current->sigaction + signr - 1;
+			sa = current->sig->action + signr - 1;
 		}
 		if (sa->sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
@@ -268,7 +268,7 @@
 					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 						SA_NOCLDSTOP))
 					notify_parent(current);
 				schedule();
@@ -315,7 +315,7 @@
 	pc = regs->pc;
 	frame = (struct sigcontext_struct *) rdusp();
 	signr = 1;
-	sa = current->sigaction;
+	sa = current->sig->action;
 	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 		if (mask > handler_signal)
 			break;
diff -u --recursive --new-file v1.3.25/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.25/linux/arch/i386/config.in	Sat Sep  9 15:26:51 1995
+++ linux/arch/i386/config.in	Mon Sep 11 20:54:25 1995
@@ -169,7 +169,6 @@
 fi
 bool 'Other ISA cards' CONFIG_NET_ISA n
 if [ "$CONFIG_NET_ISA" = "y" ]; then
-	tristate 'Arcnet support' CONFIG_ARCNET n
 	tristate 'Cabletron E21xx support' CONFIG_E2100 n
 	tristate 'DEPCA support' CONFIG_DEPCA n
 	tristate 'EtherWorks 3 support' CONFIG_EWRK3 n
@@ -216,6 +215,7 @@
 if [ "$CONFIG_TR" = "y" ]; then
 	tristate 'IBM Tropic chipset based adaptor support' CONFIG_IBMTR y
 fi
+tristate 'Arcnet support' CONFIG_ARCNET n
 fi
 fi
 
@@ -247,8 +247,8 @@
 comment 'Filesystems'
 
 tristate 'Standard (minix) fs support' CONFIG_MINIX_FS y
-bool 'Extended fs support' CONFIG_EXT_FS n
-bool 'Second extended fs support' CONFIG_EXT2_FS y
+tristate 'Extended fs support' CONFIG_EXT_FS n
+tristate 'Second extended fs support' CONFIG_EXT2_FS y
 tristate 'xiafs filesystem support' CONFIG_XIA_FS n
 tristate 'msdos fs support' CONFIG_MSDOS_FS y
 if [ "$CONFIG_MSDOS_FS" != "n" ]; then
@@ -267,13 +267,13 @@
 
 bool 'Cyclades async mux support' CONFIG_CYCLADES n
 tristate 'Parallel printer support' CONFIG_PRINTER n
-bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
-bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
+tristate 'Logitech busmouse support' CONFIG_BUSMOUSE n
+tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
 if [ "$CONFIG_PSMOUSE" = "y" ]; then
   bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
 fi
-bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
-bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
+tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
+tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
 
 
 bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
diff -u --recursive --new-file v1.3.25/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v1.3.25/linux/arch/i386/kernel/process.c	Sat Sep  9 15:26:51 1995
+++ linux/arch/i386/kernel/process.c	Wed Sep 13 10:08:38 1995
@@ -44,17 +44,9 @@
  */
 asmlinkage int sys_idle(void)
 {
-	int i;
-	pmd_t * pmd;
-
 	if (current->pid != 0)
 		return -EPERM;
 
-	/* Map out the low memory: it's no longer needed */
-	pmd = pmd_offset(swapper_pg_dir, 0);
-	for (i = 0 ; i < 768 ; i++)
-		pmd_clear(pmd++);
-
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
@@ -120,6 +112,9 @@
  */
 void exit_thread(void)
 {
+	/* forget lazy i387 state */
+	if (last_task_used_math == current)
+		last_task_used_math = NULL;
 	/* forget local segments */
 	__asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
 		: /* no outputs */
@@ -255,8 +250,8 @@
 	unsigned long clone_flags;
 	unsigned long newsp;
 
-	newsp = regs.ebx;
-	clone_flags = regs.ecx;
+	clone_flags = regs.ebx;
+	newsp = regs.ecx;
 	if (!newsp)
 		newsp = regs.esp;
 	return do_fork(clone_flags, newsp, &regs);
diff -u --recursive --new-file v1.3.25/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v1.3.25/linux/arch/i386/kernel/signal.c	Thu Sep  7 17:17:16 1995
+++ linux/arch/i386/kernel/signal.c	Mon Sep 11 14:40:15 1995
@@ -156,7 +156,7 @@
 			"btrl %1,%0"
 			:"=m" (current->signal),"=r" (signr)
 			:"0" (current->signal), "1" (signr));
-		sa = current->sigaction + signr;
+		sa = current->sig->action + signr;
 		signr++;
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
@@ -172,7 +172,7 @@
 				current->signal |= _S(signr);
 				continue;
 			}
-			sa = current->sigaction + signr - 1;
+			sa = current->sig->action + signr - 1;
 		}
 		if (sa->sa_handler == SIG_IGN) {
 			if (signr != SIGCHLD)
@@ -194,7 +194,7 @@
 					continue;
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
-				if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
+				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 						SA_NOCLDSTOP))
 					notify_parent(current);
 				schedule();
@@ -235,7 +235,7 @@
 	eip = regs->eip;
 	frame = (unsigned long *) regs->esp;
 	signr = 1;
-	sa = current->sigaction;
+	sa = current->sig->action;
 	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 		if (mask > handler_signal)
 			break;
diff -u --recursive --new-file v1.3.25/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.25/linux/drivers/block/genhd.c	Sun Sep  3 16:12:48 1995
+++ linux/drivers/block/genhd.c	Sun Sep 10 09:37:21 1995
@@ -234,6 +234,14 @@
 			continue;
 		if (p->sys_ind == EXTENDED_PARTITION) {
 			printk(" <");
+			/*
+			 * If we are rereading the partition table, we need
+			 * to set the size of the partition so that we will
+			 * be able to bread the block containing the extended
+			 * partition info.
+			 */
+			hd->sizes[minor] = hd->part[minor].nr_sects 
+			  	>> (BLOCK_SIZE_BITS - 9);
 			extended_partition(hd, (hd->major << 8) | minor);
 			printk(" >");
 			/* prevent someone doing mkfs or mkswap on
@@ -384,6 +392,10 @@
 	current_minor = 1 + first_minor;
 	check_partition(dev, major + first_minor);
 
+ 	/*
+ 	 * We need to set the sizes array before we will be able to access
+ 	 * any of the partitions on this device.
+ 	 */
 	if (dev->sizes != NULL) {	/* optional safeguard in ll_rw_blk.c */
 		for (i = first_minor; i < end_minor; i++)
 			dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
diff -u --recursive --new-file v1.3.25/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.25/linux/drivers/block/ide.c	Thu Sep  7 17:17:17 1995
+++ linux/drivers/block/ide.c	Sun Sep 10 10:30:32 1995
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.13  Sep 4, 1995
+ *  linux/drivers/block/ide.c	Version 5.13b  Sep 9, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
@@ -140,6 +140,8 @@
  *			made do_drive_cmd() into public ide_do_drive_cmd()
  *  Version 5.13	fixed typo ('B'), thanks to houston@boyd.geog.mcgill.ca
  *			fixed ht6560b support
+ *  Version 5.13b (sss)	fix problem in calling ide_cdrom_setup()
+ *                      don't bother invalidating nonexistent partitions
  *
  *  Driver compile-time options are in ide.h
  *
@@ -1720,9 +1722,11 @@
 	restore_flags(flags);
 
 	for (p = 0; p < (1<<PARTN_BITS); ++p) {
-		sync_dev           (major | (minor + p));
-		invalidate_inodes  (major | (minor + p));
-		invalidate_buffers (major | (minor + p));
+		if (drive->part[p].nr_sects > 0) {
+			sync_dev           (major | (minor + p));
+			invalidate_inodes  (major | (minor + p));
+			invalidate_buffers (major | (minor + p));
+		}
 		drive->part[p].start_sect = 0;
 		drive->part[p].nr_sects   = 0;
 	};
@@ -2292,18 +2296,20 @@
 		 * Second drive should only exist if first drive was found,
 		 * but a lot of cdrom drives seem to be configured as slave-only
 		 */
-		for (unit = 0; unit < 2; ++unit)  /* note the hardcoded '2' */
-			(void) probe_for_drive(&hwif->drives[unit]);
+		for (unit = 0; unit < 2; ++unit) { /* note the hardcoded '2' */
+			ide_drive_t *drive = &hwif->drives[unit];
+			(void) probe_for_drive (drive);
+#ifdef CONFIG_BLK_DEV_IDECD
+			if (drive->present && drive->media == cdrom)
+				ide_cdrom_setup(drive);
+#endif	/* CONFIG_BLK_DEV_IDECD */
+		}
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
 			if (drive->present) {
 				hwif->present = 1;
 				request_region(hwif->io_base,  8, hwif->name);
 				request_region(hwif->ctl_port, 1, hwif->name);
-#ifdef CONFIG_BLK_DEV_IDECD
-				if (drive->media == cdrom)
-					ide_cdrom_setup(drive);
-#endif	/* CONFIG_BLK_DEV_IDECD */
 				break;
 			}
 		}
diff -u --recursive --new-file v1.3.25/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.25/linux/drivers/char/Makefile	Thu Sep  7 17:17:17 1995
+++ linux/drivers/char/Makefile	Wed Sep 13 10:08:38 1995
@@ -24,14 +24,24 @@
 L_OBJS += cyclades.o
 endif
 
-ifdef CONFIG_ATIXL_BUSMOUSE
+ifeq ($(CONFIG_ATIXL_BUSMOUSE),y)
 M = y
 L_OBJS += atixlmouse.o
+else
+  ifeq ($(CONFIG_ATIXL_BUSMOUSE),m)
+  M_OBJS += atixlmouse.o
+  MM = m
+  endif
 endif
 
-ifdef CONFIG_BUSMOUSE
+ifeq ($(CONFIG_BUSMOUSE),y)
 M = y
 L_OBJS += busmouse.o
+else
+  ifeq ($(CONFIG_BUSMOUSE),m)
+  M_OBJS += busmouse.o
+  MM = m
+  endif
 endif
 
 ifeq ($(CONFIG_PRINTER),y)
@@ -42,18 +52,24 @@
   endif
 endif
 
-ifdef CONFIG_MS_BUSMOUSE
+ifeq ($(CONFIG_MS_BUSMOUSE),y)
 M = y
 L_OBJS += msbusmouse.o
+else
+  ifeq ($(CONFIG_MS_BUSMOUSE),m)
+  M_OBJS += msbusmouse.o
+  MM = m
+  endif
 endif
 
-ifdef CONFIG_82C710_MOUSE
-CONFIG_PSMOUSE = CONFIG_PSMOUSE
-endif
-
-ifdef CONFIG_PSMOUSE
+ifeq ($(CONFIG_PSMOUSE),y)
 M = y
 L_OBJS += psaux.o
+else
+  ifeq ($(CONFIG_PSMOUSE),m)
+  M_OBJS += psaux.o
+  MM = m
+  endif
 endif
 
 ifdef CONFIG_QIC02_TAPE
@@ -62,6 +78,10 @@
 
 ifdef M
 L_OBJS += mouse.o
+else
+  ifdef MM
+  M_OBJS += mouse.o
+  endif
 endif
   
 ifdef CONFIG_SCC
diff -u --recursive --new-file v1.3.25/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v1.3.25/linux/drivers/char/atixlmouse.c	Wed Aug  2 13:21:00 1995
+++ linux/drivers/char/atixlmouse.c	Wed Sep 13 10:08:39 1995
@@ -5,10 +5,19 @@
  * Uses VFS interface for linux 0.98 (01OCT92)
  *
  * Modified by Chris Colohan (colohan@eecg.toronto.edu)
+ * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  *
- * version 0.3
+ * version 0.3a
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -19,6 +28,8 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 
+#include "mouse.h"
+
 #define ATIXL_MOUSE_IRQ		5 /* H/W interrupt # set up on ATIXL board */
 #define ATIXL_BUSMOUSE		3 /* Minor device # (mknod c 10 3 /dev/bm) */
 
@@ -61,6 +72,7 @@
 	int ready;
 	int active;
 	struct wait_queue *wait;
+	struct fasync_struct *fasync;
 } mouse;
 
 void mouse_interrupt(int irq, struct pt_regs * regs)
@@ -80,19 +92,31 @@
 		mouse.dy += dy;
 		mouse.ready = 1;
 		wake_up_interruptible(&mouse.wait);
+		if (mouse.fasync)
+			kill_fasync(mouse.fasync, SIGIO);
 	}
 	ATIXL_MSE_ENABLE_UPDATE();
 }
 
+static int fasync_mouse(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &mouse.fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
 static void release_mouse(struct inode * inode, struct file * file)
 {
 	ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
 	mouse.active = 0;
 	mouse.ready = 0;
 	free_irq(ATIXL_MOUSE_IRQ);
+	fasync_mouse(inode, file, 0);
 }
 
-
 static int open_mouse(struct inode * inode, struct file * file)
 {
 	if (!mouse.present)
@@ -169,9 +193,21 @@
 	NULL,		/* mouse_mmap */
 	open_mouse,
 	release_mouse,
+	NULL,
+	fasync_mouse,
 };
 
+static struct mouse atixl_mouse = { 
+	ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops
+};
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void)
+#else
 unsigned long atixl_busmouse_init(unsigned long kmem_start)
+#endif
 {
 	unsigned char a,b,c;
 
@@ -182,7 +218,11 @@
 		printk("\nATI Inport ");
 	else{
 		mouse.present = 0;
+#ifdef MODULE
+		return -EIO;
+#else
 		return kmem_start;
+#endif
 	}
 	outb(0x80, ATIXL_MSE_CONTROL_PORT);	/* Reset the Inport device */
 	outb(0x07, ATIXL_MSE_CONTROL_PORT);	/* Select Internal Register 7 */
@@ -194,5 +234,19 @@
 	mouse.dx = mouse.dy = 0;
 	mouse.wait = NULL;
 	printk("Bus mouse detected and installed.\n");
+	mouse_register(&atixl_mouse);
+#ifdef MODULE
+	return 0;
+#else
 	return kmem_start;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("atixlmouse: in use, remove delayed\n");
+	mouse_deregister(&atixl_mouse);
 }
+#endif
diff -u --recursive --new-file v1.3.25/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v1.3.25/linux/drivers/char/busmouse.c	Wed Aug  2 13:21:00 1995
+++ linux/drivers/char/busmouse.c	Wed Sep 13 10:08:39 1995
@@ -21,8 +21,21 @@
  *   removed assignment chr_fops[10] = &mouse_fops; see mouse.c
  *   renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public.
  *   renamed this file mouse.c => busmouse.c
+ *
+ * Minor addition by Cliff Matthews
+ *   added fasync support
+ *
+ * Modularised 6-Sep-95 Philip Blundell <pjb27@cam.ac.uk> 
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/busmouse.h>
@@ -81,10 +94,23 @@
 	      mouse.dy = -2048;
 	  if (mouse.dy >  2048)
 	      mouse.dy =  2048;
+
+	  if (mouse.fasyncptr)
+	      kill_fasync(mouse.fasyncptr, SIGIO);
 	}
 	MSE_INT_ON();
 }
 
+static int fasync_mouse(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &mouse.fasyncptr);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
 /*
  * close access to the mouse (can deal with multiple
  * opens if allowed in the future)
@@ -96,6 +122,7 @@
 	    MSE_INT_OFF();
 	    free_irq(mouse_irq);
 	}
+	fasync_mouse(inode, file, 0);
 }
 
 /*
@@ -212,9 +239,21 @@
 	NULL,		/* mouse_mmap */
 	open_mouse,
 	close_mouse,
+	NULL,
+	fasync_mouse,
 };
 
+static struct mouse bus_mous = {
+	LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
+};
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void)
+#else
 unsigned long bus_mouse_init(unsigned long kmem_start)
+#endif
 {
 	int i;
 
@@ -224,7 +263,11 @@
 		/* busy loop */;
 	if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
 		mouse.present = 0;
+#ifdef MODULE
+		return -EIO;
+#else
 		return kmem_start;
+#endif
 	}
 	outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
 	MSE_INT_OFF();
@@ -237,5 +280,19 @@
 	mouse.wait = NULL;
 	printk("Logitech Bus mouse detected and installed with IRQ %d.\n",
 	       mouse_irq);
+	mouse_register(&bus_mouse);
+#ifdef MODULE
+	return 0;
+#else
 	return kmem_start;
+#endif
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("busmouse: in use - remove delayed\n");
+	mouse_deregister(&bus_mouse);
 }
+#endif
diff -u --recursive --new-file v1.3.25/linux/drivers/char/mouse.c linux/drivers/char/mouse.c
--- v1.3.25/linux/drivers/char/mouse.c	Thu Oct 13 14:07:06 1994
+++ linux/drivers/char/mouse.c	Wed Sep 13 10:08:39 1995
@@ -12,57 +12,56 @@
  *
  * Made things a lot mode modular - easy to compile in just one or two
  * of the mouse drivers, as they are now completely independent. Linus.
+ *
+ * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/mouse.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
+#include <linux/malloc.h>
+
+#include "mouse.h"
 
 /*
- * note that you can remove any or all of the drivers by undefining
- * the minor values in <linux/mouse.h>
+ * Head entry for the doubly linked mouse list
  */
-extern struct file_operations bus_mouse_fops;
-extern struct file_operations psaux_fops;
-extern struct file_operations ms_bus_mouse_fops;
-extern struct file_operations atixl_busmouse_fops;
+static struct mouse mouse_list = { 0, "head", NULL, &mouse_list, &mouse_list };
 
+#ifndef MODULE
 extern unsigned long bus_mouse_init(unsigned long);
 extern unsigned long psaux_init(unsigned long);
 extern unsigned long ms_bus_mouse_init(unsigned long);
 extern unsigned long atixl_busmouse_init(unsigned long);
+#endif
 
 static int mouse_open(struct inode * inode, struct file * file)
 {
 	int minor = MINOR(inode->i_rdev);
+	struct mouse *c = mouse_list.next;
+	file->f_op = NULL;
 
-	switch (minor) {
-#ifdef CONFIG_BUSMOUSE
-		case BUSMOUSE_MINOR:
-	                file->f_op = &bus_mouse_fops;
-	                break;
-#endif
-#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
-		case PSMOUSE_MINOR:
-	                file->f_op = &psaux_fops;
-	                break;
-#endif
-#ifdef CONFIG_MS_BUSMOUSE
-		case MS_BUSMOUSE_MINOR:
-		        file->f_op = &ms_bus_mouse_fops;
-		        break;
-#endif
-#ifdef CONFIG_ATIXL_BUSMOUSE
-		case ATIXL_BUSMOUSE_MINOR:
-			file->f_op = &atixl_busmouse_fops;
+	while (c != &mouse_list) {
+		if (c->minor == minor) {
+			file->f_op = c->fops;
 			break;
-#endif
-		default:
-			return -ENODEV;
+		}
+		c = c->next;
 	}
+
+	if (file->f_op == NULL)
+		return -ENODEV;
         return file->f_op->open(inode,file);
 }
 
@@ -78,8 +77,37 @@
         NULL		/* release */
 };
 
+int mouse_register(struct mouse * mouse)
+{
+	if (mouse->next || mouse->prev)
+		return -EBUSY;
+	mouse->next = &mouse_list;
+	mouse->prev = mouse_list.prev;
+	mouse->prev->next = mouse;
+	mouse->next->prev = mouse;
+	return 0;
+}
+
+int mouse_deregister(struct mouse * mouse)
+{
+	if (!mouse->next || !mouse->prev)
+		return -EINVAL;
+	mouse->prev->next = mouse->next;
+	mouse->next->prev = mouse->prev;
+	mouse->next = NULL;
+	mouse->prev = NULL;
+	return 0;
+}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void)
+#else
 unsigned long mouse_init(unsigned long kmem_start)
+#endif
 {
+#ifndef MODULE
 #ifdef CONFIG_BUSMOUSE
 	kmem_start = bus_mouse_init(kmem_start);
 #endif
@@ -92,8 +120,34 @@
 #ifdef CONFIG_ATIXL_BUSMOUSE
  	kmem_start = atixl_busmouse_init(kmem_start);
 #endif
-	if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops))
-		printk("unable to get major %d for mouse devices\n",
-		       MOUSE_MAJOR);
+#endif /* !MODULE */
+	if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) {
+	  printk("unable to get major %d for mouse devices\n",
+		 MOUSE_MAJOR);
+#ifdef MODULE
+		return -EIO;
+#endif
+	}
+#ifdef MODULE
+	return 0;
+#else
 	return kmem_start;
+#endif
 }
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	mouse_data *c = mouse_list, *n;
+	if (MOD_IN_USE) {
+		printk("mouse: in use, remove delayed\n");
+		return;
+	}
+	unregister_chrdev(MOUSE_MAJOR, "mouse");
+	while (c) {
+		n = c->next;
+		kfree(c);
+		c = n;
+	}
+}
+#endif
diff -u --recursive --new-file v1.3.25/linux/drivers/char/mouse.h linux/drivers/char/mouse.h
--- v1.3.25/linux/drivers/char/mouse.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/mouse.h	Wed Sep 13 10:08:39 1995
@@ -0,0 +1,14 @@
+#ifndef __MOUSE_H
+#define __MOUSE_H
+
+struct mouse {
+	int minor;
+	const char *name;
+	struct file_operations *fops;
+	struct mouse * next, * prev;
+};
+
+extern int mouse_register(struct mouse * mouse);
+extern int mouse_deregister(struct mouse * mouse);
+
+#endif
diff -u --recursive --new-file v1.3.25/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v1.3.25/linux/drivers/char/msbusmouse.c	Wed Aug  2 13:21:00 1995
+++ linux/drivers/char/msbusmouse.c	Wed Sep 13 10:08:39 1995
@@ -25,9 +25,19 @@
  *	     Changed detection code to use inb_p() instead of doing empty
  *	     loops to delay i/o.
  *
- * version 0.3a
+ * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
+ *
+ * version 0.3b
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/busmouse.h>
@@ -67,14 +77,27 @@
 		mouse.dy += dy;
 		mouse.ready = 1;
 		wake_up_interruptible(&mouse.wait);
+		if (mouse.fasyncptr)
+			kill_fasync(mouse.fasyncptr, SIGIO);
 	}
 }
 
+static int fasync_mouse(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &mouse.fasyncptr);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
 static void release_mouse(struct inode * inode, struct file * file)
 {
 	MS_MSE_INT_OFF();
 	mouse.active = mouse.ready = 0; 
 	free_irq(MOUSE_IRQ);
+	fasync_mouse(inode, file, 0);
 }
 
 static int open_mouse(struct inode * inode, struct file * file)
@@ -142,9 +165,21 @@
 	NULL,		/* mouse_mmap */
 	open_mouse,
 	release_mouse,
+	NULL,
+	fasync_mouse,
+};
+
+static struct mouse ms_bus_mouse = {
+	MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops
 };
 
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void)
+#else
 unsigned long ms_bus_mouse_init(unsigned long kmem_start)
+#endif
 {
 	int mse_byte, i;
 
@@ -167,9 +202,28 @@
 		}
 	}
 	if (mouse.present == 0) {
+#ifdef MODULE
+	  return -EIO;
+#else
 		return kmem_start;
+#endif
 	}
 	MS_MSE_INT_OFF();
 	printk("Microsoft BusMouse detected and installed.\n");
+	mouse_register(&ms_bus_mouse);
+#ifdef MODULE
+	return 0;
+#else
 	return kmem_start;
+#endif
 }
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("msbusmouse: in use, remove delayed\n");
+	mouse_deregister(&ms_bus_mouse);
+}
+#endif
+
diff -u --recursive --new-file v1.3.25/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.3.25/linux/drivers/char/n_tty.c	Wed Aug  2 13:21:00 1995
+++ linux/drivers/char/n_tty.c	Mon Sep 11 14:40:15 1995
@@ -611,7 +611,7 @@
 int is_ignored(int sig)
 {
 	return ((current->blocked & (1<<(sig-1))) ||
-	        (current->sigaction[sig-1].sa_handler == SIG_IGN));
+	        (current->sig->action[sig-1].sa_handler == SIG_IGN));
 }
 
 static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
diff -u --recursive --new-file v1.3.25/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v1.3.25/linux/drivers/char/psaux.c	Thu Sep  7 17:17:17 1995
+++ linux/drivers/char/psaux.c	Wed Sep 13 10:08:39 1995
@@ -21,12 +21,24 @@
  * & Technologies 82C710 interface chip. 15Nov93 jem@pandora.pp.fi
  *
  * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi
+ *
+ * Rearranged SIGIO support to use code from tty_io.  9Sept95 ctm@ardi.com
+ *
+ * Modularised 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
  */
 
 /* Uncomment the following line if your mouse needs initialization. */
 
 /* #define INITIALIZE_DEVICE */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+ 
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/fcntl.h>
@@ -40,6 +52,10 @@
 
 #include <linux/config.h>
 
+#include "mouse.h"
+
+#define PSMOUSE_MINOR      1            /* minor device # for this mouse */
+
 /* aux controller ports */
 #define AUX_INPUT_PORT	0x60		/* Aux device output buffer */
 #define AUX_OUTPUT_PORT	0x60		/* Aux device input buffer */
@@ -273,40 +289,11 @@
 
 static int fasync_aux(struct inode *inode, struct file *filp, int on)
 {
-	struct fasync_struct *fa, *prev;
-	unsigned long flags;
+	int retval;
 
-	for (fa = queue->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) {
-		if (fa->fa_file == filp)
-			break;
-	}
-
-	if (on) {
-		if (fa)
-		    return 0;
-		fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
-		if (!fa)
-			return -ENOMEM;
-		save_flags(flags);
-		cli();
-		fa->magic = FASYNC_MAGIC;
-		fa->fa_file = filp;
-		fa->fa_next = queue->fasync;
-		queue->fasync = fa;
-		restore_flags(flags);
-	}
-	else {
-		if (!fa)
-			return 0;
-		save_flags(flags);
-		cli();
-		if (prev)
-			prev->fa_next = fa->fa_next;
-		else
-			queue->fasync = fa->fa_next;
-		restore_flags(flags);
-		kfree_s(fa, sizeof(struct fasync_struct));
-	}
+	retval = fasync_helper(inode, filp, on, &queue->fasync);
+	if (retval < 0)
+		return retval;
 	return 0;
 }
 
@@ -483,7 +470,7 @@
 	open_aux,
 	release_aux,
 	NULL,
-	fasync_aux
+	fasync_aux,
 };
 
 
@@ -491,6 +478,9 @@
  * Initialize driver. First check for a 82C710 chip; if found
  * forget about the Aux port and use the *_qp functions.
  */
+static struct mouse psaux_mouse = {
+	PSMOUSE_MINOR, "ps2aux", &psaux_fops
+};
 
 unsigned long psaux_init(unsigned long kmem_start)
 {
@@ -510,8 +500,13 @@
 		printk("PS/2 auxiliary pointing device detected -- driver installed.\n");
 	 	aux_present = 1;
 		kbd_read_mask = AUX_OBUF_FULL;
+		mouse_register(&psaux_mouse);
 	} else {
+#ifdef MODULE
+		return -EIO;
+#else
 		return kmem_start;              /* No mouse at all */
+#endif
 	}
 	queue = (struct aux_queue *) kmem_start;
 	kmem_start += sizeof (struct aux_queue);
@@ -534,8 +529,21 @@
 		poll_aux_status_nosleep();             /* Disable interrupts */
 		outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /*  on the controller */
 	}
+#ifdef MODULE
+	return 0;
+#else
 	return kmem_start;
+#endif
 }
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("psaux: in use, remove delayed\n");
+	mouse_deregister(&psaux_mouse);
+}
+#endif
 
 static int poll_aux_status(void)
 {
diff -u --recursive --new-file v1.3.25/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.25/linux/drivers/char/tty_io.c	Tue Aug  8 12:31:34 1995
+++ linux/drivers/char/tty_io.c	Sun Sep 10 11:04:59 1995
@@ -35,6 +35,9 @@
  *
  * Rewrote canonical mode and added more termios flags.
  * 	-- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ *
+ * Reorganized FASYNC support so mouse code can share it.
+ *	-- ctm@ardi.com, 9Sep95
  */
 
 #include <linux/types.h>
@@ -1217,16 +1220,17 @@
 	return 0;
 }
 
-static int tty_fasync(struct inode * inode, struct file * filp, int on)
+/*
+ * fasync_helper() is used by some character device drivers (mainly mice)
+ * to set up the fasync queue. It returns negative on error, 0 if it did
+ * no changes and positive if it added/deleted the entry.
+ */
+int fasync_helper(struct inode * inode, struct file * filp, int on, struct fasync_struct **fapp)
 {
-	struct tty_struct * tty;
-	struct fasync_struct *fa, *prev;
-
-	tty = (struct tty_struct *)filp->private_data;
-	if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
-		return 0;
+	struct fasync_struct *fa, **fp;
+	unsigned long flags;
 
-	for (fa = tty->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) {
+	for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
 		if (fa->fa_file == filp)
 			break;
 	}
@@ -1239,8 +1243,37 @@
 			return -ENOMEM;
 		fa->magic = FASYNC_MAGIC;
 		fa->fa_file = filp;
-		fa->fa_next = tty->fasync;
-		tty->fasync = fa;
+		save_flags(flags);
+		cli();
+		fa->fa_next = *fapp;
+		*fapp = fa;
+		restore_flags(flags);
+		return 1;
+	}
+	if (!fa)
+		return 0;
+	save_flags(flags);
+	cli();
+	*fp = fa->fa_next;
+	restore_flags(flags);
+	kfree(fa);
+	return 1;
+}
+
+static int tty_fasync(struct inode * inode, struct file * filp, int on)
+{
+	struct tty_struct * tty;
+	int retval;
+
+	tty = (struct tty_struct *)filp->private_data;
+	if (tty_paranoia_check(tty, inode->i_rdev, "tty_fasync"))
+		return 0;
+	
+	retval = fasync_helper(inode, filp, on, &tty->fasync);
+	if (retval <= 0)
+		return retval;
+
+	if (on) {
 		if (!tty->read_wait)
 			tty->minimum_to_wake = 1;
 		if (filp->f_owner == 0) {
@@ -1250,17 +1283,10 @@
 				filp->f_owner = current->pid;
 		}
 	} else {
-		if (!fa)
-			return 0;
-		if (prev)
-			prev->fa_next = fa->fa_next;
-		else
-			tty->fasync = fa->fa_next;
-		kfree_s(fa, sizeof(struct fasync_struct));
 		if (!tty->fasync && !tty->read_wait)
 			tty->minimum_to_wake = N_TTY_BUF_SIZE;
 	}
-	return 0;	
+	return 0;
 }
 
 #if 0
diff -u --recursive --new-file v1.3.25/linux/drivers/net/dummy.c linux/drivers/net/dummy.c
--- v1.3.25/linux/drivers/net/dummy.c	Sat Sep  9 15:26:52 1995
+++ linux/drivers/net/dummy.c	Mon Sep 11 14:26:35 1995
@@ -159,6 +159,8 @@
 		sprintf(dev_dummy.name,"dummy%d",ct);
 		ct++;
 	}
+	if(ct==100)
+		return -ENFILE;
 	
 	if (register_netdev(&dev_dummy) != 0)
 		return -EIO;
diff -u --recursive --new-file v1.3.25/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.25/linux/drivers/pci/pci.c	Sat Sep  9 15:26:53 1995
+++ linux/drivers/pci/pci.c	Mon Sep 11 20:15:45 1995
@@ -7,6 +7,7 @@
  *	David Mosberger-Tang
  */
 #include <linux/config.h>
+#include <linux/ptrace.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/bios32.h>
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v1.3.25/linux/drivers/scsi/README.st	Sun Sep  3 12:26:57 1995
+++ linux/drivers/scsi/README.st	Mon Sep 11 10:23:41 1995
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Sun Aug 27 12:49:11 1995 by root@kai.makisara.fi
+Last modified: Sun Sep 10 13:19:02 1995 by root@kai.makisara.fi
 
 BASICS
 
@@ -41,9 +41,15 @@
 
 The buffer size is defined (in 1024 byte units) by ST_BUFFER_BLOCKS or
 at boot time. The maximum number of buffers allocated is defined by
-ST_MAX_BUFFERS. One buffer is allocated for each detected drive up to
-the maximum. The threshold for triggering asynchronous write is
-defined by ST_WRITE_THRESHOLD.
+ST_MAX_BUFFERS. One buffer is allocated for each drive detected when
+the driver is initialized up to the maximum. The minimum number of
+allocated buffers is ST_EXTRA_DEVS (in hosts.h). This ensures some
+functionality also for the drives found after tape driver
+initialization (a SCSI adapter driver is loaded as a module). The
+default for ST_EXTRA_DEVS is two. This is enough to enable tape copies.
+
+The threshold for triggering asynchronous write is defined by
+ST_WRITE_THRESHOLD.
 
 
 BOOT TIME CONFIGURATION
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v1.3.25/linux/drivers/scsi/aha1542.c	Sun Sep  3 12:26:59 1995
+++ linux/drivers/scsi/aha1542.c	Sun Sep 10 09:37:22 1995
@@ -1011,6 +1011,8 @@
 			    }
 		    }
 		    aha_host[irq_level - 9] = shpnt;
+ 		    shpnt->this_id = scsi_id;
+ 		    shpnt->unique_id = base_io;
 		    shpnt->io_port = base_io;
 		    shpnt->n_io_port = 4;  /* Number of bytes of I/O space used */
 		    shpnt->dma_channel = dma_chan;
@@ -1172,33 +1174,28 @@
     unchar ahacmd = CMD_START_SCSI;
     int i;
 
-    DEB(printk("aha1542_reset called\n"));
-#if 0
-    /* This does a scsi reset for all devices on the bus */
-    outb(SCRST, CONTROL(SCpnt->host->io_port));
-#else
-    /* This does a selective reset of just the one device */
-    /* First locate the ccb for this command */
-    for(i=0; i< AHA1542_MAILBOXES; i++)
-      if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt)
-	{
-	  HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;  /* BUS DEVICE RESET */
-	  /* Now tell the 1542 to flush all pending commands for this target */
-	  aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
-
-	  /* Here is the tricky part.  What to do next.  Do we get an interrupt
-	     for the commands that we aborted with the specified target, or
-	     do we generate this on our own?  Try it without first and see
-	     what happens */
-	  printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
-
-	  /* If the first does not work, then try the second.  I think the
-	     first option is more likely to be correct. Free the command
-	     block for all commands running on this target... */
-#if 1
-	  for(i=0; i< AHA1542_MAILBOXES; i++)
-	    if(HOSTDATA(SCpnt->host)->SCint[i] &&
-	       HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
+    /*
+     * See if a bus reset was suggested.
+     */
+    if( SCpnt->host->suggest_bus_reset )
+      {
+	/* 
+	 * This does a scsi reset for all devices on the bus.
+	 * In principle, we could also reset the 1542 - should
+	 * we do this?  Try this first, and we can add that later
+	 * if it turns out to be useful.
+	 */
+	outb(SCRST, CONTROL(SCpnt->host->io_port));
+	/*
+	 * Now try and pick up the pieces.  Restart all commands
+	 * that are currently active on the bus, and reset all of
+	 * the datastructures.  We have some time to kill while
+	 * things settle down, so print a nice message.
+	 */
+	printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+	for(i=0; i< AHA1542_MAILBOXES; i++)
+	  if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
 	    {
 	      Scsi_Cmnd * SCtmp;
 	      SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
@@ -1210,13 +1207,50 @@
 	      HOSTDATA(SCpnt->host)->SCint[i] = NULL;
 	      HOSTDATA(SCpnt->host)->mb[i].status = 0;
 	    }
-	  return SCSI_RESET_SUCCESS;
-#else
-	  return SCSI_RESET_PENDING;
-#endif
-	}
-
-#endif
+	/*
+	 * Now tell the mid-level code what we did here.  Since
+	 * we have restarted all of the outstanding commands,
+	 * then report SUCCESS.
+	 */
+	return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+      }
+    else
+      {
+	/* This does a selective reset of just the one device */
+	/* First locate the ccb for this command */
+	for(i=0; i< AHA1542_MAILBOXES; i++)
+	  if(HOSTDATA(SCpnt->host)->SCint[i] == SCpnt)
+	    {
+	      HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;  /* BUS DEVICE RESET */
+	      /* Now tell the 1542 to flush all pending commands for this target */
+	      aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+	      
+	      /* Here is the tricky part.  What to do next.  Do we get an interrupt
+		 for the commands that we aborted with the specified target, or
+		 do we generate this on our own?  Try it without first and see
+		 what happens */
+	      printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+	      
+	      /* If the first does not work, then try the second.  I think the
+		 first option is more likely to be correct. Free the command
+		 block for all commands running on this target... */
+	      for(i=0; i< AHA1542_MAILBOXES; i++)
+		if(HOSTDATA(SCpnt->host)->SCint[i] &&
+		   HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
+		  {
+		    Scsi_Cmnd * SCtmp;
+		    SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+		    SCtmp->result = DID_RESET << 16;
+		    if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512);
+		    printk("Sending DID_RESET for target %d\n", SCpnt->target);
+		    SCtmp->scsi_done(SCpnt);
+		    
+		    HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+		    HOSTDATA(SCpnt->host)->mb[i].status = 0;
+		  }
+	      return SCSI_RESET_SUCCESS;
+	    }
+      }
     /* No active command at this time, so this means that each time we got
        some kind of response the last time through.  Tell the mid-level code
        to request sense information in order to decide what to do next. */
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.3.25/linux/drivers/scsi/hosts.c	Fri Jul  7 08:54:50 1995
+++ linux/drivers/scsi/hosts.c	Sun Sep 10 09:37:22 1995
@@ -287,6 +287,7 @@
     retval->max_id = 8;      
     retval->max_lun = 8;
 
+    retval->unique_id = 0;
     retval->io_port = 0;
     retval->forbidden_addr = 0;
     retval->forbidden_size = 0;
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v1.3.25/linux/drivers/scsi/hosts.h	Tue Aug  8 12:31:38 1995
+++ linux/drivers/scsi/hosts.h	Mon Sep 11 10:23:41 1995
@@ -1,11 +1,14 @@
 /*
  *  hosts.h Copyright (C) 1992 Drew Eckhardt 
- *  mid to low-level SCSI driver interface header by	
- *	Drew Eckhardt 
+ *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *
+ *  mid to low-level SCSI driver interface header
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
  *
  *  <drew@colorado.edu>
  *
- *	 Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *	 Modified by Eric Youngdale eric@aib.com to
  *	 add scatter-gather, multiple outstanding request, and other
  *	 enhancements.
  * 
@@ -274,6 +277,15 @@
     unsigned char dma_channel;
     
     /*
+     * This is a unique identifier that must be assigned so that we
+     * have some way of identifying each detected host adapter properly
+     * and uniquely.  For hosts that do not support more than one card
+     * in the system at one time, this does not need to be set.  It is
+     * initialized to 0 in scsi_register.
+     */
+    unsigned int unique_id;
+
+    /*
      * Set these if there are conflicts between memory
      * in the < 1mb region and regions at 16mb multiples.
      * The address must be on a page boundary.
@@ -297,6 +309,12 @@
      */
     unsigned loaded_as_module:1;
     
+    /*
+     * True when we call the low-level reset function, and
+     * the midlevel code suggests a full bus reset.
+     */
+    unsigned suggest_bus_reset:1;
+ 
     int hostdata[0];  /* Used for storage of host specific stuff */
 };
 
@@ -344,7 +362,7 @@
     unsigned char dev_max;	  /* Current size of arrays */
     unsigned blk:1;		  /* 0 if character device */
     int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
-    void (*init)(void);		  /* Sizes arrays based upon number of devices
+    int (*init)(void);		  /* Sizes arrays based upon number of devices
 		   *  detected */
     void (*finish)(void);	  /* Perform initialization after attachment */
     int (*attach)(Scsi_Device *); /* Attach devices to arrays */
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.25/linux/drivers/scsi/scsi.c	Mon Aug 28 14:52:21 1995
+++ linux/drivers/scsi/scsi.c	Mon Sep 11 10:23:41 1995
@@ -13,7 +13,7 @@
  *      Tommy Thorn <tthorn>
  *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
  *
- *  Modified by Eric Youngdale ericy@cais.com to
+ *  Modified by Eric Youngdale eric@aib.com to
  *  add scatter-gather, multiple outstanding request, and other
  *  enhancements.
  *
@@ -430,6 +430,7 @@
 		     * and then fix this field later if it turns out it doesn't
 		     */
 		    SDpnt->borken = 1;
+                    SDpnt->was_reset = 0;
 		    
 		    scsi_cmd[0] = TEST_UNIT_READY;
 		    scsi_cmd[1] = lun << 5;
@@ -801,7 +802,7 @@
     case IN_ABORT:
 	printk("SCSI host %d abort() timed out - resetting\n",
 	       SCpnt->host->host_no);
-	if (!scsi_reset (SCpnt))
+	if (!scsi_reset (SCpnt, FALSE))
 	    return;
     case IN_RESET:
     case (IN_ABORT | IN_RESET):
@@ -811,6 +812,7 @@
 	 */
 	printk("Unable to reset scsi host %d - ", SCpnt->host->host_no);
 	printk("probably a SCSI bus hang.\n");
+        scsi_reset (SCpnt, TRUE);
 	return;
 	
     default:
@@ -1319,7 +1321,7 @@
 #endif
 
     SCpnt->flags |= (WAS_RESET | IS_RESETTING);
-    scsi_reset(SCpnt);
+    scsi_reset(SCpnt, FALSE);
 
 #ifdef DEBUG
     printk("performing request sense\n");
@@ -1865,7 +1867,7 @@
     }
 }
 
-int scsi_reset (Scsi_Cmnd * SCpnt)
+int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
 {
     int temp, oldto;
     unsigned long flags;
@@ -1876,6 +1878,43 @@
     printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",
 	   host->host_no);
 #endif
+ 
+    /*
+     * First of all, we need to make a recommendation to the low-level
+     * driver as to whether a BUS_DEVICE_RESET should be performed,
+     * or whether we should do a full BUS_RESET.  There is no simple
+     * algorithm here - we basically use a series of heuristics
+     * to determine what we should do.
+     */
+    SCpnt->host->suggest_bus_reset = FALSE;
+    
+    /*
+     * First see if all of the active devices on the bus have
+     * been jammed up so that we are attempting resets.  If so,
+     * then suggest a bus reset.  Forcing a bus reset could
+     * result in some race conditions, but no more than
+     * you would usually get with timeouts.  We will cross
+     * that bridge when we come to it.
+     */
+    SCpnt1 = host->host_queue;
+    while(SCpnt1) {
+        if( SCpnt->request.dev > 0
+           && (SCpnt->flags & WAS_RESET) == 0 )
+            break;
+        SCpnt1 = SCpnt1->next;
+ 	}
+    if( SCpnt1 == NULL )
+        SCpnt->host->suggest_bus_reset = TRUE;
+    
+    
+    /*
+     * If the code that called us is suggesting a hard reset, then
+     * definitely request it.  This usually occurs because a
+     * BUS_DEVICE_RESET times out.
+     */
+    if( bus_reset_flag )
+        SCpnt->host->suggest_bus_reset = TRUE;
+    
     while (1) {
 	save_flags(flags);
 	cli();
@@ -1923,7 +1962,26 @@
 #ifdef DEBUG
 	    printk("scsi reset function returned %d\n", temp);
 #endif
-	    switch(temp) {
+ 
+            if( temp & SCSI_RESET_BUS_RESET )
+            {
+                /*
+                 * The low level driver did a bus reset, so we should
+                 * go through and mark all of the devices on that bus
+                 * as having been reset.
+                 */
+                SCpnt1 = host->host_queue;
+                while(SCpnt1) {
+                    SCpnt1->device->was_reset = 1;
+                    SCpnt1 = SCpnt1->next;
+                }
+            }
+            
+            /*
+             * Now figure out what we need to do, based upon
+             * what the low level driver said that it did.
+             */
+            switch(temp & SCSI_RESET_ACTION) {
 	    case SCSI_RESET_SUCCESS:
 		save_flags(flags);
 		cli();
@@ -1934,9 +1992,27 @@
 	    case SCSI_RESET_PENDING:
 		return 0;
 	    case SCSI_RESET_PUNT:
+                SCpnt->internal_timeout &= ~IN_RESET;
+                scsi_request_sense (SCpnt);
+                return 0;
 	    case SCSI_RESET_WAKEUP:
 		SCpnt->internal_timeout &= ~IN_RESET;
 		scsi_request_sense (SCpnt);
+                /*
+                 * Since a bus reset was performed, we
+                 * need to wake up each and every command
+                 * that was active on the bus.
+                 */
+                if( temp & SCSI_RESET_BUS_RESET )
+                {
+                    SCpnt1 = host->host_queue;
+                    while(SCpnt1) {
+                        if( SCpnt->request.dev > 0
+                           && SCpnt1 != SCpnt)
+                            scsi_request_sense (SCpnt);
+                        SCpnt1 = SCpnt1->next;
+                    }
+                }
 		return 0;
 	    case SCSI_RESET_SNOOZE:
 		/* In this case, we set the timeout field to 0
@@ -2856,7 +2932,8 @@
      * If any of the devices would match this driver, then perform the
      * init function.
      */
-    if(tpnt->init && tpnt->dev_noticed) (*tpnt->init)();
+    if(tpnt->init && tpnt->dev_noticed)
+        if ((*tpnt->init)()) return 1;
     
     /*
      * Now actually connect the devices to the new driver.
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.25/linux/drivers/scsi/scsi.h	Tue Aug  8 12:31:39 1995
+++ linux/drivers/scsi/scsi.h	Mon Sep 11 10:39:52 1995
@@ -1,11 +1,13 @@
 /*
  *  scsi.h Copyright (C) 1992 Drew Eckhardt 
+ *         Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *  generic SCSI package header file by
- *      Drew Eckhardt 
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
  *
  *  <drew@colorado.edu>
  *
- *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *       Modified by Eric Youngdale eric@aib.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
@@ -14,135 +16,33 @@
 #define _SCSI_H
 
 /*
-    $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
-
-    For documentation on the OPCODES, MESSAGES, and SENSE values,
-    please consult the SCSI standard.
-
-*/
+ * Some of the public constants are being movedd to this file.
+ * We include it here so that what came from where is transparent.
+ */
+#include <linux/scsi.h>
 
 /*
- *      SCSI opcodes
- */
-
-#define TEST_UNIT_READY       0x00
-#define REZERO_UNIT           0x01
-#define REQUEST_SENSE         0x03
-#define FORMAT_UNIT           0x04
-#define READ_BLOCK_LIMITS     0x05
-#define REASSIGN_BLOCKS       0x07
-#define READ_6                0x08
-#define WRITE_6               0x0a
-#define SEEK_6                0x0b
-#define READ_REVERSE          0x0f
-#define WRITE_FILEMARKS       0x10
-#define SPACE                 0x11
-#define INQUIRY               0x12
-#define RECOVER_BUFFERED_DATA 0x14
-#define MODE_SELECT           0x15
-#define RESERVE               0x16
-#define RELEASE               0x17
-#define COPY                  0x18
-#define ERASE                 0x19
-#define MODE_SENSE            0x1a
-#define START_STOP            0x1b
-#define RECEIVE_DIAGNOSTIC    0x1c
-#define SEND_DIAGNOSTIC       0x1d
-#define ALLOW_MEDIUM_REMOVAL  0x1e
-
-#define SET_WINDOW            0x24
-#define READ_CAPACITY         0x25
-#define READ_10               0x28
-#define WRITE_10              0x2a
-#define SEEK_10               0x2b
-#define WRITE_VERIFY          0x2e
-#define VERIFY                0x2f
-#define SEARCH_HIGH           0x30
-#define SEARCH_EQUAL          0x31
-#define SEARCH_LOW            0x32
-#define SET_LIMITS            0x33
-#define PRE_FETCH             0x34
-#define READ_POSITION         0x34
-#define SYNCHRONIZE_CACHE     0x35
-#define LOCK_UNLOCK_CACHE     0x36
-#define READ_DEFECT_DATA      0x37
-#define MEDIUM_SCAN           0x38
-#define COMPARE               0x39
-#define COPY_VERIFY           0x3a
-#define WRITE_BUFFER          0x3b
-#define READ_BUFFER           0x3c
-#define UPDATE_BLOCK          0x3d
-#define READ_LONG             0x3e
-#define WRITE_LONG            0x3f
-#define CHANGE_DEFINITION     0x40
-#define WRITE_SAME            0x41
-#define LOG_SELECT            0x4c
-#define LOG_SENSE             0x4d
-#define MODE_SELECT_10        0x55
-#define MODE_SENSE_10         0x5a
-#define READ_12               0xa8
-#define WRITE_12              0xaa
-#define WRITE_VERIFY_12       0xae
-#define SEARCH_HIGH_12        0xb0
-#define SEARCH_EQUAL_12       0xb1
-#define SEARCH_LOW_12         0xb2
-#define SEND_VOLUME_TAG       0xb6
-#define WRITE_LONG_2          0xea
+ * Some defs, in case these are not defined elsewhere.
+ */
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
 
 extern void scsi_make_blocked_list(void);
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 #define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
 
-/*
- *  MESSAGE CODES
- */
-
-#define COMMAND_COMPLETE    0x00
-#define EXTENDED_MESSAGE    0x01
-#define     EXTENDED_MODIFY_DATA_POINTER    0x00
-#define     EXTENDED_SDTR                   0x01
-#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
-#define     EXTENDED_WDTR                   0x03
-#define SAVE_POINTERS       0x02
-#define RESTORE_POINTERS    0x03
-#define DISCONNECT          0x04
-#define INITIATOR_ERROR     0x05
-#define ABORT               0x06
-#define MESSAGE_REJECT      0x07
-#define NOP                 0x08
-#define MSG_PARITY_ERROR    0x09
-#define LINKED_CMD_COMPLETE 0x0a
-#define LINKED_FLG_CMD_COMPLETE 0x0b
-#define BUS_DEVICE_RESET    0x0c
-
-#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
-#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
-
-#define SIMPLE_QUEUE_TAG    0x20
-#define HEAD_OF_QUEUE_TAG   0x21
-#define ORDERED_QUEUE_TAG   0x22
-
 #define IDENTIFY_BASE       0x80
 #define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
 		     ((can_disconnect) ?  0x40 : 0) |\
 		     ((lun) & 0x07)) 
 
 		 
-/*
- *  Status codes
- */
-
-#define GOOD                 0x00
-#define CHECK_CONDITION      0x01
-#define CONDITION_GOOD       0x02
-#define BUSY                 0x04
-#define INTERMEDIATE_GOOD    0x08
-#define INTERMEDIATE_C_GOOD  0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define QUEUE_FULL           0x1a
-
-#define STATUS_MASK          0x1e
     
 /*
  *  the return of the status word will be in the following format :
@@ -201,40 +101,6 @@
 #define DRIVER_MASK         0x0f
 #define SUGGEST_MASK        0xf0
 
-/*
- *  SENSE KEYS
- */
-
-#define NO_SENSE            0x00
-#define RECOVERED_ERROR     0x01
-#define NOT_READY           0x02
-#define MEDIUM_ERROR        0x03
-#define HARDWARE_ERROR      0x04
-#define ILLEGAL_REQUEST     0x05
-#define UNIT_ATTENTION      0x06
-#define DATA_PROTECT        0x07
-#define BLANK_CHECK         0x08
-#define COPY_ABORTED        0x0a
-#define ABORTED_COMMAND     0x0b
-#define VOLUME_OVERFLOW     0x0d
-#define MISCOMPARE          0x0e
-
-
-/*
- *  DEVICE TYPES
- */
-
-#define TYPE_DISK           0x00
-#define TYPE_TAPE           0x01
-#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
-#define TYPE_WORM           0x04    /* Treated as ROM by our system */
-#define TYPE_ROM            0x05
-#define TYPE_SCANNER        0x06
-#define TYPE_MOD            0x07    /* Magneto-optical disk - 
-				     * - treated as TYPE_DISK */
-#define TYPE_NO_LUN         0x7f
-
-
 #define MAX_COMMAND_SIZE    12
 
 /*
@@ -300,6 +166,10 @@
     char type;
     char scsi_level;
     char vendor[8], model[16], rev[4];
+    unsigned char current_tag;      /* current tag */
+    unsigned char sync_min_period;  /* Not less than this period */
+    unsigned char sync_max_offset;  /* Not greater than this offset */
+
     unsigned writeable:1;
     unsigned removable:1; 
     unsigned random:1;
@@ -316,9 +186,8 @@
     unsigned sync:1;                /* Negotiate for sync transfers */
     unsigned single_lun:1;          /* Indicates we should only allow I/O to
                                        one of the luns for the device at a time. */
-    unsigned char current_tag;      /* current tag */
-    unsigned char sync_min_period;  /* Not less than this period */
-    unsigned char sync_max_offset;  /* Not greater than this offset */
+    unsigned was_reset:1;	/* There was a bus reset on the bus for this
+                                   device */
 } Scsi_Device;
 
 /*
@@ -366,6 +235,9 @@
  * These are the return codes for the abort and reset functions.  The mid-level
  * code uses these to decide what to do next.  Each of the low level abort
  * and reset functions must correctly indicate what it has done.
+ * The descriptions are written from the point of view of the mid-level code,
+ * so that the return code is telling the mid-level drivers exactly what
+ * the low level driver has already done, and what remains to be done.
  */
 
 /* We did not do anything.  
@@ -410,12 +282,18 @@
  * the commands that should be restarted, and we should be able to continue
  * on normally from here.  We do not expect any interrupts that will return
  * DID_RESET to any of the other commands in the host_queue, and the mid-level
- * code does not need to do anything special to keep the commands alive. */
+ * code does not need to do anything special to keep the commands alive. 
+ * If a hard reset was performed then all outstanding commands on the
+ * bus have been restarted. */
 #define SCSI_RESET_SUCCESS 2
 
 /* We called for a reset of this bus, and we should get an interrupt 
  * when this succeeds.  Each command should get its own status
- * passed up to scsi_done, but this has not happened yet. */
+ * passed up to scsi_done, but this has not happened yet. 
+ * If a hard reset was performed, then we expect an interrupt
+ * for *each* of the outstanding commands that will have the
+ * effect of restarting the commands.
+ */
 #define SCSI_RESET_PENDING 3
 
 /* We did a reset, but do not expect an interrupt to signal DID_RESET.
@@ -426,6 +304,17 @@
 /* Something went wrong, and we do not know how to fix it. */
 #define SCSI_RESET_ERROR 5
 
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a hard reset.
+ */
+#define SCSI_RESET_BUS_RESET 0x100
+/*
+ * Used to mask off bits and to obtain the basic action that was
+ * performed.  
+ */
+#define SCSI_RESET_ACTION   0xff
+
 void *   scsi_malloc(unsigned int);
 int      scsi_free(void *, unsigned int);
 extern unsigned int dma_free_sectors;  /* How much room do we have left */
@@ -547,7 +436,7 @@
 extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
 
 extern Scsi_Cmnd * request_queueable(struct request *, Scsi_Device *);
-extern int scsi_reset (Scsi_Cmnd *);
+extern int scsi_reset (Scsi_Cmnd *, int);
 
 extern int max_scsi_hosts;
 
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v1.3.25/linux/drivers/scsi/scsi_debug.c	Tue Jul 11 10:02:50 1995
+++ linux/drivers/scsi/scsi_debug.c	Sun Sep 10 09:37:22 1995
@@ -118,15 +118,16 @@
 extern void scsi_debug_interrupt();
 
 volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
-static volatile unsigned int timeout[SCSI_DEBUG_MAILBOXES] ={0,};
-
-static char sense_buffer[128] = {0,};
+static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
+static volatile unsigned int timeout[8] ={0,};
 
 /*
  * Semaphore used to simulate bus lockups.
  */
 static int scsi_debug_lockup = 0;
 
+static char sense_buffer[128] = {0,};
+
 static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
     int i;
 #if 0
@@ -199,6 +200,15 @@
 	return 0;
     };
     
+    if( SCrst[target] != 0 && !scsi_debug_lockup )
+    {
+        SCrst[target] = 0;
+        memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+        SCpnt->sense_buffer[0] = 0x70;
+        SCpnt->sense_buffer[2] = UNIT_ATTENTION;
+	SCpnt->result = (CHECK_CONDITION << 1);
+	done(SCpnt);         
+    }
     switch(*cmd){
     case REQUEST_SENSE:
 	printk("Request sense...\n");
@@ -559,6 +569,7 @@
     unsigned long flags;
     
     DEB(printk("scsi_debug_abort\n"));
+#if 0
     SCpnt->result = SCpnt->abort_reason << 16;
     for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {
 	if(SCpnt == SCint[j]) {
@@ -572,7 +583,8 @@
 	    restore_flags(flags);
 	};
     };
-    return 0;
+#endif
+    return SCSI_ABORT_SNOOZE;
 }
 
 int scsi_debug_biosparam(Disk * disk, int dev, int* info){
@@ -590,11 +602,12 @@
     unsigned long flags;
     
     void (*my_done)(Scsi_Cmnd *);
+    printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset);
     scsi_debug_lockup = 0;
     DEB(printk("scsi_debug_reset called\n"));
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
         if (SCint[i] == NULL) continue;
-        SCint[i]->result = DID_ABORT << 16;
+        SCint[i]->result = DID_RESET << 16;
         my_done = do_done[i];
         my_done(SCint[i]);
         save_flags(flags);
@@ -604,7 +617,7 @@
         timeout[i] = 0;
         restore_flags(flags);
     }
-    return 0;
+    return SCSI_RESET_SUCCESS;
 }
 
 const char *scsi_debug_info(void)
@@ -620,6 +633,7 @@
 		     int length, int inode, int inout)
 {
     int len, pos, begin;
+    int orig_length;
 
     if(inout == 1)
     {
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v1.3.25/linux/drivers/scsi/scsi_ioctl.c	Tue Jul 11 10:02:50 1995
+++ linux/drivers/scsi/scsi_ioctl.c	Sun Sep 10 09:37:22 1995
@@ -318,15 +318,15 @@
     
     switch (cmd) {
     case SCSI_IOCTL_GET_IDLUN:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+        result = verify_area(VERIFY_WRITE, (void *) arg, 2*sizeof(long));
         if (result) return result;
 
-	put_user(dev->id + (dev->lun << 8) + (dev->host->host_no << 16) +
-		    /* This has been added to support 
-		     * multichannel HBAs, it might cause 
-		     * problems with some software */ 
-		    (dev->channel << 24), 
+	put_user(dev->id 
+                 + (dev->lun << 8) 
+                 + (dev->channel << 16)
+                 + ((dev->host->hostt->low_ino & 0xff) << 24),
 		    (unsigned long *) arg);
+        put_user( dev->host->unique_id, (unsigned long *) arg+1);
 	return 0;
     case SCSI_IOCTL_TAGGED_ENABLE:
 	if(!suser())  return -EACCES;
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/scsi_ioctl.h linux/drivers/scsi/scsi_ioctl.h
--- v1.3.25/linux/drivers/scsi/scsi_ioctl.h	Tue Aug  2 11:29:21 1994
+++ linux/drivers/scsi/scsi_ioctl.h	Sun Sep 10 09:37:22 1995
@@ -1,7 +1,6 @@
 #ifndef _SCSI_IOCTL_H
 #define _SCSI_IOCTL_H 
 
-#define SCSI_IOCTL_PROBE_HOST 0
 #define SCSI_IOCTL_SEND_COMMAND 1
 #define SCSI_IOCTL_TEST_UNIT_READY 2
 #define SCSI_IOCTL_BENCHMARK_COMMAND 3
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.3.25/linux/drivers/scsi/sd.c	Tue Aug 15 20:39:04 1995
+++ linux/drivers/scsi/sd.c	Mon Sep 11 10:23:41 1995
@@ -81,7 +81,7 @@
 
 static void requeue_sd_request (Scsi_Cmnd * SCpnt);
 
-static void sd_init(void);
+static int sd_init(void);
 static void sd_finish(void);
 static int sd_attach(Scsi_Device *);
 static int sd_detect(Scsi_Device *);
@@ -338,6 +338,16 @@
 		    requeue_sd_request(SCpnt);
 		    return;
 		}
+                else
+                {
+                    /*
+                     * Must have been a power glitch, or a bus reset.
+                     * Could not have been a media change, so we just retry
+                     * the request and see what happens.
+                     */
+                    requeue_sd_request(SCpnt);
+                    return;
+                }
 	    }
 	}
 	
@@ -383,6 +393,7 @@
 static void do_sd_request (void)
 {
     Scsi_Cmnd * SCpnt = NULL;
+    Scsi_Device * SDev;
     struct request * req = NULL;
     unsigned long flags;
     int flag = 0;
@@ -396,6 +407,27 @@
 	};
 	
 	INIT_SCSI_REQUEST;
+        SDev = rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device;
+        
+        /*
+         * I am not sure where the best place to do this is.  We need
+         * to hook in a place where we are likely to come if in user
+         * space.
+         */
+        if( SDev->was_reset )
+        {
+	    /*
+	     * We need to relock the door, but we might
+	     * be in an interrupt handler.  Only do this
+	     * from user space, since we do not want to
+	     * sleep from an interrupt.
+	     */
+	    if( SDev->removable && !intr_count )
+	    {
+                scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
+	    }
+	    SDev->was_reset = 0;
+        }
 		
 	/* We have to be careful here. allocate_device will get a free pointer,
 	 * but there is no guarantee that it is queueable.  In normal usage, 
@@ -1122,24 +1154,24 @@
  * their size, and reads partition table entries for them.
  */
 
+static int sd_registered = 0;
 
-static void sd_init()
+static int sd_init()
 {
     int i;
-    static int sd_registered = 0;
     
-    if (sd_template.dev_noticed == 0) return;
+    if (sd_template.dev_noticed == 0) return 0;
     
     if(!sd_registered) {
 	  if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
 	      printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
-	      return;
+	      return 1;
 	  }
 	  sd_registered++;
       }
     
     /* We do not support attaching loadable devices yet. */
-    if(rscsi_disks) return;
+    if(rscsi_disks) return 0;
     
     sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
     
@@ -1172,7 +1204,7 @@
     sd_gendisk.part = sd;
     sd_gendisk.sizes = sd_sizes;
     sd_gendisk.real_devices = (void *) rscsi_disks;
-    
+    return 0;
 }
 
 static void sd_finish()
@@ -1287,6 +1319,11 @@
 	invalidate_buffers(major | start | i);
 	gdev->part[start+i].start_sect = 0;
 	gdev->part[start+i].nr_sects = 0;
+        /*
+         * Reset the blocksize for everything so that we can read
+         * the partition table.
+         */
+        blksize_size[MAJOR_NR][i] = 1024;
     };
     
 #ifdef MAYBE_REINIT
@@ -1364,7 +1401,8 @@
 	return;
     }
     scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
-    unregister_blkdev(SCSI_GENERIC_MAJOR, "sd");
+    unregister_blkdev(SCSI_DISK_MAJOR, "sd");
+    sd_registered--;
     if( rscsi_disks != NULL )
     {
 	scsi_init_free((char *) rscsi_disks,
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h
--- v1.3.25/linux/drivers/scsi/sd.h	Fri Jun 30 16:22:29 1995
+++ linux/drivers/scsi/sd.h	Mon Sep 11 10:42:13 1995
@@ -5,7 +5,7 @@
  *
  *	<drew@colorado.edu>
  *
- *	 Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *	 Modified by Eric Youngdale eric@aib.com to
  *	 add scatter-gather, multiple outstanding request, and other
  *	 enhancements.
  */
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v1.3.25/linux/drivers/scsi/sg.c	Tue Aug  8 12:31:39 1995
+++ linux/drivers/scsi/sg.c	Mon Sep 11 10:23:41 1995
@@ -31,7 +31,7 @@
 #include "scsi_ioctl.h"
 #include "sg.h"
 
-static void sg_init(void);
+static int sg_init(void);
 static int sg_attach(Scsi_Device *);
 static int sg_detect(Scsi_Device *);
 static void sg_detach(Scsi_Device *);
@@ -459,12 +459,40 @@
     return count;
 }
 
+static int sg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
+{
+    int dev=MINOR(inode->i_rdev);
+    int i;
+    int r = 0;
+    struct scsi_generic *device=&scsi_generics[dev];
+
+    if (sel_type == SEL_IN) {
+        if(device->pending && device->complete)
+        {
+            r = 1;
+    	} else {
+	    select_wait(&scsi_generics[dev].read_wait, wait);
+    	}
+    }
+    if (sel_type == SEL_OUT) {
+        if(!device->pending){
+            r = 1;
+        }
+        else
+        {
+	    select_wait(&scsi_generics[dev].write_wait, wait);
+        }
+    }
+
+    return(r);
+}
+
 static struct file_operations sg_fops = {
     NULL,            /* lseek */
     sg_read,         /* read */
     sg_write,        /* write */
     NULL,            /* readdir */
-    NULL,            /* select */
+    sg_select,       /* select */
     sg_ioctl,        /* ioctl */
     NULL,            /* mmap */
     sg_open,         /* open */
@@ -479,24 +507,24 @@
 }
 
 /* Driver initialization */
-static void sg_init()
+static int sg_init()
 {
     static int sg_registered = 0;
     
-    if (sg_template.dev_noticed == 0) return;
+    if (sg_template.dev_noticed == 0) return 0;
     
     if(!sg_registered) {
 	if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) 
 	{
 	    printk("Unable to get major %d for generic SCSI device\n",
 		   SCSI_GENERIC_MAJOR);
-	    return;
+	    return 1;
 	}
 	sg_registered++;
     }
     
     /* If we have already been through here, return */
-    if(scsi_generics) return;
+    if(scsi_generics) return 0;
     
 #ifdef DEBUG
     printk("sg: Init generic device.\n");
@@ -513,6 +541,7 @@
 	   * sizeof(struct scsi_generic));
     
     sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
+    return 0;
 }
 
 static int sg_attach(Scsi_Device * SDp)
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.3.25/linux/drivers/scsi/sr.c	Wed Aug  2 13:21:14 1995
+++ linux/drivers/scsi/sr.c	Mon Sep 11 10:23:41 1995
@@ -45,7 +45,7 @@
 #define MAX_RETRIES 3
 #define SR_TIMEOUT (150 * HZ)
 
-static void sr_init(void);
+static int sr_init(void);
 static void sr_finish(void);
 static int sr_attach(Scsi_Device *);
 static int sr_detect(Scsi_Device *);
@@ -543,14 +543,16 @@
 
 
 /*
- * do_sr_request() is the request handler function for the sr driver.  Its function in life 
- * is to take block device requests, and translate them to SCSI commands.
+ * do_sr_request() is the request handler function for the sr driver.
+ * Its function in life is to take block device requests, and
+ * translate them to SCSI commands.  
  */
 
 static void do_sr_request (void)
 {
     Scsi_Cmnd * SCpnt = NULL;
     struct request * req = NULL;
+    Scsi_Device * SDev;
     unsigned long flags;
     int flag = 0;
     
@@ -563,7 +565,29 @@
 	};
 	
 	INIT_SCSI_REQUEST;
-	
+ 
+        SDev = scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device;
+        
+        /*
+         * I am not sure where the best place to do this is.  We need
+         * to hook in a place where we are likely to come if in user
+         * space.
+         */
+        if( SDev->was_reset )
+        {
+ 	    /*
+ 	     * We need to relock the door, but we might
+ 	     * be in an interrupt handler.  Only do this
+ 	     * from user space, since we do not want to
+ 	     * sleep from an interrupt.
+ 	     */
+ 	    if( SDev->removable && !intr_count )
+ 	    {
+                scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
+ 	    }
+ 	    SDev->was_reset = 0;
+        }
+        
 	if (flag++ == 0)
 	    SCpnt = allocate_device(&CURRENT,
 				    scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device, 0); 
@@ -1016,23 +1040,24 @@
     scsi_free(buffer, 512);
 }
 
-static void sr_init()
+static int sr_registered = 0;
+
+static int sr_init()
 {
 	int i;
-	static int sr_registered = 0;
     
-	if(sr_template.dev_noticed == 0) return;
+	if(sr_template.dev_noticed == 0) return 0;
     
 	if(!sr_registered) {
 	if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
 	    printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
-	    return;
+	    return 1;
 	}
 	sr_registered++;
 	}
     
 	
-	if (scsi_CDs) return;
+	if (scsi_CDs) return 0;
 	sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
 	scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
 	memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
@@ -1044,7 +1069,7 @@
 					     sizeof(int), GFP_ATOMIC);
 	for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
 	blksize_size[MAJOR_NR] = sr_blocksizes;
-    
+        return 0;
 }
 
 void sr_finish()
@@ -1136,7 +1161,8 @@
 	return;
     }
     scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
-    unregister_blkdev(SCSI_GENERIC_MAJOR, "sr");
+    unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
+    sr_registered--;
     if(scsi_CDs != NULL) {
 	scsi_init_free((char *) scsi_CDs,
 		       (sr_template.dev_noticed + SR_EXTRA_DEVS) 
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v1.3.25/linux/drivers/scsi/sr.h	Tue Jul 11 10:02:51 1995
+++ linux/drivers/scsi/sr.h	Mon Sep 11 10:42:24 1995
@@ -9,7 +9,7 @@
  *
  *	<drew@colorado.edu>
  *
- *       Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
+ *       Modified by Eric Youngdale eric@aib.com to
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.3.25/linux/drivers/scsi/st.c	Thu Sep  7 17:17:17 1995
+++ linux/drivers/scsi/st.c	Mon Sep 11 10:23:41 1995
@@ -11,7 +11,7 @@
   Copyright 1992, 1993, 1994, 1995 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Sat Sep  2 11:50:15 1995 by root@kai.makisara.fi
+  Last modified: Sun Sep 10 20:33:24 1995 by makisara@kai.makisara.fi
 */
 #ifdef MODULE
 #include <linux/autoconf.h>
@@ -71,6 +71,7 @@
 #define ST_LONG_TIMEOUT (2000 * HZ)
 
 static int st_nbr_buffers;
+static int st_req_nbr_buffers;
 static ST_buffer **st_buffers;
 static int st_buffer_size = ST_BUFFER_SIZE;
 static int st_write_threshold = ST_WRITE_THRESHOLD;
@@ -78,7 +79,7 @@
 
 Scsi_Tape * scsi_tapes = NULL;
 
-static void st_init(void);
+static int st_init(void);
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
@@ -376,6 +377,14 @@
   STp = &(scsi_tapes[dev]);
   STbuffer = STp->buffer;
 
+
+  /*
+   * If there was a bus reset, block further access
+   * to this device.
+   */
+  if( STp->device->was_reset )
+    return (-EIO);
+
   if (STp->ready != ST_READY)
     return 0;
 
@@ -765,6 +774,14 @@
     STp = &(scsi_tapes[dev]);
     if (STp->ready != ST_READY)
       return (-EIO);
+
+    /*
+     * If there was a bus reset, block further access
+     * to this device.
+     */
+    if( STp->device->was_reset )
+      return (-EIO);
+
 #if DEBUG
     if (!STp->in_use) {
       printk("st%d: Incorrect device.\n", dev);
@@ -1790,6 +1807,15 @@
    }
 #endif
 
+   /*
+    * If this is something intended for the lower layer, just pass it
+    * through.
+    */
+   if( cmd_in == SCSI_IOCTL_GET_IDLUN || cmd_in == SCSI_IOCTL_PROBE_HOST )
+     {
+       return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+     }
+   
    cmd = cmd_in & IOCCMD_MASK;
    if (cmd == (MTIOCTOP & IOCCMD_MASK)) {
 
@@ -1800,6 +1826,22 @@
      if (i)
 	return i;
 
+     /*
+      * If there was a bus reset, block further access
+      * to this device.  If the user wants to rewind the tape,
+      * then reset the flag and allow access again.
+      */
+     if( STp->device->was_reset) 
+       {
+	 if(mtc.mt_op != MTREW && 
+	    mtc.mt_op != MTOFFL &&
+	    mtc.mt_op != MTRESET && 
+	    mtc.mt_op != MTRETEN && 
+	    mtc.mt_op != MTEOM)
+	   return (-EIO);
+	 STp->device->was_reset = 0;
+       }
+
      memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
 
      i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
@@ -2038,25 +2080,30 @@
 static int st_registered = 0;
 
 /* Driver initialization */
-static void st_init()
+static int st_init()
 {
   int i;
   Scsi_Tape * STp;
 
-  if (st_template.dev_noticed == 0) return;
+  if (st_template.dev_noticed == 0) return 0;
 
   if(!st_registered) {
     if (register_chrdev(SCSI_TAPE_MAJOR,"st",&st_fops)) {
       printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR);
-      return;
+      return 1;
     }
     st_registered++;
   }
 
-  if (scsi_tapes) return;
+  if (scsi_tapes) return 0;
   scsi_tapes = (Scsi_Tape *) scsi_init_malloc(
   		(st_template.dev_noticed + ST_EXTRA_DEVS) * 
 					      sizeof(Scsi_Tape), GFP_ATOMIC);
+  if (scsi_tapes == NULL) {
+    printk("Unable to allocate descriptors for SCSI tapes.\n");
+    unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+    return 1;
+  }
   st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
 
 #if DEBUG
@@ -2091,11 +2138,24 @@
   }
 
   /* Allocate the buffers */
-  st_nbr_buffers = st_template.dev_noticed + ST_EXTRA_DEVS;
+  st_nbr_buffers = st_template.dev_noticed;
+  if (st_nbr_buffers < ST_EXTRA_DEVS)
+    st_nbr_buffers = ST_EXTRA_DEVS;
   if (st_nbr_buffers > st_max_buffers)
     st_nbr_buffers = st_max_buffers;
+  st_req_nbr_buffers = st_nbr_buffers;
   st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers * 
-					       sizeof(ST_buffer *), GFP_ATOMIC);
+					       sizeof(ST_buffer *),
+					       GFP_ATOMIC);
+  if (st_buffers == NULL) {
+    printk("Unable to allocate tape buffer pointers.\n");
+    unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+    scsi_init_free((char *) scsi_tapes,
+		   (st_template.dev_noticed + ST_EXTRA_DEVS) 
+		   * sizeof(Scsi_Tape));
+    return 1;
+  }
+
   /* FIXME - if we are hitting this because we are loading a tape module
   as a loadable driver, we should not use kmalloc - it will allocate
   a 64Kb region in order to buffer about 32Kb.  Try using 31 blocks
@@ -2103,14 +2163,32 @@
   
   for (i=0; i < st_nbr_buffers; i++) {
     st_buffers[i] = (ST_buffer *) scsi_init_malloc(sizeof(ST_buffer) - 
-						   1 + st_buffer_size, GFP_ATOMIC | GFP_DMA);
+						   1 + st_buffer_size,
+						   GFP_ATOMIC | GFP_DMA);
+    if (st_buffers[i] == NULL) {
+      printk("Not enough memory for buffer %d.\n", i);
+      if (i == 0) {
+	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+	scsi_init_free((char *) scsi_tapes,
+		       (st_template.dev_noticed + ST_EXTRA_DEVS) 
+		       * sizeof(Scsi_Tape));
+	scsi_init_free((char *) st_buffers,
+		       st_nbr_buffers * sizeof(ST_buffer *));
+	return 1;
+      }
+      st_nbr_buffers = i;
+      printk("Number of tape buffers adjusted.\n");
+      break;
+    }
+    else {
 #if DEBUG
 /*    printk("st: Buffer address: %p\n", st_buffers[i]); */
 #endif
-    st_buffers[i]->in_use = 0;
-    st_buffers[i]->writing = 0;
+      st_buffers[i]->in_use = 0;
+      st_buffers[i]->writing = 0;
+    }
   }
-  return;
+  return 0;
 }
 
 static void st_detach(Scsi_Device * SDp)
@@ -2153,13 +2231,17 @@
     scsi_init_free((char *) scsi_tapes,
 		   (st_template.dev_noticed + ST_EXTRA_DEVS) 
 		   * sizeof(Scsi_Tape));
-    
-    for (i=0; i < st_nbr_buffers; i++) {
-      scsi_init_free((char *) st_buffers[i],
-		     sizeof(ST_buffer) - 1 + st_buffer_size);
+
+    if (st_buffers != NULL) {
+      for (i=0; i < st_nbr_buffers; i++)
+	if (st_buffers[i] != NULL) {
+	  scsi_init_free((char *) st_buffers[i],
+			 sizeof(ST_buffer) - 1 + st_buffer_size);
+	}
+      
+      scsi_init_free((char *) st_buffers,
+		     st_req_nbr_buffers * sizeof(ST_buffer *));
     }
-    
-    scsi_init_free((char *) st_buffers, st_nbr_buffers * sizeof(ST_buffer *));
   }
   st_template.dev_max = 0;
 }
diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h
--- v1.3.25/linux/drivers/scsi/st_options.h	Sun Sep  3 12:27:00 1995
+++ linux/drivers/scsi/st_options.h	Mon Sep 11 10:23:41 1995
@@ -3,7 +3,7 @@
 
    Copyright 1995 Kai Makisara.
 
-   Last modified: Sun Aug 27 22:26:53 1995 by root@kai.makisara.fi
+   Last modified: Sun Sep 10 13:26:02 1995 by root@kai.makisara.fi
 */
 
 #ifndef _ST_OPTIONS_H
@@ -30,8 +30,15 @@
    SENSE. */
 #define ST_DEFAULT_BLOCK 0
 
-/* The tape driver buffer size in kilobytes. */
+/* The tape driver buffer size in kilobytes. When loading as module, the
+   memory block being used is slightly less than a power of two, i.e.,
+   a 64 kB block is used for a 32 kB buffer => we may as well use what is
+   being allocated! */
+#ifdef MODULE
+#define ST_BUFFER_BLOCKS 63
+#else
 #define ST_BUFFER_BLOCKS 32
+#endif
 
 /* The number of kilobytes of data in the buffer that triggers an
    asynchronous write in fixed block mode. See also ST_ASYNC_WRITES
diff -u --recursive --new-file v1.3.25/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.3.25/linux/drivers/sound/os.h	Sun Aug 13 14:45:34 1995
+++ linux/drivers/sound/os.h	Wed Sep 13 07:44:15 1995
@@ -155,7 +155,7 @@
  */
 
 #define ACTIVATE_TIMER(name, proc, time) \
-  {name.expires = time; \
+  {name.expires = (time)+jiffies; \
   add_timer (&name);}
 
 #define INB	inb
diff -u --recursive --new-file v1.3.25/linux/fs/Makefile linux/fs/Makefile
--- v1.3.25/linux/fs/Makefile	Thu Sep  7 17:17:17 1995
+++ linux/fs/Makefile	Mon Sep 11 07:27:49 1995
@@ -26,12 +26,20 @@
   endif
 endif
 
-ifdef CONFIG_EXT_FS
+ifeq ($(CONFIG_EXT_FS),y)
 SUB_DIRS += ext
+else
+  ifeq ($(CONFIG_EXT_FS),m)
+  MOD_SUB_DIRS += ext
+  endif
 endif
 
-ifdef CONFIG_EXT2_FS
+ifeq ($(CONFIG_EXT2_FS),y)
 SUB_DIRS += ext2
+else
+  ifeq ($(CONFIG_EXT2_FS),m)
+  MOD_SUB_DIRS += ext2
+  endif
 endif
 
 ifeq ($(CONFIG_MSDOS_FS),y)
diff -u --recursive --new-file v1.3.25/linux/fs/exec.c linux/fs/exec.c
--- v1.3.25/linux/fs/exec.c	Sat Sep  9 15:26:53 1995
+++ linux/fs/exec.c	Tue Sep 12 12:17:10 1995
@@ -524,6 +524,32 @@
 	return result;
 }
 
+static void exec_mmap(void)
+{
+	/*
+	 * The clear_page_tables done later on exec does the right thing
+	 * to the page directory when shared, except for graceful abort
+	 * (the oom is wrong there, too, IMHO)
+	 */
+	if (current->mm->count > 1) {
+		struct mm_struct *mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+		if (!mm) {
+			/* this is wrong, I think. */
+			oom(current);
+			return;
+		}
+		*mm = *current->mm;
+		mm->count = 1;
+		mm->mmap = NULL;
+		mm->mmap_avl = NULL;
+		current->mm->count--;
+		current->mm = mm;
+		new_page_tables(current);
+		return;
+	}
+	exit_mmap(current->mm);
+	clear_page_tables(current);
+}
 
 /*
  * This function flushes out all traces of the currently running executable so
@@ -549,7 +575,7 @@
 	current->comm[i] = '\0';
 
 	/* Release all of the old mmap stuff. */
-	exit_mmap(current->mm);
+	exec_mmap();
 
 	flush_thread();
 
@@ -558,16 +584,15 @@
 		current->dumpable = 0;
 	current->signal = 0;
 	for (i=0 ; i<32 ; i++) {
-		current->sigaction[i].sa_mask = 0;
-		current->sigaction[i].sa_flags = 0;
-		if (current->sigaction[i].sa_handler != SIG_IGN)
-			current->sigaction[i].sa_handler = NULL;
+		current->sig->action[i].sa_mask = 0;
+		current->sig->action[i].sa_flags = 0;
+		if (current->sig->action[i].sa_handler != SIG_IGN)
+			current->sig->action[i].sa_handler = NULL;
 	}
 	for (i=0 ; i<NR_OPEN ; i++)
 		if (FD_ISSET(i,&current->files->close_on_exec))
 			sys_close(i);
 	FD_ZERO(&current->files->close_on_exec);
-	clear_page_tables(current);
 	if (last_task_used_math == current)
 		last_task_used_math = NULL;
 	current->used_math = 0;
@@ -583,7 +608,9 @@
 	int i;
 	int retval;
 	int sh_bang = 0;
+#ifdef __alpha__
 	int loader = 0;
+#endif
 
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)	/* clear page-table */
diff -u --recursive --new-file v1.3.25/linux/fs/ext/inode.c linux/fs/ext/inode.c
--- v1.3.25/linux/fs/ext/inode.c	Mon Jun 12 16:49:40 1995
+++ linux/fs/ext/inode.c	Mon Sep 11 07:27:49 1995
@@ -10,6 +10,14 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <linux/sched.h>
 #include <linux/ext_fs.h>
 #include <linux/kernel.h>
@@ -40,6 +48,7 @@
 	if (sb->u.ext_sb.s_firstfreeblock)
 		brelse (sb->u.ext_sb.s_firstfreeblock);
 	unlock_super(sb);
+	MOD_DEC_USE_COUNT;
 	return;
 }
 
@@ -61,12 +70,14 @@
 	struct ext_super_block *es;
 	int dev = s->s_dev,block;
 
+	MOD_INC_USE_COUNT;
 	lock_super(s);
 	set_blocksize(dev, BLOCK_SIZE);
 	if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
 		s->s_dev=0;
 		unlock_super(s);
 		printk("EXT-fs: unable to read superblock\n");
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	es = (struct ext_super_block *) bh->b_data;
@@ -89,6 +100,7 @@
 		if (!silent)
 			printk("VFS: Can't find an extfs filesystem on dev 0x%04x.\n",
 				   dev);
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	if (!s->u.ext_sb.s_firstfreeblocknumber)
@@ -99,6 +111,7 @@
 			printk("ext_read_super: unable to read first free block\n");
 			s->s_dev = 0;
 			unlock_super(s);
+			MOD_DEC_USE_COUNT;
 			return NULL;
 		}
 	if (!s->u.ext_sb.s_firstfreeinodenumber)
@@ -110,6 +123,7 @@
 			brelse(s->u.ext_sb.s_firstfreeblock);
 			s->s_dev = 0;
 			unlock_super (s);
+			MOD_DEC_USE_COUNT;
 			return NULL;
 		}
 	}
@@ -120,6 +134,7 @@
 	if (!(s->s_mounted = iget(s,EXT_ROOT_INO))) {
 		s->s_dev=0;
 		printk("EXT-fs: get root inode failed\n");
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	return s;
@@ -440,3 +455,23 @@
 	return err;
 }
 
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type ext_fs_type = {
+        ext_read_super, "ext", 1, NULL
+};
+
+int init_module(void)
+{
+        register_filesystem(&ext_fs_type);
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        unregister_filesystem(&ext_fs_type);
+}
+
+#endif
diff -u --recursive --new-file v1.3.25/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v1.3.25/linux/fs/ext2/super.c	Sun Aug 13 14:45:34 1995
+++ linux/fs/ext2/super.c	Mon Sep 11 07:27:49 1995
@@ -13,6 +13,14 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
 #include <stdarg.h>
 
 #include <asm/bitops.h>
@@ -114,6 +122,7 @@
 			brelse (sb->u.ext2_sb.s_block_bitmap[i]);
 	brelse (sb->u.ext2_sb.s_sbh);
 	unlock_super (sb);
+	MOD_DEC_USE_COUNT;
 	return;
 }
 
@@ -369,12 +378,14 @@
 		return NULL;
 	}
 
+	MOD_INC_USE_COUNT;
 	lock_super (sb);
 	set_blocksize (dev, BLOCK_SIZE);
 	if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) {
 		sb->s_dev = 0;
 		unlock_super (sb);
 		printk ("EXT2-fs: unable to read superblock\n");
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	/*
@@ -405,8 +416,10 @@
 		logic_sb_block = (sb_block*BLOCK_SIZE) / sb->s_blocksize;
 		offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize;
 		bh = bread (dev, logic_sb_block, sb->s_blocksize);
-		if(!bh)
+		if(!bh) {
+		        MOD_DEC_USE_COUNT;
 			return NULL;
+		      }
 		es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
 		sb->u.ext2_sb.s_es = es;
 		if (es->s_magic != EXT2_SUPER_MAGIC) {
@@ -414,6 +427,7 @@
 			unlock_super (sb);
 			brelse (bh);
 			printk ("EXT2-fs: Magic mismatch, very weird !\n");
+		        MOD_DEC_USE_COUNT;
 			return NULL;
 		}
 	}
@@ -458,6 +472,8 @@
 		if (!silent)
 			printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n",
 				MAJOR(dev), MINOR(dev));
+
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	if (sb->s_blocksize != bh->b_size) {
@@ -467,6 +483,7 @@
 		if (!silent)
 			printk ("VFS: Unsupported blocksize on dev 0x%04x.\n",
 				dev);
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
@@ -476,6 +493,7 @@
 		brelse (bh);
 		printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
 			sb->u.ext2_sb.s_frag_size, sb->s_blocksize);
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
@@ -485,6 +503,7 @@
 		brelse (bh);
 		printk ("EXT2-fs: #blocks per group too big: %lu\n",
 			sb->u.ext2_sb.s_blocks_per_group);
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	if (sb->u.ext2_sb.s_frags_per_group > sb->s_blocksize * 8) {
@@ -493,6 +512,7 @@
 		brelse (bh);
 		printk ("EXT2-fs: #fragments per group too big: %lu\n",
 			sb->u.ext2_sb.s_frags_per_group);
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	if (sb->u.ext2_sb.s_inodes_per_group > sb->s_blocksize * 8) {
@@ -501,6 +521,7 @@
 		brelse (bh);
 		printk ("EXT2-fs: #inodes per group too big: %lu\n",
 			sb->u.ext2_sb.s_inodes_per_group);
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 
@@ -516,6 +537,7 @@
 		unlock_super (sb);
 		brelse (bh);
 		printk ("EXT2-fs: not enough memory\n");
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	for (i = 0; i < db_count; i++) {
@@ -530,6 +552,7 @@
 				 db_count * sizeof (struct buffer_head *));
 			brelse (bh);
 			printk ("EXT2-fs: unable to read group descriptors\n");
+			MOD_DEC_USE_COUNT;
 			return NULL;
 		}
 	}
@@ -542,6 +565,7 @@
 			 db_count * sizeof (struct buffer_head *));
 		brelse (bh);
 		printk ("EXT2-fs: group descriptors corrupted !\n");
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
@@ -568,6 +592,7 @@
 			 db_count * sizeof (struct buffer_head *));
 		brelse (bh);
 		printk ("EXT2-fs: get root inode failed\n");
+		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	ext2_setup_super (sb, es);
@@ -659,6 +684,27 @@
 	}
 	return 0;
 }
+
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type ext2_fs_type = {
+        ext2_read_super, "ext2", 1, NULL
+};
+
+int init_module(void)
+{
+        register_filesystem(&ext2_fs_type);
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        unregister_filesystem(&ext2_fs_type);
+}
+
+#endif
 
 void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
 {
diff -u --recursive --new-file v1.3.25/linux/fs/nfs/sock.c linux/fs/nfs/sock.c
--- v1.3.25/linux/fs/nfs/sock.c	Tue Jul 18 16:28:58 1995
+++ linux/fs/nfs/sock.c	Mon Sep 11 14:40:15 1995
@@ -94,9 +94,9 @@
 		| _S(SIGSTOP)
 #endif
 		| ((server->flags & NFS_MOUNT_INTR)
-		? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL
+		? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL
 			? _S(SIGINT) : 0)
-		| (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL
+		| (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL
 			? _S(SIGQUIT) : 0))
 		: 0));
 	fs = get_fs();
diff -u --recursive --new-file v1.3.25/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.25/linux/fs/proc/array.c	Sat Sep  9 15:26:53 1995
+++ linux/fs/proc/array.c	Tue Sep 12 13:16:45 1995
@@ -288,7 +288,7 @@
 	pmd_t *page_middle;
 	pte_t pte;
 
-	if (!p || ptr >= TASK_SIZE)
+	if (!p || !p->mm || ptr >= TASK_SIZE)
 		return 0;
 	page_dir = pgd_offset(p->mm,ptr);
 	if (pgd_none(*page_dir))
@@ -349,7 +349,7 @@
 {
 	struct task_struct ** p = get_task(pid);
 
-	if (!p || !*p)
+	if (!p || !*p || !(*p)->mm)
 		return 0;
 	return get_array(p, (*p)->mm->env_start, (*p)->mm->env_end, buffer);
 }
@@ -358,7 +358,7 @@
 {
 	struct task_struct ** p = get_task(pid);
 
-	if (!p || !*p)
+	if (!p || !*p || !(*p)->mm)
 		return 0;
 	return get_array(p, (*p)->mm->arg_start, (*p)->mm->arg_end, buffer);
 }
@@ -394,76 +394,86 @@
 
 static int get_stat(int pid, char * buffer)
 {
-	struct task_struct ** p = get_task(pid);
-	unsigned long sigignore=0, sigcatch=0, bit=1, wchan;
+	struct task_struct ** p = get_task(pid), *tsk;
+	unsigned long sigignore=0, sigcatch=0, wchan;
 	unsigned long vsize, eip, esp;
 	int i,tty_pgrp;
 	char state;
 
-	if (!p || !*p)
+	if (!p || (tsk = *p) == NULL)
 		return 0;
-	if ((*p)->state < 0 || (*p)->state > 5)
+	if (tsk->state < 0 || tsk->state > 5)
 		state = '.';
 	else
-		state = "RSDZTD"[(*p)->state];
-	eip = esp = 0;
-	vsize = (*p)->kernel_stack_page;
-	if (vsize) {
-		eip = KSTK_EIP(vsize);
-		esp = KSTK_ESP(vsize);
-		vsize = (*p)->mm->brk - (*p)->mm->start_code + PAGE_SIZE-1;
-		if (esp)
-			vsize += TASK_SIZE - esp;
+		state = "RSDZTD"[tsk->state];
+	vsize = eip = esp = 0;
+	if (tsk->mm) {
+		vsize = tsk->kernel_stack_page;
+		if (vsize) {
+			eip = KSTK_EIP(vsize);
+			esp = KSTK_ESP(vsize);
+			vsize = tsk->mm->brk - tsk->mm->start_code + PAGE_SIZE-1;
+			if (esp)
+				vsize += TASK_SIZE - esp;
+		}
 	}
-	wchan = get_wchan(*p);
-	for(i=0; i<32; ++i) {
-		switch((unsigned long) (*p)->sigaction[i].sa_handler) {
-		case 1: sigignore |= bit; break;
-		case 0: break;
-		default: sigcatch |= bit;
-		} bit <<= 1;
+	wchan = get_wchan(tsk);
+	if (tsk->sig) {
+		unsigned long bit = 1;
+		for(i=0; i<32; ++i) {
+			switch((unsigned long) tsk->sig->action[i].sa_handler) {
+				case 0:
+					break;
+				case 1:
+					sigignore |= bit;
+					break;
+				default:
+					sigcatch |= bit;
+			}
+			bit <<= 1;
+		}
 	}
-	if ((*p)->tty)
-		tty_pgrp = (*p)->tty->pgrp;
+	if (tsk->tty)
+		tty_pgrp = tsk->tty->pgrp;
 	else
 		tty_pgrp = -1;
 	return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu \
 %lu %lu %lu %lu\n",
 		pid,
-		(*p)->comm,
+		tsk->comm,
 		state,
-		(*p)->p_pptr->pid,
-		(*p)->pgrp,
-		(*p)->session,
-	        (*p)->tty ? (*p)->tty->device : 0,
+		tsk->p_pptr->pid,
+		tsk->pgrp,
+		tsk->session,
+	        tsk->tty ? tsk->tty->device : 0,
 		tty_pgrp,
-		(*p)->flags,
-		(*p)->mm->min_flt,
-		(*p)->mm->cmin_flt,
-		(*p)->mm->maj_flt,
-		(*p)->mm->cmaj_flt,
-		(*p)->utime,
-		(*p)->stime,
-		(*p)->cutime,
-		(*p)->cstime,
-		(*p)->counter,  /* this is the kernel priority ---
+		tsk->flags,
+		tsk->mm ? tsk->mm->min_flt : 0,
+		tsk->mm ? tsk->mm->cmin_flt : 0,
+		tsk->mm ? tsk->mm->maj_flt : 0,
+		tsk->mm ? tsk->mm->cmaj_flt : 0,
+		tsk->utime,
+		tsk->stime,
+		tsk->cutime,
+		tsk->cstime,
+		tsk->counter,  /* this is the kernel priority ---
 				   subtract 30 in your user-level program. */
-		(*p)->priority, /* this is the nice value ---
+		tsk->priority, /* this is the nice value ---
 				   subtract 15 in your user-level program. */
-		(*p)->timeout,
-		(*p)->it_real_value,
-		(*p)->start_time,
+		tsk->timeout,
+		tsk->it_real_value,
+		tsk->start_time,
 		vsize,
-		(*p)->mm->rss, /* you might want to shift this left 3 */
-		(*p)->rlim[RLIMIT_RSS].rlim_cur,
-		(*p)->mm->start_code,
-		(*p)->mm->end_code,
-		(*p)->mm->start_stack,
+		tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */
+		tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
+		tsk->mm ? tsk->mm->start_code : 0,
+		tsk->mm ? tsk->mm->end_code : 0,
+		tsk->mm ? tsk->mm->start_stack : 0,
 		esp,
 		eip,
-		(*p)->signal,
-		(*p)->blocked,
+		tsk->signal,
+		tsk->blocked,
 		sigignore,
 		sigcatch,
 		wchan);
@@ -544,16 +554,16 @@
 
 static int get_statm(int pid, char * buffer)
 {
-	struct task_struct ** p = get_task(pid);
+	struct task_struct ** p = get_task(pid), *tsk;
 	int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
 
-	if (!p || !*p)
+	if (!p || (tsk = *p) == NULL)
 		return 0;
-	if ((*p)->state != TASK_ZOMBIE) {
-		struct vm_area_struct * vma = (*p)->mm->mmap;
+	if (tsk->mm) {
+		struct vm_area_struct * vma = tsk->mm->mmap;
 
 		while (vma) {
-			pgd_t *pgd = pgd_offset((*p)->mm, vma->vm_start);
+			pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
 			int pages = 0, shared = 0, dirty = 0, total = 0;
 
 			statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
@@ -613,7 +623,7 @@
 	if (!p || !*p)
 		return -EINVAL;
 
-	if (count == 0)
+	if (!(*p)->mm || count == 0)
 		return 0;
 
 	/* decode f_pos */
diff -u --recursive --new-file v1.3.25/linux/fs/readdir.c linux/fs/readdir.c
--- v1.3.25/linux/fs/readdir.c	Tue Jun 27 14:11:44 1995
+++ linux/fs/readdir.c	Mon Sep 11 20:15:45 1995
@@ -86,7 +86,7 @@
 };
 
 struct getdents_callback {
-	struct linux_dirent * current;
+	struct linux_dirent * current_dir;
 	struct linux_dirent * previous;
 	int count;
 	int error;
@@ -104,14 +104,14 @@
 	dirent = buf->previous;
 	if (dirent)
 		put_user(offset, &dirent->d_off);
-	dirent = buf->current;
+	dirent = buf->current_dir;
 	buf->previous = dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(reclen, &dirent->d_reclen);
 	memcpy_tofs(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
 	((char *) dirent) += reclen;
-	buf->current = dirent;
+	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
 }
@@ -130,7 +130,7 @@
 	error = verify_area(VERIFY_WRITE, dirent, count);
 	if (error)
 		return error;
-	buf.current = (struct linux_dirent *) dirent;
+	buf.current_dir = (struct linux_dirent *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
diff -u --recursive --new-file v1.3.25/linux/include/asm-alpha/ptrace.h linux/include/asm-alpha/ptrace.h
--- v1.3.25/linux/include/asm-alpha/ptrace.h	Fri Jun  2 13:51:17 1995
+++ linux/include/asm-alpha/ptrace.h	Wed Sep 13 10:08:39 1995
@@ -64,6 +64,7 @@
 
 #ifdef __KERNEL__
 #define user_mode(regs) ((regs)->ps & 8)
+#define instruction_pointer(regs) ((regs)->pc)
 extern void show_regs(struct pt_regs *);
 #endif
 
diff -u --recursive --new-file v1.3.25/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- v1.3.25/linux/include/asm-alpha/unistd.h	Sun Sep  3 12:27:01 1995
+++ linux/include/asm-alpha/unistd.h	Wed Sep 13 10:08:39 1995
@@ -125,6 +125,7 @@
 #define __NR_get_kernel_syms	309
 #define __NR_syslog		310
 #define __NR_reboot		311
+#define __NR_clone		312
 
 
 #ifdef __LIBRARY__
@@ -172,11 +173,18 @@
 #ifdef __KERNEL_SYSCALLS__
 
 #include <linux/string.h>
+#include <linux/signal.h>
 
-extern unsigned long kernel_fork(void);
-static inline unsigned long fork(void)
+extern unsigned long kernel_clone(unsigned long clone_flags, void * stack);
+
+static inline long clone(unsigned long clone_flags, void * stack)
+{
+	return kernel_clone(clone_flags, stack);
+}
+
+static inline long fork(void)
 {
-	return kernel_fork();
+	return kernel_clone(SIGCHLD, NULL);
 }
 
 extern void sys_idle(void);
diff -u --recursive --new-file v1.3.25/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- v1.3.25/linux/include/asm-i386/checksum.h	Wed Aug  2 13:21:16 1995
+++ linux/include/asm-i386/checksum.h	Mon Sep 11 20:15:45 1995
@@ -100,6 +100,25 @@
 }
 
 /*
+ *	Fold a partial checksum without adding pseudo headers
+ */
+
+static inline unsigned short int csum_fold(unsigned int sum)
+{
+ 	__asm__("
+ 		movl %0, %1
+ 		shrl $16, %1
+ 		addw %w1, %w0
+ 		adcl $0, %0
+ 		notl %0
+ 		"
+ 		: "=&r" (sum)
+ 		: "0" (sum)
+ 	);
+ 	return sum;
+ }
+ 
+/*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
  */
diff -u --recursive --new-file v1.3.25/linux/include/asm-i386/i82489.h linux/include/asm-i386/i82489.h
--- v1.3.25/linux/include/asm-i386/i82489.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/i82489.h	Mon Sep 11 20:15:45 1995
@@ -0,0 +1,88 @@
+#ifndef __ASM_I82489_H
+#define __ASM_I82489_H
+
+/*
+ *	Offsets for programming the 82489 and Pentium integrated APIC
+ *
+ *	Alan Cox <Alan.Cox@linux.org>, 1995.
+ */
+ 
+#define		APIC_ID		0x20
+#define			GET_APIC_ID(x)		(((x)>>24)&0x0F)
+#define		APIC_VERSION	0x30
+#define		APIC_TASKPRI	0x80
+#define			APIC_TPRI_MASK		0xFF
+#define		APIC_ARBPRI	0x90
+#define		APIC_PROCPRI	0xA0
+#define		APIC_EOI	0xB0
+#define			APIC_EIO_ACK		0x0		/* Write this to the EOI register */
+#define		APIC_RRR	0xC0
+#define		APIC_LDR	0xD0
+#define			GET_APIC_LOGICAL_ID(x)	(((x)>>24)&0xFF)
+#define		APIC_DFR	0xE0
+#define			GET_APIC_DFR(x)		(((x)>>28)&0x0F)
+#define			SET_APIC_DFR(x)		((x)<<28)
+#define		APIC_SPIV	0xF0
+#define		APIC_ISR	0x100
+#define		APIC_TMR	0x180
+#define 	APIC_IRR	0x200
+#define 	APIC_ESR	0x280
+#define			APIC_ESR_SEND_CS	0x00001
+#define			APIC_ESR_RECV_CS	0x00002
+#define			APIC_ESR_SEND_ACC	0x00004
+#define			APIC_ESR_RECV_ACC	0x00008
+#define			APIC_ESR_SENDILL	0x00020
+#define			APIC_ESR_RECVILL	0x00040
+#define			APIC_ESR_ILLREGA	0x00080
+#define		APIC_ICR	0x300
+#define			APIC_DEST_FIELD		0x00000
+#define			APIC_DEST_SELF		0x40000
+#define			APIC_DEST_ALLINC	0x80000
+#define			APIC_DEST_ALLBUT	0xC0000
+#define			APIC_DEST_RR_MASK	0x30000
+#define			APIC_DEST_RR_INVALID	0x00000
+#define			APIC_DEST_RR_INPROG	0x10000
+#define			APIC_DEST_RR_VALID	0x20000
+#define			APIC_DEST_LEVELTRIG	0x08000
+#define			APIC_DEST_ASSERT	0x04000
+#define			APIC_DEST_BUSY		0x01000
+#define			APIC_DEST_LOGICAL	0x00800
+#define			APIC_DEST_DM_FIXED	0x00000
+#define			APIC_DEST_DM_LOWEST	0x00100
+#define			APIC_DEST_DM_SMI	0x00200
+#define			APIC_DEST_DM_REMRD	0x00300
+#define			APIC_DEST_DM_NMI	0x00400
+#define			APIC_DEST_DM_INIT	0x00500
+#define			APIC_DEST_DM_STARTUP	0x00600
+#define			APIC_DEST_VECTOR_MASK	0x000FF
+#define		APIC_ICR2	0x310
+#define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
+#define			SET_APIC_DEST_FIELD(x)	((x)<<24)
+#define		APIC_LVTT	0x320
+#define		APIC_LVT0	0x350
+#define			APIC_LVT_TIMER_PERIODIC		(1<<17)
+#define			APIC_LVT_MASKED			(1<<16)
+#define			APIC_LVT_LEVEL_TRIGGER		(1<<15)
+#define			APIC_LVT_REMOTE_IRR		(1<<14)
+#define			APIC_INPUT_POLARITY		(1<<13)
+#define			APIC_SEND_PENDING		(1<<12)
+#define			GET_APIC_DELIVERY_MODE(x)	(((x)>>8)&0x7)
+#define			SET_APIC_DELIVERY_MODE(x,y)	(((x)&~0x700)|((y)<<8))
+#define				APIC_MODE_FIXED		0x0
+#define				APIC_MODE_NMI		0x4
+#define				APIC_MODE_EXINT		0x7
+#define 	APIC_LVT1	0x360
+#define		APIC_LVERR	0x370
+#define		APIC_TMICT	0x380
+#define		APIC_TMCCT	0x390
+#define		APIC_TDCR	0x3E0
+#define			APIC_TDR_DIV_1		0xB
+#define			APIC_TDR_DIV_2		0x0
+#define			APIC_TDR_DIV_4		0x1
+#define			APIC_TDR_DIV_8		0x2
+#define			APIC_TDR_DIV_16		0x3
+#define			APIC_TDR_DIV_32		0x8
+#define			APIC_TDR_DIV_64		0x9
+#define			APIC_TDR_DIV_128	0xA
+
+#endif
diff -u --recursive --new-file v1.3.25/linux/include/asm-i386/ptrace.h linux/include/asm-i386/ptrace.h
--- v1.3.25/linux/include/asm-i386/ptrace.h	Wed Feb  1 21:46:08 1995
+++ linux/include/asm-i386/ptrace.h	Wed Sep 13 10:08:39 1995
@@ -45,6 +45,7 @@
 
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->cs))
+#define instruction_pointer(regs) ((regs)->eip)
 extern void show_regs(struct pt_regs *);
 #endif
 
diff -u --recursive --new-file v1.3.25/linux/include/asm-i386/shmparam.h linux/include/asm-i386/shmparam.h
--- v1.3.25/linux/include/asm-i386/shmparam.h	Fri Jun 16 22:02:55 1995
+++ linux/include/asm-i386/shmparam.h	Tue Sep 12 09:49:24 1995
@@ -33,7 +33,7 @@
  * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
  */
 
-#define SHMMAX 0x3fa000			/* max shared seg size (bytes) */
+#define SHMMAX 0x1000000		/* max shared seg size (bytes) */
 #define SHMMIN 1 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
 #define SHMALL				/* max shm system wide (pages) */ \
diff -u --recursive --new-file v1.3.25/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v1.3.25/linux/include/asm-i386/smp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/smp.h	Mon Sep 11 20:15:45 1995
@@ -0,0 +1,229 @@
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+#ifndef ASSEMBLY
+
+#include <asm/i82489.h>
+
+/*
+ *	Support definitions for SMP machines following the intel multiprocessing
+ *	specification
+ */
+
+/*
+ *	This tag identifies where the SMP configuration
+ *	information is. 
+ */
+ 
+#define SMP_MAGIC_IDENT	('_'<<24)|('P'<<16)|('M'<<8)|'_'
+
+struct intel_mp_floating
+{
+	char mpf_signature[4];		/* "_MP_" 			*/
+	unsigned long mpf_physptr;	/* Configuration table address	*/
+	unsigned char mpf_length;	/* Our length (paragraphs)	*/
+	unsigned char mpf_specification;/* Specification version	*/
+	unsigned char mpf_checksum;	/* Checksum (makes sum 0)	*/
+	unsigned char mpf_feature1;	/* Standard or configuration ? 	*/
+	unsigned char mpf_feature2;	/* Bit7 set for IMCR|PIC	*/
+	unsigned char mpf_feature3;	/* Unused (0)			*/
+	unsigned char mpf_feature4;	/* Unused (0)			*/
+	unsigned char mpf_feature5;	/* Unused (0)			*/
+};
+
+struct mp_config_table
+{
+	char mpc_signature[4];
+#define MPC_SIGNATURE "PCMP"
+	unsigned short mpc_length;	/* Size of table */
+	char  mpc_spec;			/* 0x01 */
+	char  mpc_checksum;
+	char  mpc_oem[8];
+	char  mpc_productid[12];
+	unsigned long mpc_oemptr;	/* 0 if not present */
+	unsigned short mpc_oemsize;	/* 0 if not present */
+	unsigned short mpc_oemcount;
+	unsigned long mpc_lapic;	/* APIC address */
+	unsigned long reserved;
+};
+
+/* Followed by entries */
+
+#define	MP_PROCESSOR	0
+#define	MP_BUS		1
+#define	MP_IOAPIC	2
+#define	MP_INTSRC	3
+#define	MP_LINTSRC	4
+
+struct mpc_config_processor
+{
+	unsigned char mpc_type;
+	unsigned char mpc_apicid;	/* Local APIC number */
+	unsigned char mpc_apicver;	/* Its versions */
+	unsigned char mpc_cpuflag;
+#define CPU_ENABLED		1	/* Processor is available */
+#define CPU_BOOTPROCESSOR	2	/* Processor is the BP */
+	unsigned long mpc_cpufeature;		
+#define CPU_STEPPING_MASK 0x0F
+#define CPU_MODEL_MASK	0xF0
+#define CPU_FAMILY_MASK	0xF00
+	unsigned long mpc_featureflag;	/* CPUID feature value */
+	unsigned long mpc_reserved[2];
+};
+
+struct mpc_config_bus
+{
+	unsigned char mpc_type;
+	unsigned char mpc_busid;
+	unsigned char mpc_bustype[6] __attribute((packed));
+};
+
+#define BUSTYPE_EISA	"EISA"
+#define BUSTYPE_ISA	"ISA"
+#define BUSTYPE_INTERN	"INTERN"	/* Internal BUS */
+#define BUSTYPE_MCA	"MCA"
+#define BUSTYPE_VL	"VL"		/* Local bus */
+#define BUSTYPE_PCI	"PCI"
+#define BUSTYPE_PCMCIA	"PCMCIA"
+
+/* We don't understand the others */
+
+struct mpc_config_ioapic
+{
+	unsigned char mpc_type;
+	unsigned char mpc_apicid;
+	unsigned char mpc_apicver;
+	unsigned char mpc_flags;
+#define MPC_APIC_USABLE		0x01
+	unsigned long mpc_apicaddr;
+};
+
+struct mpc_config_intsrc
+{
+	unsigned char mpc_type;
+	unsigned char mpc_irqtype;
+	unsigned short mpc_irqflag;
+	unsigned char mpc_srcbus;
+	unsigned char mpc_srcbusirq;
+	unsigned char mpc_dstapic;
+	unsigned char mpc_dstirq;
+};
+
+#define MP_INT_VECTORED		0
+#define MP_INT_NMI		1
+#define MP_INT_SMI		2
+#define MP_INT_EXTINT		3
+
+#define MP_IRQDIR_DEFAULT	0
+#define MP_IRQDIR_HIGH		1
+#define MP_IRQDIR_LOW		3
+
+
+struct mpc_config_intlocal
+{
+	unsigned char mpc_type;
+	unsigned char mpc_irqtype;
+	unsigned short mpc_irqflag;
+	unsigned char mpc_srcbusid;
+	unsigned char mpc_srcbusirq;
+	unsigned char mpc_destapic;	
+#define MP_APIC_ALL	0xFF
+	unsigned char mpc_destapiclint;
+};
+
+
+/*
+ *	Default configurations
+ *
+ *	1	2 CPU ISA 82489DX
+ *	2	2 CPU EISA 82489DX no IRQ 8 or timer chaining
+ *	3	2 CPU EISA 82489DX
+ *	4	2 CPU MCA 82489DX
+ *	5	2 CPU ISA+PCI
+ *	6	2 CPU EISA+PCI
+ *	7	2 CPU MCA+PCI
+ */
+
+/*
+ *	Per process x86 parameters
+ */
+ 
+struct cpuinfo_x86
+{
+	char hard_math;
+	char x86;
+	char x86_model;
+	char x86_mask;
+	char x86_vendor_id[16];
+	int  x86_capability;
+	int  fdiv_bug;
+	char wp_works_ok;
+	char hlt_works_ok;
+	unsigned long udelay_val;
+};
+
+
+extern struct cpuinfo_x86 cpu_data[32];
+
+/*
+ *	Private routines/data
+ */
+ 
+extern void smp_scan_config(unsigned long, unsigned long);
+extern unsigned long smp_alloc_memory(unsigned long mem_base);
+extern unsigned char *apic_reg;
+extern unsigned char *kernel_stacks[32];
+extern unsigned char boot_cpu_id;
+extern unsigned long cpu_present_map;
+extern void smp_invalidate(void);
+extern volatile unsigned long kernel_flag, kernel_counter;
+extern volatile unsigned char active_kernel_processor;
+extern void smp_message_irq(int cpl, struct pt_regs *regs);
+extern void smp_reschedule_irq(int cpl, struct pt_regs *regs);
+extern unsigned long ipi_count;
+extern void smp_invalidate_rcv(void);		/* Process an NMI */
+extern volatile unsigned long kernel_counter;
+extern volatile unsigned long syscall_count;
+
+/*
+ *	General functions that each host system must provide.
+ */
+ 
+extern void smp_callin(void);
+extern void smp_boot_cpus(void);
+extern void smp_store_cpu_info(int id);		/* Store per cpu info (like the initial udelay numbers */
+
+/*
+ *	APIC handlers: Note according to the Intel specification update
+ *	you should put reads between APIC writes.
+ *	Intel Pentium processor specification update [11AP, pg 64]
+ *		"Back to Back Assertions of HOLD May Cause Lost APIC Write Cycle"
+ */
+
+extern __inline void apic_write(unsigned long reg, unsigned long v)
+{
+	*((unsigned long *)(apic_reg+reg))=v;
+}
+
+extern __inline unsigned long apic_read(unsigned long reg)
+{
+	return *((unsigned long *)(apic_reg+reg));
+}
+
+/*
+ *	This function is needed by all SMP systems. It must _always_ be valid from the initial
+ *	startup. This may require magic on some systems (in the i86 case we dig out the boot 
+ *	cpu id from the config and set up a fake apic_reg pointer so that before we activate
+ *	the apic we get the right answer). Hopefully other processors are more sensible 8)
+ */
+ 
+extern __inline int smp_processor_id(void)
+{
+	return GET_APIC_ID(apic_read(APIC_ID));
+}
+
+#endif /* !ASSEMBLY */
+
+#define NO_PROC_ID		0xFF		/* No processor magic marker */
+
+#endif
diff -u --recursive --new-file v1.3.25/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v1.3.25/linux/include/asm-i386/unistd.h	Mon Aug 28 14:52:22 1995
+++ linux/include/asm-i386/unistd.h	Wed Sep 13 11:53:24 1995
@@ -251,6 +251,7 @@
 #define __NR__exit __NR_exit
 static inline _syscall0(int,idle)
 static inline _syscall0(int,fork)
+static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
 static inline _syscall0(int,pause)
 static inline _syscall0(int,setup)
 static inline _syscall0(int,sync)
diff -u --recursive --new-file v1.3.25/linux/include/linux/busmouse.h linux/include/linux/busmouse.h
--- v1.3.25/linux/include/linux/busmouse.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/busmouse.h	Wed Sep 13 12:30:48 1995
@@ -91,6 +91,7 @@
 	int		ready;
 	int		active;
 	struct wait_queue *wait;
+	struct fasync_struct *fasyncptr;
 };
 
 /* Function Prototypes */
diff -u --recursive --new-file v1.3.25/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.25/linux/include/linux/fs.h	Tue Aug  8 12:31:42 1995
+++ linux/include/linux/fs.h	Mon Sep 11 20:55:58 1995
@@ -111,16 +111,6 @@
 #define BLKRASET 4706 /* Set read ahead for block device */
 #define BLKRAGET 4707 /* get current read ahead setting */
 
-/* These are a few other constants  only used by scsi  devices */
-
-#define SCSI_IOCTL_GET_IDLUN 0x5382
-
-/* Used to turn on and off tagged queuing for scsi devices */
-
-#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
-#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
-
-
 #define BMAP_IOCTL 1	/* obsolete - kept for compatibility */
 #define FIBMAP	   1	/* bmap access */
 #define FIGETBSZ   2	/* get the block size used for bmap */
@@ -285,6 +275,8 @@
 
 #define FASYNC_MAGIC 0x4601
 
+extern int fasync_helper(struct inode *, struct file *, int, struct fasync_struct **);
+
 #include <linux/minix_fs_sb.h>
 #include <linux/ext_fs_sb.h>
 #include <linux/ext2_fs_sb.h>
@@ -490,6 +482,7 @@
 extern void clear_inode(struct inode *);
 extern struct inode * get_pipe_inode(void);
 extern struct file * get_empty_filp(void);
+extern int close_fp(struct file *filp);
 extern struct buffer_head * get_hash_table(dev_t dev, int block, int size);
 extern struct buffer_head * getblk(dev_t dev, int block, int size);
 extern void ll_rw_block(int rw, int nr, struct buffer_head * bh[]);
diff -u --recursive --new-file v1.3.25/linux/include/linux/igmp.h linux/include/linux/igmp.h
--- v1.3.25/linux/include/linux/igmp.h	Thu Sep  7 17:17:19 1995
+++ linux/include/linux/igmp.h	Mon Sep 11 20:15:45 1995
@@ -83,11 +83,12 @@
 extern struct ip_mc_list *ip_mc_head;
 
 
-extern int igmp_rcv(struct sk_buff *, struct device *, struct options *, unsigned long, unsigned short,
-	unsigned long, int , struct inet_protocol *);
+extern int igmp_rcv(struct sk_buff *, struct device *, struct options *, __u32, unsigned short,
+	__u32, int , struct inet_protocol *);
 extern void ip_mc_drop_device(struct device *dev); 
 extern int ip_mc_join_group(struct sock *sk, struct device *dev, unsigned long addr);
 extern int ip_mc_leave_group(struct sock *sk, struct device *dev,unsigned long addr);
 extern void ip_mc_drop_socket(struct sock *sk);
+extern void ip_mr_init(void);
 #endif
 #endif
diff -u --recursive --new-file v1.3.25/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h
--- v1.3.25/linux/include/linux/ip_fw.h	Sun Aug 13 14:45:35 1995
+++ linux/include/linux/ip_fw.h	Wed Sep 13 12:00:03 1995
@@ -162,6 +162,12 @@
 extern void ip_acct_cnt(struct iphdr *, struct device *, struct ip_fw *);
 extern int ip_acct_ctl(int, void *, int);
 #endif
+
+#define FW_BLOCK	0
+#define FW_ACCEPT	1
+#define FW_REJECT	(-1)
+#define FW_MASQUERADE	2
+
 extern int ip_fw_chk(struct iphdr *, struct device *rif,struct ip_fw *, int, int);
 extern void ip_fw_init(void);
 #endif /* KERNEL */
diff -u --recursive --new-file v1.3.25/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.25/linux/include/linux/mm.h	Thu Sep  7 17:17:19 1995
+++ linux/include/linux/mm.h	Wed Sep 13 11:52:16 1995
@@ -174,11 +174,14 @@
 
 extern void free_page_tables(struct task_struct * tsk);
 extern void clear_page_tables(struct task_struct * tsk);
+extern int new_page_tables(struct task_struct * tsk);
 extern int copy_page_tables(struct task_struct * to);
 extern int clone_page_tables(struct task_struct * to);
 extern int unmap_page_range(unsigned long from, unsigned long size);
 extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
 extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
+extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
+extern int zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
 
 extern void handle_mm_fault(struct vm_area_struct *vma, unsigned long address, int write_access);
 extern void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access);
diff -u --recursive --new-file v1.3.25/linux/include/linux/mroute.h linux/include/linux/mroute.h
--- v1.3.25/linux/include/linux/mroute.h	Sun Sep  3 12:27:02 1995
+++ linux/include/linux/mroute.h	Mon Sep 11 20:15:45 1995
@@ -118,6 +118,7 @@
 extern int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern void mroute_close(struct sock *sk);
 
+
 struct vif_device
 {
 	struct device *dev;		/* Device we are using */
diff -u --recursive --new-file v1.3.25/linux/include/linux/net.h linux/include/linux/net.h
--- v1.3.25/linux/include/linux/net.h	Tue Aug  8 12:31:42 1995
+++ linux/include/linux/net.h	Mon Sep 11 20:15:45 1995
@@ -135,7 +135,6 @@
 	void (*init_func)(struct net_proto *);	/* Bootstrap */
 };
 
-extern int	sock_awaitconn(struct socket *mysock, struct socket *servsock, int flags);
 extern int	sock_wake_async(struct socket *sock, int how);
 extern int	sock_register(int family, struct proto_ops *ops);
 extern int	sock_unregister(int family);
diff -u --recursive --new-file v1.3.25/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v1.3.25/linux/include/linux/netdevice.h	Sat Sep  9 15:26:53 1995
+++ linux/include/linux/netdevice.h	Wed Sep 13 11:52:55 1995
@@ -78,7 +78,7 @@
   /* I/O specific fields - FIXME: Merge these and struct ifmap into one */
   unsigned long		  rmem_end;		/* shmem "recv" end	*/
   unsigned long		  rmem_start;		/* shmem "recv" start	*/
-  unsigned long		  mem_end;		/* sahared mem end	*/
+  unsigned long		  mem_end;		/* shared mem end	*/
   unsigned long		  mem_start;		/* shared mem start	*/
   unsigned long		  base_addr;		/* device I/O address	*/
   unsigned char		  irq;			/* device IRQ number	*/
diff -u --recursive --new-file v1.3.25/linux/include/linux/route.h linux/include/linux/route.h
--- v1.3.25/linux/include/linux/route.h	Tue Jun  6 11:22:11 1995
+++ linux/include/linux/route.h	Mon Sep 11 20:15:53 1995
@@ -50,11 +50,4 @@
 #define RTF_IRTT	0x0100		/* Initial round trip time	  */
 #define RTF_REJECT	0x0200		/* Reject route			  */
 
-/*
- *	REMOVE THESE BY 1.2.0 !!!!!!!!!!!!!!!!!
- */
- 
-#define	RTF_MTU		RTF_MSS
-#define rt_mtu		rt_mss		
-
 #endif	/* _LINUX_ROUTE_H */
diff -u --recursive --new-file v1.3.25/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.3.25/linux/include/linux/sched.h	Sat Sep  9 15:26:53 1995
+++ linux/include/linux/sched.h	Wed Sep 13 11:42:18 1995
@@ -22,6 +22,15 @@
 #include <asm/page.h>
 
 /*
+ * cloning flags:
+ */
+#define CSIGNAL		0x000000ff	/* signal mask to be sent at exit */
+#define CLONE_VM	0x00000100	/* set if VM shared between processes */
+#define CLONE_FS	0x00000200	/* set if fs info shared between processes */
+#define CLONE_FILES	0x00000400	/* set if open files shared between processes */
+#define CLONE_SIGHAND	0x00000800	/* set if signal handlers shared */
+
+/*
  * These are the constant used to fake the fixed-point load-average
  * counting. Some notes:
  *  - 11 bit fractions expand to 22 bits by the multiplies: this gives
@@ -87,8 +96,6 @@
 
 asmlinkage void schedule(void);
 
-#endif /* __KERNEL__ */
-
 struct files_struct {
 	int count;
 	fd_set close_on_exec;
@@ -142,6 +149,15 @@
 /* swap */	0, 0, 0, 0, \
 		&init_mmap, &init_mmap }
 
+struct signal_struct {
+	int count;
+	struct sigaction action[32];
+};
+
+#define INIT_SIGNALS { \
+		1, \
+		{ {0,}, } }
+
 struct task_struct {
 /* these are hardcoded - don't touch */
 	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
@@ -157,7 +173,6 @@
 	struct linux_binfmt *binfmt;
 	struct task_struct *next_task, *prev_task;
 	struct task_struct *next_run,  *prev_run;
-	struct sigaction *sigaction;
 	unsigned long saved_kernel_stack;
 	unsigned long kernel_stack_page;
 	int exit_code, exit_signal;
@@ -199,6 +214,8 @@
 	struct files_struct *files;
 /* memory management info */
 	struct mm_struct *mm;
+/* signal handlers */
+	struct signal_struct *sig;
 };
 
 /*
@@ -213,15 +230,6 @@
 #define PF_EXITING	0x00000200	/* getting shut down */
 
 /*
- * cloning flags:
- */
-#define CSIGNAL		0x000000ff	/* signal mask to be sent at exit */
-#define CLONE_VM	0x00000100	/* set if VM shared between processes */
-#define CLONE_FS	0x00000200	/* set if fs info shared between processes */
-#define CLONE_FILES	0x00000400	/* set if open files shared between processes */
-#define CLONE_SIGHAND	0x00000800	/* set if signal handlers shared */
-
-/*
  * Limit the stack by to some sane default: root can always
  * increase this limit if needed..  8MB seems reasonable.
  */
@@ -237,7 +245,6 @@
 /* exec domain */&default_exec_domain, \
 /* binfmt */	NULL, \
 /* schedlink */	&init_task,&init_task, &init_task, &init_task, \
-/* signals */	init_sigaction, \
 /* stack */	0,(unsigned long) &init_kernel_stack, \
 /* ec,brk... */	0,0,0,0,0, \
 /* pid etc.. */	0,0,0,0,0, \
@@ -259,11 +266,10 @@
 /* tss */	INIT_TSS, \
 /* fs */	&init_fs, \
 /* files */	&init_files, \
-/* mm */	&init_mm \
+/* mm */	&init_mm, \
+/* signals */	&init_signals, \
 }
 
-#ifdef __KERNEL__
-
 extern struct   mm_struct init_mm;
 extern struct task_struct init_task;
 extern struct task_struct *task[NR_TASKS];
@@ -298,6 +304,10 @@
 extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
 extern void exit_thread(void);
+
+extern void exit_fs(struct task_struct *);
+extern void exit_files(struct task_struct *);
+extern void exit_sighand(struct task_struct *);
 
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
diff -u --recursive --new-file v1.3.25/linux/include/linux/scsi.h linux/include/linux/scsi.h
--- v1.3.25/linux/include/linux/scsi.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/scsi.h	Sun Sep 10 09:37:21 1995
@@ -0,0 +1,198 @@
+#ifndef _LINUX_SCSI_H
+#define _LINUX_SCSI_H
+
+/*
+ * This header file contains public constants and structures used by
+ * the scsi code for linux.
+ */
+
+/*
+    $Header: /usr/src/linux/include/linux/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
+
+    For documentation on the OPCODES, MESSAGES, and SENSE values,
+    please consult the SCSI standard.
+
+*/
+
+/*
+ *      SCSI opcodes
+ */
+
+#define TEST_UNIT_READY       0x00
+#define REZERO_UNIT           0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define REASSIGN_BLOCKS       0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SEEK_6                0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+
+#define SET_WINDOW            0x24
+#define READ_CAPACITY         0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define WRITE_VERIFY          0x2e
+#define VERIFY                0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG             0x3e
+#define WRITE_LONG            0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME            0x41
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define MODE_SELECT_10        0x55
+#define MODE_SENSE_10         0x5a
+#define READ_12               0xa8
+#define WRITE_12              0xaa
+#define WRITE_VERIFY_12       0xae
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define SEND_VOLUME_TAG       0xb6
+#define WRITE_LONG_2          0xea
+
+/*
+ *  Status codes
+ */
+
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x01
+#define CONDITION_GOOD       0x02
+#define BUSY                 0x04
+#define INTERMEDIATE_GOOD    0x08
+#define INTERMEDIATE_C_GOOD  0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define QUEUE_FULL           0x1a
+
+#define STATUS_MASK          0x1e
+
+/*
+ *  SENSE KEYS
+ */
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+
+/*
+ *  DEVICE TYPES
+ */
+
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07    /* Magneto-optical disk - 
+				     * - treated as TYPE_DISK */
+#define TYPE_NO_LUN         0x7f
+
+
+/*
+ *  MESSAGE CODES
+ */
+
+#define COMMAND_COMPLETE    0x00
+#define EXTENDED_MESSAGE    0x01
+#define     EXTENDED_MODIFY_DATA_POINTER    0x00
+#define     EXTENDED_SDTR                   0x01
+#define     EXTENDED_EXTENDED_IDENTIFY      0x02    /* SCSI-I only */
+#define     EXTENDED_WDTR                   0x03
+#define SAVE_POINTERS       0x02
+#define RESTORE_POINTERS    0x03
+#define DISCONNECT          0x04
+#define INITIATOR_ERROR     0x05
+#define ABORT               0x06
+#define MESSAGE_REJECT      0x07
+#define NOP                 0x08
+#define MSG_PARITY_ERROR    0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define BUS_DEVICE_RESET    0x0c
+
+#define INITIATE_RECOVERY   0x0f            /* SCSI-II only */
+#define RELEASE_RECOVERY    0x10            /* SCSI-II only */
+
+#define SIMPLE_QUEUE_TAG    0x20
+#define HEAD_OF_QUEUE_TAG   0x21
+#define ORDERED_QUEUE_TAG   0x22
+
+/*
+ * Here are some scsi specific ioctl commands which are sometimes useful.
+ */
+/* These are a few other constants  only used by scsi  devices */
+
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+
+/* Used to turn on and off tagged queuing for scsi devices */
+
+#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
+#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
+
+/* Used to obtain the host number of a device. */
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
+
+#endif
diff -u --recursive --new-file v1.3.25/linux/include/linux/smp.h linux/include/linux/smp.h
--- v1.3.25/linux/include/linux/smp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/smp.h	Mon Sep 11 20:15:53 1995
@@ -0,0 +1,31 @@
+#ifndef __LINUX_SMP_H
+#define __LINUX_SMP_H
+
+/*
+ *	Generic SMP support
+ *		Alan Cox. <alan@cymru.net>
+ */
+
+#include <asm/smp.h>
+
+ 
+extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
+extern void smp_boot_cpus(void);		/* Boot processor call to load the other CPU's */
+extern void smp_callin(void);			/* Processor call in. Must hold processors until .. */
+extern void smp_commence(void);			/* Multiprocessors may now schedule */
+extern int smp_num_cpus;
+extern int smp_threads_ready;			/* True once the per process idle is forked */
+extern volatile unsigned long smp_spins;	/* Count of spins */
+
+extern volatile unsigned long smp_msg_data;
+extern volatile int smp_src_cpu;
+extern volatile int smp_msg_id;
+
+#define MSG_ALL_BUT_SELF	0x8000		/* Assume <32768 CPU's */
+#define MSG_ALL			0x8001
+
+#define MSG_INVALIDATE_TLB	0x0001		/* Remote processor TLB invalidate */
+#define MSG_STOP_CPU		0x0002		/* Sent to shut down slave CPU's when rebooting */
+#define MSG_RESCHEDULE		0x0003		/* Reschedule request from master CPU */
+
+#endif
diff -u --recursive --new-file v1.3.25/linux/include/linux/tasks.h linux/include/linux/tasks.h
--- v1.3.25/linux/include/linux/tasks.h	Mon Feb 27 11:16:24 1995
+++ linux/include/linux/tasks.h	Mon Sep 11 20:15:53 1995
@@ -4,6 +4,9 @@
 /*
  * This is the maximum nr of tasks - change it if you need to
  */
+ 
+#define NR_PROCS	32		/* Max processors that can be running */
+
 #define NR_TASKS	512
 
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
diff -u --recursive --new-file v1.3.25/linux/include/net/icmp.h linux/include/net/icmp.h
--- v1.3.25/linux/include/net/icmp.h	Tue Jun  6 11:22:17 1995
+++ linux/include/net/icmp.h	Mon Sep 11 21:12:52 1995
@@ -20,19 +20,17 @@
 
 #include <linux/icmp.h>
 
-
 extern struct icmp_err icmp_err_convert[];
 extern struct icmp_mib icmp_statistics;
 
-
 extern void	icmp_send(struct sk_buff *skb_in,  int type, int code,
 			  unsigned long info, struct device *dev);
 extern int	icmp_rcv(struct sk_buff *skb1, struct device *dev,
-			 struct options *opt, unsigned long daddr,
-			 unsigned short len, unsigned long saddr,
+			 struct options *opt, __u32 daddr,
+			 unsigned short len, __u32 saddr,
 			 int redo, struct inet_protocol *protocol);
-
 extern int	icmp_ioctl(struct sock *sk, int cmd,
 			   unsigned long arg);
+extern void	icmp_init(struct proto_ops *ops);
 
 #endif	/* _ICMP_H */
diff -u --recursive --new-file v1.3.25/linux/include/net/ip.h linux/include/net/ip.h
--- v1.3.25/linux/include/net/ip.h	Tue Aug 15 20:39:05 1995
+++ linux/include/net/ip.h	Wed Sep 13 11:52:55 1995
@@ -73,15 +73,13 @@
 };
 
 
-extern int		backoff(int n);
-
 extern void		ip_print(const struct iphdr *ip);
 extern int		ip_ioctl(struct sock *sk, int cmd,
 				 unsigned long arg);
-extern void		ip_route_check(unsigned long daddr);
+extern void		ip_route_check(__u32 daddr);
 extern int		ip_build_header(struct sk_buff *skb,
-					unsigned long saddr,
-					unsigned long daddr,
+					__u32 saddr,
+					__u32 daddr,
 					struct device **dev, int type,
 					struct options *opt, int len,
 					int tos,int ttl);
@@ -99,13 +97,13 @@
 extern void		ip_init(void);
 extern int		ip_build_xmit(struct sock *sk,
 				      void getfrag (const void *,
-						    int,
+						    __u32,
 						    char *,
 						    unsigned int,
 						    unsigned int),
 				      const void *frag,
 				      unsigned short int length,
-				      int daddr,
+				      __u32 daddr,
 				      int flags,
 				      int type);
 
diff -u --recursive --new-file v1.3.25/linux/include/net/ipip.h linux/include/net/ipip.h
--- v1.3.25/linux/include/net/ipip.h	Tue Jun  6 11:22:17 1995
+++ linux/include/net/ipip.h	Mon Sep 11 20:15:53 1995
@@ -1,4 +1,4 @@
 extern int ipip_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, 
-		unsigned long daddr, unsigned short len, unsigned long saddr,
+		__u32 daddr, unsigned short len, __u32 saddr,
                                    int redo, struct inet_protocol *protocol);
                                    
diff -u --recursive --new-file v1.3.25/linux/include/net/protocol.h linux/include/net/protocol.h
--- v1.3.25/linux/include/net/protocol.h	Wed Aug  2 13:21:16 1995
+++ linux/include/net/protocol.h	Mon Sep 11 20:15:53 1995
@@ -17,6 +17,7 @@
  *	Changes:
  *		Alan Cox	:	Added a name field and a frag handler
  *					field for later.
+ *		Alan Cox	:	Cleaned up, and sorted types.
  */
  
 #ifndef _PROTOCOL_H
@@ -29,16 +30,12 @@
 /* This is used to register protocols. */
 struct inet_protocol {
   int			(*handler)(struct sk_buff *skb, struct device *dev,
-				   struct options *opt, unsigned long daddr,
-				   unsigned short len, unsigned long saddr,
+				   struct options *opt, __u32 daddr,
+				   unsigned short len, __u32 saddr,
 				   int redo, struct inet_protocol *protocol);
-  int			(*frag_handler)(struct sk_buff *skb, struct device *dev,
-				   struct options *opt, unsigned long daddr,
-				   unsigned short len, unsigned long saddr,
-				   int redo, struct inet_protocol *protocol);
-  void			(*err_handler)(int err, unsigned char *buff,
-				       unsigned long daddr,
-				       unsigned long saddr,
+  void			(*err_handler)(int type, int code, unsigned char *buff,
+				       __u32 daddr,
+				       __u32 saddr,
 				       struct inet_protocol *protocol);
   struct inet_protocol *next;
   unsigned char		protocol;
diff -u --recursive --new-file v1.3.25/linux/include/net/raw.h linux/include/net/raw.h
--- v1.3.25/linux/include/net/raw.h	Tue Jun  6 11:22:18 1995
+++ linux/include/net/raw.h	Mon Sep 11 20:15:53 1995
@@ -21,14 +21,14 @@
 extern struct proto raw_prot;
 
 
-extern void	raw_err(int err, unsigned char *header, unsigned long daddr,
-			unsigned long saddr, struct inet_protocol *protocol);
+extern void	raw_err(int type, int code, unsigned char *header, __u32 daddr,
+			__u32 saddr, struct inet_protocol *protocol);
 extern int	raw_recvfrom(struct sock *sk, unsigned char *to,
 			int len, int noblock, unsigned flags,
 			struct sockaddr_in *sin, int *addr_len);
 extern int	raw_read(struct sock *sk, unsigned char *buff,
 			int len, int noblock, unsigned flags);
 extern int 	raw_rcv(struct sock *, struct sk_buff *, struct device *, 
-			long, long);
+			__u32, __u32);
 
 #endif	/* _RAW_H */
diff -u --recursive --new-file v1.3.25/linux/include/net/route.h linux/include/net/route.h
--- v1.3.25/linux/include/net/route.h	Sun Aug 13 14:45:35 1995
+++ linux/include/net/route.h	Mon Sep 11 20:15:53 1995
@@ -29,9 +29,9 @@
 struct rtable 
 {
 	struct rtable		*rt_next;
-	unsigned long		rt_dst;
-	unsigned long		rt_mask;
-	unsigned long		rt_gateway;
+	__u32			rt_dst;
+	__u32			rt_mask;
+	__u32			rt_gateway;
 	unsigned short		rt_flags;
 	short			rt_metric;
 	unsigned int		rt_refcnt;
@@ -44,10 +44,10 @@
 
 
 extern void		ip_rt_flush(struct device *dev);
-extern void		ip_rt_add(short flags, unsigned long addr, unsigned long mask,
-			       unsigned long gw, struct device *dev, unsigned short mss, unsigned long window, unsigned short irtt, short metric);
-extern struct rtable	*ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr);
-extern struct rtable 	*ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr);
+extern void		ip_rt_add(short flags, __u32 addr, __u32 mask,
+			       __u32 gw, struct device *dev, unsigned short mss, unsigned long window, unsigned short irtt, short metric);
+extern struct rtable	*ip_rt_route(__u32 daddr, struct options *opt, __u32 *src_addr);
+extern struct rtable 	*ip_rt_local(__u32 daddr, struct options *opt, __u32 *src_addr);
 extern int		rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy);
 extern int		ip_rt_ioctl(unsigned int cmd, void *arg);
 
diff -u --recursive --new-file v1.3.25/linux/include/net/sock.h linux/include/net/sock.h
--- v1.3.25/linux/include/net/sock.h	Thu Sep  7 17:17:19 1995
+++ linux/include/net/sock.h	Wed Sep 13 11:52:55 1995
@@ -81,6 +81,7 @@
   struct options		*opt;
   volatile unsigned long	wmem_alloc;
   volatile unsigned long	rmem_alloc;
+  unsigned long			allocation;		/* Allocation mode */
   __u32				write_seq;
   __u32				sent_seq;
   __u32				acked_seq;
@@ -126,8 +127,8 @@
 				receive_queue;
   struct proto			*prot;
   struct wait_queue		**sleep;
-  unsigned long			daddr;
-  unsigned long			saddr;
+  __u32				daddr;
+  __u32				saddr;
   unsigned short		max_unacked;
   unsigned short		window;
   unsigned short		bytes_rcv;
@@ -260,8 +261,8 @@
 				    unsigned flags, struct sockaddr_in *usin,
 				    int *addr_len);
   int			(*build_header)(struct sk_buff *skb,
-					unsigned long saddr,
-					unsigned long daddr,
+					__u32 saddr,
+					__u32 daddr,
 					struct device **dev, int type,
 					struct options *opt, int len,
 					int tos, int ttl);
@@ -275,8 +276,8 @@
   void			(*write_wakeup)(struct sock *sk);
   void			(*read_wakeup)(struct sock *sk);
   int			(*rcv)(struct sk_buff *buff, struct device *dev,
-			       struct options *opt, unsigned long daddr,
-			       unsigned short len, unsigned long saddr,
+			       struct options *opt, __u32 daddr,
+			       unsigned short len, __u32 saddr,
 			       int redo, struct inet_protocol *protocol);
   int			(*select)(struct sock *sk, int which,
 				  select_table *wait);
@@ -292,9 +293,7 @@
   unsigned long		retransmits;
   char			name[32];
   int			inuse, highestinuse;
-#ifndef PACKET_C		/* Hack to save 1K for packet sockets */ 
   struct sock *		sock_array[SOCK_ARRAY_SIZE];
-#endif PACKET_C  
 };
 
 #define TIME_WRITE	1
diff -u --recursive --new-file v1.3.25/linux/include/net/tcp.h linux/include/net/tcp.h
--- v1.3.25/linux/include/net/tcp.h	Thu Jul 13 16:20:21 1995
+++ linux/include/net/tcp.h	Mon Sep 11 20:15:53 1995
@@ -111,8 +111,8 @@
  * convinced that this is the solution for the 'getpeername(2)'
  * problem. Thanks to Stephen A. Wood <saw@cebaf.gov>  -FvK
  */
-extern __inline const int
-tcp_connected(const int state)
+
+extern __inline const int tcp_connected(const int state)
 {
   return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
 	 state == TCP_FIN_WAIT1   || state == TCP_FIN_WAIT2 ||
@@ -123,12 +123,12 @@
 extern struct proto tcp_prot;
 
 
-extern void	tcp_err(int err, unsigned char *header, unsigned long daddr,
-			unsigned long saddr, struct inet_protocol *protocol);
+extern void	tcp_err(int type, int code, unsigned char *header, __u32 daddr,
+			__u32, struct inet_protocol *protocol);
 extern void	tcp_shutdown (struct sock *sk, int how);
 extern int	tcp_rcv(struct sk_buff *skb, struct device *dev,
-			struct options *opt, unsigned long daddr,
-			unsigned short len, unsigned long saddr, int redo,
+			struct options *opt, __u32 daddr,
+			unsigned short len, __u32 saddr, int redo,
 			struct inet_protocol *protocol);
 
 extern int	tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
diff -u --recursive --new-file v1.3.25/linux/include/net/udp.h linux/include/net/udp.h
--- v1.3.25/linux/include/net/udp.h	Tue Jun  6 11:22:18 1995
+++ linux/include/net/udp.h	Mon Sep 11 20:15:53 1995
@@ -31,10 +31,10 @@
 extern struct proto udp_prot;
 
 
-extern void	udp_err(int err, unsigned char *header, unsigned long daddr,
-			unsigned long saddr, struct inet_protocol *protocol);
-extern void	udp_send_check(struct udphdr *uh, unsigned long saddr, 
-			unsigned long daddr, int len, struct sock *sk);
+extern void	udp_err(int type, int code, unsigned char *header, __u32 daddr,
+			__u32 saddr, struct inet_protocol *protocol);
+extern void	udp_send_check(struct udphdr *uh, __u32 saddr, 
+			__u32 daddr, int len, struct sock *sk);
 extern int	udp_recvfrom(struct sock *sk, unsigned char *to,
 			     int len, int noblock, unsigned flags,
 			     struct sockaddr_in *sin, int *addr_len);
@@ -43,8 +43,8 @@
 extern int	udp_connect(struct sock *sk,
 			    struct sockaddr_in *usin, int addr_len);
 extern int	udp_rcv(struct sk_buff *skb, struct device *dev,
-			struct options *opt, unsigned long daddr,
-			unsigned short len, unsigned long saddr, int redo,
+			struct options *opt, __u32 daddr,
+			unsigned short len, __u32 saddr, int redo,
 			struct inet_protocol *protocol);
 extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern void	udp_cache_zap(void);	/* Remove udp last socket cache */
diff -u --recursive --new-file v1.3.25/linux/init/main.c linux/init/main.c
--- v1.3.25/linux/init/main.c	Sat Sep  9 15:26:53 1995
+++ linux/init/main.c	Wed Sep 13 10:08:39 1995
@@ -276,11 +276,20 @@
 	return 0;
 }
 
-unsigned long loops_per_sec = 1;
+/* this should be approx 2 Bo*oMips to start (note initial shift), and will
+   still work even if initally too large, it will just take slightly longer */
+unsigned long loops_per_sec = (1<<12);
+
+/* This is the number of bits of precision for the loops_per_second.  Each
+   bit takes on average 1.5/HZ seconds.  This (like the original) is a little
+   better than 1% */
+#define LPS_PREC 8
 
 static void calibrate_delay(void)
 {
 	int ticks;
+	int loopbit;
+	int lps_precision = LPS_PREC;
 
 	printk("Calibrating delay loop.. ");
 	while (loops_per_sec <<= 1) {
@@ -292,17 +301,31 @@
 		ticks = jiffies;
 		__delay(loops_per_sec);
 		ticks = jiffies - ticks;
-		if (ticks >= HZ) {
-			loops_per_sec = muldiv(loops_per_sec, HZ, ticks);
-			printk("ok - %lu.%02lu BogoMIPS\n",
-				loops_per_sec/500000,
-				(loops_per_sec/5000) % 100);
-			return;
+		if (ticks)
+			break;
 		}
+
+/* Do a binary approximation to get loops_per_second set to equal one clock
+   (up to lps_precision bits) */
+	loops_per_sec >>= 1;
+	loopbit = loops_per_sec;
+	while ( lps_precision-- && (loopbit >>= 1) ) {
+		loops_per_sec |= loopbit;
+		ticks = jiffies;
+		while (ticks == jiffies);
+		ticks = jiffies;
+		__delay(loops_per_sec);
+		if (jiffies != ticks)	/* longer than 1 tick */
+			loops_per_sec &= ~loopbit;
 	}
-	printk("failed\n");
-}
 
+/* finally, adjust loops per second in terms of seconds instead of clocks */	
+	loops_per_sec *= HZ;
+/* Round the value and print it */	
+	printk("ok - %lu.%02lu BogoMIPS\n",
+		(loops_per_sec+2500)/500000,
+		((loops_per_sec+2500)/5000) % 100);
+}
 
 /*
  * This is a simple kernel command line parsing function: it parses
@@ -383,6 +406,8 @@
 
 extern void setup_arch(char **, unsigned long *, unsigned long *);
 
+static char init_stack[PAGE_SIZE];
+
 asmlinkage void start_kernel(void)
 {
 	char * command_line;
@@ -443,7 +468,8 @@
 
 	printk(linux_banner);
 
-	if (!fork())		/* we count on this going ok */
+	/* we count on the clone going ok */
+	if (!clone(CLONE_VM, init_stack+sizeof(init_stack)))
 		init();
 /*
  * task[0] is meant to be used as an "idle" task: it may not sleep, but
diff -u --recursive --new-file v1.3.25/linux/kernel/exit.c linux/kernel/exit.c
--- v1.3.25/linux/kernel/exit.c	Thu Sep  7 17:17:19 1995
+++ linux/kernel/exit.c	Tue Sep 12 17:48:11 1995
@@ -24,7 +24,7 @@
 static int generate(unsigned long sig, struct task_struct * p)
 {
 	unsigned long mask = 1 << (sig-1);
-	struct sigaction * sa = sig + p->sigaction - 1;
+	struct sigaction * sa = sig + p->sig->action - 1;
 
 	/* always generate signals for traced processes ??? */
 	if (!(p->flags & PF_PTRACED)) {
@@ -54,7 +54,7 @@
 	/*
 	 * Forget it if the process is already zombie'd.
 	 */
-	if (p->state == TASK_ZOMBIE)
+	if (!p->sig)
 		return 0;
 	if ((sig == SIGKILL) || (sig == SIGCONT)) {
 		if (p->state == TASK_STOPPED)
@@ -97,11 +97,7 @@
 			if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
 				printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
 			free_page(p->kernel_stack_page);
-			free_page((long) p->mm);
-			free_page((long) p->files);
-			free_page((long) p->fs);
-			free_page((long) p->sigaction);
-			free_page((long) p);
+			kfree(p);
 			return;
 		}
 	panic("trying to release non-existent task");
@@ -359,51 +355,76 @@
 	}
 }
 
-static void exit_files(void)
+void exit_files(struct task_struct *tsk)
 {
-	if (!--current->files->count) {
-		int i;
-		for (i=0 ; i<NR_OPEN ; i++)
-			if (current->files->fd[i])
-				sys_close(i);
+	struct files_struct * files = tsk->files;
+
+	if (files) {
+		tsk->files = NULL;
+		if (!--files->count) {
+			int i;
+			for (i=0 ; i<NR_OPEN ; i++) {
+				struct file * filp = files->fd[i];
+				if (!filp)
+					continue;
+				files->fd[i] = NULL;
+				close_fp(filp);
+			}
+			kfree(files);
+		}
 	}
 }
 
-static void exit_fs(void)
+void exit_fs(struct task_struct *tsk)
 {
-	if (!--current->fs->count) {
-		iput(current->fs->pwd);
-		current->fs->pwd = NULL;
-		iput(current->fs->root);
-		current->fs->root = NULL;
+	struct fs_struct * fs = tsk->fs;
+
+	if (fs) {
+		tsk->fs = NULL;
+		if (!--fs->count) {
+			iput(fs->root);
+			iput(fs->pwd);
+			kfree(fs);
+		}
 	}
 }
 
-static void exit_mm(void)
+void exit_sighand(struct task_struct *tsk)
 {
-	if (!--current->mm->count) {
-		current->mm->rss = 0;
-		exit_mmap(current->mm);
+	struct signal_struct * sig = tsk->sig;
+
+	if (sig) {
+		tsk->sig = NULL;
+		if (!--sig->count) {
+			kfree(sig);
+		}
 	}
-	free_page_tables(current);
 }
 
-NORET_TYPE void do_exit(long code)
+static void exit_mm(void)
 {
-	struct task_struct *p;
+	struct mm_struct * mm = current->mm;
 
-	if (intr_count) {
-		printk("Aiee, killing interrupt handler\n");
-		intr_count = 0;
+	if (mm) {
+		if (!--mm->count) {
+			current->p_pptr->mm->cmin_flt += mm->min_flt + mm->cmin_flt;
+			current->p_pptr->mm->cmaj_flt += mm->maj_flt + mm->cmaj_flt;
+			exit_mmap(mm);
+			free_page_tables(current);
+			kfree(mm);
+		}
+		current->mm = NULL;
 	}
-fake_volatile:
-	current->flags |= PF_EXITING;
-	del_timer(&current->real_timer);
-	sem_exit();
-	exit_mm();
-	exit_files();
-	exit_fs();
-	exit_thread();
+}
+
+/* 
+ * Send signals to all our closest relatives so that they know
+ * to properly mourn us..
+ */
+static void exit_notify(void)
+{
+	struct task_struct * p;
+
 	forget_original_parent(current);
 	/* 
 	 * Check to see if any process groups have become orphaned
@@ -413,7 +434,7 @@
 	 * Case i: Our father is in a different pgrp than we are
 	 * and we were the only connection outside, so our pgrp
 	 * is about to become orphaned.
- 	 */
+	 */
 	if ((current->p_pptr->pgrp != current->pgrp) &&
 	    (current->p_pptr->session == current->session) &&
 	    is_orphaned_pgrp(current->pgrp) &&
@@ -461,8 +482,24 @@
 	}
 	if (current->leader)
 		disassociate_ctty(1);
-	if (last_task_used_math == current)
-		last_task_used_math = NULL;
+}
+
+NORET_TYPE void do_exit(long code)
+{
+	if (intr_count) {
+		printk("Aiee, killing interrupt handler\n");
+		intr_count = 0;
+	}
+fake_volatile:
+	current->flags |= PF_EXITING;
+	del_timer(&current->real_timer);
+	sem_exit();
+	exit_mm();
+	exit_files(current);
+	exit_fs(current);
+	exit_sighand(current);
+	exit_thread();
+	exit_notify();
 	current->state = TASK_ZOMBIE;
 	current->exit_code = code;
 #ifdef DEBUG_PROC_TREE
@@ -540,8 +577,6 @@
 			case TASK_ZOMBIE:
 				current->cutime += p->utime + p->cutime;
 				current->cstime += p->stime + p->cstime;
-				current->mm->cmin_flt += p->mm->min_flt + p->mm->cmin_flt;
-				current->mm->cmaj_flt += p->mm->maj_flt + p->mm->cmaj_flt;
 				if (ru != NULL)
 					getrusage(p, RUSAGE_BOTH, ru);
 				flag = p->pid;
diff -u --recursive --new-file v1.3.25/linux/kernel/fork.c linux/kernel/fork.c
--- v1.3.25/linux/kernel/fork.c	Sat Sep  9 15:26:53 1995
+++ linux/kernel/fork.c	Tue Sep 12 09:26:08 1995
@@ -23,25 +23,7 @@
 
 #include <asm/segment.h>
 #include <asm/system.h>
-
-/*
- * This is how a process data structure is allocated. In most
- * cases, the "tsk" pointers point to the same allocation unit
- * substructures, but if the new process shares part (or all)
- * of the sub-units with the parent process, the tsk pointers
- * may point to the parent instead.
- *
- * Regardless, we always allocate the full allocation unit, as
- * the normal fork() semantics require all of them and doing
- * suballocations would be wasteful.
- */
-struct allocation_struct {
-	struct task_struct tsk;
-	struct sigaction sigaction[32];
-	struct fs_struct fs;
-	struct files_struct files;
-	struct mm_struct mm;
-};
+#include <asm/pgtable.h>
 
 int nr_tasks=1;
 int nr_running=1;
@@ -103,6 +85,10 @@
 		}
 		if (tmp->vm_ops && tmp->vm_ops->open)
 			tmp->vm_ops->open(tmp);
+		if (copy_page_range(mm, current->mm, tmp)) {
+			exit_mmap(mm);
+			return -ENOMEM;
+		}
 		*p = tmp;
 		p = &tmp->vm_next;
 	}
@@ -110,74 +96,82 @@
 	return 0;
 }
 
-static int copy_mm(unsigned long clone_flags, struct allocation_struct * u)
+static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
 	if (clone_flags & CLONE_VM) {
-		if (clone_page_tables(&u->tsk))
-			return -1;
+		SET_PAGE_DIR(tsk, current->mm->pgd);
 		current->mm->count++;
-		mem_map[MAP_NR(current->mm)]++;
 		return 0;
 	}
-	u->tsk.mm = &u->mm;
-	u->mm = *current->mm;
-	u->mm.count = 1;
-	u->mm.min_flt = u->mm.maj_flt = 0;
-	u->mm.cmin_flt = u->mm.cmaj_flt = 0;
-	if (copy_page_tables(&u->tsk))
+	tsk->mm = kmalloc(sizeof(*tsk->mm), GFP_KERNEL);
+	if (!tsk->mm)
+		return -1;
+	*tsk->mm = *current->mm;
+	tsk->mm->count = 1;
+	tsk->mm->min_flt = tsk->mm->maj_flt = 0;
+	tsk->mm->cmin_flt = tsk->mm->cmaj_flt = 0;
+	if (new_page_tables(tsk))
 		return -1;
-	if (dup_mmap(&u->mm))
+	if (dup_mmap(tsk->mm)) {
+		free_page_tables(tsk);
 		return -1;
-	mem_map[MAP_NR(u)]++;
+	}
 	return 0;
 }
 
-static void copy_fs(unsigned long clone_flags, struct allocation_struct * u)
+static int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
 {
 	if (clone_flags & CLONE_FS) {
 		current->fs->count++;
-		mem_map[MAP_NR(current->fs)]++;
-		return;
+		return 0;
 	}
-	u->tsk.fs = &u->fs;
-	u->fs = *current->fs;
-	u->fs.count = 1;
-	if (u->fs.pwd)
-		u->fs.pwd->i_count++;
-	if (u->fs.root)
-		u->fs.root->i_count++;
-	mem_map[MAP_NR(u)]++;
+	tsk->fs = kmalloc(sizeof(*tsk->fs), GFP_KERNEL);
+	if (!tsk->fs)
+		return -1;
+	tsk->fs->count = 1;
+	tsk->fs->umask = current->fs->umask;
+	if ((tsk->fs->root = current->fs->root))
+		tsk->fs->root->i_count++;
+	if ((tsk->fs->pwd = current->fs->pwd))
+		tsk->fs->pwd->i_count++;
+	return 0;
 }
 
-static void copy_files(unsigned long clone_flags, struct allocation_struct * u)
+static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
 {
 	int i;
 
 	if (clone_flags & CLONE_FILES) {
 		current->files->count++;
-		mem_map[MAP_NR(current->files)]++;
-		return;
+		return 0;
 	}
-	u->tsk.files = &u->files;
-	u->files = *current->files;
-	u->files.count = 1;
+	tsk->files = kmalloc(sizeof(*tsk->files), GFP_KERNEL);
+	if (!tsk->files)
+		return -1;
+	tsk->files->count = 1;
+	memcpy(&tsk->files->close_on_exec, &current->files->close_on_exec,
+		sizeof(tsk->files->close_on_exec));
 	for (i = 0; i < NR_OPEN; i++) {
-		struct file * f = u->files.fd[i];
+		struct file * f = current->files->fd[i];
 		if (f)
 			f->f_count++;
+		tsk->files->fd[i] = f;
 	}
-	mem_map[MAP_NR(u)]++;
+	return 0;
 }
 
-static void copy_sighand(unsigned long clone_flags, struct allocation_struct * u)
+static int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
 {
 	if (clone_flags & CLONE_SIGHAND) {
-		mem_map[MAP_NR(current->sigaction)]++;
-		return;
+		current->sig->count++;
+		return 0;
 	}
-	u->tsk.sigaction = u->sigaction;
-	memcpy(u->sigaction, current->sigaction, sizeof(u->sigaction));
-	mem_map[MAP_NR(u)]++;
+	tsk->sig = kmalloc(sizeof(*tsk->sig), GFP_KERNEL);
+	if (!tsk->sig)
+		return -1;
+	tsk->sig->count = 1;
+	memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
+	return 0;
 }
 
 /*
@@ -191,12 +185,10 @@
 	int error = -ENOMEM;
 	unsigned long new_stack;
 	struct task_struct *p;
-	struct allocation_struct *alloc;
 
-	alloc = (struct allocation_struct *) __get_free_page(GFP_KERNEL);
-	if (!alloc)
+	p = (struct task_struct *) kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
 		goto bad_fork;
-	p = &alloc->tsk;
 	new_stack = get_free_page(GFP_KERNEL);
 	if (!new_stack)
 		goto bad_fork_free;
@@ -238,13 +230,16 @@
 
 	error = -ENOMEM;
 	/* copy all the process information */
-	copy_thread(nr, clone_flags, usp, p, regs);
-	if (copy_mm(clone_flags, alloc))
+	if (copy_files(clone_flags, p))
 		goto bad_fork_cleanup;
+	if (copy_fs(clone_flags, p))
+		goto bad_fork_cleanup_files;
+	if (copy_sighand(clone_flags, p))
+		goto bad_fork_cleanup_fs;
+	if (copy_mm(clone_flags, p))
+		goto bad_fork_cleanup_sighand;
+	copy_thread(nr, clone_flags, usp, p, regs);
 	p->semundo = NULL;
-	copy_files(clone_flags, alloc);
-	copy_fs(clone_flags, alloc);
-	copy_sighand(clone_flags, alloc);
 
 	/* ok, now we should be set up.. */
 	p->mm->swappable = 1;
@@ -253,6 +248,12 @@
 	wake_up_process(p);			/* do this last, just in case */
 	return p->pid;
 
+bad_fork_cleanup_sighand:
+	exit_sighand(p);
+bad_fork_cleanup_fs:
+	exit_fs(p);
+bad_fork_cleanup_files:
+	exit_files(p);
 bad_fork_cleanup:
 	if (p->exec_domain && p->exec_domain->use_count)
 		(*p->exec_domain->use_count)--;
@@ -263,7 +264,7 @@
 	nr_tasks--;
 bad_fork_free:
 	free_page(new_stack);
-	free_page((long) p);
+	kfree(p);
 bad_fork:
 	return error;
 }
diff -u --recursive --new-file v1.3.25/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.25/linux/kernel/ksyms.c	Sun Sep  3 12:27:03 1995
+++ linux/kernel/ksyms.c	Mon Sep 11 21:09:22 1995
@@ -33,8 +33,12 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/config.h>
+#include <linux/sem.h>
+#include <linux/minix_fs.h>
+#include <linux/ext2_fs.h>
 
 #ifdef CONFIG_NET
+#include <linux/in.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #ifdef CONFIG_INET
@@ -42,6 +46,8 @@
 #include <linux/etherdevice.h>
 #include <net/protocol.h>
 #include <net/arp.h>
+#include <net/ip.h>
+#include <net/udp.h>
 #include <net/tcp.h>
 #include <net/route.h>
 #if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
@@ -96,7 +102,6 @@
 extern void free_dma(unsigned int dmanr);
 extern int (*rarp_ioctl_hook)(int,void*);
 
-extern int close_fp(struct file *filp);
 extern void (* iABI_hook)(struct pt_regs * regs);
 
 struct symbol_table symbol_table = {
@@ -315,6 +320,9 @@
 	X(init_etherdev),
 	X(ip_rt_route),
 	X(arp_send),
+#ifdef CONFIG_IP_FORWARD
+	X(ip_forward),
+#endif
 #if defined(CONFIG_PPP) || defined(CONFIG_SLIP)
     	/* VJ header compression */
 	X(slhc_init),
@@ -459,6 +467,8 @@
 #ifdef CONFIG_PROC_FS
 	X(proc_register),
 	X(proc_unregister),
+	X(in_group_p),
+	X(generate_cluster),
 #endif
 	/********************************************************
 	 * Do not add anything below this line,
diff -u --recursive --new-file v1.3.25/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.25/linux/kernel/sched.c	Sat Sep  9 15:26:53 1995
+++ linux/kernel/sched.c	Wed Sep 13 10:08:39 1995
@@ -84,7 +84,7 @@
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct sigaction init_sigaction[32] = { {0,}, };
+static struct signal_struct init_signals = INIT_SIGNALS;
 
 struct mm_struct init_mm = INIT_MM;
 struct task_struct init_task = INIT_TASK;
@@ -667,10 +667,11 @@
 			kstat.cpu_system++;
 		if (prof_buffer && current != task[0]) {
 			extern int _stext;
-			unsigned long eip = regs->eip - (unsigned long) &_stext;
-			eip >>= prof_shift;
-			if (eip < prof_len)
-				prof_buffer[eip]++;
+			unsigned long ip = instruction_pointer(regs);
+			ip -= (unsigned long) &_stext;
+			ip >>= prof_shift;
+			if (ip < prof_len)
+				prof_buffer[ip]++;
 		}
 	}
 	/*
diff -u --recursive --new-file v1.3.25/linux/kernel/signal.c linux/kernel/signal.c
--- v1.3.25/linux/kernel/signal.c	Tue Jul 11 10:03:00 1995
+++ linux/kernel/signal.c	Mon Sep 11 14:40:15 1995
@@ -94,7 +94,7 @@
 {
 	struct sigaction *p;
 
-	p = signum - 1 + current->sigaction;
+	p = signum - 1 + current->sig->action;
 	if (p->sa_handler == SIG_IGN) {
 		if (signum == SIGCHLD)
 			return;
@@ -126,8 +126,8 @@
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.sa_handler = handler;
 	tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
-	handler = current->sigaction[signum-1].sa_handler;
-	current->sigaction[signum-1] = tmp;
+	handler = current->sig->action[signum-1].sa_handler;
+	current->sig->action[signum-1] = tmp;
 	check_pending(signum);
 	return (unsigned long) handler;
 }
@@ -141,7 +141,7 @@
 		return -EINVAL;
 	if (signum==SIGKILL || signum==SIGSTOP)
 		return -EINVAL;
-	p = signum - 1 + current->sigaction;
+	p = signum - 1 + current->sig->action;
 	if (action) {
 		int err = verify_area(VERIFY_READ, action, sizeof(*action));
 		if (err)
diff -u --recursive --new-file v1.3.25/linux/mm/memory.c linux/mm/memory.c
--- v1.3.25/linux/mm/memory.c	Sat Sep  9 15:26:53 1995
+++ linux/mm/memory.c	Tue Sep 12 13:18:05 1995
@@ -73,29 +73,17 @@
 void oom(struct task_struct * task)
 {
 	printk("\nOut of memory for %s.\n", current->comm);
-	task->sigaction[SIGKILL-1].sa_handler = NULL;
+	task->sig->action[SIGKILL-1].sa_handler = NULL;
 	task->blocked &= ~(1<<(SIGKILL-1));
 	send_sig(SIGKILL,task,1);
 }
 
-static inline void free_one_pte(pte_t * page_table)
-{
-	pte_t page = *page_table;
-
-	if (pte_none(page))
-		return;
-	pte_clear(page_table);
-	if (!pte_present(page)) {
-		swap_free(pte_val(page));
-		return;
-	}
-	free_page(pte_page(page));
-	return;
-}
-
+/*
+ * Note: this doesn't free the actual pages themselves. That
+ * has been handled earlier when unmapping all the memory regions.
+ */
 static inline void free_one_pmd(pmd_t * dir)
 {
-	int j;
 	pte_t * pte;
 
 	if (pmd_none(*dir))
@@ -107,12 +95,6 @@
 	}
 	pte = pte_offset(dir, 0);
 	pmd_clear(dir);
-	if (pte_inuse(pte)) {
-		pte_free(pte);
-		return;
-	}
-	for (j = 0; j < PTRS_PER_PTE ; j++)
-		free_one_pte(pte+j);
 	pte_free(pte);
 }
 
@@ -137,6 +119,20 @@
 	pmd_free(pmd);
 }
 	
+int new_page_tables(struct task_struct * tsk)
+{
+	pgd_t * page_dir, * new_pg;
+	int i;
+
+	if (!(new_pg = pgd_alloc()))
+		return -ENOMEM;
+	page_dir = pgd_offset(&init_mm, 0);
+	for (i = USER_PTRS_PER_PGD ; i < PTRS_PER_PGD ; i++)
+		new_pg[i] = page_dir[i];
+	SET_PAGE_DIR(tsk, new_pg);
+	tsk->mm->pgd = new_pg;
+	return 0;
+}
 
 /*
  * This function clears all user-level page tables of a process - this
@@ -155,24 +151,20 @@
 	if (tsk == task[0])
 		panic("task[0] (swapper) doesn't support exec()\n");
 	page_dir = pgd_offset(tsk->mm, 0);
-	if (!page_dir || page_dir == swapper_pg_dir) {
-		printk("%s trying to clear kernel page-directory: not good\n", tsk->comm);
+	if (!page_dir) {
+		printk("%s trying to clear NULL page-directory: not good\n", tsk->comm);
 		return;
 	}
 	if (pgd_inuse(page_dir)) {
-		pgd_t * new_pg;
-
-		if (!(new_pg = pgd_alloc())) {
+		if (new_page_tables(tsk))
 			oom(tsk);
-			return;
-		}
-		for (i = USER_PTRS_PER_PGD ; i < PTRS_PER_PGD ; i++)
-			new_pg[i] = page_dir[i];
-		SET_PAGE_DIR(tsk, new_pg);
-		tsk->mm->pgd = new_pg;
 		pgd_free(page_dir);
 		return;
 	}
+	if (page_dir == swapper_pg_dir) {
+		printk("%s trying to clear kernel page-directory: not good\n", tsk->comm);
+		return;
+	}
 	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
 		free_one_pgd(page_dir + i);
 	invalidate();
@@ -187,13 +179,7 @@
 	int i;
 	pgd_t * page_dir;
 
-	if (!tsk)
-		return;
-	if (tsk == task[0]) {
-		printk("task[0] (swapper) killed: unable to recover\n");
-		panic("Trying to free up swapper memory space");
-	}
-	page_dir = pgd_offset(tsk->mm, 0);
+	page_dir = tsk->mm->pgd;
 	if (!page_dir || page_dir == swapper_pg_dir) {
 		printk("%s trying to free kernel page-directory: not good\n", tsk->comm);
 		return;
@@ -210,23 +196,6 @@
 	invalidate();
 }
 
-/*
- * clone_page_tables() clones the page table for a process - both
- * processes will have the exact same pages in memory. There are
- * probably races in the memory management with cloning, but we'll
- * see..
- */
-int clone_page_tables(struct task_struct * tsk)
-{
-	pgd_t * pg_dir;
-
-	pg_dir = pgd_offset(current->mm, 0);
-	pgd_reuse(pg_dir);
-	SET_PAGE_DIR(tsk, pg_dir);
-	tsk->mm->pgd = pg_dir;
-	return 0;
-}
-
 static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte)
 {
 	pte_t pte = *old_pte;
@@ -251,95 +220,93 @@
 	mem_map[MAP_NR(pte_page(pte))]++;
 }
 
-static inline int copy_one_pmd(pmd_t * old_pmd, pmd_t * new_pmd)
+static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long address, unsigned long size)
 {
-	int j;
-	pte_t *old_pte, *new_pte;
+	pte_t * src_pte, * dst_pte;
+	unsigned long end;
 
-	if (pmd_none(*old_pmd))
+	if (pmd_none(*src_pmd))
 		return 0;
-	if (pmd_bad(*old_pmd)) {
-		printk("copy_one_pmd: bad page table (%08lx): probable memory corruption\n", pmd_val(*old_pmd));
-		pmd_clear(old_pmd);
+	if (pmd_bad(*src_pmd)) {
+		printk("copy_pte_range: bad pmd (%08lx)\n", pmd_val(*src_pmd));
+		pmd_clear(src_pmd);
 		return 0;
 	}
-	old_pte = pte_offset(old_pmd, 0);
-	if (pte_inuse(old_pte)) {
-		pte_reuse(old_pte);
-		*new_pmd = *old_pmd;
-		return 0;
-	}
-	new_pte = pte_alloc(new_pmd, 0);
-	if (!new_pte)
-		return -ENOMEM;
-	for (j = 0 ; j < PTRS_PER_PTE ; j++) {
-		copy_one_pte(old_pte, new_pte);
-		old_pte++;
-		new_pte++;
+	src_pte = pte_offset(src_pmd, address);
+	if (pmd_none(*dst_pmd)) {
+		if (!pte_alloc(dst_pmd, 0))
+			return -ENOMEM;
 	}
+	dst_pte = pte_offset(dst_pmd, address);
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end >= PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		/* I would like to switch arguments here, to make it
+		 * consistent with copy_xxx_range and memcpy syntax.
+		 */
+		copy_one_pte(src_pte++, dst_pte++);
+		address += PAGE_SIZE;
+	} while (address < end);
 	return 0;
 }
 
-static inline int copy_one_pgd(pgd_t * old_pgd, pgd_t * new_pgd)
+static inline int copy_pmd_range(pgd_t *dst_pgd, pgd_t *src_pgd, unsigned long address, unsigned long size)
 {
-	int j;
-	pmd_t *old_pmd, *new_pmd;
+	pmd_t * src_pmd, * dst_pmd;
+	unsigned long end;
+	int error = 0;
 
-	if (pgd_none(*old_pgd))
+	if (pgd_none(*src_pgd))
 		return 0;
-	if (pgd_bad(*old_pgd)) {
-		printk("copy_one_pgd: bad page table (%p: %08lx): probable memory corruption\n", old_pgd, pgd_val(*old_pgd));
-		pgd_clear(old_pgd);
+	if (pgd_bad(*src_pgd)) {
+		printk("copy_pmd_range: bad pgd (%08lx)\n", pgd_val(*src_pgd));
+		pgd_clear(src_pgd);
 		return 0;
 	}
-	old_pmd = pmd_offset(old_pgd, 0);
-	if (pmd_inuse(old_pmd)) {
-		pmd_reuse(old_pmd);
-		*new_pgd = *old_pgd;
-		return 0;
+	src_pmd = pmd_offset(src_pgd, address);
+	if (pgd_none(*dst_pgd)) {
+		if (!pmd_alloc(dst_pgd, 0))
+			return -ENOMEM;
 	}
-	new_pmd = pmd_alloc(new_pgd, 0);
-	if (!new_pmd)
-		return -ENOMEM;
-	for (j = 0 ; j < PTRS_PER_PMD ; j++) {
-		int error = copy_one_pmd(old_pmd, new_pmd);
+	dst_pmd = pmd_offset(dst_pgd, address);
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	do {
+		error = copy_pte_range(dst_pmd++, src_pmd++, address, end - address);
 		if (error)
-			return error;
-		old_pmd++;
-		new_pmd++;
-	}
-	return 0;
+			break;
+		address = (address + PMD_SIZE) & PMD_MASK; 
+	} while (address < end);
+	return error;
 }
 
 /*
- * copy_page_tables() just copies the whole process memory range:
- * note the special handling of RESERVED (ie kernel) pages, which
- * means that they are always shared by all processes.
+ * copy one vm_area from one task to the other. Assumes the page tables
+ * already present in the new task to be cleared in the whole range
+ * covered by this vma.
  */
-int copy_page_tables(struct task_struct * tsk)
+int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
+			struct vm_area_struct *vma)
 {
-	int i;
-	pgd_t *old_pgd;
-	pgd_t *new_pgd;
+	pgd_t * src_pgd, * dst_pgd;
+	unsigned long address = vma->vm_start;
+	unsigned long end = vma->vm_end;
+	int error = 0;
 
-	new_pgd = pgd_alloc();
-	if (!new_pgd)
-		return -ENOMEM;
-	SET_PAGE_DIR(tsk, new_pgd);
-	tsk->mm->pgd = new_pgd;
-	old_pgd = pgd_offset(current->mm, 0);
-	for (i = 0 ; i < PTRS_PER_PGD ; i++) {
-		int errno = copy_one_pgd(old_pgd, new_pgd);
-		if (errno) {
-			free_page_tables(tsk);
-			invalidate();
-			return errno;
-		}
-		old_pgd++;
-		new_pgd++;
+	src_pgd = pgd_offset(src, address);
+	dst_pgd = pgd_offset(dst, address);
+	while (address < end) {
+		error = copy_pmd_range(dst_pgd++, src_pgd++, address, end - address);
+		if (error)
+			break;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 	}
 	invalidate();
-	return 0;
+	return error;
 }
 
 static inline void forget_pte(pte_t page)
@@ -409,15 +376,14 @@
 }
 
 /*
- * a more complete version of free_page_tables which performs with page
- * granularity.
+ * remove user pages in a given range.
  */
-int unmap_page_range(unsigned long address, unsigned long size)
+int zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
 {
 	pgd_t * dir;
 	unsigned long end = address + size;
 
-	dir = pgd_offset(current->mm, address);
+	dir = pgd_offset(mm, address);
 	while (address < end) {
 		unmap_pmd_range(dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -425,6 +391,15 @@
 	}
 	invalidate();
 	return 0;
+}
+
+/*
+ * a more complete version of free_page_tables which performs with page
+ * granularity.
+ */
+int unmap_page_range(unsigned long address, unsigned long size)
+{
+	return zap_page_range(current->mm, address, size);
 }
 
 static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte)
diff -u --recursive --new-file v1.3.25/linux/mm/mmap.c linux/mm/mmap.c
--- v1.3.25/linux/mm/mmap.c	Thu Sep  7 17:17:20 1995
+++ linux/mm/mmap.c	Tue Sep 12 12:49:48 1995
@@ -231,6 +231,8 @@
 #if 0 /* equivalent, but slow */
 	struct vm_area_struct * vma;
 
+	if (!task->mm)
+		return NULL;
 	for (vma = task->mm->mmap ; ; vma = vma->vm_next) {
 		if (!vma)
 			return NULL;
@@ -241,6 +243,8 @@
 	struct vm_area_struct * result = NULL;
 	struct vm_area_struct * tree;
 
+	if (!task->mm)
+		return NULL;
 	for (tree = task->mm->mmap_avl ; ; ) {
 		if (tree == avl_empty)
 			return result;
@@ -798,6 +802,7 @@
 		remove_shared_vm_struct(mpnt);
 		if (mpnt->vm_inode)
 			iput(mpnt->vm_inode);
+		zap_page_range(mm, mpnt->vm_start, mpnt->vm_end-mpnt->vm_start);
 		kfree(mpnt);
 		mpnt = next;
 	}
diff -u --recursive --new-file v1.3.25/linux/mm/swap.c linux/mm/swap.c
--- v1.3.25/linux/mm/swap.c	Thu Sep  7 17:17:20 1995
+++ linux/mm/swap.c	Tue Sep 12 09:26:57 1995
@@ -578,7 +578,7 @@
 			}
 
 			p = task[swap_task];
-			if (p && p->mm->swappable && p->mm->rss)
+			if (p && p->mm && p->mm->swappable && p->mm->rss)
 				break;
 
 			swap_task++;
diff -u --recursive --new-file v1.3.25/linux/net/Changes linux/net/Changes
--- v1.3.25/linux/net/Changes	Sat Sep  9 15:26:53 1995
+++ linux/net/Changes	Mon Sep 11 20:27:48 1995
@@ -203,7 +203,27 @@
 o	Closing socket change (Marc Tamsky)		[IN]
 o	RFC1122 verification of tcp.c <Mike Shaver>	[IN]
 
----------- Things Linus had for a while and not merged ----------------
+-------->>>>> 1.3.26 <<<<<-------
+
+o	Rewrote ICMP completely				[TESTED -
+							 fragmenting is wrong]
+o	Moved most IP addresses to __u32		[IN]
+o	Cleaned up ICMP reporting			[IN]
+o	Tidied remove_sock				[IN]
+o	Added memory allocation type to ip_build_xmit	[IN]
+o	Cleaned up af_inet to use inet_error		[IN]
+o	Named firewall returns				[IN]
+o	Added firewall output checks to ip_build_xmit	[IN]
+o	Multicast router downs VIF's when their
+	physical interface is dropped			[IN]
+o	Reformatted ipv4/protocol.c, dropped frag field	[IN]
+o	Fixed MSS for TCP				[IN]
+o	Dropped sock_awaitconn				[IN]
+o	Added ip_forward to ksyms for IPIP etc		[IN]
+o	Appletalk TIOCINQ/TIOCOUTQ bug fix		[IN]
+o	Rewrote the IFF_UP/IFF_DOWN handling code	[IN]
+
+---------- Things I thought Linus had for a while and not merged ----------------
 
 o	Paul Gortmakers 8390 Copy and checksum		[PLEASE ADD 8)]
 
@@ -222,6 +242,7 @@
 
 --------------- Tbings That Need Doing Before 1.4 ------------------
 
+o	inet_error for other layers
 o	Finish merging the bridge code
 o	SIOCSLEEPRT patch
 o	Options support in ip_build_xmit		[PENDING]
@@ -239,8 +260,8 @@
 o	Full variable length AX.25 support		[JSN doing]
 o	Tidy BPQ support to use a bpqip tunnel device
 o	Strange eth0-eth3 bug 
-o	Finish IPIP bug fixes
-o	Why doesnt the PROTO_UNREACH get sent ?
+o	Finish IPIP bug fixes				[Done hopefully]
+o	Why doesnt the PROTO_UNREACH get sent ?		[Should now work]
 o	IP protocols using sendmsg()
 o	Kill off old ip_queue_xmit/ip_send stuff.
 o	Remove kernel RARP and replace with user mode daemon.
@@ -248,7 +269,7 @@
 
 0.2
 ---
-o	New icmp.c.
+o	New icmp.c.					[IN]
 o	Better TCP window handling [Pedro Roque]
 o	IP option support.
 o	Add tty support to sonix driver.
diff -u --recursive --new-file v1.3.25/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.25/linux/net/appletalk/ddp.c	Thu Sep  7 17:17:20 1995
+++ linux/net/appletalk/ddp.c	Mon Sep 11 20:15:58 1995
@@ -1071,6 +1071,7 @@
 	sk->next=NULL;
 	sk->broadcast=0;
 	sk->no_check=0;		/* Checksums on by default */
+	sk->allocation=GFP_KERNEL;
 	sk->rcvbuf=SK_RMEM_MAX;
 	sk->sndbuf=SK_WMEM_MAX;
 	sk->pair=NULL;
@@ -1774,7 +1775,6 @@
 	int err;
 	long amount=0;
 	atalk_socket *sk=(atalk_socket *)sock->data;
-	int v;
 	
 	switch(cmd)
 	{
@@ -1782,16 +1782,16 @@
 		 *	Protocol layer
 		 */
 		case TIOCOUTQ:
-			v=sk->sndbuf-sk->wmem_alloc;
-			if(v<0)
-				v=0;
+			amount=sk->sndbuf-sk->wmem_alloc;
+			if(amount<0)
+				amount=0;
 			break;
 		case TIOCINQ:
 		{
 			struct sk_buff *skb;
 			/* These two are safe on a single CPU system as only user tasks fiddle here */
 			if((skb=skb_peek(&sk->receive_queue))!=NULL)
-				v=skb->len-sizeof(struct ddpehdr);
+				amount=skb->len-sizeof(struct ddpehdr);
 			break;
 		}
 		case SIOCGSTAMP:
@@ -1921,6 +1921,6 @@
 		atalk_if_get_info
 	});
 
-	printk("Appletalk BETA 0.12 for Linux NET3.030\n");
+	printk("Appletalk BETA 0.13 for Linux NET3.031\n");
 }
 #endif
diff -u --recursive --new-file v1.3.25/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.25/linux/net/ax25/af_ax25.c	Sat Sep  9 15:26:53 1995
+++ linux/net/ax25/af_ax25.c	Mon Sep 11 20:15:58 1995
@@ -886,6 +886,7 @@
 	sk->dead          = 0;
 	sk->next          = NULL;
 	sk->broadcast     = 0;
+	sk->allocation	  = GFP_KERNEL;
 	sk->rcvbuf        = SK_RMEM_MAX;
 	sk->sndbuf        = SK_WMEM_MAX;
 	sk->wmem_alloc    = 0;
@@ -2171,7 +2172,7 @@
 		ax25_cs_get_info
 	});
 
-	printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.30 ALPHA for Linux NET3.030 (Linux 1.3.20)\n");
+	printk("G4KLX/GW4PTS AX.25 for Linux. Version 0.30 ALPHA for Linux NET3.031 (Linux 1.3.25)\n");
 }
 
 /*
diff -u --recursive --new-file v1.3.25/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.25/linux/net/core/dev.c	Sat Sep  9 15:26:53 1995
+++ linux/net/core/dev.c	Mon Sep 11 20:31:04 1995
@@ -119,7 +119,7 @@
  
 static __inline__ unsigned long min(unsigned long a, unsigned long b)
 {
-  return (a < b)? a : b;
+	return (a < b)? a : b;
 }
 
 
@@ -256,10 +256,15 @@
 	 *	Call the device specific close. This cannot fail.
 	 *	Only if device is UP
 	 */
+	 
 	if ((dev->flags & IFF_UP) && dev->stop)
 		dev->stop(dev);
 
-	dev->flags = 0;
+	/*
+	 *	Device is now down.
+	 */
+	 
+	dev->flags&=~(IFF_UP|IFF_RUNNING);
 
 	/*
 	 *	Tell people we are going down
@@ -1008,11 +1013,15 @@
 				
 				dev_lock_wait();
 				
-				dev->flags = ifr.ifr_flags & (
-					IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
+				/*
+				 *	Set the flags on our device.
+				 */
+				 
+				dev->flags = (ifr.ifr_flags & (
+					IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
 					IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
 					IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER
-					| IFF_MULTICAST);
+					| IFF_MULTICAST)) | (dev->flags & IFF_UP);
 				/*
 				 *	Load in the correct multicast list now the flags have changed.
 				 */				
@@ -1020,32 +1029,29 @@
 				dev_mc_upload(dev);
 
 			  	/*
-			  	 *	Have we downed the interface
+			  	 *	Have we downed the interface. We handle IFF_UP ourselves
+			  	 *	according to user attempts to set it, rather than blindly
+			  	 *	setting it.
 			  	 */
-		
-				if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) 
-				{
-					/*
-					 *	Restore IFF_UP so dev_close knows to shut
-					 *	it down. FIXME: Tidy me up sometime.
-					 */
-					dev->flags|=IFF_UP;
-					ret = dev_close(dev);
-				}
-				else
-				{
-					/*
-					 *	Have we upped the interface 
-					 */
-					 
-			      		ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
-						? dev_open(dev) : 0;
-					/* 
-					 *	Check the flags.
-					 */
-					if(ret<0)
-						dev->flags&=~IFF_UP;	/* Didn't open so down the if */
+			  	 
+			  	if ((old_flags^ifr.ifr_flags)&IFF_UP)	/* Bit is different  ? */
+			  	{
+					if(old_flags&IFF_UP)		/* Gone down */
+						ret=dev_close(dev); 		
+					else				/* Come up */
+					{
+						ret=dev_open(dev);
+						if(ret<0)
+							dev->flags&=~IFF_UP;	/* Open failed */
+					}	
 			  	}
+			  	else
+			  		ret=0;
+				/*
+				 *	Load in the correct multicast list now the flags have changed.
+				 */				
+
+				dev_mc_upload(dev);
 	        	}
 			break;
 		
diff -u --recursive --new-file v1.3.25/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c
--- v1.3.25/linux/net/core/dev_mcast.c	Tue Jun  6 12:16:43 1995
+++ linux/net/core/dev_mcast.c	Mon Sep 11 20:16:03 1995
@@ -11,6 +11,7 @@
  *	Fixes:
  *		Alan Cox	:	Update the device on a real delete
  *					rather than any time but...
+ *		Alan Cox	:	IFF_ALLMULTI support.
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -70,21 +71,48 @@
 		return;
 		
 		
-	/* Devices with no set multicast don't get set */
+	/*
+	 *	Devices with no set multicast don't get set 
+	 */
+	 
 	if(dev->set_multicast_list==NULL)
 		return;
-	/* Promiscuous is promiscuous - so no filter needed */
+		
+	/*
+	 *	Promiscuous is promiscuous - so no filter needed 
+	 */
+	 
 	if(dev->flags&IFF_PROMISC)
 	{
 		dev->set_multicast_list(dev, -1, NULL);
 		return;
 	}
 	
+	/*
+	 *	All multicasts. Older cards will interpret this as
+	 * 	promisc mode, which is the next best thing.
+	 */
+	
+	if(dev->flags&IFF_ALLMULTI)
+	{
+		dev->set_multicast_list(dev, -2, NULL);
+		return;
+	}
+	
+	/*
+	 *	No multicasts
+	 */
+	
 	if(dev->mc_count==0)
 	{
 		dev->set_multicast_list(dev,0,NULL);
 		return;
 	}
+	
+	/*
+	 *	The drivers need changing to process the list themselves... this is
+	 *	a mess.
+	 */
 	
 	data=kmalloc(dev->mc_count*dev->addr_len, GFP_KERNEL);
 	if(data==NULL)
diff -u --recursive --new-file v1.3.25/linux/net/core/sock.c linux/net/core/sock.c
--- v1.3.25/linux/net/core/sock.c	Thu Sep  7 17:17:20 1995
+++ linux/net/core/sock.c	Mon Sep 11 20:16:03 1995
@@ -65,6 +65,7 @@
  *		Alan Cox	:	Allow anyone to clear SO_DEBUG
  *					(compatibility fix)
  *		Alan Cox	:	Added optimistic memory grabbing for AF_UNIX throughput.
+ *		Alan Cox	:	Allocator for a socket is settable.
  *
  * To Fix:
  *
@@ -448,7 +449,7 @@
 		}
 		
 		if(!fallback)
-			skb = sock_wmalloc(sk, size, 0, GFP_KERNEL);
+			skb = sock_wmalloc(sk, size, 0, sk->allocation);
 		else
 		{
 			/* The buffer get won't block, or use the atomic queue. It does
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.25/linux/net/ipv4/af_inet.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/af_inet.c	Mon Sep 11 21:30:09 1995
@@ -247,7 +247,7 @@
 
 static void remove_sock(struct sock *sk1)
 {
-	struct sock *sk2;
+	struct sock **p;
 	unsigned long flags;
 
 	if (sk1->type==SOCK_PACKET)
@@ -262,26 +262,18 @@
 	/* We can't have this changing out from under us. */
 	save_flags(flags);
 	cli();
-	sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
-	if (sk2 == sk1) 
-	{
-		sk1->prot->inuse -= 1;
-		sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
-		restore_flags(flags);
-		return;
-	}
-
-	while(sk2 && sk2->next != sk1) 
-	{
-		sk2 = sk2->next;
-	}
-
-	if (sk2) 
+	
+	p=&(sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)]);
+	
+	while(*p!=NULL)
 	{
-		sk1->prot->inuse -= 1;
-		sk2->next = sk1->next;
-		restore_flags(flags);
-		return;
+		if(*p==sk1)
+		{
+			sk1->prot->inuse--;
+			*p=sk1->next;
+			break;
+		}
+		p=&((*p)->next);
 	}
 	restore_flags(flags);
 }
@@ -368,7 +360,7 @@
   	/* And now the backlog. */
   	while((skb=skb_dequeue(&sk->back_log))!=NULL) 
   	{
-		/* this should never happen. */
+		/* this should [almost] never happen. */
 /*		printk("cleaning back_log\n");*/
 		kfree_skb(skb, FREE_READ);
 	}
@@ -387,12 +379,12 @@
 	 * everything is gone.
 	 */
 
-	  if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) 
-	  {
+	if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0) 
+	{
 		kfree_s((void *)sk,sizeof(*sk));
-	  } 
-	  else 
-	  {
+	} 
+	else 
+	{
 		/* this should never happen. */
 		/* actually it can if an ack has just been sent. */
 		sk->destroy = 1;
@@ -633,6 +625,7 @@
 #endif  
 	sk->type = sock->type;
 	sk->protocol = protocol;
+	sk->allocation = GFP_KERNEL;
 	sk->sndbuf = SK_WMEM_MAX;
 	sk->rcvbuf = SK_RMEM_MAX;
 	sk->rto = TCP_TIMEOUT_INIT;		/*TCP_WRITE_TIME*/
@@ -780,6 +773,7 @@
 /*
  * Return 1 if we still have things to send in our buffers.
  */
+ 
 static inline int closing(struct sock * sk)
 {
 	switch (sk->state) {
@@ -982,13 +976,7 @@
 	if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
 	{
 		if(sk->err!=0)
-		{
-			cli();
-			err=sk->err;
-			sk->err=0;
-			sti();
-			return -err;
-		}
+			return inet_error(sk);
 		return -EALREADY;	/* Connecting is currently in progress */
   	}
 	if (sock->state != SS_CONNECTING) 
@@ -1007,11 +995,7 @@
 	if (sk->state > TCP_FIN_WAIT2 && sock->state==SS_CONNECTING)
 	{
 		sock->state=SS_UNCONNECTED;
-		cli();
-		err=sk->err;
-		sk->err=0;
-		sti();
-		return -err;
+		return inet_error(sk);
 	}
 
 	if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) 
@@ -1031,10 +1015,8 @@
 		if(sk->err && sk->protocol == IPPROTO_TCP)
 		{
 			sock->state = SS_UNCONNECTED;
-			err = -sk->err;
-			sk->err=0;
 			sti();
-			return err; /* set by tcp_err() */
+			return inet_error(sk); /* set by tcp_err() */
 		}
 	}
 	sti();
@@ -1043,11 +1025,7 @@
 	if (sk->state != TCP_ESTABLISHED && sk->err) 
 	{
 		sock->state = SS_UNCONNECTED;
-		cli();
-		err=sk->err;
-		sk->err=0;
-		sti();
-		return(-err);
+		return inet_error(sk);
 	}
 	return(0);
 }
@@ -1097,9 +1075,7 @@
 		sk2 = sk1->prot->accept(sk1,flags);
 		if (sk2 == NULL) 
 		{
-			err=sk1->err;
-			sk1->err=0;
-			return(-err);
+			return inet_error(sk1);
 		}
 	}
 	newsock->data = (void *)sk2;
@@ -1127,12 +1103,11 @@
 
 	if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) 
 	{
-		err = -sk2->err;
-		sk2->err=0;
-		sk2->dead=1;	/* ANK */
+		err = inet_error(sk2);
+		sk2->dead=1;			/* ANK */
 		destroy_sock(sk2);
 		newsock->data = NULL;
-		return(err);
+		return err;
 	}
 	newsock->state = SS_CONNECTED;
 	return(0);
@@ -1566,7 +1541,7 @@
 	int i;
 
 
-	printk("Swansea University Computer Society TCP/IP for NET3.030 (Snapshot #1)\n");
+	printk("Swansea University Computer Society TCP/IP for NET3.031 (Snapshot #4)\n");
 
 	/*
 	 *	Tell SOCKET that we are alive... 
@@ -1610,11 +1585,26 @@
   	 *	Set the IP module up
   	 */
 	ip_init();
-
+	/*
+	 *	Set the ICMP layer up
+	 */
+	icmp_init(&inet_proto_ops);
+	/*
+	 *	Set the firewalling up
+	 */
 #if defined(CONFIG_IP_ACCT)||defined(CONFIG_IP_FIREWALL)|| \
     defined(CONFIG_IP_MASQUERADE)
 	ip_fw_init();
 #endif
+	/*
+	 *	Initialise the multicast router
+	 */
+#if defined(CONFIG_IP_MROUTE)
+	ip_mr_init();
+#endif
+	/*
+	 *	Create all the /proc entries.
+	 */
 
 #ifdef CONFIG_INET_RARP
 	proc_net_register(&(struct proc_dir_entry) {
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v1.3.25/linux/net/ipv4/icmp.c	Mon Aug 28 14:52:25 1995
+++ linux/net/ipv4/icmp.c	Mon Sep 11 21:27:53 1995
@@ -1,109 +1,84 @@
 /*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
+ *	NET3:	Implementation of the ICMP protocol layer. 
+ *	
+ *		Alan Cox, <alan@cymru.net>
  *
- *		Internet Control Message Protocol (ICMP)
+ *	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
+ *	2 of the License, or (at your option) any later version.
  *
- * Version:	@(#)icmp.c	1.0.11	06/02/93
+ *	Some of the function names and the icmp unreach table for this
+ *	module were derived from [icmp.c 1.0.11 06/02/93] by
+ *	Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting.
+ *	Other than that this module is a complete rewrite.
  *
- * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
- *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *		Mark Evans, <evansmp@uhura.aston.ac.uk>
- *		Alan Cox, <gw4pts@gw4pts.ampr.org>
- *		Stefan Becker, <stefanb@yello.ping.de>
- *
- * Fixes:	
- *		Alan Cox	:	Generic queue usage.
- *		Gerhard Koerting:	ICMP addressing corrected
- *		Alan Cox	:	Use tos/ttl settings
- *		Alan Cox	:	Protocol violations
- *		Alan Cox	:	SNMP Statistics		
- *		Alan Cox	:	Routing errors
- *		Alan Cox	:	Changes for newer routing code
- *		Alan Cox	:	Removed old debugging junk
- *		Alan Cox	:	Fixed the ICMP error status of net/host unreachable
- *	Gerhard Koerting	:	Fixed broadcast ping properly
- *		Ulrich Kunitz	:	Fixed ICMP timestamp reply
- *		A.N.Kuznetsov	:	Multihoming fixes.
- *		Laco Rusnak	:	Multihoming fixes.
- *		Alan Cox	:	Tightened up icmp_send().
- *		Alan Cox	:	Multicasts.
- *		Stefan Becker   :       ICMP redirects in icmp_send().
- *		Peter Belding	:	Tightened up ICMP redirect handling
- *		Alan Cox	:	Tightened even more.
- *		Arnt Gulbrandsen:	Misplaced #endif with net redirect and break
- *		A.N.Kuznetsov	:	ICMP timestamp still used skb+1
+ *	Fixes:
  *		Mike Shaver	:	RFC1122 checks.
- * 
  *
- *		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
- *		2 of the License, or (at your option) any later version.
- */
-
-/* RFC1122 Status: (boy, are there a lot of rules for ICMP)
-   3.2.2 (Generic ICMP stuff)
-     MUST discard messages of unknown type. (OK)
-     MUST copy at least the first 8 bytes from the offending packet
-       when sending ICMP errors. (OK)
-     MUST pass received ICMP errors up to protocol level. (OK)
-     SHOULD send ICMP errors with TOS == 0. (OK)
-     MUST NOT send ICMP errors in reply to:
-       ICMP errors (OK)
-       Broadcast/multicast datagrams (OK)
-       MAC broadcasts (OK)
-       Non-initial fragments (OK)
-       Datagram with a source address that isn't a single host. (OK)
-  3.2.2.1 (Destination Unreachable)
-    All the rules govern the IP layer, and are dealt with in ip.c, not here.
-  3.2.2.2 (Redirect)
-    Host SHOULD NOT send ICMP_REDIRECTs.  (OK)
-    MUST update routing table in response to host or network redirects. 
-      (host OK, network NOT YET) [Intentionally -- AC]
-    SHOULD drop redirects if they're not from directly connected gateway
-      (OK -- we drop it if it's not from our old gateway, which is close
-       enough)
-  3.2.2.3 (Source Quench)
-    MUST pass incoming SOURCE_QUENCHs to transport layer (OK)
-    Other requirements are dealt with at the transport layer.
-  3.2.2.4 (Time Exceeded)
-    MUST pass TIME_EXCEEDED to transport layer (OK)
-    Other requirements dealt with at IP (generating TIME_EXCEEDED).
-  3.2.2.5 (Parameter Problem)
-    SHOULD generate these, but it doesn't say for what.  So we're OK. =)
-    MUST pass received PARAMPROBLEM to transport layer (NOT YET)
-    	[Solaris 2.X seems to assert EPROTO when this occurs] -- AC
-  3.2.2.6 (Echo Request/Reply)
-    MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK)
-    MAY discard broadcast ECHO_REQUESTs. (We don't, but that's OK.)
-    MUST reply using same source address as the request was sent to.
-      We're OK for unicast ECHOs, and it doesn't say anything about
-      how to handle broadcast ones, since it's optional.
-    MUST copy data from REQUEST to REPLY (OK)
-      unless it would require illegal fragmentation (MUST) (NOT YET)
-    MUST pass REPLYs to transport/user layer (OK)
-    MUST use any provided source route (reversed) for REPLY. (NOT YET)
- 3.2.2.7 (Information Request/Reply)
-   MUST NOT implement this. (I guess that means silently discard...?) (OK)
- 3.2.2.8 (Timestamp Request/Reply)
-   MAY implement (OK)
-   SHOULD be in-kernel for "minimum variability" (OK)
-   MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
-   MUST reply using same source address as the request was sent to. (OK)
-   MUST reverse source route, as per ECHO (NOT YET)
-   MUST pass REPLYs to transport/user layer (requires RAW, just like ECHO) (OK)
-   MUST update clock for timestamp at least 15 times/sec (OK)
-   MUST be "correct within a few minutes" (OK)
- 3.2.2.9 (Address Mask Request/Reply)
-   MAY implement (OK)
-   MUST send a broadcast REQUEST if using this system to set netmask
-     (OK... we don't use it)
-   MUST discard received REPLYs if not using this system (OK)
-   MUST NOT send replies unless specifically made agent for this sort
-     of thing. (OK)
-*/
+ *
+ *
+ * RFC1122 Status: (boy, are there a lot of rules for ICMP)
+ *  3.2.2 (Generic ICMP stuff)
+ *   MUST discard messages of unknown type. (OK)
+ *   MUST copy at least the first 8 bytes from the offending packet
+ *     when sending ICMP errors. (OK)
+ *   MUST pass received ICMP errors up to protocol level. (OK)
+ *   SHOULD send ICMP errors with TOS == 0. (OK)
+ *   MUST NOT send ICMP errors in reply to:
+ *     ICMP errors (OK)
+ *     Broadcast/multicast datagrams (OK)
+ *     MAC broadcasts (OK)
+ *     Non-initial fragments (OK)
+ *     Datagram with a source address that isn't a single host. (OK)
+ *  3.2.2.1 (Destination Unreachable)
+ *   All the rules govern the IP layer, and are dealt with in ip.c, not here.
+ *  3.2.2.2 (Redirect)
+ *   Host SHOULD NOT send ICMP_REDIRECTs.  (OK)
+ *   MUST update routing table in response to host or network redirects. 
+ *     (host OK, network NOT YET) [Intentionally -- AC]
+ *   SHOULD drop redirects if they're not from directly connected gateway
+ *     (OK -- we drop it if it's not from our old gateway, which is close
+ *      enough)
+ * 3.2.2.3 (Source Quench)
+ *   MUST pass incoming SOURCE_QUENCHs to transport layer (OK)
+ *   Other requirements are dealt with at the transport layer.
+ * 3.2.2.4 (Time Exceeded)
+ *   MUST pass TIME_EXCEEDED to transport layer (OK)
+ *   Other requirements dealt with at IP (generating TIME_EXCEEDED).
+ * 3.2.2.5 (Parameter Problem)
+ *   SHOULD generate these, but it doesn't say for what.  So we're OK. =)
+ *   MUST pass received PARAMPROBLEM to transport layer (NOT YET)
+ *   	[Solaris 2.X seems to assert EPROTO when this occurs] -- AC
+ * 3.2.2.6 (Echo Request/Reply)
+ *   MUST reply to ECHO_REQUEST, and give app to do ECHO stuff (OK, OK)
+ *   MAY discard broadcast ECHO_REQUESTs. (We don't, but that's OK.)
+ *   MUST reply using same source address as the request was sent to.
+ *     We're OK for unicast ECHOs, and it doesn't say anything about
+ *     how to handle broadcast ones, since it's optional.
+ *   MUST copy data from REQUEST to REPLY (OK)
+ *     unless it would require illegal fragmentation (N/A)
+ *   MUST pass REPLYs to transport/user layer (OK)
+ *   MUST use any provided source route (reversed) for REPLY. (NOT YET)
+ * 3.2.2.7 (Information Request/Reply)
+ *   MUST NOT implement this. (I guess that means silently discard...?) (OK)
+ * 3.2.2.8 (Timestamp Request/Reply)
+ *   MAY implement (OK)
+ *   SHOULD be in-kernel for "minimum variability" (OK)
+ *   MAY discard broadcast REQUESTs.  (OK, but see source for inconsistency)
+ *   MUST reply using same source address as the request was sent to. (OK)
+ *   MUST reverse source route, as per ECHO (NOT YET)
+ *   MUST pass REPLYs to transport/user layer (requires RAW, just like ECHO) (OK)
+ *   MUST update clock for timestamp at least 15 times/sec (OK)
+ *   MUST be "correct within a few minutes" (OK)
+ * 3.2.2.9 (Address Mask Request/Reply)
+ *   MAY implement (OK)
+ *   MUST send a broadcast REQUEST if using this system to set netmask
+ *     (OK... we don't use it)
+ *   MUST discard received REPLYs if not using this system (OK)
+ *   MUST NOT send replies unless specifically made agent for this sort
+ *     of thing. (OK)
+ */
 
 #include <linux/types.h>
 #include <linux/sched.h>
@@ -129,18 +104,17 @@
 #include <asm/segment.h>
 #include <net/checksum.h>
 
-
 #define min(a,b)	((a)<(b)?(a):(b))
 
-
 /*
  *	Statistics
  */
  
-struct icmp_mib	icmp_statistics={0,};
-
+struct icmp_mib icmp_statistics;
 
 /* An array of errno for error messages from dest unreach. */
+/* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOS_UNREACH and SR_FAIELD MUST be considered 'transient errrs'. */
+
 struct icmp_err icmp_err_convert[] = {
   { ENETUNREACH,	0 },	/*	ICMP_NET_UNREACH	*/
   { EHOSTUNREACH,	0 },	/*	ICMP_HOST_UNREACH	*/
@@ -157,238 +131,254 @@
   { EOPNOTSUPP,		0 }	/*	ICMP_HOST_UNR_TOS	*/
 };
 
+/*
+ *	A spare long used to speed up statistics udpating
+ */
+ 
+unsigned long dummy;
 
 /*
- *	Send an ICMP message in response to a situation
+ *	ICMP control array. This specifies what to do with each ICMP.
  */
  
+struct icmp_control
+{
+	unsigned long *output;		/* Address to increment on output */
+	unsigned long *input;		/* Address to increment on input */
+	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len);
+	unsigned long error;		/* This ICMP is classed as an error message */	
+};
+
+static struct icmp_control icmp_pointers[19];
+
+/*
+ *	Build xmit assembly blocks
+ */
+
+struct icmp_bxm
+{
+	void *data_ptr;
+	int data_len;
+	struct icmphdr icmph;
+	unsigned long csum;
+};
+
+/*
+ *	The ICMP socket. This is the most convenient way to flow control
+ *	our ICMP output as well as maintain a clean interface throughout
+ *	all layers. All Socketless IP sends will soon be gone.
+ */
+	
+struct socket icmp_socket;
+
+/*
+ *	Send an ICMP frame.
+ */
+ 
+
+/*
+ *	Maintain the counters used in the SNMP statistics for outgoing ICMP
+ */
+ 
+static void icmp_out_count(int type)
+{
+	if(type>18)
+		return;
+	(*icmp_pointers[type].output)++;
+	icmp_statistics.IcmpOutMsgs++;
+}
+ 
+/*
+ *	Checksum each fragment, and on the first include the headers and final checksum.
+ */
+ 
+static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
+{
+	struct icmp_bxm *icmp_param=(struct icmp_bxm *)p;
+	struct icmphdr *icmph;
+	if(offset)
+		icmp_param->csum=csum_partial_copy(icmp_param->data_ptr+offset-sizeof(struct icmphdr), 
+				to, fraglen,icmp_param->csum);
+	else
+	{
+#ifdef CSUM_FOLD_WORKS
+		/*
+		 *	Need this fixed to make multifragment ICMP's work again.
+		 */
+		icmp_param->csum=csum_partial_copy((void *)&icmp_param->icmph, to, sizeof(struct icmphdr),
+			icmp_param->csum);
+		icmp_param->csum=csum_partial_copy(icmp_param->data_ptr, to+sizeof(struct icmphdr),
+				fraglen-sizeof(struct icmphdr), icmp_param->csum);
+		icmph=(struct icmphdr *)to;
+		icmph->checksum = csum_fold(icmp_param->csum);
+#else
+		memcpy(to, &icmp_param->icmph, sizeof(struct icmphdr));
+		memcpy(to+sizeof(struct icmphdr), icmp_param->data_ptr, fraglen-sizeof(struct icmphdr));
+		icmph=(struct icmphdr *)to;
+		icmph->checksum=ip_compute_csum(to, fraglen);
+#endif
+				
+	}
+}
+ 
+/*
+ *	Driving logic for building and sending ICMP messages.
+ */
+ 
+static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr)
+{
+	struct sock *sk=icmp_socket.data;
+	sk->saddr=saddr;
+	icmp_param->icmph.checksum=0;
+	icmp_out_count(icmp_param->icmph.type);
+	ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
+		icmp_param->data_len+sizeof(struct icmphdr),
+		daddr, 0, IPPROTO_ICMP);
+}
+
+
+/*
+ *	Send an ICMP message in response to a situation
+ *
+ *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header. MAY send more (we don't).
+ *			MUST NOT change this header information.
+ *			MUST NOT reply to a multicast/broadcast IP address.
+ *			MUST NOT reply to a multicast/broadcast MAC address.
+ *			MUST reply to only the first fragment.
+ */
+
 void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, struct device *dev)
 {
-	struct sk_buff *skb;
 	struct iphdr *iph;
-	int offset;
 	struct icmphdr *icmph;
-	int len;
-	struct device *ndev=NULL;	/* Make this =dev to force replies on the same interface */
-	unsigned long our_addr;
 	int atype;
+	struct icmp_bxm icmp_param;
+	__u32 saddr;
 	
 	/*
-	 *	Find the original IP header.
+	 *	Find the original header
 	 */
 	 
-	iph = (struct iphdr *) skb_in->data;
+	iph = skb_in->ip_hdr;
 	
 	/*
-	 *	No replies to MAC multicast
+	 *	No replies to physical multicast/broadcast
 	 */
 	 
 	if(skb_in->pkt_type!=PACKET_HOST)
 		return;
 		
 	/*
-	 *	No replies to IP multicasting
+	 *	Now check at the protocol level
 	 */
 	 
 	atype=ip_chk_addr(iph->daddr);
-	if(atype==IS_BROADCAST || atype==IS_MULTICAST)
+	if(atype==IS_BROADCAST||atype==IS_MULTICAST)
 		return;
-
+		
 	/*
-	 *	Only reply to first fragment.
+	 *	Only reply to fragment 0. We byte re-order the constant
+	 *	mask for efficiency.
 	 */
 	 
-	if(ntohs(iph->frag_off)&IP_OFFSET)
+	if(iph->frag_off&htons(IP_OFFSET))
 		return;
-	 		
-	/*
-	 *	We must NEVER NEVER send an ICMP error to an ICMP error message
+		
+	/* 
+	 *	If we send an ICMP error to an ICMP error a mess would result..
 	 */
 	 
-	if(type==ICMP_DEST_UNREACH||type==ICMP_REDIRECT||type==ICMP_SOURCE_QUENCH||type==ICMP_TIME_EXCEEDED)
+	if(icmp_pointers[type].error)
 	{
-
 		/*
-		 *	Is the original packet an ICMP packet?
+		 *	We are an error, check if we are replying to an ICMP error
 		 */
-
+		 
 		if(iph->protocol==IPPROTO_ICMP)
 		{
-			icmph = (struct icmphdr *) ((char *) iph +
-                                                    4 * iph->ihl);
+			icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
 			/*
-			 *	Check for ICMP error packets (Must never reply to
-			 *	an ICMP error).
+			 *	Assume any unknown ICMP type is an error. This isn't
+			 *	specified by the RFC, but think about it..
 			 */
-	
-			if (icmph->type == ICMP_DEST_UNREACH ||
-				icmph->type == ICMP_SOURCE_QUENCH ||
-				icmph->type == ICMP_REDIRECT ||
-				icmph->type == ICMP_TIME_EXCEEDED ||
-				icmph->type == ICMP_PARAMETERPROB)
+			if(icmph->type>18 || icmp_pointers[icmph->type].error)
 				return;
 		}
 	}
-	icmp_statistics.IcmpOutMsgs++;
 	
 	/*
-	 *	This needs a tidy.	
-	 */
-		
-	switch(type)
-	{
-		case ICMP_DEST_UNREACH:
-			icmp_statistics.IcmpOutDestUnreachs++;
-			break;
-		case ICMP_SOURCE_QUENCH:
-			icmp_statistics.IcmpOutSrcQuenchs++;
-			break;
-		case ICMP_REDIRECT:
-		/* RFC1122: (3.2.2.2) Sorta bad.  SHOULDN'T send */
-		/* ICMP_REDIRECTs unless we're a gateway. -- MS */
-		/* We don't .. this path isnt invoked -- AC */
-			icmp_statistics.IcmpOutRedirects++;
-			break;
-		case ICMP_ECHO:
-			icmp_statistics.IcmpOutEchos++;
-			break;
-		case ICMP_ECHOREPLY:
-			icmp_statistics.IcmpOutEchoReps++;
-			break;
-		case ICMP_TIME_EXCEEDED:
-			icmp_statistics.IcmpOutTimeExcds++;
-			break;
-		case ICMP_PARAMETERPROB:
-			icmp_statistics.IcmpOutParmProbs++;
-			break;
-		case ICMP_TIMESTAMP:
-			icmp_statistics.IcmpOutTimestamps++;
-			break;
-		case ICMP_TIMESTAMPREPLY:
-			icmp_statistics.IcmpOutTimestampReps++;
-			break;
-		case ICMP_ADDRESS:
-			icmp_statistics.IcmpOutAddrMasks++;
-			break;
-		case ICMP_ADDRESSREPLY:
-			icmp_statistics.IcmpOutAddrMaskReps++;
-			break;
-	}		
-	/*
-	 *	Get some memory for the reply. 
+	 *	Tell our driver what to send
 	 */
 	 
-	len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) +
-		sizeof(struct iphdr) + 32;	/* amount of header to return */
-	   
-	skb = (struct sk_buff *) alloc_skb(len+15, GFP_ATOMIC);
-	if (skb == NULL) 
-	{
-		icmp_statistics.IcmpOutErrors++;
-		return;
-	}
-	skb->free = 1;
-
-	/*
-	 *	Build Layer 2-3 headers for message back to source. 
-	 */
-
-	our_addr = dev->pa_addr;
-
-	/* RFC1122: (3.2.2).  MUST NOT send ICMP in reply to */
-	/* packet with a source IP address that doesn't define a single */
-	/* host. -- MS.  Checked higher up -- AC */
-
-	if (iph->daddr != our_addr && ip_chk_addr(iph->daddr) == IS_MYADDR)
-		our_addr = iph->daddr;
-	offset = ip_build_header(skb, our_addr, iph->saddr,
-			   &ndev, IPPROTO_ICMP, NULL, len,
-			   skb_in->ip_hdr->tos,255);
-	if (offset < 0) 
-	{
-		icmp_statistics.IcmpOutErrors++;
-		skb->sk = NULL;
-		kfree_skb(skb, FREE_READ);
-		return;
-	}
-
-	/* 
-	 *	Re-adjust length according to actual IP header size. 
-	 */
-
-	skb_put(skb,sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
+	saddr=iph->daddr;
+	if(saddr!=dev->pa_addr && ip_chk_addr(saddr)!=IS_MYADDR)
+		saddr=dev->pa_addr;
+	
+	icmp_param.icmph.type=type;
+	icmp_param.icmph.code=code;
+	icmp_param.icmph.type=type;
+	icmp_param.icmph.un.gateway=0;
+	icmp_param.data_ptr=iph;
+	icmp_param.data_len=(iph->ihl<<2)+8;	/* RFC says return header + 8 bytes */
 	
 	/*
-	 *	Fill in the frame
+	 *	Set it to build.
 	 */
 	 
-	/* RFC1122: SHOULD send with TOS == 0, and I guess this does. */
-	/* Perhaps it should be explicit? -- MS */
-
-	icmph = (struct icmphdr *) (skb->data + offset);
-	icmph->type = type;
-	icmph->code = code;
-	icmph->checksum = 0;
-	icmph->un.gateway = info;	/* This might not be meant for 
-					   this form of the union but it will
-					   be right anyway */
-
-	/* RFC1122: OK. Copies the minimum 8 bytes unchanged from the offending */
-	/* packet (MUST) as per 3.2.2. -- MS */
-	memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
-
-	icmph->checksum = ip_compute_csum((unsigned char *)icmph,
-                         sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
-
-	/*
-	 *	Send it and free it once sent.
-	 */
-	ip_queue_xmit(NULL, ndev, skb, 1);
+	icmp_build_xmit(&icmp_param, saddr, iph->saddr);
 }
 
 
 /* 
- *	Handle ICMP_UNREACH and ICMP_QUENCH. 
+ *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. 
  */
  
-static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
+static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
-	struct inet_protocol *ipprot;
 	struct iphdr *iph;
-	unsigned char hash;
-	int err;
-
-	err = (icmph->type << 8) | icmph->code;
+	int hash;
+	struct inet_protocol *ipprot;
+	unsigned char *dp;	
+	
 	iph = (struct iphdr *) (icmph + 1);
 	
-	switch(icmph->code & 7) 
+	dp= ((unsigned char *)iph)+(iph->ihl<<2);
+	
+	if(icmph->type==ICMP_DEST_UNREACH)
 	{
-		case ICMP_NET_UNREACH:
-			break;
-		case ICMP_HOST_UNREACH:
-			break;
-		case ICMP_PROT_UNREACH:
-#ifdef CONFIG_NET_DEBUG
-			printk("ICMP: %s:%d: protocol unreachable.\n",
-				in_ntoa(iph->daddr), ntohs(iph->protocol));
-#endif
-			break;
-		case ICMP_PORT_UNREACH:
-			break;
-		case ICMP_FRAG_NEEDED:
-#ifdef CONFIG_NET_DEBUG
-			printk("ICMP: %s: fragmentation needed and DF set.\n",
+		switch(icmph->code & 15)
+		{
+			case ICMP_NET_UNREACH:
+				break;
+			case ICMP_HOST_UNREACH:
+				break;
+			case ICMP_PROT_UNREACH:
+				printk("ICMP: %s:%d: protocol unreachable.\n",
+					in_ntoa(iph->daddr), ntohs(iph->protocol));
+				break;
+			case ICMP_PORT_UNREACH:
+				break;
+			case ICMP_FRAG_NEEDED:
+				printk("ICMP: %s: fragmentation needed and DF set.\n",
 								in_ntoa(iph->daddr));
-#endif
-			break;
-		case ICMP_SR_FAILED:
-#ifdef CONFIG_NET_DEBUG
-			printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
-#endif
-			break;
-		default:
-			break;
+				break;
+			case ICMP_SR_FAILED:
+				printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
+				break;
+			default:
+				break;
+		}
+		if(icmph->code>12)	/* Invalid type */
+			return;
 	}
+	
+	/*
+	 *	Throw it at our lower layers
+	 *
+	 *	RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header.
+	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.
+	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.
+	 */
 
 	/*
 	 *	Get the protocol(s). 
@@ -398,6 +388,8 @@
 
 	/*
 	 *	This can't change while we are doing it. 
+	 *
+	 *	FIXME: Deliver to appropriate raw sockets too.
 	 */
 	 
 	ipprot = (struct inet_protocol *) inet_protos[hash];
@@ -416,7 +408,7 @@
 
 		if (iph->protocol == ipprot->protocol && ipprot->err_handler) 
 		{
-			ipprot->err_handler(err, (unsigned char *)(icmph + 1),
+			ipprot->err_handler(icmph->type, icmph->code, dp,
 					    iph->daddr, iph->saddr, ipprot);
 		}
 
@@ -430,8 +422,7 @@
  *	Handle ICMP_REDIRECT. 
  */
 
-static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb,
-	struct device *dev, unsigned long source)
+static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 source, __u32 daddr, int len)
 {
 #ifndef CONFIG_IP_FORWARD
 	struct rtable *rt;
@@ -500,396 +491,210 @@
   	kfree_skb(skb, FREE_READ);
 }
 
-
 /*
  *	Handle ICMP_ECHO ("ping") requests. 
+ *
+ *	RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests.
+ *	RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply.
+ *	See also WRT handling of options once they are done and working.
  */
  
-static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
-	  unsigned long saddr, unsigned long daddr, int len,
-	  struct options *opt)
-{
-	struct icmphdr *icmphr;
-	struct sk_buff *skb2;
-	struct device *ndev=NULL;
-	int size, offset;
-
-	icmp_statistics.IcmpOutEchoReps++;
-	icmp_statistics.IcmpOutMsgs++;
-	
-	size = dev->hard_header_len + 64 + len + 15;
-	skb2 = alloc_skb(size, GFP_ATOMIC);
-
-	if (skb2 == NULL) 
-	{
-		icmp_statistics.IcmpOutErrors++;
-		kfree_skb(skb, FREE_READ);
-		return;
-	}
-	skb2->free = 1;
-
-	/* Build Layer 2-3 headers for message back to source */
-	offset = ip_build_header(skb2, daddr, saddr, &ndev,
-	 	IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
-	if (offset < 0) 
-	{
-		icmp_statistics.IcmpOutErrors++;
-		printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
-		kfree_skb(skb2,FREE_WRITE);
-		kfree_skb(skb, FREE_READ);
-		return;
-	}
-
-	/*
-	 *	Re-adjust length according to actual IP header size. 
-	 */
-	 
-	skb_put(skb2,len);
-
-	/*
-	 *	Build ICMP_ECHO Response message. 
-	 */
-	icmphr = (struct icmphdr *) (skb2->data + offset);
-	memcpy((char *) icmphr, (char *) icmph, len);
-
-	/* Are we copying the data from the ECHO datagram? */
-	/* We're supposed to, and it looks like we are. -- MS */
-	/* We're also supposed to truncate it if it would force */
-	/* illegal fragmentation. *sigh*  */
-
-	icmphr->type = ICMP_ECHOREPLY;
-	icmphr->code = 0;
-	icmphr->checksum = 0;
-	icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
-	/*
-	 *	Ship it out - free it when done 
-	 */
-	ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
-
-	/*
-	 *	Free the received frame
-	 */
-	 
+static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
+{
+	struct icmp_bxm icmp_param;
+	icmp_param.icmph=*icmph;
+	icmp_param.icmph.type=ICMP_ECHOREPLY;
+	icmp_param.data_ptr=(icmph+1);
+	icmp_param.data_len=len;
+	icmp_build_xmit(&icmp_param, daddr, saddr);
 	kfree_skb(skb, FREE_READ);
 }
 
 /*
  *	Handle ICMP Timestamp requests. 
+ *	RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests.
+ *		  SHOULD be in the kernel for minimum random latency.
+ *		  MUST be accurate to a few minutes.
+ *		  MUST be updated at least at 15Hz.
  */
  
-static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
-	  unsigned long saddr, unsigned long daddr, int len,
-	  struct options *opt)
-{
-	struct icmphdr *icmphr;
-	struct sk_buff *skb2;
-	int size, offset;
-	unsigned long *timeptr, midtime;
-	struct device *ndev=NULL;
-
-        if (len < 12)
-	{
-		printk(
-		  "ICMP: Size (%d) of ICMP_TIMESTAMP request should be 20!\n",
-		  len);
-		icmp_statistics.IcmpInErrors++;		
-                /* correct answers are possible for everything >= 12 */
-	}
-
-	size = dev->hard_header_len + 84 + 15;
-
-	if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) 
-	{
-		skb->sk = NULL;
-		kfree_skb(skb, FREE_READ);
-		icmp_statistics.IcmpOutErrors++;		
-		return;
-	}
-	skb2->free = 1;
- 
-/*
- *	Build Layer 2-3 headers for message back to source 
- */
- 
-	offset = ip_build_header(skb2, daddr, saddr, &ndev, IPPROTO_ICMP, opt, len, 
-				skb->ip_hdr->tos, 255);
-	if (offset < 0) 
+static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
+{
+	__u32 times[3];		/* So the new timestamp works on ALPHA's.. */
+	struct icmp_bxm icmp_param;
+	
+	/*
+	 *	Too short.
+	 */
+	 
+	if(len<12)
 	{
-		printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
-		kfree_skb(skb2, FREE_WRITE);
+		icmp_statistics.IcmpInErrors++;
 		kfree_skb(skb, FREE_READ);
-		icmp_statistics.IcmpOutErrors++;
 		return;
 	}
- 
-	/*
-	 *	Re-adjust length according to actual IP header size. 
-	 */
-	skb_put(skb2,20);
- 
-	/*
-	 *	Build ICMP_TIMESTAMP Response message. 
-	 */
-
-	icmphr = (struct icmphdr *) (skb2->data + offset);
-	memcpy((char *) icmphr, (char *) icmph, 12);
-	icmphr->type = ICMP_TIMESTAMPREPLY;
-	icmphr->code = icmphr->checksum = 0;
-
-	/* fill in the current time as ms since midnight UT: */
-	midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
-	timeptr = (unsigned long *) (icmphr + 1);
-	/*
-	 *	the originate timestamp (timeptr [0]) is still in the copy: 
-	 */
-	timeptr [1] = timeptr [2] = htonl(midtime);
-
-	icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, 20);
-
+	
 	/*
-	 *	Ship it out - free it when done 
+	 *	Fill in the current time as ms since midnight UT: 
 	 */
-
-	ip_queue_xmit((struct sock *) NULL, ndev, skb2, 1);
-	icmp_statistics.IcmpOutTimestampReps++;
-	kfree_skb(skb, FREE_READ);
+	 
+	times[1] = htonl((xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000);
+	times[2] = times[1];
+	memcpy((void *)&times[0], icmph+1, 4);		/* Incoming stamp */
+	icmp_param.icmph=*icmph;
+	icmp_param.icmph.type=ICMP_TIMESTAMPREPLY;
+	icmp_param.icmph.code=0;
+	icmp_param.data_ptr=&times;
+	icmp_param.data_len=12;
+	icmp_build_xmit(&icmp_param, daddr,saddr);
+	kfree_skb(skb,FREE_READ);
 }
- 
- 
 
 
-/*
- *	Handle the ICMP INFORMATION REQUEST. 
+/* 
+ *	Handle ICMP_ADDRESS_MASK requests.  (RFC950)
+ *
+ * RFC1122 (3.2.2.9).  A host MUST only send replies to 
+ * ADDRESS_MASK requests if it's been configured as an address mask 
+ * agent.  Receiving a request doesn't constitute implicit permission to 
+ * act as one. Of course, implementing this correctly requires (SHOULD) 
+ * a way to turn the functionality on and off.  Another one for sysctl(), 
+ * I guess. -- MS 
+ * Botched with a CONFIG option for now - Linus add scts sysctl please.. 
  */
  
-static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
-	  unsigned long saddr, unsigned long daddr, int len,
-	  struct options *opt)
+static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
-	/* Obsolete */
-	kfree_skb(skb, FREE_READ);
+#ifdef CONFIG_IP_ADDR_AGENT
+	__u32 answer;
+	struct icmp_bxm icmp_param;
+	icmp_param.icmph.type=ICMP_ADDRESSREPLY;
+	icmp_param.icmph.code=0;
+	icmp_param.icmph.un.echo.id = icmph->un.echo.id;
+	icmp_param.icmph.un.echo.sequence = icmph->un.echo.sequence;
+	icmp_param.data_ptr=&dev->pa_mask;
+	icmp_param.data_len=4;
+	icmp_build_xmit(&icmp_param, daddr, saddr);
+#endif	
+	kfree_skb(skb, FREE_READ);	
 }
 
-
-/* 
- *	Handle ICMP_ADDRESS_MASK requests. 
- */
-
-/* RFC1122 (3.2.2.9).  A host MUST only send replies to */
-/* ADDRESS_MASK requests if it's been configured as an address mask */
-/* agent.  Receiving a request doesn't constitute implicit permission to */
-/* act as one. Of course, implementing this correctly requires (SHOULD) */
-/* a way to turn the functionality on and off.  Another one for sysctl(), */
-/* I guess. -- MS */
-/* Botched with a CONFIG option for now - Linus add scts sysctl please.. */
- 
-static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
-	  unsigned long saddr, unsigned long daddr, int len,
-	  struct options *opt)
+static void icmp_discard(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len)
 {
-#ifdef CONFIG_IP_ADDR_AGENT
-	struct icmphdr *icmphr;
-	struct sk_buff *skb2;
-	int size, offset;
-	struct device *ndev=NULL;
-
-	icmp_statistics.IcmpOutMsgs++;
-	icmp_statistics.IcmpOutAddrMaskReps++;
-	
-	size = dev->hard_header_len + 64 + len + 15;
-	skb2 = alloc_skb(size, GFP_ATOMIC);
-	if (skb2 == NULL) 
-	{
-		icmp_statistics.IcmpOutErrors++;
-		kfree_skb(skb, FREE_READ);
-		return;
-  	}
-  	skb2->free = 1;
-	
-	/* 
-	 *	Build Layer 2-3 headers for message back to source 
-	 */
-
-	offset = ip_build_header(skb2, daddr, saddr, &ndev,
-		 	IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
-	if (offset < 0) 
-	{
-		icmp_statistics.IcmpOutErrors++;
-		printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
-		kfree_skb(skb2,FREE_WRITE);
-		kfree_skb(skb, FREE_READ);
-		return;
-	}
-
-	/*
-	 *	Re-adjust length according to actual IP header size. 
-	 */
-
-	skb_put(skb2,len);
-
-	/*
-	 *	Build ICMP ADDRESS MASK Response message. 
-	 */
-
-	icmphr = (struct icmphdr *) (skb2->data + offset);
-	icmphr->type = ICMP_ADDRESSREPLY;
-	icmphr->code = 0;
-	icmphr->checksum = 0;
-	icmphr->un.echo.id = icmph->un.echo.id;
-	icmphr->un.echo.sequence = icmph->un.echo.sequence;
-	memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
-
-	icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
-	/* Ship it out - free it when done */
-	ip_queue_xmit((struct sock *)NULL, ndev, skb2, 1);
-#endif
-	skb->sk = NULL;
 	kfree_skb(skb, FREE_READ);
 }
 
-
 /* 
  *	Deal with incoming ICMP packets. 
  */
  
-int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
-	 unsigned long daddr, unsigned short len,
-	 unsigned long saddr, int redo, struct inet_protocol *protocol)
+int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+	 __u32 daddr, unsigned short len,
+	 __u32 saddr, int redo, struct inet_protocol *protocol)
 {
-	struct icmphdr *icmph;
-	unsigned char *buff;
-
-	/*
-	 *	Drop broadcast packets. IP has done a broadcast check and ought one day
-	 *	to pass on that information.
-	 */
-	
+	struct icmphdr *icmph=(void *)skb->h.raw;
 	icmp_statistics.IcmpInMsgs++;
-	 
-  	
+	
   	/*
-  	 *	Grab the packet as an icmp object
+	 *	Validate the packet
   	 */
-
-	buff = skb1->h.raw;
-	icmph = (struct icmphdr *) buff;
-
-	/*
-	 *	Validate the packet first 
-	 */
-
+	
 	if (ip_compute_csum((unsigned char *) icmph, len)) 
 	{
 		/* Failed checksum! */
 		icmp_statistics.IcmpInErrors++;
 		printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
-		kfree_skb(skb1, FREE_READ);
+		kfree_skb(skb, FREE_READ);
 		return(0);
 	}
-
+	
+	/*
+	 *	18 is the highest 'known' icmp type. Anything else is a mystery
+	 *
+	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently discarded.
+	 */
+	 
+	if(icmph->type > 18)
+	{
+		icmp_statistics.IcmpInErrors++;		/* Is this right - or do we ignore ? */
+		kfree_skb(skb,FREE_READ);
+		return(0);
+	}
+	
 	/*
 	 *	Parse the ICMP message 
 	 */
 
-	if (ip_chk_addr(daddr) != IS_MYADDR)
+	if (daddr!=dev->pa_addr && ip_chk_addr(daddr) == IS_BROADCAST)
 	{
+		/*
+		 *	RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be silently ignored (we don't as it is used
+		 *	by some network mapping tools).
+		 *	RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently discarded if to broadcast/multicast.
+		 */
 		if (icmph->type != ICMP_ECHO) 
-		/* RFC1122: We're allowed to reply to ICMP_TIMESTAMP */
-		/* requests in the same manner as ICMP_ECHO (optionally */
-		/* drop those to a bcast/mcast), so perhaps we should be */
-		/* consistent? -- MS */
-
 		{
 			icmp_statistics.IcmpInErrors++;
-			kfree_skb(skb1, FREE_READ);
+			kfree_skb(skb, FREE_READ);
 			return(0);
   		}
 		daddr=dev->pa_addr;
 	}
-
-	switch(icmph->type) 
-	{
-		case ICMP_TIME_EXCEEDED:
-			icmp_statistics.IcmpInTimeExcds++;
-			icmp_unreach(icmph, skb1);
-			return 0;
-		case ICMP_DEST_UNREACH:
-			icmp_statistics.IcmpInDestUnreachs++;
-			icmp_unreach(icmph, skb1);
-			return 0;
-		case ICMP_SOURCE_QUENCH:
-			icmp_statistics.IcmpInSrcQuenchs++;
-			icmp_unreach(icmph, skb1);
-			return(0);
-		case ICMP_REDIRECT:
-			icmp_statistics.IcmpInRedirects++;
-			icmp_redirect(icmph, skb1, dev, saddr);
-			return(0);
-		case ICMP_ECHO: 
-			icmp_statistics.IcmpInEchos++;
-			icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
-			return 0;
-		case ICMP_ECHOREPLY:
-			icmp_statistics.IcmpInEchoReps++;
-			kfree_skb(skb1, FREE_READ);
-			return(0);
-		case ICMP_TIMESTAMP:
-			icmp_statistics.IcmpInTimestamps++;
-			icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
-			return 0;
-		case ICMP_TIMESTAMPREPLY:
-		/* RFC1122: MUST pass TIMESTAMPREPLY messages up to app layer, */
-		/* just as with ECHOREPLY.  You have to use raw to get that */
-		/* functionality, just as with ECHOREPLY. Close enough. -- MS */
-			icmp_statistics.IcmpInTimestampReps++;
-			kfree_skb(skb1,FREE_READ);
-			return 0;
-		/* INFO is obsolete and doesn't even feature in the SNMP stats */
-		case ICMP_INFO_REQUEST:
-			icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
-			return 0;
-		case ICMP_INFO_REPLY:
-			skb1->sk = NULL;
-			kfree_skb(skb1, FREE_READ);
-			return(0);
-		case ICMP_ADDRESS:
-			icmp_statistics.IcmpInAddrMasks++;
-			icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
-			return 0;
-		case ICMP_ADDRESSREPLY:
-			/*
-			 *	We ought to set our netmask on receiving this, but 
-			 *	experience shows it's a waste of effort.
-			 */
-			icmp_statistics.IcmpInAddrMaskReps++;
-			kfree_skb(skb1, FREE_READ);
-			return(0);
-		default:
-			/* RFC1122: OK.  Silently discarding weird ICMP (MUST), */
-			/* as per 3.2.2. -- MS */
-			icmp_statistics.IcmpInErrors++;
-			kfree_skb(skb1, FREE_READ);
-			return(0);
- 	}
-  /*NOTREACHED*/
-	kfree_skb(skb1, FREE_READ);
-	return(-1);
+	
+	len-=sizeof(struct icmphdr);
+	(*icmp_pointers[icmph->type].input)++;
+	(icmp_pointers[icmph->type].handler)(icmph,skb,skb->dev,saddr,daddr,len);
+	return 0;
 }
 
-
 /*
- *	Perform any ICMP-related I/O control requests. 
- *	[to vanish soon]
+ *	This table is the definition of how we handle ICMP.
  */
  
-int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+static struct icmp_control icmp_pointers[19] = {
+/* ECHO REPLY (0) */
+ { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0 },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+/* DEST UNREACH (3) */
+ { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1 },
+/* SOURCE QUENCH (4) */
+ { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1 },
+/* REDIRECT (5) */
+ { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1 },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+/* ECHO (8) */
+ { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0 },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+ { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 },
+/* TIME EXCEEDED (11) */
+ { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1 },
+/* PARAMETER PROBLEM (12) */
+/* FIXME: RFC1122 3.2.2.5 - MUST pass PARAM_PROB messages to transport layer */
+ { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1 },
+/* TIMESTAMP (13) */
+ { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0 },
+/* TIMESTAMP REPLY (14) */
+ { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0 },
+/* INFO (15) */
+ { &dummy, &dummy, icmp_discard, 0 },
+/* INFO REPLY (16) */
+ { &dummy, &dummy, icmp_discard, 0 },
+/* ADDR MASK (17) */
+ { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0 },
+/* ADDR MASK REPLY (18) */
+ { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0 }
+};
+
+void icmp_init(struct proto_ops *ops)
 {
-  	switch(cmd) 
-  	{
-		default:
-			return(-EINVAL);
-  	}
- 	return(0);
+	struct sock *sk;
+	icmp_socket.type=SOCK_RAW;
+	icmp_socket.ops=ops;
+	if(ops->create(&icmp_socket, IPPROTO_ICMP)<0)
+		panic("Failed to create the ICMP control socket.\n");
+	sk=icmp_socket.data;
+	sk->allocation=GFP_ATOMIC;
 }
+
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v1.3.25/linux/net/ipv4/igmp.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/igmp.c	Mon Sep 11 20:16:03 1995
@@ -1,6 +1,11 @@
 /*
  *	Linux NET3:	Internet Gateway Management Protocol  [IGMP]
  *
+ *	This code implements the IGMP protocol as defined in RFC1122. There has
+ *	been a further revision of this protocol since, but since it is not 
+ *	cleanly specified in any IETF standards we implement the old one properly
+ *	rather than play a game of guess the BSD unofficial extensions.
+ *
  *	Authors:
  *		Alan Cox <Alan.Cox@linux.org>	
  *
@@ -206,7 +211,7 @@
 }
 
 int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
-	unsigned long daddr, unsigned short len, unsigned long saddr, int redo,
+	__u32 daddr, unsigned short len, __u32 saddr, int redo,
 	struct inet_protocol *protocol)
 {
 	/* This basically follows the spec line by line -- see RFC1112 */
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
--- v1.3.25/linux/net/ipv4/ip.c	Sat Sep  9 15:26:54 1995
+++ linux/net/ipv4/ip.c	Mon Sep 11 20:35:21 1995
@@ -91,6 +91,8 @@
  *		Alan Cox	:	Device lock against page fault.
  *		Alan Cox	:	IP_HDRINCL facility.
  *	Werner Almesberger	:	Zero fragment bug
+ *		Alan Cox	:	RAW IP frame length bug
+ *		Alan Cox	:	Outgoing firewall on build_xmit
  *
  *  
  *
@@ -185,7 +187,7 @@
  *	Take an skb, and fill in the MAC header.
  */
 
-static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr)
+static int ip_send(struct sk_buff *skb, __u32 daddr, int len, struct device *dev, __u32 saddr)
 {
 	int mac = 0;
 
@@ -209,7 +211,7 @@
 	return mac;
 }
 
-static int ip_send_room(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, unsigned long saddr)
+static int ip_send_room(struct sk_buff *skb, __u32 daddr, int len, struct device *dev, __u32 saddr)
 {
 	int mac = 0;
 
@@ -237,13 +239,13 @@
  * protocol knows what it's doing, otherwise it uses the
  * routing/ARP tables to select a device struct.
  */
-int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
+int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr,
 		struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
 {
 	struct rtable *rt;
-	unsigned long raddr;
+	__u32 raddr;
 	int tmp;
-	unsigned long src;
+	__u32 src;
 	struct iphdr *iph;
 
 	/*
@@ -1069,12 +1071,12 @@
 	{
 		fw_res=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0);
 		switch (fw_res) {
-		case 1:
+		case FW_ACCEPT:
 #ifdef CONFIG_IP_MASQUERADE
-		case 2:
+		case FW_MASQUERADE:
 #endif
 			break;
-		case -1:
+		case FW_REJECT:
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
 			/* fall thru */
 		default:
@@ -1394,9 +1396,9 @@
 
 #ifdef	CONFIG_IP_FIREWALL
 	
-	if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy, 0))<1)
+	if ((err=ip_fw_chk(iph,dev,ip_fw_blk_chain,ip_fw_blk_policy, 0))<FW_ACCEPT)
 	{
-		if(err==-1)
+		if(err==FW_REJECT)
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);
 		kfree_skb(skb, FREE_WRITE);
 		return 0;	
@@ -1835,7 +1837,7 @@
 	iph->tot_len = ntohs(skb->len-(((unsigned char *)iph)-skb->data));
 
 #ifdef CONFIG_IP_FIREWALL
-	if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) < 1)
+	if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) < FW_ACCEPT)
 		/* just don't send this packet */
 		return;
 #endif	
@@ -2198,7 +2200,7 @@
  *	FIXME: Add/Del membership should have a semaphore protecting them from re-entry
  */
 			struct ip_mreq mreq;
-			unsigned long route_src;
+			__u32 route_src;
 			struct rtable *rt;
 			struct device *dev=NULL;
 			
@@ -2254,7 +2256,7 @@
 		{
 			struct ip_mreq mreq;
 			struct rtable *rt;
-                        unsigned long route_src;
+			__u32 route_src;
 			struct device *dev=NULL;
 
 			/*
@@ -2436,20 +2438,20 @@
 
 int ip_build_xmit(struct sock *sk,
 		   void getfrag (const void *,
-				 int,
+				 __u32,
 				 char *,
-				 unsigned int,
+				 unsigned int,	
 				 unsigned int),
 		   const void *frag,
 		   unsigned short int length,
-		   int daddr,
+		   __u32 daddr,
 		   int flags,
 		   int type) 
 {
 	struct rtable *rt;
 	unsigned int fraglen, maxfraglen, fragheaderlen;
 	int offset, mf;
-	unsigned long saddr;
+	__u32 saddr;
 	unsigned short id;
 	struct iphdr *iph;
 	int local=0;
@@ -2458,7 +2460,6 @@
 	
 	ip_statistics.IpOutRequests++;
 
-
 #ifdef CONFIG_IP_MULTICAST	
 	if(sk && MULTICAST(daddr) && *sk->ip_mc_name)
 	{
@@ -2593,8 +2594,15 @@
 			getfrag(frag,saddr,(void *)(iph+1),0, length-20);
 		}
 		else
-			getfrag(frag,saddr,(void *)iph,0,length);
+			getfrag(frag,saddr,(void *)iph,0,length-20);
 		dev_unlock_list();
+#ifdef CONFIG_IP_FIREWALL
+		if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy,0) < FW_ACCEPT)
+		{
+			kfree_skb(skb, FREE_WRITE);
+			return -EPERM;
+		}
+#endif
 #ifdef CONFIG_IP_ACCT
 		ip_fw_chk((void *)skb->data,dev,ip_acct_chain, IP_FW_F_ACCEPT,1);
 #endif		
@@ -2772,6 +2780,14 @@
 		 *	Account for the fragment.
 		 */
 		 
+#ifdef CONFIG_IP_FIREWALL
+		if(!offset && ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy,0) < FW_ACCEPT)
+		{
+			kfree_skb(skb, FREE_WRITE);
+			dev_unlock_list();
+			return -EPERM;
+		}
+#endif		
 #ifdef CONFIG_IP_ACCT
 		if(!offset)
 			ip_fw_chk(iph, dev, ip_acct_chain, IP_FW_F_ACCEPT, 1);
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.25/linux/net/ipv4/ip_fw.c	Sat Sep  9 15:26:54 1995
+++ linux/net/ipv4/ip_fw.c	Mon Sep 11 20:16:03 1995
@@ -192,7 +192,7 @@
 	__u32			src, dst;
 	__u16			src_port=0, dst_port=0, icmp_type=0;
 	unsigned short		f_prt=0, prt;
-	char			notcpsyn=1, notcpack=1, frag1, match;
+	char			notcpsyn=1, notcpack=1, match;
 	unsigned short		f_flag;
 	unsigned short		offset;
 
@@ -221,8 +221,6 @@
 
 	offset = ntohs(ip->frag_off) & IP_OFFSET;
 	
-	frag1 = (offset == 0);
-
 	/*
 	 *	Don't allow a fragment of TCP 8 bytes in. Nobody
 	 *	normal causes this. Its a cracker trying to break
@@ -231,25 +229,25 @@
 	 */
 	 
 	if (offset == 1 && ip->protocol == IPPROTO_TCP)
-		return 0;
+		return FW_BLOCK;
 		
-	if (!frag1 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
+	if (offset!=0 && (opt != 1) && (ip->protocol == IPPROTO_TCP ||
 			ip->protocol == IPPROTO_UDP))
-		return(1);
+		return FW_ACCEPT;
 		
 	/*
 	 *	 Header fragment for TCP is too small to check the bits.
 	 */
 	 
 	if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
-		return 0;
+		return FW_BLOCK;
 	
 	/*
 	 *	Too short.
 	 */
 	 
 	else if(ntohs(ip->tot_len)<8+(ip->ihl<<2))
-		return 0;
+		return FW_BLOCK;
 		
 	src = ip->saddr;
 	dst = ip->daddr;
@@ -268,7 +266,7 @@
 		case IPPROTO_TCP:
 			dprintf1("TCP ");
 			/* ports stay 0 if it is not the first fragment */
-			if (frag1) {
+			if (offset!=0) {
 				src_port=ntohs(tcp->source);
 				dst_port=ntohs(tcp->dest);
 				if(tcp->ack)
@@ -283,7 +281,7 @@
 		case IPPROTO_UDP:
 			dprintf1("UDP ");
 			/* ports stay 0 if it is not the first fragment */
-			if (frag1) {
+			if (offset!=0) {
 				src_port=ntohs(udp->source);
 				dst_port=ntohs(udp->dest);
 			}
@@ -478,10 +476,10 @@
 	else
 		f_flag=policy;
 	if(f_flag&IP_FW_F_ACCEPT)
-		return ((f_flag&IP_FW_F_MASQ)?2:1);
+		return ((f_flag&IP_FW_F_MASQ)?FW_MASQUERADE:FW_ACCEPT);
 	if(f_flag&IP_FW_F_ICMPRPL)
-		return -1;
-	return 0;
+		return FW_REJECT;
+	return FW_BLOCK;
 }
 
 #ifdef CONFIG_IP_MASQUERADE
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/ipip.c linux/net/ipv4/ipip.c
--- v1.3.25/linux/net/ipv4/ipip.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/ipip.c	Mon Sep 11 20:16:03 1995
@@ -61,7 +61,7 @@
  */
 
 int ipip_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, 
-		unsigned long daddr, unsigned short len, unsigned long saddr,
+		__u32 daddr, unsigned short len, __u32 saddr,
                                    int redo, struct inet_protocol *protocol)
 {
 #ifdef CONFIG_IP_FIREWALL
@@ -90,9 +90,9 @@
 	 *	Check the firewall [well spotted Olaf]
 	 */
 	 
-	if((err=ip_fw_chk(skb->ip_hdr,dev,ip_fw_blk_chain, ip_fw_blk_policy,0))<1)
+	if((err=ip_fw_chk(skb->ip_hdr,dev,ip_fw_blk_chain, ip_fw_blk_policy,0))<FW_ACCEPT)
 	{
-		if(err==-1)
+		if(err==FW_REJECT)
 			icmp_send(skb,ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0 , dev);
 		kfree_skb(skb, FREE_READ);
 		return 0;
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v1.3.25/linux/net/ipv4/ipmr.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/ipmr.c	Mon Sep 11 20:16:03 1995
@@ -30,6 +30,7 @@
 #include <net/sock.h>
 #include <net/icmp.h>
 #include <net/udp.h>
+#include <linux/notifier.h>
 #include <net/checksum.h>
 
 #ifdef CONFIG_IP_MROUTE
@@ -41,6 +42,20 @@
 static struct vif_device vif_table[MAXVIFS];
 static unsigned long vifc_map;
 int mroute_do_pim = 0;
+
+/*
+ *	Delete a VIF entry
+ */
+ 
+static void vif_delete(struct vif_device *v)
+{
+	if(!(v->flags&VIFF_TUNNEL))
+	{
+		v->dev->flags&=~IFF_ALLMULTI;
+		dev_mc_upload(v->dev);
+	}
+	v->dev=NULL;
+}
  
 /*
  *	Socket options and virtual interface manipulation. The whole
@@ -148,11 +163,7 @@
 				struct vif_device *v=&vif_table[vif.vifc_vifi];
 				if(vifc_map&(1<<vif.vifc_vifi))
 				{
-					if(!(v->flags&VIFF_TUNNEL))
-					{
-						v->dev->flags&=~IFF_ALLMULTI;
-						dev_mc_upload(v->dev);
-					}
+					vif_delete(v);
 					vifc_map&=~(1<<vif.vifc_vifi);
 					return 0;					
 				}
@@ -282,6 +293,39 @@
 		v++;
 	}		
 	vifc_map=0;	
+}
+
+static int ipmr_device_event(unsigned long event, void *ptr)
+{
+	struct vif_device *v;
+	int ct;
+	if(event!=NETDEV_DOWN)
+		return NOTIFY_DONE;
+	v=&vif_table[0];
+	for(ct=0;ct<MAXVIFS;ct++)
+	{
+		if((vifc_map&(1<<ct)) && v->dev==ptr)
+		{
+			vif_delete(v);
+			vifc_map&=~(1<<ct);
+		}
+		v++;
+	}
+	return NOTIFY_DONE;
+}
+
+
+static struct notifier_block ip_mr_notifier={
+	ipmr_device_event,
+	NULL,
+	0
+};
+	
+
+void ip_mr_init(void)
+{
+	printk("Linux IP multicast router 0.00pre-working 8)\n");
+	register_netdevice_notifier(&ip_mr_notifier);
 }
 
 #endif
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v1.3.25/linux/net/ipv4/proc.c	Wed Aug  9 14:55:44 1995
+++ linux/net/ipv4/proc.c	Mon Sep 11 20:16:03 1995
@@ -22,6 +22,7 @@
  *	Erik Schoenfelder	:	/proc/net/snmp
  *		Alan Cox	:	Handle dead sockets properly.
  *	Gerhard Koerting	:	Show both timers
+ *		Alan Cox	:	Allow inode to be NULL (kernel socket)
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -113,7 +114,7 @@
 				format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
 				format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
 				timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
-				sp->socket?SOCK_INODE(sp->socket)->i_uid:0,
+				(sp->socket&&SOCK_INODE(sp->socket))?SOCK_INODE(sp->socket)->i_uid:0,
 				timer_active?sp->timeout:0);
 			if (timer_active1) add_timer(&sp->retransmit_timer);
 			if (timer_active2) add_timer(&sp->timer);
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/protocol.c linux/net/ipv4/protocol.c
--- v1.3.25/linux/net/ipv4/protocol.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/protocol.c	Mon Sep 11 20:16:03 1995
@@ -22,6 +22,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  */
+
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/types.h>
@@ -48,154 +49,172 @@
 #ifdef CONFIG_IP_FORWARD
 #ifdef CONFIG_NET_IPIP
 
-static struct inet_protocol ipip_protocol = {
-  ipip_rcv,             /* IPIP handler          */
-  NULL,                 /* Will be UDP fraglist handler */
-  NULL,                 /* TUNNEL error control    */
-  0,                    /* next                 */
-  IPPROTO_IPIP,         /* protocol ID          */
-  0,                    /* copy                 */
-  NULL,                 /* data                 */
-  "IPIP"                /* name                 */
+static struct inet_protocol ipip_protocol = 
+{
+	ipip_rcv,             /* IPIP handler          */
+	NULL,                 /* TUNNEL error control    */
+	0,                    /* next                 */
+	IPPROTO_IPIP,         /* protocol ID          */
+	0,                    /* copy                 */
+	NULL,                 /* data                 */
+	"IPIP"                /* name                 */
 };
 
 
 #endif
 #endif
 
-static struct inet_protocol tcp_protocol = {
-  tcp_rcv,		/* TCP handler		*/
-  NULL,			/* No fragment handler (and won't be for a long time) */
-  tcp_err,		/* TCP error control	*/  
+static struct inet_protocol tcp_protocol = 
+{
+	tcp_rcv,		/* TCP handler		*/
+	tcp_err,		/* TCP error control	*/  
 #if defined(CONFIG_NET_IPIP) && defined(CONFIG_IP_FORWARD)
-  &ipip_protocol,
+	&ipip_protocol,
 #else  
-  NULL,			/* next			*/
+	NULL,			/* next			*/
 #endif  
-  IPPROTO_TCP,		/* protocol ID		*/
-  0,			/* copy			*/
-  NULL,			/* data			*/
-  "TCP"			/* name			*/
+	IPPROTO_TCP,		/* protocol ID		*/
+	0,			/* copy			*/
+	NULL,			/* data			*/
+	"TCP"			/* name			*/
 };
 
 
-static struct inet_protocol udp_protocol = {
-  udp_rcv,		/* UDP handler		*/
-  NULL,			/* Will be UDP fraglist handler */
-  udp_err,		/* UDP error control	*/
-  &tcp_protocol,	/* next			*/
-  IPPROTO_UDP,		/* protocol ID		*/
-  0,			/* copy			*/
-  NULL,			/* data			*/
-  "UDP"			/* name			*/
+static struct inet_protocol udp_protocol = 
+{
+	udp_rcv,		/* UDP handler		*/
+	udp_err,		/* UDP error control	*/
+	&tcp_protocol,		/* next			*/
+	IPPROTO_UDP,		/* protocol ID		*/
+	0,			/* copy			*/
+	NULL,			/* data			*/
+	"UDP"			/* name			*/
 };
 
 
-static struct inet_protocol icmp_protocol = {
-  icmp_rcv,		/* ICMP handler		*/
-  NULL,			/* ICMP never fragments anyway */
-  NULL,			/* ICMP error control	*/
-  &udp_protocol,	/* next			*/
-  IPPROTO_ICMP,		/* protocol ID		*/
-  0,			/* copy			*/
-  NULL,			/* data			*/
-  "ICMP"		/* name			*/
+static struct inet_protocol icmp_protocol = 
+{
+	icmp_rcv,		/* ICMP handler		*/
+	NULL,			/* ICMP error control	*/
+	&udp_protocol,		/* next			*/
+	IPPROTO_ICMP,		/* protocol ID		*/
+	0,			/* copy			*/
+	NULL,			/* data			*/
+	"ICMP"			/* name			*/
 };
 
 #ifndef CONFIG_IP_MULTICAST
 struct inet_protocol *inet_protocol_base = &icmp_protocol;
 #else
-static struct inet_protocol igmp_protocol = {
-  igmp_rcv,		/* IGMP handler		*/
-  NULL,			/* IGMP never fragments anyway */
-  NULL,			/* IGMP error control	*/
-  &icmp_protocol,	/* next			*/
-  IPPROTO_IGMP,		/* protocol ID		*/
-  0,			/* copy			*/
-  NULL,			/* data			*/
-  "IGMP"		/* name			*/
+static struct inet_protocol igmp_protocol = 
+{
+	igmp_rcv,		/* IGMP handler		*/
+	NULL,			/* IGMP error control	*/
+	&icmp_protocol,		/* next			*/
+	IPPROTO_IGMP,		/* protocol ID		*/
+	0,			/* copy			*/
+	NULL,			/* data			*/
+	"IGMP"			/* name			*/
 };
 
 struct inet_protocol *inet_protocol_base = &igmp_protocol;
 #endif
 
-struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
-  NULL
+struct inet_protocol *inet_protos[MAX_INET_PROTOS] = 
+{
+	NULL
 };
 
 
-struct inet_protocol *
-inet_get_protocol(unsigned char prot)
+/*
+ *	Find a protocol in the protocol tables given its
+ *	IP type.
+ */
+
+struct inet_protocol *inet_get_protocol(unsigned char prot)
 {
-  unsigned char hash;
-  struct inet_protocol *p;
+	unsigned char hash;
+	struct inet_protocol *p;
 
-  hash = prot & (MAX_INET_PROTOS - 1);
-  for (p = inet_protos[hash] ; p != NULL; p=p->next) {
-	if (p->protocol == prot) return((struct inet_protocol *) p);
-  }
-  return(NULL);
+	hash = prot & (MAX_INET_PROTOS - 1);
+	for (p = inet_protos[hash] ; p != NULL; p=p->next) 
+	{
+		if (p->protocol == prot) 
+			return((struct inet_protocol *) p);
+	}
+	return(NULL);
 }
 
+/*
+ *	Add a protocol handler to the hash tables
+ */
 
-void
-inet_add_protocol(struct inet_protocol *prot)
+void inet_add_protocol(struct inet_protocol *prot)
 {
-  unsigned char hash;
-  struct inet_protocol *p2;
+	unsigned char hash;
+	struct inet_protocol *p2;
 
-  hash = prot->protocol & (MAX_INET_PROTOS - 1);
-  prot ->next = inet_protos[hash];
-  inet_protos[hash] = prot;
-  prot->copy = 0;
-
-  /* Set the copy bit if we need to. */
-  p2 = (struct inet_protocol *) prot->next;
-  while(p2 != NULL) {
-	if (p2->protocol == prot->protocol) {
-		prot->copy = 1;
-		break;
+	hash = prot->protocol & (MAX_INET_PROTOS - 1);
+	prot ->next = inet_protos[hash];
+	inet_protos[hash] = prot;
+	prot->copy = 0;
+
+	/*
+	 *	Set the copy bit if we need to. 
+	 */
+	 
+	p2 = (struct inet_protocol *) prot->next;
+	while(p2 != NULL) 
+	{
+		if (p2->protocol == prot->protocol) 
+		{
+			prot->copy = 1;
+			break;
+		}
+		p2 = (struct inet_protocol *) p2->next;
 	}
-	p2 = (struct inet_protocol *) p2->next;
-  }
 }
 
-
-int
-inet_del_protocol(struct inet_protocol *prot)
+/*
+ *	Remove a protocol from the hash tables.
+ */
+ 
+int inet_del_protocol(struct inet_protocol *prot)
 {
-  struct inet_protocol *p;
-  struct inet_protocol *lp = NULL;
-  unsigned char hash;
-
-  hash = prot->protocol & (MAX_INET_PROTOS - 1);
-  if (prot == inet_protos[hash]) {
-	inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
-	return(0);
-  }
+	struct inet_protocol *p;
+	struct inet_protocol *lp = NULL;
+	unsigned char hash;
+
+	hash = prot->protocol & (MAX_INET_PROTOS - 1);
+	if (prot == inet_protos[hash]) 
+	{
+		inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
+		return(0);
+	}
 
-  p = (struct inet_protocol *) inet_protos[hash];
-  while(p != NULL) {
-	/*
-	 * We have to worry if the protocol being deleted is
-	 * the last one on the list, then we may need to reset
-	 * someone's copied bit.
-	 */
-	if (p->next != NULL && p->next == prot) {
+	p = (struct inet_protocol *) inet_protos[hash];
+	while(p != NULL) 
+	{
 		/*
-		 * if we are the last one with this protocol and
-		 * there is a previous one, reset its copy bit.
+		 * We have to worry if the protocol being deleted is
+		 * the last one on the list, then we may need to reset
+		 * someone's copied bit.
 		 */
-	     if (p->copy == 0 && lp != NULL) lp->copy = 0;
-	     p->next = prot->next;
-	     return(0);
-	}
+		if (p->next != NULL && p->next == prot) 
+		{
+			/*
+			 * if we are the last one with this protocol and
+			 * there is a previous one, reset its copy bit.
+			 */
+			if (p->copy == 0 && lp != NULL) 
+				lp->copy = 0;
+			p->next = prot->next;
+			return(0);
+		}
+		if (p->next != NULL && p->next->protocol == prot->protocol) 
+			lp = p;
 
-	if (p->next != NULL && p->next->protocol == prot->protocol) {
-		lp = p;
+		p = (struct inet_protocol *) p->next;
 	}
-
-	p = (struct inet_protocol *) p->next;
-  }
-  return(-1);
+	return(-1);
 }
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v1.3.25/linux/net/ipv4/raw.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/raw.c	Mon Sep 11 20:16:03 1995
@@ -69,9 +69,12 @@
 }
 
 
-/* raw_err gets called by the icmp module. */
-void raw_err (int err, unsigned char *header, unsigned long daddr,
-	 unsigned long saddr, struct inet_protocol *protocol)
+/*
+ *	Raw_err does not currently get called by the icmp module - FIXME:
+ */
+ 
+void raw_err (int type, int code, unsigned char *header, __u32 daddr,
+	 __u32 saddr, struct inet_protocol *protocol)
 {
 	struct sock *sk;
    
@@ -82,15 +85,24 @@
 		return;
 
 	/* This is meaningless in raw sockets. */
-	if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
+	if (type == ICMP_SOURCE_QUENCH) 
 	{
 		if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
 		return;
 	}
+	
+	if(type == ICMP_PARAMETERPROB)
+	{
+		sk->err = EPROTO;
+		sk->error_report(sk);
+	}
 
-	sk->err = icmp_err_convert[err & 0xff].errno;
-	sk->error_report(sk);
-  
+	if(code<13)
+	{
+		sk->err = icmp_err_convert[code & 0xff].errno;
+		sk->error_report(sk);
+	}
+	
 	return;
 }
 
@@ -101,16 +113,17 @@
  *	in ip.c
  */
 
-int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, long saddr, long daddr)
+int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr)
 {
 	/* Now we need to copy this into memory. */
 	skb->sk = sk;
 	skb_trim(skb,ntohs(skb->ip_hdr->tot_len));
+	
 	skb->h.raw = (unsigned char *) skb->ip_hdr;
 	skb->dev = dev;
 	skb->saddr = daddr;
 	skb->daddr = saddr;
-
+	
 	/* Charge it to the socket. */
 	
 	if(sock_queue_rcv_skb(sk,skb)<0)
@@ -134,7 +147,7 @@
  *	Callback support is trivial for SOCK_RAW
  */
   
-static void raw_getfrag(const void *p, int saddr, char *to, unsigned int offset, unsigned int fraglen)
+static void raw_getfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
 {
 	memcpy_fromfs(to, (const unsigned char *)p+offset, fraglen);
 }
@@ -143,7 +156,7 @@
  *	IPPROTO_RAW needs extra work.
  */
  
-static void raw_getrawfrag(const void *p, int saddr, char *to, unsigned int offset, unsigned int fraglen)
+static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
 {
 	memcpy_fromfs(to, (const unsigned char *)p+offset, fraglen);
 	if(offset==0)
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v1.3.25/linux/net/ipv4/route.c	Sun Aug 13 14:45:36 1995
+++ linux/net/ipv4/route.c	Mon Sep 11 20:16:03 1995
@@ -31,6 +31,7 @@
  *		Jonathan Naylor	:	Added Metric support.
  *	Miquel van Smoorenburg	:	BSD API fixes.
  *	Miquel van Smoorenburg	:	Metrics.
+ *		Alan Cox	:	Use __u32 properly
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -77,8 +78,8 @@
  *	Should we return a status value here ?
  */
 
-static void rt_del(unsigned long dst, unsigned long mask,
-		char *devname, unsigned long gtw, short rt_flags, short metric)
+static void rt_del(__u32 dst, __u32 mask,
+		char *devname, __u32 gtw, short rt_flags, short metric)
 {
 	struct rtable *r, **rp;
 	unsigned long flags;
@@ -160,7 +161,7 @@
  *	masks judging by the destination address and our device netmask.
  */
  
-static inline unsigned long default_mask(unsigned long dst)
+static __u32 unsigned long default_mask(__u32 dst)
 {
 	dst = ntohl(dst);
 	if (IN_CLASSA(dst))
@@ -175,9 +176,9 @@
  *	If no mask is specified then generate a default entry.
  */
 
-static unsigned long guess_mask(unsigned long dst, struct device * dev)
+static __u32 guess_mask(__u32 dst, struct device * dev)
 {
-	unsigned long mask;
+	__u32 mask;
 
 	if (!dst)
 		return 0;
@@ -192,7 +193,7 @@
  *	Find the route entry through which our gateway will be reached
  */
  
-static inline struct device * get_gw_dev(unsigned long gw)
+static inline struct device * get_gw_dev(__u32 gw)
 {
 	struct rtable * rt;
 
@@ -220,8 +221,8 @@
  *	by the superuser.
  */
  
-void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
-	unsigned long gw, struct device *dev, unsigned short mtu,
+void ip_rt_add(short flags, __u32 dst, __u32 mask,
+	__u32 gw, struct device *dev, unsigned short mtu,
 	unsigned long window, unsigned short irtt, short metric)
 {
 	struct rtable *r, *rt;
@@ -393,7 +394,7 @@
  *	Check if a mask is acceptable.
  */
  
-static inline int bad_mask(unsigned long mask, unsigned long addr)
+static inline int bad_mask(__u32 mask, __u32 addr)
 {
 	if (addr & (mask = ~mask))
 		return 1;
@@ -412,7 +413,8 @@
 	int err;
 	char * devname;
 	struct device * dev = NULL;
-	unsigned long flags, daddr, mask, gw;
+	unsigned long flags;
+	__u32 daddr, mask, gw;
 	short metric;
 
 	/*
@@ -443,9 +445,9 @@
 	 */
 	 
 	flags = r->rt_flags;
-	daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
-	mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
-	gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
+	daddr = (__u32) ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
+	mask  = (__u32) ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
+	gw    = (__u32) ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
 	metric = r->rt_metric > 0 ? r->rt_metric - 1 : 0;
 
 	/*
@@ -473,7 +475,7 @@
 	 */
 	 
 	if (bad_mask(mask, daddr))
-		mask = 0;
+		mask=0;
 
 	/*
 	 *	Set the mask to nothing for host routes.
@@ -539,8 +541,8 @@
 	 * metric can become negative here if it wasn't filled in
 	 * but that's a fortunate accident; we really use that in rt_del.
 	 */
-	rt_del(trg->sin_addr.s_addr, msk->sin_addr.s_addr, devname,
-		gtw->sin_addr.s_addr, r->rt_flags, r->rt_metric - 1);
+	rt_del((__u32)trg->sin_addr.s_addr, (__u32)msk->sin_addr.s_addr, devname,
+		(__u32)gtw->sin_addr.s_addr, r->rt_flags, r->rt_metric - 1);
 	if ( devname != NULL )
 		putname(devname);
 	return 0;
@@ -570,9 +572,9 @@
 	for (r = rt_base; r != NULL; r = r->rt_next) 
 	{
         	size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\t%u\n",
-			r->rt_dev->name, r->rt_dst, r->rt_gateway,
+			r->rt_dev->name, (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
 			r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
-			r->rt_mask, (int)r->rt_mss, r->rt_window, (int)r->rt_irtt);
+			(unsigned long)r->rt_mask, (int)r->rt_mss, r->rt_window, (int)r->rt_irtt);
 		len+=size;
 		pos+=size;
 		if(pos<offset)
@@ -604,7 +606,7 @@
  *	ARP/IP routing/Socket pointer cache. Volunteers welcome
  */
  
-struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned long *src_addr)
+struct rtable * ip_rt_route(__u32 daddr, struct options *opt, __u32 *src_addr)
 {
 	struct rtable *rt;
 
@@ -638,7 +640,7 @@
 	return NULL;
 }
 
-struct rtable * ip_rt_local(unsigned long daddr, struct options *opt, unsigned long *src_addr)
+struct rtable * ip_rt_local(__u32 daddr, struct options *opt, __u32 *src_addr)
 {
 	struct rtable *rt;
 
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.25/linux/net/ipv4/tcp.c	Sat Sep  9 15:26:54 1995
+++ linux/net/ipv4/tcp.c	Mon Sep 11 20:16:03 1995
@@ -1033,8 +1033,8 @@
  * to find the appropriate port.
  */
 
-void tcp_err(int err, unsigned char *header, unsigned long daddr,
-	unsigned long saddr, struct inet_protocol *protocol)
+void tcp_err(int type, int code, unsigned char *header, __u32 daddr,
+	__u32 saddr, struct inet_protocol *protocol)
 {
 	struct tcphdr *th;
 	struct sock *sk;
@@ -1049,14 +1049,7 @@
 	if (sk == NULL) 
 		return;
   
-	if(err<0)
-	{
-	  	sk->err = -err;
-	  	sk->error_report(sk);
-	  	return;
-	}
-
-	if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
+	if (type == ICMP_SOURCE_QUENCH) 
 	{
 		/*
 		 * FIXME:
@@ -1067,17 +1060,22 @@
 			sk->cong_window--;
 		return;
 	}
+	
+	if (type == ICMP_PARAMETERPROB)
+	{
+		sk->err=EPROTO;
+		sk->error_report(sk);
+	}
 
 	/*
 	 * If we've already connected we will keep trying
 	 * until we time out, or the user gives up.
 	 */
 
-	err &= 0xff;
-	if (err < 13 && (icmp_err_convert[err].fatal || sk->state == TCP_SYN_SENT))
+	if (code < 13 && (icmp_err_convert[code].fatal || sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV))
 	{
-		sk->err = icmp_err_convert[err].errno;
-		if (sk->state == TCP_SYN_SENT) 
+		sk->err = icmp_err_convert[code].errno;
+		if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) 
 		{
 			tcp_statistics.TcpAttemptFails++;
 			tcp_set_state(sk,TCP_CLOSE);
@@ -3024,7 +3022,7 @@
 	if (sk->user_mss)
 		newsk->mtu = sk->user_mss;
 	else if(rt!=NULL && (rt->rt_flags&RTF_MSS))
-		newsk->mtu = rt->rt_mss - HEADER_SIZE;
+		newsk->mtu = rt->rt_mss - sizeof(struct iphdr) - sizeof(struct tcphdr);
 	else 
 	{
 #ifdef CONFIG_INET_SNARL	/* Sub Nets Are Local */
@@ -3032,7 +3030,7 @@
 #else
 		if ((saddr ^ daddr) & dev->pa_mask)
 #endif
-			newsk->mtu = 576 - HEADER_SIZE;
+			newsk->mtu = 576 - sizeof(struct iphdr) - sizeof(struct tcphdr);
 		else
 			newsk->mtu = MAX_WINDOW;
 	}
@@ -3041,7 +3039,7 @@
 	 *	But not bigger than device MTU 
 	 */
 
-	newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE);
+	newsk->mtu = min(newsk->mtu, dev->mtu - sizeof(struct iphdr) - sizeof(struct tcphdr));
 
 	/*
 	 *	This will min with what arrived in the packet 
@@ -4550,7 +4548,7 @@
 
 	if (sk->user_mss)
 		sk->mtu = sk->user_mss;
-	else if(rt!=NULL && (rt->rt_flags&RTF_MTU))
+	else if(rt!=NULL && (rt->rt_flags&RTF_MSS))
 		sk->mtu = rt->rt_mss;
 	else 
 	{
@@ -4559,7 +4557,7 @@
 #else
 		if ((sk->saddr ^ sk->daddr) & dev->pa_mask)
 #endif
-			sk->mtu = 576 - HEADER_SIZE;
+			sk->mtu = 576 - sizeof(struct iphdr) - sizeof(struct tcphdr);
 		else
 			sk->mtu = MAX_WINDOW;
 	}
@@ -4570,7 +4568,7 @@
 	if(sk->mtu <32)
 		sk->mtu = 32;	/* Sanity limit */
 		
-	sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
+	sk->mtu = min(sk->mtu, dev->mtu - sizeof(struct iphdr) - sizeof(struct tcphdr));
 	
 	/*
 	 *	Put in the TCP options to say MTU. 
@@ -4700,8 +4698,8 @@
  */
  
 int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
-	unsigned long daddr, unsigned short len,
-	unsigned long saddr, int redo, struct inet_protocol * protocol)
+	__u32 daddr, unsigned short len,
+	__u32 saddr, int redo, struct inet_protocol * protocol)
 {
 	struct tcphdr *th;
 	struct sock *sk;
diff -u --recursive --new-file v1.3.25/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v1.3.25/linux/net/ipv4/udp.c	Sun Sep  3 12:27:06 1995
+++ linux/net/ipv4/udp.c	Mon Sep 11 20:16:03 1995
@@ -150,33 +150,37 @@
  * to find the appropriate port.
  */
 
-void udp_err(int err, unsigned char *header, unsigned long daddr,
-	unsigned long saddr, struct inet_protocol *protocol)
+void udp_err(int type, int code, unsigned char *header, __u32 daddr,
+	__u32 saddr, struct inet_protocol *protocol)
 {
-	struct udphdr *th;
+	struct udphdr *uh;
 	struct sock *sk;
-	struct iphdr *ip=(struct iphdr *)header;
-  
-	header += 4*ip->ihl;
 
 	/*
 	 *	Find the 8 bytes of post IP header ICMP included for us
 	 */  
 	
-	th = (struct udphdr *)header;  
+	uh = (struct udphdr *)header;  
    
-	sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
+	sk = get_sock(&udp_prot, uh->source, daddr, uh->dest, saddr);
 
 	if (sk == NULL) 
 	  	return;	/* No socket for error */
   	
-	if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) 
+	if (type == ICMP_SOURCE_QUENCH) 
 	{	/* Slow down! */
 		if (sk->cong_window > 1) 
 			sk->cong_window = sk->cong_window/2;
 		return;
 	}
 
+	if (type == ICMP_PARAMETERPROB)
+	{
+		sk->err = EPROTO;
+		sk->error_report(sk);
+		return;
+	}
+			
 	/*
 	 *	Various people wanted BSD UDP semantics. Well they've come 
 	 *	back out because they slow down response to stuff like dead
@@ -189,10 +193,9 @@
 	/* 4.1.3.3. */
 	/* After the comment above, that should be no surprise. */
 
-	err &= 0xff;
-	if (err < 13 && icmp_err_convert[err].fatal)
+	if (code < 13 && icmp_err_convert[code].fatal)
 	{
-		sk->err = icmp_err_convert[err].errno;
+		sk->err = icmp_err_convert[code].errno;
 		sk->error_report(sk);
 	}
 }
@@ -218,7 +221,7 @@
  *	for direct user->board I/O transfers. That one will be fun.
  */
  
-static void udp_getfrag(const void *p, int saddr, char * to, unsigned int offset, unsigned int fraglen) 
+static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) 
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 	const char *src;
@@ -258,7 +261,7 @@
  *	this is a valid decision.
  */
  
-static void udp_getfrag_nosum(const void *p, int saddr, char * to, unsigned int offset, unsigned int fraglen) 
+static void udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) 
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 	const char *src;
@@ -523,7 +526,7 @@
 int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
 {
 	struct rtable *rt;
-	unsigned long sa;
+	__u32 sa;
 	if (addr_len < sizeof(*usin)) 
 	  	return(-EINVAL);
 
@@ -535,7 +538,7 @@
 	if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST)
 		return -EACCES;			/* Must turn broadcast on first */
   	
-  	rt=(sk->localroute?ip_rt_local:ip_rt_route)(usin->sin_addr.s_addr, NULL, &sa);
+  	rt=(sk->localroute?ip_rt_local:ip_rt_route)((__u32)usin->sin_addr.s_addr, NULL, &sa);
   	if(rt==NULL)
   		return -ENETUNREACH;
   	sk->saddr = sa;		/* Update source address */
@@ -567,8 +570,8 @@
  */
  
 int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
-	unsigned long daddr, unsigned short len,
-	unsigned long saddr, int redo, struct inet_protocol *protocol)
+	__u32 daddr, unsigned short len,
+	__u32 saddr, int redo, struct inet_protocol *protocol)
 {
   	struct sock *sk;
   	struct udphdr *uh;
diff -u --recursive --new-file v1.3.25/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v1.3.25/linux/net/ipx/af_ipx.c	Fri Aug 18 08:45:00 1995
+++ linux/net/ipx/af_ipx.c	Mon Sep 11 20:16:03 1995
@@ -1990,7 +1990,7 @@
 		ipx_rt_get_info
 	});
 		
-	printk("Swansea University Computer Society IPX 0.31 for NET3.030\n");
+	printk("Swansea University Computer Society IPX 0.31 for NET3.031\n");
 	printk("IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
 }
 #endif
diff -u --recursive --new-file v1.3.25/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v1.3.25/linux/net/netrom/af_netrom.c	Thu Sep  7 17:17:21 1995
+++ linux/net/netrom/af_netrom.c	Mon Sep 11 20:16:04 1995
@@ -450,6 +450,7 @@
 	sk->dead          = 0;
 	sk->next          = NULL;
 	sk->broadcast     = 0;
+	sk->allocation	  = GFP_KERNEL;
 	sk->rcvbuf        = SK_RMEM_MAX;
 	sk->sndbuf        = SK_WMEM_MAX;
 	sk->wmem_alloc    = 0;
@@ -1434,7 +1435,7 @@
 {
 	sock_register(nr_proto_ops.family, &nr_proto_ops);
 	register_netdevice_notifier(&nr_dev_notifier);
-	printk("G4KLX NET/ROM for Linux. Version 0.3 ALPHA for AX25 030 Linux 1.3.0\n");
+	printk("G4KLX NET/ROM for Linux. Version 0.3 ALPHA for AX25.030 Linux 1.3.25\n");
 
 	nr_default.quality    = NR_DEFAULT_QUAL;
 	nr_default.obs_count  = NR_DEFAULT_OBS;
diff -u --recursive --new-file v1.3.25/linux/net/socket.c linux/net/socket.c
--- v1.3.25/linux/net/socket.c	Sun Aug 13 14:45:37 1995
+++ linux/net/socket.c	Mon Sep 11 20:16:04 1995
@@ -198,7 +198,8 @@
  * The original socket implementation wasn't very clever, which is
  * why this exists at all..
  */
-inline struct socket *socki_lookup(struct inode *inode)
+
+__inline struct socket *socki_lookup(struct inode *inode)
 {
 	return &inode->u.socket_i;
 }
@@ -207,7 +208,7 @@
  *	Go from a file number to its socket slot.
  */
 
-static inline struct socket *sockfd_lookup(int fd, struct file **pfile)
+extern __inline struct socket *sockfd_lookup(int fd, struct file **pfile)
 {
 	struct file *file;
 	struct inode *inode;
@@ -477,83 +478,6 @@
 	return 0;
 }
 
-	
-/*
- *	Wait for a connection.
- */
-
-int sock_awaitconn(struct socket *mysock, struct socket *servsock, int flags)
-{
-	struct socket *last;
-
-	/*
-	 *	We must be listening
-	 */
-	if (!(servsock->flags & SO_ACCEPTCON)) 
-	{
-		return(-EINVAL);
-	}
-
-  	/*
-  	 *	Put ourselves on the server's incomplete connection queue. 
-  	 */
-  	 
-	mysock->next = NULL;
-	cli();
-	if (!(last = servsock->iconn)) 
-		servsock->iconn = mysock;
-	else 
-	{
-		while (last->next) 
-			last = last->next;
-		last->next = mysock;
-	}
-	mysock->state = SS_CONNECTING;
-	mysock->conn = servsock;
-	sti();
-
-	/*
-	 * Wake up server, then await connection. server will set state to
-	 * SS_CONNECTED if we're connected.
-	 */
-	wake_up_interruptible(servsock->wait);
-	sock_wake_async(servsock, 0);
-
-	if (mysock->state != SS_CONNECTED) 
-	{
-		if (flags & O_NONBLOCK)
-			return -EINPROGRESS;
-
-		interruptible_sleep_on(mysock->wait);
-		if (mysock->state != SS_CONNECTED &&
-		    mysock->state != SS_DISCONNECTING) 
-		{
-		/*
-		 * if we're not connected we could have been
-		 * 1) interrupted, so we need to remove ourselves
-		 *    from the server list
-		 * 2) rejected (mysock->conn == NULL), and have
-		 *    already been removed from the list
-		 */
-			if (mysock->conn == servsock) 
-			{
-				cli();
-				if ((last = servsock->iconn) == mysock)
-					servsock->iconn = mysock->next;
-				else 
-				{
-					while (last->next != mysock) 
-						last = last->next;
-					last->next = mysock->next;
-				}
-				sti();
-			}
-			return(mysock->conn ? -EINTR : -EACCES);
-		}
-	}
-	return(0);
-}
-
 
 /*
  *	Perform the socket system call. we locate the appropriate
@@ -1361,7 +1285,7 @@
 {
 	int i;
 
-	printk("Swansea University Computer Society NET3.030 Snap #1 for Linux 1.3.4\n");
+	printk("Swansea University Computer Society NET3.031 Snap #1 for Linux 1.3.25\n");
 
 	/*
 	 *	Initialize all address (protocol) families. 
diff -u --recursive --new-file v1.3.25/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v1.3.25/linux/net/unix/af_unix.c	Thu Sep  7 17:17:21 1995
+++ linux/net/unix/af_unix.c	Mon Sep 11 20:16:04 1995
@@ -291,6 +291,7 @@
 	sk->broadcast=0;
 	sk->rcvbuf=SK_RMEM_MAX;
 	sk->sndbuf=SK_WMEM_MAX;
+	sk->allocation=GFP_KERNEL;
 	sk->inuse=0;
 	sk->debug=0;
 	sk->prot=NULL;
@@ -1094,7 +1095,7 @@
 
 void unix_proto_init(struct net_proto *pro)
 {
-	printk("NET3: Unix domain sockets 0.09 BETA for Linux NET3.030.\n");
+	printk("NET3: Unix domain sockets 0.10 BETA for Linux NET3.031.\n");
 	sock_register(unix_proto_ops.family, &unix_proto_ops);
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_UNIX,  4, "unix",
diff -u --recursive --new-file v1.3.25/linux/scripts/ksymoops.cc linux/scripts/ksymoops.cc
--- v1.3.25/linux/scripts/ksymoops.cc	Thu Jan  1 02:00:00 1970
+++ linux/scripts/ksymoops.cc	Mon Sep 11 07:47:01 1995
@@ -0,0 +1,182 @@
+/* ksymoops.c -- simple Linux Oops-log symbol resolver
+   Copyright (C) 1995 Greg McGary
+  
+   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 2, or (at your option)
+   any later version.
+  
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not, write to the
+   Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* This is a simple filter to resolve EIP and call-trace symbols from
+   a Linux kernel "Oops" log.  Supply the symbol-map file name as a
+   command-line argument, and redirect the oops-log into stdin.
+   Out will come the EIP and call-trace in symbolic form.  */
+
+#include <fstream.h>
+#include <string.h>
+#include <stdlib.h>
+
+inline int strequ(char const* x, char const* y) { return (::strcmp(x, y) == 0); }
+
+//////////////////////////////////////////////////////////////////////////////
+
+class KSym
+{
+    friend class NameList;
+
+  private:
+    long address_;
+    char type_;
+    char* name_;
+    long offset_;
+    long extent_;
+
+  public:
+    void set_extent(KSym const& next_ksym) { extent_ = next_ksym.address_ - address_; }
+    friend istream& operator >> (istream&, KSym&);
+    friend ostream& operator << (ostream&, const KSym&);
+};
+
+istream&
+operator >> (istream& is, KSym& n)
+{
+    is >> hex >> n.address_;
+    is >> n.type_;
+    char name[128];
+    is >> name;
+    n.name_ = new char [strlen(name)+1];
+    strcpy(n.name_, name);
+    n.offset_ = 0;
+    return is;
+}
+
+ostream&
+operator << (ostream& os, const KSym& n)
+{
+    os << hex << n.address_ + n.offset_ << ' ' << n.type_ << ' ' << n.name_;
+    if (n.offset_)
+	os << '+' << hex << n.offset_ << '/' << hex << n.extent_;
+    return os;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+class NameList
+{
+  private:
+    // Caution: Fixed Allocation!
+    // This should suffice for awhile since 1.1.86 has only 2482 symbols.
+    KSym ksyms_0_[4096];
+    int cardinality_;
+
+  public:
+    NameList() : cardinality_(0) { }
+    
+  public:
+    KSym* find(long address);
+    
+  public:
+    friend istream& operator >> (istream&, NameList&);
+};
+
+KSym*
+NameList::find(long address)
+{
+    KSym* start = ksyms_0_;
+    KSym* end = &ksyms_0_[cardinality_];
+    KSym* mid;
+
+    while (start <= end) {
+	mid = &start[(end - start) / 2];
+	if (mid->address_ < address)
+	    start = mid + 1;
+	else if (mid->address_ > address)
+	    end = mid - 1;
+	else
+	    return mid;
+    }
+    while (mid->address_ > address)
+	--mid;
+    mid->offset_ = address - mid->address_;
+    if (mid->offset_ > mid->extent_)
+	clog << "Oops! " << *mid << endl;
+    return mid;
+}
+
+istream&
+operator >> (istream& is, NameList& n)
+{
+    KSym* ksyms = n.ksyms_0_;
+    int cardinality = 0;
+    while (!is.eof()) {
+	is >> *ksyms;
+	ksyms[-1].set_extent(*ksyms);
+	ksyms++;
+	cardinality++;
+    }
+    n.cardinality_ = --cardinality;
+    return is;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+char const* program_name;
+
+void
+usage()
+{
+    clog << "Usage: " << program_name << " system-map-file < oops-log" << endl;
+    exit(1);
+}
+
+int
+main(int argc, char** argv)
+{
+    program_name = (argc--, *argv++);
+    if (argc != 1)
+	usage();
+
+    char const* map_file_name = (argc--, *argv++);
+    ifstream map(map_file_name);
+    if (map.bad()) {
+	clog << program_name << ": Can't open `" << map_file_name << "'" << endl;
+	return 1;
+    }
+    
+    NameList names;
+    map >> names;
+
+    char buffer[1024];
+    while (!cin.eof())
+    {
+	long address;
+	cin >> buffer;
+	if (strequ(buffer, "EIP:")) {
+	    cin >> hex >> address;
+	    cin >> buffer[0];
+	    cin >> hex >> address;
+	    KSym* ksym = names.find(address);
+	    if (ksym)
+		cout << "EIP: " << *ksym << endl;
+	} else if (strequ(buffer, "Trace:")) {
+	    while ((cin >> address) && address > 0xc) {
+		KSym* ksym = names.find(address);
+		if (ksym)
+		    cout << "Trace: " << *ksym << endl;
+	    }
+	    cout << endl;
+	}
+    }
+    cout << flush;
+
+    return 0;
+}
