diff -u --recursive --new-file v2.1.13/linux/CREDITS linux/CREDITS
--- v2.1.13/linux/CREDITS	Fri Nov 22 18:28:12 1996
+++ linux/CREDITS	Fri Nov 29 12:10:11 1996
@@ -108,8 +108,8 @@
 N: Randolph Bentson
 E: bentson@grieg.seaslug.org
 D: author of driver for Cyclades Cyclom-Y async mux
-S: 2500 Gilman Dr W, #404
-S: Seattle, Washington 98119-2102
+S: 2322 37th Ave SW
+S: Seattle, Washington 98126-2010
 S: USA
 
 N: Stephen R. van den Berg (AKA BuGless)
@@ -956,7 +956,7 @@
 S: USA
 
 N: Rick Miller
-E: rdmiller@execpc.com
+E: rick@digalogsys.com
 D: Original Linux Device Registrar (Major/minor numbers), au-play, bwBASIC
 S: S78 W16203 Woods Road
 S: Muskego, Wisconsin 53150
diff -u --recursive --new-file v2.1.13/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.13/linux/Documentation/Changes	Fri Nov 15 23:49:05 1996
+++ linux/Documentation/Changes	Fri Nov 29 12:12:08 1996
@@ -19,7 +19,7 @@
 generated by texinfo so a diff is useless anyway (though I can
 incorporate one by hand if you insist upon sending it that way ;-).
 
-Last updated: November 13, 1996.
+Last updated: November 20, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
@@ -28,14 +28,14 @@
    Upgrade to at *least* these software revisions before thinking you've
 encountered a bug!
 
-- Kernel modules	 2.0.0
+- Kernel modules	 2.0.8
 - Gnu C 		 2.7.2.1
 - Binutils		 2.7.0.3
 - Linux C Library	 5.4.12
+- Dynamic Linker (ld.so) 1.8.5
 - Linux C++ Library	 2.7.2.1
 - Procps		 1.01
 - SysVinit		 2.64
-- Util-linux		 2.5
 - Mount                  2.5p
 - Net-tools              1.32-alpha
 - Kbd                    0.91
@@ -65,6 +65,24 @@
 example) and since 5.4.7 is missing a few needed symbols, try to get
 the latest 5.4.x you can.  Currently, that is libc-5.4.12.
 
+   If you upgrade to libc-5.4.x, you also have to upgrade your dynamic
+linker (ld.so) to at least 1.8.3, or all sorts of weirdness will happen.
+
+Modules
+=======
+
+   You need to upgrade to modules-2.0.8 for kernels 2.1.8 and later.
+Currently, there is no modules package which works with kernel 2.1.1.
+
+Gnu C
+=====
+
+   You need at least GCC 2.7.2 to compile the kernel.  If you're
+upgrading from an earlier release, you might as well get GCC 2.7.2.1,
+the latest public release.  If you already have GCC 2.7.2 on your
+system, you don't have to upgrade just so the kernel will work (though
+feel free to upgrade if you want the gcc bug fixes).
+
 How to know the version of the installed programs
 *************************************************
 
@@ -121,12 +139,12 @@
 Dynamic Linker
 ==============
 
-ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.7.14.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.8.5.tar.gz
 
 Modules utilities
 =================
 
-ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/kernel/v2.1/modules-2.0.8.tar.gz
 
 Procps utilities
 ================
@@ -138,11 +156,6 @@
 
 ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz
 
-Util-linux
-==========
-
-ftp://sunsite.unc.edu/pub/Linux/system/Misc/util-linux-2.5.tar.gz
-
 Other Info
 ==========
 
@@ -154,8 +167,8 @@
 distribution), most of these are available in RPM format.  Check around
 your favorite Red Hat mirror site before installing the non-RPM
 version.  Remember, you might need to use the -force option to get the
-upgrade to install.  Almost everything you need is available in
-ftp://ftp.redhat.com/pub/contrib/
+upgrade to install.  ftp://ftp.redhat.com/pub/contrib/ will have almost
+everything you need.
 
    For others, David Bourgin has put together a package of everything
 necessary to quickly and easily upgrade to 2.1.x.  See
diff -u --recursive --new-file v2.1.13/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.13/linux/Documentation/Configure.help	Fri Nov 22 18:28:12 1996
+++ linux/Documentation/Configure.help	Sun Dec  1 18:21:32 1996
@@ -1664,10 +1664,10 @@
 EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
 CONFIG_SCSI_EATA
   This driver supports all the EATA/DMA-compliant SCSI host adapters
-  and does not need any BIOS32 or PCI BIOS service.
-  Only ISA (0x1F0, 0x170, 0x230, 0x330) and EISA (0x1C88 through 0xFC88)
-  addresses are probed. In order to detect a generic EATA PCI board you
-  can force on it any unused EISA address.
+  and does not need any BIOS32 service.
+  DPT ISA and all EISA i/o addresses are probed looking for the "EATA"
+  signature. If "PCI bios support" is enabled, the addresses of all the
+  PCI SCSI controllers reported by BIOS32 are probed as well.
   Note that there is also another driver for the same hardware:
   "EATA-DMA support". You should enable only one of them.
   You want to read the start of drivers/scsi/eata.c and the
@@ -3156,15 +3156,12 @@
   removed from the running kernel whenever you want), say M here and
   read Documentation/modules.txt. Most people say N, however.
 
-SMB long filename support (EXPERIMENTAL)
-CONFIG_SMB_LONG
-  SMBFS was designed to support long filenames using the LanManager
-  2.0 protocol. I had to find out that the support for long filenames
-  sometimes causes problems, which can even result in kernel OOPSes. I
-  did not yet find out what the problem is, but hopefully I will find
-  this bug eventually. As many people seem to run long filenames with
-  no problems, I leave this support in the kernel as an option. The
-  careful among you should say N here.
+SMB Win95 bug work-around
+CONFIG_SMB_WIN95
+  If you want to connect to a share exported by Windows 95, you should
+  say Y here. The Windows 95 server contains a bug that makes listing
+  directories unreliable. This option slows down the listing of
+  directories. This makes the Windows 95 server a bit more stable.
 
 NCP filesystem support (to mount NetWare volumes)
 CONFIG_NCP_FS
diff -u --recursive --new-file v2.1.13/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.1.13/linux/Documentation/devices.tex	Fri Nov 15 23:49:06 1996
+++ linux/Documentation/devices.tex	Fri Nov 29 12:09:08 1996
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: November 13, 1996}
+\date{Last revised: November 18, 1996}
 \maketitle
 %
 \noindent
@@ -183,7 +183,7 @@
 \major{56}{}{char }{Apple Desktop Bus}
 \major{57}{}{char }{Hayes ESP serial card}
 \major{58}{}{char }{Hayes ESP serial card -- alternate devices}
-\major{59}{}{}{Unallocated}
+\major{59}{}{char }{sf firewall package}
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
@@ -1149,7 +1149,8 @@
 \end{devicelist}
 
 \begin{devicelist}
-\major{59}{}{}{Unallocated}
+\major{59}{}{char }{sf firewall package}
+	\minor{0}{/dev/firewall}{Communication with sf kernel module}
 \end{devicelist}
 
 \begin{devicelist}
diff -u --recursive --new-file v2.1.13/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.1.13/linux/Documentation/devices.txt	Fri Nov 15 23:49:06 1996
+++ linux/Documentation/devices.txt	Fri Nov 29 12:09:08 1996
@@ -2,7 +2,7 @@
 
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		   Last revised: November 13, 1996
+		   Last revised: November 18, 1996
 
 This list is the successor to Rick Miller's Linux Device List, which
 he stopped maintaining when he got busy with other things in 1993.  It
@@ -805,7 +805,8 @@
 		  1 = /dev/cup1		Callout device corresponding to ttyP1
 		      ...
 
- 59		UNALLOCATED
+ 59 char	sf firewall package
+		  0 = /dev/firewall	Communication with sf kernel module
 
  60-63		LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
diff -u --recursive --new-file v2.1.13/linux/Documentation/networking/arcnet.txt linux/Documentation/networking/arcnet.txt
--- v2.1.13/linux/Documentation/networking/arcnet.txt	Tue Sep 10 09:08:32 1996
+++ linux/Documentation/networking/arcnet.txt	Sun Dec  1 09:47:41 1996
@@ -55,10 +55,10 @@
 Where do I discuss these drivers?
 ---------------------------------
 
-Tomasz Motylewski has been so kind as to set up a new and improved
-mailing list.  Subscribe by sending a message with the BODY "subscribe
-linux-arcnet YOUR REAL NAME" to listserv@tichy.ch.uj.edu.pl.  Then, to
-submit messages to the list, mail to linux-arcnet@tichy.ch.uj.edu.pl.
+Tomasz has been so kind as to set up a new and improved mailing list. 
+Subscribe by sending a message with the BODY "subscribe linux-arcnet YOUR
+REAL NAME" to listserv@tichy.ch.uj.edu.pl.  Then, to submit messages to the
+list, mail to linux-arcnet@tichy.ch.uj.edu.pl.
 
 There are archives of the mailing list at:
 	http://tichy.ch.uj.edu.pl/lists/linux-arcnet
@@ -97,10 +97,18 @@
 Installing the Driver
 ---------------------
 
-If this driver was included as part of your Linux kernel source, all you
-will need to do in order to install it is:
+** Note: the latest version of the driver contains preliminary support for
+	ARCnet RIM I cards.  These are very old cards that don't use I/O
+	ports at all, but rather map the status and command ports into
+	shared memory.  To compile the driver in RIM I mode, you must (for
+	now) edit linux/drivers/net/arcnet.c, find the line that says:
+		#undef RIM_I_MODE
+	and change it to:
+		#define RIM_I_MODE
+
+All you will need to do in order to install the driver is:
 	make config
-		(be sure to choose ARCnet under "other ISA cards")
+		(be sure to choose ARCnet in the network devices)
 	make dep
 	make clean
 	make zImage
@@ -109,9 +117,20 @@
 your current kernel, you will need to first copy arcnet.c over the one in
 the linux/drivers/net directory.
 
-You will know the driver is installed properly if you get a lot of ARCnet
-messages when you boot into the new Linux kernel.  (These messages can be
-disabled by taking D_INIT out of the list of debug flags in arcnet.c.)
+You will know the driver is installed properly if you get some ARCnet
+messages when you reboot into the new Linux kernel.
+
+If you use a RIM I card, you will need to give the kernel boot parameters
+specifying your card's irq, node ID, and shared memory.  For example,
+	LILO boot: linux ether=9,0x42,0xD0000,0,arc0
+if your card is node number 42h, irq 9, with shared memory at 0xD0000.
+
+NOTE that if you aren't using RIM I, the above command will still work but
+you will need to replace the node ID with an I/O port number, for example:
+	LILO boot: linux ether=9,0x300,0xD0000,0,arc0
+
+You can add the ether= parameter to /etc/lilo.conf to avoid typing this
+every time.
 
 
 Loadable Module Support
@@ -137,6 +156,9 @@
 
 You can name the device using something like "device=arc1" (for a second
 card) or "device=eth0" (for weird compatibility reasons) if you like.
+
+If you use RIM I, you don't need to specify io= but you must include node=
+for your ARCnet card's station ID.
 	
 
 Using the Driver
diff -u --recursive --new-file v2.1.13/linux/Documentation/networking/ax25.txt linux/Documentation/networking/ax25.txt
--- v2.1.13/linux/Documentation/networking/ax25.txt	Wed Jul  5 13:06:27 1995
+++ linux/Documentation/networking/ax25.txt	Sun Nov 24 13:28:15 1996
@@ -1,50 +1,55 @@
-This is version 029 of the new AX.25 and NET/ROM code for Linux. It
-incorporates many enhancements since the last release, notably the rewriting
-of the connected mode IP code and the IP over NET/ROM code. The opportunity
-has been taken to add the G8BPQ NET/ROM extensions and to add BPQ Ethernet
-support. The latter has been much eased by the use of the new variable
-length header code by Alan Cox.
+With the version of the AX.25, NET/ROM and Rose protocol stacks provided in
+the Linux kernel from 2.1.9 onwards, a change has occurred in the
+configuration of the protocols. With previous versions such changes were
+made via ioctl calls, but now use is being made of the sysctl interface.
+
+Each AX.25 device will be represented in the directory /proc/sys/net/ax25,
+in the form "dev.parms"  where dev is the device name, eg ax0. In it are a
+string of numbers that represent different values for the different
+parameters, they are: 
+
+No.	Name			Meaning				Default
+1	IP Default Mode		0=DG 1=VC			0
+2	AX.25 Default Mode	0=Normal 1=Extended		0
+3	Allow Vanilla Connects	0=No 1=Yes			1
+4	Backoff			0=Linear 1=Exponential		1
+5	Connected Mode		0=No 1=Yes			1
+6	Standard Window		1  <= N <= 7			2
+7	Extended Window		1  <= N <= 63			32
+8	T1 Timeout		1s <= N <= 30s			10s
+9	T2 Timeout		1s <= N <= 20s			3s
+10	T3 Timeout		0s <= N <= 3600s		300s
+11	Idle Timeout		0m <= N				20m
+12	N2			1  <= N <= 31			10
+13	AX.25 MTU		1  <= N <= 512			256
+14	Max Queue		1  <= N <= 20			2
+15	Digipeater Mode		0=None 1=Inband 2=XBand 3=Both	3
+
+In the above list T1, T2 and T3 are given in seconds, and the Idle Timeout
+is given in minutes. But please note that the values used in the sysctl
+interface are given in internal units where the time in seconds is
+multiplied by 10, this allows resolution down to 1/10 of a second. With
+timers that are allowed to be zero, eg T3 and Idle, a zero value indicates
+that the timer is disabled. 
+
+With NET/ROM and Rose protocol stacks, the entries in /proc/sys/net/netrom
+and /proc/sys/net/rose are more obvious. Each file in these directories has
+a name more in keeping with its function, and will not be explained in any
+greater depth here. As with the AX.25 sysctl entries, timers operate with a
+resolution of 100ms and so values should be written accordingly.
+
+It is possible that the AX.25 sysctl interface will change in the future and
+become more user friendly.
+
+For more information about the AX.25 and NET/ROM protocol stacks, see the
+AX25-HOWTO written by Terry Dawson <terry@perf.no.itg.telstra.com.au> who is
+also the AX.25 Utilities maintainer.
+
+There is an active mailing list for discussing Linux amateur radio matters
+called linux-hams. To subscribe to it, send a message to
+majordomo@vger.rutgers.edu with the words "subscribe linux-hams" in the body
+of the message, the subject field is ignored.
 
-To use the BPQ Ethernet option, first up the ethernet interface in the usual
-manner, the IP address of the interface is not that important but it will
-be required for the ARP table. Next create an ARP entry in the ARP table of
-type ax25 for the interface binding it to an AX.25 callsign, this callsign
-will be the callsign of that interface. By default BPQ Ethernet uses a
-multi-cast address, this implementation does not, instead the standard
-ethernet broadcast address is used. Therefore the NET.CFG file for the
-ODI driver should look similar to this:
+Jonathan G4KLX
 
------------------------------- cut here ------------------------------------
-
-LINK SUPPORT
-
-	MAX STACKS 1
-	MAX BOARDS 1
-
-LINK DRIVER E2000			; or other MLID to suit your card
-
-	INT 10				;
-	PORT 300			; to suit your card
-
-	FRAME ETHERNET_II
-
-	PROTOCOL BPQ 8FF ETHERNET_II	; required for BPQ - can change PID
-
-BPQPARMS				; optional - only needed if you want
-					; to override the default target addr
-
-	ETH_ADDR  FF:FF:FF:FF:FF:FF	; Target address
-
------------------------------ cut here -------------------------------------
-
-The above configuration assumes that only BPQ Ethernet is being used.
-
-It is not possible to run IP over AX.25 on the BPQ Ethernet port. To simply
-route IP frames to (say) eth0 would create standard ethernet IP frames and
-completely bypass the AX.25 code. However it is possible to use IP over
-NET/ROM across a BPQ Ethernet link, the performance of such a system is
-very acceptable indeed.
-
-Jonathan Naylor G4KLX
-
-g4klx@amsat.org
+jsn@cs.nott.ac.uk
diff -u --recursive --new-file v2.1.13/linux/Makefile linux/Makefile
--- v2.1.13/linux/Makefile	Sat Nov 30 12:03:07 1996
+++ linux/Makefile	Sat Nov 23 15:28:45 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 13
+SUBLEVEL = 14
 
 ARCH = i386
 
diff -u --recursive --new-file v2.1.13/linux/Rules.make linux/Rules.make
--- v2.1.13/linux/Rules.make	Sun Sep 15 13:21:20 1996
+++ linux/Rules.make	Sun Dec  1 10:58:16 1996
@@ -184,6 +184,11 @@
 # fs/ext.o.  (Otherwise, not all subobjects will be recompiled when
 # version information changes.)
 
+else
+
+$(TOPDIR)/include/linux/modversions.h:
+	@touch $(TOPDIR)/include/linux/modversions.h
+
 endif
 
 #
diff -u --recursive --new-file v2.1.13/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- v2.1.13/linux/arch/alpha/kernel/bios32.c	Sat Nov 30 12:03:08 1996
+++ linux/arch/alpha/kernel/bios32.c	Sat Nov 30 11:13:54 1996
@@ -693,6 +693,7 @@
 
 static inline void alphapc164_fixup(void)
 {
+	extern int SMCInit(void);
 	char irq_tab[7][5] = {
 	  /*
 	   *      int   intA  intB   intC   intD
@@ -708,6 +709,8 @@
 	};
 
 	common_fixup(5, 11, 5, irq_tab, 0);
+
+	SMCInit();
 }
 
 /*
@@ -1285,4 +1288,263 @@
 	}
 	return err;
 }
+
+#ifdef CONFIG_ALPHA_PC164
+
+/* device "activate" register contents */
+#define DEVICE_ON		1
+#define DEVICE_OFF		0
+
+/* configuration on/off keys */
+#define CONFIG_ON_KEY		0x55
+#define CONFIG_OFF_KEY		0xaa
+
+/* configuration space device definitions */
+#define FDC			0
+#define IDE1			1
+#define IDE2			2
+#define PARP			3
+#define SER1			4
+#define SER2			5
+#define RTCL			6
+#define KYBD			7
+#define AUXIO			8
+
+/* Chip register offsets from base */
+#define CONFIG_CONTROL		0x02
+#define INDEX_ADDRESS		0x03
+#define LOGICAL_DEVICE_NUMBER	0x07
+#define DEVICE_ID		0x20
+#define DEVICE_REV		0x21
+#define POWER_CONTROL		0x22
+#define POWER_MGMT		0x23
+#define OSC			0x24
+
+#define ACTIVATE		0x30
+#define ADDR_HI			0x60
+#define ADDR_LO			0x61
+#define INTERRUPT_SEL		0x70
+#define INTERRUPT_SEL_2		0x72 /* KYBD/MOUS only */
+#define DMA_CHANNEL_SEL		0x74 /* FDC/PARP only */
+
+#define FDD_MODE_REGISTER	0x90
+#define FDD_OPTION_REGISTER	0x91
+
+/* values that we read back that are expected ... */
+#define VALID_DEVICE_ID		2
+
+/* default device addresses */
+#define KYBD_INTERRUPT		1
+#define MOUS_INTERRUPT		12
+#define COM2_BASE		0x2f8
+#define COM2_INTERRUPT		3
+#define COM1_BASE		0x3f8
+#define COM1_INTERRUPT		4
+#define PARP_BASE		0x3bc
+#define PARP_INTERRUPT		7
+
+#define SMC_DEBUG 0
+
+unsigned long SMCConfigState( unsigned long baseAddr )
+{
+    unsigned char devId;
+    unsigned char devRev;
+
+    unsigned long configPort;
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    configPort = indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )configPort + 1 );
+
+    outb(CONFIG_ON_KEY, configPort);
+    outb(CONFIG_ON_KEY, configPort);
+    outb(DEVICE_ID, indexPort);
+    devId = inb(dataPort);
+    if ( devId == VALID_DEVICE_ID ) {
+        outb(DEVICE_REV, indexPort);
+        devRev = inb(dataPort);
+    }
+    else {
+        baseAddr = 0;
+    }
+    return( baseAddr );
+}
+
+void SMCRunState( unsigned long baseAddr )
+{
+    outb(CONFIG_OFF_KEY, baseAddr);
+}
+
+unsigned long SMCDetectUltraIO(void)
+{
+    unsigned long baseAddr;
+
+    baseAddr = 0x3F0;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
+        return( baseAddr );
+    }
+    baseAddr = 0x370;
+    if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
+        return( baseAddr );
+    }
+    return( ( unsigned long )0 );
+}
+
+void SMCEnableDevice( unsigned long baseAddr,
+		      unsigned long device,
+		      unsigned long portaddr,
+		      unsigned long interrupt)
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(device, dataPort);
+
+    outb(ADDR_LO, indexPort);
+    outb(( portaddr & 0xFF ), dataPort);
+
+    outb(ADDR_HI, indexPort);
+    outb(( ( portaddr >> 8 ) & 0xFF ), dataPort);
+
+    outb(INTERRUPT_SEL, indexPort);
+    outb(interrupt, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableKYBD( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(KYBD, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(KYBD_INTERRUPT, dataPort);
+
+    outb(INTERRUPT_SEL_2, indexPort);/* Secondary interrupt select */
+    outb(MOUS_INTERRUPT, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+void SMCEnableFDC( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+
+    unsigned char oldValue;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(LOGICAL_DEVICE_NUMBER, indexPort);
+    outb(FDC, dataPort);
+
+    outb(FDD_MODE_REGISTER, indexPort);
+    oldValue = inb(dataPort);
+
+    oldValue |= 0x0E;                   /* Enable burst mode */
+    outb(oldValue, dataPort);
+
+    outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
+    outb(0x06, dataPort );
+
+    outb(DMA_CHANNEL_SEL, indexPort);  /* DMA channel select */
+    outb(0x02, dataPort);
+
+    outb(ACTIVATE, indexPort);
+    outb(DEVICE_ON, dataPort);
+}
+
+#if SMC_DEBUG
+void SMCReportDeviceStatus( unsigned long baseAddr )
+{
+    unsigned long indexPort;
+    unsigned long dataPort;
+    unsigned char currentControl;
+
+    indexPort = baseAddr;
+    dataPort = ( unsigned long )( ( char * )baseAddr + 1 );
+
+    outb(POWER_CONTROL, indexPort);
+    currentControl = inb(dataPort);
+
+    if ( currentControl & ( 1 << FDC ) )
+        printk( "\t+FDC Enabled\n" );
+    else
+        printk( "\t-FDC Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE1 ) )
+        printk( "\t+IDE1 Enabled\n" );
+    else
+        printk( "\t-IDE1 Disabled\n" );
+
+    if ( currentControl & ( 1 << IDE2 ) )
+        printk( "\t+IDE2 Enabled\n" );
+    else
+        printk( "\t-IDE2 Disabled\n" );
+
+    if ( currentControl & ( 1 << PARP ) )
+        printk( "\t+PARP Enabled\n" );
+    else
+        printk( "\t-PARP Disabled\n" );
+
+    if ( currentControl & ( 1 << SER1 ) )
+        printk( "\t+SER1 Enabled\n" );
+    else
+        printk( "\t-SER1 Disabled\n" );
+
+    if ( currentControl & ( 1 << SER2 ) )
+        printk( "\t+SER2 Enabled\n" );
+    else
+        printk( "\t-SER2 Disabled\n" );
+
+    printk( "\n" );
+}
+#endif
+
+int SMCInit(void)
+{
+    unsigned long SMCUltraBase;
+
+    if ( ( SMCUltraBase = SMCDetectUltraIO( ) ) != ( unsigned long )0 ) {
+        printk( "SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
+		SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCEnableDevice( SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT );
+        SMCEnableDevice( SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT );
+	/* on PC164, IDE on the SMC is not enabled; CMD646 (PCI) on MB */
+        SMCEnableKYBD( SMCUltraBase );
+        SMCEnableFDC( SMCUltraBase );
+#if SMC_DEBUG
+        SMCReportDeviceStatus( SMCUltraBase );
+#endif
+        SMCRunState( SMCUltraBase );
+        return( 1 );
+    }
+    else {
+#if SMC_DEBUG
+        printk( "No SMC FDC37C93X Ultra I/O Controller found\n" );
+#endif
+        return( 0 );
+    }
+}
+
+#endif /* CONFIG_ALPHA_PC164 */
+
 #endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.1.13/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile
--- v2.1.13/linux/arch/alpha/lib/Makefile	Sun Nov 10 20:12:08 1996
+++ linux/arch/alpha/lib/Makefile	Tue Nov 26 10:46:41 1996
@@ -8,6 +8,14 @@
 	strchr.o strrchr.o \
 	copy_user.o clear_user.o strncpy_from_user.o strlen_user.o
 
+ifeq($(CONFIG_IPV6),y)
+  OBJS += csum_ipv6_magic.o
+else
+  ifeq($(CONFIG_IPV6),m)
+    OBJS += csum_ipv6_magic.o
+  endif
+endif
+
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
 
diff -u --recursive --new-file v2.1.13/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.1.13/linux/drivers/block/ide-cd.c	Fri Nov 15 23:49:07 1996
+++ linux/drivers/block/ide-cd.c	Sun Dec  1 19:38:34 1996
@@ -140,6 +140,9 @@
  *                     -- Fully integrated with the 2.1.X kernel.
  *                     -- Other stuff that I forgot (lots of changes)
  *
+ * 4.02  Dec 01, 1996  -- Applied patch from Gadi Oxman <gadio@netvision.net.il>
+ *                          to fix the drive door locking problems.
+ *
  *
  * MOSTLY DONE LIST:
  *  Query the drive to find what features are available
@@ -154,8 +157,12 @@
  *  Implement ide_cdrom_disc_status using the generic cdrom interface
  *  Implement ide_cdrom_select_speed using the generic cdrom interface
  *  Fix ide_cdrom_reset so that it works (it does nothing right now)
- *  -- Suggestions are welcome.  Patches that work are more welcome though.
  *
+ *  -- Suggestions are welcome.  Patches that work are more welcome though.
+ *       For those wishing to work on this driver, please be sure you download
+ *       and comply with the latest ATAPI standard.  This document can 
+ *       obtained by anonymous ftp from fission.dt.wdc.com in directory:
+ *       /pub/standards/atapi/spec/SFF8020-r2.6/PDF/8020r26.pdf
  *
  */
 
@@ -1217,7 +1224,7 @@
 		   and we think that the door is presently, lock it again.
 		   (The door was probably unlocked via an explicit
 		   CDROMEJECT ioctl.) */
-		if (CDROM_STATE_FLAGS (drive)->door_locked == 0 &&
+		if (CDROM_STATE_FLAGS (drive)->door_locked == 0 && drive->usage &&
 		    (pc->c[0] != REQUEST_SENSE &&
 		     pc->c[0] != ALLOW_MEDIUM_REMOVAL &&
 		     pc->c[0] != START_STOP)) {
diff -u --recursive --new-file v2.1.13/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.1.13/linux/drivers/block/loop.c	Tue Nov 19 15:53:53 1996
+++ linux/drivers/block/loop.c	Fri Nov 29 11:20:08 1996
@@ -457,7 +457,7 @@
 			return -ENXIO;
 		if (!arg)
 			return -EINVAL;
-		return put_user(loop_sizes[lo->lo_number] << 1, (int *) arg);
+		return put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
 	default:
 		return -EINVAL;
 	}
diff -u --recursive --new-file v2.1.13/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.13/linux/drivers/cdrom/cdrom.c	Fri Nov 15 23:49:07 1996
+++ linux/drivers/cdrom/cdrom.c	Tue Nov 26 19:06:51 1996
@@ -350,9 +350,11 @@
                 
         case CDROMEJECT:
                 if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) {
-			if (cdi->use_count == 1)
+			if (cdi->use_count == 1) {
+			        if (cdo->capability & ~cdi->mask & CDC_LOCK)
+					cdo->lock_door(cdi, 0);
 				return cdo->tray_move(cdi, 1);
-			else
+			} else
 				return -EBUSY;
 		} else
                         return -EINVAL;
diff -u --recursive --new-file v2.1.13/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.1.13/linux/drivers/char/cyclades.c	Tue Nov 19 15:53:54 1996
+++ linux/drivers/char/cyclades.c	Sat Nov 30 10:48:33 1996
@@ -1937,12 +1937,15 @@
 set_modem_info(struct cyclades_port * info, unsigned int cmd,
                           unsigned int *value)
 {
-  int card,chip,channel,index;
-  unsigned char *base_addr;
-  unsigned long flags;
-  unsigned int arg;
+    int card,chip,channel,index;
+    unsigned char *base_addr;
+    unsigned long flags;
+    unsigned int arg;
+    int error;
   
-    get_user(arg,(unsigned int *) value);
+    error = get_user(arg, value);
+    if (error)
+	return error;
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
@@ -2250,31 +2253,19 @@
 
 /* The following commands are incompletely implemented!!! */
         case TIOCGSOFTCAR:
-            error = verify_area(VERIFY_WRITE, (void *) arg
-                                ,sizeof(unsigned int *));
-            if (error){
-                ret_val = error;
-                break;
-            }
-            put_user(C_CLOCAL(tty) ? 1 : 0,
-                        (unsigned int *) arg);
-            break;
+            ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
+	    break;
         case TIOCSSOFTCAR:
-            error = verify_area(VERIFY_READ, (void *) arg
-                                 ,sizeof(unsigned long *));
-            if (error) {
-                 ret_val = error;
-                 break;
-            }
-
-            get_user(arg,(unsigned int *) arg);
+            ret_val = get_user(arg,(unsigned int *) arg);
+	    if (ret_val)
+		break;
             tty->termios->c_cflag =
                     ((tty->termios->c_cflag & ~CLOCAL) |
                      (arg ? CLOCAL : 0));
             break;
         case TIOCMGET:
             error = verify_area(VERIFY_WRITE, (void *) arg
-                                ,sizeof(unsigned int *));
+                                ,sizeof(unsigned int));
             if (error){
                 ret_val = error;
                 break;
diff -u --recursive --new-file v2.1.13/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.1.13/linux/drivers/char/istallion.c	Tue Nov 19 15:53:54 1996
+++ linux/drivers/char/istallion.c	Sat Nov 30 10:48:33 1996
@@ -1791,13 +1791,14 @@
 		}
 		break;
 	case TIOCGSOFTCAR:
-		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0)
-			put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg);
+		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+		    (unsigned int *) arg);
 		break;
 	case TIOCSSOFTCAR:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0);
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int value;
+			get_user(value, (unsigned int *) arg);
+			tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0);
 		}
 		break;
 	case TIOCMGET:
@@ -1809,23 +1810,26 @@
 		}
 		break;
 	case TIOCMBIS:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1));
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int value;
+			get_user(value, (unsigned int *) arg);
+			stli_mkasysigs(&portp->asig, ((value & TIOCM_DTR) ? 1 : -1), ((value & TIOCM_RTS) ? 1 : -1));
 			rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
 		}
 		break;
 	case TIOCMBIC:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1));
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int value;
+			get_user(value, (unsigned int *) arg);
+			stli_mkasysigs(&portp->asig, ((value & TIOCM_DTR) ? 0 : -1), ((value & TIOCM_RTS) ? 0 : -1));
 			rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
 		}
 		break;
 	case TIOCMSET:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			stli_mkasysigs(&portp->asig, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0));
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int value;
+			get_user(value, (unsigned int *) arg);
+			stli_mkasysigs(&portp->asig, ((value & TIOCM_DTR) ? 1 : 0), ((value & TIOCM_RTS) ? 1 : 0));
 			rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0);
 		}
 		break;
diff -u --recursive --new-file v2.1.13/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.13/linux/drivers/char/mem.c	Tue Oct 29 19:58:06 1996
+++ linux/drivers/char/mem.c	Mon Nov 25 12:13:22 1996
@@ -189,17 +189,52 @@
 	return count;
 }
 
+/*
+ * For fun, somebody might look into using the MMU for this.
+ * NOTE! It's not trivial: you have to check that the mapping
+ * is a private mapping and if so you can just map in the
+ * zero page directly. But shared mappings _have_ to use the
+ * physical copy.
+ */
+static inline unsigned long read_zero_pagealigned(char * buf, unsigned long size)
+{
+	do {
+		if (clear_user(buf, PAGE_SIZE))
+			break;
+		if (need_resched)
+			schedule();
+		buf += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	} while (size);
+	return size;
+}
+
 static long read_zero(struct inode * node, struct file * file,
 	char * buf, unsigned long count)
 {
-	int left;
+	unsigned long left;
 
-	for (left = count; left > 0; left--) {
-		put_user(0,buf);
-		buf++;
-		if (need_resched)
-			schedule();
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+
+	left = count;
+
+	/* do we want to be clever? Arbitrary cut-off */
+	if (count >= PAGE_SIZE*4) {
+		unsigned long partial, unwritten;
+
+		/* How much left of the page? */
+		partial = (PAGE_SIZE-1) & -(unsigned long) buf;
+		clear_user(buf, partial);
+		left -= partial;
+		buf += partial;
+		unwritten = read_zero_pagealigned(buf, left & PAGE_MASK);
+		buf += left & PAGE_MASK;
+		left &= ~PAGE_MASK;
+		if (unwritten)
+			return count - left - unwritten;
 	}
+	clear_user(buf, left);
 	return count;
 }
 
diff -u --recursive --new-file v2.1.13/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- v2.1.13/linux/drivers/char/pcxx.c	Tue Oct 29 19:58:06 1996
+++ linux/drivers/char/pcxx.c	Sat Nov 30 10:48:33 1996
@@ -1971,19 +1971,17 @@
 			return 0;
 
 		case TIOCGSOFTCAR:
-			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
-			if(error)
-				return error;
-			put_fs_long(C_CLOCAL(tty) ? 1 : 0,
-				    (unsigned long *) arg);
-			return 0;
+			return put_user(C_CLOCAL(tty) ? 1 : 0,
+			    (unsigned int *) arg);
 
 		case TIOCSSOFTCAR:
-			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
-			if(error)
+			{
+			    unsigned int value;
+			    error = get_user( value, (unsigned int *) arg);
+			    if (error)
 				return error;
-			arg = get_fs_long((unsigned long *) arg);
-			tty->termios->c_cflag =	((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+			    tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
+			}
 			return 0;
 
 		case TIOCMODG:
@@ -2009,20 +2007,18 @@
 			if(mstat & ch->dcd)
 				mflag |= TIOCM_CD;
 
-			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+			error = put_user(mflag, (unsigned int *) arg);
 			if(error)
 				return error;
-			put_fs_long(mflag, (unsigned long *) arg);
 			break;
 
 		case TIOCMBIS:
 		case TIOCMBIC:
 		case TIOCMODS:
 		case TIOCMSET:
-			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
+			error = get_user(mstat, (unsigned int *) arg);
 			if(error)
 				return error;
-			mstat = get_fs_long((unsigned long *) arg);
 
 			mflag = 0;
 			if(mstat & TIOCM_DTR)
diff -u --recursive --new-file v2.1.13/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v2.1.13/linux/drivers/char/riscom8.c	Tue Nov 19 15:53:54 1996
+++ linux/drivers/char/riscom8.c	Sat Nov 30 10:48:33 1996
@@ -1356,7 +1356,7 @@
 		| ((status & MSVR_CD)  ? TIOCM_CAR : 0)
 		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
 		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-	put_user(result,(unsigned long *) value);
+	put_user(result, value);
 	return 0;
 }
 
@@ -1368,10 +1368,9 @@
 	unsigned long flags;
 	struct riscom_board *bp = port_Board(port);
 
-	error = verify_area(VERIFY_READ, value, sizeof(int));
+	error = get_user(arg, value);
 	if (error) 
 		return error;
-	get_user(arg,(unsigned int *) value);
 	switch (cmd) {
 	 case TIOCMBIS: 
 		if (arg & TIOCM_RTS) 
@@ -1523,14 +1522,11 @@
 		rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
 		return 0;
 	 case TIOCGSOFTCAR:
-		error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
-		if (error)
-			return error;
-		put_user(C_CLOCAL(tty) ? 1 : 0,
-			    (unsigned long *) arg);
-		return 0;
+		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
 	 case TIOCSSOFTCAR:
-		get_user(arg,(unsigned int *) arg);
+		retval = get_user(arg,(unsigned int *) arg);
+		if (retval)
+			return retval;
 		tty->termios->c_cflag =
 			((tty->termios->c_cflag & ~CLOCAL) |
 			(arg ? CLOCAL : 0));
diff -u --recursive --new-file v2.1.13/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.13/linux/drivers/char/serial.c	Fri Nov 15 23:49:08 1996
+++ linux/drivers/char/serial.c	Sat Nov 30 10:48:34 1996
@@ -1747,10 +1747,9 @@
 	int error;
 	unsigned int arg;
 
-	error = verify_area(VERIFY_READ, value, sizeof(int));
+	error = get_user(arg, value);
 	if (error)
 		return error;
-	get_user(arg, value);
 	switch (cmd) {
 	case TIOCMBIS: 
 		if (arg & TIOCM_RTS) {
@@ -2024,16 +2023,11 @@
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
-			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
-			if (error)
-				return error;
-			put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
-			return 0;
+			return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
 		case TIOCSSOFTCAR:
-			error = verify_area(VERIFY_READ, (void *) arg,sizeof(long));
+			error = get_user(arg, (unsigned int *) arg);
 			if (error)
 				return error;
-			get_user(arg, (unsigned int *) arg);
 			tty->termios->c_cflag =
 				((tty->termios->c_cflag & ~CLOCAL) |
 				 (arg ? CLOCAL : 0));
diff -u --recursive --new-file v2.1.13/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.1.13/linux/drivers/char/stallion.c	Tue Nov 19 15:53:54 1996
+++ linux/drivers/char/stallion.c	Sat Nov 30 10:48:34 1996
@@ -1122,7 +1122,6 @@
 static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	stlport_t	*portp;
-	unsigned long	val;
 	int		rc;
 
 #if DEBUG
@@ -1152,37 +1151,42 @@
 		}
 		break;
 	case TIOCGSOFTCAR:
-		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long))) == 0)
-			put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned long *) arg);
+		rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
+		    (unsigned int *) arg);
 		break;
 	case TIOCSSOFTCAR:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0);
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int	val;
+			get_user(val, (unsigned int *) arg);
+			tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0);
 		}
 		break;
 	case TIOCMGET:
 		if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) {
-			val = (unsigned long) stl_getsignals(portp);
-			put_user(val, (unsigned long *) arg);
+			unsigned int	val;
+			val = stl_getsignals(portp);
+			put_user(val, (unsigned int *) arg);
 		}
 		break;
 	case TIOCMBIS:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : -1), ((arg & TIOCM_RTS) ? 1 : -1));
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int	val;
+			get_user(val, (unsigned int *) arg);
+			stl_setsignals(portp, ((val & TIOCM_DTR) ? 1 : -1), ((val & TIOCM_RTS) ? 1 : -1));
 		}
 		break;
 	case TIOCMBIC:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			stl_setsignals(portp, ((arg & TIOCM_DTR) ? 0 : -1), ((arg & TIOCM_RTS) ? 0 : -1));
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int	val;
+			get_user(val, (unsigned int *) arg);
+			stl_setsignals(portp, ((val & TIOCM_DTR) ? 0 : -1), ((val & TIOCM_RTS) ? 0 : -1));
 		}
 		break;
 	case TIOCMSET:
-		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(long))) == 0) {
-			get_user(arg, (unsigned long *) arg);
-			stl_setsignals(portp, ((arg & TIOCM_DTR) ? 1 : 0), ((arg & TIOCM_RTS) ? 1 : 0));
+		if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) {
+			unsigned int	val;
+			get_user(val, (unsigned int *) arg);
+			stl_setsignals(portp, ((val & TIOCM_DTR) ? 1 : 0), ((val & TIOCM_RTS) ? 1 : 0));
 		}
 		break;
 	case TIOCGSERIAL:
diff -u --recursive --new-file v2.1.13/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c
--- v2.1.13/linux/drivers/char/tty_ioctl.c	Sun Nov 10 20:12:11 1996
+++ linux/drivers/char/tty_ioctl.c	Sat Nov 30 10:48:34 1996
@@ -513,7 +513,7 @@
 			return 0;
 		case TIOCINQ:
 			retval = verify_area(VERIFY_WRITE, (void *) arg,
-					     sizeof (unsigned long));
+					     sizeof (unsigned int));
 			if (retval)
 				return retval;
 			retval = tty->read_cnt;
diff -u --recursive --new-file v2.1.13/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.1.13/linux/drivers/isdn/isdn_tty.c	Fri Nov  1 17:13:16 1996
+++ linux/drivers/isdn/isdn_tty.c	Sat Nov 30 10:48:34 1996
@@ -1014,7 +1014,7 @@
 	status = info->lsr;
 	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	return put_user(result, (ulong *) value);
+	return put_user(result, value);
 }
 
 
@@ -1035,7 +1035,7 @@
 	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
 	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
 	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result, (ulong *) value);
+	return put_user(result, value);
 }
 
 static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
@@ -1144,17 +1144,14 @@
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                         printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
 #endif
-                        error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
-						if (error)
-							    return error;
-                        return 0;
+			return put_user(C_CLOCAL(tty) ? 1 : 0, (uint *) arg);
                 case TIOCSSOFTCAR:
 #ifdef ISDN_DEBUG_MODEM_IOCTL
                         printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
 #endif
-                        error = get_user(arg ,((ulong *) arg));
-						if (error)
-							    return error;
+                        error = get_user(arg ,((uint *) arg));
+			if (error)
+				return error;
                         tty->termios->c_cflag =
                                 ((tty->termios->c_cflag & ~CLOCAL) |
                                  (arg ? CLOCAL : 0));
diff -u --recursive --new-file v2.1.13/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.1.13/linux/drivers/net/3c509.c	Fri Sep 20 09:11:44 1996
+++ linux/drivers/net/3c509.c	Fri Nov 29 12:29:45 1996
@@ -449,7 +449,7 @@
 		return 0;
 
 	if (el3_debug > 4) {
-		printk("%s: el3_start_xmit(length = %ld) called, status %4.4x.\n",
+		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
 			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
 	}
 #if 0
@@ -754,37 +754,62 @@
 }
 
 #ifdef MODULE
-static char devicename[9] = { 0, };
-static struct device dev_3c509 = {
-        devicename, /* device name is inserted by linux/drivers/net/net_init.c */
-        0, 0, 0, 0,
-        0, 0,
-        0, 0, 0, NULL, el3_probe };
+#define MAX_3C_CARDS	4	/* Max number of NE cards per module */
+#define NAMELEN		8	/* # of chars for storing dev->name */
+static char namelist[NAMELEN * MAX_3C_CARDS] = { 0, };
+static struct device dev_3c509[MAX_3C_CARDS] = {
+	{
+		NULL,		/* assign a chunk of namelist[] below */
+		0, 0, 0, 0,
+		0, 0,
+		0, 0, 0, NULL, NULL
+	},
+};
 
-static int io  = 0;
-static int irq = 0;
+static int io[MAX_3C_CARDS] = { 0, };
+static int irq[MAX_3C_CARDS]  = { 0, };
 
 int
 init_module(void)
 {
-	dev_3c509.base_addr = io;
-        dev_3c509.irq       = irq;
-        if (!EISA_bus && !io) {
-		printk("3c509: WARNING! Module load-time probing works reliably only for EISA bus!!\n");
+	int this_dev, found = 0;
+
+	for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) {
+		struct device *dev = &dev_3c509[this_dev];
+		dev->name = namelist+(NAMELEN*this_dev);
+		dev->irq = irq[this_dev];
+		dev->base_addr = io[this_dev];
+		dev->init = el3_probe;
+		if (io[this_dev] == 0)  {
+			if (this_dev != 0) break; /* only complain once */
+			printk("3c509: WARNING! Module load-time probing works reliably only for EISA bus!!\n");
+		}
+		if (register_netdev(dev) != 0) {
+			printk(KERN_WARNING "3c509.c: No 3c509 card found (i/o = 0x%x).\n", io[this_dev]);
+			if (found != 0) return 0;	/* Got at least one. */
+			return -ENXIO;
+		}
+		found++;
 	}
-	if (register_netdev(&dev_3c509) != 0)
-		return -EIO;
 	return 0;
 }
 
 void
 cleanup_module(void)
 {
-	unregister_netdev(&dev_3c509);
-	kfree_s(dev_3c509.priv,sizeof(struct el3_private));
-	dev_3c509.priv=NULL;
-	/* If we don't do this, we can't re-insmod it later. */
-	release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
+	int this_dev;
+
+	for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) {
+		struct device *dev = &dev_3c509[this_dev];
+		if (dev->priv != NULL) {
+			kfree_s(dev->priv,sizeof(struct el3_private));
+			dev->priv = NULL;
+			free_irq(dev->irq, NULL);
+			irq2dev_map[dev->irq] = NULL;
+			release_region(dev->base_addr, EL3_IO_EXTENT);
+			unregister_netdev(dev);
+		}
+	}
 }
 #endif /* MODULE */
 
diff -u --recursive --new-file v2.1.13/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.1.13/linux/drivers/net/arcnet.c	Tue Oct 29 19:58:11 1996
+++ linux/drivers/net/arcnet.c	Sun Dec  1 09:47:18 1996
@@ -17,114 +17,38 @@
          
 	**********************
 	
+	v2.60 ALPHA (96/11/23)
+	  - Added patch from Vojtech Pavlik <vojtech@atrey.karlin.mff.cuni.cz>
+	    and Martin Mares <mj@k332.feld.cvut.cz> to make the driver work
+	    with the new Linux 2.1.x memory management.  I modified their
+	    patch quite a bit though; bugs are my fault.  More changes should
+	    be made to get eliminate any remaining phys_to_virt calls.
+	  - Quietly ignore protocol id's 0, 1, 8, and 243.  Thanks to Jake
+	    Messinger <jake@ams.com> for reporting these codes and their
+	    meanings.
+	  - Smarter shmem probe for cards with 4k mirrors. (does it work?)
+	  - Initial support for RIM I type cards which use no I/O ports at
+	    all.  To use this option, you need to compile with RIM_I_MODE
+	    enabled.  Thanks to Kolja Waschk <kawk@yo.com> for explaining
+	    RIM I programming to me.  Now, does my RIM I code actually
+	    work?
+
 	v2.56 (96/10/18)
 	  - Turned arc0e/arc0s startup messages back on by default, as most
 	    people will probably not notice the additional devices
-	    otherwise, and experience more protocol confusion than
-	    necessary.
+	    otherwise.  This causes undue confusion.
 	  - Fixed a tiny but noticeable bug in the packet debugging routines
 	    (thanks Tomasz)
 
-	v2.55 (96/08/05)
-	  - A couple more messages moved to D_EXTRA.
-	  - SLOW_XMIT_COPY off by default.
-	  - Some tiny changes.
-	
-	v2.54 (96/07/05)
-	  - Under some situations, Stage 5 autoprobe was a little bit too
-	    picky about the TXACK flag.
-	  - D_EXTRA removed from default debugging flags.  Hey, it's stable,
-	    right?
-	  - Removed redundant "unknown protocol ID" messages and made remaining
-	    ones D_EXTRA.
-	
-	v2.53 (96/06/06)
-	  - arc0e and arc0s wouldn't initialize in newer kernels, which
-	    don't like dev->open==NULL or dev->stop==NULL.
-	
-	v2.52 (96/04/20)
-	  - Replaced more decimal node ID's with hex, for consistency.
-	  - Changed a couple of printk debug levels.
-
-	v2.51 (96/02/29)
-	  - Inserted a rather important missing "volatile" in autoprobe.
-	  - arc0e and arc0s are now options in drivers/net/Config.in.
-	
-	v2.50 (96/02/24)
-	  - Increased IRQ autoprobe delay.  Thanks to Andrew J. Kroll for
-	    noticing the problem, which seems to only affect certain cards.
-	  - Errors reserving ports and IRQ's now clean up after themselves.
-	  - We now replace the TESTvalue byte from unused shmem addresses.
-	  - You can now use "irq=" as well as "irqnum=" to set the IRQ
-	    during module autoprobe.  This doesn't seem to crash insmod
-	    anymore. (?)
-	  - You can now define the name of the ARCnet device more easily
-	    when loading the module: insmod arcnet.o device=test1
-	    A new option, CONFIG_ARCNET_ETHNAME, allows the kernel to
-	    choose one of the standard eth?-style device names
-	    automatically.  This currently only works as a module.
-	  - printk's now try to make some use of the KERN_xxx priority level
-	    macros (though they may not be perfect yet).
-	  - Packet and skb dump loops are now separate functions.
-	  - Removed D_INIT from default debug level, because I am (finally)
-	    pretty confident that autoprobe shouldn't toast anyone's
-	    computer.
-	  - This version is no longer ALPHA.
-
-	v2.41 ALPHA (96/02/10)
-	  - Incorporated changes someone made to arcnet_setup in 1.3.60.
-	  - Increased reset timeout to 3/10 of a second because some cards
-	    are too slow.
-	  - Removed a useless delay from autoprobe stage 4; I wonder
-	    how that got there!  (oops)
-	  - If FAST_IFCONFIG is defined, don't reset the card during
-	    arcnet_open; rather, do it in arcnet_close but don't delay. 
-	    This speeds up calls to ifconfig up/down.  (Thanks to Vojtech
-	    for the idea to speed this up.)
-	  - If FAST_PROBE is defined, don't bother to reset the card in
-	    autoprobe Stage 5 when there is only one io port and one shmem
-	    left in the list.  They "obviously" correspond to each other. 
-	    Another good idea from Vojtech.
-
-	v2.40 ALPHA (96/02/03)
-	  - Checked the RECON flag last in the interrupt handler (when
-	    enabled) so the flag will show up in "status" when reporting
-	    other errors.  (I had a cabling problem that was hard to notice
-	    until I saw the huge RECON count in /proc/net/dev.)
-	  - Moved "IRQ for unknown device" message to D_DURING.
-	  - "transmit timed out" and "not acknowledged" messages are
-	    now D_EXTRA, because they very commonly happen when things
-	    are working fine.  "transmit timed out" due to missed IRQ's
-	    is still D_NORMAL, because it's probably a bug.
-	  - "Transmit timed out" messages now include destination station id.
-	  - The virtual arc0e and arc0s devices can now be disabled. 
-	    Massive (but simple) code rearrangement to support this with
-	    fewer ifdef's.
-	  - SLOW_XMIT_COPY option so fast computers don't hog the bus.  It's
-	    weird, but it works.
-	  - Finally redesigned autoprobe after some discussion with Vojtech
-	    Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>.  It should be much safer
-	    and more reliable now, I think.  We now probe several more io
-	    ports and many more shmem addresses.
-	  - Rearranged D_* debugging flags slightly.  Watch out!  There is
-	    now a new flag, disabled by default, that will tell you the
-	    reason a particular port or shmem is discarded from the list.
-
-	v2.30 ALPHA (96/01/10)
-	  - Abandoned support for Linux 1.2 to simplify coding and allow me
-	    to take advantage of new features in 1.3.
-	  - Updated cabling/jumpers documentation with MUCH information that
-	    people have recently (and in some cases, not so recently) sent
-	    me.  I don't mind writing documentation, but the jumpers
-	    database is REALLY starting to get dull.
-	  - Autoprobing works as a module now - but ONLY with my fix to
-	    register_netdev and unregister_netdev.  It's also much faster,
-	    and uses the "new-style" IRQ autoprobe routines.  Autoprobe is
-	    still a horrible mess and will be cleaned up further as time
-	    passes.
-	    
 	The following has been SUMMARIZED.  The complete ChangeLog is
-	available in the full Linux-ARCnet package.
+	available in the full Linux-ARCnet package at
+		http://www.foxnet.net/~apenwarr/arcnet
+		
+	v2.50 (96/02/24)
+	  - Massively improved autoprobe routines; they now work even as a
+	    module.  Thanks to Vojtech Pavlik <Vojtech.Pavlik@st.mff.cuni.cz>
+	    for his ideas and help in this area.
+	  - Changed printk's around quite a lot.
 	
 	v2.22 (95/12/08)
 	  - Major cleanups, speedups, and better code-sharing.
@@ -164,17 +88,20 @@
 	v1.00 (95/02/15)
 	  - Initial non-alpha release.
 	
-         
+	
 	TO DO: (semi-prioritized)
 	
+         - Use cleaner "architecture-independent" shared memory access.
+           This is half-done in ARCnet 2.60, but still uses some
+           undocumented i386 stuff.  (We shouldn't call phys_to_virt,
+           for example.)
          - Support "arpless" mode like NetBSD does, and as recommended
            by the (obsoleted) RFC1051.
+         - Some way to make RIM_I_MODE runtime switchable?  Yuck...
          - Smarter recovery from RECON-during-transmit conditions. (ie.
            retransmit immediately)
          - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
            packet into ARCnet memory.
-         - Some cards have shared memory with 4k mirrors instead of just 2k,
-           so we (uneventfully) find the "wrong" shmem when probing.
          - Probe for multiple devices in one shot (trying to decide whether
            to do it the "ugly" way or not).
          - Add support for the new 1.3.x IP header cache, and other features.
@@ -210,7 +137,7 @@
 */
 
 static const char *version =
- "arcnet.c: v2.56 96/10/18 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.60 96/11/23 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -245,6 +172,12 @@
 
 /**************************************************************************/
 
+/* Define this if you have a really ancient "RIM I" ARCnet card with no I/O
+ * port at all and _only_ shared memory; this option MAY work for you.  It's
+ * untested, though, so good luck and write to me with any results!
+ */
+#undef RIM_I_MODE
+
 /* Normally, the ARCnet device needs to be assigned a name (default arc0). 
  * Ethernet devices have a function to automatically try eth0, eth1, etc
  * until a free name is found.  To name the ARCnet device using an "eth?"
@@ -367,7 +300,7 @@
 #endif
 
 #ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL)
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
 #endif
 int arcnet_debug = ARCNET_DEBUG;
 
@@ -409,15 +342,33 @@
 /* The number of low I/O ports used by the ethercard. */
 #define ARCNET_TOTAL_SIZE	16
 
-
 /* Handy defines for ARCnet specific stuff */
 	/* COM 9026 controller chip --> ARCnet register addresses */
-#define INTMASK	(ioaddr+0)		/* writable */
-#define STATUS	(ioaddr+0)		/* readable */
-#define COMMAND (ioaddr+1)	/* writable, returns random vals on read (?) */
-#define RESET  (ioaddr+8)		/* software reset writable */
+#define _INTMASK (ioaddr+0)	/* writable */
+#define _STATUS  (ioaddr+0)	/* readable */
+#define _COMMAND (ioaddr+1)	/* writable, returns random vals on read (?) */
+#define _RESET  (ioaddr+8)	/* software reset (on read) */
+
+/* RIM I (command/status is memory mapped) versus RIM III (standard I/O
+ * mapped) macros.  These make things a bit cleaner.
+ */
+#ifdef RIM_I_MODE
+  #define IOADDR	(dev->mem_start+0x800)
+  #define ARCSTATUS	readb(_STATUS)
+  #define ACOMMAND(cmd) writeb((cmd),_COMMAND)
+  #define ARCRESET	writeb(TESTvalue,ioaddr-0x800)	/* fake reset */
+  #define AINTMASK(msk)	writeb((msk),_INTMASK)
+  #define RELEASE_REGION(x,y)	/* nothing */
+#else
+  #define IOADDR	(dev->base_addr)
+  #define ARCSTATUS	inb(_STATUS)
+  #define ACOMMAND(cmd) outb((cmd),_COMMAND)
+  #define AINTMASK(msk)	outb((msk),_INTMASK)
+  #define ARCRESET	inb(_RESET)
+  #define RELEASE_REGION(x,y)	release_region((x),(y))
+#endif
 
-#define SETMASK outb(lp->intmask,INTMASK);
+#define SETMASK AINTMASK(lp->intmask)
 
 	/* Time needed to reset the card - in jiffies.  This works on my SMC
 	 * PC100.  I can't find a reference that tells me just how long I
@@ -479,7 +430,7 @@
 
 	/* Starts receiving packets into recbuf.
 	 */
-#define EnableReceiver()	outb(RXcmd|(recbuf<<3)|RXbcasts,COMMAND)
+#define EnableReceiver()	ACOMMAND(RXcmd|(recbuf<<3)|RXbcasts)
 
 	/* RFC1201 Protocol ID's */
 #define ARC_P_IP	212		/* 0xD4 */
@@ -496,6 +447,10 @@
 #define ARC_P_ETHER	0xE8
 
 	/* Unsupported/indirectly supported protocols */
+#define ARC_P_DATAPOINT_BOOT	0	/* very old Datapoint equipment */
+#define ARC_P_DATAPOINT_MOUNT	1
+#define ARC_P_POWERLAN_BEACON	8	/* Probably ATA-Netbios related */
+#define ARC_P_POWERLAN_BEACON2	243
 #define ARC_P_LANSOFT	251		/* 0xFB - what is this? */
 #define ARC_P_ATALK	0xDD
 
@@ -750,7 +705,40 @@
  * Probe and initialization                                                 *
  *                                                                          *
  ****************************************************************************/
- 
+
+#ifdef RIM_I_MODE
+
+/* We cannot probe for a RIM I card; one reason is I don't know how to reset
+ * them.  In fact, we can't even get their node ID automatically.  So, we
+ * need to be passed a specific shmem address, IRQ, and node ID (stored in
+ * dev->base_addr)
+ */
+int arcnet_probe(struct device *dev)
+{
+	BUGLVL(D_NORMAL) printk(version);
+	BUGMSG(D_NORMAL,"Compiled for ARCnet RIM I (autoprobe disabled)\n");
+	BUGMSG(D_NORMAL,"Given: node %02lXh, shmem %lXh, irq %d\n",
+		dev->base_addr,dev->mem_start,dev->irq);
+	
+	if (dev->mem_start<=0 || dev->irq<=0)
+	{
+		BUGMSG(D_NORMAL,"No autoprobe for RIM I; you "
+			"must specify the shmem and irq!\n");
+		return -ENODEV;
+	}
+	
+	if (dev->base_addr<=0 || dev->base_addr>255)
+	{
+		BUGMSG(D_NORMAL,"You need to specify your card's station "
+			"ID!\n");
+		return -ENODEV;
+	}
+	
+	return arcnet_found(dev,dev->base_addr,dev->irq,dev->mem_start);
+}
+
+#else /* not RIM_I_MODE, so use a real autoprobe */
+
 /* Check for an ARCnet network adaptor, and return '0' if one exists.
  *  If dev->base_addr == 0, probe all likely locations.
  *  If dev->base_addr == 1, always return failure.
@@ -793,13 +781,13 @@
 		sizeof(ports)+sizeof(shmems));
 
 	
-#if 0
+#if 1
 	BUGLVL(D_EXTRA)
 	{
 		printk("arcnet: ***\n");
 		printk("arcnet: * Read arcnet.txt for important release notes!\n");
 		printk("arcnet: *\n");
-		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.22)  E-mail me if\n");
+		printk("arcnet: * This is an ALPHA version!  (Last stable release: v2.56)  E-mail me if\n");
 		printk("arcnet: * you have any questions, comments, or bug reports.\n");
 		printk("arcnet: ***\n");
 	}
@@ -852,7 +840,7 @@
 			continue;
 		}
 		
-		if (inb(STATUS) == 0xFF)
+		if (ARCSTATUS == 0xFF)
 		{
 			BUGMSG2(D_INIT_REASONS,"(empty)\n");
 			BUGMSG(D_INIT_REASONS,"Stage 1: ");
@@ -863,7 +851,7 @@
 			continue;
 		}
 		
-		inb(RESET);	/* begin resetting card */
+		ARCRESET;	/* begin resetting card */
 
 		BUGMSG2(D_INIT_REASONS,"\n");
 		BUGMSG(D_INIT_REASONS,"Stage 1: ");
@@ -906,8 +894,8 @@
 	numprint=0;
 	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
 	{
-		volatile u_char *cptr;
-	
+		u_long ptr;
+
 		numprint++;
 		if (numprint>8)
 		{
@@ -917,12 +905,12 @@
 		}
 		BUGMSG2(D_INIT,"%lXh ",*shmem);
 		
-		cptr=(u_char *)(*shmem);
+		ptr=(u_long)(*shmem);
 		
-		if (*cptr != TESTvalue)
+		if (readb(ptr) != TESTvalue)
 		{
 			BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
-				*cptr,TESTvalue);
+				readb(ptr),TESTvalue);
 			BUGMSG(D_INIT_REASONS,"Stage 3: ");
 			BUGLVL(D_INIT_REASONS) numprint=0;
 			*shmem=shmems[numshmems-1];
@@ -936,8 +924,8 @@
 		 * in another pass through this loop, they will be discarded
 		 * because *cptr != TESTvalue.
 		 */
-		*cptr=0x42;
-		if (*cptr != 0x42)
+		writeb(0x42,ptr);
+		if (readb(ptr) != 0x42)
 		{
 			BUGMSG2(D_INIT_REASONS,"(read only)\n");
 			BUGMSG(D_INIT_REASONS,"Stage 3: ");
@@ -999,7 +987,7 @@
 		BUGMSG2(D_INIT,"%Xh ",*port);
 		
 		ioaddr=*port;
-		status=inb(STATUS);
+		status=ARCSTATUS;
 		
 		if ((status & 0x9D)
 			!= (NORXflag|RECONflag|TXFREEflag|RESETflag))
@@ -1013,8 +1001,8 @@
 			continue;
 		}
 
-		outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
-		status=inb(STATUS);
+		ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
+		status=ARCSTATUS;
 		if (status & RESETflag)
 		{
 			BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n",
@@ -1037,9 +1025,9 @@
 			 * we tell it to start receiving.
 			 */
 			airqmask = probe_irq_on();
-			outb(NORXflag,INTMASK);
+			AINTMASK(NORXflag);
 			udelay(1);
-			outb(0,INTMASK);
+			AINTMASK(0);
 			airq = probe_irq_off(airqmask);
 	
 			if (airq<=0)
@@ -1070,26 +1058,26 @@
 #ifdef FAST_PROBE
 		if (numports>1 || numshmems>1)
 		{
-			inb(RESET);
+			ARCRESET;
 			JIFFER(RESETtime);
 		}
 		else
 		{
 			/* just one shmem and port, assume they match */
-			*(u_char *)(shmems[0]) = TESTvalue;
+			writeb(TESTvalue,shmems[0]);
 		}
 #else
-		inb(RESET);
+		ARCRESET;
 		JIFFER(RESETtime);
 #endif
 
 
 		for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
 		{
-			u_char *cptr;
-			cptr=(u_char *)(*shmem);
+			u_long ptr;
+			ptr=(u_long)(*shmem);
 			
-			if (*cptr == TESTvalue)	/* found one */
+			if (readb(ptr) == TESTvalue)	/* found one */
 			{
 				BUGMSG2(D_INIT,"%lXh)\n", *shmem);
 				openparen=0;
@@ -1106,7 +1094,7 @@
 			}
 			else
 			{
-				BUGMSG2(D_INIT_REASONS,"%Xh-", *cptr);
+				BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
 			}
 		}
 
@@ -1128,48 +1116,67 @@
 	/* Now put back TESTvalue on all leftover shmems.
 	 */
 	for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
-		*(u_char *)(*shmem) = TESTvalue;
+		writeb(TESTvalue,*shmem);
 		
 	if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n");
 	return retval;
 }
 
+#endif /* !RIM_I_MODE */
+
+
 /* Set up the struct device associated with this card.  Called after
  * probing succeeds.
  */
 int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
 {
-	u_char *first_mirror,*last_mirror;
+	u_long first_mirror,last_mirror;
 	struct arcnet_local *lp;
+	int mirror_size;
 	
-	/* reserve the I/O region */
-	request_region(port,ARCNET_TOTAL_SIZE,"arcnet");
-	dev->base_addr=port;
-
 	/* reserve the irq */
 	if (request_irq(airq,&arcnet_interrupt,0,"arcnet",NULL))
 	{
 		BUGMSG(D_NORMAL,"Can't get IRQ %d!\n",airq);
-		release_region(port,ARCNET_TOTAL_SIZE);
 		return -ENODEV;
 	}
 	irq2dev_map[airq]=dev;
 	dev->irq=airq;
+
+#ifdef RIM_I_MODE
+	dev->base_addr=0;
+	writeb(TESTvalue,shmem);
+	writeb(port,shmem+1);	/* actually the node ID */
+#else
+	/* reserve the I/O region - guaranteed to work by check_region */
+	request_region(port,ARCNET_TOTAL_SIZE,"arcnet");
+	dev->base_addr=port;
+#endif
 	
 	/* find the real shared memory start/end points, including mirrors */
 	
 	#define BUFFER_SIZE (512)
 	#define MIRROR_SIZE (BUFFER_SIZE*4)
-	
-	first_mirror=last_mirror=(u_char *)shmem;
-	while (*first_mirror==TESTvalue) first_mirror-=MIRROR_SIZE;
-	first_mirror+=MIRROR_SIZE;
 
-	while (*last_mirror==TESTvalue) last_mirror+=MIRROR_SIZE;
-	last_mirror-=MIRROR_SIZE;
+	/* guess the actual size of one "memory mirror" - the number of
+	 * bytes between copies of the shared memory.  On most cards, it's
+	 * 2k (or there are no mirrors at all) but on some, it's 4k.
+	 */
+	mirror_size=MIRROR_SIZE;
+	if (readb(shmem)==TESTvalue
+	    && readb(shmem-mirror_size)!=TESTvalue
+	    && readb(shmem-2*mirror_size)==TESTvalue)
+		mirror_size*=2;
+	
+	first_mirror=last_mirror=shmem;
+	while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
+	first_mirror+=mirror_size;
+
+	while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size;
+	last_mirror-=mirror_size;
 
-	dev->mem_start=(u_long)first_mirror;
-	dev->mem_end=(u_long)last_mirror+MIRROR_SIZE-1;
+	dev->mem_start=first_mirror;
+	dev->mem_end=last_mirror+MIRROR_SIZE-1;
 	dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
 	dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
 	 
@@ -1180,7 +1187,7 @@
 	{
 		irq2dev_map[airq] = NULL;
 		free_irq(airq,NULL);
-		release_region(port,ARCNET_TOTAL_SIZE);
+		RELEASE_REGION(port,ARCNET_TOTAL_SIZE);
 		return -ENOMEM;
 	}
 	memset(dev->priv,0,sizeof(struct arcnet_local));
@@ -1211,7 +1218,7 @@
 		sizeof(struct HardHeader));
 
 	/* get and check the station ID from offset 1 in shmem */
-	lp->stationid = first_mirror[1];
+	lp->stationid = readb(first_mirror+1);
 	if (lp->stationid==0)
 		BUGMSG(D_NORMAL,"WARNING!  Station address 00 is reserved "
 			"for broadcasts!\n");
@@ -1221,10 +1228,10 @@
 	dev->dev_addr[0]=lp->stationid;
 
 	BUGMSG(D_NORMAL,"ARCnet station %02Xh found at %03lXh, IRQ %d, "
-		"ShMem %lXh (%ld bytes).\n",
+		"ShMem %lXh (%ld*%d bytes).\n",
 		lp->stationid,
 		dev->base_addr,dev->irq,dev->mem_start,
-		dev->mem_end-dev->mem_start+1);
+		(dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size);
 		
 	return 0;
 }
@@ -1240,30 +1247,28 @@
 int arcnet_reset(struct device *dev,int reset_delay)
 {
 	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	short ioaddr=dev->base_addr;
+	short ioaddr=IOADDR;
 	int delayval,recbuf=lp->recbuf;
-	u_char *cardmem;
 	
 	/* no IRQ's, please! */
 	lp->intmask=0;
 	SETMASK;
 	
 	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
-			dev->name,inb(STATUS));
+			dev->name,ARCSTATUS);
 
 	if (reset_delay)
 	{
 		/* reset the card */
-		inb(RESET);
+		ARCRESET;
 		JIFFER(RESETtime);
 	}
 
-	outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
-	outb(CFLAGScmd|CONFIGclear,COMMAND);
+	ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
+	ACOMMAND(CFLAGScmd|CONFIGclear);
 
 	/* verify that the ARCnet signature byte is present */
-	cardmem = (u_char *) dev->mem_start;
-	if (cardmem[0] != TESTvalue)
+	if (readb(dev->mem_start) != TESTvalue)
 	{
 		BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
 		return 1;
@@ -1274,12 +1279,12 @@
 	lp->txbuf=2;
 
 	/* enable extended (512-byte) packets */
-	outb(CONFIGcmd|EXTconf,COMMAND);
-	
+	ACOMMAND(CONFIGcmd|EXTconf);
+
 #ifndef SLOW_XMIT_COPY
 	/* clean out all the memory to make debugging make more sense :) */
 	BUGLVL(D_DURING)
-		memset((void *)dev->mem_start,0x42,2048);
+		memset_io(dev->mem_start,0x42,2048);
 #endif
 	
 	/* and enable receive of our first packet to the first buffer */
@@ -1346,7 +1351,7 @@
 arcnet_open(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr;
+	int ioaddr=IOADDR;
 	
 	if (dev->metric>=1000)
 	{
@@ -1418,7 +1423,7 @@
 	 * START is set to 1, it could be ignored.  So, we turn IRQ's
 	 * off, then on again to clean out the IRQ controller.
 	 */
-	outb(0,INTMASK);
+	AINTMASK(0);
 	udelay(1);	/* give it time to set the mask before
 			 * we reset it again. (may not even be
 			 * necessary)
@@ -1435,7 +1440,7 @@
 static int
 arcnet_close(struct device *dev)
 {
-	int ioaddr = dev->base_addr;
+	int ioaddr=IOADDR;
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 	
 	TBUSY=1;
@@ -1443,12 +1448,12 @@
 
 	/* Shut down the card */
 #ifdef FAST_IFCONFIG
-	inb(RESET);	/* reset IRQ won't run if START=0 */
+	ARCRESET;	/* reset IRQ won't run if START=0 */
 #else
 	lp->intmask=0;
 	SETMASK;	/* no IRQ's (except RESET, of course) */
-	outb(NOTXcmd,COMMAND);  /* stop transmit */
-	outb(NORXcmd,COMMAND);	/* disable receive */
+	ACOMMAND(NOTXcmd);	/* stop transmit */
+	ACOMMAND(NORXcmd);	/* disable receive */
 #endif
 
 	/* reset more flags */
@@ -1497,10 +1502,10 @@
 arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr;
+	int ioaddr=IOADDR;
 	
 	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
-			inb(STATUS),lp->intx);
+			ARCSTATUS,lp->intx);
 			
 	if (lp->in_txhandler)
 	{
@@ -1522,7 +1527,7 @@
 		   There should really be a "kick me" function call instead. */
 		int tickssofar = jiffies - dev->trans_start;
 		/*int recbuf=lp->recbuf;*/
-		int status=inb(STATUS);
+		int status=ARCSTATUS;
 		
 		if (tickssofar < TX_TIMEOUT) 
 		{
@@ -1549,7 +1554,7 @@
 			lp->stats.tx_errors++;
 			lp->stats.tx_aborted_errors++;
 
-			outb(NOTXcmd,COMMAND);
+			ACOMMAND(NOTXcmd);
 		}
 
 		if (lp->outgoing.skb)
@@ -1571,7 +1576,7 @@
 	   itself. */
 	if (skb == NULL) {
 		BUGMSG(D_NORMAL,"tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-			inb(STATUS),lp->intx,jiffies-dev->trans_start);
+			ARCSTATUS,lp->intx,jiffies-dev->trans_start);
 		lp->stats.tx_errors++;
 		dev_tint(dev);
 		return 0;
@@ -1580,10 +1585,10 @@
 	if (lp->txready)	/* transmit already in progress! */
 	{
 		BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n",
-			inb(STATUS));
+			ARCSTATUS);
 		lp->intmask &= ~TXFREEflag;
 		SETMASK;
-		outb(NOTXcmd,COMMAND); /* abort current send */
+		ACOMMAND(NOTXcmd); /* abort current send */
 		arcnet_inthandler(dev); /* fake an interrupt */
 		lp->stats.tx_errors++;
 		lp->stats.tx_fifo_errors++;
@@ -1597,7 +1602,7 @@
         if (set_bit(0, (void*)&dev->tbusy) != 0)
         {
             BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-            		inb(STATUS),lp->intx,jiffies-dev->trans_start);
+            		ARCSTATUS,lp->intx,jiffies-dev->trans_start);
             lp->stats.tx_errors++;
             lp->stats.tx_fifo_errors++;
             return -EBUSY;
@@ -1613,7 +1618,7 @@
 arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad;
+	int ioaddr=IOADDR,bad;
 	struct Outgoing *out=&(lp->outgoing);
 
 	lp->intx++;
@@ -1723,11 +1728,11 @@
 static void arcnetA_continue_tx(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
+	int ioaddr=IOADDR,maxsegsize=XMTU-4;
 	struct Outgoing *out=&(lp->outgoing);
 	
 	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
-		inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
+		ARCSTATUS,lp->intx,lp->in_txhandler,lp->intmask);
 	
 	if (lp->txready)
 	{
@@ -1773,7 +1778,7 @@
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
 	struct ClientData *arcsoft;
 	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+		(union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1));
 	int offset;
 	
 #ifdef SLOW_XMIT_COPY
@@ -1790,7 +1795,7 @@
 #ifndef SLOW_XMIT_COPY
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
-		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+		memset_io(dev->mem_start+lp->txbuf*512,0x42,512);
 #endif
 
 	arcpacket->hardheader.destination=daddr;
@@ -1877,10 +1882,10 @@
 arcnet_go_tx(struct device *dev,int enable_irq)
 {
 	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr;
+	int ioaddr=IOADDR;
 
 	BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n",
-		inb(STATUS),lp->intmask,lp->txready,lp->sending);
+		ARCSTATUS,lp->intmask,lp->txready,lp->sending);
 
 	if (lp->sending || !lp->txready)
 	{
@@ -1893,7 +1898,7 @@
 	}
 	
 	/* start sending */
-	outb(TXcmd|(lp->txready<<3),COMMAND);
+	ACOMMAND(TXcmd|(lp->txready<<3));
 
 	lp->stats.tx_packets++;
 	lp->txready=0;
@@ -1940,11 +1945,11 @@
 	/* RESET flag was enabled - if !dev->start, we must clear it right
 	 * away (but nothing else) since inthandler() is never called.
 	 */
-	ioaddr=dev->base_addr;
+	ioaddr=IOADDR;	/* can't do this before checking dev!=NULL */
 	if (!dev->start)
 	{
-		if (inb(STATUS) & RESETflag)
-			outb(CFLAGScmd|RESETclear, COMMAND);
+		if (ARCSTATUS & RESETflag)
+			ACOMMAND(CFLAGScmd|RESETclear);
 		return;
 	}
 
@@ -1960,7 +1965,7 @@
 arcnet_inthandler(struct device *dev)
 {	
 	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
+	int ioaddr=IOADDR, status, boguscount = 3, didsomething;
 
 	if (IF_INTERRUPT)
 	{
@@ -1968,15 +1973,15 @@
 		return;	/* don't even try. */
 	}
 	
-	outb(0,INTMASK);
+	AINTMASK(0);
 	INTERRUPT = 1;
 
 	BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
-		inb(STATUS),lp->intmask);
+		ARCSTATUS,lp->intmask);
 
 	do
 	{
-		status = inb(STATUS);
+		status = ARCSTATUS;
 		didsomething=0;
 	
 
@@ -2049,7 +2054,7 @@
 			if (lp->intx)
 			{
 				BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
-					inb(STATUS),lp->intx);
+					ARCSTATUS,lp->intx);
 				lp->in_txhandler--;
 				continue;
 			}
@@ -2108,7 +2113,7 @@
 #ifdef DETECT_RECONFIGS
 		if (status & (lp->intmask) & RECONflag)
 		{
-			outb(CFLAGScmd|CONFIGclear,COMMAND);
+			ACOMMAND(CFLAGScmd|CONFIGclear);
 			lp->stats.tx_carrier_errors++;
 			
 			#ifdef SHOW_RECONFIGS
@@ -2179,7 +2184,7 @@
 	} while (--boguscount && didsomething);
 
 	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
-			inb(STATUS),boguscount);
+			ARCSTATUS,boguscount);
 	BUGMSG(D_DURING,"\n");
 
 	SETMASK;	/* put back interrupt mask */
@@ -2203,9 +2208,9 @@
 arcnet_rx(struct device *dev,int recbuf)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr = dev->base_addr;
+	int ioaddr=IOADDR;
 	union ArcPacket *arcpacket=
-		(union ArcPacket *)(dev->mem_start+recbuf*512);
+		(union ArcPacket *)phys_to_virt(dev->mem_start+recbuf*512);
 	u_char *arcsoft;
 	short length,offset;
 	u_char daddr,saddr;
@@ -2219,7 +2224,7 @@
 	if (saddr==0)
 	{
 		BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
-			inb(STATUS));
+			ARCSTATUS);
 		lp->stats.rx_errors++;
 		return;
 	}
@@ -2263,6 +2268,12 @@
 		arcnetS_rx(lp->sdev,arcsoft,length,saddr,daddr);
 		break;
 #endif
+	case ARC_P_DATAPOINT_BOOT:
+	case ARC_P_DATAPOINT_MOUNT:
+		break;
+	case ARC_P_POWERLAN_BEACON:
+	case ARC_P_POWERLAN_BEACON2:
+		break;
 	case ARC_P_LANSOFT: /* don't understand.  fall through. */
 	default:
 		BUGMSG(D_EXTRA,"received unknown protocol %d (%Xh) from station %d.\n",
@@ -2585,7 +2596,7 @@
 	return &lp->stats;
 }
 
-#if 0
+#if 0	/* standard ARCnet cards have no promiscuous mode */
 /* Set or clear the multicast filter for this adaptor.
  * num_addrs == -1	Promiscuous mode, receive all packets
  * num_addrs == 0	Normal mode, clear multicast list
@@ -2595,15 +2606,10 @@
 static void
 set_multicast_list(struct device *dev)
 {
-#if 0	  /* no promiscuous mode at all on most ARCnet models */
-	struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
-	short ioaddr = dev->base_addr;
 	if (num_addrs) {
-		outw(69, ioaddr);		/* Enable promiscuous mode */
+		/* Enable promiscuous mode */
 	} else
-		outw(99, ioaddr);		/* Disable promiscuous mode, use normal mode */
-#endif
+		/* Disable promiscuous mode, use normal mode */
 }
 #endif
 
@@ -2809,9 +2815,9 @@
 arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad;
+	int ioaddr=IOADDR,bad;
 	union ArcPacket *arcpacket = 
-		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
+		(union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1));
 	u_char *arcsoft,daddr;
 	short offset,length=skb->len+1;
 
@@ -2844,7 +2850,7 @@
 #ifndef SLOW_XMIT_COPY
 	/* clean out the page to make debugging make more sense :) */
 	BUGLVL(D_DURING)
-		memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
+		memset_io(dev->mem_start+lp->txbuf*512,0x42,512);
 #endif
 
 	/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
@@ -2989,7 +2995,7 @@
 arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int ioaddr=dev->base_addr,bad,length;
+	int ioaddr=IOADDR,bad,length;
 	struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
 
 	lp->intx++;
@@ -3253,61 +3259,67 @@
 static int shmem=0;
 static char *device = NULL;	/* use eg. device="arc1" to change name */
 
-int
-init_module(void)
+#ifdef RIM_I_MODE
+  static int node=0;	/* you must specify the node ID for RIM I cards */
+#endif
+
+int init_module(void)
 {
+	struct device *dev=&thiscard;
 	if (device)
-		strcpy(thiscard.name,device);
-#ifndef CONFIG_ARCNET_ETHNAME
-	else if (!thiscard.name[0]) strcpy(thiscard.name,"arc0");
-#endif
+		strcpy(dev->name,device);
+	#ifndef CONFIG_ARCNET_ETHNAME
+	  else if (!dev->name[0]) strcpy(dev->name,"arc0");
+	#endif
+
+	#ifdef RIM_I_MODE
+	if (node) io=node;
+	#endif
 
-	thiscard.base_addr=io;
+	dev->base_addr=io;
 	
 	if (irq) irqnum=irq;
-
-	thiscard.irq=irqnum;
-	if (thiscard.irq==2) thiscard.irq=9;
+	dev->irq=irqnum;
+	if (dev->irq==2) dev->irq=9;
 
 	if (shmem)
 	{
-		thiscard.mem_start=shmem;
-		thiscard.mem_end=thiscard.mem_start+512*4-1;
-		thiscard.rmem_start=thiscard.mem_start+512*0;
-		thiscard.rmem_end=thiscard.mem_start+512*2-1;
+		dev->mem_start=shmem;
+		dev->mem_end=thiscard.mem_start+512*4-1;
+		dev->rmem_start=thiscard.mem_start+512*0;
+		dev->rmem_end=thiscard.mem_start+512*2-1;
 	}
 
-	if (register_netdev(&thiscard) != 0)
+	if (register_netdev(dev) != 0)
 		return -EIO;
 	return 0;
 }
 
-void
-cleanup_module(void)
+void cleanup_module(void)
 {
-	int ioaddr=thiscard.base_addr;
+	struct device *dev=&thiscard;
+	int ioaddr=IOADDR;
 
-	if (thiscard.start) arcnet_close(&thiscard);
+	if (dev->start) arcnet_close(dev);
 
 	/* Flush TX and disable RX */
 	if (ioaddr)
 	{
-		outb(0,INTMASK);	/* disable IRQ's */
-		outb(NOTXcmd,COMMAND);  /* stop transmit */
-		outb(NORXcmd,COMMAND);	/* disable receive */
+		AINTMASK(0);		/* disable IRQ's */
+		ACOMMAND(NOTXcmd);	/* stop transmit */
+		ACOMMAND(NORXcmd);	/* disable receive */
 	}
 
-	if (thiscard.irq)
+	if (dev->irq)
 	{
-		irq2dev_map[thiscard.irq] = NULL;
-		free_irq(thiscard.irq,NULL);
+		irq2dev_map[dev->irq] = NULL;
+		free_irq(dev->irq,NULL);
 	}
 	
-	if (thiscard.base_addr) release_region(thiscard.base_addr,
-						ARCNET_TOTAL_SIZE);
-	unregister_netdev(&thiscard);
-	kfree(thiscard.priv);
-	thiscard.priv = NULL;
+	if (dev->base_addr) RELEASE_REGION(dev->base_addr,ARCNET_TOTAL_SIZE);
+	unregister_netdev(dev);
+	kfree(dev->priv);
+	dev->priv = NULL;
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.13/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.1.13/linux/drivers/net/wavelan.c	Sat Aug 17 21:02:01 1996
+++ linux/drivers/net/wavelan.c	Fri Nov 29 11:59:15 1996
@@ -69,7 +69,7 @@
 
 extern int		wavelan_probe(device *);	/* See Space.c */
 
-static const char	*version	= "wavelan.c:v8 96/8/18\n";
+static const char	*version	= "wavelan.c:v9 96/11/17\n";
 
 /*
  * Entry point forward declarations.
@@ -881,7 +881,11 @@
 		||
 		psa.psa_univ_mac_addr[1] != SA_ADDR1
 		||
-		psa.psa_univ_mac_addr[2] != SA_ADDR2
+		(
+			psa.psa_univ_mac_addr[2] != SA_ADDR2
+			&&
+			psa.psa_univ_mac_addr[2] != SA_ALT_ADDR2
+		)
 	)
 	{
 		if (wavelan_debug > 0)
diff -u --recursive --new-file v2.1.13/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h
--- v2.1.13/linux/drivers/net/wavelan.h	Sun Jul  2 10:30:38 1995
+++ linux/drivers/net/wavelan.h	Fri Nov 29 11:59:15 1996
@@ -2,6 +2,7 @@
 #define SA_ADDR0		0x08	/* First octet of WaveLAN MAC addresses */
 #define SA_ADDR1		0x00	/* Second octet of WaveLAN MAC addresses */
 #define SA_ADDR2		0x0E	/* Third octet of WaveLAN MAC addresses */
+#define SA_ALT_ADDR2		0x6A	/* Alternate third octet of WaveLAN MAC addresses */
 #define WAVELAN_MTU		1500	/* Maximum size of WaveLAN packet */
 
 /*
diff -u --recursive --new-file v2.1.13/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.1.13/linux/drivers/sbus/char/sunserial.c	Mon May  6 12:26:09 1996
+++ linux/drivers/sbus/char/sunserial.c	Sat Nov 30 10:48:34 1996
@@ -1365,17 +1365,18 @@
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
-			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
-			if (error)
-				return error;
-			put_fs_long(C_CLOCAL(tty) ? 1 : 0,
-				    (unsigned long *) arg);
-			return 0;
+			return put_user(C_CLOCAL(tty) ? 1 : 0,
+			    (unsigned int *) arg);
 		case TIOCSSOFTCAR:
-			arg = get_fs_long((unsigned long *) arg);
-			tty->termios->c_cflag =
-				((tty->termios->c_cflag & ~CLOCAL) |
-				 (arg ? CLOCAL : 0));
+			{
+			    unsigned int value;
+			    retval = get_user(value, (unsigned int *) arg);
+			    if (retval)
+				return retval;
+			    tty->termios->c_cflag =
+				    ((tty->termios->c_cflag & ~CLOCAL) |
+				     (value ? CLOCAL : 0));
+			}
 			return 0;
 		case TIOCGSERIAL:
 			error = verify_area(VERIFY_WRITE, (void *) arg,
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.1.13/linux/drivers/scsi/BusLogic.c	Tue Oct 29 19:58:12 1996
+++ linux/drivers/scsi/BusLogic.c	Sun Dec  1 09:44:53 1996
@@ -25,7 +25,7 @@
 
 
 #define BusLogic_DriverVersion		"2.0.6"
-#define BusLogic_DriverDate		"19 October 1996"
+#define BusLogic_DriverDate		"1 December 1996"
 
 
 #include <linux/module.h>
@@ -763,7 +763,7 @@
 					     *HostAdapter)
 {
   boolean TraceHardReset = (BusLogic_GlobalOptions & BusLogic_TraceHardReset);
-  int TimeoutCounter = loops_per_sec >> 2;
+  int TimeoutCounter = loops_per_sec;
   unsigned char StatusRegister = 0;
   /*
     Issue a Hard Reset Command to the Host Adapter.  The Host Adapter should
@@ -1185,7 +1185,8 @@
   /*
     ISA Host Adapters require Bounce Buffers if there is more than 16MB memory.
   */
-  if (HostAdapter->BusType == BusLogic_ISA_Bus && high_memory > MAX_DMA_ADDRESS)
+  if (HostAdapter->BusType == BusLogic_ISA_Bus &&
+      high_memory > (void *) MAX_DMA_ADDRESS)
     HostAdapter->BounceBuffersRequired = true;
   /*
     BusLogic BT-445S Host Adapters prior to controller revision E have a
@@ -1198,7 +1199,7 @@
   if (HostAdapter->BIOS_Address > 0 &&
       strcmp(HostAdapter->ModelName, "BT-445S") == 0 &&
       strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 &&
-      high_memory > MAX_DMA_ADDRESS)
+      high_memory > (void *) MAX_DMA_ADDRESS)
     HostAdapter->BounceBuffersRequired = true;
   /*
     Determine the maximum number of Target IDs and Logical Units supported by
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.1.13/linux/drivers/scsi/eata.c	Fri Nov 22 18:28:18 1996
+++ linux/drivers/scsi/eata.c	Sat Nov 23 15:28:50 1996
@@ -1,6 +1,14 @@
 /*
  *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
  *
+ *      22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
+ *          When CONFIG_PCI is defined, BIOS32 is used to include in the
+ *          list of i/o ports to be probed all the PCI SCSI controllers.
+ *          The list of i/o ports to be probed can be overwritten by the
+ *          "eata=port0, port1,...." boot command line option.
+ *          Scatter/gather lists are now allocated by a number of kmalloc
+ *          calls, in order to avoid the previous size limit of 64Kb.
+ *
  *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
  *          Added support for EATA 2.0C, PCI, multichannel and wide SCSI.
  *
@@ -79,6 +87,11 @@
  *
  *  Copyright (C) 1994, 1995, 1996 Dario Ballabio (dario@milano.europe.dg.com)
  *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that redistributions of source
+ *  code retain the above copyright notice and this comment without
+ *  modification.
+ *
  */
 
 /*
@@ -103,9 +116,10 @@
  *  supported by this driver.
  *
  *  This code has been tested with up to 3 Distributed Processing Technology 
- *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) eisa controllers,
+ *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
  *  in any combination of private and shared IRQ.
- *  PCI support has been tested using a DPT PM3224W (firmware v07G.0).
+ *  PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS 
+ *  v003.D0, firmware v07G.0).
  *
  *  Multiple ISA, EISA and PCI boards can be configured in the same system.
  *  It is suggested to put all the EISA boards on the same IRQ level, all
@@ -116,16 +130,32 @@
  *  be _level_ triggered (not _edge_ triggered).
  *
  *  This driver detects EATA boards by probes at fixed port addresses,
- *  so no BIOS32 or PCI BIOS support is used or required.
+ *  so no BIOS32 or PCI BIOS support is required.
  *  The suggested way to detect a generic EATA PCI board is to force on it
  *  any unused EISA address, even if there are other controllers on the EISA
  *  bus, or even if you system has no EISA bus at all.
  *  Do not force any ISA address on EATA PCI boards.
  *
+ *  If PCI bios support is configured into the kernel, BIOS32 is used to 
+ *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
+ *
+ *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
+ *  address on more then a single DPT PCI board, so in this case you have to
+ *  let the PCI BIOS assign the addresses.
+ *
  *  The sequence of detection probes is:
+ *
  *  - ISA 0x1F0; 
+ *  - PCI SCSI controllers (only if BIOS32 is available);
  *  - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
  *  - ISA  0x170, 0x230, 0x330.
+ * 
+ *  The above list of detection probes can be totally replaced by the
+ *  boot command line option: "eata=port0, port1, port2,...", where the
+ *  port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
+ *  For example using "eata=0x7410, 0x7450, 0x230", the driver probes
+ *  only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230,
+ *  in this order; "eata=0" totally disables this driver.
  *
  *  The boards are named EATA0, EATA1,... according to the detection order.
  *
@@ -152,9 +182,11 @@
 #include "sd.h"
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include "linux/in.h"
 #include "eata.h"
 #include<linux/stat.h>
+#include<linux/config.h>
+#include<linux/bios32.h>
+#include<linux/pci.h>
 
 struct proc_dir_entry proc_scsi_eata2x = {
     PROC_SCSI_EATA2X, 6, "eata2x",
@@ -172,17 +204,22 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
+#define MAX_ISA 4
+#define MAX_VESA 0 
+#define MAX_EISA 15
+#define MAX_PCI 16
+#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
 #define MAX_CHANNEL 4
 #define MAX_LUN 32
 #define MAX_TARGET 32
 #define MAX_IRQ 16
-#define MAX_BOARDS 18
 #define MAX_MAILBOXES 64
 #define MAX_SGLIST 64
 #define MAX_LARGE_SGLIST 252
 #define MAX_INTERNAL_RETRIES 64
 #define MAX_CMD_PER_LUN 2
 
+#define SKIP 1
 #define FALSE 0
 #define TRUE 1
 #define FREE 0
@@ -190,7 +227,6 @@
 #define LOCKED   2
 #define IN_RESET 3
 #define IGNORE   4
-#define NO_IRQ  0xff
 #define NO_DMA  0xff
 #define MAXLOOP 200000
 
@@ -205,7 +241,8 @@
 #define REG_MID         4
 #define REG_MSB         5
 #define REGION_SIZE     9
-#define EISA_RANGE      0x1000
+#define ISA_RANGE       0x0fff
+#define EISA_RANGE      0xfc88
 #define BSY_ASSERTED      0x80
 #define DRQ_ASSERTED      0x08
 #define ABSY_ASSERTED     0x01
@@ -261,13 +298,18 @@
    /* Structure extension defined in EATA 2.0B */
    unchar  isaena:1,    /* ISA i/o addressing is disabled/enabled */
 	 forcaddr:1,    /* Port address has been forced */
-		 :6;
+         large_sg:1,    /* 1 if large SG lists are supported */
+             res1:1,
+		 :4;
    unchar  max_id:5,    /* Max SCSI target ID number */
 	 max_chan:3;    /* Max SCSI channel number on this board */
 
    /* Structure extension defined in EATA 2.0C */
    unchar   max_lun;    /* Max SCSI LUN number */
-   unchar   notused[3];
+   unchar        :6,
+              pci:1,    /* This board is PCI */
+             eisa:1;    /* This board is EISA */
+   unchar   notused[2];
 
    ushort ipad[247];
    };
@@ -294,6 +336,11 @@
    char mess[12];
    };
 
+struct sg_list {
+   unsigned int address;                /* Segment Address */
+   unsigned int num_bytes;              /* Segment Length */
+   };
+
 /* MailBox SCSI Command Packet */
 struct mscp {
    unchar  sreset:1,     /* SCSI Bus Reset Signal should be asserted */
@@ -317,17 +364,12 @@
    unchar mess[3];       /* Massage to/from Target */
    unchar cdb[12];       /* Command Descriptor Block */
    ulong  data_len;      /* If sg=0 Data Length, if sg=1 sglist length */
-   Scsi_Cmnd *SCpnt;     /* Address to be returned is sp */
+   Scsi_Cmnd *SCpnt;     /* Address to be returned in sp */
    ulong  data_address;  /* If sg=0 Data Address, if sg=1 sglist address */
    ulong  sp_addr;       /* Address where sp is DMA'ed when cp completes */
    ulong  sense_addr;    /* Address where Sense Data is DMA'ed on error */
-
-   struct sg_list {
-      unsigned int address;     /* Segment Address */
-      unsigned int num_bytes;   /* Segment Length */
-      } sglist[MAX_SGLIST];
-
    unsigned int index;   /* cp index */
+   struct sg_list *sglist;
    };
 
 struct hostdata {
@@ -353,6 +395,26 @@
 static const char *driver_name = "EATA";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
+static unsigned int io_port[MAX_BOARDS + 1] = { 
+
+   /* First ISA */
+   0x1f0,
+
+   /* Space for MAX_PCI ports possibly reported by PCI_BIOS */
+    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
+    SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
+
+   /* MAX_EISA ports */
+   0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
+   0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
+
+   /* Other (MAX_ISA - 1) ports */
+   0x170,  0x230,  0x330,
+ 
+   /* End of list */
+   0x0
+   };
+
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
@@ -363,6 +425,7 @@
 
 static void eata2x_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
+static int setup_done = FALSE;
 
 static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
@@ -404,11 +467,12 @@
    return FALSE;
 }
 
-static inline int port_detect(unsigned int *port_base, unsigned int j, 
+static inline int port_detect(unsigned int port_base, unsigned int j, 
 			      Scsi_Host_Template *tpnt) {
-   unsigned char irq, dma_channel, subversion, c;
+   unsigned char irq, dma_channel, subversion, i;
    unsigned char protocol_rev;
    struct eata_info info;
+   char *bus_type;
 
    /* Allowed DMA channels for ISA (0 indicates reserved) */
    unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
@@ -417,16 +481,15 @@
 
    sprintf(name, "%s%d", driver_name, j);
 
-   if(check_region(*port_base, REGION_SIZE)) {
-      printk("%s: address 0x%03x in use, skipping probe.\n", 
-	     name, *port_base);
+   if(check_region(port_base, REGION_SIZE)) {
+      printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
       return FALSE;
       }
 
-   if (do_dma(*port_base, 0, READ_CONFIG_PIO)) return FALSE;
+   if (do_dma(port_base, 0, READ_CONFIG_PIO)) return FALSE;
 
    /* Read the info structure */
-   if (read_pio(*port_base, (ushort *)&info, (ushort *)&info.ipad[0])) 
+   if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) 
       return FALSE;
 
    /* Check the controller "EATA" signature */
@@ -446,7 +509,7 @@
 
    irq = info.irq;
 
-   if (*port_base >= EISA_RANGE) {
+   if (port_base > ISA_RANGE) {
 
       if (!info.haaval || info.ata || info.drqvld) {
 	 printk("%s: unusable EISA/PCI board found (%d%d%d), detaching.\n", 
@@ -477,8 +540,8 @@
 	     name, irq);
 
    /* Board detected, allocate its IRQ if not already done */
-   if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
-       (irq, eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+   if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
+              eata2x_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
@@ -499,7 +562,7 @@
    config.len = (ushort) htons((ushort)510);
    config.ocena = TRUE;
 
-   if (do_dma(*port_base, (unsigned int)&config, SET_CONFIG_DMA)) {
+   if (do_dma(port_base, (unsigned int)&config, SET_CONFIG_DMA)) {
       printk("%s: busy timeout sending configuration, detaching.\n", name);
       return FALSE;
       }
@@ -511,15 +574,15 @@
    if (sh[j] == NULL) {
       printk("%s: unable to register host, detaching.\n", name);
 
-      if (irqlist[irq] == NO_IRQ) free_irq(irq, NULL);
+      if (!irqlist[irq]) free_irq(irq, NULL);
 
       if (subversion == ISA) free_dma(dma_channel);
 
       return FALSE;
       }
 
-   sh[j]->io_port = *port_base;
-   sh[j]->unique_id = *port_base;
+   sh[j]->io_port = port_base;
+   sh[j]->unique_id = port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->dma_channel = dma_channel;
    sh[j]->irq = irq;
@@ -529,13 +592,13 @@
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
 
    /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, REGION_SIZE, driver_name);
+   request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name);
 
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
    HD(j)->board_number = j;
-   irqlist[irq] = j;
+   irqlist[irq]++;
 
    if (HD(j)->subversion == ESA)
       sh[j]->unchecked_isa_dma = FALSE;
@@ -548,66 +611,138 @@
       enable_dma(dma_channel);
       }
 
-   if (protocol_rev != 'A' && info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
-      sh[j]->max_channel = info.max_chan;
-
-   if (protocol_rev != 'A' && info.max_id > 7 && info.max_id < MAX_TARGET)
-      sh[j]->max_id = info.max_id + 1;
-
-   if (protocol_rev == 'C' && info.max_lun > 7 && info.max_lun < MAX_LUN)
-      sh[j]->max_lun = info.max_lun + 1;
-
    strcpy(BN(j), name);
 
-   printk("%s: rev. 2.0%c, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
-	  "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev,
-	   sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
-	   sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
-
    /* DPT PM2012 does not allow to detect sg_tablesize correctly */
    if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
-      printk("%s: detect, forcing to use %d SG lists.\n", BN(j), MAX_SGLIST);
+      printk("%s: detect, wrong n. of SG lists %d, fixed.\n",
+             BN(j), sh[j]->sg_tablesize);
       sh[j]->sg_tablesize = MAX_SGLIST;
       }
 
    /* DPT PM2012 does not allow to detect can_queue correctly */
    if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue  < 2) {
-      printk("%s: detect, forcing to use %d Mbox.\n", BN(j), MAX_MAILBOXES);
+      printk("%s: detect, wrong n. of Mbox %d, fixed.\n",
+             BN(j), sh[j]->can_queue);
       sh[j]->can_queue = MAX_MAILBOXES;
       }
 
+   if (protocol_rev != 'A') {
+
+      if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
+         sh[j]->max_channel = info.max_chan;
+
+      if (info.max_id > 7 && info.max_id < MAX_TARGET)
+         sh[j]->max_id = info.max_id + 1;
+
+      if (info.large_sg && sh[j]->sg_tablesize == MAX_SGLIST)
+         sh[j]->sg_tablesize = MAX_LARGE_SGLIST;
+      }
+
+   if (protocol_rev == 'C') {
+
+      if (info.max_lun > 7 && info.max_lun < MAX_LUN)
+         sh[j]->max_lun = info.max_lun + 1;
+      }
+
+   if (subversion == ESA && protocol_rev == 'C' && info.pci) bus_type = "PCI";
+   else if (sh[j]->io_port > EISA_RANGE) bus_type = "PCI";
+   else if (subversion == ESA) bus_type = "EISA";
+   else bus_type = "ISA";
+
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (! ((&HD(j)->cp[i])->sglist = kmalloc(
+            sh[j]->sg_tablesize * sizeof(struct sg_list), 
+            (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
+         printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
+         eata2x_release(sh[j]);
+         return FALSE;
+         }
+      
+   printk("%s: rev. 2.0%c, %s, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
+	  "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, bus_type,
+	   sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
+	   sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
+
    if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
       printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
-   for (c = 0; c <= sh[j]->max_channel; c++)
+   for (i = 0; i <= sh[j]->max_channel; i++)
       printk("%s: SCSI channel %u enabled, host target ID %u.\n",
-             BN(j), c, info.host_addr[3 - c]);
+             BN(j), i, info.host_addr[3 - i]);
 
 #if defined (DEBUG_DETECT)
-   if (protocol_rev != 'A')
-      printk("%s: EATA 2.0%c, isaena %u, forcaddr %u, max_id %u,"\
-	     " max_chan %u, max_lun %u.\n", name, protocol_rev, info.isaena, 
-	     info.forcaddr, info.max_id, info.max_chan, info.max_lun);
-
-   printk("%s: Vers. 0x%x, SYNC 0x%x, sec. %u, infol %ld, cpl %ld spl %ld.\n", 
-	  name, info.version, info.sync, info.second, DEV2H(info.data_len), 
-	  DEV2H(info.cp_len), DEV2H(info.sp_len));
+   printk("%s: Vers. 0x%x, ocs %u, tar %u, SYNC 0x%x, sec. %u, "\
+          "infol %ld, cpl %ld spl %ld.\n", name, info.version,
+          info.ocsena, info.tarsup, info.sync, info.second,
+          DEV2H(info.data_len), DEV2H(info.cp_len), DEV2H(info.sp_len));
+
+   if (protocol_rev == 'B' || protocol_rev == 'C')
+      printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\
+             "large_sg %u, res1 %u.\n", name, info.isaena, info.forcaddr,
+             info.max_id, info.max_chan, info.large_sg, info.res1);
+
+   if (protocol_rev == 'C')
+      printk("%s: max_lun %u, pci %u, eisa %u.\n", name, 
+             info.max_lun, info.pci, info.eisa);
 #endif
 
    return TRUE;
 }
 
-int eata2x_detect(Scsi_Host_Template *tpnt) {
-   unsigned int j = 0, k, flags;
+void eata2x_setup(char *str, int *ints) {
+   int i, argc = ints[0];
 
-   unsigned int io_port[] = { 
-      0x1f0,  0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88,
-      0x8c88, 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, 
-      0x170,  0x230,  0x330,  0x0
-      };
+   if (argc <= 0) return;
 
-   unsigned int *port_base = io_port;
+   if (argc > MAX_BOARDS) argc = MAX_BOARDS;
+
+   for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; 
+   
+   io_port[i] = 0;
+   setup_done = TRUE;
+   return;
+}
+
+static void add_pci_ports(void) {
+
+#if defined(CONFIG_PCI)
+
+   unsigned short i = 0;
+   unsigned char bus, devfn;
+   unsigned int addr, k;
+
+   if (!pcibios_present()) return;
+
+   for (k = 0; k < MAX_PCI; k++) {
+
+      if (pcibios_find_class(PCI_CLASS_STORAGE_SCSI << 8, i++, &bus, &devfn)
+             != PCIBIOS_SUCCESSFUL) break;
+
+      if (pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &addr)
+             != PCIBIOS_SUCCESSFUL) continue;
+
+#if defined(DEBUG_DETECT)
+      printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+             driver_name, k, bus, devfn, addr);
+#endif
+
+      if ((addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+             continue;
+
+      /* Reverse the returned address order */
+      io_port[MAX_PCI - k] = 
+             (addr & PCI_BASE_ADDRESS_IO_MASK) + PCI_BASE_ADDRESS_0;
+      }
+#endif
+
+   return;
+}
+
+int eata2x_detect(Scsi_Host_Template *tpnt) {
+   unsigned long flags;
+   unsigned int j = 0, k;
 
    tpnt->proc_dir = &proc_scsi_eata2x;
 
@@ -615,17 +750,19 @@
    cli();
 
    for (k = 0; k < MAX_IRQ; k++) {
-      irqlist[k] = NO_IRQ;
+      irqlist[k] = 0;
       calls[k] = 0;
       }
 
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
-   while (*port_base) {
+   if (!setup_done) add_pci_ports();
 
-      if (j < MAX_BOARDS && port_detect(port_base, j, tpnt)) j++;
+   for (k = 0; io_port[k]; k++) {
 
-      port_base++;
+      if (io_port[k] == SKIP) continue;
+
+      if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
    if (j > 0) 
@@ -651,7 +788,8 @@
 }
 
 int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k, flags;
+   unsigned long flags;
+   unsigned int i, j, k;
    struct mscp *cpp;
    struct mssp *spp;
 
@@ -702,7 +840,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp));
+   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
 
    /* Set pointer to status packet structure */
    spp = &HD(j)->sp[i];
@@ -766,7 +904,8 @@
 }
 
 int eata2x_abort(Scsi_Cmnd *SCarg) {
-   unsigned int i, j, flags;
+   unsigned long flags;
+   unsigned int i, j;
 
    save_flags(flags);
    cli();
@@ -805,6 +944,9 @@
 	 panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
 	       BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
+      if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
       restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
       }
@@ -825,7 +967,8 @@
 }
 
 int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, c, limit = 0;
+   unsigned long flags;
+   unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
@@ -944,14 +1087,15 @@
 static void eata2x_interrupt_handler(int irq, void *dev_id,
                                      struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
+   unsigned long flags;
+   unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0;
    struct mssp *spp;
    struct mscp *cpp;
 
    save_flags(flags);
    cli();
 
-   if (irqlist[irq] == NO_IRQ) {
+   if (!irqlist[irq]) {
       printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
       restore_flags(flags);
       return;
@@ -1158,6 +1302,31 @@
 
    restore_flags(flags);
    return;
+}
+
+int eata2x_release(struct Scsi_Host *shpnt) {
+   unsigned long flags;
+   unsigned int i, j;
+
+   save_flags(flags);
+   cli();
+
+   for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
+    
+   if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
+                            driver_name);
+
+   for (i = 0; i < sh[j]->can_queue; i++) 
+      if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
+
+   if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+
+   if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
+
+   release_region(sh[j]->io_port, sh[j]->n_io_port);
+   scsi_unregister(sh[j]);
+   restore_flags(flags);
+   return FALSE;
 }
 
 #if defined(MODULE)
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/eata.h linux/drivers/scsi/eata.h
--- v2.1.13/linux/drivers/scsi/eata.h	Fri Nov 22 18:28:18 1996
+++ linux/drivers/scsi/eata.h	Sat Nov 23 15:28:50 1996
@@ -7,11 +7,12 @@
 #include <scsi/scsicam.h>
 
 int eata2x_detect(Scsi_Host_Template *);
+int eata2x_release(struct Scsi_Host *);
 int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *, unsigned int);
 
-#define EATA_VERSION "2.20.00"
+#define EATA_VERSION "2.30.00"
 
 
 #define EATA {                                                 \
@@ -21,7 +22,7 @@
 		NULL,                                          \
 		"EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
 		eata2x_detect,				       \
-		NULL, /* Release */     		       \
+		eata2x_release,          		       \
 		NULL,					       \
 		NULL,    			       	       \
 		eata2x_queuecommand,			       \
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c
--- v2.1.13/linux/drivers/scsi/sd_ioctl.c	Tue Oct 29 19:58:13 1996
+++ linux/drivers/scsi/sd_ioctl.c	Fri Nov 29 11:20:08 1996
@@ -76,10 +76,10 @@
     case BLKRAGET:
 	if (!arg)
 		return -EINVAL;
-	error = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
+	error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 	if (error)
 	    return error;
-	put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) arg);
+	put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
 	return 0;
 
     case BLKFLSBUF:
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.1.13/linux/drivers/scsi/seagate.c	Tue Oct 29 19:58:13 1996
+++ linux/drivers/scsi/seagate.c	Fri Nov 29 11:12:37 1996
@@ -345,7 +345,7 @@
 
 	if (base_address)
 		{
-		st0x_cr_sr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00)); 
+		st0x_cr_sr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00); 
 		st0x_dr = st0x_cr_sr + 0x200;
 #ifdef DEBUG
 		printk("%s detected. Base address = %x, cr = %x, dr = %x\n", tpnt->name, base_address, st0x_cr_sr, st0x_dr);
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.1.13/linux/drivers/scsi/sr_ioctl.c	Fri Nov 22 18:28:19 1996
+++ linux/drivers/scsi/sr_ioctl.c	Fri Nov 29 11:20:08 1996
@@ -209,6 +209,8 @@
 }
 
 /* ----------------------------------------------------------------------- */
+/* this is called by the generic cdrom driver. arg is a _kernel_ pointer,  */
+/* becauce the generic cdrom driver does the user access stuff for us.     */
 
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
 {
@@ -246,22 +248,17 @@
 	
     case CDROMPLAYMSF:
     {
-	struct cdrom_msf msf;
-
-	if (copy_from_user(&msf, (void *) arg, sizeof(msf))) {
-		result = -EFAULT;
-		break;
-	}
+	struct cdrom_msf* msf = (struct cdrom_msf*)arg;
 
 	sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
 	sr_cmd[1] = scsi_CDs[target].device->lun << 5;
 	sr_cmd[2] = 0;
-	sr_cmd[3] = msf.cdmsf_min0;
-	sr_cmd[4] = msf.cdmsf_sec0;
-	sr_cmd[5] = msf.cdmsf_frame0;
-	sr_cmd[6] = msf.cdmsf_min1;
-	sr_cmd[7] = msf.cdmsf_sec1;
-	sr_cmd[8] = msf.cdmsf_frame1;
+	sr_cmd[3] = msf->cdmsf_min0;
+	sr_cmd[4] = msf->cdmsf_sec0;
+	sr_cmd[5] = msf->cdmsf_frame0;
+	sr_cmd[6] = msf->cdmsf_min1;
+	sr_cmd[7] = msf->cdmsf_sec1;
+	sr_cmd[8] = msf->cdmsf_frame1;
 	sr_cmd[9] = 0;
 	
 	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
@@ -270,22 +267,17 @@
 
     case CDROMPLAYBLK:
     {
-	struct cdrom_blk blk;
-
-	if (copy_from_user(&blk, (void *) arg, sizeof(blk))) {
-		result = -EFAULT;
-		break;
-	}
+	struct cdrom_blk* blk = (struct cdrom_blk*)arg;
 
 	sr_cmd[0] = SCMD_PLAYAUDIO10;
 	sr_cmd[1] = scsi_CDs[target].device->lun << 5;
-	sr_cmd[2] = blk.from >> 24;
-	sr_cmd[3] = blk.from >> 16;
-	sr_cmd[4] = blk.from >> 8;
-	sr_cmd[5] = blk.from;
+	sr_cmd[2] = blk->from >> 24;
+	sr_cmd[3] = blk->from >> 16;
+	sr_cmd[4] = blk->from >> 8;
+	sr_cmd[5] = blk->from;
 	sr_cmd[6] = 0;
-	sr_cmd[7] = blk.len >> 8;
-	sr_cmd[8] = blk.len;
+	sr_cmd[7] = blk->len >> 8;
+	sr_cmd[8] = blk->len;
 	sr_cmd[9] = 0;
 	
 	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
@@ -294,22 +286,17 @@
 		
     case CDROMPLAYTRKIND:
     {
-	struct cdrom_ti ti;
-
-	if (copy_from_user(&ti, (void *) arg, sizeof(ti))) {
-		result = -EFAULT;
-		break;
-	}
+	struct cdrom_ti* ti = (struct cdrom_ti*)arg;
 
 	sr_cmd[0] = SCMD_PLAYAUDIO_TI;
 	sr_cmd[1] = scsi_CDs[target].device->lun << 5;
 	sr_cmd[2] = 0;
 	sr_cmd[3] = 0;
-	sr_cmd[4] = ti.cdti_trk0;
-	sr_cmd[5] = ti.cdti_ind0;
+	sr_cmd[4] = ti->cdti_trk0;
+	sr_cmd[5] = ti->cdti_ind0;
 	sr_cmd[6] = 0;
-	sr_cmd[7] = ti.cdti_trk1;
-	sr_cmd[8] = ti.cdti_ind1;
+	sr_cmd[7] = ti->cdti_trk1;
+	sr_cmd[8] = ti->cdti_ind1;
 	sr_cmd[9] = 0;
 	
 	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
@@ -318,7 +305,7 @@
 	
     case CDROMREADTOCHDR:
     {
-	struct cdrom_tochdr tochdr;
+	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
 	char * buffer;
 	
 	sr_cmd[0] = SCMD_READ_TOC;
@@ -334,31 +321,23 @@
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 12);
 	
-	tochdr.cdth_trk0 = buffer[2];
-	tochdr.cdth_trk1 = buffer[3];
+	tochdr->cdth_trk0 = buffer[2];
+	tochdr->cdth_trk1 = buffer[3];
 	
 	scsi_free(buffer, 512);
-
-	if (copy_to_user ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr)))
-		result = -EFAULT;
         break;
     }
 	
     case CDROMREADTOCENTRY:
     {
-	struct cdrom_tocentry tocentry;
+	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
 	unsigned char * buffer;
 	
-	if (copy_from_user (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry))) {
-		result = -EFAULT;
-		break;
-	}
-
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
-          (tocentry.cdte_format == CDROM_MSF ? 0x02 : 0);
+          (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = tocentry.cdte_track;
+	sr_cmd[6] = tocentry->cdte_track;
 	sr_cmd[7] = 0;             /* MSB of length (12)  */
 	sr_cmd[8] = 12;            /* LSB of length */
 	sr_cmd[9] = 0;
@@ -368,21 +347,18 @@
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 12);
 	
-        tocentry.cdte_ctrl = buffer[5] & 0xf;	
-        tocentry.cdte_adr = buffer[5] >> 4;
-        tocentry.cdte_datamode = (tocentry.cdte_ctrl & 0x04) ? 1 : 0;
-	if (tocentry.cdte_format == CDROM_MSF) {
-	    tocentry.cdte_addr.msf.minute = buffer[9];
-	    tocentry.cdte_addr.msf.second = buffer[10];
-	    tocentry.cdte_addr.msf.frame = buffer[11];
+        tocentry->cdte_ctrl = buffer[5] & 0xf;	
+        tocentry->cdte_adr = buffer[5] >> 4;
+        tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+	if (tocentry->cdte_format == CDROM_MSF) {
+	    tocentry->cdte_addr.msf.minute = buffer[9];
+	    tocentry->cdte_addr.msf.second = buffer[10];
+	    tocentry->cdte_addr.msf.frame = buffer[11];
 	} else
-	    tocentry.cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
                                        + buffer[10]) << 8) + buffer[11];
 	
 	scsi_free(buffer, 512);
-
-	if (copy_to_user ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry)))
-		result = -EFAULT;
         break;
     }
 	
@@ -407,13 +383,8 @@
     case CDROMVOLCTRL:
     {
 	char * buffer, * mask;
-	struct cdrom_volctrl volctrl;
+	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
 	
-	if (copy_from_user (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl))) {
-		result = -EFAULT;
-		break;
-	}
-
 	/* First we get the current params so we can just twiddle the volume */
 	
 	sr_cmd[0] = MODE_SENSE;
@@ -456,10 +427,10 @@
 	/* Now mask and substitute our own volume and reuse the rest */
 	buffer[0] = 0;  /* Clear reserved field */
 	
-	buffer[21] = volctrl.channel0 & mask[21];
-	buffer[23] = volctrl.channel1 & mask[23];
-	buffer[25] = volctrl.channel2 & mask[25];
-	buffer[27] = volctrl.channel3 & mask[27];
+	buffer[21] = volctrl->channel0 & mask[21];
+	buffer[23] = volctrl->channel1 & mask[23];
+	buffer[25] = volctrl->channel2 & mask[25];
+	buffer[27] = volctrl->channel3 & mask[27];
 	
 	sr_cmd[0] = MODE_SELECT;
 	sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;    /* Params are SCSI-2 */
@@ -476,7 +447,7 @@
     case CDROMVOLREAD:
     {
 	char * buffer;
-	struct cdrom_volctrl volctrl;
+	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
 	
 	/* Get the current params */
 	
@@ -496,21 +467,18 @@
             break;
 	}
 
-	volctrl.channel0 = buffer[21];
-	volctrl.channel1 = buffer[23];
-	volctrl.channel2 = buffer[25];
-	volctrl.channel3 = buffer[27];
+	volctrl->channel0 = buffer[21];
+	volctrl->channel1 = buffer[23];
+	volctrl->channel2 = buffer[25];
+	volctrl->channel3 = buffer[27];
 
 	scsi_free(buffer, 512);
-
-	if (copy_to_user ((void *) arg, &volctrl, sizeof (struct cdrom_volctrl)))
-		result = -EFAULT;
         break;
     }
 	
     case CDROMSUBCHNL:
     {
-	struct cdrom_subchnl subchnl;
+	struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
 	char * buffer;
 	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
@@ -528,23 +496,20 @@
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 16);
 	
-	subchnl.cdsc_audiostatus = buffer[1];
-	subchnl.cdsc_format = CDROM_MSF;
-	subchnl.cdsc_ctrl = buffer[5] & 0xf;
-	subchnl.cdsc_trk = buffer[6];
-	subchnl.cdsc_ind = buffer[7];
-	
-	subchnl.cdsc_reladdr.msf.minute = buffer[13];
-	subchnl.cdsc_reladdr.msf.second = buffer[14];
-	subchnl.cdsc_reladdr.msf.frame = buffer[15];
-	subchnl.cdsc_absaddr.msf.minute = buffer[9];
-	subchnl.cdsc_absaddr.msf.second = buffer[10];
-	subchnl.cdsc_absaddr.msf.frame = buffer[11];
+	subchnl->cdsc_audiostatus = buffer[1];
+	subchnl->cdsc_format = CDROM_MSF;
+	subchnl->cdsc_ctrl = buffer[5] & 0xf;
+	subchnl->cdsc_trk = buffer[6];
+	subchnl->cdsc_ind = buffer[7];
+	
+	subchnl->cdsc_reladdr.msf.minute = buffer[13];
+	subchnl->cdsc_reladdr.msf.second = buffer[14];
+	subchnl->cdsc_reladdr.msf.frame = buffer[15];
+	subchnl->cdsc_absaddr.msf.minute = buffer[9];
+	subchnl->cdsc_absaddr.msf.second = buffer[10];
+	subchnl->cdsc_absaddr.msf.frame = buffer[11];
 	
 	scsi_free(buffer, 512);
-
-	if (copy_to_user ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl)))
-		result = -EFAULT;
         break;
     }
     default:
@@ -573,10 +538,10 @@
     case BLKRAGET:
 	if (!arg)
 		return -EINVAL;
-	err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
+	err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 	if (err)
 		return err;
-	put_user(read_ahead[MAJOR(cdi->dev)], (int *) arg);
+	put_user(read_ahead[MAJOR(cdi->dev)], (long *) arg);
 	return 0;
 
     case BLKRASET:
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.1.13/linux/drivers/scsi/u14-34f.c	Fri Nov 22 18:28:19 1996
+++ linux/drivers/scsi/u14-34f.c	Sat Nov 23 15:28:50 1996
@@ -1,6 +1,12 @@
 /*
  *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
  *
+ *      21 Nov 1996 rev. 2.30 for linux 2.1.11 and 2.0.25
+ *          The list of i/o ports to be probed can be overwritten by the
+ *          "u14-34f=port0, port1,...." boot command line option.
+ *          Scatter/gather lists are now allocated by a number of kmalloc
+ *          calls, in order to avoid the previous size limit of 64Kb.
+ *
  *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
  *          Added multichannel support.
  *
@@ -74,6 +80,11 @@
  *
  *  Copyright (C) 1994, 1995, 1996 Dario Ballabio (dario@milano.europe.dg.com)
  *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that redistributions of source
+ *  code retain the above copyright notice and this comment without
+ *  modification.
+ *
  *      WARNING: if your 14/34F board has an old firmware revision (see below)
  *               you must change "#undef" into "#define" in the following
  *               statement.
@@ -149,6 +160,15 @@
  *  the latest firmware prom is 28008-006. Older firmware 28008-005 has
  *  problems when using more then 16 scatter/gather lists.
  *
+ *  The list of i/o ports to be probed can be totally replaced by the
+ *  boot command line option: "u14-34f=port0, port1, port2,...", where the
+ *  port0, port1... arguments are ISA/VESA addresses to be probed.
+ *  For example using "u14-34f=0x230, 0x340", the driver probes only the two
+ *  addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables
+ *  this driver.
+ *
+ *  The boards are named Ux4F0, Ux4F1,... according to the detection order.
+ *
  *  In order to support multiple ISA boards in a reliable way,
  *  the driver sets host->wish_block = TRUE for all ISA boards.
  */
@@ -205,11 +225,15 @@
 #undef  DEBUG_STATISTICS
 #undef  DEBUG_RESET
 
+#define MAX_ISA 3
+#define MAX_VESA 1 
+#define MAX_EISA 0
+#define MAX_PCI 0
+#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
 #define MAX_CHANNEL 1
 #define MAX_LUN 8
 #define MAX_TARGET 8
 #define MAX_IRQ 16
-#define MAX_BOARDS 4
 #define MAX_MAILBOXES 16
 #define MAX_SGLIST 32
 #define MAX_SAFE_SGLIST 16
@@ -223,7 +247,6 @@
 #define LOCKED   2
 #define IN_RESET 3
 #define IGNORE   4
-#define NO_IRQ  0xff
 #define NO_DMA  0xff
 #define MAXLOOP 200000
 
@@ -251,6 +274,11 @@
 
 #define PACKED          __attribute__((packed))
 
+struct sg_list {
+   unsigned int address;                /* Segment Address */
+   unsigned int num_bytes;              /* Segment Length */
+   };
+
 /* MailBox SCSI Command Packet */
 struct mscp {
    unsigned char opcode: 3;             /* type of command */
@@ -272,15 +300,9 @@
    unsigned char adapter_status;        /* non-zero indicates HA error */
    unsigned char target_status;         /* non-zero indicates target error */
    unsigned int sense_addr PACKED;
-
    Scsi_Cmnd *SCpnt;
-
-   struct sg_list {
-      unsigned int address;             /* Segment Address */
-      unsigned int num_bytes;           /* Segment Length */
-      } sglist[MAX_SGLIST];
-
-   unsigned int index;   /* cp index */
+   unsigned int index;                  /* cp index */
+   struct sg_list *sglist;
    };
 
 struct hostdata {
@@ -309,6 +331,13 @@
 static const char *driver_name = "Ux4F";
 static unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
+static unsigned int io_port[] = {
+      0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140,
+
+      /* End of list */
+      0x0
+      };
+
 #define HD(board) ((struct hostdata *) &sh[board]->hostdata)
 #define BN(board) (HD(board)->board_name)
 
@@ -328,6 +357,7 @@
 
 static void u14_34f_interrupt_handler(int, void *, struct pt_regs *);
 static int do_trace = FALSE;
+static int setup_done = FALSE;
 
 static inline int wait_on_busy(unsigned int iobase) {
    unsigned int loop = MAXLOOP;
@@ -381,9 +411,9 @@
    return FALSE;
 }
 
-static inline int port_detect(unsigned int *port_base, unsigned int j, 
-			      Scsi_Host_Template *tpnt) {
-   unsigned char irq, dma_channel, subversion, c;
+static inline int port_detect(unsigned int port_base, unsigned int j, 
+                              Scsi_Host_Template *tpnt) {
+   unsigned char irq, dma_channel, subversion, i;
    unsigned char in_byte;
 
    /* Allowed BIOS base addresses (NULL indicates reserved) */
@@ -425,28 +455,27 @@
 
    sprintf(name, "%s%d", driver_name, j);
 
-   if(check_region(*port_base, REGION_SIZE)) {
-      printk("%s: address 0x%03x in use, skipping probe.\n", 
-	     name, *port_base);
+   if(check_region(port_base, REGION_SIZE)) {
+      printk("%s: address 0x%03x in use, skipping probe.\n", name, port_base);
       return FALSE;
       }
 
-   if (inb(*port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) return FALSE;
+   if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) return FALSE;
 
-   in_byte = inb(*port_base + REG_PRODUCT_ID2);
+   in_byte = inb(port_base + REG_PRODUCT_ID2);
 
    if ((in_byte & 0xf0) != PRODUCT_ID2) return FALSE;
 
-   *(char *)&config_1 = inb(*port_base + REG_CONFIG1);
-   *(char *)&config_2 = inb(*port_base + REG_CONFIG2);
+   *(char *)&config_1 = inb(port_base + REG_CONFIG1);
+   *(char *)&config_2 = inb(port_base + REG_CONFIG2);
 
    irq = interrupt_table[config_1.interrupt];
    dma_channel = dma_channel_table[config_1.dma_channel];
    subversion = (in_byte & 0x0f);
 
    /* Board detected, allocate its IRQ if not already done */
-   if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
-       (irq, u14_34f_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
+   if ((irq >= MAX_IRQ) || (!irqlist[irq] && request_irq(irq,
+              u14_34f_interrupt_handler, SA_INTERRUPT, driver_name, NULL))) {
       printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
       return FALSE;
       }
@@ -463,15 +492,15 @@
    if (sh[j] == NULL) {
       printk("%s: unable to register host, detaching.\n", name);
 
-      if (irqlist[irq] == NO_IRQ) free_irq(irq, NULL);
+      if (!irqlist[irq]) free_irq(irq, NULL);
 
       if (subversion == ISA) free_dma(dma_channel);
 
       return FALSE;
       }
 
-   sh[j]->io_port = *port_base;
-   sh[j]->unique_id = *port_base;
+   sh[j]->io_port = port_base;
+   sh[j]->unique_id = port_base;
    sh[j]->n_io_port = REGION_SIZE;
    sh[j]->base = bios_segment_table[config_1.bios_segment];
    sh[j]->irq = irq;
@@ -494,14 +523,14 @@
    if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
 
    /* Register the I/O space that we use */
-   request_region(sh[j]->io_port, REGION_SIZE, driver_name);
+   request_region(sh[j]->io_port, sh[j]->n_io_port, driver_name);
 
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->heads = mapping_table[config_2.mapping_mode].heads;
    HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
    HD(j)->subversion = subversion;
    HD(j)->board_number = j;
-   irqlist[irq] = j;
+   irqlist[irq]++;
 
    if (HD(j)->subversion == ESA) {
 
@@ -546,6 +575,15 @@
 	 }
       }
 
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (! ((&HD(j)->cp[i])->sglist = kmalloc(
+            sh[j]->sg_tablesize * sizeof(struct sg_list), 
+            (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
+         printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
+         u14_34f_release(sh[j]);
+         return FALSE;
+         }
+      
    printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
 	  "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
 	  (int)sh[j]->base, sh[j]->irq, sh[j]->dma_channel,
@@ -556,21 +594,30 @@
       printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
-   for (c = 0; c <= sh[j]->max_channel; c++)
+   for (i = 0; i <= sh[j]->max_channel; i++)
       printk("%s: SCSI channel %u enabled, host target ID %u.\n",
-             BN(j), c, sh[j]->this_id);
+             BN(j), i, sh[j]->this_id);
 
    return TRUE;
 }
 
-int u14_34f_detect(Scsi_Host_Template *tpnt) {
-   unsigned int j = 0, k, flags;
+void u14_34f_setup(char *str, int *ints) {
+   int i, argc = ints[0];
 
-   unsigned int io_port[] = {
-      0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, 0x0
-      };
+   if (argc <= 0) return;
 
-   unsigned int *port_base = io_port;
+   if (argc > MAX_BOARDS) argc = MAX_BOARDS;
+
+   for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; 
+   
+   io_port[i] = 0;
+   setup_done = TRUE;
+   return;
+}
+
+int u14_34f_detect(Scsi_Host_Template *tpnt) {
+   unsigned long flags;
+   unsigned int j = 0, k;
 
    tpnt->proc_dir = &proc_scsi_u14_34f;
 
@@ -578,18 +625,14 @@
    cli();
 
    for (k = 0; k < MAX_IRQ; k++) {
-      irqlist[k] = NO_IRQ;
+      irqlist[k] = 0;
       calls[k] = 0;
       }
 
    for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
 
-   while (*port_base) {
-
-      if (j < MAX_BOARDS && port_detect(port_base, j, tpnt)) j++;
-
-      port_base++;
-      }
+   for (k = 0; io_port[k]; k++)
+      if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
 
    if (j > 0) 
       printk("UltraStor 14F/34F: Copyright (C) 1994, 1995, 1996 Dario Ballabio.\n");
@@ -616,7 +659,8 @@
 }
 
 int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
-   unsigned int i, j, k, flags;
+   unsigned long flags;
+   unsigned int i, j, k;
    struct mscp *cpp;
 
    static const unsigned char data_out_cmds[] = {
@@ -666,7 +710,7 @@
    /* Set pointer to control packet structure */
    cpp = &HD(j)->cp[i];
 
-   memset(cpp, 0, sizeof(struct mscp));
+   memset(cpp, 0, sizeof(struct mscp) - sizeof(struct sg_list *));
    SCpnt->scsi_done = done;
    cpp->index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->index;
@@ -726,7 +770,8 @@
 }
 
 int u14_34f_abort(Scsi_Cmnd *SCarg) {
-   unsigned int i, j, flags;
+   unsigned long flags;
+   unsigned int i, j;
 
    save_flags(flags);
    cli();
@@ -765,6 +810,9 @@
 	 panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
 	       BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
 
+      if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
       restore_flags(flags);
       return SCSI_ABORT_SNOOZE;
       }
@@ -785,7 +833,8 @@
 }
 
 int u14_34f_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
-   unsigned int i, j, flags, time, k, c, limit = 0;
+   unsigned long flags;
+   unsigned int i, j, time, k, c, limit = 0;
    int arg_done = FALSE;
    Scsi_Cmnd *SCpnt;
 
@@ -909,19 +958,20 @@
    dkinfo[0] = HD(j)->heads;
    dkinfo[1] = HD(j)->sectors;
    dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
-   return 0;
+   return FALSE;
 }
 
 static void u14_34f_interrupt_handler(int irq, void *dev_id,
                                       struct pt_regs *regs) {
    Scsi_Cmnd *SCpnt;
-   unsigned int i, j, k, c, flags, status, tstatus, loops, total_loops = 0;
+   unsigned long flags;
+   unsigned int i, j, k, c, status, tstatus, loops, total_loops = 0;
    struct mscp *spp;
 
    save_flags(flags);
    cli();
 
-   if (irqlist[irq] == NO_IRQ) {
+   if (!irqlist[irq]) {
       printk("%s, ihdlr, irq %d, unexpected interrupt.\n", driver_name, irq);
       restore_flags(flags);
       return;
@@ -1122,6 +1172,31 @@
 
    restore_flags(flags);
    return;
+}
+
+int u14_34f_release(struct Scsi_Host *shpnt) {
+   unsigned long flags;
+   unsigned int i, j;
+
+   save_flags(flags);
+   cli();
+
+   for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
+    
+   if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
+                            driver_name);
+
+   for (i = 0; i < sh[j]->can_queue; i++) 
+      if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
+
+   if (! --irqlist[sh[j]->irq]) free_irq(sh[j]->irq, NULL);
+
+   if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
+
+   release_region(sh[j]->io_port, sh[j]->n_io_port);
+   scsi_unregister(sh[j]);
+   restore_flags(flags);
+   return FALSE;
 }
 
 #if defined(MODULE)
diff -u --recursive --new-file v2.1.13/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h
--- v2.1.13/linux/drivers/scsi/u14-34f.h	Fri Nov 22 18:28:19 1996
+++ linux/drivers/scsi/u14-34f.h	Sat Nov 23 15:28:50 1996
@@ -5,12 +5,13 @@
 #define _U14_34F_H
 
 int u14_34f_detect(Scsi_Host_Template *);
+int u14_34f_release(struct Scsi_Host *);
 int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *, unsigned int);
 int u14_34f_biosparam(Disk *, kdev_t, int *);
 
-#define U14_34F_VERSION "2.20.00"
+#define U14_34F_VERSION "2.30.00"
 
 #define ULTRASTOR_14_34F {                                            \
 		NULL, /* Ptr for modules */                           \
@@ -19,7 +20,7 @@
 		NULL,		                                      \
 		"UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
 		u14_34f_detect,                                       \
-		NULL, /* Release */                                   \
+		u14_34f_release,                                      \
 		NULL,						      \
 		NULL,                                                 \
 		u14_34f_queuecommand,                                 \
diff -u --recursive --new-file v2.1.13/linux/drivers/sound/.blurb.orig linux/drivers/sound/.blurb.orig
--- v2.1.13/linux/drivers/sound/.blurb.orig	Sun Jun 30 11:43:44 1996
+++ linux/drivers/sound/.blurb.orig	Thu Jan  1 02:00:00 1970
@@ -1,10 +0,0 @@
-*********************************************************
-* Readme.cards (this directory) contains some card	*
-* specific instructions.				*
-* See http://www.4front-tech.com/usslite for most up    *
-* to date info.                                         *
-* (European mirror http://personal.eunet.fi/pp/voxware) *
-*							*
-* DON'T USE PROGRAMS FROM SND_UTIL PACKAGE EARLIER THAN *
-* snd-util-3.5 WITH THIS SOUND DRIVER VERSION.          *
-*********************************************************
diff -u --recursive --new-file v2.1.13/linux/drivers/sound/.objects.orig linux/drivers/sound/.objects.orig
--- v2.1.13/linux/drivers/sound/.objects.orig	Tue Oct 29 19:58:13 1996
+++ linux/drivers/sound/.objects.orig	Thu Jan  1 02:00:00 1970
@@ -1,98 +0,0 @@
-OBJS=
-
-ifdef CONFIG_AD1848
-	OBJS := $(OBJS)  ad1848.o
-endif
-
-ifdef CONFIG_YM3812
-	OBJS := $(OBJS)  adlib_card.o
-endif
-
-ifdef CONFIG_AEDSP16
-	OBJS := $(OBJS)  aedsp16.o
-endif
-
-ifdef CONFIG_AUDIO
-	OBJS := $(OBJS)  audio.o
-endif
-
-ifdef CONFIG_CS4232
-	OBJS := $(OBJS)  cs4232.o
-endif
-
-ifdef CONFIG_AUDIO
-	OBJS := $(OBJS)  dmabuf.o
-endif
-
-ifdef CONFIG_GUSHW
-	OBJS := $(OBJS)  gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
-endif
-
-ifdef CONFIG_MAD16
-	OBJS := $(OBJS)  mad16.o
-endif
-
-ifdef CONFIG_MAUI
-	OBJS := $(OBJS)  maui.o
-endif
-
-ifdef CONFIG_MIDI
-	OBJS := $(OBJS)  midi_synth.o midibuf.o
-endif
-
-ifdef CONFIG_MPU401
-	OBJS := $(OBJS)  mpu401.o
-else
-  ifdef CONFIG_MPU_EMU
-	OBJS := $(OBJS)  mpu401.o
-  endif
-endif
-
-ifdef CONFIG_YM3812
-	OBJS := $(OBJS)  opl3.o
-endif
-
-ifdef CONFIG_PAS
-	OBJS := $(OBJS)  pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
-endif
-
-ifdef CONFIG_SEQUENCER
-	OBJS := $(OBJS)  patmgr.o
-endif
-
-ifdef CONFIG_PSS
-	OBJS := $(OBJS)  pss.o
-endif
-
-ifdef CONFIG_SBDSP
-	OBJS := $(OBJS) sb_card.o sb_common.o sb_audio.o sb_mixer.o sb_midi.o
-endif
-
-ifdef CONFIG_SEQUENCER
-	OBJS := $(OBJS)  sequencer.o
-endif
-
-ifdef CONFIG_SEQUENCER
-	OBJS := $(OBJS)  sound_timer.o
-endif
-
-ifdef CONFIG_SSCAPEHW
-	OBJS := $(OBJS)  sscape.o
-endif
-
-ifdef CONFIG_TRIX
-	OBJS := $(OBJS)  trix.o
-endif
-
-ifdef CONFIG_SEQUENCER
-	OBJS := $(OBJS)  sys_timer.o
-endif
-
-ifdef CONFIG_UART6850
-	OBJS := $(OBJS)  uart6850.o
-endif
-
-ifdef CONFIG_UART401
-	OBJS := $(OBJS)  uart401.o
-endif
-
diff -u --recursive --new-file v2.1.13/linux/drivers/sound/.version.orig linux/drivers/sound/.version.orig
--- v2.1.13/linux/drivers/sound/.version.orig	Tue Oct 29 19:58:13 1996
+++ linux/drivers/sound/.version.orig	Thu Jan  1 02:00:00 1970
@@ -1,2 +0,0 @@
-3.7-beta6
-0x030701
diff -u --recursive --new-file v2.1.13/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v2.1.13/linux/drivers/sound/dev_table.h	Sat Nov 30 12:03:09 1996
+++ linux/drivers/sound/dev_table.h	Mon Nov 25 15:27:31 1996
@@ -322,7 +322,7 @@
 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
 		{"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401",	attach_mpu401, probe_mpu401, unload_mpu401},
 #endif
-#if (defined(CONFIG_UART401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+#if defined(CONFIG_UART401) && defined(CONFIG_MIDI)
 	{"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", 
 		attach_uart401, probe_uart401, unload_uart401},
 #endif
diff -u --recursive --new-file v2.1.13/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.1.13/linux/drivers/sound/dmabuf.c	Sat Nov 30 12:03:09 1996
+++ linux/drivers/sound/dmabuf.c	Sun Nov 24 16:32:06 1996
@@ -581,6 +581,7 @@
   audio_devs[dev]->dmap_out->closing = 1;
   audio_devs[dev]->dmap_in->closing = 1;
 
+  if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED))
   if (!((current->signal & ~current->blocked))
       && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT))
     {
diff -u --recursive --new-file v2.1.13/linux/fs/Config.in linux/fs/Config.in
--- v2.1.13/linux/fs/Config.in	Tue Nov 12 15:56:11 1996
+++ linux/fs/Config.in	Sun Dec  1 18:21:32 1996
@@ -27,8 +27,8 @@
     fi
   fi
   tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS
-  if [ "$CONFIG_SMB_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'SMB long filename support (EXPERIMENTAL)' CONFIG_SMB_LONG
+  if [ "$CONFIG_SMB_FS" != "n" ]; then
+    bool 'SMB Win95 bug work-around' CONFIG_SMB_WIN95
   fi
 fi
 if [ "$CONFIG_IPX" != "n" ]; then
diff -u --recursive --new-file v2.1.13/linux/fs/binfmt_script.c linux/fs/binfmt_script.c
--- v2.1.13/linux/fs/binfmt_script.c	Fri Nov 22 18:28:20 1996
+++ linux/fs/binfmt_script.c	Mon Nov 25 15:29:51 1996
@@ -13,7 +13,7 @@
 
 static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
 {
-	char *cp, *i_name, *i_arg;
+	char *cp, *i_name, *i_name_start, *i_arg;
 	char interp[128];
 	int retval;
 	if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) 
@@ -39,10 +39,9 @@
 			break;
 	}
 	for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++);
-	if (cp == '\0') 
+	if (*cp == '\0') 
 		return -ENOEXEC; /* No interpreter name found */
-	strcpy (interp, cp);
-	i_name = cp;
+	i_name_start = i_name = cp;
 	i_arg = 0;
 	for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) {
  		if (*cp == '/')
@@ -52,6 +51,7 @@
 		*cp++ = '\0';
 	if (*cp)
 		i_arg = cp;
+	strcpy (interp, i_name_start);
 	/*
 	 * OK, we've parsed out the interpreter name and
 	 * (optional) argument.
diff -u --recursive --new-file v2.1.13/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.1.13/linux/fs/fat/inode.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/fat/inode.c	Sat Nov 30 12:27:26 1996
@@ -48,13 +48,12 @@
 	}
 	inode->i_size = 0;
 	fat_truncate(inode);
-	clear_inode(inode);
 	if (depend) {
 		if (MSDOS_I(depend)->i_old != inode) {
 			printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
 			    depend, inode, MSDOS_I(depend)->i_old);
 			fat_fs_panic(sb,"...");
-			return;
+			goto done;
 		}
 		MSDOS_I(depend)->i_old = NULL;
 		iput(depend);
@@ -64,11 +63,13 @@
 			printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
 			    linked, inode, MSDOS_I(linked)->i_oldlink);
 			fat_fs_panic(sb,"...");
-			return;
+			goto done;
 		}
 		MSDOS_I(linked)->i_oldlink = NULL;
 		iput(linked);
 	}
+done:
+	clear_inode(inode);
 }
 
 
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.1.13/linux/fs/smbfs/dir.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/smbfs/dir.c	Sun Dec  1 19:09:54 1996
@@ -1,7 +1,7 @@
 /*
  *  dir.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -12,98 +12,70 @@
 #include <linux/malloc.h>
 #include <linux/mm.h>
 #include <linux/smb_fs.h>
-#include <asm/uaccess.h>
+#include <linux/smbno.h>
 #include <linux/errno.h>
 
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 static long
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count);
-
-static int 
-smb_readdir(struct inode *inode, struct file *filp,
-            void *dirent, filldir_t filldir);
-
-static int 
-get_pname(struct inode *dir, const char *name, int len,
-          char **res_path, int *res_len);
+ smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count);
 
 static int
-get_pname_static(struct inode *dir, const char *name, int len,
-                 char *path, int *res_len);
-
-static void 
-put_pname(char *path);
+ smb_readdir(struct inode *inode, struct file *filp,
+	     void *dirent, filldir_t filldir);
 
 static struct smb_inode_info *
-smb_find_inode(struct smb_server *server, const char *path);
+ smb_find_dir_inode(struct inode *parent, const char *name, int len);
 
 static int
-smb_lookup(struct inode *dir, const char *__name,
-           int len, struct inode **result);
+ smb_lookup(struct inode *dir, const char *__name,
+	    int len, struct inode **result);
 
-static int 
-smb_create(struct inode *dir, const char *name, int len, int mode, 
-           struct inode **result);
-
-static int 
-smb_mkdir(struct inode *dir, const char *name, int len, int mode);
+static int
+ smb_create(struct inode *dir, const char *name, int len, int mode,
+	    struct inode **result);
 
-static int 
-smb_rmdir(struct inode *dir, const char *name, int len);
+static int
+ smb_mkdir(struct inode *dir, const char *name, int len, int mode);
 
 static int
-smb_unlink(struct inode *dir, const char *name, int len);
+ smb_rmdir(struct inode *dir, const char *name, int len);
 
 static int
-smb_rename(struct inode *old_dir, const char *old_name, int old_len, 
-           struct inode *new_dir, const char *new_name, int new_len,
-           int must_be_dir);
+ smb_unlink(struct inode *dir, const char *name, int len);
 
-static inline void str_upper(char *name)
-{
-	while (*name) {
-		if (*name >= 'a' && *name <= 'z')
-			*name -= ('a' - 'A');
-		name++;
-	}
-}
+static int
+ smb_rename(struct inode *old_dir, const char *old_name, int old_len,
+	    struct inode *new_dir, const char *new_name, int new_len,
+	    int must_be_dir);
 
-static inline void str_lower(char *name)
+static struct file_operations smb_dir_operations =
 {
-	while (*name) {
-		if (*name >= 'A' && *name <= 'Z')
-			*name += ('a' - 'A');
-		name ++;
-	}
-}
-
-static struct file_operations smb_dir_operations = {
-        NULL,			/* lseek - default */
+	NULL,			/* lseek - default */
 	smb_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	smb_readdir,		/* readdir */
 	NULL,			/* select - default */
 	smb_ioctl,		/* ioctl - default */
-	NULL,                   /* mmap */
+	NULL,			/* mmap */
 	NULL,			/* no special open code */
 	NULL,			/* no special release code */
 	NULL			/* fsync */
 };
 
-struct inode_operations smb_dir_inode_operations = 
+struct inode_operations smb_dir_inode_operations =
 {
 	&smb_dir_operations,	/* default directory file ops */
 	smb_create,		/* create */
-	smb_lookup,    		/* lookup */
+	smb_lookup,		/* lookup */
 	NULL,			/* link */
-	smb_unlink,    		/* unlink */
+	smb_unlink,		/* unlink */
 	NULL,			/* symlink */
-	smb_mkdir,     		/* mkdir */
-	smb_rmdir,     		/* rmdir */
+	smb_mkdir,		/* mkdir */
+	smb_rmdir,		/* rmdir */
 	NULL,			/* mknod */
-	smb_rename,    		/* rename */
+	smb_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
 	NULL,			/* readpage */
@@ -111,336 +83,301 @@
 	NULL,			/* bmap */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL                    /* smap */
+	NULL			/* smap */
 };
 
-
-static long
-smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+static int
+strncasecmp(const char *s1, const char *s2, int len)
 {
-	return -EISDIR;
-}
+	int result = 0;
 
-/*
- * Description:
- *  smb_readdir provides a listing in the form of filling the dirent structure.
- *  Note that dirent resides in the user space. This is to support reading of a
- *  directory "stream". 
- * Notes:
- *     Since we want to reduce directory lookups we revert into a
- *     dircache. It is taken rather directly out of the nfs_readdir.
- */
+	for (; len > 0; len -= 1)
+	{
+		char c1, c2;
 
-/* In smbfs, we have unique inodes across all mounted filesystems, for
-   all inodes that are in memory. That's why it's enough to index the
-   directory cache by the inode number. */
-
-static unsigned long      c_ino = 0;
-static int                c_size;
-static int                c_seen_eof;
-static int                c_last_returned_index;
-static struct smb_dirent* c_entry = NULL;
+		c1 = (*s1 >= 'a' && *s1 <= 'z') ? *s1 - ('a' - 'A') : *s1;
+		c2 = (*s2 >= 'a' && *s2 <= 'z') ? *s2 - ('a' - 'A') : *s2;
+		s1 += 1;
+		s2 += 1;
+
+		if ((result = c1 - c2) != 0 || c1 == 0)
+		{
+			return result;
+		}
+	}
+	return result;
+}
 
 static int
-smb_readdir(struct inode *inode, struct file *filp,
-            void *dirent, filldir_t filldir)
+compare_filename(const struct smb_server *server,
+		 const char *s1, int len, struct smb_dirent *entry)
 {
-	int result, i = 0;
-        int index = 0;
-	struct smb_dirent *entry = NULL;
-        struct smb_server *server = SMB_SERVER(inode);
-
-	DDPRINTK("smb_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
-	DDPRINTK("smb_readdir: inode->i_ino = %ld, c_ino = %ld\n",
-		 inode->i_ino, c_ino);
-
-	if (!inode || !S_ISDIR(inode->i_mode)) {
-		printk("smb_readdir: inode is NULL or not a directory\n");
-		return -EBADF;
+	if (len != entry->len)
+	{
+		return 1;
+	}
+	if (server->case_handling == CASE_DEFAULT)
+	{
+		return strncasecmp(s1, entry->name, len);
 	}
+	return strncmp(s1, entry->name, len);
+}
 
-	if (c_entry == NULL) 
+struct smb_inode_info *
+smb_find_inode(struct smb_server *server, ino_t ino)
+{
+	struct smb_inode_info *root = &(server->root);
+	struct smb_inode_info *this = root;
+
+	do
 	{
-		i = sizeof (struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
-		c_entry = (struct smb_dirent *) smb_kmalloc(i, GFP_KERNEL);
-		if (c_entry == NULL) {
-			printk("smb_readdir: no MEMORY for cache\n");
-			return -ENOMEM;
-		}
-		for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
-			c_entry[i].path =
-                                (char *) smb_kmalloc(SMB_MAXNAMELEN + 1,
-                                                     GFP_KERNEL);
-                        if (c_entry[i].path == NULL) {
-                                DPRINTK("smb_readdir: could not alloc path\n");
-				while (--i>=0)
-					kfree(c_entry[i].path);
-				kfree(c_entry);
-				c_entry = NULL;
-				return -ENOMEM;
-                        }
-                }
-	}
-
-        if (filp->f_pos == 0) {
-                smb_invalid_dir_cache(inode->i_ino);
-        }
-
-	if (inode->i_ino == c_ino) {
-		for (i = 0; i < c_size; i++) {
-			if (filp->f_pos == c_entry[i].f_pos) {
-                                entry = &c_entry[i];
-                                c_last_returned_index = i;
-                                index = i;
-                                break;
-			}
+		if (ino == smb_info_ino(this))
+		{
+			return this;
 		}
-                if ((entry == NULL) && c_seen_eof)
-                        return 0;
+		this = this->next;
 	}
+	while (this != root);
 
-	if (entry == NULL) {
-		DPRINTK("smb_readdir: Not found in cache.\n");
-		result = smb_proc_readdir(server, inode,
-                                          filp->f_pos, SMB_READDIR_CACHE_SIZE,
-                                          c_entry);
+	return NULL;
+}
 
-		if (result < 0) {
-			c_ino = 0;
-			return result;
-		}
+static ino_t
+smb_fresh_inodes(struct smb_server *server, int no)
+{
+	static ino_t seed = 1;
+	struct smb_inode_info *root = &(server->root);
+	struct smb_inode_info *this;
 
-		if (result > 0) {
-                        c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
-			c_ino  = inode->i_ino;
-			c_size = result;
-			entry = c_entry;
-                        c_last_returned_index = 0;
-                        index = 0;
-                        for (i = 0; i < c_size; i++) {
-
-                                switch (server->case_handling) 
-                                {
-                                case CASE_UPPER:
-                                        str_upper(c_entry[i].path); break;
-                                case CASE_LOWER:
-                                        str_lower(c_entry[i].path); break;
-                                case CASE_DEFAULT:
-                                        break;
-                                }
-                        }
+      retry:
+	if (seed + no <= no)
+	{
+		/* avoid inode number of 0 at wrap-around */
+		seed += no;
+	}
+	this = root;
+	do
+	{
+		/* We assume that ino_t is unsigned! */
+		if (this->finfo.f_ino - seed < no)
+		{
+			seed += no;
+			goto retry;
 		}
+		this = this->next;
 	}
+	while (this != root);
 
-        if (entry == NULL) {
-                /* Nothing found, even from a smb call */
-                return 0;
-        }
-
-        while (index < c_size) {
-
-                /* We found it.  For getwd(), we have to return the
-                   correct inode in d_ino if the inode is currently in
-                   use. Otherwise the inode number does not
-                   matter. (You can argue a lot about this..) */ 
-
-                int path_len;
-                int len;
-                struct smb_inode_info *ino_info;
-                char complete_path[SMB_MAXPATHLEN];
-
-		len = strlen(entry->path);
-                if ((result = get_pname_static(inode, entry->path, len,
-                                               complete_path,
-                                               &path_len)) < 0)
-                        return result;
-
-                ino_info = smb_find_inode(server, complete_path);
-
-                /* Some programs seem to be confused about a zero
-                   inode number, so we set it to one.  Thanks to
-                   Gordon Chaffee for this one. */
-                if (ino_info == NULL) {
-                        ino_info = (struct smb_inode_info *) 1;
-                }
+	seed += no;
 
-		DDPRINTK("smb_readdir: entry->path = %s\n", entry->path);
-		DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
-
-                if (filldir(dirent, entry->path, len,
-                            entry->f_pos, (ino_t)ino_info) < 0) {
-                        break;
-                }
-
-                if (   (inode->i_ino != c_ino)
-                    || (entry->f_pos != filp->f_pos)) {
-                        /* Someone has destroyed the cache while we slept
-                           in filldir */
-                        break;
-                }
-                filp->f_pos += 1;
-                index += 1;
-                entry += 1;
-	}
-	return 0;
+	return seed - no;
 }
 
-void
-smb_init_dir_cache(void)
+static long
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
 {
-        c_ino   = 0;
-        c_entry = NULL;
+	return -EISDIR;
 }
 
-void
-smb_invalid_dir_cache(unsigned long ino)
+
+static unsigned long c_ino = 0;
+static kdev_t c_dev;
+static int c_size;
+static int c_seen_eof;
+static int c_last_returned_index;
+static struct smb_dirent *c_entry = NULL;
+
+static struct smb_dirent *
+smb_search_in_cache(struct inode *dir, unsigned long f_pos)
 {
-	if (ino == c_ino) {
-                c_ino = 0;
-                c_seen_eof = 0;
-        }
+	int i;
+
+	if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino))
+	{
+		return NULL;
+	}
+	for (i = 0; i < c_size; i++)
+	{
+		if (f_pos == c_entry[i].f_pos)
+		{
+			c_last_returned_index = i;
+			return &(c_entry[i]);
+		}
+	}
+	return NULL;
 }
 
-void
-smb_free_dir_cache(void)
+static int
+smb_refill_dir_cache(struct smb_server *server, struct inode *dir,
+		     unsigned long f_pos)
 {
-        int i;
+	int result;
+	static struct semaphore sem = MUTEX;
+	int i;
+	ino_t ino;
 
-        DPRINTK("smb_free_dir_cache: enter\n");
-        
-        if (c_entry == NULL)
-                return;
+	do
+	{
+		down(&sem);
+		result = smb_proc_readdir(server, dir, f_pos,
+					  SMB_READDIR_CACHE_SIZE, c_entry);
 
-        for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
-                smb_kfree_s(c_entry[i].path, NAME_MAX + 1);
-        }
+		if (result <= 0)
+		{
+			smb_invalid_dir_cache(dir->i_ino);
+			up(&sem);
+			return result;
+		}
+		c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
+		c_dev = dir->i_dev;
+		c_ino = dir->i_ino;
+		c_size = result;
+		c_last_returned_index = 0;
 
-        smb_kfree_s(c_entry,
-                    sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE);
-        c_entry = NULL;
+		ino = smb_fresh_inodes(server, c_size);
+		for (i = 0; i < c_size; i++)
+		{
+			c_entry[i].f_ino = ino;
+			ino += 1;
+		}
 
-        DPRINTK("smb_free_dir_cache: exit\n");
-}
+		up(&sem);
 
+	}
+	while ((c_dev != dir->i_dev) || (c_ino != dir->i_ino));
 
-/* get_pname_static: it expects the res_path to be a preallocated
-   string of len SMB_MAXPATHLEN. */
+	return result;
+}
 
 static int
-get_pname_static(struct inode *dir, const char *name, int len,
-                 char *path, int *res_len)
+smb_readdir(struct inode *dir, struct file *filp,
+	    void *dirent, filldir_t filldir)
 {
-        char *parentname = SMB_INOP(dir)->finfo.path;
-        int   parentlen  = SMB_INOP(dir)->finfo.len;
-
-#if 1
-        if (parentlen != strlen(parentname)) {
-                printk("get_pname: parent->finfo.len = %d instead of %d\n",
-                       parentlen, strlen(parentname));
-                parentlen = strlen(parentname);
-        }
-	
-#endif
-	DDPRINTK("get_pname_static: parentname = %s, len = %d\n",
-                 parentname, parentlen);
-	
-        if (len > SMB_MAXNAMELEN) {
-                return -ENAMETOOLONG;
-        }
+	int result, i = 0;
+	struct smb_dirent *entry = NULL;
+	struct smb_server *server = SMB_SERVER(dir);
 
-	/* Fast cheat for . */
-	if (len == 0 || (len == 1 && name[0] == '.')) {
+	DPRINTK("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
+	DDPRINTK("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
+		 dir->i_ino, c_ino);
 
-		memcpy(path, parentname, parentlen + 1);
-		*res_len = parentlen;
-		return 0;
+	if ((dir == NULL) || !S_ISDIR(dir->i_mode))
+	{
+		printk("smb_readdir: dir is NULL or not a directory\n");
+		return -EBADF;
+	}
+	if (c_entry == NULL)
+	{
+		i = sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
+		c_entry = (struct smb_dirent *) smb_vmalloc(i);
+		if (c_entry == NULL)
+		{
+			printk("smb_readdir: no MEMORY for cache\n");
+			return -ENOMEM;
+		}
 	}
-	
-	/* Hmm, what about .. ? */
-	if (len == 2 && name[0] == '.' && name[1] == '.') {
-
-		char *pos = strrchr(parentname, '\\');
-
-                if (   (pos == NULL)
-                    && (parentlen == 0)) {
-
-                        /* We're at the top */
-
-                        path[0] = '\\';
-                        path[1] = '\0';
-                        *res_len  = 2;
-                        return 0;
-                }
-                        
-                
-		if (pos == NULL) {
-			printk("smb_make_name: Bad parent SMB-name: %s",
-                               parentname);
-			return -ENODATA;
-		}
-		
-		len = pos - parentname;
+	if (filp->f_pos == 0)
+	{
+		c_ino = 0;
+		c_dev = 0;
+		c_seen_eof = 0;
 
-	        memcpy(path, parentname, len);
-		path[len] = '\0';
+		if (filldir(dirent, ".", 1, filp->f_pos,
+			    smb_info_ino(SMB_INOP(dir))) < 0)
+		{
+			return 0;
+		}
+		filp->f_pos += 1;
 	}
-	else
+	if (filp->f_pos == 1)
 	{
-		if (len + parentlen + 2 > SMB_MAXPATHLEN) 
-			return -ENAMETOOLONG;
-				
-		memcpy(path, parentname, parentlen);
-		path[parentlen] = '\\';
-		memcpy(path + parentlen + 1, name, len);
-		path[parentlen + 1 + len] = '\0';
-		len = parentlen + len + 1;
-	}
-
-	switch (SMB_SERVER(dir)->case_handling) 
-	{
-        case CASE_UPPER: 
-                str_upper(path); 
-                break;
-        case CASE_LOWER: 
-                str_lower(path); 
-                break;
-        case CASE_DEFAULT: 
-                break;
+		if (filldir(dirent, "..", 2, filp->f_pos,
+			    smb_info_ino(SMB_INOP(dir)->dir)) < 0)
+		{
+			return 0;
+		}
+		filp->f_pos += 1;
 	}
+	entry = smb_search_in_cache(dir, filp->f_pos);
 
-	*res_len = len;
+	if (entry == NULL)
+	{
+		if (c_seen_eof)
+		{
+			/* End of directory */
+			return 0;
+		}
+		result = smb_refill_dir_cache(server, dir, filp->f_pos);
+		if (result <= 0)
+		{
+			return result;
+		}
+		entry = c_entry;
+	}
+	while (entry < &(c_entry[c_size]))
+	{
+		/* We found it.  For getwd(), we have to return the
+		   correct inode in d_ino if the inode is currently in
+		   use. Otherwise the inode number does not
+		   matter. (You can argue a lot about this..) */
 
-	DDPRINTK("get_pname: path = %s, *pathlen = %d\n",
-                 path, *res_len);
+		struct smb_inode_info *ino_info
+		= smb_find_dir_inode(dir, entry->name, entry->len);
+
+		ino_t ino = entry->f_ino;
+
+		if (ino_info != NULL)
+		{
+			ino = smb_info_ino(ino_info);
+		}
+		DDPRINTK("smb_readdir: entry->name = %s\n", entry->name);
+		DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
+
+		if (filldir(dirent, entry->name, strlen(entry->name),
+			    entry->f_pos, ino) < 0)
+		{
+			break;
+		}
+		if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino)
+		    || (entry->f_pos != filp->f_pos))
+		{
+			/* Someone has destroyed the cache while we slept
+			   in filldir */
+			break;
+		}
+		filp->f_pos += 1;
+		entry += 1;
+	}
 	return 0;
 }
-        
-static int 
-get_pname(struct inode *dir, const char *name, int len,
-          char **res_path, int *res_len)
-{
-        char result[SMB_MAXPATHLEN];
-        int  result_len;
-        int  res;
 
-        if ((res = get_pname_static(dir,name,len,result,&result_len) != 0)) {
-                return res;
-        }
-
-        if ((*res_path = smb_kmalloc(result_len+1, GFP_KERNEL)) == NULL) {
-                printk("get_pname: Out of memory while allocating name.");
-                return -ENOMEM;
-        }
+void
+smb_init_dir_cache(void)
+{
+	c_ino = 0;
+	c_dev = 0;
+	c_entry = NULL;
+}
 
-        strcpy(*res_path, result);
-        *res_len = result_len;
-        return 0;
+void
+smb_invalid_dir_cache(unsigned long ino)
+{
+	/* TODO: check for dev as well */
+	if (ino == c_ino)
+	{
+		c_ino = 0;
+		c_seen_eof = 0;
+	}
 }
 
-static void
-put_pname(char *path)
+void
+smb_free_dir_cache(void)
 {
-	smb_kfree_s(path, 0);
+	if (c_entry != NULL)
+	{
+		smb_vfree(c_entry);
+	}
+	c_entry = NULL;
 }
 
 /* Insert a NEW smb_inode_info into the inode tree of our filesystem,
@@ -448,45 +385,35 @@
    assume that path is allocated for us. */
 
 static struct inode *
-smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo,
-	 struct smb_inode_info *new_inode_info)
+smb_iget(struct inode *dir, struct smb_inode_info *new_inode_info)
 {
 	struct inode *inode;
-	int len;
-        struct smb_inode_info *root;
+	struct smb_inode_info *root;
 
-	if (   (dir == NULL) || (path == NULL) || (finfo == NULL)
-	    || (new_inode_info == NULL))
+	if ((dir == NULL) || (new_inode_info == NULL))
 	{
 		printk("smb_iget: parameter is NULL\n");
 		return NULL;
 	}
+	new_inode_info->state = SMB_INODE_LOOKED_UP;
+	new_inode_info->nused = 0;
+	new_inode_info->dir = SMB_INOP(dir);
+
+	SMB_INOP(dir)->nused += 1;
+
+	/* We have to link the new inode_info into the doubly linked
+	   list of inode_infos to make a complete linear search
+	   possible. */
+
+	root = &(SMB_SERVER(dir)->root);
 
-        len = strlen(path);
+	new_inode_info->prev = root;
+	new_inode_info->next = root->next;
+	root->next->prev = new_inode_info;
+	root->next = new_inode_info;
 
-        new_inode_info->state = SMB_INODE_LOOKED_UP;
-        new_inode_info->nused = 0;
-        new_inode_info->dir   = SMB_INOP(dir);
-
-        new_inode_info->finfo        = *finfo;
-        new_inode_info->finfo.opened = 0;
-        new_inode_info->finfo.path   = path;
-        new_inode_info->finfo.len    = len;
-
-        SMB_INOP(dir)->nused += 1;
-
-        /* We have to link the new inode_info into the doubly linked
-           list of inode_infos to make a complete linear search
-           possible. */
-
-        root = &(SMB_SERVER(dir)->root);
-
-        new_inode_info->prev = root;
-        new_inode_info->next = root->next;
-        root->next->prev = new_inode_info;
-        root->next = new_inode_info;
-        
-	if (!(inode = iget(dir->i_sb, (int)new_inode_info))) {
+	if (!(inode = iget(dir->i_sb, smb_info_ino(new_inode_info))))
+	{
 		new_inode_info->next->prev = new_inode_info->prev;
 		new_inode_info->prev->next = new_inode_info->next;
 		SMB_INOP(dir)->nused -= 1;
@@ -494,337 +421,327 @@
 		printk("smb_iget: iget failed!");
 		return NULL;
 	}
-
 	return inode;
 }
 
 void
 smb_free_inode_info(struct smb_inode_info *i)
 {
-        if (i == NULL) {
-                printk("smb_free_inode: i == NULL\n");
-                return;
-        }
-
-        i->state = SMB_INODE_CACHED;
-        while ((i->nused == 0) && (i->state == SMB_INODE_CACHED)) {
-                struct smb_inode_info *dir = i->dir;
-
-                i->next->prev = i->prev;
-                i->prev->next = i->next;
+	if (i == NULL)
+	{
+		printk("smb_free_inode: i == NULL\n");
+		return;
+	}
+	i->state = SMB_INODE_CACHED;
+	while ((i->nused == 0) && (i->state == SMB_INODE_CACHED))
+	{
+		struct smb_inode_info *dir = i->dir;
 
-                smb_kfree_s(i->finfo.path, i->finfo.len+1);
-                smb_kfree_s(i, sizeof(struct smb_inode_info));
+		i->next->prev = i->prev;
+		i->prev->next = i->next;
 
-                if (dir == NULL) return;
+		smb_kfree_s(i, sizeof(struct smb_inode_info));
 
-                (dir->nused)--;
-                i = dir;
-        }
+		if (dir == NULL)
+		{
+			return;
+		}
+		dir->nused -= 1;
+		i = dir;
+	}
 }
-        
+
 void
 smb_init_root(struct smb_server *server)
 {
-        struct smb_inode_info *root = &(server->root);
+	struct smb_inode_info *root = &(server->root);
 
-        root->finfo.path = server->m.root_path;
-        root->finfo.len  = strlen(root->finfo.path);
-        root->finfo.opened = 0;
-
-        root->state = SMB_INODE_LOOKED_UP;
-        root->nused = 1;
-        root->dir   = NULL;
-        root->next = root->prev = root;
-        return;
-}
-
-int
-smb_stat_root(struct smb_server *server)
-{
-        struct smb_inode_info *root = &(server->root);
-        int result;
-
-        if (root->finfo.len == 0) {
-                result = smb_proc_getattr(server, "\\", 1, &(root->finfo));
-        }
-        else
-        {
-                result = smb_proc_getattr(server, 
-                                          root->finfo.path, root->finfo.len,
-                                          &(root->finfo));
-        }
-        return result;
+	root->state = SMB_INODE_LOOKED_UP;
+	root->nused = 1;
+	root->dir = NULL;
+	root->next = root->prev = root;
+
+	return;
 }
 
 void
 smb_free_all_inodes(struct smb_server *server)
 {
-        /* Here nothing should be to do. I do not know whether it's
-           better to leave some memory allocated or be stuck in an
-           endless loop */
+	/* Here nothing should be to do. I do not know whether it's
+	   better to leave some memory allocated or be stuck in an
+	   endless loop */
 #if 1
-        struct smb_inode_info *root = &(server->root);
+	struct smb_inode_info *root = &(server->root);
 
-        if (root->next != root) {
-                printk("smb_free_all_inodes: INODES LEFT!!!\n");
-        }
-
-        while (root->next != root) {
-                printk("smb_free_all_inodes: freeing inode\n");
-                smb_free_inode_info(root->next);
-                /* In case we have an endless loop.. */
-                schedule();
-        }
-#endif        
-        
-        return;
+	if (root->next != root)
+	{
+		printk("smb_free_all_inodes: INODES LEFT!!!\n");
+	}
+	while (root->next != root)
+	{
+		printk("smb_free_all_inodes: freeing inode\n");
+		smb_free_inode_info(root->next);
+		/* In case we have an endless loop.. */
+		schedule();
+	}
+#endif
+
+	return;
 }
 
 /* This has to be called when a connection has gone down, so that all
    file-handles we got from the server are invalid */
-
 void
 smb_invalidate_all_inodes(struct smb_server *server)
 {
-        struct smb_inode_info *ino = &(server->root);
+	struct smb_inode_info *ino = &(server->root);
+
+	do
+	{
+		ino->finfo.opened = 0;
+		ino = ino->next;
+	}
+	while (ino != &(server->root));
 
-        do {
-                ino->finfo.opened = 0;
-                ino = ino->next;
-        } while (ino != &(server->root));
-        
-        return;
+	return;
 }
-        
 
 /* We will search the inode that belongs to this name, currently by a
    complete linear search through the inodes belonging to this
    filesystem. This has to be fixed. */
-
 static struct smb_inode_info *
-smb_find_inode(struct smb_server *server, const char *path)
+smb_find_dir_inode(struct inode *parent, const char *name, int len)
 {
-        struct smb_inode_info *result = &(server->root);
-
-        if (path == NULL)
-                return NULL;
-
-        do {
-                if (strcmp(result->finfo.path, path) == 0)
-                        return result;
-                result = result->next;
+	struct smb_server *server = SMB_SERVER(parent);
+	struct smb_inode_info *dir = SMB_INOP(parent);
+	struct smb_inode_info *result = &(server->root);
 
-        } while (result != &(server->root));
+	if (name == NULL)
+	{
+		return NULL;
+	}
+	if ((len == 1) && (name[0] == '.'))
+	{
+		return dir;
+	}
+	if ((len == 2) && (name[0] == '.') && (name[1] == '.'))
+	{
+		return dir->dir;
+	}
+	do
+	{
+		if (result->dir == dir)
+		{
+			if (compare_filename(server, name, len,
+					     &(result->finfo)) == 0)
+			{
+				return result;
+			}
+		}
+		result = result->next;
+	}
+	while (result != &(server->root));
 
-        return NULL;
+	return NULL;
 }
 
-
-static int 
-smb_lookup(struct inode *dir, const char *__name, int len,
-           struct inode **result)
+static int
+smb_lookup(struct inode *dir, const char *name, int len,
+	   struct inode **result)
 {
-	char *name = NULL;
 	struct smb_dirent finfo;
-        struct smb_inode_info *result_info;
+	struct smb_inode_info *result_info;
 	int error;
-        int found_in_cache;
+	int found_in_cache;
 
 	struct smb_inode_info *new_inode_info = NULL;
 
 	*result = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_lookup: inode is NULL or not a directory.\n");
 		iput(dir);
 		return -ENOENT;
 	}
-
-        DDPRINTK("smb_lookup: %s\n", __name);
+	DDPRINTK("smb_lookup: %s\n", name);
 
 	/* Fast cheat for . */
-	if (len == 0 || (len == 1 && __name[0] == '.')) {
+	if (len == 0 || (len == 1 && name[0] == '.'))
+	{
 		*result = dir;
 		return 0;
 	}
+	/* ..and for .. */
+	if (len == 2 && name[0] == '.' && name[1] == '.')
+	{
+		struct smb_inode_info *parent = SMB_INOP(dir)->dir;
 
-	/* Now we will have to build up an SMB filename. */
-	if ((error = get_pname(dir, __name, len, &name, &len)) < 0) {
+		if (parent->state == SMB_INODE_CACHED)
+		{
+			parent->state = SMB_INODE_LOOKED_UP;
+		}
+		*result = iget(dir->i_sb, smb_info_ino(parent));
 		iput(dir);
-		return error;
+		if (*result == 0)
+		{
+			return -EACCES;
+		}
+		return 0;
 	}
+	result_info = smb_find_dir_inode(dir, name, len);
 
-        result_info = smb_find_inode(SMB_SERVER(dir), name);
-
-in_tree:
-        if (result_info != NULL) {
-                if (result_info->state == SMB_INODE_CACHED)
-                        result_info->state = SMB_INODE_LOOKED_UP;
-
-                /* Here we convert the inode_info address into an
-                   inode number */
-
-                *result = iget(dir->i_sb, (int)result_info);
+      in_tree:
+	if (result_info != NULL)
+	{
+		if (result_info->state == SMB_INODE_CACHED)
+		{
+			result_info->state = SMB_INODE_LOOKED_UP;
+		}
+		*result = iget(dir->i_sb, smb_info_ino(result_info));
+		iput(dir);
 
 		if (new_inode_info != NULL)
 		{
 			smb_kfree_s(new_inode_info,
 				    sizeof(struct smb_inode_info));
 		}
-			
-                put_pname(name);
-                iput(dir);
-
-		if (*result == NULL) {
+		if (*result == NULL)
+		{
 			return -EACCES;
 		}
 		return 0;
-        }
+	}
+	/* If the file is in the dir cache, we do not have to ask the
+	   server. */
+	found_in_cache = 0;
 
-	/* Ok, now we have made our name. We have to build a new
-           smb_inode_info struct and insert it into the tree, if it is
-           a name that exists on the server */
-
-        /* If the file is in the dir cache, we do not have to ask the
-           server. */
-
-        found_in_cache = 0;
-        
-        if (dir->i_ino == c_ino) {
-                int first = c_last_returned_index;
-                int i;
-
-                i = first;
-                do {
-                        DDPRINTK("smb_lookup: trying index: %d, name: %s\n",
-                                i, c_entry[i].path);
-                        if (strcmp(c_entry[i].path, __name) == 0) {
-                                DPRINTK("smb_lookup: found in cache!\n");
-                                finfo = c_entry[i];
-                                finfo.path = NULL; /* It's not ours! */
-                                found_in_cache = 1;
-                                break;
-                        }
-                        i = (i + 1) % c_size;
-                        DDPRINTK("smb_lookup: index %d, name %s failed\n",
-                                 i, c_entry[i].path);
-                } while (i != first);
-        }
-
-        if (found_in_cache == 0) {
-                error = smb_proc_getattr(SMB_SERVER(dir), name, len, &finfo);
-                if (error < 0) {
-                        put_pname(name);
-                        iput(dir);
-                        return error;
-                }
-        }
+	if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino) && (c_size != 0))
+	{
+		int first = c_last_returned_index;
+		int i;
 
+		i = first;
+		do
+		{
+			if (compare_filename(SMB_SERVER(dir), name, len,
+					     &(c_entry[i])) == 0)
+			{
+				finfo = c_entry[i];
+				found_in_cache = 1;
+				break;
+			}
+			i = (i + 1) % c_size;
+		}
+		while (i != first);
+	}
+	if (found_in_cache == 0)
+	{
+		DPRINTK("smb_lookup: not found in cache: %s\n", name);
+		if (len > SMB_MAXNAMELEN)
+		{
+			iput(dir);
+			return -ENAMETOOLONG;
+		}
+		error = smb_proc_getattr(dir, name, len, &finfo);
+		if (error < 0)
+		{
+			iput(dir);
+			return error;
+		}
+		finfo.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);
+	}
 	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
 				     GFP_KERNEL);
 
 	/* Here somebody else might have inserted the inode */
-	result_info = smb_find_inode(SMB_SERVER(dir), name);
+
+	result_info = smb_find_dir_inode(dir, name, len);
 	if (result_info != NULL)
 	{
 		goto in_tree;
 	}
+	new_inode_info->finfo = finfo;
+
+	DPRINTK("attr: %x\n", finfo.attr);
 
-	if ((*result = smb_iget(dir, name, &finfo, new_inode_info)) == NULL)
+	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
 	{
 		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		put_pname(name);
 		iput(dir);
 		return -EACCES;
 	}
-
-        DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long)result_info);
+	DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long) result_info);
 	iput(dir);
 	return 0;
 }
 
-static int 
+static int
 smb_create(struct inode *dir, const char *name, int len, int mode,
-           struct inode **result)
+	   struct inode **result)
 {
 	int error;
-	char *path = NULL;
 	struct smb_dirent entry;
 	struct smb_inode_info *new_inode_info;
 
 	*result = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_create: inode is NULL or not a directory\n");
 		iput(dir);
 		return -ENOENT;
 	}
-
-	/* Now we will have to build up an SMB filename. */
-	if ((error = get_pname(dir, name, len, &path, &len)) < 0) {
-		iput(dir);
-		return error;
-	}
-
 	new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
 				     GFP_KERNEL);
 	if (new_inode_info == NULL)
 	{
-		put_pname(path);
 		iput(dir);
 		return -ENOMEM;
 	}
+	error = smb_proc_create(dir, name, len, 0, CURRENT_TIME);
+	if (error < 0)
+	{
+		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
+		iput(dir);
+		return error;
+	}
+	smb_invalid_dir_cache(dir->i_ino);
 
-        entry.attr  = 0;
-        entry.ctime = CURRENT_TIME;
-        entry.atime = CURRENT_TIME;
-        entry.mtime = CURRENT_TIME;
-        entry.size  = 0;
-
-        error = smb_proc_create(SMB_SERVER(dir), path, len, &entry);
-	if (error < 0) {
+	if ((error = smb_proc_getattr(dir, name, len, &entry)) < 0)
+	{
 		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		put_pname(path);
 		iput(dir);
 		return error;
 	}
+	entry.f_ino = smb_fresh_inodes(SMB_SERVER(dir), 1);
 
-        smb_invalid_dir_cache(dir->i_ino);
+	new_inode_info->finfo = entry;
 
-	if ((*result = smb_iget(dir, path, &entry, new_inode_info)) == NULL)
+	if ((*result = smb_iget(dir, new_inode_info)) == NULL)
 	{
 		smb_kfree_s(new_inode_info, sizeof(struct smb_inode_info));
-		put_pname(path);
 		iput(dir);
 		return error;
 	}
 	iput(dir);
-	return 0;	
+	return 0;
 }
 
 static int
 smb_mkdir(struct inode *dir, const char *name, int len, int mode)
 {
 	int error;
-	char path[SMB_MAXPATHLEN];
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("smb_mkdir: inode is NULL or not a directory\n");
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		iput(dir);
-		return -ENOENT;
+		return -EINVAL;
 	}
-
-	/* Now we will have to build up an SMB filename. */
-	if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
-		iput(dir);
-		return error;
+	if ((error = smb_proc_mkdir(dir, name, len)) == 0)
+	{
+		smb_invalid_dir_cache(dir->i_ino);
 	}
-
-	if ((error = smb_proc_mkdir(SMB_SERVER(dir), path, len)) == 0) {
-                smb_invalid_dir_cache(dir->i_ino);
-        }
-
 	iput(dir);
 	return error;
 }
@@ -833,23 +750,23 @@
 smb_rmdir(struct inode *dir, const char *name, int len)
 {
 	int error;
-        char path[SMB_MAXPATHLEN];
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_rmdir: inode is NULL or not a directory\n");
 		iput(dir);
 		return -ENOENT;
 	}
-	if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
-		iput(dir);
-		return error;
+	if (smb_find_dir_inode(dir, name, len) != NULL)
+	{
+		error = -EBUSY;
+	} else
+	{
+		if ((error = smb_proc_rmdir(dir, name, len)) == 0)
+		{
+			smb_invalid_dir_cache(dir->i_ino);
+		}
 	}
-        if (smb_find_inode(SMB_SERVER(dir), path) != NULL) {
-                error = -EBUSY;
-        } else {
-                if ((error = smb_proc_rmdir(SMB_SERVER(dir), path, len)) == 0)
-                        smb_invalid_dir_cache(dir->i_ino);
-        }
 	iput(dir);
 	return error;
 }
@@ -858,82 +775,72 @@
 smb_unlink(struct inode *dir, const char *name, int len)
 {
 	int error;
-	char path[SMB_MAXPATHLEN];
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
+	if (!dir || !S_ISDIR(dir->i_mode))
+	{
 		printk("smb_unlink: inode is NULL or not a directory\n");
 		iput(dir);
 		return -ENOENT;
 	}
-	if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
-		iput(dir);
-		return error;
+	if (smb_find_dir_inode(dir, name, len) != NULL)
+	{
+		error = -EBUSY;
+	} else
+	{
+		if ((error = smb_proc_unlink(dir, name, len)) == 0)
+		{
+			smb_invalid_dir_cache(dir->i_ino);
+		}
 	}
-        if (smb_find_inode(SMB_SERVER(dir), path) != NULL) {
-                error = -EBUSY;
-        } else {
-                if ((error = smb_proc_unlink(SMB_SERVER(dir), path, len)) == 0)
-                        smb_invalid_dir_cache(dir->i_ino);
-        }
 	iput(dir);
 	return error;
 }
 
 static int
 smb_rename(struct inode *old_dir, const char *old_name, int old_len,
-           struct inode *new_dir, const char *new_name, int new_len,
-           int must_be_dir)
+	   struct inode *new_dir, const char *new_name, int new_len,
+	   int must_be_dir)
 {
 	int res;
-	char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN];
 
-	if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
+	if (!old_dir || !S_ISDIR(old_dir->i_mode))
+	{
 		printk("smb_rename: old inode is NULL or not a directory\n");
-                res = -ENOENT;
-                goto finished;
+		res = -ENOENT;
+		goto finished;
 	}
-
-	if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
+	if (!new_dir || !S_ISDIR(new_dir->i_mode))
+	{
 		printk("smb_rename: new inode is NULL or not a directory\n");
-                res = -ENOENT;
-                goto finished;
-	}
-
-        res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len);
-        if (res < 0) {
-                goto finished;
+		res = -ENOENT;
+		goto finished;
 	}
-
-        res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len);
-	if (res < 0) {
-                goto finished;
+	if ((smb_find_dir_inode(old_dir, old_name, old_len) != NULL)
+	    || (smb_find_dir_inode(new_dir, new_name, new_len) != NULL))
+	{
+		res = -EBUSY;
+		goto finished;
 	}
-	
-        if (   (smb_find_inode(SMB_SERVER(old_dir), old_path) != NULL)
-            || (smb_find_inode(SMB_SERVER(new_dir), new_path) != NULL)) {
-                res = -EBUSY;
-                goto finished;
-        }
+	res = smb_proc_mv(old_dir, old_name, old_len,
+			  new_dir, new_name, new_len);
 
-	res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len,
-                          new_path, new_len);
+	if (res == -EEXIST)
+	{
+		int res1 = smb_proc_unlink(old_dir, new_name, new_len);
 
-	if (res == -EEXIST) {
-		int res1;
-		res1 = smb_proc_unlink(SMB_SERVER(old_dir), new_path, new_len);
-		if (res1 == 0) {
-			res = smb_proc_mv(SMB_SERVER(old_dir), old_path,
-					  old_len, new_path, new_len);
+		if (res1 == 0)
+		{
+			res = smb_proc_mv(old_dir, old_name, old_len,
+					  new_dir, new_name, new_len);
 		}
 	}
-
-        if (res == 0) {
-                smb_invalid_dir_cache(old_dir->i_ino);
-                smb_invalid_dir_cache(new_dir->i_ino);
-        }		
-	
- finished:
-	iput(old_dir); 
+	if (res == 0)
+	{
+		smb_invalid_dir_cache(old_dir->i_ino);
+		smb_invalid_dir_cache(new_dir->i_ino);
+	}
+      finished:
+	iput(old_dir);
 	iput(new_dir);
 	return res;
 }
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.1.13/linux/fs/smbfs/file.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/smbfs/file.c	Sun Dec  1 18:26:22 1996
@@ -1,13 +1,10 @@
 /*
  *  file.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -17,12 +14,16 @@
 #include <linux/smb_fs.h>
 #include <linux/malloc.h>
 
-static inline int min(int a, int b)
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+static inline int
+min(int a, int b)
 {
-	return a<b ? a : b;
+	return a < b ? a : b;
 }
 
-static int 
+static int
 smb_fsync(struct inode *inode, struct file *file)
 {
 	return 0;
@@ -31,36 +32,37 @@
 int
 smb_make_open(struct inode *i, int right)
 {
-        struct smb_dirent *dirent;
-
-        if (i == NULL) {
-                printk("smb_make_open: got NULL inode\n");
-                return -EINVAL;
-        }
+	struct smb_dirent *dirent;
 
-        dirent = &(SMB_INOP(i)->finfo);
+	if (i == NULL)
+	{
+		printk("smb_make_open: got NULL inode\n");
+		return -EINVAL;
+	}
+	dirent = &(SMB_INOP(i)->finfo);
 
-        DDPRINTK("smb_make_open: dirent->opened = %d\n", dirent->opened);
+	DDPRINTK("smb_make_open: dirent->opened = %d\n", dirent->opened);
 
-        if ((dirent->opened) == 0) {
-                /* tries max. rights */
+	if ((dirent->opened) == 0)
+	{
+		/* tries max. rights */
 		int open_result = smb_proc_open(SMB_SERVER(i),
-						dirent->path, dirent->len,
+						SMB_INOP(i)->dir,
+						dirent->name, dirent->len,
 						dirent);
-                if (open_result)
+		if (open_result)
 		{
-                        return open_result;
+			return open_result;
 		}
-        }
-
-        if (   ((right == O_RDONLY) && (   (dirent->access == O_RDONLY)
-                                        || (dirent->access == O_RDWR)))
-            || ((right == O_WRONLY) && (   (dirent->access == O_WRONLY)
-                                        || (dirent->access == O_RDWR)))
-            || ((right == O_RDWR)   && (dirent->access == O_RDWR)))
-                return 0;
+	}
+	if (((right == O_RDONLY) && ((dirent->access == O_RDONLY)
+				     || (dirent->access == O_RDWR)))
+	    || ((right == O_WRONLY) && ((dirent->access == O_WRONLY)
+					|| (dirent->access == O_RDWR)))
+	    || ((right == O_RDWR) && (dirent->access == O_RDWR)))
+		return 0;
 
-        return -EACCES;
+	return -EACCES;
 }
 
 static long
@@ -68,76 +70,67 @@
 {
 	int result, bufsize, to_read, already_read;
 	off_t pos;
-        int errno;
+	int errno;
+
+	DPRINTK("smb_file_read: enter %s\n", SMB_FINFO(inode)->name);
 
-        DPRINTK("smb_file_read: enter %s\n", SMB_FINFO(inode)->path);
-        
-	if (!inode) {
+	if (!inode)
+	{
 		DPRINTK("smb_file_read: inode = NULL\n");
 		return -EINVAL;
 	}
-
-	if (!S_ISREG(inode->i_mode)) {
+	if (!S_ISREG(inode->i_mode))
+	{
 		DPRINTK("smb_file_read: read from non-file, mode %07o\n",
-                        inode->i_mode);
+			inode->i_mode);
 		return -EINVAL;
 	}
+	if ((errno = smb_make_open(inode, O_RDONLY)) != 0)
+		return errno;
 
-        if ((errno = smb_make_open(inode, O_RDONLY)) != 0)
-                return errno;
-        
 	pos = file->f_pos;
 
 	if (pos + count > inode->i_size)
+	{
 		count = inode->i_size - pos;
-
+	}
 	if (count <= 0)
+	{
 		return 0;
+	}
 	bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
 
-        already_read = 0;
+	already_read = 0;
 
 	/* First read in as much as possible for each bufsize. */
-        while (already_read < count) {
-
-                result = 0;
-                to_read = 0;
-                
-                if ((SMB_SERVER(inode)->blkmode & 1) != 0) {
-                        to_read = min(65535, count - already_read);
-                        DPRINTK("smb_file_read: Raw %d bytes\n", to_read);
-                        result = smb_proc_read_raw(SMB_SERVER(inode),
-                                                   SMB_FINFO(inode),
-                                                   pos, to_read, buf);
-                        DPRINTK("smb_file_read: returned %d\n", result);
-                }
-
-                if (result <= 0) {
-                        to_read = min(bufsize, count - already_read);
-                        result = smb_proc_read(SMB_SERVER(inode),
-                                               SMB_FINFO(inode),
-                                               pos, to_read, buf, 1);
-                }
-
+	while (already_read < count)
+	{
+		to_read = min(bufsize, count - already_read);
+		result = smb_proc_read(SMB_SERVER(inode), SMB_FINFO(inode),
+				       pos, to_read, buf, 1);
 		if (result < 0)
+		{
 			return result;
+		}
 		pos += result;
 		buf += result;
-                already_read += result;
+		already_read += result;
 
-		if (result < to_read) {
-                        break;
+		if (result < to_read)
+		{
+			break;
 		}
 	}
 
-        file->f_pos = pos;
+	file->f_pos = pos;
 
-	if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
+	if (!IS_RDONLY(inode))
+		inode->i_atime = CURRENT_TIME;
 	inode->i_dirt = 1;
 
-        DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->path);
+	DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->name);
 
-        return already_read;
+	return already_read;
 }
 
 static long
@@ -145,28 +138,30 @@
 	       unsigned long count)
 {
 	int result, bufsize, to_write, already_written;
-        off_t pos;
-        int errno;
-			  
-	if (!inode) {
+	off_t pos;
+	int errno;
+
+	if (!inode)
+	{
 		DPRINTK("smb_file_write: inode = NULL\n");
 		return -EINVAL;
 	}
-
-	if (!S_ISREG(inode->i_mode)) {
+	if (!S_ISREG(inode->i_mode))
+	{
 		DPRINTK("smb_file_write: write to non-file, mode %07o\n",
-                       inode->i_mode);
+			inode->i_mode);
 		return -EINVAL;
 	}
+	DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->name);
 
-        DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->path);
-
-	if (!count)
+	if (count <= 0)
+	{
 		return 0;
-
-        if ((errno = smb_make_open(inode, O_RDWR)) != 0)
-                return errno;
-        
+	}
+	if ((errno = smb_make_open(inode, O_RDWR)) != 0)
+	{
+		return errno;
+	}
 	pos = file->f_pos;
 
 	if (file->f_flags & O_APPEND)
@@ -174,41 +169,28 @@
 
 	bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
 
-        already_written = 0;
+	already_written = 0;
 
-        DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
-                SMB_SERVER(inode)->blkmode,
-                SMB_SERVER(inode)->blkmode & 2);
-        
-        while (already_written < count) {
-
-                result = 0;
-                to_write = 0;
-
-                if ((SMB_SERVER(inode)->blkmode & 2) != 0) {
-                        to_write = min(65535, count - already_written);
-                        DPRINTK("smb_file_write: Raw %d bytes\n", to_write);
-                        result = smb_proc_write_raw(SMB_SERVER(inode),
-                                                    SMB_FINFO(inode), 
-                                                    pos, to_write, buf);
-                        DPRINTK("smb_file_write: returned %d\n", result);
-                }
-
-                if (result <= 0) {
-                        to_write = min(bufsize, count - already_written);
-                        result = smb_proc_write(SMB_SERVER(inode),
-                                                SMB_FINFO(inode), 
-                                                pos, to_write, buf);
-                }
+	DPRINTK("smb_write_file: blkmode = %d, blkmode & 2 = %d\n",
+		SMB_SERVER(inode)->blkmode,
+		SMB_SERVER(inode)->blkmode & 2);
+
+	while (already_written < count)
+	{
+		to_write = min(bufsize, count - already_written);
+		result = smb_proc_write(SMB_SERVER(inode), SMB_FINFO(inode),
+					pos, to_write, buf);
 
 		if (result < 0)
+		{
 			return result;
-
+		}
 		pos += result;
 		buf += result;
-                already_written += result;
+		already_written += result;
 
-		if (result < to_write) {
+		if (result < to_write)
+		{
 			break;
 		}
 	}
@@ -218,29 +200,31 @@
 
 	file->f_pos = pos;
 
-        if (pos > inode->i_size) {
-                inode->i_size = pos;
-        }
-
-        DPRINTK("smb_file_write: exit %s\n", SMB_FINFO(inode)->path);
+	if (pos > inode->i_size)
+	{
+		inode->i_size = pos;
+	}
+	DPRINTK("smb_file_write: exit %s\n", SMB_FINFO(inode)->name);
 
 	return already_written;
 }
 
-static struct file_operations smb_file_operations = {
+static struct file_operations smb_file_operations =
+{
 	NULL,			/* lseek - default */
 	smb_file_read,		/* read */
 	smb_file_write,		/* write */
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	smb_ioctl,		/* ioctl */
-	smb_mmap,               /* mmap */
-	NULL,                   /* open */
-	NULL,                   /* release */
+	smb_mmap,		/* mmap */
+	NULL,			/* open */
+	NULL,			/* release */
 	smb_fsync,		/* fsync */
 };
 
-struct inode_operations smb_file_inode_operations = {
+struct inode_operations smb_file_inode_operations =
+{
 	&smb_file_operations,	/* default file operations */
 	NULL,			/* create */
 	NULL,			/* lookup */
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.13/linux/fs/smbfs/inode.c	Sun Nov 10 20:12:13 1996
+++ linux/fs/smbfs/inode.c	Sun Dec  1 18:26:54 1996
@@ -1,15 +1,12 @@
 /*
  *  inode.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
 #include <linux/module.h>
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
 #include <linux/sched.h>
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -22,6 +19,9 @@
 #include <linux/fcntl.h>
 #include <linux/malloc.h>
 
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
 extern int close_fp(struct file *filp);
 
 static void smb_put_inode(struct inode *);
@@ -29,16 +29,17 @@
 static void smb_put_super(struct super_block *);
 static void smb_statfs(struct super_block *, struct statfs *, int bufsiz);
 
-static struct super_operations smb_sops = {
-	smb_read_inode,         /* read inode */
-	smb_notify_change,      /* notify change */
+static struct super_operations smb_sops =
+{
+	smb_read_inode,		/* read inode */
+	smb_notify_change,	/* notify change */
 	NULL,			/* write inode */
 	smb_put_inode,		/* put inode */
 	smb_put_super,		/* put superblock */
 	NULL,			/* write superblock */
 	smb_statfs,		/* stat filesystem */
 	NULL
-        };
+};
 
 /* smb_read_inode: Called from iget, it only traverses the allocated
    smb_inode_info's and initializes the inode from the data found
@@ -47,187 +48,205 @@
 static void
 smb_read_inode(struct inode *inode)
 {
-        /* Our task should be extremely simple here. We only have to
-           look up the information somebody else (smb_iget) put into
-           the inode tree. The address of this information is the
-           inode->i_ino. Just to make sure everything went well, we
-           check it's there. */
-
-        struct smb_inode_info *inode_info
-                = (struct smb_inode_info *)(inode->i_ino);
-
-#if 1
-        struct smb_inode_info *root = &(SMB_SERVER(inode)->root);
-        struct smb_inode_info *check_info = root;
-
-        do {
-                if (inode_info == check_info) {
-                        if (check_info->state == SMB_INODE_LOOKED_UP) {
-                                DDPRINTK("smb_read_inode: found it!\n");
-                                goto good;
-                        }
-                        else {
-                                printk("smb_read_inode: "
-                                       "state != SMB_INODE_LOOKED_UP\n");
-                                return;
-                        }
-                }
-                check_info = check_info->next;
-        } while (check_info != root);
-
-        /* Ok, now we're in trouble. The inode info is not there. What
-           should we do now??? */
-        printk("smb_read_inode: inode info not found\n");
-        return;
-
- good:
-#endif
-        inode_info->state = SMB_INODE_VALID;
+	/* Our task should be extremely simple here. We only have to
+	   look up the information somebody else (smb_iget) put into
+	   the inode tree. */
+	struct smb_server *server = SMB_SERVER(inode);
+	struct smb_inode_info *inode_info
+	= smb_find_inode(server, inode->i_ino);
 
-        SMB_INOP(inode) = inode_info;
+	if (inode_info == NULL)
+	{
+		/* Ok, now we're in trouble. The inode info is not
+		   there. What should we do now??? */
+		printk("smb_read_inode: inode info not found\n");
+		return;
+	}
+	inode_info->state = SMB_INODE_VALID;
 
-        if (SMB_INOP(inode)->finfo.attr & aDIR)
-                inode->i_mode = SMB_SERVER(inode)->m.dir_mode;
-        else
-                inode->i_mode = SMB_SERVER(inode)->m.file_mode;
-
-        DDPRINTK("smb_read_inode: inode->i_mode = %u\n", inode->i_mode);
-
-        inode->i_nlink   = 1;
-        inode->i_uid     = SMB_SERVER(inode)->m.uid;
-        inode->i_gid     = SMB_SERVER(inode)->m.gid;
-        inode->i_size    = SMB_INOP(inode)->finfo.size;
-        inode->i_blksize = 1024;
-        inode->i_rdev    = 0;
-        if ((inode->i_blksize != 0) && (inode->i_size != 0))
-                inode->i_blocks =
-                        (inode->i_size - 1) / inode->i_blksize + 1;
-        else
-                inode->i_blocks = 0;
-
-        inode->i_mtime = SMB_INOP(inode)->finfo.mtime;
-        inode->i_ctime = SMB_INOP(inode)->finfo.ctime;
-        inode->i_atime = SMB_INOP(inode)->finfo.atime;
-
-        if (S_ISREG(inode->i_mode))
-                inode->i_op = &smb_file_inode_operations;
-        else if (S_ISDIR(inode->i_mode))
-                inode->i_op = &smb_dir_inode_operations;
-        else
-                inode->i_op = NULL;
+	SMB_INOP(inode) = inode_info;
+	inode->i_mode = inode_info->finfo.f_mode;
+	inode->i_nlink = inode_info->finfo.f_nlink;
+	inode->i_uid = inode_info->finfo.f_uid;
+	inode->i_gid = inode_info->finfo.f_gid;
+	inode->i_rdev = inode_info->finfo.f_rdev;
+	inode->i_size = inode_info->finfo.f_size;
+	inode->i_mtime = inode_info->finfo.f_mtime;
+	inode->i_ctime = inode_info->finfo.f_ctime;
+	inode->i_atime = inode_info->finfo.f_atime;
+	inode->i_blksize = inode_info->finfo.f_blksize;
+	inode->i_blocks = inode_info->finfo.f_blocks;
 
+	if (S_ISREG(inode->i_mode))
+	{
+		inode->i_op = &smb_file_inode_operations;
+	} else if (S_ISDIR(inode->i_mode))
+	{
+		inode->i_op = &smb_dir_inode_operations;
+	} else
+	{
+		inode->i_op = NULL;
+	}
 }
 
 static void
 smb_put_inode(struct inode *inode)
 {
-        struct smb_dirent *finfo  = SMB_FINFO(inode);
+	struct smb_dirent *finfo = SMB_FINFO(inode);
 	struct smb_server *server = SMB_SERVER(inode);
 	struct smb_inode_info *info = SMB_INOP(inode);
 
-	int opened        = finfo->opened;
-	int mtime         = inode->i_mtime;
-	int file_id       = finfo->fileid;
-	int isdir         = S_ISDIR(inode->i_mode);
-	unsigned long ino = inode->i_ino;
-
-	/* Remove the inode before closing the file, because the close
-           will sleep. This hopefully removes a race condition. */
-
-	clear_inode(inode);
-        smb_free_inode_info(info);
-
-        if (isdir)
+	if (S_ISDIR(inode->i_mode))
 	{
-                DDPRINTK("smb_put_inode: put directory %ld\n",
-                         inode->i_ino);
-                smb_invalid_dir_cache(ino);
-        }                
-
-        if (opened != 0)
+		smb_invalid_dir_cache(inode->i_ino);
+	}
+	if (finfo->opened != 0)
 	{
-                if (smb_proc_close(server, file_id, mtime))
+		if (smb_proc_close(server, finfo->fileid, inode->i_mtime))
 		{
-                        /* We can't do anything but complain. */
-                        DPRINTK("smb_put_inode: could not close\n");
-                }
-        }
+			/* We can't do anything but complain. */
+			DPRINTK("smb_put_inode: could not close\n");
+		}
+	}
+	smb_free_inode_info(info);
+	clear_inode(inode);
 }
 
 static void
 smb_put_super(struct super_block *sb)
 {
-        struct smb_server *server = &(SMB_SBP(sb)->s_server);
+	struct smb_server *server = &(SMB_SBP(sb)->s_server);
 
-        smb_proc_disconnect(server);
+	smb_proc_disconnect(server);
 	smb_dont_catch_keepalive(server);
 	close_fp(server->sock_file);
 
 	lock_super(sb);
 
-        smb_free_all_inodes(server);
+	smb_free_all_inodes(server);
 
-        smb_kfree_s(server->packet, server->max_xmit);
+	smb_vfree(server->packet);
+	server->packet = NULL;
 
 	sb->s_dev = 0;
-        smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
+	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
 
 	unlock_super(sb);
 
-        MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 }
 
+struct smb_mount_data_v4
+{
+	int version;
+	unsigned int fd;
+	uid_t mounted_uid;
+	struct sockaddr_in addr;
+
+	char server_name[17];
+	char client_name[17];
+	char service[64];
+	char root_path[64];
+
+	char username[64];
+	char password[64];
+
+	unsigned short max_xmit;
+
+	uid_t uid;
+	gid_t gid;
+	mode_t file_mode;
+	mode_t dir_mode;
+};
+
+static int
+smb_get_mount_data(struct smb_mount_data *target, void *source)
+{
+	struct smb_mount_data_v4 *v4 = (struct smb_mount_data_v4 *) source;
+	struct smb_mount_data *cur = (struct smb_mount_data *) source;
+
+	if (source == NULL)
+	{
+		return 1;
+	}
+	if (cur->version == SMB_MOUNT_VERSION)
+	{
+		memcpy(target, cur, sizeof(struct smb_mount_data));
+		return 0;
+	}
+	if (v4->version == 4)
+	{
+		target->version = 5;
+		target->fd = v4->fd;
+		target->mounted_uid = v4->mounted_uid;
+		target->addr = v4->addr;
+
+		memcpy(target->server_name, v4->server_name, 17);
+		memcpy(target->client_name, v4->client_name, 17);
+		memcpy(target->service, v4->service, 64);
+		memcpy(target->root_path, v4->root_path, 64);
+		memcpy(target->username, v4->username, 64);
+		memcpy(target->password, v4->password, 64);
+
+		target->max_xmit = v4->max_xmit;
+		target->uid = v4->uid;
+		target->gid = v4->gid;
+		target->file_mode = v4->file_mode;
+		target->dir_mode = v4->dir_mode;
+
+		memset(target->domain, 0, 64);
+		strcpy(target->domain, "?");
+		return 0;
+	}
+	return 1;
+}
 
-/* Hmm, should we do this like the NFS mount command does? Guess so.. */
 struct super_block *
 smb_read_super(struct super_block *sb, void *raw_data, int silent)
 {
-	struct smb_mount_data *data = (struct smb_mount_data *) raw_data;
+	struct smb_mount_data data;
 	struct smb_server *server;
-        struct smb_sb_info *smb_sb;
+	struct smb_sb_info *smb_sb;
 	unsigned int fd;
 	struct file *filp;
 	kdev_t dev = sb->s_dev;
 	int error;
 
-	if (!data) {
-		printk("smb_read_super: missing data argument\n");
+	if (smb_get_mount_data(&data, raw_data) != 0)
+	{
+		printk("smb_read_super: wrong data argument\n");
 		sb->s_dev = 0;
 		return NULL;
 	}
-	fd = data->fd;
-	if (data->version != SMB_MOUNT_VERSION) {
-		printk("smb warning: mount version %s than kernel\n",
-		       (data->version < SMB_MOUNT_VERSION) ?
-                       "older" : "newer");
-	}
-	if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) {
+	fd = data.fd;
+	if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+	{
 		printk("smb_read_super: invalid file descriptor\n");
 		sb->s_dev = 0;
 		return NULL;
 	}
-	if (!S_ISSOCK(filp->f_inode->i_mode)) {
+	if (!S_ISSOCK(filp->f_inode->i_mode))
+	{
 		printk("smb_read_super: not a socket!\n");
 		sb->s_dev = 0;
 		return NULL;
 	}
+	/* We must malloc our own super-block info */
+	smb_sb = (struct smb_sb_info *) smb_kmalloc(sizeof(struct smb_sb_info),
+						    GFP_KERNEL);
 
-        /* We must malloc our own super-block info */
-        smb_sb = (struct smb_sb_info *)smb_kmalloc(sizeof(struct smb_sb_info),
-                                                   GFP_KERNEL);
-
-        if (smb_sb == NULL) {
-                printk("smb_read_super: could not alloc smb_sb_info\n");
-                return NULL;
-        }
-
-	filp->f_count += 1; 
+	if (smb_sb == NULL)
+	{
+		printk("smb_read_super: could not alloc smb_sb_info\n");
+		return NULL;
+	}
+	filp->f_count += 1;
 
 	lock_super(sb);
 
-        SMB_SBP(sb) = smb_sb;
-        
-	sb->s_blocksize = 1024; /* Eh...  Is this correct? */
+	SMB_SBP(sb) = smb_sb;
+
+	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = SMB_SUPER_MAGIC;
 	sb->s_dev = dev;
@@ -237,100 +256,90 @@
 	server->sock_file = filp;
 	server->lock = 0;
 	server->wait = NULL;
-        server->packet = NULL;
-	server->max_xmit = data->max_xmit;
+	server->packet = NULL;
+	server->max_xmit = data.max_xmit;
 	if (server->max_xmit <= 0)
+	{
 		server->max_xmit = SMB_DEF_MAX_XMIT;
-   
+	}
 	server->tid = 0;
 	server->pid = current->pid;
 	server->mid = current->pid + 20;
 
-        server->m = *data;
+	server->m = data;
 	server->m.file_mode = (server->m.file_mode &
-                             (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
-	server->m.dir_mode  = (server->m.dir_mode &
-                             (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
-
-        smb_init_root(server);
-
-        /*
-         * Make the connection to the server
-         */
-        
+			       (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
+	server->m.dir_mode = (server->m.dir_mode &
+			      (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
+
+	smb_init_root(server);
+
 	error = smb_proc_connect(server);
 
 	unlock_super(sb);
 
-	if (error < 0) {
+	if (error < 0)
+	{
 		sb->s_dev = 0;
-		printk("smb_read_super: Failed connection, bailing out "
-                       "(error = %d).\n", -error);
-                goto fail;
+		DPRINTK("smb_read_super: Failed connection, bailing out "
+			"(error = %d).\n", -error);
+		goto fail;
 	}
-
-        if (server->protocol >= PROTOCOL_LANMAN2)
-                server->case_handling = CASE_DEFAULT;
-        else
-                server->case_handling = CASE_LOWER;
-
-	if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0) {
-		sb->s_dev = 0;
-		printk("smb_read_super: could not get super block "
-                       "attributes\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
+	if (server->protocol >= PROTOCOL_LANMAN2)
+	{
+		server->case_handling = CASE_DEFAULT;
+	} else
+	{
+		server->case_handling = CASE_LOWER;
 	}
 
-	if ((error = smb_stat_root(server)) < 0) {
+	if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0)
+	{
 		sb->s_dev = 0;
-		printk("smb_read_super: could not get root dir attributes\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
+		printk("smb_read_super: could not get super block "
+		       "attributes\n");
+		goto fail;
 	}
+	smb_init_root_dirent(server, &(server->root.finfo));
 
-	DPRINTK("smb_read_super : %u %u %u %u\n",
-                SMB_SBP(sb)->s_attr.total,
-                SMB_SBP(sb)->s_attr.blocksize,
-                SMB_SBP(sb)->s_attr.allocblocks,
-                SMB_SBP(sb)->s_attr.free);
-
-        DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb));
-
-	if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) {
+	if (!(sb->s_mounted = iget(sb, smb_info_ino(&(server->root)))))
+	{
 		sb->s_dev = 0;
 		printk("smb_read_super: get root inode failed\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
+		goto fail;
 	}
-
-        MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 	return sb;
 
- fail:
-	filp->f_count -= 1; 
+      fail:
+	if (server->packet != NULL)
+	{
+		smb_vfree(server->packet);
+		server->packet = NULL;
+	}
+	filp->f_count -= 1;
 	smb_dont_catch_keepalive(server);
-        smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
-        return NULL;
+	smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
+	return NULL;
 }
 
-static void 
+static void
 smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	int error;
 	struct smb_dskattr attr;
 	struct statfs tmp;
-	
+
 	error = smb_proc_dskattr(sb, &attr);
 
-	if (error) {
+	if (error)
+	{
 		printk("smb_statfs: dskattr error = %d\n", -error);
 		attr.total = attr.allocblocks = attr.blocksize =
-                        attr.free = 0;
+		    attr.free = 0;
 	}
-
 	tmp.f_type = SMB_SUPER_MAGIC;
-	tmp.f_bsize = attr.blocksize*attr.allocblocks;
+	tmp.f_bsize = attr.blocksize * attr.allocblocks;
 	tmp.f_blocks = attr.total;
 	tmp.f_bfree = attr.free;
 	tmp.f_bavail = attr.free;
@@ -340,7 +349,6 @@
 	copy_to_user(buf, &tmp, bufsiz);
 }
 
-/* DO MORE */
 int
 smb_notify_change(struct inode *inode, struct iattr *attr)
 {
@@ -349,93 +357,101 @@
 	if ((error = inode_change_ok(inode, attr)) < 0)
 		return error;
 
-	if (((attr->ia_valid & ATTR_UID) && 
+	if (((attr->ia_valid & ATTR_UID) &&
 	     (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
 		return -EPERM;
 
-	if (((attr->ia_valid & ATTR_GID) && 
+	if (((attr->ia_valid & ATTR_GID) &&
 	     (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
-                return -EPERM;
+		return -EPERM;
 
 	if (((attr->ia_valid & ATTR_MODE) &&
-	     (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
+	(attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
 		return -EPERM;
 
-        if ((attr->ia_valid & ATTR_SIZE) != 0) {
-
-                if ((error = smb_make_open(inode, O_WRONLY)) < 0)
-                        goto fail;
-
-                if ((error = smb_proc_trunc(SMB_SERVER(inode),
-                                            SMB_FINFO(inode)->fileid,
-                                            attr->ia_size)) < 0)
-                        goto fail;
-
-        }
-
-        if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0) {
-
-                struct smb_dirent finfo;
+	if ((attr->ia_valid & ATTR_SIZE) != 0)
+	{
 
-                finfo.attr  = 0;
+		if ((error = smb_make_open(inode, O_WRONLY)) < 0)
+			goto fail;
 
-                if ((attr->ia_valid & ATTR_CTIME) != 0)
-                        finfo.ctime = attr->ia_ctime;
-                else
-                        finfo.ctime = inode->i_ctime;
+		if ((error = smb_proc_trunc(SMB_SERVER(inode),
+					    SMB_FINFO(inode)->fileid,
+					    attr->ia_size)) < 0)
+			goto fail;
 
-                if ((attr->ia_valid & ATTR_MTIME) != 0)
-                        finfo.mtime = attr->ia_mtime;
-                else
-                        finfo.mtime = inode->i_mtime;
+	}
+	if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
+	{
 
-                if ((attr->ia_valid & ATTR_ATIME) != 0)
-                        finfo.atime = attr->ia_atime;
-                else
-                        finfo.atime = inode->i_atime;
+		struct smb_dirent finfo;
 
-                if ((error = smb_proc_setattr(SMB_SERVER(inode),
-                                              inode, &finfo)) >= 0) {
-                        inode->i_ctime = finfo.ctime;
-                        inode->i_mtime = finfo.mtime;
-                        inode->i_atime = finfo.atime;
-                }
-        }
+		finfo.attr = 0;
+		finfo.f_size = inode->i_size;
+		finfo.f_blksize = inode->i_blksize;
+
+		if ((attr->ia_valid & ATTR_CTIME) != 0)
+			finfo.f_ctime = attr->ia_ctime;
+		else
+			finfo.f_ctime = inode->i_ctime;
+
+		if ((attr->ia_valid & ATTR_MTIME) != 0)
+			finfo.f_mtime = attr->ia_mtime;
+		else
+			finfo.f_mtime = inode->i_mtime;
+
+		if ((attr->ia_valid & ATTR_ATIME) != 0)
+			finfo.f_atime = attr->ia_atime;
+		else
+			finfo.f_atime = inode->i_atime;
 
- fail:
-        smb_invalid_dir_cache((unsigned long)(SMB_INOP(inode)->dir));
+		if ((error = smb_proc_setattr(SMB_SERVER(inode),
+					      inode, &finfo)) >= 0)
+		{
+			inode->i_ctime = finfo.f_ctime;
+			inode->i_mtime = finfo.f_mtime;
+			inode->i_atime = finfo.f_atime;
+		}
+	}
+      fail:
+	smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));
 
 	return error;
 }
 
-		
+
 #ifdef DEBUG_SMB_MALLOC
 int smb_malloced;
-int smb_current_malloced;
+int smb_current_kmalloced;
+int smb_current_vmalloced;
 #endif
 
-static struct file_system_type smb_fs_type = {
-        smb_read_super, "smbfs", 0, NULL
-        };
+static struct file_system_type smb_fs_type =
+{
+	smb_read_super, "smbfs", 0, NULL
+};
 
-int init_smb_fs(void)
+int
+init_smb_fs(void)
 {
-        return register_filesystem(&smb_fs_type);
+	return register_filesystem(&smb_fs_type);
 }
 
 #ifdef MODULE
-int init_module(void)
+int
+init_module(void)
 {
 	int status;
 
-        DPRINTK("smbfs: init_module called\n");
+	DPRINTK("smbfs: init_module called\n");
 
 #ifdef DEBUG_SMB_MALLOC
-        smb_malloced = 0;
-        smb_current_malloced = 0;
+	smb_malloced = 0;
+	smb_current_kmalloced = 0;
+	smb_current_vmalloced = 0;
 #endif
 
-        smb_init_dir_cache();
+	smb_init_dir_cache();
 
 	if ((status = init_smb_fs()) == 0)
 		register_symtab(0);
@@ -445,12 +461,13 @@
 void
 cleanup_module(void)
 {
-        DPRINTK("smbfs: cleanup_module called\n");
-        smb_free_dir_cache();
-        unregister_filesystem(&smb_fs_type);
+	DPRINTK("smbfs: cleanup_module called\n");
+	smb_free_dir_cache();
+	unregister_filesystem(&smb_fs_type);
 #ifdef DEBUG_SMB_MALLOC
-        printk("smb_malloced: %d\n", smb_malloced);
-        printk("smb_current_malloced: %d\n", smb_current_malloced);
+	printk("smb_malloced: %d\n", smb_malloced);
+	printk("smb_current_kmalloced: %d\n", smb_current_kmalloced);
+	printk("smb_current_vmalloced: %d\n", smb_current_vmalloced);
 #endif
 }
 
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- v2.1.13/linux/fs/smbfs/ioctl.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/smbfs/ioctl.c	Sun Dec  1 19:02:04 1996
@@ -1,11 +1,10 @@
 /*
  *  ioctl.c
  *
- *  Copyright (C) 1995 by Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Volker Lendecke
  *
  */
 
-#include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/smb_fs.h>
@@ -13,21 +12,18 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 
+#include <asm/uaccess.h>
+
 int
-smb_ioctl (struct inode * inode, struct file * filp,
-           unsigned int cmd, unsigned long arg)
+smb_ioctl(struct inode *inode, struct file *filp,
+	  unsigned int cmd, unsigned long arg)
 {
-	int result;
+	switch (cmd)
+	{
+	case SMB_IOC_GETMOUNTUID:
+		return put_user(SMB_SERVER(inode)->m.mounted_uid, (uid_t *) arg);
 
-	switch (cmd) {
-        case SMB_IOC_GETMOUNTUID:
-                if ((result = verify_area(VERIFY_WRITE, (uid_t*) arg,
-                                          sizeof(uid_t))) != 0) {
-                        return result;
-                }
-                put_user(SMB_SERVER(inode)->m.mounted_uid, (uid_t*) arg);
-                return 0;
-        default:
+	default:
 		return -EINVAL;
 	}
 }
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c
--- v2.1.13/linux/fs/smbfs/mmap.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/smbfs/mmap.c	Sun Dec  1 18:26:22 1996
@@ -1,7 +1,7 @@
 /*
  *  mmap.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -23,11 +23,11 @@
 /*
  * Fill in the supplied page for mmap
  */
-static unsigned long 
-smb_file_mmap_nopage(struct vm_area_struct * area,
+static unsigned long
+smb_file_mmap_nopage(struct vm_area_struct *area,
 		     unsigned long address, int no_share)
 {
-	struct inode * inode = area->vm_inode;
+	struct inode *inode = area->vm_inode;
 	unsigned long page;
 	unsigned int clear;
 	unsigned long tmp;
@@ -42,50 +42,54 @@
 	pos = address - area->vm_start + area->vm_offset;
 
 	clear = 0;
-	if (address + PAGE_SIZE > area->vm_end) {
+	if (address + PAGE_SIZE > area->vm_end)
+	{
 		clear = address + PAGE_SIZE - area->vm_end;
 	}
-
-        /* what we can read in one go */
+	/* what we can read in one go */
 	n = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 3 - 10;
 
-        if (smb_make_open(inode, O_RDONLY) < 0) {
-                clear = PAGE_SIZE;
-        }
-        else
-        {
-        
-                for (i = 0; i < (PAGE_SIZE - clear); i += n) {
-                        int hunk, result;
-
-                        hunk = PAGE_SIZE - i;
-                        if (hunk > n)
-                                hunk = n;
-
-                        DDPRINTK("smb_file_mmap_nopage: reading\n");
-                        DDPRINTK("smb_file_mmap_nopage: pos = %d\n", pos);
-                        result = smb_proc_read(SMB_SERVER(inode),
-                                               SMB_FINFO(inode), pos, hunk,
-                                               (char *) (page + i), 0);
-                        DDPRINTK("smb_file_mmap_nopage: result= %d\n", result);
-                        if (result < 0)
-                                break;
-                        pos += result;
-                        if (result < n) {
-                                i += result;
-                                break;
-                        }
-                }
-        }
+	if (smb_make_open(inode, O_RDONLY) < 0)
+	{
+		clear = PAGE_SIZE;
+	} else
+	{
+
+		for (i = 0; i < (PAGE_SIZE - clear); i += n)
+		{
+			int hunk, result;
+
+			hunk = PAGE_SIZE - i;
+			if (hunk > n)
+				hunk = n;
+
+			DDPRINTK("smb_file_mmap_nopage: reading\n");
+			DDPRINTK("smb_file_mmap_nopage: pos = %d\n", pos);
+			result = smb_proc_read(SMB_SERVER(inode),
+					       SMB_FINFO(inode), pos, hunk,
+					       (char *) (page + i), 0);
+			DDPRINTK("smb_file_mmap_nopage: result= %d\n", result);
+			if (result < 0)
+				break;
+			pos += result;
+			if (result < n)
+			{
+				i += result;
+				break;
+			}
+		}
+	}
 
 	tmp = page + PAGE_SIZE;
-	while (clear--) {
-		*(char *)--tmp = 0;
+	while (clear--)
+	{
+		*(char *) --tmp = 0;
 	}
 	return page;
 }
 
-struct vm_operations_struct smb_file_mmap = {
+struct vm_operations_struct smb_file_mmap =
+{
 	NULL,			/* open */
 	NULL,			/* close */
 	NULL,			/* unmap */
@@ -101,20 +105,20 @@
 
 /* This is used for a general mmap of a smb file */
 int
-smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+smb_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma)
 {
-        DPRINTK("smb_mmap: called\n");
+	DPRINTK("smb_mmap: called\n");
 
-        /* only PAGE_COW or read-only supported now */
-	if (vma->vm_flags & VM_SHARED)	
+	/* only PAGE_COW or read-only supported now */
+	if (vma->vm_flags & VM_SHARED)
 		return -EINVAL;
 	if (!inode->i_sb || !S_ISREG(inode->i_mode))
 		return -EACCES;
-	if (!IS_RDONLY(inode)) {
+	if (!IS_RDONLY(inode))
+	{
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
-
 	vma->vm_inode = inode;
 	inode->i_count++;
 	vma->vm_ops = &smb_file_mmap;
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.1.13/linux/fs/smbfs/proc.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/smbfs/proc.c	Sun Dec  1 18:27:31 1996
@@ -1,7 +1,7 @@
 /*
  *  proc.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  */
@@ -15,28 +15,47 @@
 #include <linux/malloc.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
+
 #include <asm/uaccess.h>
 #include <asm/string.h>
 
-#define ARCH i386
 #define SMB_VWV(packet)  ((packet) + SMB_HEADER_LEN)
-#define SMB_CMD(packet)  ((packet)[8])
-#define SMB_WCT(packet)  ((packet)[SMB_HEADER_LEN - 1])
+#define SMB_CMD(packet)  (BVAL(packet,8))
+#define SMB_WCT(packet)  (BVAL(packet, SMB_HEADER_LEN - 1))
 #define SMB_BCC(packet)  smb_bcc(packet)
 #define SMB_BUF(packet)  ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2)
 
 #define SMB_DIRINFO_SIZE 43
 #define SMB_STATUS_SIZE  21
 
-#define HI_WORD(l) ((word)(l >> 16))
-#define LO_WORD(l) ((word)(l % 0xFFFF))
-
-void smb_printerr(int class, int num);
 static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc);
 
-static inline int min(int a, int b)
+static inline int
+min(int a, int b)
+{
+	return a < b ? a : b;
+}
+
+static void
+str_upper(char *name)
+{
+	while (*name)
+	{
+		if (*name >= 'a' && *name <= 'z')
+			*name -= ('a' - 'A');
+		name++;
+	}
+}
+
+static void
+str_lower(char *name)
 {
-	return a<b ? a : b;
+	while (*name)
+	{
+		if (*name >= 'A' && *name <= 'Z')
+			*name += ('a' - 'A');
+		name++;
+	}
 }
 
 /*****************************************************************************/
@@ -45,94 +64,105 @@
 /*                                                                           */
 /*****************************************************************************/
 
-static byte *
-smb_encode_word(byte *p, word data)
+static inline byte *
+smb_decode_word(byte * p, word * data)
 {
-#if (ARCH == i386)
-        *((word *)p) = data;
-#else
-	p[0] = data & 0x00ffU;
-	p[1] = (data & 0xff00U) >> 8;
-#error "Non-Intel"
-#endif
-	return &p[2];
-}
-
-static byte *
-smb_decode_word(byte *p, word *data)
-{
-#if (ARCH == i386)
-	*data = *(word *)p;
-#else
-	*data = (word) p[0] | p[1] << 8;
-#endif 
-	return &p[2];
+	*data = WVAL(p, 0);
+	return p + 2;
 }
 
 byte *
-smb_encode_smb_length(byte *p, dword len)
+smb_encode_smb_length(byte * p, dword len)
 {
-	p[0] = p[1] = 0;
-	p[2] = (len & 0xFF00) >> 8;
-	p[3] = (len & 0xFF);
+	BSET(p, 0, 0);
+	BSET(p, 1, 0);
+	BSET(p, 2, (len & 0xFF00) >> 8);
+	BSET(p, 3, (len & 0xFF));
 	if (len > 0xFFFF)
-		p[1] |= 0x01;
-	return &p[4];
+	{
+		BSET(p, 1, 1);
+	}
+	return p + 4;
 }
 
 static byte *
-smb_encode_dialect(byte *p, const byte *name, int len)
+smb_encode_ascii(byte * p, const byte * name, int len)
 {
-	*p ++ = 2;
+	*p++ = 4;
 	strcpy(p, name);
 	return p + len + 1;
 }
 
 static byte *
-smb_encode_ascii(byte *p, const byte *name, int len)
+smb_encode_this_name(byte * p, const char *name, const int len)
 {
-	*p ++ = 4;
-	strcpy(p, name);
-	return p + len + 1;
+	*p++ = '\\';
+	strncpy(p, name, len);
+	return p + len;
 }
 
+/* I put smb_encode_parents into a separate function so that the
+   recursion only takes 16 bytes on the stack per path component on a
+   386. */
+
 static byte *
-smb_encode_vblock(byte *p, const byte *data, word len, int fs)
+smb_encode_parents(byte * p, struct smb_inode_info *ino)
 {
-	*p ++ = 5;
-	p = smb_encode_word(p, len);
-	if (fs)
-		copy_from_user(p, data, len);
-	else
-		memcpy(p, data, len);
-	return p + len;
+	byte *q;
+
+	if (ino->dir == NULL)
+	{
+		return p;
+	}
+	q = smb_encode_parents(p, ino->dir);
+	if (q - p + 1 + ino->finfo.len > SMB_MAXPATHLEN)
+	{
+		return p;
+	}
+	return smb_encode_this_name(q, ino->finfo.name, ino->finfo.len);
 }
 
 static byte *
-smb_decode_data(byte *p, byte *data, word *data_len, int fs)
-{
-        word len;
+smb_encode_path(struct smb_server *server,
+		byte * p, struct smb_inode_info *dir,
+		const char *name, const int len)
+{
+	byte *start = p;
+	p = smb_encode_parents(p, dir);
+	p = smb_encode_this_name(p, name, len);
+	*p++ = 0;
+	if (server->protocol <= PROTOCOL_COREPLUS)
+	{
+		str_upper(start);
+	}
+	return p;
+}
 
-	if (!(*p == 1 || *p == 5)) {
-                printk("smb_decode_data: Warning! Data block not starting "
-                       "with 1 or 5\n");
-        }
+static byte *
+smb_decode_data(byte * p, byte * data, word * data_len, int fs)
+{
+	word len;
 
-        len = WVAL(p, 1);
-        p += 3;
+	if (!(*p == 1 || *p == 5))
+	{
+		printk("smb_decode_data: Warning! Data block not starting "
+		       "with 1 or 5\n");
+	}
+	len = WVAL(p, 1);
+	p += 3;
 
-        if (fs)
-                copy_to_user(data, p, len);
-        else
-                memcpy(data, p, len);
+	if (fs)
+		copy_to_user(data, p, len);
+	else
+		memcpy(data, p, len);
 
-        *data_len = len;
+	*data_len = len;
 
-        return p + len;
+	return p + len;
 }
 
 static byte *
-smb_name_mangle(byte *p, const byte *name)
+smb_name_mangle(byte * p, const byte * name)
 {
 	int len, pad = 0;
 
@@ -141,19 +171,21 @@
 	if (len < 16)
 		pad = 16 - len;
 
-	*p ++ = 2 * (len + pad);
+	*p++ = 2 * (len + pad);
 
-	while (*name) {
-		*p ++ = (*name >> 4) + 'A';
-		*p ++ = (*name & 0x0F) + 'A';
-		name ++;
-	}
-	while (pad --) {
-		*p ++ = 'C';
-		*p ++ = 'A';
+	while (*name)
+	{
+		*p++ = (*name >> 4) + 'A';
+		*p++ = (*name & 0x0F) + 'A';
+		name++;
+	}
+	while (pad--)
+	{
+		*p++ = 'C';
+		*p++ = 'A';
 	}
 	*p++ = '\0';
-	
+
 	return p;
 }
 
@@ -161,7 +193,8 @@
 
 /* Linear day numbers of the respective 1sts in non-leap years. */
 
-static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+static int day_n[] =
+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
 		  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
 
 
@@ -170,30 +203,28 @@
 static int
 utc2local(int time)
 {
-        return time - sys_tz.tz_minuteswest*60 +
-	    (sys_tz.tz_dsttime ? 3600 : 0);
+	return time - sys_tz.tz_minuteswest * 60;
 }
 
 static int
 local2utc(int time)
 {
-        return time + sys_tz.tz_minuteswest*60 -
-	    (sys_tz.tz_dsttime ? 3600 : 0);
+	return time + sys_tz.tz_minuteswest * 60;
 }
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 
 static int
-date_dos2unix(unsigned short time,unsigned short date)
+date_dos2unix(unsigned short time, unsigned short date)
 {
-	int month,year,secs;
+	int month, year, secs;
 
-	month = ((date >> 5) & 15)-1;
+	month = ((date >> 5) & 15) - 1;
 	year = date >> 9;
-	secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
-	    ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
-	    month < 2 ? 1 : 0)+3653);
-			/* days since 1.1.70 plus 80's leap day */
+	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
+	    ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
+						   month < 2 ? 1 : 0) + 3653);
+	/* days since 1.1.70 plus 80's leap day */
 	return local2utc(secs);
 }
 
@@ -201,27 +232,32 @@
 /* Convert linear UNIX date to a MS-DOS time/date pair. */
 
 static void
-date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
+date_unix2dos(int unix_date, byte * date, byte * time)
 {
-	int day,year,nl_day,month;
+	int day, year, nl_day, month;
 
 	unix_date = utc2local(unix_date);
-	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
-	    (((unix_date/3600) % 24) << 11);
-	day = unix_date/86400-3652;
-	year = day/365;
-	if ((year+3)/4+365*year > day) year--;
-	day -= (year+3)/4+365*year;
-	if (day == 59 && !(year & 3)) {
+	WSET(time, 0,
+	     (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
+	     (((unix_date / 3600) % 24) << 11));
+	day = unix_date / 86400 - 3652;
+	year = day / 365;
+	if ((year + 3) / 4 + 365 * year > day)
+		year--;
+	day -= (year + 3) / 4 + 365 * year;
+	if (day == 59 && !(year & 3))
+	{
 		nl_day = day;
 		month = 2;
-	}
-	else {
-		nl_day = (year & 3) || day <= 59 ? day : day-1;
+	} else
+	{
+		nl_day = (year & 3) || day <= 59 ? day : day - 1;
 		for (month = 0; month < 12; month++)
-			if (day_n[month] > nl_day) break;
+			if (day_n[month] > nl_day)
+				break;
 	}
-	*date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+	WSET(date, 0,
+	     nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
 }
 
 
@@ -233,43 +269,39 @@
 /*****************************************************************************/
 
 dword
-smb_len(byte *packet) 
+smb_len(byte * p)
 {
-	return ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]);
+	return ((BVAL(p, 1) & 0x1) << 16L) | (BVAL(p, 2) << 8L) | (BVAL(p, 3));
 }
 
 static word
-smb_bcc(byte *packet)
+smb_bcc(byte * packet)
 {
 	int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word);
-#if (ARCH == i386)
-	return *((word *)((byte *)packet + pos));
-#else
-	return packet[pos] | packet[pos+1] << 8;
-#endif
+	return WVAL(packet, pos);
 }
 
 /* smb_valid_packet: We check if packet fulfills the basic
    requirements of a smb packet */
 
 static int
-smb_valid_packet(byte *packet)
+smb_valid_packet(byte * packet)
 {
-        DDPRINTK("len: %ld, wct: %d, bcc: %d\n",
-                 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
-	return (   packet[4] == 0xff
-                && packet[5] == 'S'
-                && packet[6] == 'M'
-                && packet[7] == 'B'
-                && (smb_len(packet) + 4 == SMB_HEADER_LEN
-                    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
+	DDPRINTK("len: %d, wct: %d, bcc: %d\n",
+		 smb_len(packet), SMB_WCT(packet), SMB_BCC(packet));
+	return (packet[4] == 0xff
+		&& packet[5] == 'S'
+		&& packet[6] == 'M'
+		&& packet[7] == 'B'
+		&& (smb_len(packet) + 4 == SMB_HEADER_LEN
+		    + SMB_WCT(packet) * 2 + SMB_BCC(packet)));
 }
 
 /* smb_verify: We check if we got the answer we expected, and if we
    got enough data. If bcc == -1, we don't care. */
 
 static int
-smb_verify(byte *packet, int command, int wct, int bcc)
+smb_verify(byte * packet, int command, int wct, int bcc)
 {
 	return (SMB_CMD(packet) == command &&
 		SMB_WCT(packet) >= wct &&
@@ -279,119 +311,100 @@
 static int
 smb_errno(int errcls, int error)
 {
-
-#if DEBUG_SMB > 1
-	if (errcls) {
-		printk("smb_errno: ");
-		smb_printerr(errcls, error);
-		printk("\n");
-	}
-#endif
-
-	if (errcls == ERRDOS) 
-		switch (error) {
-			case ERRbadfunc:    return EINVAL;
-			case ERRbadfile:    return ENOENT;
-			case ERRbadpath:    return ENOENT;
-			case ERRnofids:     return EMFILE;
-			case ERRnoaccess:   return EACCES;
-			case ERRbadfid:     return EBADF;
-			case ERRbadmcb:     return EREMOTEIO;
-			case ERRnomem:      return ENOMEM;
-			case ERRbadmem:     return EFAULT;
-			case ERRbadenv:     return EREMOTEIO;
-			case ERRbadformat:  return EREMOTEIO;
-			case ERRbadaccess:  return EACCES;
-			case ERRbaddata:    return E2BIG;
-			case ERRbaddrive:   return ENXIO;
-			case ERRremcd:      return EREMOTEIO;
-			case ERRdiffdevice: return EXDEV;
-			case ERRnofiles:    return 0;
-			case ERRbadshare:   return ETXTBSY;
-			case ERRlock:       return EDEADLK;
-			case ERRfilexists:  return EEXIST;
-			case 87:            return 0; /* Unknown error!! */
+	if (errcls == ERRDOS)
+		switch (error)
+		{
+		case ERRbadfunc:
+			return EINVAL;
+		case ERRbadfile:
+			return ENOENT;
+		case ERRbadpath:
+			return ENOENT;
+		case ERRnofids:
+			return EMFILE;
+		case ERRnoaccess:
+			return EACCES;
+		case ERRbadfid:
+			return EBADF;
+		case ERRbadmcb:
+			return EREMOTEIO;
+		case ERRnomem:
+			return ENOMEM;
+		case ERRbadmem:
+			return EFAULT;
+		case ERRbadenv:
+			return EREMOTEIO;
+		case ERRbadformat:
+			return EREMOTEIO;
+		case ERRbadaccess:
+			return EACCES;
+		case ERRbaddata:
+			return E2BIG;
+		case ERRbaddrive:
+			return ENXIO;
+		case ERRremcd:
+			return EREMOTEIO;
+		case ERRdiffdevice:
+			return EXDEV;
+		case ERRnofiles:
+			return 0;
+		case ERRbadshare:
+			return ETXTBSY;
+		case ERRlock:
+			return EDEADLK;
+		case ERRfilexists:
+			return EEXIST;
+		case 87:
+			return 0;	/* Unknown error!! */
 			/* This next error seems to occur on an mv when
 			 * the destination exists */
-			case 183:	    return EEXIST;
-			default:            return EIO;
-		}
-	else if (errcls == ERRSRV) 
-		switch (error) {
-			case ERRerror: return ENFILE;
-			case ERRbadpw: return EINVAL;
-			case ERRbadtype: return EIO;
-			case ERRaccess: return EACCES;
-			default: return EIO;
-		}
-	else if (errcls == ERRHRD) 
-		switch (error) {
-			case ERRnowrite: return EROFS; 
-			case ERRbadunit: return ENODEV;
-			case ERRnotready: return EUCLEAN;
-			case ERRbadcmd: return EIO;
-			case ERRdata: return EIO;
-			case ERRbadreq: return ERANGE;
-			case ERRbadshare: return ETXTBSY;
-			case ERRlock: return EDEADLK;
-			default: return EIO;
-		}
-	else if (errcls == ERRCMD) 
-	        return EIO;
+		case 183:
+			return EEXIST;
+		default:
+			return EIO;
+	} else if (errcls == ERRSRV)
+		switch (error)
+		{
+		case ERRerror:
+			return ENFILE;
+		case ERRbadpw:
+			return EINVAL;
+		case ERRbadtype:
+			return EIO;
+		case ERRaccess:
+			return EACCES;
+		default:
+			return EIO;
+	} else if (errcls == ERRHRD)
+		switch (error)
+		{
+		case ERRnowrite:
+			return EROFS;
+		case ERRbadunit:
+			return ENODEV;
+		case ERRnotready:
+			return EUCLEAN;
+		case ERRbadcmd:
+			return EIO;
+		case ERRdata:
+			return EIO;
+		case ERRbadreq:
+			return ERANGE;
+		case ERRbadshare:
+			return ETXTBSY;
+		case ERRlock:
+			return EDEADLK;
+		default:
+			return EIO;
+	} else if (errcls == ERRCMD)
+		return EIO;
 	return 0;
 }
 
-#if DEBUG_SMB > 0
-static char
-print_char(char c)
-{
-	if ((c < ' ') || (c > '~'))
-		return '.';
-	return c;
-}
-
-static void
-smb_dump_packet(byte *packet) {
-	int i, j, len;
-        int errcls, error;
-
-        errcls = (int)packet[9];
-        error  = (int)(int)(packet[11]|packet[12]<<8);
-
-	printk("smb_len = %d  valid = %d    \n", 
-	       len = smb_len(packet), smb_valid_packet(packet));
-	printk("smb_cmd = %d  smb_wct = %d  smb_bcc = %d\n", 
-	       packet[8], SMB_WCT(packet), SMB_BCC(packet)); 
-	printk("smb_rcls = %d smb_err = %d\n", errcls, error);
-
-	if (errcls) {
-		smb_printerr(errcls, error);
-		printk("\n");
-	}
-
-        if (len > 100)
-                len = 100;
-	
-	for (i = 0; i < len; i += 10) {
-		printk("%03d:", i);
-		for (j = i; j < i+10; j++)
-			if (j < len)
-				printk("%02x ", packet[j]);
-			else
-				printk("   ");
-		printk(": ");
-	        for (j = i; j < i+10; j++)
-			if (j < len)
-				printk("%c", print_char(packet[j]));
-		printk("\n");
-	}
-}
-#endif
-
 static void
 smb_lock_server(struct smb_server *server)
 {
-        while (server->lock)
+	while (server->lock)
 		sleep_on(&server->wait);
 	server->lock = 1;
 }
@@ -399,14 +412,14 @@
 static void
 smb_unlock_server(struct smb_server *server)
 {
-        if (server->lock != 1) {
-                printk("smb_unlock_server: was not locked!\n");
-        }
-
-        server->lock = 0;
-        wake_up(&server->wait);
+	if (server->lock != 1)
+	{
+		printk("smb_unlock_server: was not locked!\n");
+	}
+	server->lock = 0;
+	wake_up(&server->wait);
 }
-        
+
 /* smb_request_ok: We expect the server to be locked. Then we do the
    request and check the answer completely. When smb_request_ok
    returns 0, you can be quite sure that everything went well. When
@@ -415,27 +428,27 @@
 static int
 smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
 {
-        int result = 0;
-        s->rcls = 0;
-        s->err  = 0;
-
-        if (smb_request(s) < 0) {
-                DPRINTK("smb_request failed\n");
-                result = -EIO;
-        }
-        else if (smb_valid_packet(s->packet) != 0) {
-                DPRINTK("not a valid packet!\n");
-                result = -EIO;
-        }
-        else if (s->rcls != 0) {
-                result =  -smb_errno(s->rcls, s->err);
-        }
-        else if (smb_verify(s->packet, command, wct, bcc) != 0) {
-                DPRINTK("smb_verify failed\n");
-                result = -EIO;
-        }
+	int result = 0;
+	s->rcls = 0;
+	s->err = 0;
 
-        return result;
+	if (smb_request(s) < 0)
+	{
+		DPRINTK("smb_request failed\n");
+		result = -EIO;
+	} else if (smb_valid_packet(s->packet) != 0)
+	{
+		DPRINTK("not a valid packet!\n");
+		result = -EIO;
+	} else if (s->rcls != 0)
+	{
+		result = -smb_errno(s->rcls, s->err);
+	} else if (smb_verify(s->packet, command, wct, bcc) != 0)
+	{
+		DPRINTK("smb_verify failed\n");
+		result = -EIO;
+	}
+	return result;
 }
 
 /* smb_retry: This function should be called when smb_request_ok has
@@ -447,72 +460,73 @@
 static int
 smb_retry(struct smb_server *server)
 {
-        if (server->state != CONN_INVALID) {
-                return 0;
-        }
-        
-        if (smb_release(server) < 0) {
-                DPRINTK("smb_retry: smb_release failed\n");
-                server->state = CONN_RETRIED;
-                return 0;
-        }
-        if(smb_proc_reconnect(server) < 0) {
-                DPRINTK("smb_proc_reconnect failed\n");
-                server->state = CONN_RETRIED;
-                return 0;
-        }
-
-        server->state = CONN_VALID;
-        return 1;
+	if (server->state != CONN_INVALID)
+	{
+		return 0;
+	}
+	if (smb_release(server) < 0)
+	{
+		DPRINTK("smb_retry: smb_release failed\n");
+		server->state = CONN_RETRIED;
+		return 0;
+	}
+	if (smb_proc_reconnect(server) < 0)
+	{
+		DPRINTK("smb_proc_reconnect failed\n");
+		server->state = CONN_RETRIED;
+		return 0;
+	}
+	server->state = CONN_VALID;
+	return 1;
 }
 
 static int
 smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc)
 {
-        int result = smb_request_ok(s, command, wct, bcc);
+	int result = smb_request_ok(s, command, wct, bcc);
 
-        smb_unlock_server(s);
+	smb_unlock_server(s);
 
-        return result;
+	return result;
 }
-        
+
 /* smb_setup_header: We completely set up the packet. You only have to
    insert the command-specific fields */
 
-static byte *
-smb_setup_header(struct smb_server *server, byte command, word wct, word bcc)
+__u8 *
+smb_setup_header(struct smb_server * server, byte command, word wct, word bcc)
 {
 	dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2;
 	byte *p = server->packet;
-        byte *buf = server->packet;
+	byte *buf = server->packet;
 
-	p = smb_encode_smb_length(p, xmit_len);
+	p = smb_encode_smb_length(p, xmit_len - 4);
 
-        BSET(p,0,0xff);
-        BSET(p,1,'S');
-        BSET(p,2,'M');
-        BSET(p,3,'B');
-        BSET(p,4,command);
+	BSET(p, 0, 0xff);
+	BSET(p, 1, 'S');
+	BSET(p, 2, 'M');
+	BSET(p, 3, 'B');
+	BSET(p, 4, command);
 
-        p += 5;
+	p += 5;
 	memset(p, '\0', 19);
 	p += 19;
-        p += 8;
+	p += 8;
+
+	WSET(buf, smb_tid, server->tid);
+	WSET(buf, smb_pid, server->pid);
+	WSET(buf, smb_uid, server->server_uid);
+	WSET(buf, smb_mid, server->mid);
 
-        WSET(buf, smb_tid, server->tid);
-        WSET(buf, smb_pid, server->pid);
-        WSET(buf, smb_uid, server->server_uid);
-        WSET(buf, smb_mid, server->mid);
-
-        if (server->protocol > PROTOCOL_CORE) {
-                BSET(buf, smb_flg, 0x8);
-                WSET(buf, smb_flg2, 0x3);
-        }
-        
+	if (server->protocol > PROTOCOL_CORE)
+	{
+		BSET(buf, smb_flg, 0x8);
+		WSET(buf, smb_flg2, 0x3);
+	}
 	*p++ = wct;		/* wct */
-        p += 2*wct;
-        WSET(p, 0, bcc);
-        return p+2;
+	p += 2 * wct;
+	WSET(p, 0, bcc);
+	return p + 2;
 }
 
 /* smb_setup_header_exclusive waits on server->lock and locks the
@@ -521,10 +535,22 @@
 
 static byte *
 smb_setup_header_exclusive(struct smb_server *server,
-                           byte command, word wct, word bcc)
+			   byte command, word wct, word bcc)
+{
+	smb_lock_server(server);
+	return smb_setup_header(server, command, wct, bcc);
+}
+
+static void
+smb_setup_bcc(struct smb_server *server, byte * p)
 {
-        smb_lock_server(server);
-        return smb_setup_header(server, command, wct, bcc);
+	__u8 *packet = server->packet;
+	__u8 *pbcc = packet + SMB_HEADER_LEN + 2 * SMB_WCT(packet);
+	__u16 bcc = p - (pbcc + 2);
+
+	WSET(pbcc, 0, bcc);
+	smb_encode_smb_length(packet,
+			      SMB_HEADER_LEN + 2 * SMB_WCT(packet) - 2 + bcc);
 }
 
 
@@ -535,17 +561,19 @@
 /*****************************************************************************/
 
 int
-smb_proc_open(struct smb_server *server, const char *pathname, int len,
-              struct smb_dirent *entry)
+smb_proc_open(struct smb_server *server,
+	      struct smb_inode_info *dir, const char *name, int len,
+	      struct smb_dirent *entry)
 {
 	int error;
-	char* p;
-        char* buf = server->packet;
+	char *p;
+	char *buf;
 	const word o_attr = aSYSTEM | aHIDDEN | aDIR;
 
-        DPRINTK("smb_proc_open: path=%s\n", pathname);
+	DPRINTK("smb_proc_open: name=%s\n", name);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
 	if (entry->opened != 0)
 	{
@@ -553,69 +581,74 @@
 		smb_unlock_server(server);
 		return 0;
 	}
+      retry:
+	p = smb_setup_header(server, SMBopen, 2, 0);
+	WSET(buf, smb_vwv0, 0x42);	/* read/write */
+	WSET(buf, smb_vwv1, o_attr);
+	*p++ = 4;
+	p = smb_encode_path(server, p, dir, name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-        p = smb_setup_header(server, SMBopen, 2, 2 + len);
-        WSET(buf, smb_vwv0, 0x42); /* read/write */
-        WSET(buf, smb_vwv1, o_attr);
-        smb_encode_ascii(p, pathname, len);
-
-        if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
-
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                
-                if (error != -EACCES) {
-                        smb_unlock_server(server);
-                        return error;
-                }
-
-                p = smb_setup_header(server, SMBopen, 2, 2 + len);
-                WSET(buf, smb_vwv0, 0x40); /* read only */
-                WSET(buf, smb_vwv1, o_attr);
-                smb_encode_ascii(p, pathname, len);
-
-                if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) {
-                        if (smb_retry(server)) {
-                                goto retry;
-                        }
-                        smb_unlock_server(server);
-                        return error;
-                }
-        }
+	if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+	{
+
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		if ((error != -EACCES) && (error != -ETXTBSY)
+		    && (error != -EROFS))
+		{
+			smb_unlock_server(server);
+			return error;
+		}
+		p = smb_setup_header(server, SMBopen, 2, 0);
+		WSET(buf, smb_vwv0, 0x40);	/* read only */
+		WSET(buf, smb_vwv1, o_attr);
+		*p++ = 4;
+		p = smb_encode_path(server, p, dir, name, len);
+		smb_setup_bcc(server, p);
 
+		if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+		{
+			if (smb_retry(server))
+			{
+				goto retry;
+			}
+			smb_unlock_server(server);
+			return error;
+		}
+	}
 	/* We should now have data in vwv[0..6]. */
 
-        entry->fileid = WVAL(buf, smb_vwv0);
-        entry->attr   = WVAL(buf, smb_vwv1);
-        entry->ctime = entry->atime =
-                entry->mtime = local2utc(DVAL(buf, smb_vwv2));
-        entry->size   = DVAL(buf, smb_vwv4);
-        entry->access = WVAL(buf, smb_vwv6);
+	entry->fileid = WVAL(buf, smb_vwv0);
+	entry->attr = WVAL(buf, smb_vwv1);
+	entry->f_ctime = entry->f_atime =
+	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv2));
+	entry->f_size = DVAL(buf, smb_vwv4);
+	entry->access = WVAL(buf, smb_vwv6);
 
 	entry->opened = 1;
 	entry->access &= 3;
 
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 
-        DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
+	DPRINTK("smb_proc_open: entry->access = %d\n", entry->access);
 	return 0;
 }
 
-/* smb_proc_close: in finfo->mtime we can send a modification time to
-   the server */
 int
 smb_proc_close(struct smb_server *server,
 	       __u16 fileid, __u32 mtime)
 {
-        char *buf = server->packet;
+	char *buf;
 
 	smb_setup_header_exclusive(server, SMBclose, 3, 0);
-        WSET(buf, smb_vwv0, fileid);
-        DSET(buf, smb_vwv1, utc2local(mtime));
+	buf = server->packet;
+	WSET(buf, smb_vwv0, fileid);
+	DSET(buf, smb_vwv1, utc2local(mtime));
 
-        return smb_request_ok_unlock(server, SMBclose, 0, 0);
+	return smb_request_ok_unlock(server, SMBclose, 0, 0);
 }
 
 /* In smb_proc_read and smb_proc_write we do not retry, because the
@@ -625,311 +658,333 @@
    copy_to_user. */
 
 int
-smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, 
-              off_t offset, long count, char *data, int fs)
+smb_proc_read(struct smb_server *server, struct smb_dirent *finfo,
+	      off_t offset, long count, char *data, int fs)
 {
 	word returned_count, data_len;
-        char *buf = server->packet;
-        int error;
+	char *buf;
+	int error;
 
 	smb_setup_header_exclusive(server, SMBread, 5, 0);
+	buf = server->packet;
 
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        DSET(buf, smb_vwv2, offset);
-        WSET(buf, smb_vwv4, 0);
-	
-	if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0) {
-                smb_unlock_server(server);
-		return error;
-        }
+	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv1, count);
+	DSET(buf, smb_vwv2, offset);
+	WSET(buf, smb_vwv4, 0);
 
+	if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0)
+	{
+		smb_unlock_server(server);
+		return error;
+	}
 	returned_count = WVAL(buf, smb_vwv0);
-	
+
 	smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs);
 
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 
-	if (returned_count != data_len) {
+	if (returned_count != data_len)
+	{
 		printk("smb_proc_read: Warning, returned_count != data_len\n");
-                printk("smb_proc_read: ret_c=%d, data_len=%d\n",
-                       returned_count, data_len);
-        }
-
-        return data_len;
-}
-
-/* count must be <= 65535. No error number is returned.  A result of 0
-   indicates an error, which has to be investigated by a normal read
-   call. */
-int
-smb_proc_read_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                  off_t offset, long count, char *data)
-{
-        char *buf = server->packet;
-        int result;
-
-        if ((count <= 0) || (count > 65535)) {
-                return -EINVAL;
-        }
-
-	smb_setup_header_exclusive(server, SMBreadbraw, 8, 0);
-
-        WSET(buf, smb_vwv0, finfo->fileid);
-        DSET(buf, smb_vwv1, offset);
-        WSET(buf, smb_vwv3, count);
-        WSET(buf, smb_vwv4, 0);
-        DSET(buf, smb_vwv5, 0);
-
-        result = smb_request_read_raw(server, data, count);
-        smb_unlock_server(server);
-        return result;
+		printk("smb_proc_read: ret_c=%d, data_len=%d\n",
+		       returned_count, data_len);
+	}
+	return data_len;
 }
 
 int
 smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
-               off_t offset, int count, const char *data)
+	       off_t offset, int count, const char *data)
 {
-        int res = 0;
-        char *buf = server->packet;
-        byte *p;
+	int res = 0;
+	char *buf;
+	byte *p;
 
 	p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3);
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        DSET(buf, smb_vwv2, offset);
-        WSET(buf, smb_vwv4, 0);
-
-        *p++ = 1;
-        WSET(p, 0, count);
-        copy_from_user(p+2, data, count);
-
-	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) {
-                res = WVAL(buf, smb_vwv0);
-        }
+	buf = server->packet;
+	WSET(buf, smb_vwv0, finfo->fileid);
+	WSET(buf, smb_vwv1, count);
+	DSET(buf, smb_vwv2, offset);
+	WSET(buf, smb_vwv4, 0);
+
+	*p++ = 1;
+	WSET(p, 0, count);
+	copy_from_user(p + 2, data, count);
 
-        smb_unlock_server(server);
+	if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
+	{
+		res = WVAL(buf, smb_vwv0);
+	}
+	smb_unlock_server(server);
 
 	return res;
 }
 
-/* count must be <= 65535 */
 int
-smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
-                   off_t offset, long count, const char *data)
+smb_proc_create(struct inode *dir, const char *name, int len,
+		word attr, time_t ctime)
 {
-        char *buf = server->packet;
-        int result;
+	int error;
+	char *p;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
+	__u16 fileid;
 
-        if ((count <= 0) || (count > 65535)) {
-                return -EINVAL;
-        }
-
-	smb_setup_header_exclusive(server, SMBwritebraw, 11, 0);
-
-        WSET(buf, smb_vwv0, finfo->fileid);
-        WSET(buf, smb_vwv1, count);
-        WSET(buf, smb_vwv2, 0); /* reserved */
-        DSET(buf, smb_vwv3, offset);
-        DSET(buf, smb_vwv5, 0); /* timeout */
-        WSET(buf, smb_vwv7, 1); /* send final result response */
-        DSET(buf, smb_vwv8, 0); /* reserved */
-        WSET(buf, smb_vwv10, 0); /* no data in this buf */
-        WSET(buf, smb_vwv11, 0); /* no data in this buf */
-
-        result = smb_request_ok(server, SMBwritebraw, 1, 0);
-
-        DPRINTK("smb_proc_write_raw: first request returned %d\n", result);
-        
-        if (result < 0) {
-                smb_unlock_server(server);
-                return result;
-        }
-        
-        result = smb_request_write_raw(server, data, count);
-
-        DPRINTK("smb_proc_write_raw: raw request returned %d\n", result);
-        
-        if (result > 0) {
-                /* We have to do the checks of smb_request_ok here as well */
-                if (smb_valid_packet(server->packet) != 0) {
-                        DPRINTK("not a valid packet!\n");
-                        result = -EIO;
-                } else if (server->rcls != 0) {
-                        result = -smb_errno(server->rcls, server->err);
-                } else if (smb_verify(server->packet, SMBwritec,1,0) != 0) {
-                        DPRINTK("smb_verify failed\n");
-                        result = -EIO;
-                }
-        }
+	smb_lock_server(server);
+	buf = server->packet;
+      retry:
+	p = smb_setup_header(server, SMBcreate, 3, 0);
+	WSET(buf, smb_vwv0, attr);
+	DSET(buf, smb_vwv1, utc2local(ctime));
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
-        smb_unlock_server(server);
-        return result;
-}
+	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return error;
+	}
+	fileid = WVAL(buf, smb_vwv0);
+	smb_unlock_server(server);
 
+	smb_proc_close(server, fileid, CURRENT_TIME);
 
-/* smb_proc_create: We expect entry->attr & entry->ctime to be set. */
+	return 0;
+}
 
 int
-smb_proc_create(struct smb_server *server, const char *path, int len, 
-		struct smb_dirent *entry)
+smb_proc_mv(struct inode *odir, const char *oname, const int olen,
+	    struct inode *ndir, const char *nname, const int nlen)
 {
-	int error;
 	char *p;
-        char *buf = server->packet;
-	__u16 fileid;
+	struct smb_server *server = SMB_SERVER(odir);
+	char *buf;
+	int result;
 
 	smb_lock_server(server);
- retry:
-	p = smb_setup_header(server, SMBcreate, 3, len + 2);
-        WSET(buf, smb_vwv0, entry->attr);
-        DSET(buf, smb_vwv1, utc2local(entry->ctime));
-	smb_encode_ascii(p, path, len);
-
-	if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
-		return error;
-        }
-
-        entry->opened = 0;
-        fileid = WVAL(buf, smb_vwv0);
-        smb_unlock_server(server);
+	buf = server->packet;
 
-        smb_proc_close(server, fileid, 0);
+      retry:
+	p = smb_setup_header(server, SMBmv, 1, 0);
+	WSET(buf, smb_vwv0, aSYSTEM | aHIDDEN);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(odir), oname, olen);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(ndir), nname, nlen);
+	smb_setup_bcc(server, p);
 
-	return 0;
+	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_mv(struct smb_server *server, 
-            const char *opath, const int olen,
-            const char *npath, const int nlen)
+smb_proc_mkdir(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        char *buf = server->packet;
-        int result;
+	int result;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	smb_lock_server(server);
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBmkdir, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBmv, 1, olen + nlen + 4);
-        WSET(buf, smb_vwv0, 0);
-	p = smb_encode_ascii(p, opath, olen);
-	smb_encode_ascii(p, npath, olen);
-
-        if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_mkdir(struct smb_server *server, const char *path, const int len)
+smb_proc_rmdir(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        int result;
+	int result;
+	struct smb_server *server = SMB_SERVER(dir);
+
+	smb_lock_server(server);
+
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBrmdir, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBmkdir, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_rmdir(struct smb_server *server, const char *path, const int len)
+smb_proc_unlink(struct inode *dir, const char *name, const int len)
 {
 	char *p;
-        int result;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
+	int result;
+
+	smb_lock_server(server);
+	buf = server->packet;
 
-        smb_lock_server(server);
+      retry:
+	p = smb_setup_header(server, SMBunlink, 1, 0);
+	WSET(buf, smb_vwv0, aSYSTEM | aHIDDEN);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
- retry:
-	p = smb_setup_header(server, SMBrmdir, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
 int
-smb_proc_unlink(struct smb_server *server, const char *path, const int len)
+smb_proc_trunc(struct smb_server *server, word fid, dword length)
 {
 	char *p;
-        char *buf = server->packet;
-        int result;
+	char *buf;
+	int result;
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
- retry:
-	p = smb_setup_header(server, SMBunlink, 1, 2 + len);
-        WSET(buf, smb_vwv0, 0);
-	smb_encode_ascii(p, path, len);
-
-        if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+      retry:
+	p = smb_setup_header(server, SMBwrite, 5, 0);
+	WSET(buf, smb_vwv0, fid);
+	WSET(buf, smb_vwv1, 0);
+	DSET(buf, smb_vwv2, length);
+	WSET(buf, smb_vwv4, 0);
+	p = smb_encode_ascii(p, "", 0);
+	smb_setup_bcc(server, p);
+
+	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
-int
-smb_proc_trunc(struct smb_server *server, word fid, dword length)
+static void
+smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
 {
-        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- retry:
-        p = smb_setup_header(server, SMBwrite, 5, 3);
-        WSET(buf, smb_vwv0, fid);
-        WSET(buf, smb_vwv1, 0);
-        DSET(buf, smb_vwv2, length);
-        WSET(buf, smb_vwv4, 0);
-	smb_encode_ascii(p, "", 0);
-	
-        if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	memset(entry, 0, sizeof(struct smb_dirent));
+
+	entry->f_nlink = 1;
+	entry->f_uid = server->m.uid;
+	entry->f_gid = server->m.gid;
+	entry->f_blksize = 512;
 }
 
+static void
+smb_finish_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+	if ((entry->attr & aDIR) != 0)
+	{
+		entry->f_mode = server->m.dir_mode;
+		entry->f_size = 512;
+	} else
+	{
+		entry->f_mode = server->m.file_mode;
+	}
+
+	if ((entry->f_blksize != 0) && (entry->f_size != 0))
+	{
+		entry->f_blocks =
+		    (entry->f_size - 1) / entry->f_blksize + 1;
+	} else
+	{
+		entry->f_blocks = 0;
+	}
+	return;
+}
+
+void
+smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+	smb_init_dirent(server, entry);
+	entry->attr = aDIR;
+	entry->f_ino = 1;
+	smb_finish_dirent(server, entry);
+}
+
+
 static char *
-smb_decode_dirent(char *p, struct smb_dirent *entry)
+smb_decode_dirent(struct smb_server *server, char *p, struct smb_dirent *entry)
 {
-	p += SMB_STATUS_SIZE;                  /* reserved (search_status) */
-        entry->attr = BVAL(p, 0);
-        entry->mtime = entry->atime = entry->ctime =
-                date_dos2unix(WVAL(p, 1), WVAL(p, 3));
-        entry->size = DVAL(p, 5);
-        memcpy(entry->path, p+9, 13);
-	DDPRINTK("smb_decode_dirent: path = %s\n", entry->path);
+	smb_init_dirent(server, entry);
+
+	p += SMB_STATUS_SIZE;	/* reserved (search_status) */
+	entry->attr = BVAL(p, 0);
+	entry->f_mtime = entry->f_atime = entry->f_ctime =
+	    date_dos2unix(WVAL(p, 1), WVAL(p, 3));
+	entry->f_size = DVAL(p, 5);
+	entry->len = strlen(p + 9);
+	if (entry->len > 12)
+	{
+		entry->len = 12;
+	}
+	memcpy(entry->name, p + 9, entry->len);
+	entry->name[entry->len] = '\0';
+	while (entry->len > 2)
+	{
+		/* Pathworks fills names with spaces */
+		entry->len -= 1;
+		if (entry->name[entry->len] == ' ')
+		{
+			entry->name[entry->len] = '\0';
+		}
+	}
+	switch (server->case_handling)
+	{
+	case CASE_UPPER:
+		str_upper(entry->name);
+		break;
+	case CASE_LOWER:
+		str_lower(entry->name);
+		break;
+	default:
+		break;
+	}
+	DPRINTK("smb_decode_dirent: name = %s\n", entry->name);
+	smb_finish_dirent(server, entry);
 	return p + 22;
 }
 
@@ -942,118 +997,126 @@
 		       int cache_size, struct smb_dirent *entry)
 {
 	char *p;
-        char *buf;
+	char *buf;
 	int error;
-        int result;
+	int result;
 	int i;
 	int first, total_count;
-        struct smb_dirent *current_entry;
+	struct smb_dirent *current_entry;
 	word bcc;
 	word count;
 	char status[SMB_STATUS_SIZE];
 	int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE;
-	int dirlen = strlen(SMB_FINFO(dir)->path);
-	char mask[dirlen + 5];
-
-	strcpy(mask, SMB_FINFO(dir)->path);
-	strcat(mask, "\\*.*");
-
- 	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);        
-	DPRINTK("          mask = %s\n", mask);
 
-        buf = server->packet;
+	DPRINTK("SMB call  readdir %d @ %d\n", cache_size, fpos);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
- retry:
+      retry:
 	first = 1;
-        total_count = 0;
-        current_entry = entry;
-	
-	while (1) {
-		if (first == 1) {
-			p = smb_setup_header(server, SMBsearch, 2,
-                                             5 + strlen(mask));
-                        WSET(buf, smb_vwv0, entries_asked);
-                        WSET(buf, smb_vwv1, aDIR);
-			p = smb_encode_ascii(p, mask, strlen(mask));
-			*p ++ = 5;
-		        p = smb_encode_word(p, 0);
-		} else {
-			p = smb_setup_header(server, SMBsearch, 2,
-                                             5 + SMB_STATUS_SIZE);
-                        WSET(buf, smb_vwv0, entries_asked);
-                        WSET(buf, smb_vwv1, aDIR);
+	total_count = 0;
+	current_entry = entry;
+
+	while (1)
+	{
+		if (first == 1)
+		{
+			p = smb_setup_header(server, SMBsearch, 2, 0);
+			WSET(buf, smb_vwv0, entries_asked);
+			WSET(buf, smb_vwv1, aDIR);
+			*p++ = 4;
+			p = smb_encode_path(server, p, SMB_INOP(dir), "*.*", 3);
+			*p++ = 5;
+			WSET(p, 0, 0);
+			p += 2;
+		} else
+		{
+			p = smb_setup_header(server, SMBsearch, 2, 0);
+			WSET(buf, smb_vwv0, entries_asked);
+			WSET(buf, smb_vwv1, aDIR);
 			p = smb_encode_ascii(p, "", 0);
-			p = smb_encode_vblock(p, status, SMB_STATUS_SIZE, 0);
+			*p++ = 5;
+			WSET(p, 0, SMB_STATUS_SIZE);
+			p += 2;
+			memcpy(p, status, SMB_STATUS_SIZE);
+			p += SMB_STATUS_SIZE;
 		}
-		
-		if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0) {
-                        if (   (server->rcls == ERRDOS)
-                            && (server->err  == ERRnofiles)) {
-                                result = total_count - fpos;
-                                goto unlock_return;
-                        }
-                        else
-                        {
-                                if (smb_retry(server)) {
-                                        goto retry;
-                                }
-                                result = error;
-                                goto unlock_return;
-                        }
-                }
 
+		smb_setup_bcc(server, p);
+
+		if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0)
+		{
+			if ((server->rcls == ERRDOS)
+			    && (server->err == ERRnofiles))
+			{
+				result = total_count - fpos;
+				goto unlock_return;
+			} else
+			{
+				if (smb_retry(server))
+				{
+					goto retry;
+				}
+				result = error;
+				goto unlock_return;
+			}
+		}
 		p = SMB_VWV(server->packet);
-		p = smb_decode_word(p, &count); /* vwv[0] = count-returned */
-		p = smb_decode_word(p, &bcc);           
-		
+		p = smb_decode_word(p, &count);
+		p = smb_decode_word(p, &bcc);
+
 		first = 0;
-		
-		if (count <= 0) {
+
+		if (count <= 0)
+		{
 			result = total_count - fpos;
-                        goto unlock_return;
-                }
-		if (bcc != count * SMB_DIRINFO_SIZE + 3) {
+			goto unlock_return;
+		}
+		if (bcc != count * SMB_DIRINFO_SIZE + 3)
+		{
 			result = -EIO;
-                        goto unlock_return;
-                }
-
-		p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */
+			goto unlock_return;
+		}
+		p += 3;		/* Skipping VBLOCK header
+				   (5, length lo, length hi). */
 
 		/* Read the last entry into the status field. */
 		memcpy(status,
-                       SMB_BUF(server->packet) + 3 +
-                       (count - 1) * SMB_DIRINFO_SIZE, 
-                       SMB_STATUS_SIZE);
+		       SMB_BUF(server->packet) + 3 +
+		       (count - 1) * SMB_DIRINFO_SIZE,
+		       SMB_STATUS_SIZE);
 
 		/* Now we are ready to parse smb directory entries. */
-		
-		for (i = 0; i < count; i ++) {
-			if (total_count < fpos) {
+
+		for (i = 0; i < count; i++)
+		{
+			if (total_count < fpos)
+			{
 				p += SMB_DIRINFO_SIZE;
 				DDPRINTK("smb_proc_readdir: skipped entry.\n");
 				DDPRINTK("                  total_count = %d\n"
-                                         "                i = %d, fpos = %d\n",
-                                         total_count, i, fpos);
-                        }
-                        else if (total_count >= fpos + cache_size) {
-                                result = total_count - fpos;
-                                goto unlock_return;
-			}
-			else {
-				p = smb_decode_dirent(p, current_entry);
+					 "                i = %d, fpos = %d\n",
+					 total_count, i, fpos);
+			} else if (total_count >= fpos + cache_size)
+			{
+				result = total_count - fpos;
+				goto unlock_return;
+			} else
+			{
+				p = smb_decode_dirent(server, p,
+						      current_entry);
 				current_entry->f_pos = total_count;
 				DDPRINTK("smb_proc_readdir: entry->f_pos = "
-                                         "%lu\n", entry->f_pos);	
+					 "%lu\n", entry->f_pos);
 				current_entry += 1;
 			}
 			total_count += 1;
 		}
 	}
- unlock_return:
-        smb_unlock_server(server);
-        return result;
+      unlock_return:
+	smb_unlock_server(server);
+	return result;
 }
 
 /* interpret a long filename structure - this is mostly guesses at the
@@ -1062,524 +1125,483 @@
    is used by OS/2. */
 
 static char *
-smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level)
+smb_decode_long_dirent(struct smb_server *server, char *p,
+		       struct smb_dirent *entry, int level)
 {
-        char *result;
+	char *result;
 
-        if (finfo) {
-                /* I have to set times to 0 here, because I do not
-                   have specs about this for all info levels. */
-                finfo->ctime = finfo->mtime = finfo->atime = 0;
-        }
-
-        switch (level)
-        {
-        case 1:                 /* OS/2 understands this */
-                if (finfo)
-                {
-                        DPRINTK("received entry\n");
-                        strcpy(finfo->path,p+27);
-                        finfo->len  = strlen(finfo->path);
-                        finfo->size = DVAL(p,16);
-                        finfo->attr = BVAL(p,24);
-
-                        finfo->ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
-                        finfo->atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
-                        finfo->mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
-                }
-                result = p + 28 + BVAL(p,26);
-                break;
-
-        case 2:                 /* this is what OS/2 uses */
-                if (finfo)
-                {
-                        strcpy(finfo->path,p+31);
-                        finfo->len  = strlen(finfo->path);
-                        finfo->size = DVAL(p,16);
-                        finfo->attr = BVAL(p,24);
-#if 0
-                        finfo->atime = make_unix_date2(p+8);
-                        finfo->mtime = make_unix_date2(p+12);
-#endif
-                }
-                result = p + 32 + BVAL(p,30);
-                break;
-
-        case 260:               /* NT uses this, but also accepts 2 */
-                result = p + WVAL(p,0);
-                if (finfo)
-                {
-                        int namelen;
-                        p += 4; /* next entry offset */
-                        p += 4; /* fileindex */
-                        /* finfo->ctime = interpret_filetime(p);*/
-                        p += 8;
-                        /* finfo->atime = interpret_filetime(p);*/
-                        p += 8;
-                        p += 8; /* write time */
-                        /* finfo->mtime = interpret_filetime(p);*/
-                        p += 8;
-                        finfo->size = DVAL(p,0);
-                        p += 8;
-                        p += 8; /* alloc size */
-                        finfo->attr = BVAL(p,0);
-                        p += 4;
-                        namelen = min(DVAL(p,0), SMB_MAXNAMELEN);
-                        p += 4;
-                        p += 4; /* EA size */
-                        p += 2; /* short name len? */
-                        p += 24; /* short name? */	  
-                        strncpy(finfo->path,p,namelen);
-                        finfo->len = namelen;
-                }
-                break;
-
-        default:
-                DPRINTK("Unknown long filename format %d\n",level);
-                result = p + WVAL(p,0);
-        }
-        return result;
+	smb_init_dirent(server, entry);
+
+	switch (level)
+	{
+		/* We might add more levels later... */
+	case 1:
+		entry->len = BVAL(p, 26);
+		strncpy(entry->name, p + 27, entry->len);
+		entry->name[entry->len] = '\0';
+		entry->f_size = DVAL(p, 16);
+		entry->attr = BVAL(p, 24);
+
+		entry->f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
+		entry->f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
+		entry->f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
+		result = p + 28 + BVAL(p, 26);
+		break;
+
+	default:
+		DPRINTK("Unknown long filename format %d\n", level);
+		result = p + WVAL(p, 0);
+	}
+
+	switch (server->case_handling)
+	{
+	case CASE_UPPER:
+		str_upper(entry->name);
+		break;
+	case CASE_LOWER:
+		str_lower(entry->name);
+		break;
+	default:
+		break;
+	}
+
+	smb_finish_dirent(server, entry);
+	return result;
 }
 
 int
 smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos,
-                      int cache_size, struct smb_dirent *entry)
+		      int cache_size, struct smb_dirent *cache)
 {
-        int max_matches = 64; /* this should actually be based on the 
-				 maxxmit */
-  
-        /* NT uses 260, OS/2 uses 2. Both accept 1. */
-        int info_level = 1;
+	/* NT uses 260, OS/2 uses 2. Both accept 1. */
+	const int info_level = 1;
+	const int max_matches = 512;
 
 	char *p;
 	char *lastname;
-	int   lastname_len;
+	int lastname_len;
 	int i;
-	int first, total_count;
-        struct smb_dirent *current_entry;
+	int first, entries, entries_seen;
 
-        char *resp_data;
-        char *resp_param;
-        int resp_data_len = 0;
-        int resp_param_len=0;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
 
-        int attribute = aSYSTEM | aHIDDEN | aDIR;
-        int result;
+	__u16 command;
 
-        int ff_resume_key = 0;
-        int ff_searchcount=0;
-        int ff_eos=0;
-        int ff_lastname=0;
-        int ff_dir_handle=0;
-        int loop_count = 0;
+	int result;
 
-	int dirlen = strlen(SMB_FINFO(dir)->path) + 3;
-	char *mask;
+	int ff_resume_key = 0;
+	int ff_searchcount = 0;
+	int ff_eos = 0;
+	int ff_lastname = 0;
+	int ff_dir_handle = 0;
+	int loop_count = 0;
+
+	char param[SMB_MAXPATHLEN + 2 + 12];
+	int mask_len;
+	unsigned char *mask = &(param[12]);
 
-	mask = smb_kmalloc(dirlen, GFP_KERNEL);
-	if (mask == NULL)
-	{
-		printk("smb_proc_readdir_long: Memory allocation failed\n");
-		return -ENOMEM;
-	}
-	strcpy(mask, SMB_FINFO(dir)->path);
-	strcat(mask, "\\*");
+	mask_len = smb_encode_path(server, mask,
+				   SMB_INOP(dir), "*", 1) - mask;
 
- 	DPRINTK("SMB call lreaddir %d @ %d\n", cache_size, fpos);        
-	DPRINTK("          mask = %s\n", mask);
+	mask[mask_len] = 0;
+	mask[mask_len + 1] = 0;
 
-        resp_param = NULL;
-        resp_data  = NULL;
+	DPRINTK("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
+		cache_size, fpos, mask);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
 
- retry:
+      retry:
 
 	first = 1;
-        total_count = 0;
-        current_entry = entry;
-	
-        while (ff_eos == 0)
-        {
-                int masklen = strlen(mask);
-                unsigned char *outbuf = server->packet;
-                
-                loop_count += 1;
-                if (loop_count > 200)
-                {
-                        printk("smb_proc_readdir_long: "
-                               "Looping in FIND_NEXT??\n");
-                        break;
-                }
-
-                smb_setup_header(server, SMBtrans2, 15,
-                                 5 + 12 + masklen + 1);
-
-                WSET(outbuf,smb_tpscnt,12 + masklen +1);
-                WSET(outbuf,smb_tdscnt,0);
-                WSET(outbuf,smb_mprcnt,10); 
-                WSET(outbuf,smb_mdrcnt,TRANS2_MAX_TRANSFER);
-                WSET(outbuf,smb_msrcnt,0);
-                WSET(outbuf,smb_flags,0); 
-                DSET(outbuf,smb_timeout,0);
-                WSET(outbuf,smb_pscnt,WVAL(outbuf,smb_tpscnt));
-                WSET(outbuf,smb_psoff,((SMB_BUF(outbuf)+3) - outbuf)-4);
-                WSET(outbuf,smb_dscnt,0);
-                WSET(outbuf,smb_dsoff,0);
-                WSET(outbuf,smb_suwcnt,1);
-                WSET(outbuf,smb_setup0,
-                     first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT);
-
-                p = SMB_BUF(outbuf);
-                *p++=0;         /* put in a null smb_name */
-                *p++='D'; *p++ = ' '; /* this was added because OS/2 does it */
-
-                if (first != 0)
-                {
-                        WSET(p,0,attribute); /* attribute */
-                        WSET(p,2,max_matches); /* max count */
-                        WSET(p,4,8+4+2); /* resume required + close on end +
-                                            continue */
-                        WSET(p,6,info_level); 
-                        DSET(p,8,0);
-                        p += 12;
-                        strncpy(p, mask, masklen);
-                        p += masklen;
-                        *p++ = 0; *p++ = 0;
-                }
-                else
-                {
-                        DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
-                                ff_dir_handle,ff_resume_key,ff_lastname,mask);
-                        WSET(p,0,ff_dir_handle);
-                        WSET(p,2,max_matches); /* max count */
-                        WSET(p,4,info_level); 
-                        DSET(p,6,ff_resume_key); /* ff_resume_key */
-                        WSET(p,10,8+4+2); /* resume required + close on end +
-                                             continue */
-                        p += 12;
-                        strncpy(p, mask, masklen);
-                        p += masklen;
-                        *p++ = 0; *p++ = 0;
-                }
-
-                result = smb_trans2_request(server,
-                                            &resp_data_len,&resp_param_len,
-                                            &resp_data,&resp_param);
-
-                if (result < 0) {
-                        if (smb_retry(server)) {
-                                goto retry;
-                        }
-                        DPRINTK("smb_proc_readdir_long: "
-                                "got error from trans2_request\n");
-                        break;
-                }
-
-                if (server->rcls != 0)
-                {
-                        result = -EIO;
-                        break;
-                }
-
-                /* parse out some important return info */
-                p = resp_param;
-                if (first != 0)
-                {
-                        ff_dir_handle  = WVAL(p,0);
-                        ff_searchcount = WVAL(p,2);
-                        ff_eos         = WVAL(p,4);
-                        ff_lastname    = WVAL(p,8);
-                }
-                else
-                {
-                        ff_searchcount = WVAL(p,0);
-                        ff_eos         = WVAL(p,2);
-                        ff_lastname    = WVAL(p,6);
-                }
+	entries = 0;
+	entries_seen = 2;
+
+	while (ff_eos == 0)
+	{
+		loop_count += 1;
+		if (loop_count > 200)
+		{
+			printk("smb_proc_readdir_long: "
+			       "Looping in FIND_NEXT??\n");
+			break;
+		}
+		if (first != 0)
+		{
+			command = TRANSACT2_FINDFIRST;
+			WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
+			WSET(param, 2, max_matches);	/* max count */
+			WSET(param, 4, 8 + 4 + 2);	/* resume required +
+							   close on end +
+							   continue */
+			WSET(param, 6, info_level);
+			DSET(param, 8, 0);
+		} else
+		{
+			command = TRANSACT2_FINDNEXT;
+			DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
+			     ff_dir_handle, ff_resume_key, ff_lastname, mask);
+			WSET(param, 0, ff_dir_handle);
+			WSET(param, 2, max_matches);	/* max count */
+			WSET(param, 4, info_level);
+			DSET(param, 6, ff_resume_key);	/* ff_resume_key */
+			WSET(param, 10, 8 + 4 + 2);	/* resume required +
+							   close on end +
+							   continue */
+#ifdef CONFIG_SMB_WIN95
+			/* Windows 95 is not able to deliver answers
+			   to FIND_NEXT fast enough, so sleep 0.2 seconds */
+			current->timeout = jiffies + HZ / 5;
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			current->timeout = 0;
+#endif
+		}
 
-                if (ff_searchcount == 0) 
-                        break;
+		result = smb_trans2_request(server, command,
+					    0, NULL, 12 + mask_len + 2, param,
+					    &resp_data_len, &resp_data,
+					    &resp_param_len, &resp_param);
+
+		if (result < 0)
+		{
+			if (smb_retry(server))
+			{
+				goto retry;
+			}
+			DPRINTK("smb_proc_readdir_long: "
+				"got error from trans2_request\n");
+			break;
+		}
+		if (server->rcls != 0)
+		{
+			result = -EIO;
+			break;
+		}
+		/* parse out some important return info */
+		if (first != 0)
+		{
+			ff_dir_handle = WVAL(resp_param, 0);
+			ff_searchcount = WVAL(resp_param, 2);
+			ff_eos = WVAL(resp_param, 4);
+			ff_lastname = WVAL(resp_param, 8);
+		} else
+		{
+			ff_searchcount = WVAL(resp_param, 0);
+			ff_eos = WVAL(resp_param, 2);
+			ff_lastname = WVAL(resp_param, 6);
+		}
 
-                /* point to the data bytes */
-                p = resp_data;
+		if (ff_searchcount == 0)
+		{
+			break;
+		}
+		/* point to the data bytes */
+		p = resp_data;
 
-                /* we might need the lastname for continuations */
+		/* we might need the lastname for continuations */
 		lastname = "";
 		lastname_len = 0;
-                if (ff_lastname > 0)
-                {
-                        switch(info_level)
-                        {
-                        case 260:
+		if (ff_lastname > 0)
+		{
+			switch (info_level)
+			{
+			case 260:
 				lastname = p + ff_lastname;
 				lastname_len = resp_data_len - ff_lastname;
 				ff_resume_key = 0;
-                                break;
-                        case 1:
+				break;
+			case 1:
 				lastname = p + ff_lastname + 1;
-				lastname_len = strlen(lastname);
-                                ff_resume_key = 0;
-                                break;
-                        }
-                }
-  
-		/* Increase size of mask, if it is too small */
-		i = strlen(lastname) + 1;
-		if (i > dirlen)
-		{
-			smb_kfree_s(mask,  0);
-			dirlen = i;
-			mask = smb_kmalloc(dirlen, GFP_KERNEL);
-			if (mask == NULL)
-			{
-				printk("smb_proc_readdir_long: "
-				       "Memory allocation failed\n");
-				result = -ENOMEM;
+				lastname_len = BVAL(p, ff_lastname);
+				ff_resume_key = 0;
 				break;
 			}
 		}
+		lastname_len = min(lastname_len, 256);
 		strncpy(mask, lastname, lastname_len);
 		mask[lastname_len] = '\0';
-  
+
 		/* Now we are ready to parse smb directory entries. */
-		
-		for (i = 0; i < ff_searchcount; i ++) {
-			if (total_count < fpos) {
-				p = smb_decode_long_dirent(p, NULL,
-                                                           info_level);
-				DPRINTK("smb_proc_readdir: skipped entry.\n");
-				DDPRINTK("                  total_count = %d\n"
-                                         "                i = %d, fpos = %d\n",
-                                         total_count, i, fpos);
-                        }
-                        else if (total_count >= fpos + cache_size) {
-                                goto finished;
+
+		for (i = 0; i < ff_searchcount; i++)
+		{
+			struct smb_dirent *entry = &(cache[entries]);
+
+			p = smb_decode_long_dirent(server, p,
+						   entry, info_level);
+
+			DDPRINTK("smb_readdir_long: got %s\n", entry->name);
+
+			if ((entry->name[0] == '.')
+			    && ((entry->name[1] == '\0')
+				|| ((entry->name[1] == '.')
+				    && (entry->name[2] == '\0'))))
+			{
+				/* ignore . and .. from the server */
+				continue;
 			}
-			else {
-				p = smb_decode_long_dirent(p, current_entry,
-                                                           info_level);
-				current_entry->f_pos = total_count;
-				DDPRINTK("smb_proc_readdir: entry->f_pos = "
-                                         "%lu\n", entry->f_pos);	
-				current_entry += 1;
+			if (entries_seen >= fpos)
+			{
+				entry->f_pos = entries_seen;
+				entries += 1;
 			}
-			total_count += 1;
+			if (entries >= cache_size)
+			{
+				goto finished;
+			}
+			entries_seen += 1;
 		}
 
-                if (resp_data != NULL) {
-                        smb_kfree_s(resp_data,  0);
-                        resp_data = NULL;
-                }
-                if (resp_param != NULL) {
-                        smb_kfree_s(resp_param, 0);
-                        resp_param = NULL;
-                }
-
-                DPRINTK("received %d entries (eos=%d resume=%d)\n",
-                        ff_searchcount,ff_eos,ff_resume_key);
-
-                first = 0;
-        }
-
- finished:
- 	if (mask != NULL)
-		smb_kfree_s(mask,  0);
-
-        if (resp_data != NULL) {
-                smb_kfree_s(resp_data,  0);
-                resp_data = NULL;
-        }
-        if (resp_param != NULL) {
-                smb_kfree_s(resp_param, 0);
-                resp_param = NULL;
-        }
+		DPRINTK("received %d entries (eos=%d resume=%d)\n",
+			ff_searchcount, ff_eos, ff_resume_key);
 
-        smb_unlock_server(server);
+		first = 0;
+	}
 
-        return total_count - fpos;
+      finished:
+	smb_unlock_server(server);
+	return entries;
 }
 
 int
 smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos,
 		 int cache_size, struct smb_dirent *entry)
 {
-        if (server->protocol >= PROTOCOL_LANMAN2)
-                return smb_proc_readdir_long(server, dir, fpos, cache_size,
-                                             entry);
-        else
-                return smb_proc_readdir_short(server, dir, fpos, cache_size,
-                                              entry);
+	if (server->protocol >= PROTOCOL_LANMAN2)
+		return smb_proc_readdir_long(server, dir, fpos, cache_size,
+					     entry);
+	else
+		return smb_proc_readdir_short(server, dir, fpos, cache_size,
+					      entry);
 }
-		
+
 static int
-smb_proc_getattr_core(struct smb_server *server, const char *path, int len, 
-                      struct smb_dirent *entry)
+smb_proc_getattr_core(struct inode *dir, const char *name, int len,
+		      struct smb_dirent *entry)
 {
 	int result;
 	char *p;
-        char *buf = server->packet;
+	struct smb_server *server = SMB_SERVER(dir);
+	char *buf;
 
-        smb_lock_server(server);
+	smb_lock_server(server);
+	buf = server->packet;
 
-        DDPRINTK("smb_proc_getattr: %s\n", path);
+	DDPRINTK("smb_proc_getattr: %s\n", name);
 
- retry:
-	p = smb_setup_header(server, SMBgetatr, 0, 2 + len);
-	smb_encode_ascii(p, path, len);
-	
-	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
-		return result;
-        }
+      retry:
+	p = smb_setup_header(server, SMBgetatr, 0, 0);
+	*p++ = 4;
+	p = smb_encode_path(server, p, SMB_INOP(dir), name, len);
+	smb_setup_bcc(server, p);
 
-        entry->attr         = WVAL(buf, smb_vwv0);
-        entry->ctime = entry->atime = /* The server only tells us 1 time */
-                entry->mtime = local2utc(DVAL(buf, smb_vwv1));
+	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return result;
+	}
+	entry->attr = WVAL(buf, smb_vwv0);
+	entry->f_ctime = entry->f_atime =
+	    entry->f_mtime = local2utc(DVAL(buf, smb_vwv1));
 
-        entry->size         = DVAL(buf, smb_vwv3);
-        smb_unlock_server(server);
+	entry->f_size = DVAL(buf, smb_vwv3);
+	smb_unlock_server(server);
 	return 0;
 }
 
-/* smb_proc_getattrE: entry->fid must be valid */
-
 static int
-smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry)
+smb_proc_getattr_trans2(struct inode *dir, const char *name, int len,
+			struct smb_dirent *entry)
 {
-        char* buf = server->packet;
-        int result;
+	struct smb_server *server = SMB_SERVER(dir);
+	char param[SMB_MAXPATHLEN + 20];
+	char *p;
+	int result;
 
-        smb_setup_header_exclusive(server, SMBgetattrE, 1, 0);
-        WSET(buf, smb_vwv0, entry->fileid);
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+	DSET(param, 2, 0);
+	p = smb_encode_path(server, param + 6, SMB_INOP(dir), name, len);
 
-        if ((result = smb_request_ok(server, SMBgetattrE, 11, 0)) != 0) {
-                smb_unlock_server(server);
-                return result;
-        }
-
-        entry->ctime = date_dos2unix(WVAL(buf, smb_vwv1), WVAL(buf, smb_vwv0));
-        entry->atime = date_dos2unix(WVAL(buf, smb_vwv3), WVAL(buf, smb_vwv2));
-        entry->mtime = date_dos2unix(WVAL(buf, smb_vwv5), WVAL(buf, smb_vwv4));
-        entry->size  = DVAL(buf, smb_vwv6);
-        entry->attr  = WVAL(buf, smb_vwv10);
+	smb_lock_server(server);
+      retry:
+	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
+				    0, NULL, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
 
-        smb_unlock_server(server);
-        return 0;
+	if (server->rcls != 0)
+	{
+		smb_unlock_server(server);
+		return -smb_errno(server->rcls, server->err);
+	}
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
+		return result;
+	}
+	if (resp_data_len < 22)
+	{
+		smb_unlock_server(server);
+		return -ENOENT;
+	}
+	entry->f_ctime = date_dos2unix(WVAL(resp_data, 2),
+				       WVAL(resp_data, 0));
+	entry->f_atime = date_dos2unix(WVAL(resp_data, 6),
+				       WVAL(resp_data, 4));
+	entry->f_mtime = date_dos2unix(WVAL(resp_data, 10),
+				       WVAL(resp_data, 8));
+	entry->f_size = DVAL(resp_data, 12);
+	entry->attr = WVAL(resp_data, 20);
+	smb_unlock_server(server);
+
+	return 0;
 }
 
 int
-smb_proc_getattr(struct smb_server *server, const char *path, int len, 
-                 struct smb_dirent *entry)
+smb_proc_getattr(struct inode *dir, const char *name, int len,
+		 struct smb_dirent *entry)
 {
-        if (server->protocol >= PROTOCOL_LANMAN1) {
+	struct smb_server *server = SMB_SERVER(dir);
+	int result = 0;
 
-                int result = 0;
-                struct smb_dirent temp_entry;
+	smb_init_dirent(server, entry);
 
-		memset(&temp_entry, 0, sizeof(temp_entry));
-
-                if ((result=smb_proc_open(server,path,len,
-                                          &temp_entry)) < 0) {
-                        /* We cannot open directories, so we try to use the
-                           core variant */
-                        return smb_proc_getattr_core(server,path,len,entry);
-                }
-
-                if ((result=smb_proc_getattrE(server, &temp_entry)) >= 0) {
-                        entry->attr  = temp_entry.attr;
-                        entry->atime = temp_entry.atime;
-                        entry->mtime = temp_entry.mtime;
-                        entry->ctime = temp_entry.ctime;
-                        entry->size  = temp_entry.size;
-                }
-
-                smb_proc_close(server, temp_entry.fileid, temp_entry.mtime);
-                return result;
-
-        } else {
-                return smb_proc_getattr_core(server, path, len, entry);
-        }
+	if (server->protocol >= PROTOCOL_LANMAN2)
+	{
+		result = smb_proc_getattr_trans2(dir, name, len, entry);
+	}
+	if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
+	{
+		result = smb_proc_getattr_core(dir, name, len, entry);
+	}
+	smb_finish_dirent(server, entry);
+
+	entry->len = len;
+	memcpy(entry->name, name, len);
+	/* entry->name is null terminated from smb_init_dirent */
+
+	return result;
 }
 
 
 /* In core protocol, there is only 1 time to be set, we use
-   entry->mtime, to make touch work. */
+   entry->f_mtime, to make touch work. */
 static int
 smb_proc_setattr_core(struct smb_server *server,
-                      const char *path, int len,
-                      struct smb_dirent *new_finfo)
+		      struct inode *i, struct smb_dirent *new_finfo)
 {
-        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- retry:
-        p = smb_setup_header(server, SMBsetatr, 8, 4 + len);
-        WSET(buf, smb_vwv0, new_finfo->attr);
-        DSET(buf, smb_vwv1, utc2local(new_finfo->mtime));
-        p = smb_encode_ascii(p, path, len);
-        p = smb_encode_ascii(p, "", 0);
-
-        if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-        }
-        smb_unlock_server(server);
-        return result;
+	char *p;
+	char *buf;
+	int result;
+
+	smb_lock_server(server);
+	buf = server->packet;
+
+      retry:
+	p = smb_setup_header(server, SMBsetatr, 8, 0);
+	WSET(buf, smb_vwv0, new_finfo->attr);
+	DSET(buf, smb_vwv1, utc2local(new_finfo->f_mtime));
+	*p++ = 4;
+	p = smb_encode_path(server, p,
+			    SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
+			    SMB_INOP(i)->finfo.len);
+	p = smb_encode_ascii(p, "", 0);
+
+	smb_setup_bcc(server, p);
+	if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return result;
 }
 
-/* smb_proc_setattrE: we do not retry here, because we rely on fid,
-   which would not be valid after a retry. */
 static int
-smb_proc_setattrE(struct smb_server *server, word fid,
-                  struct smb_dirent *new_entry)
+smb_proc_setattr_trans2(struct smb_server *server,
+			struct inode *i, struct smb_dirent *new_finfo)
 {
-        char *buf = server->packet;
-        word date, time;
-
-        smb_setup_header_exclusive(server, SMBsetattrE, 7, 0);
+	char param[SMB_MAXPATHLEN + 20];
+	char data[26];
+	char *p;
+	int result;
 
-        WSET(buf, smb_vwv0, fid);
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+	DSET(param, 2, 0);
+	p = smb_encode_path(server, param + 6,
+			    SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
+			    SMB_INOP(i)->finfo.len);
+
+	date_unix2dos(new_finfo->f_ctime, &(data[0]), &(data[2]));
+	date_unix2dos(new_finfo->f_atime, &(data[4]), &(data[6]));
+	date_unix2dos(new_finfo->f_mtime, &(data[8]), &(data[10]));
+	DSET(data, 12, new_finfo->f_size);
+	DSET(data, 16, new_finfo->f_blksize);
+	WSET(data, 20, new_finfo->attr);
+	WSET(data, 22, 0);
 
-        date_unix2dos(new_entry->ctime, &time, &date);
-        WSET(buf, smb_vwv1, date);
-        WSET(buf, smb_vwv2, time);
-        
-        date_unix2dos(new_entry->atime, &time, &date);
-        WSET(buf, smb_vwv3, date);
-        WSET(buf, smb_vwv4, time);
-        
-        date_unix2dos(new_entry->mtime, &time, &date);
-        WSET(buf, smb_vwv5, date);
-        WSET(buf, smb_vwv6, time);
+	smb_lock_server(server);
+      retry:
+	result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
+				    26, data, p - param, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
 
-        return smb_request_ok_unlock(server, SMBsetattrE, 0, 0);
+	if (server->rcls != 0)
+	{
+		smb_unlock_server(server);
+		return -smb_errno(server->rcls, server->err);
+	}
+	if (result < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+	}
+	smb_unlock_server(server);
+	return 0;
 }
 
-/* smb_proc_setattr: for protocol >= LANMAN1 we expect the file to be
-   opened for writing. */
 int
 smb_proc_setattr(struct smb_server *server, struct inode *inode,
-                 struct smb_dirent *new_finfo)
+		 struct smb_dirent *new_finfo)
 {
-        struct smb_dirent *finfo = SMB_FINFO(inode);
-        int result;
+	int result;
 
-        if (server->protocol >= PROTOCOL_LANMAN1) {
-                if ((result = smb_make_open(inode, O_RDWR)) < 0)
-                        return result;
-                return smb_proc_setattrE(server, finfo->fileid, new_finfo);
-        } else {
-                return smb_proc_setattr_core(server, finfo->path, finfo->len,
-                                             new_finfo);
-        }
+	if (server->protocol >= PROTOCOL_LANMAN2)
+	{
+		result = smb_proc_setattr_trans2(server, inode, new_finfo);
+	}
+	if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
+	{
+		result = smb_proc_setattr_core(server, inode, new_finfo);
+	}
+	return result;
 }
 
 int
@@ -1589,25 +1611,26 @@
 	char *p;
 	struct smb_server *server = &(SMB_SBP(super)->s_server);
 
-        smb_lock_server(server);
+	smb_lock_server(server);
 
- retry:
+      retry:
 	smb_setup_header(server, SMBdskattr, 0, 0);
-	
-	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
-                if (smb_retry(server)) {
-                        goto retry;
-                }
-                smb_unlock_server(server);
+
+	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0)
+	{
+		if (smb_retry(server))
+		{
+			goto retry;
+		}
+		smb_unlock_server(server);
 		return error;
-        }
-	
+	}
 	p = SMB_VWV(server->packet);
 	p = smb_decode_word(p, &attr->total);
 	p = smb_decode_word(p, &attr->allocblocks);
 	p = smb_decode_word(p, &attr->blocksize);
 	p = smb_decode_word(p, &attr->free);
-        smb_unlock_server(server);
+	smb_unlock_server(server);
 	return 0;
 }
 
@@ -1617,7 +1640,8 @@
 /*                                                                           */
 /*****************************************************************************/
 
-struct smb_prots {
+struct smb_prots
+{
 	enum smb_protocol prot;
 	const char *name;
 };
@@ -1631,50 +1655,50 @@
 smb_proc_reconnect(struct smb_server *server)
 {
 	struct smb_prots prots[] =
-        { { PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
-          { PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+	{
+		{PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
+		{PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
 #ifdef LANMAN1
-          { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
-          { PROTOCOL_LANMAN1,"LANMAN1.0"},
+		{PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
+		{PROTOCOL_LANMAN1, "LANMAN1.0"},
 #endif
-#ifdef CONFIG_SMB_LONG
 #ifdef LANMAN2
-          { PROTOCOL_LANMAN2,"LM1.2X002"},
+		{PROTOCOL_LANMAN2, "LM1.2X002"},
 #endif
 #ifdef NT1
-	  { PROTOCOL_NT1,"NT LM 0.12"},
-	  { PROTOCOL_NT1,"NT LANMAN 1.0"},
-#endif
+		{PROTOCOL_NT1, "NT LM 0.12"},
+		{PROTOCOL_NT1, "NT LANMAN 1.0"},
 #endif
-          {-1, NULL} };
+		{-1, NULL}};
 	char dev[] = "A:";
 	int i, plength;
 	int max_xmit = 1024;	/* Space needed for first request. */
-        int given_max_xmit = server->m.max_xmit;
+	int given_max_xmit = server->m.max_xmit;
 	int result;
 	byte *p;
 
-        if ((result = smb_connect(server)) < 0) {
-                DPRINTK("smb_proc_reconnect: could not smb_connect\n");
-                goto fail;
-        }
-
-        /* Here we assume that the connection is valid */
-        server->state = CONN_VALID;
-
-        if (server->packet != NULL) {
-                smb_kfree_s(server->packet, server->max_xmit);
-        }
-        
-	server->packet = smb_kmalloc(max_xmit, GFP_KERNEL);
+	if ((result = smb_connect(server)) < 0)
+	{
+		DPRINTK("smb_proc_reconnect: could not smb_connect\n");
+		goto fail;
+	}
+	/* Here we assume that the connection is valid */
+	server->state = CONN_VALID;
 
-	if (server->packet == NULL) {
-		printk("smb_proc_connect: No memory! Bailing out.\n");
-                result = -ENOMEM;
-                goto fail;
+	if (server->packet != NULL)
+	{
+		smb_vfree(server->packet);
+		server->packet_size = 0;
 	}
+	server->packet = smb_vmalloc(max_xmit);
 
-        server->max_xmit = max_xmit;
+	if (server->packet == NULL)
+	{
+		printk("smb_proc_connect: No memory! Bailing out.\n");
+		result = -ENOMEM;
+		goto fail;
+	}
+	server->packet_size = server->max_xmit = max_xmit;
 
 	/*
 	 * Start with an RFC1002 session request packet.
@@ -1683,98 +1707,110 @@
 
 	p = smb_name_mangle(p, server->m.server_name);
 	p = smb_name_mangle(p, server->m.client_name);
-	
+
 	smb_encode_smb_length(server->packet,
-                              (void *)p - (void *)(server->packet));
-	
-	server->packet[0] = 0x81; /* SESSION REQUEST */
-
-        if (smb_catch_keepalive(server) < 0) {
-                printk("smb_proc_connect: could not catch_keepalives\n");
-        }
-        
-	if ((result = smb_request(server)) < 0) {
-		printk("smb_proc_connect: Failed to send SESSION REQUEST.\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+			      (void *) p - (void *) (server->packet));
+
+	server->packet[0] = 0x81;	/* SESSION REQUEST */
+
+	if (smb_catch_keepalive(server) < 0)
+	{
+		printk("smb_proc_connect: could not catch_keepalives\n");
 	}
-	
-	if (server->packet[0] != 0x82) {
+	if ((result = smb_request(server)) < 0)
+	{
+		DPRINTK("smb_proc_connect: Failed to send SESSION REQUEST.\n");
+		smb_dont_catch_keepalive(server);
+		goto fail;
+	}
+	if (server->packet[0] != 0x82)
+	{
 		printk("smb_proc_connect: Did not receive positive response "
-                       "(err = %x)\n", 
+		       "(err = %x)\n",
 		       server->packet[0]);
-                smb_dont_catch_keepalive(server);
-#if DEBUG_SMB > 0
-                smb_dump_packet(server->packet);
-#endif
-                result = -EIO;
-                goto fail;
+		smb_dont_catch_keepalive(server);
+		result = -EIO;
+		goto fail;
 	}
+	DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
 
-        DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n");
-	
 	/* Now we are ready to send a SMB Negotiate Protocol packet. */
 	memset(server->packet, 0, SMB_HEADER_LEN);
 
 	plength = 0;
-	for (i = 0; prots[i].name != NULL; i++) {
+	for (i = 0; prots[i].name != NULL; i++)
+	{
 		plength += strlen(prots[i].name) + 2;
-        }
+	}
 
 	smb_setup_header(server, SMBnegprot, 0, plength);
 
 	p = SMB_BUF(server->packet);
-	
-	for (i = 0; prots[i].name != NULL; i++) {
-		p = smb_encode_dialect(p,prots[i].name, strlen(prots[i].name));
-        }
-	
-	if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0) {
-         	printk("smb_proc_connect: Failure requesting SMBnegprot\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
-	} else {
-                DDPRINTK("smb_proc_connect: Request SMBnegprot..");
-        }
-
-        DDPRINTK("Verified!\n");
-
-        p = SMB_VWV(server->packet);
-	p = smb_decode_word(p, (word *)&i);
-        server->protocol = prots[i].prot;
+
+	for (i = 0; prots[i].name != NULL; i++)
+	{
+		*p++ = 2;
+		strcpy(p, prots[i].name);
+		p += strlen(prots[i].name) + 1;
+	}
+
+	if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0)
+	{
+		DPRINTK("smb_proc_connect: Failure requesting SMBnegprot\n");
+		smb_dont_catch_keepalive(server);
+		goto fail;
+	} else
+	{
+		DDPRINTK("smb_proc_connect: Request SMBnegprot..");
+	}
+
+	DDPRINTK("Verified!\n");
+
+	p = SMB_VWV(server->packet);
+	p = smb_decode_word(p, (word *) & i);
+	server->protocol = prots[i].prot;
 
 	DPRINTK("smb_proc_connect: Server wants %s protocol.\n",
-                prots[i].name);
+		prots[i].name);
+
+	if (server->protocol >= PROTOCOL_LANMAN1)
+	{
+
+		word passlen = strlen(server->m.password);
+		word userlen = strlen(server->m.username);
 
-        if (server->protocol >= PROTOCOL_LANMAN1) {
+		DPRINTK("smb_proc_connect: password = %s\n",
+			server->m.password);
+		DPRINTK("smb_proc_connect: usernam = %s\n",
+			server->m.username);
+		DPRINTK("smb_proc_connect: blkmode = %d\n",
+			WVAL(server->packet, smb_vwv5));
 
-                word passlen = strlen(server->m.password);
-                word userlen = strlen(server->m.username);
-                
-                DPRINTK("smb_proc_connect: password = %s\n",
-                        server->m.password);
-                DPRINTK("smb_proc_connect: usernam = %s\n",
-                        server->m.username);
-                DPRINTK("smb_proc_connect: blkmode = %d\n",
-                        WVAL(server->packet, smb_vwv5));
-
-		if (server->protocol >= PROTOCOL_NT1) {
-			server->maxxmt = DVAL(server->packet,smb_vwv3+1);
-			server->maxmux = WVAL(server->packet, smb_vwv1+1);
-			server->maxvcs = WVAL(server->packet, smb_vwv2+1);
-			server->blkmode= DVAL(server->packet, smb_vwv9+1);
-			server->sesskey= DVAL(server->packet, smb_vwv7+1);
-		} else {
-			server->maxxmt = WVAL(server->packet, smb_vwv2);
+		if (server->protocol >= PROTOCOL_NT1)
+		{
+			server->max_xmit = DVAL(server->packet, smb_vwv3 + 1);
+			server->maxmux = WVAL(server->packet, smb_vwv1 + 1);
+			server->maxvcs = WVAL(server->packet, smb_vwv2 + 1);
+			server->blkmode = DVAL(server->packet, smb_vwv9 + 1);
+			server->sesskey = DVAL(server->packet, smb_vwv7 + 1);
+		} else
+		{
+			server->max_xmit = WVAL(server->packet, smb_vwv2);
 			server->maxmux = WVAL(server->packet, smb_vwv3);
 			server->maxvcs = WVAL(server->packet, smb_vwv4);
-			server->blkmode= WVAL(server->packet, smb_vwv5);
-			server->sesskey= DVAL(server->packet, smb_vwv6);
+			server->blkmode = WVAL(server->packet, smb_vwv5);
+			server->sesskey = DVAL(server->packet, smb_vwv6);
 		}
 
-
-		if (server->protocol >= PROTOCOL_NT1) {
-			char *workgroup = "WORKGROUP";
+		if (server->max_xmit < given_max_xmit)
+		{
+			/* We do not distinguish between the client
+			   requests and the server response. */
+			given_max_xmit = server->max_xmit;
+		}
+		if (server->protocol >= PROTOCOL_NT1)
+		{
+			char *workgroup = server->m.domain;
 			char *OS_id = "Unix";
 			char *client_id = "ksmbfs";
 
@@ -1782,7 +1818,7 @@
 					 5 + userlen + passlen +
 					 strlen(workgroup) + strlen(OS_id) +
 					 strlen(client_id));
-			
+
 			WSET(server->packet, smb_vwv0, 0x00ff);
 			WSET(server->packet, smb_vwv1, 0);
 			WSET(server->packet, smb_vwv2, given_max_xmit);
@@ -1803,7 +1839,8 @@
 			strcpy(p, OS_id);
 			p += strlen(p) + 1;
 			strcpy(p, client_id);
-		} else {
+		} else
+		{
 			smb_setup_header(server, SMBsesssetupX, 10,
 					 2 + userlen + passlen);
 
@@ -1823,47 +1860,59 @@
 			strcpy(p, server->m.username);
 		}
 
-                if ((result = smb_request_ok(server,SMBsesssetupX,3,0)) < 0) {
-                        DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
-                        smb_dont_catch_keepalive(server);
-                        goto fail;
-                }
-                smb_decode_word(server->packet+32, &(server->server_uid));
-        }
-        else
-        {
-                server->maxxmt = 0;
-                server->maxmux = 0;
-                server->maxvcs = 0;
-                server->blkmode = 0;
-                server->sesskey = 0;
-        }
+		if ((result = smb_request_ok(server, SMBsesssetupX, 3, 0)) < 0)
+		{
+			DPRINTK("smb_proc_connect: SMBsessetupX failed\n");
+			smb_dont_catch_keepalive(server);
+			goto fail;
+		}
+		smb_decode_word(server->packet + 32, &(server->server_uid));
+	} else
+	{
+		server->max_xmit = 0;
+		server->maxmux = 0;
+		server->maxvcs = 0;
+		server->blkmode = 0;
+		server->sesskey = 0;
+	}
 
 	/* Fine! We have a connection, send a tcon message. */
 
 	smb_setup_header(server, SMBtcon, 0,
-                         6 + strlen(server->m.service) +
-                         strlen(server->m.password) + strlen(dev));
+			 6 + strlen(server->m.service) +
+			 strlen(server->m.password) + strlen(dev));
 
 	p = SMB_BUF(server->packet);
 	p = smb_encode_ascii(p, server->m.service, strlen(server->m.service));
-	p = smb_encode_ascii(p,server->m.password, strlen(server->m.password));
+	p = smb_encode_ascii(p, server->m.password, strlen(server->m.password));
 	p = smb_encode_ascii(p, dev, strlen(dev));
 
-	if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0) {
+	if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0)
+	{
 		DPRINTK("smb_proc_connect: SMBtcon not verified.\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+		smb_dont_catch_keepalive(server);
+		goto fail;
 	}
+	DDPRINTK("OK! Managed to set up SMBtcon!\n");
 
-        DDPRINTK("OK! Managed to set up SMBtcon!\n");
-   
 	p = SMB_VWV(server->packet);
-	p = smb_decode_word(p, &server->max_xmit);
 
-        if (server->max_xmit > given_max_xmit)
-                server->max_xmit = given_max_xmit;
-        
+	if (server->protocol <= PROTOCOL_COREPLUS)
+	{
+		word max_xmit;
+
+		p = smb_decode_word(p, &max_xmit);
+		server->max_xmit = max_xmit;
+
+		if (server->max_xmit > given_max_xmit)
+		{
+			server->max_xmit = given_max_xmit;
+		}
+	} else
+	{
+		p += 2;
+	}
+
 	p = smb_decode_word(p, &server->tid);
 
 	/* Ok, everything is fine. max_xmit does not include */
@@ -1873,22 +1922,24 @@
 	DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid);
 
 	/* Now make a new packet with the correct size. */
-	smb_kfree_s(server->packet, max_xmit); 
+	smb_vfree(server->packet);
 
-	server->packet = smb_kmalloc(server->max_xmit, GFP_KERNEL);
-	if (server->packet == NULL) {
+	server->packet = smb_vmalloc(server->max_xmit);
+	if (server->packet == NULL)
+	{
 		printk("smb_proc_connect: No memory left in end of "
-                       "connection phase :-(\n");
-                smb_dont_catch_keepalive(server);
-                goto fail;
+		       "connection phase :-(\n");
+		smb_dont_catch_keepalive(server);
+		goto fail;
 	}
+	server->packet_size = server->max_xmit;
 
-        DPRINTK("smb_proc_connect: Normal exit\n");
-        return 0;
+	DPRINTK("smb_proc_connect: Normal exit\n");
+	return 0;
 
- fail:
-        server->state = CONN_INVALID;
-        return result;
+      fail:
+	server->state = CONN_INVALID;
+	return result;
 }
 
 /* smb_proc_reconnect: server->packet is allocated with
@@ -1896,172 +1947,23 @@
 int
 smb_proc_connect(struct smb_server *server)
 {
-        int result;
-        smb_lock_server(server);
-
-        result = smb_proc_reconnect(server);
+	int result;
+	smb_lock_server(server);
 
-        if ((result < 0) && (server->packet != NULL)) {
-                smb_kfree_s(server->packet, server->max_xmit);
-                server->packet = NULL;
-        }
+	result = smb_proc_reconnect(server);
 
-        smb_unlock_server(server);
-        return result;
+	if ((result < 0) && (server->packet != NULL))
+	{
+		smb_vfree(server->packet);
+		server->packet = NULL;
+	}
+	smb_unlock_server(server);
+	return result;
 }
-	
+
 int
 smb_proc_disconnect(struct smb_server *server)
 {
 	smb_setup_header_exclusive(server, SMBtdis, 0, 0);
 	return smb_request_ok_unlock(server, SMBtdis, 0, 0);
 }
-
-/* error code stuff - put together by Merik Karman
-   merik@blackadder.dsh.oz.au */
-
-#if DEBUG_SMB > 0
-
-typedef struct {
-	char *name;
-	int code;
-	char *message;
-} err_code_struct;
-
-/* Dos Error Messages */
-err_code_struct dos_msgs[] = {
-  { "ERRbadfunc",1,"Invalid function."},
-  { "ERRbadfile",2,"File not found."},
-  { "ERRbadpath",3,"Directory invalid."},
-  { "ERRnofids",4,"No file descriptors available"},
-  { "ERRnoaccess",5,"Access denied."},
-  { "ERRbadfid",6,"Invalid file handle."},
-  { "ERRbadmcb",7,"Memory control blocks destroyed."},
-  { "ERRnomem",8,"Insufficient server memory to perform the requested function."},
-  { "ERRbadmem",9,"Invalid memory block address."},
-  { "ERRbadenv",10,"Invalid environment."},
-  { "ERRbadformat",11,"Invalid format."},
-  { "ERRbadaccess",12,"Invalid open mode."},
-  { "ERRbaddata",13,"Invalid data."},
-  { "ERR",14,"reserved."},
-  { "ERRbaddrive",15,"Invalid drive specified."},
-  { "ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
-  { "ERRdiffdevice",17,"Not same device."},
-  { "ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
-  { "ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
-  { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an  invalid mode,  or an Unlock requested attempted to remove a lock held by another process."},
-  { "ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
-  { "ERRbadpipe",230,"Pipe invalid."},
-  { "ERRpipebusy",231,"All instances of the requested pipe are busy."},
-  { "ERRpipeclosing",232,"Pipe close in progress."},
-  { "ERRnotconnected",233,"No process on other end of pipe."},
-  { "ERRmoredata",234,"There is more data to be returned."},
-  { NULL,-1,NULL}};
-
-/* Server Error Messages */
-err_code_struct server_msgs[] = { 
-  { "ERRerror",1,"Non-specific error code."},
-  { "ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
-  { "ERRbadtype",3,"reserved."},
-  { "ERRaccess",4,"The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID."},
-  { "ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
-  { "ERRinvnetname",6,"Invalid network name in tree connect."},
-  { "ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
-  { "ERRqfull",49,"Print queue full (files) -- returned by open print file."},
-  { "ERRqtoobig",50,"Print queue full -- no space."},
-  { "ERRqeof",51,"EOF on print queue dump."},
-  { "ERRinvpfid",52,"Invalid print file FID."},
-  { "ERRsmbcmd",64,"The server did not recognize the command received."},
-  { "ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
-  { "ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
-  { "ERRreserved",68,"reserved."},
-  { "ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
-  { "ERRreserved",70,"reserved."},
-  { "ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
-  { "ERRpaused",81,"Server is paused."},
-  { "ERRmsgoff",82,"Not receiving messages."},
-  { "ERRnoroom",83,"No room to buffer message."},
-  { "ERRrmuns",87,"Too many remote user names."},
-  { "ERRtimeout",88,"Operation timed out."},
-  { "ERRnoresource",89,"No resources currently available for request."},
-  { "ERRtoomanyuids",90,"Too many UIDs active on this session."},
-  { "ERRbaduid",91,"The UID is not known as a valid ID on this session."},
-  { "ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
-  { "ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
-  { "ERRcontmpx",252,"Continue in MPX mode."},
-  { "ERRreserved",253,"reserved."},
-  { "ERRreserved",254,"reserved."},
-  { "ERRnosupport",0xFFFF,"Function not supported."},
-  { NULL,-1,NULL}};
-
-/* Hard Error Messages */
-err_code_struct hard_msgs[] = { 
-  { "ERRnowrite",19,"Attempt to write on write-protected diskette."},
-  { "ERRbadunit",20,"Unknown unit."},
-  { "ERRnotready",21,"Drive not ready."},
-  { "ERRbadcmd",22,"Unknown command."},
-  { "ERRdata",23,"Data error (CRC)."},
-  { "ERRbadreq",24,"Bad request structure length."},
-  { "ERRseek",25 ,"Seek error."},
-  { "ERRbadmedia",26,"Unknown media type."},
-  { "ERRbadsector",27,"Sector not found."},
-  { "ERRnopaper",28,"Printer out of paper."},
-  { "ERRwrite",29,"Write fault."},
-  { "ERRread",30,"Read fault."},
-  { "ERRgeneral",31,"General failure."},
-  { "ERRbadshare",32,"A open conflicts with an existing open."},
-  { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
-  { "ERRwrongdisk",34,"The wrong disk was found in a drive."},
-  { "ERRFCBUnavail",35,"No FCBs are available to process request."},
-  { "ERRsharebufexc",36,"A sharing buffer has been exceeded."},
-  { NULL,-1,NULL}
-};
-
-
-struct { 
-	int code;
-	char *class;
-	err_code_struct *err_msgs;
-} err_classes[] = {  
-  { 0,"SUCCESS",NULL},
-  { 0x01,"ERRDOS",dos_msgs},
-  { 0x02,"ERRSRV",server_msgs},
-  { 0x03,"ERRHRD",hard_msgs},
-  { 0x04,"ERRXOS",NULL},
-  { 0xE1,"ERRRMX1",NULL},
-  { 0xE2,"ERRRMX2",NULL},
-  { 0xE3,"ERRRMX3",NULL},
-  { 0xFF,"ERRCMD",NULL},
-  { -1,NULL,NULL}
-};
-
-void
-smb_printerr(int class, int num)
-{
-	int i,j;
-	err_code_struct *err;
-
-	for (i=0; err_classes[i].class; i++) {
-		if (err_classes[i].code != class)
-			continue;
-		if (!err_classes[i].err_msgs) {
-			printk("%s - %d", err_classes[i].class, num);
-			return;
-		}
-
-		err = err_classes[i].err_msgs;
-		for (j=0; err[j].name; j++) {
-			if (num != err[j].code)
-				continue;
-			printk("%s - %s (%s)",
-			       err_classes[i].class, err[j].name,
-                               err[j].message);
-			return;
-		}
-	}
-	
-	printk("Unknown error - (%d,%d)", class, num);
-	return;
-}
-
-#endif /* DEBUG_SMB > 0 */
diff -u --recursive --new-file v2.1.13/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.1.13/linux/fs/smbfs/sock.c	Tue Oct 29 19:58:44 1996
+++ linux/fs/smbfs/sock.c	Sun Dec  1 18:26:22 1996
@@ -1,7 +1,7 @@
 /*
  *  sock.c
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -11,7 +11,6 @@
 #include <linux/socket.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
-#include <asm/uaccess.h>
 #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/mm.h>
@@ -21,6 +20,7 @@
 #include <linux/smb.h>
 #include <linux/smbno.h>
 
+#include <asm/uaccess.h>
 
 #define _S(nr) (1<<((nr)-1))
 
@@ -28,747 +28,687 @@
 _recvfrom(struct socket *sock, unsigned char *ubuf, int size,
 	  int noblock, unsigned flags, struct sockaddr_in *sa, int *addr_len)
 {
-        struct iovec iov;
-        struct msghdr msg;
+	struct iovec iov;
+	struct msghdr msg;
 
-        iov.iov_base = ubuf;
-        iov.iov_len  = size;
+	iov.iov_base = ubuf;
+	iov.iov_len = size;
 
-        msg.msg_name      = (void *)sa;
-        msg.msg_namelen   = 0;
-        if (addr_len)
-                msg.msg_namelen = *addr_len;
-        msg.msg_control = NULL;
-        msg.msg_iov       = &iov;
-        msg.msg_iovlen    = 1;
+	msg.msg_name = (void *) sa;
+	msg.msg_namelen = 0;
+	if (addr_len)
+		msg.msg_namelen = *addr_len;
+	msg.msg_control = NULL;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
 
-        return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
+	return sock->ops->recvmsg(sock, &msg, size, noblock, flags, addr_len);
 }
 
 static int
 _send(struct socket *sock, const void *buff, int len,
       int nonblock, unsigned flags)
 {
-        struct iovec iov;
-        struct msghdr msg;
+	struct iovec iov;
+	struct msghdr msg;
 
-        iov.iov_base = (void *)buff;
-        iov.iov_len  = len;
+	iov.iov_base = (void *) buff;
+	iov.iov_len = len;
 
-        msg.msg_name      = NULL;
-        msg.msg_namelen   = 0;
-        msg.msg_control = NULL;
-        msg.msg_iov       = &iov;
-        msg.msg_iovlen    = 1;
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = NULL;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
 
-        return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
+	return sock->ops->sendmsg(sock, &msg, len, nonblock, flags);
 }
 
 static void
-smb_data_callback(struct sock *sk,int len)
+smb_data_callback(struct sock *sk, int len)
 {
-        struct socket *sock = sk->socket;
+	struct socket *sock = sk->socket;
 
-	if(!sk->dead)
+	if (!sk->dead)
 	{
-                unsigned char peek_buf[4];
-                int result;
-                unsigned short fs;
-
-                fs = get_fs();
-                set_fs(get_ds());
-
-		result = _recvfrom(sock, (void *)peek_buf, 1, 1,
-                                             MSG_PEEK, NULL, NULL);
-
-                while ((result != -EAGAIN) && (peek_buf[0] == 0x85)) {
-
-                        /* got SESSION KEEP ALIVE */
-                        result = _recvfrom(sock, (void *)peek_buf,
-                                                     4, 1, 0, NULL, NULL);
-
-                        DDPRINTK("smb_data_callback:"
-                                 " got SESSION KEEP ALIVE\n");
-
-                        if (result == -EAGAIN)
-                                break;
+		unsigned char peek_buf[4];
+		int result;
+		unsigned short fs;
+
+		fs = get_fs();
+		set_fs(get_ds());
+
+		result = _recvfrom(sock, (void *) peek_buf, 1, 1,
+				   MSG_PEEK, NULL, NULL);
+
+		while ((result != -EAGAIN) && (peek_buf[0] == 0x85))
+		{
+			/* got SESSION KEEP ALIVE */
+			result = _recvfrom(sock, (void *) peek_buf,
+					   4, 1, 0, NULL, NULL);
+
+			DDPRINTK("smb_data_callback:"
+				 " got SESSION KEEP ALIVE\n");
+
+			if (result == -EAGAIN)
+			{
+				break;
+			}
+			result = _recvfrom(sock, (void *) peek_buf,
+					   1, 1, MSG_PEEK,
+					   NULL, NULL);
+		}
+		set_fs(fs);
+
+		if (result != -EAGAIN)
+		{
+			wake_up_interruptible(sk->sleep);
+		}
+	}
+}
 
-                        result = _recvfrom(sock, (void *)peek_buf,
-                                                     1, 1, MSG_PEEK,
-                                                     NULL, NULL);
+int
+smb_catch_keepalive(struct smb_server *server)
+{
+	struct file *file;
+	struct inode *inode;
+	struct socket *sock;
+	struct sock *sk;
+
+	if ((server == NULL)
+	    || ((file = server->sock_file) == NULL)
+	    || ((inode = file->f_inode) == NULL)
+	    || (!S_ISSOCK(inode->i_mode)))
+	{
+		printk("smb_catch_keepalive: did not get valid server!\n");
+		server->data_ready = NULL;
+		return -EINVAL;
+	}
+	sock = &(inode->u.socket_i);
 
-                }
+	if (sock->type != SOCK_STREAM)
+	{
+		printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
+		server->data_ready = NULL;
+		return -EINVAL;
+	}
+	sk = (struct sock *) (sock->data);
 
-                set_fs(fs);
+	if (sk == NULL)
+	{
+		printk("smb_catch_keepalive: sk == NULL");
+		server->data_ready = NULL;
+		return -EINVAL;
+	}
+	DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
+		 (unsigned int) (sk->data_ready),
+		 (unsigned int) (server->data_ready));
 
-                if (result != -EAGAIN) {
-                        wake_up_interruptible(sk->sleep);
-                }
+	if (sk->data_ready == smb_data_callback)
+	{
+		printk("smb_catch_keepalive: already done\n");
+		return -EINVAL;
 	}
+	server->data_ready = sk->data_ready;
+	sk->data_ready = smb_data_callback;
+	return 0;
 }
 
 int
-smb_catch_keepalive(struct smb_server *server)
+smb_dont_catch_keepalive(struct smb_server *server)
 {
-        struct file   *file;
-        struct inode  *inode;
-        struct socket *sock;
-        struct sock   *sk;
-
-        if (   (server == NULL)
-            || ((file  = server->sock_file) == NULL)
-            || ((inode = file->f_inode) == NULL)
-            || (!S_ISSOCK(inode->i_mode))) {
-
-                printk("smb_catch_keepalive: did not get valid server!\n");
-                server->data_ready = NULL;
-                return -EINVAL;
-        }
-
-        sock = &(inode->u.socket_i);
-
-        if (sock->type != SOCK_STREAM) {
-                printk("smb_catch_keepalive: did not get SOCK_STREAM\n");
-                server->data_ready = NULL;
-                return -EINVAL;
-        }
-
-        sk   = (struct sock *)(sock->data);
-
-        if (sk == NULL) {
-                printk("smb_catch_keepalive: sk == NULL");
-                server->data_ready = NULL;
-                return -EINVAL;
-        }
-
-        DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n",
-                 (unsigned int)(sk->data_ready),
-                 (unsigned int)(server->data_ready));
-
-        if (sk->data_ready == smb_data_callback) {
-                printk("smb_catch_keepalive: already done\n");
-                return -EINVAL;
-        }
-
-        server->data_ready = sk->data_ready;
-        sk->data_ready = smb_data_callback;
-        return 0;
+	struct file *file;
+	struct inode *inode;
+	struct socket *sock;
+	struct sock *sk;
+
+	if ((server == NULL)
+	    || ((file = server->sock_file) == NULL)
+	    || ((inode = file->f_inode) == NULL)
+	    || (!S_ISSOCK(inode->i_mode)))
+	{
+		printk("smb_dont_catch_keepalive: "
+		       "did not get valid server!\n");
+		return -EINVAL;
+	}
+	sock = &(inode->u.socket_i);
+
+	if (sock->type != SOCK_STREAM)
+	{
+		printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
+		return -EINVAL;
+	}
+	sk = (struct sock *) (sock->data);
+
+	if (sk == NULL)
+	{
+		printk("smb_dont_catch_keepalive: sk == NULL");
+		return -EINVAL;
+	}
+	if (server->data_ready == NULL)
+	{
+		printk("smb_dont_catch_keepalive: "
+		       "server->data_ready == NULL\n");
+		return -EINVAL;
+	}
+	if (sk->data_ready != smb_data_callback)
+	{
+		printk("smb_dont_catch_keepalive: "
+		       "sk->data_callback != smb_data_callback\n");
+		return -EINVAL;
+	}
+	DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
+		 (unsigned int) (sk->data_ready),
+		 (unsigned int) (server->data_ready));
+
+	sk->data_ready = server->data_ready;
+	server->data_ready = NULL;
+	return 0;
 }
-                
-int
-smb_dont_catch_keepalive(struct smb_server *server)
+
+static int
+smb_send_raw(struct socket *sock, unsigned char *source, int length)
 {
-        struct file   *file;
-        struct inode  *inode;
-        struct socket *sock;
-        struct sock   *sk;
-
-        if (   (server == NULL)
-            || ((file  = server->sock_file) == NULL)
-            || ((inode = file->f_inode) == NULL)
-            || (!S_ISSOCK(inode->i_mode))) {
-
-                printk("smb_dont_catch_keepalive: "
-                       "did not get valid server!\n");
-                return -EINVAL;
-        }
-
-        sock = &(inode->u.socket_i);
-
-        if (sock->type != SOCK_STREAM) {
-                printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
-                return -EINVAL;
-        }
-
-        sk   = (struct sock *)(sock->data);
-
-        if (sk == NULL) {
-                printk("smb_dont_catch_keepalive: sk == NULL");
-                return -EINVAL;
-        }
-
-        if (server->data_ready == NULL) {
-                printk("smb_dont_catch_keepalive: "
-                       "server->data_ready == NULL\n");
-                return -EINVAL;
-        }
-
-        if (sk->data_ready != smb_data_callback) {
-                printk("smb_dont_catch_keepalive: "
-                       "sk->data_callback != smb_data_callback\n");
-                return -EINVAL;
-        }
-
-        DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n",
-                 (unsigned int)(sk->data_ready),
-                 (unsigned int)(server->data_ready));
-
-        sk->data_ready = server->data_ready;
-        server->data_ready = NULL;
-        return 0;
+	int result;
+	int already_sent = 0;
+
+	while (already_sent < length)
+	{
+		result = _send(sock,
+			       (void *) (source + already_sent),
+			       length - already_sent, 0, 0);
+
+		if (result < 0)
+		{
+			DPRINTK("smb_send_raw: sendto error = %d\n",
+				-result);
+			return result;
+		}
+		already_sent += result;
+	}
+	return already_sent;
 }
 
-/*
- * smb_receive_raw
- * fs points to the correct segment, sock != NULL, target != NULL
- * The smb header is only stored if want_header != 0.
- */
 static int
-smb_receive_raw(struct socket *sock, unsigned char *target,
-                int max_raw_length, int want_header)
+smb_receive_raw(struct socket *sock, unsigned char *target, int length)
 {
-        int len, result;
-        int already_read;
-        unsigned char peek_buf[4];
-        unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
+	int result;
+	int already_read = 0;
 
+	while (already_read < length)
+	{
+		result = _recvfrom(sock,
+				   (void *) (target + already_read),
+				   length - already_read, 0, 0,
+				   NULL, NULL);
+
+		if (result < 0)
+		{
+			DPRINTK("smb_receive_raw: recvfrom error = %d\n",
+				-result);
+			return result;
+		}
+		already_read += result;
+	}
+	return already_read;
+}
 
- re_recv:
+static int
+smb_get_length(struct socket *sock, unsigned char *header)
+{
+	int result;
+	unsigned char peek_buf[4];
+	unsigned short fs;
 
+      re_recv:
 	fs = get_fs();
 	set_fs(get_ds());
-        result = _recvfrom(sock, (void *)peek_buf, 4, 0,
-                                     0, NULL, NULL);
-        set_fs(fs);
-
-        if (result < 0) {
-                DPRINTK("smb_receive_raw: recv error = %d\n", -result);
-                return result;
-        }
-
-        if (result < 4) {
-                DPRINTK("smb_receive_raw: got less than 4 bytes\n");
-                return -EIO;
-        }
-
-        switch (peek_buf[0]) {
-
-        case 0x00:
-        case 0x82:
-                break;
-
-        case 0x85:
-                DPRINTK("smb_receive_raw: Got SESSION KEEP ALIVE\n");
-                goto re_recv;
-                
-        default:
-                printk("smb_receive_raw: Invalid packet\n");
-                return -EIO;
-        }
-
-        /* The length in the RFC NB header is the raw data length */
-	len = smb_len(peek_buf); 
-        if (len > max_raw_length) { 
-                printk("smb_receive_raw: Received length (%d) > max_xmit (%d)!\n", 
-		       len, max_raw_length);
-                return -EIO;
-	}
-
-        if (want_header != 0) {
-                copy_to_user(target, peek_buf, 4);
-                target += 4;
-        }
-
-        already_read = 0;
-
-        while (already_read < len) {
-                
-                result = _recvfrom(sock,
-                                 (void *)(target+already_read),
-                                 len - already_read, 0, 0,
-                                 NULL, NULL);
-   
-                if (result < 0) {
-                        printk("smb_receive_raw: recvfrom error = %d\n",
-                               -result);
-                        return result;
-                }
-
-                already_read += result;
-        }
-        return already_read;
+	result = smb_receive_raw(sock, peek_buf, 4);
+	set_fs(fs);
+
+	if (result < 0)
+	{
+		DPRINTK("smb_get_length: recv error = %d\n", -result);
+		return result;
+	}
+	switch (peek_buf[0])
+	{
+	case 0x00:
+	case 0x82:
+		break;
+
+	case 0x85:
+		DPRINTK("smb_get_length: Got SESSION KEEP ALIVE\n");
+		goto re_recv;
+
+	default:
+		printk("smb_get_length: Invalid NBT packet\n");
+		return -EIO;
+	}
+
+	if (header != NULL)
+	{
+		memcpy(header, peek_buf, 4);
+	}
+	/* The length in the RFC NB header is the raw data length */
+	return smb_len(peek_buf);
+}
+
+static struct socket *
+server_sock(struct smb_server *server)
+{
+	struct file *file;
+	struct inode *inode;
+
+	if (server == NULL)
+		return NULL;
+	if ((file = server->sock_file) == NULL)
+		return NULL;
+	if ((inode = file->f_inode) == NULL)
+		return NULL;
+	return &(inode->u.socket_i);
 }
 
 /*
  * smb_receive
- * fs points to the correct segment, server != NULL, sock!=NULL
+ * fs points to the correct segment
  */
 static int
-smb_receive(struct smb_server *server, struct socket *sock)
+smb_receive(struct smb_server *server)
 {
-        int result;
-
-        result = smb_receive_raw(sock, server->packet,
-                                 server->max_xmit - 4, /* max_xmit in server
-                                                          includes NB header */
-                                 1); /* We want the header */
+	struct socket *sock = server_sock(server);
+	int len;
+	int result;
+	unsigned char peek_buf[4];
 
-        if (result < 0) {
-                printk("smb_receive: receive error: %d\n", result);
-                return result;
-        }
+	len = smb_get_length(sock, peek_buf);
 
-        server->rcls = *((unsigned char *)(server->packet+9));
-        server->err  = *((unsigned short *)(server->packet+11));
+	if (len < 0)
+	{
+		return len;
+	}
+	if (len + 4 > server->packet_size)
+	{
+		/* Some servers do not care about our max_xmit. They
+		   send larger packets */
+		DPRINTK("smb_receive: Increase packet size from %d to %d\n",
+			server->packet_size, len + 4);
+		smb_vfree(server->packet);
+		server->packet_size = 0;
+		server->packet = smb_vmalloc(len + 4);
+		if (server->packet == NULL)
+		{
+			return -ENOMEM;
+		}
+		server->packet_size = len + 4;
+	}
+	memcpy(server->packet, peek_buf, 4);
+	result = smb_receive_raw(sock, server->packet + 4, len);
 
-        if (server->rcls != 0) {
-                DPRINTK("smb_receive: rcls=%d, err=%d\n",
-                        server->rcls, server->err);
-        }
+	if (result < 0)
+	{
+		printk("smb_receive: receive error: %d\n", result);
+		return result;
+	}
+	server->rcls = BVAL(server->packet, 9);
+	server->err = WVAL(server->packet, 11);
 
-        return result;
+	if (server->rcls != 0)
+	{
+		DPRINTK("smb_receive: rcls=%d, err=%d\n",
+			server->rcls, server->err);
+	}
+	return result;
 }
 
-
-/*
- * smb_receive's preconditions also apply here.
- */
 static int
-smb_receive_trans2(struct smb_server *server, struct socket *sock,
-                   int *data_len, int *param_len,
-                   char **data, char **param)
-{
-        int total_data=0;
-        int total_param=0;
-        int result;
-        unsigned char *inbuf = server->packet;
-
-        *data_len = *param_len = 0;
-
-        DDPRINTK("smb_receive_trans2: enter\n");
-        
-        if ((result = smb_receive(server, sock)) < 0) {
-                return result;
-        }
-
-        if (server->rcls != 0) {
-                return result;
-        }
-
-        /* parse out the lengths */
-        total_data = WVAL(inbuf,smb_tdrcnt);
-        total_param = WVAL(inbuf,smb_tprcnt);
-
-        if (   (total_data  > TRANS2_MAX_TRANSFER)
-            || (total_param > TRANS2_MAX_TRANSFER)) {
-                printk("smb_receive_trans2: data/param too long\n");
-                return -EIO;
-        }
-
-        /* allocate it */
-        if ((*data  = smb_kmalloc(total_data, GFP_KERNEL)) == NULL) {
-                printk("smb_receive_trans2: could not alloc data area\n");
-                return -ENOMEM;
-        }
-
-        if ((*param = smb_kmalloc(total_param, GFP_KERNEL)) == NULL) {
-                printk("smb_receive_trans2: could not alloc param area\n");
-                smb_kfree_s(*data, total_data);
-                return -ENOMEM;
-        }
-
-        DDPRINTK("smb_rec_trans2: total_data/param: %d/%d\n",
-                 total_data, total_param);
-
-        while (1)
-        {
-                if (WVAL(inbuf,smb_prdisp)+WVAL(inbuf, smb_prcnt)
-                    > total_param) {
-                        printk("smb_receive_trans2: invalid parameters\n");
-                        result = -EIO;
-                        goto fail;
-                }
-                memcpy(*param + WVAL(inbuf,smb_prdisp),
-                       smb_base(inbuf) + WVAL(inbuf,smb_proff),
-                       WVAL(inbuf,smb_prcnt));
-                *param_len += WVAL(inbuf,smb_prcnt);
-
-
-                if (WVAL(inbuf,smb_drdisp)+WVAL(inbuf, smb_drcnt)>total_data) {
-                        printk("smb_receive_trans2: invalid data block\n");
-                        result = -EIO;
-                        goto fail;
-                }
-                memcpy(*data + WVAL(inbuf,smb_drdisp),
-                       smb_base(inbuf) + WVAL(inbuf,smb_droff),
-                       WVAL(inbuf,smb_drcnt));
-                *data_len += WVAL(inbuf,smb_drcnt);
-
-                DDPRINTK("smb_rec_trans2: drcnt/prcnt: %d/%d\n",
-                         WVAL(inbuf, smb_drcnt), WVAL(inbuf, smb_prcnt));
-
-                /* parse out the total lengths again - they can shrink! */
-
-                if (   (WVAL(inbuf,smb_tdrcnt) > total_data)
-                    || (WVAL(inbuf,smb_tprcnt) > total_param)) {
-                        printk("smb_receive_trans2: data/params grew!\n");
-                        result = -EIO;
-                        goto fail;
-                }
-
-                total_data = WVAL(inbuf,smb_tdrcnt);
-                total_param = WVAL(inbuf,smb_tprcnt);
-
-                if (total_data <= *data_len && total_param <= *param_len)
-                        break;
-
-                if ((result = smb_receive(server, sock)) < 0) {
-                        goto fail;
-                }
-                if (server->rcls != 0) {
-                        result = -EIO;
-                        goto fail;
-                }
-        }
-
-        DDPRINTK("smb_receive_trans2: normal exit\n");
-
-        return 0;
-
- fail:
-        DPRINTK("smb_receive_trans2: failed exit\n");
-
-        smb_kfree_s(*param, 0); *param = NULL;
-        smb_kfree_s(*data, 0);  *data = NULL;
-        return result;
-}
+smb_receive_trans2(struct smb_server *server,
+		   int *ldata, unsigned char **data,
+		   int *lparam, unsigned char **param)
+{
+	int total_data = 0;
+	int total_param = 0;
+	int result;
+	unsigned char *inbuf = server->packet;
+	unsigned char *rcv_buf;
+	int buf_len;
+	int data_len = 0;
+	int param_len = 0;
 
-static inline struct socket *
-server_sock(struct smb_server *server)
-{
-        struct file *file;
-        struct inode *inode;
+	if ((result = smb_receive(server)) < 0)
+	{
+		return result;
+	}
+	if (server->rcls != 0)
+	{
+		*param = *data = server->packet;
+		*ldata = *lparam = 0;
+		return 0;
+	}
+	total_data = WVAL(inbuf, smb_tdrcnt);
+	total_param = WVAL(inbuf, smb_tprcnt);
+
+	DDPRINTK("smb_receive_trans2: td=%d,tp=%d\n", total_data, total_param);
+
+	if ((total_data > TRANS2_MAX_TRANSFER)
+	    || (total_param > TRANS2_MAX_TRANSFER))
+	{
+		DPRINTK("smb_receive_trans2: data/param too long\n");
+		return -EIO;
+	}
+	buf_len = total_data + total_param;
+	if (server->packet_size > buf_len)
+	{
+		buf_len = server->packet_size;
+	}
+	if ((rcv_buf = smb_vmalloc(buf_len)) == NULL)
+	{
+		DPRINTK("smb_receive_trans2: could not alloc data area\n");
+		return -ENOMEM;
+	}
+	*param = rcv_buf;
+	*data = rcv_buf + total_param;
+
+	while (1)
+	{
+		if (WVAL(inbuf, smb_prdisp) + WVAL(inbuf, smb_prcnt)
+		    > total_param)
+		{
+			DPRINTK("smb_receive_trans2: invalid parameters\n");
+			result = -EIO;
+			goto fail;
+		}
+		memcpy(*param + WVAL(inbuf, smb_prdisp),
+		       smb_base(inbuf) + WVAL(inbuf, smb_proff),
+		       WVAL(inbuf, smb_prcnt));
+		param_len += WVAL(inbuf, smb_prcnt);
+
+		if (WVAL(inbuf, smb_drdisp) + WVAL(inbuf, smb_drcnt)
+		    > total_data)
+		{
+			DPRINTK("smb_receive_trans2: invalid data block\n");
+			result = -EIO;
+			goto fail;
+		}
+		DDPRINTK("target: %X\n", *data + WVAL(inbuf, smb_drdisp));
+		DDPRINTK("source: %X\n",
+			 smb_base(inbuf) + WVAL(inbuf, smb_droff));
+		DDPRINTK("disp: %d, off: %d, cnt: %d\n",
+			 WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
+			 WVAL(inbuf, smb_drcnt));
+
+		memcpy(*data + WVAL(inbuf, smb_drdisp),
+		       smb_base(inbuf) + WVAL(inbuf, smb_droff),
+		       WVAL(inbuf, smb_drcnt));
+		data_len += WVAL(inbuf, smb_drcnt);
+
+		if ((WVAL(inbuf, smb_tdrcnt) > total_data)
+		    || (WVAL(inbuf, smb_tprcnt) > total_param))
+		{
+			printk("smb_receive_trans2: data/params grew!\n");
+			result = -EIO;
+			goto fail;
+		}
+		/* the total lengths might shrink! */
+		total_data = WVAL(inbuf, smb_tdrcnt);
+		total_param = WVAL(inbuf, smb_tprcnt);
+
+		if ((data_len >= total_data) && (param_len >= total_param))
+		{
+			break;
+		}
+		if ((result = smb_receive(server)) < 0)
+		{
+			goto fail;
+		}
+		if (server->rcls != 0)
+		{
+			result = -EIO;
+			goto fail;
+		}
+	}
+	*ldata = data_len;
+	*lparam = param_len;
 
-        if (server == NULL)
-                return NULL;
-        if ((file = server->sock_file) == NULL)
-                return NULL;
-        if ((inode = file->f_inode) == NULL)
-                return NULL;
-        return &(inode->u.socket_i);
+	smb_vfree(server->packet);
+	server->packet = rcv_buf;
+	server->packet_size = buf_len;
+	return 0;
+
+      fail:
+	smb_vfree(rcv_buf);
+	return result;
 }
 
 int
 smb_release(struct smb_server *server)
 {
-        struct socket *sock = server_sock(server);
-        int result;
+	struct socket *sock = server_sock(server);
+	int result;
 
-        if (sock == NULL)
-                return -EINVAL;
+	if (sock == NULL)
+	{
+		return -EINVAL;
+	}
+	result = sock->ops->release(sock, NULL);
+	DPRINTK("smb_release: sock->ops->release = %d\n", result);
 
-        result = sock->ops->release(sock, NULL);
-        DPRINTK("smb_release: sock->ops->release = %d\n", result);
+	/* inet_release does not set sock->state.  Maybe someone is
+	   confused about sock->state being SS_CONNECTED while there
+	   is nothing behind it, so I set it to SS_UNCONNECTED. */
+	sock->state = SS_UNCONNECTED;
 
-        /* inet_release does not set sock->state.  Maybe someone is
-           confused about sock->state being SS_CONNECTED while there
-           is nothing behind it, so I set it to SS_UNCONNECTED.*/
-        sock->state = SS_UNCONNECTED;
-
-        result = sock->ops->create(sock, 0);
-        DPRINTK("smb_release: sock->ops->create = %d\n", result);
-        return result;
+	result = sock->ops->create(sock, 0);
+	DPRINTK("smb_release: sock->ops->create = %d\n", result);
+	return result;
 }
 
 int
 smb_connect(struct smb_server *server)
 {
-        struct socket *sock = server_sock(server);
-        if (sock == NULL)
-                return -EINVAL;
-        if (sock->state != SS_UNCONNECTED) {
-                DPRINTK("smb_connect: socket is not unconnected: %d\n",
-                        sock->state);
-        }
-        return sock->ops->connect(sock, (struct sockaddr *)&(server->m.addr),
-                                  sizeof(struct sockaddr_in), 0);
-}
-        
-/*****************************************************************************/
-/*                                                                           */
-/*  This routine was once taken from nfs, which is for udp. Here TCP does     */
-/*  most of the ugly stuff for us (thanks, Alan!)                            */
-/*                                                                           */
-/*****************************************************************************/
-int
-smb_request(struct smb_server *server)
-{
-	unsigned long old_mask;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-	int len, result, result2;
-
 	struct socket *sock = server_sock(server);
-	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
-
-	if ((sock == NULL) || (buffer == NULL)) {
-		printk("smb_request: Bad server!\n");
-		return -EBADF;
+	if (sock == NULL)
+	{
+		return -EINVAL;
 	}
-
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
-
-        len = smb_len(buffer) + 4;
-
-        DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
-	old_mask = current->blocked;
-	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
-	fs = get_fs();
-	set_fs(get_ds());
-
-        result = _send(sock, (void *)buffer, len, 0, 0);
-        if (result < 0) {
-                printk("smb_request: send error = %d\n", result);
-        }
-        else {
-                result = smb_receive(server, sock);
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
-
-	current->blocked = old_mask;
-	set_fs(fs);
-
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-        
-        DDPRINTK("smb_request: result = %d\n", result);
-
-	return result;
+	if (sock->state != SS_UNCONNECTED)
+	{
+		DPRINTK("smb_connect: socket is not unconnected: %d\n",
+			sock->state);
+	}
+	return sock->ops->connect(sock, (struct sockaddr *) &(server->m.addr),
+				  sizeof(struct sockaddr_in), 0);
 }
 
-/*
- * This is not really a trans2 request, we assume that you only have
- * one packet to send.
- */ 
 int
-smb_trans2_request(struct smb_server *server,
-                   int *data_len, int *param_len,
-                   char **data, char **param)
+smb_request(struct smb_server *server)
 {
 	unsigned long old_mask;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-	int len, result, result2;
+	unsigned short fs;
+	int len, result;
 
-	struct socket *sock = server_sock(server);
 	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
 
-	if ((sock == NULL) || (buffer == NULL)) {
-		printk("smb_trans2_request: Bad server!\n");
+	if (buffer == NULL)
+	{
+		printk("smb_request: Bad server!\n");
 		return -EBADF;
 	}
+	if (server->state != CONN_VALID)
+	{
+		return -EIO;
+	}
+	if ((result = smb_dont_catch_keepalive(server)) != 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+		return result;
+	}
+	len = smb_len(buffer) + 4;
 
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
-
-        len = smb_len(buffer) + 4;
+	DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
 
 	old_mask = current->blocked;
 	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 	fs = get_fs();
 	set_fs(get_ds());
 
-        DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
-
-        result = _send(sock, (void *)buffer, len, 0, 0);
-        if (result < 0) {
-                printk("smb_trans2_request: send error = %d\n", result);
-        }
-        else {
-                result = smb_receive_trans2(server, sock,
-                                            data_len, param_len,
-                                            data, param);
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
-
+	result = smb_send_raw(server_sock(server), (void *) buffer, len);
+	if (result > 0)
+	{
+		result = smb_receive(server);
+	}
+	/* read/write errors are handled by errno */
+	current->signal &= ~_S(SIGPIPE);
 	current->blocked = old_mask;
 	set_fs(fs);
 
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-        
-        DDPRINTK("smb_trans2_request: result = %d\n", result);
+	if (result >= 0)
+	{
+		int result2 = smb_catch_keepalive(server);
+		if (result2 < 0)
+		{
+			result = result2;
+		}
+	}
+	if (result < 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+	}
+	DDPRINTK("smb_request: result = %d\n", result);
 
 	return result;
 }
 
-/* target must be in user space */
-int
-smb_request_read_raw(struct smb_server *server,
-                     unsigned char *target, int max_len)
+#define ROUND_UP(x) (((x)+3) & ~3)
+static int
+smb_send_trans2(struct smb_server *server, __u16 trans2_command,
+		int ldata, unsigned char *data,
+		int lparam, unsigned char *param)
 {
-	unsigned long old_mask;
-	int len, result, result2;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-
 	struct socket *sock = server_sock(server);
-	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
 
-	if ((sock == NULL) || (buffer == NULL)) {
-		printk("smb_request_read_raw: Bad server!\n");
-		return -EBADF;
-	}
+	/* I know the following is very ugly, but I want to build the
+	   smb packet as efficiently as possible. */
 
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
+	const int smb_parameters = 15;
+	const int oparam =
+	ROUND_UP(SMB_HEADER_LEN + 2 * smb_parameters + 2 + 3);
+	const int odata =
+	ROUND_UP(oparam + lparam);
+	const int bcc =
+	odata + ldata - (SMB_HEADER_LEN + 2 * smb_parameters + 2);
+	const int packet_length =
+	SMB_HEADER_LEN + 2 * smb_parameters + bcc + 2;
+
+	unsigned char padding[4] =
+	{0,};
+	char *p;
 
-        len = smb_len(buffer) + 4;
+	struct iovec iov[4];
+	struct msghdr msg;
 
-	old_mask = current->blocked;
-	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
-	fs = get_fs();
-	set_fs(get_ds());
-
-        DPRINTK("smb_request_read_raw: len = %d cmd = 0x%X\n",
-                len, buffer[8]);
-        DPRINTK("smb_request_read_raw: target=%X, max_len=%d\n",
-                (unsigned int)target, max_len);
-        DPRINTK("smb_request_read_raw: buffer=%X, sock=%X\n",
-                (unsigned int)buffer, (unsigned int)sock);
-
-        result = _send(sock, (void *)buffer, len, 0, 0);
-
-        DPRINTK("smb_request_read_raw: send returned %d\n", result);
-
-	set_fs(fs);             /* We recv into user space */
-
-        if (result < 0) {
-                printk("smb_request_read_raw: send error = %d\n", result);
-        }
-        else {
-                result = smb_receive_raw(sock, target, max_len, 0);
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
-	current->blocked = old_mask;
+	if ((bcc + oparam) > server->max_xmit)
+	{
+		return -ENOMEM;
+	}
+	p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
 
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-        
-        DPRINTK("smb_request_read_raw: result = %d\n", result);
+	WSET(server->packet, smb_tpscnt, lparam);
+	WSET(server->packet, smb_tdscnt, ldata);
+	WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
+	WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
+	WSET(server->packet, smb_msrcnt, 0);
+	WSET(server->packet, smb_flags, 0);
+	DSET(server->packet, smb_timeout, 0);
+	WSET(server->packet, smb_pscnt, lparam);
+	WSET(server->packet, smb_psoff, oparam - 4);
+	WSET(server->packet, smb_dscnt, ldata);
+	WSET(server->packet, smb_dsoff, odata - 4);
+	WSET(server->packet, smb_suwcnt, 1);
+	WSET(server->packet, smb_setup0, trans2_command);
+	*p++ = 0;		/* null smb_name for trans2 */
+	*p++ = 'D';		/* this was added because OS/2 does it */
+	*p++ = ' ';
+
+	iov[0].iov_base = (void *) server->packet;
+	iov[0].iov_len = oparam;
+	iov[1].iov_base = (param == NULL) ? padding : param;
+	iov[1].iov_len = lparam;
+	iov[2].iov_base = padding;
+	iov[2].iov_len = odata - oparam - lparam;
+	iov[3].iov_base = (data == NULL) ? padding : data;
+	iov[3].iov_len = ldata;
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_control = NULL;
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 4;
 
-	return result;
+	return sock->ops->sendmsg(sock, &msg, packet_length, 0, 0);
 }
 
-/* Source must be in user space. smb_request_write_raw assumes that
- * the request SMBwriteBraw has been completed successfully, so that
- * we can send the raw data now.  */
+/*
+ * This is not really a trans2 request, we assume that you only have
+ * one packet to send.
+ */
 int
-smb_request_write_raw(struct smb_server *server,
-                      unsigned const char *source, int length)
+smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+		   int ldata, unsigned char *data,
+		   int lparam, unsigned char *param,
+		   int *lrdata, unsigned char **rdata,
+		   int *lrparam, unsigned char **rparam)
 {
 	unsigned long old_mask;
-	int result, result2;
-	unsigned short fs;      /* We fool the kernel to believe
-                                   we call from user space. */
-        byte nb_header[4];
+	unsigned short fs;
+	int result;
 
-	struct socket *sock = server_sock(server);
-	unsigned char *buffer = (server == NULL) ? NULL : server->packet;
+	DDPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
+		 trans2_command, ldata, lparam);
 
-	if ((sock == NULL) || (buffer == NULL)) {
-                printk("smb_request_write_raw: Bad server!\n");
-		return -EBADF;
+	if (server->state != CONN_VALID)
+	{
+		return -EIO;
+	}
+	if ((result = smb_dont_catch_keepalive(server)) != 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+		return result;
 	}
-
-        if (server->state != CONN_VALID)
-                return -EIO;
-        	
-        if ((result = smb_dont_catch_keepalive(server)) != 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-                return result;
-        }
-
 	old_mask = current->blocked;
 	current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
 	fs = get_fs();
 	set_fs(get_ds());
 
-        smb_encode_smb_length(nb_header, length);
-
-        result = _send(sock, (void *)nb_header, 4, 0, 0);
-
-        if (result == 4) {
-                set_fs(fs);     /* source is in user-land */
-                result = _send(sock, (void *)source, length, 0, 0);
-                set_fs(get_ds());
-        } else {
-                result = -EIO;
-        }
-
-        DPRINTK("smb_request_write_raw: send returned %d\n", result);
-
-        if (result == length) {
-                result = smb_receive(server, sock);
-        } else {
-                result = -EIO;
-        }
-
-        /* read/write errors are handled by errno */
-        current->signal &= ~_S(SIGPIPE);
+	result = smb_send_trans2(server, trans2_command,
+				 ldata, data, lparam, param);
+	if (result >= 0)
+	{
+		result = smb_receive_trans2(server,
+					    lrdata, rdata, lrparam, rparam);
+	}
+	/* read/write errors are handled by errno */
+	current->signal &= ~_S(SIGPIPE);
 	current->blocked = old_mask;
 	set_fs(fs);
 
-        if ((result2 = smb_catch_keepalive(server)) < 0) {
-                result = result2;
-        }
-
-        if (result < 0) {
-                server->state = CONN_INVALID;
-                smb_invalidate_all_inodes(server);
-        }
-
-        if (result > 0) {
-                result = length;
-        }
-        
-        DPRINTK("smb_request_write_raw: result = %d\n", result);
+	if (result >= 0)
+	{
+		int result2 = smb_catch_keepalive(server);
+		if (result2 < 0)
+		{
+			result = result2;
+		}
+	}
+	if (result < 0)
+	{
+		server->state = CONN_INVALID;
+		smb_invalidate_all_inodes(server);
+	}
+	DDPRINTK("smb_trans2_request: result = %d\n", result);
 
 	return result;
 }
diff -u --recursive --new-file v2.1.13/linux/include/asm-alpha/termbits.h linux/include/asm-alpha/termbits.h
--- v2.1.13/linux/include/asm-alpha/termbits.h	Wed May  8 10:32:40 1996
+++ linux/include/asm-alpha/termbits.h	Sat Nov 23 13:59:01 1996
@@ -101,7 +101,7 @@
 #define XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
 
 /* c_cflag bit meaning */
-#define CBAUD	0000017
+#define CBAUD	0000037
 #define  B0	0000000		/* hang up */
 #define  B50	0000001
 #define  B75	0000002
@@ -120,7 +120,7 @@
 #define  B38400	0000017
 #define EXTA B19200
 #define EXTB B38400
-#define CBAUDEX 0000020
+#define CBAUDEX 0000000
 #define  B57600   00020
 #define  B115200  00021
 #define  B230400  00022
diff -u --recursive --new-file v2.1.13/linux/include/linux/icmpv6.h linux/include/linux/icmpv6.h
--- v2.1.13/linux/include/linux/icmpv6.h	Sun Nov 10 20:12:14 1996
+++ linux/include/linux/icmpv6.h	Sun Dec  1 18:57:13 1996
@@ -108,8 +108,7 @@
  *	constants for (set|get)sockopt
  */
 
-#define RAW_CHECKSUM			1
-#define ICMPV6_FILTER			256
+#define ICMPV6_FILTER			1
 
 /*
  *	ICMPV6 filter
diff -u --recursive --new-file v2.1.13/linux/include/linux/if.h linux/include/linux/if.h
--- v2.1.13/linux/include/linux/if.h	Sun Aug  4 14:38:04 1996
+++ linux/include/linux/if.h	Sat Nov 30 13:34:27 1996
@@ -106,7 +106,7 @@
 		struct	sockaddr ifru_netmask;
 		struct  sockaddr ifru_hwaddr;
 		short	ifru_flags;
-		int	ifru_metric;
+		int	ifru_ivalue;
 		int	ifru_mtu;
 		struct  ifmap ifru_map;
 		char	ifru_slave[IFNAMSIZ];	/* Just fits the size */
@@ -121,11 +121,12 @@
 #define	ifr_broadaddr	ifr_ifru.ifru_broadaddr	/* broadcast address	*/
 #define	ifr_netmask	ifr_ifru.ifru_netmask	/* interface net mask	*/
 #define	ifr_flags	ifr_ifru.ifru_flags	/* flags		*/
-#define	ifr_metric	ifr_ifru.ifru_metric	/* metric		*/
+#define	ifr_metric	ifr_ifru.ifru_ivalue	/* metric		*/
 #define	ifr_mtu		ifr_ifru.ifru_mtu	/* mtu			*/
 #define ifr_map		ifr_ifru.ifru_map	/* device map		*/
 #define ifr_slave	ifr_ifru.ifru_slave	/* slave device		*/
 #define	ifr_data	ifr_ifru.ifru_data	/* for use by interface	*/
+#define ifr_ifindex	ifr_ifru.ifru_ivalue	/* interface index	*/
 
 /*
  * Structure used in SIOCGIFCONF request.
diff -u --recursive --new-file v2.1.13/linux/include/linux/in6.h linux/include/linux/in6.h
--- v2.1.13/linux/include/linux/in6.h	Tue Nov 12 15:56:14 1996
+++ linux/include/linux/in6.h	Tue Nov 26 10:46:41 1996
@@ -5,10 +5,13 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	Source:
+ *	Sources:
  *	IPv6 Program Interfaces for BSD Systems
  *      <draft-ietf-ipngwg-bsd-api-05.txt>
  *
+ *	Advanced Sockets API for IPv6
+ *	<draft-stevens-advanced-api-00.txt>
+ *
  *	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
@@ -88,12 +91,20 @@
 
 #define IPV6_ADDRFORM		1
 #define IPV6_RXINFO		2
+#define IPV6_RXHOPOPTS		3
+#define IPV6_RXDSTOPTS		4
+#define IPV6_RXSRCRT		5
+#define IPV6_PKTOPTIONS		6
+#define IPV6_CHECKSUM		7
+
+/*
+ *	Alternative names
+ */
 #define IPV6_TXINFO		IPV6_RXINFO
 #define SCM_SRCINFO		IPV6_TXINFO
-#define SCM_SRCRT		4
-#define IPV6_UNICAST_HOPS	5
-
+#define SCM_SRCRT		IPV6_RXSRCRT
 
+#define IPV6_UNICAST_HOPS	16
 #define IPV6_MULTICAST_IF	17
 #define IPV6_MULTICAST_HOPS	18
 #define IPV6_MULTICAST_LOOP	19
diff -u --recursive --new-file v2.1.13/linux/include/linux/ipv6_route.h linux/include/linux/ipv6_route.h
--- v2.1.13/linux/include/linux/ipv6_route.h	Tue Nov 12 15:56:14 1996
+++ linux/include/linux/ipv6_route.h	Tue Nov 26 10:46:41 1996
@@ -35,7 +35,7 @@
 	__u16			rtmsg_metric;
 	unsigned long		rtmsg_info;
         __u32			rtmsg_flags;
-	char			rtmsg_device[16];
+	int			rtmsg_ifindex;
 };
 
 #endif
diff -u --recursive --new-file v2.1.13/linux/include/linux/quota.h linux/include/linux/quota.h
--- v2.1.13/linux/include/linux/quota.h	Thu Jul  4 13:36:52 1996
+++ linux/include/linux/quota.h	Sun Dec  1 10:53:15 1996
@@ -209,7 +209,7 @@
 
 #else
 
-#include <sys/cdefs.h>
+# /* nodep */ include <sys/cdefs.h>
 
 __BEGIN_DECLS
 int quotactl __P ((int, const char *, int, caddr_t));
diff -u --recursive --new-file v2.1.13/linux/include/linux/route.h linux/include/linux/route.h
--- v2.1.13/linux/include/linux/route.h	Sun Nov 10 20:12:14 1996
+++ linux/include/linux/route.h	Sat Nov 30 13:37:40 1996
@@ -80,5 +80,6 @@
 #define RTMSG_NEWDEVICE		0x11
 #define RTMSG_DELDEVICE		0x12
 
+#define RTMSG_AR_FAILED		0x21	/* Address Resolution failed	*/
 #endif	/* _LINUX_ROUTE_H */
 
diff -u --recursive --new-file v2.1.13/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.13/linux/include/linux/skbuff.h	Sat Nov 30 12:03:11 1996
+++ linux/include/linux/skbuff.h	Sun Dec  1 18:55:11 1996
@@ -125,6 +125,8 @@
 	void 		(*destructor)(struct sk_buff *);	/* Destruct function		*/
 	__u16		redirport;		/* Redirect port				*/
 	__u16		inclone;		/* Inline clone	*/
+#define SKB_CLONE_ORIG		1
+#define SKB_CLONE_INLINE	2
 };
 
 #ifdef CONFIG_SKB_LARGE
diff -u --recursive --new-file v2.1.13/linux/include/linux/smb.h linux/include/linux/smb.h
--- v2.1.13/linux/include/linux/smb.h	Wed Jun  5 13:22:48 1996
+++ linux/include/linux/smb.h	Sun Dec  1 18:21:33 1996
@@ -28,26 +28,53 @@
 typedef unsigned long dword;
 #endif
 
-/*
- * Set/Get values in SMB-byte order
- */
-#define ARCH i386
-#if (ARCH == i386)
-#define BVAL(p,off)      (*((byte  *)(((void *)p)+off)))
-#define WVAL(p,off)      (*((word  *)(((void *)p)+off)))
-#define DVAL(p,off)      (*((dword *)(((void *)p)+off)))
-#define BSET(p,off,new)  (*((byte  *)(((void *)p)+off))=(new))
-#define WSET(p,off,new)  (*((word  *)(((void *)p)+off))=(new))
-#define DSET(p,off,new)  (*((dword *)(((void *)p)+off))=(new))
+/* The following macros have been taken directly from Samba. Thanks,
+   Andrew! */
 
-/* where to find the base of the SMB packet proper */
-#define smb_base(buf) ((byte *)(((byte *)(buf))+4))
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right" 
+   byteorder */
+#if defined(__i386__)
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
 
+#define BVAL(buf,pos) (((u8 *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
+#define BSET(buf,pos,val) (BVAL(buf,pos) = (val))
+
+
+#if CAREFUL_ALIGNMENT
+#define WVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define DVAL(buf,pos) (WVAL(buf,pos)|WVAL(buf,(pos)+2)<<16)
+
+#define SSVALX(buf,pos,val) (BVAL(buf,pos)=(val)&0xFF,BVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define WSET(buf,pos,val) { word __val = (val); \
+	SSVALX((buf),(pos),((word)(__val))); }
+#define DSET(buf,pos,val) { dword __val = (val); \
+	SIVALX((buf),(pos),((dword)(__val))); }
 #else
-#error "Currently only on 386, sorry"
+/* this handles things for architectures like the 386 that can handle
+   alignment errors */
+/*
+   WARNING: This section is dependent on the length of word and dword
+   being correct 
+*/
+#define WVAL(buf,pos) (*(word *)((char *)(buf) + (pos)))
+#define DVAL(buf,pos) (*(dword *)((char *)(buf) + (pos)))
+#define WSET(buf,pos,val) WVAL(buf,pos)=((word)(val))
+#define DSET(buf,pos,val) DVAL(buf,pos)=((dword)(val))
 #endif
 
 
+/* where to find the base of the SMB packet proper */
+#define smb_base(buf) ((byte *)(((byte *)(buf))+4))
+
 #define LANMAN1
 #define LANMAN2
 #define NT1
@@ -87,19 +114,28 @@
  * Contains all relevant data on a SMB networked file.
  */
 struct smb_dirent {
+
+	unsigned long	f_ino;
+	umode_t		f_mode;
+	nlink_t		f_nlink;
+	uid_t		f_uid;
+	gid_t		f_gid;
+	kdev_t		f_rdev;
+	off_t		f_size;
+	time_t		f_atime;
+	time_t		f_mtime;
+	time_t		f_ctime;
+	unsigned long	f_blksize;
+	unsigned long	f_blocks;
+	
         int             opened; /* is it open on the fileserver? */
 	word            fileid;	/* What id to handle a file with? */
 	word            attr;	/* Attribute fields, DOS value */
 
-        time_t atime, mtime,    /* Times, as seen by the server, normalized */
-               ctime;           /* to UTC. The ugly conversion happens in */
-                                /* proc.c */
-
-	unsigned long   size;	/* File size. */
 	unsigned short  access;	/* Access bits. */
         unsigned long   f_pos;	/* File position. (For readdir.) */
-	char*           path;   /* Complete path, MS-DOS notation, with '\' */
-	int             len;	/* Namelength. */
+	unsigned char   name[SMB_MAXNAMELEN+1];
+	int             len;	/* namelength */
 };
 
 #endif  /* __KERNEL__ */
diff -u --recursive --new-file v2.1.13/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.1.13/linux/include/linux/smb_fs.h	Mon Sep 30 11:24:25 1996
+++ linux/include/linux/smb_fs.h	Sun Dec  1 19:02:59 1996
@@ -12,6 +12,7 @@
 #include <linux/fs.h>
 #include <linux/in.h>
 #include <linux/types.h>
+#include <linux/vmalloc.h>
 
 #include <linux/smb_mount.h>
 #include <linux/smb_fs_sb.h>
@@ -55,27 +56,45 @@
 #include <linux/malloc.h>
 
 extern int smb_malloced;
-extern int smb_current_malloced;
+extern int smb_current_kmalloced;
+extern int smb_current_vmalloced;
 
 static inline void *
 smb_kmalloc(unsigned int size, int priority)
 {
         smb_malloced += 1;
-        smb_current_malloced += 1;
+        smb_current_kmalloced += 1;
         return kmalloc(size, priority);
 }
 
 static inline void
 smb_kfree_s(void *obj, int size)
 {
-        smb_current_malloced -= 1;
+        smb_current_kmalloced -= 1;
         kfree_s(obj, size);
 }
 
+static inline void *
+smb_vmalloc(unsigned int size)
+{
+        smb_malloced += 1;
+        smb_current_vmalloced += 1;
+        return vmalloc(size);
+}
+
+static inline void
+smb_vfree(void *obj)
+{
+        smb_current_vmalloced -= 1;
+        vfree(obj);
+}
+
 #else /* DEBUG_SMB_MALLOC */
 
 #define smb_kmalloc(s,p) kmalloc(s,p)
 #define smb_kfree_s(o,s) kfree_s(o,s)
+#define smb_vmalloc(s)   vmalloc(s)
+#define smb_vfree(o)     vfree(o)
 
 #endif /* DEBUG_SMB_MALLOC */
 
@@ -92,12 +111,27 @@
 #endif
 
 
+static inline ino_t
+smb_info_ino(struct smb_inode_info *info)
+{
+#if 0
+	return (ino_t) info;
+#else
+	if (info != NULL)
+	{
+		return info->finfo.f_ino;
+	}
+	return 1;
+#endif
+}
+
 /* linux/fs/smbfs/file.c */
 extern struct inode_operations smb_file_inode_operations;
 int smb_make_open(struct inode *i, int right);
 
 /* linux/fs/smbfs/dir.c */
 extern struct inode_operations smb_dir_inode_operations;
+struct smb_inode_info *smb_find_inode(struct smb_server *server, ino_t ino);
 void smb_free_inode_info(struct smb_inode_info *i);
 void smb_free_all_inodes(struct smb_server *server);
 void smb_init_root(struct smb_server *server);
@@ -122,8 +156,12 @@
 /* linux/fs/smbfs/proc.c */
 dword smb_len(unsigned char *packet);
 byte *smb_encode_smb_length(byte *p, dword len);
-int smb_proc_open(struct smb_server *server, const char *pathname,
-                  int len, struct smb_dirent *entry);
+__u8 *smb_setup_header(struct smb_server *server, byte command,
+		       word wct, word bcc);
+void smb_init_root_dirent(struct smb_server *server, struct smb_dirent *entry);
+int smb_proc_open(struct smb_server *server,
+		  struct smb_inode_info *dir, const char *name, int len,
+		  struct smb_dirent *entry);
 int smb_proc_close(struct smb_server *server, 
 		   __u16 fileid, __u32 mtime);
 int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, 
@@ -134,19 +172,18 @@
 		   off_t offset, int count, const char *data);
 int smb_proc_write_raw(struct smb_server *server, struct smb_dirent *finfo, 
                        off_t offset, long count, const char *data);
-int smb_proc_create(struct smb_server *server, const char *path,
-                    int len, struct smb_dirent *entry);
-int smb_proc_mv(struct smb_server *server, const char *opath, const int olen, 
-		const char *npath, const int nlen);
-int smb_proc_mkdir(struct smb_server *server, const char *path, const int len);
-int smb_proc_rmdir(struct smb_server *server, const char *path, const int len);
-int smb_proc_unlink(struct smb_server *server, const char *path,
-                    const int len);
+int smb_proc_create(struct inode *dir, const char *name, int len,
+		    word attr, time_t ctime);
+int smb_proc_mv(struct inode *odir, const char *oname, const int olen,
+		struct inode *ndir, const char *nname, const int nlen);
+int smb_proc_mkdir(struct inode *dir, const char *name, const int len);
+int smb_proc_rmdir(struct inode *dir, const char *name, const int len);
+int smb_proc_unlink(struct inode *dir, const char *name, const int len);
 int smb_proc_readdir(struct smb_server *server, struct inode *dir,
                      int fpos, int cache_size, 
 		     struct smb_dirent *entry);
-int smb_proc_getattr(struct smb_server *server, const char *path,
-                     int len, struct smb_dirent *entry);
+int smb_proc_getattr(struct inode *dir, const char *name, int len,
+		     struct smb_dirent *entry);
 int smb_proc_setattr(struct smb_server *server,
                      struct inode *ino,
                      struct smb_dirent *new_finfo);
@@ -168,9 +205,11 @@
                           unsigned const char *source, int length);
 int smb_catch_keepalive(struct smb_server *server);
 int smb_dont_catch_keepalive(struct smb_server *server);
-int smb_trans2_request(struct smb_server *server,
-                       int *data_len, int *param_len,
-                       char **data, char **param);
+int smb_trans2_request(struct smb_server *server, __u16 trans2_command,
+		       int ldata, unsigned char *data,
+		       int lparam, unsigned char *param,
+		       int *lrdata, unsigned char **rdata,
+		       int *lrparam, unsigned char **rparam);
 
 /* linux/fs/smbfs/mmap.c */
 int smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma);
diff -u --recursive --new-file v2.1.13/linux/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h
--- v2.1.13/linux/include/linux/smb_fs_sb.h	Mon Sep 30 11:24:25 1996
+++ linux/include/linux/smb_fs_sb.h	Sun Dec  1 18:59:35 1996
@@ -25,7 +25,7 @@
                                               protocols. */
 	struct wait_queue *wait;
 
-	word               max_xmit;
+	__u32              max_xmit;
 	char               hostname[256];
 	word               pid;
 	word               server_uid;
@@ -38,6 +38,8 @@
 
         unsigned short     rcls; /* The error codes we received */
         unsigned short     err;
+
+	__u32              packet_size;
 	unsigned char *    packet;
 
         enum smb_conn_state state;
@@ -46,7 +48,6 @@
         /* The following are LANMAN 1.0 options transferred to us in
            SMBnegprot */
         word   secmode;
-        word   maxxmt;
         word   maxmux;
         word   maxvcs;
         word   blkmode;
diff -u --recursive --new-file v2.1.13/linux/include/linux/smb_mount.h linux/include/linux/smb_mount.h
--- v2.1.13/linux/include/linux/smb_mount.h	Mon Sep 30 11:24:25 1996
+++ linux/include/linux/smb_mount.h	Sun Dec  1 18:59:35 1996
@@ -1,7 +1,7 @@
 /*
  *  smb_mount.h
  *
- *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *  Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
  *
  */
 
@@ -11,7 +11,7 @@
 #include <linux/types.h>
 #include <linux/in.h>
 
-#define SMB_MOUNT_VERSION 4
+#define SMB_MOUNT_VERSION 5
 
 struct smb_mount_data {
 	int version;
@@ -26,6 +26,7 @@
 
         char username[64];
 	char password[64];
+	char domain[64];
 
 	unsigned short max_xmit;
 
diff -u --recursive --new-file v2.1.13/linux/include/linux/sockios.h linux/include/linux/sockios.h
--- v2.1.13/linux/include/linux/sockios.h	Mon May 13 23:23:07 1996
+++ linux/include/linux/sockios.h	Tue Nov 26 10:46:41 1996
@@ -52,6 +52,7 @@
 #define SIOCSIFSLAVE	0x8930
 #define SIOCADDMULTI	0x8931		/* Multicast address lists	*/
 #define SIOCDELMULTI	0x8932
+#define SIOGIFINDEX	0x8933		/* name -> if_index mapping	*/
 
 #define SIOCGIFBR	0x8940		/* Bridging support		*/
 #define SIOCSIFBR	0x8941		/* Set bridging options 	*/
diff -u --recursive --new-file v2.1.13/linux/include/linux/ucdrom.h linux/include/linux/ucdrom.h
--- v2.1.13/linux/include/linux/ucdrom.h	Fri Nov 22 18:28:21 1996
+++ linux/include/linux/ucdrom.h	Sun Dec  1 11:01:02 1996
@@ -82,9 +82,8 @@
 #define CDO_CHECK_TYPE	0x10            /* check type on open for data */
 
 /* Special codes for specifying changer slots. */
-#include <limits.h>
-#define CDSL_NONE       INT_MAX-1
-#define CDSL_CURRENT    INT_MAX
+#define CDSL_NONE       ((int) (~0U>>1)-1)
+#define CDSL_CURRENT    ((int) (~0U>>1))
 
 /* Some more ioctls to control these options */
 #define CDROM_SET_OPTIONS	0x5320
diff -u --recursive --new-file v2.1.13/linux/include/net/addrconf.h linux/include/net/addrconf.h
--- v2.1.13/linux/include/net/addrconf.h	Sun Nov 10 20:12:15 1996
+++ linux/include/net/addrconf.h	Tue Nov 26 10:46:41 1996
@@ -51,6 +51,7 @@
 
 extern int			addrconf_add_ifaddr(void *arg);
 extern int			addrconf_set_dstaddr(void *arg);
+extern int			addrconf_get_ifindex(void *arg);
 
 extern struct inet6_ifaddr *	ipv6_chk_addr(struct in6_addr *addr);
 extern struct inet6_ifaddr *	ipv6_get_saddr(struct rt6_info *rt, 
diff -u --recursive --new-file v2.1.13/linux/include/net/ipv6_route.h linux/include/net/ipv6_route.h
--- v2.1.13/linux/include/net/ipv6_route.h	Tue Nov 12 15:56:14 1996
+++ linux/include/net/ipv6_route.h	Tue Nov 26 10:46:41 1996
@@ -156,8 +156,8 @@
 
 extern void			rt6_sndmsg(__u32 type, struct in6_addr *dst,
 					   struct in6_addr *gw, __u16 plen,
-					   __u16 metric, char *devname,
-					   __u16 flags);
+					   struct device *dev,
+					   __u16 metric, __u16 flags);
 /*
  *	ICMP interface
  */
diff -u --recursive --new-file v2.1.13/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.13/linux/include/net/sock.h	Sat Nov 30 12:03:12 1996
+++ linux/include/net/sock.h	Sun Dec  1 18:57:13 1996
@@ -50,7 +50,7 @@
 #include <linux/skbuff.h>	/* struct sk_buff */
 #include <net/protocol.h>		/* struct inet_protocol */
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
-#include <net/x25.h>
+#/* notyet */include <net/x25.h>
 #endif
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 #include <net/ax25.h>
diff -u --recursive --new-file v2.1.13/linux/init/main.c linux/init/main.c
--- v2.1.13/linux/init/main.c	Sat Nov 30 12:03:12 1996
+++ linux/init/main.c	Sun Dec  1 11:06:02 1996
@@ -9,10 +9,6 @@
  */
 
 #define __KERNEL_SYSCALLS__
-#include <stdarg.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
 
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -37,8 +33,13 @@
 #include <linux/nfs_fs.h>
 #endif
 
+#include <asm/system.h>
+#include <asm/io.h>
 #include <asm/bugs.h>
 
+#include <stdarg.h>
+
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -91,6 +92,8 @@
 extern void aic7xxx_setup(char *str, int *ints);
 extern void AM53C974_setup(char *str, int *ints);
 extern void BusLogic_Setup(char *str, int *ints);
+extern void eata2x_setup(char *str, int *ints);
+extern void u14_34f_setup(char *str, int *ints);
 extern void fdomain_setup(char *str, int *ints);
 extern void in2000_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
@@ -320,6 +323,12 @@
 #endif
 #ifdef CONFIG_SCSI_BUSLOGIC
 	{ "BusLogic=", BusLogic_Setup},
+#endif
+#ifdef CONFIG_SCSI_EATA
+	{ "eata=", eata2x_setup},
+#endif
+#ifdef CONFIG_SCSI_U14_34F
+	{ "u14-34f=", u14_34f_setup},
 #endif
 #ifdef CONFIG_SCSI_AM53C974
         { "AM53C974=", AM53C974_setup},
diff -u --recursive --new-file v2.1.13/linux/net/README linux/net/README
--- v2.1.13/linux/net/README	Mon May 13 07:17:23 1996
+++ linux/net/README	Sun Nov 24 13:28:15 1996
@@ -12,7 +12,9 @@
 ipv4			alan@lxorguk.ukuu.org.uk
 ipx			alan@lxorguk.ukuu.org.uk,greg@caldera.com
 netrom			jsn@cs.nott.ac.uk
+rose			jsn@cs.nott.ac.uk
 unix			alan@lxorguk.ukuu.org.uk
+x25			jsn@cs.nott.ac.uk
 
 
 	If in doubt contact me <alan@lxorguk.ukuu.org.uk> first.
diff -u --recursive --new-file v2.1.13/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v2.1.13/linux/net/ax25/ax25_in.c	Fri Nov 22 18:28:23 1996
+++ linux/net/ax25/ax25_in.c	Sun Nov 24 13:28:15 1996
@@ -790,12 +790,8 @@
 {
 	int queued = 0, frametype, ns, nr, pf;
 	
-	if (ax25->sk != NULL && ax25->state == AX25_STATE_0 && ax25->sk->dead)
-		return queued;
-
-	if (ax25->state != AX25_STATE_1 && ax25->state != AX25_STATE_2 &&
-	    ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4)
-		return queued;
+	if (ax25->state == AX25_STATE_0)
+		return 0;
 
 	del_timer(&ax25->timer);
 
diff -u --recursive --new-file v2.1.13/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v2.1.13/linux/net/ax25/ax25_timer.c	Fri Nov 22 18:28:23 1996
+++ linux/net/ax25/ax25_timer.c	Sun Nov 24 13:28:16 1996
@@ -85,7 +85,7 @@
 /*
  *	AX.25 TIMER 
  *
- *	This routine is called every 500ms. Decrement timer by this
+ *	This routine is called every 100ms. Decrement timer by this
  *	amount - if expired then process the event.
  */
 static void ax25_timer(unsigned long param)
diff -u --recursive --new-file v2.1.13/linux/net/ax25/sysctl_net_ax25.c linux/net/ax25/sysctl_net_ax25.c
--- v2.1.13/linux/net/ax25/sysctl_net_ax25.c	Tue Nov 19 15:53:59 1996
+++ linux/net/ax25/sysctl_net_ax25.c	Sun Nov 24 13:28:16 1996
@@ -9,8 +9,8 @@
 #include <linux/sysctl.h>
 #include <net/ax25.h>
 
-static int min_ax25[] = {0, 0, 0, 0, 0, 1,  1,  1 * PR_SLOWHZ,  1 * PR_SLOWHZ,
-	   0 * PR_SLOWHZ,     0 * PR_SLOWHZ,  1,   1,  1, 0x00};
+static int min_ax25[] = {0, 0, 0, 0, 0, 1,  1,              1,              1,
+	               0,                 0,  1,   1,  1, 0x00};
 static int max_ax25[] = {1, 1, 1, 1, 1, 7, 63, 30 * PR_SLOWHZ, 20 * PR_SLOWHZ,
 	3600 * PR_SLOWHZ, 65535 * PR_SLOWHZ, 31, 512, 20, 0x03};
 
diff -u --recursive --new-file v2.1.13/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.1.13/linux/net/core/skbuff.c	Sat Nov 30 12:03:13 1996
+++ linux/net/core/skbuff.c	Tue Nov 26 10:46:41 1996
@@ -735,12 +735,17 @@
 
 	/* don't do anything if somebody still uses us */
 	if (atomic_dec_and_test(&skb->count)) {
+
+		int free_head;
+
+		free_head = (skb->inclone != SKB_CLONE_INLINE);
+
 		/* free the skb that contains the actual data if we've clone()'d */
 		if (skb->data_skb) {
 			addr = skb;
 			__kfree_skbmem(skb->data_skb);
 		}
-		if (!skb->inclone)
+		if (free_head)
 			kfree(addr);
 		atomic_dec(&net_skbcount);
 	}
@@ -761,7 +766,8 @@
 	{
 		n = ((struct sk_buff *) skb->end) - 1;
 		skb->end -= sizeof(struct sk_buff);
-		inbuff = 1;
+		skb->inclone = SKB_CLONE_ORIG;
+		inbuff = SKB_CLONE_INLINE;
 	}
 	else
 	{
@@ -803,7 +809,7 @@
 	 
 	IS_SKB(skb);
 	
-	n=alloc_skb(skb->truesize-sizeof(struct sk_buff),priority);
+	n=alloc_skb(skb->end - skb->head, priority);
 	if(n==NULL)
 		return NULL;
 
diff -u --recursive --new-file v2.1.13/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.13/linux/net/ipv6/addrconf.c	Fri Nov 22 18:28:23 1996
+++ linux/net/ipv6/addrconf.c	Tue Nov 26 10:46:41 1996
@@ -11,7 +11,12 @@
  *      as published by the Free Software Foundation; either version
  *      2 of the License, or (at your option) any later version.
  */
-
+/*
+ *	Changes:
+ *
+ *	Janos Farkas			:	delete timer on ifdown
+ *	<chexum@bankinf.banki.hu>
+ */
 
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -472,9 +477,10 @@
 	return ifp;	
 }
 
-static void sit_route_add(struct device *dev)
+static void sit_route_add(struct inet6_dev *idev)
 {
-	struct in6_rtmsg rtmsg;	
+	struct in6_rtmsg rtmsg;
+	struct device *dev = idev->dev;
 	int err;
 
 	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
@@ -498,7 +504,7 @@
 		rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_UP;
 	}
 
-	strcpy(rtmsg.rtmsg_device, dev->name);
+	rtmsg.rtmsg_ifindex = idev->if_index; 
 
 	err = ipv6_route_add(&rtmsg);
 
@@ -514,7 +520,6 @@
 	struct inet6_dev  *idev;
 	struct inet6_ifaddr * ifp;
 	struct in6_rtmsg rtmsg;
-	char devname[] = "lo";
 	int err;
 
 	/* ::1 */
@@ -545,7 +550,7 @@
 
 	rtmsg.rtmsg_prefixlen = 128;
 	rtmsg.rtmsg_metric = 1;
-	strcpy(rtmsg.rtmsg_device, devname);
+	rtmsg.rtmsg_ifindex = idev->if_index;
 
 	rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_HOST|RTF_UP;
 
@@ -688,14 +693,19 @@
 	else if (pinfo->onlink && valid_lft)
 	{
 		struct in6_rtmsg rtmsg;
-
+		struct inet6_dev *idev;
+		
 		printk(KERN_DEBUG "adding on link route\n");
 		ipv6_addr_copy(&rtmsg.rtmsg_dst, &pinfo->prefix);
 		memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
 
 		rtmsg.rtmsg_prefixlen = pinfo->prefix_len;
 		rtmsg.rtmsg_metric = 1;
-		memcpy(rtmsg.rtmsg_device, dev->name, strlen(dev->name) + 1);
+		
+		if ((idev = ipv6_get_idev(dev)))
+		{
+			rtmsg.rtmsg_ifindex = idev->if_index;
+		}
 		rtmsg.rtmsg_flags = RTF_UP | RTF_ADDRCONF;
 		rtmsg.rtmsg_info = rt_expires;
 
@@ -818,6 +828,7 @@
 			if (ifa->idev == idev)
 			{
 				*bifa = ifa->lst_next;
+				del_timer(&ifa->timer);
 				kfree(ifa);
 				ifa = *bifa;
 				continue;
@@ -871,6 +882,40 @@
 }
 
 /*
+ *	Obtain if_index from device name
+ */
+int addrconf_get_ifindex(void *arg)
+{
+	struct ifreq ifr;
+	int res = -ENODEV;
+	
+	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+	{
+		res = -EFAULT;		
+	}
+	else
+	{
+		struct inet6_dev *idev;
+
+		for (idev = inet6_dev_lst; idev; idev=idev->next)
+		{
+			if (!strncmp(ifr.ifr_name, idev->dev->name, IFNAMSIZ))
+			{
+				res = 0;
+				ifr.ifr_ifindex = idev->if_index;
+				if (copy_to_user(arg, &ifr, sizeof(ifr)))
+				{
+					res = -EFAULT;
+				}
+				break;
+			}
+		}
+	}
+
+	return res;
+}
+
+/*
  *	Manual configuration of address on an interface
  */
 int addrconf_add_ifaddr(void *arg)
@@ -1005,7 +1050,7 @@
 			 *  route.
 			 */
 
-			sit_route_add(dev);
+			sit_route_add(idev);
 			break;
 
 		case ARPHRD_LOOPBACK:
@@ -1018,7 +1063,7 @@
 			addrconf_eth_config(dev);
 			break;
 		}
-		rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, 0, dev->name, 0);
+		rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, dev, 0, 0);
 		break;
 
 	case NETDEV_DOWN:
@@ -1029,8 +1074,7 @@
 		if (addrconf_ifdown(dev) == 0)
 		{
 			rt6_ifdown(dev);
-			rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, 0,
-				   dev->name, 0);
+			rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, 0, dev, 0, 0);
 		}
 
 		break;
@@ -1062,7 +1106,7 @@
 
 		rtmsg.rtmsg_prefixlen = ifp->prefix_len;
 		rtmsg.rtmsg_metric = 1;
-		memcpy(rtmsg.rtmsg_device, dev->name, strlen(dev->name) + 1);
+		rtmsg.rtmsg_ifindex = ifp->idev->if_index;
 
 		rtmsg.rtmsg_flags = RTF_UP;
 
diff -u --recursive --new-file v2.1.13/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.13/linux/net/ipv6/af_inet6.c	Sat Nov 30 12:03:13 1996
+++ linux/net/ipv6/af_inet6.c	Tue Nov 26 10:46:41 1996
@@ -550,6 +550,13 @@
 		
 		return -EINVAL;
 
+	case SIOGIFINDEX:
+		/*
+		 *	This one will be moved to the generic device
+		 *	layer in the near future
+		 */
+		return addrconf_get_ifindex((void *) arg);
+		
 	case SIOCSIFADDR:
 		return addrconf_add_ifaddr((void *) arg);
 	case SIOCSIFDSTADDR:
diff -u --recursive --new-file v2.1.13/linux/net/ipv6/ipv6_route.c linux/net/ipv6/ipv6_route.c
--- v2.1.13/linux/net/ipv6/ipv6_route.c	Fri Nov 22 18:28:23 1996
+++ linux/net/ipv6/ipv6_route.c	Tue Nov 26 15:24:07 1996
@@ -859,10 +859,15 @@
 {
 	struct rt6_info *rt;
 	struct device * dev = NULL;
+	struct inet6_dev *idev;
 	struct rt6_req *request;
 	int flags = rtmsg->rtmsg_flags;
 
-	dev = dev_get(rtmsg->rtmsg_device);
+	idev = ipv6_dev_by_index(rtmsg->rtmsg_ifindex);
+	if (idev)
+	{
+		dev = idev->dev; 
+	}
 	
 	rt = (struct rt6_info *) kmalloc(sizeof(struct rt6_info),
 					 GFP_ATOMIC);
@@ -979,21 +984,26 @@
 
 		if (!test)
 		{
-			/*
-			 *	This function is called from user
-			 *	context only (at the moment).
-			 *	As we don't sleep we should never see
-			 *	a lock count > 1.
-			 *
-			 *	If this assumptions becomes invalid we'll
-			 *	just have to had a del request to the
-			 *	queue in this case.
-			 */
-			res = -EBUSY;
+			struct rt6_req *request;
+			
+			request = kmalloc(sizeof(struct rt6_req), GFP_KERNEL);
+			
+			if (!request)
+			{
+				res = -ENOMEM;
+				goto out;
+			}
+			request->operation = RT_OPER_DEL;
+			request->ptr = rt;
+			request->next = request->prev = NULL;
+			rtreq_queue(request);
+			rt6_bh_mask |= RT_BH_REQUEST;
+			res = 0;
 		}
 	}
-	
+  out:
 	atomic_dec(&rt6_lock);
+	rt6_run_bh();
 	return res;
 }
 
@@ -1670,6 +1680,25 @@
 	}
 }
 
+static void rt6_sndrtmsg(struct in6_rtmsg *rtmsg)
+{
+	struct sk_buff *skb;
+	
+	skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
+	if (skb == NULL)
+		return;
+
+	skb->free = 1;
+	
+	memcpy(skb_put(skb, sizeof(struct in6_rtmsg)), &rtmsg,
+	       sizeof(struct in6_rtmsg));
+	
+	if (netlink_post(NETLINK_ROUTE6, skb))
+	{
+		kfree_skb(skb, FREE_WRITE);
+	}
+}
+
 int ipv6_route_ioctl(unsigned int cmd, void *arg)
 {
 	struct in6_rtmsg rtmsg;
@@ -1685,8 +1714,15 @@
 					     sizeof(struct in6_rtmsg));
 			if (err)
 				return -EFAULT;
-			return (cmd == SIOCDELRT) ? ipv6_route_del(&rtmsg) : 
-				ipv6_route_add(&rtmsg);
+			
+			err = (cmd == SIOCDELRT) ? ipv6_route_del(&rtmsg) :
+			      ipv6_route_add(&rtmsg);
+
+			if (err == 0)
+			{
+				rt6_sndrtmsg(&rtmsg);
+			}
+			return err;
 	}
 
 	return -EINVAL;
@@ -1895,7 +1931,7 @@
 {
 #ifdef 	CONFIG_PROC_FS
 	proc_net_register(&(struct proc_dir_entry) {
-		PROC_NET_RT6, 6, "route6",
+		PROC_NET_RT6, 10, "ipv6_route",
 		S_IFREG | S_IRUGO, 1, 0, 0,
 		0, &proc_net_inode_operations,
 		rt6_proc_info
@@ -1965,10 +2001,11 @@
 }
 
 void rt6_sndmsg(__u32 type, struct in6_addr *dst, struct in6_addr *gw,
-		__u16 plen, __u16 metric, char *devname, __u16 flags)
+		__u16 plen, struct device *dev, __u16 metric, __u16 flags)
 {
 	struct sk_buff *skb;
 	struct in6_rtmsg *msg;
+	int ifindex = 0;
 	
 	skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
 	if (skb == NULL)
@@ -1996,7 +2033,20 @@
 
 	msg->rtmsg_prefixlen = plen;
 	msg->rtmsg_metric = metric;
-	strcpy(msg->rtmsg_device, devname);
+
+	if (dev)
+	{
+		struct inet6_dev *idev;
+
+		idev = ipv6_get_idev(dev);
+		if (idev)
+		{
+			ifindex = idev->if_index;
+		}
+	}
+	
+	msg->rtmsg_ifindex = ifindex;
+
 	msg->rtmsg_flags = flags;
 
 	if (netlink_post(NETLINK_ROUTE6, skb))
diff -u --recursive --new-file v2.1.13/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.1.13/linux/net/ipv6/ndisc.c	Tue Nov 19 15:54:02 1996
+++ linux/net/ipv6/ndisc.c	Tue Nov 26 10:46:41 1996
@@ -18,8 +18,9 @@
  *	Changes:
  *
  *	Lars Fenneberg			:	fixed MTU setting on receipt
- *						of an RA. 
+ *						of an RA.
  *
+ *	Janos Farkas			:	kmalloc failure checks
  */
 
 /*
@@ -580,6 +581,7 @@
 	if (skb == NULL)
 	{
 		printk(KERN_DEBUG "send_na: alloc skb failed\n");
+		return;
 	}
 
 	skb->free=1;
@@ -737,6 +739,7 @@
 	if (skb == NULL)
 	{
 		printk(KERN_DEBUG "send_ns: alloc skb failed\n");
+		return;
 	}
 
 	skb->free=1;
@@ -1296,29 +1299,40 @@
 	{
 		printk(KERN_DEBUG "ndisc_rdisc: new default router\n");
 
-		rt = (struct rt6_info *)kmalloc(sizeof(struct rt6_info),
-						GFP_ATOMIC);
-
-		neigh = ndisc_retrieve_neigh(skb->dev, &skb->ipv6_hdr->saddr);
-
-		if (neigh == NULL)
+		rt = (struct rt6_info *) kmalloc(sizeof(struct rt6_info),
+						 GFP_ATOMIC);
+		if (rt)
 		{
-			neigh = ndisc_new_neigh(skb->dev,
-						&skb->ipv6_hdr->saddr);
-		}
+			neigh = ndisc_retrieve_neigh(skb->dev,
+						     &skb->ipv6_hdr->saddr);
 
-		atomic_inc(&neigh->refcnt);
-		neigh->flags |= NCF_ROUTER;
+			if (neigh == NULL)
+			{
+				neigh = ndisc_new_neigh(skb->dev,
+							&skb->ipv6_hdr->saddr);
+			}
 
-		memset(rt, 0, sizeof(struct rt6_info));
+			if (neigh)
+			{
+				atomic_inc(&neigh->refcnt);
+				neigh->flags |= NCF_ROUTER;
+				
+				memset(rt, 0, sizeof(struct rt6_info));
 
-		ipv6_addr_copy(&rt->rt_dst, &skb->ipv6_hdr->saddr);
-		rt->rt_metric = 1;
-		rt->rt_flags = RTF_GATEWAY | RTF_DYNAMIC;
-		rt->rt_dev = skb->dev;
-		rt->rt_nexthop = neigh;
+				ipv6_addr_copy(&rt->rt_dst,
+					       &skb->ipv6_hdr->saddr);
+				rt->rt_metric = 1;
+				rt->rt_flags = RTF_GATEWAY | RTF_DYNAMIC;
+				rt->rt_dev = skb->dev;
+				rt->rt_nexthop = neigh;
 
-		ndisc_add_dflt_router(rt);
+				ndisc_add_dflt_router(rt);
+			}
+			else
+			{
+				kfree(rt);
+			}
+		}
 	}
 
 	if (rt)
diff -u --recursive --new-file v2.1.13/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.13/linux/net/ipv6/raw.c	Fri Nov 15 23:49:12 1996
+++ linux/net/ipv6/raw.c	Tue Nov 26 10:46:41 1996
@@ -386,6 +386,9 @@
 				return -EOPNOTSUPP;
 			return rawv6_seticmpfilter(sk, level, optname, optval,
 						   optlen);
+		case SOL_IPV6:
+			if (optname == IPV6_CHECKSUM)
+				break;
 		default:
 			return ipv6_setsockopt(sk, level, optname, optval,
 					       optlen);
@@ -398,11 +401,18 @@
   	if(err)
   		return err;
 
-	switch (optname) 
+	switch (optname)
 	{
-		case RAW_CHECKSUM:
-			opt->checksum = 1;
-			opt->offset = val;
+		case IPV6_CHECKSUM:
+			if (val < 0)
+			{
+				opt->checksum = 0;
+			}
+			else
+			{
+				opt->checksum = 1;
+				opt->offset = val;
+			}
 
 			return 0;
 			break;
diff -u --recursive --new-file v2.1.13/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- v2.1.13/linux/net/netrom/nr_in.c	Fri Nov 22 18:28:24 1996
+++ linux/net/netrom/nr_in.c	Sun Nov 24 13:28:16 1996
@@ -315,14 +315,8 @@
 {
 	int queued = 0, frametype;
 	
-	if (sk->protinfo.nr->state == NR_STATE_0 && sk->dead)
-		return queued;
-
-	if (sk->protinfo.nr->state != NR_STATE_1 && sk->protinfo.nr->state != NR_STATE_2 &&
-	    sk->protinfo.nr->state != NR_STATE_3) {
-		printk(KERN_ERR "nr_process_rx_frame: frame received - state: %d\n", sk->protinfo.nr->state);
-		return queued;
-	}
+	if (sk->protinfo.nr->state == NR_STATE_0)
+		return 0;
 
 	del_timer(&sk->timer);
 
diff -u --recursive --new-file v2.1.13/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c
--- v2.1.13/linux/net/netrom/nr_timer.c	Fri Nov 22 18:28:24 1996
+++ linux/net/netrom/nr_timer.c	Sun Nov 24 13:28:16 1996
@@ -80,7 +80,7 @@
 /*
  *	NET/ROM TIMER 
  *
- *	This routine is called every 500ms. Decrement timer by this
+ *	This routine is called every 100ms. Decrement timer by this
  *	amount - if expired then process the event.
  */
 static void nr_timer(unsigned long param)
diff -u --recursive --new-file v2.1.13/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.13/linux/net/rose/af_rose.c	Sat Nov 30 12:03:14 1996
+++ linux/net/rose/af_rose.c	Sat Nov 30 10:48:34 1996
@@ -1263,12 +1263,12 @@
 
 	switch (cmd) {
 		case TIOCOUTQ:
-			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
 				return err;
 			amount = sk->sndbuf - sk->wmem_alloc;
 			if (amount < 0)
 				amount = 0;
-			put_user(amount, (unsigned long *)arg);
+			put_user(amount, (unsigned int *)arg);
 			return 0;
 
 		case TIOCINQ: {
@@ -1276,9 +1276,9 @@
 			/* These two are safe on a single CPU system as only user tasks fiddle here */
 			if ((skb = skb_peek(&sk->receive_queue)) != NULL)
 				amount = skb->len - 20;
-			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int))) != 0)
 				return err;
-			put_user(amount, (unsigned long *)arg);
+			put_user(amount, (unsigned int *)arg);
 			return 0;
 		}
 
diff -u --recursive --new-file v2.1.13/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
--- v2.1.13/linux/net/rose/rose_in.c	Fri Nov 22 18:28:24 1996
+++ linux/net/rose/rose_in.c	Sun Nov 24 13:28:16 1996
@@ -303,14 +303,8 @@
 {
 	int queued = 0, frametype, ns, nr, q, d, m;
 	
-	if (sk->protinfo.rose->state == ROSE_STATE_0 && sk->dead)
-		return queued;
-
-	if (sk->protinfo.rose->state != ROSE_STATE_1 && sk->protinfo.rose->state != ROSE_STATE_2 &&
-	    sk->protinfo.rose->state != ROSE_STATE_3 && sk->protinfo.rose->state != ROSE_STATE_4) {
-		printk(KERN_ERR "rose_process_rx_frame: frame received - state: %d\n", sk->protinfo.rose->state);
-		return queued;
-	}
+	if (sk->protinfo.rose->state == ROSE_STATE_0)
+		return 0;
 
 	del_timer(&sk->timer);
 
diff -u --recursive --new-file v2.1.13/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.1.13/linux/net/rose/rose_link.c	Tue Nov 19 15:54:02 1996
+++ linux/net/rose/rose_link.c	Sun Nov 24 13:28:16 1996
@@ -79,9 +79,9 @@
 }
 
 /*
- *	Rose link TIMER 
+ *	Rose Link Timer
  *
- *	This routine is called every 500ms. Decrement timer by this
+ *	This routine is called every 100ms. Decrement timer by this
  *	amount - if expired then process the event.
  */
 static void rose_link_timer(unsigned long param)
diff -u --recursive --new-file v2.1.13/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c
--- v2.1.13/linux/net/rose/rose_timer.c	Fri Nov 22 18:28:24 1996
+++ linux/net/rose/rose_timer.c	Sun Nov 24 13:28:16 1996
@@ -78,9 +78,9 @@
 }
 
 /*
- *	Rose TIMER 
+ *	Rose Timer
  *
- *	This routine is called every 500ms. Decrement timer by this
+ *	This routine is called every 100ms. Decrement timer by this
  *	amount - if expired then process the event.
  */
 static void rose_timer(unsigned long param)
diff -u --recursive --new-file v2.1.13/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.1.13/linux/scripts/mkdep.c	Sat Sep 21 10:46:07 1996
+++ linux/scripts/mkdep.c	Sun Dec  1 11:11:00 1996
@@ -26,15 +26,20 @@
 	int plen;
 	struct path_struct *path = path_array+type;
 
-	if (len == 14 && !memcmp(name, "linux/config.h", len))
-		hasconfig = 1;
+	if (!type) {
+		if (memcmp(name, "linux/", 6) &&
+		    memcmp(name, "asm/", 4) &&
+		    memcmp(name, "net/", 4) &&
+		    memcmp(name, "scsi/", 5))
+			return;
+		if (len == 14 && !memcmp(name, "linux/config.h", len))
+			hasconfig = 1;
+	}
 
 	plen = path->len;
 	memcpy(path->buffer+plen, name, len);
 	len += plen;
 	path->buffer[len] = '\0';
-	if (access(path->buffer, F_OK))
-		return;
 
 	if (!hasdep) {
 		hasdep = 1;
