diff -u --recursive --new-file v2.1.21/linux/Documentation/00-INDEX linux/Documentation/00-INDEX
--- v2.1.21/linux/Documentation/00-INDEX	Sun Dec 22 16:37:16 1996
+++ linux/Documentation/00-INDEX	Thu Jan 16 04:46:05 1997
@@ -52,6 +52,8 @@
 	- list of magic numbers used to mark/protect kernel data structures.
 mandatory.txt
 	- info on the linux implementation of Sys V mandatory file locking.
+memory.txt
+	- info on typical Linux memory problems.
 mca.txt
 	- info on supporting Micro Channel Architecture (e.g. PS/2) systems.
 modules.txt
diff -u --recursive --new-file v2.1.21/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.21/linux/Documentation/Changes	Wed Jan 15 19:45:38 1997
+++ linux/Documentation/Changes	Sun Jan 19 15:47:24 1997
@@ -49,7 +49,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.
+in Lilo. A small number of machines need "reboot=bios" to reboot via the 
+BIOS.
 
 Libc
 ====
@@ -128,15 +129,18 @@
 installed programs and libraries.  The SysVinit version display
 requires that you be logged in as root.
 
+Binutils: ld -v
 Gnu C: gcc -v or gcc --version
+Kbd: loadkeys -h
+Ld.so:  ldd -v
 Libc: ls -l /lib/libc.so.*
 Libc++: ls -l /usr/lib/libg++.so.*
-Ld.so:  ldd-v
-Binutils: ld -v
-modules: insmod -V
+modules: /sbin/insmod -V
+mount: mount --version
 procps: ps --version
-SysVinit: cat /proc/`cat /var/run/klogd.pid`/environ|strings|awk '$1 ~
-/INIT_VERSION/ {print}'
+SysVinit: (must be logged in as root)
+    strings `egrep -li INIT_VERSION=sysvinit- /proc/*/environ | head -1` | \
+    egrep -i INIT_VERSION=sysvinit-
 RPM:  rpm --version
 
 Where to get the files
diff -u --recursive --new-file v2.1.21/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.21/linux/Documentation/Configure.help	Wed Jan 15 19:45:39 1997
+++ linux/Documentation/Configure.help	Thu Jan 16 04:46:06 1997
@@ -550,27 +550,6 @@
   Machine") (as opposed to Mustang (AS200), M3 (AS250) or Avanti
   (AS400)), say Y, otherwise N.
 
-Limit memory to low 16MB
-CONFIG_MAX_16M
-  This is for some buggy motherboards which cannot properly deal with
-  the memory above 16MB. If you have more than 16MB of RAM and
-  experience weird problems, you might want to try Y, everyone else
-  says N. Note for machines with more that 64MB of RAM: in order for
-  the kernel to be able to use the memory above 64MB, pass the command
-  line option "mem=XXXM" (where XXX is the memory size in megabytes)
-  to your kernel during boot time. See the documentation of your boot
-  loader (lilo or loadlin) about how to pass options to the
-  kernel. The lilo procedure is also explained in the SCSI-HOWTO,
-  available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  You also need at least 512kB
-  of RAM cache if you have more than 64MB of RAM.  Some other things
-  to try when experiencing seemingly random, "weird" problems: 1)
-  passing the "no-hlt" option to the kernel 2) passing the "no-387"
-  option to the kernel 3) passing the "mem=4M" option to the kernel
-  (thereby disabling all but the first 4M of RAM) 4) disabling the
-  cache from your BIOS settings 5) exchanging RAM chips 6) exchanging
-  the motherboard.
-
 Using SRM as bootloader
 CONFIG_ALPHA_SRM
   There are two different types of booting firmware on Alphas: SRM,
diff -u --recursive --new-file v2.1.21/linux/Documentation/memory.txt linux/Documentation/memory.txt
--- v2.1.21/linux/Documentation/memory.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/memory.txt	Thu Jan 16 04:46:06 1997
@@ -0,0 +1,60 @@
+There are several classic problems related to memory on Linux
+systems.
+
+	1) There are some buggy motherboards which cannot properly 
+	   deal with the memory above 16MB.  Consider exchanging
+	   your motherboard.
+
+	2) You cannot do DMA on the ISA bus to addresses above
+	   16M.  Most device drivers under Linux allow the use
+           of bounce buffers which work around this problem.  Drivers
+	   that don't use bounce buffers will be unstable with
+	   more than 16M installed.  Drivers that use bounce buffers
+	   will be OK, but may have slightly higher overhead.
+	
+	3) There are some motherboards that will not cache above
+	   a certain quantity of memory.  If you have one of these
+	   motherboards, your system will be SLOWER, not faster
+	   as you add more memory.  Consider exchanging your 
+           motherboard.
+
+	4) Linux will not currently detect above 64M of RAM, 
+	   regardless of how much memory is actually installed.
+
+All of these problems can be addressed with the "mem=XXXM" boot option
+(where XXX is the size of RAM to use in megabytes).  Adding this boot
+option to your boot loader can help Linux see more than 64M.  It can
+also tell Linux to use less memory than is actually installed.
+
+See the documentation of your boot loader (LILO, loadlin, etc.) about
+how to pass options to the kernel.
+
+There are other memory problems which Linux cannot deal with.  Random
+corruption of memory is usually a sign of serious hardware trouble.
+Try:
+
+	* Reducing memory settings in the BIOS to the most conservative 
+          timings.
+
+	* Adding a cooling fan.
+
+	* Not overclocking your CPU.
+
+	* Having the memory tested in a memory tester or exchanged
+	  with the vendor.
+	
+	* Exchanging your CPU, cache, or motherboard for one that works.
+
+	* Disabling the cache from the BIOS.
+
+	* Try passing the "mem=4M" option to the kernel to limit
+	  Linux to using a very small amount of memory.
+
+
+Other tricks:
+
+	* Try passing the "no-387" option to the kernel to ignore
+	  a buggy FPU.
+
+	* Try passing the "no-hlt" option to disable the potentially
+          buggy HLT instruction in your CPU.
diff -u --recursive --new-file v2.1.21/linux/Documentation/pcwd-watchdog.txt linux/Documentation/pcwd-watchdog.txt
--- v2.1.21/linux/Documentation/pcwd-watchdog.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/pcwd-watchdog.txt	Sun Jan 19 15:47:24 1997
@@ -0,0 +1,131 @@
+                     Berkshire Products PC Watchdog Card
+                   Support for ISA Cards  Revision A and C
+           Documentation and Driver by Ken Hollis <khollis@nurk.org>
+
+ The PC Watchdog is a card that offers the same type of functionality that
+ the WDT card does, only it doesn't require an IRQ to run.  Furthermore,
+ the Revision C card allows you to monitor any IO Port to automatically
+ trigger the card into being reset.  This way you can make the card
+ monitor hard drive status, or anything else you need.
+
+ The Watchdog Driver has one basic role: to talk to the card and send
+ signals to it so it doesn't reset your computer ... at least during
+ normal operation.
+
+ The Watchdog Driver will automatically find your watchdog card, and will
+ attach a running driver for use with that card.  After the watchdog
+ drivers have initialized, you can then talk to the card using the PC
+ Watchdog program, available from ftp.bitgate.com:/pub/bitgate/pcwd.
+
+ I suggest putting a "watchdog -d" before the beginning of an fsck, and
+ a "watchdog -e -t 1" immediately after the end of an fsck.  (Remember
+ to run the program with an "&" to run it in the background!)
+
+ If you want to write a program to be compatible with the PC Watchdog
+ driver, simply do the following:
+
+-- Snippet of code --
+/*
+ * Watchdog Driver Test Program
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/pcwd.h>
+
+int fd;
+
+/*
+ * This function simply sends an IOCTL to the driver, which in turn ticks
+ * the PC Watchdog card to reset its internal timer so it doesn't trigger
+ * a computer reset.
+ */
+void keep_alive(void)
+{
+    int dummy;
+
+    ioctl(fd, WDIOC_KEEPALIVE, &dummy);
+}
+
+/*
+ * The main program.  Run the program with "-d" to disable the card,
+ * or "-e" to enable the card.
+ */
+int main(int argc, char *argv[])
+{
+    fd = open("/dev/watchdog", O_WRONLY);
+
+    if (fd == -1) {
+	fprintf(stderr, "Watchdog device not enabled.\n");
+	fflush(stderr);
+	exit(-1);
+    }
+
+    if (argc > 1) {
+	if (!strncasecmp(argv[1], "-d", 2)) {
+	    ioctl(fd, WDIOC_SETOPTIONS, WDIOS_DISABLECARD);
+	    fprintf(stderr, "Watchdog card disabled.\n");
+	    fflush(stderr);
+	    exit(0);
+	} else if (!strncasecmp(argv[1], "-e", 2)) {
+	    ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD);
+	    fprintf(stderr, "Watchdog card enabled.\n");
+	    fflush(stderr);
+	    exit(0);
+	} else {
+	    fprintf(stderr, "-d to disable, -e to enable.\n");
+	    fprintf(stderr, "run by itself to tick the card.\n");
+	    fflush(stderr);
+	    exit(0);
+	}
+    } else {
+	fprintf(stderr, "Watchdog Ticking Away!\n");
+	fflush(stderr);
+    }
+
+    while(1) {
+	keep_alive();
+	sleep(1);
+    }
+}
+-- End snippet --
+
+ Other IOCTL functions include:
+
+	WDIOC_GETSUPPORT
+		This returns the support of the card itself.  This
+		returns in structure "PCWDS" which returns:
+			options = WDIOS_TEMPPANIC
+				  (This card supports temperature)
+			firmware_version = xxxx
+				  (Firmware version of the card)
+
+	WDIOC_GETSTATUS
+		This returns the status of the card, with the bits of
+		WDIOF_* bitwise-anded into the value.  (The comments
+		are in linux/pcwd.h)
+
+	WDIOC_GETBOOTSTATUS
+		This returns the status of the card that was reported
+		at bootup.
+
+	WDIOC_GETTEMP
+		This returns the temperature of the card.  (You can also
+		read /dev/watchdog, which gives a temperature update
+		every second.)
+
+	WDIOC_SETOPTIONS
+		This lets you set the options of the card.  You can either
+		enable or disable the card this way.
+
+	WDIOC_KEEPALIVE
+		This pings the card to tell it not to reset your computer.
+
+ And that's all she wrote!
+
+ -- Ken Hollis
+    (khollis@nurk.org)
diff -u --recursive --new-file v2.1.21/linux/Documentation/watchdog.txt linux/Documentation/watchdog.txt
--- v2.1.21/linux/Documentation/watchdog.txt	Thu Jun  6 14:57:43 1996
+++ linux/Documentation/watchdog.txt	Sun Jan 19 15:47:24 1997
@@ -11,17 +11,20 @@
 	ICS	WDT501-P (no fan tachometer)
 	ICS	WDT500-P
 	Software Only
+	Berkshire Products PC Watchdog Revision A & C (by Ken Hollis)
 
-All four interfaces provide /dev/watchdog, which when open must be written
-to within a minute or the machine will reboot. Each write delays the reboot
-time another minute. In the case of the software watchdog the ability to 
+
+All five interfaces provide /dev/watchdog, which when open must be written
+to within a timeout or the machine will reboot. Each write delays the reboot
+time another timeout. In the case of the software watchdog the ability to 
 reboot will depend on the state of the machines and interrupts. The hardware
 boards physically pull the machine down off their own onboard timers and
 will reboot from almost anything.
 
 A second temperature monitoring interface is available on the WDT501P cards
-and provides /dev/temperature. This is the machine internal temperature in
-degrees farenheit. Each read returns a single byte giving the temperature.
+and some Berkshire cards. This provides /dev/temperature. This is the machine 
+internal temperature in degrees farenheit. Each read returns a single byte 
+giving the temperature.
 
 The third interface logs kernel messages on additional alert events.
 
@@ -29,16 +32,20 @@
 kernel. If you are using the software watchdog, you probably also want
 to use "panic=60" as a boot argument as well.
 
+The wdt card cannot be safely probed for. Instead you need to pass
+wdt=ioaddr,irq as a boot parameter - eg "wdt=0x240,11".
+
 Features
 --------
-		WDT501P		WDT500P		Software
-Reboot Timer	   X               X                X
-External Reboot	   X	           X                o
-Temperature	   X		   o		    o
-Fan Speed          X		   o		    o
-Power Under	   X               o                o
-Power Over         X               o                o
-Overheat           X               o                o
+		WDT501P		WDT500P		Software	Berkshire
+Reboot Timer	   X               X                X		    X
+External Reboot	   X	           X                o		    o
+I/O Port Monitor   o		   o		    o		    X
+Temperature	   X		   o		    o               X
+Fan Speed          X		   o		    o               o
+Power Under	   X               o                o               o
+Power Over         X               o                o               o
+Overheat           X               o                o               o
 
 The external event interfaces on the WDT boards are not currently supported.
 Minor numbers are however allocated for it.
@@ -81,3 +88,5 @@
 San Diego, CA     
 
 and please mention Linux when enquiring.
+
+For full information about the PCWD cards see the pcwd-watchdog.txt document.
diff -u --recursive --new-file v2.1.21/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.21/linux/MAINTAINERS	Sun Dec 22 16:37:20 1996
+++ linux/MAINTAINERS	Sun Jan 19 19:15:39 1997
@@ -28,7 +28,7 @@
 	job the maintainers (and especially Linus) do is to keep things
 	looking the same. Sometimes this means that the clever hack in
 	your driver to get around a problem actual needs to become a
-	generalised kernel feature ready for next time.
+	generalized kernel feature ready for next time.
 
 	PLEASE try to include any credit lines you want added with the
 	patch. It avoids people being missed off by mistake and makes
@@ -387,4 +387,4 @@
 
 REST:
 P:	Linus Torvalds
-S:	Buried alive in email
+S:	Buried alive in diapers
diff -u --recursive --new-file v2.1.21/linux/Makefile linux/Makefile
--- v2.1.21/linux/Makefile	Wed Jan 15 19:45:39 1997
+++ linux/Makefile	Wed Jan 15 20:07:25 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 21
+SUBLEVEL = 22
 
 ARCH = i386
 
diff -u --recursive --new-file v2.1.21/linux/README linux/README
--- v2.1.21/linux/README	Thu Dec 12 19:36:57 1996
+++ linux/README	Sun Jan 19 15:47:24 1997
@@ -108,15 +108,35 @@
 
    You should now have the sources correctly installed.
 
+SOFTWARE REQUIREMENTS
+
+   Compiling and running the 2.1.x kernels requires up-to-date
+   versions of various software packages.  Consult
+   ./Documentation/Changes for the minimum version numbers required
+   and how to get updates for these packages.  Beware that using
+   excessively old versions of these packages can cause indirect
+   errors that are very difficult to track down, so don't assume that
+   you can just update packages when obvious problems arise during
+   build or operation.
+
 CONFIGURING the kernel:
 
  - Do a "make config" to configure the basic kernel.  "make config"
    needs bash to work: it will search for bash in $BASH, /bin/bash and
    /bin/sh (in that order), so hopefully one of those is correct. 
 
+   (Do not skip this step even if you are only upgrading one minor
+   version.  New configuration options are added in each release, and
+   odd problems will turn up if the configuration files are not set up
+   as expected.  If you want to carry your existing configuration to a
+   new version with minimal work, use "make oldconfig", which will
+   only ask you for the answers to new questions.)
+
  - Alternate configuration commands are:
 	"make menuconfig"  Text based color menus, radiolists & dialogs.
 	"make xconfig"     X windows based configuration tool.
+	"make oldconfig"   Default all questions based on the contents of
+			   your existing ./.config file.
    
 	NOTES on "make config":
 	- having unnecessary drivers will make the kernel bigger, and can
@@ -134,8 +154,8 @@
 	  bigger or slower kernel (or both), and can even make the kernel
 	  less stable by configuring some routines to actively try to
 	  break bad code to find kernel problems (kmalloc()).  Thus you
-	  should probably answer 'n' to the questions for a "production"
-	  kernel. 
+	  should probably answer 'n' to the questions for
+          "development", "experimental", or "debugging" features.
 
  - Check the top Makefile for further site-dependent configuration
    (default SVGA mode etc). 
diff -u --recursive --new-file v2.1.21/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.21/linux/arch/alpha/defconfig	Wed Jan 15 19:45:39 1997
+++ linux/arch/alpha/defconfig	Wed Jan 15 02:46:07 1997
@@ -165,6 +165,7 @@
 # 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
 
@@ -196,6 +197,7 @@
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
diff -u --recursive --new-file v2.1.21/linux/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c
--- v2.1.21/linux/arch/i386/boot/compressed/misc.c	Mon Sep 23 11:29:03 1996
+++ linux/arch/i386/boot/compressed/misc.c	Sun Jan 19 15:47:24 1997
@@ -340,7 +340,11 @@
 
 void setup_normal_output_buffer()
 {
-	if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n");
+#ifdef STANDARD_MEMORY_BIOS_CALL
+	if (EXT_MEM_K < 1024) error("<2M of mem\n");
+#else
+	if (EXT_MEM_K*64 < 1024) error("<2M of mem\n");
+#endif
 	output_data = (char *)0x100000; /* Points to 1M */
 }
 
diff -u --recursive --new-file v2.1.21/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.1.21/linux/arch/i386/boot/setup.S	Wed Dec 18 15:58:34 1996
+++ linux/arch/i386/boot/setup.S	Sun Jan 19 15:47:24 1997
@@ -232,9 +232,40 @@
 loader_ok:
 ! Get memory size (extended mem, kB)
 
+#ifdef STANDARD_MEMORY_BIOS_CALL
 	mov	ah,#0x88
 	int	0x15
 	mov	[2],ax
+#else
+	push	ax
+	push	cx
+	push	dx
+	mov	ax,#0xe801
+	int	0x15
+	jc	oldstylemem
+
+! memory size is (ax+(64*bx)) * 1024; we store bx+(ax/64)
+
+	mov	[2],bx		! store extended memory size
+	xor	dx,dx
+	mov	cx,#64		! convert lower memory size from K into
+	div	cx		! 64k chunks.
+
+	add	[2],ax		! add lower memory into total size.
+	jmp	gotmem
+
+oldstylemem:
+	mov	ah,#0x88
+	int	0x15
+	mov	cx,#64		! got memory size in kbytes, so we need to
+	xor	dx,dx		! adjust to 64k chunks for the system.
+	div	cx
+	mov	[2],ax
+gotmem:
+	pop	dx
+	pop	cx
+	pop	ax
+#endif
 
 ! Set the keyboard repeat rate to the max
 
diff -u --recursive --new-file v2.1.21/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.1.21/linux/arch/i386/config.in	Thu Dec 12 19:36:57 1996
+++ linux/arch/i386/config.in	Thu Jan 16 04:46:06 1997
@@ -23,7 +23,6 @@
 
 bool 'Kernel math emulation' CONFIG_MATH_EMULATION
 bool 'Networking support' CONFIG_NET
-bool 'Limit memory to low 16MB' CONFIG_MAX_16M
 bool 'PCI bios support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file v2.1.21/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.21/linux/arch/i386/defconfig	Wed Jan 15 19:45:39 1997
+++ linux/arch/i386/defconfig	Thu Jan 16 04:46:06 1997
@@ -19,7 +19,6 @@
 #
 # CONFIG_MATH_EMULATION is not set
 CONFIG_NET=y
-# CONFIG_MAX_16M is not set
 CONFIG_PCI=y
 # CONFIG_MCA is not set
 CONFIG_SYSVIPC=y
diff -u --recursive --new-file v2.1.21/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.21/linux/arch/i386/kernel/irq.c	Sun Nov 10 20:12:08 1996
+++ linux/arch/i386/kernel/irq.c	Thu Jan 16 04:33:35 1997
@@ -285,7 +285,7 @@
 		for (j=0;j<smp_num_cpus;j++)
 			len+=sprintf(buf+len, "%10d ",
 				int_count[cpu_logical_map[j]][i]);
-		len += sprintf(buf+len, "%c %s\n",
+		len += sprintf(buf+len, "%c %s",
 			(action->flags & SA_INTERRUPT) ? '+' : ' ',
 			action->name);
 		for (action=action->next; action; action = action->next) {
@@ -293,6 +293,7 @@
 				(action->flags & SA_INTERRUPT) ? " +" : "",
 				action->name);
 		}
+		len += sprintf(buf+len, "\n");
 	}
 	len+=sprintf(buf+len, "LCK: %10lu",
 		sum_spins);
diff -u --recursive --new-file v2.1.21/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.1.21/linux/arch/i386/kernel/setup.c	Thu Dec 12 19:36:57 1996
+++ linux/arch/i386/kernel/setup.c	Sun Jan 19 15:47:24 1997
@@ -142,16 +142,16 @@
 		BIOS_revision = SYS_DESC_TABLE.table[2];
 	}
 	aux_device_present = AUX_DEVICE_INFO;
+#ifdef STANDARD_MEMORY_BIOS_CALL
 	memory_end = (1<<20) + (EXT_MEM_K<<10);
+#else
+	memory_end = (1<<20) + (EXT_MEM_K*64L*1024L);	/* 64kb chunks */
+#endif
 	memory_end &= PAGE_MASK;
 #ifdef CONFIG_BLK_DEV_RAM
 	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
 	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
 	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-#ifdef CONFIG_MAX_16M
-	if (memory_end > 16*1024*1024)
-		memory_end = 16*1024*1024;
 #endif
 	if (!MOUNT_ROOT_RDONLY)
 		root_mountflags &= ~MS_RDONLY;
diff -u --recursive --new-file v2.1.21/linux/arch/i386/lib/semaphore.S linux/arch/i386/lib/semaphore.S
--- v2.1.21/linux/arch/i386/lib/semaphore.S	Sat Oct  5 16:58:34 1996
+++ linux/arch/i386/lib/semaphore.S	Wed Jan 15 19:32:17 1997
@@ -7,21 +7,26 @@
 #include <linux/linkage.h>
 
 /*
- * "down_failed" is called with the eventual return address
- * in %eax, and the address of the semaphore in %ecx. We need
- * to call "__down()", and then re-try until we succeed..
+ * The semaphore operations have a special calling sequence that
+ * allow us to do a simpler in-line version of them. These routines
+ * need to convert that sequence back into the C sequence when
+ * there is contention on the semaphore.
  */
 ENTRY(__down_failed)
 	pushl %eax	/* return address */
 	pushl %edx	/* save %edx */
-1:	pushl %ecx	/* save %ecx (and argument) */
+	pushl %ecx	/* save %ecx (and argument) */
 	call SYMBOL_NAME(__down)
 	popl %ecx	/* restore %ecx (count on __down not changing it) */
-#ifdef __SMP__
-	lock
-#endif
-	decl (%ecx)
-	js 1b
+	popl %edx	/* restore %edx */
+	ret
+
+ENTRY(__down_failed_interruptible)
+	pushl %eax	/* return address */
+	pushl %edx	/* save %edx */
+	pushl %ecx	/* save %ecx (and argument) */
+	call SYMBOL_NAME(__down_interruptible)
+	popl %ecx	/* restore %ecx (count on __down_interruptible not changing it) */
 	popl %edx	/* restore %edx */
 	ret
 
diff -u --recursive --new-file v2.1.21/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.1.21/linux/arch/ppc/config.in	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/config.in	Thu Jan 16 04:46:06 1997
@@ -23,7 +23,6 @@
 
 bool 'Kernel math emulation' CONFIG_MATH_EMULATION
 bool 'Networking support' CONFIG_NET
-bool 'Limit memory to low 16MB' CONFIG_MAX_16M
 bool 'PCI bios support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file v2.1.21/linux/drivers/block/README.fd linux/drivers/block/README.fd
--- v2.1.21/linux/drivers/block/README.fd	Mon Dec 30 15:39:04 1996
+++ linux/drivers/block/README.fd	Sun Jan 19 15:27:57 1997
@@ -49,14 +49,9 @@
 
  The floppy related options include:
 
- floppy=<mask>,allowed_drive_mask         
-	Obsolete. Use the floppy=<drive>,<type>,cmos option instead
-
- floppy=all_drives
-	Obsolete. Use the floppy=<drive>,<type>,cmos option instead
-
  floppy=asus_pci
-	Sets the bit mask to allow only units 0 and 1. (The default)
+	Sets the bit mask to allow only units 0 and 1. Obsolete, as
+	this is the default setting anyways	
 
  floppy=daring
 	Tells the floppy driver that you have a well behaved floppy controller.
@@ -161,6 +156,28 @@
 	to be an interaction between video and floppy. The unexpected interrupts
 	only affect performance, and can safely be ignored.)
 
+ floppy=broken_dcl
+	Don't use the disk change line, but assume that the disk was
+	changed whenever the device node is reopened. Needed on some
+	boxes where the disk change line is broken or unsupported.
+	This should be regarded as a stopgap measure, indeed it makes
+	floppy operation less efficient due to unneeded cache
+	flushings, and slightly more unreliable. Please verify your
+	cable, connection and jumper settings if you have any DCL
+	problems. However, some older drives, and also some Laptops
+	are known not to have a DCL.
+
+ floppy=debug
+	Print debugging messages
+
+ floppy=messages
+	Print informational messages for some operations (disk change
+	notifications, warnings about over and underruns, and about
+	autodetection)
+
+ floppy=silent_dcl_clear
+	Uses a less noisy way to clear the disk change line (which
+	doesn't involve seeks). Implied by daring.
 
 Supporting utilities and additional documentation:
 ==================================================
diff -u --recursive --new-file v2.1.21/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.21/linux/drivers/block/floppy.c	Mon Dec 30 15:39:04 1996
+++ linux/drivers/block/floppy.c	Sun Jan 19 16:10:13 1997
@@ -2252,7 +2252,8 @@
 				return;
 			}
 			current_type[current_drive] = _floppy;
-			floppy_sizes[TOMINOR(current_drive) ]= _floppy->size>>1;
+			floppy_sizes[TOMINOR(current_drive) ]= 
+				(_floppy->size+1)>>1;
 			break;
 	}
 
@@ -2261,7 +2262,7 @@
 			DPRINT("Auto-detected floppy type %s in fd%d\n",
 				_floppy->name,current_drive);
 		current_type[current_drive] = _floppy;
-		floppy_sizes[TOMINOR(current_drive)] = _floppy->size >> 1;
+		floppy_sizes[TOMINOR(current_drive)] = (_floppy->size+1) >> 1;
 		probing = 0;
 	}
 
@@ -2450,8 +2451,13 @@
 
 	TRACK = CURRENT->sector / max_sector;
 	sector_t = CURRENT->sector % max_sector;
-	if (_floppy->track && TRACK >= _floppy->track)
-		return 0;
+	if (_floppy->track && TRACK >= _floppy->track) {
+		if(CURRENT->current_nr_sectors & 1) {
+			current_count_sectors = 1;
+			return 1;
+		} else
+			return 0;
+	}
 	HEAD = sector_t / _floppy->sect;
 
 	if (((_floppy->stretch & FD_SWAPSIDES) || TESTF(FD_NEED_TWADDLE)) &&
@@ -3108,7 +3114,7 @@
 		floppy_type[type].name="user format";
 		for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
 			floppy_sizes[cnt]= floppy_sizes[cnt+0x80]=
-				floppy_type[type].size>>1;
+				(floppy_type[type].size+1)>>1;
 		process_fd_request();
 		for (cnt = 0; cnt < N_DRIVE; cnt++){
 			if (ITYPE(drive_state[cnt].fd_device) == type &&
@@ -3127,7 +3133,7 @@
 		if (buffer_drive == drive)
 			SUPBOUND(buffer_max, user_params[drive].sect);
 		current_type[drive] = &user_params[drive];
-		floppy_sizes[drive] = user_params[drive].size >> 1;
+		floppy_sizes[drive] = (user_params[drive].size+1) >> 1;
 		if (cmd == FDDEFPRM)
 			DRS->keep_data = -1;
 		else
@@ -3794,23 +3800,20 @@
 
 /* lilo configuration */
 
-/* we make the invert_dcl function global. One day, somebody might
- * want to centralize all thinkpad related options into one lilo option,
- * there are just so many thinkpad related quirks! */
-void floppy_invert_dcl(int *ints,int param)
+void floppy_set_flags(int *ints,int param, int param2)
 {
 	int i;
 
 	for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
 		if (param)
-			default_drive_params[i].params.flags |= 0x80;
+			default_drive_params[i].params.flags |= param2;
 		else
-			default_drive_params[i].params.flags &= ~0x80;
+			default_drive_params[i].params.flags &= ~param2;
 	}
-	DPRINT("Configuring drives for inverted dcl\n");
+	DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
 }
 
-static void daring(int *ints,int param)
+static void daring(int *ints,int param, int param2)
 {
 	int i;
 
@@ -3826,7 +3829,7 @@
 	DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
 }
 
-static void set_cmos(int *ints, int dummy)
+static void set_cmos(int *ints, int dummy, int dummy2)
 {
 	int current_drive=0;
 
@@ -3852,34 +3855,39 @@
 
 static struct param_table {
 	const char *name;
-	void (*fn)(int *ints, int param);
+	void (*fn)(int *ints, int param, int param2);
 	int *var;
 	int def_param;
+	int param2;
 } config_params[]={
-	{ "allowed_drive_mask", 0, &allowed_drive_mask, 0xff },
-	{ "all_drives", 0, &allowed_drive_mask, 0xff },
-	{ "asus_pci", 0, &allowed_drive_mask, 0x33 },
-
-	{ "daring", daring, 0, 1},
-
-	{ "two_fdc",  0, &FDC2, 0x370 },
-	{ "one_fdc", 0, &FDC2, 0 },
-
-	{ "thinkpad", floppy_invert_dcl, 0, 1 },
-
-	{ "nodma", 0, &use_virtual_dma, 1 },
-	{ "omnibook", 0, &use_virtual_dma, 1 },
-	{ "dma", 0, &use_virtual_dma, 0 },
-
-	{ "fifo_depth", 0, &fifo_depth, 0xa },
-	{ "nofifo", 0, &no_fifo, 0x20 },
-	{ "usefifo", 0, &no_fifo, 0 },
-
-	{ "cmos", set_cmos, 0, 0 },
-
-	{ "unexpected_interrupts", 0, &print_unex, 1 },
-	{ "no_unexpected_interrupts", 0, &print_unex, 0 },
-	{ "L40SX", 0, &print_unex, 0 } };
+	{ "allowed_drive_mask", 0, &allowed_drive_mask, 0xff, 0}, /* obsolete */
+	{ "all_drives", 0, &allowed_drive_mask, 0xff, 0 }, /* obsolete */
+	{ "asus_pci", 0, &allowed_drive_mask, 0x33, 0},
+
+	{ "daring", daring, 0, 1, 0},
+
+	{ "two_fdc",  0, &FDC2, 0x370, 0 },
+	{ "one_fdc", 0, &FDC2, 0, 0 },
+
+	{ "thinkpad", floppy_set_flags, 0, 1, FD_INVERTED_DCL },
+	{ "broken_dcl", floppy_set_flags, 0, 1, FD_BROKEN_DCL },
+	{ "messages", floppy_set_flags, 0, 1, FTD_MSG },
+	{ "silent_dcl_clear", floppy_set_flags, 0, 1, FD_SILENT_DCL_CLEAR },
+	{ "debug", floppy_set_flags, 0, 1, FD_DEBUG },
+
+	{ "nodma", 0, &use_virtual_dma, 1, 0 },
+	{ "omnibook", 0, &use_virtual_dma, 1, 0 },
+	{ "dma", 0, &use_virtual_dma, 0, 0 },
+
+	{ "fifo_depth", 0, &fifo_depth, 0xa, 0 },
+	{ "nofifo", 0, &no_fifo, 0x20, 0 },
+	{ "usefifo", 0, &no_fifo, 0, 0 },
+
+	{ "cmos", set_cmos, 0, 0, 0 },
+
+	{ "unexpected_interrupts", 0, &print_unex, 1, 0 },
+	{ "no_unexpected_interrupts", 0, &print_unex, 0, 0 },
+	{ "L40SX", 0, &print_unex, 0, 0 } };
 
 #define FLOPPY_SETUP
 void floppy_setup(char *str, int *ints)
@@ -3894,7 +3902,9 @@
 				else
 					param = config_params[i].def_param;
 				if(config_params[i].fn)
-					config_params[i].fn(ints,param);
+					config_params[i].
+						fn(ints,param,
+						   config_params[i].param2);
 				if(config_params[i].var) {
 					DPRINT("%s=%d\n", str, param);
 					*config_params[i].var = param;
@@ -3928,7 +3938,7 @@
 
 	for (i=0; i<256; i++)
 		if (ITYPE(i))
-			floppy_sizes[i] = floppy_type[ITYPE(i)].size >> 1;
+			floppy_sizes[i] = (floppy_type[ITYPE(i)].size+1) >> 1;
 		else
 			floppy_sizes[i] = MAX_DISK_SIZE;
 
@@ -4209,6 +4219,12 @@
 	/* eject disk, if any */
 	dummy = fd_eject(0);
 }
+
+MODULE_PARM(floppy,"s");
+MODULE_PARM(FLOPPY_IRQ,"i");
+MODULE_PARM(FLOPPY_DMA,"i");
+MODULE_AUTHOR("Alain L. Knaff");
+MODULE_SUPPORTED_DEVICE("fd");
 
 #ifdef __cplusplus
 }
diff -u --recursive --new-file v2.1.21/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.1.21/linux/drivers/block/ps2esdi.c	Thu Dec 12 19:36:59 1996
+++ linux/drivers/block/ps2esdi.c	Sun Jan 19 15:47:24 1997
@@ -431,7 +431,7 @@
 	   list + sanity checks.                     */
 	INIT_REQUEST;
 
-	if (virt_to_bus((u_int) CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) {
+	if (virt_to_bus(CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) {
 		printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);
 		end_request(FAIL);
 		if (CURRENT)
diff -u --recursive --new-file v2.1.21/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.1.21/linux/drivers/block/xd.c	Tue Oct 29 19:58:03 1996
+++ linux/drivers/block/xd.c	Wed Jan 15 03:01:18 1997
@@ -29,6 +29,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/genhd.h>
+#include <linux/hdreg.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -250,77 +251,75 @@
 /* xd_ioctl: handle device ioctl's */
 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
 {
-	XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
-	int dev = DEVICE_NR(inode->i_rdev),err;
+	int dev;
 
-	if (inode && (dev < xd_drives))
-		switch (cmd) {
-			case HDIO_GETGEO:
-				if (arg) {
-					if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
-						return (err);
-					put_user(xd_info[dev].heads, &geometry->heads);
-					put_user(xd_info[dev].sectors, &geometry->sectors);
-					put_user(xd_info[dev].cylinders, &geometry->cylinders);
-					put_user(xd[MINOR(inode->i_rdev)].start_sect,&geometry->start);
-
-					return (0);
-				}
-				break;
-			case BLKRASET:
-				if(!suser())
-					return -EACCES;
-				if(!(inode->i_rdev))
-					return -EINVAL;
-				if(arg > 0xff)
-					return -EINVAL;
-				read_ahead[MAJOR(inode->i_rdev)] = arg;
-				return 0;
-			case BLKGETSIZE:
-				if (arg) {
-					if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
-						return (err);
-					put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
-
-					return (0);
-				}
-				break;
-			case BLKFLSBUF:
-				if(!suser())  return -EACCES;
-				if(!(inode->i_rdev))
-					return -EINVAL;
-				fsync_dev(inode->i_rdev);
-				invalidate_buffers(inode->i_rdev);
-				return 0;
-				
-			case BLKRRPART:
-				return (xd_reread_partitions(inode->i_rdev));
-			RO_IOCTLS(inode->i_rdev,arg);
+	if ((!inode) || !(inode->i_rdev))
+		return -EINVAL;
+ 	dev = DEVICE_NR(inode->i_rdev);
+
+	if (dev >= xd_drives) return -EINVAL;
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *geometry = (struct hd_geometry *) arg;
+			if (!geometry) return -EINVAL;
+			if(put_user(xd_info[dev].heads, (char *) &geometry->heads)
+		 	|| put_user(xd_info[dev].sectors, (char *) &geometry->sectors)
+			|| put_user(xd_info[dev].cylinders, (short *) &geometry->cylinders)
+			|| put_user(xd[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &geometry->start))
+				return -EFAULT;
+			return 0;
 		}
-	return (-EINVAL);
+		case BLKRASET:
+			if(!suser()) return -EACCES;
+			if(arg > 0xff) return -EINVAL;
+			read_ahead[MAJOR(inode->i_rdev)] = arg;
+			return 0;
+		case BLKGETSIZE:
+			if (!arg) return -EINVAL;
+			put_user(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+			return 0;
+		case BLKFLSBUF:   /* Return devices size */
+			if(!suser())  return -EACCES;
+			fsync_dev(inode->i_rdev);
+			invalidate_buffers(inode->i_rdev);
+			return 0;
+		case BLKRRPART:
+			return xd_reread_partitions(inode->i_rdev);
+		RO_IOCTLS(inode->i_rdev,arg);
+		default:
+			return -EINVAL;
+	}
 }
 
 /* xd_release: release the device */
 static void xd_release (struct inode *inode, struct file *file)
 {
-	int dev = DEVICE_NR(inode->i_rdev);
+	int target;
 
-	if (dev < xd_drives) {
+	target= DEVICE_NR(inode->i_rdev);
+	if (target < xd_drives) {
 		sync_dev(inode->i_rdev);
-		xd_access[dev]--;
+		xd_access[target]--;
 	}
 }
 
 /* xd_reread_partitions: rereads the partition table from a drive */
 static int xd_reread_partitions(kdev_t dev)
 {
-	int target = DEVICE_NR(dev);
-	int start = target << xd_gendisk.minor_shift;
+	int target;
+	int start;
 	int partition;
-
-	cli(); xd_valid[target] = (xd_access[target] != 1); sti();
+	
+	target = DEVICE_NR(dev);
+ 	start = target << xd_gendisk.minor_shift;
+
+	cli();
+	xd_valid[target] = (xd_access[target] != 1);
+        sti();
 	if (xd_valid[target])
-		return (-EBUSY);
+		return -EBUSY;
 
 	for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
 		int minor = (start | partition);
@@ -338,7 +337,7 @@
 	xd_valid[target] = 1;
 	wake_up(&xd_wait_open);
 
-	return (0);
+	return 0;
 }
 
 /* xd_readwrite: handle a read/write request */
diff -u --recursive --new-file v2.1.21/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.21/linux/drivers/char/Config.in	Thu Jan  2 15:55:15 1997
+++ linux/drivers/char/Config.in	Sun Jan 19 15:47:24 1997
@@ -70,15 +70,9 @@
      if [ "$CONFIG_WDT_501" = "y" ]; then
          bool '       Fan Tachometer' CONFIG_WDT_501_FAN
      fi
-  else
-     tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   fi
+  tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
-  if [ "$CONFIG_PCWATCHDOG" != "n" ]; then
-      bool '       Support for Revision A cards' CONFIG_PCWD_REV_A
-      bool '       Support for Revision C cards' CONFIG_PCWD_REV_C
-      bool '       Show card state on reset' CONFIG_PCWD_SHOW_PREVSTAT
-  fi
 fi
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 endmenu
diff -u --recursive --new-file v2.1.21/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.21/linux/drivers/char/mem.c	Mon Dec 30 15:39:07 1996
+++ linux/drivers/char/mem.c	Sun Jan 19 15:47:24 1997
@@ -231,14 +231,39 @@
 }
 
 /*
- * For fun, somebody might look into using the MMU for this.
- * NOTE! It's not trivial: you have to check that the mapping
- * is a private mapping and if so you can just map in the
- * zero page directly. But shared mappings _have_ to use the
- * physical copy.
+ * For fun, we are using the MMU for this.
  */
 static inline unsigned long read_zero_pagealigned(char * buf, unsigned long size)
 {
+	struct vm_area_struct * curr_vma;
+	unsigned long addr=(unsigned long)buf;
+
+/*
+ * First we take the most obvious case: when we have one VM area to deal with,
+ * and it's privately mapped.
+ */
+	curr_vma = find_vma(current->mm, addr);
+
+	if ( !(curr_vma->vm_flags & VM_SHARED) &&
+	      (addr + size <= curr_vma->vm_end) ) {
+
+		flush_cache_range(current->mm, addr, addr + size);
+		zap_page_range(current->mm, addr, size);
+        	zeromap_page_range(addr, size, PAGE_COPY);
+        	flush_tlb_range(current->mm, addr, addr + size);
+
+		return 0;
+	}
+
+/*
+ * Ooops, the shared case is hard. Lets do the conventional
+ *        zeroing.
+ *
+ * FIXME: same for the multiple-vma case, we dont handle it
+ *	  now for simplicity, although it's much easier than
+ *	  the shared case. Not that it should happen often ...
+ */ 
+
 	do {
 		if (clear_user(buf, PAGE_SIZE))
 			break;
@@ -247,6 +272,7 @@
 		buf += PAGE_SIZE;
 		size -= PAGE_SIZE;
 	} while (size);
+
 	return size;
 }
 
diff -u --recursive --new-file v2.1.21/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.21/linux/drivers/char/misc.c	Mon Dec 30 15:39:07 1996
+++ linux/drivers/char/misc.c	Sun Jan 19 15:47:24 1997
@@ -175,7 +175,6 @@
 
 #endif
 
-/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 #ifndef MODULE
@@ -219,14 +218,20 @@
 #ifdef CONFIG_SUN_MOUSE
 	sun_mouse_init();
 #endif
-#ifdef CONFIG_SOFT_WATCHDOG
-	watchdog_init();
+/*
+ *	Only one watchdog can succeed. We probe the pcwatchdog first,
+ *	then the wdt cards and finally the software watchdog which always
+ *	works. This means if your hardware watchdog dies or is 'borrowed'
+ *	for some reason the software watchdog still gives you some cover.
+ */
+#ifdef CONFIG_PCWATCHDOG
+	pcwatchdog_init();
 #endif
 #ifdef CONFIG_WDT
 	wdt_init();
 #endif
-#ifdef CONFIG_PCWATCHDOG
-	pcwatchdog_init();
+#ifdef CONFIG_SOFT_WATCHDOG
+	watchdog_init();
 #endif
 #ifdef CONFIG_APM
 	apm_bios_init();
diff -u --recursive --new-file v2.1.21/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- v2.1.21/linux/drivers/char/pcwd.c	Mon Dec 30 15:39:07 1996
+++ linux/drivers/char/pcwd.c	Sun Jan 19 15:47:24 1997
@@ -19,6 +19,15 @@
  *		typedefs to replace them.  Made heartbeat reset only available
  *		via ioctl, and removed the write routine.
  * 960828	Added new items for PC Watchdog Rev.C card.
+ * 960829	Changed around all of the IOCTLs, added new features,
+ *		added watchdog disable/re-enable routines.  Added firmware
+ *		version reporting.  Added read routine for temperature.
+ *		Removed some extra defines, added an autodetect Revision
+ *		routine.
+ * 961006       Revised some documentation, fixed some cosmetic bugs.  Made
+ *              drivers to panic the system if it's overheating at bootup.
+ * 961118	Changed some verbiage on some of the output, tidied up
+ *		code bits, and added compatibility to 2.1.x.
  */
 
 #include <linux/module.h>
@@ -39,65 +48,60 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/watchdog.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
 
-typedef struct pcwd_ioports {
-	int first_port;
-	int range;
-} IOPS;
+#include <asm/uaccess.h>
+#include <asm/io.h>
 
 /*
-** These are the auto-probe addresses available for the Rev.A version of the
-** PC Watchdog card.
-*/
-
-static IOPS pcwd_ioports[] = {
-	{ 0x270, 3 },
-	{ 0x350, 3 },
-	{ 0x370, 3 },
-	{ 0x000, 0 }
-};
+ * These are the auto-probe addresses available.
+ *
+ * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
+ * Revision A has an address range of 2 addresses, while Revision C has 3.
+ */
+static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
 
-#ifdef DEBUG
-#define dprintk(x)	printk(x)
-#else
-#define dprintk(x)
+#define WD_VER                  "1.0 (11/18/96)"
+#define	WD_MINOR		130	/* Minor device number */
+#ifndef	TEMP_MINOR
+#define	TEMP_MINOR		131	/* Uses the same as WDT */
 #endif
 
-#ifdef CONFIG_PCWD_REV_A
-#define CARD_REV	"A"
-#define PORT_OFFSET	0
-#define PORT_RANGE	2
+/*
+ * It should be noted that PCWD_REVISION_B was removed because A and B
+ * are essentially the same types of card, with the exception that B
+ * has temperature reporting.  Since I didn't receive a Rev.B card,
+ * the Rev.B card is not supported.  (It's a good thing too, as they
+ * are no longer in production.)
+ */
+#define	PCWD_REVISION_A		1
+#define	PCWD_REVISION_C		2
+
+#define	WD_TIMEOUT		3	/* 1 1/2 seconds for a timeout */
+
+/*
+ * These are the defines for the PC Watchdog card, revision A.
+ */
 #define WD_WDRST                0x01	/* Previously reset state */
 #define WD_T110                 0x02	/* Temperature overheat sense */
 #define WD_HRTBT                0x04	/* Heartbeat sense */
 #define WD_RLY2                 0x08	/* External relay triggered */
 #define WD_SRLY2                0x80	/* Software external relay triggered */
-#endif
-#ifdef CONFIG_PCWD_REV_C
-#define CARD_REV	"C"
-#define PORT_OFFSET	1
-#define PORT_RANGE	4
-#define WD_WDRST                0x01	/* Previously reset state */
-#define WD_T110                 0x04	/* Temperature overheat sense */
-#endif
 
-#define WD_VER                  "0.52 (08/28/96)"
-#define	WD_MINOR		130	/* Minor device number */
-
-#define	WD_TIMEOUT		3	/* 1 1/2 seconds for a timeout */
-
-
-static int current_readport;
+static int current_readport, revision, temp_panic;
 static int is_open, initial_status, supports_temp, mode_debug;
 
-int pcwd_checkcard(void)
+/*
+ * PCWD_CHECKCARD
+ *
+ * This routine checks the "current_readport" to see if the card lies there.
+ * If it does, it returns accordingly.
+ */
+static int pcwd_checkcard(void)
 {
 	int card_dat, prev_card_dat, found = 0, count = 0, done = 0;
 
-	/* As suggested by Alan Cox */
-	if (check_region(current_readport, PORT_RANGE)) {
+	/* As suggested by Alan Cox - this is a safety measure. */
+	if (check_region(current_readport, 4)) {
 		printk("pcwd: Port 0x%x unavailable.\n", current_readport);
 		return 0;
 	}
@@ -106,13 +110,10 @@
 	prev_card_dat = 0x00;
 
 	prev_card_dat = inb(current_readport);
-	if (prev_card_dat == 0xFF) {
-		dprintk(("pcwd: No card detected at 0x%03x\n", current_readport));
+	if (prev_card_dat == 0xFF)
 		return 0;
-	}
 
 	while(count < WD_TIMEOUT) {
-		dprintk(("pcwd: Run #%d on port 0x%03x\n", count, current_readport));
 
 	/* Read the raw card data from the port, and strip off the
 	   first 4 bits */
@@ -125,17 +126,6 @@
 		udelay(500000L);
 		done = 0;
 
-	/* 0x0F usually means that no card data is present, or the card
-	   is not installed on this port.  If 0x0F is present here, it's
-	   normally safe to assume there's no card at that base address. */
-
-		if (card_dat == 0x0F) {
-			count++;
-			done = 1;
-
-			dprintk(("pcwd: I show nothing on this port.\n"));
-		}
-
 	/* If there's a heart beat in both instances, then this means we
 	   found our card.  This also means that either the card was
 	   previously reset, or the computer was power-cycled. */
@@ -144,8 +134,6 @@
 			(!done)) {
 			found = 1;
 			done = 1;
-			
-			dprintk(("pcwd: I show alternate heart beats.  Card detected.\n"));
 			break;
 		}
 
@@ -159,7 +147,6 @@
 
 		if ((card_dat == prev_card_dat) && (!done)) {
 			count++;
-			dprintk(("pcwd: The card data is exactly the same (possibility).\n"));
 			done = 1;
 		}
 
@@ -169,7 +156,6 @@
 		if ((card_dat != prev_card_dat) && (!done)) {
 			done = 1;
 			found = 1;
-			dprintk(("pcwd: I show alternate heart beats.  Card detected.\n"));
 			break;
 		}
 
@@ -186,18 +172,36 @@
 {
 	int card_status = 0x0000;
 
-	initial_status = card_status = inb(current_readport + PORT_OFFSET);
-
-	if (card_status & WD_WDRST)
-		printk("pcwd: Previous reboot was caused by the card.\n");
+	if (revision == PCWD_REVISION_A)
+		initial_status = card_status = inb(current_readport);
+	else
+		initial_status = card_status = inb(current_readport + 1);
+
+	if (revision == PCWD_REVISION_A) {
+		if (card_status & WD_WDRST)
+			printk("pcwd: Previous reboot was caused by the card.\n");
+
+		if (card_status & WD_T110) {
+			printk("pcwd: Card senses a CPU Overheat.  Panicking!\n");
+			panic("pcwd: CPU Overheat.\n");
+		}
 
-	if (supports_temp)
-		if(card_status & WD_T110)
-			printk("pcwd: CPU overheat sense.\n");
+		if ((!(card_status & WD_WDRST)) &&
+		    (!(card_status & WD_T110)))
+			printk("pcwd: Cold boot sense.\n");
+	} else {
+		if (card_status & 0x01)
+			printk("pcwd: Previous reboot was caused by the card.\n");
+
+		if (card_status & 0x04) {
+			printk("pcwd: Card senses a CPU Overheat.  Panicking!\n");
+			panic("pcwd: CPU Overheat.\n");
+		}
 
-	if ((!(card_status & WD_WDRST)) &&
-	    (!(card_status & WD_T110)))
-		printk("pcwd: Cold boot sense.\n");
+		if ((!(card_status & 0x01)) &&
+		    (!(card_status & 0x04)))
+			printk("pcwd: Cold boot sense.\n");
+	}
 }
 
 static void pcwd_send_heartbeat(void)
@@ -207,14 +211,15 @@
 	if (!is_open)
 		return;
 
-	dprintk(("pcwd: heartbeat\n"));
-
 	wdrst_stat = inb_p(current_readport);
 	wdrst_stat &= 0x0F;
 
 	wdrst_stat |= WD_WDRST;
 
-	outb_p(wdrst_stat, current_readport + PORT_OFFSET);
+	if (revision == PCWD_REVISION_A)
+		outb_p(wdrst_stat, current_readport + 1);
+	else
+		outb_p(wdrst_stat, current_readport);
 }
 
 static int pcwd_ioctl(struct inode *inode, struct file *file,
@@ -223,15 +228,12 @@
 	int i, cdat, rv;
 	static struct watchdog_info ident=
 	{
+		/* FIXME: should set A/C here */
 		WDIOF_OVERHEAT|WDIOF_CARDRESET,
-#ifdef CONFIG_PCWD_REV_A	
 		1,
-#else
-		3,
-#endif				
-		"PCWD revision "CARD_REV"."
+		"PCWD."
 	};
-		
+
 	switch(cmd) {
 	default:
 		return -ENOIOCTLCMD;
@@ -244,33 +246,112 @@
 		cdat = inb(current_readport);
 		rv = 0;
 
-		if (cdat & WD_WDRST)
-			rv |= WDIOF_CARDRESET;
-
-		if (cdat & WD_T110)
-			rv |= WDIOF_OVERHEAT;
+		if (revision == PCWD_REVISION_A) 
+		{
+			if (cdat & WD_WDRST)
+				rv |= WDIOF_CARDRESET;
+
+			if (cdat & WD_T110) 
+			{
+				rv |= WDIOF_OVERHEAT;
+
+				if (temp_panic)
+					panic("pcwd: Temperature overheat trip!\n");
+			}
+		}
+		else 
+		{
+			if (cdat & 0x01)
+				rv |= WDIOF_CARDRESET;
+
+			if (cdat & 0x04) 
+			{
+				rv |= WDIOF_OVERHEAT;
+
+				if (temp_panic)
+					panic("pcwd: Temperature overheat trip!\n");
+			}
+		}
 
-		return put_user(rv, (int *) arg);
-		break;
+		if(put_user(rv, (int *) arg))
+			return -EFAULT;
+		return 0;
 
 	case WDIOC_GETBOOTSTATUS:
 		rv = 0;
 
-		if (initial_status & WD_WDRST)
-			rv |= WDIOF_CARDRESET;
+		if (revision == PCWD_REVISION_A) 
+		{
+			if (initial_status & WD_WDRST)
+				rv |= WDIOF_CARDRESET;
 
-		if (initial_status & WD_T110)
-			rv |= WDIOF_OVERHEAT;
-		return put_user(rv, (int *) arg);
+			if (initial_status & WD_T110)
+				rv |= WDIOF_OVERHEAT;
+		}
+		else
+		{
+			if (initial_status & 0x01)
+				rv |= WDIOF_CARDRESET;
+
+			if (initial_status & 0x04)
+				rv |= WDIOF_OVERHEAT;
+		}
+
+		if(put_user(rv, (int *) arg))
+			return -EFAULT;
+		return 0;
 
 	case WDIOC_GETTEMP:
+
 		rv = 0;
-		if ((supports_temp) && (mode_debug == 0)) {
+		if ((supports_temp) && (mode_debug == 0)) 
+		{
 			rv = inb(current_readport);
-			return put_user(rv, (int*) arg);
-		} else
-			return put_user(rv, (int*) arg);
+			if(put_user(rv, (int*) arg))
+				return -EFAULT;
+		} else if(put_user(rv, (int*) arg))
+				return -EFAULT;
+		return 0;
 
+	case WDIOC_SETOPTIONS:
+		if (revision == PCWD_REVISION_C) 
+		{
+			if(copy_from_user(&rv, (int*) arg, sizeof(int)))
+				return -EFAULT;
+
+			if (rv & WDIOS_DISABLECARD) 
+			{
+				outb_p(0xA5, current_readport + 3);
+				outb_p(0xA5, current_readport + 3);
+				cdat = inb_p(current_readport + 2);
+				if ((cdat & 0x10) == 0) 
+				{
+					printk("pcwd: Could not disable card.\n");
+					return -EIO;
+				}
+
+				return 0;
+			}
+
+			if (rv & WDIOS_ENABLECARD) 
+			{
+				outb_p(0x00, current_readport + 3);
+				cdat = inb_p(current_readport + 2);
+				if (cdat & 0x10) 
+				{
+					printk("pcwd: Could not enable card.\n");
+					return -EIO;
+				}
+				return 0;
+			}
+
+			if (rv & WDIOS_TEMPPANIC) 
+			{
+				temp_panic = 1;
+			}
+		}
+		return -EINVAL;
+		
 	case WDIOC_KEEPALIVE:
 		pcwd_send_heartbeat();
 		return 0;
@@ -279,7 +360,7 @@
 	return 0;
 }
 
-static long pcwd_write(struct file *file, struct inode *inode, const char *buf, unsigned long len)
+static long pcwd_write(struct inode *inode, struct file *file, const char *buf, unsigned long len)
 {
 	if (len)
 	{
@@ -291,30 +372,107 @@
 
 static int pcwd_open(struct inode *ino, struct file *filep)
 {
-	dprintk(("pcwd: open request\n"));
-
 	MOD_INC_USE_COUNT;
 	return(0);
 }
 
-static void pcwd_close(struct inode *ino, struct file *filep)
+static long pcwd_read(struct inode *inode, struct file *file, char *buf,
+	unsigned long count)
 {
-	dprintk(("pcwd: close request\n"));
+	unsigned short c = inb(current_readport);
+	unsigned char cp;
+
+	switch(MINOR(inode->i_rdev)) 
+	{
+		case TEMP_MINOR:
+			cp = c;
+			if(copy_to_user(buf, &cp, 1))
+				return -EFAULT;
+			return 1;
+		default:
+			return -EINVAL;
+	}
+}
 
+static void pcwd_close(struct inode *ino, struct file *filep)
+{
 	MOD_DEC_USE_COUNT;
 }
 
 static void get_support(void)
 {
-#ifdef CONFIG_PCWD_REV_C
 	if (inb(current_readport) != 0xF0)
-#endif	
 		supports_temp = 1;
 }
 
+static int get_revision(void)
+{
+	if ((inb(current_readport + 2) == 0xFF) ||
+	    (inb(current_readport + 3) == 0xFF))
+		return(PCWD_REVISION_A);
+
+	return(PCWD_REVISION_C);
+}
+
+static int send_command(int cmd)
+{
+	int i;
+
+	outb_p(cmd, current_readport + 2);
+	udelay(1000L);
+
+	i = inb(current_readport);
+	i = inb(current_readport);
+
+	return(i);
+}
+
+static char *get_firmware(void)
+{
+	int i, found = 0, count = 0, one, ten, hund, minor;
+	char *ret;
+
+	ret = kmalloc(6, GFP_KERNEL);
+
+	while((count < 3) && (!found)) {
+		outb_p(0x80, current_readport + 2);
+		i = inb(current_readport);
+
+		if (i == 0x00)
+			found = 1;
+		else if (i == 0xF3)
+			outb_p(0x00, current_readport + 2);
+
+		udelay(400L);
+		count++;
+	}
+
+	if (found) {
+		mode_debug = 1;
+
+		one = send_command(0x81);
+		ten = send_command(0x82);
+		hund = send_command(0x83);
+		minor = send_command(0x84);
+	}
+
+	if (found)
+		sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
+	else
+		sprintf(ret, "ERROR");
+
+	return(ret);
+}
+
+static void debug_off(void)
+{
+	outb_p(0x00, current_readport + 2);
+	mode_debug = 0;
+}
+
 static struct file_operations pcwd_fops = {
 	NULL,		/* Seek */
-	NULL,		/* Read */
+	pcwd_read,	/* Read */
 	pcwd_write,	/* Write */
 	NULL,		/* Readdir */
 	NULL,		/* Select */
@@ -329,6 +487,12 @@
 	"pcwatchdog",
 	&pcwd_fops
 };
+
+static struct miscdevice temp_miscdev = {
+	TEMP_MINOR,
+	"temperature",
+	&pcwd_fops
+};
  
 #ifdef	MODULE
 int init_module(void)
@@ -338,24 +502,21 @@
 {
 	int i, found = 0;
 
-	dprintk(("pcwd: Success.\n"));
-	printk(KERN_INFO "pcwd: v%s Ken Hollis (khollis@bitgate.com)\n", WD_VER);
+	revision = PCWD_REVISION_A;
 
-	dprintk(("pcwd: About to perform card autosense loop.\n"));
+	printk("pcwd: v%s Ken Hollis (khollis@nurk.org)\n", WD_VER);
 
 	/* Initial variables */
 	is_open = 0;
 	supports_temp = 0;
 	mode_debug = 0;
+	temp_panic = 0;
 	initial_status = 0x0000;
 
-	dprintk(("pcwd: Revision " CARD_REV " support defined.\n"));
+#ifndef	PCWD_BLIND
+	for (i = 0; pcwd_ioports[i] != 0; i++) {
+		current_readport = pcwd_ioports[i];
 
-	for (i = 0; pcwd_ioports[i].first_port != 0; i++) {
-		current_readport = pcwd_ioports[i].first_port;
-
-	if (!pcwd_checkcard()) {
-		dprintk(("pcwd: Trying port 0x%03x.\n", pcwd_ioports[i].first_port));
 		if (pcwd_checkcard()) {
 			found = 1;
 			break;
@@ -363,33 +524,45 @@
 	}
 
 	if (!found) {
-		printk("pcwd: No card detected.\n");
+		printk("pcwd: No card detected, or port not available.\n");
 		return(-EIO);
 	}
+#endif
 
 	is_open = 1;
 
+#ifdef	PCWD_BLIND
+	current_readport = PCWD_BLIND;
+#endif
+
 	get_support();
+	revision = get_revision();
 
-#ifdef	CONFIG_PCWD_REV_A
-	printk("pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport);
-#endif
-#ifdef	CONFIG_PCWD_REV_C
-	printk("pcwd: PC Watchdog (REV.C) detected at port 0x%03x -%stemp. support\n",
-		current_readport, (supports_temp) ? " Has " : " No ");
-#endif
+	if (revision == PCWD_REVISION_A)
+		printk("pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport);
+	else if (revision == PCWD_REVISION_C)
+		printk("pcwd: PC Watchdog (REV.C) detected at port 0x%03x (Firmware version: %s)\n",
+			current_readport, get_firmware());
+	else {
+		/* Should NEVER happen, unless get_revision() fails. */
+		printk("pcwd: Unable to get revision.\n");
+		return -1;
+	}
 
-#ifdef	CONFIG_PCWD_SHOW_PREVSTAT
-  	pcwd_showprevstate();
-#endif
-	dprintk(("pcwd: Requesting region entry\n"));
+	debug_off();
 
-	request_region(current_readport, PORT_RANGE, "PCWD Rev." CARD_REV "(Berkshire)");
+	pcwd_showprevstate();
 
-	dprintk(("pcwd: character device creation.\n"));
+	if (revision == PCWD_REVISION_A)
+		request_region(current_readport, 2, "PCWD Rev.A (Berkshire)");
+	else
+		request_region(current_readport, 4, "PCWD Rev.C (Berkshire)");
 
 	misc_register(&pcwd_miscdev);
 
+	if (supports_temp)
+		misc_register(&temp_miscdev);
+
 	return 0;
 }
 
@@ -397,23 +570,9 @@
 void cleanup_module(void)
 {
 	misc_deregister(&pcwd_miscdev);
-	release_region(current_readport, PORT_RANGE);
+	if (supports_temp)
+		misc_deregister(&temp_miscdev);
 
-	dprintk(("pcwd: Cleanup successful.\n"));
+	release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
 }
 #endif
-
-/*
-** TODO:
-**
-**	Both Revisions:
-**	o) Implement the rest of the IOCTLs as discussed with Alan Cox
-**	o) Faster card detection routines
-**	o) /proc device creation
-**
-**	Revision B functions:
-**	o) /dev/temp device creation for temperature device (possibly use
-**	   the one from the WDT drivers?)
-**	o) Direct Motorola controller chip access via read/write routines
-**	o) Autoprobe IO Ports for autodetection (possibly by chip detect?)
-*/
diff -u --recursive --new-file v2.1.21/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.1.21/linux/drivers/char/tpqic02.c	Thu Jan  2 15:55:16 1997
+++ linux/drivers/char/tpqic02.c	Wed Jan 15 20:44:18 1997
@@ -2696,7 +2696,7 @@
 	 */
 
 	/* copy results to user space */
-	if (copy_to_user((char *) &ioctl_status, (char *) ioarg, sizeof(ioctl_status)))
+	if (copy_to_user((char *) ioarg, (char *) &ioctl_status, sizeof(ioctl_status)))
 	{
 	    return -EFAULT;
 	}	
diff -u --recursive --new-file v2.1.21/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
--- v2.1.21/linux/drivers/char/wdt.c	Thu Jan  2 15:55:16 1997
+++ linux/drivers/char/wdt.c	Sun Jan 19 15:47:24 1997
@@ -50,8 +50,8 @@
  *	You can use wdt=x,y to set these now.
  */
  
-int io=0x240;
-int irq=14;
+static int io=0x240;
+static int irq=14;
 
 #define WD_TIMO (100*60)		/* 1 minute */
 
diff -u --recursive --new-file v2.1.21/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.1.21/linux/drivers/net/3c523.c	Tue Dec 31 21:41:02 1996
+++ linux/drivers/net/3c523.c	Sun Jan 19 15:47:24 1997
@@ -1134,19 +1134,6 @@
     return 0;
   }
 
-  if(skb == NULL) {
-    dev_tint(dev);
-    return 0;
-  }
-
-  if (skb->len <= 0) {
-    return 0;
-  }
-  if(skb->len > XMIT_BUFF_SIZE) {
-    printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %ld bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
-    return 0;
-  }
-
   if (set_bit(0, (void*)&dev->tbusy) != 0) {
      printk("%s: Transmitter access conflict.\n", dev->name);
   } else {
diff -u --recursive --new-file v2.1.21/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.1.21/linux/drivers/net/atp.c	Fri Mar  1 07:50:43 1996
+++ linux/drivers/net/atp.c	Sun Jan 19 15:47:24 1997
@@ -762,7 +762,7 @@
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
-	int num_addrs=dev->mc_list;
+	int num_addrs=dev->mc_count;
 	
 	if(dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
 		num_addrs=1;
diff -u --recursive --new-file v2.1.21/linux/drivers/net/dlci.c linux/drivers/net/dlci.c
--- v2.1.21/linux/drivers/net/dlci.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/dlci.c	Sun Jan 19 15:47:24 1997
@@ -587,7 +587,6 @@
 int dlci_init(struct device *dev)
 {
    struct dlci_local *dlp;
-   int i;
 
    dev->priv = kmalloc(sizeof(struct dlci_local), GFP_KERNEL);
    if (!dev->priv)
diff -u --recursive --new-file v2.1.21/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.1.21/linux/drivers/net/eql.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/eql.c	Sun Jan 19 15:47:24 1997
@@ -213,7 +213,6 @@
 	static unsigned version_printed = 0;
 	/* static unsigned num_masters     = 0; */
 	equalizer_t *eql = 0;
-	int i;
 
 	if ( version_printed++ == 0 && eql_debug > 0)
 		printk(version);
diff -u --recursive --new-file v2.1.21/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c
--- v2.1.21/linux/drivers/net/hdlcdrv.c	Wed Jan 15 19:45:41 1997
+++ linux/drivers/net/hdlcdrv.c	Sun Jan 19 15:47:24 1997
@@ -50,6 +50,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/hdlcdrv.h>
+#include <net/ax25.h>
 
 /* make genksyms happy */
 #include <linux/ip.h>
@@ -743,7 +744,6 @@
 static int hdlcdrv_probe(struct device *dev)
 {
 	struct hdlcdrv_channel_params dflt_ch_params = { 20, 2, 10, 40, 0 };
-	int i;
 	struct hdlcdrv_state *s;
 
 	if (!dev)
diff -u --recursive --new-file v2.1.21/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.1.21/linux/drivers/net/ibmtr.c	Tue Dec 31 21:41:05 1996
+++ linux/drivers/net/ibmtr.c	Sun Jan 19 15:47:24 1997
@@ -1,61 +1,59 @@
-/* ibmtr.c:  A shared-memory IBM Token Ring 16/4 driver for linux */
-/*
-  Written 1993 by Mark Swanson and Peter De Schrijver.
-  This software may be used and distributed according to the terms
-  of the GNU Public License, incorporated herein by reference.
-
-  This device driver should work with Any IBM Token Ring Card that does
-  not use DMA.
-
-  I used Donald Becker's (becker@super.org) device driver work
-  as a base for most of my initial work.
-*/
-
-/*
-   Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
-
-	+ changed name to ibmtr.c in anticipation of other tr boards.
-	+ changed reset code and adapter open code.
-	+ added SAP open code.
-	+ a first attempt to write interrupt, transmit and receive routines.
-
-   Changes by David W. Morris (dwm@shell.portal.com) :
-     941003 dwm: - Restructure tok_probe for multiple adapters, devices
-                 - Add comments, misc reorg for clarity
-                 - Flatten interrupt handler levels
-
-   Changes by Farzad Farid (farzy@zen.via.ecp.fr)
-   and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) :
-        - multi ring support clean up
-        - RFC1042 compliance enhanced
-
-   Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) :
-        - bug correction in tr_tx
-        - removed redundant information display
-        - some code reworking
-
-   Changes by Michel Lespinasse (walken@via.ecp.fr),
-     Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr)
-     (February 18, 1996) :
-	- modified shared memory and mmio access port the driver to
-          alpha platform (structure access -> readb/writeb)
-
-   Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com)
-                           (January 18 1996):
-        - swapped WWOR and WWCR in ibmtr.h
-        - moved some init code from tok_probe into trdev_init.  The
-          PCMCIA code can call trdev_init to complete initializing
-          the driver.
-	- added -DPCMCIA to support PCMCIA
-	- detecting PCMCIA Card Removal in interrupt handler.  if
-	  ISRP is FF, then a PCMCIA card has been removed
-
-   Changes by Paul Norton (pnorton@cts.com) :
- 	- restructured the READ.LOG logic to prevent the transmit SRB
-	  from being rudely overwritten before the transmit cycle is
-	  complete. (August 15 1996)
-        - completed multiple adapter support. (November 20 1996)
-*/
+/* ibmtr.c:  A shared-memory IBM Token Ring 16/4 driver for linux
+ *
+ *	Written 1993 by Mark Swanson and Peter De Schrijver.
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License, incorporated herein by reference.
+ *
+ *	This device driver should work with Any IBM Token Ring Card that does
+ *	not use DMA.
+ *
+ *	I used Donald Becker's (becker@cesdis.gsfc.nasa.gov) device driver work
+ *	as a base for most of my initial work.
+ *
+ *	Changes by Peter De Schrijver (Peter.Deschrijver@linux.cc.kuleuven.ac.be) :
+ *
+ *	+ changed name to ibmtr.c in anticipation of other tr boards.
+ *	+ changed reset code and adapter open code.
+ *	+ added SAP open code.
+ *	+ a first attempt to write interrupt, transmit and receive routines.
+ *
+ *	Changes by David W. Morris (dwm@shell.portal.com) :
+ *	941003 dwm: - Restructure tok_probe for multiple adapters, devices.
+ *	+ Add comments, misc reorg for clarity.
+ *	+ Flatten interrupt handler levels.
+ *
+ *	Changes by Farzad Farid (farzy@zen.via.ecp.fr)
+ *	and Pascal Andre (andre@chimay.via.ecp.fr) (March 9 1995) :
+ *	+ multi ring support clean up.
+ *	+ RFC1042 compliance enhanced.
+ *
+ *	Changes by Pascal Andre (andre@chimay.via.ecp.fr) (September 7 1995) :
+ *	+ bug correction in tr_tx
+ *	+ removed redundant information display
+ *	+ some code reworking
+ *
+ *	Changes by Michel Lespinasse (walken@via.ecp.fr),
+ *	Yann Doussot (doussot@via.ecp.fr) and Pascal Andre (andre@via.ecp.fr)
+ *	(February 18, 1996) :
+ *	+ modified shared memory and mmio access port the driver to
+ *	  alpha platform (structure access -> readb/writeb)
+ *
+ *	Changes by Steve Kipisz (bungy@ibm.net or kipisz@vnet.ibm.com)
+ *	(January 18 1996):
+ *	+ swapped WWOR and WWCR in ibmtr.h
+ *	+ moved some init code from tok_probe into trdev_init.  The
+ *	  PCMCIA code can call trdev_init to complete initializing
+ *	  the driver.
+ *	+ added -DPCMCIA to support PCMCIA
+ *	+ detecting PCMCIA Card Removal in interrupt handler.  If
+ *	  ISRP is FF, then a PCMCIA card has been removed
+ *
+ *	Changes by Paul Norton (pnorton@cts.com) :
+ *	+ restructured the READ.LOG logic to prevent the transmit SRB
+ *	  from being rudely overwritten before the transmit cycle is
+ *	  complete. (August 15 1996)
+ *	+ completed multiple adapter support. (November 20 1996)
+ */
 
 #ifdef PCMCIA
 #define MODULE
@@ -89,18 +87,23 @@
 "ibmtr.c: v1.3.57  8/ 7/94 Peter De Schrijver and Mark Swanson\n"
 "         v2.1.10 11/20/96 Paul Norton <pnorton@cts.com>\n";
 
-static char pcchannelid[]={0x05, 0x00, 0x04, 0x09,
-			   0x04, 0x03, 0x04, 0x0f,
-			   0x03, 0x06, 0x03, 0x01,
-			   0x03, 0x01, 0x03, 0x00,
-			   0x03, 0x09, 0x03, 0x09,
-			   0x03, 0x00, 0x02, 0x00};
-static char mcchannelid[]={0x04, 0x0d, 0x04, 0x01,
-			   0x05, 0x02, 0x05, 0x03,
-			   0x03, 0x06, 0x03, 0x03,
-			   0x05, 0x08, 0x03, 0x04,
-			   0x03, 0x05, 0x03, 0x01,
-			   0x03, 0x08, 0x02, 0x00};
+static char pcchannelid[] = {
+	0x05, 0x00, 0x04, 0x09,
+	0x04, 0x03, 0x04, 0x0f,
+	0x03, 0x06, 0x03, 0x01,
+	0x03, 0x01, 0x03, 0x00,
+	0x03, 0x09, 0x03, 0x09,
+	0x03, 0x00, 0x02, 0x00
+};
+
+static char mcchannelid[] = {
+	0x04, 0x0d, 0x04, 0x01,
+	0x05, 0x02, 0x05, 0x03,
+	0x03, 0x06, 0x03, 0x03,
+	0x05, 0x08, 0x03, 0x04,
+	0x03, 0x05, 0x03, 0x01,
+	0x03, 0x08, 0x02, 0x00
+};
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -130,11 +133,15 @@
 
 #if TR_NEWFORMAT
 /* this allows displaying full adapter information */
-const char *channel_def[] = { "ISA", "MCA", "ISA P&P" };
+
+const char *channel_def[] = { 
+	"ISA", "MCA", "ISA P&P" 
+};
 
 char *adapter_def(char type)
 {
-	switch (type) {
+	switch (type) 
+	{
 	      case 0xF : return "PC Adapter | PC Adapter II | Adapter/A";
 	      case 0xE : return "16/4 Adapter | 16/4 Adapter/A (long)";
 	      case 0xD : return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
@@ -153,42 +160,43 @@
 #define TRC_INIT 0x01              /*  Trace initialization & PROBEs */
 #define TRC_INITV 0x02             /*  verbose init trace points     */
 
-int ibmtr_probe(struct device *dev);
-static int ibmtr_probe1(struct device *dev, int ioaddr);
-unsigned char get_sram_size(struct tok_info *adapt_info);
-
-static int tok_init_card(struct device *dev);
-int trdev_init(struct device *dev);
-void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void initial_tok_int(struct device *dev);
-
-static void open_sap(unsigned char type,struct device *dev);
-void tok_open_adapter(unsigned long dev_addr);
-static void tr_rx(struct device *dev);
-static void tr_tx(struct device *dev);
-
-static int tok_open(struct device *dev);
-static int tok_close(struct device *dev);
-static int tok_send_packet(struct sk_buff *skb, struct device *dev);
+int		ibmtr_probe(struct device *dev);
+static int	ibmtr_probe1(struct device *dev, int ioaddr);
+unsigned char	get_sram_size(struct tok_info *adapt_info);
+static int	tok_init_card(struct device *dev);
+int		trdev_init(struct device *dev);
+void		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void 	initial_tok_int(struct device *dev);
+static void 	open_sap(unsigned char type,struct device *dev);
+void		tok_open_adapter(unsigned long dev_addr);
+static		void tr_rx(struct device *dev);
+static		void tr_tx(struct device *dev);
+static int	tok_open(struct device *dev);
+static int	tok_close(struct device *dev);
+static int	tok_send_packet(struct sk_buff *skb, struct device *dev);
 static struct enet_statistics * tok_get_stats(struct device *dev);
-void tr_readlog(struct device *dev);
+void		tr_readlog(struct device *dev);
 
-static struct timer_list tr_timer={NULL,NULL,0,0L,tok_open_adapter};
-static unsigned int ibmtr_portlist[] = {0xa20, 0xa24, 0};
-static __u32 ibmtr_mem_base = 0xd0000;
-
-#if 0
-int DummyCallCount=0;
+/* 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
+};
 
-/*  This routine combined with the #DEFINE DPRINTD serves
-    to workaround the gcc apparent bug.   in tr_tx() */
+static unsigned int ibmtr_portlist[] = {
+	0xa20, 0xa24, 0
+};
 
-static void DummyCall(const char * fmt,...)
-{ DummyCallCount++; return; }
-#endif
+static __u32 ibmtr_mem_base = 0xd0000;
 
-static void PrtChanID(char *pcid, short stride) {
+static void PrtChanID(char *pcid, short stride) 
+{
 	short i, j;
 	for (i=0, j=0; i<24; i++, j+=stride)
 		printk("%1x", ((int) pcid[j]) & 0x0f);
@@ -203,35 +211,44 @@
 	printk("\n");
 }
 
-/* ibmtr_probe():  Routine specified in the network device structure
-          to probe for an IBM Token Ring Adapter.  Routine outline:
-          I.  Interrogate hardware to determine if an adapter exists
-              and what the speeds and feeds are
-         II.  Setup data structures to control execution based upon
-              adapter characteristics.
-         III. Initialize adapter operation
-     We expect ibmtr_probe to be called once for each device entry
-     which references it.
+/*
+ *	ibmtr_probe():  Routine specified in the network device structure
+ *	to probe for an IBM Token Ring Adapter.  Routine outline:
+ *	I.    Interrogate hardware to determine if an adapter exists
+ *	      and what the speeds and feeds are
+ *	II.   Setup data structures to control execution based upon
+ *	      adapter characteristics.
+ *	III.  Initialize adapter operation
+ *
+ *	We expect ibmtr_probe to be called once for each device entry
+ *	which references it.
  */
+ 
 int ibmtr_probe(struct device *dev)
 {
         int i;
         int base_addr = dev ? dev->base_addr : 0;
 
-        if (base_addr > 0x1ff) {    /* check a single specified location. */
-	        if (ibmtr_probe1(dev, base_addr)) {
+        if (base_addr > 0x1ff) 
+        { 
+        	/*
+        	 *	Check a single specified location. 
+ 		 */
+ 		 
+	        if (ibmtr_probe1(dev, base_addr)) 
+	        {
 #ifndef MODULE
 		       tr_freedev(dev);
 #endif
 		       return -ENODEV;
-		} else {
+		} else
 		       return 0;
-	        }
 	}
         else if (base_addr != 0)   /* Don't probe at all. */
 	        return -ENXIO;
 
-	for (i = 0; ibmtr_portlist[i]; i++) {
+	for (i = 0; ibmtr_portlist[i]; i++) 
+	{
 	        int ioaddr = ibmtr_portlist[i];
 		if (check_region(ioaddr, IBMTR_IO_EXTENT))
 		        continue;
@@ -239,9 +256,8 @@
 #ifndef MODULE
 		        tr_freedev(dev);
 #endif
-		} else {
+		} else
 			return 0;
-		}
         }
 
         return -ENODEV;
@@ -259,30 +275,44 @@
 	dev = init_trdev(dev,0);
 #endif
 
-	/* Query the adapter PIO base port which will return
-	indication of where MMIO was placed. We also have a
-	coded interrupt number. */
+	/*	Query the adapter PIO base port which will return
+	 *	indication of where MMIO was placed. We also have a
+	 *	coded interrupt number.
+	 */
 
        	segment = inb(PIOaddr);
-	/* out of range values so we'll assume non-existent IO device */
+	
+	/*
+	 *	Out of range values so we'll assume non-existent IO device 
+	 */
+	 
 	if (segment < 0x40 || segment > 0xe0)
                 return -ENODEV;
 
-	/* Compute the linear base address of the MMIO area
-	   as LINUX doesn't care about segments          */
+	/*
+	 *	Compute the linear base address of the MMIO area
+	 *	as LINUX doesn't care about segments
+	 */
+
 	t_mmio=(((__u32)(segment & 0xfc) << 11) + 0x80000);
 	intr = segment & 0x03;   /* low bits is coded interrupt # */
 	if (ibmtr_debug_trace & TRC_INIT)
 		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n",
                          PIOaddr, (int)segment, t_mmio, (int)intr);
 
-	/* Now we will compare expected 'channelid' strings with
-	   what we is there to learn of ISA/MCA or not TR card */
+	/*
+	 *	Now we will compare expected 'channelid' strings with
+	 *	what we is there to learn of ISA/MCA or not TR card
+	 */
+	 
 	cd_chanid = (CHANNEL_ID + t_mmio);  /* for efficiency */
 	tchanid=pcchannelid;
 	cardpresent=TR_ISA;  /* try ISA */
 
-	/* suboptimize knowing first byte different */
+	/*
+	 *	Suboptimize knowing first byte different
+	 */
+
 	ctemp = readb(cd_chanid) & 0x0f;
 	if (ctemp != *tchanid) { /* NOT ISA card, try MCA */
 		tchanid=mcchannelid;
@@ -291,8 +321,13 @@
 			cardpresent=NOTOK;
 	}
 
-	if (cardpresent != NOTOK) { /* know presumed type, try rest of ID */
-		for (i=2,j=1; i<=46; i=i+2,j++) {
+	if (cardpresent != NOTOK) 
+	{
+		/* 
+		 *	Know presumed type, try rest of ID 
+		 */
+		for (i=2,j=1; i<=46; i=i+2,j++) 
+		{
 			if ((readb(cd_chanid+i) & 0x0f) != tchanid[j]) {
 				cardpresent=NOTOK;   /* match failed, not TR card */
 				break;
@@ -300,8 +335,11 @@
 		}
 	}
 
-	/* If we have an ISA board check for the ISA P&P version,
-	   as it has different IRQ settings */
+	/* 
+	 *	If we have an ISA board check for the ISA P&P version,
+	 *	as it has different IRQ settings 
+	 */
+
 	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio)==0x0e))
 	        cardpresent=TR_ISAPNP;
 
@@ -317,7 +355,8 @@
 
 	/* Now, allocate some of the pl0 buffers for this driver.. */
 	ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
-	if (ti == NULL) return -ENOMEM;
+	if (ti == NULL) 
+		return -ENOMEM;
 
 	memset(ti, 0, sizeof(struct tok_info));
 
@@ -330,39 +369,54 @@
                          should fit with out future hope of multiple
                          adapter support as well /dwm   */
 
-	switch (cardpresent) {
-	      case TR_ISA:
-		if (intr==0) irq=9; /* irq2 really is irq9 */
-		if (intr==1) irq=3;
-		if (intr==2) irq=6;
-		if (intr==3) irq=7;
-		ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq);
-		ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
-		ti->sram=0;
+	switch (cardpresent) 
+	{
+		case TR_ISA:
+			if (intr==0)
+				irq=9; /* irq2 really is irq9 */
+			if (intr==1)
+				irq=3;
+			if (intr==2)
+				irq=6;
+			if (intr==3)
+				irq=7;
+			ti->global_int_enable=GLOBAL_INT_ENABLE+((irq==9) ? 2 : irq);
+			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
+			ti->sram=0;
 #if !TR_NEWFORMAT
-		DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);
+			DPRINTK("ti->global_int_enable: %04X\n",ti->global_int_enable);
 #endif
-		break;
-	      case TR_MCA:
-		if (intr==0) irq=9;
-		if (intr==1) irq=3;
-		if (intr==2) irq=10;
-		if (intr==3) irq=11;
-		ti->global_int_enable=0;
-		ti->adapter_int_enable=0;
-		ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12);
-		break;
-	      case TR_ISAPNP:
-		if (intr==0) irq=9;
-		if (intr==1) irq=3;
-		if (intr==2) irq=10;
-		if (intr==3) irq=11;
-		while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN));
-		ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
-		ti->global_int_enable=PIOaddr+ADAPTINTREL;
-		ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
-		break;
-
+			break;
+		case TR_MCA:
+			if (intr==0)
+				irq=9;
+			if (intr==1)
+				irq=3;
+			if (intr==2)
+				irq=10;
+			if (intr==3)
+				irq=11;
+			ti->global_int_enable=0;
+			ti->adapter_int_enable=0;
+			ti->sram=((__u32)(inb(PIOaddr+ADAPTRESETREL) & 0xfe) << 12);
+			break;
+		case TR_ISAPNP:
+			if (intr==0)
+				irq=9;
+			if (intr==1)
+				irq=3;
+			if (intr==2)
+				irq=10;
+			if (intr==3)
+				irq=11;
+			/*
+			 *	FIXME: this wait should have a timeout
+			 */
+			while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN));
+			ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
+			ti->global_int_enable=PIOaddr+ADAPTINTREL;
+			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
+			break;
 	}
 
 	if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
@@ -379,7 +433,8 @@
 	DPRINTK("hw address: ");
 #endif
 	j=0;
-	for (i=0; i<0x18; i=i+2) {
+	for (i=0; i<0x18; i=i+2) 
+	{
 		/* technical reference states to do this */
 		temp = readb(ti->mmio + AIP + i) & 0x0f;
 #if !TR_NEWFORMAT
@@ -424,14 +479,17 @@
 		ti->shared_ram_paging, ti->dhb_size4mb, ti->dhb_size16mb);
 #endif
 
-	/* We must figure out how much shared memory space this adapter
-	   will occupy so that if there are two adapters we can fit both
-	   in.  Given a choice, we will limit this adapter to 32K.  The
-	   maximum space will will use for two adapters is 64K so if the
-	   adapter we are working on demands 64K (it also doesn't support
-	   paging), then only one adapter can be supported.  */
-
-	/* determine how much of total RAM is mapped into PC space */
+	/*	We must figure out how much shared memory space this adapter
+	 *	will occupy so that if there are two adapters we can fit both
+	 *	in.  Given a choice, we will limit this adapter to 32K.  The
+	 *	maximum space will will use for two adapters is 64K so if the
+	 *	adapter we are working on demands 64K (it also doesn't support
+	 *	paging), then only one adapter can be supported.  
+	 */
+
+	/*
+	 *	determine how much of total RAM is mapped into PC space 
+	 */
 	ti->mapped_ram_size=1<<((((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD)) >>2) & 0x03) + 4);
 	ti->page_mask=0;
 	if (ti->shared_ram_paging == 0xf) { /* No paging in adapter */
@@ -445,33 +503,34 @@
 		DPRINTK("shared ram page size: %dK\n",ti->mapped_ram_size/2);
 #endif
 #ifdef ENABLE_PAGING
-	switch(ti->shared_ram_paging) {
-	      case 0xf:
-		break;
-	      case 0xe:
-		ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-		pg_size=32;   /* 16KB page size */
-		break;
-	      case 0xd:
-		ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-		pg_size=64;   /* 32KB page size */
-		break;
-	      case 0xc:
-		ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
-		ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
-		DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
-		/* nb/dwm: I did this because RRR (3,2) bits are documented as
-		   R/O and I can't find how to select which page size
-		   Also, the above conditional statement sequence is invalid
-		   as page_mask will always be set by the second stmt */
-		kfree_s(ti, sizeof(struct tok_info));
-		return -ENODEV;
-		break;
-	      default:
-		DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
-		kfree_s(ti, sizeof(struct tok_info));
-		return -ENODEV;
-		break;
+	switch(ti->shared_ram_paging) 
+	{
+		case 0xf:
+			break;
+		case 0xe:
+			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
+			pg_size=32;   /* 16KB page size */
+			break;
+		case 0xd:
+			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
+			pg_size=64;   /* 32KB page size */
+			break;
+		case 0xc:
+			ti->page_mask=(ti->mapped_ram_size==32) ? 0xc0 : 0;
+			ti->page_mask=(ti->mapped_ram_size==64) ? 0x80 : 0;
+			DPRINTK("Dual size shared RAM page (code=0xC), don't support it!\n");
+			/* nb/dwm: I did this because RRR (3,2) bits are documented as
+			   R/O and I can't find how to select which page size
+			   Also, the above conditional statement sequence is invalid
+			   as page_mask will always be set by the second stmt */
+			kfree_s(ti, sizeof(struct tok_info));
+			return -ENODEV;
+			break;
+		default:
+			DPRINTK("Unknown shared ram paging info %01X\n",ti->shared_ram_paging);
+			kfree_s(ti, sizeof(struct tok_info));
+			return -ENODEV;
+			break;
 	}
 	if (ti->page_mask) {
 		if (pg_size > ti->mapped_ram_size) {
@@ -571,24 +630,22 @@
 
 int trdev_init(struct device *dev)
 {
-  struct tok_info *ti=(struct tok_info *)dev->priv;
+	struct tok_info *ti=(struct tok_info *)dev->priv;
 
-  ti->open_status=CLOSED;
+	ti->open_status		= CLOSED;
 
-  dev->init=tok_init_card;
-  dev->open=tok_open;
-  dev->stop=tok_close;
-  dev->hard_start_xmit=tok_send_packet;
-  dev->get_stats = NULL;
-  dev->get_stats = tok_get_stats;
-  dev->set_multicast_list = NULL;
+	dev->init		= tok_init_card;
+	dev->open		= tok_open;
+	dev->stop		= tok_close;
+	dev->hard_start_xmit	= tok_send_packet;
+	dev->get_stats 		= NULL;
+	dev->get_stats 		= tok_get_stats;
+	dev->set_multicast_list = NULL;
 
 #ifndef MODULE
-  tr_setup(dev);
+	tr_setup(dev);
 #endif
-
-
-  return 0;
+	return 0;
 }
 
 
@@ -670,7 +727,7 @@
 		    original solution.   */
 
 		status=readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_ODD);
-		#ifdef PCMCIA
+#ifdef PCMCIA
       		/* Check if the PCMCIA card was pulled. */
     		if (status == 0xFF)
        		{
@@ -680,13 +737,13 @@
        		}
 
     	        /* Check ISRP EVEN too. */
-      	        if ( *(unsigned char *)(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
+      	        if ( readb (ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN) == 0xFF)
     	        {
          		 DPRINTK("PCMCIA card removed.\n");
          		 dev->interrupt = 0;
          		 return;
       		 }
-		#endif
+#endif
 
 
 		if (status & ADAP_CHK_INT) {
@@ -706,7 +763,7 @@
 			writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET  + ISRP_EVEN);
 			dev->interrupt=0;
 
-		}	else if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
+		} else if (readb(ti->mmio + ACA_OFFSET + ACA_RW + ISRP_EVEN)
 				 & (TCR_INT | ERR_INT | ACCESS_INT)) {
 
 			DPRINTK("adapter error: ISRP_EVEN : %02x\n",
@@ -774,15 +831,21 @@
 					      if (open_ret_code==7) {
 
 						      if (!ti->auto_ringspeedsave && (open_error_code==0x24)) {
-							      DPRINTK("open failed: Adapter speed must match ring "
-								      "speed if Automatic Ring Speed Save is disabled\n");
+							      DPRINTK("Open failed: Adapter speed must match ring "
+								      "speed if Automatic Ring Speed Save is disabled.\n");
 							      ti->open_status=FAILURE;
 							      wake_up(&ti->wait_for_reset);
 						      } else if (open_error_code==0x24)
-							      DPRINTK("retrying open to adjust to ring speed\n");
+							      DPRINTK("Retrying open to adjust to ring speed.\n");
 						      else if ((open_error_code==0x2d) && ti->auto_ringspeedsave)
-							      DPRINTK("No signal detected for Auto Speed Detection\n");
-						      else DPRINTK("Unrecoverable error: error code = %04x\n",
+							      DPRINTK("No signal detected for Auto Speed Detection.\n");
+						      else if (open_error_code==0x11)
+						      {
+						      	      ti->open_status=FAILURE;
+						      	      DPRINTK("Ring broken/disconnected.\n");
+						      	      wake_up(&ti->wait_for_reset);
+						      }
+						      else DPRINTK("Unrecoverable error: error code = %04x.\n",
 								   open_error_code);
 
 					      } else if (!open_ret_code) {
diff -u --recursive --new-file v2.1.21/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.1.21/linux/drivers/net/lance.c	Wed Aug 21 09:12:49 1996
+++ linux/drivers/net/lance.c	Sun Jan 19 15:47:25 1997
@@ -309,7 +309,7 @@
 {
 	int *port;
 
-	if (high_memory <= 16*1024*1024)
+	if (virt_to_bus(high_memory) <= 16*1024*1024)
 		lance_need_isa_bounce_buffers = 0;
 
 #if defined(CONFIG_PCI)
diff -u --recursive --new-file v2.1.21/linux/drivers/net/lapbether.c linux/drivers/net/lapbether.c
--- v2.1.21/linux/drivers/net/lapbether.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/lapbether.c	Sun Jan 19 15:47:25 1997
@@ -48,12 +48,8 @@
 #include <linux/net_alias.h>
 #include <linux/lapb.h>
 
-#include <linux/lapbether.h>
-
 static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
 
-static char lapbeth_eth_addr[6];
-
 static int lapbeth_rcv(struct sk_buff *, struct device *, struct packet_type *);
 static int lapbeth_device_event(struct notifier_block *, unsigned long, void *);
 
@@ -79,8 +75,6 @@
 	struct device *ethdev;		/* link to ethernet device */
 	struct device axdev;		/* lapbeth device (lapb#) */
 	struct enet_statistics stats;	/* some statistics */
-	char   dest_addr[6];		/* ether destination address */
-	char   acpt_addr[6];		/* accept ether frames from this address only */
 } *lapbeth_devices = NULL;
 
 
@@ -171,7 +165,6 @@
 static int lapbeth_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
 {
 	int len, err;
-	struct ethhdr *eth = (struct ethhdr *)skb->mac.raw;
 	struct lapbethdev *lapbeth;
 
 	skb->sk = NULL;		/* Initially we don't know who it's for */
@@ -183,20 +176,9 @@
 		return 0;
 	}
 
-	/*
-	 * if we want to accept frames from just one ethernet device
-	 * we check the source address of the sender.
-	 */
-
 	lapbeth = (struct lapbethdev *)dev->priv;
 
-	if (!(lapbeth->acpt_addr[0] & 0x01) && memcmp(eth->h_source, lapbeth->acpt_addr, ETH_ALEN)) {
-		printk(KERN_DEBUG "lapbeth: wrong dest address\n");
-		kfree_skb(skb, FREE_READ);
-		return 0;
-	}
-
-	((struct lapbethdev *)dev->priv)->stats.rx_packets++;
+	lapbeth->stats.rx_packets++;
 
 	len = skb->data[0] + skb->data[1] * 256;
 
@@ -296,7 +278,7 @@
 
 	skb->dev = dev = lapbeth->ethdev;
 
-	dev->hard_header(skb, dev, ETH_P_DEC, lapbeth->dest_addr, NULL, 0);
+	dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
 	dev->hard_start_xmit(skb, dev);
 }
@@ -369,37 +351,9 @@
     return 0;
 }
 
-/*	Ioctl commands
- *
- *		SIOCSLAPBETHADDR	set the destination and accepted
- *					source ethernet address (broadcast
- *					or multicast: accept all)
- */
 static int lapbeth_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
 {
-	int err;
-	struct lapbeth_ethaddr *ethaddr = (struct lapbeth_ethaddr *)ifr->ifr_data;
-	struct lapbethdev *lapbeth = dev->priv;
-
-	if (!suser())
-		return -EPERM;
-	
-	if (lapbeth == NULL)		/* woops! */
-		return -ENODEV;
-	
-	switch (cmd) {
-		case SIOCSLAPBETHADDR:
-			if ((err = verify_area(VERIFY_READ, ethaddr, sizeof(struct lapbeth_ethaddr))) != 0)
-				return err;
-			copy_from_user(lapbeth->dest_addr, ethaddr->destination, ETH_ALEN);
-			copy_from_user(lapbeth->acpt_addr, ethaddr->accept, ETH_ALEN);
-			break;
-
-		default:
-			return -EINVAL;
-	}
-
-	return 0;
+	return -EINVAL;
 }
 
 /*
@@ -481,9 +435,6 @@
 
 	lapbeth->ethname[sizeof(lapbeth->ethname)-1] = '\0';
 	strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1);
-
-	memcpy(lapbeth->dest_addr, bcast_addr, sizeof(lapbeth_eth_addr));
-	memcpy(lapbeth->acpt_addr, bcast_addr, sizeof(lapbeth_eth_addr));
 
 	dev = &lapbeth->axdev;
 	buf = (unsigned char *)kmalloc(14, GFP_KERNEL);
diff -u --recursive --new-file v2.1.21/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.1.21/linux/drivers/net/net_init.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/net_init.c	Sun Jan 19 15:47:25 1997
@@ -38,9 +38,7 @@
 #include <linux/trdevice.h>
 #include <linux/if_arp.h>
 #include <linux/fddidevice.h>
-#ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
-#endif
 
 /* The network devices currently exist only in the socket namespace, so these
    entries are unused.  The only ones that make sense are
@@ -304,6 +302,7 @@
 		else
 			dev_base = dev;
 		dev->next = NULL;
+		dev->ifindex = dev_new_index();
 	}
 	restore_flags(flags);
 	return 0;
diff -u --recursive --new-file v2.1.21/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v2.1.21/linux/drivers/net/pi2.c	Thu Jan  2 15:55:18 1997
+++ linux/drivers/net/pi2.c	Sun Jan 19 15:47:25 1997
@@ -1283,7 +1283,6 @@
 {
     short ioaddr;
     struct pi_local *lp;
-    int i;
     unsigned long flags;
     unsigned long mem_ptr;
 
@@ -1401,7 +1400,7 @@
 
     /* Fill in the fields of the device structure */
 
-    dev_init_buffers(dev):
+    dev_init_buffers(dev);
     
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
     dev->hard_header    = ax25_encapsulate;
diff -u --recursive --new-file v2.1.21/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.1.21/linux/drivers/net/ppp.c	Wed Jan 15 19:45:41 1997
+++ linux/drivers/net/ppp.c	Sun Jan 19 15:47:25 1997
@@ -388,8 +388,6 @@
 static int
 ppp_init_dev (struct device *dev)
 {
-	int    indx;
-
 	dev->hard_header_len  = PPP_HARD_HDR_LEN;
 
 	/* device INFO */
@@ -3354,6 +3352,8 @@
 	return (struct compressor *) 0;
 }
 
+#ifdef CONFIG_MODULES
+
 static int ppp_register_compressor (struct compressor *cp)
 {
 	struct compressor_link *new;
@@ -3405,6 +3405,8 @@
 	}
 	restore_flags(flags);
 }
+
+#endif
 
 /*************************************************************
  * Module support routines
diff -u --recursive --new-file v2.1.21/linux/drivers/net/scc.c linux/drivers/net/scc.c
--- v2.1.21/linux/drivers/net/scc.c	Thu Jan  2 15:55:19 1997
+++ linux/drivers/net/scc.c	Sun Jan 19 15:51:16 1997
@@ -1,4 +1,4 @@
-#define RCS_ID "$Id: scc.c,v 1.64 1996/10/30 18:58:26 jreuter Exp jreuter $"
+#define RCS_ID "$Id: scc.c,v 1.66 1997/01/08 22:56:06 jreuter Exp jreuter $"
 
 #define VERSION "3.0"
 #define BANNER  "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n"
@@ -83,9 +83,10 @@
    		  * Invents brand new bugs... ;-)
 
    		  The move to version number 3.0 reflects theses changes.
-   		  You can use version 2.4a if you need a KISS TNC emulator.
+   		  You can use 'kissbridge' if you need a KISS TNC emulator.
 
-   961213	- Fixed for Linux networking changes.
+   961213	- Fixed for Linux networking changes. (G4KLX)
+   960108	- Fixed the remaining problems.
 
    Thanks to all who contributed to this driver with ideas and bug
    reports!
@@ -202,7 +203,6 @@
 static int scc_net_tx(struct sk_buff *skb, struct device *dev);
 static int scc_net_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
 static int scc_net_set_mac_address(struct device *dev, void *addr);
-static int scc_net_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb);
 static int scc_net_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);
 static struct enet_statistics * scc_net_get_stats(struct device *dev);
 
@@ -347,7 +347,6 @@
 	skb = dev_alloc_skb(2);
 	if (skb != NULL)
 	{
-		skb->free = 1;
 		bp = skb_put(skb, 2);
 		*bp++ = PARAM_HWEVENT;
 		*bp++ = event;
@@ -548,9 +547,7 @@
 			return;
 		}
 		
-		skb->free = 1;
 		scc->rx_buff = skb;
-		
 		*(skb_put(skb, 1)) = 0;	/* KISS data */
 	}
 	
@@ -1540,7 +1537,7 @@
 
 	dev->hard_start_xmit = scc_net_tx;
 	dev->hard_header     = scc_net_header;
-	dev->rebuild_header  = scc_net_rebuild_header;
+	dev->rebuild_header  = ax25_rebuild_header;
 	dev->set_mac_address = scc_net_set_mac_address;
 	dev->get_stats       = scc_net_get_stats;
 	dev->do_ioctl        = scc_net_ioctl;
@@ -1967,13 +1964,6 @@
 	struct sockaddr *sa = (struct sockaddr *) addr;
 	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
 	return 0;
-}
-
-/* ----> rebuild header <---- */
-
-static int scc_net_rebuild_header(struct sk_buff *skb)
-{
-    return ax25_rebuild_header(skb);
 }
 
 /* ----> "hard" header <---- */
diff -u --recursive --new-file v2.1.21/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.1.21/linux/drivers/net/smc-mca.c	Tue Dec 31 21:41:06 1996
+++ linux/drivers/net/smc-mca.c	Sun Jan 19 15:47:25 1997
@@ -74,7 +74,10 @@
 	unsigned char pos2, pos3, pos4, pos5;
 	int i;
 
-	if( (slot=mca_find_adapter(0x61c8,0)) != MCA_NOTFOUND)
+	/* Look for two flavors of SMC Elite/A (3013EP/A) -jeh- */
+	if(( (slot=mca_find_adapter(0x61c8,0)) != MCA_NOTFOUND) ||
+            ((slot=mca_find_adapter(0xefd5,0)) != MCA_NOTFOUND) )
+
 	{
 #ifndef MODULE
 		mca_set_adapter_name( slot, "SMC Elite/A (8013EP/A)" );
diff -u --recursive --new-file v2.1.21/linux/drivers/net/strip.c linux/drivers/net/strip.c
--- v2.1.21/linux/drivers/net/strip.c	Thu Jan  2 15:55:20 1997
+++ linux/drivers/net/strip.c	Sun Jan 19 15:47:25 1997
@@ -1,3 +1,5 @@
+#error "Doesn't run with 2.1.x"
+
 /*
  * Copyright 1996 The Board of Trustees of The Leland Stanford
  * Junior University. All Rights Reserved.
@@ -1804,17 +1806,16 @@
  * or non-zero if it needs more time to do an address lookup
  */
 
-static int strip_rebuild_header(void *buff, struct device *dev,
-        unsigned long dst, struct sk_buff *skb)
+static int strip_rebuild_header(struct sk_buff *skb)
 {
-    STRIP_Header *header = (STRIP_Header *)buff;
+    STRIP_Header *header = (STRIP_Header *)skb->data;
 
-    /*printk(KERN_INFO "%s: strip_rebuild_header\n", dev->name);*/
+    /*printk(KERN_INFO "%s: strip_rebuild_header\n", skb->dev->name);*/
 
 #ifdef CONFIG_INET
     /* Arp find returns zero if if knows the address, */
     /* or if it doesn't know the address it sends an ARP packet and returns non-zero */
-    return arp_find(header->dst_addr.c, dst, dev, dev->pa_addr, skb)? 1 : 0;
+    return arp_find(header->dst_addr.c, skb)? 1 : 0;
 #else
     return 0;
 #endif
diff -u --recursive --new-file v2.1.21/linux/drivers/net/tunnel.c linux/drivers/net/tunnel.c
--- v2.1.21/linux/drivers/net/tunnel.c	Thu Jan  2 15:55:20 1997
+++ linux/drivers/net/tunnel.c	Sun Jan 19 15:47:25 1997
@@ -122,7 +122,6 @@
 {
 	struct enet_statistics *stats;		/* This device's statistics */
 	struct rtable *rt;     			/* Route to the other host */
-	struct hh_cache *hh;
 	struct device *tdev;			/* Device to other host */
 	struct iphdr  *iph;			/* Our new IP header */
 	int    max_headroom;			/* The extra header space needed */
@@ -143,7 +142,6 @@
 		return 0;
 	}
 	tdev = rt->u.dst.dev;
-	hh = rt->u.dst.hh;
 
 	if (tdev->type == ARPHRD_TUNNEL) { 
 		/* Tunnel to tunnel?  -- I don't think so. */
@@ -161,7 +159,7 @@
 	 */
 	max_headroom = (((tdev->hard_header_len+15)&~15)+tunnel_hlen);
 
-	if (skb_headroom(skb) < max_headroom || skb->users != 1) {
+	if (skb_headroom(skb) < max_headroom || skb_shared(skb)) {
 		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
 		if (!new_skb) {
 			ip_rt_put(rt);
diff -u --recursive --new-file v2.1.21/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.1.21/linux/drivers/net/wavelan.c	Sun Dec 22 16:37:36 1996
+++ linux/drivers/net/wavelan.c	Sun Jan 19 15:47:25 1997
@@ -4017,8 +4017,8 @@
  * We follow the example in drivers/net/ne.c.)
  * (called in "Space.c")
  */
-extern int
-wavelan_probe(device *	dev)
+ 
+int wavelan_probe(device *	dev)
 {
   short		base_addr;
   mac_addr	mac;		/* Mac address (check wavelan existence) */
diff -u --recursive --new-file v2.1.21/linux/drivers/net/wic.c linux/drivers/net/wic.c
--- v2.1.21/linux/drivers/net/wic.c	Thu Jan  2 15:55:20 1997
+++ linux/drivers/net/wic.c	Sun Jan 19 15:47:25 1997
@@ -920,7 +920,7 @@
 
 	for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
 		eth->h_dest[i] = 0xfc;
-	memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
+	memcpy(&(eth->h_dest[i]), &skb->daddr, 4);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.21/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.21/linux/drivers/pci/pci.c	Mon Dec 30 15:39:10 1996
+++ linux/drivers/pci/pci.c	Mon Jan 20 09:35:36 1997
@@ -72,6 +72,7 @@
 	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
 	DEVICE( DEC,		DEC_21052,	"DC21052"),
 	DEVICE( DEC,		DEC_21152,	"DC21152"),
+	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
 	DEVICE( CIRRUS,		CIRRUS_5430,	"GD 5430"),
 	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
 	DEVICE( CIRRUS,		CIRRUS_5434_8,	"GD 5434"),
@@ -158,6 +159,7 @@
 	DEVICE( AL,		AL_M1511,	"M1511"),
 	DEVICE( AL,		AL_M1513,	"M1513"),
 	DEVICE( AL,		AL_M4803,	"M4803"),
+	DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070"),
 	DEVICE( ASP,		ASP_ABP940,	"ABP940"),
 	DEVICE( CERN,		CERN_SPSB_PMC,	"STAR/RD24 SCI-PCI (PMC)"),
 	DEVICE( CERN,		CERN_SPSB_PCI,	"STAR/RD24 SCI-PCI (PMC)"),
@@ -165,6 +167,7 @@
 	DEVICE( TEKRAM2,	TEKRAM2_690c,	"DC690c"),
 	DEVICE( AMCC,		AMCC_MYRINET,	"Myrinet PCI (M2-PCI-32)"),
 	DEVICE( INTERG,		INTERG_1680,	"IGA-1680"),
+	DEVICE( INTERG,         INTERG_1682,    "IGA-1682"),
 	DEVICE( REALTEK,	REALTEK_8029,	"8029"),
 	DEVICE( INIT,		INIT_320P,	"320 P"),
 	DEVICE( VIA,		VIA_82C505,	"VT 82C505"),
@@ -242,6 +245,8 @@
 	DEVICE( INTEL,		INTEL_82437,	"82437"),
 	DEVICE( INTEL,		INTEL_82371_0,	"82371 Triton PIIX"),
 	DEVICE( INTEL,		INTEL_82371_1,	"82371 Triton PIIX"),
+	DEVICE( INTEL,		INTEL_430MX_0,	"Triton I"),
+	DEVICE( INTEL,		INTEL_430MX_1,	"Triton I"),
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
 	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
@@ -506,6 +511,7 @@
 	      case PCI_VENDOR_ID_WINBOND:	return "Winbond";
 	      case PCI_VENDOR_ID_3COM:		return "3Com";
 	      case PCI_VENDOR_ID_AL:		return "Acer Labs";
+	      case PCI_VENDOR_ID_NEOMAGIC:	return "Neomagic";
 	      case PCI_VENDOR_ID_ASP:		return "Advanced System Products";
 	      case PCI_VENDOR_ID_CERN:		return "CERN";
 	      case PCI_VENDOR_ID_IMS:		return "IMS";
diff -u --recursive --new-file v2.1.21/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.21/linux/drivers/scsi/sd.c	Mon Dec 30 15:39:11 1996
+++ linux/drivers/scsi/sd.c	Wed Jan 15 02:46:07 1997
@@ -77,7 +77,7 @@
 static int check_scsidisk_media_change(kdev_t);
 static int fop_revalidate_scsidisk(kdev_t);
 
-static sd_init_onedisk(int);
+static int sd_init_onedisk(int);
 
 static void requeue_sd_request (Scsi_Cmnd * SCpnt);
 
diff -u --recursive --new-file v2.1.21/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.21/linux/fs/dquot.c	Thu Jan  2 15:55:22 1997
+++ linux/fs/dquot.c	Sun Jan 19 15:47:25 1997
@@ -586,7 +586,6 @@
 {
 	struct dquot *dquot;
 	struct dqblk dq_dqblk;
-	int error;
 
 	if (dqblk == (struct dqblk *)NULL)
 		return(-EFAULT);
@@ -660,8 +659,6 @@
 
 static int get_stats(caddr_t addr)
 {
-	int error;
-
 	dqstats.allocated_dquots = nr_dquots;
 	dqstats.free_dquots = nr_free_dquots;
 	return copy_to_user(addr, (caddr_t)&dqstats, sizeof(struct dqstats)) 
diff -u --recursive --new-file v2.1.21/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.1.21/linux/fs/ext2/symlink.c	Thu Jan  2 15:55:23 1997
+++ linux/fs/ext2/symlink.c	Mon Jan 20 08:39:33 1997
@@ -124,11 +124,11 @@
 		link = (char *) inode->u.ext2_i.i_data;
 	
 	/* XXX I hope link is always '\0'-terminated. */ 	
-	i = strlen(link)+1; 
-	if (i > buflen) 
-		i = buflen; 
-	if (copy_to_user(buffer, link, i))
-		i = -EFAULT; 	
+	i = strlen(link);
+	if (i >= buflen)
+		i = buflen-1;
+	if (copy_to_user(buffer, link, i+1))
+		i = -EFAULT;
  	if (DO_UPDATE_ATIME(inode)) {
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
diff -u --recursive --new-file v2.1.21/linux/fs/fat/misc.c linux/fs/fat/misc.c
--- v2.1.21/linux/fs/fat/misc.c	Sun Dec 22 16:37:38 1996
+++ linux/fs/fat/misc.c	Wed Jan 15 02:46:07 1997
@@ -77,7 +77,7 @@
 /* (rename might deadlock before detecting cross-FS moves.) */
 
 static struct wait_queue *creation_wait = NULL;
-static creation_lock = 0;
+static int creation_lock = 0;
 
 
 void fat_lock_creation(void)
diff -u --recursive --new-file v2.1.21/linux/fs/namei.c linux/fs/namei.c
--- v2.1.21/linux/fs/namei.c	Thu Dec 12 19:37:17 1996
+++ linux/fs/namei.c	Wed Jan 15 02:46:07 1997
@@ -17,6 +17,7 @@
 #include <linux/mm.h>
 
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
@@ -162,7 +163,7 @@
 		return -ENOENT;
 /* check permissions before traversing mount-points */
 	perm = permission(dir,MAY_EXEC);
-	if (len==2 && name[0] == '.' && name[1] == '.') {
+	if (len==2 && get_unaligned((u16 *) name) == 0x2e2e) {
 		if (dir == current->fs->root) {
 			*result = dir;
 			return 0;
@@ -215,7 +216,7 @@
 static int dir_namei(const char *pathname, int *namelen, const char **name,
                      struct inode * base, struct inode **res_inode)
 {
-	char c;
+	unsigned char c;
 	const char * thisname;
 	int len,error;
 	struct inode * inode;
diff -u --recursive --new-file v2.1.21/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.1.21/linux/fs/ncpfs/inode.c	Wed Jan 15 19:45:43 1997
+++ linux/fs/ncpfs/inode.c	Sun Jan 19 15:47:26 1997
@@ -552,11 +552,8 @@
 #ifdef MODULE
 EXPORT_NO_SYMBOLS;
 
-int
-init_module( void)
+int init_module( void)
 {
-	int status;
-
         DPRINTK("ncpfs: init_module called\n");
 
 #ifdef DEBUG_NCP_MALLOC
diff -u --recursive --new-file v2.1.21/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.21/linux/fs/nfs/nfsroot.c	Wed Dec 18 15:58:51 1996
+++ linux/fs/nfs/nfsroot.c	Sun Jan 19 15:47:26 1997
@@ -154,11 +154,6 @@
 /* Yes, we use sys_socket, but there's no include file for it */
 extern asmlinkage int sys_socket(int family, int type, int protocol);
 
-extern void fib_lock(void);
-extern void fib_unlock(void);
-extern int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r);
-extern unsigned long ip_get_mask(unsigned long addr);
-
 /***************************************************************************
 
 			Device Handling Subroutines
@@ -182,13 +177,12 @@
 		    !(dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
 		    (0 != strncmp(dev->name, "dummy", 5)) &&
 		    (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) {
-			/* First up the interface */
+			struct ifreq ifr;
 			old_flags = dev->flags;
-			dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
-			if (!(old_flags & IFF_UP) && dev_open(dev)) {
-				dev->flags = old_flags;
+			strncpy(ifr.ifr_name, dev->name, IFNAMSIZ);
+			ifr.ifr_flags = old_flags | IFF_UP | IFF_RUNNING;
+			if (dev_ioctl(SIOCSIFFLAGS, &ifr) < 0)
 				continue;
-			}
 			openp = (struct open_dev *) kmalloc(sizeof(struct open_dev),
 						GFP_ATOMIC);
 			if (openp == NULL)
@@ -229,9 +223,10 @@
 		nextp = openp->next;
 		openp->next = NULL;
 		if (openp->dev != root_dev) {
-			if (!(openp->old_flags & IFF_UP))
-				dev_close(openp->dev);
-			openp->dev->flags = openp->old_flags;
+			struct ifreq ifr;
+			strncpy(ifr.ifr_name, openp->dev->name, IFNAMSIZ);
+			ifr.ifr_flags = openp->old_flags;
+			dev_ioctl(SIOCSIFFLAGS, &ifr);
 		}
 		kfree_s(openp, sizeof(struct open_dev));
 		openp = nextp;
@@ -467,20 +462,22 @@
  */
 static int root_add_bootp_route(void)
 {
-	struct nlmsghdr dummy_nlh;
-	struct in_rtmsg rtm;
+	struct {
+		struct nlmsghdr nlh;
+		struct in_rtmsg rtm;
+	} rtreq;
 	int err;
+	unsigned short fs;
 
-	memset(&rtm, 0, sizeof(struct in_rtmsg));
-	dummy_nlh.nlmsg_seq = 0;
-	dummy_nlh.nlmsg_pid = current->pid;
-	dummy_nlh.nlmsg_type = RTMSG_NEWROUTE;
-	memcpy(&rtm.rtmsg_device, bootp_dev->name, 15);
-	rtm.rtmsg_mtu = bootp_dev->mtu;
-	rtm.rtmsg_flags = RTF_UP;
-	fib_lock();
-	err = rtmsg_process(&dummy_nlh, &rtm);
-	fib_unlock();
+	memset(&rtreq, 0, sizeof(rtreq));
+	rtreq.nlh.nlmsg_type = RTMSG_NEWROUTE;
+	rtreq.nlh.nlmsg_len = sizeof(rtreq);
+	rtreq.rtm.rtmsg_ifindex = bootp_dev->ifindex;
+	rtreq.rtm.rtmsg_flags = RTF_UP;
+	fs = get_fs();
+	set_fs(get_ds());
+	err = ip_rt_ioctl(SIOCRTMSG, &rtreq);
+	set_fs(fs);
 	if (err) {
 		printk(KERN_ERR "BOOTP: Adding of route failed!\n");
 		return -1;
@@ -495,19 +492,24 @@
  */
 static int root_del_bootp_route(void)
 {
-	struct nlmsghdr dummy_nlh;
-	struct in_rtmsg rtm;
+	struct {
+		struct nlmsghdr nlh;
+		struct in_rtmsg rtm;
+	} rtreq;
 	int err;
+	unsigned short fs;
 
 	if (!bootp_have_route)
 		return 0;
-	memset(&rtm, 0, sizeof(struct in_rtmsg));
-	dummy_nlh.nlmsg_seq = 0;
-	dummy_nlh.nlmsg_pid = current->pid;
-	dummy_nlh.nlmsg_type = RTMSG_DELROUTE;
-	fib_lock();
-	err = rtmsg_process(&dummy_nlh, &rtm);
-	fib_unlock();
+	memset(&rtreq, 0, sizeof(rtreq));
+	rtreq.nlh.nlmsg_type = RTMSG_DELROUTE;
+	rtreq.nlh.nlmsg_len = sizeof(rtreq);
+	rtreq.rtm.rtmsg_ifindex = bootp_dev->ifindex;
+	rtreq.rtm.rtmsg_flags = RTF_UP;
+	fs = get_fs();
+	set_fs(get_ds());
+	err = ip_rt_ioctl(SIOCRTMSG, &rtreq);
+	set_fs(fs);
 	if (err) {
 		printk(KERN_ERR "BOOTP: Deleting of route failed!\n");
 		return -1;
@@ -596,6 +598,8 @@
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
 	result = sock_sendmsg(sock, &msg, size);
 	set_fs(oldfs);
 	return (result != size);
@@ -620,6 +624,7 @@
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
 	msg.msg_namelen = 0;
 	result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT);
 	set_fs(oldfs);
@@ -1286,14 +1291,36 @@
 	rarp_serv = server;
 }
 
+static int root_nfs_add_default_route(struct in_addr gw, struct device *dev)
+{
+	unsigned short fs;
+	int err;
+	struct {
+		struct nlmsghdr nlh;
+		struct in_rtmsg rtm;
+	} rtreq;
+
+	memset(&rtreq, 0, sizeof(rtreq));
+	rtreq.nlh.nlmsg_type = RTMSG_NEWROUTE;
+	rtreq.nlh.nlmsg_len  = sizeof(rtreq);
+
+	rtreq.rtm.rtmsg_ifindex = dev->ifindex;
+	rtreq.rtm.rtmsg_flags = RTF_UP|RTF_GATEWAY;
+	rtreq.rtm.rtmsg_gateway = gw;
+	fs = get_fs();
+	set_fs(get_ds());
+	err = ip_rt_ioctl(SIOCRTMSG, &rtreq);
+	set_fs(fs);
+	return err;
+}
 
 /*
  *  Set the interface address and configure a route to the server.
  */
 static int root_nfs_setup(void)
 {
-	struct in_rtmsg rtm;
-	struct nlmsghdr dummy_nlh;
+	unsigned short fs;
+	struct ifreq ifr;
 	int err;
 
 	/* Set the default system name in case none was previously found */
@@ -1302,16 +1329,21 @@
 		system_utsname.nodename[__NEW_UTS_LEN] = '\0';
 	}
 
-	/* Set the correct netmask */
-	if (netmask.sin_addr.s_addr == INADDR_NONE)
-		netmask.sin_addr.s_addr = ip_get_mask(myaddr.sin_addr.s_addr);
-
-	/* Setup the device correctly */
-	root_dev->family     = myaddr.sin_family;
-	root_dev->pa_addr    = myaddr.sin_addr.s_addr;
-	root_dev->pa_mask    = netmask.sin_addr.s_addr;
-	root_dev->pa_brdaddr = root_dev->pa_addr | ~root_dev->pa_mask;
-	root_dev->pa_dstaddr = 0;
+	fs = get_fs();
+	set_fs(get_ds());
+	strncpy(ifr.ifr_name, root_dev->name, IFNAMSIZ);
+	memcpy(&ifr.ifr_addr, &myaddr, sizeof(myaddr));
+	devinet_ioctl(SIOCSIFADDR, &ifr);
+	if (netmask.sin_addr.s_addr != INADDR_NONE &&
+	    netmask.sin_addr.s_addr != root_dev->pa_mask) {
+		memcpy(&ifr.ifr_netmask, &netmask, sizeof(netmask));
+		devinet_ioctl(SIOCSIFNETMASK, &ifr);
+		memcpy(&ifr.ifr_broadaddr, &netmask, sizeof(netmask));
+		((struct sockaddr_in*)&ifr.ifr_broadaddr)->sin_addr.s_addr =
+			root_dev->pa_addr | ~root_dev->pa_mask;
+		devinet_ioctl(SIOCSIFBRDADDR, &ifr);
+	}
+	set_fs(fs);
 
 	/*
 	 * Now add a route to the server. If there is no gateway given,
@@ -1321,36 +1353,9 @@
 	 * gatewayed default route. Note that this gives sufficient network
 	 * setup even for full system operation in all common cases.
 	 */
-	dummy_nlh.nlmsg_seq = 0;
-	dummy_nlh.nlmsg_pid = current->pid;
-	dummy_nlh.nlmsg_type = RTMSG_NEWROUTE;
-
-	memset(&rtm, 0, sizeof(struct in_rtmsg));	/* Local subnet route */
-	memcpy(&rtm.rtmsg_device, root_dev->name, 15);
-	rtm.rtmsg_mtu = root_dev->mtu;
-	rtm.rtmsg_flags = RTF_UP;
-	rtm.rtmsg_prefixlen = (32 - ffz(~(netmask.sin_addr.s_addr)));
-	rtm.rtmsg_prefix = myaddr.sin_addr;
-	fib_lock();
-	err = rtmsg_process(&dummy_nlh, &rtm);
-	fib_unlock();
-	if (err) {
-		printk(KERN_ERR "Root-NFS: Adding of local route failed!\n");
-		return -1;
-	}
 
 	if (gateway.sin_addr.s_addr != INADDR_NONE) {	/* Default route */
-		rtm.rtmsg_prefix.s_addr = INADDR_ANY;
-		rtm.rtmsg_prefixlen = 32;
-		rtm.rtmsg_gateway = gateway.sin_addr;
-		rtm.rtmsg_flags |= RTF_GATEWAY;
-		if ((gateway.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) {
-			printk(KERN_ERR "Root-NFS: Gateway not on local network!\n");
-			return -1;
-		}
-		fib_lock();
-		err = rtmsg_process(&dummy_nlh, &rtm);
-		fib_unlock();
+		err = root_nfs_add_default_route(gateway.sin_addr, root_dev); 
 		if (err) {
 			printk(KERN_ERR "Root-NFS: Adding of default route failed!\n");
 			return -1;
diff -u --recursive --new-file v2.1.21/linux/fs/nfs/rpcsock.c linux/fs/nfs/rpcsock.c
--- v2.1.21/linux/fs/nfs/rpcsock.c	Thu Dec 12 19:37:18 1996
+++ linux/fs/nfs/rpcsock.c	Sun Jan 19 15:47:26 1997
@@ -361,6 +361,9 @@
 	if (result < 4) {
 		printk(KERN_WARNING "RPC: impossible RPC reply size %d\n",
 						result);
+		iov[0].iov_base=(void*)&xid;	/* xid=32bits, which is large enough */
+		iov[0].iov_len=result;
+		rpc_recvmsg(rsock, iov, 1, result, 0);
 		return 0;
 	}
 
diff -u --recursive --new-file v2.1.21/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.21/linux/fs/smbfs/inode.c	Wed Jan 15 19:45:44 1997
+++ linux/fs/smbfs/inode.c	Sun Jan 19 15:47:26 1997
@@ -444,8 +444,6 @@
 int
 init_module(void)
 {
-	int status;
-
 	DPRINTK("smbfs: init_module called\n");
 
 #ifdef DEBUG_SMB_MALLOC
diff -u --recursive --new-file v2.1.21/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.1.21/linux/include/asm-alpha/semaphore.h	Wed Sep 11 21:41:51 1996
+++ linux/include/asm-alpha/semaphore.h	Thu Jan 16 04:47:21 1997
@@ -11,7 +11,7 @@
 
 struct semaphore {
 	atomic_t count;
-	atomic_t waiting;
+	atomic_t waking;
 	struct wait_queue * wait;
 };
 
@@ -19,6 +19,7 @@
 #define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
 
 extern void __down(struct semaphore * sem);
+extern int  __down_interruptible(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
 /*
@@ -27,11 +28,16 @@
  */
 extern inline void down(struct semaphore * sem)
 {
-	for (;;) {
-		if (atomic_dec_return(&sem->count) >= 0)
-			break;
+	if (atomic_dec_return(&sem->count) < 0)
 		__down(sem);
-	}
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+	if (atomic_dec_return(&sem->count) < 0)
+		ret = __down_interruptible(sem);
+	return ret;
 }
 
 extern inline void up(struct semaphore * sem)
diff -u --recursive --new-file v2.1.21/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.1.21/linux/include/asm-i386/semaphore.h	Wed Oct 16 10:48:29 1996
+++ linux/include/asm-i386/semaphore.h	Thu Jan 16 04:47:21 1997
@@ -7,11 +7,21 @@
  * SMP- and interrupt-safe semaphores..
  *
  * (C) Copyright 1996 Linus Torvalds
+ *
+ * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in
+ *                     the original code and to make semaphore waits
+ *                     interruptible so that processes waiting on
+ *                     semaphores can be killed.
+ *
+ * If you would like to see an analysis of this implementation, please
+ * ftp to gcom.com and download the file
+ * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz.
+ *
  */
 
 struct semaphore {
 	int count;
-	int waiting;
+	int waking;
 	struct wait_queue * wait;
 };
 
@@ -19,6 +29,7 @@
 #define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
 
 asmlinkage void __down_failed(void /* special register calling convention */);
+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
 asmlinkage void __up_wakeup(void /* special register calling convention */);
 
 extern void __down(struct semaphore * sem);
@@ -29,20 +40,46 @@
  * "down_failed" is a special asm handler that calls the C
  * routine that actually waits. See arch/i386/lib/semaphore.S
  */
-extern __inline__ void down(struct semaphore * sem)
+extern inline void down(struct semaphore * sem)
 {
 	__asm__ __volatile__(
 		"# atomic down operation\n\t"
+		"movl $1f,%%eax\n\t"
 #ifdef __SMP__
 		"lock ; "
 #endif
-		"decl %0\n\t"
-		"movl $1f,%%eax\n\t"
+		"decl 0(%0)\n\t"
 		"js " SYMBOL_NAME_STR(__down_failed)
 		"\n1:"
 		:/* no outputs */
-		:"m" (sem->count), "c" (sem)
-		:"ax", "memory");
+		:"c" (sem)
+		:"ax","memory");
+}
+
+/*
+ * This version waits in interruptible state so that the waiting
+ * process can be killed.  The down_failed_interruptible routine
+ * returns negative for signalled and zero for semaphore acquired.
+ */
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	int	ret;
+
+	__asm__ __volatile__(
+		"# atomic interruptible down operation\n\t"
+		"movl $1f,%0\n\t"
+#ifdef __SMP__
+		"lock ; "
+#endif
+		"decl 0(%1)\n\t"
+		"js " SYMBOL_NAME_STR(__down_failed_interruptible) "\n\t"
+		"xorl %0,%0"
+		"\n1:"
+		:"=a" (ret)
+		:"c" (sem)
+		:"memory");
+
+	return ret;
 }
 
 /*
@@ -51,19 +88,19 @@
  * The default case (no contention) will result in NO
  * jumps for both down() and up().
  */
-extern __inline__ void up(struct semaphore * sem)
+extern inline void up(struct semaphore * sem)
 {
 	__asm__ __volatile__(
 		"# atomic up operation\n\t"
+		"movl $1f,%%eax\n\t"
 #ifdef __SMP__
 		"lock ; "
 #endif
-		"incl %0\n\t"
-		"movl $1f,%%eax\n\t"
+		"incl 0(%0)\n\t"
 		"jle " SYMBOL_NAME_STR(__up_wakeup)
 		"\n1:"
 		:/* no outputs */
-		:"m" (sem->count), "c" (sem)
+		:"c" (sem)
 		:"ax", "memory");
 }
 
diff -u --recursive --new-file v2.1.21/linux/include/linux/atalk.h linux/include/linux/atalk.h
--- v2.1.21/linux/include/linux/atalk.h	Thu Dec 12 19:37:18 1996
+++ linux/include/linux/atalk.h	Sun Jan 19 15:47:26 1997
@@ -88,7 +88,7 @@
 };
 
 /*
- *	Unused (and currently unsupported)
+ *	Short form header
  */
  
 struct ddpshdr
@@ -134,7 +134,16 @@
 extern struct datalink_proto *ddp_dl, *aarp_dl;
 extern void aarp_proto_init(void);
 /* Inter module exports */
-extern struct atalk_iface *atalk_find_dev(struct device *dev);
+
+/*
+ *	Give a device find its atif control structure
+ */
+
+extern __inline__ struct atalk_iface *atalk_find_dev(struct device *dev)
+{
+	return dev->atalk_ptr;
+}
+
 extern struct at_addr *atalk_find_dev_addr(struct device *dev);
 extern int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr);
 extern void aarp_send_probe(struct device *dev, struct at_addr *addr);
diff -u --recursive --new-file v2.1.21/linux/include/linux/ax25.h linux/include/linux/ax25.h
--- v2.1.21/linux/include/linux/ax25.h	Tue Nov 19 15:53:56 1996
+++ linux/include/linux/ax25.h	Sun Jan 19 15:47:26 1997
@@ -2,10 +2,10 @@
  * These are the public elements of the Linux kernel AX.25 code. A similar
  * file netrom.h exists for the NET/ROM protocol.
  */
- 
+
 #ifndef	AX25_KERNEL_H
 #define	AX25_KERNEL_H
- 
+
 #define PF_AX25		AF_AX25
 #define AX25_MTU	256
 #define AX25_MAX_DIGIS	6	/* This is wrong, should be 8 */
@@ -21,6 +21,7 @@
 #define AX25_IDLE	9
 #define AX25_PACLEN	10
 #define AX25_MAXQUEUE	11
+#define AX25_IAMDIGI	12
 
 #define AX25_KILL	99
 
@@ -28,8 +29,11 @@
 #define SIOCAX25ADDUID		(SIOCPROTOPRIVATE+1)
 #define SIOCAX25DELUID		(SIOCPROTOPRIVATE+2)
 #define SIOCAX25NOUID		(SIOCPROTOPRIVATE+3)
-#define SIOCAX25OPTRT		(SIOCPROTOPRIVATE+4)
-#define SIOCAX25CTLCON		(SIOCPROTOPRIVATE+5)
+#define SIOCAX25OPTRT		(SIOCPROTOPRIVATE+7)
+#define SIOCAX25CTLCON		(SIOCPROTOPRIVATE+8)
+#define SIOCAX25GETINFO		(SIOCPROTOPRIVATE+9)
+#define SIOCAX25ADDFWD		(SIOCPROTOPRIVATE+10)
+#define SIOCAX25DELFWD		(SIOCPROTOPRIVATE+11)
 
 #define AX25_SET_RT_IPMODE	2
 
@@ -37,13 +41,13 @@
 #define AX25_NOUID_BLOCK	1
 
 typedef struct {
-	char ax25_call[7];	/* 6 call + SSID (shifted ascii!) */
+	char		ax25_call[7];	/* 6 call + SSID (shifted ascii!) */
 } ax25_address;
 
 struct sockaddr_ax25 {
-	sa_family_t sax25_family;
-	ax25_address sax25_call;
-	int sax25_ndigis;
+	sa_family_t	sax25_family;
+	ax25_address	sax25_call;
+	int		sax25_ndigis;
 	/* Digipeater ax25_address sets follow */
 };
 
@@ -51,29 +55,44 @@
 
 struct full_sockaddr_ax25 {
 	struct sockaddr_ax25 fsa_ax25;
-	ax25_address fsa_digipeater[AX25_MAX_DIGIS];
+	ax25_address	fsa_digipeater[AX25_MAX_DIGIS];
 };
 
 struct ax25_routes_struct {
-	ax25_address port_addr;
-	ax25_address dest_addr;
-	unsigned char digi_count;
-	ax25_address digi_addr[AX25_MAX_DIGIS];
+	ax25_address	port_addr;
+	ax25_address	dest_addr;
+	unsigned char	digi_count;
+	ax25_address	digi_addr[AX25_MAX_DIGIS];
 };
 
 struct ax25_route_opt_struct {
-	ax25_address port_addr;
-	ax25_address dest_addr;
-	int cmd;
-	int arg;
+	ax25_address	port_addr;
+	ax25_address	dest_addr;
+	int		cmd;
+	int		arg;
 };
 
 struct ax25_ctl_struct {
-	ax25_address port_addr;
-	ax25_address source_addr;
-	ax25_address dest_addr;
-	unsigned int cmd;
-	unsigned long arg;
+	ax25_address	port_addr;
+	ax25_address	source_addr;
+	ax25_address	dest_addr;
+	unsigned int	cmd;
+	unsigned long	arg;
+};
+
+struct ax25_info_struct {
+	unsigned int	n2, n2count;
+	unsigned int	t1, t1timer;
+	unsigned int	t2, t2timer;
+	unsigned int	t3, t3timer;
+	unsigned int	idle, idletimer;
+	unsigned int	state;
+	unsigned int	rcv_q, snd_q;
+};
+
+struct ax25_fwd_struct {
+	ax25_address	port_from;
+	ax25_address	port_to;
 };
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/include/linux/bios32.h linux/include/linux/bios32.h
--- v2.1.21/linux/include/linux/bios32.h	Fri May  3 15:40:09 1996
+++ linux/include/linux/bios32.h	Wed Jan 15 02:46:07 1997
@@ -54,8 +54,8 @@
 				      unsigned char where, unsigned char val);
 extern int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn,
 				      unsigned char where, unsigned short val);
-extern pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
-				   unsigned char where, unsigned int val);
+extern int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn,
+				       unsigned char where, unsigned int val);
 extern const char *pcibios_strerror (int error);
 
 #endif /* BIOS32_H */
diff -u --recursive --new-file v2.1.21/linux/include/linux/fd.h linux/include/linux/fd.h
--- v2.1.21/linux/include/linux/fd.h	Sun Apr 28 18:47:40 1996
+++ linux/include/linux/fd.h	Sun Jan 19 15:27:58 1997
@@ -153,7 +153,8 @@
 #define FD_BROKEN_DCL 0x20
 #define FD_DEBUG 0x02
 #define FD_SILENT_DCL_CLEAR 0x4
-#define FD_INVERTED_DCL 0x80
+#define FD_INVERTED_DCL 0x80 /* must be 0x80, because of hardware 
+				considerations */
 
 	char read_track;		/* use readtrack during probing? */
 
diff -u --recursive --new-file v2.1.21/linux/include/linux/in.h linux/include/linux/in.h
--- v2.1.21/linux/include/linux/in.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/in.h	Sun Jan 19 16:04:26 1997
@@ -49,10 +49,12 @@
 #define IP_TTL		2
 #define IP_HDRINCL	3
 #define IP_OPTIONS	4
-#define IP_LOCALADDR	5
+#define IP_LOCALADDR	5	/* Cannot remove; a lot of apps still use it. ANK */
 #define IP_RECVOPTS	6
 #define IP_RETOPTS	7
-#define IP_LOCALDEV	8
+#define IP_RXINFO	8
+#define IP_TXINFO	IP_RXINFO
+/* Gated uses it. Remove later or preserve for 4.4BSD compatibility??? */
 #define IP_RECVDSTADDR  9
 #define IP_PMTUDISC	10
 #define IP_RECVERR	11
@@ -91,11 +93,14 @@
 {
 	struct in_addr	imr_multiaddr;		/* IP multicast address of group */
 	struct in_addr	imr_address;		/* local IP address of interface */
-#if 1
-	char		imr_interface[16];
-#else
 	int		imr_ifindex;		/* Interface index */
-#endif
+};
+
+struct in_pktinfo
+{
+	int		ipi_ifindex;
+	struct in_addr	ipi_spec_dst;
+	struct in_addr	ipi_addr;
 };
 
 /* Structure describing an Internet (IP) socket address. */
diff -u --recursive --new-file v2.1.21/linux/include/linux/in6.h linux/include/linux/in6.h
--- v2.1.21/linux/include/linux/in6.h	Wed Jan 15 19:45:45 1997
+++ linux/include/linux/in6.h	Sun Jan 19 15:47:26 1997
@@ -31,12 +31,14 @@
 	union 
 	{
 		__u8		u6_addr8[16];
+		__u16		u6_addr16[8];
 		__u32		u6_addr32[4];
 #if (~0UL) > 0xffffffff
 		__u64		u6_addr64[2];
 #endif
 	} in6_u;
 #define s6_addr			in6_u.u6_addr8
+#define s6_addr16		in6_u.u6_addr16
 #define s6_addr32		in6_u.u6_addr32
 #define s6_addr64		in6_u.u6_addr64
 };
diff -u --recursive --new-file v2.1.21/linux/include/linux/lapb.h linux/include/linux/lapb.h
--- v2.1.21/linux/include/linux/lapb.h	Thu Jan  2 15:55:24 1997
+++ linux/include/linux/lapb.h	Sun Jan 19 15:47:26 1997
@@ -1,10 +1,10 @@
 /*
  * These are the public elements of the Linux LAPB module.
  */
- 
+
 #ifndef	LAPB_KERNEL_H
 #define	LAPB_KERNEL_H
- 
+
 #define	LAPB_OK			0
 #define	LAPB_BADTOKEN		1
 #define	LAPB_INVALUE		2
diff -u --recursive --new-file v2.1.21/linux/include/linux/lapbether.h linux/include/linux/lapbether.h
--- v2.1.21/linux/include/linux/lapbether.h	Thu Jan  2 15:55:24 1997
+++ linux/include/linux/lapbether.h	Thu Jan  1 02:00:00 1970
@@ -1,19 +0,0 @@
-#ifndef	__LAPBETHER_H
-#define	__LAPBETHER_H
-
-/*
- * 	Defines for the LAPBETHER pseudo device driver
- */
-
-#ifndef __LINUX_IF_ETHER_H
-#include <linux/if_ether.h>
-#endif
-
-#define SIOCSLAPBETHADDR	(SIOCDEVPRIVATE+1)
- 
-struct lapbeth_ethaddr {
-	unsigned char destination[ETH_ALEN];
-	unsigned char accept[ETH_ALEN];
-};
-
-#endif
diff -u --recursive --new-file v2.1.21/linux/include/linux/module.h linux/include/linux/module.h
--- v2.1.21/linux/include/linux/module.h	Wed Jan 15 19:45:45 1997
+++ linux/include/linux/module.h	Sun Jan 19 16:04:34 1997
@@ -221,7 +221,7 @@
 
 /* We want the EXPORT_SYMBOL tag left intact for recognition.  */
 
-#elif !defined(EXPORT_SYMTAB)
+#elif !defined(EXPORT_SYMTAB) && defined(CONFIG_MODULES)
 
 #define __EXPORT_SYMBOL(sym,str)   error EXPORT_SYMTAB_not_defined
 #define EXPORT_SYMBOL(var)	   error EXPORT_SYMTAB_not_defined
diff -u --recursive --new-file v2.1.21/linux/include/linux/net_alias.h linux/include/linux/net_alias.h
--- v2.1.21/linux/include/linux/net_alias.h	Thu Jan  2 15:55:24 1997
+++ linux/include/linux/net_alias.h	Sun Jan 19 16:06:40 1997
@@ -18,6 +18,8 @@
 #define _NET_ALIAS_H
 
 #include <linux/config.h>
+
+#ifdef CONFIG_NET_ALIAS
 #include <linux/types.h>
 #include <linux/if.h>
 #include <linux/netdevice.h>
@@ -173,5 +175,13 @@
 extern struct device * net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 dst);
 
 
+
+#else
+
+#define net_alias_is(a)		0
+#define net_alias_main_dev(dev)	(dev)
+#define net_alias_has(dev)	0
+
+#endif
 
 #endif  /* _NET_ALIAS_H */
diff -u --recursive --new-file v2.1.21/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.1.21/linux/include/linux/netdevice.h	Thu Jan  2 15:55:24 1997
+++ linux/include/linux/netdevice.h	Sun Jan 19 16:06:37 1997
@@ -145,6 +145,7 @@
 	 *	Some hardware also needs these fields, but they are not
 	 *	part of the usual set specified in Space.c.
 	 */
+
 	unsigned char		if_port;	/* Selectable AUI, TP,..*/
 	unsigned char		dma;		/* DMA channel		*/
 
@@ -155,9 +156,7 @@
 	 */
 	 
 	struct enet_statistics* (*get_stats)(struct device *dev);
-#ifdef CONFIG_NET_RADIO
 	struct iw_statistics*	(*get_wireless_stats)(struct device *dev);
-#endif
 
 	/*
 	 * This marks the end of the "visible" part of the structure. All
@@ -194,7 +193,6 @@
   
 	struct ip_mc_list	*ip_mc_list;	/* IP multicast filter chain    */
 	unsigned		ip_flags;	/* IP layer control flags	*/
-	__u8			hash;		/* Hashing index 		*/	
 	__u32			tx_queue_len;	/* Max frames per queue allowed */
     
 	/* For load balancing driver pair support */
@@ -203,7 +201,12 @@
 	struct device		*slave;		/* Slave device		*/
 	struct net_alias_info	*alias_info;	/* main dev alias info	*/
 	struct net_alias	*my_alias;	/* alias devs		*/
-  
+
+	/* Protocol specific pointers */
+	
+	void 			*atalk_ptr;	/* Appletalk link 	*/
+	void			*ip_ptr;	/* Not used yet 	*/  
+
 	/* Pointer to the interface buffers.	*/
 	struct sk_buff_head	buffs[DEV_NUMBUFFS];
 
@@ -322,31 +325,6 @@
 		schedule();
 }
 
-/* NOTE: about to be replaced with if_index */
-
-extern __inline__ __u8 dev_hash_name(char *name)
-{
-	__u8 hash = 0;
-	__u8 *p;
-	for (p=name; *p; p++)
-		hash ^= *p;
-	return hash;
-}
-
-extern __inline__ __u8 dev_hash_mc_name(char *name)
-{
-	int i;
-	__u8 hash = 0;
-	unsigned *p = (unsigned*)name;
-	for (i=0; i<MAX_ADDR_LEN/sizeof(unsigned); i++) {
-		unsigned h = p[i];
-		h ^= (h>>16);
-		h ^= (h>>8);
-		hash ^= h;
-	}
-	return hash;
-}
-
 /*
  *	Buffer initialisation function. This used to appear in all the
  *	drivers but is now an inline in case we ever want to change the
@@ -384,6 +362,8 @@
 extern void		dev_mc_discard(struct device *dev);
 /* Load a device via the kerneld */
 extern void		dev_load(const char *name);
+extern int		dev_new_index(void);
+extern struct device *	dev_get_by_index(int ifindex);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.21/linux/include/linux/netrom.h linux/include/linux/netrom.h
--- v2.1.21/linux/include/linux/netrom.h	Thu Jan  2 15:55:24 1997
+++ linux/include/linux/netrom.h	Sun Jan 19 15:47:26 1997
@@ -3,7 +3,7 @@
  * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the
  * definition of the ax25_address structure.
  */
- 
+
 #ifndef	NETROM_KERNEL_H
 #define	NETROM_KERNEL_H
 
@@ -20,28 +20,28 @@
 
 #define	NETROM_KILL	99
 
-#define	SIOCNRDECOBS		(SIOCPROTOPRIVATE+0)
-#define	SIOCNRCTLCON		(SIOCPROTOPRIVATE+1)
+#define	SIOCNRDECOBS		(SIOCPROTOPRIVATE+2)
+#define	SIOCNRCTLCON		(SIOCPROTOPRIVATE+4)
 
 struct nr_route_struct {
 #define	NETROM_NEIGH	0
 #define	NETROM_NODE	1
-	int type;
-	ax25_address callsign;
-	char device[16];
-	unsigned int quality;
-	char mnemonic[7];
-	ax25_address neighbour;
-	unsigned int obs_count;
-	unsigned int ndigis;
-	ax25_address digipeaters[AX25_MAX_DIGIS];
+	int		type;
+	ax25_address	callsign;
+	char		device[16];
+	unsigned int	quality;
+	char		mnemonic[7];
+	ax25_address	neighbour;
+	unsigned int	obs_count;
+	unsigned int	ndigis;
+	ax25_address	digipeaters[AX25_MAX_DIGIS];
 };
 
 struct nr_ctl_struct {
-	unsigned char index;
-	unsigned char id;
-	unsigned int  cmd;
-	unsigned long arg;
+	unsigned char	index;
+	unsigned char	id;
+	unsigned int	cmd;
+	unsigned long	arg;
 };
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/include/linux/notifier.h linux/include/linux/notifier.h
--- v2.1.21/linux/include/linux/notifier.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/notifier.h	Sun Jan 19 15:47:26 1997
@@ -93,6 +93,10 @@
 				   - we can use this eg to kick tcp sessions
 				   once done */
 #define NETDEV_CHANGE	0x0004	/* Notify device state change */
+#define NETDEV_REGISTER 0x0005
+#define NETDEV_UNREGISTER	0x0006
+#define NETDEV_CHANGEMTU	0x0007
+#define NETDEV_CHANGEADDR	0x0008
 
 #define SYS_DOWN	0x0001	/* Notify of system down */
 #define SYS_HALT	0x0002	/* Notify of system halt */
diff -u --recursive --new-file v2.1.21/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.21/linux/include/linux/pci.h	Wed Dec 18 15:59:03 1996
+++ linux/include/linux/pci.h	Mon Jan 20 09:35:37 1997
@@ -269,6 +269,7 @@
 #define PCI_DEVICE_ID_DEC_21152		0x0024
 
 #define PCI_VENDOR_ID_CIRRUS		0x1013
+#define PCI_DEVICE_ID_CIRRUS_7548	0x0038
 #define PCI_DEVICE_ID_CIRRUS_5430	0x00a0
 #define PCI_DEVICE_ID_CIRRUS_5434_4	0x00a4
 #define PCI_DEVICE_ID_CIRRUS_5434_8	0x00a8
@@ -427,6 +428,9 @@
 #define PCI_DEVICE_ID_AL_M1513		0x1513
 #define PCI_DEVICE_ID_AL_M4803		0x5215
 
+#define PCI_VENDOR_ID_NEOMAGIC          0x10c8
+#define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2070 0x0001
+
 #define PCI_VENDOR_ID_ASP		0x10cd
 #define PCI_DEVICE_ID_ASP_ABP940	0x1200
 
@@ -445,6 +449,7 @@
 
 #define PCI_VENDOR_ID_INTERG		0x10ea
 #define PCI_DEVICE_ID_INTERG_1680	0x1680
+#define PCI_DEVICE_ID_INTERG_1682	0x1682
 
 #define PCI_VENDOR_ID_REALTEK		0x10ec
 #define PCI_DEVICE_ID_REALTEK_8029	0x8029
@@ -572,6 +577,8 @@
 #define PCI_DEVICE_ID_INTEL_82437	0x122d
 #define PCI_DEVICE_ID_INTEL_82371_0	0x122e
 #define PCI_DEVICE_ID_INTEL_82371_1	0x1230
+#define PCI_DEVICE_ID_INTEL_430MX_0	0x1234
+#define PCI_DEVICE_ID_INTEL_430MX_1	0x1235
 #define PCI_DEVICE_ID_INTEL_82441	0x1237
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
diff -u --recursive --new-file v2.1.21/linux/include/linux/rose.h linux/include/linux/rose.h
--- v2.1.21/linux/include/linux/rose.h	Sun Dec 22 16:37:41 1996
+++ linux/include/linux/rose.h	Sun Jan 19 15:47:26 1997
@@ -3,7 +3,7 @@
  * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the
  * definition of the ax25_address structure.
  */
- 
+
 #ifndef	ROSE_KERNEL_H
 #define	ROSE_KERNEL_H
 
@@ -20,10 +20,11 @@
 
 #define	ROSE_KILL	99
 
-#define	SIOCRSCTLCON		(SIOCPROTOPRIVATE+0)
+#define	SIOCRSCTLCON		(SIOCPROTOPRIVATE+1)
+#define	SIOCRSL2CALL		(SIOCPROTOPRIVATE+2)
 
 typedef struct {
-	char rose_addr[5];
+	char		rose_addr[5];
 } rose_address;
 
 struct sockaddr_rose {
@@ -44,10 +45,10 @@
 };
 
 struct rose_ctl_struct {
-	unsigned int  lci;
-	char          dev[20];
-	unsigned int  cmd;
-	unsigned long arg;
+	unsigned int	lci;
+	char		dev[20];
+	unsigned int	cmd;
+	unsigned long	arg;
 };
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/include/linux/route.h linux/include/linux/route.h
--- v2.1.21/linux/include/linux/route.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/route.h	Sun Jan 19 16:10:11 1997
@@ -125,7 +125,7 @@
 	unsigned char	rtmsg_class;
 	unsigned char	rtmsg_prefixlen;
 	unsigned char	rtmsg_reserved;
-	char		rtmsg_device[16];
+	int		rtmsg_ifindex;
 };
 
 
@@ -139,7 +139,8 @@
 	short		ifmsg_metric;
 	unsigned char	ifmsg_prefixlen;
 	unsigned char	ifmsg_reserved;
-	char		ifmsg_device[16];
+	int		ifmsg_index;
+	char		ifmsg_name[16];
 };
 
 enum rtrule_actions
@@ -160,11 +161,11 @@
 	struct in_addr	rtrmsg_src;
 	struct in_addr	rtrmsg_dst;
 	struct in_addr	rtrmsg_srcmap;
+	int		rtrmsg_ifindex;
 	unsigned char	rtrmsg_srclen;
 	unsigned char	rtrmsg_dstlen;
 	unsigned char	rtrmsg_tos;
 	unsigned char	rtrmsg_class;
-	char		rtrmsg_device[16];
 	unsigned char	rtrmsg_flags;
 	unsigned char	rtrmsg_action;
 	unsigned char	rtrmsg_preference;
diff -u --recursive --new-file v2.1.21/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.21/linux/include/linux/skbuff.h	Wed Dec 18 15:59:03 1996
+++ linux/include/linux/skbuff.h	Sun Jan 19 16:04:34 1997
@@ -199,10 +199,27 @@
 		__kfree_skb(skb);
 }
 
+extern __inline__ int skb_cloned(struct sk_buff *skb)
+{
+	return (skb->data_skb->count != 1);
+}
+
+extern __inline__ int skb_shared(struct sk_buff *skb)
+{
+	return (skb->users != 1);
+}
+
+/*
+ *	Copy shared buffers into a new sk_buff. We effectively do COW on
+ *	packets to handle cases where we have a local reader and forward
+ *	and a couple of other messy ones. The normal one is tcpdumping
+ *	a packet thats being forwarded.
+ */
+ 
 extern __inline__ struct sk_buff *skb_unshare(struct sk_buff *skb, int pri, int dir)
 {
 	struct sk_buff *nskb;
-	if(skb->users==1)
+	if(!skb_cloned(skb))
 		return skb;
 	nskb=skb_copy(skb, pri);
 	kfree_skb(skb, dir);	/* Free our shared copy */
@@ -215,6 +232,7 @@
  *	list and someone else may run off with it. For an interrupt
  *	type system cli() peek the buffer copy the data and sti();
  */
+ 
 extern __inline__ struct sk_buff *skb_peek(struct sk_buff_head *list_)
 {
 	struct sk_buff *list = ((struct sk_buff *)list_)->next;
diff -u --recursive --new-file v2.1.21/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.21/linux/include/linux/socket.h	Mon Dec 30 15:39:16 1996
+++ linux/include/linux/socket.h	Sun Jan 19 15:47:26 1997
@@ -63,9 +63,16 @@
 
 #define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
 
-#define	CMSG_FIRST(msg)	((msg)->msg_controllen >= sizeof(struct cmsghdr) ? \
-			 (struct cmsghdr *)(msg)->msg_control : \
-			 (struct cmsghdr *)NULL)
+/* Stevens's Adv. API specifies CMSG_SPACE & CMSG_LENGTH,
+ * I cannot understand, what the differenece? --ANK
+ */
+
+#define CMSG_SPACE(len) CMSG_ALIGN((len)+sizeof(struct cmsghdr))
+#define CMSG_LENGTH(len) CMSG_ALIGN((len)+sizeof(struct cmsghdr))
+
+#define	CMSG_FIRSTHDR(msg)	((msg)->msg_controllen >= sizeof(struct cmsghdr) ? \
+				 (struct cmsghdr *)(msg)->msg_control : \
+				 (struct cmsghdr *)NULL)
 
 extern __inline__ struct cmsghdr * cmsg_nxthdr(struct msghdr *mhdr,
 					       struct cmsghdr *cmsg)
@@ -83,20 +90,6 @@
 	return (struct cmsghdr *) ptr;
 }
 
-#ifdef __KERNEL__
-
-#define	KCMSG_NXTHDR(msg, cmsg)	({ \
-	struct cmsghdr * __cmptr = (struct cmsghdr *)((unsigned char*)(cmsg) + CMSG_ALIGN(kcm.cmsg_len)); \
-	( (void *)(__cmptr + 1) <= (msg)->msg_control + (msg)->msg_controllen && \
-	  !copy_from_user(&kcm, __cmptr, sizeof(struct cmsghdr)) ? __cmptr : NULL); })
-
-#define	KCMSG_FIRSTHDR(msg)	((msg)->msg_control && (msg)->msg_controllen >= sizeof(struct cmsghdr) \
-				 && !copy_from_user(&kcm, (msg)->msg_control, sizeof(struct cmsghdr)) ? \
-				 (struct cmsghdr *)(msg)->msg_control : \
-				 (struct cmsghdr *)NULL)
-
-#endif
-
 /* "Socket"-level control message types: */
 
 #define	SCM_RIGHTS	0x01		/* rw: access rights (array of int) */
@@ -154,7 +147,7 @@
 #define PF_AAL5		AF_AAL5
 #define PF_X25		AF_X25
 #define PF_INET6	AF_INET6
-#define PR_ROSE		AF_ROSE
+#define PF_ROSE		AF_ROSE
 #define PF_DECNET	AF_DECNET
 #define PF_NETBEUI	AF_NETBEUI
 
diff -u --recursive --new-file v2.1.21/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.21/linux/include/linux/sysctl.h	Wed Dec 18 15:59:03 1996
+++ linux/include/linux/sysctl.h	Sun Jan 19 15:47:26 1997
@@ -139,7 +139,8 @@
 	NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,
 	NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,
 	NET_NETROM_TRANSPORT_PACKET_LENGTH,
-	NET_NETROM_ROUTING_CONTROL
+	NET_NETROM_ROUTING_CONTROL,
+	NET_NETROM_LINK_FAILS_COUNT
 };
 
 /* /proc/sys/net/ax25 */
diff -u --recursive --new-file v2.1.21/linux/include/linux/watchdog.h linux/include/linux/watchdog.h
--- v2.1.21/linux/include/linux/watchdog.h	Thu Dec 12 19:37:20 1996
+++ linux/include/linux/watchdog.h	Sun Jan 19 15:47:26 1997
@@ -37,3 +37,4 @@
 
 #define	WDIOS_DISABLECARD	0x0001	/* Turn off the watchdog timer */
 #define	WDIOS_ENABLECARD	0x0002	/* Turn on the watchdog timer */
+#define	WDIOS_TEMPPANIC		0x0004	/* Kernel panic on temperature trip */
diff -u --recursive --new-file v2.1.21/linux/include/linux/x25.h linux/include/linux/x25.h
--- v2.1.21/linux/include/linux/x25.h	Wed Dec 18 15:59:03 1996
+++ linux/include/linux/x25.h	Sun Jan 19 15:47:26 1997
@@ -1,22 +1,23 @@
 /*
  * These are the public elements of the Linux kernel X.25 implementation.
  */
- 
+
 #ifndef	X25_KERNEL_H
 #define	X25_KERNEL_H
 
 #define PF_X25			AF_X25
 
-#define	SIOCX25SETSUBSCR	(SIOCPROTOPRIVATE + 0)
+#define	SIOCX25GSUBSCRIP	(SIOCPROTOPRIVATE + 0)
+#define	SIOCX25SSUBSCRIP	(SIOCPROTOPRIVATE + 1)
+#define	SIOCX25GFACILITIES	(SIOCPROTOPRIVATE + 2)
+#define	SIOCX25SFACILITIES	(SIOCPROTOPRIVATE + 3)
+#define	SIOCX25GCALLUSERDATA	(SIOCPROTOPRIVATE + 4)
+#define	SIOCX25SCALLUSERDATA	(SIOCPROTOPRIVATE + 5)
 
 /*
  *	Values for {get,set}sockopt.
  */
 #define	X25_QBITINCL		1
-#define	X25_PACKET_SIZE		10
-#define	X25_WINDOW_SIZE		11
-#define	X25_THROUGHPUT_SPEED	12
-#define	X25_REVERSE_CHARGE	13
 
 /*
  *	X.25 Packet Size values.
@@ -93,6 +94,24 @@
 	x25_address	address;
 	unsigned int	sigdigits;
 	char		device[200];
+};
+
+/*
+ *	Facilities structure.
+ */
+struct x25_facilities {
+	unsigned int	winsize_in, winsize_out;
+	unsigned int	pacsize_in, pacsize_out;
+	unsigned int	throughput;
+	unsigned int	reverse;
+};
+
+/*
+ *	Call User Data structure.
+ */
+struct x25_calluserdata {
+	unsigned int	cudlength;
+	unsigned char	cuddata[128];
 };
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/include/net/arp.h linux/include/net/arp.h
--- v2.1.21/linux/include/net/arp.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/arp.h	Sun Jan 19 16:10:12 1997
@@ -7,7 +7,6 @@
 extern void	arp_init(void);
 extern int	arp_rcv(struct sk_buff *skb, struct device *dev,
 			struct packet_type *pt);
-extern int	arp_query(unsigned char *haddr, u32 paddr, struct device *dev);
 extern int	arp_find(unsigned char *haddr, struct sk_buff *skb);
 extern int	arp_find_1(unsigned char *haddr, struct dst_entry* dst, struct dst_entry *neigh);
 extern int	arp_ioctl(unsigned int cmd, void *arg);
diff -u --recursive --new-file v2.1.21/linux/include/net/ax25.h linux/include/net/ax25.h
--- v2.1.21/linux/include/net/ax25.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/ax25.h	Sun Jan 19 16:06:41 1997
@@ -8,45 +8,43 @@
 #define _AX25_H 
 #include <linux/ax25.h>
 
-#define PR_SLOWHZ	10		/*  Run timing at 1/10 second - gives us better resolution for 56kbit links */
+#define AX25_SLOWHZ			10	/* Run timing at 1/10 second - gives us better resolution for 56kbit links */
 
-#define	AX25_T1CLAMPLO  (1 * PR_SLOWHZ)	/* If defined, clamp at 1 second **/
-#define	AX25_T1CLAMPHI (30 * PR_SLOWHZ)	/* If defined, clamp at 30 seconds **/
+#define	AX25_T1CLAMPLO  		(1 * AX25_SLOWHZ)	/* If defined, clamp at 1 second **/
+#define	AX25_T1CLAMPHI 			(30 * AX25_SLOWHZ)	/* If defined, clamp at 30 seconds **/
 
-#define	AX25_BROKEN_NETMAC
+#define	AX25_BPQ_HEADER_LEN		16
+#define	AX25_KISS_HEADER_LEN		1
 
-#define	AX25_BPQ_HEADER_LEN	16
-#define	AX25_KISS_HEADER_LEN	1
-
-#define	AX25_HEADER_LEN		17
-#define	AX25_ADDR_LEN		7
-#define	AX25_DIGI_HEADER_LEN	(AX25_MAX_DIGIS * AX25_ADDR_LEN)
-#define	AX25_MAX_HEADER_LEN	(AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN)
- 
-#define AX25_P_ROSE	0x01
-#define AX25_P_IP	0xCC
-#define AX25_P_ARP	0xCD
-#define AX25_P_TEXT 	0xF0
-#define AX25_P_NETROM 	0xCF
-#define	AX25_P_SEGMENT	0x08
-
-#define	SEG_REM		0x7F
-#define	SEG_FIRST	0x80
-
-#define LAPB_UI		0x03
-#define LAPB_C		0x80
-#define LAPB_E		0x01
-
-#define SSSID_SPARE	0x60	/* Unused bits in SSID for standard AX.25 */
-#define ESSID_SPARE	0x20	/* Unused bits in SSID for extended AX.25 */
-#define DAMA_FLAG	0x20	/* Well, it is *NOT* unused! (dl1bke 951121 */
-
-#define AX25_REPEATED	0x80
-
-#define	ACK_PENDING_CONDITION		0x01
-#define	REJECT_CONDITION		0x02
-#define	PEER_RX_BUSY_CONDITION		0x04
-#define	OWN_RX_BUSY_CONDITION		0x08
+#define	AX25_HEADER_LEN			17
+#define	AX25_ADDR_LEN			7
+#define	AX25_DIGI_HEADER_LEN		(AX25_MAX_DIGIS * AX25_ADDR_LEN)
+#define	AX25_MAX_HEADER_LEN		(AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN)
+
+/* AX.25 Protocol IDs */
+#define AX25_P_ROSE			0x01
+#define AX25_P_IP			0xCC
+#define AX25_P_ARP			0xCD
+#define AX25_P_TEXT 			0xF0
+#define AX25_P_NETROM 			0xCF
+#define	AX25_P_SEGMENT			0x08
+
+/* AX.25 Segment control values */
+#define	AX25_SEG_REM			0x7F
+#define	AX25_SEG_FIRST			0x80
+
+#define AX25_CBIT			0x80	/* Command/Response bit */
+#define AX25_EBIT			0x01	/* HDLC Address Extension bit */
+#define AX25_HBIT			0x80	/* Has been repeated bit */
+
+#define AX25_SSSID_SPARE		0x60	/* Unused bits in SSID for standard AX.25 */
+#define AX25_ESSID_SPARE		0x20	/* Unused bits in SSID for extended AX.25 */
+#define AX25_DAMA_FLAG			0x20	/* Well, it is *NOT* unused! (dl1bke 951121 */
+
+#define	AX25_COND_ACK_PENDING		0x01
+#define	AX25_COND_REJECT		0x02
+#define	AX25_COND_PEER_RX_BUSY		0x04
+#define	AX25_COND_OWN_RX_BUSY		0x08
 
 #ifndef _LINUX_NETDEVICE_H
 #include <linux/netdevice.h>
@@ -76,44 +74,43 @@
 /* Upper sub-layer (LAPB) definitions */
 
 /* Control field templates */
-#define	I	0x00	/* Information frames */
-#define	S	0x01	/* Supervisory frames */
-#define	RR	0x01	/* Receiver ready */
-#define	RNR	0x05	/* Receiver not ready */
-#define	REJ	0x09	/* Reject */
-#define	U	0x03	/* Unnumbered frames */
-#define	SABM	0x2f	/* Set Asynchronous Balanced Mode */
-#define	SABME	0x6f	/* Set Asynchronous Balanced Mode Extended */
-#define	DISC	0x43	/* Disconnect */
-#define	DM	0x0f	/* Disconnected mode */
-#define	UA	0x63	/* Unnumbered acknowledge */
-#define	FRMR	0x87	/* Frame reject */
-#define	UI	0x03	/* Unnumbered information */
-#define	PF	0x10	/* Poll/final bit for standard AX.25 */
-#define	EPF	0x01	/* Poll/final bit for extended AX.25 */
+#define	AX25_I			0x00	/* Information frames */
+#define	AX25_S			0x01	/* Supervisory frames */
+#define	AX25_RR			0x01	/* Receiver ready */
+#define	AX25_RNR		0x05	/* Receiver not ready */
+#define	AX25_REJ		0x09	/* Reject */
+#define	AX25_U			0x03	/* Unnumbered frames */
+#define	AX25_SABM		0x2f	/* Set Asynchronous Balanced Mode */
+#define	AX25_SABME		0x6f	/* Set Asynchronous Balanced Mode Extended */
+#define	AX25_DISC		0x43	/* Disconnect */
+#define	AX25_DM			0x0f	/* Disconnected mode */
+#define	AX25_UA			0x63	/* Unnumbered acknowledge */
+#define	AX25_FRMR		0x87	/* Frame reject */
+#define	AX25_UI			0x03	/* Unnumbered information */
 
-#define ILLEGAL	0x100	/* Impossible to be a real frame type */
+#define	AX25_PF			0x10	/* Poll/final bit for standard AX.25 */
+#define	AX25_EPF		0x01	/* Poll/final bit for extended AX.25 */
 
-#define	POLLOFF		0
-#define	POLLON		1
+#define AX25_ILLEGAL		0x100	/* Impossible to be a real frame type */
 
-/* AX25 L2 C-bit */
+#define	AX25_POLLOFF		0
+#define	AX25_POLLON		1
 
-#define C_COMMAND	1	/* C_ otherwise it clashes with the de600 defines (sigh)) */
-#define C_RESPONSE	2
+/* AX25 L2 C-bit */
+#define AX25_COMMAND		1
+#define AX25_RESPONSE		2
 
 /* Define Link State constants. */
-
-#define AX25_STATE_0	0
-#define AX25_STATE_1	1
-#define AX25_STATE_2	2
-#define AX25_STATE_3	3
-#define AX25_STATE_4	4
+#define AX25_STATE_0		0
+#define AX25_STATE_1		1
+#define AX25_STATE_2		2
+#define AX25_STATE_3		3
+#define AX25_STATE_4		4
 
 #define	AX25_MAX_DEVICES	20	/* Max No of AX.25 devices */
 
-#define MODULUS 		8	/*  Standard AX.25 modulus */
-#define	EMODULUS		128	/*  Extended AX.25 modulus */
+#define AX25_MODULUS 		8	/*  Standard AX.25 modulus */
+#define	AX25_EMODULUS		128	/*  Extended AX.25 modulus */
 
 #define	AX25_DIGI_INBAND	0x01	/* Allow digipeating within port **/
 #define	AX25_DIGI_XBAND		0x02	/* Allow digipeating across ports **/
@@ -142,11 +139,11 @@
 #define	AX25_DEF_CONMODE	1			/* Connected mode allowed */
 #define	AX25_DEF_WINDOW		2			/* Window=2 */
 #define	AX25_DEF_EWINDOW	32			/* Module-128 Window=32 */
-#define	AX25_DEF_T1		(10 * PR_SLOWHZ)	/* T1=10s */
-#define	AX25_DEF_T2		(3 * PR_SLOWHZ)		/* T2=3s  */
-#define	AX25_DEF_T3		(300 * PR_SLOWHZ)	/* T3=300s */
+#define	AX25_DEF_T1		(10 * AX25_SLOWHZ)	/* T1=10s */
+#define	AX25_DEF_T2		(3 * AX25_SLOWHZ)	/* T2=3s  */
+#define	AX25_DEF_T3		(300 * AX25_SLOWHZ)	/* T3=300s */
 #define	AX25_DEF_N2		10			/* N2=10 */
-#define AX25_DEF_IDLE		(20 * 60 * PR_SLOWHZ)	/* Idle=20 mins */		
+#define AX25_DEF_IDLE		(20 * 60 * AX25_SLOWHZ)	/* Idle=20 mins */		
 #define AX25_DEF_PACLEN		256			/* Paclen=256 */
 #define AX25_DEF_MAXQUEUE	2			/* 1 * ax25->window */
 #define	AX25_DEF_DIGI		0x03			/* All digis alowed */
@@ -168,7 +165,7 @@
 	struct ax25_cb		*next;
 	ax25_address		source_addr, dest_addr;
 	struct device		*device;
-	unsigned char		dama_slave;	/* dl1bke 951121 */
+	unsigned char		dama_slave, iamdigi;
 	unsigned char		state, modulus, hdrincl;
 	unsigned short		vs, vr, va;
 	unsigned char		condition, backoff;
@@ -191,6 +188,7 @@
 struct ax25_dev {
 	char name[20];
 	struct device *dev;
+	struct device *forward;
 	int values[AX25_MAX_VALUES];
 };
 
@@ -245,6 +243,8 @@
 extern int  ax25_dev_get_value(struct device *, int);
 extern void ax25_dev_device_up(struct device *);
 extern void ax25_dev_device_down(struct device *);
+extern int  ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *);
+extern struct device *ax25_fwd_dev(struct device *);
 extern void ax25_rt_free(void);
 
 /* ax25_subr.c */
@@ -289,5 +289,6 @@
 extern void ax25_linkfail_release(void (*)(ax25_address *, struct device *));
 extern int  ax25_listen_register(ax25_address *, struct device *);
 extern void ax25_listen_release(ax25_address *, struct device *);
+extern int  ax25_protocol_is_registered(unsigned int);
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/include/net/ip.h linux/include/net/ip.h
--- v2.1.21/linux/include/net/ip.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/ip.h	Sun Jan 19 16:10:11 1997
@@ -199,7 +199,7 @@
 extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
 extern void ip_options_fragment(struct sk_buff *skb);
 extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb);
-extern int ip_options_getfromuser(struct ip_options **optp, unsigned char *data, int optlen);
+extern int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, int user);
 extern void ip_options_undo(struct ip_options * opt);
 extern void ip_forward_options(struct sk_buff *skb);
 extern int ip_options_rcv_srr(struct sk_buff *skb);
diff -u --recursive --new-file v2.1.21/linux/include/net/lapb.h linux/include/net/lapb.h
--- v2.1.21/linux/include/net/lapb.h	Thu Jan  2 15:55:25 1997
+++ linux/include/net/lapb.h	Sun Jan 19 15:47:27 1997
@@ -116,6 +116,6 @@
  *	2 = Packets I/O and State Changes
  *	3 = Hex dumps, Packets I/O and State Changes.
  */
-#define	LAPB_DEBUG	2
+#define	LAPB_DEBUG	0
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/include/net/netrom.h linux/include/net/netrom.h
--- v2.1.21/linux/include/net/netrom.h	Wed Dec 18 15:59:03 1996
+++ linux/include/net/netrom.h	Sun Jan 19 15:47:27 1997
@@ -3,50 +3,59 @@
  *
  *	Jonathan Naylor G4KLX	9/4/95
  */
- 
+
 #ifndef _NETROM_H
 #define _NETROM_H 
 #include <linux/netrom.h>
 
-#define	NR_T1CLAMPLO   (1 * PR_SLOWHZ)	/* If defined, clamp at 1 second **/
-#define	NR_T1CLAMPHI (300 * PR_SLOWHZ)	/* If defined, clamp at 30 seconds **/
+#define	NR_SLOWHZ			10	/* Run timing at 1/10 second */
+
+#define	NR_T1CLAMPLO  	 		(1 * NR_SLOWHZ)		/* If defined, clamp at 1 second **/
+#define	NR_T1CLAMPHI 			(300 * NR_SLOWHZ)	/* If defined, clamp at 30 seconds **/
+
+#define	NR_NETWORK_LEN			15
+#define	NR_TRANSPORT_LEN		5
 
-#define	NR_NETWORK_LEN		15
-#define	NR_TRANSPORT_LEN	5
- 
-#define	NR_PROTO_IP		0x0C
-
-#define	NR_PROTOEXT		0x00
-#define	NR_CONNREQ		0x01
-#define	NR_CONNACK		0x02
-#define	NR_DISCREQ		0x03
-#define	NR_DISCACK		0x04
-#define	NR_INFO			0x05
-#define	NR_INFOACK		0x06
-
-#define	NR_CHOKE_FLAG		0x80
-#define	NR_NAK_FLAG		0x40
-#define	NR_MORE_FLAG		0x20
+#define	NR_PROTO_IP			0x0C
+
+#define	NR_PROTOEXT			0x00
+#define	NR_CONNREQ			0x01
+#define	NR_CONNACK			0x02
+#define	NR_DISCREQ			0x03
+#define	NR_DISCACK			0x04
+#define	NR_INFO				0x05
+#define	NR_INFOACK			0x06
+
+#define	NR_CHOKE_FLAG			0x80
+#define	NR_NAK_FLAG			0x40
+#define	NR_MORE_FLAG			0x20
 
 /* Define Link State constants. */
 
-#define NR_STATE_0		0
-#define NR_STATE_1		1
-#define NR_STATE_2		2
-#define NR_STATE_3		3
-
-#define NR_DEFAULT_T1		(120 * PR_SLOWHZ)	/* Outstanding frames - 120 seconds */
-#define NR_DEFAULT_T2		(5   * PR_SLOWHZ)	/* Response delay     - 5 seconds */
-#define NR_DEFAULT_N2		3			/* Number of Retries - 3 */
-#define	NR_DEFAULT_T4		(180 * PR_SLOWHZ)	/* Busy Delay - 180 seconds */
-#define	NR_DEFAULT_IDLE		(20* 60 * PR_SLOWHZ)	/* No Activuty Timeout - 900 seconds*/
-#define	NR_DEFAULT_WINDOW	4			/* Default Window Size - 4 */
-#define	NR_DEFAULT_OBS		6			/* Default Obsolescence Count - 6 */
-#define	NR_DEFAULT_QUAL		10			/* Default Neighbour Quality - 10 */
-#define	NR_DEFAULT_TTL		16			/* Default Time To Live - 16 */
-#define NR_MODULUS 		256
-#define NR_MAX_WINDOW_SIZE	127			/* Maximum Window Allowable - 127 */
-#define	NR_DEFAULT_PACLEN	236			/* Default Packet Length - 236 */
+#define NR_STATE_0			0
+#define NR_STATE_1			1
+#define NR_STATE_2			2
+#define NR_STATE_3			3
+
+#define	NR_COND_ACK_PENDING		0x01
+#define	NR_COND_REJECT			0x02
+#define	NR_COND_PEER_RX_BUSY		0x04
+#define	NR_COND_OWN_RX_BUSY		0x08
+
+#define NR_DEFAULT_T1			(120 * NR_SLOWHZ)	/* Outstanding frames - 120 seconds */
+#define NR_DEFAULT_T2			(5   * NR_SLOWHZ)	/* Response delay     - 5 seconds */
+#define NR_DEFAULT_N2			3			/* Number of Retries - 3 */
+#define	NR_DEFAULT_T4			(180 * NR_SLOWHZ)	/* Busy Delay - 180 seconds */
+#define	NR_DEFAULT_IDLE			(20* 60 * NR_SLOWHZ)	/* No Activuty Timeout - 900 seconds*/
+#define	NR_DEFAULT_WINDOW		4			/* Default Window Size - 4 */
+#define	NR_DEFAULT_OBS			6			/* Default Obsolescence Count - 6 */
+#define	NR_DEFAULT_QUAL			10			/* Default Neighbour Quality - 10 */
+#define	NR_DEFAULT_TTL			16			/* Default Time To Live - 16 */
+#define NR_MODULUS 			256
+#define NR_MAX_WINDOW_SIZE		127			/* Maximum Window Allowable - 127 */
+#define	NR_DEFAULT_PACLEN		236			/* Default Packet Length - 236 */
+#define	NR_DEFAULT_ROUTING		1			/* Is routing enabled ? */
+#define	NR_DEFAULT_FAILS		2			/* Link fails until route fails */
 
 typedef struct {
 	ax25_address		user_addr, source_addr, dest_addr;
@@ -74,6 +83,7 @@
 	unsigned char   locked;
 	unsigned short  count;
 	unsigned int    number;
+	unsigned char	failed;
 };
 
 struct nr_route {
@@ -103,6 +113,7 @@
 extern int  sysctl_netrom_transport_no_activity_timeout;
 extern int  sysctl_netrom_transport_packet_length;
 extern int  sysctl_netrom_routing_control;
+extern int  sysctl_netrom_link_fails_count;
 extern int  nr_rx_frame(struct sk_buff *, struct device *);
 extern void nr_destroy_socket(struct sock *);
 
diff -u --recursive --new-file v2.1.21/linux/include/net/rose.h linux/include/net/rose.h
--- v2.1.21/linux/include/net/rose.h	Sun Dec 22 16:37:42 1996
+++ linux/include/net/rose.h	Sun Jan 19 15:47:27 1997
@@ -3,20 +3,22 @@
  *
  *	Jonathan Naylor G4KLX	25/8/96
  */
- 
+
 #ifndef _ROSE_H
 #define _ROSE_H 
 #include <linux/rose.h>
 
+#define	ROSE_SLOWHZ			10	/* Run timing at 1/10 second */
+
 #define	ROSE_ADDR_LEN			5
 
 #define	ROSE_MIN_LEN			3
 
-#define	GFI				0x10
-#define	Q_BIT				0x80
-#define	D_BIT				0x40
-#define	M_BIT				0x10
- 
+#define	ROSE_GFI			0x10
+#define	ROSE_Q_BIT			0x80
+#define	ROSE_D_BIT			0x40
+#define	ROSE_M_BIT			0x10
+
 #define	ROSE_CALL_REQUEST		0x0B
 #define	ROSE_CALL_ACCEPTED		0x0F
 #define	ROSE_CLEAR_REQUEST		0x13
@@ -38,33 +40,37 @@
 
 /* Define Link State constants. */
 
-#define ROSE_STATE_0		0		/* Ready */
-#define ROSE_STATE_1		1		/* Awaiting Call Accepted */
-#define ROSE_STATE_2		2		/* Awaiting Clear Confirmation */
-#define ROSE_STATE_3		3		/* Data Transfer */
-#define	ROSE_STATE_4		4		/* Awaiting Reset Confirmation */
-
-#define ROSE_DEFAULT_T0		(180 * PR_SLOWHZ)	/* Default T10 T20 value */
-#define ROSE_DEFAULT_T1		(200 * PR_SLOWHZ)	/* Default T11 T21 value */
-#define ROSE_DEFAULT_T2		(180 * PR_SLOWHZ)	/* Default T12 T22 value */
-#define	ROSE_DEFAULT_T3		(180 * PR_SLOWHZ)	/* Default T13 T23 value */
-#define	ROSE_DEFAULT_HB		(5 * PR_SLOWHZ)		/* Default Holdback value */
-#define	ROSE_DEFAULT_IDLE	(20 * 60 * PR_SLOWHZ)	/* Default No Activity value */
-#define	ROSE_DEFAULT_WINDOW	2			/* Default Window Size	*/
-#define ROSE_MODULUS 		8
-#define ROSE_MAX_WINDOW_SIZE	7			/* Maximum Window Allowable */
-#define	ROSE_PACLEN		128			/* Default Packet Length */
-
-#define	FAC_NATIONAL		0x00
-#define	FAC_CCITT		0x0F
-
-#define	FAC_NATIONAL_RAND	0x7F
-#define	FAC_NATIONAL_FLAGS	0x3F
-#define	FAC_NATIONAL_DEST_DIGI	0xE9
-#define	FAC_NATIONAL_SRC_DIGI	0xEB
+#define ROSE_STATE_0			0		/* Ready */
+#define ROSE_STATE_1			1		/* Awaiting Call Accepted */
+#define ROSE_STATE_2			2		/* Awaiting Clear Confirmation */
+#define ROSE_STATE_3			3		/* Data Transfer */
+#define	ROSE_STATE_4			4		/* Awaiting Reset Confirmation */
+
+#define ROSE_DEFAULT_T0			(180 * ROSE_SLOWHZ)	/* Default T10 T20 value */
+#define ROSE_DEFAULT_T1			(200 * ROSE_SLOWHZ)	/* Default T11 T21 value */
+#define ROSE_DEFAULT_T2			(180 * ROSE_SLOWHZ)	/* Default T12 T22 value */
+#define	ROSE_DEFAULT_T3			(180 * ROSE_SLOWHZ)	/* Default T13 T23 value */
+#define	ROSE_DEFAULT_HB			(5 * ROSE_SLOWHZ)	/* Default Holdback value */
+#define	ROSE_DEFAULT_IDLE		(20 * 60 * ROSE_SLOWHZ)	/* Default No Activity value */
+#define	ROSE_DEFAULT_WINDOW		2			/* Default Window Size	*/
+#define ROSE_MODULUS 			8
+#define ROSE_MAX_WINDOW_SIZE		7			/* Maximum Window Allowable */
+#define	ROSE_PACLEN			128			/* Default Packet Length */
+
+#define	ROSE_COND_ACK_PENDING		0x01
+#define	ROSE_COND_PEER_RX_BUSY		0x02
+#define	ROSE_COND_OWN_RX_BUSY		0x04
+
+#define	FAC_NATIONAL			0x00
+#define	FAC_CCITT			0x0F
+
+#define	FAC_NATIONAL_RAND		0x7F
+#define	FAC_NATIONAL_FLAGS		0x3F
+#define	FAC_NATIONAL_DEST_DIGI		0xE9
+#define	FAC_NATIONAL_SRC_DIGI		0xEB
 
-#define	FAC_CCITT_DEST_NSAP	0xC9
-#define	FAC_CCITT_SRC_NSAP	0xCB
+#define	FAC_CCITT_DEST_NSAP		0xC9
+#define	FAC_CCITT_SRC_NSAP		0xCB
 
 struct rose_neigh {
 	struct rose_neigh *next;
@@ -108,12 +114,12 @@
 	unsigned short		timer;
 	unsigned short		t1, t2, t3, hb, idle;
 	unsigned short		fraglen;
-	struct sk_buff_head	ack_queue;
 	struct sk_buff_head	frag_queue;
 	struct sock		*sk;		/* Backlink to socket */
 } rose_cb;
 
 /* af_rose.c */
+extern ax25_address rose_callsign;
 extern int  sysctl_rose_restart_request_timeout;
 extern int  sysctl_rose_call_request_timeout;
 extern int  sysctl_rose_reset_request_timeout;
@@ -169,8 +175,6 @@
 
 /* rose_subr.c */
 extern void rose_clear_queues(struct sock *);
-extern void rose_frames_acked(struct sock *, unsigned short);
-extern void rose_requeue_frames(struct sock *);
 extern int  rose_validate_nr(struct sock *, unsigned short);
 extern void rose_write_internal(struct sock *, int);
 extern int  rose_decode(struct sk_buff *, int *, int *, int *, int *, int *);
diff -u --recursive --new-file v2.1.21/linux/include/net/route.h linux/include/net/route.h
--- v2.1.21/linux/include/net/route.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/route.h	Sun Jan 19 16:10:11 1997
@@ -115,7 +115,7 @@
 extern void		ip_rt_advice(struct rtable **rp, int advice);
 extern void		rt_cache_flush(int how);
 extern int		ip_route_output(struct rtable **, u32 dst, u32 src, u8 tos, struct device *devout);
-extern int		ip_route_output_dev(struct rtable **, u32 dst, u32 src, u8 tos, char *devname);
+extern int		ip_route_output_dev(struct rtable **, u32 dst, u32 src, u8 tos, int);
 extern int		ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct device *devin);
 extern unsigned short	ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
 extern void		ip_rt_send_redirect(struct sk_buff *skb);
diff -u --recursive --new-file v2.1.21/linux/include/net/scm.h linux/include/net/scm.h
--- v2.1.21/linux/include/net/scm.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/scm.h	Sun Jan 19 15:47:27 1997
@@ -39,7 +39,7 @@
 	scm->creds.gid = current->gid;
 	scm->creds.pid = current->pid;
 	scm->sock      = sock;
-	if (!msg->msg_control)
+	if (msg->msg_controllen <= 0)
 		return 0;
 	return __scm_send(sock, msg, scm);
 }
diff -u --recursive --new-file v2.1.21/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.21/linux/include/net/sock.h	Wed Jan 15 19:45:45 1997
+++ linux/include/net/sock.h	Sun Jan 19 16:06:41 1997
@@ -466,7 +466,8 @@
 	__u8			ip_mc_loop;		/* Loopback */
 	__u8			ip_recverr;
 	__u8			ip_pmtudisc;
-	char			ip_mc_name[MAX_ADDR_LEN];/* Multicast device name */
+	int			ip_mc_index;		/* Multicast device index */
+	__u32			ip_mc_addr;
 	struct ip_mc_socklist	*ip_mc_list;		/* Group array */
 
 /*
@@ -686,11 +687,23 @@
 extern int			sock_getsockopt(struct socket *sock, int level,
 						int op, char *optval, 
 						int *optlen);
-extern struct sk_buff 		*sock_alloc_send_skb(struct sock *skb,
+extern struct sk_buff 		*sock_alloc_send_skb(struct sock *sk,
 						     unsigned long size,
 						     unsigned long fallback,
 						     int noblock,
 						     int *errcode);
+extern int 			sock_no_fcntl(struct socket *, unsigned int, unsigned long);
+
+/*
+ *	Default socket callbacks and setup code
+ */
+ 
+extern void sock_def_callback1(struct sock *);
+extern void sock_def_callback2(struct sock *, int);
+extern void sock_def_callback3(struct sock *);
+
+/* Initialise core socket variables */
+extern void sock_init_data(struct socket *sock, struct sock *sk);
 
 extern void sklist_remove_socket(struct sock **list, struct sock *sk);
 extern void sklist_insert_socket(struct sock **list, struct sock *sk);
diff -u --recursive --new-file v2.1.21/linux/include/net/x25.h linux/include/net/x25.h
--- v2.1.21/linux/include/net/x25.h	Thu Jan  2 15:55:25 1997
+++ linux/include/net/x25.h	Sun Jan 19 15:47:27 1997
@@ -3,7 +3,7 @@
  *
  *	Jonathan Naylor		17/11/96
  */
- 
+
 #ifndef _X25_H
 #define _X25_H 
 #include <linux/x25.h>
@@ -25,7 +25,7 @@
 #define	X25_D_BIT			0x40
 #define	X25_STD_M_BIT			0x10
 #define	X25_EXT_M_BIT			0x01
- 
+
 #define	X25_CALL_REQUEST		0x0B
 #define	X25_CALL_ACCEPTED		0x0F
 #define	X25_CLEAR_REQUEST		0x13
@@ -95,6 +95,7 @@
 #define	X25_FAC_WINDOW_SIZE	0x43
 
 #define	X25_MAX_FAC_LEN		20		/* Plenty to spare */
+#define	X25_MAX_CUD_LEN		128
 
 struct x25_route {
 	struct x25_route	*next;
@@ -113,27 +114,21 @@
 	struct timer_list	timer;
 };
 
-struct x25_facilities {
-	int window_size;
-	int packet_size;
-	int throughput;
-	int reverse;
-};
-
 typedef struct {
 	x25_address		source_addr, dest_addr;
 	struct x25_neigh	*neighbour;
 	unsigned int		lci;
-	unsigned char		state, condition, qbitincl, intflg;
+	unsigned char		state, condition, qbitincl, intflag;
 	unsigned short		vs, vr, va, vl;
 	unsigned short		timer;
 	unsigned short		t2, t21, t22, t23;
 	unsigned short		fraglen;
-	struct sk_buff_head	ack_queue;
 	struct sk_buff_head	fragment_queue;
-	struct sk_buff_head	interrupt_queue;
+	struct sk_buff_head	interrupt_in_queue;
+	struct sk_buff_head	interrupt_out_queue;
 	struct sock		*sk;		/* Backlink to socket */
 	struct x25_facilities	facilities;
+	struct x25_calluserdata	calluserdata;
 } x25_cb;
 
 /* af_x25.c */
@@ -194,8 +189,6 @@
 
 /* x25_subr.c */
 extern void x25_clear_queues(struct sock *);
-extern void x25_frames_acked(struct sock *, unsigned short);
-extern void x25_requeue_frames(struct sock *);
 extern int  x25_validate_nr(struct sock *, unsigned short);
 extern void x25_write_internal(struct sock *, int);
 extern int  x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *);
diff -u --recursive --new-file v2.1.21/linux/init/main.c linux/init/main.c
--- v2.1.21/linux/init/main.c	Wed Jan 15 19:45:46 1997
+++ linux/init/main.c	Sun Jan 19 15:49:31 1997
@@ -224,7 +224,7 @@
 #endif
 
 int root_mountflags = MS_RDONLY;
-char *execute_command = 0;
+char *execute_command = NULL;
 
 #ifdef CONFIG_ROOT_NFS
 char nfs_root_name[NFS_ROOT_NAME_LEN] = { "default" };
@@ -960,7 +960,7 @@
 	smp_begin();
 #endif	
 
-	#ifdef CONFIG_UMSDOS_FS
+#ifdef CONFIG_UMSDOS_FS
 	{
 		/*
 			When mounting a umsdos fs as root, we detect
@@ -973,13 +973,14 @@
 			current->fs->pwd  = pseudo_root;
 		}
 	}
-	#endif
+#endif
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	root_mountflags = real_root_mountflags;
 	if (mount_initrd && ROOT_DEV != real_root_dev && ROOT_DEV == MKDEV(RAMDISK_MAJOR,0)) {
 		int error;
-
+		int pid,i;
+		
 		pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 		if (pid>0)
 			while (pid != wait(&i));
@@ -1012,10 +1013,11 @@
 	 * trying to recover a really broken machine.
 	 */
 
-	execve(execute_command,argv_init,envp_init);
+	if (execute_command)
+		execve(execute_command,argv_init,envp_init);
+	execve("/sbin/init",argv_init,envp_init);
 	execve("/etc/init",argv_init,envp_init);
 	execve("/bin/init",argv_init,envp_init);
-	execve("/sbin/init",argv_init,envp_init);
 	execve("/bin/sh",argv_init,envp_init);
 	panic("No init found.  Try passing init= option to kernel.");
 }
diff -u --recursive --new-file v2.1.21/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.21/linux/kernel/sched.c	Tue Nov 19 15:53:59 1996
+++ linux/kernel/sched.c	Thu Jan 16 04:47:21 1997
@@ -4,6 +4,8 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  1996-04-21	Modified by Ulrich Windl to make NTP work
+ *  1996-12-23  Modified by Dave Grothe to fix bugs in semaphores and
+ *              make semaphores SMP safe
  */
 
 /*
@@ -482,32 +484,48 @@
 	printk("       *q = %p\n",*q);
 }
 
+
 /*
  * Semaphores are implemented using a two-way counter:
  * The "count" variable is decremented for each process
- * that tries to sleep, while the "waiting" variable is
- * incremented _while_ the process is sleeping on that
- * semaphore. 
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
  *
  * Notably, the inline "up()" and "down()" functions can
  * efficiently test if they need to do any extra work (up
  * needs to do something only if count was negative before
  * the increment operation.
+ *
+ * This routine must execute atomically.
  */
-static inline void normalize_semaphore(struct semaphore *sem)
+static inline int waking_non_zero(struct semaphore *sem)
 {
-	atomic_add(xchg(&sem->waiting,0), &sem->count);
+	int ret;
+	long flags;
+
+	save_flags(flags);
+	cli();
+
+	ret = 0;
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	}
+
+	restore_flags(flags);
+	return ret;
 }
 
 /*
  * When __up() is called, the count was negative before
- * incrementing it, and we need to wake up somebody. In
- * most cases "waiting" will be positive, and the normalization
- * will allow things to continue. However, if somebody has
- * /just/ done a down(), it may be that count was negative
- * without waiting being positive (or in the generic case
- * "count is more negative than waiting is positive"), and
- * the waiter needs to check this itself (see __down).
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
  *
  * Note that these functions are only called when there is
  * contention on the lock, and as such all this is the
@@ -517,54 +535,82 @@
  */
 void __up(struct semaphore *sem)
 {
-	normalize_semaphore(sem);
+	atomic_inc(&sem->waking);
 	wake_up(&sem->wait);
 }
 
-void __down(struct semaphore * sem)
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+static inline int __do_down(struct semaphore * sem, int task_state)
 {
 	struct task_struct *tsk = current;
 	struct wait_queue wait = { tsk, NULL };
+	int		  ret = 0;
 
-	/*
-	 * The order here is important. We add ourselves to the
-	 * wait queues and mark ourselves sleeping _first_. That
-	 * way, if a "up()" comes in here, we'll either get
-	 * woken up (up happens after the wait queues are set up)
-	 * OR we'll have "waiting > 0".
-	 */
-	tsk->state = TASK_UNINTERRUPTIBLE;
+	tsk->state = task_state;
 	add_wait_queue(&sem->wait, &wait);
-	atomic_inc(&sem->waiting);
 
 	/*
-	 * Ok, we're set up. The only race here is really that
-	 * an "up()" might have incremented count before we got
-	 * here, so we check "count+waiting". If that is larger
-	 * than zero, we shouldn't sleep, but re-try the lock.
+	 * Ok, we're set up.  sem->count is known to be less than zero
+	 * so we must wait.
+	 *
+	 * We can let go the lock for purposes of waiting.
+	 * We re-acquire it after awaking so as to protect
+	 * all semaphore operations.
+	 *
+	 * If "up()" is called before we call waking_non_zero() then
+	 * we will catch it right away.  If it is called later then
+	 * we will have to go through a wakeup cycle to catch it.
+	 *
+	 * Multiple waiters contend for the semaphore lock to see
+	 * who gets to gate through and who has to wait some more.
 	 */
-	if (sem->count+sem->waiting <= 0) {
-		/*
-		 * If "count+waiting" <= 0, we have to wait
-		 * for a up(), which will normalize the count.
-		 * Remember, at this point we have decremented
-		 * count, and incremented up, so if count is
-		 * zero or positive we need to return to re-try
-		 * the lock.  It _may_ be that both count and
-		 * waiting is zero and that it is still locked,
-		 * but we still want to re-try the lock in that
-		 * case to make count go negative again so that
-		 * the optimized "up()" wake_up sequence works.
-		 */
-		do {
-			schedule();
-			tsk->state = TASK_UNINTERRUPTIBLE;
-		} while (sem->count < 0);
+	for (;;) {
+		if (waking_non_zero(sem))	/* are we waking up?  */
+			break;			/* yes, exit loop */
+
+		if (   task_state == TASK_INTERRUPTIBLE
+		    && (tsk->signal & ~tsk->blocked)	/* signalled */
+		   ) {
+			ret = -EINTR;			/* interrupted */
+			atomic_inc(&sem->count);	/* give up on down operation */
+			break;
+		}
+
+		schedule();
+		tsk->state = task_state;
 	}
+
 	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&sem->wait, &wait);
-	normalize_semaphore(sem);
+	return ret;
 }
+
+void __down(struct semaphore * sem)
+{
+	__do_down(sem,TASK_UNINTERRUPTIBLE);
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+	return __do_down(sem,TASK_INTERRUPTIBLE);
+}
+
 
 static inline void __sleep_on(struct wait_queue **p, int state)
 {
diff -u --recursive --new-file v2.1.21/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.21/linux/kernel/sys.c	Sun Dec 22 16:37:42 1996
+++ linux/kernel/sys.c	Wed Jan 15 02:46:07 1997
@@ -182,7 +182,7 @@
 #ifdef __sparc__
 extern void halt_now(void);
 #endif
-extern asmlinkage sys_kill(int, int);
+extern asmlinkage int sys_kill(int, int);
 
 /*
  * Reboot system call: for obvious reasons only root may call it,
diff -u --recursive --new-file v2.1.21/linux/net/802/Makefile linux/net/802/Makefile
--- v2.1.21/linux/net/802/Makefile	Thu Dec 12 19:37:21 1996
+++ linux/net/802/Makefile	Sun Jan 19 15:47:27 1997
@@ -12,8 +12,8 @@
 
 ifeq ($(CONFIG_LLC),y)
 SUB_DIRS += transit
-O_OBJS += llc_macinit.o llc_sendpdu.o llc_utility.o cl2llc.o
-
+O_OBJS += llc_sendpdu.o llc_utility.o cl2llc.o
+OX_OBJS += llc_macinit.o 
 
 endif
 
diff -u --recursive --new-file v2.1.21/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c
--- v2.1.21/linux/net/802/llc_macinit.c	Thu Jan  2 15:55:26 1997
+++ linux/net/802/llc_macinit.c	Sun Jan 19 15:47:27 1997
@@ -19,6 +19,7 @@
  *					Started restructuring handlers
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.1.21/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.21/linux/net/appletalk/ddp.c	Thu Jan  2 15:55:26 1997
+++ linux/net/appletalk/ddp.c	Sun Jan 19 15:47:27 1997
@@ -248,6 +248,7 @@
 		{
 			*iface = tmp->next;
 			kfree_s(tmp, sizeof(struct atalk_iface));
+			dev->atalk_ptr=NULL;
 		}
 		else
 			iface = &tmp->next;
@@ -262,6 +263,7 @@
 	if(iface==NULL)
 		return NULL;
 	iface->dev=dev;
+	dev->atalk_ptr=iface;
 	iface->address= *sa;
 	iface->status=0;
 	save_flags(flags);
@@ -377,10 +379,9 @@
 
 struct at_addr *atalk_find_dev_addr(struct device *dev)
 {
-	struct atalk_iface *iface;
-	for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
-		if(iface->dev==dev)
-			return &iface->address;
+	struct atalk_iface *iface=dev->atalk_ptr;
+	if(iface)
+		return &iface->address;
 	return NULL;
 }
 
@@ -390,24 +391,10 @@
 	for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
 		if(!(iface->dev->flags&IFF_LOOPBACK))
 			return &iface->address;
-	if ( atalk_iface_list != NULL ) {
-	    return &atalk_iface_list->address;
-	} else {
-	    return NULL;
-	}
-}
-
-/*
- *	Give a device find its atif control structure
- */
-
-struct atalk_iface *atalk_find_dev(struct device *dev)
-{
-	struct atalk_iface *iface;
-	for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
-		if(iface->dev==dev)
-			return iface;
-	return NULL;
+	if ( atalk_iface_list != NULL )
+		return &atalk_iface_list->address;
+	else
+		return NULL;
 }
 
 /*
@@ -472,7 +459,7 @@
 
 /*
  *	Given an appletalk network find the device to use. This can be
- *	a simple lookup. Funny stuff like routers can wait 8)
+ *	a simple lookup.
  */
 
 static struct device *atrtr_get_dev(struct at_addr *sa)
@@ -925,52 +912,13 @@
 }
 
 /*
- *	Generic fcntl calls are already dealt with. If we don't need funny ones
- *	this is the all you need. Async I/O is also separate.
- */
-
-static int atalk_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-/*	struct sock *sk=sock->sk;*/
-	switch(cmd)
-	{
-		default:
-			return(-EINVAL);
-	}
-}
-
-/*
  *	Set 'magic' options for appletalk. If we don't have any this is fine
  *	as it is.
  */
 
 static int atalk_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
 {
-	struct sock *sk;
-	int err,opt;
-
-	sk=sock->sk;
-
-	if(optval==NULL)
-		return(-EINVAL);
-
-	err = get_user(opt, (int *)optval);
-	if (err)
-		return err;
-
-	switch(level)
-	{
-		case SOL_ATALK:
-			switch(optname)
-			{
-				default:
-					return -EOPNOTSUPP;
-			}
-			break;
-
-		default:
-			return -EOPNOTSUPP;
-	}
+	return -EOPNOTSUPP;
 }
 
 
@@ -981,30 +929,7 @@
 static int atalk_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
-	int val=0;
-	int err;
-
-	sk=sock->sk;
-
-	switch(level)
-	{
-
-		case SOL_ATALK:
-			switch(optname)
-			{
-				default:
-					return -ENOPROTOOPT;
-			}
-			break;
-
-		default:
-			return -EOPNOTSUPP;
-	}
-	err = put_user(sizeof(int),optlen);
-	if (!err)
-		err = put_user(val, (int *) optval);
-	return err;
+	return -ENOPROTOOPT;
 }
 
 /*
@@ -1017,34 +942,6 @@
 }
 
 /*
- *	These are standard.
- */
-
-static void def_callback1(struct sock *sk)
-{
-	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
-	}
-}
-
-static void def_callback3(struct sock *sk)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
-	}
-}
-
-/*
  *	Create a socket. Initialise the socket, blank the addresses
  *	set the state.
  */
@@ -1071,32 +968,10 @@
 
 	MOD_INC_USE_COUNT;
 
-	sk->no_check=0;		/* Checksums on by default */
-	sk->allocation=GFP_KERNEL;
-	sk->rcvbuf=SK_RMEM_MAX;
-	sk->sndbuf=SK_WMEM_MAX;
-	sk->pair=NULL;
-	sk->priority=1;
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-	sk->state=TCP_CLOSE;
-	sk->socket=sock;
-	sk->type=sock->type;
-
+	sock_init_data(sock,sk);
+	
+	/* Checksums on by default */
 	sk->mtu=DDP_MAXSZ;
-
-	if(sock!=NULL)
-	{
-		sk->sleep=&sock->wait;
-		sock->sk=sk;
-	}
-
-	sk->state_change=def_callback1;
-	sk->data_ready=def_callback2;
-	sk->write_space=def_callback3;
-	sk->error_report=def_callback1;
-
 	sk->zapped=1;
 	return(0);
 }
@@ -1909,7 +1784,7 @@
 	atalk_shutdown,
 	atalk_setsockopt,
 	atalk_getsockopt,
-	atalk_fcntl,
+	sock_no_fcntl,
 	atalk_sendmsg,
 	atalk_recvmsg
 };
diff -u --recursive --new-file v2.1.21/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.21/linux/net/ax25/af_ax25.c	Thu Jan  2 15:55:26 1997
+++ linux/net/ax25/af_ax25.c	Sun Jan 19 15:47:27 1997
@@ -90,6 +90,8 @@
  *						format.
  *			Hans(PE1AYX)		Fixed interface to IP layer.
  *			Alan(GW4PTS)		Added asynchronous support.
+ *			Frederic(F1OAT)		Support for pseudo-digipeating.
+ *			Jonathan(G4KLX)		Support for packet forwarding.
  *
  *	To do:
  *		Restructure the ax25_rcv code to be cleaner/faster and
@@ -136,7 +138,7 @@
  */
 ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
 
-ax25_cb *volatile ax25_list = NULL;
+ax25_cb *ax25_list = NULL;
 
 static struct proto_ops ax25_proto_ops;
 
@@ -228,6 +230,26 @@
 }
 
 /*
+ *	Compare two AX.25 digipeater paths.
+ */
+static int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2)
+{
+	int i;
+
+	if (digi1->ndigi != digi2->ndigi)
+		return 1;
+
+	if (digi1->lastrepeat != digi2->lastrepeat)
+		return 1;
+
+	for (i = 0; i < digi1->ndigi; i++)
+		if (ax25cmp(&digi1->calls[i], &digi2->calls[i]) != 0)
+			return 1;
+
+	return 0;
+}
+
+/*
  *	Free an allocated ax25 control block. This is done to centralise
  *	the MOD count code.
  */
@@ -343,7 +365,7 @@
  *	Find a socket that wants to accept the SABM we have just
  *	received.
  */
-static struct sock *ax25_find_listener(ax25_address *addr, struct device *dev, int type)
+static struct sock *ax25_find_listener(ax25_address *addr, int digi, struct device *dev, int type)
 {
 	unsigned long flags;
 	ax25_cb *s;
@@ -352,6 +374,8 @@
 	cli();
 
 	for (s = ax25_list; s != NULL; s = s->next) {
+		if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
+			continue;
 		if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) {
 			/* If device is null we match any device */
 			if (s->device == NULL || s->device == dev) {
@@ -393,7 +417,7 @@
  *	floating AX.25 control blocks or non Raw socket bound control blocks.
  */
 
-static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, struct device *dev)
+static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
 {
 	ax25_cb *s;
 	unsigned long flags;
@@ -405,6 +429,12 @@
 		if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
 			continue;
 		if (ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->device == dev) {
+			if (digi != NULL) {
+				if (s->digipeat == NULL && digi->ndigi != 0)
+					continue;
+				if (s->digipeat != NULL && ax25digicmp(s->digipeat, digi) != 0)
+					continue;
+			}
 			restore_flags(flags);
 			return s;
 		}
@@ -418,7 +448,6 @@
 /*
  *	Look for any matching address - RAW sockets can bind to arbitrary names
  */
-
 static struct sock *ax25_addr_match(ax25_address *addr)
 {
 	unsigned long flags;
@@ -615,13 +644,13 @@
 	if ((dev = ax25rtr_get_dev(&ax25_ctl.port_addr)) == NULL)
 		return -ENODEV;
 
-	if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, dev)) == NULL)
+	if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, NULL, dev)) == NULL)
 		return -ENOTCONN;
 
 	switch (ax25_ctl.cmd) {
 		case AX25_KILL:
 			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 
 			ax25->state = AX25_STATE_0;
 			if (ax25->sk != NULL) {
@@ -638,7 +667,7 @@
 	  		break;
 
 	  	case AX25_WINDOW:
-	  		if (ax25->modulus == MODULUS) {
+	  		if (ax25->modulus == AX25_MODULUS) {
 	  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
 	  				return -EINVAL;
 	  		} else {
@@ -651,8 +680,8 @@
 	  	case AX25_T1:
   			if (ax25_ctl.arg < 1)
   				return -EINVAL;
-  			ax25->rtt = (ax25_ctl.arg * PR_SLOWHZ) / 2;
-  			ax25->t1 = ax25_ctl.arg * PR_SLOWHZ;
+  			ax25->rtt = (ax25_ctl.arg * AX25_SLOWHZ) / 2;
+  			ax25->t1 = ax25_ctl.arg * AX25_SLOWHZ;
   			save_flags(flags); cli();
   			if (ax25->t1timer > ax25->t1)
   				ax25->t1timer = ax25->t1;
@@ -663,7 +692,7 @@
 	  		if (ax25_ctl.arg < 1)
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		ax25->t2 = ax25_ctl.arg * PR_SLOWHZ;
+	  		ax25->t2 = ax25_ctl.arg * AX25_SLOWHZ;
 	  		if (ax25->t2timer > ax25->t2)
 	  			ax25->t2timer = ax25->t2;
 	  		restore_flags(flags);
@@ -680,7 +709,7 @@
 	  		if (ax25_ctl.arg < 0)
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		ax25->t3 = ax25_ctl.arg * PR_SLOWHZ;
+	  		ax25->t3 = ax25_ctl.arg * AX25_SLOWHZ;
 	  		if (ax25->t3timer != 0)
 	  			ax25->t3timer = ax25->t3;
 	  		restore_flags(flags);
@@ -690,7 +719,7 @@
 	  		if (ax25_ctl.arg < 0)
 	  			return -EINVAL;
 			save_flags(flags); cli();
-	  		ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60;
+	  		ax25->idle = ax25_ctl.arg * AX25_SLOWHZ * 60;
 	  		if (ax25->idletimer != 0)
 	  			ax25->idletimer = ax25->idle;
 	  		restore_flags(flags);
@@ -750,10 +779,10 @@
 	ax25->idle    = AX25_DEF_IDLE;
 
 	if (AX25_DEF_AXDEFMODE) {
-		ax25->modulus = EMODULUS;
+		ax25->modulus = AX25_EMODULUS;
 		ax25->window  = AX25_DEF_EWINDOW;
 	} else {
-		ax25->modulus = MODULUS;
+		ax25->modulus = AX25_MODULUS;
 		ax25->window  = AX25_DEF_WINDOW;
 	}
 
@@ -802,10 +831,10 @@
 	ax25->idle     = ax25_dev_get_value(dev, AX25_VALUES_IDLE);
 
 	if (ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE)) {
-		ax25->modulus = EMODULUS;
+		ax25->modulus = AX25_EMODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW);
 	} else {
-		ax25->modulus = MODULUS;
+		ax25->modulus = AX25_MODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_WINDOW);
 	}
 
@@ -914,19 +943,13 @@
  *	Handling for system calls applied via the various interfaces to an
  *	AX25 socket object
  */
-static int ax25_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
 
 static int ax25_setsockopt(struct socket *sock, int level, int optname,
 	char *optval, int optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int err, opt;
 
-	sk = (struct sock *)sock->sk;
-
 	if (level != SOL_AX25)
 		return -EOPNOTSUPP;
 
@@ -940,7 +963,7 @@
 
 	switch (optname) {
 		case AX25_WINDOW:
-			if (sk->protinfo.ax25->modulus == MODULUS) {
+			if (sk->protinfo.ax25->modulus == AX25_MODULUS) {
 				if (opt < 1 || opt > 7)
 					return -EINVAL;
 			} else {
@@ -953,13 +976,13 @@
 		case AX25_T1:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.ax25->rtt = (opt * PR_SLOWHZ) / 2;
+			sk->protinfo.ax25->rtt = (opt * AX25_SLOWHZ) / 2;
 			return 0;
 
 		case AX25_T2:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.ax25->t2 = opt * PR_SLOWHZ;
+			sk->protinfo.ax25->t2 = opt * AX25_SLOWHZ;
 			return 0;
 
 		case AX25_N2:
@@ -971,13 +994,13 @@
 		case AX25_T3:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.ax25->t3 = opt * PR_SLOWHZ;
+			sk->protinfo.ax25->t3 = opt * AX25_SLOWHZ;
 			return 0;
 
 		case AX25_IDLE:
 			if (opt < 0)
 				return -EINVAL;
-			sk->protinfo.ax25->idle = opt * PR_SLOWHZ * 60;
+			sk->protinfo.ax25->idle = opt * AX25_SLOWHZ * 60;
 			return 0;
 
 		case AX25_BACKOFF:
@@ -985,13 +1008,17 @@
 			return 0;
 
 		case AX25_EXTSEQ:
-			sk->protinfo.ax25->modulus = opt ? EMODULUS : MODULUS;
+			sk->protinfo.ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
 			return 0;
 
 		case AX25_HDRINCL:
 			sk->protinfo.ax25->hdrincl = opt ? 1 : 0;
 			return 0;
 
+		case AX25_IAMDIGI:
+			sk->protinfo.ax25->iamdigi = opt ? 1 : 0;
+			return 0;
+
 		case AX25_PACLEN:
 			if (opt < 16 || opt > 65535)
 				return -EINVAL;
@@ -1006,12 +1033,10 @@
 static int ax25_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int val = 0;
 	int err;
 
-	sk = (struct sock *)sock->sk;
-
 	if (level != SOL_AX25)
 		return -EOPNOTSUPP;
 
@@ -1021,11 +1046,11 @@
 			break;
 
 		case AX25_T1:
-			val = (sk->protinfo.ax25->t1 * 2) / PR_SLOWHZ;
+			val = (sk->protinfo.ax25->t1 * 2) / AX25_SLOWHZ;
 			break;
 
 		case AX25_T2:
-			val = sk->protinfo.ax25->t2 / PR_SLOWHZ;
+			val = sk->protinfo.ax25->t2 / AX25_SLOWHZ;
 			break;
 
 		case AX25_N2:
@@ -1033,11 +1058,11 @@
 			break;
 
 		case AX25_T3:
-			val = sk->protinfo.ax25->t3 / PR_SLOWHZ;
+			val = sk->protinfo.ax25->t3 / AX25_SLOWHZ;
 			break;
 
 		case AX25_IDLE:
-			val = sk->protinfo.ax25->idle / (PR_SLOWHZ * 60);
+			val = sk->protinfo.ax25->idle / (AX25_SLOWHZ * 60);
 			break;
 
 		case AX25_BACKOFF:
@@ -1045,13 +1070,17 @@
 			break;
 
 		case AX25_EXTSEQ:
-			val = (sk->protinfo.ax25->modulus == EMODULUS);
+			val = (sk->protinfo.ax25->modulus == AX25_EMODULUS);
 			break;
 
 		case AX25_HDRINCL:
 			val = sk->protinfo.ax25->hdrincl;
 			break;
 
+		case AX25_IAMDIGI:
+			val = sk->protinfo.ax25->iamdigi;
+			break;
+
 		case AX25_PACLEN:
 			val = sk->protinfo.ax25->paclen;
 			break;
@@ -1075,7 +1104,7 @@
 
 static int ax25_listen(struct socket *sock, int backlog)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
 		sk->max_ack_backlog = backlog;
@@ -1086,30 +1115,6 @@
 	return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if (!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if (!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
-	}
-}
-
-static void def_callback3(struct sock *sk, int len)
-{
-	if (!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,2);
-	}
-}
-
 static int ax25_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -1131,13 +1136,23 @@
 				case AX25_P_ARP:
 				case AX25_P_IP:
 #endif
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#ifdef CONFIG_NETROM
 				case AX25_P_NETROM:
 #endif
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+#ifdef CONFIG_ROSE
 				case AX25_P_ROSE:
 #endif
 					return -ESOCKTNOSUPPORT;
+#ifdef CONFIG_NETROM_MODULE
+				case AX25_P_NETROM:
+					if (ax25_protocol_is_registered(AX25_P_NETROM))
+						return -ESOCKTNOSUPPORT;
+#endif
+#ifdef CONFIG_ROSE_MODULE
+				case AX25_P_ROSE:
+					if (ax25_protocol_is_registered(AX25_P_ROSE))
+						return -ESOCKTNOSUPPORT;
+#endif
 				default:
 					break;
 			}
@@ -1156,33 +1171,12 @@
 		return -ENOMEM;
 	}
 
+	sock_init_data(sock,sk);
+	
 	sock->ops = &ax25_proto_ops;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	sk->socket        = sock;
-	sk->type          = sock->type;
 	sk->protocol      = protocol;
-	sk->next          = NULL;
-	sk->allocation	  = GFP_KERNEL;
-	sk->rcvbuf        = SK_RMEM_MAX;
-	sk->sndbuf        = SK_WMEM_MAX;
-	sk->state         = TCP_CLOSE;
-	sk->priority      = SOPRI_NORMAL;
 	sk->mtu           = AX25_MTU;	/* 256 */
-	sk->zapped        = 1;
-
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
-	if (sock != NULL) {
-		sock->sk  = sk;
-		sk->sleep = &sock->wait;
-	}
 
 	ax25->sk          = sk;
 	sk->protinfo.ax25 = ax25;
@@ -1219,11 +1213,8 @@
 			return NULL;
 	}
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	sk->next        = NULL;
+	sock_init_data(NULL,sk);
+	
 	sk->priority    = osk->priority;
 	sk->protocol    = osk->protocol;
 	sk->rcvbuf      = osk->rcvbuf;
@@ -1234,14 +1225,10 @@
 	sk->sleep       = osk->sleep;
 	sk->zapped      = osk->zapped;
 
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
 	ax25->modulus = osk->protinfo.ax25->modulus;
 	ax25->backoff = osk->protinfo.ax25->backoff;
 	ax25->hdrincl = osk->protinfo.ax25->hdrincl;
+	ax25->iamdigi = osk->protinfo.ax25->iamdigi;
 	ax25->rtt     = osk->protinfo.ax25->rtt;
 	ax25->t1      = osk->protinfo.ax25->t1;
 	ax25->t2      = osk->protinfo.ax25->t2;
@@ -1273,14 +1260,17 @@
 
 static int ax25_dup(struct socket *newsock, struct socket *oldsock)
 {
-	struct sock *sk = (struct sock *)oldsock->sk;
+	struct sock *sk = oldsock->sk;
+
+	if (sk == NULL || newsock == NULL)
+		return -EINVAL;
 
 	return ax25_create(newsock, sk->protocol);
 }
 
 static int ax25_release(struct socket *sock, struct socket *peer)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk == NULL) return 0;
 
@@ -1295,7 +1285,7 @@
 				break;
 
 			case AX25_STATE_1:
-				ax25_send_control(sk->protinfo.ax25, DISC, POLLON, C_COMMAND);
+				ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 				sk->protinfo.ax25->state = AX25_STATE_0;
 				sk->state                = TCP_CLOSE;
 				sk->shutdown            |= SEND_SHUTDOWN;
@@ -1306,9 +1296,9 @@
 
 			case AX25_STATE_2:
 				if (sk->protinfo.ax25->dama_slave)
-					ax25_send_control(sk->protinfo.ax25, DISC, POLLON, C_COMMAND);
+					ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 				else
-					ax25_send_control(sk->protinfo.ax25, DM, POLLON, C_RESPONSE);
+					ax25_send_control(sk->protinfo.ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
 				sk->protinfo.ax25->state = AX25_STATE_0;
 				sk->state                = TCP_CLOSE;
 				sk->shutdown            |= SEND_SHUTDOWN;
@@ -1322,7 +1312,7 @@
 				ax25_clear_queues(sk->protinfo.ax25);
 				sk->protinfo.ax25->n2count = 0;
 				if (!sk->protinfo.ax25->dama_slave) {
-					ax25_send_control(sk->protinfo.ax25, DISC, POLLON, C_COMMAND);
+					ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 					sk->protinfo.ax25->t3timer = 0;
 				} else {
 					sk->protinfo.ax25->t3timer = sk->protinfo.ax25->t3;	/* DAMA slave timeout */
@@ -1358,24 +1348,23 @@
  *	digipeated via a local address as source. This is a hack until we add
  *	BSD 4.4 ADDIFADDR type support. It is however small and trivially backward
  *	compatible 8)
- *
- *	FIXME: Check family
  */
 static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
 	struct device *dev;
 	ax25_address *call;
 
-	sk = (struct sock *)sock->sk;
-
 	if (sk->zapped == 0)
 		return -EINVAL;
 
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
+	if (addr->fsa_ax25.sax25_family != AF_AX25)
+		return -EINVAL;
+
 	call = ax25_findbyuid(current->euid);
 	if (call == NULL && ax25_uid_policy && !suser())
 		return -EACCES;
@@ -1424,14 +1413,12 @@
 }
 
 /*
- *	FIXME: nonblock behaviour looks like it may have a bug. Also check
- *	the family in the connect.
+ *	FIXME: nonblock behaviour looks like it may have a bug.
  */
- 
 static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
 	int addr_len, int flags)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
 	int err;
 
@@ -1454,6 +1441,9 @@
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
+	if (addr->sax25_family != AF_AX25)
+		return -EINVAL;
+
 	/*
 	 *	Handle digi-peaters to be used.
 	 */
@@ -1470,15 +1460,19 @@
 				return -ENOBUFS;
 		}
 
-		sk->protinfo.ax25->digipeat->ndigi = addr->sax25_ndigis;
+		sk->protinfo.ax25->digipeat->ndigi      = addr->sax25_ndigis;
+		sk->protinfo.ax25->digipeat->lastrepeat = -1;
 
 		while (ct < addr->sax25_ndigis) {
-			sk->protinfo.ax25->digipeat->repeated[ct] = 0;
+			if ((fsa->fsa_digipeater[ct].ax25_call[6] & AX25_HBIT) && sk->protinfo.ax25->iamdigi) {
+				sk->protinfo.ax25->digipeat->repeated[ct] = 1;
+				sk->protinfo.ax25->digipeat->lastrepeat   = ct;
+			} else {
+				sk->protinfo.ax25->digipeat->repeated[ct] = 0;
+			}
 			sk->protinfo.ax25->digipeat->calls[ct]    = fsa->fsa_digipeater[ct];
 			ct++;
 		}
-
-		sk->protinfo.ax25->digipeat->lastrepeat = 0;
 	}
 
 	/*
@@ -1496,7 +1490,7 @@
 			return -EHOSTUNREACH;
 	}
 
-	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, sk->protinfo.ax25->device) != NULL)
+	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, NULL, sk->protinfo.ax25->device) != NULL)
 		return -EADDRINUSE;			/* Already such a connection */
 
 	sk->protinfo.ax25->dest_addr = addr->sax25_call;
@@ -1560,12 +1554,13 @@
 	struct sock *newsk;
 	struct sk_buff *skb;
 
-	if (newsock->sk)
-		sk_free(newsock->sk);
+	if (newsock->sk != NULL)
+		ax25_destroy_socket(newsock->sk->protinfo.ax25);
 
 	newsock->sk = NULL;
 
-	sk = (struct sock *)sock->sk;
+	if ((sk = sock->sk) == NULL)
+		return -EINVAL;
 
 	if (sk->type != SOCK_SEQPACKET)
 		return -EOPNOTSUPP;
@@ -1582,7 +1577,7 @@
 		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
 			if (flags & O_NONBLOCK) {
 				sti();
-				return 0;
+				return -EWOULDBLOCK;
 			}
 			interruptible_sleep_on(sk->sleep);
 			if (current->signal & ~current->blocked) {
@@ -1609,11 +1604,9 @@
 	int *uaddr_len, int peer)
 {
 	struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	unsigned char ndigi, i;
 
-	sk = (struct sock *)sock->sk;
-
 	if (peer != 0) {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
@@ -1649,9 +1642,10 @@
 	struct sock *make;
 	struct sock *sk;
 	int type = 0;
-	ax25_digi dp;
+	ax25_digi dp, reverse_dp;
 	ax25_cb *ax25;
 	ax25_address src, dest;
+	ax25_address *next_digi = NULL;
 	struct sock *raw;
 	int mine = 0;
 	int dama;
@@ -1682,6 +1676,7 @@
 	 *	Ours perhaps ?
 	 */
 	if (dp.lastrepeat + 1 < dp.ndigi) {		/* Not yet digipeated completely */
+		next_digi = &dp.calls[dp.lastrepeat + 1];
 		if (ax25cmp(&dp.calls[dp.lastrepeat + 1], dev_addr) == 0) {
 			struct device *dev_out = dev;
 
@@ -1713,7 +1708,7 @@
 				return 0;
 			}
 
-			build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS);
+			build_ax25_addr(skb->data, &src, &dest, &dp, type, AX25_MODULUS);
 #ifdef CONFIG_FIREWALL
 			if (call_fw_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) {
 				kfree_skb(skb, FREE_READ);
@@ -1724,11 +1719,9 @@
 			skb->dev = dev_out;
 			skb->priority = SOPRI_NORMAL;
 			ax25_queue_xmit(skb);
-		} else {
-			kfree_skb(skb, FREE_READ);
-		}
 
-		return 0;
+			return 0;
+		}
 	}
 
 	/*
@@ -1737,14 +1730,15 @@
 	skb_pull(skb, size_ax25_addr(&dp));
 
 	/* For our port addresses ? */
-	if (ax25cmp(&dest, dev_addr) == 0)
+	if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi)
 		mine = 1;
 
 	/* Also match on any registered callsign from L3/4 */
-	if (!mine && ax25_listen_mine(&dest, dev))
+	if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi)
 		mine = 1;
 
-	if ((*skb->data & ~0x10) == LAPB_UI) {	/* UI frame - bypass LAPB processing */
+	/* UI frame - bypass LAPB processing */
+	if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
 		skb->h.raw = skb->data + 2;		/* skip control and pid */
 
 		if ((raw = ax25_addr_match(&dest)) != NULL)
@@ -1786,8 +1780,8 @@
 						 *	Remove the control and PID.
 						 */
 						skb_pull(skb, 2);
-						skb_queue_tail(&sk->receive_queue, skb);
 						skb_set_owner_r(skb, sk);
+						skb_queue_tail(&sk->receive_queue, skb);
 						if (!sk->dead)
 							sk->data_ready(sk, skb->len);
 					}
@@ -1818,7 +1812,9 @@
 
 	/* AX.25 state 1-4 */
 
-	if ((ax25 = ax25_find_cb(&dest, &src, dev)) != NULL) {
+	ax25_digi_invert(&dp, &reverse_dp);
+
+	if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
 		/*
 		 *	Process the frame. If it is queued up internally it returns one otherwise we
 		 *	free it immediately. This routine itself wakes the user context layers so we
@@ -1834,12 +1830,12 @@
 
 	/* a) received not a SABM(E) */
 
-	if ((*skb->data & ~PF) != SABM && (*skb->data & ~PF) != SABME) {
+	if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) {
 		/*
 		 *	Never reply to a DM. Also ignore any connects for
 		 *	addresses that are not our interfaces and not a socket.
 		 */
-		if ((*skb->data & ~PF) != DM && mine)
+		if ((*skb->data & ~AX25_PF) != AX25_DM && mine)
 			ax25_return_dm(dev, &src, &dest, &dp);
 
 		kfree_skb(skb, FREE_READ);
@@ -1848,7 +1844,12 @@
 
 	/* b) received SABM(E) */
 
-	if ((sk = ax25_find_listener(&dest, dev, SOCK_SEQPACKET)) != NULL) {
+	if (dp.lastrepeat + 1 == dp.ndigi)
+		sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET);
+	else
+		sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
+
+	if (sk != NULL) {
 		if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) {
 			if (mine)
 				ax25_return_dm(dev, &src, &dest, &dp);
@@ -1901,20 +1902,20 @@
 		}
 	} else {
 		/* Reverse the source SABM's path */
-		ax25_digi_invert(&dp, ax25->digipeat);
+		*ax25->digipeat = reverse_dp;
 	}
 
-	if ((*skb->data & ~PF) == SABME) {
-		ax25->modulus = EMODULUS;
+	if ((*skb->data & ~AX25_PF) == AX25_SABME) {
+		ax25->modulus = AX25_EMODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW);
 	} else {
-		ax25->modulus = MODULUS;
+		ax25->modulus = AX25_MODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_WINDOW);
 	}
 
 	ax25->device = dev;
 
-	ax25_send_control(ax25, UA, POLLON, C_RESPONSE);
+	ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE);
 
 	if (dama) ax25_dama_on(ax25);	/* bke 951121 */
 
@@ -1957,7 +1958,7 @@
 static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 	struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
 	int err;
 	struct sockaddr_ax25 sax;
@@ -1968,21 +1969,21 @@
 	ax25_digi dtmp;
 	int lv;
 	int addr_len = msg->msg_namelen;
-	
+
 	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
 	if (sk->zapped)
 		return -EADDRNOTAVAIL;
-		
+
 	if (sk->shutdown & SEND_SHUTDOWN) {
 		send_sig(SIGPIPE, current, 0);
 		return -EPIPE;
 	}
-		
+
 	if (sk->protinfo.ax25->device == NULL)
 		return -ENETUNREACH;
-		
+
 	if (usax) {
 		if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 			return -EINVAL;
@@ -2040,8 +2041,7 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->sk   = sk;
-	skb->arp  = 1;
+	skb->arp = 1;
 
 	skb_reserve(skb, size - len);
 
@@ -2078,7 +2078,7 @@
 		}
 
 		/* Build an AX.25 header */
-		asmptr += (lv = build_ax25_addr(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, C_COMMAND, MODULUS));
+		asmptr += (lv = build_ax25_addr(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS));
 
 		if (sk->debug)
 			printk("Built header (%d bytes)\n",lv);
@@ -2088,7 +2088,7 @@
 		if (sk->debug)
 			printk("base=%p pos=%p\n", skb->data, asmptr);
 
-		*asmptr = LAPB_UI;
+		*asmptr = AX25_UI;
 
 		/* Datagram frames go straight out of the door as UI */
 		skb->dev      = sk->protinfo.ax25->device;
@@ -2104,7 +2104,7 @@
 static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags,
 	struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
 	int copied, length;
 	struct sk_buff *skb;
@@ -2179,7 +2179,8 @@
 
 static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
+	struct ax25_info_struct ax25_info;
 	int err;
 	long amount = 0;
 
@@ -2248,6 +2249,36 @@
 				return -EPERM;
 			return ax25_ctl_ioctl(cmd, (void *)arg);
 
+		case SIOCAX25GETINFO:
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(ax25_info))) != 0)
+				return err;
+			ax25_info.t1        = sk->protinfo.ax25->t1;
+			ax25_info.t2        = sk->protinfo.ax25->t2;
+			ax25_info.t3        = sk->protinfo.ax25->t3;
+			ax25_info.idle      = sk->protinfo.ax25->idle;
+			ax25_info.n2        = sk->protinfo.ax25->n2;
+			ax25_info.t1timer   = sk->protinfo.ax25->t1timer;
+			ax25_info.t2timer   = sk->protinfo.ax25->t2timer;
+			ax25_info.t3timer   = sk->protinfo.ax25->t3timer;
+			ax25_info.idletimer = sk->protinfo.ax25->idletimer;
+			ax25_info.n2count   = sk->protinfo.ax25->n2count;
+			ax25_info.state     = sk->protinfo.ax25->state;
+			ax25_info.rcv_q     = sk->rmem_alloc;
+			ax25_info.snd_q     = sk->wmem_alloc;
+			copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info));
+			return 0;
+
+		case SIOCAX25ADDFWD:
+		case SIOCAX25DELFWD: {
+			struct ax25_fwd_struct ax25_fwd;
+			if (!suser())
+				return -EPERM;
+			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_fwd))) != 0)
+				return err;
+			copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd));
+			return ax25_fwd_ioctl(cmd, &ax25_fwd);
+		}
+
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -2294,16 +2325,16 @@
 			ax2asc(&ax25->source_addr), devname,
 			ax25->state,
 			ax25->vs, ax25->vr, ax25->va,
-			ax25->t1timer / PR_SLOWHZ,
-			ax25->t1      / PR_SLOWHZ,
-			ax25->t2timer / PR_SLOWHZ,
-			ax25->t2      / PR_SLOWHZ,
-			ax25->t3timer / PR_SLOWHZ,
-			ax25->t3      / PR_SLOWHZ,
-			ax25->idletimer / (PR_SLOWHZ * 60),
-			ax25->idle      / (PR_SLOWHZ * 60),
+			ax25->t1timer / AX25_SLOWHZ,
+			ax25->t1      / AX25_SLOWHZ,
+			ax25->t2timer / AX25_SLOWHZ,
+			ax25->t2      / AX25_SLOWHZ,
+			ax25->t3timer / AX25_SLOWHZ,
+			ax25->t3      / AX25_SLOWHZ,
+			ax25->idletimer / (AX25_SLOWHZ * 60),
+			ax25->idle      / (AX25_SLOWHZ * 60),
 			ax25->n2count, ax25->n2,
-			ax25->rtt     / PR_SLOWHZ,
+			ax25->rtt     / AX25_SLOWHZ,
 			ax25->window,
 			ax25->paclen);
 
@@ -2360,7 +2391,7 @@
 	ax25_shutdown,
 	ax25_setsockopt,
 	ax25_getsockopt,
-	ax25_fcntl,
+	sock_no_fcntl,
 	ax25_sendmsg,
 	ax25_recvmsg
 };
@@ -2384,7 +2415,6 @@
 
 EXPORT_SYMBOL(ax25_encapsulate);
 EXPORT_SYMBOL(ax25_rebuild_header);
-#if defined(CONFIG_NETROM_MODULE) || defined(CONFIG_ROSE_MODULE)
 EXPORT_SYMBOL(ax25_findbyuid);
 EXPORT_SYMBOL(ax25_link_up);
 EXPORT_SYMBOL(ax25_linkfail_register);
@@ -2399,7 +2429,6 @@
 EXPORT_SYMBOL(ax2asc);
 EXPORT_SYMBOL(asc2ax);
 EXPORT_SYMBOL(null_ax25_address);
-#endif
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_ax25_route = {
@@ -2440,7 +2469,8 @@
 }
 
 /*
- *	A small shim to dev_queue_xmit to add the KISS control byte.
+ *	A small shim to dev_queue_xmit to add the KISS control byte, and do
+ *	any packet forwarding in operation.
  */
 void ax25_queue_xmit(struct sk_buff *skb)
 {
@@ -2454,6 +2484,7 @@
 #endif
 
 	skb->protocol = htons(ETH_P_AX25);
+	skb->dev      = ax25_fwd_dev(skb->dev);
 
 	ptr = skb_push(skb, 1);
 	*ptr++ = 0;			/* KISS */
@@ -2482,9 +2513,9 @@
 	if (daddr != NULL)
 		memcpy(buff, daddr, dev->addr_len);	/* Address specified */
 
-  	buff[6] &= ~LAPB_C;
-  	buff[6] &= ~LAPB_E;
-  	buff[6] |= SSSID_SPARE;
+  	buff[6] &= ~AX25_CBIT;
+  	buff[6] &= ~AX25_EBIT;
+  	buff[6] |= AX25_SSSID_SPARE;
   	buff += AX25_ADDR_LEN;
 
   	if (saddr != NULL)
@@ -2492,19 +2523,18 @@
   	else
   		memcpy(buff, dev->dev_addr, dev->addr_len);
 
-  	buff[6] &= ~LAPB_C;
-  	buff[6] |= LAPB_E;
-  	buff[6] |= SSSID_SPARE;
+  	buff[6] &= ~AX25_CBIT;
+  	buff[6] |= AX25_EBIT;
+  	buff[6] |= AX25_SSSID_SPARE;
   	buff   += AX25_ADDR_LEN;
 
-  	*buff++ = LAPB_UI;	/* UI */
+  	*buff++ = AX25_UI;	/* UI */
 
   	/* Append a suitable AX.25 PID */
   	switch (type) {
   		case ETH_P_IP:
   			*buff++ = AX25_P_IP;
  			break;
-
   		case ETH_P_ARP:
   			*buff++ = AX25_P_ARP;
   			break;
@@ -2548,8 +2578,8 @@
 				return 1;
 			}
 
-			if (ourskb->sk != NULL)
-				skb_set_owner_w(ourskb, ourskb->sk);
+			if (skb->sk != NULL)
+				skb_set_owner_w(ourskb, skb->sk);
 
 			kfree_skb(skb, FREE_WRITE);
 
@@ -2561,13 +2591,13 @@
 		}
 	}
 
-  	bp[7]  &= ~LAPB_C;
-  	bp[7]  &= ~LAPB_E;
-  	bp[7]  |= SSSID_SPARE;
-
-  	bp[14] &= ~LAPB_C;
-  	bp[14] |= LAPB_E;
-  	bp[14] |= SSSID_SPARE;
+  	bp[7]  &= ~AX25_CBIT;
+  	bp[7]  &= ~AX25_EBIT;
+  	bp[7]  |= AX25_SSSID_SPARE;
+
+  	bp[14] &= ~AX25_CBIT;
+  	bp[14] |= AX25_EBIT;
+  	bp[14] |= AX25_SSSID_SPARE;
 
   	/*
   	 * dl1bke 960317: we use ax25_queue_xmit here to allow mode datagram
diff -u --recursive --new-file v2.1.21/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v2.1.21/linux/net/ax25/ax25_in.c	Thu Jan  2 15:55:26 1997
+++ linux/net/ax25/ax25_in.c	Sun Jan 19 15:47:27 1997
@@ -72,12 +72,12 @@
 {
 	struct sk_buff *skbn, *skbo;
 	int hdrlen, nhdrlen;
-	
+
 	if (ax25->fragno != 0) {
-		if (!(*skb->data & SEG_FIRST)) {
-			if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) {
+		if (!(*skb->data & AX25_SEG_FIRST)) {
+			if ((ax25->fragno - 1) == (*skb->data & AX25_SEG_REM)) {
 				/* Enqueue fragment */
-				ax25->fragno = *skb->data & SEG_REM;
+				ax25->fragno = *skb->data & AX25_SEG_REM;
 				skb_pull(skb, 1);	/* skip fragno */
 				ax25->fraglen += skb->len;
 				skb_queue_tail(&ax25->frag_queue, skb);
@@ -123,16 +123,16 @@
 					if (ax25_rx_iframe(ax25, skbn) == 0)
 						kfree_skb(skbn, FREE_READ);
 				}
-				
+
 				return 1;
 			}
 		}
 	} else {
 		/* First fragment received */
-		if (*skb->data & SEG_FIRST) {
+		if (*skb->data & AX25_SEG_FIRST) {
 			while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL)
 				kfree_skb(skbo, FREE_READ);
-			ax25->fragno = *skb->data & SEG_REM;
+			ax25->fragno = *skb->data & AX25_SEG_REM;
 			skb_pull(skb, 1);		/* skip fragno */
 			ax25->fraglen = skb->len;
 			skb_queue_tail(&ax25->frag_queue, skb);
@@ -152,7 +152,7 @@
 	int (*func)(struct sk_buff *, ax25_cb *);
 	volatile int queued = 0;
 	unsigned char pid;
-	
+
 	if (skb == NULL) return 0;
 
 	ax25->idletimer = ax25->idle;
@@ -179,12 +179,12 @@
 		skb_pull(skb, 1);	/* Remove PID */
 		return (*func)(skb, ax25);
 	}
-	
+
 	if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) {
 		if (sock_queue_rcv_skb(ax25->sk, skb) == 0)
 			queued = 1;
 		else
-			ax25->condition |= OWN_RX_BUSY_CONDITION;
+			ax25->condition |= AX25_COND_OWN_RX_BUSY;
 	}
 
 	return queued;
@@ -198,23 +198,23 @@
 static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type, int dama)
 {
 	switch (frametype) {
-		case SABM:
-			ax25->modulus = MODULUS;
+		case AX25_SABM:
+			ax25->modulus = AX25_MODULUS;
 			ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			break;
 
-		case SABME:
-			ax25->modulus = EMODULUS;
+		case AX25_SABME:
+			ax25->modulus = AX25_EMODULUS;
 			ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			break;
 
-		case DISC:
-			ax25_send_control(ax25, DM, pf, C_RESPONSE);
+		case AX25_DISC:
+			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
 			break;
 
-		case UA:
+		case AX25_UA:
 			if (pf || dama) {
 				if (dama) ax25_dama_on(ax25); /* bke */
 					
@@ -238,9 +238,9 @@
 			}
 			break;
 
-		case DM:
+		case AX25_DM:
 			if (pf) {
-				if (ax25->modulus == MODULUS) {
+				if (ax25->modulus == AX25_MODULUS) {
 					ax25_clear_queues(ax25);
 					ax25->state = AX25_STATE_0;
 					if (ax25->sk != NULL) {
@@ -252,7 +252,7 @@
 						ax25->sk->dead      = 1;
 					}
 				} else {
-					ax25->modulus = MODULUS;
+					ax25->modulus = AX25_MODULUS;
 					ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
 				}
 			}
@@ -260,7 +260,7 @@
 
 		default:
 			if (dama && pf)
-				ax25_send_control(ax25, SABM, POLLON, C_COMMAND);
+				ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
 			break;
 	}
 
@@ -275,15 +275,15 @@
 static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
 	switch (frametype) {
-		case SABM:
-		case SABME:
-			ax25_send_control(ax25, DM, pf, C_RESPONSE);
+		case AX25_SABM:
+		case AX25_SABME:
+			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
 			if (ax25->dama_slave)
-				ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 			break;
 
-		case DISC:
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+		case AX25_DISC:
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			if (ax25->dama_slave) {
 				ax25->state = AX25_STATE_0;
 				ax25_dama_off(ax25);
@@ -298,7 +298,7 @@
 			}
 			break;
 
-		case UA:
+		case AX25_UA:
 			if (pf) {
 				ax25->state = AX25_STATE_0;
 				ax25_dama_off(ax25);
@@ -313,7 +313,7 @@
 			}
 			break;
 
-		case DM:
+		case AX25_DM:
 			if (pf) {
 				ax25->state = AX25_STATE_0;
 				ax25_dama_off(ax25);
@@ -328,18 +328,18 @@
 			}
 			break;
 
-		case I:
-		case REJ:
-		case RNR:
-		case RR:
+		case AX25_I:
+		case AX25_REJ:
+		case AX25_RNR:
+		case AX25_RR:
 			if (pf) {
 				if (ax25->dama_slave)
-					ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+					ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 				else
-					ax25_send_control(ax25, DM, POLLON, C_RESPONSE);
+					ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
 			}
 			break;
-				
+
 		default:
 			break;
 	}
@@ -357,11 +357,11 @@
 	int queued = 0;
 
 	switch (frametype) {
-		case SABM:
+		case AX25_SABM:
 			if (dama) ax25_dama_on(ax25);
-			ax25->modulus   = MODULUS;
+			ax25->modulus   = AX25_MODULUS;
 			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
@@ -372,11 +372,11 @@
 			ax25->dama_slave = dama;
 			break;
 
-		case SABME:
+		case AX25_SABME:
 			if (dama) ax25_dama_on(ax25);
-			ax25->modulus   = EMODULUS;
+			ax25->modulus   = AX25_EMODULUS;
 			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
@@ -387,9 +387,9 @@
 			ax25->dama_slave = dama;
 			break;
 
-		case DISC:
+		case AX25_DISC:
 			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
 			ax25_dama_off(ax25);
@@ -403,7 +403,7 @@
 			}
 			break;
 
-		case DM:
+		case AX25_DM:
 			ax25_clear_queues(ax25);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
@@ -418,8 +418,8 @@
 			}
 			break;
 
-		case RNR:
-			ax25->condition |= PEER_RX_BUSY_CONDITION;
+		case AX25_RNR:
+			ax25->condition |= AX25_COND_PEER_RX_BUSY;
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_check_iframes_acked(ax25, nr);
@@ -429,9 +429,9 @@
 				ax25->state = AX25_STATE_1;
 			}
 			break;
-			
-		case RR:
-			ax25->condition &= ~PEER_RX_BUSY_CONDITION;
+
+		case AX25_RR:
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_check_iframes_acked(ax25, nr);
@@ -441,9 +441,9 @@
 				ax25->state = AX25_STATE_1;
 			}
 			break;
-				
-		case REJ:
-			ax25->condition &= ~PEER_RX_BUSY_CONDITION;
+
+		case AX25_REJ:
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
@@ -457,23 +457,19 @@
 				ax25->state = AX25_STATE_1;
 			}
 			break;
-			
-		case I:
-#ifndef AX25_BROKEN_NETMAC
-			if (type != C_COMMAND)
-				break;
-#endif
+
+		case AX25_I:
 			if (!ax25_validate_nr(ax25, nr)) {
 				ax25_nr_error_recovery(ax25);
 				ax25->state = AX25_STATE_1;
 				break;
 			}
-			if (ax25->condition & PEER_RX_BUSY_CONDITION) {
+			if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
 				ax25_frames_acked(ax25, nr);
 			} else {
 				ax25_check_iframes_acked(ax25, nr);
 			}
-			if (ax25->condition & OWN_RX_BUSY_CONDITION) {
+			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
 				if (pf)	{
 					if (ax25->dama_slave)
 						dama_enquiry_response(ax25);
@@ -485,7 +481,7 @@
 			if (ns == ax25->vr) {
 				ax25->vr = (ax25->vr + 1) % ax25->modulus;
 				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & OWN_RX_BUSY_CONDITION) {
+				if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
 					ax25->vr = ns;	/* ax25->vr - 1 */
 					if (pf) {
 						if (ax25->dama_slave)
@@ -495,20 +491,20 @@
 					}
 					break;
 				}
-				ax25->condition &= ~REJECT_CONDITION;
+				ax25->condition &= ~AX25_COND_REJECT;
 				if (pf) {
 					if (ax25->dama_slave)
 						dama_enquiry_response(ax25);
 					else
 						ax25_enquiry_response(ax25);
 				} else {
-					if (!(ax25->condition & ACK_PENDING_CONDITION)) {
+					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
 						ax25->t2timer = ax25->t2;
-						ax25->condition |= ACK_PENDING_CONDITION;
+						ax25->condition |= AX25_COND_ACK_PENDING;
 					}
 				}
 			} else {
-				if (ax25->condition & REJECT_CONDITION) {
+				if (ax25->condition & AX25_COND_REJECT) {
 					if (pf) {
 						if (ax25->dama_slave)
 							dama_enquiry_response(ax25);
@@ -516,18 +512,18 @@
 							ax25_enquiry_response(ax25);
 					}
 				} else {
-					ax25->condition |= REJECT_CONDITION;
+					ax25->condition |= AX25_COND_REJECT;
 					if (ax25->dama_slave)
 						dama_enquiry_response(ax25);
 					else
-						ax25_send_control(ax25, REJ, pf, C_RESPONSE);
-					ax25->condition &= ~ACK_PENDING_CONDITION;
+						ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
+					ax25->condition &= ~AX25_COND_ACK_PENDING;
 				}
 			}
 			break;
 
-		case FRMR:
-		case ILLEGAL:
+		case AX25_FRMR:
+		case AX25_ILLEGAL:
 			ax25_establish_data_link(ax25);
 			ax25->state = AX25_STATE_1;
 			break;
@@ -549,12 +545,12 @@
 	int queued = 0;
 
 	switch (frametype) {
-		case SABM:
+		case AX25_SABM:
 			if (dama) ax25_dama_on(ax25);
 			ax25->dama_slave = dama;
-			ax25->modulus   = MODULUS;
+			ax25->modulus   = AX25_MODULUS;
 			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
@@ -566,12 +562,12 @@
 			ax25->n2count   = 0;
 			break;
 
-		case SABME:
+		case AX25_SABME:
 			if (dama) ax25_dama_on(ax25);
 			ax25->dama_slave = dama;
-			ax25->modulus   = EMODULUS;
+			ax25->modulus   = AX25_EMODULUS;
 			ax25->window    = ax25_dev_get_value(ax25->device, AX25_VALUES_EWINDOW);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
@@ -583,9 +579,9 @@
 			ax25->n2count   = 0;
 			break;
 
-		case DISC:
+		case AX25_DISC:
 			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
 			ax25_dama_off(ax25);
@@ -599,7 +595,7 @@
 			}
 			break;
 
-		case DM:
+		case AX25_DM:
 			ax25_clear_queues(ax25);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
@@ -614,9 +610,9 @@
 			}
 			break;
 
-		case RNR:
-			ax25->condition |= PEER_RX_BUSY_CONDITION;
-			if (type == C_RESPONSE && pf) {
+		case AX25_RNR:
+			ax25->condition |= AX25_COND_PEER_RX_BUSY;
+			if (type == AX25_RESPONSE && pf) {
 				ax25->t1timer = 0;
 				if (ax25_validate_nr(ax25, nr)) {
 					ax25_frames_acked(ax25, nr);
@@ -631,7 +627,7 @@
 				}
 				break;
 			}
-			 
+
 			ax25_check_need_response(ax25, type, pf);
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
@@ -641,10 +637,10 @@
 				ax25->state = AX25_STATE_1;
 			}
 			break;
-			
-		case RR:
-			ax25->condition &= ~PEER_RX_BUSY_CONDITION;
-			if (pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND))) {
+
+		case AX25_RR:
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+			if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) {
 				ax25->t1timer = 0;
 				if (ax25_validate_nr(ax25, nr)) {
 					ax25_frames_acked(ax25, nr);
@@ -673,9 +669,9 @@
 			}
 			break;
 
-		case REJ:
-			ax25->condition &= ~PEER_RX_BUSY_CONDITION;
-			if (pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND))) {
+		case AX25_REJ:
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+			if (pf && (type == AX25_RESPONSE || (ax25->dama_slave && type == AX25_COMMAND))) {
 				ax25->t1timer = 0;
 				if (ax25_validate_nr(ax25, nr)) {
 					ax25_frames_acked(ax25, nr);
@@ -693,7 +689,7 @@
 				}
 				break;
 			}
-			
+
 			ax25_check_need_response(ax25, type, pf);	
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
@@ -707,18 +703,14 @@
 			}
 			break;
 
-		case I:
-#ifndef	AX25_BROKEN_NETMAC
-			if (type != C_COMMAND)
-				break;
-#endif
+		case AX25_I:
 			if (!ax25_validate_nr(ax25, nr)) {
 				ax25_nr_error_recovery(ax25);
 				ax25->state = AX25_STATE_1;
 				break;
 			}
 			ax25_frames_acked(ax25, nr);
-			if (ax25->condition & OWN_RX_BUSY_CONDITION) {
+			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
 				if (pf) {
 					if (ax25->dama_slave)
 						ax25_enquiry_response(ax25);
@@ -730,7 +722,7 @@
 			if (ns == ax25->vr) {
 				ax25->vr = (ax25->vr + 1) % ax25->modulus;
 				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & OWN_RX_BUSY_CONDITION) {
+				if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
 					ax25->vr = ns;	/* ax25->vr - 1 */
 					if (pf) {
 						if (ax25->dama_slave)
@@ -740,20 +732,20 @@
 					}
 					break;
 				}
-				ax25->condition &= ~REJECT_CONDITION;
+				ax25->condition &= ~AX25_COND_REJECT;
 				if (pf) {
 					if (ax25->dama_slave)
 						dama_enquiry_response(ax25);
 					else
 						ax25_enquiry_response(ax25);
 				} else {
-					if (!(ax25->condition & ACK_PENDING_CONDITION)) {
+					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
 						ax25->t2timer = ax25->t2;
-						ax25->condition |= ACK_PENDING_CONDITION;
+						ax25->condition |= AX25_COND_ACK_PENDING;
 					}
 				}
 			} else {
-				if (ax25->condition & REJECT_CONDITION) {
+				if (ax25->condition & AX25_COND_REJECT) {
 					if (pf) {
 						if (ax25->dama_slave)
 							dama_enquiry_response(ax25);
@@ -761,18 +753,18 @@
 							ax25_enquiry_response(ax25);
 					}
 				} else {
-					ax25->condition |= REJECT_CONDITION;
+					ax25->condition |= AX25_COND_REJECT;
 					if (ax25->dama_slave)
 						dama_enquiry_response(ax25);
 					else
-						ax25_send_control(ax25, REJ, pf, C_RESPONSE);
-					ax25->condition &= ~ACK_PENDING_CONDITION;
+						ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
+					ax25->condition &= ~AX25_COND_ACK_PENDING;
 				}
 			}
 			break;
-		
-		case FRMR:
-		case ILLEGAL:
+
+		case AX25_FRMR:
+		case AX25_ILLEGAL:
 			ax25_establish_data_link(ax25);
 			ax25->state = AX25_STATE_1;
 			break;
@@ -790,7 +782,7 @@
 int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama)
 {
 	int queued = 0, frametype, ns, nr, pf;
-	
+
 	if (ax25->state == AX25_STATE_0)
 		return 0;
 
diff -u --recursive --new-file v2.1.21/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v2.1.21/linux/net/ax25/ax25_out.c	Thu Jan  2 15:55:26 1997
+++ linux/net/ax25/ax25_out.c	Sun Jan 19 15:47:27 1997
@@ -64,17 +64,9 @@
 	unsigned char *p;
 	int frontlen, mtu, len, fragno, ka9qfrag, first = 1;
 	long flags;
-	
-	/*
-	 * dl1bke 960301: We use the new PACLEN parameter as MTU of the AX.25 layer.
-	 *                This will (hopefully) allow user programs to write() data
-	 *                w/o having to think of the maximal amount of data we can
-	 *		  send with one call. It's called PACLEN to (1) avoid confusion
-	 *		  with (IP) MTU and (2) TAPR calls this PACLEN, too ;-)
-	 */
 
 	mtu = ax25->paclen;
-	
+
 	if ((skb->len - 1) > mtu) {
 		if (*skb->data == AX25_P_TEXT) {
 			skb_pull(skb, 1); /* skip PID */
@@ -83,7 +75,7 @@
 			mtu -= 2;	/* Allow for fragment control info */
 			ka9qfrag = 1;
 		}
-		
+
 		fragno = skb->len / mtu;
 		if (skb->len % mtu == 0) fragno--;
 
@@ -92,17 +84,14 @@
 		while (skb->len > 0) {
 			save_flags(flags); 
 			cli();
-			/* 
-			 * do _not_ use sock_alloc_send_skb, our socket may have
-			 * sk->shutdown set...
-			 */
+
 			if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) {
 				restore_flags(flags);
 				printk(KERN_DEBUG "ax25_output: alloc_skb returned NULL\n");
 				return;
 			}
 
-			if (skbn->sk)
+			if (skb->sk != NULL)
 				skb_set_owner_w(skbn, skb->sk);
 			
 			restore_flags(flags);
@@ -110,7 +99,7 @@
 			skbn->arp  = 1;
 
 			len = (mtu > skb->len) ? skb->len : mtu;
-			
+
 			if (ka9qfrag == 1) {
 				skb_reserve(skbn, frontlen + 2);
 
@@ -121,7 +110,7 @@
 
 				*p = fragno--;
 				if (first) {
-					*p |= SEG_FIRST;
+					*p |= AX25_SEG_FIRST;
 					first = 0;
 				}
 			} else {
@@ -134,7 +123,7 @@
 			skb_pull(skb, len);
 			skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
 		}
-		
+
 		kfree_skb(skb, FREE_WRITE);
 	} else {
 		skb_queue_tail(&ax25->write_queue, skb);	  /* Throw it on the queue */
@@ -157,23 +146,23 @@
 	if (skb == NULL)
 		return;
 
-	if (ax25->modulus == MODULUS) {
+	if (ax25->modulus == AX25_MODULUS) {
 		frame = skb_push(skb, 1);
 
-		*frame = I;
-		*frame |= (poll_bit) ? PF : 0;
+		*frame = AX25_I;
+		*frame |= (poll_bit) ? AX25_PF : 0;
 		*frame |= (ax25->vr << 5);
 		*frame |= (ax25->vs << 1);
 	} else {
 		frame = skb_push(skb, 2);
 
-		frame[0] = I;
+		frame[0] = AX25_I;
 		frame[0] |= (ax25->vs << 1);
-		frame[1] = (poll_bit) ? EPF : 0;
+		frame[1] = (poll_bit) ? AX25_EPF : 0;
 		frame[1] |= (ax25->vr << 1);
 	}
 
-	ax25_transmit_buffer(ax25, skb, C_COMMAND);	
+	ax25_transmit_buffer(ax25, skb, AX25_COMMAND);
 }
 
 void ax25_kick(ax25_cb *ax25)
@@ -187,8 +176,8 @@
 	start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
 	end   = (ax25->va + ax25->window) % ax25->modulus;
 
-	if (!(ax25->condition & PEER_RX_BUSY_CONDITION) &&
-	    start != end                                   &&
+	if (!(ax25->condition & AX25_COND_PEER_RX_BUSY) &&
+	    start != end                                &&
 	    skb_peek(&ax25->write_queue) != NULL) {
 
 		ax25->vs = start;
@@ -210,18 +199,18 @@
 				break;
 			}
 
+			if (skb->sk != NULL)
+				skb_set_owner_w(skbn, skb->sk);
+
 			next = (ax25->vs + 1) % ax25->modulus;
-#ifdef notdef
-			last = (next == end) || skb_peek(&ax25->write_queue) == NULL;
-#else
 			last = (next == end);
-#endif
+
 			/*
 			 * Transmit the frame copy.
 			 * bke 960114: do not set the Poll bit on the last frame
 			 * in DAMA mode.
 			 */
-			ax25_send_iframe(ax25, skbn, (last && !ax25->dama_slave) ? POLLON : POLLOFF);
+			ax25_send_iframe(ax25, skbn, (last && !ax25->dama_slave) ? AX25_POLLON : AX25_POLLOFF);
 
 			ax25->vs = next;
 
@@ -229,12 +218,10 @@
 			 * Requeue the original data frame.
 			 */
 			skb_queue_tail(&ax25->ack_queue, skb);
-#ifdef notdef
-		} while (!last);
-#else
+
 		} while (!last && (skb = skb_dequeue(&ax25->write_queue)) != NULL);
-#endif
-		ax25->condition &= ~ACK_PENDING_CONDITION;
+
+		ax25->condition &= ~AX25_COND_ACK_PENDING;
 
 		if (ax25->t1timer == 0) {
 			ax25->t3timer = 0;
@@ -292,12 +279,11 @@
 	ax25->condition = 0x00;
 	ax25->n2count   = 0;
 
-	if (ax25->modulus == MODULUS) {
-		ax25_send_control(ax25, SABM, POLLON, C_COMMAND);
-	} else {
-		ax25_send_control(ax25, SABME, POLLON, C_COMMAND);
-	}
-	
+	if (ax25->modulus == AX25_MODULUS)
+		ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+	else
+		ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
+
 	ax25->t3timer = 0;
 	ax25->t2timer = 0;
 	ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
@@ -305,34 +291,34 @@
 
 void ax25_transmit_enquiry(ax25_cb *ax25)
 {
-	if (ax25->condition & OWN_RX_BUSY_CONDITION)
-		ax25_send_control(ax25, RNR, POLLON, C_COMMAND);
+	if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+		ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_COMMAND);
 	else
-		ax25_send_control(ax25, RR, POLLON, C_COMMAND);
+		ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_COMMAND);
 
-	ax25->condition &= ~ACK_PENDING_CONDITION;
+	ax25->condition &= ~AX25_COND_ACK_PENDING;
 
 	ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
 }
  	
 void ax25_enquiry_response(ax25_cb *ax25)
 {
-	if (ax25->condition & OWN_RX_BUSY_CONDITION)
-		ax25_send_control(ax25, RNR, POLLON, C_RESPONSE);
+	if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+		ax25_send_control(ax25, AX25_RNR, AX25_POLLON, AX25_RESPONSE);
 	else
-		ax25_send_control(ax25, RR, POLLON, C_RESPONSE);
+		ax25_send_control(ax25, AX25_RR, AX25_POLLON, AX25_RESPONSE);
 
-	ax25->condition &= ~ACK_PENDING_CONDITION;
+	ax25->condition &= ~AX25_COND_ACK_PENDING;
 }
 
 void ax25_timeout_response(ax25_cb *ax25)
 {
-	if (ax25->condition & OWN_RX_BUSY_CONDITION)
-		ax25_send_control(ax25, RNR, POLLOFF, C_RESPONSE);
+	if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+		ax25_send_control(ax25, AX25_RNR, AX25_POLLOFF, AX25_RESPONSE);
 	else
-		ax25_send_control(ax25, RR, POLLOFF, C_RESPONSE);
+		ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
 
-	ax25->condition &= ~ACK_PENDING_CONDITION;
+	ax25->condition &= ~AX25_COND_ACK_PENDING;
 }
 
 void ax25_check_iframes_acked(ax25_cb *ax25, unsigned short nr)
@@ -356,7 +342,7 @@
  */
 void ax25_check_need_response(ax25_cb *ax25, int type, int pf)
 {
-	if (!ax25->dama_slave && type == C_COMMAND && pf)
+	if (!ax25->dama_slave && type == AX25_COMMAND && pf)
 		ax25_enquiry_response(ax25);
 }
 
@@ -366,35 +352,32 @@
 void dama_enquiry_response(ax25_cb *ax25)
 {
 	ax25_cb *ax25o;
-	
-	if (!(ax25->condition & PEER_RX_BUSY_CONDITION)) {
+
+	if (!(ax25->condition & AX25_COND_PEER_RX_BUSY)) {
 		ax25_requeue_frames(ax25);
 		ax25_kick(ax25);
 	}
 
-	if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 ||
-	    skb_peek(&ax25->ack_queue) != NULL) {
+	if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 || skb_peek(&ax25->ack_queue) != NULL)
 		ax25_t1_timeout(ax25);
-	} else {
+	else
 		ax25->n2count = 0;
-	}
-	
+
 	ax25->t3timer = ax25->t3;
-	
 
 	/* The FLEXNET DAMA master implementation refuses to send us ANY */
 	/* I frame for this connection if we send a REJ here, probably   */
 	/* due to its frame collector scheme? A simple RR or  RNR will   */
 	/* invoke the retransmission, and in fact REJs are superfluous   */
 	/* in DAMA mode anyway...					 */
-	
+
 #if 0
-	if (ax25->condition & REJECT_CONDITION)
-		ax25_send_control(ax25, REJ, POLLOFF, C_RESPONSE);
+	if (ax25->condition & AX25_COND_REJECT)
+		ax25_send_control(ax25, AX25_REJ, AX25_POLLOFF, AX25_RESPONSE);
 	else
-#endif	
+#endif
 		ax25_enquiry_response(ax25);
-		
+
 	/* Note that above response to the poll could be sent behind the  */
 	/* transmissions of the other channels as well... This version    */	
 	/* gives better performance on FLEXNET nodes. (Why, Gunter?)	  */
@@ -413,18 +396,16 @@
 
 		if (!ax25o->dama_slave)
 			continue;
-			
-		if ( !(ax25o->condition & PEER_RX_BUSY_CONDITION) && 
+
+		if ( !(ax25o->condition & AX25_COND_PEER_RX_BUSY) && 
 		     (ax25o->state == AX25_STATE_3 || 
 		     (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
 			ax25_requeue_frames(ax25o);
 			ax25_kick(ax25o);
 		}
-		
-		if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 ||
-		    skb_peek(&ax25o->ack_queue) != NULL) {
+
+		if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL)
 			ax25_t1_timeout(ax25o);
-		}
 
 		ax25o->t3timer = ax25o->t3;
 	}
@@ -432,7 +413,7 @@
 
 void dama_check_need_response(ax25_cb *ax25, int type, int pf)
 {
-	if (ax25->dama_slave && type == C_COMMAND && pf)
+	if (ax25->dama_slave && type == AX25_COMMAND && pf)
 		dama_enquiry_response(ax25);
 }
 
diff -u --recursive --new-file v2.1.21/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
--- v2.1.21/linux/net/ax25/ax25_route.c	Thu Jan  2 15:55:26 1997
+++ linux/net/ax25/ax25_route.c	Sun Jan 19 15:47:27 1997
@@ -39,8 +39,10 @@
  *					on routes.
  *	AX.25 033	Jonathan(G4KLX)	Remove auto-router.
  *			Joerg(DL1BKE)	Moved BPQ Ethernet driver to seperate device.
+ *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
+ *			Jonathan(G4KLX)	Support for packet forwarding.
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 #include <linux/errno.h>
@@ -121,7 +123,7 @@
 						kfree_s((void *)s, sizeof(*s));
 						break;
 					}
-				}				
+				}
 			}
 		}
 	}
@@ -154,7 +156,7 @@
 					if (route.digi_count != 0) {
 						if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
 							return -ENOMEM;
-						ax25_rt->digipeat->lastrepeat = 0;
+						ax25_rt->digipeat->lastrepeat = -1;
 						ax25_rt->digipeat->ndigi      = route.digi_count;
 						for (i = 0; i < route.digi_count; i++) {
 							ax25_rt->digipeat->repeated[i] = 0;
@@ -175,7 +177,7 @@
 					kfree_s(ax25_rt, sizeof(struct ax25_route));
 					return -ENOMEM;
 				}
-				ax25_rt->digipeat->lastrepeat = 0;
+				ax25_rt->digipeat->lastrepeat = -1;
 				ax25_rt->digipeat->ndigi      = route.digi_count;
 				for (i = 0; i < route.digi_count; i++) {
 					ax25_rt->digipeat->repeated[i] = 0;
@@ -287,20 +289,20 @@
 				len += sprintf(buffer + len, "    *");
 				break;
 		}
-		
+
 		if (ax25_rt->digipeat != NULL)
 			for (i = 0; i < ax25_rt->digipeat->ndigi; i++)
 				len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i]));
-		
+
 		len += sprintf(buffer + len, "\n");
-				
+
 		pos = begin + len;
 
 		if (pos < offset) {
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -358,7 +360,7 @@
 	struct ax25_route *ax25_spe_rt = NULL;
 	struct ax25_route *ax25_def_rt = NULL;
 	struct ax25_route *ax25_rt;
-	
+
 	/*
 	 *	Bind to the physical interface we heard them on, or the default
 	 *	route if none is found;
@@ -379,7 +381,7 @@
 
 	if (ax25_spe_rt != NULL)
 		return ax25_spe_rt;
-		
+
 	return ax25_def_rt;
 }
 
@@ -391,12 +393,12 @@
 static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
 {
 	int k;
-	
+
 	for (k = 0; k < digipeat->ndigi; k++) {
 		if (ax25cmp(addr, &digipeat->calls[k]) == 0)
 			break;
 	}
-	
+
 	digipeat->ndigi = k;
 }
  
@@ -411,7 +413,7 @@
 
 	if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL)
 		return -EHOSTUNREACH;
-		
+
 	ax25->device = ax25_rt->dev;
 
 	if ((call = ax25_findbyuid(current->euid)) == NULL) {
@@ -442,10 +444,10 @@
 void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr, struct device *dev)
 {
 	struct ax25_route *ax25_rt;
-	
+
 	if ((ax25_rt = ax25_find_route(addr, dev)) == NULL)
 		return;
-	
+
 	if (ax25_rt->digipeat == NULL)
 		return;
 
@@ -472,24 +474,24 @@
 
 	if (ax25_rt->digipeat == NULL)
 		return;
-		
+
 	digipeat = *ax25_rt->digipeat;
-	
+
 	ax25_adjust_path(addr, &digipeat);
 
 	len = ax25_rt->digipeat->ndigi * AX25_ADDR_LEN;
-		
+
 	if (skb_headroom(skb) < len) {
 		printk(KERN_CRIT "ax25_dg_build_path: not enough headroom for digis in skb\n");
 		return;
 	}
-	
+
 	memcpy(&dest, skb->data    , AX25_ADDR_LEN);
 	memcpy(&src,  skb->data + 7, AX25_ADDR_LEN);
 
 	bp = skb_push(skb, len);
 
-	build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, C_COMMAND, MODULUS);
+	build_ax25_addr(bp, &src, &dest, ax25_rt->digipeat, AX25_COMMAND, AX25_MODULUS);
 }
 
 /*
@@ -506,20 +508,30 @@
 	return ' ';
 }
 
+static struct ax25_dev *ax25_dev_get_dev(struct device *dev)
+{
+	int i;
+
+	for (i = 0; i < AX25_MAX_DEVICES; i++)
+		if (ax25_device[i].dev != NULL && ax25_device[i].dev == dev)
+			return ax25_device + i;
+
+	return NULL;
+}
+
 /*
  *	Wow, a bit of data hiding. Is this C++ or what ?
  */
 int ax25_dev_get_value(struct device *dev, int valueno)
 {
-	int i;
+	struct ax25_dev *ax25_dev;
 
-	for (i = 0; i < AX25_MAX_DEVICES; i++)
-		if (ax25_device[i].dev != NULL && ax25_device[i].dev == dev)
-			return ax25_device[i].values[valueno];
-	
-	printk(KERN_WARNING "ax25_dev_get_value called with invalid device\n");
+	if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL) {
+		printk(KERN_WARNING "ax25_dev_get_value called with invalid device\n");
+		return 1;
+	}
 
-	return 0;
+	return ax25_dev->values[valueno];
 }
 
 /*
@@ -530,7 +542,7 @@
 {
 	struct ax25_dev *ax25_dev = NULL;
 	int i;
-	
+
 	for (i = 0; i < AX25_MAX_DEVICES; i++) {
 		if (ax25_device[i].dev == NULL) {
 			ax25_dev = ax25_device + i;
@@ -547,7 +559,8 @@
 
 	sprintf(ax25_dev->name, "%s.parms", dev->name);
 
-	ax25_dev->dev = dev;
+	ax25_dev->dev     = dev;
+	ax25_dev->forward = NULL;
 
 	ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
 	ax25_dev->values[AX25_VALUES_AXDEFMODE] = AX25_DEF_AXDEFMODE;
@@ -570,16 +583,61 @@
 
 void ax25_dev_device_down(struct device *dev)
 {
-	int i;
+	struct ax25_dev *ax25_dev;
 
 	ax25_unregister_sysctl();
 
-	for (i = 0; i < AX25_MAX_DEVICES; i++)
-		if (ax25_device[i].dev != NULL && ax25_device[i].dev == dev)
-			ax25_device[i].dev = NULL;
+	if ((ax25_dev = ax25_dev_get_dev(dev)) != NULL)
+		ax25_dev->dev = NULL;
 
 	ax25_register_sysctl();
 }
+
+int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
+{
+	struct device *dev;
+	struct ax25_dev *ax25_dev;
+
+	if ((dev = ax25rtr_get_dev(&fwd->port_from)) == NULL)
+		return -EINVAL;
+
+	if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
+		return -EINVAL;
+
+	switch (cmd) {
+		case SIOCAX25ADDFWD:
+			if ((dev = ax25rtr_get_dev(&fwd->port_to)) == NULL)
+				return -EINVAL;
+			if (ax25_dev->forward != NULL)
+				return -EINVAL;
+			ax25_dev->forward = dev;
+			break;
+
+		case SIOCAX25DELFWD:
+			if (ax25_dev->forward == NULL)
+				return -EINVAL;
+			ax25_dev->forward = NULL;
+			break;
+
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct device *ax25_fwd_dev(struct device *dev)
+{
+	struct ax25_dev *ax25_dev;
+
+	if ((ax25_dev = ax25_dev_get_dev(dev)) == NULL)
+		return dev;
+
+	if (ax25_dev->forward == NULL)
+		return dev;
+
+	return ax25_dev->forward;
+}
       
 #ifdef MODULE
 
@@ -589,7 +647,7 @@
 void ax25_rt_free(void)
 {
 	struct ax25_route *s, *ax25_rt = ax25_route;
-  
+
 	while (ax25_rt != NULL) {
 		s       = ax25_rt;
 		ax25_rt = ax25_rt->next;
@@ -604,4 +662,3 @@
 #endif
 
 #endif
-            
diff -u --recursive --new-file v2.1.21/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c
--- v2.1.21/linux/net/ax25/ax25_subr.c	Thu Jan  2 15:55:26 1997
+++ linux/net/ax25/ax25_subr.c	Sun Jan 19 15:47:27 1997
@@ -32,6 +32,7 @@
  *			Joerg(DL1BKE)	Found the real bug in ax25.h, sri.
  *	AX.25 032	Joerg(DL1BKE)	Added ax25_queue_length to count the number of
  *					enqueued buffers of a socket..
+ *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
  */
 
 #include <linux/config.h>
@@ -134,7 +135,7 @@
 		if (nr == vc) return 1;
 		vc = (vc + 1) % ax25->modulus;
 	}
-	
+
 	if (nr == ax25->vs) return 1;
 
 	return 0;
@@ -147,41 +148,41 @@
 int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
 {
 	unsigned char *frame;
-	int frametype = ILLEGAL;
+	int frametype = AX25_ILLEGAL;
 
 	frame = skb->data;
 	*ns = *nr = *pf = 0;
 
-	if (ax25->modulus == MODULUS) {
-		if ((frame[0] & S) == 0) {
-			frametype = I;			/* I frame - carries NR/NS/PF */
+	if (ax25->modulus == AX25_MODULUS) {
+		if ((frame[0] & AX25_S) == 0) {
+			frametype = AX25_I;			/* I frame - carries NR/NS/PF */
 			*ns = (frame[0] >> 1) & 0x07;
 			*nr = (frame[0] >> 5) & 0x07;
-			*pf = frame[0] & PF;
-		} else if ((frame[0] & U) == 1) { 	/* S frame - take out PF/NR */
+			*pf = frame[0] & AX25_PF;
+		} else if ((frame[0] & AX25_U) == 1) { 	/* S frame - take out PF/NR */
 			frametype = frame[0] & 0x0F;
 			*nr = (frame[0] >> 5) & 0x07;
-			*pf = frame[0] & PF;
-		} else if ((frame[0] & U) == 3) { 	/* U frame - take out PF */
-			frametype = frame[0] & ~PF;
-			*pf = frame[0] & PF;
+			*pf = frame[0] & AX25_PF;
+		} else if ((frame[0] & AX25_U) == 3) { 	/* U frame - take out PF */
+			frametype = frame[0] & ~AX25_PF;
+			*pf = frame[0] & AX25_PF;
 		}
 		skb_pull(skb, 1);
 	} else {
-		if ((frame[0] & S) == 0) {
-			frametype = I;			/* I frame - carries NR/NS/PF */
+		if ((frame[0] & AX25_S) == 0) {
+			frametype = AX25_I;			/* I frame - carries NR/NS/PF */
 			*ns = (frame[0] >> 1) & 0x7F;
 			*nr = (frame[1] >> 1) & 0x7F;
-			*pf = frame[1] & EPF;
+			*pf = frame[1] & AX25_EPF;
 			skb_pull(skb, 2);
-		} else if ((frame[0] & U) == 1) { 	/* S frame - take out PF/NR */
+		} else if ((frame[0] & AX25_U) == 1) { 	/* S frame - take out PF/NR */
 			frametype = frame[0] & 0x0F;
 			*nr = (frame[1] >> 1) & 0x7F;
-			*pf = frame[1] & EPF;
+			*pf = frame[1] & AX25_EPF;
 			skb_pull(skb, 2);
-		} else if ((frame[0] & U) == 3) { 	/* U frame - take out PF */
-			frametype = frame[0] & ~PF;
-			*pf = frame[0] & PF;
+		} else if ((frame[0] & AX25_U) == 3) { 	/* U frame - take out PF */
+			frametype = frame[0] & ~AX25_PF;
+			*pf = frame[0] & AX25_PF;
 			skb_pull(skb, 1);
 		}
 	}
@@ -199,7 +200,7 @@
 	struct sk_buff *skb;
 	unsigned char  *dptr;
 	struct device *dev;
-	
+
 	if ((dev = ax25->device) == NULL)
 		return;	/* Route died */
 
@@ -208,26 +209,23 @@
 
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat));
 
-	if (ax25->sk != NULL)
-		skb_set_owner_w(skb, ax25->sk);
-
 	/* Assume a response - address structure for DTE */
-	if (ax25->modulus == MODULUS) {
+	if (ax25->modulus == AX25_MODULUS) {
 		dptr = skb_put(skb, 1);
 		*dptr = frametype;
-		*dptr |= (poll_bit) ? PF : 0;
-		if ((frametype & U) == S)		/* S frames carry NR */
+		*dptr |= (poll_bit) ? AX25_PF : 0;
+		if ((frametype & AX25_U) == AX25_S)		/* S frames carry NR */
 			*dptr |= (ax25->vr << 5);
 	} else {
-		if ((frametype & U) == U) {
+		if ((frametype & AX25_U) == AX25_U) {
 			dptr = skb_put(skb, 1);
 			*dptr = frametype;
-			*dptr |= (poll_bit) ? PF : 0;
+			*dptr |= (poll_bit) ? AX25_PF : 0;
 		} else {
 			dptr = skb_put(skb, 2);
 			dptr[0] = frametype;
 			dptr[1] = (ax25->vr << 1);
-			dptr[1] |= (poll_bit) ? EPF : 0;
+			dptr[1] |= (poll_bit) ? AX25_EPF : 0;
 		}
 	}
 
@@ -256,16 +254,15 @@
 	ax25_digi_invert(digi, &retdigi);
 
 	dptr = skb_put(skb, 1);
-	skb->sk = NULL;
 
-	*dptr = DM | PF;
+	*dptr = AX25_DM | AX25_PF;
 
 	/*
 	 *	Do the address ourselves
 	 */
 
 	dptr  = skb_push(skb, size_ax25_addr(digi));
-	dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE, MODULUS);
+	dptr += build_ax25_addr(dptr, dest, src, &retdigi, AX25_RESPONSE, AX25_MODULUS);
 
 	skb->arp      = 1;
 	skb->dev      = dev;
@@ -299,19 +296,11 @@
 	if (ax25->t1timer > 0 && ax25->n2count == 0)
 		ax25->rtt = (9 * ax25->rtt + ax25->t1 - ax25->t1timer) / 10;
 
-#ifdef	AX25_T1CLAMPLO
-	/* Don't go below one tenth of a second */
-	if (ax25->rtt < (AX25_T1CLAMPLO))
-		ax25->rtt = (AX25_T1CLAMPLO);
-#else	/* Failsafe - some people might have sub 1/10th RTTs :-) **/
-	if (ax25->rtt == 0)
-		ax25->rtt = PR_SLOWHZ;
-#endif
-#ifdef	AX25_T1CLAMPHI
-	/* OR above clamped seconds **/
-	if (ax25->rtt > (AX25_T1CLAMPHI))
-		ax25->rtt = (AX25_T1CLAMPHI);
-#endif
+	if (ax25->rtt < AX25_T1CLAMPLO)
+		ax25->rtt = AX25_T1CLAMPLO;
+
+	if (ax25->rtt > AX25_T1CLAMPHI)
+		ax25->rtt = AX25_T1CLAMPHI;
 }
 
 /*
@@ -326,23 +315,21 @@
 unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama)
 {
 	int d = 0;
-	
+
 	if (len < 14) return NULL;
-		
+
 	if (flags != NULL) {
 		*flags = 0;
-	
-		if (buf[6] & LAPB_C) {
-			*flags = C_COMMAND;
-		}
-		if (buf[13] & LAPB_C) {
-			*flags = C_RESPONSE;
-		}
+
+		if (buf[6] & AX25_CBIT)
+			*flags = AX25_COMMAND;
+		if (buf[13] & AX25_CBIT)
+			*flags = AX25_RESPONSE;
 	}
-		
+
 	if (dama != NULL) 
-		*dama = ~buf[13] & DAMA_FLAG;
-		
+		*dama = ~buf[13] & AX25_DAMA_FLAG;
+
 	/* Copy to, from */
 	if (dest != NULL) 
 		memcpy(dest, buf + 0, AX25_ADDR_LEN);
@@ -352,15 +339,15 @@
 	len -= 2 * AX25_ADDR_LEN;
 	digi->lastrepeat = -1;
 	digi->ndigi      = 0;
-	
-	while (!(buf[-1] & LAPB_E)) {
+
+	while (!(buf[-1] & AX25_EBIT)) {
 		if (d >= AX25_MAX_DIGIS)  return NULL;	/* Max of 6 digis */
 		if (len < 7) return NULL;	/* Short packet */
 
 		if (digi != NULL) {
 			memcpy(&digi->calls[d], buf, AX25_ADDR_LEN);
 			digi->ndigi = d + 1;
-			if (buf[6] & AX25_REPEATED) {
+			if (buf[6] & AX25_HBIT) {
 				digi->repeated[d] = 1;
 				digi->lastrepeat  = d;
 			} else {
@@ -385,53 +372,54 @@
 	int ct  = 0;
 
 	memcpy(buf, dest, AX25_ADDR_LEN);
-	buf[6] &= ~(LAPB_E | LAPB_C);
-	buf[6] |= SSSID_SPARE;
+	buf[6] &= ~(AX25_EBIT | AX25_CBIT);
+	buf[6] |= AX25_SSSID_SPARE;
 
-	if (flag == C_COMMAND) buf[6] |= LAPB_C;
+	if (flag == AX25_COMMAND) buf[6] |= AX25_CBIT;
 
 	buf += AX25_ADDR_LEN;
 	len += AX25_ADDR_LEN;
 
 	memcpy(buf, src, AX25_ADDR_LEN);
-	buf[6] &= ~(LAPB_E | LAPB_C);
-	buf[6] &= ~SSSID_SPARE;
+	buf[6] &= ~(AX25_EBIT | AX25_CBIT);
+	buf[6] &= ~AX25_SSSID_SPARE;
 
-	if (modulus == MODULUS) {
-		buf[6] |= SSSID_SPARE;
-	} else {
-		buf[6] |= ESSID_SPARE;
-	}
+	if (modulus == AX25_MODULUS)
+		buf[6] |= AX25_SSSID_SPARE;
+	else
+		buf[6] |= AX25_ESSID_SPARE;
 
-	if (flag == C_RESPONSE) buf[6] |= LAPB_C;
+	if (flag == AX25_RESPONSE) buf[6] |= AX25_CBIT;
 
 	/*
 	 *	Fast path the normal digiless path
 	 */
 	if (d == NULL || d->ndigi == 0) {
-		buf[6] |= LAPB_E;
+		buf[6] |= AX25_EBIT;
 		return 2 * AX25_ADDR_LEN;
 	}	
-	
+
 	buf += AX25_ADDR_LEN;
 	len += AX25_ADDR_LEN;
-	
+
 	while (ct < d->ndigi) {
 		memcpy(buf, &d->calls[ct], AX25_ADDR_LEN);
+
 		if (d->repeated[ct])
-			buf[6] |= AX25_REPEATED;
+			buf[6] |= AX25_HBIT;
 		else
-			buf[6] &= ~AX25_REPEATED;
-		buf[6] &= ~LAPB_E;
-		buf[6] |= SSSID_SPARE;
+			buf[6] &= ~AX25_HBIT;
+
+		buf[6] &= ~AX25_EBIT;
+		buf[6] |= AX25_SSSID_SPARE;
 
 		buf += AX25_ADDR_LEN;
 		len += AX25_ADDR_LEN;
 		ct++;
 	}
 
-	buf[-1] |= LAPB_E;
-	
+	buf[-1] |= AX25_EBIT;
+
 	return len;
 }
 
@@ -442,34 +430,36 @@
 
 	return AX25_ADDR_LEN * (2 + dp->ndigi);
 }
-	
+
 /* 
  *	Reverse Digipeat List. May not pass both parameters as same struct
- */	
+ */
 void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
 {
 	int ct = 0;
-	
+
+	out->ndigi      = in->ndigi;
+	out->lastrepeat = in->ndigi - in->lastrepeat - 2;
+
 	/* Invert the digipeaters */
-	
+
 	while (ct < in->ndigi) {
 		out->calls[ct]    = in->calls[in->ndigi - ct - 1];
-		out->repeated[ct] = 0;
+		if (ct <= out->lastrepeat) {
+			out->calls[ct].ax25_call[6] |= AX25_HBIT;
+			out->repeated[ct]            = 1;
+		} else {
+			out->calls[ct].ax25_call[6] &= ~AX25_HBIT;
+			out->repeated[ct]            = 0;
+		}
 		ct++;
 	}
-	
-	/* Copy ndigis */
-	out->ndigi = in->ndigi;
-
-	/* Finish off */
-	out->lastrepeat = 0;
 }
 
 /*
  *	count the number of buffers on a list belonging to the same
  *	socket as skb
  */
-
 static int ax25_list_length(struct sk_buff_head *list, struct sk_buff *skb)
 {
 	int count = 0;
@@ -489,6 +479,7 @@
 			count++;
 
         restore_flags(flags);
+
         return count;
 }
 
@@ -521,20 +512,15 @@
 	if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
 		return;
 
-	skb->arp = 1;
-
-	if (ax25->sk != NULL)
-		skb_set_owner_w(skb, ax25->sk);
-
-	skb->protocol = htons(ETH_P_AX25);
-
 	p = skb_put(skb, 2);
 
 	*p++ = cmd;
 	*p++ = param;
 
+	skb->arp      = 1;
 	skb->dev      = ax25->device;
 	skb->priority = SOPRI_NORMAL;
+	skb->protocol = htons(ETH_P_AX25);
 
 	dev_queue_xmit(skb);
 }
diff -u --recursive --new-file v2.1.21/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v2.1.21/linux/net/ax25/ax25_timer.c	Thu Jan  2 15:55:26 1997
+++ linux/net/ax25/ax25_timer.c	Sun Jan 19 15:47:27 1997
@@ -20,6 +20,7 @@
  *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
  *	AX.25 032	Joerg(DL1BKE)	Fixed DAMA timeout bug
  *	AX.25 033	Jonathan(G4KLX)	Modularisation functions.
+ *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
  */
 
 #include <linux/config.h>
@@ -109,11 +110,11 @@
 			 * Check the state of the receive buffer.
 			 */
 			if (ax25->sk != NULL) {
-				if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & OWN_RX_BUSY_CONDITION)) {
-					ax25->condition &= ~OWN_RX_BUSY_CONDITION;
+				if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+					ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+					ax25->condition &= ~AX25_COND_ACK_PENDING;
 					if (!ax25->dama_slave)
-						ax25_send_control(ax25, RR, POLLOFF, C_RESPONSE);
-					ax25->condition &= ~ACK_PENDING_CONDITION;
+						ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
 					break;
 				}
 			}
@@ -130,8 +131,8 @@
 
 	if (ax25->t2timer > 0 && --ax25->t2timer == 0) {
 		if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) {
-			if (ax25->condition & ACK_PENDING_CONDITION) {
-				ax25->condition &= ~ACK_PENDING_CONDITION;
+			if (ax25->condition & AX25_COND_ACK_PENDING) {
+				ax25->condition &= ~AX25_COND_ACK_PENDING;
 				if (!ax25->dama_slave)
 					ax25_timeout_response(ax25);
 			}
@@ -144,8 +145,8 @@
 		if (ax25->dama_slave) {
 			ax25_link_failed(&ax25->dest_addr, ax25->device);
 			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
-				
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+
 			ax25->state = AX25_STATE_0;
 			if (ax25->sk != NULL) {
 				if (ax25->sk->debug)
@@ -161,7 +162,7 @@
 			ax25_reset_timer(ax25);
 			return;
 		}
-		
+
 		if (ax25->state == AX25_STATE_3) {
 			ax25->n2count = 0;
 			ax25_transmit_enquiry(ax25);
@@ -169,7 +170,7 @@
 		}
 		ax25->t3timer = ax25->t3;
 	}
-	
+
 	if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
 		/* dl1bke 960228: close the connection when IDLE expires */
 		/* 		  similar to DAMA T3 timeout but with    */
@@ -180,13 +181,13 @@
 		ax25->n2count = 0;
 		if (!ax25->dama_slave) {
 			ax25->t3timer = 0;
-			ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 		} else {
 			ax25->t3timer = ax25->t3;
 		}
-		
+
 		/* state 1 or 2 should not happen, but... */
-		
+
 		if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
 			ax25->state = AX25_STATE_0;
 		else
@@ -204,10 +205,10 @@
 			ax25->sk->destroy   = 1;
 		}
 	}
-		                                                                                                                                                                                                                                                                                                                                        
+
 	/* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */
 	/* 		  nevertheless we have to re-enqueue the timer struct...   */
-	
+
 	if (ax25->t1timer == 0 || --ax25->t1timer > 0) {
 		ax25_reset_timer(ax25);
 		return;
@@ -225,7 +226,7 @@
  *                within the poll of any connected channel. Remember 
  *                that we are not allowed to send anything unless we
  *                get polled by the Master.
- *                
+ *
  *                Thus we'll have to do parts of our T1 handling in
  *                ax25_enquiry_response().
  */
@@ -234,7 +235,7 @@
 	switch (ax25->state) {
 		case AX25_STATE_1: 
 			if (ax25->n2count == ax25->n2) {
-				if (ax25->modulus == MODULUS) {
+				if (ax25->modulus == AX25_MODULUS) {
 					ax25_link_failed(&ax25->dest_addr, ax25->device);
 					ax25_clear_queues(ax25);
 					ax25->state = AX25_STATE_0;
@@ -247,18 +248,17 @@
 						ax25->sk->dead      = 1;
 					}
 				} else {
-					ax25->modulus = MODULUS;
+					ax25->modulus = AX25_MODULUS;
 					ax25->window  = ax25_dev_get_value(ax25->device, AX25_VALUES_WINDOW);
 					ax25->n2count = 0;
-					ax25_send_control(ax25, SABM, ax25_dev_is_dama_slave(ax25->device)? POLLOFF : POLLON, C_COMMAND);
+					ax25_send_control(ax25, AX25_SABM, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND);
 				}
 			} else {
 				ax25->n2count++;
-				if (ax25->modulus == MODULUS) {
-					ax25_send_control(ax25, SABM, ax25_dev_is_dama_slave(ax25->device)? POLLOFF : POLLON, C_COMMAND);
-				} else {
-					ax25_send_control(ax25, SABME, ax25_dev_is_dama_slave(ax25->device)? POLLOFF : POLLON, C_COMMAND);
-				}
+				if (ax25->modulus == AX25_MODULUS)
+					ax25_send_control(ax25, AX25_SABM, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND);
+				else
+					ax25_send_control(ax25, AX25_SABME, ax25_dev_is_dama_slave(ax25->device) ? AX25_POLLOFF : AX25_POLLON, AX25_COMMAND);
 			}
 			break;
 
@@ -267,8 +267,8 @@
 				ax25_link_failed(&ax25->dest_addr, ax25->device);
 				ax25_clear_queues(ax25);
 				ax25->state = AX25_STATE_0;
-				ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
-				
+				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+
 				if (ax25->sk != NULL) {
 					ax25->sk->state     = TCP_CLOSE;
 					ax25->sk->err       = ETIMEDOUT;
@@ -280,7 +280,7 @@
 			} else {
 				ax25->n2count++;
 				if (!ax25_dev_is_dama_slave(ax25->device))
-					ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+					ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 			}
 			break;
 
@@ -295,7 +295,7 @@
 			if (ax25->n2count == ax25->n2) {
 				ax25_link_failed(&ax25->dest_addr, ax25->device);
 				ax25_clear_queues(ax25);
-				ax25_send_control(ax25, DM, POLLON, C_RESPONSE);
+				ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
 				ax25->state = AX25_STATE_0;
 				if (ax25->sk != NULL) {
 					if (ax25->sk->debug)
@@ -357,13 +357,13 @@
 
 	protocol->pid  = pid;
 	protocol->func = func;
-	
+
 	save_flags(flags);
 	cli();
-	
+
 	protocol->next = protocol_list;
 	protocol_list  = protocol;
-	
+
 	restore_flags(flags);
 
 	return 1;
@@ -395,10 +395,10 @@
 			kfree_s(s, sizeof(struct protocol_struct));
 			return;
 		}
-		
+
 		protocol = protocol->next;
 	}
-	
+
 	restore_flags(flags);
 }
 
@@ -411,13 +411,13 @@
 		return 0;
 
 	linkfail->func = func;
-	
+
 	save_flags(flags);
 	cli();
-	
+
 	linkfail->next = linkfail_list;
 	linkfail_list  = linkfail;
-	
+
 	restore_flags(flags);
 
 	return 1;
@@ -449,10 +449,10 @@
 			kfree_s(s, sizeof(struct linkfail_struct));
 			return;
 		}
-		
+
 		linkfail = linkfail->next;
 	}
-	
+
 	restore_flags(flags);
 }
 
@@ -469,13 +469,13 @@
 
 	listen->callsign = *callsign;
 	listen->dev      = dev;
-	
+
 	save_flags(flags);
 	cli();
-	
+
 	listen->next = listen_list;
 	listen_list  = listen;
-	
+
 	restore_flags(flags);
 
 	return 1;
@@ -507,10 +507,10 @@
 			kfree_s(s, sizeof(struct listen_struct));
 			return;
 		}
-		
+
 		listen = listen->next;
 	}
-	
+
 	restore_flags(flags);
 }
 
@@ -539,9 +539,20 @@
 void ax25_link_failed(ax25_address *callsign, struct device *dev)
 {
 	struct linkfail_struct *linkfail;
-	
+
 	for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
 		(linkfail->func)(callsign, dev);
+}
+
+int ax25_protocol_is_registered(unsigned int pid)
+{
+	struct protocol_struct *protocol;
+
+	for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
+		if (protocol->pid == pid)
+			return 1;
+
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c
--- v2.1.21/linux/net/ax25/sysctl_net_ax25.c	Thu Dec 12 17:02:47 1996
+++ linux/net/ax25/sysctl_net_ax25.c	Sun Jan 19 15:47:27 1997
@@ -9,10 +9,10 @@
 #include <linux/sysctl.h>
 #include <net/ax25.h>
 
-static int min_ax25[] = {0, 0, 0, 0, 0, 1,  1,              1,              1,
-	               0,                 0,  1,   1,  1, 0x00};
-static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * PR_SLOWHZ, 20 * PR_SLOWHZ,
-	3600 * PR_SLOWHZ, 65535 * PR_SLOWHZ, 31, 512, 20, 0x03};
+static int min_ax25[] = {0, 0, 0, 0, 0, 1,  1,                1,                1,
+	                 0,                   0,  1,   1,  1, 0x00};
+static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * AX25_SLOWHZ, 20 * AX25_SLOWHZ,
+	3600 * AX25_SLOWHZ, 65535 * AX25_SLOWHZ, 31, 512, 20, 0x03};
 
 static struct ctl_table_header *ax25_table_header;
 
diff -u --recursive --new-file v2.1.21/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.21/linux/net/core/dev.c	Thu Jan  2 15:55:26 1997
+++ linux/net/core/dev.c	Sun Jan 19 15:47:27 1997
@@ -224,6 +224,32 @@
 	}
 	return NULL;
 }
+
+struct device * dev_get_by_index(int ifindex)
+{
+	struct device *dev;
+
+	for (dev = dev_base; dev != NULL; dev = dev->next) 
+	{
+		if (dev->ifindex == ifindex)
+			return(dev);
+	}
+	return NULL;
+}
+
+struct device *dev_getbyhwaddr(unsigned short type, char *ha)
+{
+	struct device *dev;
+
+	for (dev = dev_base; dev != NULL; dev = dev->next) 
+	{
+		if (dev->type == type &&
+		    !(dev->flags&(IFF_LOOPBACK|IFF_NOARP)) &&
+		    memcmp(dev->dev_addr, ha, dev->addr_len) == 0)
+			return(dev);
+	}
+	return(NULL);
+}
 	
 /*
  *	Find and possibly load an interface.
@@ -268,18 +294,17 @@
 	if (ret == 0) 
 	{
 		dev->flags |= (IFF_UP | IFF_RUNNING);
-		dev->hash = dev_hash_name(dev->name);
 		/*
 		 *	Initialise multicasting status 
 		 */
 		dev_mc_upload(dev);
 		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
-		/* 
-		 *	FIXME: This logic was wrong before. Now its
-		 *	obviously so. I think the change here (removing the
-		 *	! on the net_alias_is) is right. ANK ??
+		
+		/*
+		 *	Passive non transmitting devices (including
+		 *	aliases) need not be on this chain.
 		 */
-		if (net_alias_is(dev) || dev->tx_queue_len)
+		if (!net_alias_is(dev) && dev->tx_queue_len)
 		{
 			cli();
 			dev->next_up = dev_up_base;
@@ -931,8 +956,6 @@
 
 	for (dev = dev_base; dev != NULL; dev = dev->next) 
 	{
-		if(!(dev->flags & IFF_UP))	/* Downed devices don't count */
-			continue;
 		/*
 		 *	Have we run out of space here ?
 		 */
@@ -1282,9 +1305,9 @@
 				dev->mtu = ifr.ifr_mtu;
 				ret = 0;
 			}
-			if (!ret && (dev->flags&IFF_UP)) {
+			if (!ret && dev->flags&IFF_UP) {
 				printk(KERN_DEBUG "SIFMTU %s(%s)\n", dev->name, current->comm);
-				notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
+				notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev);
 			}
 			break;
 	
@@ -1308,6 +1331,8 @@
 			if(ifr.ifr_hwaddr.sa_family!=dev->type)
 				return -EINVAL;
 			ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr);
+			if (!ret)
+				notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
 			break;
 			
 		case SIOCGIFMAP:
@@ -1339,6 +1364,12 @@
 				return -EINVAL;
 			dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1);
 			return 0;
+
+		case SIOGIFINDEX:
+			ifr.ifr_ifindex = dev->ifindex;
+			goto rarok;
+			
+
 		/*
 		 *	Unknown or private ioctl
 		 */
@@ -1417,6 +1448,7 @@
 		case SIOCSIFHWADDR:
 		case SIOCGIFSLAVE:
 		case SIOCGIFMAP:
+		case SIOGIFINDEX:
 			return dev_ifsioc(arg, cmd);
 
 		/*
@@ -1459,6 +1491,11 @@
 	}
 }
 
+int dev_new_index()
+{
+	static int ifindex;
+	return ++ifindex;
+}
 
 /*
  *	Initialize the DEV module. At boot time this walks the device list and
@@ -1585,6 +1622,7 @@
 		else
 		{
 			dp = &dev->next;
+			dev->ifindex = dev_new_index();
 		}
 	}
 
diff -u --recursive --new-file v2.1.21/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c
--- v2.1.21/linux/net/core/dev_mcast.c	Thu Jan  2 15:55:26 1997
+++ linux/net/core/dev_mcast.c	Sun Jan 19 15:47:27 1997
@@ -72,7 +72,12 @@
 	/*
 	 *	An aliased device should end up with the combined
 	 *	multicast list of all its aliases. 
-	 *	[Check this is still ok -AC]
+	 *	Really, multicasting with logical interfaces is very
+	 *	subtle question. Now we DO forward multicast packets
+	 *	to logical interfcases, that doubles multicast
+	 *	traffic but allows mrouted to work.
+	 *	Alas, mrouted does not understand aliases even
+	 *	in 4.4BSD --ANK
 	 */
 	 
 	dev = net_alias_main_dev(dev);
diff -u --recursive --new-file v2.1.21/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.1.21/linux/net/core/iovec.c	Thu Dec 12 19:37:22 1996
+++ linux/net/core/iovec.c	Sun Jan 19 15:47:27 1997
@@ -60,14 +60,6 @@
 	} else
 		m->msg_name = NULL;
 
-	if(m->msg_controllen)
-	{
-		err=verify_area(mode, m->msg_control, m->msg_controllen);
-		if(err)
-			return err;
-	} else
-		m->msg_control = NULL;
-
 	if (m->msg_iovlen > UIO_FASTIOV)
 	{
 		iov = kmalloc(m->msg_iovlen*sizeof(struct iovec), GFP_KERNEL);
diff -u --recursive --new-file v2.1.21/linux/net/core/net_alias.c linux/net/core/net_alias.c
--- v2.1.21/linux/net/core/net_alias.c	Thu Jan  2 15:55:26 1997
+++ linux/net/core/net_alias.c	Sun Jan 19 15:47:27 1997
@@ -275,6 +275,7 @@
 	dev->init = net_alias_devinit;
 	dev->hard_start_xmit = net_alias_hard_start_xmit;
 	dev->flags = main_dev->flags & NET_ALIAS_IFF_MASK & ~IFF_UP;
+	dev->ifindex = dev_new_index();
 
 	/*
 	 *	Only makes sense if same family (arguable)
diff -u --recursive --new-file v2.1.21/linux/net/core/scm.c linux/net/core/scm.c
--- v2.1.21/linux/net/core/scm.c	Thu Jan  2 15:55:27 1997
+++ linux/net/core/scm.c	Sun Jan 19 15:47:28 1997
@@ -8,6 +8,7 @@
  *		2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -59,7 +60,7 @@
 {
 	int num;
 	struct scm_fp_list *fpl = *fplp;
-	struct file **fpp = &fpl->fp[fpl->count];
+	struct file **fpp;
 	int *fdp = (int*)cmsg->cmsg_data;
 	int i;
 
@@ -79,6 +80,7 @@
 		*fplp = fpl;
 		fpl->count = 0;
 	}
+	fpp = &fpl->fp[fpl->count];
 
 	if (fpl->count + num > SCM_MAX_FD)
 		return -EINVAL;
@@ -92,7 +94,6 @@
 		int fd;
 		
 		fd = fdp[i];
-
 		if (fd < 0 || fd >= NR_OPEN)
 			return -EBADF;
 		if (current->files->fd[fd]==NULL)
@@ -133,27 +134,19 @@
 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
 {
 	int err;
-	struct cmsghdr kcm, *cmsg;
+	struct cmsghdr *cmsg;
 	struct file *file;
 	int acc_fd;
 	unsigned scm_flags=0;
 
-	for (cmsg = KCMSG_FIRSTHDR(msg); cmsg; cmsg = KCMSG_NXTHDR(msg, cmsg)) 
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
 	{
-		if (kcm.cmsg_level != SOL_SOCKET)
+		if (cmsg->cmsg_level != SOL_SOCKET)
 			continue;
 
 		err = -EINVAL;
 
-		/*
-		 *	Temporary hack: no protocols except for AF_UNIX
-		 *	undestand scm now.
-		 */
-
-		if (sock->ops->family != AF_UNIX)
-			goto error;
-
-		switch (kcm.cmsg_type)
+		switch (cmsg->cmsg_type)
 		{
 		case SCM_RIGHTS:
 			err=scm_fp_copy(cmsg, &p->fp);
@@ -161,7 +154,7 @@
 				goto error;
 			break;
 		case SCM_CREDENTIALS:
-			if (kcm.cmsg_len < sizeof(kcm) + sizeof(struct ucred))
+			if (cmsg->cmsg_len < sizeof(*cmsg) + sizeof(struct ucred))
 				goto error;
 			memcpy(&p->creds, cmsg->cmsg_data, sizeof(struct ucred));
 			err = scm_check_creds(&p->creds);
@@ -171,10 +164,9 @@
 		case SCM_CONNECT:
 			if (scm_flags)
 				goto error;
-			if (kcm.cmsg_len < sizeof(kcm) + sizeof(int))
+			if (cmsg->cmsg_len < sizeof(*cmsg) + sizeof(int))
 				goto error;
 			memcpy(&acc_fd, cmsg->cmsg_data, sizeof(int));
-
 			p->sock = NULL;
 			if (acc_fd != -1) {
 				if (acc_fd < 0 || acc_fd >= NR_OPEN ||
@@ -193,7 +185,6 @@
 		}
 	}
 
-
 	if (p->fp && !p->fp->count)
 	{
 		kfree(p->fp);
@@ -218,6 +209,7 @@
 {
 	struct cmsghdr *cm = (struct cmsghdr*)msg->msg_control;
 	int cmlen = sizeof(*cm) + len;
+	int err;
 
 	if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
 		msg->msg_flags |= MSG_CTRUNC;
@@ -227,16 +219,18 @@
 		msg->msg_flags |= MSG_CTRUNC;
 		cmlen = msg->msg_controllen;
 	}
-	
-	cm->cmsg_level = level;
-	cm->cmsg_type = type;
-	cm->cmsg_len = cmlen;
-	memcpy(cm->cmsg_data, data, cmlen - sizeof(*cm));
-
-	cmlen = CMSG_ALIGN(cmlen);
-	msg->msg_control += cmlen;
-	msg->msg_controllen -= cmlen;
-
+	err = put_user(level, &cm->cmsg_level);
+	if (!err)
+		err = put_user(type, &cm->cmsg_type);
+	if (!err)
+		err = put_user(cmlen, &cm->cmsg_len);
+	if (!err)
+		err = copy_to_user(cm->cmsg_data, data, cmlen - sizeof(*cm));
+	if (!err) {
+		cmlen = CMSG_ALIGN(cmlen);
+		msg->msg_control += cmlen;
+		msg->msg_controllen -= cmlen;
+	}
 }
 
 void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
@@ -246,6 +240,7 @@
 	int fdmax = (msg->msg_controllen - sizeof(struct cmsghdr))/sizeof(int);
 	int fdnum = scm->fp->count;
 	int *cmfptr;
+	int err = 0;
 	int i;
 	struct file **fp = scm->fp->fp;
 
@@ -258,22 +253,28 @@
 		if (new_fd < 0)
 			break;
 		current->files->fd[new_fd] = fp[i];
-		*cmfptr = new_fd;
+		err = put_user(new_fd, cmfptr);
 		cmfptr++;
 	}
 
 	if (i > 0)
 	{
 		int cmlen = i*sizeof(int) + sizeof(struct cmsghdr);
-
-		cm->cmsg_level = SOL_SOCKET;
-		cm->cmsg_type = SCM_RIGHTS;
-		cm->cmsg_len = cmlen;
-
-		cmlen = CMSG_ALIGN(cmlen);
-		msg->msg_control += cmlen;
-		msg->msg_controllen -= cmlen;
+		if (!err)
+			err = put_user(SOL_SOCKET, &cm->cmsg_level);
+		if (!err)
+			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+		if (!err)
+			err = put_user(cmlen, &cm->cmsg_len);
+		if (!err) {
+			cmlen = CMSG_ALIGN(cmlen);
+			msg->msg_control += cmlen;
+			msg->msg_controllen -= cmlen;
+		}
 	}
+
+	if (err)
+		i = 0;
 
 	/*
 	 *	Dump those that don't fit.
diff -u --recursive --new-file v2.1.21/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.21/linux/net/core/sock.c	Thu Jan  2 15:55:27 1997
+++ linux/net/core/sock.c	Sun Jan 19 15:47:28 1997
@@ -701,3 +701,95 @@
 	}
 }
 
+/*
+ *	Support routines for general vectors
+ */
+
+/*
+ *	Socket with no special fcntl calls.
+ */ 
+ 
+int sock_no_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+
+	switch(cmd)
+	{
+		case F_SETOWN:
+			/*
+			 * This is a little restrictive, but it's the only
+			 * way to make sure that you can't send a sigurg to
+			 * another process.
+			 */
+			if (!suser() && current->pgrp != -arg &&
+				current->pid != arg) return(-EPERM);
+			sk->proc = arg;
+			return(0);
+		case F_GETOWN:
+			return(sk->proc);
+		default:
+			return(-EINVAL);
+	}
+}
+
+/*
+ *	Default Socket Callbacks
+ */
+
+void sock_def_callback1(struct sock *sk)
+{
+	if(!sk->dead)
+		wake_up_interruptible(sk->sleep);
+}
+
+void sock_def_callback2(struct sock *sk, int len)
+{
+	if(!sk->dead)
+	{
+		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket,1);
+	}
+}
+
+void sock_def_callback3(struct sock *sk)
+{
+	if(!sk->dead)
+	{
+		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket, 2);
+	}
+}
+
+void sock_init_data(struct socket *sock, struct sock *sk)
+{
+	skb_queue_head_init(&sk->receive_queue);
+	skb_queue_head_init(&sk->write_queue);
+	skb_queue_head_init(&sk->back_log);
+	skb_queue_head_init(&sk->error_queue);
+	
+	init_timer(&sk->timer);
+	
+	sk->allocation	=	GFP_KERNEL;
+	sk->rcvbuf	=	SK_RMEM_MAX;
+	sk->sndbuf	=	SK_WMEM_MAX;
+	sk->priority	=	SOPRI_NORMAL;
+	sk->state 	= 	TCP_CLOSE;
+	sk->zapped	=	1;
+	sk->socket	=	sock;
+	if(sock)
+	{
+		sk->type	=	sock->type;
+		sk->sleep	=	&sock->wait;
+		sock->sk	=	sk;
+	}
+
+	sk->state_change	=	sock_def_callback1;
+	sk->data_ready		=	sock_def_callback2;
+	sk->write_space		=	sock_def_callback3;
+	sk->error_report	=	sock_def_callback1;
+
+	sk->peercred.pid 	=	0;
+	sk->peercred.uid	=	-1;
+	sk->peercred.gid	=	-1;
+
+}
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.21/linux/net/ipv4/af_inet.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/af_inet.c	Sun Jan 19 15:47:28 1997
@@ -429,28 +429,6 @@
  *	the work.
  */
  
-int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	struct sock *sk = sock->sk;
-
-	switch(cmd)
-	{
-		case F_SETOWN:
-			/*
-			 * This is a little restrictive, but it's the only
-			 * way to make sure that you can't send a sigurg to
-			 * another process.
-			 */
-			if (!suser() && current->pgrp != -arg &&
-				current->pid != arg) return(-EPERM);
-			sk->proc = arg;
-			return(0);
-		case F_GETOWN:
-			return(sk->proc);
-		default:
-			return(-EINVAL);
-	}
-}
 
 /*
  *	Set socket options on an inet socket.
@@ -538,36 +516,6 @@
 }
 
 /*
- *	Default callbacks for user INET sockets. These just wake up
- *	the user owning the socket.
- */
-
-static void def_callback1(struct sock *sk)
-{
-	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk,int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
-	}
-}
-
-static void def_callback3(struct sock *sk)
-{
-	if(!sk->dead && sk->wmem_alloc*2 <= sk->sndbuf)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
-	}
-}
-
-
-/*
  *	Create an inet socket.
  *
  *	FIXME: Gcc would generate much better code if we set the parameters
@@ -660,39 +608,19 @@
 			sk_free(sk);
 			return(-ESOCKTNOSUPPORT);
 	}
-	sk->type = sock->type;
-	sk->socket = sock;
-	sk->sleep = &sock->wait;
-
-	sk->peercred.pid = 0;
-	sk->peercred.uid = -1;
-	sk->peercred.gid = -1;
 
-	sock->sk = sk;
+	sock_init_data(sock,sk);
+	
+	sk->zapped=0;
 #ifdef CONFIG_TCP_NAGLE_OFF
 	sk->nonagle = 1;
 #endif  
 	sk->family = AF_INET;
 	sk->protocol = protocol;
-	sk->allocation = GFP_KERNEL;
-	sk->sndbuf = SK_WMEM_MAX;
-	sk->rcvbuf = SK_RMEM_MAX;
-	sk->priority = SOPRI_NORMAL;
 
 	sk->prot = prot;
 	sk->backlog_rcv = prot->backlog_rcv;
 
-	sk->sleep = &sock->wait;
-	sock->sk = sk;
-
-	sk->state = TCP_CLOSE;
-
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->error_queue);
-	skb_queue_head_init(&sk->back_log);
-
-
 	sk->timer.data = (unsigned long)sk;
 	sk->timer.function = &net_timer;
 
@@ -705,26 +633,22 @@
 
 	sk->ip_mc_loop=1;
 	sk->ip_mc_ttl=1;
-	*sk->ip_mc_name=0;
+	sk->ip_mc_index=0;
 	sk->ip_mc_list=NULL;
+	
 	/*
 	 *	Speed up by setting some standard state for the dummy_th
 	 *	if TCP uses it (maybe move to tcp_init later)
 	 */
   	
-	sk->state_change = def_callback1;
-	sk->data_ready = def_callback2;
-	sk->write_space = def_callback3;
-	sk->error_report = def_callback1;
-
 	if (sk->num) 
 	{
-	/*
-	 * It assumes that any protocol which allows
-	 * the user to assign a number at socket
-	 * creation time automatically
-	 * shares.
-	 */
+		/*
+		 * It assumes that any protocol which allows
+		 * the user to assign a number at socket
+		 * creation time automatically
+		 * shares.
+		 */
 		inet_put_sock(sk->num, sk);
 		sk->dummy_th.source = ntohs(sk->num);
 	}
@@ -1296,7 +1220,6 @@
 			err = get_user(pid, (int *) arg);
 			if (err)
 				return err; 
-			/* see inet_fcntl */
 			if (current->pid != pid && current->pgrp != -pid && !suser())
 				return -EPERM;
 			sk->proc = pid;
@@ -1359,6 +1282,7 @@
 		case SIOCGIFMAP:
 		case SIOCSIFSLAVE:
 		case SIOCGIFSLAVE:
+		case SIOGIFINDEX:
 			return(dev_ioctl(cmd,(void *) arg));
 
 		case SIOCGIFBR:
@@ -1671,7 +1595,7 @@
 	inet_shutdown,
 	inet_setsockopt,
 	inet_getsockopt,
-	inet_fcntl,
+	sock_no_fcntl,
 	inet_sendmsg,
 	inet_recvmsg
 };
@@ -1692,7 +1616,7 @@
 	inet_shutdown,
 	inet_setsockopt,
 	inet_getsockopt,
-	inet_fcntl,
+	sock_no_fcntl,
 	inet_sendmsg,
 	inet_recvmsg
 };
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.21/linux/net/ipv4/arp.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv4/arp.c	Sun Jan 19 15:47:28 1997
@@ -572,7 +572,7 @@
 	unsigned long now = jiffies;
 	int result = 0;
 
-	static last_index;
+	static int last_index;
 
 	if (last_index >= ARP_TABLE_SIZE)
 		last_index = 0;
@@ -1000,33 +1000,6 @@
 			return entry;
 	return NULL;
 }
-
-/*
- *	Find an arp mapping in the cache. If not found, return false.
- */
-
-int arp_query(unsigned char *haddr, u32 paddr, struct device * dev)
-{
-	struct arp_table *entry;
-
-	start_bh_atomic();
-
-	entry = arp_lookup(paddr, dev);
-
-	if (entry != NULL)
-	{
-		entry->u.dst.lastuse = jiffies;
-		if (entry->flags & ATF_COM)
-		{
-			memcpy(haddr, entry->ha, dev->addr_len);
-			end_bh_atomic();
-			return 1;
-		}
-	}
-	end_bh_atomic();
-	return 0;
-}
-
 
 static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct device * dev)
 {
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.1.21/linux/net/ipv4/devinet.c	Thu Jan  2 15:55:27 1997
+++ linux/net/ipv4/devinet.c	Sun Jan 19 15:47:28 1997
@@ -43,9 +43,7 @@
 #include <net/sock.h>
 #include <net/arp.h>
 #include <linux/notifier.h>
-#ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
-#endif
 #ifdef CONFIG_KERNELD
 #include <linux/kerneld.h>
 #endif
@@ -56,7 +54,7 @@
  *	Determine a default network mask, based on the IP address. 
  */
 
-unsigned long ip_get_mask(unsigned long addr)
+static unsigned long ip_get_mask(unsigned long addr)
 {
   	unsigned long dst;
 
@@ -78,19 +76,6 @@
   	return(0);
 }
 
-struct device *dev_getbyhwaddr(unsigned short type, char *ha)
-{
-	struct device *dev;
-
-	for (dev = dev_base; dev != NULL; dev = dev->next) 
-	{
-		if (dev->type == type &&
-		    !(dev->flags&(IFF_LOOPBACK|IFF_NOARP)) &&
-		    memcmp(dev->dev_addr, ha, dev->addr_len) == 0)
-			return(dev);
-	}
-	return(NULL);
-}
 
 /*
  *	This checks bitmasks for the ioctl calls for devices.
@@ -180,9 +165,13 @@
 			
 			if(ifr.ifr_addr.sa_family==AF_UNSPEC)
 			{
+				int ret;
 				if(dev->set_mac_address==NULL)
 					return -EOPNOTSUPP;
-				return dev->set_mac_address(dev,&ifr.ifr_addr);
+				ret = dev->set_mac_address(dev,&ifr.ifr_addr);
+				if (!ret)
+					notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+				return ret;
 			}
 			if(ifr.ifr_addr.sa_family!=AF_INET)
 				return -EINVAL;
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.21/linux/net/ipv4/fib.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv4/fib.c	Sun Jan 19 15:47:28 1997
@@ -66,7 +66,7 @@
 
 static int fib_stamp;
 
-int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r);
+static int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r);
 
 
 #ifdef CONFIG_RTNETLINK
@@ -119,7 +119,7 @@
 static struct wait_queue *fib_wait;
 atomic_t fib_users;
 
-void fib_lock(void)
+static void fib_lock(void)
 {
 	while (fib_users)
 		sleep_on(&fib_wait);
@@ -127,7 +127,7 @@
 	dev_lock_list();
 }
 
-void fib_unlock(void)
+static void fib_unlock(void)
 {
 	dev_unlock_list();
 	if (atomic_dec_and_test(&fib_users)) {
@@ -496,7 +496,7 @@
 		struct fib_zone * fz;
 
 		if (((src^cl->cl_src) & cl->cl_srcmask) ||
-		    ((dst^cl->cl_dst) & cl->cl_dstmask) ||
+		    ((daddr^cl->cl_dst) & cl->cl_dstmask) ||
 		    (cl->cl_tos && cl->cl_tos != tos) ||
 		    (cl->cl_dev && cl->cl_dev != devin))
 			continue;
@@ -561,7 +561,7 @@
 	((struct sockaddr_in*)&r.arp_pa)->sin_family = AF_INET;
 	((struct sockaddr_in*)&r.arp_pa)->sin_addr.s_addr = addr;
 	((struct sockaddr_in*)&r.arp_netmask)->sin_family = AF_INET;
-	((struct sockaddr_in*)&r.arp_netmask)->sin_addr.s_addr = fib_netmask(logmask);
+	((struct sockaddr_in*)&r.arp_netmask)->sin_addr.s_addr = fib_mask(logmask);
 
 	if (op)
 		return arp_req_set(&r, NULL);
@@ -570,7 +570,8 @@
 
 	for (f1 = fz_hash(f->fib_key, fz); f1; f1=f1->fib_next)	{
 		if (f->fib_key != f1->fib_key || f1->fib_flag ||
-		    f->fib_info->fib_flags != f1->fib_info->fib_flags)
+		    (!RT_LOCALADDR(f1->fib_info->fib_flags) &&
+		     !(f1->fib_info->fib_flags&RTF_NAT)))
 			continue;
 		return 0;
 	}
@@ -1032,6 +1033,8 @@
 		cli();
 		*fp = f->fib_next;
 		sti();
+		if (class == &local_class)
+			fib_autopublish(0, f, logmask);
 #ifdef CONFIG_RTNETLINK
 		if (rt_nl_flags&RTCTL_FLUSH)
 		    rtmsg_fib(RTMSG_DELROUTE, f, logmask, class, 0);
@@ -1397,7 +1400,7 @@
 
 #endif
 
-int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r)
+static int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r)
 {
 	unsigned long cmd=n->nlmsg_type;
 	struct device * dev = NULL;
@@ -1414,7 +1417,7 @@
 	/* Reject/throw directives have no interface/gateway specification */
 
 	if (r->rtmsg_flags & (RTF_REJECT|RTF_THROW)) {
-		r->rtmsg_device[0] = 0;
+		r->rtmsg_ifindex = 0;
 		r->rtmsg_gateway.s_addr = 0;
 		r->rtmsg_flags &= ~RTF_GATEWAY;
 	}
@@ -1430,8 +1433,8 @@
 	if (cmd == RTMSG_DELROUTE)
 		r->rtmsg_flags &= RTF_FIB;
 
-	if (r->rtmsg_device[0]) {
-		dev = dev_get(r->rtmsg_device);
+	if (r->rtmsg_ifindex) {
+		dev = dev_get_by_index(r->rtmsg_ifindex);
 		if (!dev) {
 			rtmsg_ack(n, ENODEV);
 			return -ENODEV;
@@ -1525,8 +1528,8 @@
 	    (r->rtrmsg_tos & ~IPTOS_TOS_MASK))
 		return -EINVAL;
 
-	if (r->rtrmsg_device[0]) {
-		dev = dev_get(r->rtrmsg_device);
+	if (r->rtrmsg_ifindex) {
+		dev = dev_get_by_index(r->rtrmsg_ifindex);
 		if (!dev)
 			return -ENODEV;
 		if (dev->family != AF_INET)
@@ -1574,9 +1577,18 @@
 	err = copy_from_user(&r, arg, sizeof(struct rtentry));
 	if (err)
 		return -EFAULT;
-	if (r.rt_dev)
-		if (copy_from_user(&rtm->rtmsg_device, r.rt_dev, 15))
+	if (r.rt_dev) {
+		struct device *dev;
+		char   devname[16];
+
+		if (copy_from_user(devname, r.rt_dev, 15))
 			return -EFAULT;
+		devname[15] = 0;
+		dev = dev_get(devname);
+		if (!dev)
+			return -ENODEV;
+		rtm->rtmsg_ifindex = dev->ifindex;
+	}
 
 	rtm->rtmsg_flags = r.rt_flags;
 
@@ -1740,9 +1752,7 @@
 			r->rtmsg_mtu = fi->fib_mtu;
 			r->rtmsg_window = fi->fib_window;
 			r->rtmsg_rtt = fi->fib_irtt;
-			memset(r->rtmsg_device, 0, sizeof(r->rtmsg_device));
-			if (fi->fib_dev)
-				strcpy(r->rtmsg_device, fi->fib_dev->name);
+			r->rtmsg_ifindex = fi->fib_dev ? fi->fib_dev->ifindex : 0;
 		}
 	}
 	end_bh_atomic();
@@ -1777,7 +1787,8 @@
 		r->ifmsg_mtu = dev->mtu;
 		r->ifmsg_metric = dev->metric;
 		r->ifmsg_prefixlen = 32 - fib_logmask(dev->pa_mask);
-		strcpy(r->ifmsg_device, dev->name);
+		r->ifmsg_index = dev->ifindex;
+		strcpy(r->ifmsg_name, dev->name);
 	}
 	end_bh_atomic();
 }
@@ -1866,6 +1877,28 @@
 		(&r, dev, (flags&RTF_LOCAL) ? &local_class : &main_class, &n);
 }
 
+static void ip_rt_del_broadcasts(struct device *dev)
+{
+	u32 net = dev->pa_addr&dev->pa_mask;
+
+	fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
+	fib_magic(RTMSG_DELROUTE, RTF_IFBRD, net, ~0, dev);
+	fib_magic(RTMSG_DELROUTE, RTF_IFBRD, net|~dev->pa_mask, ~0, dev);
+}
+
+static void ip_rt_add_broadcasts(struct device *dev, u32 brd, u32 mask)
+{
+	u32 net = dev->pa_addr&mask;
+
+	if (dev->flags&IFF_BROADCAST)
+		fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, brd, ~0, dev);
+
+	if (net && !(mask&htonl(1))) {
+		fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, net, ~0, dev);
+		fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, net|~mask, ~0, dev);
+	}
+}
+
 void ip_rt_change_broadcast(struct device *dev, u32 new_brd)
 {
 	fib_lock();
@@ -1875,7 +1908,7 @@
 		fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
 		rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
 		rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
-		fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, new_brd, ~0, dev);
+		ip_rt_add_broadcasts(dev, new_brd, dev->pa_mask);
 	}
 	fib_unlock();
 }
@@ -1908,22 +1941,19 @@
 	}
 	net = dev->pa_addr&dev->pa_mask;
 	fib_magic(RTMSG_DELROUTE, RTF_IFPREFIX, net, dev->pa_mask, dev);
-	fib_magic(RTMSG_DELROUTE, RTF_IFBRD, net, ~0, dev);
-	fib_magic(RTMSG_DELROUTE, RTF_IFBRD, net|~dev->pa_mask, ~0, dev);
+	ip_rt_del_broadcasts(dev);
 	if (mask != 0xFFFFFFFF && dev->flags&IFF_POINTOPOINT)
 		fib_magic(RTMSG_DELROUTE, RTF_IFPREFIX, dev->pa_dstaddr, ~0, dev);
 	rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
 
-	dev->flags &= ~IFF_POINTOPOINT;
+	if (mask != 0xFFFFFFFF)
+		dev->flags &= ~IFF_POINTOPOINT;
 
 	rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
 	net = dev->pa_addr&mask;
 	if (net)
 		fib_magic(RTMSG_NEWROUTE, RTF_IFPREFIX, net, mask, dev);
-	if (net && mask != 0xFFFFFFFF) {
-		fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, net, ~0, dev);
-		fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, net|~mask, ~0, dev);
-	}
+	ip_rt_add_broadcasts(dev, dev->pa_addr, mask);
 	fib_unlock();
 }
 
@@ -1947,8 +1977,7 @@
 		else {
 			u32 net = dev->pa_addr&dev->pa_mask;
 			fib_magic(RTMSG_DELROUTE, RTF_IFPREFIX, net, dev->pa_mask, dev);
-			fib_magic(RTMSG_DELROUTE, RTF_IFBRD, net, ~0, dev);
-			fib_magic(RTMSG_DELROUTE, RTF_IFBRD, net|~dev->pa_mask, ~0, dev);
+			ip_rt_del_broadcasts(dev);
 		}
 		rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
 	}
@@ -1971,14 +2000,12 @@
 		if (dev->flags&IFF_POINTOPOINT) {
 			if (dev->pa_dstaddr && dev->type != ARPHRD_TUNNEL)
 				fib_magic(RTMSG_NEWROUTE, RTF_IFPREFIX, dev->pa_dstaddr, ~0, dev);
-		} else if (dev->pa_addr&dev->pa_mask) {
+		} else {
 			u32 net = dev->pa_addr&dev->pa_mask;
 
-			fib_magic(RTMSG_NEWROUTE, RTF_IFPREFIX, net, dev->pa_mask, dev);
-			if (dev->pa_mask != 0xFFFFFFFF) {
-				fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, net, ~0, dev);
-				fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, net|~dev->pa_mask, ~0, dev);
-			}
+			if (net)
+				fib_magic(RTMSG_NEWROUTE, RTF_IFPREFIX, net, dev->pa_mask, dev);
+			ip_rt_add_broadcasts(dev, dev->pa_brdaddr, dev->pa_mask);
 		}
 		fib_magic(RTMSG_NEWROUTE, RTF_IFLOCAL, dev->pa_addr, ~0, dev);
 		if (dev == &loopback_dev) {
@@ -1992,9 +2019,9 @@
 					  mask, dev);
 			}
 		}
-		if (dev->flags&IFF_BROADCAST)
-			fib_magic(RTMSG_NEWROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
 	}
+	if (event == NETDEV_CHANGEMTU || event == NETDEV_CHANGEADDR)
+		rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
 	fib_unlock();
 	return NOTIFY_DONE;
 }
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.1.21/linux/net/ipv4/ip_forward.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv4/ip_forward.c	Sun Jan 19 15:47:28 1997
@@ -205,7 +205,7 @@
 		}
 #endif
 
-		if (skb_headroom(skb) < dev2->hard_header_len) {
+		if (skb_headroom(skb) < dev2->hard_header_len || skb_cloned(skb)) {
 			struct sk_buff *skb2;
 			skb2 = skb_realloc_headroom(skb, (dev2->hard_header_len + 15)&~15);
 			kfree_skb(skb, FREE_WRITE);
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.1.21/linux/net/ipv4/ip_input.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/ip_input.c	Sun Jan 19 15:47:28 1997
@@ -154,9 +154,7 @@
 #include <linux/firewall.h>
 #include <linux/mroute.h>
 #include <net/netlink.h>
-#ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
-#endif
 
 /*
  *	SNMP management statistics
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/ip_options.c linux/net/ipv4/ip_options.c
--- v2.1.21/linux/net/ipv4/ip_options.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/ip_options.c	Sun Jan 19 15:47:28 1997
@@ -484,15 +484,21 @@
 	}
 }
 
-int ip_options_getfromuser(struct ip_options **optp, unsigned char *data, int optlen)
+int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen, int user)
 {
 	struct ip_options *opt;
+
 	opt = kmalloc(sizeof(struct ip_options)+((optlen+3)&~3), GFP_KERNEL);
 	if (!opt)
 		return -ENOMEM;
 	memset(opt, 0, sizeof(struct ip_options));
-	if (optlen && copy_from_user(opt->__data, data, optlen))
-		return -EFAULT;
+	if (optlen) {
+		if (user) {
+			if (copy_from_user(opt->__data, data, optlen))
+				return -EFAULT;
+		} else
+			memcpy(opt->__data, data, optlen);
+	}
 	while (optlen & 3)
 		opt->__data[optlen++] = IPOPT_END;
 	opt->optlen = optlen;
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.1.21/linux/net/ipv4/ip_sockglue.c	Thu Dec 12 19:37:26 1996
+++ linux/net/ipv4/ip_sockglue.c	Sun Jan 19 15:47:28 1997
@@ -40,11 +40,16 @@
  *	SOL_IP control messages.
  */
 
-static void ip_cmsg_recv_localdev(struct msghdr *msg, struct sk_buff *skb)
+static void ip_cmsg_recv_rxinfo(struct msghdr *msg, struct sk_buff *skb)
 {
-	static char empty_name[MAX_ADDR_LEN];
-	put_cmsg(msg, SOL_IP, IP_LOCALDEV, MAX_ADDR_LEN,
-		 skb->dev ? skb->dev->name : empty_name);
+	struct in_pktinfo info;
+	struct rtable *rt = (struct rtable *)skb->dst;
+
+	info.ipi_ifindex = skb->dev->ifindex;
+	info.ipi_addr.s_addr = skb->nh.iph->daddr;
+	info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
+
+	put_cmsg(msg, SOL_IP, IP_RXINFO, sizeof(info), &info);
 }
 
 static void ip_cmsg_recv_localaddr(struct msghdr *msg, struct sk_buff *skb, int local)
@@ -94,20 +99,20 @@
 
 	/* Ordered by supposed usage frequency */
 	if (flags & 1)
-		ip_cmsg_recv_localaddr(msg, skb, 1);
-	if ((flags>>1) == 0)
+		ip_cmsg_recv_rxinfo(msg, skb);
+	if ((flags>>=1) == 0)
 		return;
 	if (flags & 1)
-		ip_cmsg_recv_localdev(msg, skb);
-	if ((flags>>1) == 0)
+		ip_cmsg_recv_localaddr(msg, skb, 1);
+	if ((flags>>=1) == 0)
 		return;
 	if (flags & 1)
 		ip_cmsg_recv_opts(msg, skb);
-	if ((flags>>1) == 0)
+	if ((flags>>=1) == 0)
 		return;
 	if (flags & 1)
 		ip_cmsg_recv_retopts(msg, skb);
-	if ((flags>>1) == 0)
+	if ((flags>>=1) == 0)
 		return;
 	if (flags & 1)
 		ip_cmsg_recv_localaddr(msg, skb, 0);
@@ -116,38 +121,38 @@
 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc, struct device **devp)
 {
 	int err;
-	struct cmsghdr kcm, *cmsg;
-	char	devname[MAX_ADDR_LEN];
+	struct cmsghdr *cmsg;
 
-	for (cmsg = KCMSG_FIRSTHDR(msg); cmsg; cmsg = KCMSG_NXTHDR(msg, cmsg)) {
-		if (kcm.cmsg_level != SOL_IP)
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+		if (cmsg->cmsg_level != SOL_IP)
 			continue;
-		switch (kcm.cmsg_type)
+		switch (cmsg->cmsg_type)
 		{
 		case IP_LOCALADDR:
-			if (kcm.cmsg_len < sizeof(struct in_addr)+sizeof(kcm))
+			if (cmsg->cmsg_len < sizeof(struct in_addr)+sizeof(*cmsg))
 				return -EINVAL;
-			if (copy_from_user(&ipc->addr, cmsg->cmsg_data, 4))
-				return -EFAULT;
+			memcpy(&ipc->addr, cmsg->cmsg_data, 4);
 			break;
 		case IP_RETOPTS:
-			err = kcm.cmsg_len - sizeof(kcm);
-			err = ip_options_getfromuser(&ipc->opt, cmsg->cmsg_data,
-						     err < 40 ? err : 40);
+			err = cmsg->cmsg_len - sizeof(*cmsg);
+			err = ip_options_get(&ipc->opt, cmsg->cmsg_data,
+					     err < 40 ? err : 40, 0);
 			if (err)
 				return err;
 			break;
-		case IP_LOCALDEV:
-			if (kcm.cmsg_len < MAX_ADDR_LEN+sizeof(kcm))
+		case IP_TXINFO:
+		{
+			struct in_pktinfo *info;
+			if (cmsg->cmsg_len < sizeof(*info)+sizeof(*cmsg))
 				return -EINVAL;
-			if (!devp)
+			info = (struct in_pktinfo*)cmsg->cmsg_data;
+			if (info->ipi_ifindex && !devp)
 				return -EINVAL;
-			if (copy_from_user(devname, cmsg->cmsg_data, MAX_ADDR_LEN-1))
-				return -EFAULT;
-			devname[MAX_ADDR_LEN-1] = 0;
-			if ((*devp = dev_get(devname)) == NULL)
+			if ((*devp = dev_get_by_index(info->ipi_ifindex)) == NULL)
 				return -ENODEV;
+			ipc->addr = info->ipi_spec_dst.s_addr;
 			break;
+		}
 		default:
 			return -EINVAL;
 		}
@@ -200,7 +205,7 @@
 			  struct ip_options * old_opt;
 			  if (optlen > 40 || optlen < 0)
 			  	return -EINVAL;
-			  err = ip_options_getfromuser(&opt, optval, optlen);
+			  err = ip_options_get(&opt, optval, optlen, 1);
 			  if (err)
 			  	return err;
 			  /*
@@ -215,13 +220,13 @@
 			  	kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen);
 			  return 0;
 		  }
-		case IP_LOCALADDR:
+		case IP_RXINFO:
 			if (val)
 				sk->ip_cmsg_flags |= 1;
 			else
 				sk->ip_cmsg_flags &= ~1;
 			return 0;
-		case IP_LOCALDEV:
+		case IP_LOCALADDR:
 			if (val)
 				sk->ip_cmsg_flags |= 2;
 			else
@@ -313,7 +318,7 @@
 			
 			if (addr.s_addr==INADDR_ANY)	/* Default */
 			{
-				memset(sk->ip_mc_name, 0, sizeof(sk->ip_mc_name));
+				sk->ip_mc_index = 0;
 				return 0;
 			}
 			
@@ -329,8 +334,7 @@
 			 
 			if(dev) 
 			{
-				memset(sk->ip_mc_name, 0, sizeof(sk->ip_mc_name));
-				strcpy(sk->ip_mc_name, dev->name);
+				sk->ip_mc_index = dev->ifindex;
 				return 0;
 			}
 			return -EADDRNOTAVAIL;
@@ -425,25 +429,28 @@
 
 		case IP_MULTICAST_IFN:
 		{
-			struct device *dev;
-			char *devname;
+			struct ip_mreqn mreq;
+			struct device *dev = NULL;
 			
-			err = getname(optval, &devname);
+			err = copy_from_user(&mreq,optval,sizeof(mreq));
 			if (err)
-				return err;
-			if (!devname[0])
-			{
-				memset(sk->ip_mc_name, 0, sizeof(sk->ip_mc_name));
-				putname(devname);
-				return 0;
-			}
-			dev = dev_get(devname);
-			putname(devname);
+				return -EFAULT;
+
+			if (!mreq.imr_ifindex) {
+				if (!mreq.imr_address.s_addr) {
+					sk->ip_mc_index = 0;
+					sk->ip_mc_addr  = 0;
+					return 0;
+				}
+				dev = ip_dev_find(mreq.imr_address.s_addr, NULL);
+			} else
+				dev = dev_get_by_index(mreq.imr_ifindex);
+
 			if (!dev)
 				return -ENODEV;
 
-			memset(sk->ip_mc_name, 0, sizeof(sk->ip_mc_name));
-			strcpy(sk->ip_mc_name,dev->name);
+			sk->ip_mc_index = mreq.imr_ifindex;
+			sk->ip_mc_addr  = mreq.imr_address.s_addr;
 			return 0;
 		}
 		case IP_ADD_MEMBERSHIPN:
@@ -451,14 +458,10 @@
 			struct ip_mreqn mreq;
 			struct device *dev = NULL;
 			
-			/*
-			 *	Check the arguments.
-			 */
-
 			err = copy_from_user(&mreq,optval,sizeof(mreq));
 			if (err)
 				return -EFAULT; 
-			dev = dev_get(mreq.imr_interface);
+			dev = dev_get_by_index(mreq.imr_ifindex);
 			if (!dev)
 				return -ENODEV;
 			return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr);
@@ -477,7 +480,7 @@
 			if (err)
 				return -EFAULT; 
 
-			dev=dev_get(mreq.imr_interface);
+			dev=dev_get_by_index(mreq.imr_ifindex);
 			if(!dev)
 				return -ENODEV;
 			 
@@ -583,10 +586,10 @@
 				return err; 
 			}
 			return 0;
-		case IP_LOCALADDR:
+		case IP_RXINFO:
 			val = (sk->ip_cmsg_flags & 1) != 0;
 			return 0;
-		case IP_LOCALDEV:
+		case IP_LOCALADDR:
 			val = (sk->ip_cmsg_flags & 2) != 0;
 			return 0;
 		case IP_RECVOPTS:
@@ -619,17 +622,40 @@
 		case IP_MULTICAST_LOOP:
 			val=sk->ip_mc_loop;
 			break;
-		case IP_MULTICAST_IF:
 		case IP_MULTICAST_IFN:
-  			len=strlen(sk->ip_mc_name);
+		{
+			struct ip_mreqn mreq;
+			len = sizeof(struct ip_mreqn);
+  			err = put_user(len, optlen);
+			mreq.imr_ifindex = sk->ip_mc_index;
+			mreq.imr_address.s_addr = sk->ip_mc_addr;
+			mreq.imr_multiaddr.s_addr = 0;
+			if (!err) {
+				err = copy_to_user((void *)optval, &mreq, len);
+				if (err)
+					err = -EFAULT;
+			}
+			return err;
+		}
+		case IP_MULTICAST_IF:
+		{
+			struct device *dev = dev_get_by_index(sk->ip_mc_index);
+			if (dev == NULL) {
+				len = 0;
+				return put_user(len, optlen);
+			}
+			dev_lock_list();
+  			len = strlen(dev->name);
   			err = put_user(len, optlen);
 			if (!err)
 			{
-				err = copy_to_user((void *)optval,sk->ip_mc_name, len);
+				err = copy_to_user((void *)optval,dev->name, len);
 				if (err)
 				    err = -EFAULT;
 			}
+			dev_unlock_list();
 			return err;
+		}
 		default:
 			return(-ENOPROTOOPT);
 	}
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/packet.c linux/net/ipv4/packet.c
--- v2.1.21/linux/net/ipv4/packet.c	Thu Dec 12 19:37:26 1996
+++ linux/net/ipv4/packet.c	Sun Jan 19 15:47:28 1997
@@ -248,6 +248,7 @@
 	}
 	
 	release_sock(sk);
+	sk->dead = 1;
 	destroy_sock(sk);
 }
 
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.1.21/linux/net/ipv4/raw.c	Sun Dec 22 16:37:44 1996
+++ linux/net/ipv4/raw.c	Sun Jan 19 15:47:28 1997
@@ -249,8 +249,8 @@
 	}
 	tos = RT_TOS(sk->ip_tos) | (sk->localroute || (msg->msg_flags&MSG_DONTROUTE));
 
-	if (MULTICAST(daddr) && sk->ip_mc_name[0] && dev==NULL)
-		err = ip_route_output_dev(&rt, daddr, rfh.saddr, tos, sk->ip_mc_name);
+	if (MULTICAST(daddr) && sk->ip_mc_index && dev==NULL)
+		err = ip_route_output_dev(&rt, daddr, rfh.saddr, tos, sk->ip_mc_index);
 	else
 		err = ip_route_output(&rt, daddr, rfh.saddr, tos, dev);
 
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.21/linux/net/ipv4/route.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv4/route.c	Sun Jan 19 15:47:28 1997
@@ -78,7 +78,11 @@
 #include <net/sock.h>
 #include <net/icmp.h>
 #include <linux/net_alias.h>
-  
+
+/* Compile time configuretion flags */
+
+#define CONFIG_IP_LOCAL_RT_POLICY 1
+
 static void rt_run_flush(unsigned long);
   
 static struct timer_list rt_flush_timer =
@@ -629,7 +633,8 @@
 		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
 		rt->last_error = jiffies;
 		if (ipv4_config.log_martians && ++rt->errors == RT_REDIRECT_NUMBER)
-			printk(KERN_WARNING "host %08x/%s ignores redirects.\n", rt->rt_src, rt->rt_src_dev->name);
+			printk(KERN_WARNING "host %08x/%s ignores redirects for %08x to %08x.\n",
+			       rt->rt_src, rt->rt_src_dev->name, rt->rt_dst, rt->rt_gateway);
 	}
 }
 
@@ -1187,13 +1192,8 @@
 	fi = res.f->fib_info;
 	dst_map = daddr;
 
-	if (fi->fib_flags&RTF_NAT) {
-		dst_map = htonl((ntohl(daddr)&((1<<res.fm)-1)))|fi->fib_gateway;
-		fi = fib_lookup_info(dst_map, saddr, tos, &loopback_dev, dev_out);
-		if (!fi || fi->fib_flags&(RTF_NAT|RTF_LOCAL|RTF_MULTICAST|RTF_BROADCAST))
-			return -EINVAL;
-		flags = RTCF_NAT;
-	}
+	if (fi->fib_flags&RTF_NAT)
+		return -EINVAL;
 
 	if (!saddr) {
 		saddr = fi->fib_dev->pa_addr;
@@ -1305,9 +1305,7 @@
 		rth->u.dst.rtt	= TCP_TIMEOUT_INIT;
 	}
 	rth->rt_flags = flags;
-	hash = rt_hash_code(dst_key, src_key, tos);
-	if (dst_dev_key)
-		hash ^= dev_hash_name(dst_dev_key->name);
+	hash = rt_hash_code(dst_key, dst_dev_key ? src_key^(dst_dev_key->ifindex<<5) : src_key, tos);
 	*rp = rt_intern_hash(hash, rth, ETH_P_IP);
 	return 0;
 }
@@ -1317,9 +1315,8 @@
 	unsigned hash;
 	struct rtable *rth;
 
-	hash = rt_hash_code(daddr, saddr, tos);
-	if (dev_out)
-		hash ^= dev_out->hash;
+	hash = rt_hash_code(daddr, dev_out ? saddr^(dev_out->ifindex<<5)
+			                   : saddr, tos);
 
 	start_bh_atomic();
 	for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) {
@@ -1341,13 +1338,13 @@
 	return ip_route_output_slow(rp, daddr, saddr, tos, dev_out);
 }
 
-int ip_route_output_dev(struct rtable **rp, u32 daddr, u32 saddr, u8 tos, char *devname)
+int ip_route_output_dev(struct rtable **rp, u32 daddr, u32 saddr, u8 tos, int ifindex)
 {
 	unsigned hash;
 	struct rtable *rth;
 	struct device *dev_out;
 
-	hash = rt_hash_code(daddr, saddr, tos)^dev_hash_mc_name(devname);
+	hash = rt_hash_code(daddr, saddr^(ifindex<<5), tos);
 
 	start_bh_atomic();
 	for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) {
@@ -1356,7 +1353,7 @@
 		    rth->key.src_dev == NULL &&
 		    rth->key.tos == tos &&
 		    rth->key.dst_dev &&
-		    strcmp(rth->key.dst_dev->name, devname)==0) {
+		    rth->key.dst_dev->ifindex == ifindex) {
 			rth->u.dst.lastuse = jiffies;
 			atomic_inc(&rth->u.dst.use);
 			atomic_inc(&rth->u.dst.refcnt);
@@ -1367,7 +1364,7 @@
 	}
 	end_bh_atomic();
 
-	dev_out = dev_get(devname);
+	dev_out = dev_get_by_index(ifindex);
 	if (!dev_out)
 		return -ENODEV;
 	return ip_route_output_slow(rp, daddr, saddr, tos, dev_out);
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.21/linux/net/ipv4/tcp.c	Thu Jan  2 15:55:27 1997
+++ linux/net/ipv4/tcp.c	Sun Jan 19 15:47:28 1997
@@ -895,7 +895,7 @@
 			}
 	
 			/* 
-			 *Now we need to check if we have a half built packet. 
+			 *	Now we need to check if we have a half built packet. 
 			 */
 
 			/* if we have queued packets */
@@ -912,9 +912,8 @@
 				/*
 				 * This window_seq test is somewhat dangerous
 				 * If the remote does SWS avoidance we should
-				 * queue the best we can
-				 * if not we should in fact send multiple
-				 * packets...
+				 * queue the best we can if not we should in 
+				 * fact send multiple packets...
 				 * a method for detecting this would be most
 				 * welcome
 				 */
diff -u --recursive --new-file v2.1.21/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.21/linux/net/ipv4/udp.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv4/udp.c	Sun Jan 19 15:47:28 1997
@@ -375,8 +375,8 @@
 	tos = RT_TOS(sk->ip_tos) | (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) ||
 				    (ipc.opt && ipc.opt->is_strictroute));
 
-	if (MULTICAST(daddr) && sk->ip_mc_name[0] && dev == NULL)
-		err = ip_route_output_dev(&rt, daddr, ufh.saddr, tos, sk->ip_mc_name);
+	if (MULTICAST(daddr) && sk->ip_mc_index && dev == NULL)
+		err = ip_route_output_dev(&rt, daddr, ufh.saddr, tos, sk->ip_mc_index);
 	else
 		err = ip_route_output(&rt, daddr, ufh.saddr, tos, dev);
 
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.21/linux/net/ipv6/addrconf.c	Thu Jan  2 15:55:27 1997
+++ linux/net/ipv6/addrconf.c	Sun Jan 19 15:47:28 1997
@@ -56,7 +56,6 @@
  *	AF_INET6 device list
  */
 struct inet6_dev		*inet6_dev_lst;
-int				in6_ifnum = 0;
 
 atomic_t			addr_list_lock = 0;
 
@@ -167,7 +166,7 @@
 
 	memset(dev6, 0, sizeof(struct inet6_dev));
 	dev6->dev = dev;
-	dev6->if_index = ++in6_ifnum;
+	dev6->if_index = dev->ifindex;
 
 	/*
 	 *	insert at head.
@@ -892,40 +891,6 @@
 
 err_exit:
 	return err;
-}
-
-/*
- *	Obtain if_index from device name
- */
-int addrconf_get_ifindex(void *arg)
-{
-	struct ifreq ifr;
-	int res = -ENODEV;
-	
-	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
-	{
-		res = -EFAULT;		
-	}
-	else
-	{
-		struct inet6_dev *idev;
-
-		for (idev = inet6_dev_lst; idev; idev=idev->next)
-		{
-			if (!strncmp(ifr.ifr_name, idev->dev->name, IFNAMSIZ))
-			{
-				res = 0;
-				ifr.ifr_ifindex = idev->if_index;
-				if (copy_to_user(arg, &ifr, sizeof(ifr)))
-				{
-					res = -EFAULT;
-				}
-				break;
-			}
-		}
-	}
-
-	return res;
 }
 
 /*
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.21/linux/net/ipv6/af_inet6.c	Wed Dec 18 15:59:14 1996
+++ linux/net/ipv6/af_inet6.c	Sun Jan 19 15:47:28 1997
@@ -61,44 +61,6 @@
 #include <linux/ip_fw.h>
 #include <net/addrconf.h>
 
-/*
- *	Default callbacks for user INET sockets. These just wake up
- *	the user owning the socket.
- */
-
-static void def_callback1(struct sock *sk)
-{
-	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk,int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
-	}
-}
-
-static void def_callback3(struct sock *sk)
-{
-	long wmem;
-	
-	wmem = (long) sk->wmem_alloc;
-
-	if (wmem < 0) {
-		printk(KERN_DEBUG "bug wmem_alloc < 0\n");
-		sk->wmem_alloc = 0;
-	}
-		
-	if(!sk->dead && sk->wmem_alloc*2 <= sk->sndbuf)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
-	}
-}
-
 struct sock * rawv6_sock_array[SOCK_ARRAY_SIZE];
 
 extern struct proto_ops inet6_stream_ops;
@@ -114,9 +76,6 @@
 	if (sk == NULL) 
 		return(-ENOBUFS);
 
-	/* Efficient way to set most fields to zero */
-	memset(sk,0,sizeof(*sk));	
-
 	/*
 	 *	Note for tcp that also wiped the dummy_th block for us.
 	 */
@@ -168,39 +127,19 @@
 			sk_free(sk);
 			return(-ESOCKTNOSUPPORT);
 	}
-
-	sk->socket = sock;
+	
+	sock_init_data(sock,sk);
 
 	sk->family = AF_INET6;
-	sk->type = sock->type;
 	sk->protocol = protocol;
-	sk->allocation = GFP_KERNEL;
-	sk->sndbuf = SK_WMEM_MAX;
-	sk->rcvbuf = SK_RMEM_MAX;
-	sk->priority = 1;
 
 	sk->prot = prot;
 	sk->backlog_rcv = prot->backlog_rcv;
 
-	sk->sleep = &sock->wait;
-	sock->sk = sk;
-
-	sk->state = TCP_CLOSE;
-
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->error_queue);
-	skb_queue_head_init(&sk->back_log);
-
 	sk->timer.data = (unsigned long)sk;
 	sk->timer.function = &net_timer;
 	init_timer(&sk->timer);
 
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
 	sk->net_pinfo.af_inet6.hop_limit  = ipv6_hop_limit;
 	sk->net_pinfo.af_inet6.mcast_hops = IPV6_DEFAULT_MCASTHOPS;
 	sk->net_pinfo.af_inet6.mc_loop	  = 1;
@@ -212,12 +151,10 @@
 
 	sk->ip_ttl=64;
 
-#ifdef CONFIG_IP_MULTICAST
 	sk->ip_mc_loop=1;
 	sk->ip_mc_ttl=1;
-	*sk->ip_mc_name=0;
+	sk->ip_mc_index=0;
 	sk->ip_mc_list=NULL;
-#endif
 
 
 	if (sk->type==SOCK_RAW && protocol==IPPROTO_RAW)
@@ -490,7 +427,7 @@
 		if(err)
 			return err;
 
-		/* see inet_fcntl */
+		/* see sock_no_fcntl */
 		if (current->pid != pid && current->pgrp != -pid && !suser())
 			return -EPERM;
 		sk->proc = pid;
@@ -551,18 +488,10 @@
 	case SIOCGIFMAP:
 	case SIOCSIFSLAVE:
 	case SIOCGIFSLAVE:
+	case SIOGIFINDEX:
 
 		return(dev_ioctl(cmd,(void *) arg));		
 		
-		return -EINVAL;
-
-	case SIOGIFINDEX:
-		/*
-		 *	This one will be moved to the generic device
-		 *	layer in the near future
-		 */
-		return addrconf_get_ifindex((void *) arg);
-		
 	case SIOCSIFADDR:
 		return addrconf_add_ifaddr((void *) arg);
 	case SIOCSIFDSTADDR:
@@ -804,7 +733,7 @@
 	inet_shutdown,			/* ok		*/
 	inet_setsockopt,		/* ok		*/
 	inet_getsockopt,		/* ok		*/
-	inet_fcntl,			/* ok		*/
+	sock_no_fcntl,			/* ok		*/
 	inet_sendmsg,			/* ok		*/
 	inet_recvmsg			/* ok		*/
 };
@@ -825,7 +754,7 @@
 	inet_shutdown,			/* ok		*/
 	inet_setsockopt,		/* ok		*/
 	inet_getsockopt,		/* ok		*/
-	inet_fcntl,			/* ok		*/
+	sock_no_fcntl,			/* ok		*/
 	inet_sendmsg,			/* ok		*/
 	inet_recvmsg			/* ok		*/
 };
@@ -844,8 +773,15 @@
 #endif
 {
 	int i;
+	struct sk_buff *dummy_skb;
 
 	printk(KERN_INFO "IPv6 v0.1 for NET3.037\n");
+
+	if (sizeof(struct ipv6_options) > sizeof(dummy_skb->cb))
+	{
+		printk(KERN_CRIT "inet6_proto_init: panic\n");
+		return;
+	}
 
   	(void) sock_register(&inet6_family_ops);
 	
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/datagram.c linux/net/ipv6/datagram.c
--- v2.1.21/linux/net/ipv6/datagram.c	Wed Jan 15 19:45:47 1997
+++ linux/net/ipv6/datagram.c	Sun Jan 19 15:47:28 1997
@@ -31,79 +31,30 @@
 {
 	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
 	struct ipv6_options *opt = (struct ipv6_options *) skb->cb;
-	struct cmsghdr *cmsg = msg->msg_control;
-	int len = msg->msg_controllen;
-
-	msg->msg_controllen = 0;
 	
-	if (np->rxinfo && (len >= sizeof(struct cmsghdr) +
-			   sizeof(struct in6_pktinfo)))
+	if (np->rxinfo)
 	{
-		struct in6_pktinfo *src_info;
-		struct inet6_dev *in6_dev;
-
-		cmsg->cmsg_len = (sizeof(struct cmsghdr) + 
-				  sizeof(struct in6_pktinfo));
-		cmsg->cmsg_level = SOL_IPV6;
-		cmsg->cmsg_type = IPV6_RXINFO;
-
-		src_info = (struct in6_pktinfo *) cmsg->cmsg_data;
-		in6_dev = ipv6_get_idev(skb->dev);
+		struct in6_pktinfo src_info;
 
-		if (in6_dev == NULL)
-		{
-			printk(KERN_DEBUG "recv_ctl: unknown device\n");
-			return -ENODEV;
-		}
-
-		src_info->ipi6_ifindex = in6_dev->if_index;
-		ipv6_addr_copy(&src_info->ipi6_addr,
-			       &skb->nh.ipv6h->daddr);
-
-		len -= cmsg->cmsg_len;
-		msg->msg_controllen += cmsg->cmsg_len;
-		cmsg = (struct cmsghdr *)((u8*) cmsg + cmsg->cmsg_len);
+		src_info.ipi6_ifindex = skb->dev->ifindex;
+		ipv6_addr_copy(&src_info.ipi6_addr, &skb->nh.ipv6h->daddr);
+		put_cmsg(msg, SOL_IPV6, IPV6_RXINFO, sizeof(src_info), &src_info);
 	}
 
-	if (np->rxhlim && (len >= sizeof(struct cmsghdr) + sizeof(int)))
+	if (np->rxhlim)
 	{
-		int *hlim;
-		
-		cmsg->cmsg_len = (sizeof(struct cmsghdr) + sizeof(int));
-		cmsg->cmsg_level = SOL_IPV6;
-		cmsg->cmsg_type = IPV6_HOPLIMIT;
-		
-		hlim = (int *) cmsg->cmsg_data;
-		*hlim = skb->nh.ipv6h->hop_limit;
-		
-		len -= cmsg->cmsg_len;
-		msg->msg_controllen += cmsg->cmsg_len;
-		cmsg = (struct cmsghdr *)((u8*) cmsg + cmsg->cmsg_len);
+		int hlim = skb->nh.ipv6h->hop_limit;
+		put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
 	}
 
 	if (opt->srcrt)
 	{
 		int hdrlen = sizeof(struct rt0_hdr) + (opt->srcrt->hdrlen << 3);
 
-		if (len >= sizeof(struct cmsghdr) + hdrlen)
-		{
-			struct rt0_hdr *rt0;
-
-			cmsg->cmsg_len = sizeof(struct cmsghdr) + hdrlen;
-			cmsg->cmsg_level = SOL_IPV6;
-			cmsg->cmsg_type = IPV6_RXINFO;
-		
-			rt0 = (struct rt0_hdr *) cmsg->cmsg_data;
-			memcpy(rt0, opt->srcrt, hdrlen);
-
-			len -= cmsg->cmsg_len;
-			msg->msg_controllen += cmsg->cmsg_len;
-			cmsg = (struct cmsghdr *)((u8*) cmsg + cmsg->cmsg_len);
-		}
+		put_cmsg(msg, SOL_IPV6, IPV6_RXSRCRT, hdrlen, opt->srcrt);
 	}
 	return 0;
 }
-			 
 
 int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
 		      struct in6_addr **src_addr, struct ipv6_options *opt, 
@@ -116,7 +67,7 @@
 	int len;
 	int err = 0;
 
-	for (cmsg = msg->msg_control; cmsg; cmsg = cmsg_nxthdr(msg, cmsg))
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
 	{
 		if (cmsg->cmsg_level != SOL_IPV6)
 		{
@@ -165,7 +116,7 @@
 
 			break;
 			
-		case SCM_SRCRT:
+		case IPV6_RXSRCRT:
 
 			len = cmsg->cmsg_len;
 
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/ipv6_input.c linux/net/ipv6/ipv6_input.c
--- v2.1.21/linux/net/ipv6/ipv6_input.c	Thu Dec 12 19:37:30 1996
+++ linux/net/ipv6/ipv6_input.c	Sun Jan 19 15:47:28 1997
@@ -269,6 +269,11 @@
 	__u8			*nhptr;
 	int			pkt_len;
 
+	if (skb->pkt_type == PACKET_OTHERHOST) {
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
+
 	hdr = skb->nh.ipv6h;
 	skb->h.raw = (__u8*)hdr;
 
@@ -408,6 +413,11 @@
 	}
 	else
 	{
+		if (skb->pkt_type != PACKET_HOST) {
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
+
 		if (ipv6_forwarding)
 		{
 			if (addr_type & IPV6_ADDR_LINKLOCAL)
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.21/linux/net/ipv6/raw.c	Wed Jan 15 19:45:47 1997
+++ linux/net/ipv6/raw.c	Sun Jan 19 15:47:28 1997
@@ -150,16 +150,7 @@
 	}
 
 	if (msg->msg_controllen)
-	{
-		int err;
-
-		err = datagram_recv_ctl(sk, msg, skb);
-
-		if (err < 0)
-		{
-			copied = err;
-		}
-	}
+		datagram_recv_ctl(sk, msg, skb);
 
 	skb_free_datagram(sk, skb);
 	return (copied);
@@ -311,7 +302,7 @@
 	if (len + (sk->ip_hdrincl ? 0 : sizeof(struct ipv6hdr)) > 65535)
 		return -EMSGSIZE;
 
-	if (msg->msg_control)
+	if (msg->msg_controllen)
 	{
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_options));
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/sit.c linux/net/ipv6/sit.c
--- v2.1.21/linux/net/ipv6/sit.c	Thu Dec 12 19:37:31 1996
+++ linux/net/ipv6/sit.c	Sun Jan 19 15:47:28 1997
@@ -208,7 +208,7 @@
 	dev->hard_header_len 	= MAX_HEADER;
 	dev->mtu		= 1500 - sizeof(struct iphdr);
 	dev->addr_len		= 0;
-	dev->tx_queue_len	= 2;
+	dev->tx_queue_len	= 0;
 
 	memset(dev->broadcast, 0, MAX_ADDR_LEN);
 	memset(dev->dev_addr,  0, MAX_ADDR_LEN);
@@ -415,31 +415,19 @@
 	struct enet_statistics *stats;
 	struct sit_mtu_info *minfo;
 	struct in6_addr *addr6;	
-	unsigned long flags;
 	struct rtable *rt;
 	struct iphdr *iph;
 	__u32 saddr;
 	__u32 daddr;
-	__u32 raddr;
 	int addr_type;
 	int mtu;
-	int len;
+	int headroom;
 
 	/* 
 	 *	Make sure we are not busy (check lock variable) 
 	 */
 
 	stats = (struct enet_statistics *)dev->priv;
-	save_flags(flags);
-	cli();
-	if (dev->tbusy != 0) 
-	{
-		restore_flags(flags);
-		printk(KERN_DEBUG "sit_xmit: busy\n");
-		return(1);
-	}
-	dev->tbusy = 1;
-	restore_flags(flags);
 
 	daddr = dev->pa_dstaddr;
 	if (daddr == 0)
@@ -470,79 +458,57 @@
 		daddr = addr6->s6_addr32[3];
 	}
 
-	len = skb->tail - (skb->data + sizeof(struct ipv6hdr));
-
-	skb_orphan(skb);
-		
-	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr));
-	
-	skb->protocol = htons(ETH_P_IP);
-
-	/* get route */
-
 	if (ip_route_output(&rt, daddr, 0, 0, NULL)) {
 		printk(KERN_DEBUG "sit: no route to host\n");
 		goto on_error;
 	}
 
-	skb->dst = dst_clone(&rt->u.dst);
 	minfo = sit_mtu_lookup(daddr);
 
+	/* IP should calculate pmtu correctly,
+	 * let's check it...
+	 */
+#if 0
 	if (minfo)
 		mtu = minfo->mtu;
 	else
-		mtu = rt->u.dst.dev->mtu;
+#endif
+		mtu = rt->u.dst.pmtu;
 
-	if (mtu > 576 && len > mtu)
+	if (mtu > 576 && skb->tail - (skb->data + sizeof(struct ipv6hdr)) > mtu)
 	{
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+		ip_rt_put(rt);
 		goto on_error;
 	}
 
-	saddr = rt->rt_src;
-	skb->dev = rt->u.dst.dev;
-	raddr = rt->rt_gateway;	
-
-	if (raddr == 0)
-		raddr = daddr;
-
-	/* now for the device header */
-
-	skb->arp = 1;
-		
-	if (skb->dev->hard_header_len) 
-	{
-		int mac;
+	headroom = ((rt->u.dst.dev->hard_header_len+15)&~15)+sizeof(struct iphdr);
 
-		if (skb->data - skb->head < skb->dev->hard_header_len)
-		{
-			printk(KERN_DEBUG "sit: space at head < dev header\n");
+	if (skb_headroom(skb) < headroom || skb_shared(skb)) {
+		struct sk_buff *new_skb = skb_realloc_headroom(skb, headroom);
+		if (!new_skb) {
+			ip_rt_put(rt);
 			goto on_error;
 		}
-
-		if (skb->dev->hard_header)
-		{
-			mac = skb->dev->hard_header(skb, skb->dev, ETH_P_IP, 
-					       NULL, NULL, len);
-
-			if (mac < 0)
-				skb->arp = 0;
-
-		}
-		
+		dev_kfree_skb(skb, FREE_WRITE);
+		skb = new_skb;
 	}
+		
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
-	ip_rt_put(rt);
+	iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr));
+	skb->nh.iph   = iph;
 
+	saddr = rt->rt_src;
+	dst_release(skb->dst);
+	skb->dst = &rt->u.dst;
 
 	iph->version  = 4;
 	iph->ihl      = 5;
 	iph->tos      = 0;				/* tos set to 0... */
 
 	if (mtu > 576)
-	{
 		iph->frag_off = htons(IP_DF);
-	}
 	else
 		iph->frag_off = 0;
 
@@ -550,20 +516,18 @@
 	iph->saddr    = saddr;
 	iph->daddr    = daddr;
 	iph->protocol = IPPROTO_IPV6;
-	skb->nh.iph   = iph;
-
+	iph->tot_len  =	htons(skb->len);
+	iph->id	      =	htons(ip_id_count++);
 	ip_send_check(iph);
 
-	ip_queue_xmit(skb);
+	ip_send(skb);
 
 	stats->tx_packets++;
-	dev->tbusy=0;
 
 	return 0;
 
   on_error:
-	kfree_skb(skb, FREE_WRITE);
-	dev->tbusy=0;
+	dev_kfree_skb(skb, FREE_WRITE);
 	stats->tx_errors++;
 	return 0;	
 }
diff -u --recursive --new-file v2.1.21/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.21/linux/net/ipv6/udp.c	Wed Jan 15 19:45:47 1997
+++ linux/net/ipv6/udp.c	Sun Jan 19 15:47:28 1997
@@ -231,17 +231,8 @@
 			memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
 			       sizeof(struct in6_addr));
 
-			if (msg->msg_control)
-			{
-				int err;
-
-				err = datagram_recv_ctl(sk, msg, skb);
-
-				if (err < 0)
-				{
-					copied = err;
-				}
-			}
+			if (msg->msg_controllen)
+				datagram_recv_ctl(sk, msg, skb);
 		}
   	}
 	
@@ -556,7 +547,7 @@
 
 	udh.daddr = NULL;
 	
-	if (msg->msg_control)
+	if (msg->msg_controllen)
 	{
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_options));
diff -u --recursive --new-file v2.1.21/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.21/linux/net/ipx/af_ipx.c	Wed Jan 15 19:45:47 1997
+++ linux/net/ipx/af_ipx.c	Sun Jan 19 15:47:28 1997
@@ -760,6 +760,12 @@
 		struct sk_buff *skb2;
   		long *l;
 		char *c;
+		
+		if(skb->pkt_type!=PACKET_HOST)
+		{
+			kfree_skb(skb, FREE_READ);
+			return 0;
+		}
 
 #ifdef DEBUG_IPX_PPROP_ROUTING
 		printk(KERN_INFO "IPX: PPROP packet received\n"
@@ -812,6 +818,16 @@
 					printk( "IPX: Forward PPROP onto net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) );
 #endif
 					skb2 = skb_clone(skb, GFP_ATOMIC);
+#ifdef CONFIG_FIREWALL
+					/*
+					 *	See if we are allowed to firewall forward
+					 */
+					if (call_fw_firewall(PF_IPX, skb2->dev, ipx, NULL)!=FW_ACCEPT)
+					{
+						kfree_skb(skb, FREE_READ);
+						return 0;
+					}
+#endif
 					ipxrtr_route_skb(skb2);
 				}
 #ifdef DEBUG_IPX_PPROP_ROUTING
@@ -846,8 +862,7 @@
 		}
 #endif
 		/* We only route point-to-point packets. */
-		if ((skb->pkt_type != PACKET_BROADCAST) &&
-			(skb->pkt_type != PACKET_MULTICAST))
+		if (skb->pkt_type == PACKET_HOST)
 		{
 			skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ);
 			if(skb)
@@ -1699,15 +1714,6 @@
 *														    *
 \*******************************************************************************************************************/
 
-static int ipx_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	switch(cmd)
-	{
-		default:
-			return(-EINVAL);
-	}
-}
-
 static int ipx_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
 {
 	struct sock *sk;
@@ -1777,30 +1783,6 @@
 	return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
-	}
-}
-
-static void def_callback3(struct sock *sk, int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
-	}
-}
-
 static int ipx_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -1816,30 +1798,9 @@
 			sk_free(sk);
 			return(-ESOCKTNOSUPPORT);
 	}
-	sk->rcvbuf=SK_RMEM_MAX;
-	sk->sndbuf=SK_WMEM_MAX;
-	sk->prot=NULL;	/* So we use default free mechanisms */
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	sk->send_head=NULL;
-	skb_queue_head_init(&sk->back_log);
-	sk->state=TCP_CLOSE;
-	sk->socket=sock;
-	sk->type=sock->type;
+	sock_init_data(sock,sk);
 	sk->mtu=IPX_MTU;
 	sk->no_check = 1;		/* Checksum off by default */
-	if(sock!=NULL)
-	{
-		sk->sleep=&sock->wait;
-		sock->sk=sk;
-	}
-
-	sk->state_change=def_callback1;
-	sk->data_ready=def_callback2;
-	sk->write_space=def_callback3;
-	sk->error_report=def_callback1;
-
-	sk->zapped=1;
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -2384,7 +2345,7 @@
 	ipx_shutdown,
 	ipx_setsockopt,
 	ipx_getsockopt,
-	ipx_fcntl,
+	sock_no_fcntl,
 	ipx_sendmsg,
 	ipx_recvmsg
 };
diff -u --recursive --new-file v2.1.21/linux/net/lapb/lapb_iface.c linux/net/lapb/lapb_iface.c
--- v2.1.21/linux/net/lapb/lapb_iface.c	Thu Jan  2 15:55:28 1997
+++ linux/net/lapb/lapb_iface.c	Sun Jan 19 15:47:28 1997
@@ -63,7 +63,7 @@
 {
 	lapb_cb *s;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
@@ -152,7 +152,7 @@
 
 	if (lapb_tokentostruct(token) != NULL)
 		return LAPB_BADTOKEN;
-	
+
 	if ((lapb = lapb_create_cb()) == NULL)
 		return LAPB_NOMEM;
 
@@ -160,7 +160,7 @@
 	lapb->callbacks = *callbacks;
 
 	lapb_insert_cb(lapb);
-		
+
 	return LAPB_OK;
 }
 
@@ -176,7 +176,7 @@
 	lapb_remove_cb(lapb);
 
 	lapb_free_cb(lapb);
-		
+
 	return LAPB_OK;
 }
 
@@ -224,7 +224,7 @@
 			if (parms->window < 1 || parms->window > 7)
 				return LAPB_INVALUE;
 		}
-	
+
 		lapb->mode   = parms->mode;
 		lapb->window = parms->window;
 
diff -u --recursive --new-file v2.1.21/linux/net/lapb/lapb_in.c linux/net/lapb/lapb_in.c
--- v2.1.21/linux/net/lapb/lapb_in.c	Thu Jan  2 15:55:28 1997
+++ linux/net/lapb/lapb_in.c	Sun Jan 19 15:47:29 1997
@@ -232,7 +232,7 @@
 			printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, pf);
 			printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, pf);
 #endif
-			lapb_send_control(lapb, LAPB_UA, pf, C_RESPONSE);
+			lapb_send_control(lapb, LAPB_UA, pf, LAPB_RESPONSE);
 			break;
 
 		case LAPB_UA:
@@ -386,7 +386,7 @@
 				lapb->state = LAPB_STATE_1;
 			}
 			break;
-			
+
 		case LAPB_RR:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->token, pf, nr);
@@ -403,7 +403,7 @@
 				lapb->state = LAPB_STATE_1;
 			}
 			break;
-				
+
 		case LAPB_REJ:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->token, pf, nr);
@@ -422,13 +422,11 @@
 				lapb->state = LAPB_STATE_1;
 			}
 			break;
-			
+
 		case LAPB_I:
 #if LAPB_DEBUG > 1
 			printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->token, pf, ns, nr);
 #endif
-			if (type != LAPB_COMMAND)
-				break;
 			if (!lapb_validate_nr(lapb, nr)) {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token);
@@ -613,7 +611,7 @@
 				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);
@@ -700,8 +698,6 @@
 #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 (type != LAPB_COMMAND)
-				break;
 			if (!lapb_validate_nr(lapb, nr)) {
 #if LAPB_DEBUG > 0
 				printk(KERN_DEBUG "lapb: (%p) S4 -> S1\n", lapb->token);
@@ -737,7 +733,7 @@
 				}
 			}
 			break;
-		
+
 		case LAPB_FRMR:
 		case LAPB_ILLEGAL:
 #if LAPB_DEBUG > 1
@@ -765,7 +761,7 @@
 {
 	int frametype, ns, nr, pf, type;
 	lapb_cb *lapb;
-	
+
 	if ((lapb = lapb_tokentostruct(token)) == NULL)
 		return LAPB_BADTOKEN;
 
diff -u --recursive --new-file v2.1.21/linux/net/lapb/lapb_out.c linux/net/lapb/lapb_out.c
--- v2.1.21/linux/net/lapb/lapb_out.c	Thu Jan  2 15:55:28 1997
+++ linux/net/lapb/lapb_out.c	Sun Jan 19 15:47:29 1997
@@ -52,27 +52,30 @@
 	if (lapb->mode & LAPB_EXTENDED) {
 		frame = skb_push(skb, 2);
 
-		frame[0] = I;
+		frame[0] = LAPB_I;
 		frame[0] |= (lapb->vs << 1);
 		frame[1] = (poll_bit) ? LAPB_EPF : 0;
 		frame[1] |= (lapb->vr << 1);
 	} else {
 		frame = skb_push(skb, 1);
 
-		*frame = I;
+		*frame = LAPB_I;
 		*frame |= (poll_bit) ? LAPB_SPF : 0;
 		*frame |= (lapb->vr << 5);
 		*frame |= (lapb->vs << 1);
 	}
 
+#if LAPB_DEBUG > 1
+	printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n", lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr);
+#endif
+
 	lapb_transmit_buffer(lapb, skb, LAPB_COMMAND);	
 }
 
 void lapb_kick(lapb_cb *lapb)
 {
 	struct sk_buff *skb, *skbn;
-	int modulus, last = 1;
-	unsigned short start, end, next;
+	unsigned short modulus, start, end;
 
 	del_timer(&lapb->timer);
 
@@ -81,7 +84,7 @@
 	start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs;
 	end   = (lapb->va + lapb->window) % modulus;
 
-	if (!(lapb->condition & PEER_RX_BUSY_CONDITION) &&
+	if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) &&
 	    start != end                                &&
 	    skb_peek(&lapb->write_queue) != NULL) {
 
@@ -98,28 +101,23 @@
 				break;
 			}
 
-			next = (lapb->vs + 1) % modulus;
-#ifdef notdef
-			last = (next == end) || skb_peek(&lapb->write_queue) == NULL;
-#else
-			last = (next == end);
-#endif
+			if (skb->sk != NULL)
+				skb_set_owner_w(skbn, skb->sk);
+
 			/*
 			 * Transmit the frame copy.
 			 */
-			lapb_send_iframe(lapb, skbn, POLLOFF);
+			lapb_send_iframe(lapb, skbn, LAPB_POLLOFF);
 
-			lapb->vs = next;
+			lapb->vs = (lapb->vs + 1) % modulus;
 
 			/*
 			 * Requeue the original data frame.
 			 */
 			skb_queue_tail(&lapb->ack_queue, skb);
-#ifdef notdef
-		} while (!last);
-#else
-		} while (!last && (skb = skb_dequeue(&lapb->write_queue)) != NULL);
-#endif
+
+		} while (lapb->vs != end && (skb = skb_dequeue(&lapb->write_queue)) != NULL);
+
 		lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 
 		if (lapb->t1timer == 0)
@@ -183,14 +181,14 @@
 #if LAPB_DEBUG > 1
 		printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n", lapb->token, lapb->state);
 #endif
-		lapb_send_control(lapb, SABME, POLLON, LAPB_COMMAND);
+		lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
 	} else {
 #if LAPB_DEBUG > 1
 		printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n", lapb->token, lapb->state);
 #endif
-		lapb_send_control(lapb, SABM, POLLON, LAPB_COMMAND);
+		lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
 	}
-	
+
 	lapb->t2timer = 0;
 	lapb->t1timer = lapb->t1;
 }
@@ -201,20 +199,20 @@
 	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", lapb->token, lapb->state, lapb->vr);
 #endif
 
-	lapb_send_control(lapb, RR, POLLON, C_COMMAND);
+	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
 	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", lapb->token, lapb->state, lapb->vr);
 #endif
 
-	lapb_send_control(lapb, RR, POLLON, LAPB_RESPONSE);
+	lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE);
 
 	lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 }
@@ -225,7 +223,7 @@
 	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n", lapb->token, lapb->state, lapb->vr);
 #endif
 
-	lapb_send_control(lapb, RR, POLLOFF, LAPB_RESPONSE);
+	lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);
 
 	lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 }
diff -u --recursive --new-file v2.1.21/linux/net/lapb/lapb_subr.c linux/net/lapb/lapb_subr.c
--- v2.1.21/linux/net/lapb/lapb_subr.c	Thu Jan  2 15:55:28 1997
+++ linux/net/lapb/lapb_subr.c	Sun Jan 19 15:47:29 1997
@@ -131,26 +131,26 @@
 
 	if (lapb->mode & LAPB_MLP) {
 		if (lapb->mode & LAPB_DCE) {
-			if (skb->data[0] == LAPB_ADDR_C)
-				*type = LAPB_COMMAND;
 			if (skb->data[0] == LAPB_ADDR_D)
+				*type = LAPB_COMMAND;
+			if (skb->data[0] == LAPB_ADDR_C)
 				*type = LAPB_RESPONSE;
 		} else {
-			if (skb->data[0] == LAPB_ADDR_D)
-				*type = LAPB_COMMAND;
 			if (skb->data[0] == LAPB_ADDR_C)
+				*type = LAPB_COMMAND;
+			if (skb->data[0] == LAPB_ADDR_D)
 				*type = LAPB_RESPONSE;
 		}
 	} else {
 		if (lapb->mode & LAPB_DCE) {
-			if (skb->data[0] == LAPB_ADDR_A)
-				*type = LAPB_COMMAND;
 			if (skb->data[0] == LAPB_ADDR_B)
+				*type = LAPB_COMMAND;
+			if (skb->data[0] == LAPB_ADDR_A)
 				*type = LAPB_RESPONSE;
 		} else {
-			if (skb->data[0] == LAPB_ADDR_B)
-				*type = LAPB_COMMAND;
 			if (skb->data[0] == LAPB_ADDR_A)
+				*type = LAPB_COMMAND;
+			if (skb->data[0] == LAPB_ADDR_B)
 				*type = LAPB_RESPONSE;
 		}
 	}
@@ -185,7 +185,7 @@
 			*nr = (skb->data[0] >> 5) & 0x07;
 			*pf = skb->data[0] & LAPB_SPF;
 		} else if ((skb->data[0] & LAPB_U) == 3) { 	/* U frame - take out PF */
-			frametype = skb->data[0] & ~PF;
+			frametype = skb->data[0] & ~LAPB_SPF;
 			*pf = skb->data[0] & LAPB_SPF;
 		}
 
@@ -204,7 +204,7 @@
 {
 	struct sk_buff *skb;
 	unsigned char  *dptr;
-	
+
 	if ((skb = alloc_skb(LAPB_HEADER_LEN + 3, GFP_ATOMIC)) == NULL)
 		return;
 
diff -u --recursive --new-file v2.1.21/linux/net/lapb/lapb_timer.c linux/net/lapb/lapb_timer.c
--- v2.1.21/linux/net/lapb/lapb_timer.c	Thu Jan  2 15:55:28 1997
+++ linux/net/lapb/lapb_timer.c	Sun Jan 19 15:47:29 1997
@@ -63,7 +63,7 @@
 static void lapb_reset_timer(lapb_cb *lapb)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&lapb->timer);
diff -u --recursive --new-file v2.1.21/linux/net/netbeui/netbeui.c linux/net/netbeui/netbeui.c
--- v2.1.21/linux/net/netbeui/netbeui.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netbeui/netbeui.c	Sun Jan 19 15:47:29 1997
@@ -162,21 +162,6 @@
 \*******************************************************************************************************************/
 
 /*
- *	Generic fcntl calls are already dealt with. If we don't need funny ones
- *	this is the all you need. Async I/O is also separate.
- */
-
-static int netbeui_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-/*	netbeui_socket *sk=(netbeui_socket *)sock->data;*/
-	switch(cmd)
-	{
-		default:
-			return(-EINVAL);
-	}
-}
-
-/*
  *	Set 'magic' options for netbeui. If we don't have any this is fine
  *	as it is.
  */
@@ -266,34 +251,6 @@
 }
 
 /*
- *	These are standard.
- */
-
-static void def_callback1(struct sock *sk)
-{
-	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
-	}
-}
-
-static void def_callback3(struct sock *sk, int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,2);
-	}
-}
-
-/*
  *	Create a socket. Initialise the socket, blank the addresses
  *	set the state.
  */
@@ -317,30 +274,8 @@
 
 	MOD_INC_USE_COUNT;
 
-	sk->allocation=GFP_KERNEL;
-	sk->rcvbuf=SK_RMEM_MAX;
-	sk->sndbuf=SK_WMEM_MAX;
-	sk->pair=NULL;
-	sk->priority=SOPRI_NORMAL;
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-	sk->state=TCP_CLOSE;
-	sk->socket=sock;
-	sk->type=sock->type;
+	sock_init_data(sock,sk);
 	sk->mtu=1500;
-
-	if(sock!=NULL)
-	{
-		sock->data=(void *)sk;
-		sk->sleep=sock->wait;
-	}
-
-	sk->state_change=def_callback1;
-	sk->data_ready=def_callback2;
-	sk->write_space=def_callback3;
-	sk->error_report=def_callback1;
-	sk->zapped=1;
 	return(0);
 }
 
@@ -881,7 +816,7 @@
 	netbeui_shutdown,
 	netbeui_setsockopt,
 	netbeui_getsockopt,
-	netbeui_fcntl,
+	sock_no_fcntl,
 	netbeui_sendmsg,
 	netbeui_recvmsg
 };
diff -u --recursive --new-file v2.1.21/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.21/linux/net/netrom/af_netrom.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/af_netrom.c	Sun Jan 19 15:47:29 1997
@@ -31,7 +31,7 @@
  *			Alan(GW4PTS)	Started POSIXisms
  *	NET/ROM 006	Alan(GW4PTS)	Brought in line with the ANK changes
  */
-  
+
 #include <linux/config.h>
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 #include <linux/module.h>
@@ -75,7 +75,8 @@
 int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
 int sysctl_netrom_transport_no_activity_timeout   = NR_DEFAULT_IDLE;
 int sysctl_netrom_transport_packet_length         = NR_DEFAULT_PACLEN;
-int sysctl_netrom_routing_control                 = 1;
+int sysctl_netrom_routing_control                 = NR_DEFAULT_ROUTING;
+int sysctl_netrom_link_fails_count                = NR_DEFAULT_FAILS;
 
 static unsigned short circuit = 0x101;
 
@@ -88,7 +89,7 @@
 	kfree_s(sk->protinfo.nr, sizeof(*sk->protinfo.nr));
 
 	sk_free(sk);
-	
+
 	MOD_DEC_USE_COUNT;
 }
 
@@ -118,11 +119,12 @@
 /*
  *	Socket removal during an interrupt is now safe.
  */
+
 static void nr_remove_socket(struct sock *sk)
 {
 	struct sock *s;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
@@ -151,7 +153,7 @@
 static void nr_kill_by_device(struct device *dev)
 {
 	struct sock *s;
-	
+
 	for (s = nr_list; s != NULL; s = s->next) {
 		if (s->protinfo.nr->device == dev) {
 			s->protinfo.nr->state  = NR_STATE_0;
@@ -174,7 +176,7 @@
 
 	if (event != NETDEV_DOWN)
 		return NOTIFY_DONE;
-		
+
 	nr_kill_by_device(dev);
 	nr_rt_device_down(dev);
 	
@@ -269,7 +271,7 @@
 /*
  *	Deferred destroy.
  */
-void nr_destroy_socket(struct sock * sk);
+void nr_destroy_socket(struct sock *);
 
 /*
  *	Handler for deferred kills.
@@ -289,15 +291,15 @@
 {
 	struct sk_buff *skb;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
-	
+
 	del_timer(&sk->timer);
-	
+
 	nr_remove_socket(sk);
 	nr_clear_queues(sk);		/* Flush the queues */
-	
+
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
 		if (skb->sk != sk) {			/* A pending connection */
 			skb->sk->dead = 1;	/* Queue the unaccepted socket for death */
@@ -307,8 +309,8 @@
 
 		kfree_skb(skb, FREE_READ);
 	}
-	
-	if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+
+	if (sk->wmem_alloc || sk->rmem_alloc) {	/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = nr_destroy_timer;
@@ -325,11 +327,6 @@
  *	Handling for system calls applied via the various interfaces to a
  *	NET/ROM socket object.
  */
- 
-static int nr_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
 
 /*
  * dl1bke 960311: set parameters for existing NET/ROM connections,
@@ -342,12 +339,12 @@
 	struct sock *sk;
 	unsigned long flags;
 	int err;
-	
+
 	if ((err = verify_area(VERIFY_READ, arg, sizeof(nr_ctl))) != 0)
 		return err;
 
 	copy_from_user(&nr_ctl, arg, sizeof(nr_ctl));
-	
+
 	if ((sk = nr_find_socket(nr_ctl.index, nr_ctl.id)) == NULL)
 		return -ENOTCONN;
 
@@ -368,8 +365,8 @@
 	  	case NETROM_T1:
   			if (nr_ctl.arg < 1) 
   				return -EINVAL;
-  			sk->protinfo.nr->rtt = (nr_ctl.arg * PR_SLOWHZ) / 2;
-  			sk->protinfo.nr->t1  = nr_ctl.arg * PR_SLOWHZ;
+  			sk->protinfo.nr->rtt = (nr_ctl.arg * NR_SLOWHZ) / 2;
+  			sk->protinfo.nr->t1  = nr_ctl.arg * NR_SLOWHZ;
   			save_flags(flags); cli();
   			if (sk->protinfo.nr->t1timer > sk->protinfo.nr->t1)
   				sk->protinfo.nr->t1timer = sk->protinfo.nr->t1;
@@ -380,7 +377,7 @@
 	  		if (nr_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.nr->t2 = nr_ctl.arg * PR_SLOWHZ;
+	  		sk->protinfo.nr->t2 = nr_ctl.arg * NR_SLOWHZ;
 	  		if (sk->protinfo.nr->t2timer > sk->protinfo.nr->t2)
 	  			sk->protinfo.nr->t2timer = sk->protinfo.nr->t2;
 	  		restore_flags(flags);
@@ -397,7 +394,7 @@
 	  		if (nr_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.nr->t4 = nr_ctl.arg * PR_SLOWHZ;
+	  		sk->protinfo.nr->t4 = nr_ctl.arg * NR_SLOWHZ;
 	  		if (sk->protinfo.nr->t4timer > sk->protinfo.nr->t4)
 	  			sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
 	  		restore_flags(flags);
@@ -407,7 +404,7 @@
 	  		if (nr_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.nr->idle = nr_ctl.arg * 60 * PR_SLOWHZ;
+	  		sk->protinfo.nr->idle = nr_ctl.arg * 60 * NR_SLOWHZ;
 	  		if (sk->protinfo.nr->idletimer > sk->protinfo.nr->idle)
 	  			sk->protinfo.nr->idletimer = sk->protinfo.nr->idle;
 	  		restore_flags(flags);
@@ -431,11 +428,9 @@
 static int nr_setsockopt(struct socket *sock, int level, int optname,
 	char *optval, int optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int err, opt;
 
-	sk = sock->sk;
-	
 	if (level != SOL_NETROM)
 		return -EOPNOTSUPP;
 
@@ -446,38 +441,38 @@
 		return err;
 
 	get_user(opt, (int *)optval);
-	
+
 	switch (optname) {
 		case NETROM_T1:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.nr->rtt = (opt * PR_SLOWHZ) / 2;
+			sk->protinfo.nr->rtt = (opt * NR_SLOWHZ) / 2;
 			return 0;
 
 		case NETROM_T2:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.nr->t2 = opt * PR_SLOWHZ;
+			sk->protinfo.nr->t2 = opt * NR_SLOWHZ;
 			return 0;
-			
+
 		case NETROM_N2:
 			if (opt < 1 || opt > 31)
 				return -EINVAL;
 			sk->protinfo.nr->n2 = opt;
 			return 0;
-			
+
 		case NETROM_T4:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.nr->t4 = opt * PR_SLOWHZ;
+			sk->protinfo.nr->t4 = opt * NR_SLOWHZ;
 			return 0;
-			
+
 		case NETROM_IDLE:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.nr->idle = opt * 60 * PR_SLOWHZ;
+			sk->protinfo.nr->idle = opt * 60 * NR_SLOWHZ;
 			return 0;
-			
+
 		case NETROM_HDRINCL:
 			sk->protinfo.nr->hdrincl = opt ? 1 : 0;
 			return 0;
@@ -487,7 +482,7 @@
 				return -EINVAL;
 			sk->protinfo.nr->paclen = opt;
 			return 0;
-			
+
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -496,36 +491,34 @@
 static int nr_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int val = 0;
 	int err; 
 
-	sk = sock->sk;
-	
 	if (level != SOL_NETROM)
 		return -EOPNOTSUPP;
-	
+
 	switch (optname) {
 		case NETROM_T1:
-			val = (sk->protinfo.nr->t1 * 2) / PR_SLOWHZ;
+			val = (sk->protinfo.nr->t1 * 2) / NR_SLOWHZ;
 			break;
-			
+
 		case NETROM_T2:
-			val = sk->protinfo.nr->t2 / PR_SLOWHZ;
+			val = sk->protinfo.nr->t2 / NR_SLOWHZ;
 			break;
-			
+
 		case NETROM_N2:
 			val = sk->protinfo.nr->n2;
 			break;
-						
+
 		case NETROM_T4:
-			val = sk->protinfo.nr->t4 / PR_SLOWHZ;
+			val = sk->protinfo.nr->t4 / NR_SLOWHZ;
 			break;
-			
+
 		case NETROM_IDLE:
-			val = sk->protinfo.nr->idle / (PR_SLOWHZ * 60);
+			val = sk->protinfo.nr->idle / (NR_SLOWHZ * 60);
 			break;
-			
+
 		case NETROM_HDRINCL:
 			val = sk->protinfo.nr->hdrincl;
 			break;
@@ -565,30 +558,6 @@
 	return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if (!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if (!sk->dead)
-	{
-		sock_wake_async(sk->socket,1);
-		wake_up_interruptible(sk->sleep);
-	}
-}
-
-static void def_callback3(struct sock *sk, int len)
-{
-	if (!sk->dead)
-	{
-		sock_wake_async(sk->socket,2);
-		wake_up_interruptible(sk->sleep);
-	}
-}
-
 static int nr_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -602,34 +571,14 @@
 
 	nr = sk->protinfo.nr;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
+	sock_init_data(sock,sk);
 
 	init_timer(&sk->timer);
-	
+
 	sock->ops	  = &nr_proto_ops;
 
-	sk->socket        = sock;
-	sk->type          = sock->type;
 	sk->protocol      = protocol;
-	sk->allocation	  = GFP_KERNEL;
-	sk->rcvbuf        = SK_RMEM_MAX;
-	sk->sndbuf        = SK_WMEM_MAX;
-	sk->state         = TCP_CLOSE;
-	sk->priority      = SOPRI_NORMAL;
 	sk->mtu           = NETROM_MTU;	/* 236 */
-	sk->zapped        = 1;
-
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
-	if (sock != NULL) {
-		sock->sk  = sk;
-		sk->sleep = &sock->wait;
-	}
 
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
@@ -663,9 +612,7 @@
 
 	nr = sk->protinfo.nr;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
+	sock_init_data(NULL,sk);
 
 	init_timer(&sk->timer);
 
@@ -681,11 +628,6 @@
 	sk->sleep       = osk->sleep;
 	sk->zapped      = osk->zapped;
 
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
 	skb_queue_head_init(&nr->frag_queue);
@@ -710,6 +652,9 @@
 {
 	struct sock *sk = oldsock->sk;
 
+	if (sk == NULL || newsock == NULL)
+		return -EINVAL;
+
 	return nr_create(newsock, sk->protocol);
 }
 
@@ -775,19 +720,20 @@
 
 static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
 	struct device *dev;
 	ax25_address *user, *source;
-	
-	sk = sock->sk;
 
 	if (sk->zapped == 0)
 		return -EINVAL;
-		
+
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
+	if (addr->fsa_ax25.sax25_family != AF_NETROM)
+		return -EINVAL;
+
 	if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
 		if (sk->debug)
 			printk("NET/ROM: bind failed: invalid node callsign\n");
@@ -833,26 +779,29 @@
 	struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
 	ax25_address *user, *source = NULL;
 	struct device *dev;
-	
+
 	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
 		return 0;	/* Connect completed during a ERESTARTSYS event */
 	}
-	
+
 	if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
 		sock->state = SS_UNCONNECTED;
 		return -ECONNREFUSED;
 	}
-	
+
 	if (sk->state == TCP_ESTABLISHED)
 		return -EISCONN;	/* No reconnect on a seqpacket socket */
-		
+
 	sk->state   = TCP_CLOSE;	
 	sock->state = SS_UNCONNECTED;
 
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
+	if (addr->sax25_family != AF_NETROM)
+		return -EINVAL;
+
 	if (sk->zapped) {	/* Must bind first - autobinding in this may or may not work */
 		sk->zapped = 0;
 
@@ -883,14 +832,14 @@
 	sk->protinfo.nr->my_id    = circuit % 256;
 
 	circuit++;
-	
+
 	/* Move to connecting socket, start sending Connect Requests */
 	sock->state            = SS_CONNECTING;
 	sk->state              = TCP_SYN_SENT;
 	nr_establish_data_link(sk);
 	sk->protinfo.nr->state = NR_STATE_1;
 	nr_set_timer(sk);
-	
+
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
@@ -913,14 +862,14 @@
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
-	
+
 	sock->state = SS_CONNECTED;
 
 	sti();
-	
+
 	return 0;
 }
-	
+
 static int nr_socketpair(struct socket *sock1, struct socket *sock2)
 {
 	return -EOPNOTSUPP;
@@ -932,19 +881,20 @@
 	struct sock *newsk;
 	struct sk_buff *skb;
 
-	if (newsock->sk)
-		sk_free(newsock->sk);
+	if (newsock->sk != NULL)
+		nr_destroy_socket(newsock->sk);
 
 	newsock->sk = NULL;
-	
-	sk = sock->sk;
+
+	if ((sk = sock->sk) == NULL)
+		return -EINVAL;
 
 	if (sk->type != SOCK_SEQPACKET)
 		return -EOPNOTSUPP;
-	
+
 	if (sk->state != TCP_LISTEN)
 		return -EINVAL;
-		
+
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
@@ -954,7 +904,7 @@
 		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
 			if (flags & O_NONBLOCK) {
 				sti();
-				return 0;
+				return -EWOULDBLOCK;
 			}
 			interruptible_sleep_on(sk->sleep);
 			if (current->signal & ~current->blocked) {
@@ -981,10 +931,8 @@
 	int *uaddr_len, int peer)
 {
 	struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
-	struct sock *sk;
-	
-	sk = sock->sk;
-	
+	struct sock *sk = sock->sk;
+
 	if (peer != 0) {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
@@ -1002,7 +950,7 @@
 
 	return 0;
 }
- 
+
 int nr_rx_frame(struct sk_buff *skb, struct device *dev)
 {
 	struct sock *sk;
@@ -1054,7 +1002,7 @@
 
 	if ((frametype & 0x0F) != NR_CONNREQ)
 		return 0;
-		
+
 	sk = nr_find_listener(dest);
 
 	user = (ax25_address *)(skb->data + 21);
@@ -1079,7 +1027,7 @@
 
 	make->protinfo.nr->my_index    = circuit / 256;
 	make->protinfo.nr->my_id       = circuit % 256;
-	
+
 	circuit++;
 
 	/* Window negotiation */
@@ -1089,8 +1037,8 @@
 	/* L4 timeout negotiation */
 	if (skb->len == 37) {
 		timeout = skb->data[36] * 256 + skb->data[35];
-		if (timeout * PR_SLOWHZ < make->protinfo.nr->rtt * 2)
-			make->protinfo.nr->rtt = (timeout * PR_SLOWHZ) / 2;
+		if (timeout * NR_SLOWHZ < make->protinfo.nr->rtt * 2)
+			make->protinfo.nr->rtt = (timeout * NR_SLOWHZ) / 2;
 		make->protinfo.nr->bpqext = 1;
 	} else {
 		make->protinfo.nr->bpqext = 0;
@@ -1128,7 +1076,7 @@
 	struct sk_buff *skb;
 	unsigned char *asmptr;
 	int size;
-	
+
 	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
@@ -1142,7 +1090,7 @@
 
 	if (sk->protinfo.nr->device == NULL)
 		return -ENETUNREACH;
-		
+
 	if (usax) {
 		if (msg->msg_namelen < sizeof(sax))
 			return -EINVAL;
@@ -1157,7 +1105,7 @@
 		sax.sax25_family = AF_NETROM;
 		sax.sax25_call   = sk->protinfo.nr->dest_addr;
 	}
-	
+
 	if (sk->debug)
 		printk("NET/ROM: sendto: Addresses built.\n");
 
@@ -1170,11 +1118,10 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->sk   = sk;
-	skb->arp  = 1;
+	skb->arp = 1;
 
 	skb_reserve(skb, size - len);
-	
+
 	/*
 	 *	Push down the NET/ROM header
 	 */
@@ -1191,7 +1138,7 @@
 	*asmptr++ = 0;		/* To be filled in later */
 	*asmptr++ = 0;		/*      Ditto            */
 	*asmptr++ = NR_INFO;
-	
+
 	if (sk->debug)
 		printk("Built header.\n");
 
@@ -1202,7 +1149,7 @@
 	skb->h.raw = skb_put(skb, len);
 
 	asmptr = skb->h.raw;
-	
+
 	if (sk->debug)
 		printk("NET/ROM: Appending user data\n");
 
@@ -1257,17 +1204,13 @@
 	}
 
 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-	
-	if (sax != NULL) {
-		struct sockaddr_ax25 addr;
-		
-		addr.sax25_family = AF_NETROM;
-		memcpy(&addr.sax25_call, skb->data + 7, AX25_ADDR_LEN);
 
-		*sax = addr;
+	if (sax != NULL) {
+		sax->sax25_family = AF_NETROM;
+		memcpy(sax->sax25_call.ax25_call, skb->data + 7, AX25_ADDR_LEN);
 	}
 
-	msg->msg_namelen=sizeof(*sax);
+	msg->msg_namelen = sizeof(*sax);
 
 	skb_free_datagram(sk, skb);
 
@@ -1355,7 +1298,7 @@
 	int len = 0;
 	off_t pos = 0;
 	off_t begin = 0;
-  
+
 	cli();
 
 	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2    n2  rtt wnd paclen Snd-Q Rcv-Q\n");
@@ -1365,7 +1308,7 @@
 			devname = "???";
 		else
 			devname = dev->name;
-	
+
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&s->protinfo.nr->user_addr));
 		len += sprintf(buffer + len, "%-9s ",
@@ -1376,22 +1319,22 @@
 			s->protinfo.nr->your_index, s->protinfo.nr->your_id,
 			s->protinfo.nr->state,
 			s->protinfo.nr->vs, s->protinfo.nr->vr, s->protinfo.nr->va,
-			s->protinfo.nr->t1timer / PR_SLOWHZ,
-			s->protinfo.nr->t1      / PR_SLOWHZ,
-			s->protinfo.nr->t2timer / PR_SLOWHZ,
-			s->protinfo.nr->t2      / PR_SLOWHZ,
+			s->protinfo.nr->t1timer / NR_SLOWHZ,
+			s->protinfo.nr->t1      / NR_SLOWHZ,
+			s->protinfo.nr->t2timer / NR_SLOWHZ,
+			s->protinfo.nr->t2      / NR_SLOWHZ,
 			s->protinfo.nr->n2count, s->protinfo.nr->n2,
-			s->protinfo.nr->rtt     / PR_SLOWHZ,
+			s->protinfo.nr->rtt     / NR_SLOWHZ,
 			s->protinfo.nr->window, s->protinfo.nr->paclen,
 			s->wmem_alloc, s->rmem_alloc);
-		
+
 		pos = begin + len;
 
 		if (pos < offset) {
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -1414,7 +1357,7 @@
 
 static struct proto_ops nr_proto_ops = {
 	AF_NETROM,
-	
+
 	nr_dup,
 	nr_release,
 	nr_bind,
@@ -1428,7 +1371,7 @@
 	nr_shutdown,
 	nr_setsockopt,
 	nr_getsockopt,
-	nr_fcntl,
+	sock_no_fcntl,
 	nr_sendmsg,
 	nr_recvmsg
 };
diff -u --recursive --new-file v2.1.21/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.1.21/linux/net/netrom/nr_dev.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/nr_dev.c	Sun Jan 19 15:47:29 1997
@@ -86,16 +86,16 @@
 	unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 
 	memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
-	buff[6] &= ~LAPB_C;
-	buff[6] &= ~LAPB_E;
-	buff[6] |= SSSID_SPARE;
+	buff[6] &= ~AX25_CBIT;
+	buff[6] &= ~AX25_EBIT;
+	buff[6] |= AX25_SSSID_SPARE;
 	buff    += AX25_ADDR_LEN;
 
 	if (daddr != NULL)
 		memcpy(buff, daddr, dev->addr_len);
-	buff[6] &= ~LAPB_C;
-	buff[6] |= LAPB_E;
-	buff[6] |= SSSID_SPARE;
+	buff[6] &= ~AX25_CBIT;
+	buff[6] |= AX25_EBIT;
+	buff[6] |= AX25_SSSID_SPARE;
 	buff    += AX25_ADDR_LEN;
 
 	*buff++ = sysctl_netrom_network_ttl_initialiser;
@@ -124,21 +124,21 @@
 		return 1;
 	}
 
-	bp[6] &= ~LAPB_C;
-	bp[6] &= ~LAPB_E;
-	bp[6] |= SSSID_SPARE;
+	bp[6] &= ~AX25_CBIT;
+	bp[6] &= ~AX25_EBIT;
+	bp[6] |= AX25_SSSID_SPARE;
 	bp    += AX25_ADDR_LEN;
 
-	bp[6] &= ~LAPB_C;
-	bp[6] |= LAPB_E;
-	bp[6] |= SSSID_SPARE;
+	bp[6] &= ~AX25_CBIT;
+	bp[6] |= AX25_EBIT;
+	bp[6] |= AX25_SSSID_SPARE;
 
 	if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
 		kfree_skb(skb, FREE_WRITE);
 		return 1;
 	}
 
-	if (skbn->sk != NULL)
+	if (skb->sk != NULL)
 		skb_set_owner_w(skbn, skb->sk);
 
 	kfree_skb(skb, FREE_WRITE);
diff -u --recursive --new-file v2.1.21/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- v2.1.21/linux/net/netrom/nr_in.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/nr_in.c	Sun Jan 19 15:47:29 1997
@@ -59,7 +59,7 @@
 		skb_queue_tail(&sk->protinfo.nr->frag_queue, skb);
 		return 0;
 	}
-	
+
 	if (!more && sk->protinfo.nr->fraglen > 0) {	/* End of fragment */
 		sk->protinfo.nr->fraglen += skb->len;
 		skb_queue_tail(&sk->protinfo.nr->frag_queue, skb);
@@ -213,10 +213,10 @@
 		case NR_INFOACK | NR_NAK_FLAG:
 		case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
-				sk->protinfo.nr->condition |= PEER_RX_BUSY_CONDITION;
+				sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
 				sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
 			} else {
-				sk->protinfo.nr->condition &= ~PEER_RX_BUSY_CONDITION;
+				sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
 				sk->protinfo.nr->t4timer = 0;
 			}
 			if (!nr_validate_nr(sk, nr)) {
@@ -226,14 +226,14 @@
 				nr_frames_acked(sk, nr);
 				nr_send_nak_frame(sk);
 			} else {
-				if (sk->protinfo.nr->condition & PEER_RX_BUSY_CONDITION) {
+				if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) {
 					nr_frames_acked(sk, nr);
 				} else {
 					nr_check_iframes_acked(sk, nr);
 				}
 			}
 			break;
-			
+
 		case NR_INFO:
 		case NR_INFO | NR_NAK_FLAG:
 		case NR_INFO | NR_CHOKE_FLAG:
@@ -243,10 +243,10 @@
 		case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
 		case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
-				sk->protinfo.nr->condition |= PEER_RX_BUSY_CONDITION;
+				sk->protinfo.nr->condition |= NR_COND_PEER_RX_BUSY;
 				sk->protinfo.nr->t4timer = sk->protinfo.nr->t4;
 			} else {
-				sk->protinfo.nr->condition &= ~PEER_RX_BUSY_CONDITION;
+				sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
 				sk->protinfo.nr->t4timer = 0;
 			}
 			if (nr_validate_nr(sk, nr)) {
@@ -254,7 +254,7 @@
 					nr_frames_acked(sk, nr);
 					nr_send_nak_frame(sk);
 				} else {
-					if (sk->protinfo.nr->condition & PEER_RX_BUSY_CONDITION) {
+					if (sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) {
 						nr_frames_acked(sk, nr);
 					} else {
 						nr_check_iframes_acked(sk, nr);
@@ -263,7 +263,7 @@
 			}
 			queued = 1;
 			skb_queue_head(&sk->protinfo.nr->reseq_queue, skb);
-			if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION)
+			if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)
 				break;
 			skb_queue_head_init(&temp_queue);
 			do {
@@ -274,7 +274,7 @@
 						if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
 							sk->protinfo.nr->vr = (sk->protinfo.nr->vr + 1) % NR_MODULUS;
 						} else {
-							sk->protinfo.nr->condition |= OWN_RX_BUSY_CONDITION;
+							sk->protinfo.nr->condition |= NR_COND_OWN_RX_BUSY;
 							skb_queue_tail(&temp_queue, skbn);
 						}
 					} else if (nr_in_rx_window(sk, ns)) {
@@ -293,9 +293,9 @@
 			if (((sk->protinfo.nr->vl + sk->protinfo.nr->window) % NR_MODULUS) == sk->protinfo.nr->vr) {
 				nr_enquiry_response(sk);
 			} else {
-				if (!(sk->protinfo.nr->condition & ACK_PENDING_CONDITION)) {
+				if (!(sk->protinfo.nr->condition & NR_COND_ACK_PENDING)) {
 					sk->protinfo.nr->t2timer = sk->protinfo.nr->t2;
-					sk->protinfo.nr->condition |= ACK_PENDING_CONDITION;
+					sk->protinfo.nr->condition |= NR_COND_ACK_PENDING;
 				}
 			}
 			break;
diff -u --recursive --new-file v2.1.21/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c
--- v2.1.21/linux/net/netrom/nr_out.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/nr_out.c	Sun Jan 19 15:47:29 1997
@@ -53,7 +53,7 @@
 	int err, frontlen, len, mtu;
 
 	mtu = sk->protinfo.nr->paclen;
-	
+
 	if (skb->len - NR_TRANSPORT_LEN > mtu) {
 		/* Save a copy of the Transport Header */
 		memcpy(transport, skb->data, NR_TRANSPORT_LEN);
@@ -82,10 +82,10 @@
 
 			if (skb->len > 0)
 				skbn->data[4] |= NR_MORE_FLAG;
-		
+
 			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
 		}
-		
+
 		kfree_skb(skb, FREE_WRITE);
 	} else {
 		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */
@@ -107,7 +107,7 @@
 	skb->data[2] = sk->protinfo.nr->vs;
 	skb->data[3] = sk->protinfo.nr->vr;
 
-	if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION)
+	if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)
 		skb->data[4] |= NR_CHOKE_FLAG;
 
 	nr_transmit_buffer(sk, skb);	
@@ -116,22 +116,22 @@
 void nr_send_nak_frame(struct sock *sk)
 {
 	struct sk_buff *skb, *skbn;
-	
+
 	if ((skb = skb_peek(&sk->protinfo.nr->ack_queue)) == NULL)
 		return;
-		
+
 	if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL)
 		return;
 
 	skbn->data[2] = sk->protinfo.nr->va;
 	skbn->data[3] = sk->protinfo.nr->vr;
 
-	if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION)
+	if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)
 		skbn->data[4] |= NR_CHOKE_FLAG;
 
 	nr_transmit_buffer(sk, skbn);
 
-	sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION;
+	sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 	sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
 	sk->protinfo.nr->t1timer    = 0;
 }
@@ -139,16 +139,15 @@
 void nr_kick(struct sock *sk)
 {
 	struct sk_buff *skb, *skbn;
-	int last = 1;
-	unsigned short start, end, next;
+	unsigned short start, end;
 
 	del_timer(&sk->timer);
 
 	start = (skb_peek(&sk->protinfo.nr->ack_queue) == NULL) ? sk->protinfo.nr->va : sk->protinfo.nr->vs;
 	end   = (sk->protinfo.nr->va + sk->protinfo.nr->window) % NR_MODULUS;
 
-	if (!(sk->protinfo.nr->condition & PEER_RX_BUSY_CONDITION) &&
-	    start != end                                  &&
+	if (!(sk->protinfo.nr->condition & NR_COND_PEER_RX_BUSY) &&
+	    start != end                                         &&
 	    skb_peek(&sk->write_queue) != NULL) {
 
 		sk->protinfo.nr->vs = start;
@@ -169,25 +168,24 @@
 				break;
 			}
 
-			next = (sk->protinfo.nr->vs + 1) % NR_MODULUS;
-			last = (next == end);
+			skb_set_owner_w(skbn, sk);
 
 			/*
 			 * Transmit the frame copy.
 			 */
 			nr_send_iframe(sk, skbn);
 
-			sk->protinfo.nr->vs = next;
+			sk->protinfo.nr->vs = (sk->protinfo.nr->vs + 1) % NR_MODULUS;
 
 			/*
 			 * Requeue the original data frame.
 			 */
 			skb_queue_tail(&sk->protinfo.nr->ack_queue, skb);
 
-		} while (!last && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+		} while (sk->protinfo.nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
 
 		sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
-		sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION;
+		sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 
 		if (sk->protinfo.nr->t1timer == 0) {
 			sk->protinfo.nr->t1timer = sk->protinfo.nr->t1 = nr_calculate_t1(sk);
@@ -207,15 +205,15 @@
 	dptr = skb_push(skb, NR_NETWORK_LEN);
 
 	memcpy(dptr, &sk->protinfo.nr->source_addr, AX25_ADDR_LEN);
-	dptr[6] &= ~LAPB_C;
-	dptr[6] &= ~LAPB_E;
-	dptr[6] |= SSSID_SPARE;
+	dptr[6] &= ~AX25_CBIT;
+	dptr[6] &= ~AX25_EBIT;
+	dptr[6] |= AX25_SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
 	memcpy(dptr, &sk->protinfo.nr->dest_addr, AX25_ADDR_LEN);
-	dptr[6] &= ~LAPB_C;
-	dptr[6] |= LAPB_E;
-	dptr[6] |= SSSID_SPARE;
+	dptr[6] &= ~AX25_CBIT;
+	dptr[6] |= AX25_EBIT;
+	dptr[6] |= AX25_SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
 	*dptr++ = sysctl_netrom_network_ttl_initialiser;
@@ -256,19 +254,19 @@
 void nr_enquiry_response(struct sock *sk)
 {
 	int frametype = NR_INFOACK;
-	
-	if (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION) {
+
+	if (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY) {
 		frametype |= NR_CHOKE_FLAG;
 	} else {
 		if (skb_peek(&sk->protinfo.nr->reseq_queue) != NULL) {
 			frametype |= NR_NAK_FLAG;
 		}
 	}
-	
+
 	nr_write_internal(sk, frametype);
 
 	sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
-	sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION;
+	sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 }
 
 void nr_check_iframes_acked(struct sock *sk, unsigned short nr)
diff -u --recursive --new-file v2.1.21/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c
--- v2.1.21/linux/net/netrom/nr_route.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/nr_route.c	Sun Jan 19 15:47:29 1997
@@ -21,8 +21,9 @@
  *					as node callsign.
  *			Alan Cox(GW4PTS) Added the firewall hooks.
  *	NET/ROM 006	Jonathan(G4KLX)	Added the setting of digipeated neighbours.
+ *			Tomi(OH2BNS)	Routing quality and link failure changes.
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 #include <linux/errno.h>
@@ -83,6 +84,9 @@
 		if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
 			break;
 
+	if (nr_neigh != NULL)
+		nr_neigh->failed = 0;
+
 	if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
 		return 0;
 
@@ -93,10 +97,7 @@
 		nr_neigh->callsign = *ax25;
 		nr_neigh->digipeat = NULL;
 		nr_neigh->dev      = dev;
-		if (ax25cmp(nr, ax25) == 0)
-			nr_neigh->quality = quality;
-		else
-			nr_neigh->quality = sysctl_netrom_default_path_quality;
+		nr_neigh->quality  = sysctl_netrom_default_path_quality;
 		nr_neigh->locked   = 0;
 		nr_neigh->count    = 0;
 		nr_neigh->number   = nr_neigh_no++;
@@ -118,6 +119,9 @@
 		restore_flags(flags);
 	}
 
+	if (quality != 0 && ax25cmp(nr, ax25) == 0)
+		nr_neigh->quality = quality;
+
 	if (nr_node == NULL) {
 		if ((nr_node = (struct nr_node *)kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
 			return -ENOMEM;
@@ -131,7 +135,7 @@
 		nr_node->routes[0].quality   = quality;
 		nr_node->routes[0].obs_count = obs_count;
 		nr_node->routes[0].neighbour = nr_neigh;
-			
+
 		save_flags(flags);
 		cli();
 
@@ -139,15 +143,15 @@
 		nr_node_list  = nr_node;
 
 		restore_flags(flags);
-		
+
 		nr_neigh->count++;
 
 		return 0;
-	} else {
-		if (nr_node->mnemonic[0] == '\0')
-			strcpy(nr_node->mnemonic, mnemonic);
 	}
 
+	if (quality != 0)
+		strcpy(nr_node->mnemonic, mnemonic);
+
 	for (found = 0, i = 0; i < nr_node->count; i++) {
 		if (nr_node->routes[i].neighbour == nr_neigh) {
 			nr_node->routes[i].quality   = quality;
@@ -166,7 +170,7 @@
 			nr_node->routes[0].quality   = quality;
 			nr_node->routes[0].obs_count = obs_count;
 			nr_node->routes[0].neighbour = nr_neigh;
-				
+
 			nr_node->which++;
 			nr_node->count++;
 			nr_neigh->count++;
@@ -174,10 +178,10 @@
 			/* It must be better than the worst */
 			if (quality > nr_node->routes[2].quality) {
 				nr_node->routes[2].neighbour->count--;
-				
+
 				if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
 					nr_remove_neigh(nr_node->routes[2].neighbour);
-			
+
 				nr_node->routes[2].quality   = quality;
 				nr_node->routes[2].obs_count = obs_count;
 				nr_node->routes[2].neighbour = nr_neigh;
@@ -240,7 +244,7 @@
 {
 	struct nr_node *s;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
@@ -307,7 +311,7 @@
 	struct nr_node  *nr_node;
 	struct nr_neigh *nr_neigh;
 	int i;
-	
+
 	for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 		if (ax25cmp(callsign, &nr_node->callsign) == 0)
 			break;
@@ -319,7 +323,7 @@
 			break;
 
 	if (nr_neigh == NULL) return -EINVAL;
-	
+
 	for (i = 0; i < nr_node->count; i++) {
 		if (nr_node->routes[i].neighbour == nr_neigh) {
 			nr_neigh->count--;
@@ -328,7 +332,7 @@
 				nr_remove_neigh(nr_neigh);
 				
 			nr_node->count--;
-			
+
 			if (nr_node->count == 0) {
 				nr_remove_node(nr_node);
 			} else {
@@ -375,6 +379,7 @@
 	nr_neigh->locked   = 1;
 	nr_neigh->count    = 0;
 	nr_neigh->number   = nr_neigh_no++;
+	nr_neigh->failed   = 0;
 
 	if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
 		if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
@@ -386,7 +391,7 @@
 
 	save_flags(flags);
 	cli();
-			
+
 	nr_neigh->next = nr_neigh_list;
 	nr_neigh_list  = nr_neigh;
 
@@ -443,9 +448,9 @@
 
 			case 1:		/* From 1 -> 0 */
 				nr_neigh = s->routes[i].neighbour;
-				
+
 				nr_neigh->count--;
-						
+
 				if (nr_neigh->count == 0 && !nr_neigh->locked)
 					nr_remove_neigh(nr_neigh);
 
@@ -487,14 +492,14 @@
 	while (nr_neigh != NULL) {
 		s        = nr_neigh;
 		nr_neigh = nr_neigh->next;
-		
+
 		if (s->dev == dev) {
 			nr_node = nr_node_list;
 
 			while (nr_node != NULL) {
 				t       = nr_node;
 				nr_node = nr_node->next;
-				
+
 				for (i = 0; i < t->count; i++) {
 					if (t->routes[i].neighbour == s) {
 						t->count--;
@@ -509,11 +514,11 @@
 						}
 					}
 				}
-				
+
 				if (t->count <= 0)
 					nr_remove_node(t);
 			}
-			
+
 			nr_remove_neigh(s);
 		}
 	}
@@ -561,7 +566,7 @@
 	for (dev = dev_base; dev != NULL; dev = dev->next)
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0)
 			return dev;
-	
+
 	return NULL;
 }
 
@@ -658,9 +663,11 @@
 	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 		if (ax25cmp(&nr_neigh->callsign, callsign) == 0 && nr_neigh->dev == dev)
 			break;
-			
+
 	if (nr_neigh == NULL) return;
-	
+
+	if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return;
+
 	for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
 		if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh)
 			nr_node->which++;
@@ -677,7 +684,7 @@
 	struct nr_node  *nr_node;
 	struct device *dev;
 	unsigned char *dptr;
-	
+
 #ifdef CONFIG_FIREWALL
 	if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
 		return 0;
@@ -786,16 +793,17 @@
 
 	cli();
 
-	len += sprintf(buffer, "addr  callsign  dev  qual lock count digipeaters\n");
+	len += sprintf(buffer, "addr  callsign  dev  qual lock count failed digipeaters\n");
 
 	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
-		len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d",
+		len += sprintf(buffer + len, "%05d %-9s %-4s  %3d    %d   %3d    %3d",
 			nr_neigh->number,
 			ax2asc(&nr_neigh->callsign),
 			nr_neigh->dev ? nr_neigh->dev->name : "???",
 			nr_neigh->quality,
 			nr_neigh->locked,
-			nr_neigh->count);
+			nr_neigh->count,
+			nr_neigh->failed);
 
 		if (nr_neigh->digipeat != NULL) {
 			for (i = 0; i < nr_neigh->digipeat->ndigi; i++)
@@ -810,7 +818,7 @@
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
diff -u --recursive --new-file v2.1.21/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- v2.1.21/linux/net/netrom/nr_subr.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/nr_subr.c	Sun Jan 19 15:47:29 1997
@@ -16,7 +16,7 @@
  *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_subr.c
  *	NET/ROM	003	Jonathan(G4KLX)	Added G8BPQ NET/ROM extensions.
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
 #include <linux/errno.h>
@@ -48,23 +48,17 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
-		skb->sk   = sk;
+	while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&sk->protinfo.nr->ack_queue)) != NULL) {
-		skb->sk   = sk;
+	while ((skb = skb_dequeue(&sk->protinfo.nr->ack_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&sk->protinfo.nr->reseq_queue)) != NULL) {
+	while ((skb = skb_dequeue(&sk->protinfo.nr->reseq_queue)) != NULL)
 		kfree_skb(skb, FREE_READ);
-	}
 
-	while ((skb = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL) {
+	while ((skb = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL)
 		kfree_skb(skb, FREE_READ);
-	}
 }
 
 /*
@@ -82,7 +76,6 @@
 	if (sk->protinfo.nr->va != nr) {
 		while (skb_peek(&sk->protinfo.nr->ack_queue) != NULL && sk->protinfo.nr->va != nr) {
 		        skb = skb_dequeue(&sk->protinfo.nr->ack_queue);
-		        skb->sk   = sk;
 			kfree_skb(skb, FREE_WRITE);
 			sk->protinfo.nr->va = (sk->protinfo.nr->va + 1) % NR_MODULUS;
 		}
@@ -119,7 +112,7 @@
 		if (nr == vc) return 1;
 		vc = (vc + 1) % NR_MODULUS;
 	}
-	
+
 	if (nr == sk->protinfo.nr->vs) return 1;
 
 	return 0;
@@ -152,7 +145,7 @@
 	int len, timeout;
 
 	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
-	
+
 	switch (frametype & 0x0F) {
 		case NR_CONNREQ:
 			len += 17;
@@ -168,7 +161,7 @@
 			printk(KERN_ERR "nr_write_internal: invalid frame type %d\n", frametype);
 			return;
 	}
-	
+
 	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 		return;
 
@@ -182,7 +175,7 @@
 	switch (frametype & 0x0F) {
 
 		case NR_CONNREQ:
-			timeout  = (sk->protinfo.nr->rtt / PR_SLOWHZ) * 2;
+			timeout  = (sk->protinfo.nr->rtt / NR_SLOWHZ) * 2;
 			*dptr++  = sk->protinfo.nr->my_index;
 			*dptr++  = sk->protinfo.nr->my_id;
 			*dptr++  = 0;
@@ -190,14 +183,14 @@
 			*dptr++  = frametype;
 			*dptr++  = sk->protinfo.nr->window;
 			memcpy(dptr, &sk->protinfo.nr->user_addr, AX25_ADDR_LEN);
-			dptr[6] &= ~LAPB_C;
-			dptr[6] &= ~LAPB_E;
-			dptr[6] |= SSSID_SPARE;
+			dptr[6] &= ~AX25_CBIT;
+			dptr[6] &= ~AX25_EBIT;
+			dptr[6] |= AX25_SSSID_SPARE;
 			dptr    += AX25_ADDR_LEN;
 			memcpy(dptr, &sk->protinfo.nr->source_addr, AX25_ADDR_LEN);
-			dptr[6] &= ~LAPB_C;
-			dptr[6] &= ~LAPB_E;
-			dptr[6] |= SSSID_SPARE;
+			dptr[6] &= ~AX25_CBIT;
+			dptr[6] &= ~AX25_EBIT;
+			dptr[6] |= AX25_SSSID_SPARE;
 			dptr    += AX25_ADDR_LEN;
 			*dptr++  = timeout % 256;
 			*dptr++  = timeout / 256;
@@ -254,15 +247,15 @@
 	dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
 
 	memcpy(dptr, skb->data + 7, AX25_ADDR_LEN);
-	dptr[6] &= ~LAPB_C;
-	dptr[6] &= ~LAPB_E;
-	dptr[6] |= SSSID_SPARE;
+	dptr[6] &= ~AX25_CBIT;
+	dptr[6] &= ~AX25_EBIT;
+	dptr[6] |= AX25_SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 	
 	memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
-	dptr[6] &= ~LAPB_C;
-	dptr[6] |= LAPB_E;
-	dptr[6] |= SSSID_SPARE;
+	dptr[6] &= ~AX25_CBIT;
+	dptr[6] |= AX25_EBIT;
+	dptr[6] |= AX25_SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
 	*dptr++ = sysctl_netrom_network_ttl_initialiser;
@@ -303,19 +296,11 @@
 	if (sk->protinfo.nr->t1timer > 0 && sk->protinfo.nr->n2count == 0)
 		sk->protinfo.nr->rtt = (9 * sk->protinfo.nr->rtt + sk->protinfo.nr->t1 - sk->protinfo.nr->t1timer) / 10;
 
-#ifdef	NR_T1CLAMPLO
-	/* Don't go below one tenth of a second */
-	if (sk->protinfo.nr->rtt < (NR_T1CLAMPLO))
-		sk->protinfo.nr->rtt = (NR_T1CLAMPLO);
-#else   /* Failsafe - some people might have sub 1/10th RTTs :-) **/
-        if (sk->protinfo.nr->rtt == 0)
-                sk->protinfo.nr->rtt = PR_SLOWHZ;
-#endif
-#ifdef  NR_T1CLAMPHI
-        /* OR above clamped seconds **/
-        if (sk->protinfo.nr->rtt > (NR_T1CLAMPHI))
-                sk->protinfo.nr->rtt = (NR_T1CLAMPHI);
-#endif
+	if (sk->protinfo.nr->rtt < NR_T1CLAMPLO)
+		sk->protinfo.nr->rtt = NR_T1CLAMPLO;
+
+        if (sk->protinfo.nr->rtt > NR_T1CLAMPHI)
+                sk->protinfo.nr->rtt = NR_T1CLAMPHI;
 }
 
 #endif
diff -u --recursive --new-file v2.1.21/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c
--- v2.1.21/linux/net/netrom/nr_timer.c	Thu Jan  2 15:55:28 1997
+++ linux/net/netrom/nr_timer.c	Sun Jan 19 15:47:29 1997
@@ -48,7 +48,7 @@
 void nr_set_timer(struct sock *sk)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&sk->timer);
@@ -65,7 +65,7 @@
 static void nr_reset_timer(struct sock *sk)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&sk->timer);
@@ -102,11 +102,11 @@
 			/*
 			 * Check for the state of the receive buffer.
 			 */
-			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.nr->condition & OWN_RX_BUSY_CONDITION)) {
-				sk->protinfo.nr->condition &= ~OWN_RX_BUSY_CONDITION;
-				nr_write_internal(sk, NR_INFOACK);
-				sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION;
+			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.nr->condition & NR_COND_OWN_RX_BUSY)) {
+				sk->protinfo.nr->condition &= ~NR_COND_OWN_RX_BUSY;
+				sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 				sk->protinfo.nr->vl         = sk->protinfo.nr->vr;
+				nr_write_internal(sk, NR_INFOACK);
 				break;
 			}
 			/*
@@ -121,15 +121,15 @@
 
 	if (sk->protinfo.nr->t2timer > 0 && --sk->protinfo.nr->t2timer == 0) {
 		if (sk->protinfo.nr->state == NR_STATE_3) {
-			if (sk->protinfo.nr->condition & ACK_PENDING_CONDITION) {
-				sk->protinfo.nr->condition &= ~ACK_PENDING_CONDITION;
+			if (sk->protinfo.nr->condition & NR_COND_ACK_PENDING) {
+				sk->protinfo.nr->condition &= ~NR_COND_ACK_PENDING;
 				nr_enquiry_response(sk);
 			}
 		}
 	}
 
 	if (sk->protinfo.nr->t4timer > 0 && --sk->protinfo.nr->t4timer == 0) {
-		sk->protinfo.nr->condition &= ~PEER_RX_BUSY_CONDITION;
+		sk->protinfo.nr->condition &= ~NR_COND_PEER_RX_BUSY;
 	}
 
 	if (sk->protinfo.nr->t1timer == 0 || --sk->protinfo.nr->t1timer > 0) {
diff -u --recursive --new-file v2.1.21/linux/net/netrom/sysctl_net_netrom.c linux/net/netrom/sysctl_net_netrom.c
--- v2.1.21/linux/net/netrom/sysctl_net_netrom.c	Tue Nov 12 15:56:16 1996
+++ linux/net/netrom/sysctl_net_netrom.c	Sun Jan 19 15:47:29 1997
@@ -16,18 +16,19 @@
 static int min_quality[] = {0}, max_quality[] = {255};
 static int min_obs[]     = {0}, max_obs[]     = {255};
 static int min_ttl[]     = {0}, max_ttl[]     = {255};
-static int min_t1[]      = {5 * PR_SLOWHZ};
-static int max_t1[]      = {600 * PR_SLOWHZ};
+static int min_t1[]      = {5 * NR_SLOWHZ};
+static int max_t1[]      = {600 * NR_SLOWHZ};
 static int min_n2[]      = {2}, max_n2[]      = {127};
-static int min_t2[]      = {1 * PR_SLOWHZ};
-static int max_t2[]      = {60 * PR_SLOWHZ};
-static int min_t4[]      = {1 * PR_SLOWHZ};
-static int max_t4[]      = {1000 * PR_SLOWHZ};
+static int min_t2[]      = {1 * NR_SLOWHZ};
+static int max_t2[]      = {60 * NR_SLOWHZ};
+static int min_t4[]      = {1 * NR_SLOWHZ};
+static int max_t4[]      = {1000 * NR_SLOWHZ};
 static int min_window[]  = {1}, max_window[]  = {127};
-static int min_idle[]    = {0 * PR_SLOWHZ};
-static int max_idle[]    = {65535 * PR_SLOWHZ};
+static int min_idle[]    = {0 * NR_SLOWHZ};
+static int max_idle[]    = {65535 * NR_SLOWHZ};
 static int min_n1[]      = {1}, max_n1[]      = {236};
 static int min_route[]   = {0}, max_route[]   = {1};
+static int min_fails[]   = {1}, max_fails[]   = {10};
 
 static struct ctl_table_header *nr_table_header;
 
@@ -65,6 +66,9 @@
         {NET_NETROM_ROUTING_CONTROL, "routing_control",
          &sysctl_netrom_routing_control, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_route, &max_route},
+        {NET_NETROM_LINK_FAILS_COUNT, "link_fails_count",
+         &sysctl_netrom_link_fails_count, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_fails, &max_fails},
 	{0}
 };
 
diff -u --recursive --new-file v2.1.21/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.21/linux/net/netsyms.c	Mon Dec 30 15:39:17 1996
+++ linux/net/netsyms.c	Sun Jan 19 15:47:29 1997
@@ -66,6 +66,10 @@
 extern void destroy_8023_client(struct datalink_proto *);
 #endif
 
+#ifdef CONFIG_ATALK_MODULE
+#include <net/sock.h>
+#endif
+
 extern char *skb_push_errstr;
 extern char *skb_put_errstr;
 
@@ -87,6 +91,7 @@
 EXPORT_SYMBOL(sk_free);
 EXPORT_SYMBOL(sock_wake_async);
 EXPORT_SYMBOL(sock_alloc_send_skb);
+EXPORT_SYMBOL(sock_no_fcntl);
 EXPORT_SYMBOL(sock_rfree);
 EXPORT_SYMBOL(sock_wfree);
 EXPORT_SYMBOL(skb_recv_datagram);
@@ -107,6 +112,11 @@
 EXPORT_SYMBOL(destroy_EII_client);
 #endif
 
+#ifdef CONFIG_ATALK_MODULE
+EXPORT_SYMBOL(sklist_destroy_socket);
+EXPORT_SYMBOL(sklist_insert_socket);
+#endif
+
 #ifdef CONFIG_INET
 /* Internet layer registration */
 EXPORT_SYMBOL(get_new_socknum);
@@ -125,10 +135,6 @@
 EXPORT_SYMBOL(ip_dev_find_tunnel);
 EXPORT_SYMBOL(inet_family_ops);
 
-#ifdef CONFIG_IP_FORWARD
-EXPORT_SYMBOL(ip_forward);
-#endif
-
 #ifdef CONFIG_IPV6_MODULE
 /* inet functions common to v4 and v6 */
 EXPORT_SYMBOL(inet_stream_ops);
@@ -245,7 +251,6 @@
 EXPORT_SYMBOL(ether_setup);
 EXPORT_SYMBOL(eth_type_trans);
 EXPORT_SYMBOL(eth_copy_and_sum);
-EXPORT_SYMBOL(arp_query);
 EXPORT_SYMBOL(alloc_skb);
 EXPORT_SYMBOL(__kfree_skb);
 EXPORT_SYMBOL(skb_clone);
diff -u --recursive --new-file v2.1.21/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.21/linux/net/rose/af_rose.c	Thu Jan  2 15:55:28 1997
+++ linux/net/rose/af_rose.c	Sun Jan 19 15:47:29 1997
@@ -18,7 +18,7 @@
  *			Terry (VK2KTJ)	Added support for variable length
  * 					address masks.
  */
-  
+
 #include <linux/config.h>
 #if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
 #include <linux/module.h>
@@ -67,6 +67,8 @@
 
 static struct proto_ops rose_proto_ops;
 
+ax25_address rose_callsign;
+
 /*
  *	Convert a Rose address into text.
  */
@@ -99,7 +101,7 @@
 	for (i = 0; i < 5; i++)
 		if (addr1->rose_addr[i] != addr2->rose_addr[i])
 			return 1;
-			
+
 	return 0;
 }
 
@@ -113,15 +115,15 @@
 	if (mask > 10)
 		return 1;
 
-	for (i = 0, j = 0; i < mask; i++) {
+	for (i = 0; i < mask; i++) {
 		j = i / 2;
 
-		if ((i % 2) != 0) {	/* odd place */
-			if ((addr1->rose_addr[j] & 0xF0) != (addr2->rose_addr[j] & 0xF0))
-				return 1;
-		} else {		/* even place */
+		if ((i % 2) != 0) {
 			if ((addr1->rose_addr[j] & 0x0F) != (addr2->rose_addr[j] & 0x0F))
 				return 1;
+		} else {
+			if ((addr1->rose_addr[j] & 0xF0) != (addr2->rose_addr[j] & 0xF0))
+				return 1;
 		}
 	}
 
@@ -151,7 +153,7 @@
 	}
 
 	MOD_INC_USE_COUNT;
-	
+
 	memset(rose, 0x00, sizeof(*rose));
 
 	sk->protinfo.rose = rose;
@@ -167,7 +169,7 @@
 {
 	struct sock *s;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
@@ -223,7 +225,7 @@
 	rose_kill_by_device(dev);
 	rose_rt_device_down(dev);
 	rose_link_device_down(dev);
-	
+
 	return NOTIFY_DONE;
 }
 
@@ -237,8 +239,8 @@
 	save_flags(flags);
 	cli();
 
-	sk->next = rose_list;
-	rose_list  = sk;
+	sk->next  = rose_list;
+	rose_list = sk;
 
 	restore_flags(flags);
 }
@@ -335,15 +337,15 @@
 {
 	struct sk_buff *skb;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
-	
+
 	del_timer(&sk->timer);
-	
+
 	rose_remove_socket(sk);
 	rose_clear_queues(sk);		/* Flush the queues */
-	
+
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
 		if (skb->sk != sk) {			/* A pending connection */
 			skb->sk->dead = 1;	/* Queue the unaccepted socket for death */
@@ -353,8 +355,8 @@
 
 		kfree_skb(skb, FREE_READ);
 	}
-	
-	if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+
+	if (sk->wmem_alloc || sk->rmem_alloc) {	/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = rose_destroy_timer;
@@ -371,11 +373,6 @@
  *	Handling for system calls applied via the various interfaces to a
  *	Rose socket object.
  */
- 
-static int rose_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
 
 /*
  * dl1bke 960311: set parameters for existing Rose connections,
@@ -420,7 +417,7 @@
   				return -EINVAL;
   			if (sk->protinfo.rose->neighbour != NULL) {
 	  			save_flags(flags); cli();
-	  			sk->protinfo.rose->neighbour->t0 = rose_ctl.arg * PR_SLOWHZ;
+	  			sk->protinfo.rose->neighbour->t0 = rose_ctl.arg * ROSE_SLOWHZ;
 	  			restore_flags(flags);
 	  		}
   			break;
@@ -429,7 +426,7 @@
   			if (rose_ctl.arg < 1) 
   				return -EINVAL;
   			save_flags(flags); cli();
-  			sk->protinfo.rose->t1 = rose_ctl.arg * PR_SLOWHZ;
+  			sk->protinfo.rose->t1 = rose_ctl.arg * ROSE_SLOWHZ;
   			restore_flags(flags);
   			break;
 
@@ -437,7 +434,7 @@
 	  		if (rose_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.rose->t2 = rose_ctl.arg * PR_SLOWHZ;
+	  		sk->protinfo.rose->t2 = rose_ctl.arg * ROSE_SLOWHZ;
 	  		restore_flags(flags);
 	  		break;
 
@@ -445,7 +442,7 @@
 	  		if (rose_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.rose->t3 = rose_ctl.arg * PR_SLOWHZ;
+	  		sk->protinfo.rose->t3 = rose_ctl.arg * ROSE_SLOWHZ;
 	  		restore_flags(flags);
 	  		break;
 
@@ -453,7 +450,7 @@
 	  		if (rose_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.rose->hb = rose_ctl.arg * PR_SLOWHZ;
+	  		sk->protinfo.rose->hb = rose_ctl.arg * ROSE_SLOWHZ;
 	  		restore_flags(flags);
 	  		break;
 
@@ -461,7 +458,7 @@
 	  		if (rose_ctl.arg < 1) 
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		sk->protinfo.rose->idle = rose_ctl.arg * 60 * PR_SLOWHZ;
+	  		sk->protinfo.rose->idle = rose_ctl.arg * 60 * ROSE_SLOWHZ;
 	  		restore_flags(flags);
 	  		break;
 
@@ -475,11 +472,9 @@
 static int rose_setsockopt(struct socket *sock, int level, int optname,
 	char *optval, int optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int err, opt;
 
-	sk = (struct sock *)sock->sk;
-	
 	if (level != SOL_ROSE)
 		return -EOPNOTSUPP;
 
@@ -490,45 +485,45 @@
 		return err;
 
 	get_user(opt, (int *)optval);
-	
+
 	switch (optname) {
 		case ROSE_T0:
 			if (opt < 1)
 				return -EINVAL;
 			if (sk->protinfo.rose->neighbour != NULL)
-				sk->protinfo.rose->neighbour->t0 = opt * PR_SLOWHZ;
+				sk->protinfo.rose->neighbour->t0 = opt * ROSE_SLOWHZ;
 			return 0;
 
 		case ROSE_T1:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.rose->t1 = opt * PR_SLOWHZ;
+			sk->protinfo.rose->t1 = opt * ROSE_SLOWHZ;
 			return 0;
 
 		case ROSE_T2:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.rose->t2 = opt * PR_SLOWHZ;
+			sk->protinfo.rose->t2 = opt * ROSE_SLOWHZ;
 			return 0;
-			
+
 		case ROSE_T3:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.rose->t3 = opt * PR_SLOWHZ;
+			sk->protinfo.rose->t3 = opt * ROSE_SLOWHZ;
 			return 0;
-			
+
 		case ROSE_HOLDBACK:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.rose->hb = opt * PR_SLOWHZ;
+			sk->protinfo.rose->hb = opt * ROSE_SLOWHZ;
 			return 0;
-			
+
 		case ROSE_IDLE:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.rose->idle = opt * 60 * PR_SLOWHZ;
+			sk->protinfo.rose->idle = opt * 60 * ROSE_SLOWHZ;
 			return 0;
-			
+
 		case ROSE_HDRINCL:
 			sk->protinfo.rose->hdrincl = opt ? 1 : 0;
 			return 0;
@@ -541,43 +536,41 @@
 static int rose_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int val = 0;
 	int err; 
 
-	sk = (struct sock *)sock->sk;
-	
 	if (level != SOL_ROSE)
 		return -EOPNOTSUPP;
 	
 	switch (optname) {
 		case ROSE_T0:
 			if (sk->protinfo.rose->neighbour != NULL)
-				val = sk->protinfo.rose->neighbour->t0 / PR_SLOWHZ;
+				val = sk->protinfo.rose->neighbour->t0 / ROSE_SLOWHZ;
 			else
-				val = sysctl_rose_restart_request_timeout / PR_SLOWHZ;
+				val = sysctl_rose_restart_request_timeout / ROSE_SLOWHZ;
 			break;
-			
+
 		case ROSE_T1:
-			val = sk->protinfo.rose->t1 / PR_SLOWHZ;
+			val = sk->protinfo.rose->t1 / ROSE_SLOWHZ;
 			break;
-			
+
 		case ROSE_T2:
-			val = sk->protinfo.rose->t2 / PR_SLOWHZ;
+			val = sk->protinfo.rose->t2 / ROSE_SLOWHZ;
 			break;
-			
+
 		case ROSE_T3:
-			val = sk->protinfo.rose->t3 / PR_SLOWHZ;
+			val = sk->protinfo.rose->t3 / ROSE_SLOWHZ;
 			break;
-						
+
 		case ROSE_HOLDBACK:
-			val = sk->protinfo.rose->hb / PR_SLOWHZ;
+			val = sk->protinfo.rose->hb / ROSE_SLOWHZ;
 			break;
-						
+
 		case ROSE_IDLE:
-			val = sk->protinfo.rose->idle / (PR_SLOWHZ * 60);
+			val = sk->protinfo.rose->idle / (ROSE_SLOWHZ * 60);
 			break;
-						
+
 		case ROSE_HDRINCL:
 			val = sk->protinfo.rose->hdrincl;
 			break;
@@ -601,7 +594,7 @@
 
 static int rose_listen(struct socket *sock, int backlog)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk->state != TCP_LISTEN) {
 		sk->protinfo.rose->dest_ndigis = 0;
@@ -624,18 +617,17 @@
 
 static void def_callback2(struct sock *sk, int len)
 {
-	if (!sk->dead)
-	{
+	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
+		sock_wake_async(sk->socket, 1);
 	}
 }
-static void def_callback3(struct sock *sk, int len)
+
+static void def_callback3(struct sock *sk)
 {
-	if (!sk->dead)
-	{
+	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,2); 
+		sock_wake_async(sk->socket, 2); 
 	}		
 }
 
@@ -652,35 +644,12 @@
 
 	rose = sk->protinfo.rose;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	init_timer(&sk->timer);
-
+	sock_init_data(sock,sk);
+	
 	sock->ops	  = &rose_proto_ops;
-	sk->socket        = sock;
-	sk->type          = sock->type;
 	sk->protocol      = protocol;
-	sk->allocation	  = GFP_KERNEL;
-	sk->rcvbuf        = SK_RMEM_MAX;
-	sk->sndbuf        = SK_WMEM_MAX;
-	sk->state         = TCP_CLOSE;
-	sk->priority      = SOPRI_NORMAL;
 	sk->mtu           = ROSE_MTU;	/* 128 */
-	sk->zapped        = 1;
 
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback1;
-	sk->error_report = def_callback1;
-
-	if (sock != NULL) {
-		sock->sk  = sk;
-		sk->sleep = &sock->wait;
-	}
-
-	skb_queue_head_init(&rose->ack_queue);
 	skb_queue_head_init(&rose->frag_queue);
 
 	rose->t1    = sysctl_rose_call_request_timeout;
@@ -727,10 +696,9 @@
 
 	sk->state_change = def_callback1;
 	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback1;
+	sk->write_space  = def_callback3;
 	sk->error_report = def_callback1;
 
-	skb_queue_head_init(&rose->ack_queue);
 	skb_queue_head_init(&rose->frag_queue);
 
 	rose->t1      = osk->protinfo.rose->t1;
@@ -747,14 +715,17 @@
 
 static int rose_dup(struct socket *newsock, struct socket *oldsock)
 {
-	struct sock *sk = (struct sock *)oldsock->sk;
+	struct sock *sk = oldsock->sk;
+
+	if (sk == NULL || newsock == NULL)
+		return -EINVAL;
 
 	return rose_create(newsock, sk->protocol);
 }
 
 static int rose_release(struct socket *sock, struct socket *peer)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk == NULL) return 0;
 
@@ -811,19 +782,20 @@
 
 static int rose_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
 	struct device *dev;
 	ax25_address *user, *source;
-	
-	sk = (struct sock *)sock->sk;
 
 	if (sk->zapped == 0)
 		return -EINVAL;
-		
+
 	if (addr_len != sizeof(struct sockaddr_rose))
 		return -EINVAL;
 
+	if (addr->srose_family != AF_ROSE)
+		return -EINVAL;
+
 	if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) {
 		if (sk->debug)
 			printk("Rose: bind failed: invalid address\n");
@@ -859,30 +831,33 @@
 
 static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
 	ax25_address *user;
 	struct device *dev;
-	
+
 	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
 		return 0;	/* Connect completed during a ERESTARTSYS event */
 	}
-	
+
 	if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
 		sock->state = SS_UNCONNECTED;
 		return -ECONNREFUSED;
 	}
-	
+
 	if (sk->state == TCP_ESTABLISHED)
 		return -EISCONN;	/* No reconnect on a seqpacket socket */
-		
+
 	sk->state   = TCP_CLOSE;	
 	sock->state = SS_UNCONNECTED;
 
 	if (addr_len != sizeof(struct sockaddr_rose))
 		return -EINVAL;
 
+	if (addr->srose_family != AF_ROSE)
+		return -EINVAL;
+
 	if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr)) == NULL)	
 		return -ENETUNREACH;
 
@@ -919,7 +894,7 @@
 	rose_write_internal(sk, ROSE_CALL_REQUEST);
 
 	rose_set_timer(sk);
-	
+
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
@@ -942,11 +917,11 @@
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
-	
+
 	sock->state = SS_CONNECTED;
 
 	sti();
-	
+
 	return 0;
 }
 	
@@ -961,19 +936,20 @@
 	struct sock *newsk;
 	struct sk_buff *skb;
 
-	if (newsock->sk)
-		sk_free(newsock->sk);
+	if (newsock->sk != NULL)
+		rose_destroy_socket(newsock->sk);
 
 	newsock->sk = NULL;
-	
-	sk = (struct sock *)sock->sk;
+
+	if ((sk = sock->sk) == NULL)
+		return -EINVAL;
 
 	if (sk->type != SOCK_SEQPACKET)
 		return -EOPNOTSUPP;
-	
+
 	if (sk->state != TCP_LISTEN)
 		return -EINVAL;
-		
+
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
@@ -983,7 +959,7 @@
 		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
 			if (flags & O_NONBLOCK) {
 				sti();
-				return 0;
+				return -EWOULDBLOCK;
 			}
 			interruptible_sleep_on(sk->sleep);
 			if (current->signal & ~current->blocked) {
@@ -1010,10 +986,8 @@
 	int *uaddr_len, int peer)
 {
 	struct sockaddr_rose *srose = (struct sockaddr_rose *)uaddr;
-	struct sock *sk;
-	
-	sk = (struct sock *)sock->sk;
-	
+	struct sock *sk = sock->sk;
+
 	if (peer != 0) {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
@@ -1040,11 +1014,11 @@
 
 	return 0;
 }
- 
+
 int rose_rx_call_request(struct sk_buff *skb, struct device *dev, struct rose_neigh *neigh, unsigned int lci)
 {
 	struct sock *sk;
-	struct sock *make;	
+	struct sock *make;
 	rose_cb rose;
 
 	skb->sk = NULL;		/* Initially we don't know who it's for */
@@ -1059,7 +1033,7 @@
 	if (!rose_parse_facilities(skb, &rose)) {
 		return 0;
 	}
-		
+
 	sk = rose_find_listener(&rose.source_call);
 
 	/*
@@ -1084,7 +1058,7 @@
 	make->protinfo.rose->source_digi   = rose.source_digi;
 	make->protinfo.rose->neighbour     = neigh;
 	make->protinfo.rose->device        = dev;
-	
+
 	rose_write_internal(make, ROSE_CALL_ACCEPTED);
 
 	make->protinfo.rose->condition = 0x00;
@@ -1111,14 +1085,14 @@
 static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, 
 				struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name;
 	int err;
 	struct sockaddr_rose srose;
 	struct sk_buff *skb;
 	unsigned char *asmptr;
 	int size;
-	
+
 	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
@@ -1132,7 +1106,7 @@
 
 	if (sk->protinfo.rose->device == NULL)
 		return -ENETUNREACH;
-		
+
 	if (usrose != NULL) {
 		if (msg->msg_namelen < sizeof(srose))
 			return -EINVAL;
@@ -1160,7 +1134,7 @@
 			srose.srose_digi   = sk->protinfo.rose->dest_digi;
 		}
 	}
-	
+
 	if (sk->debug)
 		printk("Rose: sendto: Addresses built.\n");
 
@@ -1173,11 +1147,10 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->sk   = sk;
-	skb->arp  = 1;
+	skb->arp = 1;
 
 	skb_reserve(skb, size - len);
-	
+
 	/*
 	 *	Push down the Rose header
 	 */
@@ -1189,10 +1162,10 @@
 
 	/* Build a Rose Transport header */
 
-	*asmptr++ = ((sk->protinfo.rose->lci >> 8) & 0x0F) | GFI;
+	*asmptr++ = ((sk->protinfo.rose->lci >> 8) & 0x0F) | ROSE_GFI;
 	*asmptr++ = (sk->protinfo.rose->lci >> 0) & 0xFF;
 	*asmptr++ = ROSE_DATA;
-	
+
 	if (sk->debug)
 		printk("Built header.\n");
 
@@ -1203,7 +1176,7 @@
 	skb->h.raw = skb_put(skb, len);
 
 	asmptr = skb->h.raw;
-	
+
 	if (sk->debug)
 		printk("Rose: Appending user data\n");
 
@@ -1227,7 +1200,7 @@
 static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, 
 		   int flags, struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;
 	int copied;
 	struct sk_buff *skb;
@@ -1250,28 +1223,24 @@
 	}
 
 	copied = skb->len;
-	
+
 	if (copied > size) {
 		copied = size;
 		msg->msg_flags |= MSG_TRUNC;
 	}
-	
+
 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-	
+
 	if (srose != NULL) {
-		struct sockaddr_rose addr;
-		
-		addr.srose_family = AF_ROSE;
-		addr.srose_addr   = sk->protinfo.rose->dest_addr;
-		addr.srose_call   = sk->protinfo.rose->dest_call;
-		addr.srose_ndigis = 0;
+		srose->srose_family = AF_ROSE;
+		srose->srose_addr   = sk->protinfo.rose->dest_addr;
+		srose->srose_call   = sk->protinfo.rose->dest_call;
+		srose->srose_ndigis = 0;
 
 		if (sk->protinfo.rose->dest_ndigis == 1) {
-			addr.srose_ndigis = 1;
-			addr.srose_digi   = sk->protinfo.rose->dest_digi;
+			srose->srose_ndigis = 1;
+			srose->srose_digi   = sk->protinfo.rose->dest_digi;
 		}
-
-		*srose = addr;
 	}
 
 	msg->msg_namelen = sizeof(struct sockaddr_rose);
@@ -1288,7 +1257,7 @@
 
 static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	int err;
 	long amount = 0;
 
@@ -1341,11 +1310,22 @@
 			if (!suser()) return -EPERM;
 			return rose_rt_ioctl(cmd, (void *)arg);
 
- 		case SIOCRSCTLCON:
+		case SIOCRSCTLCON:
  			if (!suser()) return -EPERM;
  			return rose_ctl_ioctl(cmd, (void *)arg);
- 
- 		default:
+
+		case SIOCRSL2CALL:
+			if (!suser()) return -EPERM;
+			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_address))) != 0)
+				return err;
+			if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+				ax25_listen_release(&rose_callsign, NULL);
+			copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address));
+			if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+				ax25_listen_register(&rose_callsign, NULL);
+			return 0;
+
+		default:
 			return dev_ioctl(cmd, (void *)arg);
 	}
 
@@ -1361,10 +1341,10 @@
 	int len = 0;
 	off_t pos = 0;
 	off_t begin = 0;
-  
+
 	cli();
 
-	len += sprintf(buffer, "dest_addr  dest_call dest_digi src_addr   src_call  src_digi  dev   lci st vs vr va   t  t1  t2  t3  hb  Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb  Snd-Q Rcv-Q\n");
 
 	for (s = rose_list; s != NULL; s = s->next) {
 		if ((dev = s->protinfo.rose->device) == NULL)
@@ -1375,36 +1355,31 @@
 		len += sprintf(buffer + len, "%-10s %-9s ",
 			rose2asc(&s->protinfo.rose->dest_addr),
 			ax2asc(&s->protinfo.rose->dest_call));
-		len += sprintf(buffer + len, "%-9s ",
-			ax2asc(&s->protinfo.rose->dest_digi));
 
 		if (ax25cmp(&s->protinfo.rose->source_call, &null_ax25_address) == 0)
 			callsign = "??????-?";
 		else
 			callsign = ax2asc(&s->protinfo.rose->source_call);
 
-		len += sprintf(buffer + len, "%-10s %-9s ",
-			rose2asc(&s->protinfo.rose->source_addr),
-			callsign);
-		len += sprintf(buffer + len, "%-9s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
-			ax2asc(&s->protinfo.rose->source_digi),
+		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
+			rose2asc(&s->protinfo.rose->source_addr), callsign,
 			devname,  s->protinfo.rose->lci & 0x0FFF,
 			s->protinfo.rose->state,
 			s->protinfo.rose->vs, s->protinfo.rose->vr, s->protinfo.rose->va,
-			s->protinfo.rose->timer / PR_SLOWHZ,
-			s->protinfo.rose->t1    / PR_SLOWHZ,
-			s->protinfo.rose->t2    / PR_SLOWHZ,
-			s->protinfo.rose->t3    / PR_SLOWHZ,
-			s->protinfo.rose->hb    / PR_SLOWHZ,
+			s->protinfo.rose->timer / ROSE_SLOWHZ,
+			s->protinfo.rose->t1    / ROSE_SLOWHZ,
+			s->protinfo.rose->t2    / ROSE_SLOWHZ,
+			s->protinfo.rose->t3    / ROSE_SLOWHZ,
+			s->protinfo.rose->hb    / ROSE_SLOWHZ,
 			s->wmem_alloc, s->rmem_alloc);
-		
+
 		pos = begin + len;
 
 		if (pos < offset) {
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -1426,7 +1401,7 @@
 
 static struct proto_ops rose_proto_ops = {
 	AF_ROSE,
-	
+
 	rose_dup,
 	rose_release,
 	rose_bind,
@@ -1440,7 +1415,7 @@
 	rose_shutdown,
 	rose_setsockopt,
 	rose_getsockopt,
-	rose_fcntl,
+	sock_no_fcntl,
 	rose_sendmsg,
 	rose_recvmsg
 };
@@ -1490,6 +1465,8 @@
 {
 	int i;
 
+	rose_callsign = null_ax25_address;
+
 	sock_register(&rose_family_ops);
 	register_netdevice_notifier(&rose_dev_notifier);
 	printk(KERN_INFO "G4KLX Rose for Linux. Version 0.1 for AX25.035 Linux 2.1\n");
@@ -1536,6 +1513,9 @@
 
 	ax25_protocol_release(AX25_P_ROSE);
 	ax25_linkfail_release(rose_link_failed);
+
+	if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+		ax25_listen_release(&rose_callsign, NULL);
 
 	rose_unregister_sysctl();
 
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.1.21/linux/net/rose/rose_dev.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_dev.c	Sun Jan 19 15:47:29 1997
@@ -81,7 +81,7 @@
 {
 	unsigned char *buff = skb_push(skb, ROSE_MIN_LEN + 2);
 
-	*buff++ = GFI | Q_BIT;
+	*buff++ = ROSE_GFI | ROSE_Q_BIT;
 	*buff++ = 0x00;
 	*buff++ = ROSE_DATA;
 	*buff++ = 0x7F;
@@ -110,7 +110,7 @@
 		return 1;
 	}
 
-	if (skbn->sk != NULL)
+	if (skb->sk != NULL)
 		skb_set_owner_w(skbn, skb->sk);
 
 	kfree_skb(skb, FREE_WRITE);
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
--- v2.1.21/linux/net/rose/rose_in.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_in.c	Sun Jan 19 15:47:29 1997
@@ -56,7 +56,7 @@
 		skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
 		return 0;
 	}
-	
+
 	if (!more && sk->protinfo.rose->fraglen > 0) {	/* End of fragment */
 		sk->protinfo.rose->fraglen += skb->len;
 		skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
@@ -190,9 +190,9 @@
 		case ROSE_RR:
 		case ROSE_RNR:
 			if (frametype == ROSE_RNR) {
-				sk->protinfo.rose->condition |= PEER_RX_BUSY_CONDITION;
+				sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
 			} else {
-				sk->protinfo.rose->condition &= ~PEER_RX_BUSY_CONDITION;
+				sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
 			}
 			if (!rose_validate_nr(sk, nr)) {
 				rose_clear_queues(sk);
@@ -205,16 +205,16 @@
 				sk->protinfo.rose->state     = ROSE_STATE_4;
 				sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
 			} else {
-				if (sk->protinfo.rose->condition & PEER_RX_BUSY_CONDITION) {
-					rose_frames_acked(sk, nr);
+				if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
+					sk->protinfo.rose->va = nr;
 				} else {
 					rose_check_iframes_acked(sk, nr);
 				}
 			}
 			break;
-			
+
 		case ROSE_DATA:	/* XXX */
-			sk->protinfo.rose->condition &= ~PEER_RX_BUSY_CONDITION;
+			sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
 			if (!rose_validate_nr(sk, nr)) {
 				rose_clear_queues(sk);
 				rose_write_internal(sk, ROSE_RESET_REQUEST);
@@ -227,19 +227,19 @@
 				sk->protinfo.rose->timer     = sk->protinfo.rose->t2;
 				break;
 			}
-			if (sk->protinfo.rose->condition & PEER_RX_BUSY_CONDITION) {
-				rose_frames_acked(sk, nr);
+			if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
+				sk->protinfo.rose->va = nr;
 			} else {
 				rose_check_iframes_acked(sk, nr);
 			}
-			if (sk->protinfo.rose->condition & OWN_RX_BUSY_CONDITION)
+			if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
 				break;
 			if (ns == sk->protinfo.rose->vr) {
 				if (rose_queue_rx_frame(sk, skb, m) == 0) {
 					sk->protinfo.rose->vr = (sk->protinfo.rose->vr + 1) % ROSE_MODULUS;
 					queued = 1;
 				} else {
-					sk->protinfo.rose->condition |= OWN_RX_BUSY_CONDITION;
+					sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
 				}
 			}
 			/*
@@ -247,11 +247,11 @@
 			 * acknowledge hold back timer.
 			 */
 			if (((sk->protinfo.rose->vl + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
-				sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 				sk->protinfo.rose->timer      = 0;
 				rose_enquiry_response(sk);
 			} else {
-				sk->protinfo.rose->condition |= ACK_PENDING_CONDITION;
+				sk->protinfo.rose->condition |= ROSE_COND_ACK_PENDING;
 				sk->protinfo.rose->timer      = sk->protinfo.rose->hb;
 			}
 			break;
@@ -309,7 +309,7 @@
 int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
 	int queued = 0, frametype, ns, nr, q, d, m;
-	
+
 	if (sk->protinfo.rose->state == ROSE_STATE_0)
 		return 0;
 
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.1.21/linux/net/rose/rose_link.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_link.c	Sun Jan 19 15:47:29 1997
@@ -49,7 +49,7 @@
 static void rose_link_set_timer(struct rose_neigh *neigh)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&neigh->timer);
@@ -66,7 +66,7 @@
 static void rose_link_reset_timer(struct rose_neigh *neigh)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&neigh->timer);
@@ -104,6 +104,40 @@
 }
 
 /*
+ *	Interface to ax25_send_frame. Changes my level 2 callsign depending
+ *	on whether we have a global ROSE callsign or use the default port
+ *	callsign.
+ */
+static int rose_send_frame(struct sk_buff *skb, struct rose_neigh *neigh)
+{
+	ax25_address *rose_call;
+
+	if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
+		rose_call = (ax25_address *)neigh->dev->dev_addr;
+	else
+		rose_call = &rose_callsign;
+
+	return ax25_send_frame(skb, rose_call, &neigh->callsign, neigh->digipeat, neigh->dev);
+}
+
+/*
+ *	Interface to ax25_link_up. Changes my level 2 callsign depending
+ *	on whether we have a global ROSE callsign or use the default port
+ *	callsign.
+ */
+static int rose_link_up(struct rose_neigh *neigh)
+{
+	ax25_address *rose_call;
+
+	if (ax25cmp(&rose_callsign, &null_ax25_address) == 0)
+		rose_call = (ax25_address *)neigh->dev->dev_addr;
+	else
+		rose_call = &rose_callsign;
+
+	return ax25_link_up(rose_call, &neigh->callsign, neigh->dev);
+}
+
+/*
  *	This handles all restart and diagnostic frames.
  */
 void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigned short frametype)
@@ -127,7 +161,7 @@
 		case ROSE_DIAGNOSTIC:
 			printk(KERN_WARNING "rose: diagnostic #%d\n", skb->data[3]);
 			break;
-			
+
 		default:
 			printk(KERN_WARNING "rose: received unknown %02X with LCI 000\n", frametype);
 			break;
@@ -135,7 +169,7 @@
 
 	if (neigh->restarted) {
 		while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
-			if (!ax25_send_frame(skbn, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
+			if (!rose_send_frame(skbn, neigh))
 				kfree_skb(skbn, FREE_WRITE);
 	}
 }
@@ -159,7 +193,7 @@
 	dptr = skb_put(skb, ROSE_MIN_LEN + 3);
 
 	*dptr++ = AX25_P_ROSE;
-	*dptr++ = GFI;
+	*dptr++ = ROSE_GFI;
 	*dptr++ = 0x00;
 	*dptr++ = ROSE_RESTART_REQUEST;
 	*dptr++ = 0x00;
@@ -167,7 +201,7 @@
 
 	skb->sk = NULL;
 
-	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
+	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
 
@@ -190,13 +224,13 @@
 	dptr = skb_put(skb, ROSE_MIN_LEN + 1);
 
 	*dptr++ = AX25_P_ROSE;
-	*dptr++ = GFI;
+	*dptr++ = ROSE_GFI;
 	*dptr++ = 0x00;
 	*dptr++ = ROSE_RESTART_CONFIRMATION;
 
 	skb->sk = NULL;
 
-	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
+	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
 
@@ -219,14 +253,14 @@
 	dptr = skb_put(skb, ROSE_MIN_LEN + 2);
 
 	*dptr++ = AX25_P_ROSE;
-	*dptr++ = GFI;
+	*dptr++ = ROSE_GFI;
 	*dptr++ = 0x00;
 	*dptr++ = ROSE_DIAGNOSTIC;
 	*dptr++ = diag;
 
 	skb->sk = NULL;
 
-	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
+	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
 
@@ -250,7 +284,7 @@
 	dptr = skb_put(skb, ROSE_MIN_LEN + 3);
 
 	*dptr++ = AX25_P_ROSE;
-	*dptr++ = ((lci >> 8) & 0x0F) | GFI;
+	*dptr++ = ((lci >> 8) & 0x0F) | ROSE_GFI;
 	*dptr++ = ((lci >> 0) & 0xFF);
 	*dptr++ = ROSE_CLEAR_REQUEST;
 	*dptr++ = cause;
@@ -258,7 +292,7 @@
 
 	skb->sk = NULL;
 
-	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
+	if (!rose_send_frame(skb, neigh))
 		kfree_skb(skb, FREE_WRITE);
 }
 
@@ -271,7 +305,7 @@
 		return;
 #endif
 
-	if (!ax25_link_up((ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->dev))
+	if (!rose_link_up(neigh))
 		neigh->restarted = 0;
 
 	dptr = skb_push(skb, 1);
@@ -280,11 +314,11 @@
 	skb->arp = 1;
 
 	if (neigh->restarted) {
-		if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
+		if (!rose_send_frame(skb, neigh))
 			kfree_skb(skb, FREE_WRITE);
 	} else {
 		skb_queue_tail(&neigh->queue, skb);
-		
+
 		if (neigh->t0timer == 0) {
 			rose_transmit_restart_request(neigh);
 			neigh->t0timer = neigh->t0;
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_out.c linux/net/rose/rose_out.c
--- v2.1.21/linux/net/rose/rose_out.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_out.c	Sun Jan 19 15:47:29 1997
@@ -76,11 +76,11 @@
 			memcpy(skbn->data, header, ROSE_MIN_LEN);
 
 			if (skb->len > 0)
-				skbn->data[2] |= M_BIT;
-		
+				skbn->data[2] |= ROSE_M_BIT;
+
 			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
 		}
-		
+
 		kfree_skb(skb, FREE_WRITE);
 	} else {
 		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */
@@ -107,56 +107,35 @@
 
 void rose_kick(struct sock *sk)
 {
-	struct sk_buff *skb, *skbn;
-	int last = 1;
-	unsigned short start, end, next;
+	struct sk_buff *skb;
+	unsigned short end;
 
 	del_timer(&sk->timer);
 
-	start = (skb_peek(&sk->protinfo.rose->ack_queue) == NULL) ? sk->protinfo.rose->va : sk->protinfo.rose->vs;
-	end   = (sk->protinfo.rose->va + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS;
+	end = (sk->protinfo.rose->va + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS;
 
-	if (!(sk->protinfo.rose->condition & PEER_RX_BUSY_CONDITION) &&
-	    start != end                                  &&
+	if (!(sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) &&
+	    sk->protinfo.rose->vs != end                             &&
 	    skb_peek(&sk->write_queue) != NULL) {
-
-		sk->protinfo.rose->vs = start;
-
 		/*
 		 * Transmit data until either we're out of data to send or
 		 * the window is full.
 		 */
 
-		/*
-		 * Dequeue the frame and copy it.
-		 */
 		skb  = skb_dequeue(&sk->write_queue);
 
 		do {
-			if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-				skb_queue_head(&sk->write_queue, skb);
-				break;
-			}
-
-			next = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
-			last = (next == end);
-
 			/*
-			 * Transmit the frame copy.
+			 * Transmit the frame.
 			 */
-			rose_send_iframe(sk, skbn);
-
-			sk->protinfo.rose->vs = next;
+			rose_send_iframe(sk, skb);
 
-			/*
-			 * Requeue the original data frame.
-			 */
-			skb_queue_tail(&sk->protinfo.rose->ack_queue, skb);
+			sk->protinfo.rose->vs = (sk->protinfo.rose->vs + 1) % ROSE_MODULUS;
 
-		} while (!last && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+		} while (sk->protinfo.rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
 
 		sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
-		sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+		sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 		sk->protinfo.rose->timer      = 0;
 	}
 
@@ -170,25 +149,24 @@
 
 void rose_enquiry_response(struct sock *sk)
 {
-	if (sk->protinfo.rose->condition & OWN_RX_BUSY_CONDITION) {
+	if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY) {
 		rose_write_internal(sk, ROSE_RNR);
 	} else {
 		rose_write_internal(sk, ROSE_RR);
 	}
 
 	sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
-	sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+	sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 	sk->protinfo.rose->timer      = 0;
 }
 
 void rose_check_iframes_acked(struct sock *sk, unsigned short nr)
 {
 	if (sk->protinfo.rose->vs == nr) {
-		rose_frames_acked(sk, nr);
+		sk->protinfo.rose->va = nr;
 	} else {
-		if (sk->protinfo.rose->va != nr) {
-			rose_frames_acked(sk, nr);
-		}
+		if (sk->protinfo.rose->va != nr)
+			sk->protinfo.rose->va = nr;
 	}
 }
 
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_route.c linux/net/rose/rose_route.c
--- v2.1.21/linux/net/rose/rose_route.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_route.c	Sun Jan 19 15:47:29 1997
@@ -17,7 +17,7 @@
  *			Terry(VK2KTJ)	Added support for variable length
  *					address masks.
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
 #include <linux/errno.h>
@@ -99,7 +99,7 @@
 			for (i = 0; i < rose_route->ndigis; i++)
 				rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
 		}
-			
+
 		save_flags(flags); cli();
 		rose_neigh->next = rose_neigh_list;
 		rose_neigh_list  = rose_neigh;
@@ -157,7 +157,7 @@
 		}
 
 		restore_flags(flags);
-		
+
 		rose_neigh->count++;
 
 		return 0;
@@ -169,7 +169,7 @@
 		rose_node->neighbour[1] = rose_node->neighbour[0];
 
 		rose_node->neighbour[0] = rose_neigh;
-	
+
 		rose_node->count++;
 		rose_neigh->count++;
 	}
@@ -213,10 +213,10 @@
 	struct sk_buff *skb;
 
 	del_timer(&rose_neigh->timer);
-	
+
 	while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	
+
 	save_flags(flags);
 	cli();
 
@@ -283,7 +283,7 @@
 	struct rose_node  *rose_node;
 	struct rose_neigh *rose_neigh;
 	int i;
-	
+
 	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
 		if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
 			break;
@@ -295,7 +295,7 @@
 			break;
 
 	if (rose_neigh == NULL) return -EINVAL;
-	
+
 	for (i = 0; i < rose_node->count; i++) {
 		if (rose_node->neighbour[i] == rose_neigh) {
 			rose_neigh->count--;
@@ -304,7 +304,7 @@
 				rose_remove_neigh(rose_neigh);
 				
 			rose_node->count--;
-			
+
 			if (rose_node->count == 0) {
 				rose_remove_node(rose_node);
 			} else {
@@ -337,14 +337,14 @@
 	while (rose_neigh != NULL) {
 		s          = rose_neigh;
 		rose_neigh = rose_neigh->next;
-		
+
 		if (s->dev == dev) {
 			rose_node = rose_node_list;
 
 			while (rose_node != NULL) {
 				t         = rose_node;
 				rose_node = rose_node->next;
-				
+
 				for (i = 0; i < t->count; i++) {
 					if (t->neighbour[i] == s) {
 						t->count--;
@@ -359,11 +359,11 @@
 						}
 					}
 				}
-				
+
 				if (t->count <= 0)
 					rose_remove_node(t);
 			}
-			
+
 			rose_remove_neigh(s);
 		}
 	}
@@ -379,7 +379,7 @@
 	while (rose_route != NULL) {
 		s         = rose_route;
 		rose_route = rose_route->next;
-		
+
 		if (s->neigh1->dev == dev || s->neigh2->dev == dev)
 			rose_remove_route(s);
 	}
@@ -442,9 +442,9 @@
 			break;
 
 	if (node == NULL) return NULL;
-	
+
 	if (node->which >= node->count) return NULL;
-	
+
 	return node->neighbour[node->which];
 }
 
@@ -509,7 +509,7 @@
 
 	while ((skb = skb_dequeue(&rose_neigh->queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	
+
 	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
 		if (rose_node->which < rose_node->count && rose_node->neighbour[rose_node->which] == rose_neigh)
 			rose_node->which++;
@@ -748,8 +748,8 @@
 			rose_neigh->dev ? rose_neigh->dev->name : "???",
 			rose_neigh->count,
 			(rose_neigh->restarted) ? "yes" : "no",
-			rose_neigh->t0timer / PR_SLOWHZ,
-			rose_neigh->t0      / PR_SLOWHZ);
+			rose_neigh->t0timer / ROSE_SLOWHZ,
+			rose_neigh->t0      / ROSE_SLOWHZ);
 
 		pos = begin + len;
 
@@ -757,7 +757,7 @@
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -800,7 +800,7 @@
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -829,21 +829,21 @@
 	while (rose_neigh != NULL) {
 		s          = rose_neigh;
 		rose_neigh = rose_neigh->next;
-		
+
 		rose_remove_neigh(s);
 	}
 
 	while (rose_node != NULL) {
 		t          = rose_node;
 		rose_node = rose_node->next;
-		
+
 		rose_remove_node(t);
 	}
 
 	while (rose_route != NULL) {
 		u          = rose_route;
 		rose_route = rose_route->next;
-		
+
 		rose_remove_route(u);
 	}
 }
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_subr.c linux/net/rose/rose_subr.c
--- v2.1.21/linux/net/rose/rose_subr.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_subr.c	Sun Jan 19 15:47:29 1997
@@ -15,7 +15,7 @@
  *	History
  *	Rose 001	Jonathan(G4KLX)	Cloned from nr_subr.c
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
 #include <linux/errno.h>
@@ -47,59 +47,11 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
-		skb->sk   = sk;
-		kfree_skb(skb, FREE_WRITE);
-	}
-
-	while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL) {
-		skb->sk   = sk;
+	while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
+	while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL)
 		kfree_skb(skb, FREE_READ);
-	}
-}
-
-/*
- * This routine purges the input queue of those frames that have been
- * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
- * SDL diagram.
- */
-void rose_frames_acked(struct sock *sk, unsigned short nr)
-{
-	struct sk_buff *skb;
-
-	/*
-	 * Remove all the ack-ed frames from the ack queue.
-	 */
-	if (sk->protinfo.rose->va != nr) {
-		while (skb_peek(&sk->protinfo.rose->ack_queue) != NULL && sk->protinfo.rose->va != nr) {
-		        skb = skb_dequeue(&sk->protinfo.rose->ack_queue);
-		        skb->sk   = sk;
-			kfree_skb(skb, FREE_WRITE);
-			sk->protinfo.rose->va = (sk->protinfo.rose->va + 1) % ROSE_MODULUS;
-		}
-	}
-}
-
-/*
- * Requeue all the un-ack-ed frames on the output queue to be picked
- * up by rose_kick called from the timer. This arrangement handles the
- * possibility of an empty output queue.
- */
-void rose_requeue_frames(struct sock *sk)
-{
-	struct sk_buff *skb, *skb_prev = NULL;
-
-	while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL) {
-		if (skb_prev == NULL)
-			skb_queue_head(&sk->write_queue, skb);
-		else
-			skb_append(skb_prev, skb);
-		skb_prev = skb;
-	}
 }
 
 /*
@@ -114,7 +66,7 @@
 		if (nr == vc) return 1;
 		vc = (vc + 1) % ROSE_MODULUS;
 	}
-	
+
 	if (nr == sk->protinfo.rose->vs) return 1;
 
 	return 0;
@@ -133,7 +85,7 @@
 	int len, faclen = 0;
 
 	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
-	
+
 	switch (frametype) {
 		case ROSE_CALL_REQUEST:
 			len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
@@ -150,7 +102,7 @@
 			len   += 1;
 			break;
 	}
-	
+
 	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 		return;
 
@@ -165,9 +117,9 @@
 	lci2 = (sk->protinfo.rose->lci >> 0) & 0xFF;
 
 	switch (frametype) {
-	
+
 		case ROSE_CALL_REQUEST:
-			*dptr++ = GFI | lci1;
+			*dptr++ = ROSE_GFI | lci1;
 			*dptr++ = lci2;
 			*dptr++ = frametype;
 			*dptr++ = 0xAA;
@@ -180,7 +132,7 @@
 			break;
 
 		case ROSE_CALL_ACCEPTED:
-			*dptr++ = GFI | lci1;
+			*dptr++ = ROSE_GFI | lci1;
 			*dptr++ = lci2;
 			*dptr++ = frametype;
 			*dptr++ = 0x00;		/* Address length */
@@ -189,7 +141,7 @@
 
 		case ROSE_CLEAR_REQUEST:
 		case ROSE_RESET_REQUEST:
-			*dptr++ = GFI | lci1;
+			*dptr++ = ROSE_GFI | lci1;
 			*dptr++ = lci2;
 			*dptr++ = frametype;
 			*dptr++ = 0x00;		/* XXX */
@@ -197,7 +149,7 @@
 			break;
 
 		case ROSE_INTERRUPT:
-			*dptr++ = GFI | lci1;
+			*dptr++ = ROSE_GFI | lci1;
 			*dptr++ = lci2;
 			*dptr++ = frametype;
 			*dptr++ = 0x00;		/* XXX */
@@ -206,16 +158,16 @@
 		case ROSE_RR:
 		case ROSE_RNR:
 		case ROSE_REJ:
-			*dptr++ = GFI | lci1;
+			*dptr++ = ROSE_GFI | lci1;
 			*dptr++ = lci2;
 			*dptr   = frametype;
 			*dptr++ |= (sk->protinfo.rose->vr << 5) & 0xE0;
 			break;
-		
+
 		case ROSE_CLEAR_CONFIRMATION:
 		case ROSE_INTERRUPT_CONFIRMATION:
 		case ROSE_RESET_CONFIRMATION:
-			*dptr++ = GFI | lci1;
+			*dptr++ = ROSE_GFI | lci1;
 			*dptr++ = lci2;
 			*dptr++  = frametype;
 			break;
@@ -232,11 +184,11 @@
 int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
 {
 	unsigned char *frame;
-	
+
 	frame = skb->data;
-	
+
 	*ns = *nr = *q = *d = *m = 0;
-	
+
 	switch (frame[2]) {
 		case ROSE_CALL_REQUEST:
 		case ROSE_CALL_ACCEPTED:
@@ -264,14 +216,14 @@
 	}
 
 	if ((frame[2] & 0x01) == ROSE_DATA) {
-		*q  = (frame[0] & Q_BIT) == Q_BIT;
-		*d  = (frame[0] & D_BIT) == D_BIT;
-		*m  = (frame[2] & M_BIT) == M_BIT;
+		*q  = (frame[0] & ROSE_Q_BIT) == ROSE_Q_BIT;
+		*d  = (frame[0] & ROSE_D_BIT) == ROSE_D_BIT;
+		*m  = (frame[2] & ROSE_M_BIT) == ROSE_M_BIT;
 		*nr = (frame[2] >> 5) & 0x07;
 		*ns = (frame[2] >> 1) & 0x07;
 		return ROSE_DATA;
 	}
-	
+
 	return ROSE_ILLEGAL;
 }
 
@@ -286,7 +238,7 @@
 				n   += 2;
 				len -= 2;
 				break;
-				
+
 			case 0x40:
 				if (*p == FAC_NATIONAL_RAND)
 					rose->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
@@ -300,7 +252,7 @@
 				n   += 4;
 				len -= 4;
 				break;
-				
+
 			case 0xC0:
 				l = p[1];
 				if (*p == FAC_NATIONAL_DEST_DIGI) {
@@ -333,7 +285,7 @@
 				n   += 2;
 				len -= 2;
 				break;
-				
+
 			case 0x40:
 				p   += 3;
 				n   += 3;
@@ -345,7 +297,7 @@
 				n   += 4;
 				len -= 4;
 				break;
-				
+
 			case 0xC0:
 				l = p[1];
 				if (*p == FAC_CCITT_DEST_NSAP) {
@@ -383,7 +335,7 @@
 	p = skb->data + len + 4;
 
 	facilities_len = *p++;
-	
+
 	if (facilities_len == 0)
 		return 0;
 
@@ -398,13 +350,13 @@
 					facilities_len -= len + 1;
 					p += len + 1;
 					break;
-					
+
 				case FAC_CCITT:		/* CCITT */
 					len = rose_parse_ccitt(p + 1, rose, facilities_len - 1);
 					facilities_len -= len + 1;
 					p += len + 1;
 					break;
-					
+
 				default:
 					printk(KERN_DEBUG "rose_parse_facilities: unknown facilities family %02X\n", *p);
 					facilities_len--;
@@ -422,7 +374,7 @@
 	unsigned char *p = buffer + 1;
 	char *callsign;
 	int len;
-	
+
 	/* National Facilities */
 	if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
 		*p++ = 0x00;
@@ -433,7 +385,7 @@
 			*p++ = (rose->rand >> 8) & 0xFF;
 			*p++ = (rose->rand >> 0) & 0xFF;
 		}
-		
+
 		if (rose->source_ndigis == 1) {
 			*p++ = FAC_NATIONAL_SRC_DIGI;
 			*p++ = AX25_ADDR_LEN;
@@ -451,9 +403,9 @@
 
 	*p++ = 0x00;
 	*p++ = FAC_CCITT;
-	
+
 	*p++ = FAC_CCITT_DEST_NSAP;
-	
+
 	callsign = ax2asc(&rose->dest_call);
 
 	*p++ = strlen(callsign) + 10;
@@ -466,7 +418,7 @@
 
 	memcpy(p, callsign, strlen(callsign));
 	p   += strlen(callsign);
-	
+
 	*p++ = FAC_CCITT_SRC_NSAP;
 
 	callsign = ax2asc(&rose->source_call);
@@ -484,7 +436,7 @@
 
 	len       = p - buffer;
 	buffer[0] = len - 1;
-	
+
 	return len;
 }
 
diff -u --recursive --new-file v2.1.21/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c
--- v2.1.21/linux/net/rose/rose_timer.c	Thu Jan  2 15:55:29 1997
+++ linux/net/rose/rose_timer.c	Sun Jan 19 15:47:29 1997
@@ -48,7 +48,7 @@
 void rose_set_timer(struct sock *sk)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&sk->timer);
@@ -65,7 +65,7 @@
 static void rose_reset_timer(struct sock *sk)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&sk->timer);
@@ -102,9 +102,9 @@
 			/*
 			 * Check for the state of the receive buffer.
 			 */
-			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & OWN_RX_BUSY_CONDITION)) {
-				sk->protinfo.rose->condition &= ~OWN_RX_BUSY_CONDITION;
-				sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)) {
+				sk->protinfo.rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
+				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 				sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
 				sk->protinfo.rose->timer      = 0;
 				rose_write_internal(sk, ROSE_RR);
@@ -131,8 +131,8 @@
 	 */
 	switch (sk->protinfo.rose->state) {
 		case ROSE_STATE_3:	/* HB */
-			if (sk->protinfo.rose->condition & ACK_PENDING_CONDITION) {
-				sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+			if (sk->protinfo.rose->condition & ROSE_COND_ACK_PENDING) {
+				sk->protinfo.rose->condition &= ~ROSE_COND_ACK_PENDING;
 				rose_enquiry_response(sk);
 			}
 			break;
diff -u --recursive --new-file v2.1.21/linux/net/rose/sysctl_net_rose.c linux/net/rose/sysctl_net_rose.c
--- v2.1.21/linux/net/rose/sysctl_net_rose.c	Wed Dec 18 15:59:15 1996
+++ linux/net/rose/sysctl_net_rose.c	Sun Jan 19 15:47:29 1997
@@ -10,12 +10,12 @@
 #include <net/ax25.h>
 #include <net/rose.h>
 
-static int min_timer[] = {1 * PR_SLOWHZ};
-static int max_timer[] = {300 * PR_SLOWHZ};
-static int min_idle[]  = {0 * PR_SLOWHZ};
-static int max_idle[]  = {65535 * PR_SLOWHZ};
+static int min_timer[] = {1 * ROSE_SLOWHZ};
+static int max_timer[] = {300 * ROSE_SLOWHZ};
+static int min_idle[]  = {0 * ROSE_SLOWHZ};
+static int max_idle[]  = {65535 * ROSE_SLOWHZ};
 static int min_route[] = {0};
-static int max_route[] = {0};
+static int max_route[] = {1};
 
 static struct ctl_table_header *rose_table_header;
 
diff -u --recursive --new-file v2.1.21/linux/net/socket.c linux/net/socket.c
--- v2.1.21/linux/net/socket.c	Wed Jan 15 19:45:47 1997
+++ linux/net/socket.c	Sun Jan 19 15:47:29 1997
@@ -554,32 +554,18 @@
 }
 
 
-/*
- *	Perform the socket system call. we locate the appropriate
- *	family, then create a fresh socket.
- */
-
-static int find_protocol_family(int family)
-{
-	register int i;
-	for (i = 0; i < NPROTO; i++)
-	{
-		if (net_families[i] == NULL)
-			continue;
-		if (net_families[i]->family == family)
-			return i;
-	}
-	return -1;
-}
-
 asmlinkage int sys_socket(int family, int type, int protocol)
 {
 	int i, fd;
 	struct socket *sock;
 
-	/* Locate the correct protocol family. */
-	i = find_protocol_family(family);
-
+	/*
+	 *	Check protocol is in range
+	 */
+	 
+	if(family<0||family>=NPROTO)
+		return -EINVAL;
+		
 #if defined(CONFIG_KERNELD) && defined(CONFIG_NET)
 	/* Attempt to load a protocol module if the find failed. 
 	 * 
@@ -587,16 +573,15 @@
 	 * requested real, full-featured networking support upon configuration.
 	 * Otherwise module support will break!
 	 */
-	if (i < 0)
+	if (net_families[family]==NULL)
 	{
 		char module_name[30];
 		sprintf(module_name,"net-pf-%d",family);
 		request_module(module_name);
-		i = find_protocol_family(family);
 	}
 #endif
 
-	if (i < 0)
+	if (net_families[family]==NULL)
   		return -EINVAL;
 
 /*
@@ -625,7 +610,7 @@
 
 	sock->type = type;
 
-	if ((i = net_families[i]->create(sock, protocol)) < 0) 
+	if ((i = net_families[family]->create(sock, protocol)) < 0) 
 	{
 		sock_release(sock);
 		return(i);
@@ -1121,8 +1106,8 @@
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
 	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];	/* 20 is size of ipv6_pktinfo */
 	struct msghdr msg_sys;
-	void * krn_msg_ctl = NULL;
 	int err;
 	int total_len;
 	
@@ -1133,7 +1118,7 @@
 		return -EOPNOTSUPP;
 
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-		return -EFAULT;
+		return -EFAULT; 
 
 	/* do not move before msg_sys is valid */
 	if (msg_sys.msg_iovlen>UIO_MAXIOV)
@@ -1145,23 +1130,21 @@
 		return err;
 	total_len=err;
 
-	if (msg_sys.msg_control==NULL)
-		msg_sys.msg_controllen = 0;
-
-	if (msg_sys.msg_controllen)
-	{
-		krn_msg_ctl = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
-		
-		if (!krn_msg_ctl)
-		{
-			err = -ENOBUFS;
-			goto flush_it;
-		}		
-		err = copy_from_user(krn_msg_ctl, msg_sys.msg_control,
-				     msg_sys.msg_controllen);
+	if (msg_sys.msg_controllen) {
+		if (msg_sys.msg_controllen > sizeof(ctl)) {
+			char *tmp = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
+			if (tmp == NULL) {
+				err = -ENOBUFS;
+				goto failed2;
+			}
+			err = copy_from_user(tmp, msg_sys.msg_control, msg_sys.msg_controllen);
+			msg_sys.msg_control = tmp;
+		} else {
+			err = copy_from_user(ctl, msg_sys.msg_control, msg_sys.msg_controllen);
+			msg_sys.msg_control = ctl;
+		}
 		if (err)
-			goto flush_it;
-		msg_sys.msg_control = krn_msg_ctl;
+			goto failed;
 	}
 
 	msg_sys.msg_flags = flags;
@@ -1170,15 +1153,12 @@
 
 	err = sock_sendmsg(sock, &msg_sys, total_len);
 
-flush_it:
+failed:
+	if (msg_sys.msg_controllen && msg_sys.msg_control != ctl)
+		kfree(msg_sys.msg_control);
+failed2:
 	if (msg_sys.msg_iov != iov)
-		kfree(iov);
-
-	if (krn_msg_ctl)
-	{
-		kfree(krn_msg_ctl);
-	}
-
+		kfree(msg_sys.msg_iov);
 	return err;
 }
 
@@ -1192,8 +1172,7 @@
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
 	struct msghdr msg_sys;
-	void * krn_msg_ctl = NULL;
-	void * usr_msg_ctl = NULL;
+	unsigned long cmsg_ptr;
 	int err;
 	int total_len;
 	int len = 0;
@@ -1227,79 +1206,27 @@
 
 	total_len=err;
 
+	cmsg_ptr = (unsigned long)msg_sys.msg_control;
 	msg_sys.msg_flags = 0;
 	
-	if (msg_sys.msg_control==NULL)
-		msg_sys.msg_controllen = 0;
-
-	if (msg_sys.msg_controllen)
-	{
-		/*
-		 *	FIXME:
-		 *	I'm assuming that the kernel may have to examine
-		 *	the acciliary control messages passed by the user.
-		 *	Find out what POSIX says about this...
-		 */
-		krn_msg_ctl = kmalloc(msg_sys.msg_controllen, GFP_KERNEL);
-		
-		if (!krn_msg_ctl)
-		{
-			err=-ENOBUFS;
-			goto flush_it;		
-		}
-		err = copy_from_user(krn_msg_ctl, msg_sys.msg_control,
-				     msg_sys.msg_controllen);
-		if (err)
-		{
-			err = -EFAULT;
-			goto flush_it;
-		}
-		usr_msg_ctl = msg_sys.msg_control;
-		msg_sys.msg_control = krn_msg_ctl;
-	}
-
 	if (current->files->fd[fd]->f_flags&O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
-
 	len=sock_recvmsg(sock, &msg_sys, total_len, flags);
 	if (msg_sys.msg_iov != iov)
-		kfree(iov);
+		kfree(msg_sys.msg_iov);
 	if (len<0)
-	{
-		err=len;
-		goto flush_it;
-	}
-	
-	if (uaddr != NULL)
-	{
-		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr,
-					uaddr_len);
-	}
-	
-	if (err >= 0 && msg_sys.msg_controllen)
-	{
-		err = copy_to_user(usr_msg_ctl, krn_msg_ctl,
-				   msg_sys.msg_controllen);
-	}
-
-flush_it:
-	if (msg_sys.msg_iov != iov)
-		kfree(iov);
+		return len;
 
-	if (krn_msg_ctl)
+	if (uaddr != NULL)
 	{
-		kfree(krn_msg_ctl);
+		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
+		if (err)
+			return err;
 	}
-
-	if (err < 0)
-		return err;
-
 	if (put_user(msg_sys.msg_flags, &msg->msg_flags))
 		return -EFAULT;
-
-	if (put_user(msg_sys.msg_controllen, &msg->msg_controllen))
+	if (put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen))
 		return -EFAULT;
-
 	return len;
 }
 
@@ -1431,19 +1358,8 @@
  
 int sock_register(struct net_proto_family *ops)
 {
-	int i;
-
-	cli();
-	for(i = 0; i < NPROTO; i++) 
-	{
-		if (net_families[i] != NULL) 
-			continue;
-		net_families[i] = ops;
-		sti();
-		return(i);
-	}
-	sti();
-	return(-ENOMEM);
+	net_families[ops->family]=ops;
+	return 0;
 }
 
 /*
@@ -1454,22 +1370,8 @@
  
 int sock_unregister(int family)
 {
-	int i;
-
-	cli();
-	for(i = 0; i < NPROTO; i++) 
-	{
-		if (net_families[i] == NULL) 
-			continue;
-		if (net_families[i]->family == family)
-		{
-			net_families[i]=NULL;
-			sti();
-			return(i);
-		}
-	}
-	sti();
-	return(-ENOENT);
+	net_families[family]=NULL;
+	return 0;
 }
 
 void proto_init(void)
diff -u --recursive --new-file v2.1.21/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.21/linux/net/unix/af_unix.c	Thu Jan  2 15:55:29 1997
+++ linux/net/unix/af_unix.c	Sun Jan 19 15:47:30 1997
@@ -3,11 +3,6 @@
  *
  * Authors:	Alan Cox, <alan.cox@linux.org>
  *
- *		Currently this contains all but the file descriptor passing code.
- *		Before that goes in the odd bugs in the iovec handlers need 
- *		fixing, and this bit testing. BSD fd passing is not a trivial part
- *		of the exercise it turns out. Anyone like writing garbage collectors.
- *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
  *		as published by the Free Software Foundation; either version
@@ -298,11 +293,6 @@
 	}
 }
 
-static int unix_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
-
 static int unix_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
@@ -321,30 +311,6 @@
 	return 0;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if(!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 1);
-	}
-}
-
-static void def_callback3(struct sock *sk)
-{
-	if(!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket, 2);
-	}
-}
-
 extern struct proto_ops unix_stream_ops;
 extern struct proto_ops unix_dgram_ops;
 
@@ -377,33 +343,13 @@
 	sk = sk_alloc(GFP_KERNEL);
 	if (!sk)
 		return -ENOMEM;
-	sock->sk = sk;
-	sk->type = sock->type;
-	sk->socket=sock;
-	sk->sleep= &sock->wait;
-
-	sk->peercred.pid = 0;
-	sk->peercred.uid = -1;
-	sk->peercred.gid = -1;
-	
-	init_timer(&sk->timer);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->error_queue);
-	skb_queue_head_init(&sk->back_log);
+
+	sock_init_data(sock,sk);
+	
 	sk->protinfo.af_unix.family=AF_UNIX;
 	sk->protinfo.af_unix.inode=NULL;
 	sk->users=1;				/* Us */
 	sk->protinfo.af_unix.readsem=MUTEX;	/* single task reading lock */
-	sk->rcvbuf=SK_RMEM_MAX;
-	sk->sndbuf=SK_WMEM_MAX;
-	sk->allocation=GFP_KERNEL;
-	sk->state=TCP_CLOSE;
-	sk->priority=SOPRI_NORMAL;
-	sk->state_change=def_callback1;
-	sk->data_ready=def_callback2;
-	sk->write_space=def_callback3;
-	sk->error_report=def_callback1;
 	sk->mtu=4096;
 	sk->protinfo.af_unix.list=&unix_sockets_unbound;
 	unix_insert_socket(sk);
@@ -1489,7 +1435,7 @@
 	unix_shutdown,
 	NULL,
 	NULL,
-	unix_fcntl,
+	sock_no_fcntl,
 	unix_stream_sendmsg,
 	unix_stream_recvmsg
 };
@@ -1510,7 +1456,7 @@
 	unix_shutdown,
 	NULL,
 	NULL,
-	unix_fcntl,
+	sock_no_fcntl,
 	unix_dgram_sendmsg,
 	unix_dgram_recvmsg
 };
diff -u --recursive --new-file v2.1.21/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.21/linux/net/x25/af_x25.c	Thu Jan  2 15:55:29 1997
+++ linux/net/x25/af_x25.c	Sun Jan 19 15:47:30 1997
@@ -15,7 +15,7 @@
  *	History
  *	X.25 001	Jonathan Naylor	Started coding.
  */
-  
+
 #include <linux/config.h>
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
 #include <linux/module.h>
@@ -107,9 +107,9 @@
 
 	called_len  = strlen(called);
 	calling_len = strlen(calling);
-	
+
 	*p++ = (calling_len << 4) | (called_len << 0);
-	
+
 	for (i = 0; i < (called_len + calling_len); i++) {
 		if (i < called_len) {
 			if (i % 2 != 0) {
@@ -129,16 +129,38 @@
 			}
 		}
 	}
-	
+
 	return 1 + (called_len + calling_len + 1) / 2;
 }
 
 /*
  *	Socket removal during an interrupt is now safe.
  */
-extern inline void x25_remove_socket(struct sock *sk)
+static void x25_remove_socket(struct sock *sk)
 {
-	sklist_remove_socket(&x25_list,sk);
+	struct sock *s;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	if ((s = x25_list) == sk) {
+		x25_list = s->next;
+		restore_flags(flags);
+		return;
+	}
+
+	while (s != NULL && s->next != NULL) {
+		if (s->next == sk) {
+			s->next = sk->next;
+			restore_flags(flags);
+			return;
+		}
+
+		s = s->next;
+	}
+
+	restore_flags(flags);
 }
 
 /*
@@ -147,7 +169,7 @@
 static void x25_kill_by_device(struct device *dev)
 {
 	struct sock *s;
-	
+
 	for (s = x25_list; s != NULL; s = s->next) {
 		if (s->protinfo.x25->neighbour->dev == dev) {
 			s->protinfo.x25->state  = X25_STATE_0;
@@ -190,10 +212,17 @@
 /*
  *	Add a socket to the bound sockets list.
  */
- 
-extern inline void x25_insert_socket(struct sock *sk)
+static void x25_insert_socket(struct sock *sk)
 {
-	sklist_insert_socket(&x25_list,sk);
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	sk->next = x25_list;
+	x25_list = sk;
+
+	restore_flags(flags);
 }
 
 /*
@@ -263,7 +292,7 @@
 void x25_destroy_socket(struct sock *);
 
 /*
- *	Handler for deferred kills.
+ *	handler for deferred kills.
  */
 static void x25_destroy_timer(unsigned long data)
 {
@@ -280,15 +309,15 @@
 {
 	struct sk_buff *skb;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
-	
+
 	del_timer(&sk->timer);
-	
+
 	x25_remove_socket(sk);
 	x25_clear_queues(sk);		/* Flush the queues */
-	
+
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
 		if (skb->sk != sk) {		/* A pending connection */
 			skb->sk->dead = 1;	/* Queue the unaccepted socket for death */
@@ -298,8 +327,8 @@
 
 		kfree_skb(skb, FREE_READ);
 	}
-	
-	if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+
+	if (sk->wmem_alloc || sk->rmem_alloc) {	/* Defer: outstanding buffers */
 		init_timer(&sk->timer);
 		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = x25_destroy_timer;
@@ -318,20 +347,13 @@
  *	Handling for system calls applied via the various interfaces to a
  *	X.25 socket object.
  */
- 
-static int x25_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
 
 static int x25_setsockopt(struct socket *sock, int level, int optname,
 	char *optval, int optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int err, opt;
 
-	sk = (struct sock *)sock->sk;
-	
 	if (level != SOL_X25)
 		return -EOPNOTSUPP;
 
@@ -342,49 +364,12 @@
 		return err;
 
 	get_user(opt, (int *)optval);
-	
+
 	switch (optname) {
 		case X25_QBITINCL:
 			sk->protinfo.x25->qbitincl = opt ? 1 : 0;
 			return 0;
 
-		case X25_PACKET_SIZE:
-			if (sk->state != TCP_LISTEN)
-				return -EINVAL;
-			if (opt < X25_PS16 || opt > X25_PS4096)
-				return -EINVAL;
-			sk->protinfo.x25->facilities.packet_size = opt;
-			return 0;
-
-		case X25_WINDOW_SIZE:
-			if (sk->state != TCP_LISTEN)
-				return -EINVAL;
-			if (sk->protinfo.x25->neighbour->extended) {
-				if (opt < 1 || opt > 127)
-					return -EINVAL;
-			} else {
-				if (opt < 1 || opt > 7)
-					return -EINVAL;
-			}
-			sk->protinfo.x25->facilities.window_size = opt;
-			return 0;
-
-		case X25_THROUGHPUT_SPEED:
-			if (sk->state != TCP_LISTEN)
-				return -EINVAL;
-			if (opt < 0x03 || opt > 0x2C)
-				return -EINVAL;
-			sk->protinfo.x25->facilities.throughput = opt;
-			return 0;
-
-		case X25_REVERSE_CHARGE:
-			if (sk->state != TCP_LISTEN)
-				return -EINVAL;
-			if (opt != 0 && opt != 1)
-				return -EINVAL;
-			sk->protinfo.x25->facilities.reverse = opt;
-			return 0;
-
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -393,36 +378,18 @@
 static int x25_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int val = 0;
 	int err; 
 
-	sk = (struct sock *)sock->sk;
-	
 	if (level != SOL_X25)
 		return -EOPNOTSUPP;
-	
+
 	switch (optname) {
 		case X25_QBITINCL:
 			val = sk->protinfo.x25->qbitincl;
 			break;
 
-		case X25_PACKET_SIZE:
-			val = sk->protinfo.x25->facilities.packet_size;
-			break;
-			
-		case X25_WINDOW_SIZE:
-			val = sk->protinfo.x25->facilities.window_size;
-			break;
-
-		case X25_THROUGHPUT_SPEED:
-			val = sk->protinfo.x25->facilities.throughput;
-			break;
-
-		case X25_REVERSE_CHARGE:
-			val = sk->protinfo.x25->facilities.reverse;
-			break;
-
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -442,7 +409,7 @@
 
 static int x25_listen(struct socket *sock, int backlog)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk->state != TCP_LISTEN) {
 		memset(&sk->protinfo.x25->dest_addr, '\0', X25_ADDR_LEN);
@@ -462,8 +429,18 @@
 
 static void def_callback2(struct sock *sk, int len)
 {
-	if (!sk->dead)
+	if (!sk->dead) {
 		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket, 1);
+	}
+}
+
+static void def_callback3(struct sock *sk)
+{
+	if (!sk->dead) {
+		wake_up_interruptible(sk->sleep);
+		sock_wake_async(sk->socket, 2);
+	}
 }
 
 static struct sock *x25_alloc_socket(void)
@@ -494,12 +471,12 @@
 
 	sk->state_change = def_callback1;
 	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback1;
+	sk->write_space  = def_callback3;
 	sk->error_report = def_callback1;
 
-	skb_queue_head_init(&x25->ack_queue);
 	skb_queue_head_init(&x25->fragment_queue);
-	skb_queue_head_init(&x25->interrupt_queue);
+	skb_queue_head_init(&x25->interrupt_in_queue);
+	skb_queue_head_init(&x25->interrupt_out_queue);
 
 	return sk;
 }
@@ -542,8 +519,10 @@
 
 	x25->state       = X25_STATE_0;
 
-	x25->facilities.window_size = X25_DEFAULT_WINDOW_SIZE;
-	x25->facilities.packet_size = X25_DEFAULT_PACKET_SIZE;
+	x25->facilities.winsize_in  = X25_DEFAULT_WINDOW_SIZE;
+	x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
+	x25->facilities.pacsize_in  = X25_DEFAULT_PACKET_SIZE;
+	x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
 	x25->facilities.throughput  = X25_DEFAULT_THROUGHPUT;
 	x25->facilities.reverse     = X25_DEFAULT_REVERSE;
 
@@ -589,14 +568,17 @@
 
 static int x25_dup(struct socket *newsock, struct socket *oldsock)
 {
-	struct sock *sk = (struct sock *)oldsock->sk;
+	struct sock *sk = oldsock->sk;
+
+	if (sk == NULL || newsock == NULL)
+		return -EINVAL;
 
 	return x25_create(newsock, sk->protocol);
 }
 
 static int x25_release(struct socket *sock, struct socket *peer)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk == NULL) return 0;
 
@@ -653,14 +635,12 @@
 
 static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
-	
-	sk = (struct sock *)sock->sk;
 
 	if (sk->zapped == 0)
 		return -EINVAL;
-		
+
 	if (addr_len != sizeof(struct sockaddr_x25))
 		return -EINVAL;
 
@@ -681,29 +661,32 @@
 
 static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
 	struct device *dev;
-	
+
 	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
 		return 0;	/* Connect completed during a ERESTARTSYS event */
 	}
-	
+
 	if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
 		sock->state = SS_UNCONNECTED;
 		return -ECONNREFUSED;
 	}
-	
+
 	if (sk->state == TCP_ESTABLISHED)
 		return -EISCONN;	/* No reconnect on a seqpacket socket */
-		
+
 	sk->state   = TCP_CLOSE;	
 	sock->state = SS_UNCONNECTED;
 
 	if (addr_len != sizeof(struct sockaddr_x25))
 		return -EINVAL;
 
+	if (addr->sx25_family != AF_X25)
+		return -EINVAL;
+
 	if ((dev = x25_get_route(&addr->sx25_addr)) == NULL)
 		return -ENETUNREACH;
 
@@ -725,11 +708,11 @@
 	x25_write_internal(sk, X25_CALL_REQUEST);
 
 	x25_set_timer(sk);
-	
+
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
-		
+
 	cli();	/* To avoid races on the sleep */
 
 	/*
@@ -748,11 +731,11 @@
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
-	
+
 	sock->state = SS_CONNECTED;
 
 	sti();
-	
+
 	return 0;
 }
 	
@@ -767,19 +750,20 @@
 	struct sock *newsk;
 	struct sk_buff *skb;
 
-	if (newsock->sk)
-		sk_free(newsock->sk);
+	if (newsock->sk != NULL)
+		x25_destroy_socket(newsock->sk);
 
 	newsock->sk = NULL;
-	
-	sk = (struct sock *)sock->sk;
+
+	if ((sk = sock->sk) == NULL)
+		return -EINVAL;
 
 	if (sk->type != SOCK_SEQPACKET)
 		return -EOPNOTSUPP;
-	
+
 	if (sk->state != TCP_LISTEN)
 		return -EINVAL;
-		
+
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the CALL INDICATION we saved
@@ -789,7 +773,7 @@
 		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
 			if (flags & O_NONBLOCK) {
 				sti();
-				return 0;
+				return -EWOULDBLOCK;
 			}
 			interruptible_sleep_on(sk->sleep);
 			if (current->signal & ~current->blocked) {
@@ -815,10 +799,8 @@
 static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
 {
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
-	struct sock *sk;
-	
-	sk = (struct sock *)sock->sk;
-	
+	struct sock *sk = sock->sk;
+
 	if (peer != 0) {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
@@ -839,11 +821,6 @@
 	struct sock *make;
 	x25_address source_addr, dest_addr;
 	struct x25_facilities facilities;
-	int len;
-
-	/*
-	 *	skb->data points to the x25 frame start
-	 */
 
 	/*
 	 *	Remove the LCI and frame type.
@@ -851,14 +828,10 @@
 	skb_pull(skb, X25_STD_MIN_LEN);
 
 	/*
-	 *	Extract the X.25 addresses and convert them to ASCII strings.
+	 *	Extract the X.25 addresses and convert them to ASCII strings,
+	 *	and remove them.
 	 */
-	len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
-
-	/*
-	 *	Remove address lengths and addresses.
-	 */
-	skb_pull(skb, len);
+	skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
 
 	/*
 	 *	Find a listener for the particular address.
@@ -874,14 +847,10 @@
 	}
 
 	/*
-	 *	Parse the facilities.
-	 */
-	len = x25_parse_facilities(skb, &facilities);
-
-	/*
-	 *	Then remove them, leaving any Call User Data.
+	 *	Parse the facilities, and remove them, leaving any Call User
+	 *	Data.
 	 */
-	skb_pull(skb, len);
+	skb_pull(skb, x25_parse_facilities(skb, &facilities));
 
 	skb->sk     = make;
 	make->state = TCP_ESTABLISHED;
@@ -897,11 +866,15 @@
 	 */
 	make->protinfo.x25->facilities    = facilities;
 
+	x25_write_internal(make, X25_CALL_ACCEPTED);
+
 	/*
-	 *	Incoming Call User Data. XXX
+	 *	Incoming Call User Data.
 	 */
-	
-	x25_write_internal(make, X25_CALL_ACCEPTED);
+	if (skb->len >= 0) {
+		memcpy(make->protinfo.x25->calluserdata.cuddata, skb->data, skb->len);
+		make->protinfo.x25->calluserdata.cudlength = skb->len;
+	}
 
 	make->protinfo.x25->state = X25_STATE_3;
 
@@ -922,7 +895,7 @@
 
 static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
 	int err;
 	struct sockaddr_x25 sx25;
@@ -930,7 +903,7 @@
 	unsigned char *asmptr;
 	int size, qbit = 0;
 
-	if (msg->msg_flags & ~MSG_DONTWAIT)
+	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB))
 		return -EINVAL;
 
 	if (sk->zapped)
@@ -943,7 +916,7 @@
 
 	if (sk->protinfo.x25->neighbour == NULL)
 		return -ENETUNREACH;
-		
+
 	if (usx25 != NULL) {
 		if (msg->msg_namelen < sizeof(sx25))
 			return -EINVAL;
@@ -964,7 +937,7 @@
 		sx25.sx25_family = AF_X25;
 		sx25.sx25_addr   = sk->protinfo.x25->dest_addr;
 	}
-	
+
 	if (sk->debug)
 		printk(KERN_DEBUG "x25_sendmsg: sendto: Addresses built.\n");
 
@@ -972,16 +945,16 @@
 	if (sk->debug)
 		printk(KERN_DEBUG "x25_sendmsg: sendto: building packet.\n");
 
+	if ((msg->msg_flags & MSG_OOB) && len > 32)
+		len = 32;
+
 	size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
 
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->sk   = sk;
-	skb->arp  = 1;
-
 	skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
-	
+
 	/*
 	 *	Put the data on the end
 	 */
@@ -1005,26 +978,40 @@
 	/*
 	 *	Push down the X.25 header
 	 */
-	if (sk->debug)
+ 	if (sk->debug)
 		printk(KERN_DEBUG "x25_sendmsg: Building X.25 Header.\n");
 
-	if (sk->protinfo.x25->neighbour->extended) {
-		/* Build an Extended X.25 header */
-		asmptr    = skb_push(skb, X25_EXT_MIN_LEN);
-		*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ;
-		*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
-		*asmptr++ = X25_DATA;
-		*asmptr++ = X25_DATA;
+	if (msg->msg_flags & MSG_OOB) {
+		if (sk->protinfo.x25->neighbour->extended) {
+			asmptr    = skb_push(skb, X25_STD_MIN_LEN);
+			*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ;
+			*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
+			*asmptr++ = X25_INTERRUPT;
+		} else {
+			asmptr    = skb_push(skb, X25_STD_MIN_LEN);
+			*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ;
+			*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
+			*asmptr++ = X25_INTERRUPT;
+		}
 	} else {
-		/* Build an Standard X.25 header */
-		asmptr    = skb_push(skb, X25_STD_MIN_LEN);
-		*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ;
-		*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
-		*asmptr++ = X25_DATA;
-	}
+		if (sk->protinfo.x25->neighbour->extended) {
+			/* Build an Extended X.25 header */
+			asmptr    = skb_push(skb, X25_EXT_MIN_LEN);
+			*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ;
+			*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
+			*asmptr++ = X25_DATA;
+			*asmptr++ = X25_DATA;
+		} else {
+			/* Build an Standard X.25 header */
+			asmptr    = skb_push(skb, X25_STD_MIN_LEN);
+			*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ;
+			*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
+			*asmptr++ = X25_DATA;
+		}
 
-	if (qbit)
-		skb->data[0] |= X25_Q_BIT;
+		if (qbit)
+			skb->data[0] |= X25_Q_BIT;
+	}
 
 	if (sk->debug)
 		printk(KERN_DEBUG "x25_sendmsg: Built header.\n");
@@ -1037,7 +1024,14 @@
 		return -ENOTCONN;
 	}
 
-	x25_output(sk, skb);	/* Shove it onto the queue */
+	if (msg->msg_flags & MSG_OOB) {
+		skb_queue_tail(&sk->protinfo.x25->interrupt_out_queue, skb);
+	} else {
+		x25_output(sk, skb);
+	}
+
+	if (sk->protinfo.x25->state == X25_STATE_3)
+		x25_kick(sk);
 
 	return len;
 }
@@ -1045,7 +1039,7 @@
 
 static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
 	int copied, qbit;
 	struct sk_buff *skb;
@@ -1059,37 +1053,52 @@
 	if (sk->state != TCP_ESTABLISHED)
 		return -ENOTCONN;
 
-	/* Now we can treat all alike */
-	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
-		return er;
+	if (flags & MSG_OOB) {
+		if (sk->urginline || skb_peek(&sk->protinfo.x25->interrupt_in_queue) == NULL)
+			return -EINVAL;
 
-	qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
+		skb = skb_dequeue(&sk->protinfo.x25->interrupt_in_queue);
 
-	skb_pull(skb, (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
-	skb->h.raw = skb->data;
+		skb_pull(skb, X25_STD_MIN_LEN);
 
-	if (sk->protinfo.x25->qbitincl) {
-		asmptr  = skb_push(skb, 1);
-		*asmptr = qbit;
-		skb->h.raw = skb->data;
+		/*
+		 *	No Q bit information on Interrupt data.
+		 */
+		if (sk->protinfo.x25->qbitincl) {
+			asmptr  = skb_push(skb, 1);
+			*asmptr = 0x00;
+		}
+
+		msg->msg_flags |= MSG_OOB;
+	} else {
+		/* Now we can treat all alike */
+		if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
+			return er;
+
+		qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
+
+		skb_pull(skb, (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
+
+		if (sk->protinfo.x25->qbitincl) {
+			asmptr  = skb_push(skb, 1);
+			*asmptr = qbit;
+		}
 	}
 
+	skb->h.raw = skb->data;
+
 	copied = skb->len;
-	
+
 	if (copied > size) {
 		copied = size;
 		msg->msg_flags |= MSG_TRUNC;
 	}
 
 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-	
-	if (sx25 != NULL) {
-		struct sockaddr_x25 addr;
-		
-		addr.sx25_family = AF_X25;
-		addr.sx25_addr   = sk->protinfo.x25->dest_addr;
 
-		*sx25 = addr;
+	if (sx25 != NULL) {
+		sx25->sx25_family = AF_X25;
+		sx25->sx25_addr   = sk->protinfo.x25->dest_addr;
 	}
 
 	msg->msg_namelen = sizeof(struct sockaddr_x25);
@@ -1106,7 +1115,9 @@
 
 static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct x25_facilities facilities;
+	struct x25_calluserdata calluserdata;
+	struct sock *sk = sock->sk;
 	int err;
 	long amount = 0;
 
@@ -1159,10 +1170,64 @@
 			if (!suser()) return -EPERM;
 			return x25_route_ioctl(cmd, (void *)arg);
 
-		case SIOCX25SETSUBSCR:
+		case SIOCX25GSUBSCRIP:
+			return x25_subscr_ioctl(cmd, (void *)arg);
+
+		case SIOCX25SSUBSCRIP:
 			if (!suser()) return -EPERM;
 			return x25_subscr_ioctl(cmd, (void *)arg);
 
+		case SIOCX25GFACILITIES:
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(facilities))) != 0)
+				return err;
+			facilities = sk->protinfo.x25->facilities;
+			copy_to_user((void *)arg, &facilities, sizeof(facilities));
+			return 0;
+
+		case SIOCX25SFACILITIES:
+			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(facilities))) != 0)
+				return err;
+			copy_from_user(&facilities, (void *)arg, sizeof(facilities));
+			if (sk->state != TCP_LISTEN)
+				return -EINVAL;
+			if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096)
+				return -EINVAL;
+			if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096)
+				return -EINVAL;
+			if (sk->protinfo.x25->neighbour->extended) {
+				if (facilities.winsize_in < 1 || facilities.winsize_in > 127)
+					return -EINVAL;
+				if (facilities.winsize_out < 1 || facilities.winsize_out > 127)
+					return -EINVAL;
+			} else {
+				if (facilities.winsize_in < 1 || facilities.winsize_in > 7)
+					return -EINVAL;
+				if (facilities.winsize_out < 1 || facilities.winsize_out > 7)
+					return -EINVAL;
+			}
+			if (facilities.throughput < 0x03 || facilities.throughput > 0x2C)
+				return -EINVAL;
+			if (facilities.reverse != 0 && facilities.reverse != 1)
+				return -EINVAL;
+			sk->protinfo.x25->facilities = facilities;
+			return 0;
+
+		case SIOCX25GCALLUSERDATA:
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(calluserdata))) != 0)
+				return err;
+			calluserdata = sk->protinfo.x25->calluserdata;
+			copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata));
+			return 0;
+
+		case SIOCX25SCALLUSERDATA:
+			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(calluserdata))) != 0)
+				return err;
+			copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata));
+			if (calluserdata.cudlength > X25_MAX_CUD_LEN)
+				return -EINVAL;
+			sk->protinfo.x25->calluserdata = calluserdata;
+			return 0;
+
  		default:
 			return dev_ioctl(cmd, (void *)arg);
 	}
@@ -1179,7 +1244,7 @@
 	int len = 0;
 	off_t pos = 0;
 	off_t begin = 0;
-  
+
 	cli();
 
 	len += sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   t  t2 t21 t22 t23 Snd-Q Rcv-Q\n");
@@ -1202,14 +1267,14 @@
 			s->protinfo.x25->t22   / X25_SLOWHZ,
 			s->protinfo.x25->t23   / X25_SLOWHZ,
 			s->wmem_alloc, s->rmem_alloc);
-		
+
 		pos = begin + len;
 
 		if (pos < offset) {
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -1245,7 +1310,7 @@
 	x25_shutdown,
 	x25_setsockopt,
 	x25_getsockopt,
-	x25_fcntl,
+	sock_no_fcntl,
 	x25_sendmsg,
 	x25_recvmsg
 };
@@ -1254,7 +1319,7 @@
 {
 	0,		/* MUTTER ntohs(ETH_P_X25),*/
 	0,		/* copy */
-	x25_llc_receive_frame,
+	x25_lapb_receive_frame,
 	NULL,
 	NULL,
 };
@@ -1264,6 +1329,27 @@
 	0
 };
 
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_x25 = {
+	PROC_NET_X25, 3, "x25",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_net_inode_operations, 
+	x25_get_info
+};
+static struct proc_dir_entry proc_net_x25_links = {
+	PROC_NET_X25_LINKS, 9, "x25_links",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_net_inode_operations, 
+	x25_link_get_info
+};
+static struct proc_dir_entry proc_net_x25_routes = {
+	PROC_NET_X25_ROUTES, 10, "x25_routes",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_net_inode_operations, 
+	x25_routes_get_info
+};
+#endif	
+
 void x25_proto_init(struct net_proto *pro)
 {
 	sock_register(&x25_family_ops);
@@ -1278,26 +1364,9 @@
 	x25_register_sysctl();
 
 #ifdef CONFIG_PROC_FS
-	proc_net_register(&(struct proc_dir_entry) {
-		PROC_NET_X25, 3, "x25",
-		S_IFREG | S_IRUGO, 1, 0, 0,
-		0, &proc_net_inode_operations, 
-		x25_get_info
-	});
-
-	proc_net_register(&(struct proc_dir_entry) {
-		PROC_NET_X25_LINKS, 9, "x25_links",
-		S_IFREG | S_IRUGO, 1, 0, 0,
-		0, &proc_net_inode_operations, 
-		x25_link_get_info
-	});
-
-	proc_net_register(&(struct proc_dir_entry) {
-		PROC_NET_X25_ROUTES, 10, "x25_routes",
-		S_IFREG | S_IRUGO, 1, 0, 0,
-		0, &proc_net_inode_operations, 
-		x25_routes_get_info
-	});
+	proc_net_register(&proc_net_x25);
+	proc_net_register(&proc_net_x25_links);
+	proc_net_register(&proc_net_x25_routes);
 #endif	
 }
 
@@ -1306,7 +1375,20 @@
 
 int init_module(void)
 {
+	struct device *dev;
+
 	x25_proto_init(NULL);
+
+	/*
+	 *	Register any pre existing devices.
+	 */
+	for (dev = dev_base; dev != NULL; dev = dev->next)
+		if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25
+#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
+					   || dev->type == ARPHRD_ETHER
+#endif
+									))
+		x25_link_device_up(dev);
 	
 	return 0;
 }
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c
--- v2.1.21/linux/net/x25/x25_dev.c	Thu Jan  2 15:55:30 1997
+++ linux/net/x25/x25_dev.c	Sun Jan 19 15:47:30 1997
@@ -15,7 +15,7 @@
  *	History
  *	X.25 001	Jonathan Naylor	Started coding.
  */
-  
+
 #include <linux/config.h>
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
 #include <linux/errno.h>
@@ -89,8 +89,9 @@
 	/*
 	 *	Its not a Call Request, nor is it a control frame, throw it awa
 	 */
+/*
 	x25_transmit_clear_request(neigh, lci, 0x0D);
-
+*/
 	kfree_skb(skb, FREE_READ);
 
 	return 0;
@@ -101,11 +102,12 @@
 	struct x25_neigh *neigh;
 
 	skb->sk = NULL;
-	
+
 	/*
 	 *	Packet received from unrecognised device, throw it away.
 	 */
 	if ((neigh = x25_get_neigh(dev)) == NULL) {
+		printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name);
 		kfree_skb(skb, FREE_READ);
 		return 0;
 	}
@@ -129,10 +131,6 @@
 			kfree_skb(skb, FREE_READ);
 			return 0;
 
-		case 0x04:
-			kfree_skb(skb, FREE_READ);
-			return 0;
-
 		default:
 			kfree_skb(skb, FREE_READ);
 			return 0;
@@ -144,11 +142,12 @@
 	struct x25_neigh *neigh;
 
 	skb->sk = NULL;
-	
+
 	/*
 	 *	Packet received from unrecognised device, throw it away.
 	 */
 	if ((neigh = x25_get_neigh(dev)) == NULL) {
+		printk(KERN_DEBUG "X.25: unknown_neighbour - %s\n", dev->name);
 		kfree_skb(skb, FREE_READ);
 		return 0;
 	}
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.1.21/linux/net/x25/x25_in.c	Wed Dec 18 15:59:15 1996
+++ linux/net/x25/x25_in.c	Sun Jan 19 15:47:30 1997
@@ -49,7 +49,7 @@
 		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
 		return 0;
 	}
-	
+
 	if (!more && sk->protinfo.x25->fraglen > 0) {	/* End of fragment */
 		sk->protinfo.x25->fraglen += skb->len;
 		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
@@ -57,7 +57,6 @@
 		if ((skbn = alloc_skb(sk->protinfo.x25->fraglen, GFP_ATOMIC)) == NULL)
 			return 1;
 
-		skbn->arp  = 1;
 		skb_set_owner_r(skbn, sk);
 		skbn->h.raw = skbn->data;
 
@@ -84,6 +83,9 @@
  */
 static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
 {
+	x25_address source_addr, dest_addr;
+	struct x25_facilities facilities;
+
 	switch (frametype) {
 
 		case X25_CALL_ACCEPTED:
@@ -95,6 +97,20 @@
 			sk->protinfo.x25->vl        = 0;
 			sk->protinfo.x25->state     = X25_STATE_3;
 			sk->state                   = TCP_ESTABLISHED;
+			/*
+			 *	Parse the data in the frame.
+			 */
+			skb_pull(skb, X25_STD_MIN_LEN);
+			skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
+			skb_pull(skb, x25_parse_facilities(skb, &facilities));
+			/*
+			 *	Facilities XXX
+			 *	Copy any Call User Data.
+			 */
+			if (skb->len >= 0) {
+				memcpy(sk->protinfo.x25->calluserdata.cuddata, skb->data, skb->len);
+				sk->protinfo.x25->calluserdata.cudlength = skb->len;
+			}
 			if (!sk->dead)
 				sk->state_change(sk);
 			break;
@@ -202,13 +218,13 @@
 				sk->protinfo.x25->timer     = sk->protinfo.x25->t22;
 			} else {
 				if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
-					x25_frames_acked(sk, nr);
+					sk->protinfo.x25->va = nr;
 				} else {
 					x25_check_iframes_acked(sk, nr);
 				}
 			}
 			break;
-			
+
 		case X25_DATA:	/* XXX */
 			sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
 			if (!x25_validate_nr(sk, nr)) {
@@ -224,7 +240,7 @@
 				break;
 			}
 			if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
-				x25_frames_acked(sk, nr);
+				sk->protinfo.x25->va = nr;
 			} else {
 				x25_check_iframes_acked(sk, nr);
 			}
@@ -242,7 +258,7 @@
 			 *	If the window is full Ack it immediately, else
 			 *	start the holdback timer.
 			 */
-			if (((sk->protinfo.x25->vl + sk->protinfo.x25->facilities.window_size) % modulus) == sk->protinfo.x25->vr) {
+			if (((sk->protinfo.x25->vl + sk->protinfo.x25->facilities.winsize_in) % modulus) == sk->protinfo.x25->vr) {
 				sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
 				sk->protinfo.x25->timer      = 0;
 				x25_enquiry_response(sk);
@@ -252,6 +268,27 @@
 			}
 			break;
 
+		case X25_INTERRUPT_CONFIRMATION:
+			sk->protinfo.x25->intflag = 0;
+			break;
+
+		case X25_INTERRUPT:
+			if (sk->urginline) {
+				queued = (sock_queue_rcv_skb(sk, skb) == 0);
+			} else {
+				skb_set_owner_r(skb, sk);
+				skb_queue_tail(&sk->protinfo.x25->interrupt_in_queue, skb);
+				queued = 1;
+			}
+			if (sk->proc != 0) {
+				if (sk->proc > 0)
+					kill_proc(sk->proc, SIGURG, 1);
+				else
+					kill_pg(-sk->proc, SIGURG, 1);
+			}
+			x25_write_internal(sk, X25_INTERRUPT_CONFIRMATION);
+			break;
+
 		default:
 			printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype);
 			break;
@@ -305,7 +342,7 @@
 int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
 	int queued = 0, frametype, ns, nr, q, d, m;
-	
+
 	if (sk->protinfo.x25->state == X25_STATE_0)
 		return 0;
 
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_link.c linux/net/x25/x25_link.c
--- v2.1.21/linux/net/x25/x25_link.c	Thu Jan  2 15:55:30 1997
+++ linux/net/x25/x25_link.c	Sun Jan 19 15:47:30 1997
@@ -51,7 +51,7 @@
 static void x25_link_set_timer(struct x25_neigh *neigh)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&neigh->timer);
@@ -68,7 +68,7 @@
 static void x25_link_reset_timer(struct x25_neigh *neigh)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 	del_timer(&neigh->timer);
@@ -278,6 +278,9 @@
 	}
 }
 
+/*
+ *	Called when the link layer has become established.
+ */
 void x25_link_established(struct x25_neigh *neigh)
 {
 	switch (neigh->state) {
@@ -293,6 +296,10 @@
 	}
 }
 
+/*
+ *	Called when the link layer has terminated, or an establishment
+ *	request has failed. XXX should tell sockets.
+ */
 void x25_link_terminated(struct x25_neigh *neigh)
 {
 	neigh->state = X25_LINK_STATE_0;
@@ -332,7 +339,7 @@
 
 	while ((skb = skb_dequeue(&x25_neigh->queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	
+
 	del_timer(&x25_neigh->timer);
 
 	save_flags(flags);
@@ -369,7 +376,7 @@
 	while (x25_neigh != NULL) {
 		neigh     = x25_neigh;
 		x25_neigh = x25_neigh->next;
-		
+
 		if (neigh->dev == dev)
 			x25_remove_neigh(neigh);
 	}
@@ -401,7 +408,18 @@
 
 	switch (cmd) {
 
-		case SIOCX25SETSUBSCR:
+		case SIOCX25GSUBSCRIP:
+			if ((err = verify_area(VERIFY_WRITE, arg, sizeof(struct x25_subscrip_struct))) != 0)
+				return err;
+			if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
+				return -EINVAL;
+			if ((x25_neigh = x25_get_neigh(dev)) == NULL)
+				return -EINVAL;
+			x25_subscr.extended = x25_neigh->extended;
+			copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct));
+			break;
+
+		case SIOCX25SSUBSCRIP:
 			if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_subscrip_struct))) != 0)
 				return err;
 			copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct));
@@ -446,7 +464,7 @@
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -473,7 +491,7 @@
 	while (x25_neigh != NULL) {
 		neigh     = x25_neigh;
 		x25_neigh = x25_neigh->next;
-		
+
 		x25_remove_neigh(neigh);
 	}
 }
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_out.c linux/net/x25/x25_out.c
--- v2.1.21/linux/net/x25/x25_out.c	Wed Dec 18 15:59:25 1996
+++ linux/net/x25/x25_out.c	Sun Jan 19 15:47:30 1997
@@ -39,6 +39,19 @@
 #include <linux/interrupt.h>
 #include <net/x25.h>
 
+static int x25_pacsize_to_bytes(unsigned int pacsize)
+{
+	int bytes = 1;
+
+	if (pacsize == 0)
+		return 128;
+
+	while (pacsize-- > 0)
+		bytes *= 2;
+
+	return bytes;
+}
+
 /*
  *	This is where all X.25 information frames pass;
  */
@@ -46,35 +59,33 @@
 {
 	struct sk_buff *skbn;
 	unsigned char header[X25_EXT_MIN_LEN];
-	int err, frontlen, len, min_len;
-	
-	min_len  = (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
+	int err, frontlen, len, header_len, max_len;
+
+	header_len = (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
+	max_len    = x25_pacsize_to_bytes(sk->protinfo.x25->facilities.pacsize_out);
 
-	if (skb->len - min_len > 128) {		/* XXX */
+	if (skb->len - header_len > max_len) {
 		/* Save a copy of the Header */
-		memcpy(header, skb->data, min_len);
-		skb_pull(skb, min_len);
+		memcpy(header, skb->data, header_len);
+		skb_pull(skb, header_len);
 
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + 128, 0, 0, &err)) == NULL)	/* XXX */
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL)
 				return;
 
-			skbn->sk   = sk;
-			skbn->arp  = 1;
-
 			skb_reserve(skbn, frontlen);
 
-			len = (128 > skb->len) ? skb->len : 128;	/* XXX */
+			len = (max_len > skb->len) ? skb->len : max_len;
 
 			/* Copy the user data */
 			memcpy(skb_put(skbn, len), skb->data, len);
 			skb_pull(skb, len);
 
 			/* Duplicate the Header */
-			skb_push(skbn, min_len);
-			memcpy(skbn->data, header, min_len);
+			skb_push(skbn, header_len);
+			memcpy(skbn->data, header, header_len);
 
 			if (skb->len > 0) {
 				if (sk->protinfo.x25->neighbour->extended)
@@ -82,17 +93,14 @@
 				else
 					skbn->data[2] |= X25_STD_M_BIT;
 			}
-		
-			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
+
+			skb_queue_tail(&sk->write_queue, skbn);
 		}
 		
 		kfree_skb(skb, FREE_WRITE);
 	} else {
-		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */
+		skb_queue_tail(&sk->write_queue, skb);
 	}
-
-	if (sk->protinfo.x25->state == X25_STATE_3)
-		x25_kick(sk);
 }
 
 /* 
@@ -117,56 +125,46 @@
 
 void x25_kick(struct sock *sk)
 {
-	struct sk_buff *skb, *skbn;
-	int last = 1;
-	unsigned short start, end, next;
+	struct sk_buff *skb;
+	unsigned short end;
 	int modulus;
-	
-	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
 
 	del_timer(&sk->timer);
 
-	start = (skb_peek(&sk->protinfo.x25->ack_queue) == NULL) ? sk->protinfo.x25->va : sk->protinfo.x25->vs;
-	end   = (sk->protinfo.x25->va + sk->protinfo.x25->facilities.window_size) % modulus;
+	/*
+	 *	Transmit interrupt data.
+	 */
+	if (!sk->protinfo.x25->intflag && skb_peek(&sk->protinfo.x25->interrupt_out_queue) != NULL) {
+		sk->protinfo.x25->intflag = 1;
+		skb = skb_dequeue(&sk->protinfo.x25->interrupt_out_queue);
+		x25_transmit_link(skb, sk->protinfo.x25->neighbour);
+	}
 
+	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+	end     = (sk->protinfo.x25->va + sk->protinfo.x25->facilities.winsize_out) % modulus;
+
+	/*
+	 *	Transmit normal stream data.
+	 */
 	if (!(sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) &&
-	    start != end                                           &&
+	    sk->protinfo.x25->vs != end                            &&
 	    skb_peek(&sk->write_queue) != NULL) {
-
-		sk->protinfo.x25->vs = start;
-
 		/*
 		 * Transmit data until either we're out of data to send or
 		 * the window is full.
 		 */
 
-		/*
-		 * Dequeue the frame and copy it.
-		 */
-		skb  = skb_dequeue(&sk->write_queue);
+		skb = skb_dequeue(&sk->write_queue);
 
 		do {
-			if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-				skb_queue_head(&sk->write_queue, skb);
-				break;
-			}
-
-			next = (sk->protinfo.x25->vs + 1) % modulus;
-			last = (next == end);
-
 			/*
-			 * Transmit the frame copy.
+			 * Transmit the frame.
 			 */
-			x25_send_iframe(sk, skbn);
+			x25_send_iframe(sk, skb);
 
-			sk->protinfo.x25->vs = next;
-
-			/*
-			 * Requeue the original data frame.
-			 */
-			skb_queue_tail(&sk->protinfo.x25->ack_queue, skb);
+			sk->protinfo.x25->vs = (sk->protinfo.x25->vs + 1) % modulus;
 
-		} while (!last && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+		} while (sk->protinfo.x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL);
 
 		sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
 		sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
@@ -196,10 +194,10 @@
 void x25_check_iframes_acked(struct sock *sk, unsigned short nr)
 {
 	if (sk->protinfo.x25->vs == nr) {
-		x25_frames_acked(sk, nr);
+		sk->protinfo.x25->va = nr;
 	} else {
 		if (sk->protinfo.x25->va != nr) {
-			x25_frames_acked(sk, nr);
+			sk->protinfo.x25->va = nr;
 		}
 	}
 }
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_route.c linux/net/x25/x25_route.c
--- v2.1.21/linux/net/x25/x25_route.c	Thu Jan  2 15:55:30 1997
+++ linux/net/x25/x25_route.c	Sun Jan 19 15:47:30 1997
@@ -15,7 +15,7 @@
  *	History
  *	X.25 001	Jonathan Naylor	Started coding.
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
 #include <linux/errno.h>
@@ -72,7 +72,7 @@
 	x25_route->next = x25_route_list;
 	x25_route_list  = x25_route;
 	restore_flags(flags);
-		
+
 	return 0;
 }
 
@@ -80,7 +80,7 @@
 {
 	struct x25_route *s;
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
@@ -108,7 +108,7 @@
 static int x25_del_route(x25_address *address, unsigned int sigdigits, struct device *dev)
 {
 	struct x25_route *x25_route;
-	
+
 	for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
 		if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits && x25_route->dev == dev) {
 			x25_remove_route(x25_route);
@@ -129,7 +129,7 @@
 	while (x25_route != NULL) {
 		route     = x25_route;
 		x25_route = x25_route->next;
-		
+
 		if (route->dev == dev)
 			x25_remove_route(route);
 	}
@@ -161,7 +161,7 @@
 struct device *x25_get_route(x25_address *addr)
 {
 	struct x25_route *route, *use = NULL;
-	
+
 	for (route = x25_route_list; route != NULL; route = route->next) {
 		if (memcmp(&route->address, addr, route->sigdigits) == 0) {
 			if (use == NULL) {
@@ -236,7 +236,7 @@
 			len   = 0;
 			begin = pos;
 		}
-		
+
 		if (pos > offset + length)
 			break;
 	}
@@ -263,7 +263,7 @@
 	while (x25_route != NULL) {
 		route     = x25_route;
 		x25_route = x25_route->next;
-		
+
 		x25_remove_route(route);
 	}
 }
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_subr.c linux/net/x25/x25_subr.c
--- v2.1.21/linux/net/x25/x25_subr.c	Wed Dec 18 15:59:25 1996
+++ linux/net/x25/x25_subr.c	Sun Jan 19 15:47:30 1997
@@ -15,7 +15,7 @@
  *	History
  *	X.25 001	Jonathan Naylor	Started coding.
  */
- 
+
 #include <linux/config.h>
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
 #include <linux/errno.h>
@@ -46,68 +46,17 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
-		skb->sk = sk;
+	while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
-		skb->sk = sk;
-		kfree_skb(skb, FREE_WRITE);
-	}
+	while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_in_queue)) != NULL)
+		kfree_skb(skb, FREE_READ);
 
-	while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_queue)) != NULL) {
-		skb->sk = sk;
+	while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_out_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&sk->protinfo.x25->fragment_queue)) != NULL) {
-		skb->sk = sk;
+	while ((skb = skb_dequeue(&sk->protinfo.x25->fragment_queue)) != NULL)
 		kfree_skb(skb, FREE_READ);
-	}
-}
-
-/*
- * This routine purges the input queue of those frames that have been
- * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
- * SDL diagram.
- */
-void x25_frames_acked(struct sock *sk, unsigned short nr)
-{
-	struct sk_buff *skb;
-	int modulus;
-	
-	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
-
-	/*
-	 * Remove all the ack-ed frames from the ack queue.
-	 */
-	if (sk->protinfo.x25->va != nr) {
-		while (skb_peek(&sk->protinfo.x25->ack_queue) != NULL && sk->protinfo.x25->va != nr) {
-		        skb     = skb_dequeue(&sk->protinfo.x25->ack_queue);
-		        skb->sk = sk;
-			kfree_skb(skb, FREE_WRITE);
-			sk->protinfo.x25->va = (sk->protinfo.x25->va + 1) % modulus;
-		}
-	}
-}
-
-/*
- * Requeue all the un-ack-ed frames on the output queue to be picked
- * up by x25_kick called from the timer. This arrangement handles the
- * possibility of an empty output queue.
- */
-void x25_requeue_frames(struct sock *sk)
-{
-	struct sk_buff *skb, *skb_prev = NULL;
-
-	while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
-		if (skb_prev == NULL)
-			skb_queue_head(&sk->write_queue, skb);
-		else
-			skb_append(skb_prev, skb);
-		skb_prev = skb;
-	}
 }
 
 /*
@@ -125,7 +74,7 @@
 		if (nr == vc) return 1;
 		vc = (vc + 1) % modulus;
 	}
-	
+
 	if (nr == sk->protinfo.x25->vs) return 1;
 
 	return 0;
@@ -151,13 +100,13 @@
 
 	/*
 	 *	Adjust frame size.
-	 */	
+	 */
 	switch (frametype) {
 		case X25_CALL_REQUEST:
-			len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN;
+			len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
 			break;
 		case X25_CALL_ACCEPTED:
-			len += 1 + X25_MAX_FAC_LEN;
+			len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
 			break;
 		case X25_CLEAR_REQUEST:
 		case X25_RESET_REQUEST:
@@ -174,7 +123,7 @@
 			printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype);
 			return;
 	}
-	
+
 	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
 		return;
 
@@ -182,7 +131,7 @@
 	 *	Space for Ethernet and 802.2 LLC headers.
 	 */
 	skb_reserve(skb, X25_MAX_L2_LEN);
-	
+
 	/*
 	 *	Make space for the GFI and LCI, and fill them in.
 	 */
@@ -203,7 +152,7 @@
 	 *	Now fill in the frame type specific information.
 	 */
 	switch (frametype) {
-	
+
 		case X25_CALL_REQUEST:
 			dptr    = skb_put(skb, 1);
 			*dptr++ = X25_CALL_REQUEST;
@@ -213,6 +162,9 @@
 			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, facilities, len);
+			dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
+			memcpy(dptr, sk->protinfo.x25->calluserdata.cuddata, sk->protinfo.x25->calluserdata.cudlength);
+			sk->protinfo.x25->calluserdata.cudlength = 0;
 			break;
 
 		case X25_CALL_ACCEPTED:
@@ -222,6 +174,9 @@
 			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities);
 			dptr    = skb_put(skb, len);
 			memcpy(dptr, facilities, len);
+			dptr = skb_put(skb, sk->protinfo.x25->calluserdata.cudlength);
+			memcpy(dptr, sk->protinfo.x25->calluserdata.cuddata, sk->protinfo.x25->calluserdata.cudlength);
+			sk->protinfo.x25->calluserdata.cudlength = 0;
 			break;
 
 		case X25_CLEAR_REQUEST:
@@ -245,7 +200,7 @@
 				*dptr++ |= (sk->protinfo.x25->vr << 5) & 0xE0;
 			}
 			break;
-		
+
 		case X25_CLEAR_CONFIRMATION:
 		case X25_INTERRUPT_CONFIRMATION:
 		case X25_RESET_CONFIRMATION:
@@ -263,9 +218,9 @@
 int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
 {
 	unsigned char *frame;
-	
+
 	frame = skb->data;
-	
+
 	*ns = *nr = *q = *d = *m = 0;
 
 	switch (frame[2]) {
@@ -322,7 +277,7 @@
 	}
 
 	printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n", frame[0], frame[1], frame[2]);
-	
+
 	return X25_ILLEGAL;
 }
 
@@ -335,10 +290,7 @@
 	unsigned int len;
 	unsigned char *p = skb->data;
 
-	facilities->window_size = -1;
-	facilities->packet_size = -1;
-	facilities->throughput  = -1;
-	facilities->reverse     = -1;
+	memset(facilities, 0x00, sizeof(struct x25_facilities));
 
 	len = *p++;
 
@@ -359,14 +311,16 @@
 				p   += 2;
 				len -= 2;
 				break;
-				
+
 			case X25_FAC_CLASS_B:
 				switch (*p) {
 					case X25_FAC_PACKET_SIZE:
-						facilities->packet_size = p[1];
+						facilities->pacsize_in  = p[1];
+						facilities->pacsize_out = p[2];
 						break;
 					case X25_FAC_WINDOW_SIZE:
-						facilities->window_size = p[1];
+						facilities->winsize_in  = p[1];
+						facilities->winsize_out = p[2];
 						break;
 					default:
 						printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]);
@@ -381,7 +335,7 @@
 				p   += 4;
 				len -= 4;
 				break;
-				
+
 			case X25_FAC_CLASS_D:
 				printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]);
 				p   += p[1] + 2;
@@ -401,31 +355,31 @@
 	unsigned char *p = buffer + 1;
 	int len;
 
-	if (facilities->reverse != -1) {
+	if (facilities->reverse != 0) {
 		*p++ = X25_FAC_REVERSE;
 		*p++ = (facilities->reverse) ? 0x01 : 0x00;
 	}
 
-	if (facilities->throughput != -1) {
+	if (facilities->throughput != 0) {
 		*p++ = X25_FAC_THROUGHPUT;
 		*p++ = facilities->throughput;
 	}
 
-	if (facilities->packet_size != -1) {
+	if (facilities->pacsize_in != 0 || facilities->pacsize_out != 0) {
 		*p++ = X25_FAC_PACKET_SIZE;
-		*p++ = facilities->packet_size;
-		*p++ = facilities->packet_size;
+		*p++ = (facilities->pacsize_in  == 0) ? facilities->pacsize_out : facilities->pacsize_in;
+		*p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in  : facilities->pacsize_out;
 	}
 
-	if (facilities->window_size != -1) {
+	if (facilities->winsize_in != 0 || facilities->winsize_out != 0) {
 		*p++ = X25_FAC_WINDOW_SIZE;
-		*p++ = facilities->window_size;
-		*p++ = facilities->window_size;
+		*p++ = (facilities->winsize_in  == 0) ? facilities->winsize_out : facilities->winsize_in;
+		*p++ = (facilities->winsize_out == 0) ? facilities->winsize_in  : facilities->winsize_out;
 	}
 
 	len       = p - buffer;
 	buffer[0] = len - 1;
-	
+
 	return len;
 }
 
diff -u --recursive --new-file v2.1.21/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c
--- v2.1.21/linux/net/x25/x25_timer.c	Wed Dec 18 15:59:25 1996
+++ linux/net/x25/x25_timer.c	Sun Jan 19 15:47:30 1997
@@ -47,7 +47,7 @@
 void x25_set_timer(struct sock *sk)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
@@ -66,7 +66,7 @@
 static void x25_reset_timer(struct sock *sk)
 {
 	unsigned long flags;
-	
+
 	save_flags(flags);
 	cli();
 
