diff -u --recursive --new-file v1.3.80/linux/CREDITS linux/CREDITS
--- v1.3.80/linux/CREDITS	Mon Mar 25 08:58:19 1996
+++ linux/CREDITS	Fri Mar 29 09:38:46 1996
@@ -1129,10 +1129,10 @@
 S: USA
 
 N: Simmule Turner
-E: simmy@digex.com
+E: sturner@tele-tv.com
 D: Added swapping to filesystem
-S: 8504 16th Street #406
-S: Silver Spring, Maryland 20910
+S: 4226 Landgreen Street
+S: Rockville, Maryland 20853
 S: USA
 
 N: Stephen Tweedie
diff -u --recursive --new-file v1.3.80/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.80/linux/Documentation/Configure.help	Wed Mar 27 08:19:28 1996
+++ linux/Documentation/Configure.help	Sat Mar 30 13:20:33 1996
@@ -2815,6 +2815,13 @@
   plugging in a COM port (9 or 25 pins) which is supported
   automatically.
 
+Support for user miscellaneous modules
+CONFIG_UMISC
+  This option forces generic miscellaneous minor device  support in the
+  kernel, and allows later loading of user miscellaneous device  modules,
+  such as drivers for optic pens and touchscreens. Unless you need such
+  specific modules, or are willing to write/test one, just say N.
+
 QIC-02 tape support
 CONFIG_QIC02_TAPE
   If you have a non-SCSI tape drive like that, say Y.
diff -u --recursive --new-file v1.3.80/linux/Documentation/framerelay.txt linux/Documentation/framerelay.txt
--- v1.3.80/linux/Documentation/framerelay.txt	Mon Mar 25 08:58:20 1996
+++ linux/Documentation/framerelay.txt	Thu Jan  1 02:00:00 1970
@@ -1,33 +0,0 @@
-Frame Relay (FR) support for linux is built into a two tiered system of device 
-drivers.  The upper layer implements RFC1490 FR specification, and uses the
-Data Link Connection Identifier (DLCI) as it's hardware address.  Usually these
-are assigned by your network supplier, they give you the number/numbers of
-the Virtual Connections (VC) assigned to you.
-
-Each DLCI is a point-to-point link between your machine and a remote one.
-As such, a seperate device is needed to accomodate the routing.  Within the
-net-tools archives is 'dlcicfg'.  This program will communicate with the
-base "DLCI" device, and create new net devices named 'dlci00', 'dlci01'... 
-The configuration script will ask you how many DLCI's you need, as well as
-how many DLCI's you want to assign to each Frame Relay Access Device (FRAD).
-
-The DLCI uses a number of function calls to communicate with the FRAD, all
-of which are stored in the FRAD's private data area.  assoc/deassoc, 
-activate/deactivate and dlci_config.  The DLCI supplies a receive function
-to the FRAD to accept incoming packets.
-
-With this initial offering, only 1 FRAD driver is available.  With many thanks
-to Sangoma Technologies, David Mandelstam & Gene Kozin, the S502A, S502E & 
-S508 are supported.  This driver is currently set up for only FR, but as 
-Sangoma makes more firmware modules available, it can be updated to provide
-them as well.
-
-Configuration of the FRAD makes use of another net-tools program, 'fradcfg'.
-This program makes use of a configuration file (which dlcicfg can also read)
-to specify the types of boards to be configured as FRADs, as well as perform
-any board specific configuration.  The Sangoma module of fradcfg loads the
-FR firmware into the card, sets the irq/port/memory information, and provides
-an initial configuration.
-
-Additional FRAD device drivers can be added as hardware is available.
-
diff -u --recursive --new-file v1.3.80/linux/Documentation/networking/framerelay.txt linux/Documentation/networking/framerelay.txt
--- v1.3.80/linux/Documentation/networking/framerelay.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/framerelay.txt	Sat Mar 30 13:20:33 1996
@@ -0,0 +1,33 @@
+Frame Relay (FR) support for linux is built into a two tiered system of device 
+drivers.  The upper layer implements RFC1490 FR specification, and uses the
+Data Link Connection Identifier (DLCI) as it's hardware address.  Usually these
+are assigned by your network supplier, they give you the number/numbers of
+the Virtual Connections (VC) assigned to you.
+
+Each DLCI is a point-to-point link between your machine and a remote one.
+As such, a seperate device is needed to accomodate the routing.  Within the
+net-tools archives is 'dlcicfg'.  This program will communicate with the
+base "DLCI" device, and create new net devices named 'dlci00', 'dlci01'... 
+The configuration script will ask you how many DLCI's you need, as well as
+how many DLCI's you want to assign to each Frame Relay Access Device (FRAD).
+
+The DLCI uses a number of function calls to communicate with the FRAD, all
+of which are stored in the FRAD's private data area.  assoc/deassoc, 
+activate/deactivate and dlci_config.  The DLCI supplies a receive function
+to the FRAD to accept incoming packets.
+
+With this initial offering, only 1 FRAD driver is available.  With many thanks
+to Sangoma Technologies, David Mandelstam & Gene Kozin, the S502A, S502E & 
+S508 are supported.  This driver is currently set up for only FR, but as 
+Sangoma makes more firmware modules available, it can be updated to provide
+them as well.
+
+Configuration of the FRAD makes use of another net-tools program, 'fradcfg'.
+This program makes use of a configuration file (which dlcicfg can also read)
+to specify the types of boards to be configured as FRADs, as well as perform
+any board specific configuration.  The Sangoma module of fradcfg loads the
+FR firmware into the card, sets the irq/port/memory information, and provides
+an initial configuration.
+
+Additional FRAD device drivers can be added as hardware is available.
+
diff -u --recursive --new-file v1.3.80/linux/MAINTAINERS linux/MAINTAINERS
--- v1.3.80/linux/MAINTAINERS	Mon Mar 25 08:58:20 1996
+++ linux/MAINTAINERS	Sat Mar 30 12:14:55 1996
@@ -102,6 +102,12 @@
 L:      linux-scsi@vger.rutgers.edu
 S:      Odd fixes (e.g., new signatures)
 
+SCSI TAPE DRIVER
+P:	Kai Mdkisara
+M:	Kai.Makisara@metla.fi
+L:	linux-scsi@vger.rutgers.edu
+S:	Maintained
+
 FTAPE/QIC-117:
 P:	Kai Harrekilde-Petersen
 M:	khp@@dolphinics.no
diff -u --recursive --new-file v1.3.80/linux/Makefile linux/Makefile
--- v1.3.80/linux/Makefile	Thu Mar 28 17:34:33 1996
+++ linux/Makefile	Fri Mar 29 13:06:45 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 80
+SUBLEVEL = 81
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.80/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v1.3.80/linux/arch/alpha/config.in	Sun Mar 24 12:09:35 1996
+++ linux/arch/alpha/config.in	Sat Mar 30 11:48:51 1996
@@ -43,10 +43,17 @@
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_LCA y
 fi
+if [ "$CONFIG_ALPHA_AVANTI" = "y" ]
+then
+	bool 'Is it really a true XL' CONFIG_ALPHA_XL
+fi
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" ]
 then
-	bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+	if [ "$CONFIG_ALPHA_XL" = "n" ]
+	then
+		bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+	fi
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_APECS y
 fi
diff -u --recursive --new-file v1.3.80/linux/arch/alpha/kernel/apecs.c linux/arch/alpha/kernel/apecs.c
--- v1.3.80/linux/arch/alpha/kernel/apecs.c	Sat Feb 17 09:19:36 1996
+++ linux/arch/alpha/kernel/apecs.c	Sat Mar 30 11:48:51 1996
@@ -393,10 +393,34 @@
 
 unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
 {
+
+#ifdef CONFIG_ALPHA_XL
+	/*
+	 * Set up the PCI->physical memory translation windows.
+	 * For the XL we *must* use both windows, in order to
+	 * maximize the amount of physical memory that can be used
+	 * to DMA from the ISA bus, and still allow PCI bus devices
+	 * access to all of host memory.
+	 *
+	 * see <asm/apecs.h> for window bases and sizes.
+	 *
+	 * this restriction due to the true XL motherboards' 82379AB SIO
+	 * PCI<->ISA bridge chip which passes only 27 bits of address...
+	 */
+
+	*(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_XL_DMA_WIN1_BASE & 0xfff00000U);
+	*(vuip)APECS_IOC_PM1R = (APECS_XL_DMA_WIN1_SIZE - 1) & 0xfff00000U;
+	*(vuip)APECS_IOC_TB1R = 0;
+
+	*(vuip)APECS_IOC_PB2R = 1U<<19 | (APECS_XL_DMA_WIN2_BASE & 0xfff00000U);
+	*(vuip)APECS_IOC_PM2R = (APECS_XL_DMA_WIN2_SIZE - 1) & 0xfff00000U;
+	*(vuip)APECS_IOC_TB2R = 0;
+
+#else  /* CONFIG_ALPHA_XL */
 	/*
 	 * Set up the PCI->physical memory translation windows.
-	 * For now, window 1 is disabled.  In the future, we may
-	 * want to use it to do scatter/gather DMA.  Window 0
+	 * For now, window 2 is disabled.  In the future, we may
+	 * want to use it to do scatter/gather DMA.  Window 1
 	 * goes at 1 GB and is 1 GB large.
 	 */
 	*(vuip)APECS_IOC_PB2R  = 0U; /* disable window 2 */
@@ -404,6 +428,7 @@
 	*(vuip)APECS_IOC_PB1R  = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U);
 	*(vuip)APECS_IOC_PM1R  = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U;
 	*(vuip)APECS_IOC_TB1R  = 0;
+#endif /* CONFIG_ALPHA_XL */
 
 #ifdef CONFIG_ALPHA_CABRIOLET
 	/*
diff -u --recursive --new-file v1.3.80/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v1.3.80/linux/arch/alpha/kernel/bios32.c	Thu Feb 29 08:35:24 1996
+++ linux/arch/alpha/kernel/bios32.c	Sat Mar 30 11:48:51 1996
@@ -82,7 +82,20 @@
 #if PCI_MODIFY
 
 static unsigned int	io_base	 = 64*KB;	/* <64KB are (E)ISA ports */
+
+#if defined(CONFIG_ALPHA_XL)
+/*
+   an AVANTI *might* be an XL, and an XL has only 27 bits of ISA address
+   that get passed through the PCI<->ISA bridge chip. Because this causes
+   us to set the PCI->Mem window bases lower than normal, we've gotta allocate
+   PCI bus devices' memory addresses *above* the PCI<->memory mapping windows,
+   so that CPU memory DMA addresses issued by a bus device don't conflict
+   with bus memory addresses, like frame buffer memory for graphics cards.
+*/
+static unsigned int	mem_base = 1024*MB;
+#else /* CONFIG_ALPHA_XL */
 static unsigned int	mem_base = 16*MB;	/* <16MB is ISA memory */
+#endif /* CONFIG_ALPHA_XL */
 
 /*
  * Disable PCI device DEV so that it does not respond to I/O or memory
@@ -418,7 +431,7 @@
  * or 0x398/0x399.  Unfortunately, autodetecting which base address is
  * in use works only once (right after a reset).  The Super I/O chip
  * has the additional quirk that configuration register data must be
- * written twice (I believe this is a saftey feature to prevent
+ * written twice (I believe this is a safety feature to prevent
  * accidental modification---fun, isn't it?).
  */
 static inline void enable_ide(long ide_base)
diff -u --recursive --new-file v1.3.80/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v1.3.80/linux/arch/alpha/mm/init.c	Wed Mar 13 18:57:48 1996
+++ linux/arch/alpha/mm/init.c	Sat Mar 30 11:48:51 1996
@@ -21,6 +21,7 @@
 #include <asm/segment.h>
 #include <asm/pgtable.h>
 #include <asm/hwrpb.h>
+#include <asm/dma.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
@@ -156,6 +157,8 @@
 	}
 
 	for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) {
+		if (tmp >= MAX_DMA_ADDRESS)
+			mem_map[MAP_NR(tmp)].dma = 0;
 		if (mem_map[MAP_NR(tmp)].reserved)
 			continue;
 		mem_map[MAP_NR(tmp)].count = 1;
diff -u --recursive --new-file v1.3.80/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v1.3.80/linux/arch/i386/defconfig	Mon Mar 25 10:00:22 1996
+++ linux/arch/i386/defconfig	Sat Mar 30 13:49:11 1996
@@ -147,6 +147,7 @@
 # CONFIG_PSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
 # CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
diff -u --recursive --new-file v1.3.80/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.80/linux/drivers/block/ll_rw_blk.c	Thu Mar 28 17:34:34 1996
+++ linux/drivers/block/ll_rw_blk.c	Fri Mar 29 13:06:04 1996
@@ -306,7 +306,7 @@
 				return;
 			}
 			kstat.pgpgin++;
-			max_req = NR_REQUEST;	/* reads take precedence */
+			max_req = (major == MD_MAJOR) ? NR_REQUEST/2 : NR_REQUEST;	/* reads take precedence */
 			break;
 		case WRITEA:
 			rw_ahead = 1;
@@ -322,7 +322,7 @@
 			 * requests are only for reads.
 			 */
 			kstat.pgpgout++;
-			max_req = (NR_REQUEST * 2) / 3;
+			max_req =  (major == MD_MAJOR) ? NR_REQUEST/3 : (NR_REQUEST * 2) / 3;
 			break;
 		default:
 			printk("make_request: bad block dev cmd, must be R/W/RA/WA\n");
diff -u --recursive --new-file v1.3.80/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v1.3.80/linux/drivers/block/xd.c	Fri Mar  1 07:50:39 1996
+++ linux/drivers/block/xd.c	Fri Mar 29 13:06:11 1996
@@ -70,7 +70,7 @@
 	{ 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
 	{ 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
 	{ 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
-	{ 0x0010,"ST11 BIOS V1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
+	{ 0x0010,"ST11 BIOS v1.7",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11R" }, /* Alan Hourihane, alanh@fairlite.demon.co.uk */
 	{ 0x1000,"(c)Copyright 1987 SMS",xd_omti_init_controller,xd_omti_init_drive,"n OMTI 5520" }, /* Dirk Melchers, dirk@merlin.nbg.sub.org */
 };
 static u_char *xd_bases[] =
diff -u --recursive --new-file v1.3.80/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v1.3.80/linux/drivers/char/Config.in	Wed Mar  6 15:07:18 1996
+++ linux/drivers/char/Config.in	Sat Mar 30 13:20:33 1996
@@ -19,6 +19,7 @@
 fi
 tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
 tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
+bool 'Support for user misc device modules' CONFIG_UMISC
 
 bool 'QIC-02 tape support' CONFIG_QIC02_TAPE
 if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
diff -u --recursive --new-file v1.3.80/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.80/linux/drivers/char/Makefile	Wed Mar  6 15:07:18 1996
+++ linux/drivers/char/Makefile	Sat Mar 30 13:20:33 1996
@@ -100,10 +100,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_UMISC),y)
+# To support third-party modules, misc.c must reside in the kernel
+M = y
+endif
+
 ifdef CONFIG_SOFT_WATCHDOG
 L_OBJS += softdog.o
 M = y
-# This is not modularized, so if configured then "mouse.c" will be resident
+# This is not modularized, so if configured then "misc.c" will be resident
 endif
 
 ifeq ($(CONFIG_WDT),y)
@@ -134,10 +139,10 @@
 endif
 
 ifdef M
-LX_OBJS += mouse.o
+LX_OBJS += misc.o
 else
   ifdef MM
-  MX_OBJS += mouse.o
+  MX_OBJS += misc.o
   endif
 endif
 
diff -u --recursive --new-file v1.3.80/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v1.3.80/linux/drivers/char/atixlmouse.c	Fri Mar  1 07:50:40 1996
+++ linux/drivers/char/atixlmouse.c	Sat Mar 30 13:20:33 1996
@@ -16,7 +16,7 @@
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 #include <linux/random.h>
 
 #include <asm/io.h>
@@ -194,7 +194,7 @@
 	fasync_mouse,
 };
 
-static struct mouse atixl_mouse = { 
+static struct miscdevice atixl_mouse = { 
 	ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops
 };
 
@@ -222,7 +222,7 @@
 	mouse.dx = mouse.dy = 0;
 	mouse.wait = NULL;
 	printk("Bus mouse detected and installed.\n");
-	mouse_register(&atixl_mouse);
+	misc_register(&atixl_mouse);
 	return 0;
 }
 
@@ -235,6 +235,6 @@
 
 void cleanup_module(void)
 {
-	mouse_deregister(&atixl_mouse);
+	misc_deregister(&atixl_mouse);
 }
 #endif
diff -u --recursive --new-file v1.3.80/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v1.3.80/linux/drivers/char/busmouse.c	Fri Mar  1 07:50:40 1996
+++ linux/drivers/char/busmouse.c	Sat Mar 30 13:20:33 1996
@@ -41,7 +41,7 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 #include <linux/random.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
@@ -240,7 +240,7 @@
 	fasync_mouse,
 };
 
-static struct mouse bus_mouse = {
+static struct miscdevice bus_mouse = {
 	LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
 };
 
@@ -272,7 +272,7 @@
 	mouse.wait = NULL;
 	printk("Logitech bus mouse detected, using IRQ %d.\n",
 	       mouse_irq);
-	mouse_register(&bus_mouse);
+	misc_register(&bus_mouse);
 	return 0;
 }
 
@@ -285,7 +285,7 @@
 
 void cleanup_module(void)
 {
-	mouse_deregister(&bus_mouse);
+	misc_deregister(&bus_mouse);
 	release_region(LOGIBM_BASE, LOGIBM_EXTENT);
 }
 #endif
diff -u --recursive --new-file v1.3.80/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.3.80/linux/drivers/char/keyboard.c	Sun Mar  3 15:31:52 1996
+++ linux/drivers/char/keyboard.c	Sat Mar 30 11:48:51 1996
@@ -343,12 +343,30 @@
 	static unsigned int prev_scancode = 0;   /* remember E0, E1 */
 	char up_flag;				 /* 0 or 0200 */
 	char raw_mode;
+	int status;
 
 	pt_regs = regs;
 	send_cmd(0xAD);		/* disable keyboard */
 	kb_wait();
-	if ((inb_p(0x64) & kbd_read_mask) != 0x01)
-		goto end_kbd_intr;
+	status = inb_p(0x64);
+	if ((status & kbd_read_mask) != 0x01) {
+	  /*
+	   * On some platforms (Alpha XL for one), the init code may leave
+	   *  an interrupt hanging, yet with status indicating no data.
+	   * After making sure that there's no data indicated and its not a
+	   *  mouse interrupt, we will read the data register to clear it.
+	   * If we don't do this, the data reg stays full and will not
+	   *  allow new data or interrupt from the keyboard. Sigh...
+	   */
+	  if (!(status & 0x21)) { /* neither ODS nor OBF */
+	    scancode = inb(0x60); /* read data anyway */
+#if 0
+	    printk("keyboard: status 0x%x  mask 0x%x  data 0x%x\n",
+		   status, kbd_read_mask, scancode);
+#endif
+	  }
+	  goto end_kbd_intr;
+	}
 	scancode = inb(0x60);
 	mark_bh(KEYBOARD_BH);
 	if (reply_expected) {
diff -u --recursive --new-file v1.3.80/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v1.3.80/linux/drivers/char/mem.c	Thu Mar  7 15:59:02 1996
+++ linux/drivers/char/mem.c	Sat Mar 30 13:20:33 1996
@@ -11,7 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/tty.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 #include <linux/tpqic02.h>
 #include <linux/ftape.h>
 #include <linux/malloc.h>
@@ -387,10 +387,10 @@
 #ifdef CONFIG_PRINTER
 	lp_init();
 #endif
-#if defined (CONFIG_BUSMOUSE) || \
+#if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG)
-	mouse_init();
+	misc_init();
 #endif
 #ifdef CONFIG_SOUND
 	soundcard_init();
diff -u --recursive --new-file v1.3.80/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v1.3.80/linux/drivers/char/misc.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/misc.c	Sat Mar 30 13:20:33 1996
@@ -0,0 +1,204 @@
+/*
+ * linux/drivers/char/misc.c
+ *
+ * Generic misc open routine by Johan Myreen
+ *
+ * Based on code from Linus
+ *
+ * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
+ *   changes incorporated into 0.97pl4
+ *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
+ *   See busmouse.c for particulars.
+ *
+ * Made things a lot mode modular - easy to compile in just one or two
+ * of the misc drivers, as they are now completely independent. Linus.
+ *
+ * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
+ *
+ * Fixed a failing symbol register to free the device registration
+ *		Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96
+ *
+ * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
+ *
+ * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-May-96
+ */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <linux/tty.h> /* needed by selection.h */
+#include "selection.h" /* export its symbols */
+
+/*
+ * Head entry for the doubly linked miscdevice list
+ */
+static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list };
+
+/*
+ * Assigned numbers, used for dynamic minors
+ */
+#define DYNAMIC_MINORS 64 /* like dynamic majors */
+static unsigned char misc_minors[DYNAMIC_MINORS / 8];
+
+#ifndef MODULE
+extern int bus_mouse_init(void);
+extern int psaux_init(void);
+extern int ms_bus_mouse_init(void);
+extern int atixl_busmouse_init(void);
+extern void watchdog_init(void);
+
+#ifdef CONFIG_PROC_FS
+static int proc_misc_read(char *buf, char **start, off_t offset, int len, int unused)
+{
+	struct miscdevice *p;
+
+	len=0;
+	for (p = misc_list.next; p != &misc_list; p = p->next)
+		len += sprintf(buf+len, "%3i %s\n",p->minor, p->name ?: "");
+	return len;
+}
+
+#endif /* PROC_FS */
+#endif /* !MODULE */
+
+static int misc_open(struct inode * inode, struct file * file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct miscdevice *c = misc_list.next;
+	file->f_op = NULL;
+
+	while (c != &misc_list) {
+		if (c->minor == minor) {
+			file->f_op = c->fops;
+			break;
+		}
+		c = c->next;
+	}
+
+	if (file->f_op == NULL)
+		return -ENODEV;
+        return file->f_op->open(inode,file);
+}
+
+static struct file_operations misc_fops = {
+        NULL,		/* seek */
+	NULL,		/* read */
+	NULL,		/* write */
+	NULL,		/* readdir */
+	NULL,		/* select */
+	NULL,		/* ioctl */
+	NULL,		/* mmap */
+        misc_open,
+        NULL		/* release */
+};
+
+int misc_register(struct miscdevice * misc)
+{
+	if (misc->next || misc->prev)
+		return -EBUSY;
+	if (misc->minor == MISC_DYNAMIC_MINOR) {
+		int i = DYNAMIC_MINORS;
+		while (--i >= 0)
+			if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
+				break;
+		if (i<0) return -EBUSY;
+		misc->minor = i;
+	}
+	if (misc->minor < DYNAMIC_MINORS)
+		misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
+	MOD_INC_USE_COUNT;
+	misc->next = &misc_list;
+	misc->prev = misc_list.prev;
+	misc->prev->next = misc;
+	misc->next->prev = misc;
+	return 0;
+}
+
+int misc_deregister(struct miscdevice * misc)
+{
+	int i = misc->minor;
+	if (!misc->next || !misc->prev)
+		return -EINVAL;
+	MOD_DEC_USE_COUNT;
+	misc->prev->next = misc->next;
+	misc->next->prev = misc->prev;
+	misc->next = NULL;
+	misc->prev = NULL;
+	if (i < DYNAMIC_MINORS && i>0) {
+		misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
+	}
+	return 0;
+}
+
+#ifdef MODULE
+
+#define misc_init init_module
+
+void cleanup_module(void)
+{
+	unregister_chrdev(MOUSE_MAJOR, "misc");
+}
+
+#endif
+
+static struct symbol_table misc_syms = {
+/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
+#include <linux/symtab_begin.h>
+	X(misc_register),
+	X(misc_deregister),
+#ifndef MODULE
+	X(set_selection),   /* used by the kmisc module, can only */
+	X(clear_selection), /* be exported if misc.c is in linked in */
+#endif
+#include <linux/symtab_end.h>
+};
+
+int misc_init(void)
+{
+#ifndef MODULE
+#ifdef CONFIG_PROC_FS
+	proc_register_dynamic(&proc_root, &(struct proc_dir_entry) {
+		0, 4, "misc",
+		S_IRUGO, 1, 0, 0,
+		0, NULL /* ops -- default to array */,
+		&proc_misc_read /* get_info */,
+	});	
+#endif /* PROC_FS */
+#ifdef CONFIG_BUSMOUSE
+	bus_mouse_init();
+#endif
+#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
+	psaux_init();
+#endif
+#ifdef CONFIG_MS_BUSMOUSE
+	ms_bus_mouse_init();
+#endif
+#ifdef CONFIG_ATIXL_BUSMOUSE
+ 	atixl_busmouse_init();
+#endif
+#ifdef CONFIG_SOFT_WATCHDOG
+	watchdog_init();
+#endif	
+#endif /* !MODULE */
+	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
+	  printk("unable to get major %d for misc devices\n",
+		 MISC_MAJOR);
+		return -EIO;
+	}
+
+	if(register_symtab(&misc_syms)!=0)
+	{
+		unregister_chrdev(MISC_MAJOR, "misc");
+		return -EIO;
+	}
+	return 0;
+}
diff -u --recursive --new-file v1.3.80/linux/drivers/char/mouse.c linux/drivers/char/mouse.c
--- v1.3.80/linux/drivers/char/mouse.c	Wed Feb  7 08:55:35 1996
+++ linux/drivers/char/mouse.c	Thu Jan  1 02:00:00 1970
@@ -1,149 +0,0 @@
-/*
- * linux/drivers/char/mouse.c
- *
- * Generic mouse open routine by Johan Myreen
- *
- * Based on code from Linus
- *
- * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
- *   changes incorporated into 0.97pl4
- *   by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92)
- *   See busmouse.c for particulars.
- *
- * Made things a lot mode modular - easy to compile in just one or two
- * of the mouse drivers, as they are now completely independent. Linus.
- *
- * Support for loadable modules. 8-Sep-95 Philip Blundell <pjb27@cam.ac.uk>
- *
- * Fixed a failing symbol register to free the device registration
- *		Alan Cox <alan@lxorguk.ukuu.org.uk> 21-Jan-96
- */
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/mouse.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/malloc.h>
-
-/*
- * Head entry for the doubly linked mouse list
- */
-static struct mouse mouse_list = { 0, "head", NULL, &mouse_list, &mouse_list };
-
-#ifndef MODULE
-extern int bus_mouse_init(void);
-extern int psaux_init(void);
-extern int ms_bus_mouse_init(void);
-extern int atixl_busmouse_init(void);
-#endif
-
-static int mouse_open(struct inode * inode, struct file * file)
-{
-	int minor = MINOR(inode->i_rdev);
-	struct mouse *c = mouse_list.next;
-	file->f_op = NULL;
-
-	while (c != &mouse_list) {
-		if (c->minor == minor) {
-			file->f_op = c->fops;
-			break;
-		}
-		c = c->next;
-	}
-
-	if (file->f_op == NULL)
-		return -ENODEV;
-        return file->f_op->open(inode,file);
-}
-
-static struct file_operations mouse_fops = {
-        NULL,		/* seek */
-	NULL,		/* read */
-	NULL,		/* write */
-	NULL,		/* readdir */
-	NULL,		/* select */
-	NULL,		/* ioctl */
-	NULL,		/* mmap */
-        mouse_open,
-        NULL		/* release */
-};
-
-int mouse_register(struct mouse * mouse)
-{
-	if (mouse->next || mouse->prev)
-		return -EBUSY;
-	MOD_INC_USE_COUNT;
-	mouse->next = &mouse_list;
-	mouse->prev = mouse_list.prev;
-	mouse->prev->next = mouse;
-	mouse->next->prev = mouse;
-	return 0;
-}
-
-int mouse_deregister(struct mouse * mouse)
-{
-	if (!mouse->next || !mouse->prev)
-		return -EINVAL;
-	MOD_DEC_USE_COUNT;
-	mouse->prev->next = mouse->next;
-	mouse->next->prev = mouse->prev;
-	mouse->next = NULL;
-	mouse->prev = NULL;
-	return 0;
-}
-
-#ifdef MODULE
-
-#define mouse_init init_module
-
-void cleanup_module(void)
-{
-	unregister_chrdev(MOUSE_MAJOR, "mouse");
-}
-
-#endif
-
-static struct symbol_table mouse_syms = {
-/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
-#include <linux/symtab_begin.h>
-	X(mouse_register),
-	X(mouse_deregister),
-#include <linux/symtab_end.h>
-};
-
-int mouse_init(void)
-{
-#ifndef MODULE
-#ifdef CONFIG_BUSMOUSE
-	bus_mouse_init();
-#endif
-#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
-	psaux_init();
-#endif
-#ifdef CONFIG_MS_BUSMOUSE
-	ms_bus_mouse_init();
-#endif
-#ifdef CONFIG_ATIXL_BUSMOUSE
- 	atixl_busmouse_init();
-#endif
-#ifdef CONFIG_SOFT_WATCHDOG
-	watchdog_init();
-#endif	
-#endif /* !MODULE */
-	if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) {
-	  printk("unable to get major %d for mouse devices\n",
-		 MOUSE_MAJOR);
-		return -EIO;
-	}
-
-	if(register_symtab(&mouse_syms)!=0)
-	{
-		unregister_chrdev(MOUSE_MAJOR, "mouse");
-		return -EIO;
-	}
-	return 0;
-}
diff -u --recursive --new-file v1.3.80/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v1.3.80/linux/drivers/char/msbusmouse.c	Fri Mar  1 07:50:40 1996
+++ linux/drivers/char/msbusmouse.c	Sat Mar 30 13:20:33 1996
@@ -38,7 +38,7 @@
 #include <linux/busmouse.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 #include <linux/random.h>
 
 #include <asm/io.h>
@@ -170,7 +170,7 @@
 	fasync_mouse,
 };
 
-static struct mouse ms_bus_mouse = {
+static struct miscdevice ms_bus_mouse = {
 	MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops
 };
 
@@ -205,7 +205,7 @@
 	MS_MSE_INT_OFF();
 	request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
 	printk("Microsoft BusMouse detected and installed.\n");
-	mouse_register(&ms_bus_mouse);
+	misc_register(&ms_bus_mouse);
 	return 0;
 }
 
@@ -217,7 +217,7 @@
 
 void cleanup_module(void)
 {
-	mouse_deregister(&ms_bus_mouse);
+	misc_deregister(&ms_bus_mouse);
 	release_region(MS_MSE_CONTROL_PORT, 0x04);
 }
 #endif
diff -u --recursive --new-file v1.3.80/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v1.3.80/linux/drivers/char/psaux.c	Fri Mar  1 07:50:40 1996
+++ linux/drivers/char/psaux.c	Sat Mar 30 13:20:33 1996
@@ -39,7 +39,7 @@
 #include <linux/errno.h>
 #include <linux/timer.h>
 #include <linux/malloc.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 #include <linux/random.h>
 
 #include <asm/io.h>
@@ -481,7 +481,7 @@
  * Initialize driver. First check for a 82C710 chip; if found
  * forget about the Aux port and use the *_qp functions.
  */
-static struct mouse psaux_mouse = {
+static struct miscdevice psaux_mouse = {
 	PSMOUSE_MINOR, "ps2aux", &psaux_fops
 };
 
@@ -506,7 +506,7 @@
 	} else {
 		return -EIO;
 	}
-	mouse_register(&psaux_mouse);
+	misc_register(&psaux_mouse);
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
@@ -538,7 +538,7 @@
 
 void cleanup_module(void)
 {
-	mouse_deregister(&psaux_mouse);
+	misc_deregister(&psaux_mouse);
 }
 #endif
 
diff -u --recursive --new-file v1.3.80/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v1.3.80/linux/drivers/char/selection.c	Mon Sep 18 07:42:44 1995
+++ linux/drivers/char/selection.c	Sat Mar 30 13:20:33 1996
@@ -110,8 +110,8 @@
 	return v;
 }
 
-/* set the current selection. Invoked by ioctl(). */
-int set_selection(const unsigned long arg, struct tty_struct *tty)
+/* set the current selection. Invoked by ioctl() or by kernel code. */
+int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
 {
 	int sel_mode, new_sel_start, new_sel_end, spc;
 	char *bp, *obp;
@@ -122,12 +122,19 @@
 	{ unsigned short *args, xs, ys, xe, ye;
 
 	  args = (unsigned short *)(arg + 1);
-	  xs = get_user(args++) - 1;
-	  ys = get_user(args++) - 1;
-	  xe = get_user(args++) - 1;
-	  ye = get_user(args++) - 1;
-	  sel_mode = get_user(args);
-
+	  if (user) {
+		  xs = get_user(args++) - 1;
+		  ys = get_user(args++) - 1;
+		  xe = get_user(args++) - 1;
+		  ye = get_user(args++) - 1;
+		  sel_mode = get_user(args);
+	  } else {
+		  xs = *(args++) - 1; /* set selection from kernel */
+		  ys = *(args++) - 1;
+		  xe = *(args++) - 1;
+		  ye = *(args++) - 1;
+		  sel_mode = *args;
+	  }
 	  xs = limit(xs, video_num_columns - 1);
 	  ys = limit(ys, video_num_lines - 1);
 	  xe = limit(xe, video_num_columns - 1);
diff -u --recursive --new-file v1.3.80/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v1.3.80/linux/drivers/char/selection.h	Mon Mar 25 10:05:37 1996
+++ linux/drivers/char/selection.h	Sat Mar 30 13:59:07 1996
@@ -6,7 +6,7 @@
 extern int sel_cons;
 
 extern void clear_selection(void);
-extern int set_selection(const unsigned long arg, struct tty_struct *tty);
+extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user);
 extern int paste_selection(struct tty_struct *tty);
 extern int sel_loadlut(const unsigned long arg);
 extern int mouse_reporting(void);
diff -u --recursive --new-file v1.3.80/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v1.3.80/linux/drivers/char/softdog.c	Wed Feb 21 13:12:18 1996
+++ linux/drivers/char/softdog.c	Sat Mar 30 13:20:33 1996
@@ -23,7 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 
 #define WATCHDOG_MINOR	130
 #define TIMER_MARGIN	(60*HZ)		/* Allow 1 minute */
@@ -106,13 +106,13 @@
 		NULL,		
 		NULL		/* Fasync */
 	};
-	static struct mouse softdog_mouse={
+	static struct miscdevice softdog_mouse={
 		WATCHDOG_MINOR,
 		"softdog",
 		&softdog_fops
 	};
 
-	mouse_register(&softdog_mouse);
+	misc_register(&softdog_mouse);
 	init_timer(&watchdog_ticktock);
 	watchdog_ticktock.function=watchdog_fire;
 	printk("Software Watchdog Timer: 0.03\n");
diff -u --recursive --new-file v1.3.80/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.80/linux/drivers/char/tty_io.c	Sat Mar 16 20:17:23 1996
+++ linux/drivers/char/tty_io.c	Sat Mar 30 13:20:33 1996
@@ -1543,7 +1543,7 @@
 					return do_get_ps_info(arg);
 #endif
 				case 2:
-					return set_selection(arg, tty);
+					return set_selection(arg, tty, 1);
 				case 3:
 					return paste_selection(tty);
 				case 4:
diff -u --recursive --new-file v1.3.80/linux/drivers/char/wdt.c linux/drivers/char/wdt.c
--- v1.3.80/linux/drivers/char/wdt.c	Fri Mar  1 07:50:41 1996
+++ linux/drivers/char/wdt.c	Sat Mar 30 13:20:33 1996
@@ -27,7 +27,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/mouse.h>
+#include <linux/miscdevice.h>
 #include "wd501p.h"
 #include <linux/malloc.h>
 #include <linux/ioport.h>
@@ -213,7 +213,7 @@
 	wdt_release
 };
 
-static struct mouse wdt_mouse=
+static struct miscdevice wdt_mouse=
 {
 	WATCHDOG_MINOR,
 	"wdt",
@@ -221,7 +221,7 @@
 };
 
 #ifdef CONFIG_WDT_501
-static struct mouse temp_mouse=
+static struct miscdevice temp_mouse=
 {
 	TEMP_MINOR,
 	"temperature",
@@ -251,7 +251,7 @@
 {
 	mouse_deregister(&wdt_mouse);
 #ifdef CONFIG_WDT_501	
-	mouse_deregister(&temp_mouse);
+	misc_deregister(&temp_mouse);
 #endif	
 	release_region(io,8);
 	free_irq(irq, NULL);
@@ -269,7 +269,7 @@
 	}
 	mouse_register(&wdt_mouse);
 #ifdef CONFIG_WDT_501	
-	mouse_register(&temp_mouse);
+	misc_register(&temp_mouse);
 #endif	
 	request_region(io, 8, "wdt501");
 	return 0;
diff -u --recursive --new-file v1.3.80/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.80/linux/drivers/net/Makefile	Mon Mar 25 08:58:20 1996
+++ linux/drivers/net/Makefile	Sat Mar 30 13:20:33 1996
@@ -166,10 +166,14 @@
 
 ifeq ($(CONFIG_SLIP),y)
 L_OBJS += slip.o
-CONFIG_SLHC_BUILTIN = y
+  ifeq ($(CONFIG_SLIP_COMPRESSED),y)
+  CONFIG_SLHC_BUILTIN = y
+  endif
 else
   ifeq ($(CONFIG_SLIP),m)
-  CONFIG_SLHC_MODULE = y
+    ifeq ($(CONFIG_SLIP_COMPRESSED),y)
+    CONFIG_SLHC_MODULE = y
+  endif
   M_OBJS += slip.o
   endif
 endif
diff -u --recursive --new-file v1.3.80/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v1.3.80/linux/drivers/net/ibmtr.c	Wed Mar 27 08:19:28 1996
+++ linux/drivers/net/ibmtr.c	Sat Mar 30 13:20:33 1996
@@ -1158,6 +1158,7 @@
 	__u32 dhb;
 	unsigned char xmit_command;
 	int i;
+	struct trllc	*llc;
 	
 	if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF)
 		DPRINTK("ASB not free !!!\n");
@@ -1169,13 +1170,14 @@
 	   effective address where we will place data.*/
 	dhb=ti->sram 
 		+ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address)));
+	llc = (struct trllc *) &(ti->current_skb->data[sizeof(struct trh_hdr)]);
 	
 	xmit_command = readb(ti->srb + offsetof(struct srb_xmit, command));
 	
 	writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command));
 	writew(readb(ti->srb + offsetof(struct srb_xmit, station_id)),
 	       ti->asb + offsetof(struct asb_xmit_resp, station_id));
-	writeb(EXTENDED_SAP, ti->asb + offsetof(struct asb_xmit_resp, rsap_value));
+	writeb(llc->ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value));
 	writeb(readb(ti->srb + offsetof(struct srb_xmit, cmd_corr)),
 	       ti->asb + offsetof(struct asb_xmit_resp, cmd_corr));
 	writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code));
@@ -1248,6 +1250,8 @@
 	unsigned int rbuffer_len, lan_hdr_len;
 	unsigned int arb_frame_len;
 	struct sk_buff *skb;
+	unsigned int skb_size = 0;
+	int	is8022 = 0;
 	
 	rbuffer=(ti->sram
 		 +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))));
@@ -1293,6 +1297,11 @@
 			return;
 			}
 		
+		if ((readb(llc + offsetof(struct trllc, dsap))!=0xAA) ||
+		    (readb(llc + offsetof(struct trllc, ssap))!=0xAA)) {
+			is8022 = 1;
+		}
+			
 #if TR_VERBOSE
 		if ((readb(llc + offsetof(struct trllc, dsap))!=0xAA) ||
 		    (readb(llc + offsetof(struct trllc, ssap))!=0xAA)) {
@@ -1322,8 +1331,12 @@
 #endif
 		
 		arb_frame_len=ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
+		skb_size = arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr);
+		if (is8022) {
+			skb_size += sizeof(struct trllc);
+		}
 		
-		if (!(skb=dev_alloc_skb(arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr)))) {
+		if (!(skb=dev_alloc_skb(skb_size))) {
 			DPRINTK("out of memory. frame dropped.\n");	
 			ti->tr_stats.rx_dropped++;
 			writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code));
@@ -1331,7 +1344,7 @@
 			return;
 		}
 		
-		skb_put(skb, arb_frame_len-lan_hdr_len+sizeof(struct trh_hdr));
+		skb_put(skb, skb_size);
 		skb->dev=dev;
 		
 		data=skb->data;
@@ -1344,6 +1357,12 @@
 		data+=sizeof(struct trh_hdr);
 		rbuffer_len=ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len)))
 			-lan_hdr_len;
+		if (is8022) {
+			struct trllc	*local_llc = (struct trllc *)data;
+			memset(local_llc, 0, sizeof(*local_llc));
+			local_llc->ethertype = htons(ETH_P_TR_802_2);
+			data += sizeof(struct trllc);
+		}
 		
 #if TR_VERBOSE
 		DPRINTK("rbuffer_len: %d, data: %p\n", rbuffer_len, data);
diff -u --recursive --new-file v1.3.80/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- v1.3.80/linux/drivers/net/sdla.c	Mon Mar 25 10:06:28 1996
+++ linux/drivers/net/sdla.c	Sat Mar 30 13:20:33 1996
@@ -344,24 +344,24 @@
       case SDLA_RET_MODEM:
          state = data;
          if (*state & SDLA_MODEM_DCD_LOW)
-            printk(KERN_NOTICE "%s: Modem DCD unexpectedly low!\n", dev->name);
+            printk(KERN_INFO "%s: Modem DCD unexpectedly low!\n", dev->name);
          if (*state & SDLA_MODEM_CTS_LOW)
-            printk(KERN_NOTICE "%s: Modem CTS unexpectedly low!\n", dev->name);
+            printk(KERN_INFO "%s: Modem CTS unexpectedly low!\n", dev->name);
 /* I should probably do something about this! */
          break;
 
       case SDLA_RET_CHANNEL_OFF:
-         printk(KERN_NOTICE "%s: Channel became inoperative!\n", dev->name);
+         printk(KERN_INFO "%s: Channel became inoperative!\n", dev->name);
 /* same here */
          break;
 
       case SDLA_RET_CHANNEL_ON:
-         printk(KERN_NOTICE "%s: Channel became operative!\n", dev->name);
+         printk(KERN_INFO "%s: Channel became operative!\n", dev->name);
 /* same here */
          break;
 
       case SDLA_RET_DLCI_STATUS:
-         printk(KERN_NOTICE "%s: Status change reported by Access Node.\n", dev->name);
+         printk(KERN_INFO "%s: Status change reported by Access Node.\n", dev->name);
          len /= sizeof(struct _dlci_stat);
          for(pstatus = data, i=0;i < len;i++,pstatus++)
          {
@@ -376,14 +376,14 @@
                   else
                      state = "unknown status";
  
-            printk(KERN_NOTICE "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
+            printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
 /* same here */
          }
          break;
 
       case SDLA_RET_DLCI_UNKNOWN:
-         printk(KERN_DEBUG "%s: Received unknown DLCIs:", dev->name);
-         len /= 2;
+         printk(KERN_INFO "%s: Received unknown DLCIs:", dev->name);
+         len /= sizeof(short);
          for(pdlci = data,i=0;i < len;i++,pdlci++)
             printk(" %i", *pdlci);
          printk("\n");
@@ -1058,6 +1058,7 @@
    struct frad_local *flp;
    struct conf_data  data;
    int               i, err;
+   short             size;
 
    if (dev->type == 0xFFFF)
       return(-EUNATCH);
@@ -1127,11 +1128,22 @@
       if (err)
          return(err);
 
-      sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, &data, sizeof(data), NULL, NULL);
-      memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
+      /* no sense reading if the CPU isnt' started */
+      if (dev->start)
+      {
+         size = sizeof(data);
+         if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK)
+            return(-EIO);
+      }
+      else
+         if (flp->configured)
+            memcpy(&data.config, &flp->config, sizeof(struct frad_conf));
+         else
+            memset(&data.config, 0, sizeof(struct frad_conf));
 
+      memcpy(&flp->config, &data.config, sizeof(struct frad_conf));
       data.config.flags &= ~SDLA_DIRECT_RECV;
-      data.config.mtu -= sizeof(struct fradhdr);
+      data.config.mtu -= data.config.mtu > sizeof(struct fradhdr) ? sizeof(struct fradhdr) : data.config.mtu;
       memcpy_tofs(conf, &data.config, sizeof(struct frad_conf));
    }
 
diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v1.3.80/linux/drivers/scsi/g_NCR5380.c	Wed Mar 20 10:50:02 1996
+++ linux/drivers/scsi/g_NCR5380.c	Sat Mar 30 13:13:29 1996
@@ -553,7 +553,7 @@
 
 static int sprint_Scsi_Cmnd (char* buffer, int len, Scsi_Cmnd *cmd) {
     int start = len;
-    PRINTP("destination target %d, lun %d\n" ANDP
+    PRINTP("host number %d destination target %d, lun %d\n" ANDP
        cmd->host->host_no ANDP
        cmd->target ANDP
        cmd->lun);
@@ -562,7 +562,7 @@
     return len-start;
 }
 
-const char *const scsi_device_types[] =
+const char *const private_scsi_device_types[] =
 {
     "Direct-Access    ",
     "Sequential-Access",
@@ -575,7 +575,7 @@
     "Medium Changer   ",
     "Communications   "
 };
-#define MAX_SCSI_DEVICE_CODE sizeof(scsi_device_types)/sizeof(char*)
+#define MAX_SCSI_DEVICE_CODE sizeof(private_scsi_device_types)/sizeof(char*)
 
 int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout)
 {
@@ -630,7 +630,7 @@
 	    long tr = hostdata->time_read[dev->id] / HZ;
 	    long tw = hostdata->time_write[dev->id] / HZ;
 
-	    PRINTP("  T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int)dev->type] : "Unknown");
+	    PRINTP("  T:%d %s " ANDP dev->id ANDP (dev->type < MAX_SCSI_DEVICE_CODE) ? private_scsi_device_types[(int)dev->type] : "Unknown");
 	    for (i=0; i<8; i++)
 		if (dev->vendor[i] >= 0x20)
 		    *(buffer+(len++)) = dev->vendor[i];
@@ -644,13 +644,13 @@
 		    *(buffer+(len++)) = dev->rev[i];
 	    *(buffer+(len++)) = ' ';
 				    
-	    PRINTP("\n%10d kb read    in %5d secs" ANDP br/1024 ANDP tr);
+	    PRINTP("\n%10ld kb read    in %5ld secs" ANDP br/1024 ANDP tr);
 	    if (tr)
-		PRINTP(" @ %5d bps" ANDP br / tr); 
+		PRINTP(" @ %5ld bps" ANDP br / tr); 
 
-	    PRINTP("\n%10d kb written in %5d secs" ANDP bw/1024 ANDP tw);
+	    PRINTP("\n%10ld kb written in %5ld secs" ANDP bw/1024 ANDP tw);
 	    if (tw)
-		PRINTP(" @ %5d bps" ANDP bw / tw); 
+		PRINTP(" @ %5ld bps" ANDP bw / tw); 
 	    PRINTP("\n");
 	}
     }
diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v1.3.80/linux/drivers/scsi/seagate.c	Fri Mar  1 07:50:54 1996
+++ linux/drivers/scsi/seagate.c	Fri Mar 29 13:06:17 1996
@@ -1638,6 +1638,7 @@
   unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page;
   int *sizes, result, formatted_sectors, total_sectors;
   int cylinders, heads, sectors;
+  int capacity;
 
 /*
  * Only SCSI-I CCS drives and later implement the necessary mode sense 
@@ -1718,12 +1719,22 @@
  */
 
       if ((cylinders > 1024) || (sectors > 64)) 
-	result = -1;
-      else {
-	ip[0] = heads;
-	ip[1] = sectors;
-	ip[2] = cylinders;
+	/* The Seagate's seem to have some mapping
+	 * Multiple heads * sectors * cyl to get capacity
+	 * Then start rounding down. */
+	capacity = heads * sectors * cylinders;
+	sectors = 17;	/* Old MFM Drives use this, so does the Seagate */
+	heads = 2;
+	capacity = capacity / sectors;
+	while (cylinders > 1024)
+	{
+		heads *= 2;	/* For some reason, they go in multiples */
+		cylinders = capacity / heads;
+	};
       }
+      ip[0] = heads;
+      ip[1] = sectors;
+      ip[2] = cylinders;
 
 /* 
  * There should be an alternate mapping for things the seagate doesn't
diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.3.80/linux/drivers/scsi/sr.c	Mon Mar 18 11:54:26 1996
+++ linux/drivers/scsi/sr.c	Fri Mar 29 13:05:03 1996
@@ -1016,8 +1016,10 @@
 	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
 	scsi_CDs[i].needs_sector_size = 1;
     } else {
-	scsi_CDs[i].capacity = (buffer[0] << 24) |
-	    (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+	scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
+				    (buffer[1] << 16) |
+				    (buffer[2] << 8) |
+				    buffer[3]);
 	scsi_CDs[i].sector_size = (buffer[4] << 24) |
 	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
 	switch (scsi_CDs[i].sector_size) {
@@ -1042,7 +1044,7 @@
 			scsi_CDs[i].needs_sector_size = 1;
 	}
 	scsi_CDs[i].needs_sector_size = 0;
-	sr_sizes[i] = scsi_CDs[i].capacity;
+	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
     };
     scsi_free(buffer, 512);
 }
@@ -1103,7 +1105,7 @@
 	scsi_CDs[i].ten = 1;
 	scsi_CDs[i].remap = 1;
 	scsi_CDs[i].auto_eject = 0; /* Default is not to eject upon unmount. */
-	sr_sizes[i] = scsi_CDs[i].capacity;
+	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
     }
     
     
diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.3.80/linux/drivers/scsi/st.c	Wed Mar 13 08:38:54 1996
+++ linux/drivers/scsi/st.c	Sat Mar 30 12:18:07 1996
@@ -11,7 +11,7 @@
   Copyright 1992, 1993, 1994, 1995 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Mon Jan 29 21:18:12 1996 by root@kai.makisara.fi
+  Last modified: Fri Mar 29 20:55:05 1996 by root@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -84,8 +84,8 @@
 
 Scsi_Tape * scsi_tapes = NULL;
 
-static ST_buffer *new_tape_buffer(int);
-static int enlarge_buffer(ST_buffer *, int);
+static ST_buffer *new_tape_buffer(int, int);
+static int enlarge_buffer(ST_buffer *, int, int);
 static void normalize_buffer(ST_buffer *);
 
 static int st_init(void);
@@ -171,7 +171,8 @@
 	     scsi_tapes[dev].recover_count);
     }
 #endif
-    return 0;
+    if ((sense[2] & 0xe0) == 0)
+      return 0;
   }
   return (-EIO);
 }
@@ -453,7 +454,7 @@
 scsi_tape_open(struct inode * inode, struct file * filp)
 {
     unsigned short flags;
-    int i;
+    int i, need_dma_buffer;
     unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
     Scsi_Tape * STp;
@@ -471,13 +472,15 @@
     STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
 
     /* Allocate buffer for this user */
+    need_dma_buffer = STp->restr_dma;
     for (i=0; i < st_nbr_buffers; i++)
-      if (!st_buffers[i]->in_use)
+      if (!st_buffers[i]->in_use &&
+	  (!need_dma_buffer || st_buffers[i]->dma))
 	break;
     if (i >= st_nbr_buffers) {
-      STp->buffer = new_tape_buffer(FALSE);
+      STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
       if (STp->buffer == NULL) {
-	printk(KERN_WARNING "st%d: No free buffers.\n", dev);
+	printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
 	return (-EBUSY);
       }
     }
@@ -608,7 +611,7 @@
       }
 
       if (STp->block_size > (STp->buffer)->buffer_size &&
-	  !enlarge_buffer(STp->buffer, STp->block_size)) {
+	  !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
 	printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
 	       STp->block_size);
 	(STp->buffer)->in_use = 0;
@@ -775,7 +778,7 @@
 
     if (STp->block_size == 0 &&
        count > (STp->buffer)->buffer_size &&
-       !enlarge_buffer(STp->buffer, count))
+       !enlarge_buffer(STp->buffer, count, STp->restr_dma))
       return (-EOVERFLOW);
 
     if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
@@ -1016,7 +1019,7 @@
 
     if (STp->block_size == 0 &&
 	count > (STp->buffer)->buffer_size &&
-	!enlarge_buffer(STp->buffer, count))
+	!enlarge_buffer(STp->buffer, count, STp->restr_dma))
       return (-EOVERFLOW);
 
     if (!(STp->do_read_ahead) && STp->block_size != 0 &&
@@ -1968,7 +1971,7 @@
 
 /* Try to allocate a new tape buffer */
 	static ST_buffer *
-new_tape_buffer( int from_initialization )
+new_tape_buffer( int from_initialization, int need_dma )
 {
   int priority, a_size;
   ST_buffer *tb;
@@ -1977,16 +1980,18 @@
     return NULL;  /* Should never happen */
 
   if (from_initialization) {
-    priority = GFP_ATOMIC | GFP_DMA;
+    priority = GFP_ATOMIC;
     a_size = st_buffer_size;
   }
   else {
-    priority = GFP_KERNEL | GFP_DMA;
+    priority = GFP_KERNEL;
     for (a_size = PAGE_SIZE; a_size < st_buffer_size; a_size <<= 1)
       ; /* Make sure we allocate efficiently */
   }
   tb = (ST_buffer *)scsi_init_malloc(sizeof(ST_buffer), priority);
   if (tb) {
+    if (need_dma)
+      priority |= GFP_DMA;
     tb->b_data = (unsigned char *)scsi_init_malloc(a_size, priority);
     if (!tb->b_data) {
       scsi_init_free((char *)tb, sizeof(ST_buffer));
@@ -1998,13 +2003,14 @@
 	   st_nbr_buffers);
     return NULL;
   }
-
 #if DEBUG
   if (debugging)
-    printk(ST_DEB_MSG "st: Allocated tape buffer %d (%d bytes).\n",
-	   st_nbr_buffers, a_size);
+    printk(ST_DEB_MSG
+	   "st: Allocated tape buffer %d (%d bytes, dma: %d, a: %p).\n",
+	   st_nbr_buffers, a_size, need_dma, tb->b_data);
 #endif
   tb->in_use = 0;
+  tb->dma = need_dma;
   tb->buffer_size = a_size;
   tb->writing = 0;
   tb->orig_b_data = NULL;
@@ -2015,9 +2021,9 @@
 
 /* Try to allocate a temporary enlarged tape buffer */
 	static int
-enlarge_buffer(ST_buffer *STbuffer, int new_size)
+enlarge_buffer(ST_buffer *STbuffer, int new_size, int need_dma)
 {
-  int a_size;
+  int a_size, priority;
   unsigned char *tbd;
 
   normalize_buffer(STbuffer);
@@ -2025,13 +2031,17 @@
   for (a_size = PAGE_SIZE; a_size < new_size; a_size <<= 1)
     ;  /* Make sure that we allocate efficiently */
 
-  tbd = (unsigned char *)scsi_init_malloc(a_size, GFP_DMA | GFP_KERNEL);
+  priority = GFP_KERNEL;
+  if (need_dma)
+    priority |= GFP_DMA;
+  tbd = (unsigned char *)scsi_init_malloc(a_size, priority);
   if (!tbd)
     return FALSE;
-
 #if DEBUG
   if (debugging)
-    printk(ST_DEB_MSG "st: Buffer enlarged to %d bytes.\n", a_size);
+    printk(ST_DEB_MSG
+	   "st: Buffer at %p enlarged to %d bytes (dma: %d, a: %p).\n",
+	   STbuffer->b_data, a_size, need_dma, tbd);
 #endif
 
   STbuffer->orig_b_data = STbuffer->b_data;
@@ -2056,8 +2066,8 @@
 
 #if DEBUG
   if (debugging)
-    printk(ST_DEB_MSG "st: Buffer normalized to %d bytes.\n",
-	   STbuffer->buffer_size);
+    printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes.\n",
+	   STbuffer->b_data, STbuffer->buffer_size);
 #endif
 }
 
@@ -2123,6 +2133,7 @@
    tpnt->waiting = NULL;
    tpnt->in_use = 0;
    tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
+   tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
    tpnt->density = 0;
    tpnt->do_buffer_writes = ST_BUFFER_WRITES;
    tpnt->do_async_writes = ST_ASYNC_WRITES;
@@ -2131,9 +2142,10 @@
    tpnt->two_fm = ST_TWO_FM;
    tpnt->fast_mteom = ST_FAST_MTEOM;
    tpnt->write_threshold = st_write_threshold;
-   tpnt->drv_block = 0;
+   tpnt->drv_block = (-1);
    tpnt->moves_after_eof = 1;
    tpnt->at_sm = 0;
+   (tpnt->mt_status)->mt_fileno = (tpnt->mt_status)->mt_blkno = (-1);
 
    st_template.nr_dev++;
    return 0;
@@ -2238,8 +2250,9 @@
     target_nbr = st_max_buffers;
 
   for (i=st_nbr_buffers=0; i < target_nbr; i++) {
-    if (!new_tape_buffer(TRUE)) {
+    if (!new_tape_buffer(TRUE, TRUE)) {
       if (i == 0) {
+#if 0
 	printk(KERN_ERR "Can't continue without at least one tape buffer.\n");
 	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
 	scsi_init_free((char *) st_buffers,
@@ -2247,6 +2260,10 @@
 	scsi_init_free((char *) scsi_tapes,
 		       st_template.dev_max * sizeof(Scsi_Tape));
 	return 1;
+#else
+	printk(KERN_INFO "No tape buffers allocated at initialization.\n");
+	break;
+#endif
       }
       printk(KERN_INFO "Number of tape buffers adjusted.\n");
       break;
diff -u --recursive --new-file v1.3.80/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v1.3.80/linux/drivers/scsi/st.h	Sun Dec 17 10:59:24 1995
+++ linux/drivers/scsi/st.h	Sat Mar 30 12:18:07 1996
@@ -10,7 +10,8 @@
 #endif
 
 typedef struct {
-  int in_use;
+  unsigned char in_use;
+  unsigned char dma;	/* DMA-able buffer */
   int buffer_size;
   int buffer_blocks;
   int buffer_bytes;
@@ -37,6 +38,7 @@
   unsigned char in_use;
   unsigned char eof_hit;
   unsigned char drv_buffer;
+  unsigned char restr_dma;
   unsigned char do_buffer_writes;
   unsigned char do_async_writes;
   unsigned char do_read_ahead;
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/.version linux/drivers/sound/.version
--- v1.3.80/linux/drivers/sound/.version	Sun Mar 24 22:56:00 1996
+++ linux/drivers/sound/.version	Sat Mar 30 13:38:31 1996
@@ -1,2 +1,2 @@
-3.5.1
+3.5.2
 0x030500
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/.version.orig linux/drivers/sound/.version.orig
--- v1.3.80/linux/drivers/sound/.version.orig	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/.version.orig	Sun Mar 24 22:56:00 1996
@@ -0,0 +1,2 @@
+3.5.1
+0x030500
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.3.80/linux/drivers/sound/CHANGELOG	Sun Mar 24 22:55:28 1996
+++ linux/drivers/sound/CHANGELOG	Sat Mar 30 13:38:31 1996
@@ -1,6 +1,8 @@
-Changelog for version 3.5.1
+Changelog for version 3.5.2
 ---------------------------
 
+Since 3.5.1
+- TB Maui initialization support
 Since 3.5
 - Improved handling of playback underrunt situations.
 
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.3.80/linux/drivers/sound/Readme	Sun Mar 24 22:55:43 1996
+++ linux/drivers/sound/Readme	Sat Mar 30 13:38:31 1996
@@ -1,5 +1,5 @@
-Version 3.5.1 release notes
----------------------------
+Version 3.5.2 release notes
+--------------------------------
 
 Most up to date information about this driver is available from 
 http://personal.eunet.fi/pp/voxware.
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v1.3.80/linux/drivers/sound/Readme.cards	Mon Mar 25 09:25:26 1996
+++ linux/drivers/sound/Readme.cards	Sat Mar 30 13:38:31 1996
@@ -34,8 +34,6 @@
 		(Early 3.6-alpha versions?)
 	- Sound Galaxy Washington/Waverider
 		(3.6-alpha versions. Can't promise the waverider synth).
-	- TB Maui
-		(v3.6)
 	- Yamaha OPL4 (on cards having _RAM_ for samples)
 		(Late 96?. Works as OPL3 with current driver versions)
 
@@ -180,8 +178,8 @@
 
 Turtle Beach Maui and Tropez
 	This driver version supports sample, patch and program loading commands
-	described in the Maui/Tropez User's manual. There is no initialization
-	code for Maui so it must be initialized with DOS. The audio side of
+	described in the Maui/Tropez User's manual. 
+	There is now full initialization support too. The audio side of
 	the Tropez is based on the MAD16 chip (see above).
 
 Jumpers and software configuration
@@ -385,9 +383,8 @@
 	  cards made by known manufacturers such as Turtle Beach (Tropez),
 	  Reveal (some models) and Diamond (some recent models).
   "Support for TB Maui"
-	- This is just an experimental extension to the MPU401 driver.
-	  Don't enable this option unless you are writing a .MOD
-	  player for Maui.
+	- This enables TB Maui spesific initialization. Works with TB Maui
+	and TB Tropez (may not work with Tropez Plus).
 
   "Audio Excel DSP 16 initialization support",
 	- Don't know much about this card. Look at aedsp16.c for more info.
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.3.80/linux/drivers/sound/configure.c	Sun Mar 24 22:49:55 1996
+++ linux/drivers/sound/configure.c	Sat Mar 30 13:38:31 1996
@@ -1470,6 +1470,39 @@
 	}
     }
 
+  if (selected_options & B (OPT_MAUI))
+    {
+    oswf_again:
+      if (think_positively (
+			     "Do you have access to the OSWF.MOT file", 1,
+			     "TB Maui and Tropez have a microcontroller which needs to be initialized\n"
+			     "prior use. OSWF.MOT is a file distributed with card's DOS/Windows drivers\n"
+			     "which is required during initialization\n"))
+	{
+	  char            path[512];
+
+	  fprintf (stderr,
+		   "Enter full name of the OSWF.MOT file (pwd is sound): ");
+	  scanf ("%s", path);
+	  fprintf (stderr, "including microcode file %s\n", path);
+
+	  if (!bin2hex (path, "maui_boot.h", "maui_os"))
+	    {
+	      fprintf (stderr, "Couldn't open file %s\n",
+		       path);
+	      if (think_positively ("Try again with correct path", 1,
+				    "The specified file could not be opened. Enter the correct path to the\n"
+				    "file.\n"))
+		goto oswf_again;
+	    }
+	  else
+	    {
+	      printf ("#define HAVE_MAUI_BOOT\n");
+	      printf ("/*build bin2hex %s maui_boot.h maui_os */\n", path);
+	    }
+	}
+    }
+
   if (!(selected_options & ANY_DEVS))
     {
       printf ("invalid_configuration__run_make_config_again\n");
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/maui.c linux/drivers/sound/maui.c
--- v1.3.80/linux/drivers/sound/maui.c	Sun Mar 24 22:50:06 1996
+++ linux/drivers/sound/maui.c	Sat Mar 30 13:38:31 1996
@@ -55,6 +55,10 @@
 static int      (*orig_load_patch) (int dev, int format, const char *addr,
 				 int offs, int count, int pmgr_flag) = NULL;
 
+#ifdef HAVE_MAUI_BOOT
+#include "maui_boot.h"
+#endif
+
 static wait_handle *maui_sleeper = NULL;
 static volatile struct snd_wait maui_sleep_flag =
 {0};
@@ -139,6 +143,158 @@
   irq_ok = 1;
 }
 
+static int
+download_code (void)
+{
+  int             i, lines = 0;
+  int             eol_seen = 0, done = 0;
+  int             skip = 1;
+
+  printk ("Code download (%d bytes): ", maui_osLen);
+
+  for (i = 0; i < maui_osLen; i++)
+    {
+      if (maui_os[i] != '\r')
+	if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n')))
+	  {
+	    skip = 0;
+
+	    if (maui_os[i] == '\n')
+	      eol_seen = skip = 1;
+	    else if (maui_os[i] == 'S')
+	      {
+		if (maui_os[i + 1] == '8')
+		  done = 1;
+		if (!maui_write (0xF1))
+		  goto failure;
+		if (!maui_write ('S'))
+		  goto failure;
+	      }
+	    else
+	      {
+		if (!maui_write (maui_os[i]))
+		  goto failure;
+	      }
+
+	    if (eol_seen)
+	      {
+		int             c = 0;
+
+		int             n;
+
+		eol_seen = 0;
+
+		for (n = 0; n < 2; n++)
+		  if (maui_wait (STAT_RX_AVAIL))
+		    {
+		      c = inb (HOST_DATA_PORT);
+		      break;
+		    }
+
+		if (c != 0x80)
+		  {
+		    printk ("Doanload not acknowledged\n");
+		    return 0;
+		  }
+		else if (!(lines++ % 10))
+		  printk (".");
+
+		if (done)
+		  {
+		    printk ("\nDownload complete\n");
+		    return 1;
+		  }
+	      }
+	  }
+    }
+
+failure:
+
+  printk ("\nDownload failed!!!\n");
+  return 0;
+}
+
+static int
+maui_init (int irq)
+{
+  int             i;
+  unsigned char   bits;
+
+  switch (irq)
+    {
+    case 9:
+      bits = 0x00;
+      break;
+    case 5:
+      bits = 0x08;
+      break;
+    case 12:
+      bits = 0x10;
+      break;
+    case 15:
+      bits = 0x18;
+      break;
+
+    default:
+      printk ("Maui: Invalid IRQ %d\n", irq);
+      return 0;
+    }
+
+  outb (0x00, HOST_CTRL_PORT);	/* Reset */
+
+  outb (bits, HOST_DATA_PORT);	/* Set the IRQ bits */
+  outb (bits | 0x80, HOST_DATA_PORT);	/* Set the IRQ bits again? */
+
+  outb (0x80, HOST_CTRL_PORT);	/* Leave reset */
+  outb (0x80, HOST_CTRL_PORT);	/* Leave reset */
+
+  outb (0xD0, HOST_CTRL_PORT);	/* Cause interrupt */
+
+  for (i = 0; i < 1000000 && !irq_ok; i++);
+
+  if (!irq_ok)
+    return 0;
+
+  outb (0x80, HOST_CTRL_PORT);	/* Leave reset */
+
+  printk ("Turtle Beach Maui initialization\n");
+
+  if (!download_code ())
+    return 0;
+
+  outb (0xE0, HOST_CTRL_PORT);	/* Normal operation */
+
+  /* Select mpu401 mode */
+
+  maui_write (0xf0);
+  maui_write (1);
+  if (maui_read () != 0x80)
+    {
+      maui_write (0xf0);
+      maui_write (1);
+      if (maui_read () != 0x80)
+	printk ("Maui didn't acknowledge set HW mode command\n");
+    }
+
+  printk ("Maui initialized OK\n");
+  return 1;
+}
+
+static int
+maui_short_wait (int mask)
+{
+  int             i;
+
+  for (i = 0; i < 1000; i++)
+    {
+      if (inb (HOST_STAT_PORT) & mask)
+	{
+	  return 1;
+	}
+    }
+
+  return 0;
+}
 
 int
 maui_load_patch (int dev, int format, const char *addr,
@@ -222,6 +378,22 @@
     return 0;
 
   maui_sleep_flag.mode = WK_NONE;
+/*
+ * Initialize the processor if necessary
+ */
+
+  if (maui_osLen > 0)
+    {
+      if (!(inb (HOST_STAT_PORT) & STAT_TX_AVAIL) ||
+	  !maui_write (0x9F) ||	/* Report firmware version */
+	  !maui_short_wait (STAT_RX_AVAIL) ||
+	  maui_read () == -1 || maui_read () == -1)
+	if (!maui_init (hw_config->irq))
+	  {
+	    snd_release_irq (hw_config->irq);
+	    return 0;
+	  }
+    }
 
   if (!maui_write (0xCF))	/* Report hardware version */
     {
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v1.3.80/linux/drivers/sound/soundvers.h	Sun Mar 24 22:56:08 1996
+++ linux/drivers/sound/soundvers.h	Sat Mar 30 13:38:31 1996
@@ -1,2 +1,2 @@
-#define SOUND_VERSION_STRING "3.5.1-960324"
+#define SOUND_VERSION_STRING "3.5.2-960330"
 #define SOUND_INTERNAL_VERSION 0x030500
diff -u --recursive --new-file v1.3.80/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v1.3.80/linux/drivers/sound/sscape.c	Sun Mar 24 22:50:27 1996
+++ linux/drivers/sound/sscape.c	Sat Mar 30 13:38:31 1996
@@ -1196,7 +1196,9 @@
 void
 unload_sscape (struct address_info *hw_config)
 {
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
   unload_mpu401 (hw_config);
+#endif
   snd_release_irq (hw_config->irq);
   sound_free_dma (hw_config->dma);
 }
diff -u --recursive --new-file v1.3.80/linux/fs/Config.in linux/fs/Config.in
--- v1.3.80/linux/fs/Config.in	Tue Mar 19 09:05:23 1996
+++ linux/fs/Config.in	Fri Mar 29 09:10:17 1996
@@ -28,7 +28,7 @@
   fi
   tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS
 fi
-if [ "$CONFIG_IPX" = "y" ]; then
+if [ "$CONFIG_IPX" != "n" ]; then
   tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
 fi
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
diff -u --recursive --new-file v1.3.80/linux/fs/pipe.c linux/fs/pipe.c
--- v1.3.80/linux/fs/pipe.c	Mon Feb 19 13:29:08 1996
+++ linux/fs/pipe.c	Sat Mar 30 12:12:14 1996
@@ -14,6 +14,11 @@
 #include <linux/termios.h>
 #include <linux/mm.h>
 
+/*
+ * Define this if you want SunOS compatibility wrt braindead
+ * select behaviour on FIFO's.
+ */
+#undef FIFO_SUNOS_BRAINDAMAGE
 
 /* We don't use the head/tail construction any more. Now we use the start/len*/
 /* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */
@@ -169,6 +174,7 @@
 	return 0;
 }
 
+#ifdef FIFO_SUNOS_BRAINDAMAGE
 /*
  * Arggh. Why does SunOS have to have different select() behaviour
  * for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN..
@@ -194,6 +200,11 @@
 	}
 	return 0;
 }
+#else
+
+#define fifo_select pipe_select
+
+#endif /* FIFO_SUNOS_BRAINDAMAGE */
 
 /*
  * The 'connect_xxx()' functions are needed for named pipes when
diff -u --recursive --new-file v1.3.80/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.80/linux/fs/proc/array.c	Thu Mar 21 08:55:09 1996
+++ linux/fs/proc/array.c	Sat Mar 30 13:20:33 1996
@@ -1074,6 +1074,7 @@
 	int length;
 	int end;
 	unsigned int type, pid;
+	struct proc_dir_entry *dp;
 
 	if (count < 0)
 		return -EINVAL;
@@ -1085,8 +1086,13 @@
 	pid = type >> 16;
 	type &= 0x0000ffff;
 	start = NULL;
-	length = fill_array((char *) page, pid, type,
-			    &start, file->f_pos, count);
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	if (dp->get_info)
+		length = dp->get_info((char *)page, &start, file->f_pos,
+				      count, 0);
+	else
+		length = fill_array((char *) page, pid, type,
+				    &start, file->f_pos, count);
 	if (length < 0) {
 		free_page(page);
 		return length;
diff -u --recursive --new-file v1.3.80/linux/include/asm-alpha/apecs.h linux/include/asm-alpha/apecs.h
--- v1.3.80/linux/include/asm-alpha/apecs.h	Sun Mar 24 12:09:36 1996
+++ linux/include/asm-alpha/apecs.h	Sat Mar 30 11:48:51 1996
@@ -18,10 +18,61 @@
  * david.rusling@reo.mts.dec.com Initial Version.
  *
  */
+#include <linux/config.h>
 
+#ifdef CONFIG_ALPHA_XL
+/*
+   An AVANTI *might* be an XL, and an XL has only 27 bits of ISA address
+   that get passed through the PCI<->ISA bridge chip. So we've gotta use
+   both windows to max out the physical memory we can DMA to. Sigh...
+
+   If we try a window at 0 for 1GB as a work-around, we run into conflicts
+   with ISA/PCI bus memory which can't be relocated, like VGA aperture and
+   BIOS ROMs. So we must put the windows high enough to avoid these areas.
+
+   We put window 1 at BUS 64Mb for 64Mb, mapping physical 0 to 64Mb-1,
+   and window 2 at BUS 512Mb for 512Mb, mapping physical 0 to 512Mb-1.
+   Yes, this does map 0 to 64Mb-1 twice, but only window 1 will actually
+   be used for that range (via virt_to_bus()).
+
+   Window 1 will be used for all DMA from the ISA bus; yes, that does
+   limit what memory an ISA floppy or soundcard or Ethernet can touch, but
+   it's also a known limitation on other platforms as well. We use the
+   same technique that is used on INTEL platforms with similar limitation:
+   set MAX_DMA_ADDRESS and clear some pages' DMAable flags during mem_init().
+   We trust that any ISA bus device drivers will *always* ask for DMAable
+   memory explicitly via kmalloc()/get_free_pages() flags arguments.
+
+   Note that most PCI bus devices' drivers do *not* explicitly ask for
+   DMAable memory; they count on being able to DMA to any memory they
+   get from kmalloc()/get_free_pages(). They will also use window 1 for
+   any physical memory accesses below 64Mb; the rest will be handled by
+   window 2, maxing out at 512Mb of memory. I trust this is enough... :-)
+
+   Finally, the reason we make window 2 start at 512Mb for 512Mb, is so that
+   we can allocate PCI bus devices' memory starting at 1Gb and up, to ensure
+   that no conflicts occur and bookkeeping is simplified (ie we don't
+   try to fill the gap between the two windows, we just go above the top).
+
+   Note that the XL is treated differently from the AVANTI, even though
+   for most other things they are identical. It didn't seem reasonable to
+   make the AVANTI support pay for the limitations of the XL. It is true,
+   however, that an XL kernel will run on an AVANTI without problems.
+
+*/
+#define APECS_XL_DMA_WIN1_BASE	(64*1024*1024)
+#define APECS_XL_DMA_WIN1_SIZE	(64*1024*1024)
+#define APECS_XL_DMA_WIN2_BASE	(512*1024*1024)
+#define APECS_XL_DMA_WIN2_SIZE	(512*1024*1024)
+
+#else /* CONFIG_ALPHA_XL */
+
+/* these are for normal APECS family machines, AVANTI/MUSTANG/EB64/PC64 */
 #define APECS_DMA_WIN_BASE	(1024*1024*1024)
 #define APECS_DMA_WIN_SIZE	(1024*1024*1024)
 
+#endif /* CONFIG_ALPHA_XL */
+
 /*
  * 21071-DA Control and Status registers.
  * These are used for PCI memory access.
@@ -165,7 +216,15 @@
  */
 extern inline unsigned long virt_to_bus(void * address)
 {
-	return virt_to_phys(address) + APECS_DMA_WIN_BASE;
+	unsigned long paddr = virt_to_phys(address);
+#ifdef CONFIG_ALPHA_XL
+	if (paddr < APECS_XL_DMA_WIN1_SIZE)
+	  return paddr + APECS_XL_DMA_WIN1_BASE;
+	else
+	  return paddr + APECS_XL_DMA_WIN2_BASE; /* win 2 xlates to 0 also */
+#else /* CONFIG_ALPHA_XL */
+	return paddr + APECS_DMA_WIN_BASE;
+#endif /* CONFIG_ALPHA_XL */
 }
 
 extern inline void * bus_to_virt(unsigned long address)
@@ -176,9 +235,18 @@
 	 * detect null "pointers" (the NCR driver is much simpler if
 	 * NULL pointers are preserved).
 	 */
+#ifdef CONFIG_ALPHA_XL
+        if (address < APECS_XL_DMA_WIN1_BASE)
+                return 0;
+        else if (address < (APECS_XL_DMA_WIN1_BASE + APECS_XL_DMA_WIN1_SIZE))
+                return phys_to_virt(address - APECS_XL_DMA_WIN1_BASE);
+	else /* should be more checking here, maybe? */
+                return phys_to_virt(address - APECS_XL_DMA_WIN2_BASE);
+#else /* CONFIG_ALPHA_XL */
 	if (address < APECS_DMA_WIN_BASE)
 		return 0;
 	return phys_to_virt(address - APECS_DMA_WIN_BASE);
+#endif /* CONFIG_ALPHA_XL */
 }
 
 /*
diff -u --recursive --new-file v1.3.80/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h
--- v1.3.80/linux/include/asm-alpha/dma.h	Tue Aug  1 10:02:44 1995
+++ linux/include/asm-alpha/dma.h	Sat Mar 30 13:50:12 1996
@@ -18,6 +18,8 @@
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
+#include <linux/config.h>
+
 #include <asm/io.h>		/* need byte IO */
 
 #define dma_outb	outb
@@ -73,8 +75,16 @@
 
 #define MAX_DMA_CHANNELS	8
 
-/* The maximum address that we can perform a DMA transfer to on this platform */
+#ifdef CONFIG_ALPHA_XL
+/* The maximum address that we can perform a DMA transfer to on Alpha XL,
+   due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB.
+   see <asm/apecs.h> for more info */
+#define MAX_DMA_ADDRESS		(0xfffffc0004000000UL)
+#else /* CONFIG_ALPHA_XL */
+/* The maximum address that we can perform a DMA transfer to on normal
+   Alpha platforms */
 #define MAX_DMA_ADDRESS		(~0UL)
+#endif /* CONFIG_ALPHA_XL */
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff -u --recursive --new-file v1.3.80/linux/include/asm-alpha/floppy.h linux/include/asm-alpha/floppy.h
--- v1.3.80/linux/include/asm-alpha/floppy.h	Fri Mar  1 07:50:55 1996
+++ linux/include/asm-alpha/floppy.h	Sat Mar 30 11:48:51 1996
@@ -10,6 +10,8 @@
 #ifndef __ASM_ALPHA_FLOPPY_H
 #define __ASM_ALPHA_FLOPPY_H
 
+#include <linux/config.h>
+
 #define fd_inb(port)			inb_p(port)
 #define fd_outb(port,value)		outb_p(port,value)
 
@@ -47,8 +49,13 @@
 #define N_DRIVE 8
 
 /*
- * The Alpha has no problems with floppy DMA crossing 64k borders.
+ * Most Alphas have no problems with floppy DMA crossing 64k borders. Sigh...
  */
-#define CROSS_64KB(a,s)	(0)
+#ifdef CONFIG_ALPHA_XL
+#define CROSS_64KB(a,s) \
+    ((unsigned long)(a)/0x10000 != ((unsigned long)(a) + (s) - 1) / 0x10000)
+#else /* CONFIG_ALPHA_XL */
+#define CROSS_64KB(a,s) (0)
+#endif /* CONFIG_ALPHA_XL */
 
 #endif /* __ASM_ALPHA_FLOPPY_H */
diff -u --recursive --new-file v1.3.80/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v1.3.80/linux/include/asm-i386/bitops.h	Sat Mar 16 13:52:10 1996
+++ linux/include/asm-i386/bitops.h	Fri Mar 29 11:01:55 1996
@@ -78,18 +78,17 @@
 
 	if (!size)
 		return 0;
-	__asm__("
-		cld
-		movl $-1,%%eax
-		xorl %%edx,%%edx
-		repe; scasl
-		je 1f
-		xorl -4(%%edi),%%eax
-		subl $4,%%edi
-		bsfl %%eax,%%edx
-1:		subl %%ebx,%%edi
-		shll $3,%%edi
-		addl %%edi,%%edx"
+	__asm__("cld\n\t"
+		"movl $-1,%%eax\n\t"
+		"xorl %%edx,%%edx\n\t"
+		"repe; scasl\n\t"
+		"je 1f\n\t"
+		"xorl -4(%%edi),%%eax\n\t"
+		"subl $4,%%edi\n\t"
+		"bsfl %%eax,%%edx\n"
+		"1:\tsubl %%ebx,%%edi\n\t"
+		"shll $3,%%edi\n\t"
+		"addl %%edi,%%edx"
 		:"=d" (res)
 		:"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
 		:"ax", "cx", "di");
@@ -105,11 +104,10 @@
 		/*
 		 * Look for zero in first byte
 		 */
-		__asm__("
-			bsfl %1,%0
-			jne 1f
-			movl $32, %0
-1:			"
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
 			: "=r" (set)
 			: "r" (~(*p >> bit)));
 		if (set < (32 - bit))
diff -u --recursive --new-file v1.3.80/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v1.3.80/linux/include/linux/if_ether.h	Mon Mar 25 08:58:22 1996
+++ linux/include/linux/if_ether.h	Sat Mar 30 13:20:33 1996
@@ -71,6 +71,7 @@
 #define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
 #define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudeo type 	*/
 #define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
 
 /*
  *	This is an Ethernet frame header.
diff -u --recursive --new-file v1.3.80/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h
--- v1.3.80/linux/include/linux/ip_fw.h	Mon Mar 25 10:13:10 1996
+++ linux/include/linux/ip_fw.h	Sat Mar 30 14:03:16 1996
@@ -174,24 +174,6 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
-
-#ifdef CONFIG_IP_MASQUERADE
-struct ip_masq {
-	struct ip_masq	*next;		/* next member in list */
-	struct timer_list timer;	/* Expiration timer */
-	__u16 		protocol;	/* Which protocol are we talking? */
-	__u32 		src, dst;	/* Source and destination IP addresses */
-	__u16		sport,dport;	/* Source and destination ports */
-	__u16		mport;		/* Masquaraded port */
-	__u32		init_seq;	/* Add delta from this seq. on */
-	short		delta;		/* Delta in sequence numbers */
-	short		previous_delta;	/* Delta in sequence numbers before last resized PORT command */
-	char		sawfin;		/* Did we saw an FIN packet? */
-};
-extern struct ip_masq *ip_msq_hosts;
-extern void ip_fw_masquerade(struct sk_buff **, struct device *);
-extern int ip_fw_demasquerade(struct sk_buff *);
-#endif
 #ifdef CONFIG_IP_FIREWALL
 extern struct ip_fw *ip_fw_in_chain;
 extern struct ip_fw *ip_fw_out_chain;
@@ -212,21 +194,5 @@
 extern void ip_fw_init(void);
 #endif /* KERNEL */
 
-#ifdef CONFIG_IP_MASQUERADE
-
-#undef DEBUG_MASQ
-
-#define MASQUERADE_EXPIRE_TCP     15*60*HZ
-#define MASQUERADE_EXPIRE_TCP_FIN  2*60*HZ
-#define MASQUERADE_EXPIRE_UDP      5*60*HZ
-
-/*
- *	Linux ports don't normally get allocated above 32K. I used an extra 4K port-space
- */
- 
-#define PORT_MASQ_BEGIN	60000
-#define PORT_MASQ_END	(PORT_MASQ_BEGIN+4096)
-#define FTP_DPORT_TBD (PORT_MASQ_END+1) /* Avoid using hardcoded port 20 for ftp data connection */
-#endif
 
 #endif /* _IP_FW_H */
diff -u --recursive --new-file v1.3.80/linux/include/linux/ipx.h linux/include/linux/ipx.h
--- v1.3.80/linux/include/linux/ipx.h	Sun Mar 24 13:33:25 1996
+++ linux/include/linux/ipx.h	Sat Mar 30 13:20:33 1996
@@ -40,6 +40,7 @@
 #define IPX_FRAME_8022		2
 #define IPX_FRAME_ETHERII	3
 #define IPX_FRAME_8023		4
+#define IPX_FRAME_TR_8022	5
 	unsigned char ipx_special;
 #define IPX_SPECIAL_NONE	0
 #define IPX_PRIMARY		1
diff -u --recursive --new-file v1.3.80/linux/include/linux/major.h linux/include/linux/major.h
--- v1.3.80/linux/include/linux/major.h	Mon Mar  4 11:25:49 1996
+++ linux/include/linux/major.h	Sat Mar 30 13:20:33 1996
@@ -27,17 +27,14 @@
 #define SCSI_DISK_MAJOR	8
 #define SCSI_TAPE_MAJOR	9
 #define MD_MAJOR        9
-#define MOUSE_MAJOR	10
+#define MISC_MAJOR	10
 #define SCSI_CDROM_MAJOR 11
 #define QIC02_TAPE_MAJOR 12
 #define XT_DISK_MAJOR	13
 #define SOUND_MAJOR	14
 #define CDU31A_CDROM_MAJOR 15
-#define SOCKET_MAJOR	16
 #define GOLDSTAR_CDROM_MAJOR 16
-#define AF_UNIX_MAJOR	17
 #define OPTICS_CDROM_MAJOR 17
-#define AF_INET_MAJOR	18
 #define SANYO_CDROM_MAJOR 18
 #define CYCLADES_MAJOR  19
 #define CYCLADESAUX_MAJOR 20
diff -u --recursive --new-file v1.3.80/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v1.3.80/linux/include/linux/miscdevice.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/miscdevice.h	Sat Mar 30 13:20:33 1996
@@ -0,0 +1,23 @@
+#ifndef _LINUX_MISCDEVICE_H
+#define _LINUX_MISCDEVICE_H
+
+#define BUSMOUSE_MINOR 0
+#define PSMOUSE_MINOR  1
+#define MS_BUSMOUSE_MINOR 2
+#define ATIXL_BUSMOUSE_MINOR 3
+#define MISC_DYNAMIC_MINOR 255
+
+extern int misc_init(void);
+
+struct miscdevice 
+{
+	int minor;
+	const char *name;
+	struct file_operations *fops;
+	struct miscdevice * next, * prev;
+};
+
+extern int mouse_register(struct miscdevice * misc);
+extern int mouse_deregister(struct miscdevice * misc);
+
+#endif
diff -u --recursive --new-file v1.3.80/linux/include/linux/mouse.h linux/include/linux/mouse.h
--- v1.3.80/linux/include/linux/mouse.h	Tue Oct 10 14:59:19 1995
+++ linux/include/linux/mouse.h	Thu Jan  1 02:00:00 1970
@@ -1,21 +0,0 @@
-#ifndef _LINUX_MOUSE_H
-#define _LINUX_MOUSE_H
-
-#define BUSMOUSE_MINOR 0
-#define PSMOUSE_MINOR  1
-#define MS_BUSMOUSE_MINOR 2
-#define ATIXL_BUSMOUSE_MINOR 3
-
-extern int mouse_init(void);
-
-struct mouse {
-	int minor;
-	const char *name;
-	struct file_operations *fops;
-	struct mouse * next, * prev;
-};
-
-extern int mouse_register(struct mouse * mouse);
-extern int mouse_deregister(struct mouse * mouse);
-
-#endif
diff -u --recursive --new-file v1.3.80/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.80/linux/include/linux/proc_fs.h	Mon Mar 25 10:22:51 1996
+++ linux/include/linux/proc_fs.h	Sat Mar 30 13:58:07 1996
@@ -100,6 +100,7 @@
 	PROC_NET_AX25_BPQETHER,
 	PROC_NET_ALIAS_TYPES,
 	PROC_NET_ALIASES,
+	PROC_NET_IP_MASQ_APP,
 	PROC_NET_LAST
 };
 
diff -u --recursive --new-file v1.3.80/linux/include/linux/socket.h linux/include/linux/socket.h
--- v1.3.80/linux/include/linux/socket.h	Sun Mar 24 13:33:16 1996
+++ linux/include/linux/socket.h	Fri Mar 29 12:52:06 1996
@@ -96,8 +96,6 @@
 #define SOL_TCP		6
 #define SOL_UDP		17
 
-#ifdef __KERNEL__
-
 /* IP options */
 #define IP_TOS		1
 #define	IPTOS_LOWDELAY		0x10
@@ -112,8 +110,6 @@
 #define IP_MULTICAST_LOOP 		34
 #define IP_ADD_MEMBERSHIP		35
 #define IP_DROP_MEMBERSHIP		36
-
-#endif /* __KERNEL__ */
 
 /* These need to appear somewhere around here */
 #define IP_DEFAULT_MULTICAST_TTL        1
diff -u --recursive --new-file v1.3.80/linux/include/net/ip_masq.h linux/include/net/ip_masq.h
--- v1.3.80/linux/include/net/ip_masq.h	Thu Jan  1 02:00:00 1970
+++ linux/include/net/ip_masq.h	Sat Mar 30 14:03:16 1996
@@ -0,0 +1,146 @@
+/*
+ * 	IP masquerading functionality definitions
+ */
+
+#ifndef _IP_MASQ_H
+#define _IP_MASQ_H
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+/*
+ *	Linux ports don't normally get allocated above 32K.
+ *	I used an extra 4K port-space
+ */
+ 
+#define PORT_MASQ_BEGIN	60000
+#define PORT_MASQ_END	(PORT_MASQ_BEGIN+4096)
+
+#define MASQUERADE_EXPIRE_TCP     15*60*HZ
+#define MASQUERADE_EXPIRE_TCP_FIN  2*60*HZ
+#define MASQUERADE_EXPIRE_UDP      5*60*HZ
+
+#define IP_MASQ_F_OUT_SEQ              	0x01	/* must do output seq adjust */
+#define IP_MASQ_F_IN_SEQ              	0x02	/* must do input seq adjust */
+#define IP_MASQ_F_NO_DPORT    		0x04	/* no dport set yet */
+#define IP_MASQ_F_NO_DADDR      	0x08 	/* no daddr yet */
+#define IP_MASQ_F_HASHED		0x10 	/* hashed entry */
+#define IP_MASQ_F_SAW_FIN		0x20 	/* tcp fin pkt seen */
+
+#ifdef __KERNEL__
+
+/*
+ *	Delta seq. info structure
+ *	Each MASQ struct has 2 (output AND input seq. changes).
+ */
+
+struct ip_masq_seq {
+        __u32		init_seq;	/* Add delta from this seq */
+        short		delta;		/* Delta in sequence numbers */
+        short		previous_delta;	/* Delta in sequence numbers before last resized pkt */
+};
+
+/*
+ *	MASQ structure allocated for each masqueraded association
+ */
+struct ip_masq {
+        struct ip_masq  *m_link, *s_link; /* hashed link ptrs */
+	struct timer_list timer;	/* Expiration timer */
+	__u16 		protocol;	/* Which protocol are we talking? */
+	__u16		sport, dport, mport;	/* src, dst & masq ports */
+	__u32 		saddr, daddr, maddr;	/* src, dst & masq addresses */
+        struct ip_masq_seq out_seq, in_seq;
+	struct ip_masq_app *app;	/* bound ip_masq_app object */
+	unsigned  flags;        	/* status flags */
+};
+
+/*
+ *	[0]: UDP free_ports
+ *	[1]: TCP free_ports
+ */
+
+extern int ip_masq_free_ports[2];
+
+/*
+ *	ip_masq initializer (registers symbols and /proc/net entries)
+ */
+extern int ip_masq_init(void);
+
+/*
+ *	functions called from ip layer
+ */
+extern void ip_fw_masquerade(struct sk_buff **, struct device *);
+extern int ip_fw_demasquerade(struct sk_buff **, struct device *);
+
+/*
+ *	ip_masq obj creation/deletion functions.
+ */
+extern struct ip_masq *ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned flags);
+extern void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout);
+
+
+/*
+ * 	
+ *	IP_MASQ_APP: IP application masquerading definitions 
+ *
+ */
+
+struct ip_masq_app
+{
+        struct ip_masq_app *next;
+        unsigned type;          /* type = proto<<16 | port (host byte order)*/
+        int n_attach;
+        int (*masq_init_1)      /* ip_masq initializer */
+                (struct ip_masq_app *, struct ip_masq *);
+        int (*masq_done_1)      /* ip_masq fin. */
+                (struct ip_masq_app *, struct ip_masq *);
+        int (*pkt_out)          /* output (masquerading) hook */
+                (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, struct device *);
+        int (*pkt_in)           /* input (demasq) hook */
+                (struct ip_masq_app *, struct ip_masq *, struct sk_buff **, struct device *);
+};
+
+/*
+ *	ip_masq_app initializer
+ */
+extern int ip_masq_app_init(void);
+
+/*
+ * 	ip_masq_app object registration functions (port: host byte order)
+ */
+extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port);
+extern int unregister_ip_masq_app(struct ip_masq_app *mapp);
+
+/*
+ *	get ip_masq_app obj by proto,port(net_byte_order)
+ */
+extern struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port);
+
+/*
+ *	ip_masq TO ip_masq_app (un)binding functions.
+ */
+extern struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms);
+extern int ip_masq_unbind_app(struct ip_masq *ms);
+
+/*
+ *	output and input app. masquerading hooks.
+ *	
+ */
+extern int ip_masq_app_pkt_out(struct ip_masq *, struct sk_buff **skb_p, struct device *dev);
+extern int ip_masq_app_pkt_in(struct ip_masq *, struct sk_buff **skb_p, struct device *dev);
+
+/*
+ *	/proc/net entry
+ */
+extern int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy);
+
+/*
+ *	skb_replace function used by "client" modules to replace
+ *	a segment of skb.
+ */
+extern struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len);
+
+#endif /* __KERNEL__ */
+
+#endif /* _IP_MASQ_H */
diff -u --recursive --new-file v1.3.80/linux/include/net/p8022tr.h linux/include/net/p8022tr.h
--- v1.3.80/linux/include/net/p8022tr.h	Thu Jan  1 02:00:00 1970
+++ linux/include/net/p8022tr.h	Sat Mar 30 13:20:33 1996
@@ -0,0 +1,8 @@
+#ifndef _NET_P8022TR_H
+#define _NET_P8022TR_H
+
+extern struct datalink_proto *register_8022tr_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *));
+extern void unregister_8022tr_client(unsigned char type);
+
+#endif
+
diff -u --recursive --new-file v1.3.80/linux/include/net/p8022trcall.h linux/include/net/p8022trcall.h
--- v1.3.80/linux/include/net/p8022trcall.h	Thu Jan  1 02:00:00 1970
+++ linux/include/net/p8022trcall.h	Sat Mar 30 13:20:33 1996
@@ -0,0 +1,3 @@
+/* Separate to keep compilation of Space.c simpler */
+extern void p8022tr_proto_init(struct net_proto *);
+
diff -u --recursive --new-file v1.3.80/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.80/linux/kernel/sched.c	Thu Mar 28 17:34:35 1996
+++ linux/kernel/sched.c	Fri Mar 29 12:58:04 1996
@@ -861,11 +861,6 @@
 	long psecs;
 
 	p->utime += user;
-	if (p->priority < DEF_PRIORITY)
-		kstat.cpu_nice += user;
-	else
-		kstat.cpu_user += user;
-	kstat.cpu_system += system;
 	p->stime += system;
 
 	psecs = (p->stime + p->utime) / HZ;
@@ -917,14 +912,20 @@
 {
 #ifndef  __SMP__
 	struct task_struct * p = current;
+	unsigned long user = ticks - system;
 	if (p->pid) {
 		p->counter -= ticks;
 		if (p->counter < 0) {
 			p->counter = 0;
 			need_resched = 1;
 		}
+		if (p->priority < DEF_PRIORITY)
+			kstat.cpu_nice += user;
+		else
+			kstat.cpu_user += user;
+		kstat.cpu_system += system;
 	}
-	update_one_process(p, ticks, ticks-system, system);
+	update_one_process(p, ticks, user, system);
 #else
 	int cpu,j;
 	cpu = smp_processor_id();
diff -u --recursive --new-file v1.3.80/linux/net/802/Makefile linux/net/802/Makefile
--- v1.3.80/linux/net/802/Makefile	Mon Mar 25 08:58:23 1996
+++ linux/net/802/Makefile	Sat Mar 30 13:20:33 1996
@@ -15,12 +15,12 @@
 endif
 
 ifdef CONFIG_IPX
-OX_OBJS += p8022.o psnap.o
+O_OBJS += p8022.o psnap.o p8022tr.o
 endif
 
 ifdef CONFIG_ATALK
 ifndef CONFIG_IPX
-OX_OBJS += p8022.o psnap.o
+O_OBJS += p8022.o psnap.o p8022tr.o
 endif
 endif
 
diff -u --recursive --new-file v1.3.80/linux/net/802/p8022tr.c linux/net/802/p8022tr.c
--- v1.3.80/linux/net/802/p8022tr.c	Thu Jan  1 02:00:00 1970
+++ linux/net/802/p8022tr.c	Sat Mar 30 13:20:33 1996
@@ -0,0 +1,137 @@
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/datalink.h>
+#include <linux/mm.h>
+#include <linux/in.h>
+#include <net/p8022tr.h>
+
+#define SNAP_HEADER_LEN	8
+
+static struct datalink_proto *p8022tr_list = NULL;
+
+/*
+ *	We don't handle the loopback SAP stuff, the extended
+ *	802.2 command set, multicast SAP identifiers and non UI
+ *	frames. We have the absolute minimum needed for IPX,
+ *	IP and Appletalk phase 2.
+ */
+ 
+static struct datalink_proto *
+find_8022tr_client(unsigned char type)
+{
+	struct datalink_proto	*proto;
+
+	for (proto = p8022tr_list;
+		((proto != NULL) && (*(proto->type) != type));
+		proto = proto->next)
+		;
+
+	return proto;
+}
+
+int
+p8022tr_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+	struct datalink_proto	*proto;
+
+	proto = find_8022tr_client(*(skb->h.raw));
+	if (proto != NULL) {
+		skb->h.raw += 3;
+		skb_pull(skb,3);
+		return proto->rcvfunc(skb, dev, pt);
+	}
+
+	skb->sk = NULL;
+	kfree_skb(skb, FREE_READ);
+	return 0;
+}
+
+static void
+p8022tr_datalink_header(struct datalink_proto *dl, 
+		struct sk_buff *skb, unsigned char *dest_node)
+{
+	struct device	*dev = skb->dev;
+	unsigned char	*rawp;
+	unsigned char	*olddata;
+	unsigned char	*newdata;
+
+	rawp = skb_push(skb,3);
+	*rawp++ = dl->type[0];
+	*rawp++ = dl->type[0];
+	*rawp = 0x03;	/* UI */
+	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
+	olddata = skb->data;
+	newdata = skb_pull(skb, SNAP_HEADER_LEN);
+	memmove(newdata, olddata, dev->hard_header_len - SNAP_HEADER_LEN);
+}
+
+static struct packet_type p8022tr_packet_type = 
+{
+	0,	
+	NULL,		/* All devices */
+	p8022tr_rcv,
+	NULL,
+	NULL,
+};
+ 
+
+static struct symbol_table p8022tr_proto_syms = {
+#include <linux/symtab_begin.h>
+	X(register_8022tr_client),
+	X(unregister_8022tr_client),
+#include <linux/symtab_end.h>
+};
+
+void p8022tr_proto_init(struct net_proto *pro)
+{
+	p8022tr_packet_type.type=htons(ETH_P_TR_802_2);
+	dev_add_pack(&p8022tr_packet_type);
+	register_symtab(&p8022tr_proto_syms);
+}
+	
+struct datalink_proto *
+register_8022tr_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *))
+{
+	struct datalink_proto	*proto;
+
+	if (find_8022tr_client(type) != NULL)
+		return NULL;
+
+	proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
+	if (proto != NULL) {
+		proto->type[0] = type;
+		proto->type_len = 1;
+		proto->rcvfunc = rcvfunc;
+		proto->header_length = 3;
+		proto->datalink_header = p8022tr_datalink_header;
+		proto->string_name = "802.2TR";
+		proto->next = p8022tr_list;
+		p8022tr_list = proto;
+	}
+
+	return proto;
+}
+
+void unregister_8022tr_client(unsigned char type)
+{
+	struct datalink_proto *tmp, **clients = &p8022tr_list;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	while ((tmp = *clients) != NULL)
+	{
+		if (tmp->type[0] == type) {
+			*clients = tmp->next;
+			kfree_s(tmp, sizeof(struct datalink_proto));
+			break;
+		} else {
+			clients = &tmp->next;
+		}
+	}
+
+	restore_flags(flags);
+}
+
diff -u --recursive --new-file v1.3.80/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.80/linux/net/appletalk/ddp.c	Mon Mar 25 09:00:04 1996
+++ linux/net/appletalk/ddp.c	Sat Mar 30 13:20:33 1996
@@ -151,7 +151,8 @@
 	    	}
 
 	    	if ( to->sat_addr.s_net == s->protinfo.af_at.src_net &&
-		    to->sat_addr.s_node == s->protinfo.af_at.src_node ) 
+		    (to->sat_addr.s_node == s->protinfo.af_at.src_node 
+		     ||to->sat_addr.s_node == ATADDR_BCAST ))
 		{
 			break;
 	   	}
diff -u --recursive --new-file v1.3.80/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.80/linux/net/core/dev.c	Mon Mar 25 08:58:24 1996
+++ linux/net/core/dev.c	Sat Mar 30 13:20:34 1996
@@ -1349,7 +1349,9 @@
 	 *	SLHC if present needs attaching so other people see it
 	 *	even if not opened.
 	 */
-#if (defined(CONFIG_SLIP_COMPRESSED) || defined(CONFIG_PPP)) && defined(CONFIG_SLHC_BUILTIN)
+#if (defined(CONFIG_SLIP) && defined(CONFIG_SLIP_COMPRESSED)) \
+	 || defined(CONFIG_PPP) \
+    || (defined(CONFIG_ISDN) && defined(CONFIG_ISDN_PPP))
 	slhc_install();
 #endif	
 
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v1.3.80/linux/net/ipv4/Makefile	Sun Feb 11 13:28:37 1996
+++ linux/net/ipv4/Makefile	Sat Mar 30 13:20:34 1996
@@ -37,6 +37,11 @@
   endif
 endif
 
+ifeq ($(CONFIG_IP_MASQUERADE),y)
+IPV4_OBJS += ip_masq.o ip_masq_app.o
+M_OBJS += ip_masq_ftp.o ip_masq_irc.o
+endif
+
 ifeq ($(CONFIG_IP_ALIAS),y)
 IPV4_OBJS += ip_alias.o
 else
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.80/linux/net/ipv4/af_inet.c	Mon Mar 25 08:58:24 1996
+++ linux/net/ipv4/af_inet.c	Sat Mar 30 13:20:34 1996
@@ -90,6 +90,9 @@
 #include <net/raw.h>
 #include <net/icmp.h>
 #include <linux/ip_fw.h>
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
 #ifdef CONFIG_IP_ALIAS
 #include <net/ip_alias.h>
 #endif
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.80/linux/net/ipv4/arp.c	Mon Mar 25 08:58:24 1996
+++ linux/net/ipv4/arp.c	Sat Mar 30 13:20:34 1996
@@ -1115,7 +1115,6 @@
  * 	check if that someone else is one of our proxies.  If it isn't,
  * 	we can toss it.
  */
-			grat = (sip == tip) && (sha == tha);
 			arp_fast_lock();
 
 			for (proxy_entry=arp_proxy_list;
@@ -1137,12 +1136,6 @@
 			}
 			if (proxy_entry)
 			{
-				if (grat)
-				{
-					if(!(proxy_entry->flags&ATF_PERM))
-						arp_destroy(proxy_entry);
-					goto gratuitous;
-				}
 				memcpy(ha, proxy_entry->ha, dev->addr_len);
 				arp_unlock();
 				arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha, sha);
@@ -1151,11 +1144,7 @@
 			}
 			else
 			{
-				if (grat) 
-					goto gratuitous;
 				arp_unlock();
-				kfree_skb(skb, FREE_READ);
-				return 0;
 			}
 		}
 		else
@@ -1165,6 +1154,8 @@
  */
 			arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
 		}
+		grat = 1;
+		goto gratuitous;
 	}
 /*
  *	It is now an arp reply.
@@ -1182,13 +1173,13 @@
  * needs to be added to the arp cache, or have its entry updated if it is 
  * there.
  */
+ 
+gratuitous:
 
 	arp_fast_lock();
 
-gratuitous:
 
 	hash = HASH(sip);
-
 	for (entry=arp_tables[hash]; entry; entry=entry->next)
 		if (entry->ip == sip && entry->dev == dev)
 			break;
@@ -1198,8 +1189,14 @@
 /*
  *	Entry found; update it only if it is not a permanent entry.
  */
-		if (!(entry->flags & ATF_PERM)) {
-			memcpy(entry->ha, sha, dev->addr_len);
+		if (!(entry->flags & ATF_PERM)) 
+		{
+			if(memcmp(entry->ha, sha,dev->addr_len)!=0)
+			{
+				memcpy(entry->ha, sha, dev->addr_len);
+				if(entry->flags & ATF_COM)
+					arp_update_hhs(entry);
+			}
 			entry->last_updated = jiffies;
 			arpd_update(entry, __LINE__);
 		}
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v1.3.80/linux/net/ipv4/igmp.c	Wed Feb 21 08:33:26 1996
+++ linux/net/ipv4/igmp.c	Sat Mar 30 13:20:34 1996
@@ -517,15 +517,14 @@
 	{
 		if((*i)->multiaddr==addr)
 		{
-			if(--((*i)->users))
-				return;
-			else
+			if(--((*i)->users) == 0)
 			{
 				struct ip_mc_list *tmp= *i;
 				igmp_group_dropped(tmp);
 				*i=(*i)->next;
 				kfree_s(tmp,sizeof(*tmp));
 			}
+			return;
 		}
 	}
 }
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v1.3.80/linux/net/ipv4/ip_forward.c	Mon Mar 25 08:58:25 1996
+++ linux/net/ipv4/ip_forward.c	Sat Mar 30 13:20:34 1996
@@ -29,6 +29,9 @@
 #include <linux/udp.h>
 #include <linux/firewall.h>
 #include <linux/ip_fw.h>
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
 #include <net/checksum.h>
 #include <linux/route.h>
 #include <net/route.h>
@@ -210,7 +213,10 @@
 #ifndef CONFIG_IP_NO_ICMP_REDIRECT
 		if (dev == dev2 && 
 			!((iph->saddr^dev->pa_addr)&dev->pa_mask) &&
-		    	(rt->rt_flags&RTF_MODIFIED) && !opt->srr)
+			/* The daddr!=raddr test isnt obvious - what its doing
+			   is avoiding sending a frame the receiver will not 
+			   believe anyway.. */
+			iph->daddr != raddr/*ANK*/ && !opt->srr)
 				icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev);
 #endif
 #ifdef CONFIG_IP_MROUTE
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.80/linux/net/ipv4/ip_fw.c	Tue Mar 19 12:51:42 1996
+++ linux/net/ipv4/ip_fw.c	Sat Mar 30 13:20:34 1996
@@ -34,6 +34,7 @@
  *	Add support for matching on device names.
  *		Jos Vos <jos@xos.nl> 15/2/1996.
  *
+ *
  * Masquerading functionality
  *
  * Copyright (c) 1994 Pauline Middelink
@@ -52,6 +53,8 @@
  *	Alan Cox		:	Cleaned up length setting.
  *	Wouter Gadeyne		:	Fixed masquerading support of ftp PORT commands
  *
+ *	Juan Jose Ciarlante	:	Masquerading code moved to ip_masq.c
+ *
  *	All the real work was done by .....
  *
  */
@@ -98,6 +101,11 @@
 #include <net/icmp.h>
 #include <linux/firewall.h>
 #include <linux/ip_fw.h>
+
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
+
 #include <net/checksum.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
@@ -148,17 +156,6 @@
 
 #endif
 
-#ifdef CONFIG_IP_MASQUERADE
-/*
- *	Implement IP packet masquerading
- */
-
-static unsigned short masq_port = PORT_MASQ_BEGIN;
-static const char *strProt[] = {"UDP","TCP"};
-struct ip_masq *ip_msq_hosts;
-
-#endif
-
 /*
  *	Returns 1 if the port is matched by the vector, 0 otherwise
  */
@@ -522,517 +519,6 @@
 		return 0;
 }
 
-#ifdef CONFIG_IP_MASQUERADE
-
-static void masq_expire(unsigned long data)
-{
-	struct ip_masq *ms = (struct ip_masq *)data;
-	struct ip_masq *old,*cur;
-	unsigned long flags;
-
-#ifdef DEBUG_MASQ
-	printk("Masqueraded %s %lX:%X expired\n",
-			strProt[ms->protocol==IPPROTO_TCP],
-			ntohl(ms->src),ntohs(ms->sport));
-#endif
-	
-	save_flags(flags);
-	cli();
-
-	/* delete from list of hosts */
-	old = NULL;
-	cur = ip_msq_hosts;
-	while (cur!=NULL) {
-		if (cur==ms) {
-			if (old==NULL) ip_msq_hosts = ms->next;
-			else old->next = ms->next;
-			kfree_s(ms,sizeof(*ms));
-			break;
-		}
-		old = cur;
-		cur=cur->next;
-	}
-	restore_flags(flags);
-}
-
-/*
- * Create a new masquerade list entry, also allocate an
- * unused mport, keeping the portnumber between the
- * given boundaries MASQ_BEGIN and MASQ_END.
- *
- * FIXME: possible deadlock if all free ports are exhausted! 
- */
-static struct ip_masq *alloc_masq_entry(void)
-{
-	struct ip_masq *ms, *mst;
-	unsigned long flags;
-
-	ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
-	if (ms==NULL) 
-		return NULL;
-
-	memset(ms,0,sizeof(*ms));
-	init_timer(&ms->timer);
-	ms->timer.data     = (unsigned long)ms;
-	ms->timer.function = masq_expire;
-
-	save_flags(flags);
-	cli();
-	do 
-	{
-		/* Try the next available port number */
-		ms->mport = htons(masq_port++);
-		if (masq_port==PORT_MASQ_END)
-			masq_port = PORT_MASQ_BEGIN;
-
-		/* Now hunt through the used ports to see if
-		 * this port is in use... */
-		mst = ip_msq_hosts;
-		while (mst && mst->mport!=ms->mport)
-			mst = mst->next;
-	}
-	while (mst!=NULL); 
-
-	/* add new entry in front of list to minimize lookup-time */
-	ms->next  = ip_msq_hosts;
-	ip_msq_hosts = ms;
-	restore_flags(flags);
-
-	return ms;
-}
-
-/*
- * When passing an FTP 'PORT' command, try to replace the IP
- * address with an newly assigned (masquereded) port on this
- * host, so the ftp-data connect FROM the site will succeed...
- *
- * Also, when the size of the packet changes, create an delta
- * offset, which will be added to every th->seq (and subtracted for
- * (th->acqseq) whose seq > init_seq.
- *
- * Not for the faint of heart!
- */
-
-static struct sk_buff *revamp(struct sk_buff *skb, struct device *dev, struct ip_masq *ftp)
-{
-	struct iphdr *iph = skb->h.iph;
-	struct tcphdr *th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-	struct sk_buff *skb2;
-	char *p, *data = (char *)&th[1];
-	unsigned char p1,p2,p3,p4,p5,p6;
-	unsigned long from;
-	unsigned short port;
-	struct ip_masq *ms;
-	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
-	int diff;
-	__u32 seq;
-	
-	/*
-	 * Adjust seq with delta-offset for all packets after the most recent resized PORT command
-	 * and with previous_delta offset for all packets before most recent resized PORT
-	 */
-	
-	/*
-	 * seq & seq_ack are in network byte order; need conversion before comparing
-	 */
-	seq=ntohl(th->seq);
-	if (ftp->delta || ftp->previous_delta)
-	{
-		if(after(seq,ftp->init_seq) ) 
-		{
-			th->seq = htonl(seq + ftp->delta);
-#ifdef DEBUG_MASQ
-			printk("masq_revamp : added delta (%d) to seq\n",ftp->delta);
-#endif
-		}
-		else
-		{
-			th->seq = htonl(seq + ftp->previous_delta);
-#ifdef DEBUG_MASQ
-	 		printk("masq_revamp : added previous_delta (%d) to seq\n",ftp->previous_delta);
-#endif
-		}
-	}
-
-	while (skb->len - ((unsigned char *)data - skb->h.raw) > 18)
-	{
-		if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) 
-		{
-			data ++;
-			continue;
-		}
-		p = data+5;
- 		p1 = simple_strtoul(data+5,&data,10);
-		if (*data!=',')
-			continue;
-		p2 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p3 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p4 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p5 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p6 = simple_strtoul(data+1,&data,10);
-		if (*data!='\r' && *data!='\n')
-			continue;
-
-		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
-		port = (p5<<8) | p6;
-#ifdef MASQ_DEBUG
-		printk("PORT %lX:%X detected\n",from,port);
-#endif	
-		/*
-		 * Now create an masquerade entry for it
-		 */
-		ms = alloc_masq_entry();
-		if (ms==NULL)
-			return skb;
-		ms->protocol = IPPROTO_TCP;
-		ms->src      = htonl(from);	/* derived from PORT cmd */
-		ms->sport    = htons(port);	/* derived from PORT cmd */
-		ms->dst      = iph->daddr;
-		/*
-		 * Hardcoding 20 as dport is not always correct
-		 * At least 1 Windows ftpd uses a random port number instead of 20
-		 * Leave it undefined for now & wait for the first connection request to fill it out
-		 */ 
-		ms->dport    = htons(FTP_DPORT_TBD);	/* ftp-data */
-		ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
-		add_timer(&ms->timer);
-
-		/*
-		 * Replace the old PORT with the new one
-		 */
-		from = ntohl(dev->pa_addr);
-		port = ntohs(ms->mport);
-		sprintf(buf,"%ld,%ld,%ld,%ld,%d,%d",
-			from>>24&255,from>>16&255,from>>8&255,from&255,
-			port>>8&255,port&255);
-
-		/*
-		 * Calculate required delta-offset to keep TCP happy
-		 */
-		
-		diff = strlen(buf) - (data-p);
-		
-		/*
-		 *	No shift.
-		 */
-		 
-		if (diff==0) 
-		{
-			/*
-			 * simple case, just replace the old PORT cmd
- 			 */
- 			memcpy(p,buf,strlen(buf));
- 			return skb;
- 		}
- 
- 		/*
- 		 *	If the PORT command we have fiddled is the first, or is a
- 		 *	resend don't do the delta shift again. Doesn't work for
- 		 *	pathological cases, but we would need a history for that.
- 		 *	Also fails if you send 2^31 bytes of data down the link 
- 		 *	after the first port command.
- 		 *
- 		 *	FIXME: use ftp->init_seq_valid - 0 is a valid sequence.
- 		 */
- 		 
- 		if(!ftp->init_seq || after(seq,ftp->init_seq) )
- 		{
- 			ftp->previous_delta=ftp->delta;
- 			ftp->delta+=diff;
- 			ftp->init_seq = seq;
- 		}
- 		
- 		/*
- 		 * Sizes differ, make a copy
- 		 */
-#ifdef DEBUG_MASQ
-                printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",diff, skb->len);
-#endif
-		skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC);
- 		if (skb2 == NULL) {
- 			printk("MASQUERADE: No memory available\n");
- 			return skb;
- 		}
- 		skb2->free = skb->free;
- 		skb_reserve(skb2,MAX_HEADER);
- 		skb_put(skb2,skb->len + diff);
-		skb2->h.raw = skb2->data + (skb->h.raw - skb->data);
-		iph=skb2->h.iph;
-		/*
-		 *	Mend the IP header too
-		 */
-		iph->tot_len = htons(diff+ntohs(iph->tot_len));
-		iph->check = 0;
-		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
- 
- 		/*
- 		 *	Copy the packet data into the new buffer.
- 		 *	Thereby replacing the PORT cmd.
- 		 */
- 		memcpy(skb2->data, skb->data, (p - (char *)skb->data));
- 		memcpy(&skb2->data[(p - (char *)skb->data)], buf, strlen(buf));
-		memcpy(&skb2->data[(p - (char *)skb->data) + strlen(buf)], data,
-			skb->len - (data-(char *)skb->data));
-
-		/*
-		 * Update tot_len field in ip header !
-		 * Sequence numbers were allready modified in original packet
-		 */
-		iph->tot_len = htons(skb->len + diff);
-
-		/*
-		 * Problem, how to replace the new skb with old one,
-		 * preferably inplace, so all the pointers in the
-		 * calling tree keep ok :(
-		 */
-		kfree_skb(skb, FREE_WRITE);
-		return skb2;
-	}
-	return skb;
-}
-
-static void recalc_check(struct udphdr *uh, unsigned long saddr,
-	unsigned long daddr, int len)
-{
-	uh->check=0;
-	uh->check=csum_tcpudp_magic(saddr,daddr,len,
-		IPPROTO_UDP, csum_partial((char *)uh,len,0));
-	if(uh->check==0)
-		uh->check=0xFFFF;
-}
-	
-void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
-{
-	struct sk_buff  *skb=*skb_ptr;
-	struct iphdr	*iph = skb->h.iph;
-	unsigned short	*portptr;
-	struct ip_masq	*ms;
-	int		size;
-
-	/*
-	 * We can only masquerade protocols with ports...
-	 */
-
-	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
-		return;
- 
-	/*
-	 *	Now hunt the list to see if we have an old entry
-	 */
-
-	portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
-	ms = ip_msq_hosts;
-
-#ifdef DEBUG_MASQ
-	printk("Outgoing %s %lX:%X -> %lX:%X\n",
-		strProt[iph->protocol==IPPROTO_TCP],
-		ntohl(iph->saddr), ntohs(portptr[0]),
-		ntohl(iph->daddr), ntohs(portptr[1]));
-#endif
-	while (ms!=NULL) 
-	{
-		if (iph->protocol == ms->protocol &&
-		    iph->saddr == ms->src   && iph->daddr == ms->dst &&
-		    portptr[0] == ms->sport && portptr[1] == ms->dport) 
-		{
-			del_timer(&ms->timer);
-			break;
- 		}
-		ms = ms->next;
-	}
-
-	/*
-	 *	Nope, not found, create a new entry for it
-	 */
-	 
-	if (ms==NULL) 
-	{
-		ms = alloc_masq_entry();
-		if (ms==NULL) 
-		{
-			printk("MASQUERADE: no memory left !\n");
-			return;
-		}
-		ms->protocol = iph->protocol;
-		ms->src      = iph->saddr;
- 		ms->dst      = iph->daddr;
- 		ms->sport    = portptr[0];
- 		ms->dport    = portptr[1];
- 	}
- 
- 	/*
- 	 *	Change the fragments origin
- 	 */
- 	 
- 	size = skb->len - ((unsigned char *)portptr - skb->h.raw);
- 	iph->saddr = dev->pa_addr; /* my own address */
- 	portptr[0] = ms->mport;
- 
- 	/*
- 	 *	Adjust packet accordingly to protocol
- 	 */
- 	 
- 	if (iph->protocol==IPPROTO_UDP) 
- 	{
- 		ms->timer.expires = jiffies+MASQUERADE_EXPIRE_UDP;
- 		recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
- 	}
- 	else 
- 	{
- 		struct tcphdr *th;
- 		if (portptr[1]==htons(21)) 
- 		{
- 			skb = revamp(*skb_ptr, dev, ms);
- 			*skb_ptr = skb;
- 			iph = skb->h.iph;
- 			portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
- 			size = skb->len - ((unsigned char *)portptr-skb->h.raw);
- 		}
- 		th = (struct tcphdr *)portptr;
- 
- 		/*
- 		 *	Timeout depends if FIN packet was seen
- 		 */
- 		if (ms->sawfin || th->fin) 
- 		{
- 			ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
- 			ms->sawfin = 1;
- 		}
- 		else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP;
- 
-		skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
- 		tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
- 	}
- 	add_timer(&ms->timer);
- 	ip_send_check(iph);
- 
- #ifdef DEBUG_MASQ
- 	printk("O-routed from %lX:%X over %s\n",ntohl(dev->pa_addr),ntohs(ms->mport),dev->name);
- #endif
- }
- 
- /*
-  *	Check if it's an masqueraded port, look it up,
-  *	and send it on it's way...
-  *
-  *	Better not have many hosts using the designated portrange
-  *	as 'normal' ports, or you'll be spending lots of time in
-  *	this function.
-  */
-
-int ip_fw_demasquerade(struct sk_buff *skb)
-{
- 	struct iphdr	*iph = skb->h.iph;
- 	unsigned short	*portptr;
- 	struct ip_masq	*ms;
- 	struct tcphdr   *th = (struct tcphdr *)(skb->h.raw+(iph->ihl<<2));
- 
- 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
- 		return 0;
- 
- 	portptr = (unsigned short *)&(((char *)iph)[iph->ihl*4]);
- 	if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
- 	    ntohs(portptr[1]) > PORT_MASQ_END)
- 		return 0;
- 
-#ifdef DEBUG_MASQ
- 	printk("Incoming %s %lX:%X -> %lX:%X\n",
- 		strProt[iph->protocol==IPPROTO_TCP],
- 		ntohl(iph->saddr), ntohs(portptr[0]),
- 		ntohl(iph->daddr), ntohs(portptr[1]));
-#endif
-
- 	/*
- 	 * reroute to original host:port if found...
- 	 *
- 	 * NB. Cannot check destination address, just for the incoming port.
- 	 * reason: archie.doc.ac.uk has 6 interfaces, you send to
- 	 * phoenix and get a reply from any other interface(==dst)!
- 	 *
- 	 * [Only for UDP] - AC
- 	 */
- 	ms = ip_msq_hosts;
- 	while (ms!=NULL) 
- 	{
- 		if (iph->protocol==ms->protocol &&
-		    (iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) && 
- 		    (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) &&
- 		    portptr[1]==ms->mport)
- 		{
- 		
- 			int size = skb->len - ((unsigned char *)portptr - skb->h.raw);
- 			iph->daddr = ms->src;
- 			portptr[1] = ms->sport;
- 			
- 			if(ms->dport==htons(FTP_DPORT_TBD))
- 			{
- 				ms->dport=portptr[0];
-#ifdef DEBUG_MASQ
-	 			printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport));
-#endif
-			}
-
- 			/*
- 			 * Yug! adjust UDP/TCP and IP checksums
- 			 */
- 			if (iph->protocol==IPPROTO_UDP)
- 				recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
- 			else
- 			{
- 				__u32 ack_seq;
- 				/*
-				 * Adjust ack_seq with delta-offset for
-				 * the packets AFTER most recent PORT command has caused a shift
-				 * for packets before most recent PORT command, use previous_delta
-				 */
-#ifdef DEBUG_MASQ
-	 			printk("demasq : delta=%d ; previous_delta=%d ; init_seq=%lX ; ack_seq=%lX ; after=%d\n",ms->delta,ms->previous_delta,ntohl(ms->init_seq),ntohl(th->ack_seq),after(ntohl(th->ack_seq),ntohl(ms->init_seq)));
-#endif
-				ack_seq=ntohl(th->ack_seq);
-				if (ms->delta || ms->previous_delta)
-				{
-					if(after(ack_seq,ms->init_seq))
-					{
-				 		th->ack_seq = htonl(ack_seq-ms->delta);
-#ifdef DEBUG_MASQ
-						printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta);
-#endif
-					}
-					else
-					{
-				 		th->ack_seq = htonl(ack_seq-ms->previous_delta);
-#ifdef DEBUG_MASQ
-						printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta);
-#endif
-					}
-				}
-				skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
-					size - sizeof(struct tcphdr), 0);
- 				tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb);
- 			}
- 			ip_send_check(iph);
-#ifdef DEBUG_MASQ
- 			printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
-#endif
- 			return 1;
- 		}
- 		ms = ms->next;
- 	}
- 
- 	/* sorry, all this trouble for a no-hit :) */
- 	return 0;
-}
-#endif
-  
-
 
 static void zero_fw_chain(struct ip_fw *chainptr)
 {
@@ -1079,8 +565,12 @@
 	}
 
 	memcpy(ftmp, frwl, len);
-	ftmp->fw_tosand |= 0x03;
-	ftmp->fw_tosxor &= 0xFC;
+	/*
+	 *	Allow the more recent "minimise cost" flag to be
+	 *	set. [Rob van Nieuwkerk]
+	 */
+	ftmp->fw_tosand |= 0x01;
+	ftmp->fw_tosxor &= 0xFE;
 	ftmp->fw_pcnt=0L;
 	ftmp->fw_bcnt=0L;
 
@@ -1567,54 +1057,6 @@
 }
 #endif
 
-#ifdef CONFIG_IP_MASQUERADE
-
-static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
-			      int length, int unused)
-{
-	off_t pos=0, begin=0;
-	struct ip_masq *ms;
-	unsigned long flags;
-	int len=0;
-	
-	len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires\n"); 
-	save_flags(flags);
-	cli();
-	
-	ms=ip_msq_hosts;
-	while (ms!=NULL) 
-	{
-		int timer_active = del_timer(&ms->timer);
-		if (!timer_active)
-			ms->timer.expires = jiffies;
-		len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n",
-			strProt[ms->protocol==IPPROTO_TCP],
-			ntohl(ms->src),ntohs(ms->sport),
-			ntohl(ms->dst),ntohs(ms->dport),
-			ntohs(ms->mport),
-			ms->init_seq,ms->delta,ms->previous_delta,ms->timer.expires-jiffies);
-		if (timer_active)
-			add_timer(&ms->timer);
-
-		pos=begin+len;
-		if(pos<offset) 
-		{
- 			len=0;
-			begin=pos;
-		}
-		if(pos>offset+length)
-			break;
-		ms=ms->next;
-	}
-	restore_flags(flags);
-	*start=buffer+(offset-begin);
-	len-=(offset-begin);
-	if(len>length)
-		len=length;
-	return len;
-}
-  
-#endif
 
 #ifdef CONFIG_IP_FIREWALL
 /*
@@ -1722,14 +1164,16 @@
 		ip_fw_fwd_procinfo
 	});
 #endif
+
 #ifdef CONFIG_IP_MASQUERADE
-	proc_net_register(&(struct proc_dir_entry) {
-		PROC_NET_IPMSQHST, 13, "ip_masquerade",
-		S_IFREG | S_IRUGO, 1, 0, 0,
-		0, &proc_net_inode_operations,
-		ip_msqhst_procinfo
-	});
+        
+        /*
+         *	Initialize masquerading. 
+         */
+        
+        ip_masq_init();
 #endif
+        
 #if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
 	/* Register for device up/down reports */
 	register_netdevice_notifier(&ipfw_dev_notifier);
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v1.3.80/linux/net/ipv4/ip_input.c	Mon Mar 25 08:58:25 1996
+++ linux/net/ipv4/ip_input.c	Sat Mar 30 13:20:34 1996
@@ -149,6 +149,9 @@
 #include <net/checksum.h>
 #include <linux/igmp.h>
 #include <linux/ip_fw.h>
+#ifdef CONFIG_IP_MASQUERADE
+#include <net/ip_masq.h>
+#endif
 #include <linux/firewall.h>
 #include <linux/mroute.h>
 #include <net/netlink.h>
@@ -423,7 +426,7 @@
 		/*
 		 * Do we need to de-masquerade this fragment?
 		 */
-		if (ip_fw_demasquerade(skb)) 
+		if (ip_fw_demasquerade(&skb,dev)) 
 		{
 			struct iphdr *iph=skb->h.iph;
 			if (ip_forward(skb, dev, is_frag|IPFWD_MASQUERADED, iph->daddr))
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v1.3.80/linux/net/ipv4/ip_masq.c	Thu Jan  1 02:00:00 1970
+++ linux/net/ipv4/ip_masq.c	Sat Mar 30 13:20:34 1996
@@ -0,0 +1,672 @@
+/*
+ *
+ * 	Masquerading functionality
+ *
+ * 	Copyright (c) 1994 Pauline Middelink
+ *
+ *	See ip_fw.c for original log
+ *
+ * Fixes:
+ *	Juan Jose Ciarlante	:	Modularized application masquerading (see ip_masq_app.c)
+ *	Juan Jose Ciarlante	:	New struct ip_masq_seq that holds output/input delta seq.
+ *	Juan Jose Ciarlante	:	Added hashed lookup by proto,maddr,mport and proto,saddr,sport
+ *	Juan Jose Ciarlante	:	Fixed deadlock if free ports get exhausted
+ *	Juan Jose Ciarlante	:	Added NO_ADDR status flag.
+ *
+ *	
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/ip_masq.h>
+
+#define IP_MASQ_TAB_SIZE 256    /* must be power of 2 */
+
+/*
+ *	Implement IP packet masquerading
+ */
+
+static const char *strProt[] = {"UDP","TCP"};
+
+static __inline__ const char * masq_proto_name(unsigned proto)
+{
+        return strProt[proto==IPPROTO_TCP];
+}
+
+/*
+ *	Last masq_port number in use.
+ *	Will cycle in MASQ_PORT boundaries.
+ */
+static __u16 masq_port = PORT_MASQ_BEGIN;
+
+/*
+ *	free ports counters (UDP & TCP)
+ *
+ *	Their value is _less_ or _equal_ to actual free ports:
+ *	same masq port, diff masq addr (firewall iface address) allocated
+ *	entries are accounted but their actually don't eat a more than 1 port.
+ *
+ *	Greater values could lower MASQ_EXPIRATION setting as a way to
+ *	manage 'masq_entries resource'.
+ *	
+ */
+
+int ip_masq_free_ports[2] = {
+        PORT_MASQ_END - PORT_MASQ_BEGIN, 	/* UDP */
+        PORT_MASQ_END - PORT_MASQ_BEGIN 	/* TCP */
+};
+
+static struct symbol_table ip_masq_syms = {
+#include <linux/symtab_begin.h>
+	X(ip_masq_new),
+        X(ip_masq_set_expire),
+        X(ip_masq_free_ports),
+#include <linux/symtab_end.h>
+};
+
+/*
+ *	2 ip_masq hash tables: for input and output pkts lookups.
+ */
+
+struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE];
+struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE];
+
+/*
+ *	Returns hash value
+ */
+
+static __inline__ unsigned
+
+ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port)
+{
+        return (proto^ntohl(addr)^ntohs(port)) & (IP_MASQ_TAB_SIZE-1);
+}
+
+/*
+ *	Hashes ip_masq by its proto,addrs,ports.
+ *	should be called with masked interrupts.
+ *	returns bool success.
+ */
+
+static __inline__ int
+ip_masq_hash(struct ip_masq *ms)
+{
+        unsigned hash;
+
+        if (ms->flags & IP_MASQ_F_HASHED) {
+                printk("ip_masq_hash(): request for already hashed\n");
+                return 0;
+        }
+        /*
+         *	Hash by proto,m{addr,port}
+         */
+        hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
+        ms->m_link = ip_masq_m_tab[hash];
+        ip_masq_m_tab[hash] = ms;
+        
+        /*
+         *	Hash by proto,s{addr,port}
+         */
+        hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
+        ms->s_link = ip_masq_s_tab[hash];
+        ip_masq_s_tab[hash] = ms;
+        
+
+        ms->flags |= IP_MASQ_F_HASHED;
+        return 1;
+}
+
+/*
+ *	UNhashes ip_masq from ip_masq_[ms]_tables.
+ *	should be called with masked interrupts.
+ *	returns bool success.
+ */
+
+static __inline__ int ip_masq_unhash(struct ip_masq *ms)
+{
+        unsigned hash;
+        struct ip_masq ** ms_p;
+        if (!(ms->flags & IP_MASQ_F_HASHED)) {
+                printk("ip_masq_unhash(): request for unhash flagged\n");
+                return 0;
+        }
+        /*
+         *	UNhash by m{addr,port}
+         */
+        hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
+        for (ms_p = &ip_masq_m_tab[hash]; *ms_p ; ms_p = &(*ms_p)->m_link)
+                if (ms == (*ms_p))  {
+                        *ms_p = ms->m_link;
+                        break;
+                }
+        /*
+         *	UNhash by s{addr,port}
+         */
+        hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
+        for (ms_p = &ip_masq_s_tab[hash]; *ms_p ; ms_p = &(*ms_p)->s_link)
+                if (ms == (*ms_p))  {
+                        *ms_p = ms->s_link;
+                        break;
+                }
+       
+        ms->flags &= ~IP_MASQ_F_HASHED;
+        return 1;
+}
+
+/*
+ *	Returns ip_masq associated with addresses found in iph.
+ *	called for pkts coming from outside-to-INside the firewall
+ *
+ * 	NB. Cannot check destination address, just for the incoming port.
+ * 	reason: archie.doc.ac.uk has 6 interfaces, you send to
+ * 	phoenix and get a reply from any other interface(==dst)!
+ *
+ * 	[Only for UDP] - AC
+ */
+
+struct ip_masq *
+ip_masq_in_get(struct iphdr *iph)
+{
+        unsigned hash;
+        struct ip_masq *ms;
+ 	__u16 *portptr;
+        int protocol;
+        __u32 s_addr, d_addr;
+        __u16 s_port, d_port;
+
+ 	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+        protocol = iph->protocol;
+        s_addr = iph->saddr;
+        s_port = portptr[0];
+        d_addr = iph->daddr;
+        d_port = portptr[1];
+        
+        hash = ip_masq_hash_key(protocol, d_addr, d_port);
+        for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
+ 		if ( protocol==ms->protocol &&
+		    (s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR) &&
+                    (s_port==ms->dport || ms->flags & IP_MASQ_F_NO_DPORT) &&
+                    (d_addr==ms->maddr && d_port==ms->mport))
+                        return ms;
+        }
+        return NULL;
+}
+
+/*
+ *	Returns ip_masq associated with addresses found in iph.
+ *	called for pkts coming from inside-to-OUTside the firewall.
+ */
+
+struct ip_masq *
+ip_masq_out_get(struct iphdr *iph)
+{
+        unsigned hash;
+        struct ip_masq *ms;
+ 	__u16 *portptr;
+        int protocol;
+        __u32 s_addr, d_addr;
+        __u16 s_port, d_port;
+
+ 	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+        protocol = iph->protocol;
+        s_addr = iph->saddr;
+        s_port = portptr[0];
+        d_addr = iph->daddr;
+        d_port = portptr[1];
+        
+        hash = ip_masq_hash_key(protocol, s_addr, s_port);
+        for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
+		if (protocol == ms->protocol &&
+		    s_addr == ms->saddr && s_port == ms->sport &&
+                    d_addr == ms->daddr && d_port == ms->dport )
+                        return ms;
+        }
+        
+        return NULL;
+}
+
+/*
+ *	Returns ip_masq for given proto,m_addr,m_port.
+ *      called by allocation routine to find an unused m_port.
+ */
+
+struct ip_masq *
+ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
+{
+        unsigned hash;
+        struct ip_masq *ms;
+        
+        hash = ip_masq_hash_key(protocol, m_addr, m_port);
+        for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
+ 		if ( protocol==ms->protocol &&
+                    (m_addr==ms->maddr && m_port==ms->mport))
+                        return ms;
+        }
+        return NULL;
+}
+
+static void masq_expire(unsigned long data)
+{
+	struct ip_masq *ms = (struct ip_masq *)data;
+	unsigned long flags;
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+	printk("Masqueraded %s %lX:%X expired\n",
+			masq_proto_name(ms->protocol),
+			ntohl(ms->src),ntohs(ms->sport));
+#endif
+	
+	save_flags(flags);
+	cli();
+
+        if (ip_masq_unhash(ms)) {
+                ip_masq_free_ports[ms->protocol==IPPROTO_TCP]++;
+                ip_masq_unbind_app(ms);
+                kfree_s(ms,sizeof(*ms));
+        }
+        
+	restore_flags(flags);
+}
+
+/*
+ * 	Create a new masquerade list entry, also allocate an
+ * 	unused mport, keeping the portnumber between the
+ * 	given boundaries MASQ_BEGIN and MASQ_END.
+ */
+
+struct ip_masq * ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
+{
+        struct ip_masq *ms, *mst;
+        int ports_tried, *free_ports_p;
+	unsigned long flags;
+        static int n_fails = 0;
+        
+        free_ports_p = &ip_masq_free_ports[proto==IPPROTO_TCP];
+        
+        if (*free_ports_p == 0) {
+                if (++n_fails < 5)
+                        printk("ip_masq_new(proto=%s): no free ports.\n",
+                               masq_proto_name(proto));
+                return NULL;
+        }
+        ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
+        if (ms == NULL) {
+                if (++n_fails < 5)
+                        printk("ip_masq_new(proto=%s): no memory available.\n",
+                               masq_proto_name(proto));
+                return NULL;
+        }
+        memset(ms, 0, sizeof(*ms));
+	init_timer(&ms->timer);
+	ms->timer.data     = (unsigned long)ms;
+	ms->timer.function = masq_expire;
+        ms->protocol	   = proto;
+        ms->saddr    	   = saddr;
+        ms->sport	   = sport;
+        ms->daddr	   = daddr;
+        ms->dport	   = dport;
+        ms->flags	   = mflags;
+        
+        if (proto == IPPROTO_UDP)
+                ms->flags |= IP_MASQ_F_NO_DADDR;
+        
+        /* get masq address from rif */
+        ms->maddr	   = dev->pa_addr;
+
+        for (ports_tried = 0; ports_tried < *free_ports_p; ports_tried++){
+                save_flags(flags);
+                cli();
+                
+		/*
+                 *	Try the next available port number
+                 */
+                
+		ms->mport = htons(masq_port++);
+		if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
+                
+                restore_flags(flags);
+                
+                /*
+                 *	lookup to find out if this port is used.
+                 */
+                
+                mst = ip_masq_getbym(proto, ms->maddr, ms->mport);
+                if (mst == NULL) {
+                        save_flags(flags);
+                        cli();
+                
+                        if (ip_masq_free_ports == 0) {
+                                restore_flags(flags);
+                                break;
+                        }
+                        (*free_ports_p)--;
+                        ip_masq_hash(ms);
+                        
+                        restore_flags(flags);
+                        
+                        ip_masq_bind_app(ms);
+                        n_fails = 0;
+                        return ms;
+                }
+        }
+        
+        if (++n_fails < 5)
+                printk("ip_masq_new(proto=%s): could not get free masq entry (free=%d).\n",
+                       masq_proto_name(ms->protocol), *free_ports_p);
+        kfree_s(ms, sizeof(*ms));
+        return NULL;
+}
+
+/*
+ * 	Set masq expiration (deletion) and adds timer,
+ *	if timeout==0 cancel expiration.
+ *	Warning: it does not check/delete previous timer!
+ */
+
+void ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
+{
+        if (tout) {
+                ms->timer.expires = jiffies+tout;
+                add_timer(&ms->timer);
+        } else {
+                del_timer(&ms->timer);
+        }
+}
+
+static void recalc_check(struct udphdr *uh, __u32 saddr,
+	__u32 daddr, int len)
+{
+	uh->check=0;
+	uh->check=csum_tcpudp_magic(saddr,daddr,len,
+		IPPROTO_UDP, csum_partial((char *)uh,len,0));
+	if(uh->check==0)
+		uh->check=0xFFFF;
+}
+	
+void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
+{
+	struct sk_buff  *skb=*skb_ptr;
+	struct iphdr	*iph = skb->h.iph;
+	__u16	*portptr;
+	struct ip_masq	*ms;
+	int		size;
+        unsigned long 	timeout;
+
+	/*
+	 * We can only masquerade protocols with ports...
+	 */
+
+	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
+		return;
+ 
+	/*
+	 *	Now hunt the list to see if we have an old entry
+	 */
+
+	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+	printk("Outgoing %s %lX:%X -> %lX:%X\n",
+		masq_proto_name(iph->protocol),
+		ntohl(iph->saddr), ntohs(portptr[0]),
+		ntohl(iph->daddr), ntohs(portptr[1]));
+#endif
+        
+        ms = ip_masq_out_get(iph);
+        if (ms!=NULL)
+                ip_masq_set_expire(ms,0);
+
+	/*
+	 *	Nope, not found, create a new entry for it
+	 */
+	 
+	if (ms==NULL) 
+	{
+                ms = ip_masq_new(dev, iph->protocol,
+                                 iph->saddr, portptr[0],
+                                 iph->daddr, portptr[1],
+                                 0);
+                if (ms == NULL)
+			return;
+ 	}
+ 
+ 	/*
+ 	 *	Change the fragments origin
+ 	 */
+ 	 
+ 	size = skb->len - ((unsigned char *)portptr - skb->h.raw);
+        /*
+         *	Set iph addr and port from ip_masq obj.
+         */
+ 	iph->saddr = ms->maddr;
+ 	portptr[0] = ms->mport;
+ 
+ 	/*
+ 	 *	Attempt ip_masq_app call.
+         *	will fix ip_masq and iph seq stuff
+ 	 */
+        if (ip_masq_app_pkt_out(ms, skb_ptr, dev) != 0)
+	{
+                /*
+                 *	skb has possibly changed, update pointers.
+                 */
+                skb = *skb_ptr;
+                iph = skb->h.iph;
+                portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+                size = skb->len - ((unsigned char *)portptr-skb->h.raw);
+        }
+        
+ 	/*
+ 	 *	Adjust packet accordingly to protocol
+ 	 */
+ 	 
+ 	if (iph->protocol==IPPROTO_UDP) 
+ 	{
+                timeout = MASQUERADE_EXPIRE_UDP;
+ 		recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
+ 	}
+ 	else 
+ 	{
+ 		struct tcphdr *th;
+ 		th = (struct tcphdr *)portptr;
+ 
+ 		/*
+ 		 *	Timeout depends if FIN packet was seen
+ 		 */
+ 		if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
+                {
+                        timeout = MASQUERADE_EXPIRE_TCP_FIN;
+ 			ms->flags |= IP_MASQ_F_SAW_FIN;
+ 		}
+ 		else timeout = MASQUERADE_EXPIRE_TCP;
+ 
+		skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
+ 		tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
+ 	}
+        ip_masq_set_expire(ms, timeout);
+ 	ip_send_check(iph);
+ 
+ #ifdef DEBUG_CONFIG_IP_MASQUERADE
+ 	printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name);
+ #endif
+ }
+ 
+ /*
+  *	Check if it's an masqueraded port, look it up,
+  *	and send it on it's way...
+  *
+  *	Better not have many hosts using the designated portrange
+  *	as 'normal' ports, or you'll be spending many time in
+  *	this function.
+  */
+
+int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
+{
+        struct sk_buff 	*skb = *skb_p;
+ 	struct iphdr	*iph = skb->h.iph;
+ 	__u16	*portptr;
+ 	struct ip_masq	*ms;
+ 
+ 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
+ 		return 0;
+ 
+ 	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ 	if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
+ 	    ntohs(portptr[1]) > PORT_MASQ_END)
+ 		return 0;
+ 
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ 	printk("Incoming %s %lX:%X -> %lX:%X\n",
+ 		masq_proto_name(iph->protocol),
+ 		ntohl(iph->saddr), ntohs(portptr[0]),
+ 		ntohl(iph->daddr), ntohs(portptr[1]));
+#endif
+ 	/*
+ 	 * reroute to original host:port if found...
+         */
+        
+        ms = ip_masq_in_get(iph);
+        
+        if (ms != NULL)
+        {
+                int size;
+        
+                /*
+                 *	Set dport if not defined yet.
+                 */
+                
+                if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) {
+                        ms->flags &= ~IP_MASQ_F_NO_DPORT;
+                        ms->dport = portptr[0];
+#if DEBUG_CONFIG_IP_MASQUERADE
+                        printk("ip_fw_demasquerade(): filled dport=%d\n",
+                               ntohs(ms->dport));
+#endif
+                }
+                if (ms->flags & IP_MASQ_F_NO_DADDR && ms->protocol == IPPROTO_TCP)  {
+                        ms->flags &= ~IP_MASQ_F_NO_DADDR;
+                        ms->daddr = iph->saddr;
+#if DEBUG_CONFIG_IP_MASQUERADE
+                        printk("ip_fw_demasquerade(): filled daddr=%X\n",
+                               ntohs(ms->daddr));
+#endif
+                }
+                size = skb->len - ((unsigned char *)portptr - skb->h.raw);
+                iph->daddr = ms->saddr;
+                portptr[1] = ms->sport;
+                
+                /*
+                 *	Attempt ip_masq_app call.
+                 *	will fix ip_masq and iph ack_seq stuff
+                 */
+                
+                if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0)
+                {
+                        /*
+                         *	skb has changed, update pointers.
+                         */
+                        
+                        skb = *skb_p;
+                        iph = skb->h.iph;
+                        portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+                        size = skb->len - ((unsigned char *)portptr-skb->h.raw);
+                }
+                
+                /*
+                 * Yug! adjust UDP/TCP and IP checksums
+                 */
+                if (iph->protocol==IPPROTO_UDP)
+                        recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
+                else
+                {
+                        skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
+                                                 size - sizeof(struct tcphdr), 0);
+                        tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb);
+                }
+                ip_send_check(iph);
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+                printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1]));
+#endif
+                return 1;
+ 	}
+        
+ 	/* sorry, all this trouble for a no-hit :) */
+ 	return 0;
+}
+
+/*
+ *	/proc/net entry
+ */
+
+static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
+			      int length, int unused)
+{
+	off_t pos=0, begin=0;
+	struct ip_masq *ms;
+	unsigned long flags;
+        int idx = 0;
+	int len=0;
+	
+	len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq  Delta PDelta Expires (free=%d,%d)\n",
+                    ip_masq_free_ports[0], ip_masq_free_ports[1]); 
+	save_flags(flags);
+	cli();
+        
+        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+        for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
+	{
+		int timer_active = del_timer(&ms->timer);
+		if (!timer_active)
+			ms->timer.expires = jiffies;
+		len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %6d %6d %lu\n",
+			masq_proto_name(ms->protocol),
+			ntohl(ms->saddr),ntohs(ms->sport),
+			ntohl(ms->daddr),ntohs(ms->dport),
+			ntohs(ms->mport),
+			ms->out_seq.init_seq,ms->out_seq.delta,ms->out_seq.previous_delta,ms->timer.expires-jiffies);
+		if (timer_active)
+			add_timer(&ms->timer);
+
+		pos=begin+len;
+		if(pos<offset) 
+		{
+ 			len=0;
+			begin=pos;
+		}
+		if(pos>offset+length)
+			break;
+        }
+	restore_flags(flags);
+	*start=buffer+(offset-begin);
+	len-=(offset-begin);
+	if(len>length)
+		len=length;
+	return len;
+}
+
+/*
+ *	Initialize ip masquerading
+ */
+int ip_masq_init(void)
+{  
+        register_symtab (&ip_masq_syms);
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IPMSQHST, 13, "ip_masquerade",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_msqhst_procinfo
+	});
+        ip_masq_app_init();
+        
+        return 0;
+}
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c
--- v1.3.80/linux/net/ipv4/ip_masq_app.c	Thu Jan  1 02:00:00 1970
+++ linux/net/ipv4/ip_masq_app.c	Sat Mar 30 13:20:34 1996
@@ -0,0 +1,570 @@
+/*
+ *		IP_MASQ_APP application masquerading module
+ *
+ *
+ * Version:	@(#)ip_masq_app.c  0.03      03/96
+ *
+ * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ *	JJC		: Implemented also input pkt hook
+ *
+ *
+ * FIXME:
+ *	- ip_masq_skb_replace(): use same skb if space available.
+ *	
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <net/ip_masq.h>
+
+static const char *strProt[] = {"UDP","TCP"};
+
+static __inline__ const char * masq_proto_name(unsigned proto)
+{
+        return strProt[proto==IPPROTO_TCP];
+}
+
+#define IP_MASQ_APP_TAB_SIZE  16 /* must be power of 2 */
+
+#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
+#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port )
+#define IP_MASQ_APP_PORT(type)        ( type & 0xffff )
+#define IP_MASQ_APP_PROTO(type)       ( (type>>16) & 0x00ff )
+
+
+static struct symbol_table ip_masq_app_syms = {
+#include <linux/symtab_begin.h>
+	X(register_ip_masq_app),
+	X(unregister_ip_masq_app),
+	X(ip_masq_skb_replace),
+#include <linux/symtab_end.h>
+};
+
+/*
+ * 	will hold masq app. hashed list heads
+ */
+
+struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE];
+
+/*
+ * 	ip_masq_app registration routine
+ *	port: host byte order.
+ */
+
+int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port)
+{
+        unsigned long flags;
+        unsigned hash;
+        if (!mapp) {
+                printk("register_ip_masq_app(): NULL arg\n");
+                return -EINVAL;
+        }
+        mapp->type = IP_MASQ_APP_TYPE(proto, port);
+        mapp->n_attach = 0;
+        hash = IP_MASQ_APP_HASH(proto, port);
+        
+        save_flags(flags);
+        cli();
+        mapp->next = ip_masq_app_base[hash];
+        ip_masq_app_base[hash] = mapp; 
+        restore_flags(flags);
+        
+        return 0;
+}
+
+/*
+ * 	ip_masq_app unreg. routine.
+ */
+
+int unregister_ip_masq_app(struct ip_masq_app *mapp)
+{
+        struct ip_masq_app **mapp_p;
+        unsigned hash;
+        unsigned long flags;
+        if (!mapp) {
+                printk("unregister_ip_masq_app(): NULL arg\n");
+                return -EINVAL;
+        }
+        /*
+         * only allow unregistration if it has no attachments
+         */
+        if (mapp->n_attach)  {
+                printk("unregister_ip_masq_app(): has %d attachments. failed\n",
+                       mapp->n_attach);
+                return -EINVAL;
+        }
+        hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type));
+
+        save_flags(flags);
+        cli();
+        for (mapp_p = &ip_masq_app_base[hash]; *mapp_p ; mapp_p = &(*mapp_p)->next)
+                if (mapp == (*mapp_p))  {
+                        *mapp_p = mapp->next;
+                        restore_flags(flags);
+                        return 0;
+                }
+        
+        restore_flags(flags);
+        printk("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
+               masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
+        return -EINVAL;
+}
+
+/*
+ *	get ip_masq_app object by its proto and port (net byte order).
+ */
+
+struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port)
+{
+        struct ip_masq_app *mapp;
+        unsigned hash;
+        unsigned type;
+
+        port = ntohs(port);
+        type = IP_MASQ_APP_TYPE(proto,port);
+        hash = IP_MASQ_APP_HASH(proto,port);
+        for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) {
+                if (type == mapp->type) return mapp;
+        }
+        return NULL;
+}
+
+/*
+ *	ip_masq_app object binding related funcs.
+ */
+
+/*
+ * 	change ip_masq_app object's number of bindings
+ */
+
+static __inline__ int ip_masq_app_bind_chg(struct ip_masq_app *mapp, int delta)
+{
+        unsigned long flags;
+        int n_at;
+        if (!mapp) return -1;
+        save_flags(flags);
+        cli();
+        n_at = mapp->n_attach + delta;
+        if (n_at < 0) {
+                restore_flags(flags);
+                printk("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
+                       masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
+                       IP_MASQ_APP_PORT(mapp->type));
+                return -1;
+        }
+        mapp->n_attach = n_at;
+        restore_flags(flags);
+        return 0;
+}
+
+/*
+ *	Bind ip_masq to its ip_masq_app based on proto and dport ALREADY
+ *	set in ip_masq struct. Also calls constructor.
+ */
+
+struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
+{
+        struct ip_masq_app * mapp;
+        mapp = ip_masq_app_get(ms->protocol, ms->dport);
+        if (mapp != NULL) {
+                /*
+                 *	don't allow binding if already bound
+                 */
+                
+                if (ms->app != NULL) {
+                        printk("ip_masq_bind_app() called for already bound object.\n");
+                        return ms->app;
+                }
+                
+                ms->app = mapp;
+                if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
+                ip_masq_app_bind_chg(mapp, +1);
+        }
+        return mapp;
+}
+
+/*
+ * 	Unbind ms from type object and call ms destructor (does not kfree()).
+ */
+
+int ip_masq_unbind_app(struct ip_masq *ms)
+{
+        struct ip_masq_app * mapp;
+        mapp = ms->app;
+        if (mapp != NULL) {
+                if (mapp->masq_done_1) mapp->masq_done_1(mapp, ms);
+                ms->app = NULL;
+                ip_masq_app_bind_chg(mapp, -1);
+        }
+        return (mapp != NULL);
+}
+
+/*
+ *	Fixes th->seq based on ip_masq_seq info.
+ */
+
+static __inline__ void masq_fix_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
+{
+        __u32 seq;
+        
+        seq = ntohl(th->seq);
+        
+	/*
+	 * 	Adjust seq with delta-offset for all packets after
+         * 	the most recent resized pkt seq and with previous_delta offset
+         *	for all packets	before most recent resized pkt seq.
+	 */
+
+	if (ms_seq->delta || ms_seq->previous_delta) {
+		if(after(seq,ms_seq->init_seq) ) {
+			th->seq = htonl(seq + ms_seq->delta);
+#if DEBUG_CONFIG_IP_MASQ_APP
+			printk("masq_fix_seq() : added delta (%d) to seq\n",ms_seq->delta);
+#endif
+		} else {
+			th->seq = htonl(seq + ms_seq->previous_delta);
+#if DEBUG_CONFIG_IP_MASQ_APP
+	 		printk("masq_fix_seq() : added previous_delta (%d) to seq\n",ms_seq->previous_delta);
+#endif
+		}
+	}
+        
+
+}
+
+/*
+ *	Fixes th->ack_seq based on ip_masq_seq info.
+ */
+
+static __inline__ void masq_fix_ack_seq(const struct ip_masq_seq *ms_seq, struct tcphdr *th)
+{
+        __u32 ack_seq;
+        
+        ack_seq=ntohl(th->ack_seq);
+        
+        /*
+         * Adjust ack_seq with delta-offset for
+         * the packets AFTER most recent resized pkt has caused a shift
+         * for packets before most recent resized pkt, use previous_delta
+         */
+        
+        if (ms_seq->delta || ms_seq->previous_delta) {
+                if(after(ack_seq,ms_seq->init_seq)) {
+                        th->ack_seq = htonl(ack_seq-ms_seq->delta);
+#if DEBUG_CONFIG_IP_MASQ_APP
+                        printk("masq_fix_ack_seq() : substracted delta (%d) from ack_seq\n",ms_seq->delta);
+#endif
+                } else {
+                        th->ack_seq = htonl(ack_seq-ms_seq->previous_delta);
+#if DEBUG_CONFIG_IP_MASQ_APP
+                        printk("masq_fix_ack_seq() : substracted previous_delta (%d) from ack_seq\n",ms_seq->previous_delta);
+#endif
+                }
+        }
+        
+}
+
+/*
+ *	Updates ip_masq_seq if pkt has been resized
+ *	Assumes already checked proto==IPPROTO_TCP and diff!=0.
+ */
+
+static __inline__ void masq_seq_update(struct ip_masq *ms, struct ip_masq_seq *ms_seq, unsigned mflag, __u32 seq, int diff)
+{
+        /* if (diff == 0) return; */
+        
+        if ( !(ms->flags & mflag) || after(seq, ms_seq->init_seq))
+        {
+                ms_seq->previous_delta=ms_seq->delta;
+                ms_seq->delta+=diff;
+                ms_seq->init_seq=seq;
+                ms->flags |= mflag;
+        }
+}
+
+/*
+ *	Output pkt hook. Will call bound ip_masq_app specific function
+ *	called by ip_fw_masquerade(), assumes previously checked ms!=NULL
+ *	returns (new - old) skb->len diff.
+ */
+
+int ip_masq_app_pkt_out(struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+        struct ip_masq_app * mapp;
+        struct iphdr *iph;
+	struct tcphdr *th;
+        int diff;
+        __u32 seq;
+        
+        /*
+         *	check if application masquerading is bound to
+         *	this ip_masq.
+         *	assumes that once an ip_masq is bound,
+         *	it will not be unbound during its life.
+         */
+        
+        if ( (mapp = ms->app) == NULL)
+                return 0;
+        
+        iph = (*skb_p)->h.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        
+        /*
+         *	Remember seq number in case this pkt gets resized
+         */
+        
+        seq = ntohl(th->seq);
+        
+        /*
+         *	Fix seq stuff if flagged as so.
+         */
+        
+        if (ms->protocol == IPPROTO_TCP) {
+                if (ms->flags & IP_MASQ_F_OUT_SEQ)
+                        masq_fix_seq(&ms->out_seq, th);
+                if (ms->flags & IP_MASQ_F_IN_SEQ)
+                        masq_fix_ack_seq(&ms->in_seq, th);
+        }
+        
+        /*
+         *	Call private output hook function 
+         */
+        
+        if ( mapp->pkt_out == NULL )
+                return 0;
+        
+        diff = mapp->pkt_out(mapp, ms, skb_p, dev);
+        
+        /*
+         *	Update ip_masq seq stuff if len has changed.
+         */
+        
+        if (diff != 0 && ms->protocol == IPPROTO_TCP)
+                masq_seq_update(ms, &ms->out_seq, IP_MASQ_F_OUT_SEQ, seq, diff);
+
+        return diff;
+}
+
+/*
+ *	Input pkt hook. Will call bound ip_masq_app specific function
+ *	called by ip_fw_demasquerade(), assumes previously checked ms!=NULL.
+ *	returns (new - old) skb->len diff.
+ */
+
+int ip_masq_app_pkt_in(struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+        struct ip_masq_app * mapp;
+        struct iphdr *iph;
+	struct tcphdr *th;
+        int diff;
+        __u32 seq;
+        
+        /*
+         *	check if application masquerading is bound to
+         *	this ip_masq.
+         *	assumes that once an ip_masq is bound,
+         *	it will not be unbound during its life.
+         */
+        
+        if ( (mapp = ms->app) == NULL)
+                return 0;
+        
+        iph = (*skb_p)->h.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        
+        /*
+         *	Remember seq number in case this pkt gets resized
+         */
+        
+        seq = ntohl(th->seq);
+        
+        /*
+         *	Fix seq stuff if flagged as so.
+         */
+        
+        if (ms->protocol == IPPROTO_TCP) {
+                if (ms->flags & IP_MASQ_F_IN_SEQ)
+                        masq_fix_seq(&ms->in_seq, th);
+                if (ms->flags & IP_MASQ_F_OUT_SEQ)
+                        masq_fix_ack_seq(&ms->out_seq, th);
+        }
+        
+        /*
+         *	Call private input hook function 
+         */
+        
+        if ( mapp->pkt_in == NULL )
+                return 0;
+        
+        diff = mapp->pkt_in(mapp, ms, skb_p, dev);
+
+        /*
+         *	Update ip_masq seq stuff if len has changed.
+         */
+        
+        if (diff != 0 && ms->protocol == IPPROTO_TCP)
+                masq_seq_update(ms, &ms->in_seq, IP_MASQ_F_IN_SEQ, seq, diff);
+
+        return diff;
+}
+
+/*
+ *	/proc/ip_masq_app entry function
+ */
+
+int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+        off_t pos=0, begin=0;
+        int len=0;
+        struct ip_masq_app * mapp;
+        unsigned idx;
+        len=sprintf(buffer,"prot port    n_attach\n");
+        for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
+                for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
+                        len += sprintf(buffer+len, "%s  %-7u %-7d\n",
+                                       masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
+                                       IP_MASQ_APP_PORT(mapp->type), mapp->n_attach);
+                        pos=begin+len;
+                        if(pos<offset) {
+                                len=0;
+                                begin=pos;
+                        }
+                        if(pos>offset+length)
+                                break;
+                }
+        *start=buffer+(offset-begin);
+        len-=(offset-begin);
+        if(len>length)
+                len=length;	
+        return len;
+}
+
+
+/*
+ *	Initialization routine
+ */
+
+int ip_masq_app_init(void)
+{
+        
+        register_symtab (&ip_masq_app_syms);
+        
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_IP_MASQ_APP, 11, "ip_masq_app",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations,
+		ip_masq_app_getinfo
+ 	});
+        
+        return 0;
+}
+
+/*
+ *	Replace a segment (of skb->data) with a new one.
+ *	FIXME: Should re-use same skb if space available, this could
+ *	       be done if n_len < o_len, unless some extra space
+ *	       were already allocated at driver level :P .
+ */
+
+static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
+{
+        int diff, o_offset;
+        struct sk_buff *n_skb;
+
+        diff = n_len - o_len;
+        o_offset = o_buf - (char*) skb->data;
+
+        if (diff != 0)  {
+                
+                /*
+                 * 	Sizes differ, make a copy
+                 */
+        
+                n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri);
+                if (n_skb == NULL) {
+                        printk("skb_replace(): no room left (from %p)\n",
+                               __builtin_return_address(0));
+                        return skb;
+
+                }
+                n_skb->free = skb->free;
+                skb_reserve(n_skb, MAX_HEADER);
+                skb_put(n_skb, skb->len + diff);
+                n_skb->h.raw = n_skb->data + (skb->h.raw - skb->data);
+                
+                /*
+                 * Copy pkt in new buffer
+                 */
+                
+                memcpy(n_skb->data, skb->data, o_offset);
+                memcpy(n_skb->data + o_offset, n_buf, n_len);
+                memcpy(n_skb->data + o_offset + n_len, o_buf + o_len,
+                       skb->len - (o_offset + o_len) );
+                
+                /*
+                 * Problem, how to replace the new skb with old one,
+                 * preferably inplace
+                 */
+                
+                kfree_skb(skb, FREE_WRITE);
+                
+        } else {
+                
+                /*
+                 *	Same len, just copy
+                 */
+                n_skb = skb;
+                memcpy(n_skb->data + o_offset, n_buf, n_len);
+        }
+        return n_skb;
+}
+
+/*
+ *	calls skb_replace() and update ip header if new skb was allocated
+ */
+
+struct sk_buff * ip_masq_skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
+{
+        int diff;
+        struct sk_buff *n_skb;
+        unsigned skb_len;
+
+        diff = n_len - o_len;
+        n_skb = skb_replace(skb, pri, o_buf, o_len, n_buf, n_len);
+        skb_len = skb->len;
+                
+        if (diff)
+        {
+                struct iphdr *iph;
+#if DEBUG_CONFIG_IP_MASQ_APP
+                printk("masq_skb_replace(): pkt resized for %d bytes (len=%ld)\n", diff, skb->len);
+#endif
+                /*
+                 * 	update ip header
+                 */
+                iph = n_skb->h.iph;
+                iph->check = 0;
+                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+                iph->tot_len = htons(skb_len + diff);
+        }
+        return n_skb;
+}
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq_ftp.c linux/net/ipv4/ip_masq_ftp.c
--- v1.3.80/linux/net/ipv4/ip_masq_ftp.c	Thu Jan  1 02:00:00 1970
+++ linux/net/ipv4/ip_masq_ftp.c	Sat Mar 30 13:20:34 1996
@@ -0,0 +1,198 @@
+/*
+ *		IP_MASQ_FTP ftp masquerading module
+ *
+ *
+ * Version:	@(#)ip_masq_ftp.c 0.01   02/05/96
+ *
+ * Author:	Wouter Gadeyne
+ *		
+ *
+ * Fixes:
+ *	Wouter Gadeyne		:	Fixed masquerading support of ftp PORT commands
+ * 	Juan Jose Ciarlante	:	Code moved and adapted from ip_fw.c
+ *	
+ *
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *	
+ */
+
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+#define DEBUG_CONFIG_IP_MASQ_FTP 0
+
+static int
+masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static int
+masq_ftp_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+int
+masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+        struct sk_buff *skb;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *p, *data, *data_limit;
+	unsigned char p1,p2,p3,p4,p5,p6;
+	__u32 from;
+	__u16 port;
+	struct ip_masq *n_ms;
+	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
+        unsigned buf_len;
+	int diff;
+
+        skb = *skb_p;
+	iph = skb->h.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        data = (char *)&th[1];
+        
+        data_limit = skb->h.raw + skb->len - 18;
+
+	while (data < data_limit)
+	{
+		if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5)) 
+		{
+			data ++;
+			continue;
+		}
+		p = data+5;
+ 		p1 = simple_strtoul(data+5,&data,10);
+		if (*data!=',')
+			continue;
+		p2 = simple_strtoul(data+1,&data,10);
+		if (*data!=',')
+			continue;
+		p3 = simple_strtoul(data+1,&data,10);
+		if (*data!=',')
+			continue;
+		p4 = simple_strtoul(data+1,&data,10);
+		if (*data!=',')
+			continue;
+		p5 = simple_strtoul(data+1,&data,10);
+		if (*data!=',')
+			continue;
+		p6 = simple_strtoul(data+1,&data,10);
+		if (*data!='\r' && *data!='\n')
+			continue;
+
+		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
+		port = (p5<<8) | p6;
+#if DEBUG_CONFIG_IP_MASQ_FTP
+		printk("PORT %lX:%X detected\n",from,port);
+#endif	
+		/*
+		 * Now create an masquerade entry for it
+		 */
+                n_ms = ip_masq_new(dev, IPPROTO_TCP,
+                                   htonl(from), htons(port),
+                                   iph->daddr, 0,
+                                   IP_MASQ_F_NO_DPORT);
+                                   
+		if (n_ms==NULL)
+			return 0;
+
+                ip_masq_set_expire(n_ms, MASQUERADE_EXPIRE_TCP_FIN);
+                
+		/*
+		 * Replace the old PORT with the new one
+		 */
+		from = ntohl(n_ms->maddr);
+		port = ntohs(n_ms->mport);
+		sprintf(buf,"%d,%d,%d,%d,%d,%d",
+			from>>24&255,from>>16&255,from>>8&255,from&255,
+			port>>8&255,port&255);
+		buf_len = strlen(buf);
+ 
+		/*
+		 * Calculate required delta-offset to keep TCP happy
+		 */
+		
+		diff = buf_len - (data-p);
+		
+		/*
+		 *	No shift.
+		 */
+		 
+		if (diff==0) 
+		{
+			/*
+			 * simple case, just replace the old PORT cmd
+ 			 */
+ 			memcpy(p,buf,buf_len);
+ 			return 0;
+ 		}
+
+                *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
+                return diff;
+
+	}
+	return 0;
+
+}
+
+struct ip_masq_app ip_masq_ftp = {
+        NULL,			/* next */
+        0,                      /* type */
+        0,                      /* n_attach */
+        masq_ftp_init_1,        /* ip_masq_init_1 */
+        masq_ftp_done_1,        /* ip_masq_done_1 */
+        masq_ftp_out,           /* pkt_out */
+        NULL                    /* pkt_in */
+};
+
+/*
+ * 	ip_masq_ftp initialization
+ */
+
+int ip_masq_ftp_init(void)
+{
+        return register_ip_masq_app(&ip_masq_ftp, IPPROTO_TCP, 21);
+}
+
+/*
+ * 	ip_masq_ftp fin.
+ */
+
+int ip_masq_ftp_done(void)
+{
+        return unregister_ip_masq_app(&ip_masq_ftp);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+        if (ip_masq_ftp_init() != 0)
+                return -EIO;
+        register_symtab(0);
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        if (ip_masq_ftp_done() != 0)
+                printk("ip_masq_ftp: can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_masq_irc.c linux/net/ipv4/ip_masq_irc.c
--- v1.3.80/linux/net/ipv4/ip_masq_irc.c	Thu Jan  1 02:00:00 1970
+++ linux/net/ipv4/ip_masq_irc.c	Sat Mar 30 13:20:34 1996
@@ -0,0 +1,269 @@
+/*
+ *		IP_MASQ_IRC irc masquerading module
+ *
+ *
+ * Version:	@(#)ip_masq_irc.c 0.01   03/20/96
+ *
+ * Author:	Juan Jose Ciarlante
+ *		
+ *
+ * Fixes:
+ *	- set NO_DADDR flag in ip_masq_new().
+ *
+ * FIXME:
+ *	- detect also previous "PRIVMSG" string ?.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *	
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+#define DEBUG_CONFIG_IP_MASQ_IRC 0
+
+static int
+masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_INC_USE_COUNT;
+        return 0;
+}
+
+static int
+masq_irc_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_DEC_USE_COUNT;
+        return 0;
+}
+
+int
+masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+        struct sk_buff *skb;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	__u32 s_addr;
+	__u16 s_port;
+	struct ip_masq *n_ms;
+	char buf[20];		/* "m_addr m_port" (dec base)*/
+        unsigned buf_len;
+	int diff;
+        int xtra_args = 0;      /* extra int args wanted after addr */
+        char *dcc_p, *addr_beg_p, *addr_end_p;
+
+        skb = *skb_p;
+	iph = skb->h.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        data = (char *)&th[1];
+
+        /*
+         *	Hunt irc DCC string, the _shortest_:
+         *
+         *	strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
+         *	strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
+         *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
+         *		P:         bound port (min 1 d )
+         *		F:         filename   (min 1 d )
+         *		S:         size       (min 1 d ) 
+         *		0x01, \n:  terminators
+         */
+
+        data_limit = skb->h.raw + skb->len;
+        
+	while (data < (data_limit - 25) )
+	{
+		if (memcmp(data,"DCC ",4))  {
+			data ++;
+			continue;
+		}
+                
+                dcc_p = data;
+		data += 4;     /* point to DCC cmd */
+                
+                if (memcmp(data, "CHAT ", 5) == 0 ||
+                    memcmp(data, "SEND ", 5) == 0)
+                {
+                        /*
+                         *	extra arg (file_size) req. for "SEND"
+                         */
+                        
+                        if (*data == 'S') xtra_args++;
+                        data += 5;
+                }
+                else
+                        continue;
+
+                /*
+                 *	skip next string.
+                 */
+                
+                while( *data++ != ' ')
+                        
+                        /*
+                         *	must still parse, at least, "AAAAAAAA P\x01\n",
+                         *      12 bytes left.
+                         */
+                        if (data > (data_limit-12)) return 0;
+
+                
+                addr_beg_p = data;
+                
+                /*
+                 *	client bound address in dec base
+                 */
+                
+ 		s_addr = simple_strtoul(data,&data,10);
+		if (*data++ !=' ')
+			continue;
+
+                /*
+                 *	client bound port in dec base
+                 */
+                
+		s_port = simple_strtoul(data,&data,10);
+                addr_end_p = data;
+                
+                /*
+                 *	should check args consistency?
+                 */
+                
+                while(xtra_args) {
+                        if (*data != ' ')
+                                break;
+                        data++;
+                        simple_strtoul(data,&data,10);
+                        xtra_args--;
+                }
+                
+                if (xtra_args != 0) continue;
+                
+                /*
+                 *	terminators.
+                 */
+                
+                if (data[0] != 0x01)
+                        continue;
+		if (data[1]!='\r' && data[1]!='\n')
+			continue;
+                
+		/*
+		 *	Now create an masquerade entry for it
+                 * 	must set NO_DPORT and NO_DADDR because
+                 *	connection is requested by another client.
+		 */
+                
+		n_ms = ip_masq_new(dev, IPPROTO_TCP,
+                                   htonl(s_addr),htons(s_port),
+                                   0, 0,
+                                   IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR
+                                   );
+		if (n_ms==NULL)
+			return 0;
+
+                ip_masq_set_expire(n_ms, MASQUERADE_EXPIRE_TCP_FIN);
+                
+		/*
+		 * Replace the old "address port" with the new one
+		 */
+                
+		buf_len = sprintf(buf,"%lu %u",
+                        ntohl(n_ms->maddr),ntohs(n_ms->mport));
+                
+		/*
+		 * Calculate required delta-offset to keep TCP happy
+		 */
+		
+		diff = buf_len - (addr_end_p-addr_beg_p);
+
+#if DEBUG_CONFIG_IP_MASQ_IRC
+                *addr_beg_p = '\0';
+		printk("masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
+#endif	
+		/*
+		 *	No shift.
+		 */
+		 
+		if (diff==0) 
+		{
+			/*
+			 * simple case, just copy.
+ 			 */
+ 			memcpy(addr_beg_p,buf,buf_len);
+ 			return 0;
+ 		}
+
+                *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+                                             addr_beg_p, addr_end_p-addr_beg_p,
+                                             buf, buf_len);
+                return diff;
+	}
+	return 0;
+
+}
+
+/*
+ *	Main irc object
+ *     	You need 1 object per port in case you need
+ *	to offer also other used irc ports (6665,6666,etc),
+ *	they will share methods but they need own space for
+ *	data. 
+ */
+
+struct ip_masq_app ip_masq_irc = {
+        NULL,			/* next */
+        0,                      /* type */
+        0,                      /* n_attach */
+        masq_irc_init_1,        /* init_1 */
+        masq_irc_done_1,        /* done_1 */
+        masq_irc_out,           /* pkt_out */
+        NULL                    /* pkt_in */
+};
+
+/*
+ * 	ip_masq_irc initialization
+ */
+
+int ip_masq_irc_init(void)
+{
+        return register_ip_masq_app(&ip_masq_irc, IPPROTO_TCP, 6667);
+}
+
+/*
+ * 	ip_masq_irc fin.
+ */
+
+int ip_masq_irc_done(void)
+{
+        return unregister_ip_masq_app(&ip_masq_irc);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+        if (ip_masq_irc_init() != 0)
+                return -EIO;
+        register_symtab(NULL);
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        if (ip_masq_irc_done() != 0)
+                printk("ip_masq_irc: can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v1.3.80/linux/net/ipv4/ip_output.c	Sun Mar 10 09:28:57 1996
+++ linux/net/ipv4/ip_output.c	Sat Mar 30 13:20:34 1996
@@ -239,7 +239,7 @@
 	if ((LOOPBACK(saddr) && !LOOPBACK(daddr)) || !saddr)
 		saddr = rt ? rt->rt_src : (*dev)->pa_addr;
 
-	raddr = rt ? rt->rt_gateway : 0;
+	raddr = rt ? rt->rt_gateway : daddr;
 
 	if (opt && opt->is_strictroute && rt && (rt->rt_flags & RTF_GATEWAY))
 	{
@@ -247,13 +247,6 @@
 		ip_statistics.IpOutNoRoutes++;
 		return -ENETUNREACH;
 	}
-
-	/*
-	 *	No gateway so aim at the real destination
-	 */
-
-	if (raddr == 0)
-		raddr = daddr;
 
 	/*
 	 *	Now build the MAC header.
diff -u --recursive --new-file v1.3.80/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v1.3.80/linux/net/ipv4/route.c	Sat Mar 16 13:52:12 1996
+++ linux/net/ipv4/route.c	Sat Mar 30 13:20:34 1996
@@ -41,6 +41,7 @@
  *		Olaf Erb	:	irtt wasnt being copied right.
  *		Bjorn Ekwall	:	Kerneld route support.
  *		Alan Cox	:	Multicast fixed (I hope)
+ * 		Pavel Krauz	:	Limited broadcast fixed
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -1558,9 +1559,9 @@
 	if (!(rth->rt_flags & RTF_GATEWAY))
 		rth->rt_gateway = rth->rt_dst;
 	/*
-	 *	Multicast is never gatewayed.
+	 *	Multicast or limited broadcast is never gatewayed.
 	 */
-	if (MULTICAST(daddr))
+	if (MULTICAST(daddr) || daddr == 0xFFFFFFFF)
 		rth->rt_gateway = rth->rt_dst;
 
 	if (ip_rt_lock == 1)
diff -u --recursive --new-file v1.3.80/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v1.3.80/linux/net/ipx/af_ipx.c	Mon Mar 25 08:58:25 1996
+++ linux/net/ipx/af_ipx.c	Sat Mar 30 13:20:34 1996
@@ -74,6 +74,7 @@
 #include <linux/termios.h>	/* For TIOCOUTQ/INQ */
 #include <linux/interrupt.h>
 #include <net/p8022.h>
+#include <net/p8022tr.h>
 #include <net/psnap.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
@@ -90,6 +91,7 @@
 
 /* Global Variables */
 static struct datalink_proto	*p8022_datalink = NULL;
+static struct datalink_proto	*p8022tr_datalink = NULL;
 static struct datalink_proto	*pEII_datalink = NULL;
 static struct datalink_proto	*p8023_datalink = NULL;
 static struct datalink_proto	*pSNAP_datalink = NULL;
@@ -840,6 +842,7 @@
 	switch (type) {
 	case IPX_FRAME_ETHERII: return htons(ETH_P_IPX);
 	case IPX_FRAME_8022: return htons(ETH_P_802_2);
+	case IPX_FRAME_TR_8022: return htons(ETH_P_TR_802_2);
 	case IPX_FRAME_SNAP: return htons(ETH_P_SNAP);
 	case IPX_FRAME_8023: return htons(ETH_P_802_3);
 	}
@@ -869,6 +872,10 @@
 		dlink_type = htons(ETH_P_IPX);
 		datalink = pEII_datalink;
 		break;
+	case IPX_FRAME_TR_8022:
+		dlink_type = htons(ETH_P_TR_802_2);
+		datalink = p8022tr_datalink;
+		break;
 	case IPX_FRAME_8022:
 		dlink_type = htons(ETH_P_802_2);
 		datalink = p8022_datalink;
@@ -969,6 +976,7 @@
 	switch (htons(dlink_type)) {
 	case ETH_P_IPX: datalink = pEII_datalink; break;
 	case ETH_P_802_2: datalink = p8022_datalink; break;
+	case ETH_P_TR_802_2: datalink = p8022tr_datalink; break;
 	case ETH_P_SNAP: datalink = pSNAP_datalink; break;
 	case ETH_P_802_3: datalink = p8023_datalink; break;
 	default: return NULL;
@@ -1318,6 +1326,7 @@
 	case ETH_P_802_2: return "802.2";
 	case ETH_P_SNAP: return "SNAP";
 	case ETH_P_802_3: return "802.3";
+	case ETH_P_TR_802_2: return "802.2TR";
 	default: return "None";
 	}
 }
@@ -2257,6 +2266,9 @@
 	if ((p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv)) == NULL)
 		printk("IPX: Unable to register with 802.2\n");
 
+	if ((p8022tr_datalink = register_8022tr_client(ipx_8022_type, ipx_rcv)) == NULL)
+		printk("IPX: Unable to register with 802.2TR\n");
+ 
 	if ((pSNAP_datalink = register_snap_client(ipx_snap_id, ipx_rcv)) == NULL)
 		printk("IPX: Unable to register with SNAP\n");
 	
diff -u --recursive --new-file v1.3.80/linux/net/netsyms.c linux/net/netsyms.c
--- v1.3.80/linux/net/netsyms.c	Thu Mar 28 17:34:35 1996
+++ linux/net/netsyms.c	Sat Mar 30 13:20:34 1996
@@ -56,11 +56,11 @@
 static struct symbol_table net_syms = {
 #include <linux/symtab_begin.h>
 
-        /* Socket layer registration */
-        X(sock_register),
-        X(sock_unregister),
+	/* Socket layer registration */
+	X(sock_register),
+	X(sock_unregister),
 
-        /* Socket layer support routines */
+	/* Socket layer support routines */
 	X(memcpy_fromiovec),
 	X(sock_setsockopt),
 	X(sock_getsockopt),
@@ -116,8 +116,8 @@
 #endif
 
 #ifdef CONFIG_TR
-        X(tr_setup),
-        X(tr_type_trans),
+	X(tr_setup),
+	X(tr_type_trans),
 #endif
                           
 #ifdef CONFIG_NET_ALIAS
diff -u --recursive --new-file v1.3.80/linux/net/protocols.c linux/net/protocols.c
--- v1.3.80/linux/net/protocols.c	Mon Mar 25 08:58:28 1996
+++ linux/net/protocols.c	Sat Mar 30 13:20:34 1996
@@ -21,6 +21,7 @@
 #if defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE)
 #include <net/ipxcall.h>
 #include <net/p8022call.h>
+#include <net/p8022trcall.h>
 #endif
 #ifdef CONFIG_AX25
 #include <net/ax25call.h>
@@ -31,6 +32,7 @@
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
 #if ! ( defined(CONFIG_IPX) || defined(CONFIG_IPX_MODULE) )
 #include <net/p8022call.h>
+#include <net/p8022trcall.h>
 #endif
 #include <net/atalkcall.h>
 #endif
@@ -51,6 +53,7 @@
 #if defined(CONFIG_IPX)   || defined(CONFIG_IPX_MODULE) || \
     defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
   { "802.2",	p8022_proto_init },			/* 802.2 demultiplexor		*/
+  { "802.2TR",	p8022tr_proto_init },			/* 802.2 demultiplexor		*/
   { "SNAP",	snap_proto_init },			/* SNAP demultiplexor		*/
 #endif
 #ifdef CONFIG_TR
diff -u --recursive --new-file v1.3.80/linux/net/socket.c linux/net/socket.c
--- v1.3.80/linux/net/socket.c	Mon Mar 25 08:58:28 1996
+++ linux/net/socket.c	Sat Mar 30 13:44:15 1996
@@ -65,7 +65,10 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/firewall.h>
+
+#ifdef CONFIG_KERNELD
 #include <linux/kerneld.h>
+#endif
 
 #include <net/netlink.h>
 
@@ -1027,7 +1030,7 @@
 	  	return err;
   
   	msg.msg_accrights=NULL;
-  	msg.msg_iovlen=0;
+  	msg.msg_iovlen=1;
   	msg.msg_iov=&iov;
   	iov.iov_len=size;
   	iov.iov_base=ubuf;
