S: Pittsburgh, Pennsylvania 15237-5829
S: USA
+N: Eddie C. Dost
+E: ecd@skynet.be
+D: Linux/Sparc kernel hacker
+D: New Linux/Sparc maintainer (while davem is at SGI)
+S: Rue de la Chapelle 51
+S: 4850 Moresnet
+S: Belgium
+
N: Thomas Dunbar
E: tdunbar@vtaix.cc.vt.edu
D: TeX & METAFONT hacking/maintenance
N: Kai Harrekilde-Petersen
E: khp@dolphinics.no
-W: http://www.pip.dknet.dk/~pip93
-D: ftape-HOWTO, i82078 fdc detection code, various ftape related stuff.
-S: Dolphin Interconnect Solutions A/S
-S: P.O. Box 70, Borgerud
-S: N-0621 Oslo
+W: http://www.dolphinics.no/~khp
+P: 1024/D2CDF895 F6 33 E0 4E 01 17 85 8C 4F 7F 1F F8 14 E7 86 1D
+D: ftape-HOWTO, i82078 fdc detection code, ftape maintainer.
+S: Peder Holters vei 13
+S: 1168 Oslo
S: Norway
N: Andrew Haylett
S: D-52056 Aachen
S: Germany
+N: Nigel Metheringham
+E: Nigel.Metheringham@ThePLAnet.net
+D: IP Masquerading work and minor fixes
+S: Planet Online
+S: The White House, Melbourne Street, LEEDS
+S: LS2 7PS, UK
+P: 1024/31455639 B7 99 BD B8 00 17 BD 46 C1 15 B8 AB 87 BC 25 FA
+
N: Craig Metz
E: cmetz@tjhsst.edu
D: Some of PAS 16 mixer & PCM support
N: Kai Petzke
E: wpp@marie.physik.tu-berlin.de
+W: http://physik.tu-berlin.de/~wpp
+P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1
D: Driver for Laser Magnetic Storage CD-ROM
-D: Some kernel bug fixes, new swapping routine
+D: Some kernel bug fixes
D: Port of the database Postgres
-S: Stresemannstr. 62
-S: 10963 Berlin
+D: "Unix fuer Jedermann" a German introduction to linux (see my web page)
+S: M"ullerstr. 69
+S: 13349 Berlin
S: Germany
N: Ken Pizzini
S: 00980 Helsinki
S: Finland
+N: Eric Schenk
+E: schenk@cs.toronto.edu
+D: Random kernel debugging.
+D: SYSV Semaphore code rewrite.
+D: Network layer debugging.
+D: Dial on demand facility (diald).
+S: 7 Borden Street
+S: Toronto, Ontario
+S: Canada M5S 2M8
+
N: Peter De Schrijver
E: stud11@cc4.kuleuven.ac.be
D: Mitsumi CD-ROM driver patches March version
and was originally written and maintained by Alessandro Sigala
(ssigala@globalnet.it).
-Last updated: May 20, 1996.
+ There is now a web page based on this material, thanks to John
+Taylor. Check out http://www.cviog.uga.edu/LinuxBleed.html if you
+prefer a HTML-ized shopping list.
+
+Last updated: June 1, 1996.
Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
Current Releases
- Linux C++ Library 2.7.1.4
- Termcap 2.0.8
- Procps 0.99a
-- Gpm 1.06
+- Gpm 1.09
- SysVinit 2.60
- Util-linux 2.5
Network errors with recent kernels
==================================
- Many default network scripts are set up add a route to the localhost
-at 127.0.0.1 at startup. However, they do this incorrectly. To fix
-the error, which is now spotted by the kernel, look for a line like
-`route add -net 127.0.0.1' in your network configuration files and
-change it to `route add -net 127.0.0.0'.
+ Many default network scripts are set up to add a route to the
+localhost at 127.0.0.1 at startup. However, they do this incorrectly.
+To fix the error, which is now spotted by the kernel (causing many
+daemons to quit working), look for a line like `route add -net
+127.0.0.1' in your network configuration files and change it to `route
+add -net 127.0.0.0'.
+
+ This error is present in all Red Hat distributions (and derivative
+distributions like Caldera). If you're running one of these, edit
+/etc/sysconfig/network-scripts/ifup-lo, changing the line `route add
+-net $(IPADDR)' to `route add -net 127.0.0.0' and you should be fine.
The Linux C Library
===================
Another little tip: you can't have both a.out *and* ELF support
compiled as modules. Otherwise, you get a nice Catch-22 when you try
to run insmod to install a.out/ELF support so you can run insmod ;-).
-If you have an all-ELF system, but need a.out for the occasional
-Netscape session, then you can do a.out support as a module.
-Otherwise, you should probably leave it in the kernel, and if you
-haven't gone ELF yet, you can probably say no to ELF support.
-Similarly, any partitions that you have to mount at startup have to
-have their necessary file system and device drivers compiled into the
-kernel, so don't get grandiose ideas about going completely modular and
-then forget to compile ext2fs support and ide drive support into your
-kernel ;-).
+If you have an all-ELF system, but need a.out for the occasional legacy
+app, then you can do a.out support as a module. Otherwise, you should
+probably leave it in the kernel, and if you haven't gone ELF yet, you
+can probably say no to ELF support. Similarly, any partitions that you
+have to mount at startup have to have their necessary file system and
+device drivers compiled into the kernel, so don't get grandiose ideas
+about going completely modular and then forget to compile ext2fs
+support and ide drive support into your kernel ;-).
PPP driver
==========
fix this problem, upgrade to
ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7h.tar.gz.
+Kbd
+===
+
+ For those of you needing non-ASCII character/font support, you should
+upgrade to ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/kbd-0.91.tar.gz.
+
Console
=======
Better yet, just get the latest official Linux termcap from
ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz
+ Also, the console driver is now responsible for keeping track of
+correspondence between character codes and glyph bitmaps. If you
+encounter problems, try `loadunimap def' to get back the default
+correspondence.
+
Hdparm
======
to the latest net-tools in
ftp://ftp.inka.de:/pub/comp/Linux/networking/net-tools. The last
official release there is net-tools-1.2.0.tar.gz, and the latest
-release is net-tools-1.3.6-BETA5.tar.gz. If you need the upgrade, you
+release is net-tools-1.32-alpha.tar.gz. If you need the upgrade, you
probably need the latest beta release.
Xntpd
The sound driver was upgraded in the 1.3.x kernels, breaking vplay.
To fix this problem, get a new version of the sndkit from
-ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz
+ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz. Some users
+report that various other sound utils (cdd2wav-sbpcd, for example) need
+to be recompiled before they will work with the new kernels.
Tcsh
====
file as a file system, which can allow for all sorts of cool things
like encrypted file systems and such. To use it, you'll need a
modified version of mount from
-ftp://ftp.win.tue.nl:/pub/linux/util/mount-2.5X.tar.gz and preliminary
+ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5X.tar.gz and preliminary
work on encrypted file system support can be found in
ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz.
GNU CC: gcc -v and gcc --version
PPP: pppd -h (wrong but it show the version)
Libc: ls -l /lib/libc.so.5
-LibC++: ls -l /usr/lib/libg++.so
+Libc++: ls -l /usr/lib/libg++.so
Binutils: ld -v
ldd: ldd -v and ldd -V
termcap: ls -l /lib/libtermcap.so.*
Gpm mouse utilities
===================
-ftp://iride.unipv.it/pub/gpm/gpm-1.06.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.06.tar.gz
+ftp://iride.unipv.it/pub/gpm/gpm-1.09.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.09.tar.gz
SysVinit utilities
==================
favorite local linux mirror. If you can, please get them from a closer
site before checking sunsite.
- Also, for those of you running Red Hat, 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.
-
+ Also, for those of you running Red Hat (or RPM on a different
+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.
-isdn-utils
-==========
+Please send info about any other packages that 1.3.x "broke" or about
+any new features of 1.3.x that require extra or new packages for use to
+Chris Ricker (gt1355b@prism.gatech.edu). I generate this from a
+modified texinfo setup, so you don't need to bother generating a diff
+against the current version before you send the additional information
+to me.
-ftp://ftp.franken.de/pub/isdn4linux/isdn4k-utils-1.3.97.tar.gz
of the chipset, and permits faster I/O speeds to be set as well.
See the README.ide and ali14xx.c files for more info.
-PROMISE DC4030 support (ALPHA)
+PROMISE DC4030 support (EXPERIMENTAL)
CONFIG_BLK_DEV_PROMISE
This driver is enabled at runtime using the "ide0=dc4030" kernel
boot parameter. It enables support for the secondary IDE interface
packets it received. The information is handled by the klogd demon
which is responsible for kernel messages ("man klogd").
-IP: transparent proxying (ALPHA)
+IP: transparent proxying (EXPERIMENTAL)
CONFIG_IP_TRANSPARENT_PROXY
This enables you to redirect any network traffic to a local server,
acting as a "transparent proxy server". Redirection is activated
by defining special input firewall rules (using the ipfwadm utility)
and/or by doing an appropriate bind() system call.
-IP: masquerading (ALPHA)
+IP: masquerading (EXPERIMENTAL)
CONFIG_IP_MASQUERADE
If one of the computers on your local network for which your Linux
box acts as a firewall wants to send something to the outside, your
even if they don't have officially registered IP addresses. (This
last problem can also be solved by connecting the Linux box to the
Internet using SLiRP [SLiRP is a SLIP/PPP emulator that works if you
- have a regular dial up shell account on some UNIX computer; get if
- via ftp (user: anonymous) from
- sunsite.unc.edu:/pub/Linux/system/Network/serial/]). Details on how
- to set things up are contained in the IP Masquerading FAQ, available
- via ftp (user: anonymous) from ftp.eves.com:/pub/masq/. This is
- ALPHA code, which means that it need not be completely stable; it
- has nothing to do with the computer architecture of the same
- name. If you want this, say Y.
+ have a regular dial up shell account on some UNIX computer; get it
+ from ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/
+ Details on how to set things up are contained in the
+ IP Masquerading FAQ, available at http://www.indyramp.com/masq/
+ This is EXPERIMENTAL code, which means that it need not be completely
+ stable. If you want this, say Y.
IP: always defragment
CONFIG_IP_ALWAYS_DEFRAG
have a more reliable firewall (otherwise second and further fragments
will always be accepted by the firewall). When using transparent
proxying (CONFIG_IP_TRANSPARENT_PROXY), this option is implicit,
- although it is safe to say Y here.
+ although it is safe to say Y here. Do not say Y to this option except
+ when running either a firewall that is the sole link to your network or
+ a transparent proxy. Never ever say Y to this for a normal router or
+ host.
IP: aliasing support
CONFIG_IP_ALIAS
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The Bridging code is
still in test. If unsure, say N.
-Kernel/User network link driver(ALPHA)
+Kernel/User network link driver (EXPERIMENTAL)
CONFIG_NETLINK
This driver allows for two-way communication between certain parts
of the kernel or modules and user processes; the user processes are
directory having major mode 36. So far, the kernel uses it to
publish some network related information if you enable "Routing
messages", below. Say Y if you want to experiment with it; this is
- ALPHA code, which means that it need not be completely stable; it
- has nothing to do with the computer architecture of the same name.
+ EXPERIMENTAL code, which means that it need not be completely stable.
You need to include this if you want to use arpd, a daemon that
helps keep the internal ARP cache (a mapping between IP addresses
and hardware addresses on the local network) small. If unsure, say
Ioctl Numbers
-10 May 1996
+29 May 1996
Michael Chastain
<mec@duracef.shout.net>
(5) When following the convention, the driver code can use generic
code to call verify_area to validate parameters.
-This table is current to Linux 1.3.98.
+This table is current to Linux pre2.0.9.
-Ioctl Include File Comments
+Code Seq# Include File Comments
========================================================
-0x00 linux/fs.h only FIBMAP, FIGETBSZ
-0x02 linux/fd.h
-0x03 linux/hdreg.h
-0x04 linux/umsdos_fs.h
-0x06 linux/lp.h
-0x09 linux/md.h
-0x12 linux/fs.h
-0x20 linux/cm206.h
-0x22 linux/scc.h conflict! (version 2.01 of z8530drv)
-0x22 scsi/sg.h conflict!
-'A' linux/apm_bios.h
-'B' linux/baycom.h
-'C' linux/soundcard.h
-'F' linux/fb.h
-'I' linux/isdn.h
-'K' linux/kd.h
-'L' linux/loop.h
-'M' linux/soundcard.h
-'P' linux/soundcard.h
-'Q' linux/soundcard.h
-'R' linux/random.h
-'S' linux/cdrom.h conflict!
-'S' scsi/scsi.h conflict!
-'S' scsi/scsi_ioctl.h conflict!
-'T' linux/soundcard.h conflict!
-'T' asm/ioctls.h conflict!
-'V' linux/vt.h
-'Y' linux/cyclades.h codes in 0x004359NN
-'Z' linux/scc.h version 2.2 of z8530drv
-'a' various, see http://lrcwww.epfl.ch/linux-atm/magic.html
-'c' linux/comstats.h
-'f' linux/ext2_fs.h
-'m' linux/mtio.h conflict!
-'m' linux/soundcard.h conflict!
-'n' linux/ncp_fs.h
-'p' linux/mc146818rtc.h
-'r' linux/msdos_fs.h
-'s' linux/cdk.h
-'t' linux/if_ppp.h no conflict
-'t' linux/isdn_ppp.h no conflict
-'u' linux/smb_fs.h
-'v' linux/ext2_fs.h
-0x89 asm/sockios.h no conflict
-0x89 linux/sockios.h no conflict
+0x00 01-02 linux/fs.h conflict!
+0x00 01-04 scsi/scsi_ioctl.h conflict!
+0x02 all linux/fd.h
+0x03 all linux/hdreg.h
+0x04 all linux/umsdos_fs.h
+0x06 all linux/lp.h
+0x09 all linux/md.h
+0x12 all linux/fs.h
+0x20 all linux/cm206.h
+0x22 all linux/scc.h conflict! (version 2.01 of z8530drv)
+0x22 all scsi/sg.h conflict!
+'A' all linux/apm_bios.h
+'B' all linux/baycom.h
+'C' all linux/soundcard.h
+'F' all linux/fb.h
+'I' all linux/isdn.h
+'K' all linux/kd.h
+'L' all linux/loop.h
+'M' all linux/soundcard.h
+'P' all linux/soundcard.h
+'Q' all linux/soundcard.h
+'R' all linux/random.h
+'S' 00-1F linux/cdrom.h
+'S' 20-7F linux/ucdrom.h
+'S' 80-81 scsi/scsi_ioctl.h
+'S' 82-FF scsi/scsi.h
+'T' all linux/soundcard.h conflict!
+'T' all asm-i386/ioctls.h conflict!
+'V' all linux/vt.h
+'Y' all linux/cyclades.h
+'Z' all linux/scc.h version 2.2 of z8530drv
+'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html
+'c' all linux/comstats.h
+'f' all linux/ext2_fs.h
+'m' all linux/mtio.h conflict!
+'m' all linux/soundcard.h conflict!
+'n' all linux/ncp_fs.h
+'p' all linux/mc146818rtc.h
+'r' all linux/msdos_fs.h
+'s' all linux/cdk.h
+'t' 00-7F linux/if_ppp.h
+'t' 80-8F linux/isdn_ppp.h
+'u' all linux/smb_fs.h
+'v' all linux/ext2_fs.h
+0x89 00-0F asm-i386/sockios.h
+0x89 10-FF linux/sockios.h
+0x90 00 linux/sbpcd.h
--- /dev/null
+$Id: README.audio,v 1.1 1996/05/19 00:07:35 fritz Exp $
+
+ISDN subsystem for Linux.
+ Description of audio mode.
+
+When enabled during kernel configuration, the tty emulator of the ISDN
+subsystem is capable of a reduced set of commands to support audio.
+This document describes the commands supported and the format of
+audio data.
+
+Commands for enabling/disabling audio mode:
+
+ AT+FCLASS=8 Enable audio mode.
+ This affects the following registers:
+ S18: Bits 0 and 3 are set.
+ S16: Set to 48 and any further change to
+ larger values is blocked.
+ AT+FCLASS=0 Disable audio mode.
+ Register 18 is set to 4.
+ AT+FCLASS=? Show possible modes.
+ AT+FCLASS? Report current mode (0 or 8).
+
+Commands supported in audio mode:
+
+All audio mode commands have the one of the following form:
+
+ AT+Vxx? Show current setting.
+ AT+Vxx=? Show possible settings.
+ AT+Vxx=v Set simple parameter.
+ AT+Vxx=v,v ... Set complex parameter.
+
+where xx is a two-character code and v are alphanumerical parameters.
+The following commands are supported:
+
+ AT+VNH=x Auto hangup settting. NO EFFECT, supported
+ for compatibility only.
+ AT+VNH? Always reporting "1"
+ AT+VNH=? Always reporting "1"
+
+ AT+VIP Reset all audio parameters.
+
+ AT+VLS=x Line select. x is one of the following:
+ 0 = No device.
+ 2 = Phone line.
+ AT+VLS=? Always reporting "0,2"
+ AT+VLS? Show current line.
+
+ AT+VRX Start recording. Emulator responds with
+ CONNECT and starts sending audio data to
+ the application. See below for data format
+
+ AT+VSD=x,y Set silence-detection parameters.
+ NO EFFECT, supported for compatibility
+ only. Possible parameters:
+ x = 0 ... 31
+ y = 0 ... 255
+ AT+VSD=? Report possible parameters.
+ AT+VSD? Show current parameters.
+
+ AT+VSM=x Select audio data format.
+ Possible parameters:
+ 2 = ADPCM-2
+ 3 = ADPCM-3
+ 4 = ADPCM-4
+ 5 = aLAW
+ 6 = uLAW
+ AT+VSM=? Show possible audio formats.
+
+ AT+VTX Start audio playback. Emulator responds
+ with CONNECT and starts sending audio data
+ received from the application via phone line.
+General behavior and description of data formats/protocol.
+ when a connection is made:
+
+ On incoming calls, if the application responds to a RING
+ with ATA, depending on the calling service, the emulator
+ responds with either CONNECT (data call) or VCON (voice call).
+
+ On outgoing voice calls, the emulator responds with VCON
+ upon connection setup.
+
+ Audio recording.
+
+ When receiving audio data, a kind of bisync protocol is used.
+ Upon AT+VRX command, the emulator responds with CONNECT, and
+ starts sending audio data to the application. There are several
+ escape sequences defined, all using DLE (0x10) as Escape char:
+
+ <DLE><ETX> End of audio data. Emulator stops
+ recording, responding with VCON.
+ <DLE><DLE> Escape sequence for DLE in data stream.
+
+ Currently unsupported DLE sequences:
+
+ <DLE>0 Touchtone "0" received.
+ ...
+ <DLE>9 Touchtone "9" received.
+ <DLE># Touchtone "#" received.
+ <DLE>* Touchtone "*" received.
+ <DLE>c FAX calling tone received.
+ <DLE>b busy tone received.
+ <DLE>q quiet. Silence detected after non-silence.
+ <DLE>s silence. Silence dectected from the
+ start of recording.
+
+ Any character sent by the application, except XON (0x11) or XOFF (0x13)
+ immediately stops recording.
+
+ Audio playback.
+
+ When sending audio data, upon AT+VTX command, emulator responds with
+ CONNECT, and starts transfering data from application to the phone line.
+ The same DLE sequences apply to this mode.
+
+
Tel: +49 931 2877950
Fax: +49 931 2877951
-email uhl@think.de
+email info@think.de
WWW http:/www.think.de
Additional FRAD device drivers can be added as hardware is available.
+At this time, the dlcicfg and fradcfg programs have not been incorporated into
+the net-tools distribution. They can be found at ftp.invlogic.com, in
+/pub/linux. Note that with OS/2 FTPD, you end up in /pub by default, so just
+use 'cd linux'. v0.10 is for use on pre-2.0.3 and earlier, v0.15 is for
+pre-2.0.4 and later.
+
FTAPE/QIC-117:
P: Kai Harrekilde-Petersen
M: khp@dolphinics.no
+W: http://www.dolphinics.no/~khp/ftape.html
L: linux-tape@vger.rutgers.edu
S: Maintained
S: Maintained
SPARC:
-P: David S. Miller
-M: davem@caip.rutgers.edu
+P: Eddie C. Dost
+M: ecd@skynet.be
L: sparclinux@vger.rutgers.edu
S: Maintained
VERSION = 1
PATCHLEVEL = 99
-SUBLEVEL = 9
+SUBLEVEL = 10
ARCH = i386
"make zlilo" if you have lilo installed to suit the kernel makefiles,
but you may want to check your particular lilo setup first.
+ - if you configured any of the parts of the kernel as `modules', you
+ will have to do "make modules" followed by "make modules_install".
+ Read Documentation/modules.txt for more information. For example,
+ an explanation of how to use the modules is included there.
+
- keep a backup kernel handy in case something goes wrong. This is
especially true for the development releases, since each new release
contains new code which has not been debugged.
CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_UFS_FS is not set
#
# Character devices
# CONFIG_STALDRV is not set
# CONFIG_RISCOM8 is not set
# CONFIG_PRINTER is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_PSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_FTAPE is not set
register unsigned long edx asm("dx");
unsigned long tmp, quotient, low_timer, missing_time;
- /* Last jiffie when do_fast_gettimeoffset() was called.. */
+ /* Last jiffy when do_fast_gettimeoffset() was called.. */
static unsigned long last_jiffies=0;
/* Cached "clocks per usec" value.. */
static unsigned long cached_quotient=0;
- /* The "clocks per usec" value is calculated once each jiffie */
+ /* The "clocks per usec" value is calculated once each jiffy */
tmp = jiffies;
quotient = cached_quotient;
low_timer = last_timer_cc.low;
static unsigned long jiffies_p = 0;
/*
- * cache volatile jiffies temporaly, we have IRQs turned off.
+ * cache volatile jiffies temporarily; we have IRQs turned off.
*/
unsigned long jiffies_t;
The floppy driver is configured using the 'floppy=' option in
lilo. This option can be typed at the boot prompt, or entered in the
lilo configuration file.
- Example: If your kernel is called linux-72, type the following line
+ Example: If your kernel is called linux-pre2.0.9, type the following line
at the lilo boot prompt (if you have a thinkpad):
- linux-72 floppy=thinkpad
+ linux-pre2.0.9 floppy=thinkpad
You may also enter the following line in /etc/lilo.conf, in the description
-of linux-72:
+of linux-pre2.0.9:
append = "floppy=thinkpad"
Several floppy related options may be given, example:
- linux-72 floppy=daring floppy=two_fdc
+ linux-pre2.0.9 floppy=daring floppy=two_fdc
append = "floppy=daring floppy=two_fdc"
If you give options both in the lilo config file and on the boot
restore the default behavior.
If you use the floppy driver as a module, use the following syntax:
- insmod floppy floppy="<options>"
+ insmod floppy 'floppy="<options>"'
Example:
- insmod floppy floppy="daring two_fdc"
+ insmod floppy 'floppy="daring two_fdc"'
Note that in this case 'floppy=' should only be typed out once, and
not once for each option. You need at least modules-1.3.57 for this
method. However, the older environment variable based syntax is still
-available: floppy="daring two_fdc" insmod floppy
+available:
+(sh syntax): floppy="daring two_fdc" insmod floppy
+(csh syntax): setenv floppy "daring two_fdc" ; insmod floppy
+
+ Some versions of insmod are buggy in one way or another. If you have
+any problems (options not being passed correctly, segfaults during
+insmod), first check whether there is a more recent version. If there
+isn't, use the old method using environment variables.
The floppy related options include:
#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
+#define INT_OFF save_flags(flags); cli()
+#define INT_ON restore_flags(flags)
+
/* read/write */
#define COMMAND raw_cmd->cmd[0]
#define DR_SELECT raw_cmd->cmd[1]
{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
- { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"CompaQ"}, /* 9 2.88MB 3.5" */
+ { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120"}, /* 9 3.12MB 3.5" */
{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
{ 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
/* locks the driver */
static int lock_fdc(int drive, int interruptible)
{
+ unsigned long flags;
+
if (!usage_count){
printk("trying to lock fdc while usage count=0\n");
return -1;
}
floppy_grab_irq_and_dma();
- cli();
+ INT_OFF;
while (fdc_busy && NO_SIGNAL)
interruptible_sleep_on(&fdc_wait);
if (fdc_busy){
- sti();
+ INT_ON;
return -EINTR;
}
fdc_busy = 1;
- sti();
+ INT_ON;
command_status = FD_COMMAND_NONE;
reschedule_timeout(drive, "lock fdc", 0);
set_fdc(drive);
static void floppy_disable_hlt(void)
{
unsigned long flags;
- save_flags(flags);
- cli();
+
+ INT_OFF;
if (!hlt_disabled){
hlt_disabled=1;
#ifdef HAVE_DISABLE_HLT
disable_hlt();
#endif
}
- restore_flags(flags);
+ INT_ON;
}
static void floppy_enable_hlt(void)
{
unsigned long flags;
- save_flags(flags);
- cli();
+
+ INT_OFF;
if (hlt_disabled){
hlt_disabled=0;
#ifdef HAVE_DISABLE_HLT
enable_hlt();
#endif
}
- restore_flags(flags);
+ INT_ON;
}
static void setup_DMA(void)
{
+ unsigned long flags;
+
#ifdef FLOPPY_SANITY_CHECK
if (raw_cmd->length == 0){
int i;
return;
}
#endif
- cli();
+ INT_OFF;
fd_disable_dma();
fd_clear_dma_ff();
fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?
fd_set_dma_count(raw_cmd->length);
virtual_dma_port = FDCS->address;
fd_enable_dma();
- sti();
+ INT_ON;
floppy_disable_hlt();
}
static int wait_til_done(void (*handler)(void), int interruptible)
{
int ret;
+ unsigned long flags;
floppy_tq.routine = (void *)(void *) handler;
queue_task(&floppy_tq, &tq_timer);
- cli();
+ INT_OFF;
while(command_status < 2 && NO_SIGNAL){
is_alive("wait_til_done");
if (interruptible)
cancel_activity();
cont = &intr_cont;
reset_fdc();
- sti();
+ INT_ON;
return -EINTR;
}
- sti();
+ INT_ON;
if (FDCS->reset)
command_status = FD_COMMAND_ERROR;
raw_cmd = 0;
- sti();
-
if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
printk("Unable to get major %d for floppy\n",MAJOR_NR);
return -EBUSY;
static int floppy_grab_irq_and_dma(void)
{
int i;
- cli();
+ unsigned long flags;
+
+ INT_OFF;
if (usage_count++){
- sti();
+ INT_ON;
return 0;
}
- sti();
+ INT_ON;
MOD_INC_USE_COUNT;
for (i=0; i< N_FDC; i++){
if (fdc_state[i].address != -1){
#endif
long tmpsize;
unsigned long tmpaddr;
+ unsigned long flags;
- cli();
+ INT_OFF;
if (--usage_count){
- sti();
+ INT_ON;
return;
}
- sti();
+ INT_ON;
MOD_DEC_USE_COUNT;
fd_disable_dma();
fd_free_dma();
* - Philips/LMS cm260 product specification
*
* David van Leeuwen, david@tm.tno.nl. */
-#define VERSION "$Id: cm206.c,v 0.99 1996/04/14 20:26:26 david Exp $"
+#define VERSION "$Id: cm206.c,v 0.99 1996/04/14 20:26:26 david Exp david $"
#include <linux/module.h>
else printk(" IRQ %d found\n", cm206_irq);
#else
reset_cm260();
+ /* Now, the problem here is that reset_cm260 can generate an
+ interrupt. It seems that this can cause a kernel oops some time
+ later. So we wait a while and `service' this interrupt. */
+ udelay(10);
+ outw(dc_normal | READ_AHEAD, r_data_control);
printk(" using IRQ %d\n", cm206_irq);
#endif
if (send_receive_polled(c_drive_configuration) != c_drive_configuration)
fi
tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
tristate 'Parallel printer support' CONFIG_PRINTER
-tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
-tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
-if [ "$CONFIG_PSMOUSE" != "n" ]; then
- bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
+
+
+bool 'Bus Mouse Support' CONFIG_MOUSE
+if [ "$CONFIG_MOUSE" = "y" ]; then
+ tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
+ tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
+ tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
+ tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+ if [ "$CONFIG_PSMOUSE" != "n" ]; then
+ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
+ fi
fi
-tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
-tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
+
bool 'Support for user misc device modules' CONFIG_UMISC
bool 'QIC-02 tape support' CONFIG_QIC02_TAPE
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
- 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
{
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
- 0x25ba, 0x25c4, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
+ 0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
===== Release notes for ftape-2.08, 14/03/96 =====
If you correct a problem with ftape, please send your patch to
-khp@pip.dknet.dk too.
+khp@dolphinics.no too.
- Updated to reflect that NR_MEM_LISTS is gone in 1.3.74
- Teac 700 added to list of known drives.
===== Release notes for ftape-2.04, 01/01/96 =====
-This version by Kai Harrekilde-Petersen <khp@pip.dknet.dk>
+This version by Kai Harrekilde-Petersen <khp@dolphinics.no>
- ALERT! Support for Kernels earlier then v1.1.85 is about to go away.
I intend to clean up some of the code (getting rid of an annoyingly
For reasons only known to the majordomo mail list processor, Bas was
kicked off the linux-tape list sometime during the summer. Being
overworked at his for-pay job, he didn't notice it much. Instead I
-(Kai, khp@pip.dknet.dk) has worked on ftape to produce the 2.04(beta)
+(Kai, khp@dolphinics.no) has worked on ftape to produce the 2.04(beta)
version.
zftape
TRACEx1(-1, " Vendor id : 0x%04x", drive_type.vendor_id);
TRACEx1(-1, " Wakeup method : %s", methods[drive_type.wake_up].name);
TRACE(-1, "And a description of your tape drive to:");
- TRACE(-1, "Kai Harrekilde-Petersen <khp@pip.dknet.dk>");
+ TRACE(-1, "Kai Harrekilde-Petersen <khp@dolphinics.no>");
TRACE(-1, "==========================================");
drive_type.speed = 500; /* deci-ips: very safe value */
} else {
TRACEx2(-1, "found: %s, expected: %s",
methods[drive_type.wake_up].name,
methods[vendors[vendor_index].wake_up].name);
- TRACE(-1, "please report this to <khp@pip.dknet.dk>");
+ TRACE(-1, "please report this to <khp@dolphinics.no>");
TRACE(-1, "==========================================");
}
}
TRACEx1(-1, "drive : %s", drive_type.name);
TRACEx2(-1, "delta time = %d, length = %d", dt, length);
TRACEx1(-1, "has max tape speed of %d ips", drive_type.speed);
- TRACE(-1, "please report this to <khp@pip.dknet.dk>");
+ TRACE(-1, "please report this to <khp@dolphinics.no>");
TRACE(-1, "==========================================");
}
/* time to go from bot to eot at normal speed (data rate):
#ifdef MODULE
printk(KERN_INFO "ftape-2.08 960314\n"
KERN_INFO " (c) 1993-1995 Bas Laarhoven (bas@vimec.nl)\n"
- KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen (khp@pip.dknet.dk)\n"
+ KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen (khp@dolphinics.no)\n"
KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n"
KERN_INFO " Compiled for kernel version %s"
#ifdef MODVERSIONS
-/* $Id: isdn_common.c,v 1.14 1996/05/18 01:36:55 fritz Exp $
+/* $Id: isdn_common.c,v 1.15 1996/05/31 01:10:54 fritz Exp $
*
* Linux ISDN subsystem, common used functions (linklevel).
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.c,v $
+ * Revision 1.15 1996/05/31 01:10:54 fritz
+ * Bugfixes:
+ * Lowlevel modules did not get locked correctly.
+ * Did show wrong revision when initializing.
+ * Minor fixes in ioctl code.
+ * sk_buff did not get freed, if error in writebuf_stub.
+ *
* Revision 1.14 1996/05/18 01:36:55 fritz
* Added spelling corrections and some minor changes
* to stay in sync with kernel.
isdn_dev *dev = (isdn_dev *) 0;
static int has_exported = 0;
-static char *isdn_revision = "$Revision: 1.14 $";
+static char *isdn_revision = "$Revision: 1.15 $";
extern char *isdn_net_revision;
extern char *isdn_tty_revision;
}
info = &dev->mdm.info[midx];
if ((info->online < 2) &&
- (info->vonline != 1)) {
+ (!(info->vonline & 1))) {
/* If Modem not listening, drop data */
isdn_trash_skb(skb, FREE_READ);
return;
}
if (info->emu.mdmreg[13] & 2)
/* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
- if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) {
-#ifdef ISDN_DEBUG_MODEM_DUMP
- isdn_dumppkt("T70strip1:", skb->data, skb->len, skb->len);
-#endif
+ if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
skb_pull(skb,4);
-#ifdef ISDN_DEBUG_MODEM_DUMP
- isdn_dumppkt("T70strip2:", skb->data, skb->len, skb->len);
-#endif
- }
/* The users field of an sk_buff is used in a special way
* with tty's incoming data:
* users is set to the number of DLE codes when in audio mode.
*/
skb->users = 0;
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline == 1) {
+ if (info->vonline & 1) {
int ifmt = 1;
/* voice conversion/compression */
switch (info->emu.vpar[3]) {
}
/* Try to find a network-interface which will accept incoming call */
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_LOCK;
+ dev->drv[di]->interface->command(&cmd);
r = isdn_net_find_icall(di, c->arg, i, c->num);
switch (r) {
case 0:
info->msr |= UART_MSR_RI;
isdn_tty_modem_result(2, info);
isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
+ return 0;
} else if (dev->drv[di]->reject_bus) {
cmd.driver = di;
cmd.arg = c->arg;
cmd.arg = c->arg;
cmd.command = ISDN_CMD_ACCEPTD;
dev->drv[di]->interface->command(&cmd);
+ return 0;
break;
case 2: /* For calling back, first reject incoming call ... */
case 3: /* Interface found, but down, reject call actively */
case 4:
/* ... then start callback. */
isdn_net_dial();
+ return 0;
}
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_UNLOCK;
+ dev->drv[di]->interface->command(&cmd);
return 0;
break;
case ISDN_STAT_CINF:
if (dev->drvmap[i] == di) {
dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
- dev->mdm.info[i].isdn_driver = -1;
- dev->mdm.info[i].isdn_channel = -1;
- isdn_info_update();
}
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ modem_info *info = &dev->mdm.info[i];
+
+ if (info->isdn_driver == di) {
+ info->isdn_driver = -1;
+ info->isdn_channel = -1;
+ if (info->online) {
+ isdn_tty_modem_result(3, info);
+ isdn_tty_modem_hup(info);
+ }
+ }
+ }
dev->drivers--;
dev->channels -= dev->drv[di]->channels;
kfree(dev->drv[di]->rcverr);
restore_flags(flags);
return ret;
}
- memcpy_tofs((char *) &cfg, src, sizeof(cfg));
+ memcpy_fromfs((char *) &cfg, src, sizeof(cfg));
src += sizeof(cfg);
if (!isdn_net_new(cfg.name, NULL)) {
restore_flags(flags);
case IIOCNETDNM:
/* Delete a phone-number of a network-interface */
if (arg) {
- memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
if ((ret = verify_area(VERIFY_READ, (void *) arg, sizeof(phone))))
return ret;
+ memcpy_fromfs((char *) &phone, (char *) arg, sizeof(phone));
return isdn_net_delphone(&phone);
} else
return -EINVAL;
int drvidx;
isdn_ctrl c;
+ MOD_DEC_USE_COUNT;
if (minor == ISDN_MINOR_STATUS) {
infostruct *p = dev->infochain;
infostruct *q = NULL;
- MOD_DEC_USE_COUNT;
while (p) {
if (p->private == (char *) &(filep->private_data)) {
if (q)
printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
return;
}
- if (!dev->channels)
- return;
- MOD_DEC_USE_COUNT;
if (minor < ISDN_MINOR_CTRL) {
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
int i;
ulong flags;
ulong features;
+ isdn_ctrl cmd;
save_flags(flags);
cli();
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
+ cmd.driver = i;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ (void) dev->drv[i]->interface->command(&cmd);
restore_flags(flags);
return i;
} else {
dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
dev->usage[i] |= usage;
isdn_info_update();
+ cmd.driver = i;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ (void) dev->drv[i]->interface->command(&cmd);
restore_flags(flags);
return i;
}
{
int i;
ulong flags;
+ isdn_ctrl cmd;
save_flags(flags);
cli();
dev->obytes[i] = 0;
isdn_info_update();
isdn_free_queue(&dev->drv[di]->rpqueue[ch]);
+ cmd.driver = di;
+ cmd.arg = ch;
+ cmd.command = ISDN_CMD_UNLOCK;
+ (void) dev->drv[di]->interface->command(&cmd);
restore_flags(flags);
return;
}
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx,
chan, skb);
+ if (ret <= 0)
+ kfree_skb(skb, FREE_WRITE);
}
if (ret > 0)
dev->obytes[isdn_dc2minor(drvidx,chan)] += ret;
if (dev->drv[drvidx]->interface->writebuf_skb)
ret = dev->drv[drvidx]->interface->
writebuf_skb(drvidx, chan, skb);
- else {
+ else {
if ((ret = dev->drv[drvidx]->interface->
- writebuf(drvidx,chan,skb->data,skb->len,0))==skb->len)
+ writebuf(drvidx,chan,skb->data,skb->len,0)) == skb->len)
dev_kfree_skb(skb, FREE_WRITE);
}
if (ret > 0)
static char *isdn_getrev(const char *revision)
{
- static char rev[20];
+ char *rev;
char *p;
if ((p = strchr(revision, ':'))) {
- strcpy(rev, p + 2);
+ rev = p + 2;
p = strchr(rev, '$');
*--p = 0;
} else
- strcpy(rev, "???");
+ rev = "???";
return rev;
}
int isdn_init(void)
{
int i;
+ char irev[50];
+ char trev[50];
+ char nrev[50];
+ char prev[50];
+ char arev[50];
sti();
if (!(dev = (isdn_dev *) kmalloc(sizeof(isdn_dev), GFP_KERNEL))) {
return -EIO;
}
memset((char *) dev, 0, sizeof(isdn_dev));
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- dev->drvmap[i] = -1;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ dev->drvmap[i] = -1;
dev->chanmap[i] = -1;
dev->m_idx[i] = -1;
strcpy(dev->num[i], "???");
tty_unregister_driver(&dev->mdm.tty_modem);
tty_unregister_driver(&dev->mdm.cua_modem);
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(dev->mdm.info[i].xmit_buf);
+ kfree(dev->mdm.info[i].xmit_buf - 4);
unregister_chrdev(ISDN_MAJOR, "isdn");
kfree(dev);
return -EIO;
if (!has_exported)
isdn_export_syms();
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(isdn_revision));
- printk("%s/", isdn_getrev(isdn_tty_revision));
- printk("%s/", isdn_getrev(isdn_net_revision));
- printk("%s/", isdn_getrev(isdn_ppp_revision));
- printk("%s", isdn_getrev(isdn_audio_revision));
+ strcpy(irev,isdn_revision);
+ strcpy(trev,isdn_tty_revision);
+ strcpy(nrev,isdn_net_revision);
+ strcpy(prev,isdn_ppp_revision);
+ strcpy(arev,isdn_audio_revision);
+ printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(irev));
+ printk("%s/", isdn_getrev(trev));
+ printk("%s/", isdn_getrev(nrev));
+ printk("%s/", isdn_getrev(prev));
+ printk("%s", isdn_getrev(arev));
#ifdef MODULE
printk(" loaded\n");
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
isdn_tty_cleanup_xmit(&dev->mdm.info[i]);
- kfree(dev->mdm.info[i].xmit_buf);
+ kfree(dev->mdm.info[i].xmit_buf - 4);
}
if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
-/* $Id: isdn_common.h,v 1.2 1996/04/20 16:20:40 fritz Exp $
+/* $Id: isdn_common.h,v 1.3 1996/05/19 00:13:05 fritz Exp $
*
* header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_common.h,v $
+ * Revision 1.3 1996/05/19 00:13:05 fritz
+ * Removed debug flag.
+ *
* Revision 1.2 1996/04/20 16:20:40 fritz
* Misc. typos.
*
-/* $Id: isdn_tty.c,v 1.11 1996/05/18 01:37:03 fritz Exp $
+/* $Id: isdn_tty.c,v 1.13 1996/05/31 01:33:29 fritz Exp $
*
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.13 1996/05/31 01:33:29 fritz
+ * Changed buffering due to bad performance with mgetty.
+ * Now sk_buff is delayed allocated in isdn_tty_senddown
+ * using xmit_buff like in standard serial driver.
+ * Fixed module locking.
+ * Added DLE-DC4 handling in voice mode.
+ *
+ * Revision 1.12 1996/05/19 01:34:40 fritz
+ * Bugfix: ATS returned error.
+ * Register 20 made readonly.
+ *
* Revision 1.11 1996/05/18 01:37:03 fritz
* Added spelling corrections and some minor changes
* to stay in sync with kernel.
*/
#define __NO_VERSION__
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/isdn.h>
-#include <linux/config.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
-#define VBUF 0x300
+#define VBUF 0x3e0
#define VBUFX (VBUF/16)
#endif
static int bit2si[8] = {1,5,7,7,7,7,7,7};
static int si2bit[8] = {4,1,4,4,4,4,4,4};
-char *isdn_tty_revision = "$Revision: 1.11 $";
+char *isdn_tty_revision = "$Revision: 1.13 $";
+
+#define DLE 0x10
+#define ETX 0x03
+#define DC4 0x14
/* isdn_tty_try_read() is called from within isdn_receive_callback()
* to stuff incoming data directly into a tty's flip-buffer. This
* 0 = Failure, data has to be buffered and later processed by
* isdn_tty_readmodem().
*/
-#define DLE 0x10
-#define ETX 0x03
int isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
{
int c;
save_flags(flags);
cli();
- if (info->xmit_buf->qlen)
- while ((skb = skb_dequeue(info->xmit_buf))) {
+ if (skb_queue_len(&info->xmit_queue))
+ while ((skb = skb_dequeue(&info->xmit_queue))) {
skb->free = 1;
- kfree_skb(skb,FREE_WRITE);
+ kfree_skb(skb, FREE_WRITE);
}
restore_flags(flags);
}
-/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
- * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
- * outgoing data from the tty's xmit-buffer, handles voice-decompression or
- * T.70 if necessary, and finally sends it out via isdn_writebuf_stub.
- */
-static void isdn_tty_senddown(modem_info * info)
+static void isdn_tty_tint(modem_info *info)
{
- struct tty_struct *tty = info->tty;
- struct sk_buff *skb = skb_dequeue(info->xmit_buf);
+ struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
if (!skb)
return;
- if (skb->free > 1) {
- /* Post processing only once, if skb->free > 1 */
+ if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel, skb) > 0) {
+ struct tty_struct *tty = info->tty;
+ info->send_outstanding++;
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible(&tty->write_wait);
+ return;
+ }
+ skb_queue_head(&info->xmit_queue, skb);
+}
+
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline==2) {
- char *ptr = skb->data;
- int len = skb->len;
-
- /* For now, ifmt is fixed to 1 (alaw), since this
- * is used with ISDN everywhere in the world, except
- * US, Canada and Japan.
- * Later, when US-ISDN protocols are implemented,
- * this setting will depend on the D-channel protocol.
- */
- int ifmt = 1;
- /* voice conversion/decompression */
- switch (info->emu.vpar[3]) {
- case 4:
- skb_put(skb, len);
- /* fall through */
- case 3:
- skb_put(skb, len);
- /* fall through */
- case 2:
- skb_put(skb, len * 2);
- /* adpcm, compatible to ZyXel 1496 modem
- * with ROM revision 6.01
- */
- skb_pull(skb, len);
- skb_trim(skb, isdn_audio_adpcm2xlaw(info->adpcms,
- ifmt,
- ptr,
- skb->data,
- len));
- break;
- case 5:
- /* a-law */
- if (!ifmt)
- isdn_audio_alaw2ulaw(ptr,len);
+int isdn_tty_countDLE(unsigned char *buf, int len)
+{
+ int count = 0;
+
+ while (len--)
+ if (*buf++ == DLE)
+ count++;
+ return count;
+}
+
+/* This routine is called from within isdn_tty_write() to perform
+ * DLE-decoding when sending audio-data.
+ */
+static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
+{
+ unsigned char *p = &info->xmit_buf[info->xmit_count];
+ int count = 0;
+
+ while (len>0) {
+ if (m->lastDLE) {
+ m->lastDLE = 0;
+ switch (*p) {
+ case DLE:
+ /* Escape code */
+ if (len>1)
+ memmove(p,p+1,len-1);
+ p--;
+ count++;
break;
- case 6:
- /* u-law */
- if (ifmt)
- isdn_audio_ulaw2alaw(ptr,len);
+ case ETX:
+ /* End of data */
+ info->vonline |= 4;
+ return count;
+ case DC4:
+ /* Abort RX */
+ info->vonline &= ~1;
+ isdn_tty_at_cout("\020\003", info);
+ if (!info->vonline)
+ isdn_tty_at_cout("\r\nVCON\r\n", info);
+ /* Fall through */
+ case 'q':
+ case 's':
+ /* Silence */
+ if (len>1)
+ memmove(p,p+1,len-1);
+ p--;
break;
}
+ } else {
+ if (*p == DLE)
+ m->lastDLE = 1;
+ else
+ count++;
}
-#endif /* CONFIG_ISDN_AUDIO */
- if (info->emu.mdmreg[13] & 2)
- /* Add T.70 simplified header */
- memcpy(skb_push(skb,4), "\1\0\1\0", 4);
- /* Mark skb post-processed */
- skb->free = 1;
+ p++;
+ len--;
}
- if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel,
- skb) > 0) {
- if (skb_queue_empty(info->xmit_buf))
- info->xmit_count = 0;
- if ((info->send_outstanding++) > 10)
- info->msr &= ~UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible(&tty->write_wait);
+ if (len<0) {
+ printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
+ return 0;
+ }
+ return count;
+}
+
+/* This routine is called from within isdn_tty_write() when receiving
+ * audio-data. It interrupts receiving, if an character other than
+ * ^S or ^Q is sent.
+ */
+static int isdn_tty_end_vrx(const char *buf, int c, int from_user)
+{
+ char tmpbuf[VBUF];
+ char *p;
+
+ if (c > VBUF) {
+ printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n");
+ return 1;
+ }
+ if (from_user) {
+ memcpy_fromfs(tmpbuf, buf, c);
+ p = tmpbuf;
} else
- skb_queue_head(info->xmit_buf,skb);
+ p = (char *)buf;
+ while (c--) {
+ if ((*p != 0x11) && (*p != 0x13))
+ return 1;
+ p++;
+ }
+ return 0;
+}
+#endif /* CONFIG_ISDN_AUDIO */
+
+static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 };
+
+/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
+ * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
+ * outgoing data from the tty's xmit-buffer, handles voice-decompression or
+ * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
+ */
+static void isdn_tty_senddown(modem_info * info)
+{
+ unsigned char *buf = info->xmit_buf;
+ int buflen;
+ int skb_res;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ if (!(buflen = info->xmit_count)) {
+ restore_flags(flags);
+ return;
+ }
+ skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
+ if (info->vonline & 2) {
+#ifdef CONFIG_ISDN_AUDIO
+ /* For now, ifmt is fixed to 1 (alaw), since this
+ * is used with ISDN everywhere in the world, except
+ * US, Canada and Japan.
+ * Later, when US-ISDN protocols are implemented,
+ * this setting will depend on the D-channel protocol.
+ */
+ int ifmt = 1;
+ int skb_len;
+ unsigned char hbuf[VBUF];
+
+ memcpy(hbuf,info->xmit_buf,buflen);
+ info->xmit_count = 0;
+ restore_flags(flags);
+ /* voice conversion/decompression */
+ skb_len = buflen * voice_cf[info->emu.vpar[3]];
+ skb = dev_alloc_skb(skb_len + skb_res);
+ if (!skb) {
+ printk(KERN_WARNING
+ "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
+ return;
+ }
+ skb_reserve(skb, skb_res);
+ switch (info->emu.vpar[3]) {
+ case 2:
+ case 3:
+ case 4:
+ /* adpcm, compatible to ZyXel 1496 modem
+ * with ROM revision 6.01
+ */
+ buflen = isdn_audio_adpcm2xlaw(info->adpcms,
+ ifmt,
+ hbuf,
+ skb_put(skb,skb_len),
+ buflen);
+ skb_trim(skb, buflen);
+ break;
+ case 5:
+ /* a-law */
+ if (!ifmt)
+ isdn_audio_alaw2ulaw(hbuf,buflen);
+ memcpy(skb_put(skb,buflen),hbuf,buflen);
+ break;
+ case 6:
+ /* u-law */
+ if (ifmt)
+ isdn_audio_ulaw2alaw(hbuf,buflen);
+ memcpy(skb_put(skb,buflen),hbuf,buflen);
+ break;
+ }
+ if (info->vonline & 4) {
+ info->vonline &= ~6;
+ if (!info->vonline)
+ isdn_tty_at_cout("\r\nVCON\r\n",info);
+ }
+#endif /* CONFIG_ISDN_AUDIO */
+ } else {
+ skb = dev_alloc_skb(buflen + skb_res);
+ if (!skb) {
+ printk(KERN_WARNING
+ "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
+ restore_flags(flags);
+ return;
+ }
+ skb_reserve(skb, skb_res);
+ memcpy(skb_put(skb,buflen),buf,buflen);
+ info->xmit_count = 0;
+ restore_flags(flags);
+ }
+ skb->free = 1;
+ if (info->emu.mdmreg[13] & 2)
+ /* Add T.70 simplified header */
+ memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
+ skb_queue_tail(&info->xmit_queue, skb);
+ if ((info->emu.mdmreg[12] & 0x10) != 0)
+ info->msr &= UART_MSR_CTS;
+ info->lsr &= UART_LSR_TEMT;
}
/************************************************************
info->rcvsched = 0;
info->online = 0;
isdn_tty_cleanup_xmit(info);
- switch (info->vonline) {
- case 1:
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- break;
- case 2:
- break;
+ if (info->vonline & 1) {
+ /* voice-recording, add DLE-ETX */
+ isdn_tty_at_cout("\020\003", info);
+ }
+ if (info->vonline & 2) {
+ /* voice-playing, add DLE-DC4 */
+ isdn_tty_at_cout("\020\024", info);
}
info->vonline = 0;
if (info->adpcms) {
info->adpcmr = NULL;
}
info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
- info->lsr &= ~UART_LSR_TEMT;
+ info->lsr |= UART_LSR_TEMT;
if (info->isdn_driver >= 0) {
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_HANGUP;
return 0;
save_flags(flags);
cli();
-
+ isdn_MOD_INC_USE_COUNT();
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
#endif
#endif
save_flags(flags);
cli(); /* Disable interrupts */
+ isdn_MOD_DEC_USE_COUNT();
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
if (info->emu.mdmreg[13] & 4) {
restore_flags(flags);
}
-#ifdef CONFIG_ISDN_AUDIO
-
-
-int isdn_tty_countDLE(unsigned char *buf, int len)
-{
- int count = 0;
-
- while (len--)
- if (*buf++ == DLE)
- count++;
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() to perform
- * DLE-decoding when sending audio-data.
- */
-static int isdn_tty_handleDLEdown(modem_info *info, atemu *m, struct sk_buff *skb)
-{
- unsigned char *p = skb->data;
- int len = skb->len;
- int count = 0;
-
- while (len>0) {
- if (m->lastDLE) {
- m->lastDLE = 0;
- switch (*p) {
- case DLE:
- /* Escape code */
- if (len>1)
- memmove(p,p+1,len-1);
- p--;
- count++;
- break;
- case ETX:
- /* End of data */
- info->vonline = 0;
- isdn_tty_at_cout("\r\nVCON\r\n",info);
- return count;
- case 'q':
- case 's':
- /* Silence */
- if (len>1)
- memmove(p,p+1,len-1);
- p--;
- break;
- }
- } else {
- if (*p == DLE)
- m->lastDLE = 1;
- else
- count++;
- }
- p++;
- len--;
- }
- if (len<0) {
- printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
- return 0;
- }
- skb_trim(skb,count);
- return count;
-}
-
-/* This routine is called from within isdn_tty_write() when receiving
- * audio-data. It interrupts receiving, if an character other than
- * ^S or ^Q is sent.
- */
-static int isdn_tty_end_vrx(const char *buf, int c, int from_user)
-{
- char tmpbuf[VBUF];
- char *p;
-
- if (c > VBUF) {
- printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n");
- return 1;
- }
- if (from_user) {
- memcpy_fromfs(tmpbuf, buf, c);
- p = tmpbuf;
- } else
- p = (char *)buf;
- while (c--) {
- if ((*p != 0x11) && (*p != 0x13))
- return 1;
- p++;
- }
- return 0;
-}
-#endif /* CONFIG_ISDN_AUDIO */
-
/* isdn_tty_write() is the main send-routine. It is called from the upper
* levels within the kernel to perform sending data. Depending on the
* online-flag it either directs output to the at-command-interpreter or
int c, total = 0;
ulong flags;
modem_info *info = (modem_info *) tty->driver_data;
- struct sk_buff *skb;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
return 0;
if (!tty)
return 0;
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
while (1) {
c = MIN(count, info->xmit_size - info->xmit_count);
if (info->isdn_driver >= 0)
if (c <= 0)
break;
if ((info->online > 1) ||
- (info->vonline == 2)) {
+ (info->vonline & 2)) {
atemu *m = &info->emu;
- if (info->vonline != 2)
+ if (!(info->vonline & 2))
isdn_tty_check_esc(buf, m->mdmreg[2], c,
&(m->pluscount),
&(m->lastplus),
from_user);
- if ((skb = alloc_skb(((info->vonline == 2)?
- (c+(c<<2)):c)+16,GFP_ATOMIC))==NULL) {
- printk(KERN_WARNING "isdn_tty: Cannot alloc skb in tty_write\n");
- restore_flags(flags);
- return total;
- }
- skb_reserve(skb, 4); /* For T.70 header */
if (from_user)
- memcpy_fromfs(skb_put(skb, c), buf, c);
+ memcpy_fromfs(&(info->xmit_buf[info->xmit_count]), buf, c);
else
- memcpy(skb_put(skb, c), buf, c);
+ memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline == 2) {
- int cc = isdn_tty_handleDLEdown(info,m,skb);
- info->xmit_count += cc;
- if ((cc==0) && (c > 0)) {
+ if (info->vonline & 2) {
+ int cc;
+
+ if (!(cc = isdn_tty_handleDLEdown(info,m,c))) {
/* If DLE decoding results in zero-transmit, but
* c originally was non-zero, do a wakeup.
*/
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup) (tty);
wake_up_interruptible(&tty->write_wait);
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
}
+ info->xmit_count += cc;
} else
#endif
info->xmit_count += c;
- skb->users = c;
- skb_queue_tail(info->xmit_buf,skb);
if (m->mdmreg[13] & 1) {
- sti();
isdn_tty_senddown(info);
+ isdn_tty_tint(info);
}
} else {
info->msr |= UART_MSR_CTS;
info->lsr |= UART_LSR_TEMT;
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline == 1) {
+ if (info->vonline & 1) {
if (isdn_tty_end_vrx(buf, c, from_user)) {
- info->vonline = 0;
+ info->vonline &= ~1;
isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
}
} else
count -= c;
total += c;
}
- if (total)
+ if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
- restore_flags(flags);
+ restore_flags(flags);
return total;
}
static void isdn_tty_flush_buffer(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
+ unsigned long flags;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer"))
return;
+ save_flags(flags);
+ cli();
isdn_tty_cleanup_xmit(info);
info->xmit_count = 0;
+ restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_chars"))
return;
- if (skb_queue_len(info->xmit_buf))
+ if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
}
status = info->lsr;
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- put_fs_long(result, (ulong *) value);
+ put_user(result, (ulong *) value);
return 0;
}
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- put_fs_long(result, (ulong *) value);
+ put_user(result, (ulong *) value);
return 0;
}
static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
{
- uint arg = get_fs_long((ulong *) value);
+ uint arg = get_user((uint *) value);
int pre_dtr;
switch (cmd) {
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
return -ENODEV;
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
switch (cmd) {
case TCSBRK: /* SVID version: non-zero arg --> no break */
#ifdef ISDN_DEBUG_MODEM_IOCTL
error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
if (error)
return error;
- put_fs_long(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+ put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
return 0;
case TIOCSSOFTCAR:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
#endif
- arg = get_fs_long((ulong *) arg);
+ error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
+ if (error)
+ return error;
+ arg = get_user((ulong *) arg);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
+ printk(KERN_DEBUG "ttyI%d ioctl TIOSERGETLSR\n", info->line);
#endif
error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
if (error)
m->tty_modem.flags = TTY_DRIVER_REAL_RAW;
m->tty_modem.refcount = &m->refcount;
m->tty_modem.table = m->modem_table;
- m->tty_modem.termios = (struct termios **)m->modem_termios;
- m->tty_modem.termios_locked = (struct termios **)m->modem_termios_locked;
+ m->tty_modem.termios = m->modem_termios;
+ m->tty_modem.termios_locked = m->modem_termios_locked;
m->tty_modem.open = isdn_tty_open;
m->tty_modem.close = isdn_tty_close;
m->tty_modem.write = isdn_tty_write;
info->isdn_channel = -1;
info->drv_index = -1;
info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
- if (!(info->xmit_buf = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL))) {
- printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
- return -3;
- }
- skb_queue_head_init(info->xmit_buf);
+ skb_queue_head_init(&info->xmit_queue);
+ if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
+ printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
+ return -3;
+ }
+ /* Make room for T.70 header */
+ info->xmit_buf += 4;
}
return 0;
}
switch (isdn_getnum(p)) {
case 0:
m->mdmreg[13] &= ~4;
+ m->mdmreg[12] &= ~32;
break;
case 2:
m->mdmreg[13] |= 4;
switch (isdn_getnum(p)) {
case 0:
m->mdmreg[13] &= ~2;
+ info->xmit_size = m->mdmreg[16] * 16;
break;
case 1:
m->mdmreg[13] |= 2;
m->mdmreg[14] = 0;
- m->mdmreg[16] = 7;
info->xmit_size = 112;
m->mdmreg[18] = 4;
m->mdmreg[19] = 0;
}
#ifdef CONFIG_ISDN_AUDIO
+/*
+ * Parse AT+F.. commands
+ */
+static int isdn_tty_cmd_PLUSF(char **p, modem_info * info)
+{
+ atemu *m = &info->emu;
+ int par;
+ char rs[20];
+
+ if (!strncmp(p[0],"CLASS",5)) {
+ p[0] += 5;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs,"\r\n%d",
+ (m->mdmreg[18]&1)?8:0);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ switch (*p[0]) {
+ case '0':
+ p[0]++;
+ m->mdmreg[18] = 4;
+ info->xmit_size =
+ m->mdmreg[16] * 16;
+ break;
+ case '8':
+ p[0]++;
+ m->mdmreg[18] = 5;
+ info->xmit_size = VBUF;
+ break;
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n0,8",
+ info);
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+ if (!strncmp(p[0],"AA",2)) {
+ p[0] += 2;
+ switch (*p[0]) {
+ case '?':
+ p[0]++;
+ sprintf(rs,"\r\n%d",
+ m->mdmreg[0]);
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+ p[0]++;
+ par = isdn_getnum(p);
+ if ((par < 0) || (par > 255))
+ PARSE_ERROR1;
+ m->mdmreg[0]=par;
+ break;
+ default:
+ PARSE_ERROR1;
+ }
+ return 0;
+ }
+ PARSE_ERROR1;
+}
+
/*
* Parse AT+V.. commands
*/
PARSE_ERROR1;
}
}
+ m->lastDLE = 0;
info->vonline = 2;
isdn_tty_modem_result(1, info);
return 1;
p++;
switch (*p) {
case 'F':
- if (strncmp(p,"FCLASS",6))
- PARSE_ERROR;
- p += 6;
- switch (*p) {
- case '?':
- p++;
- sprintf(ds,"\r\n%d",
- (m->mdmreg[18]&1)?8:0);
- isdn_tty_at_cout(ds, info);
- break;
- case '=':
- p++;
- switch (*p) {
- case '0':
- p++;
- m->mdmreg[18] = 4;
- break;
- case '8':
- p++;
- m->mdmreg[18] = 5;
- m->mdmreg[16] = VBUFX;
- info->xmit_size = VBUF;
- break;
- case '?':
- p++;
- isdn_tty_at_cout("\r\n0,8",
- info);
- break;
- default:
- PARSE_ERROR;
- }
- break;
- default:
- PARSE_ERROR;
-
- }
+ p++;
+ if (isdn_tty_cmd_PLUSF(&p, info))
+ return;
break;
case 'V':
if (!(m->mdmreg[18] & 1))
for (cnt = count; cnt > 0; p++, cnt--) {
if (user)
- c = get_fs_byte(p);
+ c = get_user(p);
else
c = *p;
total++;
{
int ton = 0;
int i;
- int midx;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEMORVOICE(dev->usage[i]))
- if ((midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->msr & UART_MSR_RI) {
- ton = 1;
- isdn_tty_modem_result(2, info);
- }
- }
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ modem_info *info = &dev->mdm.info[i];
+ if (info->msr & UART_MSR_RI) {
+ ton = 1;
+ isdn_tty_modem_result(2, info);
+ }
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
}
*/
void isdn_tty_modem_xmit(void)
{
- int ton = 0;
+ int ton = 1;
int i;
- int midx;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEMORVOICE(dev->usage[i]))
- if ((midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if ((info->online > 1) ||
- (info->vonline ==2 )) {
- if (skb_queue_len(info->xmit_buf)) {
- ton = 1;
- isdn_tty_senddown(info);
- }
- }
- }
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ modem_info *info = &dev->mdm.info[i];
+ if (info->online) {
+ ton = 1;
+ isdn_tty_senddown(info);
+ isdn_tty_tint(info);
+ }
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
}
void isdn_tty_bsent(int drv, int chan)
{
int i;
- ulong flags;
- save_flags(flags);
- cli();
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if ((info->isdn_driver == drv) &&
- (info->isdn_channel == chan) ) {
+ modem_info *info = &dev->mdm.info[i];
+ if ((info->isdn_driver == drv) &&
+ (info->isdn_channel == chan) ) {
info->msr |= UART_MSR_CTS;
if (info->send_outstanding)
if (!(--info->send_outstanding))
- info->lsr &= ~UART_LSR_TEMT;
+ info->lsr |= UART_LSR_TEMT;
+ isdn_tty_tint(info);
}
- }
- restore_flags(flags);
+ }
return;
}
-/* $Id: buffers.c,v 1.2 1996/04/29 22:48:14 fritz Exp $
+/* $Id: buffers.c,v 1.3 1996/05/31 00:56:53 fritz Exp $
*
* $Log: buffers.c,v $
+ * Revision 1.3 1996/05/31 00:56:53 fritz
+ * removed cli() from BufPoolAdd, since it is called
+ * with interrupts off anyway.
+ *
* Revision 1.2 1996/04/29 22:48:14 fritz
* Removed compatibility-macros. No longer needed.
*
BufPoolAdd(struct BufPool *bp, int priority)
{
struct Pages *ptr;
- long flags;
byte *bptr;
int i;
struct BufHeader *bh = NULL, *prev, *first;
bptr += PART_SIZE(bp->pageorder, bp->bpps);
}
- save_flags(flags);
- cli();
first->next = bp->freelist;
bp->freelist = bh;
- restore_flags(flags);
return (0);
}
-/* $Id: callc.c,v 1.7 1996/05/17 03:40:37 fritz Exp $
+/* $Id: callc.c,v 1.8 1996/05/31 01:00:38 fritz Exp $
*
* $Log: callc.c,v $
+ * Revision 1.8 1996/05/31 01:00:38 fritz
+ * Changed return code of teles_writebuf, when out of memory.
+ *
* Revision 1.7 1996/05/17 03:40:37 fritz
* General cleanup.
*
err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21);
if (err)
- return (0);
+ return -ENOMEM;
ptr = DATAPTR(ibh);
if (chanp->lc_b.l2_establish)
-/* $Id: card.c,v 1.5 1996/05/17 03:45:02 fritz Exp $
+/* $Id: card.c,v 1.7 1996/05/31 01:02:21 fritz Exp $
*
* card.c low level stuff for the Teles S0 isdn card
*
* Beat Doebeli log all D channel traffic
*
* $Log: card.c,v $
+ * Revision 1.7 1996/05/31 01:02:21 fritz
+ * Cosmetic changes.
+ *
+ * Revision 1.6 1996/05/26 14:58:10 fritz
+ * Bugfix: Did not show port correctly, when no card found.
+ *
* Revision 1.5 1996/05/17 03:45:02 fritz
* Made error messages more clearly.
* Bugfix: Only 31 bytes of 32-byte audio frames
ibh = hsp->xmtibh;
if (!ibh)
- return;
+ return;
count = ibh->datasize - hsp->sendptr;
if (count <= 0)
- return;
+ return;
more = (hsp->mode == 1)?1:0;
if (count > 32) {
break;
case (-2):
release_region(cards[i].iobase, 8);
- teles_shiftcards(i);
printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
+ teles_shiftcards(i);
break;
}
}
-/* $Id: isdnl3.c,v 1.5 1996/05/18 01:37:16 fritz Exp $
+/* $Id: isdnl3.c,v 1.6 1996/05/21 11:33:50 keil Exp $
*
* $Log: isdnl3.c,v $
+ * Revision 1.6 1996/05/21 11:33:50 keil
+ * Adding SETUP_ACKNOWLEGDE as answer of a SETUP message.
+ *
* Revision 1.5 1996/05/18 01:37:16 fritz
* Added spelling corrections and some minor changes
* to stay in sync with kernel.
{
{0,MT_SETUP,l3s12},
{1,MT_CALL_PROCEEDING,l3s6},
+ {1,MT_SETUP_ACKNOWLEDGE,l3s6},
{1,MT_RELEASE_COMPLETE,l3s4},
{1,MT_RELEASE,l3s19},
{1,MT_DISCONNECT,l3s7},
-/* $Id: llglue.c,v 1.3 1996/05/01 14:19:57 fritz Exp $
+/* $Id: llglue.c,v 1.5 1996/05/31 00:58:47 fritz Exp $
*
* $Log: llglue.c,v $
+ * Revision 1.5 1996/05/31 00:58:47 fritz
+ * Errata: Reverted change from rev 1.4.
+ *
+ * Revision 1.4 1996/05/26 14:59:57 fritz
+ * Bugfix: maxbufsize had been set without respect to possible X.75 header.
+ *
* Revision 1.3 1996/05/01 14:19:57 fritz
* Added ISDN_FEATURE_L2_TRANS
*
int i;
for (i=0; i<lp->rxRingSize; i++) {
- if (lp->rx_skb[i]) {
+ if ((unsigned long) lp->rx_skb[i] > 1) {
dev_kfree_skb(lp->rx_skb[i], FREE_WRITE);
}
lp->rx_ring[i].status = 0;
long
attach_pss_mpu (long mem_start, struct address_info *hw_config)
{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
long ret;
-#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
{
int prev_devs;
prev_devs = num_midis;
if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */
midi_devs[prev_devs]->coproc = &pss_coproc_operations;
}
-#endif
return ret;
+#else
+ return mem_start;
+#endif
}
int
void
unload_pss_mpu (struct address_info *hw_config)
{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
unload_mpu401 (hw_config);
+#endif
}
void
tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
-if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
- define_bool CONFIG_AMIGA_PARTITION y
+if [ "$CONFIG_EXPERIMENTAL = "y" ]; then
+ tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
+ if [ "$CONFIG_AFFS_FS" != "n" ]; then
+ define_bool CONFIG_AMIGA_PARTITION y
+ fi
fi
tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
if [ "$CONFIG_UFS_FS" != "n" ]; then
if (!PageLocked(page))
panic("brw_page: page not locked for I/O");
clear_bit(PG_uptodate, &page->flags);
+ clear_bit(PG_error, &page->flags);
/*
* Allocate buffer heads pointing to this page, just for I/O.
* They do _not_ show up in the buffer hash table!
return (inode->u.isofs_i.i_first_extent >> ISOFS_BUFFER_BITS(inode)) + block;
}
+
+static void test_and_set_uid(uid_t *p, uid_t value)
+{
+ if(value) {
+ *p = value;
+#if 0
+ printk("Resetting to %d\n", value);
+#endif
+ }
+}
+
void isofs_read_inode(struct inode * inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
/* Now test for possible Rock Ridge extensions which will override some of
these numbers in the inode structure. */
- if (!high_sierra)
+ if (!high_sierra) {
parse_rock_ridge_inode(raw_inode, inode);
+ /* hmm..if we want uid or gid set, override the rock ridge setting */
+ test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
+ }
#ifdef DEBUG
printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
|| ( (len == 2)
&& (name[1] == '.'))))
{
+ iput(dir);
return -EEXIST;
}
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
name, &sattr, &fhandle, &fattr);
if (!error)
+ {
nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
+ /* The parent dir inode count may have changed ! */
+ nfs_lookup_cache_remove( NULL, dir, NULL);
+ }
+
iput(dir);
return error;
}
sizeof(nfs_data.hostname)-1);
/* Set the name of the directory to mount */
- if (nfs_path[0] == '\0' || !strncmp(name, "default", 7))
+ if (nfs_path[0] == '\0' || strncmp(name, "default", 7))
strncpy(buf, name, NFS_MAXPATHLEN);
else
strncpy(buf, nfs_path, NFS_MAXPATHLEN);
#ifndef _ALPHA_STATFS_H
#define _ALPHA_STATFS_H
-#ifndef _LINUX_TYPES_DONT_EXPORT
+#ifndef __KERNEL_STRICT_NAMES
#include <linux/posix_types.h>
#define fd_cacheflush(addr, size) /* nothing... */
#define fd_request_irq() sun_fd_request_irq()
#define fd_free_irq() /* nothing... */
+#if 0 /* P3: added by Alain, these cause a MMU corruption. 19960524 XXX */
#define fd_dma_mem_alloc(size) ((unsigned long) vmalloc(size))
#define fd_dma_mem_free(addr,size) (vfree((void *)(addr)))
+#endif
#define FLOPPY_MOTOR_MASK 0x10
case 5: /* FD_DATA */
return sun_fdc->data_82072;
case 7: /* FD_DIR */
- /* Always return 0, the disk never changes
- * without the kernel explicitly doing so.
- */
- return 0;
+ return (*AUXREG & AUXIO_FLPY_DCHG)? 0x80: 0;
};
panic("sun_82072_fd_inb: How did I get here?");
}
case 5: /* FD_DATA */
return sun_fdc->data_82077;
case 7: /* FD_DIR */
- /* Always return 0, the disk never changes
- * without the kernel explicitly ejecting it.
- */
- return 0;
+ /* XXX: Is DCL on 0x80 in sun4m? */
+ return sun_fdc->dir_82077;
};
panic("sun_82072_fd_inb: How did I get here?");
}
#define ARPHRD_ARCNET 7 /* ARCnet */
#define ARPHRD_APPLETLK 8 /* APPLEtalk */
#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
+#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */
/* Dummy types for non ARP hardware */
#define ARPHRD_SLIP 256
#define ARPHRD_SKIP 771 /* SKIP vif */
#define ARPHRD_LOOPBACK 772 /* Loopback device */
#define ARPHRD_LOCALTLK 773 /* Localtalk device */
-#define ARPHRD_METRICOM 774 /* Metricom STRIP */
/* ARP protocol opcodes. */
#define ARPOP_REQUEST 1 /* ARP request */
-/* $Id: isdn.h,v 1.10 1996/05/18 01:37:18 fritz Exp $
+/* $Id: isdn.h,v 1.11 1996/05/31 01:37:47 fritz Exp $
*
* Main header for the Linux ISDN subsystem (linklevel).
*
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn.h,v $
+ * Revision 1.11 1996/05/31 01:37:47 fritz
+ * Minor changes, due to changes in isdn_tty.c
+ *
* Revision 1.10 1996/05/18 01:37:18 fritz
* Added spelling corrections and some minor changes
* to stay in sync with kernel.
int drv_index; /* Index to dev->usage */
int ncarrier; /* Flag: schedule NO CARRIER */
struct timer_list nc_timer; /* Timer for delayed NO CARRIER */
-#define FUTURE 1
-#if FUTURE
int send_outstanding;/* # of outstanding send-requests */
-#endif
int xmit_size; /* max. # of chars in xmit_buf */
int xmit_count; /* # of chars in xmit_buf */
+ unsigned char *xmit_buf; /* transmit buffer */
+ struct sk_buff_head xmit_queue; /* transmit queue */
struct tty_struct *tty; /* Pointer to corresponding tty */
atemu emu; /* AT-emulator data */
void *adpcms; /* state for adpcm decompression */
struct termios callout_termios;
struct wait_queue *open_wait;
struct wait_queue *close_wait;
- struct sk_buff_head *xmit_buf; /* transmit-buffer queue */
} modem_info;
#define ISDN_MODEM_WINSIZE 8
struct tty_driver tty_modem; /* tty-device */
struct tty_driver cua_modem; /* cua-device */
struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
- struct termios modem_termios[ISDN_MAX_CHANNELS];
- struct termios modem_termios_locked[ISDN_MAX_CHANNELS];
+ struct termios *modem_termios[ISDN_MAX_CHANNELS];
+ struct termios *modem_termios_locked[ISDN_MAX_CHANNELS];
modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
} modem;
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
+#include <linux/interrupt.h>
/* for future expansion when we will have different priorities. */
#define DEV_NUMBUFFS 3
extern int dev_close(struct device *dev);
extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev,
int pri);
+
#define HAVE_NETIF_RX 1
extern void netif_rx(struct sk_buff *skb);
-extern void dev_transmit(void);
extern void net_bh(void);
extern void dev_tint(struct device *dev);
extern int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
#include <linux/posix_types.h>
#include <asm/types.h>
-#ifndef _LINUX_TYPES_DONT_EXPORT
+#ifndef __KERNEL_STRICT_NAMES
typedef __kernel_fd_set fd_set;
typedef __kernel_dev_t dev_t;
typedef unsigned int uint;
typedef unsigned long ulong;
-#endif /* _LINUX_TYPES_DONT_EXPORT */
+#endif /* __KERNEL_STRICT_NAMES */
/*
* Below are truly Linux-specific types that should never collide with
struct sock *prev; /* Doubly linked chain.. */
struct sock *pair;
struct sk_buff * volatile send_head;
+ struct sk_buff * volatile send_next;
struct sk_buff * volatile send_tail;
struct sk_buff_head back_log;
struct sk_buff *partial;
page_read_error:
/*
* Umm, take care of errors if the page isn't up-to-date.
- * Try to re-read it _once_.
+ * Try to re-read it _once_. We do this synchronously,
+ * because there really aren't any performance issues here
+ * and we need to check for errors.
*/
if (inode->i_op->readpage(inode, page) != 0)
goto failure;
+ wait_on_page(page);
if (PageError(page))
goto failure;
if (PageUptodate(page))
static inline struct page_descriptor * get_kmalloc_pages(unsigned long priority,
unsigned long order, int dma)
{
- struct page_descriptor * tmp;
-
- tmp = (struct page_descriptor *) __get_free_pages(priority, order, dma);
- if (!tmp && !dma && order < MAX_CACHE_ORDER)
- tmp = xchg(kmalloc_cache+order, tmp);
- return tmp;
+ return (struct page_descriptor *) __get_free_pages(priority, order, dma);
}
static inline void free_kmalloc_pages(struct page_descriptor * page,
}
+/*
+ * Ugh, this is ugly, but we want the default case to run
+ * straight through, which is why we have the ugly goto's
+ */
void *kmalloc(size_t size, int priority)
{
unsigned long flags;
int order, dma;
struct block_header *p;
struct page_descriptor *page, **pg;
+ struct size_descriptor *bucket = sizes;
/* Get order */
order = 0;
if (realsize <= ordersize)
break;
order++;
+ bucket++;
if (ordersize)
continue;
printk("kmalloc of too large a block (%d bytes).\n", (int) size);
dma = 0;
type = MF_USED;
- pg = &sizes[order].firstfree;
+ pg = &bucket->firstfree;
if (priority & GFP_DMA) {
dma = 1;
type = MF_DMA;
- pg = &sizes[order].dmafree;
+ pg = &bucket->dmafree;
}
priority &= GFP_LEVEL_MASK;
save_flags(flags);
cli();
page = *pg;
- if (page) {
- p = page->firstfree;
- if (p->bh_flags != MF_FREE)
- goto not_free_on_freelist;
- goto found_it;
- }
+ if (!page)
+ goto no_bucket_page;
+
+ p = page->firstfree;
+ if (p->bh_flags != MF_FREE)
+ goto not_free_on_freelist;
+
+found_it:
+ page->firstfree = p->bh_next;
+ page->nfree--;
+ if (!page->nfree)
+ *pg = page->next;
+ restore_flags(flags);
+ bucket->nmallocs++;
+ bucket->nbytesmalloced += size;
+ p->bh_flags = type; /* As of now this block is officially in use */
+ p->bh_length = size;
+#ifdef SADISTIC_KMALLOC
+ memset(p+1, 0xf0, size);
+#endif
+ return p + 1; /* Pointer arithmetic: increments past header */
- /* We need to get a new free page..... */
- /* This can be done with ints on: This is private to this invocation */
+
+no_bucket_page:
+ /*
+ * If we didn't find a page already allocated for this
+ * bucket size, we need to get one..
+ *
+ * This can be done with ints on: it is private to this invocation
+ */
restore_flags(flags);
{
/* sz is the size of the blocks we're dealing with */
sz = BLOCKSIZE(order);
- page = get_kmalloc_pages(priority, sizes[order].gfporder, dma);
-
+ page = get_kmalloc_pages(priority, bucket->gfporder, dma);
if (!page)
goto no_free_page;
- sizes[order].npages++;
+found_cached_page:
+
+ bucket->npages++;
+ page->order = order;
/* Loop for all but last block: */
- for (i = NBLOCKS(order), p = BH(page + 1); i > 1; i--, p = p->bh_next) {
+ i = (page->nfree = bucket->nblocks) - 1;
+ p = BH(page + 1);
+ while (i > 0) {
+ i--;
p->bh_flags = MF_FREE;
p->bh_next = BH(((long) p) + sz);
+ p = p->bh_next;
}
/* Last block: */
p->bh_flags = MF_FREE;
p->bh_next = NULL;
- page->order = order;
- page->nfree = NBLOCKS(order);
p = BH(page+1);
}
cli();
page->next = *pg;
*pg = page;
+ goto found_it;
-found_it:
- page->firstfree = p->bh_next;
- page->nfree--;
- if (!page->nfree)
- *pg = page->next;
- restore_flags(flags);
- sizes[order].nmallocs++;
- sizes[order].nbytesmalloced += size;
- p->bh_flags = type; /* As of now this block is officially in use */
- p->bh_length = size;
-#ifdef SADISTIC_KMALLOC
- memset(p+1, 0xf0, size);
-#endif
- return p + 1; /* Pointer arithmetic: increments past header */
no_free_page:
+ /*
+ * No free pages, check the kmalloc cache of
+ * pages to see if maybe we have something available
+ */
+ if (!dma && order < MAX_CACHE_ORDER) {
+ page = xchg(kmalloc_cache+order, page);
+ if (page)
+ goto found_cached_page;
+ }
{
static unsigned long last = 0;
if (priority != GFP_BUFFER && (last + 10 * HZ < jiffies)) {
register_netdevice_notifier(&ddp_notifier);
aarp_proto_init();
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_ATALK, 9, "appletalk",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
atalk_if_get_info
});
+#endif
printk(KERN_INFO "Appletalk 0.17 for Linux NET3.035\n");
}
aarp_cleanup_module();
+#ifdef CONFIG_PROC_FS
proc_net_unregister(PROC_NET_ATALK);
proc_net_unregister(PROC_NET_AT_ROUTE);
proc_net_unregister(PROC_NET_ATIF);
+#endif
unregister_netdevice_notifier(&ddp_notifier);
dev_remove_pack(<alk_packet_type);
dev_remove_pack(&ppptalk_packet_type);
dev_add_pack(&bpq_packet_type);
#endif
register_netdevice_notifier(&ax25_dev_notifier);
-
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_AX25_ROUTE, 10, "ax25_route",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
ax25_cs_get_info
});
+#endif
- printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.32 BETA for Linux NET3.035 (Linux 2.0)\n");
+ printk(KERN_INFO "G4KLX/GW4PTS AX.25 for Linux. Version 0.32 for Linux NET3.035 (Linux 2.0)\n");
#ifdef CONFIG_BPQETHER
proc_net_register(&(struct proc_dir_entry) {
* rest of the magic.
*/
-void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
+static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
{
unsigned long flags;
struct sk_buff_head *list;
}
}
}
- start_bh_atomic();
if (dev->hard_start_xmit(skb, dev) == 0) {
/*
* Packet is now solely the responsibility of the driver
*/
- end_bh_atomic();
return;
}
- end_bh_atomic();
/*
* Transmission failed, put skb back into a list. Once on the list it's safe and
restore_flags(flags);
}
+void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
+{
+ start_bh_atomic();
+ do_dev_queue_xmit(skb, dev, pri);
+ end_bh_atomic();
+}
+
/*
* Receive a packet from a device driver and queue it for the upper
* (protocol) levels. It always succeeds. This is the recommended
* This routine causes all interfaces to try to send some data.
*/
-void dev_transmit(void)
+static void dev_transmit(void)
{
struct device *dev;
* Feed them to the output stage and if it fails
* indicate they re-queue at the front.
*/
- dev_queue_xmit(skb,dev,-i - 1);
+ do_dev_queue_xmit(skb,dev,-i - 1);
/*
* If we can take no more then stop here.
*/
void skb_device_lock(struct sk_buff *skb)
{
if(skb->lock)
- printk("double lock on device queue!\n");
+ printk("double lock on device queue, lock=%d caller=%p\n",
+ skb->lock, (&skb)[-1]);
else
net_locked++;
skb->lock++;
if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE
- bool 'IP: transparent proxy support (ALPHA)' CONFIG_IP_TRANSPARENT_PROXY
+ bool 'IP: masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE
+ bool 'IP: transparent proxy support (EXPERIMENTAL)' CONFIG_IP_TRANSPARENT_PROXY
fi
bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG
fi
ifeq ($(CONFIG_IP_MASQUERADE),y)
IPV4_OBJS += ip_masq.o ip_masq_app.o
-M_OBJS += ip_masq_ftp.o ip_masq_irc.o
+M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o
endif
ifeq ($(CONFIG_IP_ALIAS),y)
skb = skb2;
}
sk->send_head = NULL;
+ sk->send_tail = NULL;
+ sk->send_next = NULL;
sti();
/*
struct ip_fw *i;
unsigned long flags;
int len, p;
+ int last_len = 0;
switch(stage)
len=0;
begin=pos;
}
+ else if(pos>offset+length)
+ {
+ len = last_len;
+ break;
+ }
else if(reset)
{
/* This needs to be done at this specific place! */
i->fw_pcnt=0L;
i->fw_bcnt=0L;
}
- if(pos>offset+length)
- break;
+ last_len = len;
i=i->fw_next;
}
restore_flags(flags);
void ip_fw_init(void)
{
+#ifdef CONFIG_PROC_FS
#ifdef CONFIG_IP_ACCT
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPACCT, 7, "ip_acct",
ip_acct_procinfo
});
#endif
+#endif
#ifdef CONFIG_IP_FIREWALL
if(register_firewall(PF_INET,&ipfw_ops)<0)
panic("Unable to register IP firewall.\n");
-
+
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPFWIN, 8, "ip_input",
S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
ip_fw_fwd_procinfo
});
#endif
-
+#endif
#ifdef CONFIG_IP_MASQUERADE
/*
}
#endif
+
#ifdef CONFIG_IP_MASQUERADE
- {
/*
* Do we need to de-masquerade this packet?
*/
- int ret = ip_fw_demasquerade(&skb,dev);
- if (ret < 0) {
- kfree_skb(skb, FREE_WRITE);
- return 0;
- }
-
- if (ret)
{
- struct iphdr *iph=skb->h.iph;
- if (ip_forward(skb, dev, IPFWD_MASQUERADED, iph->daddr))
+ int ret = ip_fw_demasquerade(&skb,dev);
+ if (ret < 0) {
kfree_skb(skb, FREE_WRITE);
- return 0;
+ return 0;
+ }
+
+ if (ret)
+ {
+ struct iphdr *iph=skb->h.iph;
+ if (ip_forward(skb, dev, IPFWD_MASQUERADED, iph->daddr))
+ kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
}
- }
#endif
/*
* Juan Jose Ciarlante : Added hashed lookup by proto,maddr,mport and proto,saddr,sport
* Juan Jose Ciarlante : Fixed deadlock if free ports get exhausted
* Juan Jose Ciarlante : Added NO_ADDR status flag.
- * Nigel Metheringham : ICMP handling.
+ * Nigel Metheringham : Added ICMP handling for demasquerade
+ * Nigel Metheringham : Checksum checking of masqueraded data
+ *
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/inet.h>
#include <net/protocol.h>
#include <net/icmp.h>
#include <net/tcp.h>
/*
* We can only masquerade protocols with ports...
+ * [TODO]
+ * We may need to consider masq-ing some ICMP related to masq-ed protocols
*/
if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
struct iphdr *iph = skb->h.iph;
struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
struct iphdr *ciph; /* The ip header contained within the ICMP */
- __u16 *portptr; /* port numbers from TCP/UDP contained header */
+ __u16 *pptr; /* port numbers from TCP/UDP contained header */
struct ip_masq *ms;
+ unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Incoming ICMP (%d) %lX -> %lX\n",
* Find the ports involved - remember this packet was
* *outgoing* so the ports are reversed (and addresses)
*/
- portptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
- if (ntohs(portptr[0]) < PORT_MASQ_BEGIN ||
- ntohs(portptr[0]) > PORT_MASQ_END)
+ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+ if (ntohs(pptr[0]) < PORT_MASQ_BEGIN ||
+ ntohs(pptr[0]) > PORT_MASQ_END)
return 0;
+ /* Ensure the checksum is correct */
+ if (ip_compute_csum((unsigned char *) icmph, len))
+ {
+ /* Failed checksum! */
+ printk(KERN_INFO "MASQ: ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr));
+ return(-1);
+ }
+
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Handling ICMP for %lX:%X -> %lX:%X\n",
- ntohl(ciph->saddr), ntohs(portptr[0]),
- ntohl(ciph->daddr), ntohs(portptr[1]));
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
#endif
/* This is pretty much what ip_masq_in_get() does, except params are wrong way round */
- ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, portptr[1], ciph->saddr, portptr[0]);
+ ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]);
if (ms == NULL)
return 0;
ip_send_check(ciph);
/* the TCP/UDP source port - cannot redo check */
- portptr[0] = ms->sport;
+ pptr[0] = ms->sport;
/* And finally the ICMP checksum */
icmph->checksum = 0;
- icmph->checksum = ip_compute_csum((unsigned char *) icmph,
- skb->len - sizeof(struct iphdr));
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Rewrote ICMP to %lX:%X -> %lX:%X\n",
- ntohl(ciph->saddr), ntohs(portptr[0]),
- ntohl(ciph->daddr), ntohs(portptr[1]));
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
#endif
return 1;
struct iphdr *iph = skb->h.iph;
__u16 *portptr;
struct ip_masq *ms;
- unsigned short frag;
-
- if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP
- && iph->protocol!=IPPROTO_ICMP)
- return 0;
-
- /*
- * Toss fragments, since we handle them in ip_rcv()
- */
-
- frag = ntohs(iph->frag_off);
-
- if ((frag & IP_MF) != 0 || (frag & IP_OFFSET) != 0)
- {
+ unsigned short len;
+
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return(ip_fw_demasq_icmp(skb_p, dev));
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ /* Make sure packet is in the masq range */
+ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
+ ntohs(portptr[1]) > PORT_MASQ_END)
+ return 0;
+ /* Check that the checksum is OK */
+ len = ntohs(iph->tot_len) - (iph->ihl * 4);
+ if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0))
+ /* No UDP checksum */
+ break;
+
+ switch (skb->ip_summed)
+ {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char *)portptr, len, 0);
+ case CHECKSUM_HW:
+ if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
+ iph->protocol, skb->csum))
+ {
+ printk(KERN_INFO "MASQ: failed TCP/UDP checksum from %s!\n",
+ in_ntoa(iph->saddr));
+ return -1;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ }
+ break;
+ default:
return 0;
}
- if (iph->protocol == IPPROTO_ICMP)
- return ip_fw_demasq_icmp(skb_p, dev);
-
- portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
- ntohs(portptr[1]) > PORT_MASQ_END)
- return 0;
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Incoming %s %lX:%X -> %lX:%X\n",
if (ms != NULL)
{
- int size;
-
/*
* Set dport if not defined yet.
*/
ntohs(ms->daddr));
#endif
}
- size = skb->len - ((unsigned char *)portptr - skb->h.raw);
iph->daddr = ms->saddr;
portptr[1] = ms->sport;
skb = *skb_p;
iph = skb->h.iph;
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- size = skb->len - ((unsigned char *)portptr-skb->h.raw);
+ len = ntohs(iph->tot_len) - (iph->ihl * 4);
}
/*
*/
if (iph->protocol==IPPROTO_UDP)
{
- recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
+ recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
ip_masq_set_expire(ms, 0);
ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
}
{
struct tcphdr *th;
skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
- size - sizeof(struct tcphdr), 0);
- tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb);
+ len - sizeof(struct tcphdr), 0);
+ tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb);
/* Check if TCP RST */
th = (struct tcphdr *)portptr;
if (th->rst)
int ip_masq_init(void)
{
register_symtab (&ip_masq_syms);
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMSQHST, 13, "ip_masquerade",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
ip_msqhst_procinfo
});
+#endif
ip_masq_app_init();
return 0;
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
struct ip_masq_app * mapp;
unsigned idx;
- if (offset < 22)
- len=sprintf(buffer,"%-21s\n", "prot port n_attach");
- pos = 22;
+ if (offset < 40)
+ len=sprintf(buffer,"%-39s\n", "prot port n_attach name");
+ pos = 40;
for (idx=0 ; idx < IP_MASQ_APP_TAB_SIZE; idx++)
for (mapp = ip_masq_app_base[idx]; mapp ; mapp = mapp->next) {
/*
* If you change the length of this sprintf, then all
* the length calculations need fixing too!
- * Line length = 22 (3 + 2 + 7 + 1 + 7 + 1 + 1)
+ * Line length = 40 (3 + 2 + 7 + 1 + 7 + 1 + 2 + 17)
*/
- pos += 22;
+ pos += 40;
if (pos < offset)
continue;
- len += sprintf(buffer+len, "%-3s %-7u %-7d \n",
+ len += sprintf(buffer+len, "%-3s %-7u %-7d %-17s\n",
masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
- IP_MASQ_APP_PORT(mapp->type), mapp->n_attach);
+ IP_MASQ_APP_PORT(mapp->type), mapp->n_attach,
+ mapp->name);
if(len >= length)
goto done;
{
register_symtab (&ip_masq_app_syms);
-
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IP_MASQ_APP, 11, "ip_masq_app",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
ip_masq_app_getinfo
});
-
+#endif
return 0;
}
--- /dev/null
+/*
+ * IP_MASQ_RAUDIO - Real Audio masquerading module
+ *
+ *
+ * Version: @(#)$Id: ip_masq_raudio.c,v 1.3 1996/05/20 13:24:26 nigel Exp $
+ *
+ * Author: Nigel Metheringham
+ * [strongly based on ftp module by Juan Jose Ciarlante & Wouter Gadeyne]
+ * [Real Audio information taken from Progressive Networks firewall docs]
+ *
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * Limitations
+ * The IP Masquerading proxies at present do not have access to a processed
+ * data stream. Hence for a protocol like the Real Audio control protocol,
+ * which depends on knowing where you are in the data stream, you either
+ * to keep a *lot* of state in your proxy, or you cheat and simplify the
+ * problem [needless to say I did the latter].
+ *
+ * This proxy only handles data in the first packet. Everything else is
+ * passed transparently. This means it should work under all normal
+ * circumstances, but it could be fooled by new data formats or a
+ * malicious application!
+ *
+ * At present the "first packet" is defined as a packet starting with
+ * the protocol ID string - "PNA".
+ * When the link is up there appears to be enough control data
+ * crossing the control link to keep it open even if a long audio
+ * piece is playing.
+ *
+ */
+
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip_masq.h>
+
+#ifndef DEBUG_CONFIG_IP_MASQ_RAUDIO
+#define DEBUG_CONFIG_IP_MASQ_RAUDIO 0
+#endif
+
+struct raudio_priv_data {
+ /* Associated data connection - setup but not used at present */
+ struct ip_masq *data_conn;
+ /* Have we seen and performed setup */
+ short seen_start;
+};
+
+static int
+masq_raudio_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_INC_USE_COUNT;
+ if ((ms->app_data = kmalloc(sizeof(struct raudio_priv_data),
+ GFP_ATOMIC)) == NULL)
+ printk(KERN_INFO "RealAudio: No memory for application data\n");
+ else
+ {
+ struct raudio_priv_data *priv =
+ (struct raudio_priv_data *)ms->app_data;
+ priv->seen_start = 0;
+ priv->data_conn = NULL;
+ }
+ return 0;
+}
+
+static int
+masq_raudio_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+ MOD_DEC_USE_COUNT;
+ if (ms->app_data)
+ kfree_s(ms->app_data, sizeof(struct raudio_priv_data));
+ return 0;
+}
+
+int
+masq_raudio_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ char *p, *data, *data_limit;
+ struct ip_masq *n_ms;
+ unsigned short version, msg_id, msg_len, udp_port;
+ struct raudio_priv_data *priv =
+ (struct raudio_priv_data *)ms->app_data;
+
+ /* Everything running correctly already */
+ if (priv && priv->seen_start)
+ return 0;
+
+ skb = *skb_p;
+ iph = skb->h.iph;
+ th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+ data = (char *)&th[1];
+
+ data_limit = skb->h.raw + skb->len - 18;
+
+ /* Check to see if this is the first packet with protocol ID */
+ if (memcmp(data, "PNA", 3)) {
+#if DEBUG_CONFIG_IP_MASQ_RAUDIO
+ printk("RealAudio: not initial protocol packet - ignored\n");
+#endif
+ return(0);
+ }
+ data += 3;
+ memcpy(&version, data, 2);
+
+#if DEBUG_CONFIG_IP_MASQ_RAUDIO
+ printk("RealAudio: initial seen - protocol version %d\n",
+ ntohs(version));
+#endif
+ if (priv)
+ priv->seen_start = 1;
+
+ if (ntohs(version) >= 256)
+ {
+ printk(KERN_INFO "RealAudio: version (%d) not supported\n",
+ ntohs(version));
+ return 0;
+ }
+
+ data += 2;
+ while (data < data_limit) {
+ memcpy(&msg_id, data, 2);
+ data += 2;
+ memcpy(&msg_len, data, 2);
+ data += 2;
+#if DEBUG_CONFIG_IP_MASQ_RAUDIO
+ printk("RealAudio: msg %d - %d byte\n",
+ ntohs(msg_id), ntohs(msg_len));
+#endif
+ p = data;
+ data += ntohs(msg_len);
+ if (data > data_limit)
+ {
+ printk(KERN_INFO "RealAudio: Packet too short for data\n");
+ return 0;
+ }
+ if (ntohs(msg_id) == 1) {
+ /* This is a message detailing the UDP port to be used */
+ memcpy(&udp_port, p, 2);
+ n_ms = ip_masq_new(dev, IPPROTO_UDP,
+ ms->saddr, udp_port,
+ ms->daddr, 0,
+ IP_MASQ_F_NO_DPORT);
+
+ if (n_ms==NULL)
+ return 0;
+
+ memcpy(p, &(n_ms->mport), 2);
+#if DEBUG_CONFIG_IP_MASQ_RAUDIO
+ printk("RealAudio: rewrote UDP port %d -> %d\n",
+ ntohs(udp_port), ntohs(n_ms->mport));
+#endif
+ ip_masq_set_expire(n_ms, ip_masq_expire->udp_timeout);
+
+ /* Make ref in application data to data connection */
+ if (priv)
+ priv->data_conn = n_ms;
+
+ /*
+ * There is nothing else useful we can do
+ * Maybe a development could do more, but for now
+ * we exit gracefully!
+ */
+ return 0;
+
+ } else if (ntohs(msg_id) == 0)
+ return 0;
+ }
+ return 0;
+}
+
+struct ip_masq_app ip_masq_raudio = {
+ NULL, /* next */
+ "RealAudio", /* name */
+ 0, /* type */
+ 0, /* n_attach */
+ masq_raudio_init_1, /* ip_masq_init_1 */
+ masq_raudio_done_1, /* ip_masq_done_1 */
+ masq_raudio_out, /* pkt_out */
+ NULL /* pkt_in */
+};
+
+/*
+ * ip_masq_raudio initialization
+ */
+
+int ip_masq_raudio_init(void)
+{
+ return register_ip_masq_app(&ip_masq_raudio, IPPROTO_TCP, 7070);
+}
+
+/*
+ * ip_masq_raudio fin.
+ */
+
+int ip_masq_raudio_done(void)
+{
+ return unregister_ip_masq_app(&ip_masq_raudio);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ if (ip_masq_raudio_init() != 0)
+ return -EIO;
+ register_symtab(0);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ if (ip_masq_raudio_done() != 0)
+ printk("ip_masq_raudio: can't remove module");
+}
+
+#endif /* MODULE */
{
sk->send_tail = skb;
sk->send_head = skb;
+ sk->send_next = skb;
}
else
{
ip_udp_init();*/
#ifdef CONFIG_IP_MULTICAST
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IGMP, 4, "igmp",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
ip_mc_procinfo
});
+#endif
#endif
}
* Resolve IFF_ALLMULTI for rest of cards
*/
+#include <linux/config.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/types.h>
{
printk(KERN_INFO "Linux IP multicast router 0.05.\n");
register_netdevice_notifier(&ip_mr_notifier);
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
ipmr_mfc_info
});
+#endif
}
* free'ing up the memory.
*/
tcp_cache_zap(); /* Kill the cache again. */
+
+ /* Now that the socket is dead, if we are in the FIN_WAIT2 state
+ * we may need to set up a timer.
+ */
+ if (sk->state==TCP_FIN_WAIT2)
+ {
+ int timer_active=del_timer(&sk->timer);
+ if(timer_active)
+ add_timer(&sk->timer);
+ else
+ tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
+ }
+
release_sock(sk);
sk->dead = 1;
}
sk->delack_timer.data = (unsigned long) sk;
sk->retransmit_timer.function = tcp_retransmit_timer;
sk->retransmit_timer.data = (unsigned long)sk;
- tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto); /* Timer for repeating the SYN until an answer */
- sk->retransmits = 0; /* Now works the right way instead of a hacked
- initial setting */
-
+ sk->retransmits = 0;
sk->prot->queue_xmit(sk, dev, buff, 0);
tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
tcp_statistics.TcpActiveOpens++;
* Eric Schenk : Yet another double ACK bug.
* Eric Schenk : Delayed ACK bug fixes.
* Eric Schenk : Floyd style fast retrans war avoidance.
+ * Eric Schenk : Skip fast retransmit on small windows.
+ * Eric schenk : Fixes to retransmission code to
+ * : avoid extra retransmission.
*/
#include <linux/config.h>
skb_queue_head_init(&newsk->receive_queue);
newsk->send_head = NULL;
newsk->send_tail = NULL;
+ newsk->send_next = NULL;
skb_queue_head_init(&newsk->back_log);
newsk->rtt = 0;
newsk->rto = TCP_TIMEOUT_INIT;
skb2 = sk->send_head;
sk->send_head = NULL;
sk->send_tail = NULL;
+ sk->send_next = NULL;
/*
* This is an artifact of a flawed concept. We want one
{
sk->send_head = skb;
sk->send_tail = skb;
+ sk->send_next = skb;
}
else
{
{
sk->send_head = NULL;
sk->send_tail = NULL;
+ sk->send_next = NULL;
sk->packets_out= 0;
}
* The packet acked data after high_seq;
* I've tried to order these in occurrence of most likely to fail
* to least likely to fail.
- * [These are the rules BSD stacks use to determine if an ACK is a
- * duplicate.]
+ * [These are an extension of the rules BSD stacks use to
+ * determine if an ACK is a duplicate.]
*/
if (sk->rcv_ack_seq == ack
&& before(ack, sk->sent_seq)
&& after(ack, sk->high_seq))
{
+ /* Prevent counting of duplicate ACKs if the congestion
+ * window is smaller than 3. Note that since we reduce
+ * the congestion window when we do a fast retransmit,
+ * we must be careful to keep counting if we were already
+ * counting. The idea behind this is to avoid doing
+ * fast retransmits if the congestion window is so small
+ * that we cannot get 3 ACKs due to the loss of a packet
+ * unless we are getting ACKs for retransmitted packets.
+ */
+ if (sk->cong_window >= 3 || sk->rcv_ack_cnt > MAX_DUP_ACKS+1)
+ sk->rcv_ack_cnt++;
/* See draft-stevens-tcpca-spec-01 for explanation
* of what we are doing here.
*/
- sk->rcv_ack_cnt++;
if (sk->rcv_ack_cnt == MAX_DUP_ACKS+1) {
sk->ssthresh = max(sk->cong_window >> 1, 2);
sk->cong_window = sk->ssthresh+MAX_DUP_ACKS+1;
- /* FIXME:
- * reduce the count. We don't want to be
- * seen to be in "retransmit" mode if we
- * are doing a fast retransmit.
- * This is also a signal to tcp_do_retransmit
- * not to set sk->high_seq.
- * This is a horrible ugly hack.
- */
- sk->retransmits--;
tcp_do_retransmit(sk,0);
} else if (sk->rcv_ack_cnt > MAX_DUP_ACKS+1) {
sk->cong_window++;
sk->send_tail = NULL;
sk->retransmits = 0;
}
+
+ /*
+ * advance the send_next pointer if needed.
+ */
+ if (sk->send_next == skb)
+ sk->send_next = sk->send_head;
+
/*
* Note that we only reset backoff and rto in the
* rtt recomputation code. And that doesn't happen
sk->write_space(sk);
}
- /*
- * XXX someone ought to look at this too.. at the moment, if skb_peek()
- * returns non-NULL, we complete ignore the timer stuff in the else
- * clause. We ought to organize the code so that else clause can
- * (should) be executed regardless, possibly moving the PROBE timer
- * reset over. The skb_peek() thing should only move stuff to the
- * write queue, NOT also manage the timer functions.
- */
-
/*
* Maybe we can take some stuff off of the write queue,
* and put it onto the xmit queue.
+ * FIXME: (?) There is bizzare case being tested here, to check if
+ * the data at the head of the queue ends before the start of
+ * the sequence we already ACKed. This does not appear to be
+ * a case that can actually occur. Why are we testing it?
*/
- if (skb_peek(&sk->write_queue) != NULL)
- {
- if (!before(sk->window_seq, sk->write_queue.next->end_seq) &&
- (sk->retransmits == 0 ||
- sk->ip_xmit_timeout != TIME_WRITE ||
- !after(sk->write_queue.next->end_seq, sk->rcv_ack_seq))
- && sk->packets_out < sk->cong_window)
- {
- /*
- * Add more data to the send queue.
- */
- flag |= 1;
- tcp_write_xmit(sk);
- }
- else if (before(sk->window_seq, sk->write_queue.next->end_seq) &&
- sk->send_head == NULL &&
- sk->ack_backlog == 0 &&
- sk->state != TCP_TIME_WAIT)
- {
- /*
- * Data to queue but no room.
- */
- tcp_reset_xmit_timer(sk, TIME_PROBE0, sk->rto);
- }
- }
- else
+
+ if (!skb_queue_empty(&sk->write_queue) &&
+ !before(sk->window_seq, sk->write_queue.next->end_seq) &&
+ (sk->retransmits == 0 ||
+ sk->ip_xmit_timeout != TIME_WRITE ||
+ !after(sk->write_queue.next->end_seq, sk->rcv_ack_seq)) &&
+ sk->packets_out < sk->cong_window)
{
/*
- * from TIME_WAIT we stay in TIME_WAIT as long as we rx packets
- * from TCP_CLOSE we don't do anything
- *
- * from anything else, if there is write data (or fin) pending,
- * we use a TIME_WRITE timeout, else if keepalive we reset to
- * a KEEPALIVE timeout, else we delete the timer.
- *
- * We do not set flag for nominal write data, otherwise we may
- * force a state where we start to write itsy bitsy tidbits
- * of data.
+ * Add more data to the send queue.
*/
+ flag |= 1;
+ tcp_write_xmit(sk);
+ }
- switch(sk->state) {
- case TCP_TIME_WAIT:
- /*
- * keep us in TIME_WAIT until we stop getting packets,
- * reset the timeout.
- */
- tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- break;
- case TCP_CLOSE:
- /*
- * don't touch the timer.
- */
- break;
- default:
- /*
- * Must check send_head and write_queue
- * to determine which timeout to use.
+ /*
+ * Reset timers to reflect the new state.
+ *
+ * from TIME_WAIT we stay in TIME_WAIT as long as we rx packets
+ * from TCP_CLOSE we don't do anything
+ *
+ * from anything else, if there is queued data (or fin) pending,
+ * we use a TIME_WRITE timeout, if there is data to write but
+ * no room in the window we use TIME_PROBE0, else if keepalive
+ * we reset to a KEEPALIVE timeout, else we delete the timer.
+ *
+ * We do not set flag for nominal write data, otherwise we may
+ * force a state where we start to write itsy bitsy tidbits
+ * of data.
+ */
+
+ switch(sk->state) {
+ case TCP_TIME_WAIT:
+ /*
+ * keep us in TIME_WAIT until we stop getting packets,
+ * reset the timeout.
+ */
+ tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ break;
+ case TCP_CLOSE:
+ /*
+ * don't touch the timer.
+ */
+ break;
+ default:
+ /*
+ * Must check send_head and write_queue
+ * to determine which timeout to use.
+ */
+ if (sk->send_head) {
+ tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
+ } else if (!skb_queue_empty(&sk->write_queue)
+ && sk->ack_backlog == 0)
+ {
+ /*
+ * if the write queue is not empty when we get here
+ * then we failed to move any data to the retransmit
+ * queue above. (If we had send_head would be non-NULL).
+ * Furthermore, since the send_head is NULL here
+ * we must not be in retransmit mode at this point.
+ * This implies we have no packets in flight,
+ * hence sk->packets_out < sk->cong_window.
+ * Examining the conditions for the test to move
+ * data to the retransmission queue we find that
+ * we must therefore have a zero window.
+ * Hence, if the ack_backlog is 0 we should initiate
+ * a zero probe.
+ * We don't do a zero probe if we have a delayed
+ * ACK in hand since the other side may have a
+ * window opening, but they are waiting to hear
+ * from us before they tell us about it.
+ * (They are applying Nagle's rule).
+ * So, we don't set up the zero window probe
+ * just yet. We do have to clear the timer
+ * though in this case...
*/
- if (sk->send_head || !skb_queue_empty(&sk->write_queue)) {
- tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- } else if (sk->keepopen) {
- tcp_reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- } else {
- del_timer(&sk->retransmit_timer);
- sk->ip_xmit_timeout = 0;
- }
- break;
+ tcp_reset_xmit_timer(sk, TIME_PROBE0, sk->rto);
+ } else if (sk->keepopen) {
+ tcp_reset_xmit_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+ } else {
+ del_timer(&sk->retransmit_timer);
+ sk->ip_xmit_timeout = 0;
}
+ break;
}
/*
flag |= 1;
sk->shutdown |= SEND_SHUTDOWN;
tcp_set_state(sk, TCP_FIN_WAIT2);
+ /* If the socket is dead, then there is no
+ * user process hanging around using it.
+ * We want to set up a FIN_WAIT2 timeout ala BSD.
+ */
+ if (sk->dead)
+ tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
}
}
}
/*
- * I make no guarantees about the first clause in the following
- * test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under
- * what conditions "!flag" would be true. However I think the rest
- * of the conditions would prevent that from causing any
- * unnecessary retransmission.
- * Clearly if the first packet has expired it should be
- * retransmitted. The other alternative, "flag&2 && retransmits", is
- * harder to explain: You have to look carefully at how and when the
- * timer is set and with what timeout. The most recent transmission always
- * sets the timer. So in general if the most recent thing has timed
- * out, everything before it has as well. So we want to go ahead and
- * retransmit some more. If we didn't explicitly test for this
- * condition with "flag&2 && retransmits", chances are "when + rto < jiffies"
- * would not be true. If you look at the pattern of timing, you can
- * show that rto is increased fast enough that the next packet would
- * almost never be retransmitted immediately. Then you'd end up
- * waiting for a timeout to send each packet on the retransmission
- * queue. With my implementation of the Karn sampling algorithm,
- * the timeout would double each time. The net result is that it would
- * take a hideous amount of time to recover from a single dropped packet.
- * It's possible that there should also be a test for TIME_WRITE, but
- * I think as long as "send_head != NULL" and "retransmit" is on, we've
- * got to be in real retransmission mode.
- * Note that tcp_do_retransmit is called with all==1. Setting cong_window
- * back to 1 at the timeout will cause us to send 1, then 2, etc. packets.
- * As long as no further losses occur, this seems reasonable.
+ * The following code has been greatly simplified from the
+ * old hacked up stuff. The wonders of properly setting the
+ * retransmission timeouts.
+ *
+ * If we are retransmitting, and we acked a packet on the retransmit
+ * queue, and there is still something in the retransmit queue,
+ * then we can output some retransmission packets.
*/
-
- if (((!flag) || (flag&4)) && sk->send_head != NULL &&
- (((flag&2) && sk->retransmits) ||
- (sk->send_head->when + sk->rto < jiffies)))
+
+ if (sk->send_head != NULL && (flag&2) && sk->retransmits)
{
- if(sk->send_head->when + sk->rto < jiffies)
- tcp_retransmit(sk,0);
- else
- {
- tcp_do_retransmit(sk, 1);
- tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
- }
+ tcp_do_retransmit(sk, 1);
}
return 1;
* for handling this timeout.
*/
- if(sk->ip_xmit_timeout != TIME_WRITE)
- tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
+ if (sk->ip_xmit_timeout != TIME_WRITE) {
+ if (sk->send_head)
+ tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
+ else
+ printk(KERN_ERR "send_head NULL in FIN_WAIT1\n");
+ }
tcp_set_state(sk,TCP_CLOSING);
break;
case TCP_FIN_WAIT2:
* Note most of these are inline now. I'll inline the lot when
* I have time to test it hard and look at what gcc outputs
*/
-
+
if (!tcp_sequence(sk, skb->seq, skb->end_seq-th->syn))
{
bad_tcp_sequence(sk, th, skb->end_seq-th->syn, dev);
* Matthew Dillon, <dillon@apollo.west.oic.com>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
* Jorge Cwik, <jorge@laser.satlink.net>
+ *
+ * Fixes: Eric Schenk : avoid multiple retransmissions in one
+ * : round trip timeout.
*/
#include <linux/config.h>
if (before(sk->window_seq, sk->write_queue.next->end_seq) &&
sk->send_head == NULL && sk->ack_backlog == 0)
tcp_reset_xmit_timer(sk, TIME_PROBE0, sk->rto);
- }
+ }
else
{
/*
sk->prot->queue_xmit(sk, skb->dev, skb, 0);
/*
- * Set for next retransmit based on expected ACK time.
- * FIXME: We set this every time which means our
- * retransmits are really about a window behind.
+ * Set for next retransmit based on expected ACK time
+ * of the first packet in the resend queue.
+ * This is no longer a window behind.
*/
tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
clear_delayed_acks(sk);
- /*
- * Again we slide the timer wrongly
- */
-
tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
}
}
struct sk_buff * skb;
struct proto *prot;
struct device *dev;
- int ct=0;
struct rtable *rt;
prot = sk->prot;
+ if (!all) {
+ /*
+ * If we are just retransmitting one packet reset
+ * to the start of the queue.
+ */
+ sk->send_next = sk->send_head;
+ sk->packets_out = 0;
+ }
skb = sk->send_head;
while (skb != NULL)
dev = skb->dev;
IS_SKB(skb);
skb->when = jiffies;
-
+
/* dl1bke 960201 - @%$$! Hope this cures strange race conditions */
/* with AX.25 mode VC. (esp. DAMA) */
/* if the buffer is locked we should not retransmit */
/* Now queue it */
ip_statistics.IpOutRequests++;
dev_queue_xmit(skb, dev, sk->priority);
+ sk->packets_out++;
}
}
}
-
/*
* Count retransmissions
*/
- ct++;
- sk->retransmits++;
sk->prot->retransmits++;
tcp_statistics.TcpRetransSegs++;
if (sk->retransmits)
sk->high_seq = sk->sent_seq;
+ /*
+ * Advance the send_next pointer so we don't keep
+ * retransmitting the same stuff every time we get an ACK.
+ */
+ sk->send_next = skb->link3;
/*
* Only one retransmit requested.
* This should cut it off before we send too many packets.
*/
- if (ct >= sk->cong_window)
+ if (sk->packets_out >= sk->cong_window)
break;
+
skb = skb->link3;
}
}
&& skb_queue_empty(&sk->write_queue)
&& sk->ip_xmit_timeout == TIME_WRITE)
{
- if(sk->keepopen)
+ if (sk->keepopen)
tcp_reset_xmit_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
else
- delete_timer(sk);
+ del_timer(&sk->retransmit_timer);
}
/*
tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), buff);
if (sk->debug)
- printk("\rtcp_ack: seq %x ack %x\n", sk->sent_seq, sk->acked_seq);
+ printk(KERN_ERR "\rtcp_ack: seq %x ack %x\n", sk->sent_seq, sk->acked_seq);
sk->prot->queue_xmit(sk, dev, buff, 1);
tcp_statistics.TcpOutSegs++;
}
* Matthew Dillon, <dillon@apollo.west.oic.com>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
* Jorge Cwik, <jorge@laser.satlink.net>
+ *
+ * Fixes:
+ *
+ * Eric Schenk : Fix retransmission timeout counting.
*/
#include <net/tcp.h>
{
del_timer(&sk->retransmit_timer);
sk->ip_xmit_timeout = why;
- if((long)when < 0)
- {
- when=3;
- printk(KERN_ERR "Error: Negative timer in xmit_timer\n");
+ if (why == TIME_WRITE) {
+ /* In this case we want to timeout on the first packet
+ * in the resend queue. If the resend queue is empty,
+ * then the packet we are sending hasn't made it there yet,
+ * so we timeout from the current time.
+ */
+ if (sk->send_head) {
+ sk->retransmit_timer.expires =
+ sk->send_head->when + when;
+ } else {
+ /* This should never happen!
+ */
+ printk(KERN_ERR "Error: send_head NULL in xmit_timer\n");
+ sk->ip_xmit_timeout = 0;
+ return;
+ }
+ } else {
+ sk->retransmit_timer.expires = jiffies+when;
+ }
+
+ if (sk->retransmit_timer.expires < jiffies) {
+ /* We can get here if we reset the timer on an event
+ * that could not fire because the interupts where disabled.
+ * make sure it happens soon.
+ */
+ sk->retransmit_timer.expires = jiffies+2;
}
- sk->retransmit_timer.expires=jiffies+when;
add_timer(&sk->retransmit_timer);
}
static void tcp_retransmit_time(struct sock *sk, int all)
{
+ /*
+ * record how many times we've timed out.
+ * This determines when we should quite trying.
+ * This needs to be counted here, because we should not be
+ * counting one per packet we send, but rather one per round
+ * trip timeout.
+ */
+ sk->retransmits++;
+
tcp_do_retransmit(sk, all);
/*
sk->backoff++;
sk->rto = min(sk->rto << 1, 120*HZ);
- tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
+
+ /* be paranoid about the data structure... */
+ if (sk->send_head)
+ tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
+ else
+ printk(KERN_ERR "send_head NULL in tcp_retransmit_time\n");
}
/*
sk->ssthresh = sk->cong_window >> 1; /* remember window where we lost */
/* sk->ssthresh in theory can be zero. I guess that's OK */
sk->cong_count = 0;
-
sk->cong_window = 1;
/* Do the actual retransmit. */
}
else
{
- printk(KERN_WARNING "IPX: Network number collision %lx\n\t%s %s and %s %s\n",
+ printk(KERN_WARNING "IPX: Network number collision %lx\n %s %s and %s %s\n",
htonl(ipx->ipx_source.net),
ipx_device_name(i),
ipx_frame_name(i->if_dlink_type),
printk(KERN_CRIT "IPX: Unable to register with SNAP\n");
register_netdevice_notifier(&ipx_dev_notifier);
-
+#ifdef CONFIG_PROC_FS
proc_net_register(&ipx_procinfo);
proc_net_register(&ipx_if_procinfo);
proc_net_register(&ipx_rt_procinfo);
+#endif
printk(KERN_INFO "Swansea University Computer Society IPX 0.34 for NET3.035\n");
printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
ipxitf_down(ifc);
}
+#ifdef CONFIG_PROC_FS
proc_net_unregister(PROC_NET_IPX_ROUTE);
proc_net_unregister(PROC_NET_IPX_INTERFACE);
proc_net_unregister(PROC_NET_IPX);
+#endif
unregister_netdevice_notifier(&ipx_dev_notifier);
nr_default.window = NR_DEFAULT_WINDOW;
nr_default.paclen = NR_DEFAULT_PACLEN;
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_NR, 2, "nr",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
nr_nodes_get_info
});
+#endif
}
#endif
then
echo; echo " Sorry, no help available for this option yet.";echo
else
- (echo; echo "$text"; echo) | more
+ (echo; echo "$text"; echo) | ${PAGER:-more}
fi
else
echo;