diff -u --recursive --new-file v2.1.25/linux/CREDITS linux/CREDITS
--- v2.1.25/linux/CREDITS	Thu Feb  6 12:41:58 1997
+++ linux/CREDITS	Thu Feb  6 14:57:24 1997
@@ -960,11 +960,8 @@
 S: LS2  7PS,   UK
 
 N: Craig Metz
-E: cmetz@tjhsst.edu
-D: Some of PAS 16 mixer & PCM support
-S: 12305 Country Ridge Lane
-S: Fairfax, Virginia 22033
-S: USA
+E: cmetz@inner.net
+D: Some of PAS 16 mixer & PCM support, inet6-apps
 
 N: William (Bill) Metzenthen
 E: billm@suburbia.net
@@ -1099,6 +1096,10 @@
 S: Albuquerque, NM  87131
 S: USA
 
+N: David Parsons
+E: orc@pell.chi.il.us
+D: improved memory detection code.
+
 N: Avery Pennarun
 E: apenwarr@foxnet.net
 D: ARCnet driver
@@ -1384,9 +1385,9 @@
 W: http://www.cs.helsinki.fi/~torvalds/
 P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A  BE 67 3C 24 03 13 62 C8
 D: Original kernel hacker
-S: Kalevankatu 55 B 37
-S: 00180 Helsinki
-S: Finland
+S: 3665 Benton Street #36
+S: Santa Clara, California 95051
+S: USA
 
 N: Jeff Tranter
 E: Jeff_Tranter@Mitel.COM
diff -u --recursive --new-file v2.1.25/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.25/linux/Documentation/Changes	Thu Jan 23 21:06:45 1997
+++ linux/Documentation/Changes	Mon Feb  3 13:06:10 1997
@@ -19,7 +19,14 @@
 generated by texinfo so a diff is useless anyway (though I can
 incorporate one by hand if you insist upon sending it that way ;-).
 
-Last updated: January 9, 1997.
+   Check out http://www.cviog.uga.edu/Misc/info/LinuxBleed.html for an
+HTML-ized shopping list.
+
+   For those of you in Europe,
+http://www.datanet.hu/generations/linux/Changes2.html is an
+English-language HTML version.
+
+Last updated: January 29, 1997.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
@@ -28,7 +35,7 @@
    Upgrade to at *least* these software revisions before thinking you've
 encountered a bug!
 
-- Kernel modules	 modutils-970104
+- Kernel modules	 modutils-2.1.23
 - Gnu C 		 2.7.2.1
 - Binutils		 2.7.0.3
 - Linux C Library	 5.4.17
@@ -39,6 +46,7 @@
 - Mount                  2.5p
 - Net-tools              1.32-alpha
 - Kbd                    0.91
+- Loadlin                1.6a
 
 Upgrade notes
 *************
@@ -49,8 +57,8 @@
    <CTRL><ALT><DEL> now performs a cold reboot instead of a warm reboot
 for increased hardware compatibility.  If you want a warm reboot and
 know it works on your hardware, add a "reboot=warm" command line option
-in Lilo. A small number of machines need "reboot=bios" to reboot via the 
-BIOS.
+in Lilo.  A small number of machines need "reboot=bios" to reboot via
+the BIOS.
 
 Libc
 ====
@@ -75,7 +83,7 @@
 Modules
 =======
 
-   You need to upgrade to modutils-970104 for kernels 2.1.8 and later.
+   You need to upgrade to modutils-2.1.23 for kernels 2.1.18 and later.
 
 Gnu C
 =====
@@ -120,7 +128,13 @@
 ======
 
    A new "stable" version of DOSEMU is available for 2.1.x kernels.
-Upgrade to 0.64.2 or later.
+Upgrade to 0.64.3 or later.
+
+Loadlin
+=======
+
+   Linux 2.1.22 and later releases use a new method of memory size
+detection, requiring loadlin users to upgrade to loadlin-1.6a.
 
 How to know the version of the installed programs
 *************************************************
@@ -132,15 +146,14 @@
 Binutils: ld -v
 Gnu C: gcc -v or gcc --version
 Kbd: loadkeys -h
-Ld.so:  ldd -v
+Ld.so: ldd -v
 Libc: ls -l /lib/libc.so.*
 Libc++: ls -l /usr/lib/libg++.so.*
-modules: /sbin/insmod -V
-mount: mount --version
-procps: ps --version
-SysVinit: (must be logged in as root)
-    strings `egrep -li INIT_VERSION=sysvinit- /proc/*/environ | head -1` | \
-    egrep -i INIT_VERSION=sysvinit-
+Modutils: insmod -V
+Mount: mount --version
+Procps: ps --version
+SysVinit: strings `egrep -li INIT_VERSION=sysvinit- /proc/*/environ | head
+-1` | egrep -i INIT_VERSION=sysvinit-
 RPM:  rpm --version
 
 Where to get the files
@@ -196,8 +209,9 @@
 Modules utilities
 =================
 
-The 970104 release:
-ftp://ftp.redhat.com/pub/alphabits/modutils-970104.tar.gz
+The 2.1.23 release:
+ftp://tsx-11.mit.edu/pub/linux/sources/system/v2.1/modutils-2.1.23.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/kernel/v2.1/modutils-2.1.23.tar.gz
 
 Procps utilities
 ================
@@ -229,9 +243,16 @@
 DOSEMU
 ======
 
-The 0.64.2 release:
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu0.64.2.tgz
-ftp://sunsite.unc.edu/pub/Linux/system/Emulators/dosemu0.64.2.tgz
+The 0.64.3.1 release:
+ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu0.64.3.1.tgz
+ftp://sunsite.unc.edu/pub/Linux/system/Emulators/dosemu0.64.3.1.tgz
+
+Loadlin
+=======
+
+The 1.6a release:
+ftp://ftp.suse.com/pub/loadlin/update-1.6a/loadlin.exe.gz
+ftp://elserv.ffm.fgan.de/pub/linux/loadlin-1.6/update-1.6a/loadlin.exe.gz
 
 Other Info
 ==========
diff -u --recursive --new-file v2.1.25/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.25/linux/Documentation/Configure.help	Thu Feb  6 12:41:58 1997
+++ linux/Documentation/Configure.help	Tue Feb  4 16:44:24 1997
@@ -2364,17 +2364,17 @@
   distances with data transfer rates significantly higher than those
   achievable with commonly used asynchronous modem connections.
   Usually, a quite expensive external device called `WAN router' is
-  needed to connect to WAN.
-      As an alternative, WAN router can be build into Linux kernel.
+  needed to connect to a WAN.
+      As an alternative, WAN routing can be built into the Linux kernel. 
   With relatively inexpensive WAN interface cards available on the
-  market, a perfectly usable router can be built for less than half a
+  market, a perfectly usable router can be built for less than half the
   price of an external router.  If you have one of those cards (with
   appropriate WAN Link Driver) and wish to use your Linux box as a WAN
   router, you may say 'Y' to this option.  You will also need a
   wan-tools package available via FTP (user: anonymous) from
   ftp.sangoma.com.  Read Documentation/networking/wan-router.txt for
   more information.
-      WAN router is always built as a module ( = code which can be
+      WAN routing is always built as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   For general information about modules read Documentation/modules.txt.
 
@@ -2390,7 +2390,7 @@
 Sangoma WANPIPE(tm) multiprotocol cards
 CONFIG_VENDOR_SANGOMA
       WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com)
-  is a family of intelligent multiprotocol WAN adapter with data
+  is a family of intelligent multiprotocol WAN adapters with data
   transfer rates up to T1 (1.544 Mbps).  They are also known as
   Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
   or S508.  If you have one of these cards, say 'Y' to this option.
diff -u --recursive --new-file v2.1.25/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.25/linux/MAINTAINERS	Thu Feb  6 12:41:59 1997
+++ linux/MAINTAINERS	Fri Feb  7 15:54:53 1997
@@ -351,6 +351,11 @@
 M:	boldt@math.ucsb.edu
 S:	Maintained
 
+PCI ID DATABASE
+P:	Jens Maurer
+M:	jmaurer@cck.uni-kl.de
+S:	Maintained
+
 LANCE AND LANCE32 NETWORK DRIVER
 P:	Thomas Bogendoerfer
 M:	tsbogend@bigbug.franken.de
diff -u --recursive --new-file v2.1.25/linux/Makefile linux/Makefile
--- v2.1.25/linux/Makefile	Thu Feb  6 12:41:59 1997
+++ linux/Makefile	Fri Feb  7 16:30:55 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 25
+SUBLEVEL = 26
 
 ARCH = i386
 
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/Makefile linux/arch/alpha/Makefile
--- v2.1.25/linux/arch/alpha/Makefile	Sun Aug  4 13:37:59 1996
+++ linux/arch/alpha/Makefile	Thu Feb  6 14:42:34 1997
@@ -24,7 +24,7 @@
 CFLAGS := $(CFLAGS) -pipe
 endif
 
-CFLAGS := $(CFLAGS) -mno-fp-regs
+CFLAGS := $(CFLAGS) -mno-fp-regs -ffixed-8
 
 HEAD := arch/alpha/kernel/head.o
 
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.1.25/linux/arch/alpha/kernel/entry.S	Tue Jan 28 18:49:45 1997
+++ linux/arch/alpha/kernel/entry.S	Thu Feb  6 14:42:35 1997
@@ -127,8 +127,8 @@
 	addq	$1,1,$1
 	stq	$1,0($0)
 /* set up the arguments to the C interrupt handler */
-	lda	$27,do_entInt
-	jsr	$26,($27),do_entInt
+	ldq	$8,current_set
+	jsr	$26,do_entInt
 /* ok, return */
 	lda	$0,intr_count
 	ldq	$1,0($0)
@@ -153,6 +153,7 @@
 	stq	$15,48($30)
 	addq	$30,56,$19
 /* handle the fault */
+	ldq	$8,current_set
 	jsr	$26,do_page_fault
 /* reload the registers after the exception code played.  */
 	ldq	$9,0($30)
@@ -172,6 +173,9 @@
 .ent	entArith
 entArith:
 	SAVE_ALL
+	ldq	$8,current_set
+	/* How much of a win is this clockwise?  We are, after all, messing
+	   up the call/return prefetch stack.  -- rth */
 	lda	$27,do_entArith
 	lda	$26,ret_from_sys_call
 	jsr	$31,($27),do_entArith
@@ -182,6 +186,7 @@
 .ent	entIF
 entIF:
 	SAVE_ALL
+	ldq	$8,current_set
 	lda	$27,do_entIF
 	lda	$26,ret_from_sys_call
 	jsr	$31,($27),do_entIF
@@ -210,8 +215,7 @@
 	stq $18,40($30)
 	bis $31,2,$0	/* Register v0: syscall nr for fork() */
 	SAVE_ALL
-	lda $27,sys_clone
-	jsr $26,($27),sys_clone
+	jsr $26,sys_clone
 	stq $0,0($30)
 	br $31,ret_from_sys_call
 .end	kernel_clone
@@ -240,11 +244,13 @@
 	ret $31,($26),1
 /* this is in child: look out as we don't have any stack here.. */
 1:	bis $9,$9,$27		/* get fn */
+	br $29,2f
+2:	ldgp $29,0($29)
 	bis $10,$10,$16		/* get arg */
+	ldq $8,current_set
 	jsr $26,($27)
 	bis $0,$0,$16
-	lda $27,sys_exit
-	jsr $26,($27),sys_exit
+	jsr $26,sys_exit
 	call_pal PAL_halt
 .end	__kernel_thread
 
@@ -382,8 +388,8 @@
 	stq $29,232($30)
 	stq $30,240($30)
 	stq $31,248($30)
-	lda $27,do_entUna
-	jsr $26,($27),do_entUna
+	ldq $8,current_set
+	jsr $26,do_entUna
 	ldq $0,0($30)
 	ldq $1,8($30)
 	ldq $2,16($30)
@@ -431,9 +437,9 @@
 	stq $13,32($30)
 	stq $14,40($30)
 	stq $15,48($30)
-	lda $27,do_entUnaUser
 	bis $31,$30,$19
-	jsr $26,($27),do_entUnaUser
+	ldq $8,current_set
+	jsr $26,do_entUnaUser
 	ldq $9,0($30)
 	ldq $10,8($30)
 	ldq $11,16($30)
@@ -457,8 +463,7 @@
 	bis $31,SIGCHLD,$16
 	bis $31,$31,$17
 	bis $30,$30,$18
-	lda $27,alpha_clone
-	jsr $26,($27),alpha_clone
+	jsr $26,alpha_clone
 	bsr $1,undo_switch_stack
 	ret $31,($26),1
 .end	sys_fork
@@ -470,8 +475,7 @@
 	bsr $1,do_switch_stack
 	/* arg1 and arg2 come from the user */
 	bis $30,$30,$18
-	lda $27,alpha_clone
-	jsr $26,($27),alpha_clone
+	jsr $26,alpha_clone
 	bsr $1,undo_switch_stack
 	ret $31,($26),1
 .end	sys_clone
@@ -499,14 +503,13 @@
 .ent	entSys
 entSys:
 	SAVE_ALL
-	lda	$1,current_set
+	ldq	$8,current_set
 	lda	$4,NR_SYSCALLS($31)
 	stq	$16,SP_OFF+24($30)
 	lda	$5,sys_call_table
-	ldq	$2,0($1)
 	lda	$27,do_entSys
 	cmpult	$0,$4,$4
-	ldq	$3,TASK_FLAGS($2)
+	ldq	$3,TASK_FLAGS($8)
 	stq	$17,SP_OFF+32($30)
 	s8addq	$0,$5,$5
 	and     $3,PF_PTRACED,$3
@@ -539,15 +542,13 @@
 	beq	$0,restore_all
 ret_from_reschedule:
 	lda	$0,need_resched
-	lda	$1,current_set
 	ldl	$2,0($0)
 	lda	$4,init_task
-	ldq	$3,0($1)
 	bne	$2,reschedule
-	subq	$4,$3,$4
+	xor	$4,$8,$4
 	beq	$4,restore_all
-	ldq	$4,TASK_SIGNAL($3)
-	ldq	$16,TASK_BLOCKED($3)
+	ldq	$4,TASK_SIGNAL($8)
+	ldq	$16,TASK_BLOCKED($8)
 	bic	$4,$16,$4
 	bne	$4,signal_return
 restore_all:
@@ -560,8 +561,7 @@
 strace:
 	/* set up signal stack, call syscall_trace */
 	bsr	$1,do_switch_stack
-	lda     $27,syscall_trace
-	jsr     $26,($27),syscall_trace
+	jsr     $26,syscall_trace
 	bsr	$1,undo_switch_stack
 
 	/* get the system call number and the arguments back.. */
@@ -590,8 +590,7 @@
 	stq	$0,0($30)		/* save return value */
 
 	bsr	$1,do_switch_stack
-	lda     $27,syscall_trace
-	jsr     $26,($27),syscall_trace
+	jsr     $26,syscall_trace
 	bsr	$1,undo_switch_stack
 	br	$31,ret_from_sys_call
 
@@ -609,8 +608,7 @@
 	bsr	$1,do_switch_stack
 	bis	$19,$19,$9	/* save old syscall number */
 	bis	$20,$20,$10	/* save old a3 */
-	lda     $27,syscall_trace
-	jsr     $26,($27),syscall_trace
+	jsr     $26,syscall_trace
 	bis	$9,$9,$19
 	bis	$10,$10,$20
 	bsr	$1,undo_switch_stack
@@ -628,8 +626,7 @@
 	subq	$30,16,$30
 	stq	$19,0($30)	/* save syscall nr */
 	stq	$20,8($30)	/* and error indication (a3) */
-	lda	$27,do_bottom_half
-	jsr	$26,($27),do_bottom_half
+	jsr	$26,do_bottom_half
 	lda	$0,intr_count
 	ldq	$19,0($30)
 	ldq	$20,8($30)
@@ -667,8 +664,7 @@
 	bis	$30,$30,$17
 	br	$1,do_switch_stack
 	bis	$30,$30,$18
-	lda	$27,do_signal
-	jsr	$26,($27),do_signal
+	jsr	$26,do_signal
 	lda	$30,SWITCH_STACK_SIZE($30)
 	br	$31,restore_all
 .end entSys
@@ -679,8 +675,7 @@
 	subq	$30,16,$30
 	stq	$19,0($30)	/* save syscall nr */
 	stq	$20,8($30)	/* and error indication (a3) */
-	lda	$27,schedule
-	jsr	$26,($27),schedule
+	jsr	$26,schedule
 	ldq	$19,0($30)
 	ldq	$20,8($30)
 	addq	$30,16,$30
@@ -693,8 +688,7 @@
 	bis	$30,$30,$17
 	lda	$30,-SWITCH_STACK_SIZE($30)
 	bis	$30,$30,$18
-	lda	$27,do_sigreturn
-	jsr	$26,($27),do_sigreturn
+	jsr	$26,do_sigreturn
 	br	$1,undo_switch_stack
 	br	$31,ret_from_sys_call
 .end sys_sigreturn
@@ -705,8 +699,7 @@
 	bis	$30,$30,$17
 	br	$1,do_switch_stack
 	bis	$30,$30,$18
-	lda	$27,do_sigsuspend
-	jsr	$26,($27),do_sigsuspend
+	jsr	$26,do_sigsuspend
 	lda	$30,SWITCH_STACK_SIZE($30)
 	br	$31,ret_from_sys_call
 .end sys_sigsuspend
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S
--- v2.1.25/linux/arch/alpha/kernel/head.S	Sat Oct 19 10:07:28 1996
+++ linux/arch/alpha/kernel/head.S	Thu Feb  6 14:42:35 1997
@@ -23,8 +23,11 @@
 __start:
 	br	$27,1f
 1:	ldgp	$29,0($27)
-	lda	$27,start_kernel
-	jsr	$26,($27),start_kernel
+	/* We need to get current loaded up with our first task.  */
+	lda	$8,init_task
+	stq	$8,current_set
+	/* And then we can start the kernel.  */
+	jsr	$26,start_kernel
 	halt
 	.end __start
 
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/copy_user.S linux/arch/alpha/lib/copy_user.S
--- v2.1.25/linux/arch/alpha/lib/copy_user.S	Wed Jan 15 19:45:39 1997
+++ linux/arch/alpha/lib/copy_user.S	Thu Feb  6 14:42:35 1997
@@ -17,7 +17,6 @@
  *	length in $0
  *	destination address in $6
  *	source address in $7
- *	exception pointer in $8
  *	return address in $28
  *
  * Outputs:
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/csum_ipv6_magic.S linux/arch/alpha/lib/csum_ipv6_magic.S
--- v2.1.25/linux/arch/alpha/lib/csum_ipv6_magic.S	Tue Nov 12 15:56:02 1996
+++ linux/arch/alpha/lib/csum_ipv6_magic.S	Thu Feb  6 12:44:41 1997
@@ -61,8 +61,8 @@
 	extwl	$0,2,$1		# e0    :
 	zapnot	$0,3,$0		# .. e1 :
 	addq	$0,$1,$0	# e0    :
-	unop			#       :
-	not	$0,$0		# e0    :
+	not	$0,$0		# e1    :
+	zapnot	$0,3,$0		# e0    :
 	ret			# .. e1 :
 
 	.end csum_ipv6_magic
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/csum_partial_copy.c linux/arch/alpha/lib/csum_partial_copy.c
--- v2.1.25/linux/arch/alpha/lib/csum_partial_copy.c	Wed Jul 17 14:39:21 1996
+++ linux/arch/alpha/lib/csum_partial_copy.c	Thu Feb  6 12:44:41 1997
@@ -7,6 +7,11 @@
  * we do for performance..
  */
 
+#include <linux/types.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+
 #define ldq_u(x,y) \
 __asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(unsigned long *)(y)))
 
@@ -31,17 +36,52 @@
 #define insqh(x,y,z) \
 __asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))
 
+
+#define __get_user_u(x,ptr)				\
+({							\
+	long __guu_err;					\
+	__asm__ __volatile__(				\
+	"1:	ldq_u %0,%2\n"				\
+	"2:\n"						\
+	".section __ex_table,\"a\"\n"			\
+	"	.gprel32 1b\n"				\
+	"	lda %0,2b-1b(%1)\n"			\
+	".previous"					\
+		: "=r"(x), "=r"(__guu_err)		\
+		: "m"(__m(ptr)), "1"(0));		\
+	__guu_err;					\
+})
+
+#define __put_user_u(x,ptr)				\
+({							\
+	long __puu_err;					\
+	__asm__ __volatile__(				\
+	"1:	stq_u %2,%1\n"				\
+	"2:\n"						\
+	".section __ex_table,\"a\"\n"			\
+	"	.gprel32 1b"				\
+	"	lda $31,2b-1b(%0)\n"			\
+	".previous"					\
+		: "=r"(__puu_err)			\
+		: "m"(__m(addr)), "rJ"(x), "0"(0));	\
+	__puu_err;					\
+})
+
+
 /*
  * Ok. This isn't fun, but this is the EASY case.
  */
-static inline unsigned long csum_partial_copy_aligned(
-	unsigned long *src, unsigned long *dst,
-	long len, unsigned long checksum)
+static inline unsigned long
+csum_partial_cfu_aligned(unsigned long *src, unsigned long *dst,
+			 long len, unsigned long checksum,
+			 int *errp)
 {
 	unsigned long carry = 0;
+	int err = 0;
 
 	while (len >= 0) {
-		unsigned long word = *src;
+		unsigned long word;
+		err |= __get_user(word, src);
 		checksum += carry;
 		src++;
 		checksum += word;
@@ -54,7 +94,7 @@
 	checksum += carry;
 	if (len) {
 		unsigned long word, tmp;
-		word = *src;
+		err |= __get_user(word, src);
 		tmp = *dst;
 		mskql(word, len, word);
 		checksum += word;
@@ -63,28 +103,31 @@
 		*dst = word | tmp;
 		checksum += carry;
 	}
-	return checksum;	
+	if (err) *errp = err;
+	return checksum;
 }
 
 /*
  * This is even less fun, but this is still reasonably
  * easy.
  */
-static inline unsigned long csum_partial_copy_dest_aligned(
-	unsigned long *src, unsigned long *dst,
-	unsigned long soff,
-	long len, unsigned long checksum)
+static inline unsigned long
+csum_partial_cfu_dest_aligned(unsigned long *src, unsigned long *dst,
+			      unsigned long soff,
+			      long len, unsigned long checksum,
+			      int *errp)
 {
 	unsigned long first;
 	unsigned long word, carry;
 	unsigned long lastsrc = 7+len+(unsigned long)src;
+	int err = 0;
 
-	ldq_u(first,src);
+	err |= __get_user_u(first,src);
 	carry = 0;
 	while (len >= 0) {
 		unsigned long second;
 
-		ldq_u(second, src+1);
+		err |= __get_user_u(second, src+1);
 		extql(first, soff, word);
 		len -= 8;
 		src++;
@@ -102,7 +145,7 @@
 	if (len) {
 		unsigned long tmp;
 		unsigned long second;
-		ldq_u(second, lastsrc);
+		err |= __get_user_u(second, lastsrc);
 		tmp = *dst;
 		extql(first, soff, word);
 		extqh(second, soff, first);
@@ -114,25 +157,28 @@
 		*dst = word | tmp;
 		checksum += carry;
 	}
+	if (err) *errp = err;
 	return checksum;
 }
 
 /*
  * This is slightly less fun than the above..
  */
-static inline unsigned long csum_partial_copy_src_aligned(
-	unsigned long *src, unsigned long *dst,
-	unsigned long doff,
-	long len, unsigned long checksum,
-	unsigned long partial_dest)
+static inline unsigned long
+csum_partial_cfu_src_aligned(unsigned long *src, unsigned long *dst,
+			     unsigned long doff,
+			     long len, unsigned long checksum,
+			     unsigned long partial_dest,
+			     int *errp)
 {
 	unsigned long carry = 0;
 	unsigned long word;
+	int err = 0;
 
 	mskql(partial_dest, doff, partial_dest);
 	while (len >= 0) {
 		unsigned long second_dest;
-		word = *src;
+		err |= __get_user(word, src);
 		len -= 8;
 		insql(word, doff, second_dest);
 		checksum += carry;
@@ -147,7 +193,7 @@
 	checksum += carry;
 	if (len >= 0) {
 		unsigned long second_dest;
-		word = *src;
+		err |= __get_user(word, src);
 		mskql(word, len-doff, word);
 		checksum += word;
 		insql(word, doff, second_dest);
@@ -162,7 +208,7 @@
 		checksum += carry;
 	} else if (len & 7) {
 		unsigned long second_dest;
-		word = *src;
+		err |= __get_user(word, src);
 		ldq_u(second_dest, dst);
 		mskql(word, len-doff, word);
 		checksum += word;
@@ -172,6 +218,7 @@
 		stq_u(partial_dest | word | second_dest, dst);
 		checksum += carry;
 	}
+	if (err) *errp = err;
 	return checksum;
 }
 
@@ -179,24 +226,26 @@
  * This is so totally un-fun that it's frightening. Don't
  * look at this too closely, you'll go blind.
  */
-static inline unsigned long csum_partial_copy_unaligned(
-	unsigned long * src, unsigned long * dst,
-	unsigned long soff, unsigned long doff,
-	long len, unsigned long checksum,
-	unsigned long partial_dest)
+static inline unsigned long
+csum_partial_cfu_unaligned(unsigned long * src, unsigned long * dst,
+			   unsigned long soff, unsigned long doff,
+			   long len, unsigned long checksum,
+			   unsigned long partial_dest,
+			   int *errp)
 {
 	unsigned long carry = 0;
 	unsigned long first;
 	unsigned long lastsrc;
+	int err = 0;
 
-	ldq_u(first, src);
+	err |= __get_user_u(first, src);
 	lastsrc = 7+len+(unsigned long)src;
 	mskql(partial_dest, doff, partial_dest);
 	while (len >= 0) {
 		unsigned long second, word;
 		unsigned long second_dest;
 
-		ldq_u(second, src+1);
+		err |= __get_user_u(second, src+1);
 		extql(first, soff, word);
 		checksum += carry;
 		len -= 8;
@@ -216,8 +265,8 @@
 	if (len >= 0) {
 		unsigned long second, word;
 		unsigned long second_dest;
-		
-		ldq_u(second, lastsrc);
+
+		err |= __get_user_u(second, lastsrc);
 		extql(first, soff, word);
 		extqh(second, soff, first);
 		word |= first;
@@ -233,12 +282,12 @@
 			mskqh(second_dest, len, second_dest);
 			stq_u(partial_dest | second_dest, dst+1);
 		}
-		checksum += carry;			
+		checksum += carry;
 	} else if (len & 7) {
 		unsigned long second, word;
 		unsigned long second_dest;
 
-		ldq_u(second, lastsrc);
+		err |= __get_user_u(second, lastsrc);
 		extql(first, soff, word);
 		extqh(second, soff, first);
 		word |= first;
@@ -251,42 +300,51 @@
 		stq_u(partial_dest | word | second_dest, dst);
 		checksum += carry;
 	}
+	if (err) *errp = err;
 	return checksum;
 }
 
-unsigned int csum_partial_copy(char *src, char *dst, int len, int sum)
+unsigned int
+csum_partial_copy_from_user(int *errp, char *src, char *dst,
+			    int len, unsigned int sum)
 {
 	unsigned long checksum = (unsigned) sum;
 	unsigned long soff = 7 & (unsigned long) src;
 	unsigned long doff = 7 & (unsigned long) dst;
 
+	if (!access_ok(src, len, VERIFY_READ)) {
+		*errp = -EFAULT;
+		memset(dst, 0, len);
+		return checksum;
+	}
+
 	if (len) {
 		if (!doff) {
 			if (!soff)
-				checksum = csum_partial_copy_aligned(
+				checksum = csum_partial_cfu_aligned(
 					(unsigned long *) src,
 					(unsigned long *) dst,
-					len-8, checksum);
+					len-8, checksum, errp);
 			else
-				checksum = csum_partial_copy_dest_aligned(
+				checksum = csum_partial_cfu_dest_aligned(
 					(unsigned long *) src,
 					(unsigned long *) dst,
-					soff, len-8, checksum);
+					soff, len-8, checksum, errp);
 		} else {
 			unsigned long partial_dest;
 			ldq_u(partial_dest, dst);
 			if (!soff)
-				checksum = csum_partial_copy_src_aligned(
+				checksum = csum_partial_cfu_src_aligned(
 					(unsigned long *) src,
 					(unsigned long *) dst,
 					doff, len-8, checksum,
-					partial_dest);
+					partial_dest, errp);
 			else
-				checksum = csum_partial_copy_unaligned(
+				checksum = csum_partial_cfu_unaligned(
 					(unsigned long *) src,
 					(unsigned long *) dst,
 					soff, doff, len-8, checksum,
-					partial_dest);
+					partial_dest, errp);
 		}
 		/* 64 -> 33 bits */
 		checksum = (checksum & 0xffffffff) + (checksum >> 32);
@@ -297,4 +355,17 @@
 		checksum = (checksum & 0xffff) + (checksum >> 16);
 	}
 	return checksum;
+}
+
+unsigned int
+csum_partial_copy (const char *src, char *dst, int len, unsigned int sum)
+{
+	unsigned int ret;
+	int error = 0;
+
+	ret = csum_partial_copy_from_user(&error, src, dst, len, sum);
+	if (error)
+		printk("csum_partial_copy_old(): tell mingo to convert me!\n");
+
+	return ret;
 }
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/strncat.S linux/arch/alpha/lib/strncat.S
--- v2.1.25/linux/arch/alpha/lib/strncat.S	Sat Oct 19 10:07:28 1996
+++ linux/arch/alpha/lib/strncat.S	Thu Feb  6 14:42:35 1997
@@ -56,11 +56,11 @@
 
 	/* Worry about the null termination.  */
 
-	zapnot	$1, $22, $2	# was last byte a null?
+	zapnot	$1, $27, $2	# was last byte a null?
 	bne	$2, 0f
 	ret
 
-0:	cmplt	$22, $24, $2	# did we fill the buffer completely?
+0:	cmplt	$27, $24, $2	# did we fill the buffer completely?
 	or	$2, $18, $2
 	bne	$2, 2f
 
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/strncpy_from_user.S linux/arch/alpha/lib/strncpy_from_user.S
--- v2.1.25/linux/arch/alpha/lib/strncpy_from_user.S	Wed Jan 15 19:45:39 1997
+++ linux/arch/alpha/lib/strncpy_from_user.S	Thu Feb  6 14:48:45 1997
@@ -44,10 +44,10 @@
 	mskqh	t1, a1, t3	# e0    :
 	ornot	t1, t2, t2	# .. e1 :
 	mskql	t0, a1, t0	# e0    : assemble the first output word
-	cmpbge	zero, t2, t7	# .. e1 : bits set iff null found
+	cmpbge	zero, t2, t8	# .. e1 : bits set iff null found
 	or	t0, t3, t0	# e0    :
 	beq	a2, $a_eoc	# .. e1 :
-	bne	t7, $a_eos	# .. e1 :
+	bne	t8, $a_eos	# .. e1 :
 
 	/* On entry to this basic block:
 	   t0 == a source word not containing a null.  */
@@ -58,34 +58,34 @@
 	EX( ldq_u t0, 0(a1) )	# e0    :
 	addq	a1, 8, a1	# .. e1 :
 	subq	a2, 1, a2	# e0    :
-	cmpbge	zero, t0, t7	# .. e1 (stall)
+	cmpbge	zero, t0, t8	# .. e1 (stall)
 	beq	a2, $a_eoc      # e1    :
-	beq	t7, $a_loop	# e1    :
+	beq	t8, $a_loop	# e1    :
 
 	/* Take care of the final (partial) word store.  At this point
-	   the end-of-count bit is set in t7 iff it applies.
+	   the end-of-count bit is set in t8 iff it applies.
 
 	   On entry to this basic block we have:
 	   t0 == the source word containing the null
-	   t7 == the cmpbge mask that found it.  */
+	   t8 == the cmpbge mask that found it.  */
 
 $a_eos:
-	negq	t7, t8		# e0    : find low bit set
-	and	t7, t8, t8	# e1 (stall)
+	negq	t8, t12		# e0    : find low bit set
+	and	t8, t12, t12	# e1 (stall)
 
 	/* For the sake of the cache, don't read a destination word
 	   if we're not going to need it.  */
-	and	t8, 0x80, t6	# e0    :
+	and	t12, 0x80, t6	# e0    :
 	bne	t6, 1f		# .. e1 (zdb)
 
 	/* We're doing a partial word store and so need to combine
 	   our source and original destination words.  */
 	ldq_u	t1, 0(a0)	# e0    :
-	subq	t8, 1, t6	# .. e1 :
-	or	t8, t6, t7	# e0    :
+	subq	t12, 1, t6	# .. e1 :
+	or	t12, t6, t8	# e0    :
 	unop			#
-	zapnot	t0, t7, t0	# e0    : clear src bytes > null
-	zap	t1, t7, t1	# .. e1 : clear dst bytes <= null
+	zapnot	t0, t8, t0	# e0    : clear src bytes > null
+	zap	t1, t8, t1	# .. e1 : clear dst bytes <= null
 	or	t0, t1, t0	# e1    :
 
 1:	stq_u	t0, 0(a0)
@@ -93,7 +93,7 @@
 
 	/* Add the end-of-count bit to the eos detection bitmask.  */
 $a_eoc:
-	or	t10, t7, t7
+	or	t10, t8, t8
 	br	$a_eos
 
 	/*** The Function Entry Point ***/
@@ -148,18 +148,18 @@
 	mskqh	t1, a0, t1	# e0    : mask leading garbage in src
 	or	t0, t1, t0	# e0    : first output word complete
 	or	t0, t6, t6	# e1    : mask original data for zero test
-	cmpbge	zero, t6, t7	# e0    :
+	cmpbge	zero, t6, t8	# e0    :
 	beq	a2, $u_eocfin	# .. e1 :
-	bne	t7, $u_final	# e1    :
+	bne	t8, $u_final	# e1    :
 
 	lda	t6, -1			# e1    : mask out the bits we have
 	mskql	t6, a1, t6		# e0    :   already seen
 	stq_u	t0, 0(a0)		# e0    : store first output word
 	or      t6, t2, t2		# .. e1 :
-	cmpbge	zero, t2, t7		# e0    : find nulls in second partial
+	cmpbge	zero, t2, t8		# e0    : find nulls in second partial
 	addq	a0, 8, a0		# .. e1 :
 	subq	a2, 1, a2		# e0    :
-	bne	t7, $u_late_head_exit	# .. e1 :
+	bne	t8, $u_late_head_exit	# .. e1 :
 
 	/* Finally, we've got all the stupid leading edge cases taken care
 	   of and we can set up to enter the main loop.  */
@@ -167,9 +167,9 @@
 	extql	t2, a1, t1	# e0    : position hi-bits of lo word
 	EX( ldq_u t2, 8(a1) )	# .. e1 : read next high-order source word
 	addq	a1, 8, a1	# e0    :
-	cmpbge	zero, t2, t7	# e1 (stall)
+	cmpbge	zero, t2, t8	# e1 (stall)
 	beq	a2, $u_eoc	# e1    :
-	bne	t7, $u_eos	# e1    :
+	bne	t8, $u_eos	# e1    :
 
 	/* Unaligned copy main loop.  In order to avoid reading too much,
 	   the loop is structured to detect zeros in aligned source words.
@@ -195,9 +195,9 @@
 	stq_u	t0, -8(a0)	# e0    : save the current word
 	mov	t3, t1		# .. e1 :
 	subq	a2, 1, a2	# e0    :
-	cmpbge	zero, t2, t7	# .. e1 : test new word for eos
+	cmpbge	zero, t2, t8	# .. e1 : test new word for eos
 	beq	a2, $u_eoc	# e1    :
-	beq	t7, $u_loop	# e1    :
+	beq	t8, $u_loop	# e1    :
 
 	/* We've found a zero somewhere in the source word we just read.
 	   If it resides in the lower half, we have one (probably partial)
@@ -211,8 +211,8 @@
 	extqh	t2, a1, t0	# e0    :
 	or	t0, t1, t0	# e1    : first (partial) source word complete
 
-	cmpbge	zero, t0, t7	# e0    : is the null in this first bit?
-	bne	t7, $u_final	# .. e1 (zdb)
+	cmpbge	zero, t0, t8	# e0    : is the null in this first bit?
+	bne	t8, $u_final	# .. e1 (zdb)
 
 	stq_u	t0, 0(a0)	# e0    : the null was in the high-order bits
 	addq	a0, 8, a0	# .. e1 :
@@ -220,27 +220,27 @@
 
 $u_late_head_exit:
 	extql	t2, a1, t0	# .. e0 :
-	cmpbge	zero, t0, t7	# e0    :
-	or	t7, t10, t6	# e1    :
-	cmoveq	a2, t6, t7	# e0    :
+	cmpbge	zero, t0, t8	# e0    :
+	or	t8, t10, t6	# e1    :
+	cmoveq	a2, t6, t8	# e0    :
 	nop			# .. e1 :
 
 	/* Take care of a final (probably partial) result word.
 	   On entry to this basic block:
 	   t0 == assembled source word
-	   t7 == cmpbge mask that found the null.  */
+	   t8 == cmpbge mask that found the null.  */
 $u_final:
-	negq	t7, t6		# e0    : isolate low bit set
-	and	t6, t7, t8	# e1    :
+	negq	t8, t6		# e0    : isolate low bit set
+	and	t6, t8, t12	# e1    :
 
-	and	t8, 0x80, t6	# e0    : avoid dest word load if we can
+	and	t12, 0x80, t6	# e0    : avoid dest word load if we can
 	bne	t6, 1f		# .. e1 (zdb)
 
 	ldq_u	t1, 0(a0)	# e0    :
-	subq	t8, 1, t6	# .. e1 :
-	or	t6, t8, t7	# e0    :
-	zapnot	t0, t7, t0	# .. e1 : kill source bytes > null
-	zap	t1, t7, t1	# e0    : kill dest bytes <= null
+	subq	t12, 1, t6	# .. e1 :
+	or	t6, t12, t8	# e0    :
+	zapnot	t0, t8, t0	# .. e1 : kill source bytes > null
+	zap	t1, t8, t1	# e0    : kill dest bytes <= null
 	or	t0, t1, t0	# e1    :
 
 1:	stq_u	t0, 0(a0)	# e0    :
@@ -249,10 +249,10 @@
 $u_eoc:				# end-of-count
 	extqh	t2, a1, t0
 	or	t0, t1, t0
-	cmpbge	zero, t0, t7
+	cmpbge	zero, t0, t8
 
 $u_eocfin:			# end-of-count, final word
-	or	t10, t7, t7
+	or	t10, t8, t8
 	br	$u_final
 
 	/* Unaligned copy entry point.  */
@@ -279,19 +279,19 @@
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t8	# e1    :
+	cmplt	t4, t5, t12	# e1    :
 	extql	t1, a1, t1	# .. e0 : shift src into place
 	lda	t2, -1		# e0    : for creating masks later
-	beq	t8, $u_head	# e1    :
+	beq	t12, $u_head	# e1    :
 
 	mskqh	t2, t5, t2	# e0    : begin src byte validity mask
-	cmpbge	zero, t1, t7	# .. e1 : is there a zero?
+	cmpbge	zero, t1, t8	# .. e1 : is there a zero?
 	extql	t2, a1, t2	# e0    :
-	or	t7, t10, t6	# .. e1 : test for end-of-count too
+	or	t8, t10, t5	# .. e1 : test for end-of-count too
 	cmpbge	zero, t2, t3	# e0    :
-	cmoveq	a2, t6, t7	# .. e1 :
-	andnot	t7, t3, t7	# e0    :
-	beq	t7, $u_head	# .. e1 (zdb)
+	cmoveq	a2, t5, t8	# .. e1 :
+	andnot	t8, t3, t8	# e0    :
+	beq	t8, $u_head	# .. e1 (zdb)
 
 	/* At this point we've found a zero in the first partial word of
 	   the source.  We need to isolate the valid source data and mask
@@ -299,26 +299,26 @@
 	   that we'll need at least one byte of that original dest word.) */
 
 	ldq_u	t0, 0(a0)	# e0    :
-	negq	t7, t6		# .. e1 : build bitmask of bytes <= zero
+	negq	t8, t6		# .. e1 : build bitmask of bytes <= zero
 	mskqh	t1, t4, t1	# e0    :
-	and	t6, t7, t8	# .. e1 :
-	subq	t8, 1, t6	# e0    :
-	or	t6, t8, t7	# e1    :
+	and	t6, t8, t12	# .. e1 :
+	subq	t12, 1, t6	# e0    :
+	or	t6, t12, t8	# e1    :
 
-	zapnot	t2, t7, t2	# e0    : prepare source word; mirror changes
-	zapnot	t1, t7, t1	# .. e1 : to source validity mask
+	zapnot	t2, t8, t2	# e0    : prepare source word; mirror changes
+	zapnot	t1, t8, t1	# .. e1 : to source validity mask
 
 	andnot	t0, t2, t0	# e0    : zero place for source to reside
 	or	t0, t1, t0	# e1    : and put it there
 	stq_u	t0, 0(a0)	# e0    :
 
 $finish_up:
-	zapnot	t0, t8, t4	# was last byte written null?
+	zapnot	t0, t12, t4	# was last byte written null?
 	cmovne	t4, 1, t4
 
-	and	t8, 0xf0, t3	# binary search for the address of the
-	and	t8, 0xcc, t2	# last byte written
-	and	t8, 0xaa, t1
+	and	t12, 0xf0, t3	# binary search for the address of the
+	and	t12, 0xcc, t2	# last byte written
+	and	t12, 0xaa, t1
 	bic	a0, 7, t0
 	cmovne	t3, 4, t3
 	cmovne	t2, 2, t2
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/stxcpy.S linux/arch/alpha/lib/stxcpy.S
--- v2.1.25/linux/arch/alpha/lib/stxcpy.S	Sat Oct 19 10:07:28 1996
+++ linux/arch/alpha/lib/stxcpy.S	Thu Feb  6 14:42:35 1997
@@ -13,7 +13,7 @@
  *	a1 = SRC
  *
  * On output:
- *	t8  = bitmask (with one bit set) indicating the last byte written
+ *	t12 = bitmask (with one bit set) indicating the last byte written
  *	a0  = unaligned address of the last *word* written
  *
  * Furthermore, v0, a3-a5, t11, and t12 are untouched.
@@ -47,9 +47,9 @@
 	mskqh	t1, a1, t3	# e0    :
 	ornot	t1, t2, t2	# .. e1 :
 	mskql	t0, a1, t0	# e0    : assemble the first output word
-	cmpbge	zero, t2, t7	# .. e1 : bits set iff null found
+	cmpbge	zero, t2, t8	# .. e1 : bits set iff null found
 	or	t0, t3, t1	# e0    :
-	bne	t7, $a_eos	# .. e1 :
+	bne	t8, $a_eos	# .. e1 :
 
 	/* On entry to this basic block:
 	   t0 == the first destination word for masking back in
@@ -60,29 +60,29 @@
 	addq	a0, 8, a0	# .. e1 :
 	ldq_u	t1, 0(a1)	# e0    :
 	addq	a1, 8, a1	# .. e1 :
-	cmpbge	zero, t1, t7	# e0 (stall)
-	beq	t7, $a_loop	# .. e1 (zdb)
+	cmpbge	zero, t1, t8	# e0 (stall)
+	beq	t8, $a_loop	# .. e1 (zdb)
 
 	/* Take care of the final (partial) word store.
 	   On entry to this basic block we have:
 	   t1 == the source word containing the null
-	   t7 == the cmpbge mask that found it.  */
+	   t8 == the cmpbge mask that found it.  */
 $a_eos:
-	negq	t7, t6		# e0    : find low bit set
-	and	t7, t6, t8	# e1 (stall)
+	negq	t8, t6		# e0    : find low bit set
+	and	t8, t6, t12	# e1 (stall)
 
 	/* For the sake of the cache, don't read a destination word
 	   if we're not going to need it.  */
-	and	t8, 0x80, t6	# e0    :
+	and	t12, 0x80, t6	# e0    :
 	bne	t6, 1f		# .. e1 (zdb)
 
 	/* We're doing a partial word store and so need to combine
 	   our source and original destination words.  */
 	ldq_u	t0, 0(a0)	# e0    :
-	subq	t8, 1, t6	# .. e1 :
+	subq	t12, 1, t6	# .. e1 :
 	zapnot	t1, t6, t1	# e0    : clear src bytes >= null
-	or	t8, t6, t7	# .. e1 :
-	zap	t0, t7, t0	# e0    : clear dst bytes <= null
+	or	t12, t6, t8	# .. e1 :
+	zap	t0, t8, t0	# e0    : clear dst bytes <= null
 	or	t0, t1, t1	# e1    :
 
 1:	stq_u	t1, 0(a0)	# e0    :
@@ -138,14 +138,14 @@
 	or	t0, t1, t1	# e1    :
 
 	or	t1, t6, t6	# e0    :
-	cmpbge	zero, t6, t7	# .. e1 :
+	cmpbge	zero, t6, t8	# .. e1 :
 	lda	t6, -1		# e0    : for masking just below
-	bne	t7, $u_final	# .. e1 :
+	bne	t8, $u_final	# .. e1 :
 
 	mskql	t6, a1, t6		# e0    : mask out the bits we have
 	or	t6, t2, t2		# e1    :   already extracted before
-	cmpbge	zero, t2, t7		# e0    :   testing eos
-	bne	t7, $u_late_head_exit	# .. e1 (zdb)
+	cmpbge	zero, t2, t8		# e0    :   testing eos
+	bne	t8, $u_late_head_exit	# .. e1 (zdb)
 
 	/* Finally, we've got all the stupid leading edge cases taken care
 	   of and we can set up to enter the main loop.  */
@@ -155,9 +155,9 @@
 	extql	t2, a1, t0	# e0    : position ho-bits of lo word
 	ldq_u	t2, 8(a1)	# .. e1 : read next high-order source word
 	addq	a1, 8, a1	# e0    :
-	cmpbge	zero, t2, t7	# .. e1 :
+	cmpbge	zero, t2, t8	# .. e1 :
 	nop			# e0    :
-	bne	t7, $u_eos	# .. e1 :
+	bne	t8, $u_eos	# .. e1 :
 
 	/* Unaligned copy main loop.  In order to avoid reading too much,
 	   the loop is structured to detect zeros in aligned source words.
@@ -182,8 +182,8 @@
 	ldq_u	t2, 0(a1)	# .. e1 : load high word for next time
 	stq_u	t1, -8(a0)	# e0    : save the current word
 	mov	t3, t0		# .. e1 :
-	cmpbge	zero, t2, t7	# e0    : test new word for eos
-	beq	t7, $u_loop	# .. e1 :
+	cmpbge	zero, t2, t8	# e0    : test new word for eos
+	beq	t8, $u_loop	# .. e1 :
 
 	/* We've found a zero somewhere in the source word we just read.
 	   If it resides in the lower half, we have one (probably partial)
@@ -197,31 +197,31 @@
 	extqh	t2, a1, t1	# e0    :
 	or	t0, t1, t1	# e1    : first (partial) source word complete
 
-	cmpbge	zero, t1, t7	# e0    : is the null in this first bit?
-	bne	t7, $u_final	# .. e1 (zdb)
+	cmpbge	zero, t1, t8	# e0    : is the null in this first bit?
+	bne	t8, $u_final	# .. e1 (zdb)
 
 $u_late_head_exit:
 	stq_u	t1, 0(a0)	# e0    : the null was in the high-order bits
 	addq	a0, 8, a0	# .. e1 :
 	extql	t2, a1, t1	# e0    :
-	cmpbge	zero, t1, t7	# .. e1 :
+	cmpbge	zero, t1, t8	# .. e1 :
 
 	/* Take care of a final (probably partial) result word.
 	   On entry to this basic block:
 	   t1 == assembled source word
-	   t7 == cmpbge mask that found the null.  */
+	   t8 == cmpbge mask that found the null.  */
 $u_final:
-	negq	t7, t6		# e0    : isolate low bit set
-	and	t6, t7, t8	# e1    :
+	negq	t8, t6		# e0    : isolate low bit set
+	and	t6, t8, t12	# e1    :
 
-	and	t8, 0x80, t6	# e0    : avoid dest word load if we can
+	and	t12, 0x80, t6	# e0    : avoid dest word load if we can
 	bne	t6, 1f		# .. e1 (zdb)
 
 	ldq_u	t0, 0(a0)	# e0    :
-	subq	t8, 1, t6	# .. e1 :
-	or	t6, t8, t7	# e0    :
+	subq	t12, 1, t6	# .. e1 :
+	or	t6, t12, t8	# e0    :
 	zapnot	t1, t6, t1	# .. e1 : kill source bytes >= null
-	zap	t0, t7, t0	# e0    : kill dest bytes <= null
+	zap	t0, t8, t0	# e0    : kill dest bytes <= null
 	or	t0, t1, t1	# e1    :
 
 1:	stq_u	t1, 0(a0)	# e0    :
@@ -251,15 +251,15 @@
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t8	# e0    :
-	beq	t8, $u_head	# .. e1 (zdb)
+	cmplt	t4, t5, t12	# e0    :
+	beq	t12, $u_head	# .. e1 (zdb)
 
 	lda	t2, -1		# e1    : mask out leading garbage in source
 	mskqh	t2, t5, t2	# e0    :
 	nop			# e0    :
 	ornot	t1, t2, t3	# .. e1 :
-	cmpbge	zero, t3, t7	# e0    : is there a zero?
-	beq	t7, $u_head	# .. e1 (zdb)
+	cmpbge	zero, t3, t8	# e0    : is there a zero?
+	beq	t8, $u_head	# .. e1 (zdb)
 
 	/* At this point we've found a zero in the first partial word of
 	   the source.  We need to isolate the valid source data and mask
@@ -268,14 +268,14 @@
 
 	ldq_u	t0, 0(a0)	# e0    :
 
-	negq	t7, t6		# .. e1 : build bitmask of bytes <= zero
-	and	t6, t7, t8	# e0    :
+	negq	t8, t6		# .. e1 : build bitmask of bytes <= zero
+	and	t6, t8, t12	# e0    :
 	and	a1, 7, t5	# .. e1 :
-	subq	t8, 1, t6	# e0    :
-	or	t6, t8, t7	# e1    :
-	srl	t8, t5, t8	# e0    : adjust final null return value
+	subq	t12, 1, t6	# e0    :
+	or	t6, t12, t8	# e1    :
+	srl	t12, t5, t12	# e0    : adjust final null return value
 
-	zapnot	t2, t7, t2	# .. e1 : prepare source word; mirror changes
+	zapnot	t2, t8, t2	# .. e1 : prepare source word; mirror changes
 	and	t1, t2, t1	# e1    : to source validity mask
 	extql	t2, a1, t2	# .. e0 :
 	extql	t1, a1, t1	# e0    :
diff -u --recursive --new-file v2.1.25/linux/arch/alpha/lib/stxncpy.S linux/arch/alpha/lib/stxncpy.S
--- v2.1.25/linux/arch/alpha/lib/stxncpy.S	Sat Oct 19 10:07:28 1996
+++ linux/arch/alpha/lib/stxncpy.S	Thu Feb  6 14:51:09 1997
@@ -18,9 +18,9 @@
  *
  * On output:
  *	t0  = last word written
- *	t8  = bitmask (with one bit set) indicating the last byte written
  *	t10 = bitmask (with one bit set) indicating the byte position of
  *	      the end of the range specified by COUNT
+ *	t12 = bitmask (with one bit set) indicating the last byte written
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
@@ -55,10 +55,10 @@
 	mskqh	t1, a1, t3	# e0    :
 	ornot	t1, t2, t2	# .. e1 :
 	mskql	t0, a1, t0	# e0    : assemble the first output word
-	cmpbge	zero, t2, t7	# .. e1 : bits set iff null found
+	cmpbge	zero, t2, t8	# .. e1 : bits set iff null found
 	or	t0, t3, t0	# e0    :
 	beq	a2, $a_eoc	# .. e1 :
-	bne	t7, $a_eos	# .. e1 :
+	bne	t8, $a_eos	# .. e1 :
 
 	/* On entry to this basic block:
 	   t0 == a source word not containing a null.  */
@@ -69,34 +69,34 @@
 	ldq_u	t0, 0(a1)	# e0    :
 	addq	a1, 8, a1	# .. e1 :
 	subq	a2, 1, a2	# e0    :
-	cmpbge	zero, t0, t7	# .. e1 (stall)
+	cmpbge	zero, t0, t8	# .. e1 (stall)
 	beq	a2, $a_eoc      # e1    :
-	beq	t7, $a_loop	# e1    :
+	beq	t8, $a_loop	# e1    :
 
 	/* Take care of the final (partial) word store.  At this point
-	   the end-of-count bit is set in t7 iff it applies.
+	   the end-of-count bit is set in t8 iff it applies.
 
 	   On entry to this basic block we have:
 	   t0 == the source word containing the null
-	   t7 == the cmpbge mask that found it.  */
+	   t8 == the cmpbge mask that found it.  */
 
 $a_eos:
-	negq	t7, t8		# e0    : find low bit set
-	and	t7, t8, t8	# e1 (stall)
+	negq	t8, t12		# e0    : find low bit set
+	and	t8, t12, t12	# e1 (stall)
 
 	/* For the sake of the cache, don't read a destination word
 	   if we're not going to need it.  */
-	and	t8, 0x80, t6	# e0    :
+	and	t12, 0x80, t6	# e0    :
 	bne	t6, 1f		# .. e1 (zdb)
 
 	/* We're doing a partial word store and so need to combine
 	   our source and original destination words.  */
 	ldq_u	t1, 0(a0)	# e0    :
-	subq	t8, 1, t6	# .. e1 :
-	or	t8, t6, t7	# e0    :
+	subq	t12, 1, t6	# .. e1 :
+	or	t12, t6, t8	# e0    :
 	unop			#
-	zapnot	t0, t7, t0	# e0    : clear src bytes > null
-	zap	t1, t7, t1	# .. e1 : clear dst bytes <= null
+	zapnot	t0, t8, t0	# e0    : clear src bytes > null
+	zap	t1, t8, t1	# .. e1 : clear dst bytes <= null
 	or	t0, t1, t0	# e1    :
 
 1:	stq_u	t0, 0(a0)	# e0    :
@@ -104,7 +104,7 @@
 
 	/* Add the end-of-count bit to the eos detection bitmask.  */
 $a_eoc:
-	or	t10, t7, t7
+	or	t10, t8, t8
 	br	$a_eos
 
 	.end stxncpy_aligned
@@ -161,18 +161,18 @@
 	mskqh	t1, a0, t1	# e0    : mask leading garbage in src
 	or	t0, t1, t0	# e0    : first output word complete
 	or	t0, t6, t6	# e1    : mask original data for zero test
-	cmpbge	zero, t6, t7	# e0    :
+	cmpbge	zero, t6, t8	# e0    :
 	beq	a2, $u_eocfin	# .. e1 :
-	bne	t7, $u_final	# e1    :
+	bne	t8, $u_final	# e1    :
 
 	lda	t6, -1			# e1    : mask out the bits we have
 	mskql	t6, a1, t6		# e0    :   already seen
 	stq_u	t0, 0(a0)		# e0    : store first output word
 	or      t6, t2, t2		# .. e1 :
-	cmpbge	zero, t2, t7		# e0    : find nulls in second partial
+	cmpbge	zero, t2, t8		# e0    : find nulls in second partial
 	addq	a0, 8, a0		# .. e1 :
 	subq	a2, 1, a2		# e0    :
-	bne	t7, $u_late_head_exit	# .. e1 :
+	bne	t8, $u_late_head_exit	# .. e1 :
 
 	/* Finally, we've got all the stupid leading edge cases taken care
 	   of and we can set up to enter the main loop.  */
@@ -180,9 +180,9 @@
 	extql	t2, a1, t1	# e0    : position hi-bits of lo word
 	ldq_u	t2, 8(a1)	# .. e1 : read next high-order source word
 	addq	a1, 8, a1	# e0    :
-	cmpbge	zero, t2, t7	# e1 (stall)
+	cmpbge	zero, t2, t8	# e1 (stall)
 	beq	a2, $u_eoc	# e1    :
-	bne	t7, $u_eos	# e1    :
+	bne	t8, $u_eos	# e1    :
 
 	/* Unaligned copy main loop.  In order to avoid reading too much,
 	   the loop is structured to detect zeros in aligned source words.
@@ -208,9 +208,9 @@
 	stq_u	t0, -8(a0)	# e0    : save the current word
 	mov	t3, t1		# .. e1 :
 	subq	a2, 1, a2	# e0    :
-	cmpbge	zero, t2, t7	# .. e1 : test new word for eos
+	cmpbge	zero, t2, t8	# .. e1 : test new word for eos
 	beq	a2, $u_eoc	# e1    :
-	beq	t7, $u_loop	# e1    :
+	beq	t8, $u_loop	# e1    :
 
 	/* We've found a zero somewhere in the source word we just read.
 	   If it resides in the lower half, we have one (probably partial)
@@ -224,8 +224,8 @@
 	extqh	t2, a1, t0	# e0    :
 	or	t0, t1, t0	# e1    : first (partial) source word complete
 
-	cmpbge	zero, t0, t7	# e0    : is the null in this first bit?
-	bne	t7, $u_final	# .. e1 (zdb)
+	cmpbge	zero, t0, t8	# e0    : is the null in this first bit?
+	bne	t8, $u_final	# .. e1 (zdb)
 
 	stq_u	t0, 0(a0)	# e0    : the null was in the high-order bits
 	addq	a0, 8, a0	# .. e1 :
@@ -233,27 +233,27 @@
 
 $u_late_head_exit:
 	extql	t2, a1, t0	# .. e0 :
-	cmpbge	zero, t0, t7	# e0    :
-	or	t7, t10, t6	# e1    :
-	cmoveq	a2, t6, t7	# e0    :
+	cmpbge	zero, t0, t8	# e0    :
+	or	t8, t10, t6	# e1    :
+	cmoveq	a2, t6, t8	# e0    :
 	nop			# .. e1 :
 
 	/* Take care of a final (probably partial) result word.
 	   On entry to this basic block:
 	   t0 == assembled source word
-	   t7 == cmpbge mask that found the null.  */
+	   t8 == cmpbge mask that found the null.  */
 $u_final:
-	negq	t7, t6		# e0    : isolate low bit set
-	and	t6, t7, t8	# e1    :
+	negq	t8, t6		# e0    : isolate low bit set
+	and	t6, t8, t12	# e1    :
 
-	and	t8, 0x80, t6	# e0    : avoid dest word load if we can
+	and	t12, 0x80, t6	# e0    : avoid dest word load if we can
 	bne	t6, 1f		# .. e1 (zdb)
 
 	ldq_u	t1, 0(a0)	# e0    :
-	subq	t8, 1, t6	# .. e1 :
-	or	t6, t8, t7	# e0    :
-	zapnot	t0, t7, t0	# .. e1 : kill source bytes > null
-	zap	t1, t7, t1	# e0    : kill dest bytes <= null
+	subq	t12, 1, t6	# .. e1 :
+	or	t6, t12, t8	# e0    :
+	zapnot	t0, t8, t0	# .. e1 : kill source bytes > null
+	zap	t1, t8, t1	# e0    : kill dest bytes <= null
 	or	t0, t1, t0	# e1    :
 
 1:	stq_u	t0, 0(a0)	# e0    :
@@ -262,10 +262,10 @@
 $u_eoc:				# end-of-count
 	extqh	t2, a1, t0
 	or	t0, t1, t0
-	cmpbge	zero, t0, t7
+	cmpbge	zero, t0, t8
 
 $u_eocfin:			# end-of-count, final word
-	or	t10, t7, t7
+	or	t10, t8, t8
 	br	$u_final
 
 	/* Unaligned copy entry point.  */
@@ -292,19 +292,19 @@
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t8	# e1    :
+	cmplt	t4, t5, t12	# e1    :
 	extql	t1, a1, t1	# .. e0 : shift src into place
 	lda	t2, -1		# e0    : for creating masks later
-	beq	t8, $u_head	# e1    :
+	beq	t12, $u_head	# e1    :
 
 	mskqh	t2, t5, t2	# e0    : begin src byte validity mask
-	cmpbge	zero, t1, t7	# .. e1 : is there a zero?
+	cmpbge	zero, t1, t8	# .. e1 : is there a zero?
 	extql	t2, a1, t2	# e0    :
-	or	t7, t10, t6	# .. e1 : test for end-of-count too
+	or	t8, t10, t5	# .. e1 : test for end-of-count too
 	cmpbge	zero, t2, t3	# e0    :
-	cmoveq	a2, t6, t7	# .. e1 :
-	andnot	t7, t3, t7	# e0    :
-	beq	t7, $u_head	# .. e1 (zdb)
+	cmoveq	a2, t5, t8	# .. e1 :
+	andnot	t8, t3, t8	# e0    :
+	beq	t8, $u_head	# .. e1 (zdb)
 
 	/* At this point we've found a zero in the first partial word of
 	   the source.  We need to isolate the valid source data and mask
@@ -312,14 +312,14 @@
 	   that we'll need at least one byte of that original dest word.) */
 
 	ldq_u	t0, 0(a0)	# e0    :
-	negq	t7, t6		# .. e1 : build bitmask of bytes <= zero
+	negq	t8, t6		# .. e1 : build bitmask of bytes <= zero
 	mskqh	t1, t4, t1	# e0    :
-	and	t6, t7, t8	# .. e1 :
-	subq	t8, 1, t6	# e0    :
-	or	t6, t8, t7	# e1    :
+	and	t6, t8, t12	# .. e1 :
+	subq	t12, 1, t6	# e0    :
+	or	t6, t12, t8	# e1    :
 
-	zapnot	t2, t7, t2	# e0    : prepare source word; mirror changes
-	zapnot	t1, t7, t1	# .. e1 : to source validity mask
+	zapnot	t2, t8, t2	# e0    : prepare source word; mirror changes
+	zapnot	t1, t8, t1	# .. e1 : to source validity mask
 
 	andnot	t0, t2, t0	# e0    : zero place for source to reside
 	or	t0, t1, t0	# e1    : and put it there
diff -u --recursive --new-file v2.1.25/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.25/linux/arch/i386/defconfig	Thu Jan 23 21:06:46 1997
+++ linux/arch/i386/defconfig	Fri Feb  7 16:49:49 1997
@@ -68,9 +68,10 @@
 # CONFIG_FIREWALL is not set
 # CONFIG_NET_ALIAS is not set
 CONFIG_INET=y
-# CONFIG_IP_FORWARD is not set
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -116,9 +117,9 @@
 # CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
-# CONFIG_LAPBETHER is not set
 # CONFIG_SLIP is not set
 # CONFIG_TR is not set
+# CONFIG_LAPBETHER is not set
 
 #
 # ISDN subsystem
diff -u --recursive --new-file v2.1.25/linux/arch/i386/kernel/ioport.c linux/arch/i386/kernel/ioport.c
--- v2.1.25/linux/arch/i386/kernel/ioport.c	Tue Jan 28 18:49:46 1997
+++ linux/arch/i386/kernel/ioport.c	Tue Feb  4 16:44:24 1997
@@ -53,19 +53,13 @@
  */
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
-	int ret = -EINVAL;
-
-	lock_kernel();
 	if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
-		goto out;
-	ret = -EPERM;
+		return -EINVAL;
 	if (!suser())
-		goto out;
+		return -EPERM;
+		
 	set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
+	return 0;
 }
 
 unsigned int *stack;
@@ -80,23 +74,18 @@
  * on system-call entry - see also fork() and the signal handling
  * code.
  */
+
 asmlinkage int sys_iopl(long ebx,long ecx,long edx,
 	     long esi, long edi, long ebp, long eax, long ds,
 	     long es, long orig_eax, long eip, long cs,
 	     long eflags, long esp, long ss)
 {
 	unsigned int level = ebx;
-	int ret = -EINVAL;
 
-	lock_kernel();
 	if (level > 3)
-		goto out;
-	ret = -EPERM;
+		return -EINVAL;
 	if (!suser())
-		goto out;
+		return -EPERM;
 	*(&eflags) = (eflags & 0xffffcfff) | (level << 12);
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
+	return 0;
 }
diff -u --recursive --new-file v2.1.25/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c
--- v2.1.25/linux/arch/i386/kernel/sys_i386.c	Tue Jan 28 18:49:47 1997
+++ linux/arch/i386/kernel/sys_i386.c	Fri Feb  7 15:54:53 1997
@@ -32,11 +32,11 @@
 
 	lock_kernel();
 	error = do_pipe(fd);
+	unlock_kernel();
 	if (!error) {
 		if (copy_to_user(fildes, fd, 2*sizeof(int)))
 			error = -EFAULT;
 	}
-	unlock_kernel();
 	return error;
 }
 
@@ -46,6 +46,7 @@
  * 4 system call parameters, so these system calls used a memory
  * block for parameter passing..
  */
+
 struct mmap_arg_struct {
 	unsigned long addr;
 	unsigned long len;
@@ -87,13 +88,12 @@
 asmlinkage int old_select(struct sel_arg_struct *arg)
 {
 	struct sel_arg_struct a;
-	int ret = -EFAULT;
+	int ret;
 
-	lock_kernel();
 	if (copy_from_user(&a, arg, sizeof(a)))
-		goto out;
+		return -EFAULT;
+	lock_kernel();
 	ret = sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
-out:
 	unlock_kernel();
 	return ret;
 }
diff -u --recursive --new-file v2.1.25/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.25/linux/arch/i386/kernel/time.c	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/kernel/time.c	Fri Feb  7 15:54:54 1997
@@ -41,38 +41,33 @@
 	unsigned long high;
 } init_timer_cc, last_timer_cc;
 
-/*
- * This is more assembly than C, but it's also rather
- * timing-critical and we have to use assembler to get
- * reasonable 64-bit arithmetic
- */
+extern volatile unsigned long lost_ticks;
+
+/* change this if you have some constant time drift */
+#define USECS_PER_JIFFY (1000020/HZ)
+
 static unsigned long do_fast_gettimeoffset(void)
 {
 	register unsigned long eax asm("ax");
 	register unsigned long edx asm("dx");
-	unsigned long tmp, quotient, low_timer, missing_time;
+	unsigned long tmp, quotient, low_timer;
 
-	/* Last jiffy when do_fast_gettimeoffset() was called.. */
+	/* Last jiffy when do_fast_gettimeoffset() was called. */
 	static unsigned long last_jiffies=0;
 
-	/* Cached "clocks per usec" value.. */
+	/*
+	 * Cached "1/(clocks per usec)*2^32" value. 
+	 * It has to be recalculated once each jiffy.
+	 */
 	static unsigned long cached_quotient=0;
 
-	/* The "clocks per usec" value is calculated once each jiffy */
 	tmp = jiffies;
+
 	quotient = cached_quotient;
 	low_timer = last_timer_cc.low;
-	missing_time = 0;
+
 	if (last_jiffies != tmp) {
 		last_jiffies = tmp;
-		/*
-		 * test for hanging bottom handler (this means xtime is not 
-		 * updated yet)
-		 */
-		if (test_bit(TIMER_BH, &bh_active) )
-		{
-			missing_time = 1000020/HZ;
-		}
 
 		/* Get last timer tick in absolute kernel time */
 		eax = low_timer;
@@ -86,14 +81,16 @@
 		 * Divide the 64-bit time with the 32-bit jiffy counter,
 		 * getting the quotient in clocks.
 		 *
-		 * Giving quotient = "average internal clocks per usec"
+		 * Giving quotient = "1/(average internal clocks per usec)*2^32"
+		 * we do this '1/...' trick to get the 'mull' into the critical 
+		 * path. 'mull' is much faster than divl (10 vs. 41 clocks)
 		 */
 		__asm__("divl %2"
 			:"=a" (eax), "=d" (edx)
 			:"r" (tmp),
 			 "0" (eax), "1" (edx));
 
-		edx = 1000020/HZ;
+		edx = USECS_PER_JIFFY;
 		tmp = eax;
 		eax = 0;
 
@@ -114,7 +111,7 @@
 	eax -= low_timer;
 
 	/*
-	 * Time offset = (1000020/HZ * time_low) / quotient.
+	 * Time offset = (USECS_PER_JIFFY * time_low) * quotient.
 	 */
 
 	__asm__("mull %2"
@@ -123,15 +120,13 @@
 		 "0" (eax), "1" (edx));
 
 	/*
- 	 * Due to rounding errors (and jiffies inconsistencies),
-	 * we need to check the result so that we'll get a timer
-	 * that is monotonic.
+ 	 * Due to possible jiffies inconsistencies, we need to check 
+	 * the result so that we'll get a timer that is monotonic.
 	 */
-	if (edx >= 1000020/HZ)
-		edx = 1000020/HZ-1;
+	if (edx >= USECS_PER_JIFFY)
+		edx = USECS_PER_JIFFY-1;
 
-	eax = edx + missing_time;
-	return eax;
+	return edx;
 }
 #endif
 
@@ -172,8 +167,8 @@
 static unsigned long do_slow_gettimeoffset(void)
 {
 	int count;
-	static int count_p = 0;
-	unsigned long offset = 0;
+
+	static int count_p = LATCH;    /* for the first call after boot */
 	static unsigned long jiffies_p = 0;
 
 	/*
@@ -183,53 +178,69 @@
 
 	/* timer count may underflow right here */
 	outb_p(0x00, 0x43);	/* latch the count ASAP */
+
 	count = inb_p(0x40);	/* read the latched count */
-	count |= inb(0x40) << 8;
 
+	/*
+	 * We do this guaranteed double memory access instead of a _p 
+	 * postfix in the previous port access. Wheee, hackady hack
+	 */
  	jiffies_t = jiffies;
 
+	count |= inb_p(0x40) << 8;
+
 	/*
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are three kinds of problems that must be avoided here:
+	 * there are two kinds of problems that must be avoided here:
 	 *  1. the timer counter underflows
 	 *  2. hardware problem with the timer, not giving us continuous time,
 	 *     the counter does small "jumps" upwards on some Pentium systems,
-	 *     thus causes time warps
-	 *  3. we are after the timer interrupt, but the bottom half handler
-	 *     hasn't executed yet.
-	 */
-	if( count > count_p ) {
-		if( jiffies_t == jiffies_p ) {
-			if( count > LATCH-LATCH/100 )
-				offset = TICK_SIZE;
-			else
+	 *     (see c't 95/10 page 335 for Neptun bug.)
+	 */
+
+/* you can safely undefine this if you dont have the Neptun chipset */
+
+#define BUGGY_NEPTUN_TIMER
+
+	if( jiffies_t == jiffies_p ) {
+		if( count > count_p ) {
+			/* the nutcase */
+
+			outb_p(0x0A, 0x20);
+
+			/* assumption about timer being IRQ1 */
+			if( inb(0x20) & 0x01 ) {
 				/*
-				 * argh, the timer is bugging we cant do nothing 
-				 * but to give the previous clock value.
+				 * We cannot detect lost timer interrupts ... 
+				 * well, thats why we call them lost, dont we? :)
+				 * [hmm, on the Pentium and Alpha we can ... sort of]
 				 */
-				count = count_p;
-		} else {
-			if( test_bit(TIMER_BH, &bh_active) ) {
-				/*
-				 * we have detected a counter underflow.
-			 	 */
-				offset = TICK_SIZE;
-				count_p = count;		
+				count -= LATCH;
 			} else {
-				count_p = count;
-				jiffies_p = jiffies_t;
+#ifdef BUGGY_NEPTUN_TIMER
+				/*
+				 * for the Neptun bug we know that the 'latch'
+				 * command doesnt latch the high and low value
+				 * of the counter atomically. Thus we have to 
+				 * substract 256 from the counter 
+				 * ... funny, isnt it? :)
+				 */
+
+				count -= 256;
+#else
+				printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+#endif
 			}
 		}
-	} else {
-		count_p = count;
+	} else
 		jiffies_p = jiffies_t;
- 	}
 
+	count_p = count;
 
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	count = (count + LATCH/2) / LATCH;
 
-	return offset + count;
+	return count;
 }
 
 /*
@@ -253,11 +264,20 @@
 	cli();
 	*tv = xtime;
 	tv->tv_usec += do_gettimeoffset();
+
+	/*
+	 * xtime is atomically updated in timer_bh. lost_ticks is
+	 * nonzero if the timer bottom half hasnt executed yet.
+	 */
+	if (lost_ticks)
+		tv->tv_usec += USECS_PER_JIFFY;
+
+	restore_flags(flags);
+
 	if (tv->tv_usec >= 1000000) {
 		tv->tv_usec -= 1000000;
 		tv->tv_sec++;
 	}
-	restore_flags(flags);
 }
 
 void do_settimeofday(struct timeval *tv)
diff -u --recursive --new-file v2.1.25/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.25/linux/arch/i386/kernel/traps.c	Tue Jan 28 18:49:47 1997
+++ linux/arch/i386/kernel/traps.c	Fri Feb  7 15:54:54 1997
@@ -198,6 +198,21 @@
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
 DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
 DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
+/* I don't have documents for this but it does seem to cover the cache
+   flush from user space exception some people get. */
+DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
+
+asmlinkage void cache_flush_denied(struct pt_regs * regs, long error_code)
+{
+	if (regs->eflags & VM_MASK) {
+		handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+		return;
+	}
+	die_if_kernel("cache flush denied",regs,error_code);
+	current->tss.error_code = error_code;
+	current->tss.trap_no = 19;
+	force_sig(SIGSEGV, current);
+}
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
diff -u --recursive --new-file v2.1.25/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c
--- v2.1.25/linux/arch/i386/lib/checksum.c	Thu Feb  6 12:41:59 1997
+++ linux/arch/i386/lib/checksum.c	Fri Feb  7 15:54:54 1997
@@ -100,225 +100,162 @@
 /*
  * Copy from ds while checksumming, otherwise like csum_partial
  *
- * The macros SRC and DST specify wether there should be exception handling
- * for the source and/or the destination addresses.
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
  *
  * FIXME: could someone double check wether i havent mixed up some SRC and
  *	  DST definitions? It's damn hard to trigger all cases, i hope i got
  *	  them all but theres no guarantee ...
  */
 
-#define csum_partial_copy_type(type) \
-unsigned int csum_partial_copy ##type (int * __csum_err, const char *src, char *dst,   \
-				  int len, int sum) {  \
-    __asm__( 									  \
-"		testl $2, %%edi		# Check alignment. 			\n" \
-"		jz 2f			# Jump if alignment is ok. 		\n" \
-"		subl $2, %%ecx		# Alignment uses up two bytes. 		\n" \
-"		jae 1f			# Jump if we had at least two bytes. 	\n" \
-"		addl $2, %%ecx		# ecx was < 2.  Deal with it. 		\n" \
-"		jmp 4f 								\n" \
-"	1000: 									\n" \
-"	 1:	movw (%%esi), %%bx						\n" \
-"		addl $2, %%esi							\n" \
-"	1001:									\n" \
-"		movw %%bx, (%%edi)						\n" \
-"		addl $2, %%edi							\n" \
-"		addw %%bx, %%ax							\n" \
-"		adcl $0, %%eax							\n" \
-"	2:									\n" \
-"		pushl %%ecx							\n" \
-"		shrl $5, %%ecx							\n" \
-"		jz 2f								\n" \
-"		testl %%esi, %%esi						\n" \
-"	1002:									\n" \
-"	1:	movl (%%esi), %%ebx						\n" \
-"	1003:									\n" \
-"		movl 4(%%esi), %%edx						\n" \
-"		adcl %%ebx, %%eax						\n" \
-"	1004:									\n" \
-"		movl %%ebx, (%%edi)						\n" \
-"		adcl %%edx, %%eax						\n" \
-"	1005:									\n" \
-"		movl %%edx, 4(%%edi)						\n" \
-"	 									\n" \
-"	1006:									\n" \
-"		movl 8(%%esi), %%ebx						\n" \
-"	1007:									\n" \
-"		movl 12(%%esi), %%edx						\n" \
-"		adcl %%ebx, %%eax						\n" \
-"	1008:									\n" \
-"		movl %%ebx, 8(%%edi)						\n" \
-"		adcl %%edx, %%eax						\n" \
-"	1009:									\n" \
-"		movl %%edx, 12(%%edi)						\n" \
-"	 									\n" \
-"	1010: 									\n" \
-"		movl 16(%%esi), %%ebx 						\n" \
-"	1011: 									\n" \
-"		movl 20(%%esi), %%edx						\n" \
-"		adcl %%ebx, %%eax						\n" \
-"	1012:									\n" \
-"		movl %%ebx, 16(%%edi)						\n" \
-"		adcl %%edx, %%eax						\n" \
-"	1013:									\n" \
-"		movl %%edx, 20(%%edi)						\n" \
-"										\n" \
-"	1014:									\n" \
-"		movl 24(%%esi), %%ebx						\n" \
-"	1015:									\n" \
-"		movl 28(%%esi), %%edx						\n" \
-"		adcl %%ebx, %%eax						\n" \
-"	1016:									\n" \
-"		movl %%ebx, 24(%%edi)						\n" \
-"		adcl %%edx, %%eax						\n" \
-"	1017:									\n" \
-"		movl %%edx, 28(%%edi)						\n" \
-"	 									\n" \
-"	1018:									\n" \
-"		lea 32(%%esi), %%esi						\n" \
-"	1019:									\n" \
-"		lea 32(%%edi), %%edi						\n" \
-"		dec %%ecx							\n" \
-"		jne 1b								\n" \
-"		adcl $0, %%eax							\n" \
-"	2:	popl %%edx							\n" \
-"		movl %%edx, %%ecx						\n" \
-"		andl $0x1c, %%edx						\n" \
-"		je 4f								\n" \
-"		shrl $2, %%edx		# This clears CF			\n" \
-"	1020:									\n" \
-"	3:	movl (%%esi), %%ebx						\n" \
-"		adcl %%ebx, %%eax						\n" \
-"	1021:									\n" \
-"		movl %%ebx, (%%edi)						\n" \
-"	1022:									\n" \
-"		lea 4(%%esi), %%esi						\n" \
-"	1023:									\n" \
-"		lea 4(%%edi), %%edi						\n" \
-"		dec %%edx							\n" \
-"		jne 3b								\n" \
-"		adcl $0, %%eax							\n" \
-"	4:	andl $3, %%ecx							\n" \
-"		jz 7f								\n" \
-"		cmpl $2, %%ecx							\n" \
-"		jb 5f								\n" \
-"	1024:									\n" \
-"		movw (%%esi), %%cx						\n" \
-"	1025:									\n" \
-"		leal 2(%%esi), %%esi						\n" \
-"	1026:									\n" \
-"		movw %%cx, (%%edi)						\n" \
-"	1027:									\n" \
-"		leal 2(%%edi), %%edi						\n" \
-"		je 6f								\n" \
-"		shll $16,%%ecx							\n" \
-"	1028:									\n" \
-"	5:	movb (%%esi), %%cl						\n" \
-"	1029:									\n" \
-"		movb %%cl, (%%edi)						\n" \
-"	6:	addl %%ecx, %%eax						\n" \
-"		adcl $0, %%eax							\n" \
-"	7:									\n" \
-"	2000:									\n" \
-"     	   .section .fixup,\"ax\"						\n" \
-"	3000:		movl %7,%1						\n" \
-/* FIXME: zero out the rest of the buffer here !!!!!! */			\
-"		jmp 2000b							\n" \
-"		.previous							\n" \
-"		.section __ex_table,\"a\"					\n" \
-"		.align 4                   					\n" \
-"										\n" \
-SRC(  "        .long 1000b,3000b        \n  "    ) \
-DST(  "        .long 1001b,3000b        \n  "    ) \
-SRC(  "        .long 1002b,3000b        \n  "    ) \
-SRC(  "        .long 1003b,3000b        \n  "    ) \
-DST(  "        .long 1004b,3000b        \n  "    ) \
-DST(  "        .long 1005b,3000b        \n  "    ) \
-SRC(  "        .long 1006b,3000b        \n  "    ) \
-SRC(  "        .long 1007b,3000b        \n  "    ) \
-DST(  "        .long 1008b,3000b        \n  "    ) \
-DST(  "        .long 1009b,3000b        \n  "    ) \
-SRC(  "        .long 1010b,3000b        \n  "    ) \
-SRC(  "        .long 1011b,3000b        \n  "    ) \
-DST(  "        .long 1012b,3000b        \n  "    ) \
-DST(  "        .long 1013b,3000b        \n  "    ) \
-SRC(  "        .long 1014b,3000b        \n  "    ) \
-SRC(  "        .long 1015b,3000b        \n  "    ) \
-DST(  "        .long 1016b,3000b        \n  "    ) \
-DST(  "        .long 1017b,3000b        \n  "    ) \
-SRC(  "        .long 1018b,3000b        \n  "    ) \
-DST(  "        .long 1019b,3000b        \n  "    ) \
-SRC(  "        .long 1020b,3000b        \n  "    ) \
-DST(  "        .long 1021b,3000b        \n  "    ) \
-SRC(  "        .long 1022b,3000b        \n  "    ) \
-DST(  "        .long 1023b,3000b        \n  "    ) \
-SRC(  "        .long 1024b,3000b        \n  "    ) \
-SRC(  "        .long 1025b,3000b        \n  "    ) \
-DST(  "        .long 1026b,3000b        \n  "    ) \
-DST(  "        .long 1027b,3000b        \n  "    ) \
-SRC(  "        .long 1028b,3000b        \n  "    ) \
-DST(  "        .long 1029b,3000b        \n  "    ) \
-"        .previous                      \n  " 				\
-	: "=a" (sum), "=r" (*__csum_err)   				\
-	:  "0" (sum), "c" (len), "S" (src), "D" (dst), 			\
-		"1" (*__csum_err), "i" (-EFAULT)   			\
-	: "bx", "cx", "dx", "si", "di" );  				\
- 									\
-    return(sum);  							\
-}
+#define SRC(y...)			\
+"	9999: "#y";			\n \
+	.section __ex_table, \"a\";	\n \
+	.long 9999b, src_access_fault	\n \
+	.previous"
+
+#define DST(y...)			\
+"	9999: "#y";			\n \
+	.section __ex_table, \"a\";	\n \
+	.long 9999b, dst_access_fault	\n \
+	.previous"
 
-/*
- *  Currently we need only 2 out of the 4 possible type combinations:
- */
-
-/*
- * Generate 'csum_partial_copy_from_user()', we need to do exception
- * handling for source addresses.
- */
-
-#define SRC(x) x
-#define DST(x)
-csum_partial_copy_type(_from_user)
-#undef SRC
-#undef DST
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+{
+    __asm__ __volatile__ ( "
+		testl $2, %%edi		# Check alignment. 
+		jz 2f			# Jump if alignment is ok.
+		subl $2, %%ecx		# Alignment uses up two bytes.
+		jae 1f			# Jump if we had at least two bytes.
+		addl $2, %%ecx		# ecx was < 2.  Deal with it.
+		jmp 4f
+"SRC(	1:	movw (%%esi), %%bx				)"
+		addl $2, %%esi
+"DST(		movw %%bx, (%%edi)				)"
+		addl $2, %%edi
+		addw %%bx, %%ax	
+		adcl $0, %%eax
+	2:
+		pushl %%ecx
+		shrl $5, %%ecx
+		jz 2f
+		testl %%esi, %%esi
+"SRC(	1:	movl (%%esi), %%ebx				)"
+"SRC(		movl 4(%%esi), %%edx				)"
+		adcl %%ebx, %%eax
+"DST(		movl %%ebx, (%%edi)				)"
+		adcl %%edx, %%eax
+"DST(		movl %%edx, 4(%%edi)				)"
+
+"SRC(		movl 8(%%esi), %%ebx				)"
+"SRC(		movl 12(%%esi), %%edx				)"
+		adcl %%ebx, %%eax
+"DST(		movl %%ebx, 8(%%edi)				)"
+		adcl %%edx, %%eax
+"DST(		movl %%edx, 12(%%edi)				)"
+
+"SRC(		movl 16(%%esi), %%ebx 				)"
+"SRC(		movl 20(%%esi), %%edx				)"
+		adcl %%ebx, %%eax
+"DST(		movl %%ebx, 16(%%edi)				)"
+		adcl %%edx, %%eax
+"DST(		movl %%edx, 20(%%edi)				)"
+
+"SRC(		movl 24(%%esi), %%ebx				)"
+"SRC(		movl 28(%%esi), %%edx				)"
+		adcl %%ebx, %%eax
+"DST(		movl %%ebx, 24(%%edi)				)"
+		adcl %%edx, %%eax
+"DST(		movl %%edx, 28(%%edi)				)"
+
+"SRC(		lea 32(%%esi), %%esi				)"
+"DST(		lea 32(%%edi), %%edi				)"
+		dec %%ecx
+		jne 1b
+		adcl $0, %%eax
+	2:	popl %%edx
+		movl %%edx, %%ecx
+		andl $0x1c, %%edx
+		je 4f
+		shrl $2, %%edx		# This clears CF
+"SRC(	3:	movl (%%esi), %%ebx				)"
+		adcl %%ebx, %%eax
+"DST(		movl %%ebx, (%%edi)				)"
+"SRC(		lea 4(%%esi), %%esi				)"
+"DST(		lea 4(%%edi), %%edi				)"
+		dec %%edx
+		jne 3b
+		adcl $0, %%eax
+	4:	andl $3, %%ecx
+		jz 7f
+		cmpl $2, %%ecx
+		jb 5f
+"SRC(		movw (%%esi), %%cx				)"
+"SRC(		leal 2(%%esi), %%esi				)"
+"DST(		movw %%cx, (%%edi)				)"
+"DST(		leal 2(%%edi), %%edi				)"
+		je 6f
+		shll $16,%%ecx
+"SRC(	5:	movb (%%esi), %%cl				)"
+"DST(		movb %%cl, (%%edi)				)"
+	6:	addl %%ecx, %%eax
+		adcl $0, %%eax
+	7:
+
+end_of_body:
+
+# Exception handler:
+################################################
+						#
+.section .fixup, \"a\"				#
+						#
+common_fixup:					#
+						#
+	movl	%7, (%%ebx)			#
+						#
+# FIXME: do zeroing of rest of the buffer here. #
+						#
+	jmp	end_of_body			#
+						#
+src_access_fault:				#
+	movl    %1, %%ebx			#
+	jmp	common_fixup			#
+						#
+dst_access_fault:				#
+	movl    %2, %%ebx			#
+	jmp	common_fixup			#
+						#
+.previous					#
+						#
+################################################
+
+"
+	: "=a" (sum), "=m" (src_err_ptr), "=m" (dst_err_ptr)
+	:  "0" (sum), "c" (len), "S" (src), "D" (dst),
+		"i" (-EFAULT)
+	: "bx", "cx", "dx", "si", "di" );
 
-/*
- * Generate 'csum_partial_copy_nocheck()', no need to do exception
- * handling.
- */
+    return(sum);
+}
 
-#define SRC(x)
-#define DST(x)
-csum_partial_copy_type(_nocheck_generic)
 #undef SRC
 #undef DST
 
 /*
- * Generate 'csum_partial_copy_old()', old and slow compability stuff,
- * full checking.
- *
- * tell us if you see something printk-ing on this. This function will be
- * removed soon.
+ * FIXME: old compatibility stuff, will be removed soon.
  */
 
-#define SRC(x) x
-#define DST(x) x
-csum_partial_copy_type(_old)
-#undef SRC
-#undef DST
-
-unsigned int csum_partial_copy ( const char *src, char *dst, 
-				  int len, int sum)
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
 {
-	int ret;
-	int error = 0;
+	int src_err=0, dst_err=0;
 
-	ret = csum_partial_copy_old (&error, src, dst, len, sum);
+	sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
 
-	if (error)
-		printk("csum_partial_copy_old(): tell mingo to convert me!\n");
+	if (src_err || dst_err)
+		printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
 
-	return ret;
+	return sum;
 }
+
 
diff -u --recursive --new-file v2.1.25/linux/drivers/ap1000/apfddi.c linux/drivers/ap1000/apfddi.c
--- v2.1.25/linux/drivers/ap1000/apfddi.c	Tue Jan 28 18:49:52 1997
+++ linux/drivers/ap1000/apfddi.c	Fri Feb  7 15:54:54 1997
@@ -126,7 +126,7 @@
 static u_char apfddi_saddr[6] = { 0x42, 0x9a, 0x08, 0x6e, 0x11, 0x41 };
 
 struct device *apfddi_device = NULL;
-struct enet_statistics *apfddi_stats = NULL;
+struct net_device_stats *apfddi_stats = NULL;
 
 volatile struct apfddi_queue *apfddi_queue_top = NULL;
 
@@ -254,7 +254,7 @@
 static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int apfddi_xmit(struct sk_buff *skb, struct device *dev);
 int apfddi_rx(struct mac_buf *mbuf);
-static struct enet_statistics *apfddi_get_stats(struct device *dev);
+static struct net_device_stats *apfddi_get_stats(struct device *dev);
 #if APFDDI_DEBUG
 void dump_packet(char *action, char *buf, int len, int seq);
 #endif
@@ -496,11 +496,11 @@
     dev->stop = apfddi_stop;
     dev->hard_start_xmit = apfddi_xmit;
     dev->get_stats = apfddi_get_stats;
-    dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_ATOMIC); 
+    dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_ATOMIC); 
     if (dev->priv == NULL)
 	return -ENOMEM;
-    memset(dev->priv, 0, sizeof(struct enet_statistics)); 
-    apfddi_stats = (struct enet_statistics *)apfddi_device->priv;
+    memset(dev->priv, 0, sizeof(struct net_device_stats)); 
+    apfddi_stats = (struct net_device_stats *)apfddi_device->priv;
 
     /* Initialise the fddi device structure */
     for (i = 0; i < DEV_NUMBUFFS; i++)
@@ -692,9 +692,9 @@
 /*
  * Return statistics of fddi driver.
  */
-static struct enet_statistics *apfddi_get_stats(struct device *dev)
+static struct net_device_stats *apfddi_get_stats(struct device *dev)
 {
-    return((struct enet_statistics *)dev->priv);
+    return((struct net_device_stats *)dev->priv);
 }
 
     
diff -u --recursive --new-file v2.1.25/linux/drivers/ap1000/apfddi.h linux/drivers/ap1000/apfddi.h
--- v2.1.25/linux/drivers/ap1000/apfddi.h	Tue Jan 28 18:49:52 1997
+++ linux/drivers/ap1000/apfddi.h	Fri Feb  7 15:54:54 1997
@@ -138,5 +138,5 @@
 void set_cf_join(int on);
 
 extern struct device *apfddi_device;
-extern struct enet_statistics *apfddi_stats;
+extern struct net_device_stats *apfddi_stats;
 
diff -u --recursive --new-file v2.1.25/linux/drivers/ap1000/bif.c linux/drivers/ap1000/bif.c
--- v2.1.25/linux/drivers/ap1000/bif.c	Tue Jan 28 18:49:52 1997
+++ linux/drivers/ap1000/bif.c	Fri Feb  7 15:54:54 1997
@@ -46,14 +46,14 @@
 #define BIF_MTU 10240
 
 static struct device *bif_device = 0;
-static struct enet_statistics *bif_stats = 0;
+static struct net_device_stats *bif_stats = 0;
 
 int bif_init(struct device *dev);
 int bif_open(struct device *dev);
 static int bif_xmit(struct sk_buff *skb, struct device *dev);
 int bif_rx(struct sk_buff *skb);
 int bif_stop(struct device *dev);
-static struct enet_statistics *bif_get_stats(struct device *dev);
+static struct net_device_stats *bif_get_stats(struct device *dev);
 
 static int bif_hard_header(struct sk_buff *skb, struct device *dev,
 			   unsigned short type, void *daddr,
@@ -128,11 +128,11 @@
     dev->open = bif_open;
     dev->flags = IFF_NOARP;   /* Don't use ARP on this device */
     dev->family = AF_INET;
-    dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+    dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
     if (dev->priv == NULL)
 	return -ENOMEM;
-    memset(dev->priv, 0, sizeof(struct enet_statistics));
-    bif_stats = (struct enet_statistics *)bif_device->priv;
+    memset(dev->priv, 0, sizeof(struct net_device_stats));
+    bif_stats = (struct net_device_stats *)bif_device->priv;
 
 
     dev->stop = bif_stop;
@@ -282,8 +282,8 @@
 /*
  * Return statistics of bif driver.
  */
-static struct enet_statistics *bif_get_stats(struct device *dev)
+static struct net_device_stats *bif_get_stats(struct device *dev)
 {
-    return((struct enet_statistics *)dev->priv);
+    return((struct net_device_stats *)dev->priv);
 }
     
diff -u --recursive --new-file v2.1.25/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.25/linux/drivers/char/esp.c	Thu Jan  2 15:55:16 1997
+++ linux/drivers/char/esp.c	Wed Feb  5 13:49:56 1997
@@ -29,19 +29,17 @@
  *     by Chris Faylor.
  *
  * Most recent changes: (Andrew J. Robinson)
- *     Remove all references to tty->hw_stopped.
- *     Request a single region for multiple ports if possible.
- *     Stop a DMA transfer on a port when it is closed.
- *     Rename esp_init() to espserial_init().
- *     Improve validation of IRQ (only accept those allowed by the ESP card).
- *     Return if a signal is received while wait for a break to start.
- *     Split NEED_DMA logic into NEED_DMA_RX and NEED_DMA_TX.
+ *     Don't cause a kernel panic if memory could not be allocated or if the
+ *     device couldn't be registered.
+ *     Always set RTS when transitioning away from B0 status (since the
+ *     flow is really being handled by the ESP card).
  *
  * This module exports the following rs232 io functions:
  *
  *	int espserial_init(void);
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
@@ -51,7 +49,6 @@
 #include <linux/tty_flip.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
-#include <linux/config.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
@@ -95,7 +92,7 @@
 #define WAKEUP_CHARS 1024
 
 static char *serial_name = "ESP serial driver";
-static char *serial_version = "1.3";
+static char *serial_version = "1.5";
 
 DECLARE_TASK_QUEUE(tq_esp);
 
@@ -1851,9 +1848,7 @@
 	/* Handle transition away from B0 status */
 	if (!(old_termios->c_cflag & CBAUD) &&
 		(tty->termios->c_cflag & CBAUD)) {
-		info->MCR |= UART_MCR_DTR;
-		if (!(tty->termios->c_cflag & CRTSCTS))
-			info->MCR |= UART_MCR_RTS;
+		info->MCR |= (UART_MCR_DTR | UART_MCR_RTS);
 		cli();
 		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 		serial_out(info, UART_ESI_CMD2, UART_MCR);
@@ -2460,14 +2455,29 @@
 	esp_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
 	if (tty_register_driver(&esp_driver))
-		panic("Couldn't register serial driver\n");
+	{
+		printk(KERN_ERR "Couldn't register esp serial driver");
+		return 1;
+	}
+
 	if (tty_register_driver(&esp_callout_driver))
-		panic("Couldn't register callout driver\n");
+	{
+		printk(KERN_ERR "Couldn't register esp callout driver");
+		tty_unregister_driver(&esp_driver);
+		return 1;
+	}
 	
 	info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct),
 		GFP_KERNEL);
+
 	if (!info)
-		panic("Could not allocate memory for device information\n");
+	{
+		printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
+		tty_unregister_driver(&esp_driver);
+		tty_unregister_driver(&esp_callout_driver);
+		return 1;
+	}
+
 	memset((void *)info, 0, sizeof(struct esp_struct));
 
 	i = 0;
@@ -2515,7 +2525,13 @@
 		info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct),
 			GFP_KERNEL);
 		if (!info)
-			panic("Could not allocate memory for device information\n");
+		{
+			printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); 
+
+			/* allow use of the already detected ports */
+			return 0;
+		}
+
 		memset((void *)info, 0, sizeof(struct esp_struct));
 
 		if (offset == 56) {
diff -u --recursive --new-file v2.1.25/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.1.25/linux/drivers/net/dgrs.c	Thu Feb  6 12:42:03 1997
+++ linux/drivers/net/dgrs.c	Mon Feb  3 13:05:51 1997
@@ -509,7 +509,7 @@
 	/*
 	 *	There are three modes here for doing the packet copy.
 	 *	If we have DMA, and the packet is "long", we use the
-	 *	chaining mode of DMA.  If its shorter, we use single
+	 *	chaining mode of DMA.  If it's shorter, we use single
 	 *	DMA's.  Otherwise, we use memcpy().
 	 */
 	if (priv0->use_dma && priv0->dmadesc_h && len > 64)
diff -u --recursive --new-file v2.1.25/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.25/linux/drivers/net/ibmtr.c	Thu Feb  6 12:42:04 1997
+++ linux/drivers/net/ibmtr.c	Fri Feb  7 15:54:54 1997
@@ -175,19 +175,10 @@
 static int	tok_close(struct device *dev);
 static int	tok_send_packet(struct sk_buff *skb, struct device *dev);
 static struct net_device_stats * tok_get_stats(struct device *dev);
-void		tr_readlog(struct device *dev);
+void		ibmtr_readlog(struct device *dev);
+void		ibmtr_reset_timer(struct timer_list *tmr, struct device *dev);
 
-/* FIXME: Should use init_timer and friends not assume the structure
-   is constant! */
-   
-static struct timer_list tr_timer =
-{
-	NULL,
-	NULL,
-	0,
-	0L,
-	tok_open_adapter
-};
+static struct timer_list tr_timer;
 
 static unsigned int ibmtr_portlist[] = {
 	0xa20, 0xa24, 0
@@ -793,7 +784,7 @@
 							      ti->current_skb=NULL;
 						      }
 						      dev->tbusy=0;
-						      if (ti->readlog_pending) tr_readlog(dev);
+						      if (ti->readlog_pending) ibmtr_readlog(dev);
 					      }
 				      }
 				      break;
@@ -810,7 +801,7 @@
 							      ti->current_skb=NULL;
 						      }
 						      dev->tbusy=0;
-						      if (ti->readlog_pending) tr_readlog(dev);
+						      if (ti->readlog_pending) ibmtr_readlog(dev);
 					      }
 				      }
 				      break;
@@ -867,10 +858,7 @@
 							      open_ret_code);
 
 					      if (ti->open_status != FAILURE) {
-						      tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
-						      tr_timer.data=(unsigned long)dev;
-						      tr_timer.next=tr_timer.prev=NULL;
-						      add_timer(&tr_timer);
+						      ibmtr_reset_timer(&tr_timer, dev);
 					      }
 
 				      }
@@ -884,10 +872,7 @@
 					if (readb(ti->srb+offsetof(struct dlc_open_sap, ret_code))) {
 						DPRINTK("open_sap failed: ret_code = %02X,retrying\n",
 							(int)readb(ti->srb+offsetof(struct dlc_open_sap, ret_code)));
-						tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
-						tr_timer.data=(unsigned long)dev;
-						tr_timer.next=tr_timer.prev=NULL;
-						add_timer(&tr_timer);
+						ibmtr_reset_timer(&tr_timer, dev);
 					} else {
 						ti->exsap_station_id=
 							readw(ti->srb+offsetof(struct dlc_open_sap, station_id));
@@ -998,11 +983,7 @@
 
 						      DPRINTK("Signal loss/Lobe fault\n");
 						      DPRINTK("We try to reopen the adapter.\n");
-						      tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
-						      tr_timer.data=(unsigned long)dev;
-						      tr_timer.next=tr_timer.prev=NULL;
-						      add_timer(&tr_timer);
-
+						      ibmtr_reset_timer(&tr_timer, dev);
 					      } else if (ring_status & (HARD_ERROR | XMIT_BEACON
 											| AUTO_REMOVAL | REMOVE_RECV | RING_RECOVER))
 						      DPRINTK("New ring status: %02X\n", ring_status);
@@ -1011,7 +992,7 @@
 						      if (dev->tbusy)
                                                               ti->readlog_pending = 1;
 						      else
-                                                              tr_readlog(dev);
+                                                              ibmtr_readlog(dev);
 					      }
 				      }
 				      break;
@@ -1124,7 +1105,8 @@
 	DPRINTK("encoded addr (%04X,%04X,%08X): ", hw_encoded_addr,
 		ntohs(hw_encoded_addr), encoded_addr);
 #else
-	DPRINTK("Initial interrupt : shared RAM located at %08x.\n", ti->sram);
+	DPRINTK("Initial interrupt : %s Mbps, shared RAM base %08x.\n",
+		(readb(ti->init_srb+offsetof(struct srb_init_response, init_status)) & 0x01) ? "16" : "4", ti->sram);
 #endif
 
 	ti->auto_ringspeedsave=readb(ti->init_srb
@@ -1342,7 +1324,7 @@
 	dev_kfree_skb(ti->current_skb,FREE_WRITE);
 	ti->current_skb=NULL;
 	mark_bh(NET_BH);
-	if (ti->readlog_pending) tr_readlog(dev);
+	if (ti->readlog_pending) ibmtr_readlog(dev);
 }
 
 static void tr_rx(struct device *dev)
@@ -1545,7 +1527,15 @@
 	return 0;
 }
 
-void tr_readlog(struct device *dev) {
+void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev) {
+	tmr->expires  = jiffies + TR_RETRY_INTERVAL;
+	tmr->data     = (unsigned long) dev;
+	tmr->function = tok_open_adapter;
+	init_timer(tmr);
+	add_timer(tmr);
+}
+
+void ibmtr_readlog(struct device *dev) {
 	 struct tok_info *ti;
 	 ti=(struct tok_info *) dev->priv;
 
diff -u --recursive --new-file v2.1.25/linux/drivers/net/pi2.h linux/drivers/net/pi2.h
--- v2.1.25/linux/drivers/net/pi2.h	Thu Feb  6 12:42:05 1997
+++ linux/drivers/net/pi2.h	Fri Feb  7 15:54:54 1997
@@ -82,7 +82,7 @@
 
 /* Information that needs to be kept for each channel. */
 struct pi_local {
-    struct netstats stats; /* %%%dp*/
+    struct net_device_stats stats; 
     long open_time;             /* Useless example local info. */
     unsigned long xtal; 
 
diff -u --recursive --new-file v2.1.25/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v2.1.25/linux/drivers/net/seeq8005.c	Thu Feb  6 12:42:06 1997
+++ linux/drivers/net/seeq8005.c	Fri Feb  7 15:54:54 1997
@@ -64,7 +64,7 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct net_driver_stats stats;
+	struct net_device_stats stats;
 	unsigned short receive_ptr;		/* What address in packet memory do we expect a recv_pkt_header? */
 	long open_time;				/* Useless example local info. */
 };
@@ -84,7 +84,7 @@
 static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void seeq8005_rx(struct device *dev);
 static int seeq8005_close(struct device *dev);
-static struct net_driver_stats *seeq8005_get_stats(struct device *dev);
+static struct net_device_stats *seeq8005_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 /* Example routines you must write ;->. */
@@ -593,7 +593,7 @@
 
 /* Get the current statistics.	This may be called with the card open or
    closed. */
-static struct net_driver_stats *seeq8005_get_stats(struct device *dev)
+static struct net_device_stats *seeq8005_get_stats(struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 
diff -u --recursive --new-file v2.1.25/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.1.25/linux/drivers/net/sk_g16.c	Thu Feb  6 12:42:08 1997
+++ linux/drivers/net/sk_g16.c	Fri Feb  7 15:54:54 1997
@@ -457,7 +457,7 @@
     int        tmdlast;  /* last sent descriptor used for error handling, etc */
     void       *rmdbufs[RMDNUM]; /* pointer to the receive buffers */
     void       *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */
-    struct net_driver_stats stats; /* Device driver statistics */
+    struct net_device_stats stats; /* Device driver statistics */
 };
 
 /* global variable declaration */
@@ -491,7 +491,7 @@
 static void  SK_txintr(struct device *dev);
 static int   SK_close(struct device *dev);
 
-static struct net_driver_stats *SK_get_stats(struct device *dev);
+static struct net_device_stats *SK_get_stats(struct device *dev);
 
 unsigned int SK_rom_addr(void);
 
@@ -1681,14 +1681,14 @@
  *                  It is called by sprintf_stats (dev.c).
  *
  * Parameters     : I : struct device *dev   - our device structure
- * Return Value   : struct net_driver_stats * - our current statistics
+ * Return Value   : struct net_device_stats * - our current statistics
  * Errors         : None
  * Side Effects   : None
  * Update History :
  *     YY/MM/DD  uid  Description
 -*/
 
-static struct net_driver_stats *SK_get_stats(struct device *dev)
+static struct net_device_stats *SK_get_stats(struct device *dev)
 {
 
     struct priv *p = (struct priv *) dev->priv;
diff -u --recursive --new-file v2.1.25/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.1.25/linux/drivers/net/smc9194.c	Thu Feb  6 12:42:09 1997
+++ linux/drivers/net/smc9194.c	Fri Feb  7 15:54:54 1997
@@ -175,7 +175,7 @@
 	   can find out semi-useless statistics of how well the card is
 	   performing
  	*/
-	struct net_driver_stats stats;
+	struct net_device_stats stats;
 
 	/*
 	   If I have to wait until memory is available to send
@@ -234,7 +234,7 @@
  . This routine allows the proc file system to query the driver's
  . statistics.
 */
-static struct net_driver_stats * smc_query_statistics( struct device *dev);
+static struct net_device_stats * smc_query_statistics( struct device *dev);
 
 /*
  . Finally, a call to set promiscuous mode ( for TCPDUMP and related
@@ -1643,7 +1643,7 @@
  . Get the current statistics.
  . This may be called with the card open or closed.
  .-------------------------------------------------------------*/
-static struct net_driver_stats* smc_query_statistics(struct device *dev) {
+static struct net_device_stats* smc_query_statistics(struct device *dev) {
 	struct smc_local *lp = (struct smc_local *)dev->priv;
 
 	return &lp->stats;
diff -u --recursive --new-file v2.1.25/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.25/linux/drivers/pci/pci.c	Tue Jan 28 18:50:07 1997
+++ linux/drivers/pci/pci.c	Fri Feb  7 14:36:07 1997
@@ -152,6 +152,7 @@
 	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4"),
 	DEVICE( 3COM,		3COM_3C595MII,	"3C595 100b-MII"),
 	DEVICE( 3COM,		3COM_3C900TPO,	"3C900 10bTPO"),
+	DEVICE( 3COM,		3COM_3C905TX,	"3C905 100bTX"),
 	DEVICE( AL,		AL_M1445,	"M1445"),
 	DEVICE( AL,		AL_M1449,	"M1449"),
 	DEVICE( AL,		AL_M1451,	"M1451"),
@@ -270,8 +271,9 @@
 	DEVICE( ADAPTEC,	ADAPTEC_7883,	"AIC-7883U"),
 	DEVICE( ADAPTEC,	ADAPTEC_7884,	"AIC-7884U"),
   	DEVICE( ATRONICS,	ATRONICS_2015,	"IDE-2015PL"),
-	DEVICE( HER,		HER_STING,	"Stingray"),
-	DEVICE( HER,		HER_STINGARK,	"Stingray ARK 2000PV")
+	DEVICE( ARK,		ARK_STING,	"Stingray"),
+	DEVICE( ARK,		ARK_STINGARK,	"Stingray ARK 2000PV"),
+	DEVICE( ARK,		ARK_2000MT,	"2000MT")
 };
 
 
@@ -546,7 +548,7 @@
 	      case PCI_VENDOR_ID_INTEL:		return "Intel";
 	      case PCI_VENDOR_ID_ADAPTEC:	return "Adaptec";
 	      case PCI_VENDOR_ID_ATRONICS:	return "Atronics";
-	      case PCI_VENDOR_ID_HER:		return "Hercules";
+	      case PCI_VENDOR_ID_ARK:		return "ARK Logic";
 	      default:				return "Unknown vendor";
 	}
 }
diff -u --recursive --new-file v2.1.25/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.25/linux/drivers/scsi/scsi.c	Thu Feb  6 12:42:10 1997
+++ linux/drivers/scsi/scsi.c	Fri Feb  7 14:02:08 1997
@@ -238,7 +238,6 @@
 {"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
 {"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
 {"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
-{"HP", "C3725S", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
 {"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
 {"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
 {"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
diff -u --recursive --new-file v2.1.25/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.1.25/linux/drivers/scsi/scsi_ioctl.c	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/scsi_ioctl.c	Fri Feb  7 14:34:19 1997
@@ -247,6 +247,7 @@
 	retries = 1;
 	break;
       case START_STOP:
+      case MOVE_MEDIUM:
 	timeout =  60 * HZ;	/* 60 seconds */
 	retries = 1;
 	break;
diff -u --recursive --new-file v2.1.25/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.25/linux/fs/nfs/nfsroot.c	Tue Jan 28 18:50:18 1997
+++ linux/fs/nfs/nfsroot.c	Fri Feb  7 15:54:54 1997
@@ -598,6 +598,7 @@
 	iov.iov_base = buf;
 	iov.iov_len = size;
 	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
 	msg.msg_control = NULL;
@@ -624,6 +625,7 @@
 	iov.iov_base = buf;
 	iov.iov_len = size;
 	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
 	msg.msg_control = NULL;
diff -u --recursive --new-file v2.1.25/linux/fs/select.c linux/fs/select.c
--- v2.1.25/linux/fs/select.c	Tue Jan 28 18:50:22 1997
+++ linux/fs/select.c	Thu Feb  6 12:51:45 1997
@@ -62,25 +62,31 @@
 }
 
 /*
- * Due to kernel stack usage, we use a _limited_ fd_set type here, and once
- * we really start supporting >256 file descriptors we'll probably have to
- * allocate the kernel fd_set copies dynamically.. (The kernel select routines
- * are careful to touch only the defined low bits of any fd_set pointer, this
- * is important for performance too).
+ * For the kernel fd_set we use a fixed set-size for allocation purposes.
+ * This set-size doesn't necessarily bear any relation to the size the user
+ * uses, but should preferably obviously be larger than any possible user
+ * size (NR_OPEN bits).
+ *
+ * We need 6 bitmaps (in/out/ex for both incoming and outgoing), and we
+ * allocate one page for all the bitmaps. Thus we have 8*PAGE_SIZE bits,
+ * to be divided by 6. And we'd better make sure we round to a full
+ * long-word (in fact, we'll round to 64 bytes).
  */
-typedef unsigned long limited_fd_set[NR_OPEN/(8*(sizeof(unsigned long)))];
+#define KFDS_64BLOCK ((PAGE_SIZE/(6*64))*64)
+#define KFDS_NR (KFDS_64BLOCK*8 > NR_OPEN ? NR_OPEN : KFDS_64BLOCK*8)
+typedef unsigned long kernel_fd_set[KFDS_NR/(8*sizeof(unsigned long))];
 
 typedef struct {
-	limited_fd_set in, out, ex;
-	limited_fd_set res_in, res_out, res_ex;
+	kernel_fd_set in, out, ex;
+	kernel_fd_set res_in, res_out, res_ex;
 } fd_set_buffer;
 
 #define __IN(in)	(in)
-#define __OUT(in)	(in + sizeof(limited_fd_set)/sizeof(unsigned long))
-#define __EX(in)	(in + 2*sizeof(limited_fd_set)/sizeof(unsigned long))
-#define __RES_IN(in)	(in + 3*sizeof(limited_fd_set)/sizeof(unsigned long))
-#define __RES_OUT(in)	(in + 4*sizeof(limited_fd_set)/sizeof(unsigned long))
-#define __RES_EX(in)	(in + 5*sizeof(limited_fd_set)/sizeof(unsigned long))
+#define __OUT(in)	(in + sizeof(kernel_fd_set)/sizeof(unsigned long))
+#define __EX(in)	(in + 2*sizeof(kernel_fd_set)/sizeof(unsigned long))
+#define __RES_IN(in)	(in + 3*sizeof(kernel_fd_set)/sizeof(unsigned long))
+#define __RES_OUT(in)	(in + 4*sizeof(kernel_fd_set)/sizeof(unsigned long))
+#define __RES_EX(in)	(in + 5*sizeof(kernel_fd_set)/sizeof(unsigned long))
 
 #define BITS(in)	(*__IN(in)|*__OUT(in)|*__EX(in))
 
@@ -277,17 +283,20 @@
 asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
 	int error = -EINVAL;
-	fd_set_buffer fds;
+	fd_set_buffer *fds;
 	unsigned long timeout;
 
 	lock_kernel();
+	fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
+	if (!fds)
+		goto out;
 	if (n < 0)
 		goto out;
-	if (n > NR_OPEN)
-		n = NR_OPEN;
-	if ((error = get_fd_set(n, inp, &fds.in)) ||
-	    (error = get_fd_set(n, outp, &fds.out)) ||
-	    (error = get_fd_set(n, exp, &fds.ex))) goto out;
+	if (n > KFDS_NR)
+		n = KFDS_NR;
+	if ((error = get_fd_set(n, inp, &fds->in)) ||
+	    (error = get_fd_set(n, outp, &fds->out)) ||
+	    (error = get_fd_set(n, exp, &fds->ex))) goto out;
 	timeout = ~0UL;
 	if (tvp) {
 		error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
@@ -303,11 +312,11 @@
 		if (timeout)
 			timeout += jiffies + 1;
 	}
-	zero_fd_set(n, &fds.res_in);
-	zero_fd_set(n, &fds.res_out);
-	zero_fd_set(n, &fds.res_ex);
+	zero_fd_set(n, &fds->res_in);
+	zero_fd_set(n, &fds->res_out);
+	zero_fd_set(n, &fds->res_ex);
 	current->timeout = timeout;
-	error = do_select(n, &fds);
+	error = do_select(n, fds);
 	timeout = current->timeout - jiffies - 1;
 	current->timeout = 0;
 	if ((long) timeout < 0)
@@ -326,10 +335,11 @@
 			goto out;
 		error = 0;
 	}
-	set_fd_set(n, inp, &fds.res_in);
-	set_fd_set(n, outp, &fds.res_out);
-	set_fd_set(n, exp, &fds.res_ex);
+	set_fd_set(n, inp, &fds->res_in);
+	set_fd_set(n, outp, &fds->res_out);
+	set_fd_set(n, exp, &fds->res_ex);
 out:
+	free_page((unsigned long) fds);
 	unlock_kernel();
 	return error;
 }
@@ -376,15 +386,12 @@
 
 asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
 {
-        int i, count, fdcount, err = -EINVAL;
+	int i, count, fdcount, err;
 	struct pollfd * fds, *fds1;
 	poll_table wait_table;
 	struct poll_table_entry *entry;
 
 	lock_kernel();
-	if (nfds > NR_OPEN)
-		goto out;
-
 	err = -ENOMEM;
 	entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
 	if (!entry)
diff -u --recursive --new-file v2.1.25/linux/include/asm-alpha/checksum.h linux/include/asm-alpha/checksum.h
--- v2.1.25/linux/include/asm-alpha/checksum.h	Sat Nov 30 12:03:11 1996
+++ linux/include/asm-alpha/checksum.h	Thu Feb  6 12:44:41 1997
@@ -44,9 +44,16 @@
 /*
  * the same as csum_partial, but copies from user space (but on the alpha
  * we have just one address space, so this is identical to the above)
+ *
+ * this is obsolete and will go away.
  */
 #define csum_partial_copy_fromuser csum_partial_copy
 
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user(int *errp, char *src, char *dst, int len, unsigned int sum);
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
diff -u --recursive --new-file v2.1.25/linux/include/asm-alpha/current.h linux/include/asm-alpha/current.h
--- v2.1.25/linux/include/asm-alpha/current.h	Tue Dec 31 21:41:08 1996
+++ linux/include/asm-alpha/current.h	Thu Feb  6 14:42:35 1997
@@ -3,10 +3,10 @@
 
 /* Some architectures may want to do something "clever" here since
  * this is the most frequently accessed piece of data in the entire
- * kernel.  For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
+ * kernel.
  */
 extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()])	/* Current on this processor */
+
+register struct task_struct *current __asm__("$8");
 
 #endif /* !(_ALPHA_CURRENT_H) */
diff -u --recursive --new-file v2.1.25/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.1.25/linux/include/asm-alpha/system.h	Wed Aug 21 09:12:49 1996
+++ linux/include/asm-alpha/system.h	Thu Feb  6 14:42:35 1997
@@ -56,8 +56,8 @@
 #define halt() __asm__ __volatile__ ("call_pal %0" : : "i" (PAL_halt) : "memory")
 
 #define switch_to(prev,next) do { \
-	current_set[0] = next; \
-	alpha_switch_to((unsigned long) &(next)->tss - 0xfffffc0000000000); \
+	current_set[0] = current = next; \
+	alpha_switch_to((unsigned long) &current->tss - 0xfffffc0000000000); \
 } while (0)
 
 extern void alpha_switch_to(unsigned long pctxp);
diff -u --recursive --new-file v2.1.25/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- v2.1.25/linux/include/asm-i386/checksum.h	Thu Feb  6 12:42:11 1997
+++ linux/include/asm-i386/checksum.h	Fri Feb  7 15:54:54 1997
@@ -23,26 +23,42 @@
  * better 64-bit) boundary
  */
 
-unsigned int csum_partial_copy_from_user( int * err, const char *src, 
-						char *dst, int len, int sum);
+unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+					int *src_err_ptr, int *dst_err_ptr);
+
+extern __inline__
+unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+					int len, int sum)
+{
+	int *src_err_ptr=NULL, *dst_err_ptr=NULL;
+
+	return csum_partial_copy_generic ( src, dst, len, sum, src_err_ptr, dst_err_ptr);
+}
+
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+						int len, int sum, int *err_ptr)
+{
+	int *dst_err_ptr=NULL;
+
+	return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, dst_err_ptr);
+}
 
 /*
- * I hope GCC will optimize 'dummy' away ...
+ * This combination is currently not used, but possible:
  */
 
-unsigned int csum_partial_copy_nocheck_generic( int * err, const char *src, char *dst,
-						 int len, int sum);
-
-extern __inline__ unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
-                                                        int len, int sum)
+extern __inline__
+unsigned int csum_partial_copy_to_user ( const char *src, char *dst,
+					int len, int sum, int *err_ptr)
 {
-        int dummy;
+	int *src_err_ptr=NULL;
 
-        return csum_partial_copy_nocheck_generic ( &dummy, src, dst, len, sum);
+	return csum_partial_copy_generic ( src, dst, len, sum, src_err_ptr, err_ptr);
 }
 
 /*
- * These are the 'old' way of doing checksums, a warning message will be
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
  * printed if they are used and an exeption occurs.
  *
  * these functions should go away after some time.
diff -u --recursive --new-file v2.1.25/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.25/linux/include/linux/fs.h	Tue Jan 28 18:50:54 1997
+++ linux/include/linux/fs.h	Thu Feb  6 12:53:33 1997
@@ -27,7 +27,7 @@
 
 /* Fixed constants first: */
 #undef NR_OPEN
-#define NR_OPEN 256
+#define NR_OPEN 1024
 
 #define NR_SUPER 64
 #define BLOCK_SIZE 1024
diff -u --recursive --new-file v2.1.25/linux/include/linux/icmp.h linux/include/linux/icmp.h
--- v2.1.25/linux/include/linux/icmp.h	Wed Dec 18 15:59:03 1996
+++ linux/include/linux/icmp.h	Fri Feb  7 15:54:54 1997
@@ -80,11 +80,12 @@
   } un;
 };
 
+#ifdef __KERNEL__
 
 struct icmp_err {
   int		errno;
   unsigned	fatal:1;
 };
-
+#endif
 
 #endif	/* _LINUX_ICMP_H */
diff -u --recursive --new-file v2.1.25/linux/include/linux/if_tr.h linux/include/linux/if_tr.h
--- v2.1.25/linux/include/linux/if_tr.h	Sun Mar 24 12:09:37 1996
+++ linux/include/linux/if_tr.h	Fri Feb  7 15:54:55 1997
@@ -94,8 +94,8 @@
 #define TR_RII 0x80
 #define TR_RCF_DIR_BIT 0x80
 #define TR_RCF_LEN_MASK 0x1f00
-#define TR_RCF_BROADCAST 0x8000
-#define TR_RCF_LIMITED_BROADCAST 0xA000
+#define TR_RCF_BROADCAST 0x8000         /* all-routes broadcast */
+#define TR_RCF_LIMITED_BROADCAST 0xC000 /* single-route broadcast */
 #define TR_RCF_FRAME2K 0x20
 #define TR_RCF_BROADCAST_MASK 0xC000
 
diff -u --recursive --new-file v2.1.25/linux/include/linux/limits.h linux/include/linux/limits.h
--- v2.1.25/linux/include/linux/limits.h	Sun Nov 10 20:12:14 1996
+++ linux/include/linux/limits.h	Thu Feb  6 12:38:33 1997
@@ -1,7 +1,7 @@
 #ifndef _LINUX_LIMITS_H
 #define _LINUX_LIMITS_H
 
-#define NR_OPEN		 256
+#define NR_OPEN		1024
 
 #define NGROUPS_MAX       32	/* supplemental group IDs are available */
 #define ARG_MAX       131072	/* # bytes of args + environ for exec() */
diff -u --recursive --new-file v2.1.25/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.1.25/linux/include/linux/netdevice.h	Thu Feb  6 12:42:11 1997
+++ linux/include/linux/netdevice.h	Fri Feb  7 15:54:55 1997
@@ -185,12 +185,6 @@
 	unsigned char		if_port;	/* Selectable AUI, TP,..*/
 	unsigned char		dma;		/* DMA channel		*/
 
-	/*
-	 *	FIXME:
-	 *	The description 'enet_statistics' is misleading. We
-	 *	should change this.
-	 */
-	 
 	struct net_device_stats* (*get_stats)(struct device *dev);
 	struct iw_statistics*	(*get_wireless_stats)(struct device *dev);
 
diff -u --recursive --new-file v2.1.25/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.25/linux/include/linux/pci.h	Tue Jan 28 18:50:56 1997
+++ linux/include/linux/pci.h	Fri Feb  7 15:54:55 1997
@@ -31,14 +31,14 @@
  *	  PCI-CPU bridge or PCI-ISA bridge.
  *	- If you can't find the actual information in your hardware
  *	  booklet, try to read the references of the chip on the board.
- *	- Send all that to linux-pcisupport@cao-vlsi.ibp.fr,
+ *	- Send all that to linux-pcisupport@cck.uni-kl.de
  *	  and I'll add your device to the list as soon as possible
  *
  * BEFORE you send a mail, please check the latest linux releases
  * to be sure it has not been recently added.
  *
  *        Thanks
- *		Frederic Potter.
+ *		Jens Maurer
  */
 
 
@@ -418,6 +418,7 @@
 #define PCI_DEVICE_ID_3COM_3C595T4	0x5951
 #define PCI_DEVICE_ID_3COM_3C595MII	0x5952
 #define PCI_DEVICE_ID_3COM_3C900TPO	0x9000
+#define PCI_DEVICE_ID_3COM_3C905TX	0x9050
 
 #define PCI_VENDOR_ID_AL		0x10b9
 #define PCI_DEVICE_ID_AL_M1445		0x1445
@@ -607,9 +608,10 @@
 #define PCI_VENDOR_ID_ATRONICS		0x907f
 #define PCI_DEVICE_ID_ATRONICS_2015	0x2015
 
-#define PCI_VENDOR_ID_HER		0xedd8
-#define PCI_DEVICE_ID_HER_STING		0xa091
-#define PCI_DEVICE_ID_HER_STINGARK	0xa099
+#define PCI_VENDOR_ID_ARK		0xedd8
+#define PCI_DEVICE_ID_ARK_STING		0xa091
+#define PCI_DEVICE_ID_ARK_STINGARK	0xa099
+#define PCI_DEVICE_ID_ARK_2000MT	0xa0a1
 
 /*
  * The PCI interface treats multi-function devices as independent
diff -u --recursive --new-file v2.1.25/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.25/linux/include/linux/proc_fs.h	Sun Feb  2 15:46:21 1997
+++ linux/include/linux/proc_fs.h	Fri Feb  7 15:54:55 1997
@@ -127,6 +127,7 @@
 	PROC_NET_X25_LINKS,
 	PROC_NET_X25_ROUTES,
 	PROC_NET_X25,
+	PROC_NET_TR_RIF,
 	PROC_NET_LAST
 };
 
diff -u --recursive --new-file v2.1.25/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.25/linux/include/linux/sched.h	Sun Feb  2 15:46:21 1997
+++ linux/include/linux/sched.h	Thu Feb  6 12:53:33 1997
@@ -127,7 +127,7 @@
 
 struct fs_struct {
 	int count;
-	unsigned short umask;
+	int umask;
 	struct inode * root, * pwd;
 };
 
diff -u --recursive --new-file v2.1.25/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.25/linux/include/linux/sysctl.h	Thu Feb  6 12:42:12 1997
+++ linux/include/linux/sysctl.h	Fri Feb  7 15:54:55 1997
@@ -84,6 +84,7 @@
 #define NET_IPV6	11
 #define NET_ROSE	12
 #define NET_X25		13
+#define NET_TR		14
 
 /* /proc/sys/net/core */
 
@@ -164,6 +165,12 @@
 	NET_X25_RESET_REQUEST_TIMEOUT,
 	NET_X25_CLEAR_REQUEST_TIMEOUT,
 	NET_X25_ACK_HOLD_BACK_TIMEOUT
+};
+
+/* /proc/sys/net/token-ring */
+enum
+{
+	NET_TR_RIF_TIMEOUT=1
 };
 
 /* CTL_PROC names: */
diff -u --recursive --new-file v2.1.25/linux/include/net/lapb.h linux/include/net/lapb.h
--- v2.1.25/linux/include/net/lapb.h	Thu Jan 23 21:06:52 1997
+++ linux/include/net/lapb.h	Tue Feb  4 16:44:24 1997
@@ -44,11 +44,11 @@
 #define	LAPB_ADDR_D	0x07
 
 /* Define Link State constants. */
-#define LAPB_STATE_0	0
-#define LAPB_STATE_1	1
-#define LAPB_STATE_2	2
-#define LAPB_STATE_3	3
-#define LAPB_STATE_4	4
+#define	LAPB_STATE_0	0		/* Disconnected State		*/
+#define	LAPB_STATE_1	1		/* Awaiting Connection State	*/
+#define	LAPB_STATE_2	2		/* Awaiting Disconnection State	*/
+#define	LAPB_STATE_3	3		/* Data Transfer State		*/
+#define	LAPB_STATE_4	4		/* Frame Reject State		*/
 
 #define	LAPB_DEFAULT_MODE		(LAPB_STANDARD | LAPB_SLP | LAPB_DTE)
 #define	LAPB_DEFAULT_WINDOW		7			/* Window=7 */
@@ -69,6 +69,7 @@
 	unsigned short		n2, n2count;
 	unsigned short		t1, t2;
 	unsigned short		t1timer, t2timer;
+	struct sk_buff_head	input_queue;
 	struct sk_buff_head	write_queue;
 	struct sk_buff_head	ack_queue;
 	unsigned char		window;
@@ -77,7 +78,6 @@
 } lapb_cb;
 
 /* lapb_iface.c */
-extern lapb_cb *lapb_tokentostruct(void *);
 extern void lapb_connect_confirmation(lapb_cb *, int);
 extern void lapb_connect_indication(lapb_cb *, int);
 extern void lapb_disconnect_confirmation(lapb_cb *, int);
@@ -86,13 +86,12 @@
 extern int  lapb_data_transmit(lapb_cb *, struct sk_buff *);
 
 /* lapb_in.c */
+extern void lapb_data_input(lapb_cb *, struct sk_buff *);
 
 /* lapb_out.c */
 extern void lapb_kick(lapb_cb *);
 extern void lapb_transmit_buffer(lapb_cb *, struct sk_buff *, int);
-extern void lapb_nr_error_recovery(lapb_cb *);
 extern void lapb_establish_data_link(lapb_cb *);
-extern void lapb_transmit_enquiry(lapb_cb *);
 extern void lapb_enquiry_response(lapb_cb *);
 extern void lapb_timeout_response(lapb_cb *);
 extern void lapb_check_iframes_acked(lapb_cb *, unsigned short);
diff -u --recursive --new-file v2.1.25/linux/include/scsi/scsi.h linux/include/scsi/scsi.h
--- v2.1.25/linux/include/scsi/scsi.h	Mon Jul  8 13:09:16 1996
+++ linux/include/scsi/scsi.h	Fri Feb  7 14:34:19 1997
@@ -74,12 +74,14 @@
 #define LOG_SENSE             0x4d
 #define MODE_SELECT_10        0x55
 #define MODE_SENSE_10         0x5a
+#define MOVE_MEDIUM           0xa5
 #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 READ_ELEMENT_STATUS   0xb8
 #define SEND_VOLUME_TAG       0xb6
 #define WRITE_LONG_2          0xea
 
diff -u --recursive --new-file v2.1.25/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.25/linux/kernel/ksyms.c	Tue Jan 28 18:50:57 1997
+++ linux/kernel/ksyms.c	Fri Feb  7 15:54:55 1997
@@ -49,7 +49,7 @@
 #include <linux/swap.h>
 #include <linux/ctype.h>
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
 extern struct drive_info_struct drive_info;
 #endif
 
@@ -202,7 +202,7 @@
 EXPORT_SYMBOL(resetup_one_dev);
 EXPORT_SYMBOL(unplug_device);
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD)
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
 EXPORT_SYMBOL(drive_info);
 #endif
 
diff -u --recursive --new-file v2.1.25/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.25/linux/kernel/sched.c	Thu Feb  6 12:42:12 1997
+++ linux/kernel/sched.c	Fri Feb  7 15:54:55 1997
@@ -1187,23 +1187,32 @@
 #endif
 }
 
-static unsigned long lost_ticks = 0;
+volatile unsigned long lost_ticks = 0;
 static unsigned long lost_ticks_system = 0;
 
 static inline void update_times(void)
 {
 	unsigned long ticks;
+	unsigned long flags;
 
-	ticks = xchg(&lost_ticks, 0);
+	save_flags(flags);
+	cli();
+
+	ticks = lost_ticks;
+	lost_ticks = 0;
 
 	if (ticks) {
 		unsigned long system;
-
 		system = xchg(&lost_ticks_system, 0);
+
 		calc_load(ticks);
 		update_wall_time(ticks);
+		restore_flags(flags);
+		
 		update_process_times(ticks, system);
-	}
+
+	} else
+		restore_flags(flags);
 }
 
 static void timer_bh(void)
@@ -1349,21 +1358,21 @@
 {
 	unsigned long newprio;
 	int increase = 0;
-	int ret = -EPERM;
 
 	/*
-	 *	We need a lock. sys_setpriority can affect other tasks.
+	 *	Setpriority might change our priority at the same moment.
+	 *	We don't have to worry. Conceptually one call occurs first
+	 *	and we have a single winner.
 	 */
 	 
-	lock_kernel();
 	newprio = increment;
 	if (increment < 0) {
 		if (!suser())
-			goto out;
+			return -EPERM;
 		newprio = -increment;
 		increase = 1;
 	}
-	ret = 0;
+
 	if (newprio > 40)
 		newprio = 40;
 	/*
@@ -1377,15 +1386,21 @@
 	increment = newprio;
 	if (increase)
 		increment = -increment;
+	/*
+	 *	Current->priority can change between this point
+	 *	and the assignment. We are assigning not doing add/subs
+	 *	so thats ok. Conceptually a process might just instantaneously
+	 *	read the value we stomp over. I don't think that is an issue
+	 *	unless posix makes it one. If so we can loop on changes
+	 *	to current->priority.
+	 */
 	newprio = current->priority - increment;
 	if ((signed) newprio < 1)
 		newprio = 1;
 	if (newprio > DEF_PRIORITY*2)
 		newprio = DEF_PRIORITY*2;
 	current->priority = newprio;
-out:
-	unlock_kernel();
-	return ret;
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.1.25/linux/kernel/signal.c linux/kernel/signal.c
--- v2.1.25/linux/kernel/signal.c	Tue Jan 28 18:50:57 1997
+++ linux/kernel/signal.c	Tue Feb  4 16:44:25 1997
@@ -72,9 +72,8 @@
 {
 	int ret;
 
-	lock_kernel();
+	/* SMP safe */
 	ret = current->blocked;
-	unlock_kernel();
 	return ret;
 }
 
diff -u --recursive --new-file v2.1.25/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.25/linux/kernel/sys.c	Thu Feb  6 12:42:12 1997
+++ linux/kernel/sys.c	Tue Feb  4 16:44:25 1997
@@ -205,18 +205,17 @@
  */
 asmlinkage int sys_reboot(int magic, int magic_too, int flag)
 {
-	int error = -EPERM;
-
-	lock_kernel();
 	if (!suser())
-		goto out;
-	error = -EINVAL;
+		return -EPERM;
 	if (magic != 0xfee1dead || 
 	    (magic_too != 672274793 && magic_too != 85072278))
-		goto out;
-	error = 0;
+		return -EINVAL;
+
+
 	if (flag == 0x01234567)
 	{
+		/* SMP: We need to lock during the shutdown still */
+		lock_kernel();
 		notifier_call_chain(&boot_notifier_list, SYS_DOWN, NULL);
 		hard_reset_now();
 	}
@@ -225,6 +224,8 @@
 	else if (!flag)
 		C_A_D = 0;
 	else if (flag == 0xCDEF0123) {
+		/* SMP: We need to lock during the shutdown still */
+		lock_kernel();
 		printk(KERN_EMERG "System halted\n");
 #ifdef __sparc__
 		halt_now();
@@ -236,10 +237,8 @@
 		notifier_call_chain(&boot_notifier_list, SYS_HALT, NULL);
 		do_exit(0);
 	} else
-		error = -EINVAL;
-out:
-	unlock_kernel();
-	return error;
+		return -EINVAL;
+	return 0;
 }
 
 /*
@@ -659,24 +658,21 @@
 
 asmlinkage long sys_times(struct tms * tbuf)
 {
-	int error;
-
-	lock_kernel();
-	if (tbuf) {
-		error = put_user(current->utime,&tbuf->tms_utime);
-		if (!error)
-			error = put_user(current->stime,&tbuf->tms_stime);
-		if (!error)
-			error = put_user(current->cutime,&tbuf->tms_cutime);
-		if (!error)
-			error =	put_user(current->cstime,&tbuf->tms_cstime);
-		if (error)
-			goto out;
+	/*
+	 *	In the SMP world we might just be unlucky and have one of
+	 *	the times increment as we use it. Since the value is an
+	 *	atomically safe type this is just fine. Conceptually its
+	 *	as if the syscall took an instant longer to occur.
+	 */
+	if (tbuf) 
+	{
+		if(put_user(current->utime,&tbuf->tms_utime)||
+		   put_user(current->stime,&tbuf->tms_stime) ||
+		   put_user(current->cutime,&tbuf->tms_cutime) ||
+		   put_user(current->cstime,&tbuf->tms_cstime))
+			return -EFAULT;
 	}
-	error = jiffies;
-out:
-	unlock_kernel();
-	return error;
+	return jiffies;
 }
 
 /*
@@ -691,6 +687,7 @@
  * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
  * LBT 04.03.94
  */
+
 asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
 {
 	struct task_struct * p;
@@ -820,45 +817,40 @@
  */
 asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
 {
-	int i, err = -EINVAL;
+	int i;
+	
+	/*
+	 *	SMP: Nobody else can change our grouplist. Thus we are
+	 *	safe.
+	 */
 
-	lock_kernel();
 	if (gidsetsize < 0)
-		goto out;
+		return -EINVAL;
 	i = current->ngroups;
 	if (gidsetsize) {
-		err = -EINVAL;
 		if (i > gidsetsize)
-		        goto out;
-		err = -EFAULT;
+		        return -EINVAL;
 		if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
-			goto out;
+			return -EFAULT;
 	}
-	err = i;
-out:
-	unlock_kernel();
-	return err;
+	return i;
 }
 
+/*
+ *	SMP: Our groups are not shared. We can copy to/from them safely
+ *	without another task interfering.
+ */
+ 
 asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
 {
-	int err = -EPERM;
-
-	lock_kernel();
 	if (!suser())
-		goto out;
-	err = -EINVAL;
+		return -EPERM;
 	if ((unsigned) gidsetsize > NGROUPS)
-		goto out;
-	err = copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t));
-	if (err) {
-		gidsetsize = 0;
-		err = -EFAULT;
-	} 
+		return -EINVAL;
+	if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
+		return -EFAULT;
 	current->ngroups = gidsetsize;
-out:
-	unlock_kernel();
-	return err;
+	return 0;
 }
 
 int in_group_p(gid_t grp)
diff -u --recursive --new-file v2.1.25/linux/kernel/time.c linux/kernel/time.c
--- v2.1.25/linux/kernel/time.c	Tue Jan 28 18:50:57 1997
+++ linux/kernel/time.c	Fri Feb  7 15:54:55 1997
@@ -66,13 +66,13 @@
 {
 	int i;
 
-	lock_kernel();
+	/* SMP: This is fairly trivial. We grab CURRENT_TIME and 
+	   stuff it to user space. No side effects */
 	i = CURRENT_TIME;
 	if (tloc) {
 		if (put_user(i,tloc))
 			i = -EFAULT;
 	}
-	unlock_kernel();
 	return i;
 }
 
@@ -82,16 +82,20 @@
  * why not move it into the appropriate arch directory (for those
  * architectures that need it).
  */
+ 
 asmlinkage int sys_stime(int * tptr)
 {
-	int value = -EPERM;
+	int value;
 
-	lock_kernel();
 	if (!suser())
-		goto out;
-	value = -EFAULT;
+		return -EPERM;
 	if (get_user(value, tptr))
-		goto out;
+		return -EFAULT;
+	/*
+	 *	SMP: We need to lock out everything for the time update
+	 *	the new cli/sti semantics will let us drop this lock soon.
+	 */
+	lock_kernel();
 	cli();
 	xtime.tv_sec = value;
 	xtime.tv_usec = 0;
@@ -99,10 +103,8 @@
 	time_maxerror = MAXPHASE;
 	time_esterror = MAXPHASE;
 	sti();
-	value = 0;
-out:
 	unlock_kernel();
-	return value;
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.1.25/linux/net/802/fddi.c linux/net/802/fddi.c
--- v2.1.25/linux/net/802/fddi.c	Thu Jan  2 15:55:26 1997
+++ linux/net/802/fddi.c	Tue Feb  4 16:44:25 1997
@@ -52,18 +52,23 @@
 int fddi_header(struct sk_buff	*skb, struct device *dev, unsigned short type,
 		void *daddr, void *saddr, unsigned len)
 {
-	struct fddihdr *fddi = (struct fddihdr *)skb_push(skb, FDDI_K_SNAP_HLEN);
-
-	/* Fill in frame header - assume 802.2 SNAP frames for now */
-
+	int hl = FDDI_K_SNAP_HLEN;
+	struct fddihdr *fddi;
+	
+	if(type!=htons(ETH_P_IP))
+		hl=FDDI_K_8022_HLEN-3;
+	fddi = (struct fddihdr *)skb_push(skb, hl);
 	fddi->fc			 = FDDI_FC_K_ASYNC_LLC_DEF;
-	fddi->hdr.llc_snap.dsap		 = FDDI_EXTENDED_SAP;
-	fddi->hdr.llc_snap.ssap		 = FDDI_EXTENDED_SAP;
-	fddi->hdr.llc_snap.ctrl		 = FDDI_UI_CMD;
-	fddi->hdr.llc_snap.oui[0]	 = 0x00;
-	fddi->hdr.llc_snap.oui[1]	 = 0x00;
-	fddi->hdr.llc_snap.oui[2]	 = 0x00;
-	fddi->hdr.llc_snap.ethertype = htons(type);
+	if(type==htons(ETH_P_IP))
+	{
+		fddi->hdr.llc_snap.dsap		 = FDDI_EXTENDED_SAP;
+		fddi->hdr.llc_snap.ssap		 = FDDI_EXTENDED_SAP;
+		fddi->hdr.llc_snap.ctrl		 = FDDI_UI_CMD;
+		fddi->hdr.llc_snap.oui[0]	 = 0x00;
+		fddi->hdr.llc_snap.oui[1]	 = 0x00;
+		fddi->hdr.llc_snap.oui[2]	 = 0x00;
+		fddi->hdr.llc_snap.ethertype = htons(type);
+	}
 
 	/* Set the source and destination hardware addresses */
 	 
@@ -75,9 +80,9 @@
 	if (daddr != NULL)
 	{
 		memcpy(fddi->daddr, daddr, dev->addr_len);
-		return(FDDI_K_SNAP_HLEN);
+		return(hl);
 	}
-	return(-FDDI_K_SNAP_HLEN);
+	return(-hl);
 }
 
 
@@ -114,15 +119,26 @@
 unsigned short fddi_type_trans(struct sk_buff *skb, struct device *dev)
 {
 	struct fddihdr *fddi = (struct fddihdr *)skb->data;
-
+	unsigned short type;
+	
 	/*
 	 * Set mac.raw field to point to FC byte, set data field to point
 	 * to start of packet data.  Assume 802.2 SNAP frames for now.
 	 */
 
 	skb->mac.raw = skb->data;			/* point to frame control (FC) */
-	skb_pull(skb, FDDI_K_SNAP_HLEN);	/* adjust for 21 byte header */
-
+	
+	if(fddi->hdr.llc_8022_1.dsap==0xe0)
+	{
+		skb_pull(skb, FDDI_K_8022_HLEN-3);
+		type=htons(ETH_P_8022);
+	}
+	else
+	{
+		skb_pull(skb, FDDI_K_SNAP_HLEN);		/* adjust for 21 byte header */
+		type=fddi->hdr.llc_snap.ethertype;
+	}
+	
 	/* Set packet type based on destination address and flag settings */
 			
 	if (*fddi->daddr & 0x01)
@@ -141,5 +157,6 @@
 
 	/* Assume 802.2 SNAP frames, for now */
 
-	return(fddi->hdr.llc_snap.ethertype);
+	return(type);
+	
 }
diff -u --recursive --new-file v2.1.25/linux/net/802/p8022.c linux/net/802/p8022.c
--- v2.1.25/linux/net/802/p8022.c	Wed Jan 15 19:45:47 1997
+++ linux/net/802/p8022.c	Fri Feb  7 15:54:55 1997
@@ -55,6 +55,7 @@
 	if (proto != NULL) 
 	{
 		skb->h.raw += 3;
+		skb->nh.raw += 3;
 		skb_pull(skb,3);
 		return proto->rcvfunc(skb, dev, pt);
 	}
diff -u --recursive --new-file v2.1.25/linux/net/802/sysctl_net_802.c linux/net/802/sysctl_net_802.c
--- v2.1.25/linux/net/802/sysctl_net_802.c	Thu Jan  2 15:55:26 1997
+++ linux/net/802/sysctl_net_802.c	Fri Feb  7 15:54:55 1997
@@ -16,3 +16,11 @@
 ctl_table e802_table[] = {
 	{0}
 };
+
+#ifdef CONFIG_TR
+extern int sysctl_tr_rif_timeout;
+ctl_table tr_table[] = {
+	{NET_TR_RIF_TIMEOUT, "rif_timeout", &sysctl_tr_rif_timeout, sizeof(int),
+	 0644, NULL, &proc_dointvec},
+};
+#endif
diff -u --recursive --new-file v2.1.25/linux/net/802/tr.c linux/net/802/tr.c
--- v2.1.25/linux/net/802/tr.c	Thu Jan  2 15:55:26 1997
+++ linux/net/802/tr.c	Fri Feb  7 15:54:55 1997
@@ -6,7 +6,10 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Fixes:
+ * Fixes:       3 Feb 97 Paul Norton <pnorton@cts.com> Minor routing fixes.
+ *              Added rif table to /proc/net/tr_rif and rif timeout to
+ *              /proc/sys/net/token-ring/rif_timeout.
+ *        
  */
 
 #include <asm/uaccess.h>
@@ -26,31 +29,35 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/net.h>
+#include <linux/proc_fs.h>
 #include <net/arp.h>
 
-static void tr_source_route(struct trh_hdr *trh,struct device *dev);
-static void tr_add_rif_info(struct trh_hdr *trh);
+static void tr_source_route(struct trh_hdr *trh, struct device *dev);
+static void tr_add_rif_info(struct trh_hdr *trh, struct device *dev);
 static void rif_check_expire(unsigned long dummy);
 
+#define TR_SR_DEBUG 0
+
 typedef struct rif_cache_s *rif_cache;
 
 /*
  *	Each RIF entry we learn is kept this way
  */
  
-struct rif_cache_s
-{	
-	 unsigned char addr[TR_ALEN];
-	 unsigned short rcf;
-	 unsigned short rseg[8];
-	 rif_cache next;
-	 unsigned long last_used;
+struct rif_cache_s {	
+	unsigned char addr[TR_ALEN];
+	unsigned char iface[5];
+	__u16 rcf;
+	__u8 rseg[8];
+	rif_cache next;
+	unsigned long last_used;
+	unsigned char local_ring;
 };
 
-#define RIF_TABLE_SIZE 16
+#define RIF_TABLE_SIZE 32
 
 /*
- *	We hash the RIF cache 16 ways. We do after all have to look it
+ *	We hash the RIF cache 32 ways. We do after all have to look it
  *	up a lot.
  */
  
@@ -63,11 +70,9 @@
  *	Garbage disposal timer.
  */
  
-static struct timer_list rif_timer=
-{
-	NULL,NULL,RIF_CHECK_INTERVAL,0L,rif_check_expire
-};
+static struct timer_list rif_timer;
 
+int sysctl_tr_rif_timeout = RIF_TIMEOUT;
 
 /*
  *	Put the headers on a token ring packet. Token ring source routing
@@ -130,7 +135,7 @@
 	 */
 	 
 	if(trllc->ethertype != htons(ETH_P_IP)) {
-		printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(	trllc->ethertype));
+		printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype));
 		return 0;
 	}
 
@@ -160,8 +165,7 @@
 	
 	skb_pull(skb,dev->hard_header_len);
 	
-	if(trh->saddr[0] & TR_RII)
-		tr_add_rif_info(trh);
+	tr_add_rif_info(trh, dev);
 
 	if(*trh->daddr & 1) 
 	{
@@ -214,11 +218,11 @@
 		 */
 		if(entry) 
 		{
-#if 0
+#if TR_SR_DEBUG
 printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0],
 		  trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]);
 #endif
-			if((ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) 
+			if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
 			{
 				trh->rcf=entry->rcf;
 				memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short));
@@ -226,8 +230,15 @@
 				trh->rcf&=htons(0x1fff);	/* Issam Chehab <ichehab@madge1.demon.co.uk> */
 
 				trh->saddr[0]|=TR_RII;
-				entry->last_used=jiffies;
+#if TR_SR_DEBUG
+				printk("entry found with rcf %04x\n", entry->rcf);
+			}
+			else
+			{
+				printk("entry found but without rcf length, local=%02x\n", entry->local_ring);
+#endif
 			}
+			entry->last_used=jiffies;
 		}
 		else 
 		{
@@ -239,6 +250,7 @@
 			trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)  
 				       | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
 			trh->saddr[0]|=TR_RII;
+			printk("no entry in rif table found - broadcasting frame\n");
 		}
 	}
 }
@@ -248,27 +260,36 @@
  *	routing.
  */
  
-static void tr_add_rif_info(struct trh_hdr *trh) 
+static void tr_add_rif_info(struct trh_hdr *trh, struct device *dev)
 {
 	int i;
-	unsigned int hash;
+	unsigned int hash, rii_p = 0;
 	rif_cache entry;
 
 	/*
 	 *	Firstly see if the entry exists
 	 */
-	trh->saddr[0]&=0x7f;
+
+       	if(trh->saddr[0] & TR_RII)
+	{
+		trh->saddr[0]&=0x7f;
+		if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
+		{
+			rii_p = 1;
+	        }
+	}
+
 	for(i=0,hash=0;i<TR_ALEN;hash+=trh->saddr[i++]);
 	hash&=RIF_TABLE_SIZE-1;
 	for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
 
 	if(entry==NULL) 
 	{
-#if 0
+#if TR_SR_DEBUG
 printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
 		trh->saddr[0],trh->saddr[1],trh->saddr[2],
        		trh->saddr[3],trh->saddr[4],trh->saddr[5],
-		trh->rcf);
+		ntohs(trh->rcf));
 #endif
 		/*
 		 *	Allocate our new entry. A failure to allocate loses
@@ -278,14 +299,26 @@
 		 *	limiting and adjust the timers to suit.
 		 */
 		entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC);
+
 		if(!entry) 
 		{
 			printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
 			return;
 		}
-		entry->rcf=trh->rcf;
-		memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+
+		if (rii_p)
+		{
+			entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
+			memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+			entry->local_ring = 0;
+		}
+		else
+		{
+			entry->local_ring = 1;
+		}
+
 		memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
+		memcpy(&(entry->iface[0]),dev->name,5);
 		entry->next=rif_table[hash];
 		entry->last_used=jiffies;
 		rif_table[hash]=entry;
@@ -295,21 +328,20 @@
 		/*
 		 *	Update existing entries
 		 */
-		if ( entry->rcf != trh->rcf ) 
-		{ 
-			if (!(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) 
-			{
-#if 0
+		if (!entry->local_ring) 
+		    if (entry->rcf != (trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK)) &&
+			 !(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
+		    {
+#if TR_SR_DEBUG
 printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
 		trh->saddr[0],trh->saddr[1],trh->saddr[2],
 		trh->saddr[3],trh->saddr[4],trh->saddr[5],
-		trh->rcf);
+		ntohs(trh->rcf));
 #endif
-				entry->rcf = trh->rcf;                  
-				memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
-				entry->last_used=jiffies;               
-			}                                          
-		}                                             
+			    entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
+        		    memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+		    }                                         
+           	entry->last_used=jiffies;               
 	}
 }
 
@@ -333,7 +365,7 @@
 			/*
 			 *	Out it goes
 			 */
-			if((now-entry->last_used) > RIF_TIMEOUT) 
+			if((now-entry->last_used) > sysctl_tr_rif_timeout) 
 			{
 				*pentry=entry->next;
 				kfree_s(entry,sizeof(struct rif_cache_s));
@@ -349,7 +381,7 @@
 	 */
 	 
 	del_timer(&rif_timer);
-	rif_timer.expires=jiffies+RIF_CHECK_INTERVAL;
+	rif_timer.expires = jiffies + sysctl_tr_rif_timeout;
 	add_timer(&rif_timer);
 
 }
@@ -359,27 +391,46 @@
  *	routing.
  */
  
-int rif_get_info(char *buffer,char **start, off_t offset, int length) 
+#ifdef CONFIG_PROC_FS
+int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy) 
 {
 	int len=0;
 	off_t begin=0;
 	off_t pos=0;
-	int size,i;
+	int size,i,j,rcf_len;
+	unsigned long now=jiffies;
 
 	rif_cache entry;
 
 	size=sprintf(buffer,
-		"   TR address     rcf             routing segments             TTL\n\n");
+		     "if     TR address       TTL   rcf   routing segments\n\n");
 	pos+=size;
 	len+=size;
 
 	for(i=0;i < RIF_TABLE_SIZE;i++) 
 	{
 		for(entry=rif_table[i];entry;entry=entry->next) {
-			size=sprintf(buffer+len,"%02X:%02X:%02X:%02X:%02X:%02X %04X %04X %04X %04X %04X %04X %04X %04X %04X %lu\n",
-								entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5],
-								entry->rcf,entry->rseg[0],entry->rseg[1],entry->rseg[2],entry->rseg[3],
-								entry->rseg[4],entry->rseg[5],entry->rseg[6],entry->rseg[7],jiffies-entry->last_used); 
+			size=sprintf(buffer+len,"%s %02X:%02X:%02X:%02X:%02X:%02X %7li ",
+				     entry->iface,entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5],
+				     sysctl_tr_rif_timeout-(now-entry->last_used));
+			len+=size;
+			pos=begin+len;
+			if (entry->local_ring)
+			        size=sprintf(buffer+len,"local\n");
+			else {
+			        size=sprintf(buffer+len,"%04X", ntohs(entry->rcf));
+				rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2; 
+				if (rcf_len)
+				        rcf_len >>= 1;
+				for(j = 0; j < rcf_len; j++) {
+				        len+=size;
+				        pos=begin+len;
+			                size=sprintf(buffer+len," %04X",ntohs(entry->rseg[j]));
+				}
+				len+=size;
+				pos=begin+len;
+			        size=sprintf(buffer+len,"\n");
+			}
 			len+=size;
 			pos=begin+len;
 
@@ -401,15 +452,28 @@
 		len=length;    /* Ending slop */
 	return len;
 }
+#endif
 
 /*
  *	Called during bootup.  We don't actually have to initialise
- *	too much for this. The timer structure is setup statically. Thats
- *	probably NOT a good thing if we change the structure.
+ *	too much for this.
  */
  
 void rif_init(struct net_proto *unused) 
 {
+
+	rif_timer.expires  = RIF_TIMEOUT;
+	rif_timer.data     = 0L;
+	rif_timer.function = rif_check_expire;
+	init_timer(&rif_timer);
 	add_timer(&rif_timer);
-}
 
+#ifdef CONFIG_PROC_FS
+	proc_net_register(&(struct proc_dir_entry) {
+	  PROC_NET_TR_RIF, 6, "tr_rif",
+	    S_IFREG | S_IRUGO, 1, 0, 0,
+	    0, &proc_net_inode_operations,
+	    rif_get_info
+        });   
+#endif
+}
diff -u --recursive --new-file v2.1.25/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.25/linux/net/core/sock.c	Tue Jan 28 18:50:58 1997
+++ linux/net/core/sock.c	Tue Feb  4 16:44:25 1997
@@ -185,6 +185,10 @@
 			if(val > 65535)
 				val = 65535;
 			sk->sndbuf = val;
+			/*
+			 *	FIXME: Wake up sending tasks if we
+			 *	upped the value.
+			 */
 			break;
 
 		case SO_RCVBUF:
diff -u --recursive --new-file v2.1.25/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v2.1.25/linux/net/ipv4/Config.in	Thu Feb  6 12:42:15 1997
+++ linux/net/ipv4/Config.in	Fri Feb  7 15:54:55 1997
@@ -18,12 +18,10 @@
   fi
 fi
 bool 'IP: accounting' CONFIG_IP_ACCT
-if [ "$CONFIG_IP_FORWARD" = "y" ]; then
-  bool 'IP: optimize as router not host' CONFIG_IP_ROUTER
-  tristate 'IP: tunneling' CONFIG_NET_IPIP
-  if [ "$CONFIG_IP_MULTICAST" = "y" ]; then
-    bool 'IP: multicast routing' CONFIG_IP_MROUTE
-  fi
+bool 'IP: optimize as router not host' CONFIG_IP_ROUTER
+tristate 'IP: tunneling' CONFIG_NET_IPIP
+if [ "$CONFIG_IP_MULTICAST" = "y" ]; then
+  bool 'IP: multicast routing' CONFIG_IP_MROUTE
 fi
 if [ "$CONFIG_NET_ALIAS" = "y" ]; then
 	tristate 'IP: aliasing support' CONFIG_IP_ALIAS
diff -u --recursive --new-file v2.1.25/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.25/linux/net/ipv4/arp.c	Thu Feb  6 12:42:15 1997
+++ linux/net/ipv4/arp.c	Tue Feb  4 16:44:25 1997
@@ -54,6 +54,10 @@
  *		Stuart Cheshire	:	Metricom and grat arp fixes
  *					*** FOR 2.1 clean this up ***
  *		Lawrence V. Stefani: (08/12/96) Added FDDI support.
+ *		Alan Cox 	:	Took the AP1000 nasty FDDI hack and
+ *					folded into the mainstream FDDI code.
+ *					Ack spit, Linus how did you allow that
+ *					one in...
  */
 
 /* RFC1122 Status:
@@ -1383,7 +1387,7 @@
  *	is not from an IP number.  We can't currently handle this, so toss
  *	it. 
  */  
-#ifdef CONFIG_FDDI
+#if defined(CONFIG_FDDI) || defined(CONFIG_AP1000)
 	if (dev->type == ARPHRD_FDDI)
 	{
 		/*
@@ -1415,18 +1419,7 @@
 	}
 #else
 	if (arp->ar_hln != dev->addr_len    || 
-#if CONFIG_AP1000
-	    /*
-	     * ARP from cafe-f was found to use ARPHDR_IEEE802 instead of
-	     * the expected ARPHDR_ETHER.
-	     */
-	    (strcmp(dev->name,"fddi") == 0 && 
-	     arp->ar_hrd != ARPHRD_ETHER && arp->ar_hrd != ARPHRD_IEEE802) ||
-	    (strcmp(dev->name,"fddi") != 0 &&
-	     dev->type != ntohs(arp->ar_hrd)) ||
-#else
 	    dev->type != ntohs(arp->ar_hrd) || 
-#endif
 		dev->flags & IFF_NOARP          ||
 	        skb->pkt_type == PACKET_OTHERHOST ||
 		arp->ar_pln != 4) {
@@ -1491,8 +1484,6 @@
 	tha=arp_ptr;
 	arp_ptr += dev->addr_len;
 	memcpy(&tip, arp_ptr, 4);
-
-
 /* 
  *	Check for bad requests for 127.x.x.x and requests for multicast
  *	addresses.  If this is one such, delete it.
diff -u --recursive --new-file v2.1.25/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.25/linux/net/ipv4/tcp.c	Thu Feb  6 12:42:15 1997
+++ linux/net/ipv4/tcp.c	Fri Feb  7 15:54:55 1997
@@ -1033,8 +1033,8 @@
 				skb->h.th->urg_ptr = ntohs(copy);
 			}
 
-			skb->csum = csum_partial_copy_from_user(&err, from,
-					skb_put(skb, copy), copy, 0);
+			skb->csum = csum_partial_copy_from_user(from,
+					skb_put(skb, copy), copy, 0, &err);
 		
 			from += copy;
 			copied += copy;
diff -u --recursive --new-file v2.1.25/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.25/linux/net/ipv4/tcp_ipv4.c	Thu Feb  6 12:42:15 1997
+++ linux/net/ipv4/tcp_ipv4.c	Tue Feb  4 16:44:25 1997
@@ -629,7 +629,7 @@
 	if (sk->ack_backlog >= sk->max_ack_backlog || 
 	    tcp_v4_syn_filter(sk, skb, saddr))
 	{
-		printk(KERN_DEBUG "droping syn ack:%d max:%d\n",
+		printk(KERN_DEBUG "dropping syn ack:%d max:%d\n",
 		       sk->ack_backlog, sk->max_ack_backlog);
 #ifdef CONFIG_IP_TCPSF
 		tcp_v4_random_drop(sk);
diff -u --recursive --new-file v2.1.25/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.25/linux/net/ipv4/udp.c	Thu Feb  6 12:42:15 1997
+++ linux/net/ipv4/udp.c	Fri Feb  7 15:54:55 1997
@@ -627,7 +627,7 @@
 			       sk->ip_tos|sk->localroute);
 	if (err)
 		return err;
-	if (rt->rt_flags&RTF_BROADCAST && !sk->broadcast) {
+	if ((rt->rt_flags&RTF_BROADCAST) && !sk->broadcast) {
 		ip_rt_put(rt);
 		return -EACCES;
 	}
diff -u --recursive --new-file v2.1.25/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.25/linux/net/ipx/af_ipx.c	Sun Feb  2 15:46:22 1997
+++ linux/net/ipx/af_ipx.c	Fri Feb  7 15:54:55 1997
@@ -2103,7 +2103,7 @@
 	ipx_interface	*intrfc;
 	struct ipxhdr *ipx;
 
-	skb->h.raw = (void *)ipx = skb->nh.ipxh;
+	ipx = skb->nh.ipxh;
 	
 	/* Too small? */
 	if(ntohs(ipx->ipx_pktsize)<sizeof(struct ipxhdr)) {
diff -u --recursive --new-file v2.1.25/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c
--- v2.1.25/linux/net/lapb/lapb_iface.c	Thu Feb  6 12:42:15 1997
+++ linux/net/lapb/lapb_iface.c	Tue Feb  4 16:44:25 1997
@@ -14,6 +14,9 @@
  *
  *	History
  *	LAPB 001	Jonathan Naylor	Started Coding
+ *
+ *	TODO
+ *	Add FRMRs.
  */
  
 #include <linux/config.h>
@@ -104,7 +107,7 @@
  *	Convert the integer token used by the device driver into a pointer
  *	to a LAPB control structure.
  */
-lapb_cb *lapb_tokentostruct(void *token)
+static lapb_cb *lapb_tokentostruct(void *token)
 {
 	lapb_cb *lapb;
 
@@ -129,6 +132,7 @@
 
 	memset(lapb, 0x00, sizeof(*lapb));
 
+	skb_queue_head_init(&lapb->input_queue);
 	skb_queue_head_init(&lapb->write_queue);
 	skb_queue_head_init(&lapb->ack_queue);
 
@@ -323,6 +327,18 @@
 	skb_queue_tail(&lapb->write_queue, skb);
 
 	lapb_kick(lapb);
+
+	return LAPB_OK;
+}
+
+int lapb_data_received(void *token, struct sk_buff *skb)
+{
+	lapb_cb *lapb;
+
+	if ((lapb = lapb_tokentostruct(token)) == NULL)
+		return LAPB_BADTOKEN;
+
+	skb_queue_tail(&lapb->input_queue, skb);
 
 	return LAPB_OK;
 }
diff -u --recursive --new-file v2.1.25/linux/net/lapb/lapb_in.c linux/net/lapb/lapb_in.c
--- v2.1.25/linux/net/lapb/lapb_in.c	Thu Feb  6 12:42:15 1997
+++ linux/net/lapb/lapb_in.c	Tue Feb  4 16:44:25 1997
@@ -312,6 +312,7 @@
 				lapb->condition = 0x00;
 				lapb->t1timer   = 0;
 				lapb->t2timer   = 0;
+				lapb->n2count   = 0;
 				lapb->vs        = 0;
 				lapb->vr        = 0;
 				lapb->va        = 0;
@@ -331,6 +332,7 @@
 				lapb->condition = 0x00;
 				lapb->t1timer   = 0;
 				lapb->t2timer   = 0;
+				lapb->n2count   = 0;
 				lapb->vs        = 0;
 				lapb->vr        = 0;
 				lapb->va        = 0;
@@ -384,7 +386,7 @@
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token);
 #endif
-				lapb_nr_error_recovery(lapb);
+				lapb_establish_data_link(lapb);
 				lapb->state = LAPB_STATE_1;
 			}
 			break;
@@ -401,7 +403,7 @@
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token);
 #endif
-				lapb_nr_error_recovery(lapb);
+				lapb_establish_data_link(lapb);
 				lapb->state = LAPB_STATE_1;
 			}
 			break;
@@ -415,12 +417,13 @@
 			if (lapb_validate_nr(lapb, nr)) {
 				lapb_frames_acked(lapb, nr);
 				lapb->t1timer = 0;
+				lapb->n2count = 0;
 				lapb_requeue_frames(lapb);
 			} else {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token);
 #endif
-				lapb_nr_error_recovery(lapb);
+				lapb_establish_data_link(lapb);
 				lapb->state = LAPB_STATE_1;
 			}
 			break;
@@ -433,7 +436,7 @@
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token);
 #endif
-				lapb_nr_error_recovery(lapb);
+				lapb_establish_data_link(lapb);
 				lapb->state = LAPB_STATE_1;
 				break;
 			}
@@ -490,284 +493,11 @@
 }
 
 /*
- *	State machine for state 4, Timer Recovery State.
- *	The handling of the timer(s) is in file lapb_timer.c
- */
-static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
-{
-	int queued = 0;
-	int modulus;
-
-	modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
-
-	switch (frametype) {
-		case LAPB_SABM:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n", lapb->token, pf);
-#endif
-			if (lapb->mode & LAPB_EXTENDED) {
-#if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, pf);
-#endif
-				lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE);
-			} else {
-#if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, pf);
-#endif
-				lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
-				lapb->condition = 0x00;
-				lapb->t1timer   = 0;
-				lapb->t2timer   = 0;
-				lapb->vs        = 0;
-				lapb->vr        = 0;
-				lapb->va        = 0;
-				lapb_requeue_frames(lapb);
-			}
-			break;
-
-		case LAPB_SABME:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n", lapb->token, pf);
-#endif
-			if (lapb->mode & LAPB_EXTENDED) {
-#if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, pf);
-#endif
-				lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
-				lapb->condition = 0x00;
-				lapb->t1timer   = 0;
-				lapb->t2timer   = 0;
-				lapb->vs        = 0;
-				lapb->vr        = 0;
-				lapb->va        = 0;
-				lapb_requeue_frames(lapb);
-			} else {
-#if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, pf);
-#endif
-				lapb_send_control(lapb, LAPB_DM, pf, LAPB_RESPONSE);
-			}
-			break;
-
-		case LAPB_DISC:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX DISC(%d)\n", lapb->token, pf);
-#endif
-#if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token);
-#endif
-			lapb_clear_queues(lapb);
-			lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
-			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = lapb->t1;
-			lapb->t2timer = 0;
-			lapb_disconnect_indication(lapb, LAPB_OK);
-			break;
-
-		case LAPB_DM:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX DM(%d)\n", lapb->token, pf);
-#endif
-#if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token);
-#endif
-			lapb_clear_queues(lapb);
-			lapb->state   = LAPB_STATE_0;
-			lapb->t1timer = lapb->t1;
-			lapb->t2timer = 0;
-			lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED);
-			break;
-
-		case LAPB_RNR:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX RNR(%d) R%d\n", lapb->token, pf, nr);
-#endif
-			lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
-			if (type == LAPB_RESPONSE && pf) {
-				lapb->t1timer = 0;
-				if (lapb_validate_nr(lapb, nr)) {
-					lapb_frames_acked(lapb, nr);
-					if (lapb->vs == lapb->va) {
-#if LAPB_DEBUG > 0
-						printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
-#endif
-						lapb->n2count = 0;
-						lapb->state   = LAPB_STATE_3;
-					}
-				} else {
-#if LAPB_DEBUG > 0
-					printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-					lapb_nr_error_recovery(lapb);
-					lapb->state = LAPB_STATE_1;
-				}
-				break;
-			}
-			 
-			lapb_check_need_response(lapb, type, pf);
-			if (lapb_validate_nr(lapb, nr)) {
-				lapb_frames_acked(lapb, nr);
-			} else {
-#if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-				lapb_nr_error_recovery(lapb);
-				lapb->state = LAPB_STATE_1;
-			}
-			break;
-
-		case LAPB_RR:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX RR(%d) R%d\n", lapb->token, pf, nr);
-#endif
-			lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
-			if (pf && type == LAPB_RESPONSE) {
-				lapb->t1timer = 0;
-				if (lapb_validate_nr(lapb, nr)) {
-					lapb_frames_acked(lapb, nr);
-					if (lapb->vs == lapb->va) {
-#if LAPB_DEBUG > 0
-						printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
-#endif
-						lapb->n2count = 0;
-						lapb->state   = LAPB_STATE_3;
-					} else {
-						lapb_requeue_frames(lapb);
-					}
-				} else {
-#if LAPB_DEBUG > 0
-					printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-					lapb_nr_error_recovery(lapb);
-					lapb->state = LAPB_STATE_1;
-				}
-				break;
-			}
-
-			lapb_check_need_response(lapb, type, pf);
-			if (lapb_validate_nr(lapb, nr)) {
-				lapb_frames_acked(lapb, nr);
-			} else {
-#if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-				lapb_nr_error_recovery(lapb);
-				lapb->state = LAPB_STATE_1;
-			}
-			break;
-
-		case LAPB_REJ:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX REJ(%d) R%d\n", lapb->token, pf, nr);
-#endif
-			lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
-			if (pf && type == LAPB_RESPONSE) {
-				lapb->t1timer = 0;
-				if (lapb_validate_nr(lapb, nr)) {
-					lapb_frames_acked(lapb, nr);
-					if (lapb->vs == lapb->va) {
-#if LAPB_DEBUG > 0
-						printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
-#endif
-						lapb->n2count = 0;
-						lapb->state   = LAPB_STATE_3;
-					} else {
-						lapb_requeue_frames(lapb);
-					}
-				} else {
-#if LAPB_DEBUG > 0
-					printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-					lapb_nr_error_recovery(lapb);
-					lapb->state = LAPB_STATE_1;
-				}
-				break;
-			}
-			
-			lapb_check_need_response(lapb, type, pf);	
-			if (lapb_validate_nr(lapb, nr)) {
-				lapb_frames_acked(lapb, nr);
-				if (lapb->vs != lapb->va)
-					lapb_requeue_frames(lapb);
-			} else {
-#if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-				lapb_nr_error_recovery(lapb);
-				lapb->state = LAPB_STATE_1;
-			}
-			break;
-
-		case LAPB_I:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX I(%d) S%d R%d\n", lapb->token, pf, ns, nr);
-#endif
-			if (!lapb_validate_nr(lapb, nr)) {
-#if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-				lapb_nr_error_recovery(lapb);
-				lapb->state = LAPB_STATE_1;
-				break;
-			}
-			lapb_frames_acked(lapb, nr);
-			if (ns == lapb->vr) {
-				lapb->vr = (lapb->vr + 1) % modulus;
-				queued = lapb_data_indication(lapb, skb);
-				lapb->condition &= ~LAPB_REJECT_CONDITION;
-				if (pf) {
-					lapb_enquiry_response(lapb);
-				} else {
-					if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) {
-						lapb->t2timer = lapb->t2;
-						lapb->condition |= LAPB_ACK_PENDING_CONDITION;
-					}
-				}
-			} else {
-				if (lapb->condition & LAPB_REJECT_CONDITION) {
-					if (pf)
-						lapb_enquiry_response(lapb);
-				} else {
-#if LAPB_DEBUG > 1
-					printk(KERN_DEBUG "lapb: (%p) S4 TX REJ(%d) R%d\n", lapb->token, pf, lapb->vr);
-#endif
-					lapb->condition |= LAPB_REJECT_CONDITION;
-					lapb_send_control(lapb, LAPB_REJ, pf, LAPB_RESPONSE);
-					lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
-				}
-			}
-			break;
-
-		case LAPB_FRMR:
-		case LAPB_ILLEGAL:
-#if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 TX {FRMR,ILLEGAL}(%d)\n", lapb->token, pf);
-#endif
-#if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
-#endif
-			lapb_establish_data_link(lapb);
-			lapb->state = LAPB_STATE_1;
-			break;
-
-		default:
-			break;
-	}
-
-	if (!queued)
-		kfree_skb(skb, FREE_READ);
-}
-
-/*
  *	Process an incoming LAPB frame
  */
-int lapb_data_received(void *token, struct sk_buff *skb)
+void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb)
 {
 	int frametype, ns, nr, pf, type;
-	lapb_cb *lapb;
-
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
 
 	del_timer(&lapb->timer);
 
@@ -786,14 +516,9 @@
 		case LAPB_STATE_3:
 			lapb_state3_machine(lapb, skb, frametype, ns, nr, pf, type);
 			break;
-		case LAPB_STATE_4:
-			lapb_state4_machine(lapb, skb, frametype, ns, nr, pf, type);
-			break;
 	}
 
 	lapb_set_timer(lapb);
-
-	return LAPB_OK;
 }
 
 #endif
diff -u --recursive --new-file v2.1.25/linux/net/lapb/lapb_out.c linux/net/lapb/lapb_out.c
--- v2.1.25/linux/net/lapb/lapb_out.c	Thu Jan 23 21:06:58 1997
+++ linux/net/lapb/lapb_out.c	Tue Feb  4 16:44:25 1997
@@ -167,11 +167,6 @@
 		kfree_skb(skb, FREE_WRITE);
 }
 
-void lapb_nr_error_recovery(lapb_cb *lapb)
-{
-	lapb_establish_data_link(lapb);
-}
-
 void lapb_establish_data_link(lapb_cb *lapb)
 {
 	lapb->condition = 0x00;
@@ -193,19 +188,6 @@
 	lapb->t1timer = lapb->t1;
 }
 
-void lapb_transmit_enquiry(lapb_cb *lapb)
-{
-#if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", lapb->token, lapb->state, lapb->vr);
-#endif
-
-	lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_COMMAND);
-
-	lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
-
-	lapb->t1timer = lapb->t1;
-}
-
 void lapb_enquiry_response(lapb_cb *lapb)
 {
 #if LAPB_DEBUG > 1
@@ -233,6 +215,7 @@
 	if (lapb->vs == nr) {
 		lapb_frames_acked(lapb, nr);
 		lapb->t1timer = 0;
+		lapb->n2count = 0;
 	} else {
 		if (lapb->va != nr) {
 			lapb_frames_acked(lapb, nr);
diff -u --recursive --new-file v2.1.25/linux/net/lapb/lapb_subr.c linux/net/lapb/lapb_subr.c
--- v2.1.25/linux/net/lapb/lapb_subr.c	Thu Jan 23 21:06:58 1997
+++ linux/net/lapb/lapb_subr.c	Tue Feb  4 16:44:26 1997
@@ -45,6 +45,9 @@
 {
 	struct sk_buff *skb;
 
+	while ((skb = skb_dequeue(&lapb->input_queue)) != NULL)
+		kfree_skb(skb, FREE_READ);
+
 	while ((skb = skb_dequeue(&lapb->write_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
 
diff -u --recursive --new-file v2.1.25/linux/net/lapb/lapb_timer.c linux/net/lapb/lapb_timer.c
--- v2.1.25/linux/net/lapb/lapb_timer.c	Thu Feb  6 12:42:15 1997
+++ linux/net/lapb/lapb_timer.c	Tue Feb  4 16:44:26 1997
@@ -67,12 +67,25 @@
 static void lapb_timer(unsigned long param)
 {
 	lapb_cb *lapb = (lapb_cb *)param;
+	struct sk_buff *skb;
 
-	if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
+	/*
+	 *	Process all packet received since the last clock tick.
+	 */
+	while ((skb = skb_dequeue(&lapb->input_queue)) != NULL)
+		lapb_data_input(lapb, skb);
+
+	/*
+	 *	If in a data transfer state, transmit any data.
+	 */
+	if (lapb->state == LAPB_STATE_3)
 		lapb_kick(lapb);
 
+	/*
+	 *	T2 expiry code.
+	 */
 	if (lapb->t2timer > 0 && --lapb->t2timer == 0) {
-		if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4) {
+		if (lapb->state == LAPB_STATE_3) {
 			if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
 				lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 				lapb_timeout_response(lapb);
@@ -80,16 +93,30 @@
 		}
 	}
 
+	/*
+	 *	If T1 isn't running, or hasn't timed out yet, keep going.
+	 */
 	if (lapb->t1timer == 0 || --lapb->t1timer > 0) {
 		lapb_set_timer(lapb);
 		return;
 	}
 
+	/*
+	 *	T1 has expired.
+	 */
 	switch (lapb->state) {
+
+		/*
+		 *	If we are a DCE, keep going DM .. DM .. DM
+		 */
 		case LAPB_STATE_0:
 			if (lapb->mode & LAPB_DCE)
 				lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE);
 			break;
+
+		/*
+		 *	Awaiting connection state, send SABM(E), up to N2 times.
+		 */
 		case LAPB_STATE_1: 
 			if (lapb->n2count == lapb->n2) {
 				lapb_clear_queues(lapb);
@@ -115,6 +142,9 @@
 			}
 			break;
 
+		/*
+		 *	Awaiting disconnection state, send DISC, up to N2 times.
+		 */
 		case LAPB_STATE_2:
 			if (lapb->n2count == lapb->n2) {
 				lapb_clear_queues(lapb);
@@ -133,27 +163,21 @@
 			}
 			break;
 
-		case LAPB_STATE_3: 
-			lapb->n2count = 1;
-			lapb_transmit_enquiry(lapb);
-			lapb->state   = LAPB_STATE_4;
-#if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
-#endif
-			break;
-
-		case LAPB_STATE_4:
+		/*
+		 *	Data transfer state, restransmit I frames, up to N2 times.
+		 */
+		case LAPB_STATE_3:
 			if (lapb->n2count == lapb->n2) {
 				lapb_clear_queues(lapb);
 				lapb->state   = LAPB_STATE_0;
 				lapb->t2timer = 0;
 				lapb_disconnect_indication(lapb, LAPB_TIMEDOUT);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
 #endif
 			} else {
 				lapb->n2count++;
-				lapb_transmit_enquiry(lapb);
+				lapb_requeue_frames(lapb);
 			}
 			break;
 	}
diff -u --recursive --new-file v2.1.25/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.1.25/linux/net/netrom/nr_dev.c	Thu Feb  6 12:42:15 1997
+++ linux/net/netrom/nr_dev.c	Tue Feb  4 16:44:26 1997
@@ -59,7 +59,7 @@
 
 int nr_rx_ip(struct sk_buff *skb, struct device *dev)
 {
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 	if (!dev->start) {
 		stats->rx_errors++;
@@ -67,6 +67,8 @@
 	}
 
 	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+
 	skb->protocol = htons(ETH_P_IP);
 
 	/* Spoof incoming device */
@@ -115,7 +117,7 @@
 static int nr_rebuild_header(struct sk_buff *skb)
 {
 	struct device *dev = skb->dev;
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 	struct sk_buff *skbn;
 	unsigned char *bp = skb->data;
 
@@ -149,6 +151,7 @@
 	}
 
 	stats->tx_packets++;
+	stats->tx_bytes += skbn->len;
 
 	return 1;
 }
@@ -188,7 +191,7 @@
 
 static int nr_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 	if (skb == NULL || dev == NULL)
 		return 0;
@@ -221,9 +224,9 @@
 	return 0;
 }
 
-static struct enet_statistics *nr_get_stats(struct device *dev)
+static struct net_device_stats *nr_get_stats(struct device *dev)
 {
-	return (struct enet_statistics *)dev->priv;
+	return (struct net_device_stats *)dev->priv;
 }
 
 int nr_init(struct device *dev)
@@ -250,10 +253,10 @@
 	dev->pa_mask		= 0;
 	dev->pa_alen		= sizeof(unsigned long);
 
-	if ((dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL)) == NULL)
+	if ((dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
-	memset(dev->priv, 0, sizeof(struct enet_statistics));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 
 	dev->get_stats = nr_get_stats;
 
diff -u --recursive --new-file v2.1.25/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.1.25/linux/net/rose/rose_dev.c	Thu Feb  6 12:42:16 1997
+++ linux/net/rose/rose_dev.c	Tue Feb  4 16:44:27 1997
@@ -55,7 +55,7 @@
 
 int rose_rx_ip(struct sk_buff *skb, struct device *dev)
 {
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 	if (!dev->start) {
 		stats->rx_errors++;
@@ -63,6 +63,8 @@
 	}
 
 	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+
 	skb->protocol = htons(ETH_P_IP);
 
 	/* Spoof incoming device */
@@ -96,7 +98,7 @@
 static int rose_rebuild_header(struct sk_buff *skb)
 {
 	struct device *dev = skb->dev;
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 	unsigned char *bp = (unsigned char *)skb->data;
 	struct sk_buff *skbn;
 
@@ -121,6 +123,7 @@
 	}
 
 	stats->tx_packets++;
+	stats->tx_bytes += skbn->len;
 
 	return 1;
 }
@@ -160,7 +163,7 @@
 
 static int rose_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 
 	if (skb == NULL || dev == NULL)
 		return 0;
@@ -193,9 +196,9 @@
 	return 0;
 }
 
-static struct enet_statistics *rose_get_stats(struct device *dev)
+static struct net_device_stats *rose_get_stats(struct device *dev)
 {
-	return (struct enet_statistics *)dev->priv;
+	return (struct net_device_stats *)dev->priv;
 }
 
 int rose_init(struct device *dev)
@@ -222,10 +225,10 @@
 	dev->pa_mask		= 0;
 	dev->pa_alen		= sizeof(unsigned long);
 
-	if ((dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL)) == NULL)
+	if ((dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
-	memset(dev->priv, 0, sizeof(struct enet_statistics));
+	memset(dev->priv, 0, sizeof(struct net_device_stats));
 
 	dev->get_stats = rose_get_stats;
 
diff -u --recursive --new-file v2.1.25/linux/net/socket.c linux/net/socket.c
--- v2.1.25/linux/net/socket.c	Thu Feb  6 12:42:16 1997
+++ linux/net/socket.c	Fri Feb  7 15:57:06 1997
@@ -645,7 +645,7 @@
 asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2])
 {
 	int fd1, fd2, i;
-	struct socket *sock1, *sock2;
+	struct socket *sock1=NULL, *sock2=NULL;
 	int err;
 
 	lock_kernel();
@@ -700,6 +700,10 @@
 		}
 	}
 out:
+	if(sock1)
+		sockfd_put(sock1);
+	if(sock2)
+		sockfd_put(sock2);
 	unlock_kernel();
 	return err;
 }
@@ -1114,6 +1118,7 @@
 		err=sock->ops->shutdown(sock, how);
 		sockfd_put(sock);
 	}
+	unlock_kernel();
 	return err;
 }
 
diff -u --recursive --new-file v2.1.25/linux/net/sysctl_net.c linux/net/sysctl_net.c
--- v2.1.25/linux/net/sysctl_net.c	Tue Nov 12 15:56:17 1996
+++ linux/net/sysctl_net.c	Fri Feb  7 15:54:55 1997
@@ -42,6 +42,10 @@
 extern ctl_table ipv6_table[];
 #endif
 
+#ifdef CONFIG_TR
+extern ctl_table tr_table[];
+#endif
+
 ctl_table net_table[] = {
 	{NET_CORE,   "core",      NULL, 0, 0555, core_table},      
         {NET_UNIX,   "unix",      NULL, 0, 0555, unix_table},
@@ -63,6 +67,9 @@
 #endif
 #ifdef CONFIG_IPV6
 	{NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table},
+#endif
+#ifdef CONFIG_TR
+	{NET_TR, "token-ring", NULL, 0, 0555, tr_table},
 #endif
 	{0}
 };
diff -u --recursive --new-file v2.1.25/linux/scripts/Configure linux/scripts/Configure
--- v2.1.25/linux/scripts/Configure	Wed Jan 15 19:45:47 1997
+++ linux/scripts/Configure	Fri Feb  7 15:54:55 1997
@@ -288,7 +288,7 @@
 	def=${old:-$3}
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
-	  if expr "$ans" : '0$\|-?[1-9][0-9]*$' > /dev/null; then
+	  if expr "$ans" : '0$\|-\?[1-9][0-9]*$' > /dev/null; then
 	    define_int "$2" "$ans"
 	    break
 	  else
@@ -319,7 +319,7 @@
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
 	  ans=${ans#*[x,X]}
-	 if expr "$ans" : '[0-9a-fA-F]+$' > /dev/null; then
+	 if expr "$ans" : '[0-9a-fA-F]\+$' > /dev/null; then
 	   define_hex "$2" "$ans"
 	   break
 	 else
diff -u --recursive --new-file v2.1.25/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.1.25/linux/scripts/Menuconfig	Wed Jan 15 19:45:47 1997
+++ linux/scripts/Menuconfig	Fri Feb  7 15:54:55 1997
@@ -400,7 +400,7 @@
 			answer="`cat MCdialog.out`"
 			answer="${answer:-$3}"
 
-			if expr $answer : '0$\|-?[1-9][0-9]*$' >/dev/null
+			if expr $answer : '0$\|-\?[1-9][0-9]*$' >/dev/null
 			then
 				eval $2="$answer"
 			else
@@ -433,7 +433,7 @@
 			answer="${answer:-$3}"
 			answer="${answer##*[x,X]}"
 
-			if expr $answer : '[0-9a-fA-F]+$' >/dev/null
+			if expr $answer : '[0-9a-fA-F]\+$' >/dev/null
 			then
 				eval $2="$answer"
 			else
