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)
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
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
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
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
*************************************************
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
================
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
==========
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
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
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
%
\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
\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}
\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}
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
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
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
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
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
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
-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
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 13
+SUBLEVEL = 14
ARCH = i386
# 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
#
static inline void alphapc164_fixup(void)
{
+ extern int SMCInit(void);
char irq_tab[7][5] = {
/*
* int intA intB intC intD
};
common_fixup(5, 11, 5, irq_tab, 0);
+
+ SMCInit();
}
/*
}
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 */
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)
* -- 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
*
*/
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)) {
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;
}
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;
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);
/* 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;
}
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:
}
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;
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;
}
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:
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)
| ((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;
}
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)
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));
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) {
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));
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
}
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:
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;
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);
}
| ((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)
#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));
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
}
#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
**********************
+ 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";
/**************************************************************************/
+/* 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?"
#endif
#ifndef ARCNET_DEBUG
-#define ARCNET_DEBUG (D_NORMAL)
+#define ARCNET_DEBUG (D_NORMAL|D_EXTRA)
#endif
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
/* 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 */
#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
* 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.
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");
}
continue;
}
- if (inb(STATUS) == 0xFF)
+ if (ARCSTATUS == 0xFF)
{
BUGMSG2(D_INIT_REASONS,"(empty)\n");
BUGMSG(D_INIT_REASONS,"Stage 1: ");
continue;
}
- inb(RESET); /* begin resetting card */
+ ARCRESET; /* begin resetting card */
BUGMSG2(D_INIT_REASONS,"\n");
BUGMSG(D_INIT_REASONS,"Stage 1: ");
numprint=0;
for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
{
- volatile u_char *cptr;
-
+ u_long ptr;
+
numprint++;
if (numprint>8)
{
}
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];
* 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: ");
BUGMSG2(D_INIT,"%Xh ",*port);
ioaddr=*port;
- status=inb(STATUS);
+ status=ARCSTATUS;
if ((status & 0x9D)
!= (NORXflag|RECONflag|TXFREEflag|RESETflag))
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",
* 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)
#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;
}
else
{
- BUGMSG2(D_INIT_REASONS,"%Xh-", *cptr);
+ BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
}
}
/* 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;
{
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));
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");
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;
}
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;
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 */
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)
{
* 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)
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;
/* 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 */
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)
{
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)
{
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
- outb(NOTXcmd,COMMAND);
+ ACOMMAND(NOTXcmd);
}
if (lp->outgoing.skb)
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;
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++;
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;
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++;
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)
{
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
#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;
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)
{
}
/* start sending */
- outb(TXcmd|(lp->txready<<3),COMMAND);
+ ACOMMAND(TXcmd|(lp->txready<<3));
lp->stats.tx_packets++;
lp->txready=0;
/* 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;
}
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)
{
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;
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;
}
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
- outb(CFLAGScmd|CONFIGclear,COMMAND);
+ ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
#ifdef SHOW_RECONFIGS
} 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 */
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;
if (saddr==0)
{
BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
- inb(STATUS));
+ ARCSTATUS);
lp->stats.rx_errors++;
return;
}
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",
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
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
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;
#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 */
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++;
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 */
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.
||
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)
#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 */
/*
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,
#define BusLogic_DriverVersion "2.0.6"
-#define BusLogic_DriverDate "19 October 1996"
+#define BusLogic_DriverDate "1 December 1996"
#include <linux/module.h>
*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
/*
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
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
/*
* 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",
#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
#define LOCKED 2
#define IN_RESET 3
#define IGNORE 4
-#define NO_IRQ 0xff
#define NO_DMA 0xff
#define MAXLOOP 200000
#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
/* 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];
};
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 */
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 {
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)
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;
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 };
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 */
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",
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;
}
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;
}
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;
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;
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;
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)
}
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;
/* 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];
}
int eata2x_abort(Scsi_Cmnd *SCarg) {
- unsigned int i, j, flags;
+ unsigned long flags;
+ unsigned int i, j;
save_flags(flags);
cli();
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;
}
}
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;
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;
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;
#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 { \
NULL, \
"EATA/DMA 2.0x rev. " EATA_VERSION " ", \
eata2x_detect, \
- NULL, /* Release */ \
+ eata2x_release, \
NULL, \
NULL, \
eata2x_queuecommand, \
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:
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);
}
/* ----------------------------------------------------------------------- */
+/* 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)
{
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);
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);
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);
case CDROMREADTOCHDR:
{
- struct cdrom_tochdr tochdr;
+ struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
char * buffer;
sr_cmd[0] = SCMD_READ_TOC;
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;
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;
}
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;
/* 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 */
case CDROMVOLREAD:
{
char * buffer;
- struct cdrom_volctrl volctrl;
+ struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
/* Get the current params */
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;
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:
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:
/*
* 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.
*/
#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
#define LOCKED 2
#define IN_RESET 3
#define IGNORE 4
-#define NO_IRQ 0xff
#define NO_DMA 0xff
#define MAXLOOP 200000
#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 */
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 {
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)
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;
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) */
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;
}
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;
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) {
}
}
+ 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,
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;
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");
}
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[] = {
/* 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;
}
int u14_34f_abort(Scsi_Cmnd *SCarg) {
- unsigned int i, j, flags;
+ unsigned long flags;
+ unsigned int i, j;
save_flags(flags);
cli();
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;
}
}
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;
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;
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;
#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 */ \
NULL, \
"UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
u14_34f_detect, \
- NULL, /* Release */ \
+ u14_34f_release, \
NULL, \
NULL, \
u14_34f_queuecommand, \
#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
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))
{
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
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))
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 == '/')
*cp++ = '\0';
if (*cp)
i_arg = cp;
+ strcpy (interp, i_name_start);
/*
* OK, we've parsed out the interpreter name and
* (optional) argument.
}
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);
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);
}
/*
* 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 */
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,
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;
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;
}
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;
}
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;
}
/*
* 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;
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
{
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
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)
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;
}
}
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 */
/*
* 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>
#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 *);
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
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;
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;
copy_to_user(buf, &tmp, bufsiz);
}
-/* DO MORE */
int
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);
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
}
/*
* 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;
}
}
/*
* 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;
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 */
/* 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;
/*
* 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++;
+ }
}
/*****************************************************************************/
/* */
/*****************************************************************************/
-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;
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;
}
/* 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 */
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);
}
/* 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));
}
/*****************************************************************************/
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 &&
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;
}
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
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
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
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);
}
/*****************************************************************************/
int
-smb_proc_open(struct smb_server *server, const char *pathname, int len,
- struct smb_dirent *entry)
+smb_proc_open(struct smb_server *server,
+ struct smb_inode_info *dir, const char *name, int len,
+ struct smb_dirent *entry)
{
int error;
- char* p;
- char* buf = server->packet;
+ char *p;
+ char *buf;
const word o_attr = aSYSTEM | aHIDDEN | aDIR;
- DPRINTK("smb_proc_open: path=%s\n", pathname);
+ DPRINTK("smb_proc_open: name=%s\n", name);
- smb_lock_server(server);
+ smb_lock_server(server);
+ buf = server->packet;
if (entry->opened != 0)
{
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
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;
}
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
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
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;
}
/* */
/*****************************************************************************/
-struct smb_prots {
+struct smb_prots
+{
enum smb_protocol prot;
const char *name;
};
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.
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";
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);
strcpy(p, OS_id);
p += strlen(p) + 1;
strcpy(p, client_id);
- } else {
+ } else
+ {
smb_setup_header(server, SMBsesssetupX, 10,
2 + userlen + passlen);
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 */
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
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 */
/*
* sock.c
*
- * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
*
*/
#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>
#include <linux/smb.h>
#include <linux/smbno.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
_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;
}
#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
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
-#define CBAUDEX 0000020
+#define CBAUDEX 0000000
#define B57600 00020
#define B115200 00021
#define B230400 00022
* constants for (set|get)sockopt
*/
-#define RAW_CHECKSUM 1
-#define ICMPV6_FILTER 256
+#define ICMPV6_FILTER 1
/*
* ICMPV6 filter
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 */
#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.
* 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
#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
__u16 rtmsg_metric;
unsigned long rtmsg_info;
__u32 rtmsg_flags;
- char rtmsg_device[16];
+ int rtmsg_ifindex;
};
#endif
#else
-#include <sys/cdefs.h>
+# /* nodep */ include <sys/cdefs.h>
__BEGIN_DECLS
int quotactl __P ((int, const char *, int, caddr_t));
#define RTMSG_NEWDEVICE 0x11
#define RTMSG_DELDEVICE 0x12
+#define RTMSG_AR_FAILED 0x21 /* Address Resolution failed */
#endif /* _LINUX_ROUTE_H */
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
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
* 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__ */
#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 */
#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);
/* 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,
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);
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);
protocols. */
struct wait_queue *wait;
- word max_xmit;
+ __u32 max_xmit;
char hostname[256];
word pid;
word server_uid;
unsigned short rcls; /* The error codes we received */
unsigned short err;
+
+ __u32 packet_size;
unsigned char * packet;
enum smb_conn_state state;
/* The following are LANMAN 1.0 options transferred to us in
SMBnegprot */
word secmode;
- word maxxmt;
word maxmux;
word maxvcs;
word blkmode;
/*
* smb_mount.h
*
- * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke
*
*/
#include <linux/types.h>
#include <linux/in.h>
-#define SMB_MOUNT_VERSION 4
+#define SMB_MOUNT_VERSION 5
struct smb_mount_data {
int version;
char username[64];
char password[64];
+ char domain[64];
unsigned short max_xmit;
#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 */
#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
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,
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
*/
#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>
*/
#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.
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);
#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
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.
{
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);
/*
* 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)
#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};
/* 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);
}
{
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
{
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;
* 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>
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;
rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_UP;
}
- strcpy(rtmsg.rtmsg_device, dev->name);
+ rtmsg.rtmsg_ifindex = idev->if_index;
err = ipv6_route_add(&rtmsg);
struct inet6_dev *idev;
struct inet6_ifaddr * ifp;
struct in6_rtmsg rtmsg;
- char devname[] = "lo";
int err;
/* ::1 */
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;
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;
if (ifa->idev == idev)
{
*bifa = ifa->lst_next;
+ del_timer(&ifa->timer);
kfree(ifa);
ifa = *bifa;
continue;
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
*/
* route.
*/
- sit_route_add(dev);
+ sit_route_add(idev);
break;
case ARPHRD_LOOPBACK:
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:
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;
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;
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:
{
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);
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;
}
}
}
+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;
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;
{
#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
}
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)
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))
* Changes:
*
* Lars Fenneberg : fixed MTU setting on receipt
- * of an RA.
+ * of an RA.
*
+ * Janos Farkas : kmalloc failure checks
*/
/*
if (skb == NULL)
{
printk(KERN_DEBUG "send_na: alloc skb failed\n");
+ return;
}
skb->free=1;
if (skb == NULL)
{
printk(KERN_DEBUG "send_ns: alloc skb failed\n");
+ return;
}
skb->free=1;
{
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)
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);
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;
{
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);
/*
* 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)
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: {
/* 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;
}
{
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);
}
/*
- * 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)
}
/*
- * 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)
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;