]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.14 2.1.14
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:12:42 +0000 (15:12 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:12:42 +0000 (15:12 -0500)
83 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/devices.tex
Documentation/devices.txt
Documentation/networking/arcnet.txt
Documentation/networking/ax25.txt
Makefile
Rules.make
arch/alpha/kernel/bios32.c
arch/alpha/lib/Makefile
drivers/block/ide-cd.c
drivers/block/loop.c
drivers/cdrom/cdrom.c
drivers/char/cyclades.c
drivers/char/istallion.c
drivers/char/mem.c
drivers/char/pcxx.c
drivers/char/riscom8.c
drivers/char/serial.c
drivers/char/stallion.c
drivers/char/tty_ioctl.c
drivers/isdn/isdn_tty.c
drivers/net/3c509.c
drivers/net/arcnet.c
drivers/net/wavelan.c
drivers/net/wavelan.h
drivers/sbus/char/sunserial.c
drivers/scsi/BusLogic.c
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/sd_ioctl.c
drivers/scsi/seagate.c
drivers/scsi/sr_ioctl.c
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
drivers/sound/dev_table.h
drivers/sound/dmabuf.c
fs/Config.in
fs/binfmt_script.c
fs/fat/inode.c
fs/smbfs/dir.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/ioctl.c
fs/smbfs/mmap.c
fs/smbfs/proc.c
fs/smbfs/sock.c
include/asm-alpha/termbits.h
include/linux/icmpv6.h
include/linux/if.h
include/linux/in6.h
include/linux/ipv6_route.h
include/linux/quota.h
include/linux/route.h
include/linux/skbuff.h
include/linux/smb.h
include/linux/smb_fs.h
include/linux/smb_fs_sb.h
include/linux/smb_mount.h
include/linux/sockios.h
include/linux/ucdrom.h
include/net/addrconf.h
include/net/ipv6_route.h
include/net/sock.h
init/main.c
net/README
net/ax25/ax25_in.c
net/ax25/ax25_timer.c
net/ax25/sysctl_net_ax25.c
net/core/skbuff.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ipv6_route.c
net/ipv6/ndisc.c
net/ipv6/raw.c
net/netrom/nr_in.c
net/netrom/nr_timer.c
net/rose/af_rose.c
net/rose/rose_in.c
net/rose/rose_link.c
net/rose/rose_timer.c
scripts/mkdep.c

diff --git a/CREDITS b/CREDITS
index 8ac4663ca483637abad43a9429faf1ad1faf5324..a3213604f2eb821962ea67a427cea1aa7e53fea2 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -108,8 +108,8 @@ S: USA
 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: East Brunswick, New Jersey 08816
 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
index ca3520d1bdf9fc12bcf3cbbb23e71df4975bbe99..66a0b416c1d5f3bccd137129cff222e43c01ad0f 100644 (file)
@@ -19,7 +19,7 @@ you don't need to bother doing so in the form of a diff, as this is
 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 @@ Current Minimal Requirements
    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 @@ Since updates to libc fix other problems as well (security flaws, for
 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 @@ ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.2.1
 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 @@ SysVinit utilities
 
 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 @@ site before checking sunsite.
 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
index b0cb3b523230ffb2058548e27fa075d6be274a79..2804e321e64c2d8e5757e462e9b42ef269712ea7 100644 (file)
@@ -1664,10 +1664,10 @@ CONFIG_SCSI_7000FASST
 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 @@ CONFIG_SMB_FS
   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
index 559368e25972bbb9e89f4c3e7a8f9d6eac20b41c..f7997b9a9bdc705f19eb0c1a5efcca92b2b9bf2b 100644 (file)
@@ -42,7 +42,7 @@ foo \kill}%
 %
 \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 @@ reply.
 \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 @@ Additional devices will be added to this number, all starting with
 \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}
index 5fd527c3a8cc7ec15b7a0cbf06b990f6d0143a92..89dc3aaacdce730f1c132cf2391215262a20497e 100644 (file)
@@ -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 @@ reply.
                  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
index 11c604a3cc3bb7782b8b7dbca27de55ed87a7998..c0eefc006d418e25ce2c0d46f261221d91bf1b54 100644 (file)
@@ -55,10 +55,10 @@ included and seems to be working fine!
 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 @@ access.
 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 @@ If you obtained this ARCnet package as an upgrade to the ARCnet driver in
 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 @@ For example:
 
 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
index c7ebdf46da4a7d8c064893842cc633afc77491b3..bcce0ff6babc1f94fbf059e43c3bc339d72e9412 100644 (file)
@@ -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.
-
-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:
-
------------------------------- 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
+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.
+
+Jonathan G4KLX
+
+jsn@cs.nott.ac.uk
index cc6f1b3d148c752bb6ba70354418bacf3495f42c..a52162c99fec834fa60bf415c221dafc842bb20f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 13
+SUBLEVEL = 14
 
 ARCH = i386
 
index b023d0b43ba4c5d53785791727ba0ce709e05dd6..0d429a30d81c857dde1ac3bda2ff2ee4979c6033 100644 (file)
@@ -184,6 +184,11 @@ endif
 # 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
 
 #
index 67c3c4f7a687373de17cf9e2de084d6f2fad4d9f..01751697f4ead0498efaca9c34fbe30776d435a0 100644 (file)
@@ -693,6 +693,7 @@ static inline void eb66p_fixup(void)
 
 static inline void alphapc164_fixup(void)
 {
+       extern int SMCInit(void);
        char irq_tab[7][5] = {
          /*
           *      int   intA  intB   intC   intD
@@ -708,6 +709,8 @@ static inline void alphapc164_fixup(void)
        };
 
        common_fixup(5, 11, 5, irq_tab, 0);
+
+       SMCInit();
 }
 
 /*
@@ -1285,4 +1288,263 @@ asmlinkage int sys_pciconfig_write(
        }
        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 */
index 87035315e0c6f7f48340abf0451534b0345d00ec..15a02a5e907a759c574067b6cad966503ea48940 100644 (file)
@@ -8,6 +8,14 @@ OBJS  = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \
        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)
 
index b3092bec58a241a3769f6a9d278ea0cce0eb1d44..a62184d9d87e4eef589942a7ed549e23d6bf3d8b 100644 (file)
  *                     -- 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
  *  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 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
                   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)) {
index c61549c379acc0a739ffa07089bbdf51c563c8cd..1030a53a31fea31c81ebf56543a3c4abd8d01a5c 100644 (file)
@@ -457,7 +457,7 @@ static int lo_ioctl(struct inode * inode, struct file * file,
                        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;
        }
index 1a12acc7b5ad2c8202ee9ccb78dd920680cab542..9d5149655deeb24e11ecc8735e7c9307589721a6 100644 (file)
@@ -350,9 +350,11 @@ int cdrom_ioctl(struct inode *ip, struct file *fp,
                 
         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;
index c18d3e35bdf7d3b4e5de22d8252ad19c2f836ad0..44b7c03ee770c2e1842f50a0784c3c4056b5edaa 100644 (file)
@@ -1937,12 +1937,15 @@ static int
 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 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
 
 /* 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;
index 7729e6ccb8b7f5a77fc39c3b895b5e45b3996168..07125699756224c7f68c2021b506d499c918e58d 100644 (file)
@@ -1791,13 +1791,14 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                }
                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 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
                }
                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;
index 1fb50fcc1c80aa349e49ebbb6ea819819c23e57d..3f13b717448b25c62aaab96cb997a86f2339d83e 100644 (file)
@@ -189,17 +189,52 @@ static long write_null(struct inode * inode, struct file * file,
        return count;
 }
 
-static long read_zero(struct inode * node, struct file * file,
-       char * buf, unsigned long 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)
 {
-       int left;
-
-       for (left = count; left > 0; left--) {
-               put_user(0,buf);
-               buf++;
+       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)
+{
+       unsigned long left;
+
+       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;
 }
 
index fdb74ced7d347c1249e9942acbf1810fe39f4f02..b3f3af024287f43c01a2efb8e94e7e79e359832c 100644 (file)
@@ -1971,19 +1971,17 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
                        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 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
                        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)
index 8a66ea259dacdb5eed440e82bfcb9eccdddd3ac2..1ca581b43aca01d338a4d5c044d97ef9b9307cf3 100644 (file)
@@ -1356,7 +1356,7 @@ static int rc_get_modem_info(struct riscom_port * port, unsigned int *value)
                | ((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 @@ static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd,
        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 @@ static int rc_ioctl(struct tty_struct * tty, struct file * filp,
                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));
index 23a99a61a2d8ef93548fc8568c2f26d60477435a..a2fbb41c73da2a439941dd348e4dcd063dc3b922 100644 (file)
@@ -1747,10 +1747,9 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
        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 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        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));
index 3ac1d26543e81981f2f57714c5616ce3a659556b..81e01058495c8fe8e55b83bc08f7373e77dc3233 100644 (file)
@@ -1122,7 +1122,6 @@ static int stl_setserial(stlport_t *portp, struct serial_struct *sp)
 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 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd
                }
                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:
index f4a68812b69cae875f5efc04ded4b19a2be3c6c3..317f0cbdd81bf1259d09b9399e1c84ecd8a79fc3 100644 (file)
@@ -513,7 +513,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        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;
index 7a10b5ceeb4bdb4b30845c18c177d7cc9521537c..e1522022ffc6d31be029f06cd59cded42565df9b 100644 (file)
@@ -1014,7 +1014,7 @@ static int isdn_tty_get_lsr_info(modem_info * info, uint * value)
        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 @@ static int isdn_tty_get_modem_info(modem_info * info, uint * value)
            | ((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 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
 #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));
index 93f4069d72cc41c8a421bc4eb9df86353ba43f98..dba1f56bbaac7f10333f76610a1a5c378c988eb0 100644 (file)
@@ -449,7 +449,7 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
                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 @@ el3_close(struct device *dev)
 }
 
 #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 */
 \f
index 2e18e2d5b069087e909604c67a7433913285ba42..a770f6e48fdf07d5e6dad6653d9f588162e26b1b 100644 (file)
          
        **********************
        
+       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.
        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.
 */
 
 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 @@ static const char *version =
 
 /**************************************************************************/
 
+/* 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 @@ static const char *version =
 #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 @@ int arcnet_debug = ARCNET_DEBUG;
 /* 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 @@ int arcnet_debug = ARCNET_DEBUG;
 
        /* 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 @@ int arcnet_debug = ARCNET_DEBUG;
 #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 @@ void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,char *desc)
  * 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 @@ int arcnet_probe(struct device *dev)
                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 @@ int arcnet_probe(struct device *dev)
                        continue;
                }
                
-               if (inb(STATUS) == 0xFF)
+               if (ARCSTATUS == 0xFF)
                {
                        BUGMSG2(D_INIT_REASONS,"(empty)\n");
                        BUGMSG(D_INIT_REASONS,"Stage 1: ");
@@ -863,7 +851,7 @@ int arcnet_probe(struct device *dev)
                        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 @@ int arcnet_probe(struct device *dev)
        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 @@ int arcnet_probe(struct device *dev)
                }
                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 @@ int arcnet_probe(struct device *dev)
                 * 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 @@ int arcnet_probe(struct device *dev)
                BUGMSG2(D_INIT,"%Xh ",*port);
                
                ioaddr=*port;
-               status=inb(STATUS);
+               status=ARCSTATUS;
                
                if ((status & 0x9D)
                        != (NORXflag|RECONflag|TXFREEflag|RESETflag))
@@ -1013,8 +1001,8 @@ int arcnet_probe(struct device *dev)
                        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 @@ int arcnet_probe(struct device *dev)
                         * 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 @@ int arcnet_probe(struct device *dev)
 #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 @@ int arcnet_probe(struct device *dev)
                        }
                        else
                        {
-                               BUGMSG2(D_INIT_REASONS,"%Xh-", *cptr);
+                               BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
                        }
                }
 
@@ -1128,48 +1116,67 @@ int arcnet_probe(struct device *dev)
        /* 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)
+
+       /* 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=(u_char *)shmem;
-       while (*first_mirror==TESTvalue) first_mirror-=MIRROR_SIZE;
-       first_mirror+=MIRROR_SIZE;
+       first_mirror=last_mirror=shmem;
+       while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
+       first_mirror+=mirror_size;
 
-       while (*last_mirror==TESTvalue) last_mirror+=MIRROR_SIZE;
-       last_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 @@ int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
        {
                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 @@ int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
                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 @@ int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
        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_found(struct device *dev,int port,int airq, u_long shmem)
 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 @@ int arcnet_reset(struct device *dev,int reset_delay)
        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 @@ static int
 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 @@ arcnet_open(struct device *dev)
         * 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 @@ arcnet_open(struct device *dev)
 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 @@ arcnet_close(struct device *dev)
 
        /* 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 @@ static int
 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 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
                   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 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
                        lp->stats.tx_errors++;
                        lp->stats.tx_aborted_errors++;
 
-                       outb(NOTXcmd,COMMAND);
+                       ACOMMAND(NOTXcmd);
                }
 
                if (lp->outgoing.skb)
@@ -1571,7 +1576,7 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
           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 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
        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 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
         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 @@ static int
 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 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
 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 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
        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 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
 #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 @@ static int
 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 @@ arcnet_go_tx(struct device *dev,int enable_irq)
        }
        
        /* start sending */
-       outb(TXcmd|(lp->txready<<3),COMMAND);
+       ACOMMAND(TXcmd|(lp->txready<<3));
 
        lp->stats.tx_packets++;
        lp->txready=0;
@@ -1940,11 +1945,11 @@ arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs)
        /* 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 @@ static void
 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 @@ arcnet_inthandler(struct device *dev)
                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 @@ arcnet_inthandler(struct device *dev)
                        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 @@ arcnet_inthandler(struct device *dev)
 #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 @@ arcnet_inthandler(struct device *dev)
        } 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 @@ static void
 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 @@ arcnet_rx(struct device *dev,int recbuf)
        if (saddr==0)
        {
                BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
-                       inb(STATUS));
+                       ARCSTATUS);
                lp->stats.rx_errors++;
                return;
        }
@@ -2263,6 +2268,12 @@ arcnet_rx(struct device *dev,int recbuf)
                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 @@ arcnet_get_stats(struct device *dev)
        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 @@ arcnet_get_stats(struct device *dev)
 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 @@ static int
 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 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
 #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 @@ static int
 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 irq=0;
 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 */
index cbe54cc0ff63f1a653291c5ad1f3853374136f9e..1066ab8bf9f23c0596ccaa560c3362e4e1850769 100644 (file)
@@ -69,7 +69,7 @@ struct net_local
 
 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 @@ wavelan_probe1(device *dev, unsigned short ioaddr)
                ||
                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)
index 3eb221c0b20013583a484541f9e62573d2309d8f..ddad1c9fab067d0730efcddd42601502c3bc85d2 100644 (file)
@@ -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 */
 
 /*
index fdea1b804e672d2678a7b9e1c74f6b37ec1bece8..ed1d75073ae42386074b52172d632d84d36ae560 100644 (file)
@@ -1365,17 +1365,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        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,
index 5e057cb993a9398ad0e5733c54b14c1d69643f39..57b9b2a0299a6006c04f9a1cda07eb832b08ed52 100644 (file)
@@ -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 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
                                             *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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   /*
     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 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
   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
index 83806bdb3800d2b255da044b55cae754e72a294a..dbf1e9e6034245d9ec76fd48c9f3abc065807fc5 100644 (file)
@@ -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.
  *
  *
  *  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.
+ *
  */
 
 /*
  *  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
  *  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.
  *
 #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 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #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 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #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 @@ struct proc_dir_entry proc_scsi_eata2x = {
 #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 @@ struct eata_info {
    /* 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 @@ struct mssp {
    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 @@ struct mscp {
    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 struct Scsi_Host *sh[MAX_BOARDS + 1];
 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 unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
 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 @@ static inline int read_pio(unsigned int iobase, ushort *start, ushort *end) {
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
 
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
 
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
             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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
       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 @@ int eata2x_detect(Scsi_Host_Template *tpnt) {
    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();
+
+   for (k = 0; io_port[k]; k++) {
 
-      if (j < MAX_BOARDS && port_detect(port_base, j, tpnt)) j++;
+      if (io_port[k] == SKIP) continue;
 
-      port_base++;
+      if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
       }
 
    if (j > 0) 
@@ -651,7 +788,8 @@ static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
 }
 
 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 @@ int eata2x_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    /* 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_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
 }
 
 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 @@ int eata2x_abort(Scsi_Cmnd *SCarg) {
         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_abort(Scsi_Cmnd *SCarg) {
 }
 
 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 @@ int eata2x_reset(Scsi_Cmnd *SCarg, unsigned int reset_flags) {
 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;
@@ -1160,6 +1304,31 @@ static void eata2x_interrupt_handler(int irq, void *dev_id,
    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)
 Scsi_Host_Template driver_template = EATA;
 
index 0edcb31d4c5ba94ec53e5f4ecf3700b687ece74a..7ea04b8af6628924b9a2753e7f48ad18783e6f47 100644 (file)
@@ -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 @@ int eata2x_reset(Scsi_Cmnd *, unsigned int);
                NULL,                                          \
                "EATA/DMA 2.0x rev. " EATA_VERSION " ",        \
                eata2x_detect,                                 \
-               NULL, /* Release */                            \
+               eata2x_release,                                \
                NULL,                                          \
                NULL,                                          \
                eata2x_queuecommand,                           \
index 78c1ba0d65923d137911c24b174edce9e5aa1c86..070e6423ea38b8652834a19af7da821aec9383e7 100644 (file)
@@ -76,10 +76,10 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
     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:
index c163d1dba36c6f641047a86a241ed5d68b1c6d76..6ca8b21f28b7ee4a8ec501fe16acd97980f83526 100644 (file)
@@ -345,7 +345,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
 
        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);
index 8734506a3de6c6039e6864c46f291141dcbdf881..f423ea25182d762f24e21017337c2350351b5b62 100644 (file)
@@ -209,6 +209,8 @@ int sr_reset(struct cdrom_device_info *cdi)
 }
 
 /* ----------------------------------------------------------------------- */
+/* 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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        
     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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
 
     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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
                
     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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        
     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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        
        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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        
        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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
     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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        /* 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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
     case CDROMVOLREAD:
     {
        char * buffer;
-       struct cdrom_volctrl volctrl;
+       struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
        
        /* Get the current params */
        
@@ -496,21 +467,18 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
             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 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
        
        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_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_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 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
     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:
index 60a7b8b166fff70f095b2cd58687208898d726f3..746e48b8aafc73fa301b441ae1453100ba4a0e6a 100644 (file)
@@ -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.
  *
  *
  *  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.
  *  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 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 #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 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 #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 @@ struct proc_dir_entry proc_scsi_u14_34f = {
 
 #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 @@ struct mscp {
    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 struct Scsi_Host *sh[MAX_BOARDS + 1];
 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 unsigned int irqlist[MAX_IRQ], calls[MAX_IRQ];
 
 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 @@ static int board_inquiry(unsigned int j) {
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
 
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
    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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
         }
       }
 
+   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 @@ static inline int port_detect(unsigned int *port_base, unsigned int j,
       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 @@ int u14_34f_detect(Scsi_Host_Template *tpnt) {
    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 @@ static inline void build_sg_list(struct mscp *cpp, Scsi_Cmnd *SCpnt) {
 }
 
 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 @@ int u14_34f_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
    /* 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_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
 }
 
 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 @@ int u14_34f_abort(Scsi_Cmnd *SCarg) {
         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_abort(Scsi_Cmnd *SCarg) {
 }
 
 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 @@ int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) {
    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;
@@ -1124,6 +1174,31 @@ static void u14_34f_interrupt_handler(int irq, void *dev_id,
    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)
 Scsi_Host_Template driver_template = ULTRASTOR_14_34F;
 
index f301f48ae629c72ffcb55f09afc117b36fefb635..cd0f46dac92114eab91f2afc7f98955aa01c0c18 100644 (file)
@@ -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 @@ int u14_34f_biosparam(Disk *, kdev_t, int *);
                NULL,                                                 \
                "UltraStor 14F/34F rev. " U14_34F_VERSION " ",        \
                u14_34f_detect,                                       \
-               NULL, /* Release */                                   \
+               u14_34f_release,                                      \
                NULL,                                                 \
                NULL,                                                 \
                u14_34f_queuecommand,                                 \
index b07f9168bc27b642717085018a8e929214f3bea4..6bbeb56387181ce830e1719bd3c832702d9407f0 100644 (file)
@@ -322,7 +322,7 @@ struct sound_timer_operations {
 #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
index 28aa8e836479813d6a5ba5d013e1366dc6281e0f..9cc363b6044005ba481193c371e96817679c64f8 100644 (file)
@@ -581,6 +581,7 @@ DMAbuf_release (int dev, int mode)
   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))
     {
index a9b8e27625f7e2b0ac8213e94cdf0812aa8e54cf..39161ad952e3b5bec1a5df34066b1390f6ce0cc4 100644 (file)
@@ -27,8 +27,8 @@ if [ "$CONFIG_INET" = "y" ]; then
     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
index 67b1b058871d606cb736c9ecca480bb029617964..9050a106ca3d8b235e01669066a2ea086c58d052 100644 (file)
@@ -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 @@ static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
                        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 @@ static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs)
                *cp++ = '\0';
        if (*cp)
                i_arg = cp;
+       strcpy (interp, i_name_start);
        /*
         * OK, we've parsed out the interpreter name and
         * (optional) argument.
index f79192f0d501d6783eed746b710024798b0dbeb8..3119074072bd5e3adb96389d3f2826bcb60b9c02 100644 (file)
@@ -48,13 +48,12 @@ void fat_put_inode(struct inode *inode)
        }
        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 @@ void fat_put_inode(struct inode *inode)
                        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);
 }
 
 
index aa945bb4431b91be012b27192e070e3ba3b0a82d..a07d135174e07914954baa4cc9650e0276d374c4 100644 (file)
@@ -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
  *
  */
 
 #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 @@ struct inode_operations smb_dir_inode_operations =
        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. */
+               c1 = (*s1 >= 'a' && *s1 <= 'z') ? *s1 - ('a' - 'A') : *s1;
+               c2 = (*s2 >= 'a' && *s2 <= 'z') ? *s2 - ('a' - 'A') : *s2;
+               s1 += 1;
+               s2 += 1;
 
-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;
+               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);
+}
+
+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;
 
-       if (c_entry == NULL) 
+       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;
-        }
+       seed += no;
 
-        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];
+       return seed - no;
+}
 
-               len = strlen(entry->path);
-                if ((result = get_pname_static(inode, entry->path, len,
-                                               complete_path,
-                                               &path_len)) < 0)
-                        return result;
+static long
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+{
+       return -EISDIR;
+}
 
-                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;
-                }
+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;
 
-               DDPRINTK("smb_readdir: entry->path = %s\n", entry->path);
-               DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
+static struct smb_dirent *
+smb_search_in_cache(struct inode *dir, unsigned long f_pos)
+{
+       int i;
 
-                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;
+       if ((dir->i_dev != c_dev) || (dir->i_ino != c_ino))
+       {
+               return NULL;
        }
-       return 0;
-}
-
-void
-smb_init_dir_cache(void)
-{
-        c_ino   = 0;
-        c_entry = 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_invalid_dir_cache(unsigned long ino)
+static int
+smb_refill_dir_cache(struct smb_server *server, struct inode *dir,
+                    unsigned long f_pos)
 {
-       if (ino == c_ino) {
-                c_ino = 0;
-                c_seen_eof = 0;
-        }
-}
+       int result;
+       static struct semaphore sem = MUTEX;
+       int i;
+       ino_t ino;
 
-void
-smb_free_dir_cache(void)
-{
-        int i;
+       do
+       {
+               down(&sem);
+               result = smb_proc_readdir(server, dir, f_pos,
+                                         SMB_READDIR_CACHE_SIZE, c_entry);
 
-        DPRINTK("smb_free_dir_cache: enter\n");
-        
-        if (c_entry == NULL)
-                return;
+               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;
+
+               ino = smb_fresh_inodes(server, c_size);
+               for (i = 0; i < c_size; i++)
+               {
+                       c_entry[i].f_ino = ino;
+                       ino += 1;
+               }
 
-        for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
-                smb_kfree_s(c_entry[i].path, NAME_MAX + 1);
-        }
+               up(&sem);
 
-        smb_kfree_s(c_entry,
-                    sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE);
-        c_entry = NULL;
+       }
+       while ((c_dev != dir->i_dev) || (c_ino != dir->i_ino));
 
-        DPRINTK("smb_free_dir_cache: exit\n");
+       return result;
 }
 
-
-/* get_pname_static: it expects the res_path to be a preallocated
-   string of len SMB_MAXPATHLEN. */
-
 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;
        }
-       
-       /* 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;
+       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;
                }
-               
-               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;
+               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);
 
-       switch (SMB_SERVER(dir)->case_handling) 
+       if (entry == NULL)
        {
-        case CASE_UPPER: 
-                str_upper(path); 
-                break;
-        case CASE_LOWER: 
-                str_lower(path); 
-                break;
-        case CASE_DEFAULT: 
-                break;
+               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..) */
+
+               struct smb_inode_info *ino_info
+               = smb_find_dir_inode(dir, entry->name, entry->len);
 
-       *res_len = len;
+               ino_t ino = entry->f_ino;
 
-       DDPRINTK("get_pname: path = %s, *pathlen = %d\n",
-                 path, *res_len);
+               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)
+
+void
+smb_init_dir_cache(void)
 {
-        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;
-        }
-
-        strcpy(*res_path, result);
-        *res_len = result_len;
-        return 0;
+       c_ino = 0;
+       c_dev = 0;
+       c_entry = NULL;
 }
 
-static void
-put_pname(char *path)
+void
+smb_invalid_dir_cache(unsigned long ino)
 {
-       smb_kfree_s(path, 0);
+       /* TODO: check for dev as well */
+       if (ino == c_ino)
+       {
+               c_ino = 0;
+               c_seen_eof = 0;
+       }
+}
+
+void
+smb_free_dir_cache(void)
+{
+       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 @@ put_pname(char *path)
    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);
 
-        len = strlen(path);
-
-        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;
 
-        new_inode_info->finfo        = *finfo;
-        new_inode_info->finfo.opened = 0;
-        new_inode_info->finfo.path   = path;
-        new_inode_info->finfo.len    = len;
+       /* We have to link the new inode_info into the doubly linked
+          list of inode_infos to make a complete linear search
+          possible. */
 
-        SMB_INOP(dir)->nused += 1;
+       root = &(SMB_SERVER(dir)->root);
 
-        /* We have to link the new inode_info into the doubly linked
-           list of inode_infos to make a complete linear search
-           possible. */
+       new_inode_info->prev = root;
+       new_inode_info->next = root->next;
+       root->next->prev = new_inode_info;
+       root->next = new_inode_info;
 
-        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 @@ smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo,
                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;
 
-        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;
+       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);
-
-        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;
+       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;
 }
 
 /* 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);
-
-        do {
-                ino->finfo.opened = 0;
-                ino = ino->next;
-        } while (ino != &(server->root));
-        
-        return;
+       struct smb_inode_info *ino = &(server->root);
+
+       do
+       {
+               ino->finfo.opened = 0;
+               ino = ino->next;
+       }
+       while (ino != &(server->root));
+
+       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);
+       struct smb_server *server = SMB_SERVER(parent);
+       struct smb_inode_info *dir = SMB_INOP(parent);
+       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;
-
-        } 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;
-        }
-
-       /* 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 the file is in the dir cache, we do not have to ask the
+          server. */
+       found_in_cache = 0;
 
+       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;
 
-       if ((*result = smb_iget(dir, name, &finfo, new_inode_info)) == NULL)
+       DPRINTK("attr: %x\n", finfo.attr);
+
+       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 @@ static int
 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 @@ static int
 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 = -ENOENT;
+               goto finished;
        }
-
-        res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len);
-        if (res < 0) {
-                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;
 }
index 754180e1f3f16c4025ef51b7ab390c7a224d38b1..525c78ab91cc56c0fbdc27f3b0472d7f5421134c 100644 (file)
@@ -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>
 #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 @@ smb_fsync(struct inode *inode, struct file *file)
 int
 smb_make_open(struct inode *i, int right)
 {
-        struct smb_dirent *dirent;
+       struct smb_dirent *dirent;
 
-        if (i == NULL) {
-                printk("smb_make_open: got NULL inode\n");
-                return -EINVAL;
-        }
-
-        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 @@ smb_file_read(struct inode *inode, struct file *file, char *buf, unsigned long c
 {
        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 @@ smb_file_write(struct inode *inode, struct file *file, const char *buf,
               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 @@ smb_file_write(struct inode *inode, struct file *file, const char *buf,
 
        bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5;
 
-        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);
-                }
+       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)
+       {
+               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 @@ smb_file_write(struct inode *inode, struct file *file, const char *buf,
 
        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 */
index e4e9ad9fbce59326a5d1b7fcbee34a1abe00b046..b39403358728ca6895e245dcaaad6f09a0df5a61 100644 (file)
@@ -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_read_inode(struct inode *);
 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 struct super_operations smb_sops = {
 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;
-
-        SMB_INOP(inode) = inode_info;
-
-        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;
+       /* 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);
 
+       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;
+
+       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 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
        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;
+                              (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);
+       smb_init_root(server);
 
-        /*
-         * Make the connection to the 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 @@ smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
        copy_to_user(buf, &tmp, bufsiz);
 }
 
-/* DO MORE */
 int
 smb_notify_change(struct inode *inode, struct iattr *attr)
 {
@@ -349,93 +357,101 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
        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_SIZE) != 0)
+       {
 
-        }
+               if ((error = smb_make_open(inode, O_WRONLY)) < 0)
+                       goto fail;
 
-        if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0) {
+               if ((error = smb_proc_trunc(SMB_SERVER(inode),
+                                           SMB_FINFO(inode)->fileid,
+                                           attr->ia_size)) < 0)
+                       goto fail;
 
-                struct smb_dirent finfo;
+       }
+       if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
+       {
 
-                finfo.attr  = 0;
+               struct smb_dirent finfo;
 
-                if ((attr->ia_valid & ATTR_CTIME) != 0)
-                        finfo.ctime = attr->ia_ctime;
-                else
-                        finfo.ctime = inode->i_ctime;
+               finfo.attr = 0;
+               finfo.f_size = inode->i_size;
+               finfo.f_blksize = inode->i_blksize;
 
-                if ((attr->ia_valid & ATTR_MTIME) != 0)
-                        finfo.mtime = attr->ia_mtime;
-                else
-                        finfo.mtime = inode->i_mtime;
+               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_ATIME) != 0)
-                        finfo.atime = attr->ia_atime;
-                else
-                        finfo.atime = inode->i_atime;
+               if ((attr->ia_valid & ATTR_MTIME) != 0)
+                       finfo.f_mtime = attr->ia_mtime;
+               else
+                       finfo.f_mtime = inode->i_mtime;
 
-                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;
-                }
-        }
+               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 @@ int init_module(void)
 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
 }
 
index b62a6e06dc7ce29d946dd4fe68f5d87ef06846e3..d4685a60b0a62565708df71ceda106a53cc8c75c 100644 (file)
@@ -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>
 #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;
        }
 }
index d790c4bce9f536ccf19e687493bcdbfba4e1572c..9fd157b2ab1a75e5e720cd0660175f141090ae4a 100644 (file)
@@ -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
  *
  */
 
 /*
  * 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 @@ smb_file_mmap_nopage(struct vm_area_struct * area,
        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;
+       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;
+                       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;
-                        }
-                }
-        }
+                       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 @@ struct vm_operations_struct smb_file_mmap = {
 
 /* 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;
index 6d146e9e5025ec8167ebbd52b924b5acdfa16126..ee998a89f13887ace3d937ec27fb06d6f94fa2bf 100644 (file)
@@ -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
  */
 #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)
 {
-       return a<b ? a : b;
+       while (*name)
+       {
+               if (*name >= 'a' && *name <= 'z')
+                       *name -= ('a' - 'A');
+               name++;
+       }
+}
+
+static void
+str_lower(char *name)
+{
+       while (*name)
+       {
+               if (*name >= 'A' && *name <= 'Z')
+                       *name += ('a' - 'A');
+               name++;
+       }
 }
 
 /*****************************************************************************/
@@ -45,94 +64,105 @@ static inline int min(int a, int b)
 /*                                                                           */
 /*****************************************************************************/
 
-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)
+smb_encode_path(struct smb_server *server,
+               byte * p, struct smb_inode_info *dir,
+               const char *name, const int len)
 {
-        word 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 @@ smb_name_mangle(byte *p, const byte *name)
        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 (*name)
+       {
+               *p++ = (*name >> 4) + 'A';
+               *p++ = (*name & 0x0F) + 'A';
+               name++;
        }
-       while (pad --) {
-               *p ++ = 'C';
-               *p ++ = 'A';
+       while (pad--)
+       {
+               *p++ = 'C';
+               *p++ = 'A';
        }
        *p++ = '\0';
-       
+
        return p;
 }
 
@@ -161,7 +193,8 @@ smb_name_mangle(byte *p, const byte *name)
 
 /* 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 @@ extern struct timezone sys_tz;
 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 @@ date_dos2unix(unsigned short time,unsigned short date)
 /* 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 @@ date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
 /*****************************************************************************/
 
 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 @@ smb_verify(byte *packet, int command, int wct, int bcc)
 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 @@ smb_lock_server(struct smb_server *server)
 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 @@ smb_unlock_server(struct smb_server *server)
 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;
-        }
-
-        return result;
+       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;
+       }
+       return result;
 }
 
 /* smb_retry: This function should be called when smb_request_ok has
@@ -447,72 +460,73 @@ smb_request_ok(struct smb_server *s, int command, int wct, int bcc)
 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;
-
-        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);
-        }
-        
+       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);
+
+       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 @@ smb_setup_header(struct smb_server *server, byte command, word wct, word bcc)
 
 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);
+       smb_lock_server(server);
+       return smb_setup_header(server, command, wct, bcc);
+}
+
+static void
+smb_setup_bcc(struct smb_server *server, byte * p)
+{
+       __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 @@ smb_setup_header_exclusive(struct smb_server *server,
 /*****************************************************************************/
 
 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;
-       charp;
-        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_proc_open(struct smb_server *server, const char *pathname, int len,
                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);
+
+       if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+       {
 
- 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 (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 @@ smb_proc_close(struct smb_server *server,
    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);
+       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 ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) {
-                res = WVAL(buf, smb_vwv0);
-        }
+       *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)
-{
-        char *buf = server->packet;
-        int result;
-
-        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_unlock_server(server);
-        return result;
-}
-
-
-/* smb_proc_create: We expect entry->attr & entry->ctime to be set. */
-
 int
-smb_proc_create(struct smb_server *server, const char *path, int len, 
-               struct smb_dirent *entry)
+smb_proc_create(struct inode *dir, const char *name, int len,
+               word attr, time_t ctime)
 {
        int error;
        char *p;
-        char *buf = server->packet;
+       struct smb_server *server = SMB_SERVER(dir);
+       char *buf;
        __u16 fileid;
 
        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);
+       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);
+
+       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);
+       }
+       fileid = WVAL(buf, smb_vwv0);
+       smb_unlock_server(server);
 
-        smb_proc_close(server, fileid, 0);
+       smb_proc_close(server, fileid, CURRENT_TIME);
 
        return 0;
 }
 
 int
-smb_proc_mv(struct smb_server *server, 
-            const char *opath, const int olen,
-            const char *npath, const int nlen)
+smb_proc_mv(struct inode *odir, const char *oname, const int olen,
+           struct inode *ndir, const char *nname, const int nlen)
 {
        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- 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;
+       struct smb_server *server = SMB_SERVER(odir);
+       char *buf;
+       int result;
+
+       smb_lock_server(server);
+       buf = server->packet;
+
+      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);
+
+       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_mkdir(struct smb_server *server, const char *path, const int len)
+smb_proc_mkdir(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, SMBmkdir, 0, 2 + len);
-       smb_encode_ascii(p, path, len);
+      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);
 
-        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, SMBmkdir, 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_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, 2 + len);
-       smb_encode_ascii(p, path, len);
+      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);
 
-        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, SMBrmdir, 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_unlink(struct inode *dir, const char *name, const int len)
 {
        char *p;
-        char *buf = server->packet;
-        int result;
-
-        smb_lock_server(server);
-
- 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;
+       struct smb_server *server = SMB_SERVER(dir);
+       char *buf;
+       int result;
+
+       smb_lock_server(server);
+       buf = server->packet;
+
+      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);
+
+       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_trunc(struct smb_server *server, word fid, dword length)
 {
-        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;
+       char *p;
+       char *buf;
+       int result;
+
+       smb_lock_server(server);
+       buf = server->packet;
+
+      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;
 }
 
+static void
+smb_init_dirent(struct smb_server *server, struct smb_dirent *entry)
+{
+       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 @@ smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos,
                       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 @@ smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos,
    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;
-
-        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;
+       char *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;
 
-       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, "\\*");
+       char param[SMB_MAXPATHLEN + 2 + 12];
+       int mask_len;
+       unsigned char *mask = &(param[12]);
+
+       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);
-                }
-
-                if (ff_searchcount == 0) 
-                        break;
-
-                /* point to the data bytes */
-                p = resp_data;
-
-                /* we might need the lastname for continuations */
+       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
+               }
+
+               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);
+               }
+
+               if (ff_searchcount == 0)
+               {
+                       break;
+               }
+               /* point to the data bytes */
+               p = resp_data;
+
+               /* 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;
-        }
-
-        smb_unlock_server(server);
-
-        return total_count - fpos;
+               DPRINTK("received %d entries (eos=%d resume=%d)\n",
+                       ff_searchcount, ff_eos, ff_resume_key);
+
+               first = 0;
+       }
+
+      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;
+
+       unsigned char *resp_data = NULL;
+       unsigned char *resp_param = NULL;
+       int resp_data_len = 0;
+       int resp_param_len = 0;
 
-        smb_setup_header_exclusive(server, SMBgetattrE, 1, 0);
-        WSET(buf, smb_vwv0, entry->fileid);
+       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;
-        }
+       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);
 
-        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);
+       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);
 
-        smb_unlock_server(server);
-        return 0;
+       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) {
-
-                int result = 0;
-                struct smb_dirent temp_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);
-        }
+       struct smb_server *server = SMB_SERVER(dir);
+       int result = 0;
+
+       smb_init_dirent(server, 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);
-
-        WSET(buf, smb_vwv0, fid);
-
-        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);
-
-        return smb_request_ok_unlock(server, SMBsetattrE, 0, 0);
+       char param[SMB_MAXPATHLEN + 20];
+       char data[26];
+       char *p;
+       int result;
+
+       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);
+
+       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);
+
+       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;
-
-        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);
-        }
+       int result;
+
+       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 @@ smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
        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 @@ smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
 /*                                                                           */
 /*****************************************************************************/
 
-struct smb_prots {
+struct smb_prots
+{
        enum smb_protocol prot;
        const char *name;
 };
@@ -1631,50 +1655,50 @@ int
 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"},
+               {PROTOCOL_NT1, "NT LM 0.12"},
+               {PROTOCOL_NT1, "NT LANMAN 1.0"},
 #endif
-#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 ((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 (server->packet != NULL)
+       {
+               smb_vfree(server->packet);
+               server->packet_size = 0;
+       }
+       server->packet = smb_vmalloc(max_xmit);
 
-       if (server->packet == NULL) {
+       if (server->packet == NULL)
+       {
                printk("smb_proc_connect: No memory! Bailing out.\n");
-                result = -ENOMEM;
-                goto fail;
+               result = -ENOMEM;
+               goto fail;
        }
-
-        server->max_xmit = max_xmit;
+       server->packet_size = server->max_xmit = max_xmit;
 
        /*
         * Start with an RFC1002 session request packet.
@@ -1683,98 +1707,110 @@ smb_proc_reconnect(struct smb_server *server)
 
        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 ((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) {
+       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);
-
-        if (server->protocol >= PROTOCOL_LANMAN1) {
-
-                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);
+               prots[i].name);
+
+       if (server->protocol >= PROTOCOL_LANMAN1)
+       {
+
+               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->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 @@ smb_proc_reconnect(struct smb_server *server)
                                         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 @@ smb_proc_reconnect(struct smb_server *server)
                        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 @@ smb_proc_reconnect(struct smb_server *server)
                        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 @@ smb_proc_reconnect(struct smb_server *server)
        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 @@ smb_proc_reconnect(struct smb_server *server)
 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 */
index 38998ce5453b17fc5f0b4cbf321a86fef0547fdb..ca6d8c26949e268ece3264c1fdb5aa9d9194c53f 100644 (file)
@@ -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 @@ static int
 _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;
+               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);
+               }
+       }
+}
 
-                fs = get_fs();
-                set_fs(get_ds());
+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);
 
-               result = _recvfrom(sock, (void *)peek_buf, 1, 1,
-                                             MSG_PEEK, NULL, NULL);
+       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);
 
-                while ((result != -EAGAIN) && (peek_buf[0] == 0x85)) {
+       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));
 
-                        /* got SESSION KEEP ALIVE */
-                        result = _recvfrom(sock, (void *)peek_buf,
-                                                     4, 1, 0, NULL, NULL);
+       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;
+}
 
-                        DDPRINTK("smb_data_callback:"
-                                 " got SESSION KEEP ALIVE\n");
+int
+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_dont_catch_keepalive: "
+                      "did not get valid server!\n");
+               return -EINVAL;
+       }
+       sock = &(inode->u.socket_i);
 
-                        if (result == -EAGAIN)
-                                break;
+       if (sock->type != SOCK_STREAM)
+       {
+               printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n");
+               return -EINVAL;
+       }
+       sk = (struct sock *) (sock->data);
 
-                        result = _recvfrom(sock, (void *)peek_buf,
-                                                     1, 1, MSG_PEEK,
-                                                     NULL, NULL);
+       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;
+}
 
-                set_fs(fs);
+static int
+smb_send_raw(struct socket *sock, unsigned char *source, int length)
+{
+       int result;
+       int already_sent = 0;
 
-                if (result != -EAGAIN) {
-                        wake_up_interruptible(sk->sleep);
-                }
+       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;
 }
 
-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);
-
-        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;
-}
-                
-int
-smb_dont_catch_keepalive(struct smb_server *server)
+static int
+smb_receive_raw(struct socket *sock, unsigned char *target, 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_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;
 }
 
-/*
- * 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_get_length(struct socket *sock, unsigned char *header)
 {
-        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. */
-
-
- re_recv:
+       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)
+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;
-
-        *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;
-}
+       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;
+
+       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);
 
-static inline 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);
+       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;
+
+       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;
-
-        if (sock == NULL)
-                return -EINVAL;
+       struct socket *sock = server_sock(server);
+       int result;
 
-        result = sock->ops->release(sock, NULL);
-        DPRINTK("smb_release: sock->ops->release = %d\n", result);
+       if (sock == NULL)
+       {
+               return -EINVAL;
+       }
+       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;
 
-        len = smb_len(buffer) + 4;
+       unsigned char padding[4] =
+       {0,};
+       char *p;
 
-       old_mask = current->blocked;
-       current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
-       fs = get_fs();
-       set_fs(get_ds());
+       struct iovec iov[4];
+       struct msghdr msg;
 
-        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 ((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);
-
-       return result;
+       if ((bcc + oparam) > server->max_xmit)
+       {
+               return -ENOMEM;
+       }
+       p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
+
+       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 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;
 }
index 80f6c484e291cd6d2c0d57c053f9942b0b7fa770..0d0a332519b310788cb7ab1801cd1cd7a60d793f 100644 (file)
@@ -101,7 +101,7 @@ struct termios {
 #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 @@ struct termios {
 #define  B38400        0000017
 #define EXTA B19200
 #define EXTB B38400
-#define CBAUDEX 0000020
+#define CBAUDEX 0000000
 #define  B57600   00020
 #define  B115200  00021
 #define  B230400  00022
index 0a099ff1718a3ad6cdbc9d636cdde5a7205ee9b8..d600403c8d83336f6b3f79a0ba0d984faa861277 100644 (file)
@@ -108,8 +108,7 @@ struct icmpv6hdr {
  *     constants for (set|get)sockopt
  */
 
-#define RAW_CHECKSUM                   1
-#define ICMPV6_FILTER                  256
+#define ICMPV6_FILTER                  1
 
 /*
  *     ICMPV6 filter
index 10799419b0af8db31ae78a906f4475324bd4c2f3..ffa226a62c3290912bd8679609c62448d84ec7de 100644 (file)
@@ -106,7 +106,7 @@ struct ifreq
                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 @@ struct ifreq
 #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.
index 5e8b14bf95678943540dfe1d5649467c8d511312..781d7339d6308456230c15eece0e258b7fbfb6ec 100644 (file)
@@ -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 @@ struct ipv6_mreq {
 
 #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
index 417b0fac890c9149429e8a9c634a2f7827415fe8..ef93e022b3fbafdad61fd8dc8d7d1d83e5c7a498 100644 (file)
@@ -35,7 +35,7 @@ struct in6_rtmsg {
        __u16                   rtmsg_metric;
        unsigned long           rtmsg_info;
         __u32                  rtmsg_flags;
-       char                    rtmsg_device[16];
+       int                     rtmsg_ifindex;
 };
 
 #endif
index b4afe779f60b9b375215298848923ee0a5e3de3a..5eebb8a7baa57a852aecc94a8496492e987d3b2a 100644 (file)
@@ -209,7 +209,7 @@ extern int sync_dquots(kdev_t dev, short type);
 
 #else
 
-#include <sys/cdefs.h>
+# /* nodep */ include <sys/cdefs.h>
 
 __BEGIN_DECLS
 int quotactl __P ((int, const char *, int, caddr_t));
index fbf3cec72af40d1ce6680cddbe26928ecb00acf0..bf677b2e042c6c1cfb735b29a16fc704ed5cfe2b 100644 (file)
@@ -80,5 +80,6 @@ struct netlink_rtinfo
 #define RTMSG_NEWDEVICE                0x11
 #define RTMSG_DELDEVICE                0x12
 
+#define RTMSG_AR_FAILED                0x21    /* Address Resolution failed    */
 #endif /* _LINUX_ROUTE_H */
 
index da7763da33186cbd82049b0d912a629c231f0156..57302ca98dde5d85c9616fa4a4378b6c76064af8 100644 (file)
@@ -125,6 +125,8 @@ struct sk_buff
        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
index f54894b045473a458a4a0927071676c76456f905..1bba4859e7f41be2dcee71c73e0a04bc2932c889 100644 (file)
@@ -28,26 +28,53 @@ typedef unsigned short word;
 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 @@ struct smb_dskattr {
  * 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__ */
index cd7775864e5a188d7a537ed22fca3ebc4d1824bc..c129cb54035e24938c7791b948c5e07fc9ccada1 100644 (file)
@@ -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>
 #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 @@ smb_kfree_s(void *obj, int size)
 #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 @@ int smb_conn_is_valid(struct smb_server *server);
 /* 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 @@ int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo,
                   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 @@ int smb_request_write_raw(struct smb_server *server,
                           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);
index c8659dba76f119c832cac42c89e7ddf557742a53..863062022def236e4ae057c000475829385bea2d 100644 (file)
@@ -25,7 +25,7 @@ struct smb_server {
                                               protocols. */
        struct wait_queue *wait;
 
-       word               max_xmit;
+       __u32              max_xmit;
        char               hostname[256];
        word               pid;
        word               server_uid;
@@ -38,6 +38,8 @@ struct smb_server {
 
         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 @@ struct smb_server {
         /* The following are LANMAN 1.0 options transferred to us in
            SMBnegprot */
         word   secmode;
-        word   maxxmt;
         word   maxmux;
         word   maxvcs;
         word   blkmode;
index 994475be791b92512a1e7a1b438c9a6140a50d99..7f17487314c7eb0f5709d2bfa666eed7adae38ef 100644 (file)
@@ -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 @@ struct smb_mount_data {
 
         char username[64];
        char password[64];
+       char domain[64];
 
        unsigned short max_xmit;
 
index 12a8ae45e74f2033646aff740b1b7689b5c60733..3ec71128e3010e7f8899318eee16462b9f9179d8 100644 (file)
@@ -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         */
index 47ee2b18d8f95c7012f6678d186070ed27f5b8e7..6cf5c05b36b81f5b79f2e4d9dcd75a9899c93365 100644 (file)
@@ -82,9 +82,8 @@ struct cdrom_device_ops {
 #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
index 1ea3930d989a3d001f5c3f55469bbf821eb70edf..03f9982bde2964de968ab58715b8fefc61c29ff0 100644 (file)
@@ -51,6 +51,7 @@ extern int                    addrconf_notify(struct notifier_block *this,
 
 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, 
index 29972d616b4c22f68e4f194383356af88fb6b35a..aaa1ba0a2af21242eb784ebef53fe8a454d7546f 100644 (file)
@@ -156,8 +156,8 @@ extern int                  fib6_del_rt(struct rt6_info *rt);
 
 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
  */
index 055aae19cb17bd970f198aab0eadbdee0692cc2e..eeb364159e765e2927b813fd6490b6c0e23012cf 100644 (file)
@@ -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>
index 310afe82f5dcc96cf358558deaaa092c26bcd131..3612aec085493dc96ab3c2b1776130aab2b574bd 100644 (file)
@@ -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>
 #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 aha1542_setup(char *str, int *ints);
 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);
@@ -321,6 +324,12 @@ struct {
 #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},
 #endif
index dbe0c43c9071df14931cd4618d877d828e206a0b..8685b38f8779a19abb3080a119295d3ddfcf7f02 100644 (file)
@@ -12,7 +12,9 @@ ethernet              alan@lxorguk.ukuu.org.uk
 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.
index b0c16dabe04acbcf8e74f4f7db6c9ef97797ea15..3ef1c3fdf0a6fb768af04955a38ae4708fde0fda 100644 (file)
@@ -790,12 +790,8 @@ int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama
 {
        int queued = 0, frametype, ns, nr, pf;
        
-       if (ax25->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);
 
index 404f787a0851cb5e7f4e5896882c93178de83eda..f6ce6e00bad4df925318bd5417f7f24bb532280e 100644 (file)
@@ -85,7 +85,7 @@ static void ax25_reset_timer(ax25_cb *ax25)
 /*
  *     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)
index 12fae19038eecf8e5f34a5b0408f3a9f07e90e2e..302d210f80093d08aeaacf4233a865128c39865a 100644 (file)
@@ -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};
 
index a4c3cc6fa768364e09d4027a476e622cde1bd177..9211fa0f2b153f7409b472980c3a44f3d25ed469 100644 (file)
@@ -735,12 +735,17 @@ void kfree_skbmem(struct sk_buff *skb)
 
        /* 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 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int priority)
        {
                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 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int priority)
         
        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;
 
index c300960cc961b7eb55d15f2ab28bff9af185fe4b..6b7ec0ad42546dc160dd691c788ddae56d2f6311 100644 (file)
  *      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 @@ struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr)
        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 @@ static void sit_route_add(struct device *dev)
                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 @@ static void init_loopback(struct device *dev)
        struct inet6_dev  *idev;
        struct inet6_ifaddr * ifp;
        struct in6_rtmsg rtmsg;
-       char devname[] = "lo";
        int err;
 
        /* ::1 */
@@ -545,7 +550,7 @@ static void init_loopback(struct device *dev)
 
        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 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
        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 @@ static int addrconf_ifdown(struct device *dev)
                        if (ifa->idev == idev)
                        {
                                *bifa = ifa->lst_next;
+                               del_timer(&ifa->timer);
                                kfree(ifa);
                                ifa = *bifa;
                                continue;
@@ -870,6 +881,40 @@ int addrconf_set_dstaddr(void *arg)
        return -EINVAL;
 }
 
+/*
+ *     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
  */
@@ -1005,7 +1050,7 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
                         *  route.
                         */
 
-                       sit_route_add(dev);
+                       sit_route_add(idev);
                        break;
 
                case ARPHRD_LOOPBACK:
@@ -1018,7 +1063,7 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
                        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 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
                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 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
 
                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;
 
index 41d1c4e9001da512efbdeb86de8cfc4bb39b59eb..2609e52947c6e4e335eb17b08fdf9f50d3bf39a4 100644 (file)
@@ -550,6 +550,13 @@ static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                
                return -EINVAL;
 
+       case SIOGIFINDEX:
+               /*
+                *      This one will be moved to the generic device
+                *      layer in the near future
+                */
+               return addrconf_get_ifindex((void *) arg);
+               
        case SIOCSIFADDR:
                return addrconf_add_ifaddr((void *) arg);
        case SIOCSIFDSTADDR:
index 2af3ceae978218727552476a5e62792163d129e2..e68990a0f6fd828615374ac0f5c5a158e0065b49 100644 (file)
@@ -859,10 +859,15 @@ int ipv6_route_add(struct in6_rtmsg *rtmsg)
 {
        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 @@ int ipv6_route_del(struct in6_rtmsg *rtmsg)
 
                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_rt_timeout(struct fib6_node *fn, void *arg)
        }
 }
 
+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 @@ int ipv6_route_ioctl(unsigned int cmd, void *arg)
                                             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 @@ void ipv6_route_init(void)
 {
 #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 @@ static int rt6_msgrcv(int unit, struct sk_buff *skb)
 }
 
 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 @@ void rt6_sndmsg(__u32 type, struct in6_addr *dst, struct in6_addr *gw,
 
        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))
index e004417fc6bb2eec5e7d93fd5b3be307cdf28028..31d50a5b5044cc353936da25a9b223d8854d6dcb 100644 (file)
@@ -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 @@ void ndisc_send_na(struct device *dev, struct neighbour *neigh,
        if (skb == NULL)
        {
                printk(KERN_DEBUG "send_na: alloc skb failed\n");
+               return;
        }
 
        skb->free=1;
@@ -737,6 +739,7 @@ void ndisc_send_rs(struct device *dev, struct in6_addr *saddr,
        if (skb == NULL)
        {
                printk(KERN_DEBUG "send_ns: alloc skb failed\n");
+               return;
        }
 
        skb->free=1;
@@ -1296,29 +1299,40 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        {
                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)
index 2b819c290ac1a3a4f768295a67dbf1ac81a1f0c1..bab6514d61674d190f161476ffaf524ddea7e7c3 100644 (file)
@@ -386,6 +386,9 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
                                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 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
        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;
index b3732441e3f47a1ada4b59273d703f3245ec5738..85d28a114b8d4aec1a093a94567cd28ceaabe9db 100644 (file)
@@ -315,14 +315,8 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
        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);
 
index ac91b1a0e22c35699c15f4b0f91831fe2cbdea4a..0149851fd41c53dde52419c80799434b676de4b6 100644 (file)
@@ -80,7 +80,7 @@ static void nr_reset_timer(struct sock *sk)
 /*
  *     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)
index c5280efa64d041d58ad17a2a61f732e82cfca3d0..4b8acd3f8385f0bfe9f1a458df2321896b389347 100644 (file)
@@ -1263,12 +1263,12 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
        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 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        /* 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;
                }
 
index 4aabfdc1eed8de70993181827055f2b1f2453bd4..20374dbb10f01b13a9945562cdcb292237500fa7 100644 (file)
@@ -303,14 +303,8 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
        int queued = 0, frametype, ns, nr, q, d, m;
        
-       if (sk->protinfo.rose->state == ROSE_STATE_0 && 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);
 
index 8f513b250c55e7de5e4afc7c7db3d293967bd598..d0bf308f0b2505ded120bb0bbc0bc56008e9591d 100644 (file)
@@ -79,9 +79,9 @@ static void rose_link_reset_timer(struct rose_neigh *neigh)
 }
 
 /*
- *     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)
index ca960480f1168e423153a58d420e845d653bc527..3137568475f2b732714911123d604992265d3dd4 100644 (file)
@@ -78,9 +78,9 @@ static void rose_reset_timer(struct sock *sk)
 }
 
 /*
- *     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)
index fc2608113cb1fbc183af069fa62e06f824da3839..43140b0a74c607e7befd911716817ff44d351473 100644 (file)
@@ -26,15 +26,20 @@ static void handle_include(int type, char *name, int len)
        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;