diff -u --recursive --new-file pre2.0.9/linux/CREDITS linux/CREDITS
--- pre2.0.9/linux/CREDITS	Tue May 28 08:09:53 1996
+++ linux/CREDITS	Fri May 31 13:54:08 1996
@@ -306,6 +306,14 @@
 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 @@
 
 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: 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 @@
 
 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
@@ -1113,6 +1132,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
diff -u --recursive --new-file pre2.0.9/linux/Documentation/Changes linux/Documentation/Changes
--- pre2.0.9/linux/Documentation/Changes	Tue May 28 08:09:53 1996
+++ linux/Documentation/Changes	Sat Jun  1 19:05:33 1996
@@ -14,7 +14,11 @@
 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 @@
 - 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 @@
 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 @@
    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 @@
 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 @@
    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 @@
 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 @@
 
    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 @@
 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 @@
 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 @@
 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 @@
 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
diff -u --recursive --new-file pre2.0.9/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- pre2.0.9/linux/Documentation/Configure.help	Tue May 28 08:09:54 1996
+++ linux/Documentation/Configure.help	Fri May 31 13:46:26 1996
@@ -267,7 +267,7 @@
   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 @@
   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 @@
   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 @@
    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 @@
   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 @@
   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
diff -u --recursive --new-file pre2.0.9/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- pre2.0.9/linux/Documentation/ioctl-number.txt	Fri May 31 08:02:18 1996
+++ linux/Documentation/ioctl-number.txt	Fri May 31 13:21:44 1996
@@ -1,5 +1,5 @@
 Ioctl Numbers
-10 May 1996
+29 May 1996
 Michael Chastain
 <mec@duracef.shout.net>
 
@@ -50,51 +50,54 @@
 (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 -u --recursive --new-file pre2.0.9/linux/Documentation/isdn/README.audio linux/Documentation/isdn/README.audio
--- pre2.0.9/linux/Documentation/isdn/README.audio	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/isdn/README.audio	Sat Jun  1 11:56:51 1996
@@ -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.
+
+
diff -u --recursive --new-file pre2.0.9/linux/Documentation/isdn/README.icn linux/Documentation/isdn/README.icn
--- pre2.0.9/linux/Documentation/isdn/README.icn	Mon May 20 08:20:58 1996
+++ linux/Documentation/isdn/README.icn	Sat Jun  1 11:58:46 1996
@@ -8,7 +8,7 @@
 Tel: +49 931 2877950
 Fax: +49 931 2877951
 
-email uhl@think.de
+email info@think.de
 WWW   http:/www.think.de
 
 
diff -u --recursive --new-file pre2.0.9/linux/Documentation/networking/framerelay.txt linux/Documentation/networking/framerelay.txt
--- pre2.0.9/linux/Documentation/networking/framerelay.txt	Tue May  7 16:22:16 1996
+++ linux/Documentation/networking/framerelay.txt	Fri May 31 13:35:27 1996
@@ -31,3 +31,9 @@
 
 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.
+
diff -u --recursive --new-file pre2.0.9/linux/MAINTAINERS linux/MAINTAINERS
--- pre2.0.9/linux/MAINTAINERS	Fri May 31 08:02:18 1996
+++ linux/MAINTAINERS	Fri May 31 13:54:08 1996
@@ -180,6 +180,7 @@
 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 @@
 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
 
diff -u --recursive --new-file pre2.0.9/linux/Makefile linux/Makefile
--- pre2.0.9/linux/Makefile	Fri May 31 08:02:18 1996
+++ linux/Makefile	Thu May 30 15:41:03 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 9
+SUBLEVEL = 10
 
 ARCH = i386
 
diff -u --recursive --new-file pre2.0.9/linux/README linux/README
--- pre2.0.9/linux/README	Wed May 15 11:01:14 1996
+++ linux/README	Fri May 31 13:46:26 1996
@@ -138,6 +138,11 @@
    "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. 
diff -u --recursive --new-file pre2.0.9/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- pre2.0.9/linux/arch/i386/defconfig	Mon May 20 08:20:58 1996
+++ linux/arch/i386/defconfig	Fri May 31 15:23:10 1996
@@ -142,8 +142,6 @@
 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_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
diff -u --recursive --new-file pre2.0.9/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- pre2.0.9/linux/arch/i386/kernel/time.c	Fri May 31 08:02:19 1996
+++ linux/arch/i386/kernel/time.c	Fri May 31 13:20:52 1996
@@ -49,13 +49,13 @@
 	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 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;
 
diff -u --recursive --new-file pre2.0.9/linux/drivers/block/README.fd linux/drivers/block/README.fd
--- pre2.0.9/linux/drivers/block/README.fd	Sun May  5 08:51:58 1996
+++ linux/drivers/block/README.fd	Thu May 30 15:56:07 1996
@@ -13,15 +13,15 @@
  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 @@
 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:
 
diff -u --recursive --new-file pre2.0.9/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- pre2.0.9/linux/drivers/block/floppy.c	Tue May 28 08:09:56 1996
+++ linux/drivers/block/floppy.c	Thu May 30 15:56:07 1996
@@ -248,6 +248,9 @@
 
 #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 @@
 	{ 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 @@
 /* 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 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 @@
 		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 @@
 	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 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 @@
 		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 @@
 
 	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 @@
 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 @@
 #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();
diff -u --recursive --new-file pre2.0.9/linux/drivers/cdrom/cm206.c linux/drivers/cdrom/cm206.c
--- pre2.0.9/linux/drivers/cdrom/cm206.c	Mon May 13 23:02:47 1996
+++ linux/drivers/cdrom/cm206.c	Thu May 30 15:40:07 1996
@@ -98,7 +98,7 @@
  * - 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 @@
   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) 
diff -u --recursive --new-file pre2.0.9/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- pre2.0.9/linux/drivers/char/Config.in	Mon May 13 23:02:48 1996
+++ linux/drivers/char/Config.in	Fri May 31 13:46:26 1996
@@ -14,13 +14,19 @@
 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
diff -u --recursive --new-file pre2.0.9/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- pre2.0.9/linux/drivers/char/consolemap.c	Fri Apr 12 15:51:51 1996
+++ linux/drivers/char/consolemap.c	Thu May 30 15:40:07 1996
@@ -57,7 +57,7 @@
     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 @@
   {
     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,
diff -u --recursive --new-file pre2.0.9/linux/drivers/char/ftape/RELEASE-NOTES linux/drivers/char/ftape/RELEASE-NOTES
--- pre2.0.9/linux/drivers/char/ftape/RELEASE-NOTES	Fri Apr 12 15:51:52 1996
+++ linux/drivers/char/ftape/RELEASE-NOTES	Fri May 31 13:54:08 1996
@@ -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 @@
 
 ===== 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 @@
 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
diff -u --recursive --new-file pre2.0.9/linux/drivers/char/ftape/ftape-ctl.c linux/drivers/char/ftape/ftape-ctl.c
--- pre2.0.9/linux/drivers/char/ftape/ftape-ctl.c	Fri Apr 12 15:51:52 1996
+++ linux/drivers/char/ftape/ftape-ctl.c	Fri May 31 13:54:08 1996
@@ -371,7 +371,7 @@
 		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 @@
 			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 @@
 		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):
diff -u --recursive --new-file pre2.0.9/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c
--- pre2.0.9/linux/drivers/char/ftape/kernel-interface.c	Tue May  7 16:22:24 1996
+++ linux/drivers/char/ftape/kernel-interface.c	Fri May 31 13:54:08 1996
@@ -127,7 +127,7 @@
 #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
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- pre2.0.9/linux/drivers/isdn/isdn_common.c	Mon May 20 08:20:59 1996
+++ linux/drivers/isdn/isdn_common.c	Sat Jun  1 11:56:51 1996
@@ -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).
  *
@@ -21,6 +21,13 @@
  * 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.
@@ -102,7 +109,7 @@
 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 @@
                 }
                 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 @@
                         }
 
 			/* 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 @@
                                                 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 @@
                                         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 @@
                                 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 @@
                                 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 @@
 			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 @@
                         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 @@
 	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 @@
 		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 i;
 	ulong flags;
 	ulong features;
+        isdn_ctrl cmd;
 
 	save_flags(flags);
 	cli();
@@ -1692,6 +1710,10 @@
 						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 @@
 							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 @@
 {
 	int i;
 	ulong flags;
+	isdn_ctrl cmd;
 
 	save_flags(flags);
 	cli();
@@ -1730,6 +1757,10 @@
                         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 @@
 
                 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 @@
         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 @@
 
 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 @@
 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 @@
 		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 @@
 		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 @@
         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 @@
 	}
 	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");
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- pre2.0.9/linux/drivers/isdn/isdn_common.h	Mon May 20 08:20:59 1996
+++ linux/drivers/isdn/isdn_common.h	Sat Jun  1 11:56:51 1996
@@ -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.
  *
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- pre2.0.9/linux/drivers/isdn/isdn_tty.c	Tue May 21 19:52:35 1996
+++ linux/drivers/isdn/isdn_tty.c	Sat Jun  1 18:02:27 1996
@@ -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).
  *
@@ -20,6 +20,17 @@
  * 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.
@@ -66,14 +77,14 @@
  */
 
 #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 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 @@
  *  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 @@
 
         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 */
-#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);
-                                        break;
-                                case 6:
-                                        /* u-law */
-                                        if (ifmt)
-                                                isdn_audio_ulaw2alaw(ptr,len);
-                                        break;
-                        }
-                }
-#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;
-        }
-        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;
+        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
+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 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++;
+                }
+                p++;
+                len--;
+        }
+        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 @@
         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 @@
                 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 @@
 		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 @@
 #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 @@
 	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 @@
 	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 @@
 		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 @@
                                             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 @@
 		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 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 @@
 
 	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 @@
 	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 @@
 	    | ((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 @@
 
 	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 @@
                         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 @@
                         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 @@
 	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 @@
 		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 @@
                         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 @@
                         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;
@@ -2054,6 +2117,76 @@
 
 #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
  */
 static int isdn_tty_cmd_PLUSV(char **p, modem_info * info)
@@ -2246,6 +2379,7 @@
                                         PARSE_ERROR1;
                                 }
                         }
+                        m->lastDLE = 0;
                         info->vonline = 2;
                         isdn_tty_modem_result(1, info);
                         return 1;
@@ -2384,42 +2518,9 @@
                                 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 @@
 
 	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 @@
 {
 	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_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_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;
 }
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/teles/buffers.c linux/drivers/isdn/teles/buffers.c
--- pre2.0.9/linux/drivers/isdn/teles/buffers.c	Mon May 20 08:21:00 1996
+++ linux/drivers/isdn/teles/buffers.c	Sat Jun  1 11:56:51 1996
@@ -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 @@
 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 @@
 		bptr += PART_SIZE(bp->pageorder, bp->bpps);
 	}
 
-	save_flags(flags);
-	cli();
 	first->next = bp->freelist;
 	bp->freelist = bh;
-	restore_flags(flags);
 	return (0);
 }
 
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c
--- pre2.0.9/linux/drivers/isdn/teles/callc.c	Mon May 20 08:21:00 1996
+++ linux/drivers/isdn/teles/callc.c	Sat Jun  1 11:56:52 1996
@@ -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 @@
 
         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)
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c
--- pre2.0.9/linux/drivers/isdn/teles/card.c	Mon May 20 08:21:00 1996
+++ linux/drivers/isdn/teles/card.c	Sat Jun  1 11:56:52 1996
@@ -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 @@
 
 	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 @@
 			  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;
 		}
         }
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c
--- pre2.0.9/linux/drivers/isdn/teles/isdnl3.c	Tue May 21 19:52:35 1996
+++ linux/drivers/isdn/teles/isdnl3.c	Sat Jun  1 11:56:52 1996
@@ -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 @@
 {
         {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},
diff -u --recursive --new-file pre2.0.9/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c
--- pre2.0.9/linux/drivers/isdn/teles/llglue.c	Tue May 21 19:52:35 1996
+++ linux/drivers/isdn/teles/llglue.c	Sat Jun  1 11:56:52 1996
@@ -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
  *
diff -u --recursive --new-file pre2.0.9/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- pre2.0.9/linux/drivers/net/de4x5.c	Tue May 28 08:09:56 1996
+++ linux/drivers/net/de4x5.c	Sat Jun  1 18:56:10 1996
@@ -2675,7 +2675,7 @@
     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;
diff -u --recursive --new-file pre2.0.9/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- pre2.0.9/linux/drivers/sound/pss.c	Mon Apr 29 18:05:18 1996
+++ linux/drivers/sound/pss.c	Sat Jun  1 09:41:05 1996
@@ -779,9 +779,9 @@
 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 @@
     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 @@
 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
diff -u --recursive --new-file pre2.0.9/linux/fs/Config.in linux/fs/Config.in
--- pre2.0.9/linux/fs/Config.in	Mon May 20 08:21:03 1996
+++ linux/fs/Config.in	Fri May 31 13:46:26 1996
@@ -35,9 +35,11 @@
 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
diff -u --recursive --new-file pre2.0.9/linux/fs/buffer.c linux/fs/buffer.c
--- pre2.0.9/linux/fs/buffer.c	Mon May 20 08:21:04 1996
+++ linux/fs/buffer.c	Fri May 31 08:01:55 1996
@@ -1145,6 +1145,7 @@
 	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!
diff -u --recursive --new-file pre2.0.9/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- pre2.0.9/linux/fs/isofs/inode.c	Tue May  7 16:22:36 1996
+++ linux/fs/isofs/inode.c	Fri May 31 13:46:26 1996
@@ -455,6 +455,17 @@
 	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 @@
 /* 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);
diff -u --recursive --new-file pre2.0.9/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- pre2.0.9/linux/fs/ncpfs/dir.c	Fri Apr 19 10:08:01 1996
+++ linux/fs/ncpfs/dir.c	Sat Jun  1 16:34:32 1996
@@ -963,6 +963,7 @@
 		|| (   (len == 2)
 		    && (name[1] == '.'))))
 	{
+		iput(dir);
 		return -EEXIST;
 	}
 
diff -u --recursive --new-file pre2.0.9/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- pre2.0.9/linux/fs/nfs/dir.c	Fri May 31 08:02:20 1996
+++ linux/fs/nfs/dir.c	Fri May 31 13:46:26 1996
@@ -450,7 +450,12 @@
 	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;
 }
diff -u --recursive --new-file pre2.0.9/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- pre2.0.9/linux/fs/nfs/nfsroot.c	Fri May 17 15:32:18 1996
+++ linux/fs/nfs/nfsroot.c	Fri May 31 13:46:27 1996
@@ -1079,7 +1079,7 @@
 						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);
diff -u --recursive --new-file pre2.0.9/linux/include/asm-alpha/statfs.h linux/include/asm-alpha/statfs.h
--- pre2.0.9/linux/include/asm-alpha/statfs.h	Wed Mar 27 08:19:29 1996
+++ linux/include/asm-alpha/statfs.h	Sat Jun  1 09:33:54 1996
@@ -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>
 
diff -u --recursive --new-file pre2.0.9/linux/include/asm-sparc/floppy.h linux/include/asm-sparc/floppy.h
--- pre2.0.9/linux/include/asm-sparc/floppy.h	Tue May 28 08:10:01 1996
+++ linux/include/asm-sparc/floppy.h	Thu May 30 15:56:07 1996
@@ -66,8 +66,10 @@
 #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 @@
 	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 @@
 	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?");
 }
diff -u --recursive --new-file pre2.0.9/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- pre2.0.9/linux/include/linux/if_arp.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/if_arp.h	Fri May 31 13:46:27 1996
@@ -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			*/
diff -u --recursive --new-file pre2.0.9/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- pre2.0.9/linux/include/linux/isdn.h	Tue May 21 19:52:38 1996
+++ linux/include/linux/isdn.h	Sat Jun  1 11:56:52 1996
@@ -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 @@
   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 @@
   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 @@
   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;
 
diff -u --recursive --new-file pre2.0.9/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- pre2.0.9/linux/include/linux/netdevice.h	Tue May  7 16:22:39 1996
+++ linux/include/linux/netdevice.h	Sat Jun  1 19:06:01 1996
@@ -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_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);
diff -u --recursive --new-file pre2.0.9/linux/include/linux/types.h linux/include/linux/types.h
--- pre2.0.9/linux/include/linux/types.h	Wed Mar 27 08:19:29 1996
+++ linux/include/linux/types.h	Sat Jun  1 09:33:54 1996
@@ -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 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
diff -u --recursive --new-file pre2.0.9/linux/include/net/sock.h linux/include/net/sock.h
--- pre2.0.9/linux/include/net/sock.h	Tue May 21 19:52:38 1996
+++ linux/include/net/sock.h	Sat Jun  1 19:06:05 1996
@@ -196,6 +196,7 @@
 	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;
diff -u --recursive --new-file pre2.0.9/linux/mm/filemap.c linux/mm/filemap.c
--- pre2.0.9/linux/mm/filemap.c	Fri May 31 08:02:20 1996
+++ linux/mm/filemap.c	Fri May 31 07:37:56 1996
@@ -852,10 +852,13 @@
 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))
diff -u --recursive --new-file pre2.0.9/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- pre2.0.9/linux/mm/kmalloc.c	Fri May 31 08:02:20 1996
+++ linux/mm/kmalloc.c	Fri May 31 16:47:46 1996
@@ -185,12 +185,7 @@
 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 @@
 }
 
 
+/*
+ * 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 @@
 	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 @@
 			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 @@
 
 	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 @@
 	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;
 
-	/* We need to get a new free page..... */
-	/* This can be done with ints on: This is private to this invocation */
+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 */
+
+
+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 @@
 		/* 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 @@
 	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)) {
diff -u --recursive --new-file pre2.0.9/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- pre2.0.9/linux/net/appletalk/ddp.c	Tue May 21 19:52:39 1996
+++ linux/net/appletalk/ddp.c	Fri May 31 13:46:27 1996
@@ -2024,6 +2024,7 @@
 	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 @@
 		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 @@
 
 	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);
diff -u --recursive --new-file pre2.0.9/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- pre2.0.9/linux/net/ax25/af_ax25.c	Tue May 21 19:52:39 1996
+++ linux/net/ax25/af_ax25.c	Fri May 31 13:46:27 1996
@@ -2395,7 +2395,7 @@
 	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 @@
 		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) {
diff -u --recursive --new-file pre2.0.9/linux/net/core/dev.c linux/net/core/dev.c
--- pre2.0.9/linux/net/core/dev.c	Fri May 17 15:32:20 1996
+++ linux/net/core/dev.c	Fri May 31 15:57:38 1996
@@ -332,7 +332,7 @@
  *	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 @@
 			}
 		}
 	}
-	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 @@
 	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 @@
  *	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 @@
 			 *	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.
 			 */
diff -u --recursive --new-file pre2.0.9/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- pre2.0.9/linux/net/core/skbuff.c	Mon May 13 23:02:51 1996
+++ linux/net/core/skbuff.c	Fri May 31 13:46:27 1996
@@ -833,7 +833,8 @@
 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++;
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- pre2.0.9/linux/net/ipv4/Config.in	Tue May 21 19:52:39 1996
+++ linux/net/ipv4/Config.in	Fri May 31 13:46:27 1996
@@ -8,8 +8,8 @@
   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
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- pre2.0.9/linux/net/ipv4/Makefile	Tue Apr  2 13:32:24 1996
+++ linux/net/ipv4/Makefile	Fri May 31 13:46:27 1996
@@ -40,7 +40,7 @@
 
 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)
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- pre2.0.9/linux/net/ipv4/af_inet.c	Tue May 21 19:52:39 1996
+++ linux/net/ipv4/af_inet.c	Thu May 30 15:40:06 1996
@@ -382,6 +382,8 @@
 		skb = skb2;
 	}
 	sk->send_head = NULL;
+	sk->send_tail = NULL;
+	sk->send_next = NULL;
 	sti();
 
   	/*
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- pre2.0.9/linux/net/ipv4/ip_fw.c	Fri May 31 08:02:20 1996
+++ linux/net/ipv4/ip_fw.c	Fri May 31 13:46:27 1996
@@ -1053,6 +1053,7 @@
 	struct ip_fw *i;
 	unsigned long flags;
 	int len, p;
+	int last_len = 0;
 	
 
 	switch(stage)
@@ -1110,14 +1111,18 @@
 			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 @@
 
 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 @@
 		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 @@
 		ip_fw_fwd_procinfo
 	});
 #endif
-
+#endif
 #ifdef CONFIG_IP_MASQUERADE
         
         /*
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- pre2.0.9/linux/net/ipv4/ip_input.c	Tue May 21 19:52:40 1996
+++ linux/net/ipv4/ip_input.c	Fri May 31 13:46:27 1996
@@ -529,25 +529,26 @@
 		}
 
 #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
 
 		/*
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- pre2.0.9/linux/net/ipv4/ip_masq.c	Fri May 17 15:32:20 1996
+++ linux/net/ipv4/ip_masq.c	Fri May 31 13:46:27 1996
@@ -12,10 +12,13 @@
  *	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 @@
 
 	/*
 	 * 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 @@
  	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 @@
 	 * 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 @@
 	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 @@
  	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()
-	 */
+	unsigned short len;
 
-	frag = ntohs(iph->frag_off);
+	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;
 
-	if ((frag & IP_MF) != 0 || (frag & IP_OFFSET) != 0)
-	{
+		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 @@
 
         if (ms != NULL)
         {
-                int size;
-
                 /*
                  *	Set dport if not defined yet.
                  */
@@ -720,7 +746,6 @@
                                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 @@
                         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 @@
                  */
                 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 @@
                 {
 			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 @@
 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;
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_masq_app.c linux/net/ipv4/ip_masq_app.c
--- pre2.0.9/linux/net/ipv4/ip_masq_app.c	Tue Apr 23 13:57:14 1996
+++ linux/net/ipv4/ip_masq_app.c	Fri May 31 13:46:27 1996
@@ -21,6 +21,7 @@
  *	
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -438,24 +439,25 @@
         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 @@
 {
         
         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 -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c
--- pre2.0.9/linux/net/ipv4/ip_masq_raudio.c	Thu Jan  1 02:00:00 1970
+++ linux/net/ipv4/ip_masq_raudio.c	Fri May 31 13:46:27 1996
@@ -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 */
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- pre2.0.9/linux/net/ipv4/ip_output.c	Tue May 21 19:52:40 1996
+++ linux/net/ipv4/ip_output.c	Fri May 31 13:46:27 1996
@@ -450,6 +450,7 @@
 		{
 			sk->send_tail = skb;
 			sk->send_head = skb;
+			sk->send_next = skb;
 		}
 		else
 		{
@@ -1115,12 +1116,14 @@
 	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
 }
 
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- pre2.0.9/linux/net/ipv4/ipmr.c	Mon May 13 23:02:53 1996
+++ linux/net/ipv4/ipmr.c	Fri May 31 13:46:27 1996
@@ -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 @@
 {
 	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 @@
 		0, &proc_net_inode_operations,
 		ipmr_mfc_info
 	});
+#endif	
 }
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- pre2.0.9/linux/net/ipv4/tcp.c	Tue May 21 19:52:40 1996
+++ linux/net/ipv4/tcp.c	Sat Jun  1 10:51:57 1996
@@ -1766,6 +1766,19 @@
 	 * 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 @@
 	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++;
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- pre2.0.9/linux/net/ipv4/tcp_input.c	Tue May 21 19:52:40 1996
+++ linux/net/ipv4/tcp_input.c	Sat Jun  1 10:50:38 1996
@@ -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 @@
 	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 @@
 	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 @@
 			{
 				sk->send_head = skb;
 				sk->send_tail = skb;
+				sk->send_next = skb;
 			}
 			else
 			{
@@ -685,6 +691,7 @@
 	{
 		sk->send_head = NULL;
 		sk->send_tail = NULL;
+		sk->send_next = NULL;
 		sk->packets_out= 0;
 	}
 
@@ -745,8 +752,8 @@
 	 *     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 @@
 		&& 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 @@
 			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
@@ -916,86 +931,97 @@
 	}
 
 	/*
-	 * 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 @@
 			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 @@
 	}
 	
 	/*
-	 * 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->when + sk->rto < jiffies)
-			tcp_retransmit(sk,0);	
-		else
-		{
-			tcp_do_retransmit(sk, 1);
-			tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
-		}
+
+	if (sk->send_head != NULL && (flag&2) && sk->retransmits)
+	{
+		tcp_do_retransmit(sk, 1);
 	}
 
 	return 1;
@@ -1230,8 +1235,12 @@
 			 * 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 @@
 	 *	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);
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- pre2.0.9/linux/net/ipv4/tcp_output.c	Mon May 20 08:21:05 1996
+++ linux/net/ipv4/tcp_output.c	Thu May 30 15:40:06 1996
@@ -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 @@
 		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 @@
 		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 @@
 
 			clear_delayed_acks(sk);
 
-			/*
-			 *	Again we slide the timer wrongly
-			 */
-			 
 			tcp_reset_xmit_timer(sk, TIME_WRITE, sk->rto);
 		}
 	}
@@ -384,10 +383,17 @@
 	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 @@
 		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 @@
 					/* 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 @@
 		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 @@
 		 *	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 @@
 	    && 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 @@
 
   	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++;
 }
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- pre2.0.9/linux/net/ipv4/tcp_timer.c	Mon May 13 23:02:53 1996
+++ linux/net/ipv4/tcp_timer.c	Thu May 30 15:40:06 1996
@@ -18,6 +18,10 @@
  *		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 @@
 {
 	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 @@
 
 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 @@
 
 	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 @@
 	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. */
diff -u --recursive --new-file pre2.0.9/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- pre2.0.9/linux/net/ipx/af_ipx.c	Tue May 21 19:52:40 1996
+++ linux/net/ipx/af_ipx.c	Fri May 31 13:46:27 1996
@@ -757,7 +757,7 @@
 		} 
 		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 @@
 		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 @@
 		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);
 
diff -u --recursive --new-file pre2.0.9/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- pre2.0.9/linux/net/netrom/af_netrom.c	Mon May 13 23:02:53 1996
+++ linux/net/netrom/af_netrom.c	Fri May 31 13:46:27 1996
@@ -1418,6 +1418,7 @@
 	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 @@
 		0, &proc_net_inode_operations, 
 		nr_nodes_get_info
 	});
+#endif	
 }
 
 #endif
diff -u --recursive --new-file pre2.0.9/linux/scripts/Configure linux/scripts/Configure
--- pre2.0.9/linux/scripts/Configure	Mon Mar 25 08:58:28 1996
+++ linux/scripts/Configure	Fri May 31 13:46:27 1996
@@ -90,7 +90,7 @@
      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;
