]> git.neil.brown.name Git - history.git/commitdiff
Import pre2.0.10 pre2.0.10
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:11:04 +0000 (15:11 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:11:04 +0000 (15:11 -0500)
66 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/ioctl-number.txt
Documentation/isdn/README.audio [new file with mode: 0644]
Documentation/isdn/README.icn
Documentation/networking/framerelay.txt
MAINTAINERS
Makefile
README
arch/i386/defconfig
arch/i386/kernel/time.c
drivers/block/README.fd
drivers/block/floppy.c
drivers/cdrom/cm206.c
drivers/char/Config.in
drivers/char/consolemap.c
drivers/char/ftape/RELEASE-NOTES
drivers/char/ftape/ftape-ctl.c
drivers/char/ftape/kernel-interface.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_tty.c
drivers/isdn/teles/buffers.c
drivers/isdn/teles/callc.c
drivers/isdn/teles/card.c
drivers/isdn/teles/isdnl3.c
drivers/isdn/teles/llglue.c
drivers/net/de4x5.c
drivers/sound/pss.c
fs/Config.in
fs/buffer.c
fs/isofs/inode.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nfs/nfsroot.c
include/asm-alpha/statfs.h
include/asm-sparc/floppy.h
include/linux/if_arp.h
include/linux/isdn.h
include/linux/netdevice.h
include/linux/types.h
include/net/sock.h
mm/filemap.c
mm/kmalloc.c
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/core/dev.c
net/core/skbuff.c
net/ipv4/Config.in
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/ip_fw.c
net/ipv4/ip_input.c
net/ipv4/ip_masq.c
net/ipv4/ip_masq_app.c
net/ipv4/ip_masq_raudio.c [new file with mode: 0644]
net/ipv4/ip_output.c
net/ipv4/ipmr.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipx/af_ipx.c
net/netrom/af_netrom.c
scripts/Configure

diff --git a/CREDITS b/CREDITS
index 6657d0167be7c6ca7f72b63fbb677a842fa22c8e..8ac2266b31847aadaa93786b13004b23c5e08c5f 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -306,6 +306,14 @@ S: 5800 Corporate Drive
 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
@@ -512,11 +520,11 @@ S: United Kingdom
 
 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
@@ -876,6 +884,14 @@ S: RWTH-Aachen
 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
@@ -1015,11 +1031,14 @@ S: CANADA P7C 5M9
 
 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
@@ -1114,6 +1133,16 @@ S: Hiekkalaiturintie 3 A 8
 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
index f788f884a7998d99cc7c4c15b1b9da675a730c48..a4d3bf39c86d5ff23d15671a585d49e33124b642 100644 (file)
@@ -14,7 +14,11 @@ Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources,
 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
@@ -29,7 +33,7 @@ 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
 
@@ -39,11 +43,17 @@ Upgrade notes
 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
 ===================
@@ -128,15 +138,14 @@ people don't need to upgrade past 1.3.57.
    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
 ==========
@@ -183,6 +192,12 @@ Uugetty
 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
 =======
 
@@ -198,6 +213,11 @@ the following as root:
    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
 ======
 
@@ -254,7 +274,7 @@ Networking
 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
@@ -269,7 +289,9 @@ Sound driver
 
    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
 ====
@@ -299,7 +321,7 @@ Loop device
 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.
 
@@ -389,7 +411,7 @@ installed programs and libraries.
 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.*
@@ -470,8 +492,8 @@ ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-0.99a.tgz
 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
 ==================
@@ -500,13 +522,16 @@ Other Info
 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
index 5d59c309f525848e9f04c3cab05c6d62b4e4bc2d..4057ca90bfeb4ece5f2c8c46f3e8699eb8d56bc5 100644 (file)
@@ -267,7 +267,7 @@ CONFIG_BLK_DEV_ALI14XX
   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
@@ -866,14 +866,14 @@ CONFIG_IP_FIREWALL_VERBOSE
   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
@@ -888,14 +888,12 @@ CONFIG_IP_MASQUERADE
   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
@@ -909,7 +907,10 @@ 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
@@ -1142,7 +1143,7 @@ CONFIG_BRIDGE
   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
@@ -1150,8 +1151,7 @@ CONFIG_NETLINK
   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
index 5ca0c696e48e5add5e7a0a7c16ae41034c98f442..7023d455c1b3c52793d437d5f6306a8af9486276 100644 (file)
@@ -1,5 +1,5 @@
 Ioctl Numbers
-10 May 1996
+29 May 1996
 Michael Chastain
 <mec@duracef.shout.net>
 
@@ -50,51 +50,54 @@ Following the convention is good because:
 (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
diff --git a/Documentation/isdn/README.audio b/Documentation/isdn/README.audio
new file mode 100644 (file)
index 0000000..07b107d
--- /dev/null
@@ -0,0 +1,115 @@
+$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.
+
+
index 3cd5171ff140357b52c3cdc7a8f6d3886b95e175..2be05a7196d1fd5b17bcd2955d1edc75f5c8561f 100644 (file)
@@ -8,7 +8,7 @@ Obere Heerbergstr. 17
 Tel: +49 931 2877950
 Fax: +49 931 2877951
 
-email uhl@think.de
+email info@think.de
 WWW   http:/www.think.de
 
 
index 0a0bc4bde4fb26c76cbc2c0814f8e198f1b95f24..f02b133d1dfb09a6b7cbc5a25cd1d05219a36000 100644 (file)
@@ -31,3 +31,9 @@ an initial configuration.
 
 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.
+
index 100bbca0991547edd77588955cca53173f8a28c6..f2fc78ac16bb051df40ee3ea7abc6b9ee15652cc 100644 (file)
@@ -180,6 +180,7 @@ S:  Maintained
 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
 
@@ -263,8 +264,8 @@ L:  linux-smp@vger.rutgers.edu
 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
 
index b00bfd888d4ed43054579540c0844d8bfe516204..9620429bb671e27126a4176605d84d085f51e295 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 9
+SUBLEVEL = 10
 
 ARCH = i386
 
diff --git a/README b/README
index 8e85e14754ad18bab9e27195fd20d6f8839abe73..3e7ba582551694e03a968bfa6e755dd07d839b61 100644 (file)
--- a/README
+++ b/README
@@ -138,6 +138,11 @@ COMPILING the kernel:
    "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. 
index f0526b08318899c5c5f7513f87f4ab1403a3e82c..622b5e4c7bdf5a2e3865c26d451bd4a132816ae7 100644 (file)
@@ -142,8 +142,6 @@ CONFIG_NFS_FS=y
 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
@@ -154,10 +152,7 @@ CONFIG_SERIAL=y
 # 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
index e2d268971959aa71e511a8d52b60d8bd44b8bbc3..b71e529f3d1f7426a8f30546899ead637b8200f9 100644 (file)
@@ -49,13 +49,13 @@ static unsigned long do_fast_gettimeoffset(void)
        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;
@@ -174,7 +174,7 @@ static unsigned long do_slow_gettimeoffset(void)
        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;
 
index 11e1455b6e0cee54e5cfe8ab0583253fe8c1e4cc..f10b9218cd08f1ec0b1d44d360446404772d3d36 100644 (file)
@@ -13,15 +13,15 @@ Lilo config options (Thinkpad users, read this)
  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
@@ -30,15 +30,22 @@ prompt options coming last. That's why there are also options to
 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:
 
index 8f12a2eff08bb260d524a57a210ad723818b33a7..c8f38d2d14e63827741917bb09a112de922c8a18 100644 (file)
@@ -248,6 +248,9 @@ static inline int DRIVE(kdev_t x) {
 
 #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]
@@ -371,7 +374,7 @@ static struct floppy_struct floppy_type[32] = {
        { 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"   */
@@ -795,20 +798,22 @@ static void set_fdc(int drive)
 /* 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);
@@ -974,34 +979,36 @@ static int hlt_disabled=0;
 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;
@@ -1029,7 +1036,7 @@ static void setup_DMA(void)
                return;
        }
 #endif
-       cli();
+       INT_OFF;
        fd_disable_dma();
        fd_clear_dma_ff();
        fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)?
@@ -1038,7 +1045,7 @@ static void setup_DMA(void)
        fd_set_dma_count(raw_cmd->length);
        virtual_dma_port = FDCS->address;
        fd_enable_dma();
-       sti();
+       INT_ON;
        floppy_disable_hlt();
 }
 
@@ -1915,11 +1922,12 @@ static struct cont_t intr_cont={
 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)
@@ -1931,10 +1939,10 @@ static int wait_til_done(void (*handler)(void), int interruptible)
                cancel_activity();
                cont = &intr_cont;
                reset_fdc();
-               sti();
+               INT_ON;
                return -EINTR;
        }
-       sti();
+       INT_ON;
 
        if (FDCS->reset)
                command_status = FD_COMMAND_ERROR;
@@ -3940,8 +3948,6 @@ int floppy_init(void)
 
        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;
@@ -4037,12 +4043,14 @@ int floppy_init(void)
 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){
@@ -4080,13 +4088,14 @@ static void floppy_release_irq_and_dma(void)
 #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();
index c823faf5f1fab3ae7c19b0e98390ab2b7b943eb8..67a08812ba4cc2d02b4def8337eced4ae53514e7 100644 (file)
@@ -98,7 +98,7 @@ History:
  * - 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>      
 
@@ -1189,6 +1189,11 @@ int cm206_init(void)
   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) 
index 160b4fc462fad0d717bf469e0b0f51ec317591f9..3ff878adfd38d971a9706db6951bf2e7dbad4460 100644 (file)
@@ -14,13 +14,19 @@ if [ "$CONFIG_STALDRV" = "y" ]; then
 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
index 9a78c2f87d4f12df8f48be14154b86a2483dda93..919e1e966dac04c884b3ae039831b193d06b53c6 100644 (file)
@@ -57,7 +57,7 @@ static unsigned short translations[][256] = {
     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,
@@ -89,7 +89,7 @@ static unsigned short translations[][256] = {
   {
     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,
index b3b98b62adb9b43ad6f2719d3b27eb9c4a1981ad..fc82f99009049c3e2f0e1a8c8fbcdf321e1a9040 100644 (file)
@@ -1,7 +1,7 @@
 ===== 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.
@@ -104,7 +104,7 @@ kernel deadlock (which is worse than a panic).
 
 ===== 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
@@ -139,7 +139,7 @@ Bas offline linux-tape
 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
index 7f6b9da034cdb7a837827da5c9ec6d51315c8edd..adab7ea83f291f1745fdd7d9be5e9152583f0700 100644 (file)
@@ -371,7 +371,7 @@ void ftape_log_vendor_id(void)
                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 {
@@ -393,7 +393,7 @@ void ftape_log_vendor_id(void)
                        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, "==========================================");
                }
        }
@@ -456,7 +456,7 @@ void ftape_calc_timeouts(void)
                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):
index fcb2f46714d1bfab84e6811a7b28c6c03d10e692..4ec106d598c4ed6a0bff347fb065f6399c873b12 100644 (file)
@@ -127,7 +127,7 @@ int ftape_init(void)
 #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
index 6cf1d2a2db2b8e3810fc0bcc5adc00ca7c3d30c9..abbc7a4a655487581e2244b0a7fc3692346a09aa 100644 (file)
@@ -1,4 +1,4 @@
-/* $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;
@@ -265,29 +272,22 @@ static void isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
                 }
                 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]) {
@@ -405,6 +405,10 @@ static int isdn_status_callback(isdn_ctrl * c)
                         }
 
                        /* 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:
@@ -416,6 +420,7 @@ static int isdn_status_callback(isdn_ctrl * c)
                                                 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;
@@ -430,6 +435,7 @@ static int isdn_status_callback(isdn_ctrl * c)
                                         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  */
@@ -444,7 +450,12 @@ static int isdn_status_callback(isdn_ctrl * c)
                                 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:
@@ -615,10 +626,19 @@ static int isdn_status_callback(isdn_ctrl * c)
                                 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);
@@ -1014,7 +1034,7 @@ static int isdn_set_allcfg(char *src)
                        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);
@@ -1264,9 +1284,9 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
                         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;
@@ -1589,10 +1609,10 @@ static void isdn_close(struct inode *ino, struct file *filep)
        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)
@@ -1607,9 +1627,6 @@ static void isdn_close(struct inode *ino, struct file *filep)
                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)
@@ -1675,6 +1692,7 @@ int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
        int i;
        ulong flags;
        ulong features;
+        isdn_ctrl cmd;
 
        save_flags(flags);
        cli();
@@ -1692,6 +1710,10 @@ int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                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 {
@@ -1699,6 +1721,10 @@ int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev
                                                        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;
                                                }
@@ -1717,6 +1743,7 @@ void isdn_free_channel(int di, int ch, int usage)
 {
        int i;
        ulong flags;
+       isdn_ctrl cmd;
 
        save_flags(flags);
        cli();
@@ -1730,6 +1757,10 @@ void isdn_free_channel(int di, int ch, int usage)
                         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;
                }
@@ -1810,6 +1841,8 @@ int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len,
 
                 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;
@@ -1831,9 +1864,9 @@ int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
         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)
@@ -1970,15 +2003,15 @@ extern int printk(const char *fmt,...);
 
 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;
 }
 
@@ -2000,6 +2033,11 @@ static void isdn_export_syms(void)
 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))) {
@@ -2007,9 +2045,8 @@ int isdn_init(void)
                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], "???");
@@ -2035,7 +2072,7 @@ int isdn_init(void)
                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;
@@ -2045,11 +2082,16 @@ int isdn_init(void)
         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");
@@ -2092,7 +2134,7 @@ void cleanup_module(void)
        }
        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");
index cae4567cb6b9c733fa16d3e5d537b8f4aca3680e..81d7905a2d7194f8e63715d0953ca3416210ed79 100644 (file)
@@ -1,4 +1,4 @@
-/* $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).
  *
@@ -21,6 +21,9 @@
  * 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.
  *
index 3a8a39807402419f8156aeef4fbcf6a6cbc8ba3b..0d5cb12dc335c29d62f54cc207e037ea16dc743f 100644 (file)
@@ -1,4 +1,4 @@
-/* $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
 
@@ -94,7 +105,11 @@ static char *isdn_ttyname_cui  = "cui";
 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
@@ -105,8 +120,6 @@ char *isdn_tty_revision        = "$Revision: 1.11 $";
  *  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;
@@ -208,92 +221,226 @@ void isdn_tty_cleanup_xmit(modem_info *info)
 
         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;
 }
 
 /************************************************************
@@ -412,13 +559,13 @@ void isdn_tty_modem_hup(modem_info * info)
         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) {
@@ -430,7 +577,7 @@ void isdn_tty_modem_hup(modem_info * info)
                 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;
@@ -533,7 +680,7 @@ static int isdn_tty_startup(modem_info * info)
                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
@@ -570,6 +717,7 @@ static void isdn_tty_shutdown(modem_info * info)
 #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) {
@@ -587,96 +735,6 @@ static void isdn_tty_shutdown(modem_info * info)
        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
@@ -691,14 +749,13 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
        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)
@@ -706,30 +763,23 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
                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.
                                          */
@@ -737,23 +787,24 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
                                             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
@@ -772,9 +823,9 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
                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;
 }
 
@@ -805,11 +856,15 @@ static int isdn_tty_chars_in_buffer(struct tty_struct *tty)
 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)
@@ -822,7 +877,7 @@ static void isdn_tty_flush_chars(struct tty_struct *tty)
 
        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);
 }
 
@@ -887,7 +942,7 @@ static int isdn_tty_get_lsr_info(modem_info * info, uint * value)
        status = info->lsr;
        restore_flags(flags);
        result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-       put_fs_long(result, (ulong *) value);
+       put_user(result, (ulong *) value);
        return 0;
 }
 
@@ -909,13 +964,13 @@ static int isdn_tty_get_modem_info(modem_info * info, uint * value)
            | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
            | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
            | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-       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) {
@@ -989,6 +1044,8 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
 
        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
@@ -1015,13 +1072,16 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
                         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));
@@ -1043,7 +1103,7 @@ static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
                         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)
@@ -1452,8 +1512,8 @@ int isdn_tty_modem_init(void)
        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;
@@ -1505,11 +1565,13 @@ int isdn_tty_modem_init(void)
                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;
 }
@@ -1886,6 +1948,7 @@ static int isdn_tty_cmd_ATand(char **p, modem_info * info)
                         switch (isdn_getnum(p)) {
                                 case 0:
                                         m->mdmreg[13] &= ~4;
+                                        m->mdmreg[12] &= ~32;
                                         break;
                                 case 2:
                                         m->mdmreg[13] |= 4;
@@ -1949,11 +2012,11 @@ static int isdn_tty_cmd_ATand(char **p, modem_info * info)
                         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;
@@ -2053,6 +2116,76 @@ static void isdn_tty_cmd_ATA(modem_info * info)
 }
 
 #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
  */
@@ -2246,6 +2379,7 @@ static int isdn_tty_cmd_PLUSV(char **p, modem_info * info)
                                         PARSE_ERROR1;
                                 }
                         }
+                        m->lastDLE = 0;
                         info->vonline = 2;
                         isdn_tty_modem_result(1, info);
                         return 1;
@@ -2384,42 +2518,9 @@ static void isdn_tty_parse_at(modem_info * info)
                                 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))
@@ -2468,7 +2569,7 @@ static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int use
 
        for (cnt = count; cnt > 0; p++, cnt--) {
                if (user)
-                       c = get_fs_byte(p);
+                       c = get_user(p);
                else
                        c = *p;
                total++;
@@ -2559,17 +2660,14 @@ void isdn_tty_modem_ring(void)
 {
        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);
 }
 
@@ -2579,22 +2677,17 @@ void isdn_tty_modem_ring(void)
  */
 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);
 }
 
@@ -2606,20 +2699,17 @@ void isdn_tty_modem_xmit(void)
 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;
 }
index 30ed168348224018aecc47e680a40c2ca743498b..2b76d95624d8f90f109f141d9406239541c95e2b 100644 (file)
@@ -1,6 +1,10 @@
-/* $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.
  *
@@ -41,7 +45,6 @@ int
 BufPoolAdd(struct BufPool *bp, int priority)
 {
        struct Pages   *ptr;
-       long            flags;
        byte           *bptr;
        int             i;
        struct BufHeader *bh = NULL, *prev, *first;
@@ -79,11 +82,8 @@ BufPoolAdd(struct BufPool *bp, int priority)
                bptr += PART_SIZE(bp->pageorder, bp->bpps);
        }
 
-       save_flags(flags);
-       cli();
        first->next = bp->freelist;
        bp->freelist = bh;
-       restore_flags(flags);
        return (0);
 }
 
index 3eea3c8a8dd7faa42b6a733721d64b56ba174bbc..ff49abee5bdc0d98ecbbb6945f0b8348b38933cf 100644 (file)
@@ -1,6 +1,9 @@
-/* $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.
  *
@@ -1387,7 +1390,7 @@ teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
 
         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)
index d7787f32eae7e32a7a4cde245b123b34147c85ff..45c15955856c98223a4ed36ef5837d0764d1a808 100644 (file)
@@ -1,4 +1,4 @@
-/* $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
  * 
@@ -7,6 +7,12 @@
  * 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
@@ -379,11 +385,11 @@ hscx_fill_fifo(struct HscxState *hsp)
 
        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) {
@@ -1700,8 +1706,8 @@ teles_inithardware(void)
                          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;
                }
         }
index 9d4dc3f2215f3622cb817f968740f53439429780..6b829ed957c63e670b630f7e955dd4dfb4799621 100644 (file)
@@ -1,6 +1,9 @@
-/* $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.
@@ -421,6 +424,7 @@ static struct stateentry datastatelist[] =
 {
         {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},
index 1dc68d84ed098ececdb4705731288bf13b6a1dfc..12e885a00fcdc93b1edf19239859a29e9f872441 100644 (file)
@@ -1,6 +1,12 @@
-/* $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
  *
index 62bff6261561a9809302e4c2015e5e58638b967c..42c9c4e7c446c068002c64cde05773ac28860078 100644 (file)
@@ -2675,7 +2675,7 @@ de4x5_free_rx_buffs(struct device *dev)
     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;
index b4b2df5032b86fcc75d9f478e343475fae9da86c..b63a1e155d3e57ffc6eb1cbef58f655dcb695f9e 100644 (file)
@@ -779,9 +779,9 @@ static coproc_operations pss_coproc_operations =
 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;
@@ -790,8 +790,10 @@ attach_pss_mpu (long mem_start, struct address_info *hw_config)
     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
@@ -863,7 +865,9 @@ unload_pss (struct address_info *hw_config)
 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
index 208856183fe8409530f9a8224ad27dd326f1edb5..ffb18033625da2101df246026f1080c895770744 100644 (file)
@@ -35,9 +35,11 @@ fi
 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
index a8952c87c638b87321af46549b44de72e4afae7c..c4925e66a86d744f33866b9e8ddb7ea57b680f3b 100644 (file)
@@ -1145,6 +1145,7 @@ int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int b
        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!
index 20e89cf9fc135f455167b8a262d10f41eac93f8b..70c205cdc6d926766a095d1392bd678a61dca9f9 100644 (file)
@@ -455,6 +455,17 @@ int isofs_bmap(struct inode * inode,int block)
        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);
@@ -593,8 +604,11 @@ void isofs_read_inode(struct inode * 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);
index 83f635b121ee5e5edee8abf1a0bcdcd5ca85cfd6..e280541ee60861966240483045e491421ad5a127 100644 (file)
@@ -963,6 +963,7 @@ ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
                || (   (len == 2)
                    && (name[1] == '.'))))
        {
+               iput(dir);
                return -EEXIST;
        }
 
index f4d4d41d8c82d4b4602c2776a857521e12ee0583..8186f726ca222a7c5e1b0540a368d8071a736078 100644 (file)
@@ -450,7 +450,12 @@ static int nfs_mknod(struct inode *dir, const char *name, int len,
        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;
 }
index 2a4f444f6749484a7640debed2aa78f220873a51..8b2dc39e04ec02055e6f071b0b807cdc10396333 100644 (file)
@@ -1079,7 +1079,7 @@ static int root_nfs_name(char *name)
                                                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);
index 9df6d95b55a7b6ca447ec95687654fef4c812b7f..7e7d88d809605ca8ce5a55fda6dc22255ef93bd6 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ALPHA_STATFS_H
 #define _ALPHA_STATFS_H
 
-#ifndef _LINUX_TYPES_DONT_EXPORT
+#ifndef __KERNEL_STRICT_NAMES
 
 #include <linux/posix_types.h>
 
index d85f6dd331f4688a29aae4dfa448170b11d90aa4..c344bd2fe303e291c50733387a778347a926ff2c 100644 (file)
@@ -66,8 +66,10 @@ static struct sun_floppy_ops sun_fdops;
 #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
 
@@ -110,10 +112,7 @@ static unsigned char sun_82072_fd_inb(int port)
        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?");
 }
@@ -164,10 +163,8 @@ static unsigned char sun_82077_fd_inb(int port)
        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?");
 }
index 9e177e338c188f708236c97a04086c144736d5d7..b36fa26af876da341c9d354a1c3b103f7d93cd68 100644 (file)
@@ -34,6 +34,7 @@
 #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
@@ -50,7 +51,6 @@
 #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                  */
index 08ecebe7fe451509b3f79b2fbb8a0aced8842331..92af7c98f2e04de7825f23a51c07b443100a418f 100644 (file)
@@ -1,4 +1,4 @@
-/* $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).
  *
@@ -21,6 +21,9 @@
  * 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.
@@ -443,12 +446,11 @@ typedef struct modem_info {
   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  */
@@ -457,7 +459,6 @@ typedef struct modem_info {
   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
@@ -468,8 +469,8 @@ typedef struct {
   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;
 
index 5b5919e582113715dc233e057db54e19717f203d..cebd1a500db6c97d5376f0170096654fe0b27881 100644 (file)
@@ -28,6 +28,7 @@
 #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
@@ -231,9 +232,9 @@ extern int          dev_open(struct device *dev);
 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);
index af7e19d07185bd444667453347af7d9f8ff5af5e..28e9bde7acee6e3da3ac5c3bc840d2738cf18f40 100644 (file)
@@ -4,7 +4,7 @@
 #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;
@@ -67,7 +67,7 @@ typedef unsigned short                ushort;
 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
index 71eb42d5deaca7992e0a809e93e3319bfbdd52c0..ea57c43fe6f5d5e399dfaa039c9e0e5774ba96df 100644 (file)
@@ -196,6 +196,7 @@ struct sock
        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;
index c7c68621738752ef7d1c98d5eb0acff9bd1ddc4e..c1a1ef3ee5d64f8ddb1d679e17cb6834da8d3d5f 100644 (file)
@@ -852,10 +852,13 @@ no_cached_page:
 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))
index fba1e260d244fb08535bacc5dfeaca5a621e2af1..b5d114faed51221fc6ef71f08691bcaaa190a27b 100644 (file)
@@ -185,12 +185,7 @@ struct page_descriptor * kmalloc_cache[MAX_CACHE_ORDER];
 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,
@@ -227,6 +222,10 @@ long kmalloc_init(long start_mem, long end_mem)
 }
 
 
+/*
+ * 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;
@@ -234,6 +233,7 @@ void *kmalloc(size_t size, int priority)
        int order, dma;
        struct block_header *p;
        struct page_descriptor *page, **pg;
+       struct size_descriptor *bucket = sizes;
 
        /* Get order */
        order = 0;
@@ -244,6 +244,7 @@ void *kmalloc(size_t size, int priority)
                        if (realsize <= ordersize)
                                break;
                        order++;
+                       bucket++;
                        if (ordersize)
                                continue;
                        printk("kmalloc of too large a block (%d bytes).\n", (int) size);
@@ -253,11 +254,11 @@ void *kmalloc(size_t size, int priority)
 
        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;
@@ -275,15 +276,36 @@ void *kmalloc(size_t size, int priority)
        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);
 
        {
@@ -292,23 +314,27 @@ void *kmalloc(size_t size, int priority)
                /* 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);
        }
 
@@ -319,23 +345,19 @@ void *kmalloc(size_t size, int priority)
        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)) {
index 99a58b1a76b956e98817d578ec532b86e2d9a2fe..f212a182c2e0cc66c317d895fbdfd36796fc5a9a 100644 (file)
@@ -2024,6 +2024,7 @@ void atalk_proto_init(struct net_proto *pro)
        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,
@@ -2042,6 +2043,7 @@ void atalk_proto_init(struct net_proto *pro)
                0, &proc_net_inode_operations,
                atalk_if_get_info
        });
+#endif 
 
        printk(KERN_INFO "Appletalk 0.17 for Linux NET3.035\n");
 }
@@ -2095,9 +2097,11 @@ void cleanup_module(void)
 
        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(&ltalk_packet_type);
        dev_remove_pack(&ppptalk_packet_type);
index 77c3737baa9ceab4c9e4474bfaa30b5e0d607a7c..ac085c9d2ac6916713608eb6ec088e8e292a2943 100644 (file)
@@ -2395,7 +2395,7 @@ void ax25_proto_init(struct net_proto *pro)
        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,
@@ -2414,8 +2414,9 @@ void ax25_proto_init(struct net_proto *pro)
                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) {
index 4950f4336d1046081b6f5951a08d76ea4415732a..ae27303b4baf8c372d41c78124b59db85e3c4993 100644 (file)
@@ -332,7 +332,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
  *     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;
@@ -443,15 +443,12 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
                        }
                }
        }
-       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
@@ -463,6 +460,13 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
        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 
@@ -521,7 +525,7 @@ void netif_rx(struct sk_buff *skb)
  *     This routine causes all interfaces to try to send some data. 
  */
  
-void dev_transmit(void)
+static void dev_transmit(void)
 {
        struct device *dev;
 
@@ -758,7 +762,7 @@ void dev_tint(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.
                         */
index f19d761ec1bab421bc472e8a62571a8e9266b491..f01fe57b67b7c5f186b5b1ebbf345377ca17b581 100644 (file)
@@ -833,7 +833,8 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int priority)
 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++;
index 79f73ebe4bd28b9ea776a0a61c558e298409ee48..03ec7ec9d452fe918e1e22b4f771714f1ea79279 100644 (file)
@@ -8,8 +8,8 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then
   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
index ea2d94e1d15126518ce2df91f8ec496afcd16257..d4f7655ea02b64cf87891a6a98506c8f0f18d098 100644 (file)
@@ -40,7 +40,7 @@ endif
 
 ifeq ($(CONFIG_IP_MASQUERADE),y)
 IPV4_OBJS += ip_masq.o ip_masq_app.o
-M_OBJS += ip_masq_ftp.o ip_masq_irc.o
+M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o
 endif
 
 ifeq ($(CONFIG_IP_ALIAS),y)
index e96f31ab9bc40b3af311ee8fa7b33c984912bff7..204340f5e7bf0e7ea208a207ee90db434fc1d4c9 100644 (file)
@@ -382,6 +382,8 @@ void destroy_sock(struct sock *sk)
                skb = skb2;
        }
        sk->send_head = NULL;
+       sk->send_tail = NULL;
+       sk->send_next = NULL;
        sti();
 
        /*
index 4e8f8e2c3791b7bc3f9cec8065daa6ad1ebf80e9..935903819484b19c4683e791c1f7b4e183e9e856 100644 (file)
@@ -1053,6 +1053,7 @@ static int ip_chain_procinfo(int stage, char *buffer, char **start,
        struct ip_fw *i;
        unsigned long flags;
        int len, p;
+       int last_len = 0;
        
 
        switch(stage)
@@ -1110,14 +1111,18 @@ static int ip_chain_procinfo(int stage, char *buffer, char **start,
                        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);
@@ -1239,6 +1244,7 @@ static struct notifier_block ipfw_dev_notifier={
 
 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",
@@ -1247,11 +1253,13 @@ void ip_fw_init(void)
                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,
@@ -1271,7 +1279,7 @@ void ip_fw_init(void)
                ip_fw_fwd_procinfo
        });
 #endif
-
+#endif
 #ifdef CONFIG_IP_MASQUERADE
         
         /*
index 6aad785f136c1bdd57aa7e1ea29dbc0cec593d8b..20a98e65b5ac2a9c17d2ad06bd4c44dbee726035 100644 (file)
@@ -529,25 +529,26 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                }
 
 #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
 
                /*
index ba3dec01f3e309cf8facf84425b792e9064f6d80..79539b64bf9594381913e51090890471b395ae20 100644 (file)
  *     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>
@@ -26,6 +29,7 @@
 #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>
@@ -458,6 +462,8 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
 
        /*
         * 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)
@@ -575,8 +581,9 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev)
        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",
@@ -600,19 +607,27 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev)
         * 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;
@@ -627,17 +642,16 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev)
        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;
@@ -659,30 +673,44 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
        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",
@@ -698,8 +726,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
 
         if (ms != NULL)
         {
-                int size;
-
                 /*
                  *     Set dport if not defined yet.
                  */
@@ -720,7 +746,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
                                ntohs(ms->daddr));
 #endif
                 }
-                size = skb->len - ((unsigned char *)portptr - skb->h.raw);
                 iph->daddr = ms->saddr;
                 portptr[1] = ms->sport;
 
@@ -738,7 +763,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
                         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);
                 }
 
                 /*
@@ -750,7 +775,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
                  */
                 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);
                }
@@ -758,8 +783,8 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
                 {
                        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)
@@ -849,12 +874,14 @@ done:
 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;
index a9b2d42c797b2eecf5c82a76cbf5c05cb64933b1..21d61ba3a154b66eb747ac87474f3d9ca7a05702 100644 (file)
@@ -21,6 +21,7 @@
  *     
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -438,24 +439,25 @@ int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, in
         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;
@@ -478,14 +480,14 @@ int ip_masq_app_init(void)
 {
         
         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;
 }
 
diff --git a/net/ipv4/ip_masq_raudio.c b/net/ipv4/ip_masq_raudio.c
new file mode 100644 (file)
index 0000000..9fe4e8f
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ *             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 */
index 8960b32be268fa09e63b3c1d663e4b7bae259ac1..a2b1a1daf32ce32462234c3302bd327916da4650 100644 (file)
@@ -450,6 +450,7 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
                {
                        sk->send_tail = skb;
                        sk->send_head = skb;
+                       sk->send_next = skb;
                }
                else
                {
@@ -1115,12 +1116,14 @@ void ip_init(void)
        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
 }
 
index a179613364d63b33eae660fee5c2e07d270784d1..786b9d9fe4ebdaeaa7a770407f9fff75393383d8 100644 (file)
@@ -24,6 +24,7 @@
  *             Resolve IFF_ALLMULTI for rest of cards
  */
 
+#include <linux/config.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 #include <linux/types.h>
@@ -910,6 +911,7 @@ void ip_mr_init(void)
 {
        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,
@@ -922,4 +924,5 @@ void ip_mr_init(void)
                0, &proc_net_inode_operations,
                ipmr_mfc_info
        });
+#endif 
 }
index c01913c74862db341d5714e47586808373ebe5b4..e94b36e3c5af88c6cfa51228891150176d4ec046 100644 (file)
@@ -1766,6 +1766,19 @@ static void tcp_close(struct sock *sk, unsigned long timeout)
         * 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;
 }
@@ -2003,10 +2016,7 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
        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++;
index 1f88f61f68e89ec2303fca94c3be9ccd5d9eae45..d1ed4549955ede70b6d89d20cf5dd197fd0aff8f 100644 (file)
@@ -25,6 +25,9 @@
  *             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>
@@ -404,6 +407,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        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;
@@ -562,6 +566,7 @@ void tcp_window_shrunk(struct sock * sk, u32 window_seq)
        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
@@ -595,6 +600,7 @@ void tcp_window_shrunk(struct sock * sk, u32 window_seq)
                        {
                                sk->send_head = skb;
                                sk->send_tail = skb;
+                               sk->send_next = skb;
                        }
                        else
                        {
@@ -685,6 +691,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
        {
                sk->send_head = NULL;
                sk->send_tail = NULL;
+               sk->send_next = NULL;
                sk->packets_out= 0;
        }
 
@@ -745,8 +752,8 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
         *     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
@@ -755,22 +762,23 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                && 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++;
@@ -878,6 +886,13 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                        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
@@ -915,87 +930,98 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                        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;
        }
 
        /*
@@ -1053,6 +1079,12 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                        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);
                }
        }
 
@@ -1094,45 +1126,18 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
        }
        
        /*
-        * 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;
@@ -1230,8 +1235,12 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
                         * 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:
@@ -1965,7 +1974,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
         *      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);
index e26154b7826a5bb858953749ad13ff1dd08b501d..f25d0fdbc49b365b90be27cf7508bdd1ef7827bd 100644 (file)
@@ -18,6 +18,9 @@
  *             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>
@@ -175,7 +178,7 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
                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 
        {
                /*
@@ -198,9 +201,9 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb)
                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);
@@ -364,10 +367,6 @@ void tcp_write_xmit(struct sock *sk)
 
                        clear_delayed_acks(sk);
 
-                       /*
-                        *      Again we slide the timer wrongly
-                        */
-                        
                        tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
                }
        }
@@ -384,10 +383,17 @@ void tcp_do_retransmit(struct sock *sk, int all)
        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)
@@ -399,7 +405,7 @@ void tcp_do_retransmit(struct sock *sk, int all)
                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 */
@@ -523,17 +529,15 @@ void tcp_do_retransmit(struct sock *sk, int all)
                                        /* 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++;
 
@@ -544,6 +548,11 @@ void tcp_do_retransmit(struct sock *sk, int all)
                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.
@@ -556,8 +565,9 @@ void tcp_do_retransmit(struct sock *sk, int all)
                 *      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;
        }
 }
@@ -888,10 +898,10 @@ void tcp_send_ack(struct sock *sk)
            && 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);
        }
 
        /*
@@ -946,7 +956,7 @@ void tcp_send_ack(struct sock *sk)
 
        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++;
 }
index 68c1f7dfc6b1c4d74340637fb7d42180147fdccb..680f5060a4d66793be64238d334061f1f69280e7 100644 (file)
  *             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>
@@ -35,12 +39,33 @@ void tcp_reset_xmit_timer(struct sock *sk, int why, unsigned long when)
 {
        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);
 }
 
@@ -56,6 +81,15 @@ void tcp_reset_xmit_timer(struct sock *sk, int why, unsigned long when)
 
 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);
 
        /*
@@ -77,7 +111,12 @@ static void tcp_retransmit_time(struct sock *sk, int 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");
 }
 
 /*
@@ -101,7 +140,6 @@ void tcp_retransmit(struct sock *sk, int all)
        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. */
index d7879263a678f8d09291b6cd84604a7477bf6723..9d44db55531f93584f8a64d455d133796a5df034 100644 (file)
@@ -757,7 +757,7 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
                } 
                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),
@@ -2365,10 +2365,11 @@ ipx_proto_init(struct net_proto *pro)
                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");
@@ -2399,9 +2400,11 @@ ipx_proto_finito(void)
                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);
 
index 3e046ed38632c028aba66f97c49bd4806d330639..4f72fdc029d1e89908bac51af0cc9550fb9c98ec 100644 (file)
@@ -1418,6 +1418,7 @@ void nr_proto_init(struct net_proto *pro)
        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,
@@ -1436,6 +1437,7 @@ void nr_proto_init(struct net_proto *pro)
                0, &proc_net_inode_operations, 
                nr_nodes_get_info
        });
+#endif 
 }
 
 #endif
index f037bd04b8b531c8a12af28cb9d2ccef2d0bd29c..9bea73153f3add70bce80763e36b3046651ae6f8 100644 (file)
@@ -90,7 +90,7 @@ function help () {
      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;