diff -u --recursive --new-file v1.3.32/linux/Documentation/networking/ppp.txt linux/Documentation/networking/ppp.txt
--- v1.3.32/linux/Documentation/networking/ppp.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/ppp.txt	Mon Oct  9 09:17:53 1995
@@ -0,0 +1,25 @@
+The PPP support for this kernel requires the 2.2.0a version of the
+pppd daemon. You will find the current version of the daemon on
+sunsite.unc.edu in the /pub/Linux/system/Network/serial directory.
+
+Sunsite has many mirror sites. Please feel free to obtain it from
+a mirror site close to you.
+
+If you attempt to use a version of pppd which is not compatible
+then you will have some error condition. It usually is reflected
+in that an ioctl operation will generate a fatal error.
+
+Please do not use earlier versions of the 2.2 package. If you
+obtained a copy from merit.edu or bellatrix then please get an
+update from the sunsite site.
+
+The CCP (Compression Control Protocol) which is supported by this
+code is functional. You will need a compatible BSD compressor on
+your peer site to use the code.
+
+The BSD compression code will only build as a loadable module. There
+was an earlier version which would build it into the kernel but that
+functionality has been removed for various reasons.
+
+--
+Al Longyear                      longyear@netcom.com
diff -u --recursive --new-file v1.3.32/linux/Documentation/smp.ez linux/Documentation/smp.ez
--- v1.3.32/linux/Documentation/smp.ez	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/smp.ez	Tue Oct 10 15:45:25 1995
@@ -0,0 +1,413 @@
+\begindata{text,748928}
+\textdsversion{12}
+\template{default}
+\center{\underline{\bigger{\bigger{\bigger{An Implementation Of 
+Multiprocessor Linux
+
+}}}}}
+\italic{
+}\indent{\indent{This document describes the implementation of a simple SMP 
+Linux kernel extension and how to use this to develop SMP Linux kernels for 
+architectures other than the Intel MP v1.1 architecture for Pentium and 486 
+processors.}\italic{
+
+}}\italic{
+
+
+Alan Cox, 1995
+
+
+The author wishes to thank Caldera Inc whose donation of an ASUS dual 
+pentium board made this project possible, and Thomas Radke, whose initial 
+work on multiprocessor Linux formed the backbone of this project.
+
+\begindata{bp,941568}
+\enddata{bp,941568}
+\view{bpv,941568,0,0,0}
+}
+\heading{Background: The Intel MP specification.
+
+}
+	Most IBM PC style multiprocessor motherboards combine Intel 486 or Pentium 
+processors and glue chipsets with a hardware/software specification. The 
+specification places much of the onus for hard work on the chipset and 
+hardware rather than the operating system.
+
+
+	The Intel pentium processors have a wide variety of inbuilt facilities for 
+supporting multiprocessing, including hardware cache coherency, built in 
+interprocessor interrupt handling and a set of atomic test and set, 
+exchange and similar operations. The cache coherency in paticular makes the 
+operating systems job far easier.
+
+
+	The specification defines a detailed configuration structure in ROM that 
+the boot up processor can read to find the full configuration of the 
+processors and busses. It also defines a procedure for starting up the 
+other processors.
+
+
+\heading{Mutual Exclusion Within A Single Processor Linux Kernel
+
+}
+	For any kernel to function in a sane manner it has to provide internal 
+locking and protection of its own tables to prevent two processes updating 
+them at once and for example allocating the same memory block. There are 
+two strategies for this within current Unix and Unixlike kernels. 
+Traditional unix systems from the earliest of days use a scheme of 'Coarse 
+Grained Locking' where the entire kernel is protected as a small number of 
+locks only. Some modern systems use fine grained locking. Because fine 
+grained locking has more overhead it is normally used only on 
+multiprocessor kernels and real time kernels. In a real time kernel the 
+fine grained locking reduces the amount of time locks are held and reduces 
+the critical (to real time programming at least) latency times.
+
+
+	Within the Linux kernel certain guarantees are made. No process running in 
+kernel mode will be pre-empted by another kernel mode process unless it 
+voluntarily sleeps.  This ensures that blocks of kernel code are 
+effectively atomic with respect to other processes and greatly simplifies 
+many operation. Secondly interrupts may pre-empt a kernel running process, 
+but will always return to that process. A process in kernel mode may 
+disable interrupts on the processor and guarantee such an interruption will 
+not occur. The final guarantee is that an interrupt will not bne pre-empted 
+by a kernel task. That is interrupts will run to completion or be 
+pre-empted by other interrupts only.
+
+
+	The SMP kernel chooses to continue these basic guarantees in order to make 
+initial implementation and deployment easier.  A single lock is maintained 
+across all processors. This lock is required to access the kernel space. 
+Any processor may hold it and once it is held may also re-enter the kernel 
+for interrupts and other services whenever it likes until the lock is 
+relinquished. This lock ensures that a kernel mode process will not be 
+pre-empted and ensures that blocking interrupts in kernel mode behaves 
+correctly. This is guaranteed because only the processor holding the lock 
+can be in kernel mode, only kernel mode processes can disable interrupts 
+and only the processor holding the lock may handle an interrupt.
+
+
+	Such a choice is however poor for performance. In the longer term it is 
+neccessary to move to finer grained parallelism in order to get the best 
+system performance. This can be done heirarchically by gradually refining 
+the locks to cover smaller areas. With the current kernel highly CPU bound 
+process sets perform well but I/O bound task sets can easily degenerate to 
+near single processor performance levels. This refinement will be needed to 
+get the best from Linux/SMP.
+
+
+\subheading{\heading{Changes To The Portable Kernel Components
+
+
+}}	The kernel changes are split into generic SMP support changes and 
+architecture specific changes neccessary to accomodate each different 
+processor type Linux is ported to.
+
+
+\subsection{Initialisation}
+
+
+	The first problem with a multiprocessor kernel is starting the other 
+processors up. Linux/SMP defines that a single processor enters the normal 
+kernel entry point start_kernel(). Other processors are assumed not to be 
+started or to have been captured elsewhere. The first processor begins the 
+normal Linux initialisation sequences and sets up paging, interrupts and 
+trap handlers. After it has obtained the processor information about the 
+boot CPU, the architecture specific function \
+
+
+\description{
+\leftindent{\bold{void smp_store_cpu_info(int processor_id)
+
+}}}
+is called to store any information about the processor into a per processor 
+array. This includes things like the bogomips speed ratings.
+
+
+	Having completed the kernel initialisation the architecture specific 
+function
+
+
+\description{\leftindent{\bold{void smp_boot_cpus(void)
+
+}}}
+is called and is expected to start up each other processor and cause it to 
+enter start_kernel() with its paging registers and other control 
+information correctly loaded. Each other processor skips the setup except 
+for calling the trap and irq initialisation functions that are needed on 
+some processors to set each CPU up correctly.  These functions will 
+probably need to be modified in existing kernels to cope with this.
+
+
+	Each additional CPU the calls the architecture specific function
+
+
+\description{\leftindent{\bold{void smp_callin(void)
+
+
+}}}which does any final setup and then spins the processor while the boot 
+up processor forks off enough idle threads for each processor. This is 
+neccessary because the scheduler assumes there is always something to run. 
+ Having generated these threads and forked init the architecture specific \
+
+
+
+\bold{\description{\leftindent{void smp_commence(void)}}}
+
+
+function is invoked. This does any final setup and indicates to the system 
+that multiprocessor mode is now active. All the processors spinning in the 
+smp_callin() function are now released to run the idle processes, which 
+they will run when they have no real work to process.
+
+
+\subsection{Scheduling
+
+}
+	The kernel scheduler implements a simple but very and effective task 
+scheduler. The basic structure of this scheduler is unchanged in the 
+multiprocessor kernel. A processor field is added to each task, and this 
+maintains the number of the processor executing a given task, or a magic 
+constant (NO_PROC_ID)  indicating the job is not allocated to a processor. \
+
+
+	\
+
+
+	Each processor executes the scheduler itself and will select the next task 
+to run from all runnable processes not allocated to a different processor. 
+The algorithm used by the selection is otherwise unchanged. This is 
+actually inadequate for the final system because there are advantages to 
+keeping a process on the same CPU, especially on processor boards with per 
+processor second level caches.
+
+
+	Throughout the kernel the variable 'current' is used as a global for the 
+current process. In Linux/SMP this becomes a macro which expands to 
+current_set[smp_processor_id()]. This enables almost the entire kernel to 
+be unaware of the array of running processors, but still allows the SMP 
+aware kernel modules to see all of the running processes.
+
+
+	The fork system call is modified to generate multiple processes with a 
+process id of zero until the SMP kernel starts up properly. This is 
+neccessary because process number 1 must be init, and it is desirable that 
+all the system threads are process 0. \
+
+
+
+	The final area within the scheduling of processes that does cause problems 
+is the fact the uniprocessor kernel hard codes tests for the idle threads 
+as task[0] and the init process as task[1]. Because there are multiple idle 
+threads it is neccessary to replace these with tests that the process id is 
+0 and a search for process ID 1, respectively.
+
+\subheading{
+}\subsection{Memory Management}\heading{
+
+
+}	The memory management core of the existing Linux system functions 
+adequately within the multiprocessor framework providing the locking is 
+used. Certain processor specific areas do need changing, in paticular 
+invalidate() must invalidate the TLB's of all processors before it returns.
+
+
+\subsection{Miscellaneous Functions}
+
+\heading{
+}	The portable SMP code rests on a small set of functions and variables 
+that are provided by the processor specification functionality. These are
+
+
+\display{\bold{int smp_processor_id(void)
+
+
+}}which returns the identity of the process the call is executed upon. This 
+call is assumed to be valid at all times. This may mean additional tests 
+are needed during initialisation.
+
+
+	\display{\bold{int smp_num_cpus;
+
+}}
+	This is the number of processors in the system. \
+
+
+
+	\bold{void smp_message_pass(int target, int msg, unsigned long data,
+
+		int wait)
+
+}
+	This function passes messages between processors. At the moment it is not 
+sufficiently defined to sensibly document and needs cleaning up and further 
+work. Refer to the processor specific code documentation for more details.
+
+
+\heading{Architecture Specific Code For the Intel MP Port
+
+}
+	The architecture specific code for the intel port splits fairly cleanly 
+into four sections. Firstly the initialisation code used to boot the 
+system, secondly the message handling and support code, thirdly the 
+interrupt and kernel syscall entry function handling and finally the 
+extensions to standard kernel facilities to cope with multiple processors.
+
+
+\subsection{Initialisation
+
+
+}	The intel MP architecture captures all the processors except for a single 
+processor known as the 'boot processor' in the BIOS at boot time. Thus a 
+single processor enters the kernel bootup code. The first processor 
+executes the bootstrap code, loads and uncompresses the kernel. Having 
+unpacked the kernel it sets up the paging and control registers then enters 
+the C kernel startup.
+
+
+	The assembler startup code for the kernel is modified so that it can be 
+used by the other processors to do the processor identification and various 
+other low level configurations but does not execute those parts of the 
+startup code that would damage the running system (such as clearing the BSS 
+segment). \
+
+
+
+	In the initialisation done by the first processor the arch/i386/mm/init 
+code is modified to scan the low page, top page and BIOS for intel MP 
+signature blocks. This is neccessary because the MP signature blocks must 
+be read and processed before the kernel is allowed to allocate and destroy 
+the page at the top of low memory. Having established the number of 
+processors it reserves a set of pages to provide a stack come boot up area 
+for each processor in the system. These must be allocated at startup to 
+ensure they fall below the 1Mb boundary.
+
+
+	Further processors are started up in smp_boot_cpus() by programming the 
+APIC controller registers and sending an inter-processor interrupt (IPI) to 
+the processor. This message causes the target processor to begin executing 
+code at the start of any page of memory within the lowest 1Mb, in 16bit 
+real mode. The kernel uses the single page it allocated for each processor 
+to use as stack. Before booting a given CPU the relocatable code from 
+trampoline.S and trampoline32.S is copied to the bottom of its stack page 
+and used as the target for the startup. \
+
+
+
+	The trampoline code calculates the desired stack base from the code 
+segment (since the code segment on startup is the bottom of the stack), 
+ enters 32bit mode and jumps to the kernel entry assembler. This as 
+described above is modified to only execute the parts necessary for each 
+processor, and then to enter start_kernel(). On entering the kernel the 
+processor initialises its trap and interrupt handlers before entering 
+smp_callin(), where it reports its status and sets a flag that causes the 
+boot processor to continue and look for further processors. The processor 
+then spins until smp_commence() is invoked.
+
+
+	Having started each processor up the smp_commence( ) function flips a 
+flag. Each processor spinning in smp_callin() then loads the task register 
+with the task state segment (TSS) of its idle thread as is needed for task 
+switching.
+
+
+\subsection{Message Handling and Support Code}
+
+
+	The architecture specific code implements the smp_processor_id() function 
+by querying the APIC logical identity register. Because the APIC isnt 
+mapped into the kernel address space at boot, the initial value returned is 
+rigged by setting the APIC base pointer to point at a suitable constant. 
+Once the system starts doing the SMP setup (in smp_boot_cpus()), the APIC 
+is mapped with a vremap() call and the apic pointer is adjusted 
+appropriately. From then on the real APIC logical identity register is 
+read.
+
+
+	Message passing is accomplished using a pair of IPI's on interrupt 13 
+(unused by the 80486 FPU's in SMP mode) and interrupt 16. Two are used in 
+order to seperate messages that cannot be processed until the receiver 
+obtains the kernel spinlock from messages that can be processed 
+immediately. In effect IRQ 13 is a fast IRQ handler that does not obtain 
+the locks, and cannot cause a reschedule, while IRQ 16 is a slow IRQ that 
+must acquire the kernel spinlocks and can cause a reschedule. This 
+interrupt is used for passing on slave timer messages from the processor 
+that receives the timer interrupt to the rest of the processors, so that 
+they can reschedule running tasks.
+
+
+\subsection{Entry And Exit Code}
+
+
+	A single spinlock protects the entire kernel. The interrupt handlers, the 
+syscall entry code and the exception handlers all acquire the lock before 
+entering the kernel proper. When the processor is trying to acquire the 
+spinlock it spins continually on the lock with interrupts disabled. This 
+causes a specific deadlock problem. The lock owner may need to send an 
+invalidate request to the rest of the processors and wait for these to 
+complete before continuing. A processor spinning on the lock would not be 
+able to do thus. Thus the loop of the spinlock tests and handles invalidate 
+requests. If the invalidate bit for the spinning CPU is set the processor 
+invalidates its TLB and atomically clears the bit. When the spinlock is 
+obtained that processor will take an IPI and in the IPI test the bit and 
+skip the invalidate as the bit is clear.
+
+
+	One complexity of the spinlock is that a process running in kernel mode 
+can sleep voluntarily and be pre-empted. A switch from such a process to a 
+process executing in user space may reduce the lock count. To track this 
+the kernel uses a syscall_count and a per process lock_depth parameter to 
+track the kernel lock state. The switch_to() function is modified in SMP 
+mode to adjust the lock appropriately.
+
+
+	The final problem is the idle thread. In the single processor kernel the 
+idle thread executes 'hlt' instructions. This saves power and reduces the 
+running temperature of the processors when they are idle. However it means 
+the process spends all its time in kernel mode and would thus hold the 
+kernel spinlock. The SMP idle thread continually reschedules a new task and 
+returns to user mode. This is far from ideal and will be modified to use 
+'hlt' instructions and release the spinlock soon. Using 'hlt' is even more 
+beneficial on a multiprocessor system as it almost completely takes an idle 
+processor off the bus.
+
+
+	Interrupts are distributed by an i82489 APIC. This chip is set up to work 
+as an emulation of the traditional PC interrupt controllers when the 
+machine boots (so that an Intel MP machine boots one CPU and PC 
+compatible). The kernel has all the relevant locks but does not yet 
+reprogram the 82489 to deliver interrupts to arbitary processors as it 
+should. This requires further modification of the standard Linux interrupt 
+handling code, and is paticularly messy as the interrupt handler behaviour 
+has to change as soon as the 82489 is switched into SMP mode.
+
+
+\subsection{Extensions To Standard Facilities}
+
+
+	The kernel maintains a set of per processor control information such as 
+the speed of the processor for delay loops. These functions on the SMP 
+kernel look the values up in a per processor array that is set up from the 
+data generated at boot up by the smp_store_cpu_info() function. This 
+includes other facts such as whether there is an FPU on the processor. The 
+current kernel does not handle only some processors having floating point.
+
+
+	The highly useful atomic bit operations are prefixed with the 'lock' 
+prefix in the SMP kernel to maintain their atomic properties when used 
+outside of (and by) the spinlock and message code. Amongst other things 
+this is needed for the invalidate handler, as all  CPU's will invalidate at 
+the same time without any locks.
+
+
+	Interrupt 13 floating point error reporting is removed. This facility is 
+not usable on a multiprocessor board, nor relevant to the Intel MP 
+architecture which does not cover the 80386/80387 processor pair. \
+
+
+
+	The /proc filesystem support is changed so that the /proc/cpuinfo file 
+contains a column for each processor present. This information is extracted 
+from the data save by smp_store_cpu_info().
+
+\enddata{text,748928}
diff -u --recursive --new-file v1.3.32/linux/Makefile linux/Makefile
--- v1.3.32/linux/Makefile	Fri Oct  6 14:35:13 1995
+++ linux/Makefile	Fri Oct  6 14:35:44 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 32
+SUBLEVEL = 33
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.32/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v1.3.32/linux/arch/alpha/config.in	Wed Sep 27 15:59:56 1995
+++ linux/arch/alpha/config.in	Mon Oct  9 13:10:40 1995
@@ -39,6 +39,7 @@
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" \
 	-o "$CONFIG_ALPHA_EB64" = "y" -o "$CONFIG_ALPHA_EB64P" = "y" ]
 then
+	bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM n
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_APECS y
 fi
@@ -151,8 +152,8 @@
   bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
 fi
 tristate 'PPP (point-to-point) support' CONFIG_PPP n
-if [ "$CONFIG_PPP" != "n" ]; then
-  bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n
+if [ ! "$CONFIG_PPP" = "n" ]; then
+comment 'CCP compressors for PPP are only built as modules.'
 fi
 if [ "$CONFIG_AX25" = "y" ]; then
 	bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y
diff -u --recursive --new-file v1.3.32/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v1.3.32/linux/arch/alpha/kernel/irq.c	Wed Oct  4 14:14:28 1995
+++ linux/arch/alpha/kernel/irq.c	Mon Oct  9 13:10:40 1995
@@ -578,7 +578,8 @@
 			machine_check(vector, la_ptr, &regs);
 			break;
 		case 3:
-#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME)
+#if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \
+    defined(CONFIG_ALPHA_SRM)
 			srm_device_interrupt(vector, &regs);
 #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 			cabriolet_and_eb66p_device_interrupt(vector, &regs);
diff -u --recursive --new-file v1.3.32/linux/arch/alpha/kernel/lca.c linux/arch/alpha/kernel/lca.c
--- v1.3.32/linux/arch/alpha/kernel/lca.c	Fri Oct  6 14:35:13 1995
+++ linux/arch/alpha/kernel/lca.c	Mon Oct  9 13:10:40 1995
@@ -305,10 +305,22 @@
 
 
 
+/*
+ * Constants used during machine-check handling.  I suppose these
+ * could be moved into lca.h but I don't see much reason why anybody
+ * else would want to use them.
+ */
+#define ESR_EAV	(1UL<< 0)	/* error address valid */
+#define ESR_CEE	(1UL<< 1)	/* correctable error */
+#define ESR_UEE (1UL<< 2)	/* uncorrectable error */
+#define ESR_NXM (1UL<<12)	/* non-existent memory */
+
+
 void lca_machine_check (unsigned long vector, unsigned long la, struct pt_regs *regs)
 {
 	const char * reason;
 	union el_lca el;
+	char buf[128];
 
 	printk("lca: machine check (la=0x%lx)\n", la);
 	el.c = (struct el_common *) la;
@@ -332,31 +344,50 @@
 	      case MCHK_K_SIO_IOCHK:	reason = "SIO IOCHK occurred on ISA bus"; break;
 	      case MCHK_K_DCSR:		reason = "MCHK_K_DCSR"; break;
 	      case MCHK_K_UNKNOWN:
-	      default:			reason = "reason for machine-check unknown"; break;
+	      default:
+		sprintf(buf, "reason for machine-check unknown (0x%lx)", el.s->reason);
+		reason = buf;
+		break;
 	}
 
+	wrmces(rdmces());	/* reset machine check pending flag */
+
 	switch (el.c->size) {
 	      case sizeof(struct el_lca_mcheck_short):
 		printk("  Reason: %s (short frame%s):\n",
-		       reason, el.h->retry ? ", retryable" : "");
-		printk("\tesr: %lx  ear: %lx\n", el.s->esr, el.s->ear);
-		printk("\tdc_stat: %lx  ioc_stat0: %lx  ioc_stat1: %lx\n",
+		       reason, el.c->retry ? ", retryable" : "");
+		printk("    esr: %lx  ear: %lx\n", el.s->esr, el.s->ear);
+		printk("    dc_stat: %lx  ioc_stat0: %lx  ioc_stat1: %lx\n",
 		       el.s->dc_stat, el.s->ioc_stat0, el.s->ioc_stat1);
+		if (el.c->retry &&
+		    (el.s->esr & (ESR_EAV|ESR_CEE|ESR_UEE|ESR_NXM)) == (ESR_EAV|ESR_CEE))
+		{
+			unsigned long addr, val;
+
+			/* temporarily disable processor/system correctable error logging: */
+			wrmces(0x18);
+			addr = el.s->ear & ~ (0x7<<29 | 0x7);
+			addr += IDENT_ADDR;
+			printk("  correcting quadword at address %lx\n", addr);
+			val = *(volatile long *)addr;
+			*(volatile long *)addr = val;
+			/* reenable all machine checks: */
+			wrmces(0x00);
+		}
 		break;
 
 	      case sizeof(struct el_lca_mcheck_long):
 		printk("  Reason: %s (long frame%s):\n",
-		       reason, el.h->retry ? ", retryable" : "");
-		printk("\treason: %lx  exc_addr: %lx  dc_stat: %lx\n", 
+		       reason, el.c->retry ? ", retryable" : "");
+		printk("    reason: %lx  exc_addr: %lx  dc_stat: %lx\n", 
 		       el.l->pt[0], el.l->exc_addr, el.l->dc_stat);
-		printk("\tesr: %lx  ear: %lx  car: %lx\n", el.l->esr, el.l->ear, el.l->car);
-		printk("\tioc_stat0: %lx  ioc_stat1: %lx\n", el.l->ioc_stat0, el.l->ioc_stat1);
+		printk("    esr: %lx  ear: %lx  car: %lx\n", el.l->esr, el.l->ear, el.l->car);
+		printk("    ioc_stat0: %lx  ioc_stat1: %lx\n", el.l->ioc_stat0, el.l->ioc_stat1);
 		break;
 
 	      default:
 		printk("  Unknown errorlog size %d\n", el.c->size);
 	}
-	wrmces(rdmces());		/* reset machine check asap */
 }
 
 #endif /* CONFIG_ALPHA_LCA */
diff -u --recursive --new-file v1.3.32/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v1.3.32/linux/arch/alpha/kernel/process.c	Fri Oct  6 14:35:13 1995
+++ linux/arch/alpha/kernel/process.c	Mon Oct  9 13:10:40 1995
@@ -25,6 +25,7 @@
 #include <linux/stat.h>
 #include <linux/mman.h>
 
+#include <asm/reg.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -144,8 +145,59 @@
 /*
  * fill in the user structure for a core dump..
  */
-void dump_thread(struct pt_regs * regs, struct user * dump)
+void dump_thread(struct pt_regs * pt, struct user * dump)
 {
+	/* switch stack follows right below pt_regs: */
+	struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
+
+	dump->magic = CMAGIC;
+	dump->start_code  = current->mm->start_code;
+	dump->start_data  = current->mm->start_data;
+	dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
+	dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
+	dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT;
+	dump->u_ssize =
+	  (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+	/*
+	 * We store the registers in an order/format that is
+	 * compatible with DEC Unix/OSF/1 as this makes life easier
+	 * for gdb.
+	 */
+	dump->regs[EF_V0]  = pt->r0;
+	dump->regs[EF_T0]  = pt->r1;
+	dump->regs[EF_T1]  = pt->r2;
+	dump->regs[EF_T2]  = pt->r3;
+	dump->regs[EF_T3]  = pt->r4;
+	dump->regs[EF_T4]  = pt->r5;
+	dump->regs[EF_T5]  = pt->r6;
+	dump->regs[EF_T6]  = pt->r7;
+	dump->regs[EF_T7]  = pt->r8;
+	dump->regs[EF_S0]  = sw->r9;
+	dump->regs[EF_S1]  = sw->r10;
+	dump->regs[EF_S2]  = sw->r11;
+	dump->regs[EF_S3]  = sw->r12;
+	dump->regs[EF_S4]  = sw->r13;
+	dump->regs[EF_S5]  = sw->r14;
+	dump->regs[EF_S6]  = sw->r15;
+	dump->regs[EF_A3]  = pt->r19;
+	dump->regs[EF_A4]  = pt->r20;
+	dump->regs[EF_A5]  = pt->r21;
+	dump->regs[EF_T8]  = pt->r22;
+	dump->regs[EF_T9]  = pt->r23;
+	dump->regs[EF_T10] = pt->r24;
+	dump->regs[EF_T11] = pt->r25;
+	dump->regs[EF_RA]  = pt->r26;
+	dump->regs[EF_T12] = pt->r27;
+	dump->regs[EF_AT]  = pt->r28;
+	dump->regs[EF_SP]  = rdusp();
+	dump->regs[EF_PS]  = pt->ps;
+	dump->regs[EF_PC]  = pt->pc;
+	dump->regs[EF_GP]  = pt->gp;
+	dump->regs[EF_A0]  = pt->r16;
+	dump->regs[EF_A1]  = pt->r17;
+	dump->regs[EF_A2]  = pt->r18;
+	memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
 }
 
 /*
diff -u --recursive --new-file v1.3.32/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.32/linux/arch/i386/config.in	Fri Oct  6 14:35:14 1995
+++ linux/arch/i386/config.in	Tue Oct 10 15:45:26 1995
@@ -58,7 +58,7 @@
   bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE y
   bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE n
 fi
-if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_MULTICAST" = "y" -a "$CONFIG_NET_IPIP" = "y" ]; then
+if [ "$CONFIG_IP_FORWARD" = "y" -a "$CONFIG_IP_MULTICAST" = "y" ]; then
   bool 'IP: multicast routing(in progress)' CONFIG_IP_MROUTE n
 fi
 comment '(it is safe to leave these untouched)'
@@ -76,6 +76,9 @@
   bool 'Amateur Radio NET/ROM' CONFIG_NETROM n
 fi
 bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK n
+if [ "$CONFIG_NETLINK" = "y" ]; then
+  bool 'Routing messages' CONFIG_RTNETLINK y
+fi
 fi
 
 comment 'SCSI support'
@@ -137,17 +140,17 @@
 comment 'Skipping network driver configuration options...'
 
 else
-tristate 'Dummy net driver support' CONFIG_DUMMY y
+tristate 'Dummy net driver support' CONFIG_DUMMY m
 tristate 'SLIP (serial line) support' CONFIG_SLIP n
 if [ "$CONFIG_SLIP" != "n" ]; then
   bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
 fi
 tristate 'PPP (point-to-point) support' CONFIG_PPP n
-if [ "$CONFIG_PPP" != "n" ]; then
-  bool ' 16 channels instead of 4' CONFIG_PPP_LOTS n
+if [ ! "$CONFIG_PPP" = "n" ]; then
+comment 'CCP compressors for PPP are only built as modules.'
 fi
 if [ "$CONFIG_AX25" = "y" ]; then
-	bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC y
+	bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC n
 else
 	bool 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC n
 fi
@@ -182,15 +185,15 @@
 		tristate 'EtherExpress support' CONFIG_EEXPRESS n
 		bool 'NI5210 support' CONFIG_NI52 n
 		bool 'NI6510 support' CONFIG_NI65 n
-		if [ "$CONFIG_AX25" = "y" ]; then
-			bool 'Ottawa PI and PI/2 support' CONFIG_PI y
-		fi
 		tristate 'WaveLAN support' CONFIG_WAVELAN n
 	fi
 	tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
 	tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
 	tristate 'HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100 n
 	tristate 'NE2000/NE1000 support' CONFIG_NE2000 y
+	if [ "$CONFIG_AX25" = "y" ]; then
+		bool 'Ottawa PI and PI/2 support' CONFIG_PI y
+	fi
 	bool 'SK_G16 support' CONFIG_SK_G16 n
 fi
 bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
diff -u --recursive --new-file v1.3.32/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v1.3.32/linux/arch/i386/kernel/Makefile	Wed Oct  4 14:14:28 1995
+++ linux/arch/i386/kernel/Makefile	Tue Oct 10 15:38:41 1995
@@ -33,6 +33,8 @@
 hexify:
 	$(HOSTCC) hexify.c -o hexify
 
+smp.c: trampoline.hex
+
 trampoline.hex: trampoline hexify
 	(dd if=trampoline bs=1 skip=32 | ./hexify >trampoline.hex )
 
diff -u --recursive --new-file v1.3.32/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v1.3.32/linux/arch/i386/kernel/smp.c	Wed Oct  4 14:14:28 1995
+++ linux/arch/i386/kernel/smp.c	Tue Oct 10 15:45:26 1995
@@ -304,8 +304,14 @@
 							mpf->mpf_feature1);
 						return;
 				}
+				/*
+				 *	Read the physical hardware table. If there isn't one
+				 *	the processors present are 0 and 1.
+				 */
 				if(mpf->mpf_physptr)
 					smp_read_mpc((void *)mpf->mpf_physptr);
+				else
+					cpu_present_map=3;
 				printk("Processors: %d\n", num_processors);
 			}
 		}
diff -u --recursive --new-file v1.3.32/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.3.32/linux/drivers/block/aztcd.c	Mon Sep 18 14:53:49 1995
+++ linux/drivers/block/aztcd.c	Tue Oct 10 11:10:42 1995
@@ -142,6 +142,7 @@
 # ifndef CONFIG_MODVERSIONS
     char kernel_version[]= UTS_RELEASE;
 # endif
+#define aztcd_init init_module
 #endif
 
 #include <linux/errno.h>
@@ -1524,22 +1525,15 @@
 /*
  * Test for presence of drive and initialize it.  Called at boot time.
  */
-#ifndef MODULE 
-unsigned long aztcd_init(unsigned long mem_start, unsigned long mem_end)
-#else
-int init_module(void)
-#endif
+
+int aztcd_init(void)
 {       long int count, max_count;
 	unsigned char result[50];
 	int st;
 
 	if (azt_port <= 0) {
 	  printk("aztcd: no Aztech CD-ROM Initialization");
-#ifndef MODULE
-	  return (mem_start);
-#else
           return -EIO;
-#endif	  
 	}
 	printk("aztcd: Aztech, Orchid, Okano, Wearnes CD-ROM Driver (C) 1994,1995 W.Zimmermann\n");
 	printk("aztcd: DriverVersion=%s  BaseAddress=0x%x \n",AZT_VERSION,azt_port);
@@ -1547,22 +1541,14 @@
 	if (check_region(azt_port, 4)) {
 	  printk("aztcd: conflict, I/O port (%X) already used\n",
 		 azt_port);
-#ifndef MODULE
-	  return (mem_start);
-#else
           return -EIO;
-#endif	  
 	}
 
 #ifdef AZT_SW32   /*CDROM connected to Soundwave32 card*/
         if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500)
            { printk("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
 		 AZT_SW32_BASE_ADDR,AZT_SW32_INIT,AZT_SW32_CONFIG_REG,AZT_SW32_ID_REG);
-#ifndef MODULE
-	         return (mem_start);
-#else
                  return -EIO;
-#endif	  
 	   }
         else                
            { printk("aztcd: Soundwave32 card detected at %x  Version %x\n",
@@ -1590,7 +1576,7 @@
 #ifndef MODULE
              if (azt_cont!=0x79)   
 	        { printk("aztcd: no AZTECH CD-ROM drive found-Try boot parameter aztcd=<BaseAddress>,0x79\n");
-	          return (mem_start);
+	          return -EIO;
                 }
 #else        
              if (0)
@@ -1611,11 +1597,7 @@
 	          STEN_LOW;
 	          if (inb(DATA_PORT)!=AFL_OP_OK)    /*OP_OK?*/
 	             { printk("aztcd: no AZTECH CD-ROM drive found\n");
-#ifndef MODULE
-	               return (mem_start);
-#else
                        return -EIO;
-#endif	     
 	             } 
 	          for (count = 0; count < AZT_TIMEOUT; count++); 
 	             { count=count*2;          /* delay a bit */
@@ -1623,11 +1605,7 @@
 	             }                        
 	          if ((st=getAztStatus())==-1)
 	             { printk("aztcd: Drive Status Error Status=%x\n",st);
-#ifndef MODULE
-	               return (mem_start);
-#else
                        return -EIO;
-#endif	      
 	             }
 #ifdef AZT_DEBUG
 	          printk("aztcd: Status = %x\n",st);
@@ -1673,22 +1651,14 @@
 	       for (count=1;count<5;count++) printk("%c",result[count]);
 	       printk("\n");
 	       printk("aztcd: Aborted\n");
-#ifndef MODULE
-	       return (mem_start);
-#else
                return -EIO;
-#endif 	          
 	     }
 	 }
 	if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
 	{
 		printk("aztcd: Unable to get major %d for Aztech CD-ROM\n",
 		       MAJOR_NR);
-#ifndef MODULE		       
-		return (mem_start);
-#else
                 return -EIO;
-#endif		
 	}
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 4;
@@ -1699,11 +1669,7 @@
 	aztPresent = 1;
 	aztCloseDoor();
 	printk("aztcd: End Init\n");
-#ifndef MODULE
-	return (mem_start);
-#else
         return (0);
-#endif
 }
 
 
diff -u --recursive --new-file v1.3.32/linux/drivers/block/blk.h linux/drivers/block/blk.h
--- v1.3.32/linux/drivers/block/blk.h	Mon Sep 18 14:53:49 1995
+++ linux/drivers/block/blk.h	Tue Oct 10 15:52:51 1995
@@ -38,51 +38,51 @@
 #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
 
 #ifdef CONFIG_CDU31A
-extern unsigned long cdu31a_init(unsigned long, unsigned long);
+extern int cdu31a_init(void);
 #endif CONFIG_CDU31A
 #ifdef CONFIG_MCD
-extern unsigned long mcd_init(unsigned long, unsigned long);
+extern int mcd_init(void);
 #endif CONFIG_MCD
 #ifdef CONFIG_MCDX
-extern unsigned long mcdx_init(unsigned long, unsigned long);
+extern int mcdx_init(void);
 #endif CONFIG_MCDX
 #ifdef CONFIG_SBPCD
-extern unsigned long sbpcd_init(unsigned long, unsigned long);
+extern int sbpcd_init(void);
 #endif CONFIG_SBPCD
 #ifdef CONFIG_AZTCD
-extern unsigned long aztcd_init(unsigned long, unsigned long);
+extern int aztcd_init(void);
 #endif CONFIG_AZTCD
 #ifdef CONFIG_CDU535
-extern unsigned long sony535_init(unsigned long, unsigned long);
+extern int sony535_init(void);
 #endif CONFIG_CDU535
 #ifdef CONFIG_GSCD
-extern unsigned long gscd_init(unsigned long, unsigned long);
+extern int gscd_init(void);
 #endif CONFIG_GSCD
 #ifdef CONFIG_CM206
-extern unsigned long cm206_init(unsigned long, unsigned long);
+extern int cm206_init(void);
 #endif CONFIG_CM206
 #ifdef CONFIG_OPTCD
-extern unsigned long optcd_init(unsigned long, unsigned long);
+extern int optcd_init(void);
 #endif CONFIG_OPTCD
 #ifdef CONFIG_SJCD
-extern unsigned long sjcd_init(unsigned long, unsigned long);
+extern int sjcd_init(void);
 #endif CONFIG_SJCD
 #ifdef CONFIG_BLK_DEV_HD
-extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end);
+extern int hd_init(void);
 #endif
 #ifdef CONFIG_BLK_DEV_IDE
-extern unsigned long ide_init(unsigned long mem_start, unsigned long mem_end);
+extern int ide_init(void);
 #endif
+#ifdef CONFIG_BLK_DEV_XD
+extern int xd_init(void);
+#endif
+
 extern void set_device_ro(kdev_t dev,int flag);
 
 extern int floppy_init(void);
 extern void rd_load(void);
 extern long rd_init(long mem_start, int length);
 extern int ramdisk_size;
-
-#ifdef CONFIG_BLK_DEV_XD
-extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
-#endif
 
 #define RO_IOCTLS(dev,where) \
   case BLKROSET: if (!suser()) return -EACCES; \
diff -u --recursive --new-file v1.3.32/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.3.32/linux/drivers/block/cdu31a.c	Mon Sep 18 14:53:49 1995
+++ linux/drivers/block/cdu31a.c	Tue Oct 10 11:11:36 1995
@@ -2918,13 +2918,12 @@
 /*
  * Initialize the driver.
  */
-#ifndef MODULE
-unsigned long
-cdu31a_init(unsigned long mem_start, unsigned long mem_end)
-#else
-int
-init_module(void)
+#ifdef MODULE
+#define cdu31a_init init_module
 #endif
+
+int
+cdu31a_init(void)
 {
    struct s_sony_drive_config drive_config;
    unsigned int res_size;
@@ -3000,11 +2999,7 @@
       if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops))
       {
 	 printk("Unable to get major %d for CDU-31a\n", MAJOR_NR);
-#ifdef MODULE
 	 return -EIO;
-#else
-	 return mem_start;
-#endif
       }
 
       if (SONY_HWC_DOUBLE_SPEED(drive_config))
@@ -3078,7 +3073,6 @@
 
    disk_changed = 1;
    
-#ifdef MODULE
    if (drive_found)
    {
       return(0);
@@ -3087,9 +3081,6 @@
    {
       return -EIO;
    }
-#else
-   return mem_start;
-#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/block/cm206.c linux/drivers/block/cm206.c
--- v1.3.32/linux/drivers/block/cm206.c	Mon Sep 18 14:53:49 1995
+++ linux/drivers/block/cm206.c	Tue Oct 10 14:50:48 1995
@@ -84,7 +84,6 @@
 #ifdef MODULE			/* OK, so some of this is stolen */
 #include <linux/module.h>	
 #include <linux/version.h>
-#include <linux/malloc.h>
 #ifndef CONFIG_MODVERSIONS
 char kernel_version[]=UTS_RELEASE;
 #endif
@@ -102,6 +101,7 @@
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
+#include <linux/malloc.h>
 
 #include <asm/io.h>
 
@@ -1064,9 +1064,7 @@
     free_irq(cm206_irq);
   case 2: 
   case 1: 
-#ifdef MODULE
     kfree(cd);
-#endif
     release_region(cm206_base, 16);
   default:
   }
@@ -1126,8 +1124,6 @@
 #endif
 
 #ifdef MODULE
-#define OK  0
-#define ERROR  -EIO
 
 static int cm206[2] = {0,0};	/* for compatible `insmod' parameter passing */
 void parse_options(void) 
@@ -1145,18 +1141,12 @@
   }
 }
 
-#else MODULE
-
-#define OK  mem_start+size
-#define ERROR  mem_start
+#define cm206_init init_module
 
 #endif MODULE
 
-#ifdef MODULE
-int init_module(void)
-#else 
-unsigned long cm206_init(unsigned long mem_start, unsigned long mem_end)
-#endif
+
+int cm206_init(void)
 {
   uch e=0;
   long int size=sizeof(struct cm206_struct);
@@ -1171,16 +1161,12 @@
   cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
   if (!cm206_base) {
     printk(" can't find adapter!\n");
-    return ERROR;
+    return -EIO;
   }
   printk(" adapter at 0x%x", cm206_base);
   request_region(cm206_base, 16, "cm206");
-#ifdef MODULE
   cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL);
-  if (!cd) return ERROR;
-#else 
-  cd = (struct cm206_struct *) mem_start;
-#endif
+  if (!cd) return -EIO;
   /* Now we have found the adaptor card, try to reset it. As we have
    * found out earlier, this process generates an interrupt as well,
    * so we might just exploit that fact for irq probing! */
@@ -1189,7 +1175,7 @@
   if (cm206_irq<=0) {
     printk("can't find IRQ!\n");
     cleanup(1);
-    return ERROR;
+    return -EIO;
   }
   else printk(" IRQ %d found\n", cm206_irq);
 #else
@@ -1200,7 +1186,7 @@
     {
       printk(" drive not there\n");
       cleanup(1);
-      return ERROR;
+      return -EIO;
     }
   e = send_receive_polled(c_gimme);
   printk("Firmware revision %d", e & dcf_revision_code);
@@ -1211,13 +1197,13 @@
   if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206")) {
     printk("\nUnable to reserve IRQ---aborted\n");
     cleanup(2);
-    return ERROR;
+    return -EIO;
   }
   printk(".\n");
   if (register_blkdev(MAJOR_NR, "cm206", &cm206_fops) != 0) {
     printk("Cannot register for major %d!\n", MAJOR_NR);
     cleanup(3);
-    return ERROR;
+    return -EIO;
   }
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
   read_ahead[MAJOR_NR] = 16;	/* reads ahead what? */
@@ -1231,10 +1217,8 @@
   cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97;
   printk("%d kB adapter memory available, "  
 	 " %ld bytes kernel memory used.\n", cd->max_sectors*2, size);
-  return OK;
+  return 0;
 }
-#undef OK
-#undef ERROR
 
 #ifdef MODULE
 void cleanup_module(void)
diff -u --recursive --new-file v1.3.32/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.32/linux/drivers/block/genhd.c	Wed Oct  4 14:14:29 1995
+++ linux/drivers/block/genhd.c	Tue Oct 10 14:34:19 1995
@@ -23,6 +23,8 @@
 #include <linux/major.h>
 #include <linux/string.h>
 
+#include <asm/system.h>
+
 struct gendisk *gendisk_head = NULL;
 
 static int current_minor = 0;
@@ -30,6 +32,11 @@
 extern void rd_load(void);
 extern int ramdisk_size;
 
+extern int chr_dev_init(void);
+extern int blk_dev_init(void);
+extern int scsi_dev_init(void);
+extern int net_dev_init(void);
+
 static void print_minor_name (struct gendisk *hd, int minor)
 {
 	unsigned int unit = minor >> hd->minor_shift;
@@ -63,6 +70,12 @@
 	print_minor_name(hd, minor);
 }
 
+static inline int is_extended_partition(struct partition *p)
+{
+	return (p->sys_ind == DOS_EXTENDED_PARTITION ||
+		p->sys_ind == LINUX_EXTENDED_PARTITION);
+}
+
 #ifdef CONFIG_MSDOS_PARTITION
 /*
  * Create devices for each logical partition in an extended partition.
@@ -120,7 +133,7 @@
 		 * First process the data partition(s)
 		 */
 		for (i=0; i<4; i++, p++) {
-		    if (!p->nr_sects || p->sys_ind == EXTENDED_PARTITION)
+		    if (!p->nr_sects || is_extended_partition(p))
 		      continue;
 
 		    /* Check the 3rd and 4th entries -
@@ -149,7 +162,7 @@
 		 */
 		p -= 4;
 		for (i=0; i<4; i++, p++)
-		  if(p->nr_sects && p->sys_ind == EXTENDED_PARTITION)
+		  if(p->nr_sects && is_extended_partition(p))
 		    break;
 		if (i == 4)
 		  goto done;	 /* nothing left to do */
@@ -254,7 +267,7 @@
 		if (!p->nr_sects)
 			continue;
 		add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects);
-		if (p->sys_ind == EXTENDED_PARTITION) {
+		if (is_extended_partition(p)) {
 			printk(" <");
 			/*
 			 * If we are rereading the partition table, we need
@@ -266,9 +279,10 @@
 			  	>> (BLOCK_SIZE_BITS - 9);
 			extended_partition(hd, MKDEV(hd->major, minor));
 			printk(" >");
-			/* prevent someone doing mkfs or mkswap on
-			   an extended partition */
-			hd->part[minor].nr_sects = 0;
+			/* prevent someone doing mkfs or mkswap on an
+			   extended partition, but leave room for LILO */
+			if (hd->part[minor].nr_sects > 2)
+				hd->part[minor].nr_sects = 2;
 		}
 	}
 	/*
@@ -456,13 +470,22 @@
 	struct gendisk *p;
 	int nr=0;
 
+	chr_dev_init();
+	blk_dev_init();
+	sti();
+#ifdef CONFIG_SCSI
+	scsi_dev_init();
+#endif
+#ifdef CONFIG_INET
+	net_dev_init();
+#endif
 	console_map_init();
 
 	for (p = gendisk_head ; p ; p=p->next) {
 		setup_dev(p);
 		nr += p->nr_real;
 	}
-		
+
 	if (ramdisk_size)
 		rd_load();
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/block/gscd.c linux/drivers/block/gscd.c
--- v1.3.32/linux/drivers/block/gscd.c	Mon Sep 18 14:53:49 1995
+++ linux/drivers/block/gscd.c	Tue Oct 10 11:04:33 1995
@@ -121,7 +121,7 @@
 
 /*    common GoldStar Initialization    */
 
-static long my_gscd_init (unsigned long , unsigned long);
+static int my_gscd_init (void);
 
 
 /*      lo-level cmd-Funktionen    */
@@ -969,12 +969,12 @@
 long err;
 
 
-     /* call the GoldStar-init with dummys */
-     err = my_gscd_init ( 10, 20 );
+     /* call the GoldStar-init */
+     err = my_gscd_init ( );
 
      if ( err < 0 )
      {
-         return -EIO;
+         return err;
      }
      else
      {
@@ -1006,18 +1006,15 @@
 
 
 /* Test for presence of drive and initialize it.  Called only at boot time. */
-unsigned long gscd_init (unsigned long mem_start, unsigned long mem_end)
+int gscd_init (void)
 {
-unsigned long err;
-
-   err = my_gscd_init ( mem_start, mem_end );
-   return ( labs(err));
+   return my_gscd_init ();
 }
 
 
 /* This is the common initalisation for the GoldStar drive. */
 /* It is called at boot time AND for module init.           */
-long my_gscd_init (unsigned long mem_start, unsigned long mem_end)
+int my_gscd_init (void)
 {
 int i;
 int result;
@@ -1028,7 +1025,7 @@
         if (check_region(gscd_port, 4)) 
         {
 	  printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port);
-	  return -mem_start;
+	  return -EIO;
 	}
 	  
 
@@ -1037,7 +1034,7 @@
         if ( result == 0x09 )
         {
            printk ("GSCD: DMA kann ich noch nicht!\n" );
-           return -mem_start;
+           return -EIO;
         }
  
         if ( result == 0x0b )
@@ -1047,14 +1044,14 @@
            if ( i == 0 )
            {
               printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" );
-              return -mem_start;
+              return -EIO;
            }
         }
 
         if ( (result != 0x0b) && (result != 0x09) )
         {
               printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" );
-              return -mem_start;
+              return -EIO;
         }          		            
 
         /* reset all drives */
@@ -1072,7 +1069,7 @@
 	{
 		printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
 		       MAJOR_NR);
-		return -mem_start;
+		return -EIO;
 	}
 
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
@@ -1084,7 +1081,7 @@
 	request_region(gscd_port, 4, "gscd");
 
         printk ( "GSCD: GoldStar CD-ROM Drive found.\n" );
-	return mem_start;
+	return 0;
 }
 
 static void gscd_hsg2msf (long hsg, struct msf *msf)
diff -u --recursive --new-file v1.3.32/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.3.32/linux/drivers/block/hd.c	Mon Sep 18 14:53:49 1995
+++ linux/drivers/block/hd.c	Tue Oct 10 11:08:09 1995
@@ -1047,18 +1047,18 @@
 	block_fsync		/* fsync */
 };
 
-unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
+int hd_init(void)
 {
 	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
 		printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);
-		return mem_start;
+		return -1;
 	}
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
 	hd_gendisk.next = gendisk_head;
 	gendisk_head = &hd_gendisk;
 	timer_table[HD_TIMER].fn = hd_times_out;
-	return mem_start;
+	return 0;
 }
 
 #define DEVICE_BUSY busy[target]
diff -u --recursive --new-file v1.3.32/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.32/linux/drivers/block/ide.c	Wed Oct  4 14:14:29 1995
+++ linux/drivers/block/ide.c	Tue Oct 10 13:39:57 1995
@@ -171,6 +171,8 @@
 #include <linux/errno.h>
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
+#include <linux/malloc.h>
+
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/segment.h>
@@ -458,6 +460,10 @@
 
 	for (unit = 0; unit < gd->nr_real; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
+#ifdef CONFIG_BLK_DEV_IDECD
+		if (drive->present && drive->media == cdrom)
+			ide_cdrom_setup(drive);
+#endif /* CONFIG_BLK_DEV_IDECD */
 		drive->part[0].nr_sects = current_capacity(drive);
 		if (!drive->present || drive->media != disk) {
 			drive->part[0].start_sect = -1; /* skip partition check */
@@ -473,33 +479,6 @@
 }
 
 /*
- * ide_alloc(): memory allocation for use *only* during driver initialization.
- * If "within_area" is non-zero, the memory will be allocated such that
- * it lies entirely within a "within_area" sized area (eg. 4096).  This is
- * needed for DMA stuff.  "within_area" must be a power of two (not validated).
- * All allocations are longword aligned.
- */
-static unsigned long ide_mem_start = 0uL;	/* used by ide_alloc() */
-
-void *ide_alloc (unsigned long bytecount, unsigned long within_area)
-{
-	const unsigned long longsize_m1 = (sizeof(long) - 1);
-	void *p;
-
-	if (!ide_mem_start)
-		panic("ide: ide_alloc() not valid now\n");
-	ide_mem_start = (ide_mem_start + longsize_m1) & ~longsize_m1;
-	if (within_area) {
-		unsigned long fraction = within_area - (ide_mem_start & (within_area - 1));
-		if (fraction < bytecount)
-			ide_mem_start += fraction; /* realign to a new page */
-	}
-	p = (void *) ide_mem_start;
-	ide_mem_start += (bytecount + longsize_m1) & ~longsize_m1;
-	return p;
-}
-
-/*
  * init_gendisk() (as opposed to ide_geninit) is called for each major device,
  * after probing for drives, to allocate partition tables and other data
  * structures needed for the routines in genhd.c.  ide_geninit() gets called
@@ -517,10 +496,10 @@
 			break;
 	}
 	minors    = units * (1<<PARTN_BITS);
-	gd        = ide_alloc (sizeof(struct gendisk), 0);
-	gd->sizes = ide_alloc (minors * sizeof(int), 0);
-	gd->part  = ide_alloc (minors * sizeof(struct hd_struct), 0);
-	bs        = ide_alloc (minors*sizeof(int), 0);
+	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
 
 	/* cdroms and msdos f/s are examples of non-1024 blocksizes */
 	blksize_size[hwif->major] = bs;
@@ -1980,7 +1959,7 @@
 	struct hd_driveid *id;
 	unsigned long capacity, check;
 
-	id = drive->id = ide_alloc (SECTOR_WORDS*4, 0);
+	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_KERNEL);
 	ide_input_data(drive, id, SECTOR_WORDS);	/* read 512 bytes of id info */
 	sti();
 
@@ -2311,10 +2290,6 @@
 		for (unit = 0; unit < 2; ++unit) { /* note the hardcoded '2' */
 			ide_drive_t *drive = &hwif->drives[unit];
 			(void) probe_for_drive (drive);
-#ifdef CONFIG_BLK_DEV_IDECD
-			if (drive->present && drive->media == cdrom)
-				ide_cdrom_setup(drive);
-#endif /* CONFIG_BLK_DEV_IDECD */
 		}
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
@@ -2771,7 +2746,7 @@
 	 * Got the irq,  now set everything else up
 	 */
 	if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
-		hwgroup = ide_alloc (sizeof(ide_hwgroup_t), 0);
+		hwgroup = kmalloc (sizeof(ide_hwgroup_t), GFP_KERNEL);
 		irq_to_hwgroup[hwif->irq] = hwgroup;
 		hwgroup->hwif 	 = hwif->next = hwif;
 		hwgroup->rq      = NULL;
@@ -2941,11 +2916,10 @@
 /*
  * This is gets invoked once during initialization, to set *everything* up
  */
-unsigned long ide_init (unsigned long mem_start, unsigned long mem_end)
+int ide_init (void)
 {
 	int h;
 
-	ide_mem_start = mem_start;	/* for ide_alloc () */
 	init_ide_data ();
 	/*
 	 * First, we determine what hardware is present
@@ -3025,7 +2999,5 @@
 			hwif->present = 1;	/* success */
 		}
 	}
-	mem_start = ide_mem_start;
-	ide_mem_start = 0uL;	/* prevent further use of ide_alloc() */
-	return mem_start;
+	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v1.3.32/linux/drivers/block/ll_rw_blk.c	Mon Sep 18 14:53:50 1995
+++ linux/drivers/block/ll_rw_blk.c	Tue Oct 10 10:18:45 1995
@@ -585,7 +585,7 @@
 	}
 }
 
-long blk_dev_init(long mem_start, long mem_end)
+int blk_dev_init(void)
 {
 	struct request * req;
 
@@ -596,13 +596,13 @@
 	}
 	memset(ro_bits,0,sizeof(ro_bits));
 #ifdef CONFIG_BLK_DEV_IDE
-	mem_start = ide_init(mem_start,mem_end); /* this MUST preceed hd_init */
+	ide_init();		/* this MUST preceed hd_init */
 #endif
 #ifdef CONFIG_BLK_DEV_HD
-	mem_start = hd_init(mem_start,mem_end);
+	hd_init();
 #endif
 #ifdef CONFIG_BLK_DEV_XD
-	mem_start = xd_init(mem_start,mem_end);
+	xd_init();
 #endif
 #ifdef CONFIG_BLK_DEV_FD
 	floppy_init();
@@ -610,36 +610,34 @@
 	outb_p(0xc, 0x3f2);
 #endif
 #ifdef CONFIG_CDU31A
-	mem_start = cdu31a_init(mem_start,mem_end);
+	cdu31a_init();
 #endif CONFIG_CDU31A
 #ifdef CONFIG_MCD
-	mem_start = mcd_init(mem_start,mem_end);
+	mcd_init();
 #endif CONFIG_MCD
 #ifdef CONFIG_MCDX
-	mem_start = mcdx_init(mem_start,mem_end);
+	mcdx_init();
 #endif CONFIG_MCDX
 #ifdef CONFIG_SBPCD
-	mem_start = sbpcd_init(mem_start, mem_end);
+	sbpcd_init();
 #endif CONFIG_SBPCD
 #ifdef CONFIG_AZTCD
-        mem_start = aztcd_init(mem_start,mem_end);
+        aztcd_init();
 #endif CONFIG_AZTCD
 #ifdef CONFIG_CDU535
-	mem_start = sony535_init(mem_start,mem_end);
+	sony535_init();
 #endif CONFIG_CDU535
 #ifdef CONFIG_GSCD
-	mem_start = gscd_init(mem_start, mem_end);
+	gscd_init();
 #endif CONFIG_GSCD
 #ifdef CONFIG_CM206
-	mem_start = cm206_init(mem_start, mem_end);
+	cm206_init();
 #endif
 #ifdef CONFIG_OPTCD
-	mem_start = optcd_init(mem_start,mem_end);
+	optcd_init();
 #endif CONFIG_OPTCD
 #ifdef CONFIG_SJCD
-	mem_start = sjcd_init(mem_start,mem_end);
+	sjcd_init();
 #endif CONFIG_SJCD
-	if (ramdisk_size)
-		mem_start += rd_init(mem_start, ramdisk_size*1024);
-	return mem_start;
+	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
--- v1.3.32/linux/drivers/block/mcd.c	Mon Sep 18 14:53:50 1995
+++ linux/drivers/block/mcd.c	Tue Oct 10 11:17:48 1995
@@ -70,6 +70,7 @@
 # ifndef CONFIG_MODVERSIONS
     char kernel_version[]= UTS_RELEASE;
 # endif
+#define mcd_init init_module
 #else
 # define MOD_INC_USE_COUNT
 # define MOD_DEC_USE_COUNT
@@ -1169,23 +1170,15 @@
  * Test for presence of drive and initialize it.  Called at boot time.
  */
 
-#ifndef MODULE
-unsigned long
-mcd_init(unsigned long mem_start, unsigned long mem_end)
-#else
-int init_module(void)
-#endif
+int
+mcd_init(void)
 {
 	int count;
 	unsigned char result[3];
 
 	if (mcd_port <= 0 || mcd_irq <= 0) {
 	  printk("skip mcd_init\n");
-#ifndef MODULE
-	  return mem_start;
-#else
           return -EIO;
-#endif
 	}
 
 	printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
@@ -1194,22 +1187,13 @@
 	{
 		printk("Unable to get major %d for Mitsumi CD-ROM\n",
 		       MAJOR_NR);
-#ifndef MODULE
-		return mem_start;
-#else
                 return -EIO;
-#endif
-              
 	}
 
         if (check_region(mcd_port, 4)) {
 	  printk("Init failed, I/O port (%X) already in use\n",
 		 mcd_port);
-#ifndef MODULE		 
-	  return mem_start;
-#else
           return -EIO;
-#endif	  
 	}
 	  
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
@@ -1229,11 +1213,7 @@
 	if (count >= 2000000) {
 		printk("Init failed. No mcd device at 0x%x irq %d\n",
 		     mcd_port, mcd_irq);
-#ifndef MODULE
-		return mem_start;
-#else
                 return -EIO;
-#endif                
 	}
 	count = inb(MCDPORT(0));		/* pick up the status */
 	
@@ -1242,19 +1222,11 @@
 		if(getValue(result+count)) {
 			printk("mitsumi get version failed at 0x%d\n",
 			       mcd_port);
-#ifndef MODULE
-			return mem_start;
-#else
                         return -EIO;
-#endif
 		}	
 
 	if (result[0] == result[1] && result[1] == result[2])
-#ifndef MODULE
-		return mem_start;
-#else
                 return -EIO;
-#endif
 	printk("Mitsumi status, type and version : %02X %c %x ",
 	       result[0],result[1],result[2]);
 
@@ -1276,11 +1248,7 @@
 	if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD"))
 	{
 		printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
-#ifndef MODULE
-		return mem_start;
-#else
                 return -EIO;
-#endif
 	}
 	request_region(mcd_port, 4,"mcd");
 
@@ -1296,11 +1264,7 @@
 
 	mcd_invalidate_buffers();
 	mcdPresent = 1;
-#ifndef MODULE	
-	return mem_start;
-#else
         return 0;
-#endif
 }
 
 
diff -u --recursive --new-file v1.3.32/linux/drivers/block/mcdx.c linux/drivers/block/mcdx.c
--- v1.3.32/linux/drivers/block/mcdx.c	Mon Sep 18 14:53:50 1995
+++ linux/drivers/block/mcdx.c	Tue Oct 10 14:33:52 1995
@@ -191,7 +191,7 @@
 	changed elsewhere. */
 
 /* declared in blk.h */
-unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
+int mcdx_init(void);
 void do_mcdx_request(void);
 
 int check_mcdx_media_change(kdev_t);
@@ -275,12 +275,6 @@
 
 /* KERNEL INTERFACE FUNCTIONS **************************************/ 
 
-#ifdef MODULE
-#define     free(x, y)      kfree((x))
-#else
-#define     free(x, y)      (mem_start -= y)
-#endif
-
 static int 
 mcdx_ioctl(
 	struct inode* ip, struct file* fp, 
@@ -955,7 +949,7 @@
 	int i;
 	int drives = 0;
 
-	mcdx_init(0, 0);
+	mcdx_init();
 	for (i = 0; i < MCDX_NDRIVES; i++)  {
 		if (mcdx_stuffp[i]) {
 		TRACE((INIT, "init_module() drive %d stuff @ %p\n",
@@ -1026,7 +1020,7 @@
 }
 
 
-unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
+int mcdx_init(void)
 {
 	int drive;
 
@@ -1047,17 +1041,11 @@
 		
 		TRACE((INIT, "init() try drive %d\n", drive));
 
-#ifdef MODULE
 		TRACE((MALLOC, "init() malloc %d bytes\n", size));
 		if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
 			WARN(("init() malloc failed\n"));
 			break; 
 		}
-#else
-        TRACE((INIT, "adjust mem_start\n"));
-        stuffp = (struct s_drive_stuff *) mem_start;
-        mem_start += size;
-#endif
 
 		TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
 
@@ -1084,7 +1072,7 @@
                     stuffp->wreg_data, 
                     stuffp->wreg_data + MCDX_IO_SIZE - 1));
 			TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
-            free(stuffp, size);
+            kfree(stuffp);
 			TRACE((INIT, "init() continue at next drive\n"));
 			continue; /* next drive */
 		}
@@ -1101,7 +1089,7 @@
                     MCDX,
                     stuffp->wreg_data, stuffp->irq));
 			TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
-            free(stuffp, size);
+            kfree(stuffp);
 			TRACE((INIT, "init() continue at next drive\n"));
 			continue;
 		}
@@ -1129,7 +1117,7 @@
 		if (!stuffp->present) {
             WARN(("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
                     MCDX, stuffp->wreg_data, stuffp->irq));
-			free(stuffp, size);
+			kfree(stuffp);
 			continue; /* next drive */
 		}
 
@@ -1138,7 +1126,7 @@
             WARN(("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
                     MCDX,
                     stuffp->wreg_data, stuffp->irq, MAJOR_NR));
-			free(stuffp, size);
+			kfree(stuffp);
 			continue; /* next drive */
 		}
 
@@ -1156,7 +1144,7 @@
                     MCDX,
                     stuffp->wreg_data, stuffp->irq, stuffp->irq));
 			stuffp->irq = 0;
-			free(stuffp, size);
+			kfree(stuffp);
 			continue;
 		}
 		request_region((unsigned int) stuffp->wreg_data, 
@@ -1188,7 +1176,7 @@
 		TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
 	}
 
-	return mem_start;
+	return 0;
 }
 
 
diff -u --recursive --new-file v1.3.32/linux/drivers/block/optcd.c linux/drivers/block/optcd.c
--- v1.3.32/linux/drivers/block/optcd.c	Sun Sep  3 12:26:51 1995
+++ linux/drivers/block/optcd.c	Tue Oct 10 11:07:25 1995
@@ -58,6 +58,7 @@
 # ifndef CONFIG_MODVERSIONS
 	char kernel_version[]= UTS_RELEASE;
 # endif
+#define optcd_init init_module
 #else
 # define MOD_INC_USE_COUNT
 # define MOD_DEC_USE_COUNT
@@ -1402,28 +1403,19 @@
 		optcd_port = ints[1];
 }
 
-#ifndef MODULE
-#define RETURN_EIO return mem_start
-#else
-#define RETURN_EIO return -EIO
-#endif
-
 /*
  * Test for presence of drive and initialize it. Called at boot time.
  */
-#ifndef MODULE
-unsigned long optcd_init(unsigned long mem_start, unsigned long mem_end) {
-#else
-int init_module(void) {
-#endif
+
+int optcd_init(void) {
 	if (optcd_port <= 0) {
 		printk("optcd: no Optics Storage CDROM Initialization\n");
-		RETURN_EIO;
+		return -EIO;
 	}
 	if (check_region(optcd_port, 4)) {
 		printk("optcd: conflict, I/O port 0x%x already used\n",
 			optcd_port);
-		RETURN_EIO;
+		return -EIO;
 	}
 
 	if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
@@ -1443,38 +1435,34 @@
 
     if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
       printk( "ISP16 cdrom interface has not been properly configured.\n" );
-      RETURN_EIO;
+      return -EIO;
     }
   }
 	}
 
 	if (!optResetDrive()) {
 		printk("optcd: drive at 0x%x not ready\n", optcd_port);
-		RETURN_EIO;
+		return -EIO;
 	}
 	if (!version_ok()) {
 		printk("optcd: unknown drive detected; aborting\n");
-		RETURN_EIO;
+		return -EIO;
 	}
 	if (optCmd(COMINITDOUBLE) < 0) {
 		printk("optcd: cannot init double speed mode\n");
-		RETURN_EIO;
+		return -EIO;
 	}
 	if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
 	{
 		printk("optcd: unable to get major %d\n", MAJOR_NR);
-		RETURN_EIO;
+		return -EIO;
 	}
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 4;
 	request_region(optcd_port, 4, "optcd");
 	optPresent = 1;
 	printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port);
-#ifndef MODULE
-	return mem_start;
-#else
 	return 0;
-#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.3.32/linux/drivers/block/sbpcd.c	Mon Sep 18 14:53:51 1995
+++ linux/drivers/block/sbpcd.c	Tue Oct 10 14:44:44 1995
@@ -314,19 +314,19 @@
  */
 #if !(SBPCD_ISSUE-1)
 #define DO_SBPCD_REQUEST(a) do_sbpcd_request(a)
-#define SBPCD_INIT(a,b) sbpcd_init(a,b)
+#define SBPCD_INIT(a) sbpcd_init(a)
 #endif
 #if !(SBPCD_ISSUE-2)
 #define DO_SBPCD_REQUEST(a) do_sbpcd2_request(a)
-#define SBPCD_INIT(a,b) sbpcd2_init(a,b)
+#define SBPCD_INIT(a) sbpcd2_init(a)
 #endif
 #if !(SBPCD_ISSUE-3)
 #define DO_SBPCD_REQUEST(a) do_sbpcd3_request(a)
-#define SBPCD_INIT(a,b) sbpcd3_init(a,b)
+#define SBPCD_INIT(a) sbpcd3_init(a)
 #endif
 #if !(SBPCD_ISSUE-4)
 #define DO_SBPCD_REQUEST(a) do_sbpcd4_request(a)
-#define SBPCD_INIT(a,b) sbpcd4_init(a,b)
+#define SBPCD_INIT(a) sbpcd4_init(a)
 #endif
 /*==========================================================================*/
 #if SBPCD_DIS_IRQ
@@ -406,13 +406,13 @@
  */
 #if !(SBPCD_ISSUE-1)
 #ifdef CONFIG_SBPCD2
-extern unsigned long sbpcd2_init(unsigned long, unsigned long);
+extern int sbpcd2_init(void);
 #endif
 #ifdef CONFIG_SBPCD3
-extern unsigned long sbpcd3_init(unsigned long, unsigned long);
+extern int sbpcd3_init(void);
 #endif
 #ifdef CONFIG_SBPCD4
-extern unsigned long sbpcd4_init(unsigned long, unsigned long);
+extern int sbpcd4_init(void);
 #endif
 #endif
 
@@ -5096,7 +5096,7 @@
 #ifdef MODULE
 int init_module(void)
 #else
-	unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
+int SBPCD_INIT(void)
 #endif MODULE
 {
 	int i=0, j=0;
@@ -5279,7 +5279,6 @@
 		D_S[j].sbp_bufsiz=SBP_BUFFER_FRAMES;
 		if (D_S[j].drv_type&drv_fam1)
 			if (READ_AUDIO>0) D_S[j].sbp_audsiz=READ_AUDIO;
-#ifdef MODULE
 		D_S[j].sbp_buf=(u_char *) vmalloc(D_S[j].sbp_bufsiz*CD_FRAMESIZE);
 		if (D_S[j].sbp_buf==NULL)
 		{
@@ -5293,15 +5292,6 @@
 			if (D_S[j].aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",D_S[j].sbp_audsiz);
 			else msg(DBG_INF,"audio buffer size: %d frames.\n",D_S[j].sbp_audsiz);
 		}
-#else
-		D_S[j].sbp_buf=(u_char *)mem_start;
-		mem_start += D_S[j].sbp_bufsiz*CD_FRAMESIZE;
-		if (D_S[j].sbp_audsiz>0)
-		{
-			D_S[j].aud_buf=(u_char *)mem_start;
-			mem_start += D_S[j].sbp_audsiz*CD_FRAMESIZE_RAW;
-		}
-#endif MODULE
 		/*
 		 * set the block size
 		 */
@@ -5315,16 +5305,16 @@
  init_done:
 #if !(SBPCD_ISSUE-1)
 #ifdef CONFIG_SBPCD2
-	mem_start=sbpcd2_init(mem_start, mem_end);
+	sbpcd2_init();
 #endif
 #ifdef CONFIG_SBPCD3
-	mem_start=sbpcd3_init(mem_start, mem_end);
+	sbpcd3_init();
 #endif
 #ifdef CONFIG_SBPCD4
-	mem_start=sbpcd4_init(mem_start, mem_end);
+	sbpcd4_init();
 #endif
 #endif
-	return (mem_start);
+	return 0;
 #endif MODULE
 }
 /*==========================================================================*/
diff -u --recursive --new-file v1.3.32/linux/drivers/block/sjcd.c linux/drivers/block/sjcd.c
--- v1.3.32/linux/drivers/block/sjcd.c	Mon Sep 18 14:53:51 1995
+++ linux/drivers/block/sjcd.c	Tue Oct 10 10:49:56 1995
@@ -1353,7 +1353,7 @@
  * Test for presence of drive and initialize it. Called at boot time.
  * Probe cdrom, find out version and status.
  */
-unsigned long sjcd_init( unsigned long mem_start, unsigned long mem_end ){
+int sjcd_init( void ){
   int i;
 
   if ( (isp16_type=isp16_detect()) < 0 )
@@ -1368,13 +1368,13 @@
 
     if ( isp16_config( sjcd_port, expected_drive, sjcd_irq, sjcd_dma ) < 0 ) {
       printk( "ISP16 cdrom interface has not been properly configured.\n" );
-      return(mem_start);
+      return -1;
     }
   }
 
   if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){
     printk( "Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR );
-    return( mem_start );
+    return -1;
   }
   
   blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST;
@@ -1383,7 +1383,7 @@
   if( check_region( sjcd_port, 4 ) ){
     printk( "Init failed, I/O port (%X) is already in use\n",
 	   sjcd_port );
-    return( mem_start );
+    return -1;
   }
   
   printk( "Sanyo CDR-H94A:" );
@@ -1395,7 +1395,7 @@
     if( !( inb( SJCDPORT( 1 ) ) & 0x04 ) ) break;
   if( i == 0 ){
     printk( " No device at 0x%x found.\n", sjcd_port );
-    return( mem_start );
+    return -1;
   }
   
   sjcd_send_cmd( SCMD_RESET );
@@ -1412,7 +1412,7 @@
 	     ( int )sjcd_version.minor );
   } else {
     printk( " Read version failed.\n" );
-    return( mem_start );
+    return -1;
   }
 
   /*
@@ -1427,7 +1427,7 @@
 	 sjcd_port, sjcd_irq );
 
   sjcd_present++;
-  return( mem_start );
+  return 0;
 }
 
 /*
diff -u --recursive --new-file v1.3.32/linux/drivers/block/sonycd535.c linux/drivers/block/sonycd535.c
--- v1.3.32/linux/drivers/block/sonycd535.c	Mon Sep 18 14:53:51 1995
+++ linux/drivers/block/sonycd535.c	Tue Oct 10 14:50:30 1995
@@ -111,11 +111,11 @@
 
 #ifdef MODULE
 # include <linux/module.h>
-# include <linux/malloc.h>
 # include <linux/version.h>
 # ifndef CONFIG_MODVERSIONS
 	char kernel_version[]= UTS_RELEASE;
 # endif
+#define sony535_init init_module
 #else
 # define MOD_INC_USE_COUNT
 # define MOD_DEC_USE_COUNT
@@ -131,6 +131,7 @@
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
 #include <linux/mm.h>
+#include <linux/malloc.h>
 
 #define REALLY_SLOW_IO
 #include <asm/system.h>
@@ -225,33 +226,31 @@
 
 static int initialized = 0;			/* Has the drive been initialized? */
 static int sony_disc_changed = 1;	/* Has the disk been changed
-									   since the last check? */
+					   since the last check? */
 static int sony_toc_read = 0;		/* Has the table of contents been
-									   read? */
+					   read? */
 static unsigned int sony_buffer_size;	/* Size in bytes of the read-ahead
-										   buffer. */
+					   buffer. */
 static unsigned int sony_buffer_sectors;	/* Size (in 2048 byte records) of
-											   the read-ahead buffer. */
+						   the read-ahead buffer. */
 static unsigned int sony_usage = 0;	/* How many processes have the
-									   drive open. */
+					   drive open. */
 
 static int sony_first_block = -1;	/* First OS block (512 byte) in
-									   the read-ahead buffer */
+					   the read-ahead buffer */
 static int sony_last_block = -1;	/* Last OS block (512 byte) in
-									   the read-ahead buffer */
+					   the read-ahead buffer */
 
 static struct s535_sony_toc *sony_toc;	/* Points to the table of
-										   contents. */
+					   contents. */
+
 static struct s535_sony_subcode *last_sony_subcode;		/* Points to the last
-														   subcode address read */
-#ifndef MODULE
-static Byte *sony_buffer;		/* Points to the read-ahead buffer */
-#else
+								   subcode address read */
 static Byte **sony_buffer;		/* Points to the pointers
-								   to the sector buffers */
-#endif
+					   to the sector buffers */
+
 static int sony_inuse = 0;		/* is the drive in use? Only one
-								   open at a time allowed */
+					   open at a time allowed */
 
 /*
  * The audio status uses the values from read subchannel data as specified
@@ -607,25 +606,16 @@
  *  it returns one of the standard error returns.
  ***************************************************************************/
 static int
-#ifndef MODULE
-seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
-					   Byte * data_buff, int buf_size)
-#else
 seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
 					   Byte **buff, int buf_size)
-#endif
 {
 	const int block_size = 2048;
 	Byte cmd_buff[7];
 	int  i;
 	int  read_status;
 	int  retry_count;
-#ifndef MODULE
-	Byte *start_pos = data_buff;
-#else
 	Byte *data_buff;
 	int  sector_count = 0;
-#endif
 
 	if (buf_size < ((long)block_size) * n_blocks)
 		return NO_ROOM;
@@ -651,9 +641,7 @@
 			}
 			if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) {
 				/* data is ready, read it */
-#ifdef MODULE
 				data_buff = buff[sector_count++];
-#endif
 				for (i = 0; i < block_size; i++)
 					*data_buff++ = inb(data_reg);	/* unrolling this loop does not seem to help */
 				break;			/* exit the timeout loop */
@@ -667,11 +655,7 @@
 	/* read all the data, now read the status */
 	if ((i = read_exec_status(status)) != 0)
 		return i;
-#ifndef MODULE
-	return data_buff - start_pos;
-#else
 	return block_size * sector_count;
-#endif
 }	/* seek_and_read_N_blocks() */
 
 /****************************************************************************
@@ -938,14 +922,9 @@
 				 * The data is in memory now, copy it to the buffer and advance to the
 				 * next block to read.
 				 */
-#ifndef MODULE
-				copyoff = (block - sony_first_block) * 512;
-				memcpy(CURRENT->buffer, sony_buffer + copyoff, 512);
-#else
 				copyoff = block - sony_first_block;
 				memcpy(CURRENT->buffer,
 					   sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);
-#endif
 
 				block += 1;
 				nsect -= 1;
@@ -1519,13 +1498,8 @@
 /*
  * Initialize the driver.
  */
-#ifndef MODULE
-unsigned long
-sony535_init(unsigned long mem_start, unsigned long mem_end)
-#else
 int
-init_module(void)
-#endif
+sony535_init(void)
 {
 	struct s535_sony_drive_config drive_config;
 	Byte cmd_buff[3];
@@ -1533,13 +1507,11 @@
 	Byte status[2];
 	int  retry_count;
 	int  tmp_irq;
-#ifdef MODULE
 	int  i;
-#endif
 
 	/* Setting the base I/O address to 0 will disable it. */
 	if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0))
-		goto bail;
+		return 0;
 
 	/* Set up all the register locations */
 	result_reg = sony535_cd_base_io;
@@ -1561,11 +1533,7 @@
 #endif
 	if (check_region(sony535_cd_base_io,4)) {
 		printk(CDU535_MESSAGE_NAME ": my base address is not free!\n");
-#ifndef MODULE
-		return mem_start;
-#else
 		return -EIO;
-#endif
 	}
 	/* look for the CD-ROM, follows the procedure in the DOS driver */
 	inb(select_unit_reg);
@@ -1639,24 +1607,11 @@
 				if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
 					printk("Unable to get major %d for %s\n",
 							MAJOR_NR, CDU535_MESSAGE_NAME);
-#ifndef MODULE
-					return mem_start;
-#else
 					return -EIO;
-#endif
 				}
 				blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 				read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read-ahead */
 
-#ifndef MODULE
-				sony_toc = (struct s535_sony_toc *)mem_start;
-				mem_start += sizeof *sony_toc;
-				last_sony_subcode = (struct s535_sony_subcode *)mem_start;
-				mem_start += sizeof *last_sony_subcode;
-				sony_buffer = (Byte *)mem_start;
-				mem_start += sony_buffer_size;
-
-#else /* MODULE */
 				sony_toc = (struct s535_sony_toc *)
 					kmalloc(sizeof *sony_toc, GFP_KERNEL);
 				if (sony_toc == NULL)
@@ -1685,7 +1640,6 @@
 						return -ENOMEM;
 					}
 				}
-#endif /* MODULE */
 				initialized = 1;
 			}
 		}
@@ -1693,18 +1647,10 @@
 
 	if (!initialized) {
 		printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
-#ifdef MODULE
 		return -EIO;
-#endif
-	} else {
-		request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
 	}
-bail:
-#ifndef MODULE
-	return mem_start;
-#else
+	request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
 	return 0;
-#endif
 }
 
 #ifndef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/block/triton.c linux/drivers/block/triton.c
--- v1.3.32/linux/drivers/block/triton.c	Wed Oct  4 14:14:29 1995
+++ linux/drivers/block/triton.c	Tue Oct 10 12:02:16 1995
@@ -85,7 +85,9 @@
 #include <linux/hdreg.h>
 #include <linux/pci.h>
 #include <linux/bios32.h>
+
 #include <asm/io.h>
+#include <asm/dma.h>
 
 #include "ide.h"
 
@@ -352,9 +354,9 @@
 			unsigned long *table;
 			request_region(base, 8, hwif->name);
 			hwif->dma_base  = base;
-			table = ide_alloc(2 * PRD_ENTRIES * sizeof(long), 4096);
+			table = (void *) __get_dma_pages(GFP_KERNEL, 0);
 			hwif->dmatable = table;
-			outl((unsigned long) table, base + 4);
+			outl(virt_to_bus(table), base + 4);
 			hwif->dmaproc  = &triton_dmaproc;
 		}
 		printk("\n    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
diff -u --recursive --new-file v1.3.32/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v1.3.32/linux/drivers/block/xd.c	Mon Sep 18 14:53:51 1995
+++ linux/drivers/block/xd.c	Tue Oct 10 10:50:23 1995
@@ -115,18 +115,18 @@
 static u_short xd_iobase = 0;
 
 /* xd_init: register the block device number and set up pointer tables */
-u_long xd_init (u_long mem_start,u_long mem_end)
+int xd_init (void)
 {
 	if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
 		printk("xd_init: unable to get major number %d\n",MAJOR_NR);
-		return (mem_start);
+		return -1;
 	}
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB) read ahead */
 	xd_gendisk.next = gendisk_head;
 	gendisk_head = &xd_gendisk;
 
-	return mem_start;
+	return 0;
 }
 
 /* xd_detect: scan the possible BIOS ROM locations for the signature strings */
diff -u --recursive --new-file v1.3.32/linux/drivers/char/atixlmouse.c linux/drivers/char/atixlmouse.c
--- v1.3.32/linux/drivers/char/atixlmouse.c	Fri Sep 15 11:13:00 1995
+++ linux/drivers/char/atixlmouse.c	Tue Oct 10 10:43:02 1995
@@ -13,6 +13,9 @@
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+
+char kernel_version[] = UTS_RELEASE;
+#define atixl_busmouse_init init_module
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
@@ -109,29 +112,31 @@
 
 static void release_mouse(struct inode * inode, struct file * file)
 {
+	fasync_mouse(inode, file, 0);
+	if (--mouse.active)
+		return;
 	ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
-	mouse.active = 0;
 	mouse.ready = 0;
 	free_irq(ATIXL_MOUSE_IRQ);
-	fasync_mouse(inode, file, 0);
+	MOD_DEC_USE_COUNT;
 }
 
 static int open_mouse(struct inode * inode, struct file * file)
 {
 	if (!mouse.present)
 		return -EINVAL;
-	if (mouse.active)
+	if (mouse.active++)
+		return 0;
+	if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse")) {
+		mouse.active--;
 		return -EBUSY;
-	mouse.active = 1;
+	}
 	mouse.ready = 0;
 	mouse.dx = 0;
 	mouse.dy = 0;
 	mouse.buttons = mouse.latch_buttons = 0;
-	if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse")) {
-		mouse.active = 0;
-		return -EBUSY;
-	}
 	ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -200,13 +205,8 @@
 	ATIXL_BUSMOUSE, "atixl", &atixl_busmouse_fops
 };
 
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
 
-int init_module(void)
-#else
-unsigned long atixl_busmouse_init(unsigned long kmem_start)
-#endif
+int atixl_busmouse_init(void)
 {
 	unsigned char a,b,c;
 
@@ -217,11 +217,7 @@
 		printk("\nATI Inport ");
 	else{
 		mouse.present = 0;
-#ifdef MODULE
 		return -EIO;
-#else
-		return kmem_start;
-#endif
 	}
 	outb(0x80, ATIXL_MSE_CONTROL_PORT);	/* Reset the Inport device */
 	outb(0x07, ATIXL_MSE_CONTROL_PORT);	/* Select Internal Register 7 */
@@ -234,18 +230,16 @@
 	mouse.wait = NULL;
 	printk("Bus mouse detected and installed.\n");
 	mouse_register(&atixl_mouse);
-#ifdef MODULE
 	return 0;
-#else
-	return kmem_start;
-#endif
 }
 
 #ifdef MODULE
 void cleanup_module(void)
 {
-	if (MOD_IN_USE)
+	if (MOD_IN_USE) {
 		printk("atixlmouse: in use, remove delayed\n");
+		return;
+	}
 	mouse_deregister(&atixl_mouse);
 }
 #endif
diff -u --recursive --new-file v1.3.32/linux/drivers/char/busmouse.c linux/drivers/char/busmouse.c
--- v1.3.32/linux/drivers/char/busmouse.c	Fri Sep 15 11:13:00 1995
+++ linux/drivers/char/busmouse.c	Tue Oct 10 10:43:54 1995
@@ -31,6 +31,9 @@
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+
+char kernel_version[] = UTS_RELEASE;
+#define bus_mouse_init init_module
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
@@ -113,37 +116,38 @@
 }
 
 /*
- * close access to the mouse (can deal with multiple
- * opens if allowed in the future)
+ * close access to the mouse
  */
 
 static void close_mouse(struct inode * inode, struct file * file)
 {
-	if (--mouse.active == 0) {
-	    MSE_INT_OFF();
-	    free_irq(mouse_irq);
-	}
 	fasync_mouse(inode, file, 0);
+	if (--mouse.active)
+		return;
+	MSE_INT_OFF();
+	free_irq(mouse_irq);
+	MOD_DEC_USE_COUNT;
 }
 
 /*
- * open access to the mouse, currently only one open is
- * allowed.
+ * open access to the mouse
  */
 
 static int open_mouse(struct inode * inode, struct file * file)
 {
 	if (!mouse.present)
 		return -EINVAL;
-	if (mouse.active)
+	if (mouse.active++)
+		return 0;
+	if (request_irq(mouse_irq, mouse_interrupt, 0, "Busmouse")) {
+		mouse.active--;
 		return -EBUSY;
+	}
 	mouse.ready = 0;
 	mouse.dx = 0;
 	mouse.dy = 0;
 	mouse.buttons = 0x87;
-	if (request_irq(mouse_irq, mouse_interrupt, 0, "Busmouse"))
-		return -EBUSY;
-	mouse.active = 1;
+	MOD_INC_USE_COUNT;
 	MSE_INT_ON();
 	return 0;
 }
@@ -208,26 +212,16 @@
 }
 
 /*
- * select for mouse input, must disable the mouse interrupt while checking
- * mouse.ready/select_wait() to avoid race condition (though in reality
- * such a condition is not fatal to the proper operation of the mouse since
- * multiple interrupts generally occur).
+ * select for mouse input
  */
-
 static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
 {
-    int r = 0;
-
-    if (sel_type == SEL_IN) {
-    	MSE_INT_OFF();
-    	if (mouse.ready) {
-    	    r = 1;
-    	} else {
-	    select_wait(&mouse.wait, wait);
+	if (sel_type == SEL_IN) {
+	    	if (mouse.ready)
+			return 1;
+		select_wait(&mouse.wait, wait);
     	}
-    	MSE_INT_ON();
-    }
-    return(r);
+	return 0;
 }
 
 struct file_operations bus_mouse_fops = {
@@ -248,13 +242,7 @@
 	LOGITECH_BUSMOUSE, "busmouse", &bus_mouse_fops
 };
 
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-
-int init_module(void)
-#else
-unsigned long bus_mouse_init(unsigned long kmem_start)
-#endif
+int bus_mouse_init(void)
 {
 	int i;
 
@@ -264,11 +252,7 @@
 		/* busy loop */;
 	if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) {
 		mouse.present = 0;
-#ifdef MODULE
 		return -EIO;
-#else
-		return kmem_start;
-#endif
 	}
 	outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
 	MSE_INT_OFF();
@@ -282,11 +266,7 @@
 	printk("Logitech Bus mouse detected and installed with IRQ %d.\n",
 	       mouse_irq);
 	mouse_register(&bus_mouse);
-#ifdef MODULE
 	return 0;
-#else
-	return kmem_start;
-#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/char/console.c linux/drivers/char/console.c
--- v1.3.32/linux/drivers/char/console.c	Wed Sep 27 15:59:57 1995
+++ linux/drivers/char/console.c	Tue Oct 10 12:19:12 1995
@@ -16,7 +16,7 @@
  *     'int vc_resize(unsigned long lines, unsigned long cols)'
  *     'void vc_disallocate(unsigned int currcons)'
  *
- *     'long con_init(long)'
+ *     'unsigned long con_init(unsigned long)'
  *     'int con_open(struct tty_struct *tty, struct file * filp)'
  *     'void con_write(struct tty_struct * tty)'
  *     'void console_print(const char * b)'
@@ -1369,6 +1369,7 @@
 	clr_kbd(kbdapplic);
 	clr_kbd(lnm);
 	kbd_table[currcons].lockstate = 0;
+	kbd_table[currcons].slockstate = 0;
 	kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
 	kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
 	set_leds();
@@ -1990,7 +1991,7 @@
 }
 
 /*
- *  long con_init(long);
+ *  unsigned long con_init(unsigned long);
  *
  * This routine initializes console interrupts, and does nothing
  * else. If you want the screen to clear, call tty_write with
@@ -1999,7 +2000,7 @@
  * Reads the information preserved by setup.s to determine the current display
  * type and sets everything accordingly.
  */
-long con_init(long kmem_start)
+unsigned long con_init(unsigned long kmem_start)
 {
 	const char *display_desc = "????";
 	int currcons = 0;
diff -u --recursive --new-file v1.3.32/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v1.3.32/linux/drivers/char/cyclades.c	Mon Sep 18 14:53:52 1995
+++ linux/drivers/char/cyclades.c	Tue Oct 10 10:41:02 1995
@@ -20,8 +20,8 @@
  * This version does not support shared irq's.
  *
  * This module exports the following rs232 io functions:
- *   long cy_init(long);
- *   int  cy_open(struct tty_struct *tty, struct file *filp);
+ *   int cy_init(void);
+ *   int cy_open(struct tty_struct *tty, struct file *filp);
  *
  * $Log: cyclades.c,v $
  * Revision 1.36.3.2  1995/09/08  22:07:14  bentson
@@ -2729,8 +2729,8 @@
     If there are more cards with more ports than have been statically
     allocated above, a warning is printed and the extra ports are ignored.
  */
-long
-cy_init(long kmem_start)
+int
+cy_init(void)
 {
   struct cyclades_port	*info;
   struct cyclades_card *cinfo;
@@ -2873,7 +2873,7 @@
 		/* info->timeout */
 	    }
     }
-    return kmem_start;
+    return 0;
     
 } /* cy_init */
 
diff -u --recursive --new-file v1.3.32/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v1.3.32/linux/drivers/char/istallion.c	Fri Sep 15 11:13:00 1995
+++ linux/drivers/char/istallion.c	Tue Oct 10 10:39:37 1995
@@ -226,14 +226,6 @@
 	INIT_C_CC
 };
 
-/*
- *	Memory allocation vars. These keep track of what memory allocation
- *	we can currently use. They help deal with memory in a consistent
- *	way, whether during init or run-time.
- */
-static int	stli_meminited = 0;
-static long	stli_memend;
-
 /*****************************************************************************/
 
 /*
@@ -587,13 +579,10 @@
 #ifdef MODULE
 int		init_module(void);
 void		cleanup_module(void);
-#else
-static void	stli_meminit(long base);
-static long	stli_memhalt(void);
 #endif
 static void	*stli_memalloc(int len);
 
-long		stli_init(long kmem_start);
+int		stli_init(void);
 static int	stli_open(struct tty_struct *tty, struct file *filp);
 static void	stli_close(struct tty_struct *tty, struct file *filp);
 static int	stli_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
@@ -738,7 +727,7 @@
 
 	save_flags(flags);
 	cli();
-	stli_init(0);
+	stli_init();
 	restore_flags(flags);
 
 	return(0);
@@ -824,33 +813,9 @@
  *	which are tightly controlled.
  */
 
-#ifndef MODULE
-
-static void stli_meminit(long base)
-{
-	stli_memend = base;
-	stli_meminited = 1;
-}
-
-static long stli_memhalt()
-{
-	stli_meminited = 0;
-	return(stli_memend);
-}
-
-#endif
-
 static void *stli_memalloc(int len)
 {
-	void	*mem;
-
-	if (stli_meminited) {
-		mem = (void *) stli_memend;
-		stli_memend += len;
-	} else {
-		mem = (void *) kmalloc(len, GFP_KERNEL);
-	}
-	return(mem);
+	return (void *) kmalloc(len, GFP_KERNEL);
 }
 
 /*****************************************************************************/
@@ -4015,14 +3980,10 @@
 
 /*****************************************************************************/
 
-long stli_init(long kmem_start)
+int stli_init(void)
 {
 	printk("%s: version %s\n", stli_drvname, stli_drvversion);
 
-#ifndef MODULE
-	stli_meminit(kmem_start);
-#endif
-
 	stli_brdinit();
 
 /*
@@ -4087,10 +4048,7 @@
 	if (tty_register_driver(&stli_callout))
 		printk("STALLION: failed to register callout driver\n");
 
-#ifndef MODULE
-	kmem_start = stli_memhalt();
-#endif
-	return(kmem_start);
+	return 0;
 }
 
 /*****************************************************************************/
diff -u --recursive --new-file v1.3.32/linux/drivers/char/kbd_kern.h linux/drivers/char/kbd_kern.h
--- v1.3.32/linux/drivers/char/kbd_kern.h	Wed Feb 15 10:50:55 1995
+++ linux/drivers/char/kbd_kern.h	Tue Oct 10 12:00:39 1995
@@ -33,6 +33,7 @@
 #define VC_SHIFTRLOCK	KG_SHIFTR	/* shiftr lock mode */
 #define VC_CTRLLLOCK	KG_CTRLL 	/* ctrll lock mode */
 #define VC_CTRLRLOCK	KG_CTRLR 	/* ctrlr lock mode */
+	unsigned char slockstate; 	/* for `sticky' Shift, Ctrl, etc. */
 
 	unsigned char ledmode:2; 	/* one 2-bit value */
 #define LED_SHOW_FLAGS 0        /* traditional state */
@@ -61,7 +62,7 @@
 
 extern struct kbd_struct kbd_table[];
 
-extern unsigned long kbd_init(unsigned long);
+extern int kbd_init(void);
 
 extern unsigned char getledstate(void);
 extern void setledstate(struct kbd_struct *kbd, unsigned int led);
@@ -104,6 +105,11 @@
 extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
 {
 	kbd->lockstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+{
+	kbd->slockstate ^= 1 << flag;
 }
 
 extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
diff -u --recursive --new-file v1.3.32/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v1.3.32/linux/drivers/char/keyboard.c	Wed Oct  4 14:14:29 1995
+++ linux/drivers/char/keyboard.c	Tue Oct 10 10:20:31 1995
@@ -13,6 +13,7 @@
  * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
  * Added decr/incr_console, dynamic keymaps, Unicode support,
  * dynamic function/string keys, led setting,  Sept 1994
+ * `Sticky' modifier keys, 951006.
  * 
  */
 
@@ -124,12 +125,12 @@
 
 static k_handfn
 	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
-	do_meta, do_ascii, do_lock, do_lowercase, do_ignore;
+	do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
 
 static k_hand key_handler[16] = {
 	do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
-	do_meta, do_ascii, do_lock, do_lowercase,
-	do_ignore, do_ignore, do_ignore, do_ignore
+	do_meta, do_ascii, do_lock, do_lowercase, do_slock,
+	do_ignore, do_ignore, do_ignore
 };
 
 typedef void (*void_fnp)(void);
@@ -151,7 +152,8 @@
 const int max_vals[] = {
 	255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
 	NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
-	255, NR_ASCII - 1, NR_LOCK - 1, 255
+	255, NR_ASCII - 1, NR_LOCK - 1, 255,
+	NR_LOCK - 1
 };
 
 const int NR_TYPES = SIZE(max_vals);
@@ -530,7 +532,7 @@
 		u_char type;
 
 		/* the XOR below used to be an OR */
-		int shift_final = shift_state ^ kbd->lockstate;
+		int shift_final = shift_state ^ kbd->lockstate ^ kbd->slockstate;
 		ushort *key_map = key_maps[shift_final];
 
 		if (key_map != NULL) {
@@ -548,6 +550,8 @@
 				}
 			    }
 			    (*key_handler[type])(keysym & 0xff, up_flag);
+			    if (type != KT_SLOCK)
+			      kbd->slockstate = 0;
 			} else {
 			    /* maybe only if (kbd->kbdmode == VC_UNICODE) ? */
 			    if (!up_flag)
@@ -1028,6 +1032,13 @@
 	chg_vc_kbd_lock(kbd, value);
 }
 
+static void do_slock(unsigned char value, char up_flag)
+{
+	if (up_flag || rep)
+		return;
+	chg_vc_kbd_slock(kbd, value);
+}
+
 /*
  * send_data sends a character to the keyboard and waits
  * for a acknowledge, possibly retrying if asked to. Returns
@@ -1165,7 +1176,7 @@
 	sti();
 }
 
-unsigned long kbd_init(unsigned long kmem_start)
+int kbd_init(void)
 {
 	int i;
 	struct kbd_struct kbd0;
@@ -1174,6 +1185,7 @@
 	kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
 	kbd0.ledmode = LED_SHOW_FLAGS;
 	kbd0.lockstate = KBD_DEFLOCK;
+	kbd0.slockstate = 0;
 	kbd0.modeflags = KBD_DEFMODE;
 	kbd0.kbdmode = VC_XLATE;
  
@@ -1202,5 +1214,5 @@
 #endif
 	mark_bh(KEYBOARD_BH);
 	enable_bh(KEYBOARD_BH);
-	return kmem_start;
+	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v1.3.32/linux/drivers/char/lp.c	Mon Sep 18 14:53:53 1995
+++ linux/drivers/char/lp.c	Tue Oct 10 10:42:01 1995
@@ -559,22 +559,17 @@
 char kernel_version[]=UTS_RELEASE;
 int io[] = {0, 0, 0};
 int irq[] = {0, 0, 0};
-
-int init_module(void)
-#else
-long lp_init(long kmem_start)
+#define lp_init init_module
 #endif
+
+int lp_init(void)
 {
 	int offset = 0;
 	int count = 0;
 
 	if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
 		printk("lp: unable to get major %d\n", LP_MAJOR);
-#ifdef MODULE
 		return -EIO;
-#else
-		return kmem_start;
-#endif
 	}
 #ifdef MODULE
 	/* When user feeds parameters, use them */
@@ -610,11 +605,7 @@
 	if (count == 0)
 		printk("lp: Driver configured but no interfaces found.\n");
 
-#ifdef MODULE
 	return 0;
-#else
-	return kmem_start;
-#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v1.3.32/linux/drivers/char/mem.c	Wed Oct  4 14:14:29 1995
+++ linux/drivers/char/mem.c	Tue Oct 10 10:13:39 1995
@@ -23,7 +23,7 @@
 #include <asm/pgtable.h>
 
 #ifdef CONFIG_SOUND
-extern long soundcard_init(long mem_start);
+int soundcard_init(void);
 #endif
 
 static int read_ram(struct inode * inode, struct file * file, char * buf, int count)
@@ -403,41 +403,27 @@
 	NULL		/* fsync */
 };
 
-#ifdef CONFIG_FTAPE
-char* ftape_big_buffer;
-#endif
-
-long chr_dev_init(long mem_start, long mem_end)
+int chr_dev_init(void)
 {
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 #ifdef CONFIG_RANDOM
 	rand_initialize();
 #endif
-	mem_start = tty_init(mem_start);
+	tty_init();
 #ifdef CONFIG_PRINTER
-	mem_start = lp_init(mem_start);
+	lp_init();
 #endif
 #if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
     defined (CONFIG_ATIXL_BUSMOUSE)
-	mem_start = mouse_init(mem_start);
+	mouse_init();
 #endif
 #ifdef CONFIG_SOUND
-	mem_start = soundcard_init(mem_start);
+	soundcard_init();
 #endif
 #if CONFIG_QIC02_TAPE
-	mem_start = qic02_tape_init(mem_start);
+	qic02_tape_init();
 #endif
-/*
- *      Rude way to allocate kernel memory buffer for tape device
- */
-#ifdef CONFIG_FTAPE
-        /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
-        ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
-        printk( "ftape: allocated %d buffers aligned at: %p\n",
-               NR_FTAPE_BUFFERS, ftape_big_buffer);
-        mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
-#endif 
-	return mem_start;
+	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/char/mouse.c linux/drivers/char/mouse.c
--- v1.3.32/linux/drivers/char/mouse.c	Fri Sep 15 11:13:00 1995
+++ linux/drivers/char/mouse.c	Tue Oct 10 10:23:09 1995
@@ -38,10 +38,10 @@
 static struct mouse mouse_list = { 0, "head", NULL, &mouse_list, &mouse_list };
 
 #ifndef MODULE
-extern unsigned long bus_mouse_init(unsigned long);
-extern unsigned long psaux_init(unsigned long);
-extern unsigned long ms_bus_mouse_init(unsigned long);
-extern unsigned long atixl_busmouse_init(unsigned long);
+extern int bus_mouse_init(void);
+extern int psaux_init(void);
+extern int ms_bus_mouse_init(void);
+extern int atixl_busmouse_init(void);
 #endif
 
 static int mouse_open(struct inode * inode, struct file * file)
@@ -79,6 +79,7 @@
 {
 	if (mouse->next || mouse->prev)
 		return -EBUSY;
+	MOD_INC_USE_COUNT;
 	mouse->next = &mouse_list;
 	mouse->prev = mouse_list.prev;
 	mouse->prev->next = mouse;
@@ -90,6 +91,7 @@
 {
 	if (!mouse->next || !mouse->prev)
 		return -EINVAL;
+	MOD_DEC_USE_COUNT;
 	mouse->prev->next = mouse->next;
 	mouse->next->prev = mouse->prev;
 	mouse->next = NULL;
@@ -99,53 +101,40 @@
 
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
-
-int init_module(void)
-#else
-unsigned long mouse_init(unsigned long kmem_start)
+#define mouse_init init_module
 #endif
+
+int mouse_init(void)
 {
 #ifndef MODULE
 #ifdef CONFIG_BUSMOUSE
-	kmem_start = bus_mouse_init(kmem_start);
+	bus_mouse_init();
 #endif
 #if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
-	kmem_start = psaux_init(kmem_start);
+	psaux_init();
 #endif
 #ifdef CONFIG_MS_BUSMOUSE
-	kmem_start = ms_bus_mouse_init(kmem_start);
+	ms_bus_mouse_init();
 #endif
 #ifdef CONFIG_ATIXL_BUSMOUSE
- 	kmem_start = atixl_busmouse_init(kmem_start);
+ 	atixl_busmouse_init();
 #endif
 #endif /* !MODULE */
 	if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) {
 	  printk("unable to get major %d for mouse devices\n",
 		 MOUSE_MAJOR);
-#ifdef MODULE
 		return -EIO;
-#endif
 	}
-#ifdef MODULE
 	return 0;
-#else
-	return kmem_start;
-#endif
 }
 
 #ifdef MODULE
 void cleanup_module(void)
 {
-	mouse_data *c = mouse_list, *n;
 	if (MOD_IN_USE) {
 		printk("mouse: in use, remove delayed\n");
 		return;
 	}
 	unregister_chrdev(MOUSE_MAJOR, "mouse");
-	while (c) {
-		n = c->next;
-		kfree(c);
-		c = n;
-	}
 }
 #endif
diff -u --recursive --new-file v1.3.32/linux/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- v1.3.32/linux/drivers/char/msbusmouse.c	Wed Oct  4 14:14:30 1995
+++ linux/drivers/char/msbusmouse.c	Tue Oct 10 10:29:30 1995
@@ -33,6 +33,9 @@
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
+
+char kernel_version[] = UTS_RELEASE;
+#define ms_bus_mouse_init init_module
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
@@ -96,26 +99,29 @@
 
 static void release_mouse(struct inode * inode, struct file * file)
 {
+	fasync_mouse(inode, file, 0);
+	if (--mouse.active)
+		return;
 	MS_MSE_INT_OFF();
-	mouse.active = mouse.ready = 0; 
+	mouse.ready = 0; 
 	free_irq(MOUSE_IRQ);
-	fasync_mouse(inode, file, 0);
+	MOD_DEC_USE_COUNT;
 }
 
 static int open_mouse(struct inode * inode, struct file * file)
 {
 	if (!mouse.present)
 		return -EINVAL;
-	if (mouse.active)
-		return -EBUSY;
-	mouse.active = 1;
-	mouse.ready = mouse.dx = mouse.dy = 0;	
-	mouse.buttons = 0x80;
+	if (mouse.active++)
+		return 0;
 	if (request_irq(MOUSE_IRQ, ms_mouse_interrupt, 0, "MS Busmouse")) {
-		mouse.active = 0;
+		mouse.active--;
 		return -EBUSY;
 	}
+	mouse.ready = mouse.dx = mouse.dy = 0;	
+	mouse.buttons = 0x80;
 	outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
+	MOD_INC_USE_COUNT;
 	MS_MSE_INT_ON();	
 	return 0;
 }
@@ -175,13 +181,7 @@
 	MICROSOFT_BUSMOUSE, "msbusmouse", &ms_bus_mouse_fops
 };
 
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-
-int init_module(void)
-#else
-unsigned long ms_bus_mouse_init(unsigned long kmem_start)
-#endif
+int ms_bus_mouse_init(void)
 {
 	int mse_byte, i;
 
@@ -207,33 +207,24 @@
 				mouse.present = 0;
 		}
 	}
-	if (mouse.present == 0) {
-#ifdef MODULE
-	  return -EIO;
-#else
-		return kmem_start;
-#endif
-	}
+	if (mouse.present == 0)
+		return -EIO;
 	MS_MSE_INT_OFF();
 	request_region(MS_MSE_CONTROL_PORT, 0x04, "MS Busmouse");
 	printk("Microsoft BusMouse detected and installed.\n");
 	mouse_register(&ms_bus_mouse);
-#ifdef MODULE
 	return 0;
-#else
-	return kmem_start;
-#endif
 }
 
 #ifdef MODULE
 void cleanup_module(void)
 {
-	if (MOD_IN_USE)
+	if (MOD_IN_USE) {
 		printk("msbusmouse: in use, remove delayed\n");
-	else {
-		mouse_deregister(&ms_bus_mouse);
-		release_region(MS_MSE_CONTROL_PORT, 0x04);
+		return;
 	}
+	mouse_deregister(&ms_bus_mouse);
+	release_region(MS_MSE_CONTROL_PORT, 0x04);
 }
 #endif
 
diff -u --recursive --new-file v1.3.32/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v1.3.32/linux/drivers/char/psaux.c	Wed Oct  4 14:14:30 1995
+++ linux/drivers/char/psaux.c	Tue Oct 10 10:25:26 1995
@@ -123,7 +123,7 @@
 
 static struct aux_queue *queue;
 static int aux_ready = 0;
-static int aux_busy = 0;
+static int aux_count = 0;
 static int aux_present = 0;
 static int poll_aux_status(void);
 static int poll_aux_status_nosleep(void);
@@ -131,7 +131,7 @@
 
 #ifdef CONFIG_82C710_MOUSE
 static int qp_present = 0;
-static int qp_busy = 0;
+static int qp_count = 0;
 static int qp_data = QP_DATA;
 static int qp_status = QP_STATUS;
 
@@ -260,13 +260,15 @@
 
 static void release_aux(struct inode * inode, struct file * file)
 {
+	fasync_aux(inode, file, 0);
+	if (--aux_count)
+		return;
 	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */
 	poll_aux_status();
 	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
 	poll_aux_status();
 	free_irq(AUX_IRQ);
-	fasync_aux(inode, file, 0);
-	aux_busy = 0;
+	MOD_DEC_USE_COUNT;
 }
 
 #ifdef CONFIG_82C710_MOUSE
@@ -274,6 +276,9 @@
 {
 	unsigned char status;
 
+	fasync_aux(inode, file, 0);
+	if (--qp_count)
+		return;
 	if (!poll_qp_status())
 		printk("Warning: Mouse device busy in release_qp()\n");
 	status = inb_p(qp_status);
@@ -281,8 +286,7 @@
 	if (!poll_qp_status())
 		printk("Warning: Mouse device busy in release_qp()\n");
 	free_irq(QP_IRQ);
-	fasync_aux(inode, file, 0);
-	qp_busy = 0;
+	MOD_DEC_USE_COUNT;
 }
 #endif
 
@@ -304,15 +308,16 @@
 static int open_aux(struct inode * inode, struct file * file)
 {
 	if (!aux_present)
-		return -EINVAL;
-	if (aux_busy)
-		return -EBUSY;
-	if (!poll_aux_status())
+		return -ENODEV;
+	if (aux_count++)
+		return 0;
+	if (!poll_aux_status()) {
+		aux_count--;
 		return -EBUSY;
-	aux_busy = 1;
+	}
 	queue->head = queue->tail = 0;		/* Flush input queue */
 	if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse")) {
-		aux_busy = 0;
+		aux_count--;
 		return -EBUSY;
 	}
 	poll_aux_status();
@@ -321,14 +326,14 @@
 	aux_write_cmd(AUX_INTS_ON);		/* enable controller ints */
 	poll_aux_status();
 	aux_ready = 0;
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 #ifdef CONFIG_82C710_MOUSE
 /*
  * Install interrupt handler.
- * Enable the device, enable interrupts. Set qp_busy
- * (allow only one opener at a time.)
+ * Enable the device, enable interrupts. 
  */
 
 static int open_qp(struct inode * inode, struct file * file)
@@ -338,13 +343,13 @@
 	if (!qp_present)
 		return -EINVAL;
 
-	if (qp_busy)
-		return -EBUSY;
+	if (qp_count++)
+		return 0;
 
-	if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse"))
+	if (request_irq(QP_IRQ, qp_interrupt, 0, "PS/2 Mouse")) {
+		qp_count--;
 		return -EBUSY;
-
-	qp_busy = 1;
+	}
 
 	status = inb_p(qp_status);
 	status |= (QP_ENABLE|QP_RESET);
@@ -358,11 +363,15 @@
 
 	while (!poll_qp_status()) {
 		printk("Error: Mouse device busy in open_qp()\n");
+		qp_count--;
+		status &= ~(QP_ENABLE|QP_INTS_ON);
+		outb_p(status, qp_status);
+		free_irq(QP_IRQ);
 		return -EBUSY;
 	}
 
 	outb_p(AUX_ENABLE_DEV, qp_data);	/* Wake up mouse */
-
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 #endif
@@ -481,7 +490,7 @@
 	PSMOUSE_MINOR, "ps2aux", &psaux_fops
 };
 
-unsigned long psaux_init(unsigned long kmem_start)
+int psaux_init(void)
 {
 	int qp_found = 0;
 
@@ -500,15 +509,10 @@
 	 	aux_present = 1;
 		kbd_read_mask = AUX_OBUF_FULL;
 	} else {
-#ifdef MODULE
 		return -EIO;
-#else
-		return kmem_start;              /* No mouse at all */
-#endif
 	}
 	mouse_register(&psaux_mouse);
-	queue = (struct aux_queue *) kmem_start;
-	kmem_start += sizeof (struct aux_queue);
+	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
 	queue->proc_list = NULL;
@@ -528,11 +532,7 @@
 		poll_aux_status_nosleep();             /* Disable interrupts */
 		outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /*  on the controller */
 	}
-#ifdef MODULE
 	return 0;
-#else
-	return kmem_start;
-#endif
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v1.3.32/linux/drivers/char/pty.c	Wed Aug  2 13:21:00 1995
+++ linux/drivers/char/pty.c	Tue Oct 10 10:30:00 1995
@@ -211,7 +211,7 @@
 	return 0;
 }
 
-long pty_init(long kmem_start)
+int pty_init(void)
 {
 	memset(&pty_state, 0, sizeof(pty_state));
 	memset(&pty_driver, 0, sizeof(struct tty_driver));
@@ -260,5 +260,5 @@
 	if (tty_register_driver(&pty_slave_driver))
 		panic("Couldn't register pty slave driver");
 	
-	return kmem_start;
+	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/char/scc.c linux/drivers/char/scc.c
--- v1.3.32/linux/drivers/char/scc.c	Mon Sep 18 14:53:53 1995
+++ linux/drivers/char/scc.c	Tue Oct 10 10:37:06 1995
@@ -158,7 +158,7 @@
 #define Z8530_MAJOR 34
 #endif
 
-long scc_init(long kmem_start);
+int scc_init(void);
 
 int scc_open(struct tty_struct *tty, struct file *filp);
 static void scc_close(struct tty_struct *tty, struct file *filp);
@@ -2298,7 +2298,7 @@
 /* * 			Init SCC driver 			      * */
 /* ******************************************************************** */
 
-long scc_init (long kmem_start)
+int scc_init (void)
 {
 	int chip, chan;
 	register io_port ctrl;
@@ -2418,6 +2418,6 @@
 #endif
 
 	
-	return kmem_start;
+	return 0;
 }
 #endif
diff -u --recursive --new-file v1.3.32/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.3.32/linux/drivers/char/serial.c	Mon Sep 18 14:53:53 1995
+++ linux/drivers/char/serial.c	Tue Oct 10 10:37:50 1995
@@ -13,8 +13,8 @@
  *
  * This module exports the following rs232 io functions:
  *
- *	long rs_init(long);
- * 	int  rs_open(struct tty_struct * tty, struct file * filp)
+ *	int rs_init(void);
+ * 	int rs_open(struct tty_struct * tty, struct file * filp)
  */
 
 #include <linux/errno.h>
@@ -2572,7 +2572,7 @@
 /*
  * The serial driver boot-time initialization code!
  */
-long rs_init(long kmem_start)
+int rs_init(void)
 {
 	int i;
 	struct async_struct * info;
@@ -2695,7 +2695,7 @@
 				break;
 		}
 	}
-	return kmem_start;
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v1.3.32/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v1.3.32/linux/drivers/char/stallion.c	Fri Sep 15 11:13:01 1995
+++ linux/drivers/char/stallion.c	Tue Oct 10 10:36:02 1995
@@ -438,16 +438,6 @@
 /*****************************************************************************/
 
 /*
- *	Memory allocation vars. These keep track of what memory allocation
- *	we can currently use. They help deal with memory in a consistent
- *	way, whether during init or run-time.
- */
-static int	stl_meminited = 0;
-static long	stl_memend;
-
-/*****************************************************************************/
-
-/*
  *	Define some handy local macros...
  */
 #ifndef	MIN
@@ -463,13 +453,10 @@
 #ifdef MODULE
 int		init_module(void);
 void		cleanup_module(void);
-#else
-static void	stl_meminit(long base);
-static long	stl_memhalt(void);
 #endif
 static void	*stl_memalloc(int len);
 
-long		stl_init(long kmem_start);
+int		stl_init(void);
 static int	stl_open(struct tty_struct *tty, struct file *filp);
 static void	stl_close(struct tty_struct *tty, struct file *filp);
 static int	stl_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
@@ -533,7 +520,7 @@
 
 	save_flags(flags);
 	cli();
-	stl_init(0);
+	stl_init();
 	restore_flags(flags);
 
 	return(0);
@@ -628,33 +615,9 @@
  *	memory and it will do the right thing.
  */
 
-#ifndef MODULE
-
-static void stl_meminit(long base)
-{
-	stl_memend = base;
-	stl_meminited = 1;
-}
-
-static long stl_memhalt()
-{
-	stl_meminited = 0;
-	return(stl_memend);
-}
-
-#endif
-
 static void *stl_memalloc(int len)
 {
-	void	*mem;
-
-	if (stl_meminited) {
-		mem = (void *) stl_memend;
-		stl_memend += len;
-	} else {
-		mem = (void *) kmalloc(len, GFP_KERNEL);
-	}
-	return(mem);
+	return (void *) kmalloc(len, GFP_KERNEL);
 }
 
 /*****************************************************************************/
@@ -2902,14 +2865,10 @@
 
 /*****************************************************************************/
 
-long stl_init(long kmem_start)
+int stl_init(void)
 {
 	printk("%s: version %s\n", stl_drvname, stl_drvversion);
 
-#ifndef	MODULE
-	stl_meminit(kmem_start);
-#endif
-
 	stl_initbrds();
 
 /*
@@ -2964,10 +2923,7 @@
 	if (tty_register_driver(&stl_callout))
 		printk("STALLION: failed to register callout driver\n");
 
-#ifndef	MODULE
-	kmem_start = stl_memhalt();
-#endif
-	return(kmem_start);
+	return 0;
 }
 
 /*****************************************************************************/
diff -u --recursive --new-file v1.3.32/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v1.3.32/linux/drivers/char/tpqic02.c	Mon Sep 18 14:53:53 1995
+++ linux/drivers/char/tpqic02.c	Tue Oct 10 10:32:05 1995
@@ -2870,17 +2870,17 @@
 } /* qic02_get_resources */
 
 
-long qic02_tape_init(long kmem_start)
+int qic02_tape_init(void)
 	/* Shouldn't this be a caddr_t ? */
 {
 
 	if (TPSTATSIZE != 6) {
 		printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
-		return kmem_start;
+		return -ENODEV;
 	}
 	if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000)) {
 		printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
-		return kmem_start;
+		return -ENODEV;
 	}
 
 	QIC02_TAPE_DEBUG = TPQD_DEFAULT_FLAGS;
@@ -2901,7 +2901,7 @@
 # endif
 		 rcs_revision, rcs_date);
 	if (qic02_get_resources())
-		return kmem_start;
+		return -ENODEV;
 #else
 	printk(TPQIC02_NAME ": Runtime config, %s, %s\n", 
 		 rcs_revision, rcs_date);
@@ -2921,7 +2921,7 @@
 #ifndef CONFIG_MAX_16M
 	if (buffaddr+TPQBUF_SIZE>=0x1000000) {
 		printk(TPQIC02_NAME ": DMA buffer *must* be in lower 16MB\n");
-		return kmem_start;
+		return -ENODEV;
 	}
 #endif
 
@@ -2932,7 +2932,7 @@
 		free_irq(QIC02_TAPE_IRQ);
 		free_dma(QIC02_TAPE_DMA);
 #endif
-		return kmem_start;
+		return -ENODEV;
 	}
 
 	/* prepare timer */
@@ -2948,7 +2948,7 @@
 		free_irq(QIC02_TAPE_IRQ);
 		free_dma(QIC02_TAPE_DMA);
 		unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
-		return kmem_start;
+		return -ENODEV;
 	} else {
 		if (is_exception()) {
 			tpqputs(TPQD_ALWAYS, "exception detected\n");
@@ -2967,6 +2967,6 @@
 	ioctl_status.mt_fileno	= 0;	/* number of current file on tape */
 	ioctl_status.mt_blkno	= 0;	/* number of current (logical) block */
 
-	return kmem_start;
+	return 0;
 } /* qic02_tape_init */
 
diff -u --recursive --new-file v1.3.32/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.32/linux/drivers/char/tty_io.c	Mon Sep 18 14:53:53 1995
+++ linux/drivers/char/tty_io.c	Tue Oct 10 10:27:28 1995
@@ -1777,7 +1777,7 @@
  * Ok, now we can initialize the rest of the tty devices and can count
  * on memory allocations, interrupts etc..
  */
-long tty_init(long kmem_start)
+int tty_init(void)
 {
 	if (sizeof(struct tty_struct) > PAGE_SIZE)
 		panic("size of tty structure > PAGE_SIZE!");
@@ -1786,21 +1786,21 @@
 	if (register_chrdev(TTYAUX_MAJOR,"cua",&tty_fops))
 		panic("unable to get major %d for tty device", TTYAUX_MAJOR);
 
-	kmem_start = kbd_init(kmem_start);
-	kmem_start = rs_init(kmem_start);
+	kbd_init();
+	rs_init();
 #ifdef CONFIG_SCC
-	kmem_start = scc_init(kmem_start);
+	scc_init();
 #endif
 #ifdef CONFIG_CYCLADES
-	kmem_start = cy_init(kmem_start);
+	cy_init();
 #endif
 #ifdef CONFIG_STALLION
-	kmem_start = stl_init(kmem_start);
+	stl_init();
 #endif
 #ifdef CONFIG_ISTALLION
-	kmem_start = stli_init(kmem_start);
+	stli_init();
 #endif
-	kmem_start = pty_init(kmem_start);
-	kmem_start = vcs_init(kmem_start);
-	return kmem_start;
+	pty_init();
+	vcs_init();
+	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v1.3.32/linux/drivers/char/vc_screen.c	Wed Aug  2 13:21:01 1995
+++ linux/drivers/char/vc_screen.c	Tue Oct 10 10:31:02 1995
@@ -204,9 +204,12 @@
 	NULL		/* fsync */
 };
 
-long vcs_init(long kmem_start)
+int vcs_init(void)
 {
-	if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
+	int error;
+
+	error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
+	if (error)
 		printk("unable to get major %d for vcs device", VCS_MAJOR);
-	return kmem_start;
+	return error;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v1.3.32/linux/drivers/net/3c503.c	Wed Oct  4 14:14:30 1995
+++ linux/drivers/net/3c503.c	Tue Oct 10 14:03:45 1995
@@ -183,7 +183,7 @@
     request_region(ioaddr, EL2_IO_EXTENT,"3c503");
 
     if (dev == NULL)
-	dev = init_etherdev(0, sizeof(struct ei_device), 0);
+	dev = init_etherdev(0, sizeof(struct ei_device));
 
     if (ei_debug  &&  version_printed++ == 0)
 	printk(version);
diff -u --recursive --new-file v1.3.32/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v1.3.32/linux/drivers/net/3c505.c	Sat Sep  9 15:26:52 1995
+++ linux/drivers/net/3c505.c	Tue Oct 10 15:04:54 1995
@@ -1258,7 +1258,7 @@
 	adapter = (elp_device *)(dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL));
 	CHECK_NULL(adapter);
 	if (adapter == NULL)
-		return -ENOMEM;
+		return;
 	memset(&(adapter->stats), 0, sizeof(struct enet_statistics));
 
 	/*
diff -u --recursive --new-file v1.3.32/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v1.3.32/linux/drivers/net/3c507.c	Fri Oct  6 14:35:15 1995
+++ linux/drivers/net/3c507.c	Tue Oct 10 15:45:26 1995
@@ -354,7 +354,7 @@
 
 	/* Allocate a new 'dev' if needed. */
 	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct net_local), 0);
+		dev = init_etherdev(0, sizeof(struct net_local));
 
 	if (net_debug  &&  version_printed++ == 0)
 		printk(version);
@@ -427,6 +427,8 @@
 	dev->get_stats	= el16_get_stats;
 
 	ether_setup(dev);	/* Generic ethernet behaviour */
+	
+	dev->flags&=~IFF_MULTICAST;	/* Multicast doesn't work */
 
 	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.32/linux/drivers/net/Makefile	Sat Sep  9 15:26:52 1995
+++ linux/drivers/net/Makefile	Mon Oct  9 09:17:53 1995
@@ -139,6 +139,10 @@
   endif
 endif
 
+ifneq ($(CONFIG_PPP),n)
+  M_OBJS += bsd_comp.o
+endif
+
 ifeq ($(CONFIG_SLIP),y)
 L_OBJS += slip.o
 CONFIG_SLHC_BUILTIN = y
diff -u --recursive --new-file v1.3.32/linux/drivers/net/README.multicast linux/drivers/net/README.multicast
--- v1.3.32/linux/drivers/net/README.multicast	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/README.multicast	Tue Oct 10 15:45:26 1995
@@ -0,0 +1,58 @@
+Behaviour of cards under Multicast. This is how they currently 
+behave not what the hardware can do. In paticular all the 8390 based
+cards don't use the onboard hash filter, and the lance driver doesn't
+use its filter, even though the code for loading it is in the DEC
+lance based driver.
+
+The following multicast requirements are needed
+-----------------------------------------------
+Appletalk	Multicast	hardware filtering not important but
+				 avoid cards only doing promisc
+IP-Multicast	Multicast	hardware filters really help
+IP-MRoute	AllMulti	hardware filters are of no help
+
+
+Board		Multicast	AllMulti	Promisc		Filter
+------------------------------------------------------------------------
+3c501		YES		YES		YES		Software
+3c503		YES		YES		YES		Software(#)
+3c505		YES		NO		YES		Hardware
+3c507		NO		NO		NO		N/A
+3c509		YES		YES		YES		Software
+ac3200		YES		YES		YES		Software(#)
+apricot		YES		PROMISC		YES		Hardware
+arcnet		NO		NO		NO		N/A
+at1700		****		PROMISC		YES		Software
+atp		****		PROMISC		YES		Software
+de4x5		YES		NO		YES		Hardware
+de600		NO		NO		NO		N/A
+de620		****		PROMISC		YES		Software
+depca		YES		PROMISC		YES		Hardware
+e2100		YES		YES		YES		Software(#)
+eepro		YES(*)		PROMISC		YES		Hardware
+eexpress	NO		NO		NO		N/A
+ewrk3		YES		PROMISC		YES		Hardware
+hp-plus		YES		YES		YES		Software(#)
+hp		YES		YES		YES		Software(#)
+hp100		YES		YES		YES		Software(#)
+ibmtr		NO		NO		NO		N/A
+lance		YES		YES		YES		Software(#)
+ne		YES		YES		YES		Software(#)
+ni52
+ni65		NO		NO		NO		N/A
+seeq		NO		NO		NO		N/A
+sk_g16		NO		NO		YES		N/A
+smc-ultra	YES		YES		YES		Software(#)
+tulip		YES		YES		YES		Hardware
+wavelan		--------Buggy--------		YES		N/A
+wd		YES		YES		YES		Software(#)
+znet		YES		YES		YES		Software
+
+
+**** = This driver would take down your entire network if you use it in a
+       multicast kernel with IP forwarding enabled (patches sent to Linus)
+YES(*) = As above but only if >64 addresses are activated.
+PROMISC = All multicasts mode is in fact promiscuous mode.
+(#) = Hardware multicast support is not used yet.
+
+
diff -u --recursive --new-file v1.3.32/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.3.32/linux/drivers/net/Space.c	Tue Aug  8 12:31:34 1995
+++ linux/drivers/net/Space.c	Mon Oct  9 09:17:54 1995
@@ -252,34 +252,10 @@
   
 #if defined(CONFIG_PPP)
 extern int ppp_init(struct device *);
-#ifdef CONFIG_PPP_LOTS
-
-    static struct device ppp15_dev={"ppp15",0,0,0,0,15,0,0,0,0,NEXT_DEV,ppp_init};
-    static struct device ppp14_dev={"ppp14",0,0,0,0,14,0,0,0,0,&ppp15_dev,ppp_init};
-    static struct device ppp13_dev={"ppp13",0,0,0,0,13,0,0,0,0,&ppp14_dev,ppp_init};
-    static struct device ppp12_dev={"ppp12",0,0,0,0,12,0,0,0,0,&ppp13_dev,ppp_init};
-    static struct device ppp11_dev={"ppp11",0,0,0,0,11,0,0,0,0,&ppp12_dev,ppp_init};
-    static struct device ppp10_dev={"ppp10",0,0,0,0,10,0,0,0,0,&ppp11_dev,ppp_init};
-    static struct device ppp9_dev={"ppp9",0,0,0,0,9,0,0,0,0,&ppp10_dev,ppp_init};
-    static struct device ppp8_dev={"ppp8",0,0,0,0,8,0,0,0,0,&ppp9_dev,ppp_init};
-    static struct device ppp7_dev={"ppp7",0,0,0,0,7,0,0,0,0,&ppp8_dev,ppp_init};
-    static struct device ppp6_dev={"ppp6",0,0,0,0,6,0,0,0,0,&ppp7_dev,ppp_init};
-    static struct device ppp5_dev={"ppp5",0,0,0,0,5,0,0,0,0,&ppp6_dev,ppp_init};
-    static struct device ppp4_dev={"ppp4",0,0,0,0,4,0,0,0,0,&ppp5_dev,ppp_init};
-#   undef	NEXT_DEV
-#   define	NEXT_DEV	(&ppp4_dev)
-#endif	/* CONFIG_PPP_LOTS */
-
-static struct device ppp3_dev = {
-    "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, NEXT_DEV,  ppp_init, };
-static struct device ppp2_dev = {
-    "ppp2", 0x0, 0x0, 0x0, 0x0, 2, 0, 0, 0, 0, &ppp3_dev, ppp_init, };
-static struct device ppp1_dev = {
-    "ppp1", 0x0, 0x0, 0x0, 0x0, 1, 0, 0, 0, 0, &ppp2_dev, ppp_init, };
-static struct device ppp0_dev = {
-    "ppp0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, &ppp1_dev, ppp_init, };
+static struct device ppp_bootstrap = {
+    "ppp_proto", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, ppp_init, };
 #undef NEXT_DEV
-#define NEXT_DEV (&ppp0_dev)
+#define NEXT_DEV (&ppp_bootstrap)
 #endif   /* PPP */
 
 #ifdef CONFIG_DUMMY
diff -u --recursive --new-file v1.3.32/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v1.3.32/linux/drivers/net/at1700.c	Fri Oct  6 14:35:15 1995
+++ linux/drivers/net/at1700.c	Tue Oct 10 15:45:26 1995
@@ -205,7 +205,7 @@
 
 	/* Allocate a new 'dev' if needed. */
 	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct net_local), 0);
+		dev = init_etherdev(0, sizeof(struct net_local));
 
 	/* Grab the region so that we can find another board if the IRQ request
 	   fails. */
@@ -623,9 +623,18 @@
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
 	short ioaddr = dev->base_addr;
-	if (num_addrs) {
+	if (num_addrs) 
+	{
+		/*
+		 *	We must make the kernel realise we had to move
+		 *	into promisc mode or we start all out war on
+		 *	the cable. - AC
+		 */
+		dev->flags|=IFF_PROMISC;		
+	
 		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
-	} else
+	} 
+	else
 		outb(2, ioaddr + RX_MODE);	/* Disable promiscuous, use normal mode */
 }
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v1.3.32/linux/drivers/net/atp.c	Sat Sep  9 15:26:52 1995
+++ linux/drivers/net/atp.c	Tue Oct 10 15:45:26 1995
@@ -765,6 +765,13 @@
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
+	/*
+	 *	We must make the kernel realise we had to move
+	 *	into promisc mode or we start all out war on
+	 *	the cable. - AC
+	 */
+	if(num_addrs)
+		dev->flags|=IFF_PROMISC;		
 	lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal;
 	write_reg_high(ioaddr, CMR2, lp->addr_mode);
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/net/bsd_comp.c linux/drivers/net/bsd_comp.c
--- v1.3.32/linux/drivers/net/bsd_comp.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/bsd_comp.c	Mon Oct  9 09:17:54 1995
@@ -0,0 +1,1207 @@
+/* Because this code is derived from the 4.3BSD compress source:
+ *
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This version is for use with contigious buffers on Linux-derived systems.
+ *
+ *  ==FILEVERSION 4==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     bsd_comp.c is shipped with a PPP distribution as well as with
+ *     the kernel; if everyone increases the FILEVERSION number above,
+ *     then scripts can do the right thing when deciding whether to
+ *     install a new bsd_comp.c file. Don't change the format of that
+ *     line otherwise, so the installation script can recognize it.
+ *
+ * $Id: bsd_comp.c,v 1.1 1994/12/08 01:59:58 paulus Exp $
+ */
+
+#ifndef MODULE
+#error This file must be compiled as a module.
+#endif
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <endian.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/sched.h>	/* to get the struct task_struct */
+#include <linux/string.h>	/* used in new tty drivers */
+#include <linux/signal.h>	/* used in new tty drivers */
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+
+#include <net/if.h>
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inet.h>
+#include <linux/ioctl.h>
+
+#include <linux/ppp_defs.h>
+
+#ifdef NEW_SKBUFF
+#include <linux/netprotocol.h>
+#endif
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if_arp.h>
+
+#undef   PACKETPTR
+#define  PACKETPTR 1
+#include <linux/ppp-comp.h>
+#undef   PACKETPTR
+
+/*
+ * PPP "BSD compress" compression
+ *  The differences between this compression and the classic BSD LZW
+ *  source are obvious from the requirement that the classic code worked
+ *  with files while this handles arbitrarily long streams that
+ *  are broken into packets.  They are:
+ *
+ *	When the code size expands, a block of junk is not emitted by
+ *	    the compressor and not expected by the decompressor.
+ *
+ *	New codes are not necessarily assigned every time an old
+ *	    code is output by the compressor.  This is because a packet
+ *	    end forces a code to be emitted, but does not imply that a
+ *	    new sequence has been seen.
+ *
+ *	The compression ratio is checked at the first end of a packet
+ *	    after the appropriate gap.	Besides simplifying and speeding
+ *	    things up, this makes it more likely that the transmitter
+ *	    and receiver will agree when the dictionary is cleared when
+ *	    compression is not going well.
+ */
+
+/*
+ * Macros to extract protocol version and number of bits
+ * from the third byte of the BSD Compress CCP configuration option.
+ */
+
+#define BSD_VERSION(x)	((x) >> 5)
+#define BSD_NBITS(x)	((x) & 0x1F)
+
+#define BSD_CURRENT_VERSION	1
+
+/*
+ * A dictionary for doing BSD compress.
+ */
+
+struct bsd_dict {
+    union {				/* hash value */
+	unsigned long	fcode;
+	struct {
+#ifndef BIG_ENDIAN_BITFIELD /* Little endian order */
+	    unsigned short	prefix;	/* preceding code */
+	    unsigned char	suffix; /* last character of new code */
+	    unsigned char	pad;
+#else /* Big endian order */
+	    unsigned char	pad;
+	    unsigned char	suffix; /* last character of new code */
+	    unsigned short	prefix; /* preceding code */
+#endif
+	} hs;
+    } f;
+    unsigned short codem1;		/* output of hash table -1 */
+    unsigned short cptr;		/* map code to hash table entry */
+};
+
+struct bsd_db {
+    int	    totlen;			/* length of this structure */
+    unsigned int   hsize;		/* size of the hash table */
+    unsigned char  hshift;		/* used in hash function */
+    unsigned char  n_bits;		/* current bits/code */
+    unsigned char  maxbits;		/* maximum bits/code */
+    unsigned char  debug;		/* non-zero if debug desired */
+    unsigned char  unit;		/* ppp unit number */
+    unsigned short seqno;		/* sequence # of next packet */
+    unsigned int   mru;			/* size of receive (decompress) bufr */
+    unsigned int   maxmaxcode;		/* largest valid code */
+    unsigned int   max_ent;		/* largest code in use */
+    unsigned int   in_count;		/* uncompressed bytes, aged */
+    unsigned int   bytes_out;		/* compressed bytes, aged */
+    unsigned int   ratio;		/* recent compression ratio */
+    unsigned int   checkpoint;		/* when to next check the ratio */
+    unsigned int   clear_count;		/* times dictionary cleared */
+    unsigned int   incomp_count;	/* incompressible packets */
+    unsigned int   incomp_bytes;	/* incompressible bytes */
+    unsigned int   uncomp_count;	/* uncompressed packets */
+    unsigned int   uncomp_bytes;	/* uncompressed bytes */
+    unsigned int   comp_count;		/* compressed packets */
+    unsigned int   comp_bytes;		/* compressed bytes */
+    unsigned short  *lens;		/* array of lengths of codes */
+    struct bsd_dict *dict;		/* dictionary */
+};
+
+#define BSD_OVHD	2		/* BSD compress overhead/packet */
+#define MIN_BSD_BITS	9
+#define BSD_INIT_BITS	MIN_BSD_BITS
+#define MAX_BSD_BITS	15
+
+static void	bsd_free (void *state);
+static void	*bsd_alloc(unsigned char *options, int opt_len, int decomp);
+static void	*bsd_comp_alloc (unsigned char *options, int opt_len);
+static void	*bsd_decomp_alloc (unsigned char *options, int opt_len);
+
+static int	bsd_init        (void *db, unsigned char *options,
+			         int opt_len, int unit, int debug, int decomp);
+static int	bsd_comp_init   (void *state, unsigned char *options,
+			         int opt_len, int unit, int opthdr, int debug);
+static int	bsd_decomp_init (void *state, unsigned char *options,
+				 int opt_len, int unit, int opthdr, int mru,
+				 int debug);
+
+static void	bsd_reset (void *state);
+static void	bsd_comp_stats (void *state, struct compstat *stats);
+
+static int	bsd_compress (void *state, unsigned char *rptr,
+			      unsigned char *obuf, int isize, int osize);
+static void	bsd_incomp (void *state, unsigned char *ibuf, int icnt);
+
+static int	bsd_decompress (void *state, unsigned char *ibuf, int isize,
+				unsigned char *obuf, int osize);
+
+/* These are in ppp.c */
+extern int  ppp_register_compressor   (struct compressor *cp);
+extern void ppp_unregister_compressor (struct compressor *cp);
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define CLEAR	256			/* table clear output code */
+#define FIRST	257			/* first free entry */
+#define LAST	255
+
+#define MAXCODE(b)	((1 << (b)) - 1)
+#define BADCODEM1	MAXCODE(MAX_BSD_BITS);
+
+#define BSD_HASH(prefix,suffix,hshift) ((((unsigned long)(suffix))<<(hshift)) \
+					 ^ (unsigned long)(prefix))
+#define BSD_KEY(prefix,suffix)		((((unsigned long)(suffix)) << 16) \
+					 + (unsigned long)(prefix))
+
+#define CHECK_GAP	10000		/* Ratio check interval */
+
+#define RATIO_SCALE_LOG	8
+#define RATIO_SCALE	(1<<RATIO_SCALE_LOG)
+#define RATIO_MAX	(0x7fffffff>>RATIO_SCALE_LOG)
+
+/*
+ * clear the dictionary
+ */
+
+static void
+bsd_clear(struct bsd_db *db)
+{
+    db->clear_count++;
+    db->max_ent      = FIRST-1;
+    db->n_bits       = BSD_INIT_BITS;
+    db->bytes_out    = 0;
+    db->in_count     = 0;
+    db->incomp_count = 0;
+    db->ratio	     = 0;
+    db->checkpoint   = CHECK_GAP;
+}
+
+/*
+ * If the dictionary is full, then see if it is time to reset it.
+ *
+ * Compute the compression ratio using fixed-point arithmetic
+ * with 8 fractional bits.
+ *
+ * Since we have an infinite stream instead of a single file,
+ * watch only the local compression ratio.
+ *
+ * Since both peers must reset the dictionary at the same time even in
+ * the absence of CLEAR codes (while packets are incompressible), they
+ * must compute the same ratio.
+ */
+
+static int bsd_check (struct bsd_db *db)	/* 1=output CLEAR */
+  {
+    unsigned int new_ratio;
+
+    if (db->in_count >= db->checkpoint)
+      {
+	/* age the ratio by limiting the size of the counts */
+	if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX)
+	  {
+	    db->in_count  -= (db->in_count  >> 2);
+	    db->bytes_out -= (db->bytes_out >> 2);
+	  }
+	
+	db->checkpoint = db->in_count + CHECK_GAP;
+	
+	if (db->max_ent >= db->maxmaxcode)
+	  {
+	    /* Reset the dictionary only if the ratio is worse,
+	     * or if it looks as if it has been poisoned
+	     * by incompressible data.
+	     *
+	     * This does not overflow, because
+	     *	db->in_count <= RATIO_MAX.
+	     */
+
+	    new_ratio = db->in_count << RATIO_SCALE_LOG;
+	    if (db->bytes_out != 0)
+	      {
+		new_ratio /= db->bytes_out;
+	      }
+	    
+	    if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
+	      {
+		bsd_clear (db);
+		return 1;
+	      }
+	    db->ratio = new_ratio;
+	  }
+      }
+    return 0;
+  }
+
+/*
+ * Return statistics.
+ */
+
+static void bsd_comp_stats (void *state, struct compstat *stats)
+  {
+    struct bsd_db *db = (struct bsd_db *) state;
+    
+    stats->unc_bytes    = db->uncomp_bytes;
+    stats->unc_packets  = db->uncomp_count;
+    stats->comp_bytes   = db->comp_bytes;
+    stats->comp_packets = db->comp_count;
+    stats->inc_bytes    = db->incomp_bytes;
+    stats->inc_packets  = db->incomp_count;
+    stats->in_count     = db->in_count;
+    stats->bytes_out    = db->bytes_out;
+  }
+
+/*
+ * Reset state, as on a CCP ResetReq.
+ */
+
+static void bsd_reset (void *state)
+  {
+    struct bsd_db *db = (struct bsd_db *) state;
+
+    bsd_clear(db);
+
+    db->seqno       = 0;
+    db->clear_count = 0;
+  }
+
+/*
+ * Release the compression structure
+ */
+
+static void bsd_free (void *state)
+  {
+    struct bsd_db *db = (struct bsd_db *) state;
+    
+    if (db)
+      {
+/*
+ * Release the dictionary
+ */
+	if (db->dict)
+	  {
+	    vfree (db->dict);
+	    db->dict = NULL;
+	  }
+/*
+ * Release the string buffer
+ */
+	if (db->lens)
+	  {
+	    vfree (db->lens);
+	    db->lens = NULL;
+	  }
+/*
+ * Finally release the structure itself.
+ */
+	kfree (db);
+	MOD_DEC_USE_COUNT;
+      }
+  }
+
+/*
+ * Allocate space for a (de) compressor.
+ */
+
+static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
+  {
+    int bits;
+    unsigned int hsize, hshift, maxmaxcode;
+    struct bsd_db *db;
+
+    if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
+	|| BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+      {
+	return NULL;
+      }
+
+    bits = BSD_NBITS(options[2]);
+
+    switch (bits)
+      {
+    case 9:			/* needs 82152 for both directions */
+    case 10:			/* needs 84144 */
+    case 11:			/* needs 88240 */
+    case 12:			/* needs 96432 */
+	hsize = 5003;
+	hshift = 4;
+	break;
+    case 13:			/* needs 176784 */
+	hsize = 9001;
+	hshift = 5;
+	break;
+    case 14:			/* needs 353744 */
+	hsize = 18013;
+	hshift = 6;
+	break;
+    case 15:			/* needs 691440 */
+	hsize = 35023;
+	hshift = 7;
+	break;
+    case 16:			/* needs 1366160--far too much, */
+	/* hsize = 69001; */	/* and 69001 is too big for cptr */
+	/* hshift = 8; */	/* in struct bsd_db */
+	/* break; */
+    default:
+	return NULL;
+      }
+/*
+ * Allocate the main control structure for this instance.
+ */
+    maxmaxcode = MAXCODE(bits);
+    db         = (struct bsd_db *) kmalloc (sizeof (struct bsd_db),
+					    GFP_KERNEL);
+    if (!db)
+      {
+	return NULL;
+      }
+
+    memset (db, 0, sizeof(struct bsd_db));
+/*
+ * Allocate space for the dictionary. This may be more than one page in
+ * length.
+ */
+    db->dict = (struct bsd_dict *) vmalloc (hsize *
+					    sizeof (struct bsd_dict));
+    if (!db->dict)
+      {
+	bsd_free (db);
+	return NULL;
+      }
+
+    MOD_INC_USE_COUNT;
+/*
+ * If this is the compression buffer then there is no length data.
+ */
+    if (!decomp)
+      {
+	db->lens = NULL;
+      }
+/*
+ * For decompression, the length information is needed as well.
+ */
+    else
+      {
+        db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
+					       sizeof (db->lens[0]));
+	if (!db->lens)
+	  {
+	    bsd_free (db);
+	    return (NULL);
+	  }
+      }
+/*
+ * Initialize the data information for the compression code
+ */
+    db->totlen     = sizeof (struct bsd_db)   +
+      		    (sizeof (struct bsd_dict) * hsize);
+
+    db->hsize      = hsize;
+    db->hshift     = hshift;
+    db->maxmaxcode = maxmaxcode;
+    db->maxbits    = bits;
+
+    return (void *) db;
+  }
+
+static void *bsd_comp_alloc (unsigned char *options, int opt_len)
+  {
+    return bsd_alloc (options, opt_len, 0);
+  }
+
+static void *bsd_decomp_alloc (unsigned char *options, int opt_len)
+  {
+    return bsd_alloc (options, opt_len, 1);
+  }
+
+/*
+ * Initialize the database.
+ */
+
+static int bsd_init (void *state, unsigned char *options,
+		     int opt_len, int unit, int debug, int decomp)
+  {
+    struct bsd_db *db = state;
+    int indx;
+    
+    if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3)
+	|| (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+	|| (BSD_NBITS(options[2]) != db->maxbits)
+	|| (decomp && db->lens == NULL))
+      {
+	return 0;
+      }
+
+    if (decomp)
+      {
+	indx = LAST;
+	do
+	  {
+	    db->lens[indx] = 1;
+	  }
+	while (indx-- > 0);
+      }
+
+    indx = db->hsize;
+    while (indx-- != 0)
+      {
+	db->dict[indx].codem1 = BADCODEM1;
+	db->dict[indx].cptr   = 0;
+      }
+
+    db->unit = unit;
+    db->mru  = 0;
+#ifndef DEBUG
+    if (debug)
+#endif
+      db->debug = 1;
+    
+    bsd_reset(db);
+    
+    return 1;
+  }
+
+static int bsd_comp_init (void *state, unsigned char *options,
+			  int opt_len, int unit, int opthdr, int debug)
+  {
+    return bsd_init (state, options, opt_len, unit, debug, 0);
+  }
+
+static int bsd_decomp_init (void *state, unsigned char *options,
+			    int opt_len, int unit, int opthdr, int mru,
+			    int debug)
+  {
+    return bsd_init (state, options, opt_len, unit, debug, 1);
+  }
+
+/*
+ * Obtain pointers to the various structures in the compression tables
+ */
+
+#define dict_ptrx(p,idx) &(p->dict[idx])
+#define lens_ptrx(p,idx) &(p->lens[idx])
+
+#ifdef DEBUG
+static unsigned short *lens_ptr(struct bsd_db *db, int idx)
+  {
+    if ((unsigned int) idx > (unsigned int) db->maxmaxcode)
+      {
+	printk ("<9>ppp: lens_ptr(%d) > max\n", idx);
+	idx = 0;
+      }
+    return lens_ptrx (db, idx);
+  }
+
+static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx)
+  {
+    if ((unsigned int) idx >= (unsigned int) db->hsize)
+      {
+	printk ("<9>ppp: dict_ptr(%d) > max\n", idx);
+	idx = 0;
+      }
+    return dict_ptrx (db, idx);
+  }
+
+#else
+#define lens_ptr(db,idx) lens_ptrx(db,idx)
+#define dict_ptr(db,idx) dict_ptrx(db,idx)
+#endif
+
+/*
+ * compress a packet
+ *
+ *	The result of this function is the size of the compressed
+ *	packet. A zero is returned if the packet was not compressed
+ *	for some reason, such as the size being larger than uncompressed.
+ *
+ *	One change from the BSD compress command is that when the
+ *	code size expands, we do not output a bunch of padding.
+ */
+
+static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf,
+			 int isize, int osize)
+  {
+    struct bsd_db *db;
+    int hshift;
+    unsigned int max_ent;
+    unsigned int n_bits;
+    unsigned int bitno;
+    unsigned long accm;
+    int ent;
+    unsigned long fcode;
+    struct bsd_dict *dictp;
+    unsigned char c;
+    int hval;
+    int disp;
+    int ilen;
+    int mxcode;
+    unsigned char *wptr;
+    int olen;
+
+#define PUTBYTE(v)			\
+  {					\
+    ++olen;				\
+    if (wptr)				\
+      {					\
+	*wptr++ = (unsigned char) (v);	\
+	if (olen >= osize)		\
+	  {				\
+	    wptr = NULL;		\
+	  }				\
+      }					\
+  }
+
+#define OUTPUT(ent)			\
+  {					\
+    bitno -= n_bits;			\
+    accm |= ((ent) << bitno);		\
+    do					\
+      {					\
+	PUTBYTE(accm >> 24);		\
+	accm <<= 8;			\
+	bitno += 8;			\
+      }					\
+    while (bitno <= 24);		\
+  }
+
+  /*
+   * If the protocol is not in the range we're interested in,
+   * just return without compressing the packet.  If it is,
+   * the protocol becomes the first byte to compress.
+   */
+
+    ent = PPP_PROTOCOL(rptr);
+    if (ent < 0x21 || ent > 0xf9)
+      {
+	return 0;
+      }
+
+    db      = (struct bsd_db *) state;
+    hshift  = db->hshift;
+    max_ent = db->max_ent;
+    n_bits  = db->n_bits;
+    bitno   = 32;
+    accm    = 0;
+    mxcode  = MAXCODE (n_bits);
+
+    /* Initialize the output pointers */
+    wptr  = obuf;
+    olen  = PPP_HDRLEN + BSD_OVHD;
+
+    if (osize > isize)
+      {
+	osize = isize;
+      }
+
+    /* This is the PPP header information */
+    if (wptr)
+      {
+	*wptr++ = PPP_ADDRESS(rptr);
+	*wptr++ = PPP_CONTROL(rptr);
+	*wptr++ = 0;
+	*wptr++ = PPP_COMP;
+	*wptr++ = db->seqno >> 8;
+	*wptr++ = db->seqno;
+      }
+
+    /* Skip the input header */
+    rptr  += PPP_HDRLEN;
+    isize -= PPP_HDRLEN;
+    ilen   = ++isize; /* This is off by one, but that is what is in draft! */
+
+    while (--ilen > 0)
+      {
+	c     = *rptr++;
+	fcode = BSD_KEY  (ent, c);
+	hval  = BSD_HASH (ent, c, hshift);
+	dictp = dict_ptr (db, hval);
+	
+	/* Validate and then check the entry. */
+	if (dictp->codem1 >= max_ent)
+	  {
+	    goto nomatch;
+	  }
+
+	if (dictp->f.fcode == fcode)
+	  {
+	    ent = dictp->codem1 + 1;
+	    continue;	/* found (prefix,suffix) */
+	  }
+	
+	/* continue probing until a match or invalid entry */
+	disp = (hval == 0) ? 1 : hval;
+
+	do
+	  {
+	    hval += disp;
+	    if (hval >= db->hsize)
+	      {
+		hval -= db->hsize;
+	      }
+	    dictp = dict_ptr (db, hval);
+	    if (dictp->codem1 >= max_ent)
+	      {
+		goto nomatch;
+	      }
+	  }
+	while (dictp->f.fcode != fcode);
+
+	ent = dictp->codem1 + 1;	/* finally found (prefix,suffix) */
+	continue;
+	
+nomatch:
+	OUTPUT(ent);		/* output the prefix */
+	
+	/* code -> hashtable */
+	if (max_ent < db->maxmaxcode)
+	  {
+	    struct bsd_dict *dictp2;
+	    struct bsd_dict *dictp3;
+	    int    indx;
+
+	    /* expand code size if needed */
+	    if (max_ent >= mxcode)
+	      {
+		db->n_bits = ++n_bits;
+		mxcode     = MAXCODE (n_bits);
+	      }
+	    
+	    /* Invalidate old hash table entry using
+	     * this code, and then take it over.
+	     */
+
+	    dictp2 = dict_ptr (db, max_ent + 1);
+	    indx   = dictp2->cptr;
+	    dictp3 = dict_ptr (db, indx);
+
+	    if (dictp3->codem1 == max_ent)
+	      {
+		dictp3->codem1 = BADCODEM1;
+	      }
+
+	    dictp2->cptr   = hval;
+	    dictp->codem1  = max_ent;
+	    dictp->f.fcode = fcode;
+	    db->max_ent    = ++max_ent;
+
+	    if (db->lens)
+	      {
+		unsigned short *len1 = lens_ptr (db, max_ent);
+		unsigned short *len2 = lens_ptr (db, ent);
+		*len1 = *len2 + 1;
+	      }
+	  }
+	ent = c;
+      }
+    
+    OUTPUT(ent);		/* output the last code */
+
+    db->bytes_out    += olen;	/* Do not count bytes from here */
+    db->uncomp_bytes += isize;
+    db->in_count     += isize;
+    ++db->uncomp_count;
+    ++db->seqno;
+
+    if (bitno < 32)
+      {
+	++db->bytes_out; /* must be set before calling bsd_check */
+      }
+
+    /*
+     * Generate the clear command if needed
+     */
+
+    if (bsd_check(db))
+      {
+	OUTPUT (CLEAR);
+      }
+    
+    /*
+     * Pad dribble bits of last code with ones.
+     * Do not emit a completely useless byte of ones.
+     */
+
+    if (bitno != 32)
+      {
+	PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
+      }
+    
+    /*
+     * Increase code size if we would have without the packet
+     * boundary because the decompressor will do so.
+     */
+
+    if (max_ent >= mxcode && max_ent < db->maxmaxcode)
+      {
+	db->n_bits++;
+      }
+
+    /* If output length is too large then this is an incomplete frame. */
+    if (wptr == NULL)
+      {
+	++db->incomp_count;
+	db->incomp_bytes += isize;
+	olen              = 0;
+      }
+    else /* Count the number of compressed frames */
+      {
+	++db->comp_count;
+	db->comp_bytes += olen;
+      }
+
+    /* Return the resulting output length */
+    return olen;
+#undef OUTPUT
+#undef PUTBYTE
+  }
+
+/*
+ * Update the "BSD Compress" dictionary on the receiver for
+ * incompressible data by pretending to compress the incoming data.
+ */
+
+static void bsd_incomp (void *state, unsigned char *ibuf, int icnt)
+  {
+    (void) bsd_compress (state, ibuf, (char *) 0, icnt, 0);
+  }
+
+/*
+ * Decompress "BSD Compress".
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression.  For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+
+static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
+			   unsigned char *obuf, int osize)
+  {
+    struct bsd_db *db;
+    unsigned int max_ent;
+    unsigned long accm;
+    unsigned int bitno;		/* 1st valid bit in accm */
+    unsigned int n_bits;
+    unsigned int tgtbitno;	/* bitno when we have a code */
+    struct bsd_dict *dictp;
+    int explen;
+    int seq;
+    unsigned int incode;
+    unsigned int oldcode;
+    unsigned int finchar;
+    unsigned char *p;
+    unsigned char *wptr;
+    int adrs;
+    int ctrl;
+    int ilen;
+    int codelen;
+    int extra;
+
+    db       = (struct bsd_db *) state;
+    max_ent  = db->max_ent;
+    accm     = 0;
+    bitno    = 32;		/* 1st valid bit in accm */
+    n_bits   = db->n_bits;
+    tgtbitno = 32 - n_bits;	/* bitno when we have a code */
+    
+    /*
+     * Save the address/control from the PPP header
+     * and then get the sequence number.
+     */
+
+    adrs  = PPP_ADDRESS (ibuf);
+    ctrl  = PPP_CONTROL (ibuf);
+
+    seq   = (ibuf[4] << 8) + ibuf[5];
+
+    ibuf += (PPP_HDRLEN + 2);
+    ilen  = isize - (PPP_HDRLEN + 2);
+    
+    /*
+     * Check the sequence number and give up if it differs from
+     * the value we're expecting.
+     */
+
+    if (seq != db->seqno)
+      {
+	if (db->debug)
+	  {
+	    printk("bsd_decomp%d: bad sequence # %d, expected %d\n",
+		   db->unit, seq, db->seqno - 1);
+	  }
+	return DECOMP_ERROR;
+      }
+
+    ++db->seqno;
+    db->bytes_out += ilen;
+
+    /*
+     * Fill in the ppp header, but not the last byte of the protocol
+     * (that comes from the decompressed data).
+     */
+
+    wptr    = obuf;
+    *wptr++ = adrs;
+    *wptr++ = ctrl;
+    *wptr++ = 0;
+    
+    oldcode = CLEAR;
+    explen  = 3;
+
+    /*
+     * Keep the checkpoint correctly so that incompressible packets
+     * clear the dictionary at the proper times.
+     */
+
+    for (;;)
+      {
+	if (ilen-- <= 0)
+	  {
+	    db->in_count += (explen - 3); /* don't count the header */
+	    break;
+	  }
+
+	/*
+	 * Accumulate bytes until we have a complete code.
+	 * Then get the next code, relying on the 32-bit,
+	 * unsigned accm to mask the result.
+	 */
+
+	bitno -= 8;
+	accm  |= *ibuf++ << bitno;
+	if (tgtbitno < bitno)
+	  {
+	    continue;
+	  }
+
+	incode = accm >> tgtbitno;
+	accm <<= n_bits;
+	bitno += n_bits;
+
+	/*
+	 * The dictionary must only be cleared at the end of a packet.
+	 */
+	
+	if (incode == CLEAR)
+	  {
+	    if (ilen > 0)
+	      {
+		if (db->debug)
+		  {
+		    printk("bsd_decomp%d: bad CLEAR\n", db->unit);
+		  }
+		return DECOMP_FATALERROR;	/* probably a bug */
+	      }
+	    
+	    bsd_clear(db);
+	    break;
+	  }
+
+	if ((incode > max_ent + 2) || (incode > db->maxmaxcode)
+	    || (incode > max_ent && oldcode == CLEAR))
+	  {
+	    if (db->debug)
+	      {
+		printk("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+		       db->unit, incode, oldcode);
+		printk("max_ent=0x%x explen=%d seqno=%d\n",
+		       max_ent, explen, db->seqno);
+	      }
+	    return DECOMP_FATALERROR;	/* probably a bug */
+	  }
+	
+	/* Special case for KwKwK string. */
+	if (incode > max_ent)
+	  {
+	    finchar = oldcode;
+	    extra   = 1;
+	  }
+	else
+	  {
+	    finchar = incode;
+	    extra   = 0;
+	  }
+	
+	codelen = *(lens_ptr (db, finchar));
+	explen += codelen + extra;
+	if (explen > osize)
+	  {
+	    if (db->debug)
+	      {
+		printk("bsd_decomp%d: ran out of mru\n", db->unit);
+#ifdef DEBUG
+		printk("  len=%d, finchar=0x%x, codelen=%d, explen=%d\n",
+		       ilen, finchar, codelen, explen);
+#endif
+	      }
+	    return DECOMP_FATALERROR;
+	  }
+	
+	/*
+	 * Decode this code and install it in the decompressed buffer.
+	 */
+
+	wptr += codelen;
+	p     = wptr;
+	while (finchar > LAST)
+	  {
+	    struct bsd_dict *dictp2 = dict_ptr (db, finchar);
+	    
+	    dictp = dict_ptr (db, dictp2->cptr);
+#ifdef DEBUG
+	    if (--codelen <= 0 || dictp->codem1 != finchar-1)
+	      {
+		if (codelen <= 0)
+		  {
+		    printk("bsd_decomp%d: fell off end of chain ", db->unit);
+		    printk("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+			   incode, finchar, dictp2->cptr, max_ent);
+		  }
+		else
+		  {
+		    if (dictp->codem1 != finchar-1)
+		      {
+			printk("bsd_decomp%d: bad code chain 0x%x "
+			       "finchar=0x%x ",
+			       db->unit, incode, finchar);
+
+			printk("oldcode=0x%x cptr=0x%x codem1=0x%x\n",
+			       oldcode, dictp2->cptr, dictp->codem1);
+		      }
+		  }
+		return DECOMP_FATALERROR;
+	      }
+#endif
+	    *--p    = dictp->f.hs.suffix;
+	    finchar = dictp->f.hs.prefix;
+	  }
+	*--p = finchar;
+	
+#ifdef DEBUG
+	if (--codelen != 0)
+	  {
+	    printk("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+		   db->unit, codelen, incode, max_ent);
+	  }
+#endif
+	
+	if (extra)		/* the KwKwK case again */
+	  {
+	    *wptr++ = finchar;
+	  }
+	
+	/*
+	 * If not first code in a packet, and
+	 * if not out of code space, then allocate a new code.
+	 *
+	 * Keep the hash table correct so it can be used
+	 * with uncompressed packets.
+	 */
+
+	if (oldcode != CLEAR && max_ent < db->maxmaxcode)
+	  {
+	    struct bsd_dict *dictp2, *dictp3;
+	    unsigned short  *lens1,  *lens2;
+	    unsigned long fcode;
+	    int hval, disp, indx;
+	    
+	    fcode = BSD_KEY(oldcode,finchar);
+	    hval  = BSD_HASH(oldcode,finchar,db->hshift);
+	    dictp = dict_ptr (db, hval);
+	    
+	    /* look for a free hash table entry */
+	    if (dictp->codem1 < max_ent)
+	      {
+		disp = (hval == 0) ? 1 : hval;
+		do
+		  {
+		    hval += disp;
+		    if (hval >= db->hsize)
+		      {
+			hval -= db->hsize;
+		      }
+		    dictp = dict_ptr (db, hval);
+		  }
+		while (dictp->codem1 < max_ent);
+	      }
+	    
+	    /*
+	     * Invalidate previous hash table entry
+	     * assigned this code, and then take it over
+	     */
+
+	    dictp2 = dict_ptr (db, max_ent + 1);
+	    indx   = dictp2->cptr;
+	    dictp3 = dict_ptr (db, indx);
+
+	    if (dictp3->codem1 == max_ent)
+	      {
+		dictp3->codem1 = BADCODEM1;
+	      }
+
+	    dictp2->cptr   = hval;
+	    dictp->codem1  = max_ent;
+	    dictp->f.fcode = fcode;
+	    db->max_ent    = ++max_ent;
+
+	    /* Update the length of this string. */
+	    lens1  = lens_ptr (db, max_ent);
+	    lens2  = lens_ptr (db, oldcode);
+	    *lens1 = *lens2 + 1;
+	    
+	    /* Expand code size if needed. */
+	    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+	      {
+		db->n_bits = ++n_bits;
+		tgtbitno   = 32-n_bits;
+	      }
+	  }
+	oldcode = incode;
+      }
+
+    ++db->comp_count;
+    ++db->uncomp_count;
+    db->comp_bytes   += isize - BSD_OVHD - PPP_HDRLEN;
+    db->uncomp_bytes += explen;
+
+    if (bsd_check(db))
+      {
+	if (db->debug)
+	  {
+	    printk("bsd_decomp%d: peer should have cleared dictionary on %d\n",
+		   db->unit, db->seqno - 1);
+	  }
+      }
+    return explen;
+  }
+     
+/*************************************************************
+ * Table of addresses for the BSD compression module
+ *************************************************************/
+
+static struct compressor ppp_bsd_compress = {
+    CI_BSD_COMPRESS,		/* compress_proto */
+    bsd_comp_alloc,		/* comp_alloc */
+    bsd_free,			/* comp_free */
+    bsd_comp_init,		/* comp_init */
+    bsd_reset,			/* comp_reset */
+    bsd_compress,		/* compress */
+    bsd_comp_stats,		/* comp_stat */
+    bsd_decomp_alloc,		/* decomp_alloc */
+    bsd_free,			/* decomp_free */
+    bsd_decomp_init,		/* decomp_init */
+    bsd_reset,			/* decomp_reset */
+    bsd_decompress,		/* decompress */
+    bsd_incomp,			/* incomp */
+    bsd_comp_stats		/* decomp_stat */
+};
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+char kernel_version[] = UTS_RELEASE;
+
+int
+init_module(void)
+{
+	int answer = ppp_register_compressor (&ppp_bsd_compress);
+	if (answer == 0)
+		printk (KERN_INFO "PPP BSD Compression module registered\n");
+	return answer;
+}
+
+void
+cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("ppp_bsd_comp: device busy, remove delayed\n");
+	else
+		ppp_unregister_compressor (&ppp_bsd_compress);
+}
diff -u --recursive --new-file v1.3.32/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v1.3.32/linux/drivers/net/de600.c	Sun Sep  3 12:26:54 1995
+++ linux/drivers/net/de600.c	Tue Oct 10 15:45:26 1995
@@ -715,6 +715,8 @@
 
 	ether_setup(dev);
 	
+	dev->flags&=~IFF_MULTICAST;
+	
 	select_prn();
 	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v1.3.32/linux/drivers/net/de620.c	Wed Aug  9 14:55:40 1995
+++ linux/drivers/net/de620.c	Tue Oct 10 15:45:27 1995
@@ -468,7 +468,15 @@
 static void
 de620_set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
-	if (num_addrs) { /* Enable promiscuous mode */
+	if (num_addrs) 
+	{ /* Enable promiscuous mode */
+		/*
+		 *	We must make the kernel realise we had to move
+		 *	into promisc mode or we start all out war on
+		 *	the cable. - AC
+		 */
+		dev->flags|=IFF_PROMISC;		
+	
 		de620_set_register(dev, W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
 	}
 	else { /* Disable promiscuous mode, use normal mode */
diff -u --recursive --new-file v1.3.32/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v1.3.32/linux/drivers/net/eepro.c	Sat Sep  9 15:26:52 1995
+++ linux/drivers/net/eepro.c	Tue Oct 10 15:45:27 1995
@@ -792,7 +792,15 @@
 	short ioaddr = dev->base_addr;
 	unsigned short mode;
 
-	if (num_addrs < -1 || num_addrs > 63) {
+	if (num_addrs <= -1 || num_addrs > 63) {
+		/*
+		 *	We must make the kernel realise we had to move
+		 *	into promisc mode or we start all out war on
+		 *	the cable. If it was a promisc rewquest the
+		 *	flag is already set. If not we assert it.
+		 */
+		dev->flags|=IFF_PROMISC;		
+
 		outb(BANK2_SELECT, ioaddr); /* be CAREFULL, BANK 2 now */
 		mode = inb(ioaddr + REG2);
 		outb(mode | PRMSC_Mode, ioaddr + REG2);	
diff -u --recursive --new-file v1.3.32/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v1.3.32/linux/drivers/net/eexpress.c	Fri Oct  6 14:35:15 1995
+++ linux/drivers/net/eexpress.c	Tue Oct 10 15:45:27 1995
@@ -414,6 +414,8 @@
 	
 	ether_setup(dev);
 	
+	dev->flags&=~IFF_MULTICAST;
+		
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.32/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v1.3.32/linux/drivers/net/ewrk3.c	Fri Oct  6 14:35:15 1995
+++ linux/drivers/net/ewrk3.c	Mon Oct  9 09:24:26 1995
@@ -1885,7 +1885,7 @@
   } else {
     release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE);
     unregister_netdev(&thisEthwrk);
-    free(thisEthwrk.priv);
+    kfree(thisEthwrk.priv);
     thisEthwrk.priv = NULL;
   }
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v1.3.32/linux/drivers/net/hp-plus.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/hp-plus.c	Tue Oct 10 14:03:45 1995
@@ -160,7 +160,7 @@
 		return ENODEV;
 
     if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct ei_device), 0);
+		dev = init_etherdev(0, sizeof(struct ei_device));
 
 	printk("%s: %s at %#3x,", dev->name, name, ioaddr);
 
diff -u --recursive --new-file v1.3.32/linux/drivers/net/hp.c linux/drivers/net/hp.c
--- v1.3.32/linux/drivers/net/hp.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/hp.c	Tue Oct 10 14:03:45 1995
@@ -129,7 +129,7 @@
 	}
 
 	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct ei_device), 0);
+		dev = init_etherdev(0, sizeof(struct ei_device));
 
 	printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
 
diff -u --recursive --new-file v1.3.32/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v1.3.32/linux/drivers/net/hp100.c	Tue Aug 15 20:39:03 1995
+++ linux/drivers/net/hp100.c	Tue Oct 10 15:45:27 1995
@@ -876,13 +876,13 @@
   hp100_page( MAC_CTRL );
   hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );	/* stop rx/tx */
 
-  if ( num_addrs < 0 )
+  if ( num_addrs == -1 )
     {
       lp -> mac2_mode = HP100_MAC2MODE6;  /* promiscuous mode, all good */
       lp -> mac1_mode = HP100_MAC1MODE6;  /* packets on the net */
     }
    else
-  if ( num_addrs > 0 )
+  if ( num_addrs != 0 )
     {
       lp -> mac2_mode = HP100_MAC2MODE5;  /* multicast mode, packets for me */
       lp -> mac1_mode = HP100_MAC1MODE5;  /* broadcasts and all multicasts */
diff -u --recursive --new-file v1.3.32/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.3.32/linux/drivers/net/lance.c	Sun Sep  3 16:12:49 1995
+++ linux/drivers/net/lance.c	Tue Oct 10 15:45:27 1995
@@ -37,7 +37,7 @@
 #include <linux/skbuff.h>
 
 static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
-unsigned long lance_probe1(int ioaddr, unsigned long mem_start);
+void lance_probe1(int ioaddr);
 
 #ifdef HAVE_DEVLIST
 struct netdev_entry lance_drv =
@@ -187,8 +187,7 @@
 
 struct lance_private {
 	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
-	   This is accomplished by allocating 7 extra bytes for the struct
-	   and adjusting the start of the struct to be 8-byte aligned.  */
+	   This is always true for kmalloc'ed memory */
 	struct lance_rx_head rx_ring[RX_RING_SIZE];
 	struct lance_tx_head tx_ring[TX_RING_SIZE];
 	struct lance_init_block		init_block;
@@ -270,11 +269,11 @@
    before the memory management system is started, and thus well before the
    other probes. */
 
-unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
+int lance_init(void)
 {
 	int *port;
 
-	if (mem_end <= 16*1024*1024)
+	if (high_memory <= 16*1024*1024)
 		lance_need_isa_bounce_buffers = 0;
 
 #if defined(CONFIG_PCI)
@@ -308,9 +307,9 @@
 				pcibios_write_config_word(pci_bus, pci_device_fn,
 										  PCI_COMMAND, pci_command);
 			}
-			printk("Found PCnet/PCI at %#x, irq %d (mem_start is %#lx).\n",
-				   pci_ioaddr, pci_irq_line, mem_start);
-			mem_start = lance_probe1(pci_ioaddr, mem_start);
+			printk("Found PCnet/PCI at %#x, irq %d.\n",
+				   pci_ioaddr, pci_irq_line);
+			lance_probe1(pci_ioaddr);
 			pci_irq_line = 0;
 		}
 	}
@@ -326,14 +325,14 @@
 			
 			if ((offset14 == 0x52 || offset14 == 0x57) &&
 				((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
-				mem_start = lance_probe1(ioaddr, mem_start);
+				lance_probe1(ioaddr);
 		}
 	}
 
-	return mem_start;
+	return 0;
 }
 
-unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
+void lance_probe1(int ioaddr)
 {
 	struct device *dev;
 	struct lance_private *lp;
@@ -372,7 +371,7 @@
 
 	outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
 	if (inw(ioaddr+LANCE_DATA) != 0x0004)
-		return mem_start;
+		return;
 
 	/* Get the version of the chip. */
 	outw(88, ioaddr+LANCE_ADDR);
@@ -385,7 +384,7 @@
 		if (lance_debug > 2)
 			printk("  LANCE chip version is %#x.\n", chip_version);
 		if ((chip_version & 0xfff) != 0x003)
-			return mem_start;
+			return;
 		chip_version = (chip_version >> 12) & 0xffff;
 		for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
 			if (chip_table[lance_version].id_number == chip_version)
@@ -393,14 +392,7 @@
 		}
 	}
 
-	dev = init_etherdev(0, 7
-						+ ((sizeof(struct lance_private) + 7) & ~7)
-						+ PKT_BUF_SZ*RX_RING_SIZE
-						+ (lance_need_isa_bounce_buffers
-						   ? PKT_BUF_SZ*TX_RING_SIZE
-						   : 0),
-						&mem_start);
-
+	dev = init_etherdev(0, 0);
 	chipname = chip_table[lance_version].name;
 	printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
 
@@ -412,13 +404,14 @@
 	dev->base_addr = ioaddr;
 	request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
-	/* Make certain the data structures used by the LANCE are aligned. */
-	dev->priv = (void *)(((int)dev->priv + 7) & ~7);
-	lp = (struct lance_private *)dev->priv;
+	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
+	lp = (struct lance_private *) kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+	dev->priv = lp;
 	lp->name = chipname;
-	lp->rx_buffs = (long)lp + ((sizeof(struct lance_private) + 7) & ~7);
-	lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ])
-						   (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE);
+	lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+	lp->tx_bounce_buffs = NULL;
+	if (lance_need_isa_bounce_buffers)
+		lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE, GFP_DMA | GFP_KERNEL);
 
 	lp->chip_version = lance_version;
 
@@ -490,7 +483,7 @@
 			printk(", probed IRQ %d", dev->irq);
 		else {
 			printk(", failed to detect IRQ line.\n");
-			return mem_start;
+			return;
 		}
 
 		/* Check for the initialization done bit, 0x0100, which means
@@ -504,7 +497,7 @@
 	} else if (dev->dma) {
 		if (request_dma(dev->dma, chipname)) {
 			printk("DMA %d allocation failed.\n", dev->dma);
-			return mem_start;
+			return;
 		} else
 			printk(", assigned DMA %d.\n", dev->dma);
 	} else {			/* OK, we have to auto-DMA. */
@@ -539,7 +532,7 @@
 		}
 		if (i == 4) {			/* Failure: bail. */
 			printk("DMA detection failed.\n");
-			return mem_start;
+			return;
 		}
 	}
 
@@ -560,7 +553,7 @@
 	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 
-	return mem_start;
+	return;
 }
 
 
@@ -1082,6 +1075,7 @@
 }
 
 /* Set or clear the multicast filter for this adaptor.
+   num_addrs == -2		All multicasts
    num_addrs == -1		Promiscuous mode, receive all packets
    num_addrs == 0		Normal mode, clear multicast list
    num_addrs > 0		Multicast mode, receive normal and MC packets, and do
@@ -1095,7 +1089,7 @@
 	outw(0, ioaddr+LANCE_ADDR);
 	outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.	 */
 
-	if (num_addrs >= 0) {
+	if (num_addrs >= 0 || num_addrs==-2) {
 		short multicast_table[4];
 		int i;
 		/* We don't use the multicast table, but rely on upper-layer filtering. */
diff -u --recursive --new-file v1.3.32/linux/drivers/net/loopback.c linux/drivers/net/loopback.c
--- v1.3.32/linux/drivers/net/loopback.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/loopback.c	Tue Oct 10 15:45:27 1995
@@ -125,8 +125,11 @@
 int loopback_init(struct device *dev)
 {
 	int i;
-
-	dev->mtu		= 2000;			/* MTU			*/
+#ifdef CONFIG_SKB_LARGE
+	dev->mtu		= 7900;			/* MTU			*/
+#else
+	dev->mtu		= 3800;
+#endif	
 	dev->tbusy		= 0;
 	dev->hard_start_xmit	= loopback_xmit;
 	dev->open		= NULL;
@@ -140,7 +143,7 @@
 	dev->family		= AF_INET;
 #ifdef CONFIG_INET    
 	dev->pa_addr		= in_aton("127.0.0.1");
-	dev->pa_brdaddr	= in_aton("127.255.255.255");
+	dev->pa_brdaddr		= in_aton("127.255.255.255");
 	dev->pa_mask		= in_aton("255.0.0.0");
 	dev->pa_alen		= 4;
 #endif  
diff -u --recursive --new-file v1.3.32/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v1.3.32/linux/drivers/net/ne.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/ne.c	Tue Oct 10 14:03:45 1995
@@ -284,7 +284,7 @@
 
 
     if (dev == NULL)
-	dev = init_etherdev(0, sizeof(struct ei_device), 0);
+	dev = init_etherdev(0, sizeof(struct ei_device));
 
     if (dev->irq < 2) {
 	autoirq_setup(0);
diff -u --recursive --new-file v1.3.32/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v1.3.32/linux/drivers/net/net_init.c	Thu Sep  7 17:17:17 1995
+++ linux/drivers/net/net_init.c	Tue Oct 10 14:01:01 1995
@@ -54,34 +54,6 @@
 #define MAX_ETH_CARDS 16 /* same as the number if irq's in irq2dev[] */
 static struct device *ethdev_index[MAX_ETH_CARDS];
 
-unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
-unsigned long pi_init(unsigned long mem_start, unsigned long mem_end);
-unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end);
-unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end);
-
-/*
-  net_dev_init() is our network device initialization routine.
-  It's called from init/main.c with the start and end of free memory,
-  and returns the new start of free memory.
-  */
-
-unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end)
-{
-
-	/* Network device initialization for devices that must allocate
-	   low-memory or contiguous DMA buffers.
-	   */
-#if defined(CONFIG_LANCE)
-	mem_start = lance_init(mem_start, mem_end);
-#endif
-#if defined(CONFIG_PI)
-	mem_start = pi_init(mem_start, mem_end);
-#endif	
-#if defined(CONFIG_DEC_ELCP)
-	mem_start = dec21040_init(mem_start, mem_end);
-#endif	
-	return mem_start;
-}
 
 /* Fill in the fields of the device structure with ethernet-generic values.
 
@@ -94,7 +66,7 @@
  */
 
 struct device *
-init_etherdev(struct device *dev, int sizeof_priv, unsigned long *mem_startp)
+init_etherdev(struct device *dev, int sizeof_priv)
 {
 	int new_device = 0;
 	int i;
@@ -114,11 +86,7 @@
 						dev = cur_dev;
 						dev->init = NULL;
 						sizeof_priv = (sizeof_priv + 3) & ~3;
-						if (mem_startp && *mem_startp ) {
-							dev->priv = (void*) *mem_startp;
-							*mem_startp += sizeof_priv;
-						} else
-							dev->priv = sizeof_priv
+						dev->priv = sizeof_priv
 							  ? kmalloc(sizeof_priv, GFP_KERNEL)
 							  :	NULL;
 						if (dev->priv) memset(dev->priv, 0, sizeof_priv);
@@ -128,11 +96,7 @@
 
 		alloc_size &= ~3;		/* Round to dword boundary. */
 
-		if (mem_startp && *mem_startp ) {
-			dev = (struct device *)*mem_startp;
-			*mem_startp += alloc_size;
-		} else
-			dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
+		dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
 		memset(dev, 0, alloc_size);
 		if (sizeof_priv)
 			dev->priv = (void *) (dev + 1);
diff -u --recursive --new-file v1.3.32/linux/drivers/net/ni65.c linux/drivers/net/ni65.c
--- v1.3.32/linux/drivers/net/ni65.c	Sat Sep  9 15:26:52 1995
+++ linux/drivers/net/ni65.c	Tue Oct 10 15:45:27 1995
@@ -256,6 +256,7 @@
 
   ether_setup(dev);
 
+  dev->flags 	     &= ~IFF_MULTICAST;
   dev->interrupt      = 0;
   dev->tbusy          = 0;
   dev->start          = 0;
diff -u --recursive --new-file v1.3.32/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v1.3.32/linux/drivers/net/pi2.c	Tue Aug 15 20:39:03 1995
+++ linux/drivers/net/pi2.c	Tue Oct 10 14:18:20 1995
@@ -79,9 +79,6 @@
 #define DEF_B_SQUELDELAY 3	/* 30 mS */
 #define DEF_B_CLOCKMODE 0	/* Normal clock mode */
 
-struct device *init_etherdev(struct device *dev, int sizeof_private,
-			     unsigned long *mem_startp);
-
 static const char *version =
 "PI: V0.8 ALPHA April 23 1995 David Perry (dp@hydra.carleton.ca)\n";
 
@@ -1207,7 +1204,7 @@
 }
 
 
-unsigned long pi_init(unsigned long mem_start, unsigned long mem_end)
+int pi_init(void)
 {
     int *port;
     int ioaddr = 0;
@@ -1236,7 +1233,7 @@
 	break;
     default:
 	printk("PI: ERROR: No card found\n");
-	return mem_start;
+	return -EIO;
     }
 
     /* Link a couple of device structures into the chain */
@@ -1247,9 +1244,7 @@
     */
     register_netdev(&pi0a);
     
-    pi0a.priv=(void *)mem_start;
-    mem_start+=sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4
-			 + 8;	/* for alignment */
+    pi0a.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA);
 			
     pi0a.dma = PI_DMA;
     pi0a.base_addr = ioaddr + 2;
@@ -1259,9 +1254,7 @@
     register_netdev(&pi0b);
     pi0b.base_addr = ioaddr;
     pi0b.irq = 0;
-    pi0b.priv=(void *)mem_start;
-    mem_start+=sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4
-			 + 8;	/* for alignment */
+    pi0b.priv = kmalloc(sizeof(struct pi_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA);
 
     /* Now initialize them */
     pi_probe(&pi0a, card_type);
@@ -1269,7 +1262,7 @@
 
     pi0b.irq = pi0a.irq;	/* IRQ is shared */
     
-    return mem_start;
+    return 0;
 }
 
 static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize)
diff -u --recursive --new-file v1.3.32/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.3.32/linux/drivers/net/ppp.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/ppp.c	Tue Oct 10 15:11:32 1995
@@ -1,5 +1,21 @@
-/* PPP for Linux
-*/
+/*  PPP for Linux
+ *
+ *  Michael Callahan <callahan@maths.ox.ac.uk>
+ *  Al Longyear <longyear@netcom.com>
+ *
+ *  Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
+ *  ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *
+ *  ==FILEVERSION 4==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp.c is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp.c
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
 
 /*
    Sources:
@@ -15,29 +31,51 @@
 
    Flags for this module (any combination is acceptable for testing.):
 
-   NET02D	      -	Define if using Net-2-Debugged in kernels earlier
-   			than v1.1.4.
-
-   NEW_TTY_DRIVERS    -	Define if using new Ted Ts'o's alpha TTY drivers
-   			from tsx-11.mit.edu. From Ted Ts'o.
-
-   OPTIMIZE_FLAG_TIME -	Number of jiffies to force sending of leading flag
+   OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
 			character. This is normally set to ((HZ * 3) / 2).
-			This is 1.5 seconds. If not defined then the leading
-			flag is always sent.  
+			This is 1.5 seconds. If zero then the leading
+			flag is always sent.
+
+   CHECK_CHARACTERS   - Enable the checking on all received characters for
+			8 data bits, no parity. This adds a small amount of
+			processing for each received character.
+			
+   NEW_SKBUFF	      - Use NET3.020 sk_buff's
 */
 
-/* #define NET02D				-* */
-#define NEW_TTY_DRIVERS				/* */
-#define OPTIMIZE_FLAG_TIME  ((HZ * 3)/2)	/* */
-#define CHECK_CHARACTERS
+/* #define NEW_SKBUFF		1 */
+#define OPTIMIZE_FLAG_TIME	((HZ * 3)/2)
+
+#define CHECK_CHARACTERS	1
+#define PPP_COMPRESS		1
+#define USE_SKB_PROTOCOL 1  /* Set by the installation program! */
+
+#ifdef  NEW_SKBUFF
+#undef  USE_SKB_PROTOCOL
+#define USE_SKB_PROTOCOL 2
+#endif
+
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV	256
+#endif
+
+/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
+ * Added dynamic allocation of channels to eliminate
+ *   compiled-in limits on the number of channels.
+ *
+ * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
+ *   released under the GNU General Public License Version 2.
+ */
 
-#include <linux/config.h>
-#ifdef MODULE
 #include <linux/module.h>
+#ifdef MODULE
 #include <linux/version.h>
-#endif
+#define STATIC
+#else
+#define STATIC static
+#endif /* def MODULE */
 
+#include <endian.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -49,2111 +87,3529 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>   /* to get the struct task_struct */
-#include <linux/string.h>  /* used in new tty drivers */
-#include <linux/signal.h>  /* used in new tty drivers */
+#include <linux/sched.h>	/* to get the struct task_struct */
+#include <linux/string.h>	/* used in new tty drivers */
+#include <linux/signal.h>	/* used in new tty drivers */
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/segment.h>
-
-#ifdef NET02D				/* v1.1.4 net code and earlier */
-#include <dev.h>
-#include <skbuff.h>
-#include <inet.h>
-#define	skb_queue_head_init(buf)	*(buf) = NULL
-#else					/* v1.1.5 and later */
+#include <net/if.h>
+#include <linux/if_ether.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/inet.h>
+#include <linux/ioctl.h>
+
+#ifdef NEW_SKBUFF
+#include <linux/netprotocol.h>
+#else
+typedef struct sk_buff	     sk_buff;
+#define skb_data(skb)	     ((unsigned char *) (skb)->data)
 #endif
 
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <linux/if_arp.h>
+#include "slhc.h"
+#include <linux/ppp_defs.h>
+#include <linux/socket.h>
 #include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
 
-#include <linux/ip.h>
-#include <linux/tcp.h>
+#undef   PACKETPTR
+#define  PACKETPTR 1
+#include <linux/ppp-comp.h>
+#undef   PACKETPTR
 
-#include "slhc.h"
+#define bsd_decompress	(*ppp->sc_rcomp->decompress)
+#define bsd_compress	(*ppp->sc_xcomp->compress)
 
-#include <linux/if_arp.h>
-#ifndef ARPHRD_PPP
-#define ARPHRD_PPP 0
+#ifndef PPP_IPX
+#define PPP_IPX 0x2b  /* IPX protocol over PPP */
 #endif
 
-#define PRINTK(p) printk p ;
-#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p))
-#define PRINTKN(n,p) {if (ppp_debug >= n) PRINTK (p)}
-#define CHECK_PPP(a)  if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return a;}
-#define CHECK_PPP_VOID()  if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return;}
-
-#define in_xmap(ppp,c)	(ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
-#define in_rmap(ppp,c)	((((unsigned int) (unsigned char) (c)) < 0x20) && \
-			ppp->recv_async_map & (1 << (c)))
-
-#define bset(p,b)	((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
-int ppp_debug = 2;
-int ppp_debug_netpackets = 0;
-
-/* Define this string only once for all macro invocations */
-static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
-
-int ppp_init(struct device *);
-static void ppp_init_ctrl_blk(struct ppp *);
-static int ppp_dev_open(struct device *);
-static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int ppp_dev_close(struct device *);
-static void ppp_kick_tty(struct ppp *);
-
-#ifdef NEW_TTY_DRIVERS
-#define ppp_find(tty) ((struct ppp *) tty->disc_data)
-#else
-static void ppp_output_done(void *);
-static void ppp_unesc(struct ppp *ppp, unsigned char *c, int n);
-static struct ppp *ppp_find(struct tty_struct *);
-#endif
-
-static void ppp_doframe(struct ppp *);
-static int ppp_do_ip(struct ppp *, unsigned short, unsigned char *, int);
-static int ppp_us_queue(struct ppp *, unsigned short, unsigned char *, int);
-static int ppp_xmit(struct sk_buff *, struct device *);
-
-#ifdef NET02D
-static int ppp_header(unsigned char *buff, struct device *dev,
-		      unsigned short type, unsigned long daddr,
-		      unsigned long saddr, unsigned len);
-static int ppp_rebuild_header(void *buff, struct device *dev);
-static void ppp_add_arp(unsigned long addr, struct sk_buff *skb,
-			struct device *dev);
-#else
-static int ppp_header(struct sk_buff *, struct device *, unsigned short,
-		      void *, void *, unsigned);
-static int ppp_rebuild_header(void *, struct device *, unsigned long,
-			      struct sk_buff *);
-#endif
-
-static struct enet_statistics *ppp_get_stats (struct device *);
-static struct ppp *ppp_alloc(void);
-static int ppp_lock(struct ppp *);
-static void ppp_unlock(struct ppp *);
-static void ppp_add_fcs(struct ppp *);
-static int ppp_check_fcs(struct ppp *);
-static void ppp_print_buffer(const char *,const char *,int,int);
-
-static int ppp_read(struct tty_struct *, struct file *, unsigned char *,
-		    unsigned int);
-static int ppp_write(struct tty_struct *, struct file *, const unsigned char *,
-		     unsigned int);
-static int ppp_ioctl(struct tty_struct *, struct file *, unsigned int,
-		     unsigned long);
-static int ppp_select(struct tty_struct *tty, struct inode * inode,
-		      struct file * filp, int sel_type, select_table * wait);
-static int ppp_open(struct tty_struct *);
-static void ppp_close(struct tty_struct *);
-
-#ifdef NEW_TTY_DRIVERS
-static int ppp_receive_room(struct tty_struct *tty);
-static void ppp_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-			    char *fp, int count);
-static void ppp_write_wakeup(struct tty_struct *tty);
-#else
-static void ppp_tty_input_ready(struct tty_struct *);
+#ifndef PPP_LQR
+#define PPP_LQR 0xc025  /* Link Quality Reporting Protocol */
 #endif
 
-/* FCS table from RFC1331 */
+STATIC int ppp_register_compressor (struct compressor *cp);
+STATIC void ppp_unregister_compressor (struct compressor *cp);
 
-static unsigned short fcstab[256] = {
-  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
-  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
-  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
-  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
-  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
-  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
-  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
-  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
-  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
-  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
-  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
-  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
-  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
-  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
-  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
-  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
-  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
-  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
-  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
-  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
-  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
-  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
-  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
-  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
-  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
-  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
-  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
-  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
-  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
-  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
-  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
-  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
-  };
-
-struct tty_ldisc ppp_ldisc;
-
-static struct ppp ppp_ctrl[PPP_NRUNIT];
-
-/*************************************************************
- * INITIALIZATION
- *************************************************************/
+/*
+ * Local functions
+ */
 
-static int first_time = 1;
+static struct compressor *find_compressor (int type);
+static void ppp_init_ctrl_blk (register struct ppp *);
+static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
+static int ppp_doframe (struct ppp *);
+static struct ppp *ppp_alloc (void);
+static void ppp_print_buffer (const u_char *, const u_char *, int);
+extern inline void ppp_stuff_char (struct ppp *ppp,
+				   register struct ppp_buffer *buf,
+				   register u_char chr);
+extern inline int lock_buffer (register struct ppp_buffer *buf);
+
+static int rcv_proto_ip         (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_ipx        (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_vjc_comp   (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_unknown    (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_lqr        (struct ppp *, u_short, u_char *, int);
+static void ppp_doframe_lower   (struct ppp *, u_char *, int);
+static int ppp_doframe          (struct ppp *);
+
+extern int  ppp_bsd_compressor_init(void);
+static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd);
+static int  rcv_proto_ccp (struct ppp *, u_short, u_char *, int);
 
-/* called at boot time for each ppp device */
+#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
 
-int
-ppp_init(struct device *dev)
-{
-  struct ppp *ppp;
-  int i;
+#ifndef OPTIMIZE_FLAG_TIME
+#define OPTIMIZE_FLAG_TIME	0
+#endif
 
-  ppp = &ppp_ctrl[dev->base_addr];
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
 
-  if (first_time) {
-    first_time = 0;
+/*
+ * Parameters which may be changed via insmod.
+ */
 
-    printk (KERN_INFO "PPP: version %s (%d channels)"
-#ifdef NET02D
-	   " NET02D"
-#endif
-#ifdef NEW_TTY_DRIVERS
-	   " NEW_TTY_DRIVERS"
-#endif
-#ifdef OPTIMIZE_FLAG_TIME
-	   " OPTIMIZE_FLAGS"
-#endif
-	   "\n", PPP_VERSION, PPP_NRUNIT);
+STATIC int  flag_time = OPTIMIZE_FLAG_TIME;
+STATIC int  max_dev   = PPP_MAX_DEV;
 
-    printk (KERN_INFO
-	   "TCP compression code copyright 1989 Regents of the "
-	   "University of California\n");
+/*
+ * The "main" procedure to the ppp device
+ */
 
-    (void) memset(&ppp_ldisc, 0, sizeof(ppp_ldisc));
-    ppp_ldisc.open    = ppp_open;
-    ppp_ldisc.close   = ppp_close;
-    ppp_ldisc.read    = ppp_read;
-    ppp_ldisc.write   = ppp_write;
-    ppp_ldisc.ioctl   = ppp_ioctl;
-    ppp_ldisc.select  = ppp_select;
+int ppp_init (struct device *);
 
-#ifdef NEW_TTY_DRIVERS
-    ppp_ldisc.magic       = TTY_LDISC_MAGIC;
-    ppp_ldisc.receive_room = ppp_receive_room;
-    ppp_ldisc.receive_buf = ppp_receive_buf;
-    ppp_ldisc.write_wakeup = ppp_write_wakeup;
-#else
-    ppp_ldisc.handler     = ppp_tty_input_ready;
-#endif
+/*
+ * Network device driver callback routines
+ */
 
-    if ((i = tty_register_ldisc(N_PPP, &ppp_ldisc)) == 0)
-      printk(KERN_INFO "PPP line discipline registered.\n");
-    else
-      printk(KERN_ERR "error registering line discipline: %d\n", i);
-  }
-
-  /* initialize PPP control block */
-  ppp_init_ctrl_blk (ppp);
-  ppp->inuse = 0;
-  ppp->line  = dev->base_addr;
-  ppp->tty   = NULL;
-  ppp->dev   = dev;
-
-  /* clear statistics */
-  memset (&ppp->stats, '\0', sizeof (struct ppp_stats));
-
-  /* device INFO */
-  dev->mtu             = PPP_MTU;
-  dev->hard_start_xmit = ppp_xmit;
-  dev->open            = ppp_dev_open;
-  dev->stop            = ppp_dev_close;
-  dev->get_stats       = ppp_get_stats;
-  dev->hard_header     = ppp_header;
-  dev->rebuild_header  = ppp_rebuild_header;
-  dev->hard_header_len = 0;
-  dev->addr_len        = 0;
-  dev->type            = ARPHRD_PPP;
-
-#ifdef NET02D
-  dev->add_arp         = ppp_add_arp;
-  dev->queue_xmit      = dev_queue_xmit;
+static int ppp_dev_open (struct device *);
+static int ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd);
+static int ppp_dev_close (struct device *);
+static int ppp_dev_xmit (sk_buff *, struct device *);
+static struct enet_statistics *ppp_dev_stats (struct device *);
+
+#if USE_SKB_PROTOCOL == 0  /* The 1.2.x kernel is here */
+#define dev_alloc_skb(count)        alloc_skb(count, GFP_ATOMIC)
+#define skb_put(skb,count)          skb_data(skb)
+#define get_long_user(addr)	    get_user_long((void *) addr)
+#define get_int_user(addr)	    ((int) get_user_long((void *) addr))
+#define put_byte_user(val,addr)	    put_fs_byte(val,((u_char *) (addr)))
+#define put_long_user(val,addr)	    put_fs_long((val),((void *) (addr)))
+
+static unsigned short ppp_dev_type (sk_buff *, struct device *);
+static int ppp_dev_header (unsigned char *buff, struct device *dev,
+			   unsigned short type, void *daddr, void *saddr,
+			   unsigned len, struct sk_buff *skb);
+
+#else /* The 1.3.x kernel is here */
+#define get_long_user(addr)	    get_user(((long *) addr))
+#define get_int_user(addr)	    ((int) get_user(((int *) addr)))
+#define put_byte_user(val,addr)	    put_user((val),((u_char *) (addr)))
+#define put_long_user(val,addr)	    put_user((val),((long *) (addr)))
+
+static int ppp_dev_header (sk_buff *, struct device *, unsigned short,
+			   void *, void *, unsigned);
+#endif
+
+#ifdef NEW_SKBUFF
+static int ppp_dev_input (struct protocol *self, struct protocol *lower,
+			  sk_buff *skb, void *saddr, void *daddr);
+static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
+			   int subid, void *saddr, void *daddr, void *opt);
+static int ppp_dev_getkey(int protocol, int subid, unsigned char *key);
 #else
-  dev->do_ioctl        = ppp_dev_ioctl;
+static int ppp_dev_rebuild (void *, struct device *, unsigned long,
+			    sk_buff *);
 #endif
 
-  for (i = 0; i < DEV_NUMBUFFS; i++)
-    skb_queue_head_init(&dev->buffs[i]);  /* = NULL if NET02D */
-
-  /* New-style flags */
-  dev->flags      = IFF_POINTOPOINT;
-  dev->family     = AF_INET;
-  dev->pa_addr    = 0;
-  dev->pa_brdaddr = 0;
-  dev->pa_mask    = 0;
-  dev->pa_alen    = 4;
-
-  return 0;
-}
+/*
+ * TTY callbacks
+ */
 
-static void
-ppp_init_ctrl_blk(struct ppp *ppp)
-{
-  ppp->magic		= PPP_MAGIC;
-  ppp->sending		= 0;
-  ppp->toss		= 0xFE;
-  ppp->escape		= 0;
-
-  ppp->flags		= 0;
-  ppp->mtu		= PPP_MTU;
-  ppp->mru		= PPP_MRU;
-  ppp->fcs		= 0;
-
-  memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
-  ppp->xmit_async_map[0] = 0xffffffff;
-  ppp->xmit_async_map[3] = 0x60000000;
-  ppp->recv_async_map	 = 0x00000000;
-
-  ppp->slcomp		= NULL;
-  ppp->rbuff		= NULL;
-  ppp->xbuff		= NULL;
-  ppp->cbuff		= NULL;
-
-  ppp->rhead		= NULL;
-  ppp->rend		= NULL;
-  ppp->rcount		= 0;
-  ppp->xhead		= NULL;
-  ppp->xtail		= NULL;
-
-  ppp->us_rbuff		= NULL;
-  ppp->us_rbuff_end	= NULL;
-  ppp->us_rbuff_head	= NULL;
-  ppp->us_rbuff_tail	= NULL;
-  ppp->read_wait	= NULL;
-  ppp->write_wait	= NULL;
-  ppp->us_rbuff_lock	= 0;
-  ppp->inp_sig		= 0;
-  ppp->inp_sig_pid	= 0;
+static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
+			 unsigned int);
+static int ppp_tty_write (struct tty_struct *, struct file *, const u_char *,
+			  unsigned int);
+static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
+			  unsigned long);
+static int ppp_tty_select (struct tty_struct *tty, struct inode *inode,
+		      struct file *filp, int sel_type, select_table * wait);
+static int ppp_tty_open (struct tty_struct *);
+static void ppp_tty_close (struct tty_struct *);
+static int ppp_tty_room (struct tty_struct *tty);
+static void ppp_tty_receive (struct tty_struct *tty, const u_char * cp,
+			     char *fp, int count);
+static void ppp_tty_wakeup (struct tty_struct *tty);
 
-#ifdef OPTIMIZE_FLAG_TIME /* ensure flag will always be sent first time */
-  ppp->last_xmit	= jiffies - OPTIMIZE_FLAG_TIME;
-#else
-  ppp->last_xmit	= 0;
-#endif
+#define CHECK_PPP(a)  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;}
+#define CHECK_PPP_VOID()  if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;}
 
-  /* clear statistics */
-  memset (&ppp->stats, '\0', sizeof (struct ppp_stats));
+#define in_xmap(ppp,c)	(ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
+#define in_rmap(ppp,c)	((((unsigned int) (u_char) (c)) < 0x20) && \
+			ppp->recv_async_map & (1 << (c)))
 
-  /* Reset the demand dial information */
-  ppp->ddinfo.ip_sjiffies  =
-  ppp->ddinfo.ip_rjiffies  =
-  ppp->ddinfo.nip_sjiffies =
-  ppp->ddinfo.nip_rjiffies = jiffies;
-}
+#define bset(p,b)	((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
 
-/*
- * MTU has been changed by the IP layer. Unfortunately we are not told
- * about this, but we spot it ourselves and fix things up. We could be
- * in an upcall from the tty driver, or in an ip packet queue.
- */
-   
-static void
-ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
-{
-  struct device *dev;
-  unsigned char *new_rbuff, *new_xbuff, *new_cbuff;
-  unsigned char *old_rbuff, *old_xbuff, *old_cbuff;
-  int mtu, mru;
-/*
- *  Allocate the buffer from the kernel for the data
- */
-  dev = ppp->dev;
-  mru = new_mru;
-  mtu = new_mtu;
-
-  /* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
-  if (mru < PPP_MRU)
-    mru = PPP_MRU;
+#define tty2ppp(tty)	((struct ppp *) (tty->disc_data))
+#define dev2ppp(dev)	((struct ppp *) (dev->priv))
+#define ppp2tty(ppp)	((struct tty_struct *) ppp->tty)
+#define ppp2dev(ppp)	((struct device *) ppp->dev)
+
+struct ppp_hdr {
+	unsigned char address;
+	unsigned char control;
+	unsigned char protocol[2];
+};
 
-  mtu = (mtu * 2) + 20;
-  mru = (mru * 2) + 20;
+#define PPP_HARD_HDR_LEN	(sizeof (struct ppp_hdr))
 
-  PRINTKN (2,(KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
-	      dev->name, new_mtu, new_mru));
-	
-  new_xbuff = (unsigned char *) kmalloc(mtu + 4, GFP_ATOMIC);
-  new_rbuff = (unsigned char *) kmalloc(mru + 4, GFP_ATOMIC);
-  new_cbuff = (unsigned char *) kmalloc(mru + 4, GFP_ATOMIC);
-/*
- *  If the buffers failed to allocate then complain.
- */
-  if (new_xbuff == NULL || new_rbuff == NULL || new_cbuff == NULL)
-    {
-      PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n"));
-/*
- *  Release new buffer pointers if the updates were not performed
- */
-      if (new_rbuff != NULL)
-	kfree (new_rbuff);
+typedef struct  ppp_ctrl {
+	struct ppp_ctrl *next;		/* Next structure in the list	*/
+	char            name [8];	/* Name of the device		*/
+	struct ppp      ppp;		/* PPP control table		*/
+	struct device   dev;		/* Device information table	*/
+} ppp_ctrl_t;
+
+static ppp_ctrl_t *ppp_list = NULL;
+
+#define ctl2ppp(ctl) (struct ppp *)    &ctl->ppp
+#define ctl2dev(ctl) (struct device *) &ctl->dev
+#undef  PPP_NRUNIT
+
+/* Buffer types */
+#define BUFFER_TYPE_DEV_RD	0  /* ppp read buffer       */
+#define BUFFER_TYPE_TTY_WR	1  /* tty write buffer      */
+#define BUFFER_TYPE_DEV_WR	2  /* ppp write buffer      */
+#define BUFFER_TYPE_TTY_RD	3  /* tty read buffer       */
+#define BUFFER_TYPE_VJ		4  /* vj compression buffer */
 
-      if (new_xbuff != NULL)
-	kfree (new_xbuff);
+/* Define this string only once for all macro envocations */
+static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
 
-      if (new_cbuff != NULL)
-	kfree (new_cbuff);
-    }
-/*
- *  Update the pointers to the new buffer structures.
- */
-  else
-    {
-      cli();
-      old_xbuff       = ppp->xbuff;
-      old_rbuff       = ppp->rbuff;
-      old_cbuff       = ppp->cbuff;
-
-      ppp->xbuff      = new_xbuff;
-      ppp->rbuff      = new_rbuff;
-      ppp->cbuff      = new_cbuff;
-
-      dev->mem_start  = (unsigned long) new_xbuff;
-      dev->mem_end    = (unsigned long) (dev->mem_start + mtu);
-
-      dev->rmem_start = (unsigned long) new_rbuff;
-      ppp->rend       = (unsigned char *)
-      dev->rmem_end   = (unsigned long) (dev->rmem_start + mru);
+static char szVersion[]         = PPP_VERSION;
+ 
+#ifdef NEW_SKBUFF
+static struct protocol proto_ppp;
+#endif
 
-      ppp->rhead      = new_rbuff;
 /*
- *  Update the parameters for the new buffer sizes
+ * Information for the protocol decoder
  */
-      ppp->toss		= 0xFE;
-      ppp->escape	= 0;
-      ppp->sending	= 0;
-      ppp->rcount	= 0;
 
-      ppp->mru		= new_mru;
+typedef int (*pfn_proto)  (struct ppp *, u_short, u_char *, int);
 
-      ppp->mtu		=
-      dev->mtu		= new_mtu;
+typedef struct ppp_proto_struct {
+	int		proto;
+	pfn_proto	func;
+} ppp_proto_type;
+
+static
+ppp_proto_type proto_list[] = {
+	{ PPP_IP,         rcv_proto_ip         },
+	{ PPP_IPX,        rcv_proto_ipx        },
+	{ PPP_VJC_COMP,   rcv_proto_vjc_comp   },
+	{ PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
+	{ PPP_LQR,        rcv_proto_lqr        },
+	{ PPP_CCP,        rcv_proto_ccp        },
+	{ 0,              rcv_proto_unknown    }  /* !!! MUST BE LAST !!! */
+};
 
-      sti();
 /*
- *  Release old buffer pointers
+ * Values for FCS calculations.
  */
-      if (old_rbuff != NULL)
-	kfree (old_rbuff);
-
-      if (old_xbuff != NULL)
-	kfree (old_xbuff);
-
-      if (old_cbuff != NULL)
-	kfree (old_cbuff);
-    }
-}
 
-/* called when we abandon the PPP line discipline */
+#define PPP_INITFCS	0xffff	/* Initial FCS value */
+#define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
+#define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ ppp_crc16_table[((fcs) ^ (c)) & 0xff])
+
+unsigned short ppp_crc16_table[256] =
+{
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
 
-static void
-ppp_release(struct ppp *ppp)
+#ifdef CHECK_CHARACTERS
+static unsigned paritytab[8] =
 {
-#ifdef NEW_TTY_DRIVERS
-  if (ppp->tty != NULL && ppp->tty->disc_data == ppp)
-    ppp->tty->disc_data = NULL; /* Break the tty->ppp link */
-#endif
-
-  if (ppp->dev) {
-    dev_close (ppp->dev);
-    ppp->dev->flags = 0;
-  }
-
-  kfree (ppp->xbuff);
-  kfree (ppp->cbuff);
-  kfree (ppp->rbuff);
-  kfree (ppp->us_rbuff);
-
-  ppp->xbuff    =
-  ppp->cbuff    =
-  ppp->rbuff    =
-  ppp->us_rbuff = NULL;
-
-  if (ppp->slcomp) {
-    slhc_free(ppp->slcomp);
-    ppp->slcomp = NULL;
-  }
+	0x96696996, 0x69969669, 0x69969669, 0x96696996,
+	0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+#endif
 
-  ppp->inuse = 0;
-  ppp->tty   = NULL;
+/* local function to store a value into the LQR frame */
+extern inline u_char * store_long (register u_char *p, register int value) {
+	*p++ = (u_char) (value >> 24);
+	*p++ = (u_char) (value >> 16);
+	*p++ = (u_char) (value >>  8);
+	*p++ = (u_char) value;
+	return p;
 }
 
-static void
-ppp_close(struct tty_struct *tty)
-{
-  struct ppp *ppp = ppp_find(tty);
-
-  if (ppp == NULL || ppp->magic != PPP_MAGIC) {
-    PRINTKN (1,(KERN_WARNING "ppp: trying to close unopened tty!\n"));
-  } else {
-    CHECK_PPP_VOID();
-    ppp_release (ppp);
+/*************************************************************
+ * INITIALIZATION
+ *************************************************************/
 
-    PRINTKN (2,(KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name));
-#ifdef MODULE
-    MOD_DEC_USE_COUNT;
-#endif
-  }
-}
+/* This procedure is called once and once only to define who we are to
+ * the operating system and the various procedures that it may use in
+ * accessing the ppp protocol.
+ */
 
-/* called when PPP line discipline is selected on a tty */
 static int
-ppp_open(struct tty_struct *tty)
+ppp_first_time (void)
 {
-  struct ppp *ppp = ppp_find(tty);
-
-  if (ppp) {
-    PRINTKN (1,(KERN_ERR "ppp_open: gack! tty already associated to %s!\n",
-		ppp->magic == PPP_MAGIC ? ppp->dev->name : "unknown"));
-    return -EEXIST;
-  }
-
-  ppp = ppp_alloc();
-  if (ppp == NULL) {
-    PRINTKN (1,(KERN_ERR "ppp_open: couldn't allocate ppp channel\n"));
-    return -ENFILE;
-  }
-
-  /* make sure the channel is actually open */
-  ppp_init_ctrl_blk (ppp);
-
-  ppp->tty = tty;
+	static struct tty_ldisc	ppp_ldisc;
+	int    status;
 
-#ifdef NEW_TTY_DRIVERS
-  tty->disc_data = ppp;
-  if (tty->driver.flush_buffer)
-    tty->driver.flush_buffer(tty);
-  if (tty->ldisc.flush_buffer)
-    tty->ldisc.flush_buffer(tty);
-#else
-  tty_read_flush (tty);
-  tty_write_flush (tty);
+	printk (KERN_INFO
+		"PPP: version %s (dynamic channel allocation)"
+#ifdef NEW_SKBUFF
+		" NEW_SKBUFF"
+#endif
+		"\n", szVersion);
+
+#ifndef MODULE /* slhc module logic has its own copyright announcment */
+	printk (KERN_INFO
+		"TCP compression code copyright 1989 Regents of the "
+		"University of California\n");
 #endif
+	
+	printk (KERN_INFO
+		"PPP Dynamic channel allocation code copyright 1995 "
+		"Caldera, Inc.\n");
+/*
+ * Register the protocol for the device
+ */
 
-  if ((ppp->slcomp = slhc_init(16, 16)) == NULL) {
-    PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n"));
-    ppp_release (ppp);
-    return -ENOMEM;
-  }
-
-  /* Define the buffers for operation */
-  ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru);
-  if (ppp->rbuff == NULL) {
-    ppp_release (ppp);
-    return -ENOMEM;
-  }
-
-  /* Allocate a user-level receive buffer */
-  ppp->us_rbuff = (unsigned char *) kmalloc (RBUFSIZE, GFP_KERNEL);
-  if (ppp->us_rbuff == NULL) {
-    PRINTKN (1,(KERN_ERR "ppp: no space for user receive buffer\n"));
-    ppp_release (ppp);
-    return -ENOMEM;
-  }
-
-  ppp->us_rbuff_head =
-  ppp->us_rbuff_tail = ppp->us_rbuff;
-  ppp->us_rbuff_end  = ppp->us_rbuff + RBUFSIZE;
+#ifdef NEW_SKBUFF  
+	memset (&proto_ppp, 0, sizeof (proto_ppp));
 
-  PRINTKN (2,(KERN_INFO "ppp: channel %s open\n", ppp->dev->name));
+	proto_ppp.name          = "PPP";
+	proto_ppp.output        = ppp_dev_output;
+	proto_ppp.input         = ppp_dev_input;
+	proto_ppp.bh_input      = ppp_dev_input;
+	proto_ppp.control_event = default_protocol_control;
+	proto_ppp.get_binding   = ppp_dev_getkey;
+	proto_ppp.header_space  = 0; /* PPP_HARD_HDR_LEN; */
 
-#ifdef MODULE
-  MOD_INC_USE_COUNT;
+	protocol_register(&proto_ppp);
 #endif
 
-  return (ppp->line);
+/*
+ * Register the tty dicipline
+ */	
+	(void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
+	ppp_ldisc.magic		= TTY_LDISC_MAGIC;
+	ppp_ldisc.open		= ppp_tty_open;
+	ppp_ldisc.close		= ppp_tty_close;
+	ppp_ldisc.read		= ppp_tty_read;
+	ppp_ldisc.write		= ppp_tty_write;
+	ppp_ldisc.ioctl		= ppp_tty_ioctl;
+	ppp_ldisc.select	= ppp_tty_select;
+	ppp_ldisc.receive_room	= ppp_tty_room;
+	ppp_ldisc.receive_buf	= ppp_tty_receive;
+	ppp_ldisc.write_wakeup	= ppp_tty_wakeup;
+	
+	status = tty_register_ldisc (N_PPP, &ppp_ldisc);
+	if (status == 0)
+		printk (KERN_INFO "PPP line discipline registered.\n");
+	else
+		printk (KERN_ERR "error registering line discipline: %d\n",
+			status);
+	return status;
 }
 
-/* called when ppp interface goes "up".  here this just means we start
-   passing IP packets */
-static int
-ppp_dev_open(struct device *dev)
-{
-  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
-
-  /* reset POINTOPOINT every time, since dev_close zaps it! */
-  dev->flags |= IFF_POINTOPOINT;
-
-  if (ppp->tty == NULL) {
-    PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n",
-		dev->name));
-    return -ENXIO;
-  }
-
-  PRINTKN (2,(KERN_INFO "ppp: channel %s going up for IP packets!\n",
-	      dev->name));
+/*************************************************************
+ * INITIALIZATION
+ *************************************************************/
 
-  CHECK_PPP(-ENXIO);
-  return 0;
-}
+/* called when the device is actually created */
 
 static int
-ppp_dev_close(struct device *dev)
+ppp_init_dev (struct device *dev)
 {
-  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
-
-  if (ppp->tty == NULL) {
-    PRINTKN (1,(KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n",
-		dev->name));
-    return -ENXIO;
-  }
+	int    indx;
+#ifdef NEW_SKBUFF  
+	dev->default_protocol = &proto_ppp;	/* Our protocol layer is PPP */
+#else
+	dev->hard_header      = ppp_dev_header;
+#if USE_SKB_PROTOCOL == 0
+	dev->type_trans       = ppp_dev_type;
+#endif
+	dev->rebuild_header   = ppp_dev_rebuild;
+	dev->hard_header_len  = 0; /* PPP_HARD_HDR_LEN; */
+#endif
+
+	/* device INFO */
+	dev->mtu              = PPP_MTU;
+	dev->hard_start_xmit  = ppp_dev_xmit;
+	dev->open             = ppp_dev_open;
+	dev->stop             = ppp_dev_close;
+	dev->get_stats        = ppp_dev_stats;
+	dev->do_ioctl         = ppp_dev_ioctl;
+	dev->addr_len         = 0;
+	dev->type             = ARPHRD_PPP;
+
+	for (indx = 0; indx < DEV_NUMBUFFS; indx++)
+		skb_queue_head_init (&dev->buffs[indx]);
+
+	/* New-style flags */
+	dev->flags      = IFF_POINTOPOINT;
+	dev->family     = AF_INET;
+	dev->pa_addr    = 0;
+	dev->pa_brdaddr = 0;
+	dev->pa_mask    = 0;
+	dev->pa_alen    = 4; /* sizeof (unsigned long) */
 
-  PRINTKN (2,(KERN_INFO "ppp: channel %s going down for IP packets!\n",
-	      dev->name));
-  CHECK_PPP(-ENXIO);
-  return 0;
+	return 0;
 }
 
-#ifndef NET02D
-static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
-{
-  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
-  int    error;
+/*
+ * Local procedure to initialize the ppp structure
+ */
 
-  struct stats
-  {
-    struct ppp_stats  ppp_stats;
-    struct slcompress slhc;
-  } *result;
+static void
+ppp_init_ctrl_blk (register struct ppp *ppp)
+{
+	ppp->magic  = PPP_MAGIC;
+	ppp->toss   = 0xE0;
+	ppp->escape = 0;
 
-  error = verify_area (VERIFY_WRITE,
-		       ifr->ifr_ifru.ifru_data,
-		       sizeof (struct stats));
+	ppp->flags  = 0;
+	ppp->mtu    = PPP_MTU;
+	ppp->mru    = PPP_MRU;
+
+	memset (ppp->xmit_async_map, 0, sizeof (ppp->xmit_async_map));
+	ppp->xmit_async_map[0] = 0xffffffff;
+	ppp->xmit_async_map[3] = 0x60000000;
+	ppp->recv_async_map    = 0x00000000;
+
+	ppp->rbuf       = NULL;
+	ppp->wbuf       = NULL;
+	ppp->ubuf       = NULL;
+	ppp->cbuf       = NULL;
+	ppp->slcomp     = NULL;
+	ppp->read_wait  = NULL;
+	ppp->write_wait = NULL;
+	ppp->last_xmit  = jiffies - flag_time;
+
+	/* clear statistics */
+	memset (&ppp->stats, '\0', sizeof (struct pppstat));
+
+	/* Reset the demand dial information */
+	ppp->ddinfo.xmit_idle=         /* time since last NP packet sent */
+	ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
+
+	/* PPP compression data */
+	ppp->sc_xc_state =
+	ppp->sc_rc_state = NULL;
+}
 
-  if (error == 0) {
-    result = (struct stats *) ifr->ifr_ifru.ifru_data;
+/* called at boot/load time for each ppp device defined in the kernel */
 
-    memcpy_tofs (&result->ppp_stats, &ppp->stats, sizeof (struct ppp_stats));
-    if (ppp->slcomp)
-      memcpy_tofs (&result->slhc,    ppp->slcomp, sizeof (struct slcompress));
-  }
+#ifndef MODULE
+int
+ppp_init (struct device *dev)
+{
+	static int first_time = 1;
+	int    answer = 0;
 
-  return error;
+	if (first_time) {
+		static struct symbol_table ppp_syms = {
+#include <linux/symtab_begin.h>
+			X(ppp_register_compressor),
+			X(ppp_unregister_compressor),
+			X(ppp_crc16_table),
+#include <linux/symtab_end.h>
+		};
+
+		first_time = 0;
+		answer     = ppp_first_time();
+		if (answer == 0)
+			(void) register_symtab (&ppp_syms);
+	}
+/*
+ * Un-register the devices defined at the start of the system. They will
+ * be added when they are needed again. The first device just gets us into
+ * this code to register the handlers.
+ */
+	unregister_netdev (dev);
+	return answer;
 }
 #endif
 
-/*************************************************************
- * TTY OUTPUT
- *    The following function delivers a fully-formed PPP
- *    frame in ppp->xbuff to the TTY for output.
- *************************************************************/
+/*
+ * Routine to allocate a buffer for later use by the driver.
+ */
 
-#ifdef NEW_TTY_DRIVERS
-static inline void
-#else
-static void
-#endif
-ppp_output_done (void *ppp)
+static struct ppp_buffer *
+ppp_alloc_buf (int size, int type)
 {
-  /* unlock the transmitter queue */
-  ppp_unlock ((struct ppp *) ppp);
+	struct ppp_buffer *buf;
 
-  /* If the device is still up then enable the transmitter of the
-     next frame. */
-  if (((struct ppp *) ppp)->dev->flags & IFF_UP)
-#ifndef NET02D
-    mark_bh (NET_BH);
-#else
-    dev_tint (((struct ppp *) ppp)->dev);
-#endif
+	buf = (struct ppp_buffer *) kmalloc (size + sizeof (struct ppp_buffer),
+					     GFP_ATOMIC);
 
-  /* enable any blocked process pending transmission */
-  wake_up_interruptible (&((struct ppp *) ppp)->write_wait);
+	if (buf != NULL) {
+		buf->size   = size - 1;	/* Mask for the buffer size */
+		buf->type   = type;
+		buf->locked = 0;
+		buf->count  = 0;
+		buf->head   = 0;
+		buf->tail   = 0;
+		buf->fcs    = PPP_INITFCS;
+	}
+	return (buf);
 }
 
-#ifndef NEW_TTY_DRIVERS
+/*
+ * Routine to release the allocated buffer.
+ */
+
 static void
-ppp_kick_tty (struct ppp *ppp)
+ppp_free_buf (struct ppp_buffer *ptr)
 {
-  register int count = ppp->xhead - ppp->xbuff;
-  register int answer;
-
-  ppp->stats.sbytes += count;
-
-  answer = tty_write_data (ppp->tty,
-			   ppp->xbuff,
-			   count,
-			   ppp_output_done,
-			   (void *) ppp);
-
-  if (answer == 0)
-    ppp_output_done (ppp);   /* Should not happen */
-  else
-    if (answer < 0) {
-      ppp->stats.serrors++;
-      ppp_output_done (ppp); /* unlock the transmitter */
-    }
+	if (ptr != NULL)
+		kfree (ptr);
 }
 
-#else
+/*
+ * Lock the indicated transmit buffer
+ */
 
-static void
-ppp_kick_tty (struct ppp *ppp)
+extern inline int
+lock_buffer (register struct ppp_buffer *buf)
 {
-	register int count, actual;
-	
-	count = ppp->xhead - ppp->xbuff;
-	
-	actual = ppp->tty->driver.write(ppp->tty, 0, ppp->xbuff, count);
-	ppp->stats.sbytes += actual;
-	if (actual == count) {
-		ppp_output_done(ppp);
-	} else {
-		ppp->xtail = ppp->xbuff + actual;
-		ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-	}
+	register int state;
+	int flags;
+/*
+ * Save the current state and if free then set it to the "busy" state
+ */
+	save_flags (flags);
+	cli ();
+	state = buf->locked;
+	if (state == 0)
+		buf->locked = 2;
+/*
+ * Restore the flags and return the previous state. 0 implies success.
+ */
+	restore_flags (flags);
+	return (state);
 }
 
-static void ppp_write_wakeup(struct tty_struct *tty)
+/*
+ * MTU has been changed by the IP layer. Unfortunately we are not told
+ * about this, but we spot it ourselves and fix things up. We could be
+ * in an upcall from the tty driver, or in an ip packet queue.
+ */
+
+static int
+ppp_changedmtu (struct ppp *ppp, int new_mtu, int new_mru)
 {
-	register int count, actual;
-	struct ppp *ppp = ppp_find(tty);
+	struct device *dev;
 
-	if (!ppp || ppp->magic != PPP_MAGIC) {
-		PRINTKN (1,
-			 (KERN_ERR "PPP: write_wakeup called but couldn't "
-			  "find PPP struct.\n"));
-		return;
-	}
+	struct ppp_buffer *new_rbuf;
+	struct ppp_buffer *new_wbuf;
+	struct ppp_buffer *new_cbuf;
+	struct ppp_buffer *new_tbuf;
+
+	struct ppp_buffer *old_rbuf;
+	struct ppp_buffer *old_wbuf;
+	struct ppp_buffer *old_cbuf;
+	struct ppp_buffer *old_tbuf;
 
-	if (!ppp->xtail)
-		return;
+	int mtu, mru;
+/*
+ *  Allocate the buffer from the kernel for the data
+ */
+	dev = ppp2dev (ppp);
+	mru = new_mru;
+	/* allow for possible escapement of every character */
+	mtu = (new_mtu * 2) + 20;
+
+	/* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
+	if (mru < PPP_MRU)
+		mru = PPP_MRU;
 
-	cli();
-	if (ppp->flags & SC_XMIT_BUSY) {
-		sti();
-		return;
-	}
-	ppp->flags |= SC_XMIT_BUSY;
-	sti();
+	mru += 10;
 	
-	count = ppp->xhead - ppp->xtail;
-	
-	actual = tty->driver.write(tty, 0, ppp->xtail, count);
-	ppp->stats.sbytes += actual;
-	if (actual == count) {
-		ppp->xtail = 0;
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-
-		ppp_output_done(ppp);
-	} else {
-		ppp->xtail += actual;
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
+			dev->name, new_mtu, new_mru);
+
+	new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN,	BUFFER_TYPE_DEV_WR);
+	new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24,	BUFFER_TYPE_TTY_WR);
+	new_rbuf = ppp_alloc_buf (mru + 84,		BUFFER_TYPE_DEV_RD);
+	new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN,	BUFFER_TYPE_VJ);
+/*
+ *  If the buffers failed to allocate then complain and release the partial
+ *  allocations.
+ */
+	if (new_wbuf == NULL || new_tbuf == NULL ||
+	    new_rbuf == NULL || new_cbuf == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+				"ppp: failed to allocate new buffers\n");
+
+		ppp_free_buf (new_wbuf);
+		ppp_free_buf (new_tbuf);
+		ppp_free_buf (new_rbuf);
+		ppp_free_buf (new_cbuf);
+		return 0;
 	}
-	ppp->flags &= ~SC_XMIT_BUSY;
-}
-#endif
+/*
+ *  Update the pointers to the new buffer structures.
+ */
+	cli ();
+	old_wbuf = ppp->wbuf;
+	old_rbuf = ppp->rbuf;
+	old_cbuf = ppp->cbuf;
+	old_tbuf = ppp->tbuf;
+
+	ppp->wbuf = new_wbuf;
+	ppp->rbuf = new_rbuf;
+	ppp->cbuf = new_cbuf;
+	ppp->tbuf = new_tbuf;
+
+	ppp->rbuf->size -= 80;  /* reserve space for vj header expansion */
+
+	dev->mem_start  = (unsigned long) buf_base (new_wbuf);
+	dev->mem_end    = (unsigned long) (dev->mem_start + mtu);
+	dev->rmem_start = (unsigned long) buf_base (new_rbuf);
+	dev->rmem_end   = (unsigned long) (dev->rmem_start + mru);
+/*
+ *  Update the parameters for the new buffer sizes
+ */
+	ppp->toss   = 0xE0;	/* To ignore characters until new FLAG */
+	ppp->escape = 0;	/* No pending escape character */
 
-/*************************************************************
- * TTY INPUT
- *    The following functions handle input that arrives from
- *    the TTY.  It recognizes PPP frames and either hands them
- *    to the network layer or queues them for delivery to a
- *    user process reading this TTY.
- *************************************************************/
+	dev->mtu    =
+	ppp->mtu    = new_mtu;
+	ppp->mru    = new_mru;
 
-/* stuff a single character into the receive buffer */
+	ppp->s1buf  = NULL;
+	ppp->s2buf  = NULL;
+	ppp->xbuf   = NULL;
 
-static inline void
-ppp_enqueue(struct ppp *ppp, unsigned char c)
-{
-  unsigned long flags;
+	ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	ppp->flags      &= ~SC_XMIT_BUSY;
 
-  save_flags(flags);
-  cli();
-  if (ppp->rhead < ppp->rend) {
-    *ppp->rhead = c;
-    ppp->rhead++;
-    ppp->rcount++;
-  } else
-    ppp->stats.roverrun++;
-  restore_flags(flags);
+	sti ();
+/*
+ *  Release old buffer pointers
+ */
+	ppp_free_buf (old_rbuf);
+	ppp_free_buf (old_wbuf);
+	ppp_free_buf (old_cbuf);
+	ppp_free_buf (old_tbuf);
+	return 1;
 }
 
-#ifdef CHECK_CHARACTERS
-static unsigned paritytab[8] = {
-    0x96696996, 0x69969669, 0x69969669, 0x96696996,
-    0x69969669, 0x96696996, 0x96696996, 0x69969669
-};
-#endif
-
-#ifndef NEW_TTY_DRIVERS
-static void
-ppp_dump_inqueue(struct tty_struct *tty)
-{
-  int  head = tty->read_q.head,
-       tail = tty->read_q.tail,
-       i, count;
-  char buffer[8];
-
-  PRINTK ((KERN_DEBUG "INQUEUE: head %d tail %d imode %x:\n", head, tail, 
-	   (unsigned int) tty->termios->c_iflag))
-
-  i     = tail;
-  count = 0;
-
-  while (i != head) {
-    buffer [count] = tty->read_q.buf[i];
-    if (++count == 8) {
-      ppp_print_buffer (NULL, buffer, 8, KERNEL_DS);
-      count = 0;
-    }
-    i = (i + 1) & (TTY_BUF_SIZE - 1);
-  }
-  ppp_print_buffer (NULL, buffer, count, KERNEL_DS);
-}
-
-/* called by lower levels of TTY driver when data becomes available.
-   all incoming data comes through this function. */
-
-void ppp_tty_input_ready(struct tty_struct *tty)
-{
-  struct ppp *ppp = ppp_find(tty);
-  int n, error;
-  unsigned char buff[128];
-
-/*  PRINTK( (KERN_DEBUG "PPP: handler called.\n") ) */
-  if (!ppp || ppp->magic != PPP_MAGIC) {
-    PRINTKN (1,
-	     (KERN_ERR "PPP: handler called but couldn't find PPP struct.\n"));
-    return;
-  }
-
-  CHECK_PPP_VOID();
-
-  /* ZZZ */
-  if (ppp_debug >= 5)
-    ppp_dump_inqueue(ppp->tty);
-
-  do {
-    n = tty_read_raw_data(tty, buff, 128);
-    if ( n == 0 )		/* nothing there */
-      break;
-
-    if (ppp_debug >= 5)
-      ppp_print_buffer ("receive buffer", buff, n > 0 ? n : -n, KERNEL_DS);
-
-    if ( n < 0 ) {
-      /* Last character is error flag.
-	 Process the previous characters, then set toss flag. */
-      n = (-n) - 1;
-      error = buff[n];
-    } else error = 0;
-    ppp->stats.rbytes += n;
-    ppp_unesc(ppp,buff,n);
-    if (error)
-      ppp->toss = error;
-  } while (1);
-}
-
-/* recover frame by undoing PPP escape mechanism;
-   copies N chars of input data from C into PPP->rbuff
-   calls ppp_doframe to dispose of any frames it finds
-*/
+/*
+ * CCP is down; free (de)compressor state if necessary.
+ */
 
 static void
-ppp_unesc(struct ppp *ppp, unsigned char *c, int n)
+ppp_ccp_closed (struct ppp *ppp)
 {
-  int i;
-
-  for (i = 0; i < n; i++, c++) {
-    PRINTKN (6,(KERN_DEBUG "(%x)", (unsigned int) *c));
-
-#ifdef CHECK_CHARACTERS
-    if (*c & 0x80)
-	sc->sc_flags |= SC_RCV_B7_1;
-    else
-	sc->sc_flags |= SC_RCV_B7_0;
-
-    if (paritytab[*c >> 5] & (1 << (*c & 0x1F)))
-	sc->sc_flags |= SC_RCV_ODDP;
-    else
-	sc->sc_flags |= SC_RCV_EVNP;
-#endif
-
-    switch (*c) {
-    case PPP_ESC:		/* PPP_ESC: invert 0x20 in next character */
-      ppp->escape = PPP_TRANS;
-      break;
-
-    case PPP_FLAG:		/* PPP_FLAG: end of frame */
-      if (ppp->escape)		/* PPP_ESC just before PPP_FLAG is illegal */
-	ppp->toss = 0xFF;
-
-      if ((ppp->toss & 0x80) == 0)
-	ppp_doframe(ppp);	/* pass frame on to next layers */
-
-      ppp->rcount = 0;
-      ppp->rhead  = ppp->rbuff;
-      ppp->escape = 0;
-      ppp->toss   = 0;
-      break;
-
-    default:			/* regular character */
-      if (!in_rmap (ppp, *c)) {
-	if (ppp->toss == 0)
-	  ppp_enqueue (ppp, *c ^ ppp->escape);
-	ppp->escape = 0;
-      }
-      break;
-    }
-  }
-}
+	if (ppp->sc_xc_state) {
+		(*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
+		ppp->sc_xc_state = NULL;
+	}
 
-#else
-static int ppp_receive_room(struct tty_struct *tty)
-{
-	return 65536;  /* We can handle an infinite amount of data. :-) */
+	if (ppp->sc_rc_state) {
+		(*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
+		ppp->sc_rc_state = NULL;
+	}
 }
 
+/*
+ * Called to release all of the information in the current PPP structure.
+ *
+ * It is called when the ppp device goes down or if it is unable to go
+ * up.
+ */
 
-static void ppp_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-			    char *fp, int count)
+static void
+ppp_release (struct ppp *ppp)
 {
-  register struct ppp *ppp = ppp_find (tty);
-  unsigned char c;
- 
-/*  PRINTK( ("PPP: handler called.\n") ); */
+	struct tty_struct *tty;
+	struct device *dev;
 
-  if (!ppp || ppp->magic != PPP_MAGIC) {
-    PRINTKN (1,("PPP: handler called but couldn't find "
-		"PPP struct.\n"));
-    return;
-  }
+	tty = ppp2tty (ppp);
+	dev = ppp2dev (ppp);
 
-  CHECK_PPP_VOID();
- 
-  if (ppp_debug >= 5) {
-    ppp_print_buffer ("receive buffer", cp, count, KERNEL_DS);
-  }
+	ppp_ccp_closed (ppp);
 
-  ppp->stats.rbytes += count;
- 
-  while (count-- > 0) {
-    c = *cp++;
+	if (tty != NULL && tty->disc_data == ppp)
+		tty->disc_data = NULL;	/* Break the tty->ppp link */
+
+	if (dev && dev->flags & IFF_UP) {
+		dev_close (dev); /* close the device properly */
+		dev->flags = 0;  /* prevent recursion */
+	}
 
-    if (fp) {
-      if (*fp && ppp->toss == 0)
-	ppp->toss = *fp;
-      fp++;
-    }
+	ppp_free_buf (ppp->rbuf);
+	ppp_free_buf (ppp->wbuf);
+	ppp_free_buf (ppp->cbuf);
+	ppp_free_buf (ppp->ubuf);
+	ppp_free_buf (ppp->tbuf);
+
+	ppp->rbuf  =
+	ppp->wbuf  =
+	ppp->cbuf  =
+	ppp->tbuf  =
+	ppp->xbuf  =
+	ppp->s1buf =
+	ppp->s2buf =
+	ppp->ubuf  = NULL;
+
+	if (ppp->slcomp) {
+		slhc_free (ppp->slcomp);
+		ppp->slcomp = NULL;
+	}
 
-#ifdef CHECK_CHARACTERS
-    if (c & 0x80)
-	ppp->flags |= SC_RCV_B7_1;
-    else
-	ppp->flags |= SC_RCV_B7_0;
-
-    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
-	ppp->flags |= SC_RCV_ODDP;
-    else
-	ppp->flags |= SC_RCV_EVNP;
-#endif
-
-    switch (c) {
-    case PPP_ESC:		/* PPP_ESC: invert 0x20 in next character */
-      ppp->escape = PPP_TRANS;
-      break;
-
-    case PPP_FLAG:		/* PPP_FLAG: end of frame */
-      if (ppp->escape)		/* PPP_ESC just before PPP_FLAG is "cancel"*/
-	ppp->toss = 0xFF;
-
-      if ((ppp->toss & 0x80) == 0)
-	ppp_doframe(ppp);	/* pass frame on to next layers */
-
-      ppp->rcount = 0;
-      ppp->rhead  = ppp->rbuff;
-      ppp->escape = 0;
-      ppp->toss   = 0;
-      break;
-
-    default:			/* regular character */
-      if (!in_rmap (ppp, c)) {
-	if (ppp->toss == 0)
-	  ppp_enqueue (ppp, c ^ ppp->escape);
-	ppp->escape = 0;
-      }
-    }
-  }
+	ppp->inuse = 0;
+	ppp->tty   = NULL;
 }
+
+/*
+ * Device callback.
+ *
+ * Called when the PPP device goes down in response to an ifconfig request.
+ */
+
+static void
+ppp_tty_close (struct tty_struct *tty)
+{
+	struct ppp *ppp = tty2ppp (tty);
+
+	if (ppp != NULL) {
+		if (ppp->magic != PPP_MAGIC) {
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_WARNING
+				       "ppp: trying to close unopened tty!\n");
+		} else {
+			CHECK_PPP_VOID();
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO "ppp: channel %s closing.\n",
+					ppp2dev(ppp) -> name);
+			ppp_release (ppp);
+			MOD_DEC_USE_COUNT;
+		}
+	}
+}
+
+/*
+ * TTY callback.
+ *
+ * Called when the tty discipline is switched to PPP.
+ */
+
+static int
+ppp_tty_open (struct tty_struct *tty)
+{
+	struct ppp *ppp = tty2ppp (tty);
+/*
+ * There should not be an existing table for this slot.
+ */
+	if (ppp) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+			"ppp_tty_open: gack! tty already associated to %s!\n",
+			ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
+						: "unknown");
+		return -EEXIST;
+	}
+/*
+ * Allocate the structure from the system
+ */
+	ppp = ppp_alloc();
+	if (ppp == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+			"ppp_tty_open: couldn't allocate ppp channel\n");
+		return -ENFILE;
+	}
+/*
+ * Initialize the control block
+ */
+	ppp_init_ctrl_blk (ppp);
+	ppp->tty       = tty;
+	tty->disc_data = ppp;
+/*
+ * Flush any pending characters in the driver and discipline.
+ */
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer (tty);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer (tty);
+/*
+ * Allocate space for the default VJ header compression slots
+ */
+	ppp->slcomp = slhc_init (16, 16);
+	if (ppp->slcomp == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+			"ppp_tty_open: no space for compression buffers!\n");
+		ppp_release (ppp);
+		return -ENOMEM;
+	}
+/*
+ * Allocate space for the MTU and MRU buffers
+ */
+	if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
+		ppp_release (ppp);
+		return -ENOMEM;
+	}
+/*
+ * Allocate space for a user level buffer
+ */
+	ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
+	if (ppp->ubuf == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+		       "ppp_tty_open: no space for user receive buffer\n");
+		ppp_release (ppp);
+		return -ENOMEM;
+	}
+
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_INFO "ppp: channel %s open\n",
+			ppp2dev(ppp)->name);
+
+	MOD_INC_USE_COUNT;
+	return (ppp->line);
+}
+
+/*
+ * Local function to send the next portion of the buffer.
+ *
+ * Called by the tty driver's tty_wakeup function should it be entered
+ * because the partial buffer was transmitted.
+ *
+ * Called by kick_tty to send the initial portion of the buffer.
+ *
+ * Completion processing of the buffer transmission is handled here.
+ */
+
+static void
+ppp_tty_wakeup_code (struct ppp *ppp, struct tty_struct *tty,
+		     struct ppp_buffer *xbuf)
+{
+	register int count, actual;
+/*
+ * Prevent re-entrancy by ensuring that this routine is called only once.
+ */
+	cli ();
+	if (ppp->flags & SC_XMIT_BUSY) {
+		sti ();
+		return;
+	}
+	ppp->flags |= SC_XMIT_BUSY;
+	sti ();
+/*
+ * Send the next block of data to the modem
+ */
+	count = xbuf->count - xbuf->tail;
+	actual = tty->driver.write (tty, 0,
+				    buf_base (xbuf) + xbuf->tail, count);
+/*
+ * Terminate transmission of any block which may have an error.
+ * This could occur should the carrier drop.
+ */
+	if (actual < 0) {
+	        ppp->stats.ppp_oerrors++;
+		actual = count;
+	} else
+		ppp->bytes_sent += actual;
+/*
+ * If the buffer has been transmitted then clear the indicators.
+ */
+	xbuf->tail += actual;
+	if (actual == count) {
+		xbuf = NULL;
+		ppp->flags &= ~SC_XMIT_BUSY;
+/*
+ * Complete the transmission on the current buffer.
+ */
+		xbuf = ppp->xbuf;
+		if (xbuf != NULL) {
+			tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
+			xbuf->locked = 0;
+			ppp->xbuf    = NULL;
+/*
+ * If the completed buffer came from the device write, then complete the
+ * transmission block.
+ */
+			if (ppp2dev (ppp) -> flags & IFF_UP) {
+				if (xbuf->type == BUFFER_TYPE_DEV_WR)
+				        ppp2dev (ppp)->tbusy = 0;
+				mark_bh (NET_BH);
+			}
+/*
+ * Wake up the transmission queue for all completion events.
+ */
+			wake_up_interruptible (&ppp->write_wait);
+/*
+ * Look at the priorities. Choose a daemon write over the device driver.
+ */
+			cli();
+			xbuf = ppp->s1buf;
+			ppp->s1buf = NULL;
+			if (xbuf == NULL) {
+				xbuf = ppp->s2buf;
+				ppp->s2buf = NULL;
+			}
+			sti();
+/*
+ * If there is a pending buffer then transmit it now.
+ */
+			if (xbuf != NULL) {
+				ppp->flags &= ~SC_XMIT_BUSY;
+				ppp_kick_tty (ppp, xbuf);
+				return;
+			}
+		}
+	}
+/*
+ * Clear the re-entry flag
+ */
+	ppp->flags &= ~SC_XMIT_BUSY;
+}
+
+/*
+ * This function is called by the tty driver when the transmit buffer has
+ * additional space. It is used by the ppp code to continue to transmit
+ * the current buffer should the buffer have been partially sent.
+ *
+ * In addition, it is used to send the first part of the buffer since the
+ * logic and the inter-locking would be identical.
+ */
+
+static void
+ppp_tty_wakeup (struct tty_struct *tty)
+{
+	struct ppp_buffer *xbuf;
+	struct ppp *ppp = tty2ppp (tty);
+
+	if (!ppp)
+		return;
+
+	if (ppp->magic != PPP_MAGIC)
+		return;
+/*
+ * Ensure that there is a transmission pending. Clear the re-entry flag if
+ * there is no pending buffer. Otherwise, send the buffer.
+ */
+	xbuf = ppp->xbuf;
+	if (xbuf == NULL)
+		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	else
+		ppp_tty_wakeup_code (ppp, tty, xbuf);
+}
+
+/*
+ * This function is called to transmit a buffer to the remote. The buffer
+ * is placed on the pending queue if there is presently a buffer being
+ * sent or it is transmitted with the aid of ppp_tty_wakeup.
+ */
+
+static void
+ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
+{
+	register int flags;
+/*
+ * Hold interrupts.
+ */
+	save_flags (flags);
+	cli ();
+/*
+ * Control the flags which are best performed with the interrupts masked.
+ */
+	xbuf->locked     = 1;
+	xbuf->tail       = 0;
+/*
+ * If the transmitter is busy then place the buffer on the appropriate
+ * priority queue.
+ */
+	if (ppp->xbuf != NULL) {
+		if (xbuf->type == BUFFER_TYPE_TTY_WR)
+			ppp->s1buf = xbuf;
+		else
+			ppp->s2buf = xbuf;
+		restore_flags (flags);
+		return;
+	}
+/*
+ * If the transmitter is not busy then this is the highest priority frame
+ */
+	ppp->flags      &= ~SC_XMIT_BUSY;
+	ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	ppp->xbuf        = xbuf;
+	restore_flags (flags);
+/*
+ * Do the "tty wakeup_code" to actually send this buffer.
+ */
+	ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
+}
+
+/*************************************************************
+ * TTY INPUT
+ *    The following functions handle input that arrives from
+ *    the TTY.	It recognizes PPP frames and either hands them
+ *    to the network layer or queues them for delivery to a
+ *    user process reading this TTY.
+ *************************************************************/
+
+/*
+ * Callback function from tty driver. Return the amount of space left
+ * in the receiver's buffer to decide if remote transmitter is to be
+ * throttled.
+ */
+
+static int
+ppp_tty_room (struct tty_struct *tty)
+{
+	return 65536;	    /* We can handle an infinite amount of data. :-) */
+}
+
+/*
+ * Callback function when data is available at the tty driver.
+ */
+
+static void
+ppp_tty_receive (struct tty_struct *tty, const u_char * data,
+		 char *flags, int count)
+{
+	register struct ppp *ppp = tty2ppp (tty);
+	register struct ppp_buffer *buf = NULL;
+	u_char chr;
+/*
+ * Fetch the pointer to the buffer. Be careful about race conditions.
+ */
+	if (ppp != NULL)
+		buf = ppp->rbuf;
+
+	if (buf == NULL)
+		return;
+/*
+ * Verify the table pointer and ensure that the line is
+ * still in PPP discipline.
+ */
+	if (ppp->magic != PPP_MAGIC) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_DEBUG
+				"PPP: handler called but couldn't find "
+				"PPP struct.\n");
+		return;
+	}
+	CHECK_PPP_VOID ();
+/*
+ * Print the buffer if desired
+ */
+	if (ppp->flags & SC_LOG_RAWIN)
+		ppp_print_buffer ("receive buffer", data, count);
+/*
+ * Collect the character and error condition for the character. Set the toss
+ * flag for the first character error.
+ */
+	while (count-- > 0) {
+		ppp->bytes_rcvd++;
+		chr = *data++;
+		if (flags) {
+			if (*flags && ppp->toss == 0)
+				ppp->toss = *flags;
+			++flags;
+		}
+/*
+ * Set the flags for 8 data bits and no parity.
+ *
+ * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
+ * so that the normal processing would have all flags set at the end of the
+ * session. A missing flag bit would denote an error condition.
+ */
+
+#ifdef CHECK_CHARACTERS
+		if (chr & 0x80)
+			ppp->flags |= SC_RCV_B7_1;
+		else
+			ppp->flags |= SC_RCV_B7_0;
+
+		if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))
+			ppp->flags |= SC_RCV_ODDP;
+		else
+			ppp->flags |= SC_RCV_EVNP;
+#endif
+/*
+ * Branch on the character. Process the escape character. The sequence ESC ESC
+ * is defined to be ESC.
+ */
+		switch (chr) {
+		case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
+			ppp->escape = PPP_TRANS;
+			break;
+/*
+ * FLAG. This is the end of the block. If the block terminated by ESC FLAG,
+ * then the block is to be ignored. In addition, characters before the very
+ * first FLAG are also tossed by this procedure.
+ */
+		case PPP_FLAG:	/* PPP_FLAG: end of frame */
+			ppp->stats.ppp_ibytes += ppp->rbuf->count;
+			if (ppp->escape)
+				ppp->toss |= 0x80;
+/*
+ * Process frames which are not to be ignored. If the processing failed,
+ * then clean up the VJ tables.
+ */
+			if ((ppp->toss & 0x80) != 0 ||
+			    ppp_doframe (ppp) == 0) {
+				slhc_toss (ppp->slcomp);
+			}
+/*
+ * Reset all indicators for the new frame to follow.
+ */
+			buf->count  = 0;
+			buf->fcs    = PPP_INITFCS;
+			ppp->escape = 0;
+			ppp->toss   = 0;
+			break;
+/*
+ * All other characters in the data come here. If the character is in the
+ * receive mask then ignore the character.
+ */
+		default:
+			if (in_rmap (ppp, chr))
+				break;
+/*
+ * Adjust the character and if the frame is to be discarded then simply
+ * ignore the character until the ending FLAG is received.
+ */
+			chr ^= ppp->escape;
+			ppp->escape = 0;
+
+			if (ppp->toss != 0)
+				break;
+/*
+ * If the count sent is within reason then store the character, bump the
+ * count, and update the FCS for the character.
+ */
+			if (buf->count < buf->size) {
+				buf_base (buf)[buf->count++] = chr;
+				buf->fcs = PPP_FCS (buf->fcs, chr);
+				break;
+			}
+/*
+ * The peer sent too much data. Set the flags to discard the current frame
+ * and wait for the re-synchronization FLAG to be sent.
+ */
+			ppp->stats.ppp_ierrors++;
+			ppp->toss |= 0xC0;
+			break;
+		}
+	}
+}
+
+/*
+ * Put the input frame into the networking system for the indicated protocol
+ */
+
+static int
+ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+{
+	sk_buff *skb = dev_alloc_skb (count);
+/*
+ * Generate a skb buffer for the new frame.
+ */
+	if (skb == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+			 "ppp_do_ip: packet dropped on %s (no memory)!\n",
+			 ppp2dev (ppp)->name);
+		return 0;
+	}
+/*
+ * Move the received data from the input buffer to the skb buffer.
+ */
+	skb->dev = ppp2dev (ppp);	/* We are the device */
+#if USE_SKB_PROTOCOL == 0
+	skb->len = count;
+#else
+	skb->protocol = proto;
+	skb->mac.raw  = skb_data(skb);
+#endif
+	memcpy (skb_put(skb,count), data, count);	/* move data */
+/*
+ * Tag the frame and kick it to the proper receive routine
+ */
+	skb->free = 1;
+	ppp->ddinfo.recv_idle = jiffies;
+	netif_rx (skb);
+	return 1;
+}
+
+/*
+ * Process the receipt of an IP frame
+ */
+
+static int
+rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+{
+	if (ppp2dev (ppp)->flags & IFF_UP) {
+		if (count > 0)
+			return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
+	}
+	return 0;
+}
+
+/*
+ * Process the receipt of an IPX frame
+ */
+
+static int
+rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+{
+#ifdef NEW_SKBUFF
+	if (ppp2dev (ppp)->flags & IFF_UP) {
+		if (count > 0)
+			return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
+	} else
+#endif
+	return 0;
+}
+
+/*
+ * Process the receipt of an VJ Compressed frame
+ */
+
+static int
+rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto,
+		    u_char *data, int count)
+{
+	if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+		int new_count = slhc_uncompress (ppp->slcomp, data, count);
+		if (new_count >= 0) {
+			return rcv_proto_ip (ppp, PPP_IP, data, new_count);
+		}
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_NOTICE
+				"ppp: error in VJ decompression\n");
+	}
+	return 0;
+}
+
+/*
+ * Process the receipt of an VJ Un-compressed frame
+ */
+
+static int
+rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto,
+		      u_char *data, int count)
+{
+	if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+		if (slhc_remember (ppp->slcomp, data, count) > 0) {
+			return rcv_proto_ip (ppp, PPP_IP, data, count);
+		}
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_NOTICE
+				"ppp: error in VJ memorizing\n");
+	}
+	return 0;
+}
+
+/*
+ * Receive all unclassified protocols.
+ */
+
+static int
+rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
+		   u_char *data, int len)
+{
+	int totlen;
+	register int current_idx;
+
+#define PUTC(c)						 \
+{							 \
+    buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \
+    current_idx &= ppp->ubuf->size;			 \
+    if (current_idx == ppp->ubuf->tail)			 \
+	    goto failure;				 \
+}
+
+/*
+ * The total length includes the protocol data.
+ * Lock the user information buffer.
+ */
+	if (set_bit (0, &ppp->ubuf->locked)) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_DEBUG
+				"ppp_us_queue: can't get lock\n");
+	} else {
+		current_idx = ppp->ubuf->head;
+/*
+ * Insert the buffer length (not counted), the protocol, and the data
+ */
+		totlen = len + 2;
+		PUTC (totlen >> 8);
+		PUTC (totlen);
+
+		PUTC (proto >> 8);
+		PUTC (proto);
+
+		totlen -= 2;
+		while (totlen-- > 0) {
+			PUTC (*data++);
+		}
+#undef PUTC
+/*
+ * The frame is complete. Update the head pointer and wakeup the pppd
+ * process.
+ */
+		ppp->ubuf->head = current_idx;
+
+		clear_bit (0, &ppp->ubuf->locked);
+		wake_up_interruptible (&ppp->read_wait);
+		if (ppp->tty->fasync != NULL)
+			kill_fasync (ppp->tty->fasync, SIGIO);
+
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_INFO
+				"ppp: successfully queued %d bytes, flags = %x\n",
+				len + 2, ppp->flags);
+
+		return 1;
+/*
+ * The buffer is full. Unlock the header
+ */
+failure:
+		clear_bit (0, &ppp->ubuf->locked);
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_INFO
+				"ppp_us_queue: ran out of buffer space.\n");
+	}
+/*
+ * Discard the frame. There are no takers for this protocol.
+ */
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_WARNING
+			"ppp: dropping packet on the floor.\n");
+	slhc_toss (ppp->slcomp);
+	return 0;
+}
+
+/*
+ * Handle a CCP packet.
+ *
+ * The CCP packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * immediate or the compressors will become confused on the peer.
+ */
+
+static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
+{
+	int slen    = CCP_LENGTH(dp);
+	u_char *opt = dp   + CCP_HDRLEN;
+	int opt_len = slen - CCP_HDRLEN;
+
+	if (slen > len)
+		return;
+
+	switch (CCP_CODE(dp)) {
+	case CCP_CONFREQ:
+	case CCP_TERMREQ:
+	case CCP_TERMACK:
+/*
+ * CCP must be going down - disable compression
+ */
+		if (ppp->flags & SC_CCP_UP) {
+			ppp->flags &= ~(SC_CCP_UP   |
+					SC_COMP_RUN |
+					SC_DECOMP_RUN);
+		}
+		break;
+
+	case CCP_CONFACK:
+		if ((ppp->flags & SC_CCP_OPEN) == 0)
+			break;
+		if (ppp->flags & SC_CCP_UP)
+			break;
+		if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN))
+			break;
+		if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
+			break;
+/*
+ * we're agreeing to send compressed packets.
+ */
+		if (!rcvd) {
+			if (ppp->sc_xc_state == NULL)
+				break;
+
+			if ((*ppp->sc_xcomp->comp_init)
+			    (ppp->sc_xc_state,
+			     opt,
+			     opt_len,
+			     ppp2dev (ppp)->base_addr,
+			     0,
+			     ppp->flags & SC_DEBUG))
+				ppp->flags |= SC_COMP_RUN;
+			break;
+		}
+/*
+ * peer is agreeing to send compressed packets.
+ */
+		if (ppp->sc_rc_state == NULL)
+			break;
+
+		if ((*ppp->sc_rcomp->decomp_init)
+		    (ppp->sc_rc_state,
+		     opt,
+		     opt_len,
+		     ppp2dev (ppp)->base_addr,
+		     0,
+		     ppp->mru,
+		     ppp->flags & SC_DEBUG)) {
+			ppp->flags |= SC_DECOMP_RUN;
+			ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
+		}
+		break;
+/*
+ * The protocol sequence is complete at this end
+ */
+	case CCP_RESETACK:
+		if ((ppp->flags & SC_CCP_UP) == 0)
+			break;
+
+		if (!rcvd) {
+			if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN))
+				(*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
+		} else {
+			if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
+			      (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
+				ppp->flags &= ~SC_DC_ERROR;
+			}
+		}
+		break;
+	}
+}
+
+static int
+rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len)
+{
+	ppp_proto_ccp (ppp, dp, len, 1);
+	return rcv_proto_unknown (ppp, proto, dp, len);
+}
+
+/*
+ * Handle a LQR packet.
+ *
+ * The LQR packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * performed to append the current data to the end of the frame.
+ */
+
+static int
+rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
+{
+#if 0 /* until support is in the pppd process don't corrupt the reject. */
+	register u_char *p;
+	if (len > 8) {
+		if (len < 48)
+			memset (&data [len], '\0', 48 - len);
+/*
+ * Fill in the fields from the driver data
+ */
+		p = &data [48];
+		p = store_long (p, ++ppp->stats.ppp_ilqrs);
+		p = store_long (p, ppp->stats.ppp_ipackets);
+		p = store_long (p, ppp->stats.ppp_discards);
+		p = store_long (p, ppp->stats.ppp_ierrors);
+		p = store_long (p, ppp->stats.ppp_ioctects + len);
+
+		len = 68;
+	}
+#endif
+/*
+ * Pass the frame to the pppd daemon.
+ */
+	return rcv_proto_unknown (ppp, proto, data, len);
+}
+
+/* on entry, a received frame is in ppp->rbuf.bufr
+   check it and dispose as appropriate */
+
+static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count)
+{
+	u_short		proto = PPP_PROTOCOL (data);
+	ppp_proto_type  *proto_ptr;
+/*
+ * Ignore empty frames
+ */
+	if (count <= 4)
+		return;
+/*
+ * Count the frame and print it
+ */
+	++ppp->stats.ppp_ipackets;
+	if (ppp->flags & SC_LOG_INPKT)
+		ppp_print_buffer ("receive frame", data, count);
+/*
+ * Find the procedure to handle this protocol. The last one is marked
+ * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
+ */
+	proto_ptr = proto_list;
+	while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
+		++proto_ptr;
+/*
+ * Update the appropriate statistic counter.
+ */
+	if ((*proto_ptr->func) (ppp, proto,
+				&data[PPP_HARD_HDR_LEN],
+				count - PPP_HARD_HDR_LEN))
+		ppp->stats.ppp_ioctects += count;
+	else
+		++ppp->stats.ppp_discards;
+}
+
+/* on entry, a received frame is in ppp->rbuf.bufr
+   check it and dispose as appropriate */
+
+static int
+ppp_doframe (struct ppp *ppp)
+{
+	u_char	*data = buf_base (ppp->rbuf);
+	int	count = ppp->rbuf->count;
+	int	addr, ctrl, proto;
+	int	new_count;
+	u_char *new_data;
+/*
+ * If there is a pending error from the receiver then log it and discard
+ * the damaged frame.
+ */
+	if (ppp->toss) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING
+				"ppp_toss: tossing frame, reason = %d\n",
+				ppp->toss);
+		ppp->stats.ppp_ierrors++;
+		return 0;
+	}
+/*
+ * An empty frame is ignored. This occurs if the FLAG sequence precedes and
+ * follows each frame.
+ */
+	if (count == 0)
+		return 1;
+/*
+ * Generate an error if the frame is too small.
+ */
+	if (count < PPP_HARD_HDR_LEN) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING
+				"ppp: got runt ppp frame, %d chars\n", count);
+		slhc_toss (ppp->slcomp);
+		ppp->stats.ppp_ierrors++;
+		return 1;
+	}
+/*
+ * Verify the CRC of the frame and discard the CRC characters from the
+ * end of the buffer.
+ */
+	if (ppp->rbuf->fcs != PPP_GOODFCS) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING
+				"ppp: frame with bad fcs, excess = %x\n",
+				ppp->rbuf->fcs ^ PPP_GOODFCS);
+		ppp->stats.ppp_ierrors++;
+		return 0;
+	}
+	count -= 2;		/* ignore the fcs characters */
+/*
+ * Ignore the leading ADDRESS and CONTROL fields in the frame.
+ */
+	addr   = PPP_ALLSTATIONS;
+	ctrl   = PPP_UI;
+
+	if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
+		data  += 2;
+		count -= 2;
+	}
+/*
+ * Obtain the protocol from the frame
+ */
+	proto = (u_short) *data++;
+	if ((proto & 1) == 0) {
+		proto = (proto << 8) | (u_short) *data++;
+		--count;
+	}
+/*
+ * Rewrite the header with the full information. This may encroach upon
+ * the 'filler' area in the buffer header. This is the purpose for the
+ * filler.
+ */
+	*(--data) = proto;
+	*(--data) = proto >> 8;
+	*(--data) = ctrl;
+	*(--data) = addr;
+	count    += 3;
+/*
+ * Process the active decompressor.
+ */
+	if ((ppp->sc_rc_state != (void *) 0) &&
+	    (ppp->flags & SC_DECOMP_RUN)     &&
+	    ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
+		if (proto == PPP_COMP) {
+/*
+ * If the frame is compressed then decompress it.
+ */
+			new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
+			if (new_data == NULL) {
+				if (ppp->flags & SC_DEBUG)
+					printk (KERN_ERR
+						"ppp_doframe: no memory\n");
+				slhc_toss (ppp->slcomp);
+				(*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+							  data,
+							  count);
+				return 1;
+			}
+/*
+ * Decompress the frame
+ */
+			new_count = bsd_decompress (ppp->sc_rc_state,
+						    data,
+						    count,
+						    new_data,
+						    ppp->mru + 4);
+			switch (new_count) {
+			default:
+				ppp_doframe_lower (ppp, new_data, new_count);
+				kfree (new_data);
+				return 1;
+
+			case DECOMP_OK:
+				break;
+
+			case DECOMP_ERROR:
+				ppp->flags |= SC_DC_ERROR;
+				break;
+
+			case DECOMP_FATALERROR:
+				ppp->flags |= SC_DC_FERROR;
+				break;
+			}
+/*
+ * Log the error condition and discard the frame.
+ */
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_ERR
+					"ppp_proto_comp: "
+					"decompress err %d\n", new_count);
+			kfree (new_data);
+			slhc_toss (ppp->slcomp);
+			return 1;
+		}
+/*
+ * The frame is not special. Pass it through the compressor without
+ * actually compressing the data
+ */
+		(*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+					  data,
+					  count);
+	}
+/*
+ * Process the uncompressed frame.
+ */
+	ppp_doframe_lower (ppp, data, count);
+	return 1;
+}
+
+/*************************************************************
+ * LINE DISCIPLINE SUPPORT
+ *    The following functions form support user programs
+ *    which read and write data on a TTY with the PPP line
+ *    discipline.  Reading is done from a circular queue,
+ *    filled by the lower TTY levels.
+ *************************************************************/
+
+/* read a PPP frame from the us_rbuff circular buffer,
+   waiting if necessary
+*/
+
+static int
+ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
+	      unsigned int nr)
+{
+	struct ppp *ppp = tty2ppp (tty);
+	u_char c;
+	int len, indx;
+
+#define GETC(c)						\
+{							\
+	c = buf_base (ppp->ubuf) [ppp->ubuf->tail++];	\
+	ppp->ubuf->tail &= ppp->ubuf->size;		\
+}
+
+/*
+ * Validate the pointer to the PPP structure
+ */
+	if (!ppp)
+		return -EIO;
+
+	if (ppp->magic != PPP_MAGIC)
+		return -EIO;
+
+	CHECK_PPP (-ENXIO);
+
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_DEBUG
+			"ppp_tty_read: called buf=%p nr=%u\n",
+			buf, nr);
+/*
+ * Acquire the read lock.
+ */
+	for (;;) {
+		ppp = tty2ppp (tty);
+		if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
+			return 0;
+
+		if (set_bit (0, &ppp->ubuf->locked) != 0) {
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_DEBUG
+				     "ppp_tty_read: sleeping(ubuf)\n");
+
+			current->timeout = 0;
+			current->state   = TASK_INTERRUPTIBLE;
+			schedule ();
+
+			if (current->signal & ~current->blocked)
+				return -EINTR;
+			continue;
+		}
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * user has access to the pages for the total buffer length.
+ */
+		indx = verify_area (VERIFY_WRITE, buf, nr);
+		if (indx != 0)
+			return (indx);
+/*
+ * Fetch the length of the buffer from the first two bytes.
+ */
+		if (ppp->ubuf->head == ppp->ubuf->tail)
+			len = 0;
+		else {
+			GETC (c);
+			len = c << 8;
+			GETC (c);
+			len += c;
+		}
+/*
+ * If there is no length then wait for the data to arrive.
+ */
+		if (len == 0) {
+			/* no data */
+			clear_bit (0, &ppp->ubuf->locked);
+			if (file->f_flags & O_NONBLOCK) {
+				if (ppp->flags & SC_DEBUG)
+					printk (KERN_DEBUG
+						"ppp_tty_read: no data "
+						"(EWOULDBLOCK)\n");
+				return -EWOULDBLOCK;
+			}
+			current->timeout = 0;
+
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_DEBUG
+					"ppp_tty_read: sleeping(read_wait)\n");
+
+			interruptible_sleep_on (&ppp->read_wait);
+			if (current->signal & ~current->blocked)
+				return -EINTR;
+			continue;
+		}
+/*
+ * Reset the time of the last read operation.
+ */
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
+/*
+ * Ensure that the frame will fit within the caller's buffer. If not, then
+ * discard the frame from the input buffer and return an error to the caller.
+ */
+		if (len + 2 > nr) {
+			/* Can't copy it, update us_rbuff_head */
+
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_DEBUG
+				"ppp: read of %u bytes too small for %d "
+				"frame\n", nr, len + 2);
+			ppp->ubuf->tail += len;
+			ppp->ubuf->tail &= ppp->ubuf->size;
+			clear_bit (0, &ppp->ubuf->locked);
+			ppp->stats.ppp_ierrors++;
+			return -EOVERFLOW;
+		}
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * page tables are proper.
+ */
+		indx = verify_area (VERIFY_WRITE, buf, len + 2);
+		if (indx != 0) {
+			ppp->ubuf->tail += len;
+			ppp->ubuf->tail &= ppp->ubuf->size;
+			clear_bit (0, &ppp->ubuf->locked);
+			return (indx);
+		}
+/*
+ * Fake the insertion of the ADDRESS and CONTROL information because these
+ * were not saved in the buffer.
+ */
+		put_byte_user (PPP_ALLSTATIONS, buf++);
+		put_byte_user (PPP_UI,          buf++);
+
+		indx = len;
+/*
+ * Copy the received data from the buffer to the caller's area.
+ */
+		while (indx-- > 0) {
+			GETC (c);
+			put_byte_user (c, buf);
+			++buf;
+		}
+/*
+ * Release the lock and return the character count in the buffer area.
+ */
+		clear_bit (0, &ppp->ubuf->locked);
+		len += 2; /* Account for ADDRESS and CONTROL bytes */
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_DEBUG
+				"ppp_tty_read: passing %d bytes up\n", len);
+		return len;
+	}
+#undef GETC
+}
+
+/* stuff a character into the transmit buffer, using PPP's way of escaping
+   special characters.
+   also, update fcs to take account of new character */
+
+extern inline void
+ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
+		register u_char chr)
+{
+/*
+ * The buffer should not be full.
+ */
+	if (ppp->flags & SC_DEBUG) {
+		if ((buf->count < 0) || (buf->count > 3000))
+			printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+				(unsigned int) buf->count,
+				(unsigned int) chr);
+	}
+/*
+ * Update the FCS and if the character needs to be escaped, do it.
+ */
+	buf->fcs = PPP_FCS (buf->fcs, chr);
+	if (in_xmap (ppp, chr)) {
+		chr ^= PPP_TRANS;
+		ins_char (buf, PPP_ESCAPE);
+	}
+/*
+ * Add the character to the buffer.
+ */
+	ins_char (buf, chr);
+}
+
+/*
+ * Procedure to encode the data with the proper escapement and send the
+ * data to the remote system.
+ */
+
+static void
+ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
+		    u_char *data, int count, int non_ip)
+{
+	unsigned short int write_fcs;
+	int     address, control;
+	int	proto;
+/*
+ * Insert the leading FLAG character
+ */
+	buf->count = 0;
+
+	if (non_ip || flag_time == 0)
+		ins_char (buf, PPP_FLAG);
+	else {
+		if (jiffies - ppp->last_xmit > flag_time)
+			ins_char (buf, PPP_FLAG);
+	}
+	ppp->last_xmit = jiffies;
+	buf->fcs       = PPP_INITFCS;
+/*
+ * Emit the address/control information if needed
+ */
+	address = PPP_ADDRESS  (data);
+	control = PPP_CONTROL  (data);
+	proto   = PPP_PROTOCOL (data);
+
+	if (address != PPP_ALLSTATIONS ||
+	    control != PPP_UI ||
+	    (ppp->flags & SC_COMP_AC) == 0) {
+		ppp_stuff_char (ppp, buf, address);
+		ppp_stuff_char (ppp, buf, control);
+	}
+/*
+ * Emit the protocol (compressed if possible)
+ */
+	if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
+		ppp_stuff_char (ppp, buf, proto >> 8);
+
+	ppp_stuff_char (ppp, buf, proto);
+/*
+ * Insert the data
+ */
+	data  += 4;
+	count -= 4;
+
+	while (count-- > 0)
+		ppp_stuff_char (ppp, buf, *data++);
+/*
+ * Add the trailing CRC and the final flag character
+ */
+	write_fcs = buf->fcs ^ 0xFFFF;
+	ppp_stuff_char (ppp, buf, write_fcs);
+	ppp_stuff_char (ppp, buf, write_fcs >> 8);
+
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
+			write_fcs);
+/*
+ * Add the trailing flag character
+ */
+	ins_char (buf, PPP_FLAG);
+/*
+ * Print the buffer
+ */
+	if (ppp->flags & SC_LOG_FLUSH)
+		ppp_print_buffer ("ppp flush", buf_base (buf),
+				  buf->count);
+	else {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_DEBUG
+				"ppp_dev_xmit: writing %d chars\n",
+				buf->count);
+	}
+/*
+ * Send the block to the tty driver.
+ */
+	ppp->stats.ppp_obytes += buf->count;
+	ppp_kick_tty (ppp, buf);
+}
+
+/*
+ * Send an frame to the remote with the proper bsd compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ *        1 if frame must be re-queued for later driver support.
+ */
+
+static int
+ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
+		    u_char *data, int count)
+{
+	int	proto;
+	int     address, control;
+	u_char *new_data;
+	int     new_count;
+/*
+ * Print the buffer
+ */
+	if (ppp->flags & SC_LOG_OUTPKT)
+		ppp_print_buffer ("write frame", data, count);
+/*
+ * Determine if the frame may be compressed. Attempt to compress the
+ * frame if possible.
+ */
+	proto   = PPP_PROTOCOL (data);
+	address = PPP_ADDRESS  (data);
+	control = PPP_CONTROL  (data);
+
+	if (((ppp->flags & SC_COMP_RUN) != 0)	&&
+	    (ppp->sc_xc_state != (void *) 0)	&&
+	    (address == PPP_ALLSTATIONS)	&&
+	    (control == PPP_UI)			&&
+	    (proto != PPP_LCP)			&&
+	    (proto != PPP_CCP)) {
+		new_data = kmalloc (count, GFP_ATOMIC);
+		if (new_data == NULL) {
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_ERR
+					"ppp_dev_xmit_frame: no memory\n");
+			return 1;
+		}
+
+		new_count = bsd_compress (ppp->sc_xc_state,
+					  data,
+					  new_data,
+					  count,
+					  count);
+
+		if (new_count > 0) {
+			++ppp->stats.ppp_opackets;
+			ppp->stats.ppp_ooctects += new_count;
+
+			ppp_dev_xmit_lower (ppp, buf, new_data,
+					    new_count, 0);
+			kfree (new_data);
+			return 0;
+		}
+/*
+ * The frame could not be compressed.
+ */
+		kfree (new_data);
+	}
+/*
+ * The frame may not be compressed. Update the statistics before the
+ * count field is destroyed. The frame will be transmitted.
+ */
+	++ppp->stats.ppp_opackets;
+	ppp->stats.ppp_ooctects += count;
+/*
+ * Go to the escape encoding
+ */
+	ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
+	return 0;
+}
+
+/*
+ * Revise the tty frame for specific protocols.
+ */
+
+static int
+send_revise_frame (register struct ppp *ppp, u_char *data, int len)
+{
+	u_char *p;
+
+	switch (PPP_PROTOCOL (data)) {
+/*
+ * Update the LQR frame with the current MIB information. This saves having
+ * the daemon read old MIB data from the driver.
+ */
+	case PPP_LQR:
+		len = 48;			/* total size of this frame */
+		p   = (u_char *) &data [40];	/* Point to last two items. */
+		p   = store_long (p, ppp->stats.ppp_opackets + 1);
+		p   = store_long (p, ppp->stats.ppp_ooctects + len);
+		break;
+/*
+ * Outbound compression frames
+ */
+	case PPP_CCP:
+		ppp_proto_ccp (ppp,
+			       data + PPP_HARD_HDR_LEN,
+			       len  - PPP_HARD_HDR_LEN,
+			       0);
+		break;
+/*
+ * All other frame types
+ */
+	default:
+		break;
+	}
+
+	return len;
+}
+
+/*
+ * write a frame with NR chars from BUF to TTY
+ * we have to put the FCS field on ourselves
+ */
+
+static int
+ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data,
+	       unsigned int count)
+{
+	struct ppp *ppp = tty2ppp (tty);
+	u_char *new_data;
+	int status;
+/*
+ * Verify the pointer to the PPP data and that the tty is still in PPP mode.
+ */
+	if (!ppp)
+		return -EIO;
+
+	if (ppp->magic != PPP_MAGIC)
+		return -EIO;
+
+	CHECK_PPP (-ENXIO);
+/*
+ * Ensure that the caller does not wish to send too much.
+ */
+	if (count > PPP_MTU) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING
+				"ppp_tty_write: truncating user packet "
+				"from %u to mtu %d\n", count, PPP_MTU);
+		count = PPP_MTU;
+	}
+/*
+ * Allocate a buffer for the data and fetch it from the user space.
+ */
+	new_data = kmalloc (count, GFP_KERNEL);
+	if (new_data == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+				"ppp_tty_write: no memory\n");
+		return 0;
+	}
+/*
+ * lock this PPP unit so we will be the only writer;
+ * sleep if necessary
+ */
+	while (lock_buffer (ppp->tbuf) != 0) {
+		current->timeout = 0;
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
+		interruptible_sleep_on (&ppp->write_wait);
+
+		ppp = tty2ppp (tty);
+		if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
+			kfree (new_data);
+			return 0;
+		}
+
+		if (current->signal & ~current->blocked) {
+			kfree (new_data);
+			return -EINTR;
+		}
+	}
+/*
+ * Ensure that the caller's buffer is valid.
+ */
+	status = verify_area (VERIFY_READ, data, count);
+	if (status != 0) {
+		kfree (new_data);
+		ppp->tbuf->locked = 0;
+		return status;
+	}
+
+	memcpy_fromfs (new_data, data, count);
+/*
+ * Change the LQR frame
+ */
+	count = send_revise_frame (ppp, new_data, count);
+/*
+ * Send the data
+ */
+	ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+	kfree (new_data);
+	return (int) count;
+}
+
+/*
+ * Process the BSD compression IOCTL event for the tty device.
+ */
+
+static int
+ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
+{
+	struct compressor *cp;
+	struct ppp_option_data data;
+	int error;
+	int nb;
+	u_char *ptr;
+	u_char ccp_option[CCP_MAX_OPTION_LENGTH];
+/*
+ * Fetch the compression parameters
+ */
+	error = verify_area (VERIFY_READ, odp, sizeof (data));
+	if (error == 0) {
+		memcpy_fromfs (&data, odp, sizeof (data));
+		nb  = data.length;
+		ptr = data.ptr;
+		if ((unsigned long) nb >= (unsigned long)CCP_MAX_OPTION_LENGTH)
+			nb = CCP_MAX_OPTION_LENGTH;
+	
+		error = verify_area (VERIFY_READ, ptr, nb);
+	}
+
+	if (error != 0)
+		return error;
+
+	memcpy_fromfs (ccp_option, ptr, nb);
+
+	if (ccp_option[1] < 2)	/* preliminary check on the length byte */
+		return (-EINVAL);
+
+	cp = find_compressor ((int) (unsigned) (unsigned char) ccp_option[0]);
+	if (cp != (struct compressor *) 0) {
+		/*
+		 * Found a handler for the protocol - try to allocate
+		 * a compressor or decompressor.
+		 */
+		error = 0;
+		if (data.transmit) {
+			if (ppp->sc_xc_state != NULL)
+				(*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+
+			ppp->sc_xcomp    = cp;
+			ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+
+			if (ppp->sc_xc_state == NULL) {
+				if (ppp->flags & SC_DEBUG)
+					printk("ppp%ld: comp_alloc failed\n",
+					       ppp2dev (ppp)->base_addr);
+				error = -ENOBUFS;
+			}
+			ppp->flags &= ~SC_COMP_RUN;
+		} else {
+			if (ppp->sc_rc_state != NULL)
+				(*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
+			ppp->sc_rcomp    = cp;
+			ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
+			if (ppp->sc_rc_state == NULL) {
+				if (ppp->flags & SC_DEBUG)
+					printk("ppp%ld: decomp_alloc failed\n",
+					       ppp2dev (ppp)->base_addr);
+				error = ENOBUFS;
+			}
+			ppp->flags &= ~SC_DECOMP_RUN;
+		}
+		return (error);
+	}
+
+	if (ppp->flags & SC_DEBUG)
+		printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
+		       ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
+		       ccp_option[2], nb);
+	return (-EINVAL);	/* no handler found */
+}
+
+/*
+ * Process the IOCTL event for the tty device.
+ */
+
+static int
+ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
+	       unsigned long param3)
+{
+	struct ppp *ppp = tty2ppp (tty);
+	register int temp_i = 0;
+	int error;
+/*
+ * Verify the status of the PPP device.
+ */
+	if (!ppp)
+		return -EBADF;
+
+	if (ppp->magic != PPP_MAGIC)
+		return -EBADF;
+
+	CHECK_PPP (-ENXIO);
+/*
+ * The user must have an euid of root to do these requests.
+ */
+	if (!suser ())
+		return -EPERM;
+/*
+ * Set the MRU value
+ */
+	switch (param2) {
+	case PPPIOCSMRU:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			temp_i = get_int_user ((int *) param3);
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				 "ppp_tty_ioctl: set mru to %x\n", temp_i);
+
+			if (ppp->mru != temp_i)
+				ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
+		}
+		break;
+/*
+ * Fetch the flags
+ */
+	case PPPIOCGFLAGS:
+		error = verify_area (VERIFY_WRITE, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			temp_i = (ppp->flags & SC_MASK);
+#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
+			temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
+				  SC_RCV_ODDP | SC_RCV_EVNP;
 #endif
+			put_long_user ((long) temp_i, param3);
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_DEBUG
+				"ppp_tty_ioctl: get flags: addr %lx flags "
+				"%x\n", param3, temp_i);
+		}
+		break;
+/*
+ * Set the flags for the various options
+ */
+	case PPPIOCSFLAGS:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			temp_i  = get_int_user (param3) & SC_MASK;
+			temp_i |= (ppp->flags & ~SC_MASK);
+
+			if ((ppp->flags & SC_CCP_OPEN) &&
+			    (temp_i & SC_CCP_OPEN) == 0)
+				ppp_ccp_closed (ppp);
+
+			if ((ppp->flags | temp_i) & SC_DEBUG)
+				printk (KERN_INFO
+			       "ppp_tty_ioctl: set flags to %x\n", temp_i);
+			ppp->flags = temp_i;
+		}
+		break;
+/*
+ * Set the compression mode
+ */
+	case PPPIOCSCOMPRESS:
+		error = ppp_set_compression (ppp,
+					    (struct ppp_option_data *) param3);
+		break;
+/*
+ * Retrieve the transmit async map
+ */
+	case PPPIOCGASYNCMAP:
+		error = verify_area (VERIFY_WRITE, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			put_long_user (ppp->xmit_async_map[0], param3);
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				     "ppp_tty_ioctl: get asyncmap: addr "
+				     "%lx asyncmap %lx\n",
+				     param3,
+				     (unsigned long) ppp->xmit_async_map[0]);
+		}
+		break;
+/*
+ * Set the transmit async map
+ */
+	case PPPIOCSASYNCMAP:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			ppp->xmit_async_map[0] = get_long_user (param3);
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				     "ppp_tty_ioctl: set xmit asyncmap %lx\n",
+				     (unsigned long) ppp->xmit_async_map[0]);
+		}
+		break;
+/*
+ * Set the receive async map
+ */
+	case PPPIOCSRASYNCMAP:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			ppp->recv_async_map = get_long_user (param3);
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				     "ppp_tty_ioctl: set rcv asyncmap %lx\n",
+				     (unsigned long) ppp->recv_async_map);
+		}
+		break;
+/*
+ * Obtain the unit number for this device.
+ */
+	case PPPIOCGUNIT:
+		error = verify_area (VERIFY_WRITE, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			put_long_user (ppp2dev (ppp)->base_addr, param3);
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+					"ppp_tty_ioctl: get unit: %ld",
+					ppp2dev (ppp)->base_addr);
+		}
+		break;
+/*
+ * Set the debug level
+ */
+	case PPPIOCSDEBUG:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			temp_i  = (get_int_user (param3) & 0x1F) << 16;
+			temp_i |= (ppp->flags & ~0x1F0000);
+
+			if ((ppp->flags | temp_i) & SC_DEBUG)
+				printk (KERN_INFO
+			       "ppp_tty_ioctl: set flags to %x\n", temp_i);
+			ppp->flags = temp_i;
+		}
+		break;
+/*
+ * Get the debug level
+ */
+	case PPPIOCGDEBUG:
+		error = verify_area (VERIFY_WRITE, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			temp_i = (ppp->flags >> 16) & 0x1F;
+			put_long_user ((long) temp_i, param3);
+
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+					"ppp_tty_ioctl: get debug level %d\n",
+					temp_i);
+      		}
+		break;
+/*
+ * Get the times since the last send/receive frame operation
+ */
+	case PPPIOCGIDLE:
+		error = verify_area (VERIFY_WRITE, (void *) param3,
+				     sizeof (struct ppp_idle));
+		if (error == 0) {
+			struct ppp_idle cur_ddinfo;
+			unsigned long cur_jiffies = jiffies;
+
+			/* change absolute times to relative times. */
+			cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
+			cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
+			memcpy_tofs ((void *) param3, &cur_ddinfo,
+				     sizeof (cur_ddinfo));
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				"ppp_tty_ioctl: read demand dial info\n");
+		}
+		break;
+/*
+ * Retrieve the extended async map
+ */
+	case PPPIOCGXASYNCMAP:
+		error = verify_area (VERIFY_WRITE,
+				     (void *) param3,
+				     sizeof (ppp->xmit_async_map));
+		if (error == 0) {
+			memcpy_tofs ((void *) param3,
+				     ppp->xmit_async_map,
+				     sizeof (ppp->xmit_async_map));
+
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				"ppp_tty_ioctl: get xasyncmap: addr %lx\n",
+				param3);
+		}
+		break;
+/*
+ * Set the async extended map
+ */
+	case PPPIOCSXASYNCMAP:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (ppp->xmit_async_map));
+		if (error == 0) {
+			__u32 temp_tbl[8];
+
+			memcpy_fromfs (temp_tbl, (void *) param3,
+				       sizeof (ppp->xmit_async_map));
+			temp_tbl[1]  =  0x00000000;
+			temp_tbl[2] &= ~0x40000000;
+			temp_tbl[3] |=  0x60000000;
+
+			if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
+			    (temp_tbl[4] & temp_tbl[5]) != 0 ||
+			    (temp_tbl[6] & temp_tbl[7]) != 0)
+				error = -EINVAL;
+			else {
+				memcpy (ppp->xmit_async_map, temp_tbl,
+					sizeof (ppp->xmit_async_map));
+
+				if (ppp->flags & SC_DEBUG)
+					printk (KERN_INFO
+					"ppp_tty_ioctl: set xasyncmap\n");
+			}
+		}
+		break;
+/*
+ * Set the maximum VJ header compression slot number.
+ */
+	case PPPIOCSMAXCID:
+		error = verify_area (VERIFY_READ, (void *) param3,
+				     sizeof (temp_i));
+		if (error == 0) {
+			temp_i = get_int_user (param3) + 1;
+			if (ppp->flags & SC_DEBUG)
+				printk (KERN_INFO
+				     "ppp_tty_ioctl: set maxcid to %d\n",
+				     temp_i);
+			if (ppp->slcomp != NULL)
+				slhc_free (ppp->slcomp);
+			ppp->slcomp = slhc_init (16, temp_i);
+
+			if (ppp->slcomp == NULL) {
+				if (ppp->flags & SC_DEBUG)
+					printk (KERN_ERR
+					"ppp: no space for compression buffers!\n");
+				ppp_release (ppp);
+				error = -ENOMEM;
+			}
+		}
+		break;
+/*
+ * Allow users to read, but not set, the serial port parameters
+ */
+	case TCGETS:
+	case TCGETA:
+		error = n_tty_ioctl (tty, file, param2, param3);
+		break;
+/*
+ *  All other ioctl() events will come here.
+ */
+	default:
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+				"ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
+				param2,
+				param3);
+
+		error = -ENOIOCTLCMD;
+		break;
+	}
+	return error;
+}
+
+/*
+ * TTY callback.
+ *
+ * Process the select() statement for the PPP device.
+ */
+
+static int
+ppp_tty_select (struct tty_struct *tty, struct inode *inode,
+		struct file *filp, int sel_type, select_table * wait)
+{
+	struct ppp *ppp = tty2ppp (tty);
+	int result = 1;
+/*
+ * Verify the status of the PPP device.
+ */
+	if (!ppp)
+		return -EBADF;
+
+	if (ppp->magic != PPP_MAGIC)
+		return -EBADF;
+
+	CHECK_PPP (0);
+/*
+ * Branch on the type of select mode. A read request must lock the user
+ * buffer area.
+ */
+	switch (sel_type) {
+	case SEL_IN:
+		if (set_bit (0, &ppp->ubuf->locked) == 0) {
+			/* Test for the presence of data in the queue */
+			if (ppp->ubuf->head != ppp->ubuf->tail) {
+				clear_bit (0, &ppp->ubuf->locked);
+				break;
+			}
+			clear_bit (0, &ppp->ubuf->locked);
+		}		/* fall through */
+		/*
+ * Exceptions or read errors.
+ */
+	case SEL_EX:
+		/* Is this a pty link and the remote disconnected? */
+		if (tty->flags & (1 << TTY_SLAVE_CLOSED))
+			break;
+
+		/* Is this a local link and the modem disconnected? */
+		if (tty_hung_up_p (filp))
+			break;
+
+		select_wait (&ppp->read_wait, wait);
+		result = 0;
+		break;
+/*
+ * Write mode. A write is allowed if there is no current transmission.
+ */
+	case SEL_OUT:
+		if (ppp->tbuf->locked != 0) {
+			select_wait (&ppp->write_wait, wait);
+			result = 0;
+		}
+		break;
+	}
+	return result;
+}
+
+/*************************************************************
+ * NETWORK OUTPUT
+ *    This routine accepts requests from the network layer
+ *    and attempts to deliver the packets.
+ *    It also includes various routines we are compelled to
+ *    have to make the network layer work (arp, etc...).
+ *************************************************************/
+
+/*
+ * Callback from the network layer when the device goes up.
+ */
+
+static int
+ppp_dev_open (struct device *dev)
+{
+	struct ppp *ppp = dev2ppp (dev);
+
+	/* reset POINTOPOINT every time, since dev_close zaps it! */
+	dev->flags |= IFF_POINTOPOINT;
+
+	if (ppp2tty (ppp) == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+			"ppp: %s not connected to a TTY! can't go open!\n",
+			dev->name);
+		return -ENXIO;
+	}
+
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_INFO
+			"ppp: channel %s going up for IP packets!\n",
+			dev->name);
+
+	CHECK_PPP (-ENXIO);
+	return 0;
+}
+
+/*
+ * Callback from the network layer when the ppp device goes down.
+ */
+
+static int
+ppp_dev_close (struct device *dev)
+{
+	struct ppp *ppp = dev2ppp (dev);
+
+	if (ppp2tty (ppp) == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+			"ppp: %s not connected to a TTY! can't go down!\n",
+			dev->name);
+		return -ENXIO;
+	}
+/*
+ * We don't do anything about the device going down. It is not important
+ * for us.
+ */
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_INFO
+			"ppp: channel %s going down for IP packets!\n",
+			dev->name);
+	CHECK_PPP (-ENXIO);
+	return 0;
+}
+
+/*
+ * IOCTL operation to read the version of the driver.
+ */
+
+static int
+ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
+{
+        int error;
+	int len;
+	char *result;
+/*
+ * Must have write access to the buffer.
+ */
+	result = (char *) ifr->ifr_ifru.ifru_data;
+	len    = strlen (szVersion) + 1;
+	error  = verify_area (VERIFY_WRITE, result, len);
+/*
+ * Move the version data
+ */
+	if (error == 0)
+		memcpy_tofs (result, szVersion, len);
+
+	return error;
+}
+
+/*
+ * IOCTL to read the statistics for the pppstats program.
+ */
+
+static int
+ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+{
+	struct ppp_stats *result, temp;
+	int    error;
+/*
+ * Must have write access to the buffer.
+ */
+	result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+	error = verify_area (VERIFY_WRITE,
+			     result,
+			     sizeof (temp));
+/*
+ * Supply the information for the caller. First move the version data
+ * then move the ppp stats; and finally the vj stats.
+ */
+	memset (&temp, 0, sizeof(temp));
+	if (error == 0 && dev->flags & IFF_UP) {
+		memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
+		if (ppp->slcomp != NULL) {
+			temp.vj.vjs_packets    = ppp->slcomp->sls_o_compressed+
+						 ppp->slcomp->sls_o_uncompressed;
+			temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
+			temp.vj.vjs_searches   = ppp->slcomp->sls_o_searches;
+			temp.vj.vjs_misses     = ppp->slcomp->sls_o_misses;
+			temp.vj.vjs_errorin    = ppp->slcomp->sls_i_error;
+			temp.vj.vjs_tossed     = ppp->slcomp->sls_i_tossed;
+			temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
+			temp.vj.vjs_compressedin   = ppp->slcomp->sls_i_compressed;
+		}
+	}
+/*
+ * Move the data to the caller's buffer
+ */
+	if (error == 0)
+		memcpy_tofs (result, &temp, sizeof (temp));
+	return error;
+}
 
-/* on entry, a received frame is in ppp->rbuff
-   check it and dispose as appropriate */
-static void
-ppp_doframe(struct ppp *ppp)
-{
-  u_char *c = ppp->rbuff;
-  u_short proto;
-  int count = ppp->rcount;
-
-  /* forget it if we've already noticed an error */
-  if (ppp->toss) {
-    PRINTKN (1, (KERN_WARNING "ppp_toss: tossing frame, reason = %d\n",
-		 ppp->toss));
-    slhc_toss (ppp->slcomp);
-    ppp->stats.rerrors++;
-    return;
-  }
-
-  /* do this before printing buffer to avoid generating copious output */
-  if (count == 0)
-    return;
-
-  if (ppp_debug >= 3)
-    ppp_print_buffer ("receive frame", c, count, KERNEL_DS);
-
-  if (count < 4) {
-    PRINTKN (1,(KERN_WARNING "ppp: got runt ppp frame, %d chars\n", count));
-    slhc_toss (ppp->slcomp);
-    ppp->stats.runts++;
-    return;
-  }
-
-  /* check PPP error detection field */
-  if (!ppp_check_fcs(ppp)) {
-    PRINTKN (1,(KERN_WARNING "ppp: frame with bad fcs\n"));
-    slhc_toss (ppp->slcomp);
-    ppp->stats.rerrors++;
-    return;
-  }
-
-  count -= 2;			/* ignore last two characters */
-
-  /* now we have a good frame */
-  /* figure out the protocol field */
-  if ((c[0] == PPP_ADDRESS) && (c[1] == PPP_CONTROL)) {
-    c = c + 2;			/* ADDR/CTRL not compressed, so skip */
-    count -= 2;
-  }
-
-  proto = (u_short) *c++;		/* PROTO compressed */
-  if (proto & 1) {
-    count--;
-  } else {
-    proto = (proto << 8) | (u_short) *c++; /* PROTO uncompressed */
-    count -= 2;
-  }
-
-  /* Send the frame to the network if the ppp device is up */
-  if ((ppp->dev->flags & IFF_UP) && ppp_do_ip(ppp, proto, c, count)) {
-    ppp->ddinfo.ip_rjiffies = jiffies;
-    return;
-  }
-
-  /* If we got here, it has to go to a user process doing a read,
-     so queue it.
-
-     User process expects to get whole frame (for some reason), so
-     use count+2 so as to include FCS field. */
-
-  if (ppp_us_queue (ppp, proto, c, count+2)) {
-    ppp->ddinfo.nip_rjiffies = jiffies;
-    ppp->stats.rothers++;
-    return;
-  }
-
-  /* couldn't cope. */
-  PRINTKN (1,(KERN_WARNING
-	      "ppp: dropping packet on the floor: nobody could take it.\n"));
-  slhc_toss (ppp->slcomp);
-  ppp->stats.tossed++;
-}
-
-/* Examine packet at C, attempt to pass up to net layer. 
-   PROTO is the protocol field from the PPP frame.
-   Return 1 if could handle it, 0 otherwise.  */
-
-static int
-ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
-	  int count)
-{
-  int flags, done;
-  struct sk_buff *skb;
-
-  PRINTKN (4,(KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n",
-	      (int) proto, count, c[0]));
-
-  if (ppp_debug_netpackets) {
-    PRINTK (("KERN_DEBUG %s <-- proto %x len %d\n", ppp->dev->name,
-	     (int) proto, count));
-  }
-    
-  if (proto == PROTO_IP) {
-    ppp->stats.runcomp++;
-    goto sendit;
-  }
-
-  if ((proto == PROTO_VJCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) {
-    /* get space for uncompressing the header */
-    done = 0;
-    save_flags (flags);
-    cli();
-    if ((ppp->rhead + 80) < ppp->rend) {
-      ppp->rhead += 80;
-      ppp->rcount += 80;
-      done = 1;
-    }
-    restore_flags(flags);
-
-    if (! done)	{
-      PRINTKN (1,(KERN_NOTICE
-		  "ppp: no space to decompress VJ compressed TCP header.\n"));
-      ppp->stats.roverrun++;
-      slhc_toss (ppp->slcomp);
-      return 1;
-    }
-
-    count = slhc_uncompress(ppp->slcomp, c, count);
-    if (count <= 0) {
-      ppp->stats.rerrors++;
-      PRINTKN (1,(KERN_NOTICE "ppp: error in VJ decompression\n"));
-      slhc_toss (ppp->slcomp);
-      return 1;
-    }
-    ppp->stats.rcomp++;
-    goto sendit;
-  }
-  
-  if ((proto == PROTO_VJUNCOMP) && !(ppp->flags & SC_REJ_COMP_TCP)) {
-    if (slhc_remember(ppp->slcomp, c, count) <= 0) {
-      ppp->stats.rerrors++;
-      PRINTKN (1,(KERN_NOTICE "ppp: error in VJ memorizing\n"));
-      slhc_toss (ppp->slcomp);
-      return 1;
-    }
-    ppp->stats.runcomp++;
-    goto sendit;
-  }
-
-  /* not ours */
-  return 0;
-
- sendit:
-  if (ppp_debug_netpackets) {
-    struct iphdr *iph = (struct iphdr *) c;
-    PRINTK ((KERN_INFO "%s <--    src %x dst %x len %d\n", ppp->dev->name, 
-	     iph->saddr, iph->daddr, count))
-  }
+/*
+ * IOCTL to read the compression statistics for the pppstats program.
+ */
 
-  /* receive the frame through the network software */
-  
-  skb=dev_alloc_skb(count);
-  if(skb)
-  {
-  	skb->mac.raw=skb->data;
-  	memcpy(skb_put(skb,count), c,count);
-  	skb->protocol=htons(ETH_P_IP);
-  	skb->dev=ppp->dev;
-  	netif_rx(skb);
-  }
-  return 1;
-}
-
-/* stuff packet at BUF, length LEN, into the us_rbuff buffer
-   prepend PROTO information */
-
-#define PUTC(c,label) *ppp->us_rbuff_head++ = c; \
-                if (ppp->us_rbuff_head == ppp->us_rbuff_end) \
-                     ppp->us_rbuff_head = ppp->us_rbuff; \
-                if (ppp->us_rbuff_head == ppp->us_rbuff_tail) \
-                     goto label;
-#define GETC(c) c = *ppp->us_rbuff_tail++; \
-                if (ppp->us_rbuff_tail == ppp->us_rbuff_end) \
-                     ppp->us_rbuff_tail = ppp->us_rbuff;
-
-static int
-ppp_us_queue(struct ppp *ppp, unsigned short proto, 
-	     unsigned char *buf, int len)
-{
-  int totlen;
-  unsigned char *saved_head;
-
-  totlen = len+2;		/* including protocol */
-
-  if (set_bit(1, &ppp->us_rbuff_lock)) {
-    PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n"));
-    return 0;
-  }
-  saved_head = ppp->us_rbuff_head;
-
-  PUTC((totlen & 0xff00) >> 8, failure);
-  PUTC(totlen & 0x00ff, failure);
-  PUTC((proto & 0xff00) >> 8, failure);
-  PUTC(proto & 0x00ff, failure);
-
-  while (len-- > 0) {
-    PUTC(*buf++, failure);
-  }
-
-  PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen));
-  clear_bit(1, &ppp->us_rbuff_lock);
-  wake_up_interruptible (&ppp->read_wait);
-
-#ifdef NEW_TTY_DRIVERS
-  kill_fasync(ppp->tty->fasync, SIGIO);
-#endif
-
-  if (ppp->inp_sig && ppp->inp_sig_pid)
-    if (kill_proc (ppp->inp_sig_pid, ppp->inp_sig, 1) != 0) {
-      /* process is gone */
-      PRINTKN (2,(KERN_NOTICE
-		  "ppp: process that requested notification is gone\n"));
-      ppp->inp_sig = 0;
-      ppp->inp_sig_pid = 0;
-    }
-  return 1;
-
- failure:
-  ppp->us_rbuff_head = saved_head;
-  clear_bit(1, &ppp->us_rbuff_lock);
+static int
+ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+{
+	struct ppp_comp_stats *result, temp;
+	int    error;
+/*
+ * Must have write access to the buffer.
+ */
+	result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
+	error = verify_area (VERIFY_WRITE,
+			     result,
+			     sizeof (temp));
+/*
+ * Supply the information for the caller.
+ */
+	memset (&temp, 0, sizeof(temp));
+	if (error == 0 && dev->flags & IFF_UP) {
+		if (ppp->sc_xc_state != NULL)
+			(*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
+						     &temp.c);
+
+		if (ppp->sc_rc_state != NULL)
+			(*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
+						       &temp.d);
+	}
+/*
+ * Move the data to the caller's buffer
+ */
+	if (error == 0)
+		memcpy_tofs (result, &temp, sizeof (temp));
+	return error;
+}
 
-  PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n"));
+/*
+ * Callback from the network layer to process the sockioctl functions.
+ */
 
-  return 0;
+static int
+ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ppp *ppp = dev2ppp (dev);
+	int error;
+/*
+ * Process the requests
+ */
+	switch (cmd) {
+	case SIOCGPPPSTATS:
+		error = ppp_dev_ioctl_stats (ppp, ifr, dev);
+		break;
+
+	case SIOCGPPPCSTATS:
+		error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
+		break;
+
+	case SIOCGPPPVER:
+		error = ppp_dev_ioctl_version (ppp, ifr);
+		break;
+
+	default:
+		error = -EINVAL;
+		break;
+	}
+	return error;
 }
 
-/*************************************************************
- * LINE DISCIPLINE SUPPORT
- *    The following functions form support user programs
- *    which read and write data on a TTY with the PPP line
- *    discipline.  Reading is done from a circular queue,
- *    filled by the lower TTY levels.
- *************************************************************/
-
-/* read a PPP frame from the us_rbuff circular buffer, 
-   waiting if necessary
-*/
+/*
+ * Send an IP frame to the remote with vj header compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ *        1 if frame must be re-queued for later driver support.
+ */
 
 static int
-ppp_read(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr)
+ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
 {
-  struct ppp *ppp = ppp_find(tty);
-  unsigned char c;
-  int len, i;
-
-  if (!ppp || ppp->magic != PPP_MAGIC) {
-    PRINTKN (1,(KERN_ERR "ppp_read: cannot find ppp channel\n"));
-    return -EIO;
-  }
-
-  CHECK_PPP(-ENXIO);
-
-  PRINTKN (4,(KERN_DEBUG "ppp_read: called %p num %u\n",
-	      buf, nr));
-
-  do {
-    /* try to acquire read lock */
-    if (set_bit(0, &ppp->us_rbuff_lock) == 0) {
-      /* got lock */
-      if (ppp->us_rbuff_head == ppp->us_rbuff_tail) {
-	/* no data */
-	PRINTKN (4,(KERN_DEBUG "ppp_read: no data\n"));
-	clear_bit(0, &ppp->us_rbuff_lock);
-        if (ppp->inp_sig) {
-	  PRINTKN (4,(KERN_DEBUG "ppp_read: EWOULDBLOCK\n"));
-	  return -EWOULDBLOCK;
-        } else goto wait;
-      }
-
-      i = verify_area (VERIFY_WRITE,buf,nr);
-      if (i != 0) {
-	ppp->us_rbuff_lock = 0;
-	return i;
-      }
-
-      /* reset the time of the last read operation */
-      ppp->ddinfo.nip_rjiffies = jiffies;
-
-      GETC (c); len = c << 8; GETC (c); len += c;
-
-      PRINTKN (4,(KERN_DEBUG "ppp_read: len = %d\n", len));
-
-      if (len + 2 > nr) {
-	/* frame too big; can't copy it, but do update us_rbuff_head */
-	PRINTKN (1,(KERN_DEBUG
-		    "ppp: read of %u bytes too small for %d frame\n",
-		    nr, len+2));
-	ppp->us_rbuff_head += len;
-	if (ppp->us_rbuff_head > ppp->us_rbuff_end)
-	  ppp->us_rbuff_head += - (ppp->us_rbuff_end - ppp->us_rbuff);
-	clear_bit(0, &ppp->us_rbuff_lock);
-	wake_up_interruptible (&ppp->read_wait);
-	ppp->stats.rgiants++;
-	return -EOVERFLOW;		/* ZZZ; HACK! */
-      } else {
-	/* have the space: copy the packet, faking the first two bytes */
-	put_user (PPP_ADDRESS, buf++);
-	put_user (PPP_CONTROL, buf++);
-	i = len;
-	while (i-- > 0) {
-	  GETC (c);
-	  put_user (c, buf++);
-	}
-      }
-
-      clear_bit(0, &ppp->us_rbuff_lock);
-      PRINTKN (3,(KERN_DEBUG "ppp_read: passing %d bytes up\n", len + 2));
-      ppp->stats.rothers++;
-      return len + 2;
-    }
-
-    /* need to wait */
-  wait:
-    current->timeout = 0;
-    PRINTKN (3,(KERN_DEBUG "ppp_read: sleeping\n"));
-    interruptible_sleep_on (&ppp->read_wait);
-
-    /* Ensure that the ppp device is still attached. */
-    ppp = ppp_find(tty);
-    if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
-      return 0;
-      
-    if (current->signal & ~current->blocked)
-      return -EINTR;
-  } while (1);
-}
+	int      proto = PPP_IP;
+	int	 len;
+	struct ppp_hdr    *hdr;
+	struct tty_struct *tty = ppp2tty (ppp);
+/*
+ * Obtain the length from the IP header.
+ */
+	len = ((struct iphdr *)data) -> tot_len;
+	len = ntohs (len);
+/*
+ * Validate the tty interface
+ */
+	if (tty == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+				"ppp_dev_xmit: %s not connected to a TTY!\n",
+				dev->name);
+		return 0;
+	}
+/*
+ * Ensure that the PPP device is still up
+ */
+	if (!(dev->flags & IFF_UP)) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING
+				"ppp_dev_xmit: packet sent on interface %s,"
+				" which is down for IP\n",
+				dev->name);
+		return 0;
+	}
+/*
+ * Detect a change in the transfer size
+ */
+	if (ppp->mtu != ppp2dev (ppp)->mtu) {
+		ppp_changedmtu (ppp,
+				ppp2dev (ppp)->mtu,
+				ppp->mru);
+	}
+/*
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy and return "failure to send, try back later" error.
+ */
+	if (lock_buffer (ppp->wbuf) != 0) {
+		dev->tbusy = 1;
+		return 1;
+	}
+/*
+ * Print the frame being sent
+ */
+	if (ppp->flags & SC_LOG_OUTPKT)
+		ppp_print_buffer ("ppp outpkt", data, len);
+/*
+ * At this point, the buffer will be transmitted. There is no other exit.
+ *
+ * Try to compress the header.
+ */
+	if (ppp->flags & SC_COMP_TCP) {
+		len = slhc_compress (ppp->slcomp, data, len,
+				     buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
+				     &data,
+				     (ppp->flags & SC_NO_TCP_CCID) == 0);
+
+		if (data[0] & SL_TYPE_COMPRESSED_TCP) {
+			proto    = PPP_VJC_COMP;
+			data[0] ^= SL_TYPE_COMPRESSED_TCP;
+		} else {
+			if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+				proto = PPP_VJC_UNCOMP;
+			data[0] = (data[0] & 0x0f) | 0x40;
+		}
+	}
+/*
+ * Send the frame
+ */
+	len  += PPP_HARD_HDR_LEN;
+	hdr   = &((struct ppp_hdr *) data)[-1];
 
-/* stuff a character into the transmit buffer, using PPP's way of escaping
-   special characters.
-   also, update ppp->fcs to take account of new character */
-static inline void
-ppp_stuff_char(struct ppp *ppp, unsigned char c)
-{
-  int curpt = ppp->xhead - ppp->xbuff;
-  if ((curpt < 0) || (curpt > 3000)) {
-    PRINTK ((KERN_DEBUG "ppp_stuff_char: %p %p %d\n",
-	     ppp->xbuff, ppp->xhead, curpt))
-  }
-  if (in_xmap (ppp, c)) {
-    *ppp->xhead++ = PPP_ESC;
-    *ppp->xhead++ = c ^ PPP_TRANS;
-  } else
-    *ppp->xhead++ = c;
-  ppp->fcs = (ppp->fcs >> 8) ^ fcstab[(ppp->fcs ^ c) & 0xff];
+	hdr->address     = PPP_ALLSTATIONS;
+	hdr->control     = PPP_UI;
+	hdr->protocol[0] = 0;
+	hdr->protocol[1] = proto;
+
+	return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
 }
 
-/* write a frame with NR chars from BUF to TTY
-   we have to put the FCS field on ourselves
-*/
+/*
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ip1 routine called
+ * by this name.
+ */
 
 static int
-ppp_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, unsigned int nr)
+ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
 {
-  struct ppp *ppp = ppp_find(tty);
-  int i;
+	struct ppp_hdr *hdr;
+	int     len;
+	int     answer;
+
+	len = ((struct iphdr *)data) -> tot_len;
+	len = ntohs (len);
+
+	hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+					  GFP_ATOMIC);
+
+	if (hdr == NULL)
+		answer = 1;
+	else {
+		memcpy (&hdr[1], data, len);
+		answer = ppp_dev_xmit_ip1 (dev, ppp, (u_char *) &hdr[1]);
+		kfree (hdr);
+	}
 
-  if (!ppp || ppp->magic != PPP_MAGIC) {
-    PRINTKN (1,(KERN_ERR "ppp_write: cannot find ppp unit\n"));
-    return -EIO;
-  }
+	return answer;
+}
 
-  CHECK_PPP(-ENXIO);
-  
-  if (ppp->mtu != ppp->dev->mtu)	/* Someone has been ifconfigging */
-    ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru);
+/*
+ * Send an IPX (or any other non-IP) frame to the remote.
+ *
+ * Return 0 if frame was queued for transmission.
+ *        1 if frame must be re-queued for later driver support.
+ */
 
-  if (nr > ppp->mtu) {
-    PRINTKN (1,(KERN_WARNING
-		"ppp_write: truncating user packet from %u to mtu %d\n",
-		nr, ppp->mtu));
-    nr = ppp->mtu;
-  }
-
-  i = verify_area (VERIFY_READ,buf,nr);
-  if (i != 0)
-    return i;
-
-  if (ppp_debug >= 3)
-    ppp_print_buffer ("write frame", buf, nr, USER_DS);
-
-  /* lock this PPP unit so we will be the only writer;
-     sleep if necessary */
-  while ((ppp->sending == 1) || !ppp_lock(ppp)) {
-    current->timeout = 0;
-    PRINTKN (3,(KERN_DEBUG "ppp_write: sleeping\n"));
-    interruptible_sleep_on(&ppp->write_wait);
-
-    /* Ensure that the ppp device is still attached. */
-    ppp = ppp_find(tty);
-    if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
-      return 0;
-
-    if (current->signal & ~current->blocked)
-      return -EINTR;
-  }
-
-  /* OK, locked.  Stuff the given bytes into the buffer. */
-
-  PRINTKN(4,(KERN_DEBUG "ppp_write: acquired write lock\n"));
-  ppp->xhead = ppp->xbuff;
-
-#ifdef OPTIMIZE_FLAG_TIME
-  if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
-    *ppp->xhead++ = PPP_FLAG;
-  ppp->last_xmit = jiffies;
-#else      
-  *ppp->xhead++ = PPP_FLAG;
-#endif
-
-  ppp->fcs = PPP_FCS_INIT;
-  i = nr;
-  while (i-- > 0)
-    ppp_stuff_char(ppp,get_user(buf++));
+#ifdef NEW_SKBUFF
+static int
+ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
+		  u_char *data, int len, int proto)
+{
+	struct tty_struct *tty = ppp2tty (ppp);
+	struct ppp_hdr    *hdr;
+/*
+ * Validate the tty interface
+ */
+	if (tty == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+				"ppp_dev_xmit: %s not connected to a TTY!\n",
+				dev->name);
+		return 0;
+	}
+/*
+ * Ensure that the PPP device is still up
+ */
+	if (!(dev->flags & IFF_UP)) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING
+				"ppp_dev_xmit: packet sent on interface %s,"
+				" which is down\n",
+				dev->name);
+		return 0;
+	}
+/*
+ * Detect a change in the transfer size
+ */
+	if (ppp->mtu != ppp2dev (ppp)->mtu) {
+		ppp_changedmtu (ppp,
+				ppp2dev (ppp)->mtu,
+				ppp->mru);
+	}
+/*
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy and return "failure to send, try back later" error.
+ */
+	if (lock_buffer (ppp->wbuf) != 0) {
+		dev->tbusy = 1;
+		return 1;
+	}
+/*
+ * Print the frame being sent
+ */
+	if (ppp->flags & SC_LOG_OUTPKT)
+		ppp_print_buffer ("ppp outpkt", data, len);
+/*
+ * Send the frame
+ */
+	len  += PPP_HARD_HDR_LEN;
+	hdr   = &((struct ppp_hdr *) data)[-1];
 
-  ppp_add_fcs(ppp);		/* concatenate FCS at end */
+	hdr->address     = PPP_ALLSTATIONS;
+	hdr->control     = PPP_UI;
+	hdr->protocol[0] = proto >> 8;
+	hdr->protocol[1] = proto;
 
-  *ppp->xhead++ = PPP_FLAG;
-  
-  /* reset the time of the last write operation */
-  ppp->ddinfo.nip_sjiffies = jiffies;
+	return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
+}
 
-  if (ppp_debug >= 6)
-    ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
-  else {
-    PRINTKN (4,(KERN_DEBUG "ppp_write: writing %d chars\n",
-		(int) (ppp->xhead - ppp->xbuff)));
-  }
-
-  /* packet is ready-to-go */
-  ++ppp->stats.sothers;
-  ppp_kick_tty(ppp);
+/*
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ipx1 routine called
+ * by this name.
+ */
 
-  return((int)nr);
-}
- 
 static int
-ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
-	  unsigned long l)
+ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
+		  u_char *data, int len, int proto)
 {
-  struct ppp *ppp = ppp_find(tty);
-  register int temp_i = 0;
-  int error;
-
-  if (!ppp || ppp->magic != PPP_MAGIC) {
-    PRINTK ((KERN_ERR "ppp_ioctl: can't find PPP block from tty!\n"))
-    return -EBADF;
-  }
-
-  CHECK_PPP(-ENXIO);
-
-  /* This must be root user */
-  if (!suser())
-    return -EPERM;
-
-  switch (i) {
-  case PPPIOCSMRU:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      temp_i = get_user ((int *) l);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set mru to %d\n", temp_i));
-      if (ppp->mru != temp_i)
-	ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
-    }
-    break;
-
-  case PPPIOCGFLAGS:
-    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      temp_i = (ppp->flags & SC_MASK);
-#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
-      temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;
-#endif
-      put_user (temp_i, (int *) l);
-      PRINTKN (3,(KERN_DEBUG "ppp_ioctl: get flags: addr %lx flags %x\n",
-		  l,
-		  temp_i));
-    }
-    break;
-
-  case PPPIOCSFLAGS:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      temp_i      = get_user ((int *) l);
-      ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set flags to %x\n", temp_i));
-    }
-    break;
-
-  case PPPIOCGASYNCMAP:
-    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      put_user (ppp->xmit_async_map[0], (int *) l);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
-		  l, (unsigned long) ppp->xmit_async_map[0]));
-    }
-    break;
-
-  case PPPIOCSASYNCMAP:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      ppp->xmit_async_map[0] = get_user ((int *) l);
-      bset (ppp->xmit_async_map, PPP_FLAG);
-      bset (ppp->xmit_async_map, PPP_ESC);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n",
-		  (unsigned long) ppp->xmit_async_map[0]));
-    }
-    break;
-
-  case PPPIOCRASYNCMAP:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      ppp->recv_async_map = get_user ((int *) l);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n",
-		  (unsigned long) ppp->recv_async_map));
-    }
-    break;
-
-  case PPPIOCGUNIT:
-    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      put_user (ppp->dev->base_addr, (int *) l);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr));
-    }
-    break;
-
-  case PPPIOCSINPSIG:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      ppp->inp_sig     = get_user ((int *) l);
-      ppp->inp_sig_pid = current->pid;
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set input signal %d\n", ppp->inp_sig));
-    }
-    break;
-
-  case PPPIOCSDEBUG:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      ppp_debug = get_user ((int *) l);
-      ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
-      ppp_debug &= 0xff;
-      PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n", 
-		   ppp_debug, ppp_debug_netpackets));
-    }
-    break;
-
-  case PPPIOCGDEBUG:
-    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      put_user ((long) (ppp_debug | (ppp_debug_netpackets << 8)), (int *) l);
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: get debug level %d\n", 
-		  ppp_debug | (ppp_debug_netpackets << 8)));
-    }
-    break;
-
-  case PPPIOCGSTAT:
-    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_stats));
-    if (error == 0) {
-      memcpy_tofs ((void *) l, &ppp->stats, sizeof (struct ppp_stats));
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: read statistics\n"));
-    }
-    break;
-
-  case PPPIOCGTIME:
-    error = verify_area (VERIFY_WRITE, (void *) l, sizeof (struct ppp_ddinfo));
-    if (error == 0) {
-      struct ppp_ddinfo cur_ddinfo;
-      unsigned long cur_jiffies = jiffies;
-
-      /* change absolute times to relative times. */
-      cur_ddinfo.ip_sjiffies  = cur_jiffies - ppp->ddinfo.ip_sjiffies;
-      cur_ddinfo.ip_rjiffies  = cur_jiffies - ppp->ddinfo.ip_rjiffies;
-      cur_ddinfo.nip_sjiffies = cur_jiffies - ppp->ddinfo.nip_sjiffies;
-      cur_ddinfo.nip_rjiffies = cur_jiffies - ppp->ddinfo.nip_rjiffies;
-      
-      memcpy_tofs ((void *) l, &cur_ddinfo, sizeof (struct ppp_ddinfo));
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: read demand dial info\n"));
-    }
-    break;
-
-  case PPPIOCGXASYNCMAP:
-    error = verify_area (VERIFY_WRITE,
-			 (void *) l,
-			 sizeof (ppp->xmit_async_map));
-    if (error == 0) {
-      memcpy_tofs ((void *) l,
-		   ppp->xmit_async_map,
-		   sizeof (ppp->xmit_async_map));
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: get xasyncmap: addr %lx\n", l));
-    }
-    break;
-
-  case PPPIOCSXASYNCMAP:
-    error = verify_area (VERIFY_READ, (void *) l,
-			 sizeof (ppp->xmit_async_map));
-    if (error == 0) {
-      __u32 temp_tbl [8];
-
-      memcpy_fromfs (temp_tbl, (void *) l, sizeof (ppp->xmit_async_map));
-      temp_tbl[1]  =  0x00000000; /* must not escape 0x20 - 0x3f */
-      temp_tbl[2] &= ~0x40000000; /* must not escape 0x5e        */
-      temp_tbl[3] |=  0x60000000; /* must escape 0x7d and 0x7e   */
-
-      if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
-	  (temp_tbl[4] & temp_tbl[5]) != 0 ||
-	  (temp_tbl[6] & temp_tbl[7]) != 0)
-	error = -EINVAL;
-      else {
-	memcpy (ppp->xmit_async_map, temp_tbl, sizeof (ppp->xmit_async_map));
-	PRINTKN (3,(KERN_INFO "ppp_ioctl: set xasyncmap\n"));
-      }
-    }
-    break;
-
-  case PPPIOCSMAXCID:
-    error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
-    if (error == 0) {
-      temp_i = get_user ((int *) l) + 1;
-      PRINTKN (3,(KERN_INFO "ppp_ioctl: set maxcid to %d\n", temp_i));
-      if (ppp->slcomp != NULL)
-	slhc_free (ppp->slcomp);
-
-      ppp->slcomp = slhc_init (temp_i, temp_i);
-
-      if (ppp->slcomp == NULL) {
-	PRINTKN (1,(KERN_ERR "ppp: no space for compression buffers!\n"));
-	ppp_release (ppp);
-	error = -ENOMEM;
-      }
-    }
-    break;
-
-#ifdef NEW_TTY_DRIVERS
-    /* Allow stty to read, but not set, the serial port */
-  case TCGETS:
-  case TCGETA:
-    error = n_tty_ioctl(tty, file, i, l);
-    break;
+	struct ppp_hdr    *hdr;
+	int     answer;
+
+	hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+					  GFP_ATOMIC);
+	if (hdr == NULL)
+		answer = 1;
+	else {
+		memcpy (&hdr[1], data, len);
+		answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1],
+					    len, proto);
+		kfree (hdr);
+	}
+
+	return answer;
+}
 #endif
 
 /*
- *  All other ioctl() events will come here.
+ * Send a frame to the remote.
+ */
+
+static int
+ppp_dev_xmit (sk_buff *skb, struct device *dev)
+{
+	int answer, len;
+	u_char *data;
+	struct ppp        *ppp = dev2ppp (dev);
+	struct tty_struct *tty = ppp2tty (ppp);
+/*
+ * just a little sanity check.
+ */
+	if (skb == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
+		return 0;
+	}
+/*
+ * Avoid timing problem should tty hangup while data is queued to be sent
+ */
+	if (!ppp->inuse) {
+		dev_kfree_skb (skb, FREE_WRITE);
+		dev_close (dev);
+		return 0;
+	}
+/*
+ * Validate the tty linkage
+ */
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n",
+			dev->name, (int) skb);
+/*
+ * Validate the tty interface
+ */
+	if (tty == NULL) {
+		if (ppp->flags & SC_DEBUG)
+			printk (KERN_ERR
+				"ppp_dev_xmit: %s not connected to a TTY!\n",
+				dev->name);
+		dev_kfree_skb (skb, FREE_WRITE);
+		return 0;
+	}
+/*
+ * Fetch the pointer to the data
+ */
+	len   = skb->len;
+	data  = skb_data(skb);
+/*
+ * Look at the protocol in the skb to determine the difference between
+ * an IP frame and an IPX frame.
  */
 
-  default:
-    PRINTKN (1,(KERN_ERR "ppp_ioctl: invalid ioctl: %x, addr %lx\n",
-		i,
-		l));
-#ifdef NEW_TTY_DRIVERS
-    error = -ENOIOCTLCMD;
+#ifdef NEW_SKBUFF
+	switch (skb->protocol) {
+	case htons (ETH_P_IPX):
+		answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
+		break;
+
+	case htons (ETH_P_IP):
+		answer = ppp_dev_xmit_ip (dev, ppp, data);
+		break;
+
+	default: /* All others have no support at this time. */
+		dev_kfree_skb (skb, FREE_WRITE);
+		return 0;
+	}
 #else
-    error = -EINVAL;
+	answer = ppp_dev_xmit_ip (dev, ppp, data);
 #endif
-    break;
-  }
-  return error;
+
+/*
+ * This is the end of the transmission. Release the buffer if it was sent.
+ */
+	if (answer == 0) {
+		dev_kfree_skb (skb, FREE_WRITE);
+		ppp->ddinfo.xmit_idle = jiffies;
+	}
+	return answer;
 }
 
-static int
-ppp_select (struct tty_struct *tty, struct inode * inode,
-	    struct file * filp, int sel_type, select_table * wait)
+/*
+ * Generate the statistic information for the /proc/net/dev listing.
+ */
+
+static struct enet_statistics *
+ppp_dev_stats (struct device *dev)
 {
-  struct ppp *ppp = ppp_find (tty);
-  
-  if (!ppp || ppp->magic != PPP_MAGIC) {
-    PRINTK ((KERN_ERR "ppp_select: can't find PPP block from tty!\n"))
-    return -EBADF;
-  }
-  
-  /* If the PPP protocol is no longer active, return false */
-  CHECK_PPP (0);
-  
-  /* Process the request based upon the type desired */
-  switch (sel_type) {
-  case SEL_IN:
-    if (set_bit(0, &ppp->us_rbuff_lock) == 0) {
-      /* Test for the presence of data in the queue */
-      if (ppp->us_rbuff_head != ppp->us_rbuff_tail) {
-	clear_bit (0, &ppp->us_rbuff_lock);
-	return 1;
-      }
-      clear_bit (0, &ppp->us_rbuff_lock);
-    } /* fall through */
-
-  case SEL_EX:
-    /* Is there a pending error condition? */
-    if (tty->packet && tty->link->ctrl_status)
-      return 1;
-    
-    /* closed? */
-    if (tty->flags & (1 << TTY_SLAVE_CLOSED))
-      return 1;
-    
-    /* If the tty is disconnected, then this is an exception too */
-    if (tty_hung_up_p(filp))
-      return 1;
+	struct ppp *ppp = dev2ppp (dev);
+	static struct enet_statistics ppp_stats;
 
-    select_wait (&ppp->read_wait, wait);
-    break;
-    
-  case SEL_OUT:
-    if (ppp_lock (ppp)) {
-      if (ppp->sending == 0) {
-	ppp_unlock (ppp);
-	return 1;
-      }
-      ppp_unlock (ppp);
-    }
-    select_wait (&ppp->write_wait, wait);
-    break;
-  }
-  return 0;
+	ppp_stats.rx_packets          = ppp->stats.ppp_ipackets;
+	ppp_stats.rx_errors           = ppp->stats.ppp_ierrors;
+	ppp_stats.rx_dropped          = ppp->stats.ppp_ierrors;
+	ppp_stats.rx_fifo_errors      = 0;
+	ppp_stats.rx_length_errors    = 0;
+	ppp_stats.rx_over_errors      = 0;
+	ppp_stats.rx_crc_errors       = 0;
+	ppp_stats.rx_frame_errors     = 0;
+	ppp_stats.tx_packets          = ppp->stats.ppp_opackets;
+	ppp_stats.tx_errors           = ppp->stats.ppp_oerrors;
+	ppp_stats.tx_dropped          = 0;
+	ppp_stats.tx_fifo_errors      = 0;
+	ppp_stats.collisions          = 0;
+	ppp_stats.tx_carrier_errors   = 0;
+	ppp_stats.tx_aborted_errors   = 0;
+	ppp_stats.tx_window_errors    = 0;
+	ppp_stats.tx_heartbeat_errors = 0;
+
+	if (ppp->flags & SC_DEBUG)
+		printk (KERN_INFO "ppp_dev_stats called");
+	return &ppp_stats;
 }
 
-/*************************************************************
- * NETWORK OUTPUT
- *    This routine accepts requests from the network layer
- *    and attempts to deliver the packets.
- *    It also includes various routines we are compelled to
- *    have to make the network layer work (arp, etc...).
- *************************************************************/
+#ifdef NEW_SKBUFF
+/*
+ *	The PPP protocol is currently pure IP (no IPX yet). This defines
+ *      the protocol layer which is blank since the driver does all the
+ *      cooking.
+ */
 
-int
-ppp_xmit(struct sk_buff *skb, struct device *dev)
-{
-  struct tty_struct *tty;
-  struct ppp *ppp;
-  unsigned char *p;
-  unsigned short proto;
-  int len;
-
-  /* just a little sanity check. */
-  if (skb == NULL) {
-    PRINTKN(3,(KERN_WARNING "ppp_xmit: null packet!\n"));
-    return 0;
-  }
-
-  /* Get pointers to the various components */
-  ppp   = &ppp_ctrl[dev->base_addr];
-  tty   = ppp->tty;
-  p     = skb->data;
-  len   = skb->len;
-  proto = PROTO_IP;
-
-  PRINTKN(4,(KERN_DEBUG "ppp_xmit [%s]: skb %lX busy %d\n", dev->name, 
-	     (unsigned long int) skb, ppp->sending));
-
-  /* avoid race conditions when the link fails */
-  if (!ppp->inuse) {
-    dev_kfree_skb(skb, FREE_WRITE);
-    dev_close (dev);
-    return 0;
-  }
-
-  if (tty == NULL) {
-    PRINTKN(1,(KERN_ERR "ppp_xmit: %s not connected to a TTY!\n", dev->name));
-    goto done;
-  }
-
-  if (!(dev->flags & IFF_UP)) {
-    PRINTKN(1,(KERN_WARNING
-	       "ppp_xmit: packet sent on interface %s, which is down for IP\n",
-	       dev->name));
-    goto done;
-  }
-
-#ifdef CURED_AGES_AGO
-  /* get length from IP header as per Alan Cox bugfix for slip.c */
-  if (len < sizeof(struct iphdr)) {
-    PRINTKN(0,(KERN_ERR "ppp_xmit: given runt packet, ignoring\n"));
-    goto done;
-  }
-  len = ntohs( ((struct iphdr *)(skb->data)) -> tot_len );
-#endif  
-
-  /* If doing demand dial then divert the first frame to pppd. */
-  if (ppp->flags & SC_IP_DOWN) {
-    if ((ppp->flags & SC_IP_FLUSH) == 0) {
-      if (ppp_us_queue (ppp, proto, p, len))
-	ppp->flags |= SC_IP_FLUSH;
-    }
-    goto done;
-  }
-
-  /* Attempt to acquire send lock */
-  if (ppp->sending || !ppp_lock(ppp)) {
-    PRINTKN(3,(KERN_WARNING "ppp_xmit: busy\n"));
-    ppp->stats.sbusy++;
-    return 1;
-  }
-
-  ppp->xhead = ppp->xbuff;
-
-  /* try to compress, if VJ compression mode is on */
-  if (ppp->flags & SC_COMP_TCP) {
-    len = slhc_compress(ppp->slcomp, p, len, ppp->cbuff, &p, 
-			!(ppp->flags & SC_NO_TCP_CCID));
-    if (p[0] & SL_TYPE_COMPRESSED_TCP)
-      proto = PROTO_VJCOMP;
-    else {
-      if (p[0] >= SL_TYPE_UNCOMPRESSED_TCP) {
-	proto = PROTO_VJUNCOMP;
-	p[0] = (p[0] & 0x0f) | 0x40; 
-      }
-    }
-  }
-
-  /* increment appropriate counter */
-  if (proto == PROTO_VJCOMP)
-    ++ppp->stats.scomp;
-  else
-    ++ppp->stats.suncomp;
-      
-  if (ppp_debug_netpackets) {
-    struct iphdr *iph = (struct iphdr *)skb->data;
-    PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x dst %x proto %d\n",
-	    dev->name, (int) proto, (int) len, (int) iph->saddr,
-	    (int) iph->daddr, (int) iph->protocol))
-  }
-
-  /* start of frame:   FLAG  ALL_STATIONS  CONTROL  <protohi> <protolo> */
-#ifdef OPTIMIZE_FLAG_TIME
-  if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
-    *ppp->xhead++ = PPP_FLAG;
-  ppp->last_xmit = jiffies;
-#else      
-  *ppp->xhead++ = PPP_FLAG;
-#endif
-
-  ppp->fcs = PPP_FCS_INIT;
-  if (!(ppp->flags & SC_COMP_AC)) { 
-    ppp_stuff_char(ppp, PPP_ADDRESS);
-    ppp_stuff_char(ppp, PPP_CONTROL);
-  }
-
-  if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00))
-    ppp_stuff_char(ppp, proto>>8);
-  ppp_stuff_char(ppp, proto&0xff);
-
-  /* data part */
-  while (len-- > 0)
-    ppp_stuff_char(ppp, *p++);
-
-  /* fcs and flag */
-  ppp_add_fcs(ppp);
-  *ppp->xhead++ = PPP_FLAG;
-
-  /* update the time for demand dial function */
-  ppp->ddinfo.ip_sjiffies = jiffies;
-
-  /* send it! */
-  if (ppp_debug >= 6)
-    ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
-  else {
-    PRINTKN (4,(KERN_DEBUG "ppp_write: writing %d chars\n",
-		(int) (ppp->xhead - ppp->xbuff)));
-  }
-
-  ppp_kick_tty(ppp);
-
- done:
-  dev_kfree_skb(skb, FREE_WRITE);
-  return 0;
-}
-  
-#ifdef NET02D
-static int
-ppp_header(unsigned char *buff, struct device *dev, unsigned short type,
-	   unsigned long daddr, unsigned long saddr, unsigned len)
+static int ppp_dev_input (struct protocol *self, struct protocol *lower,
+			  sk_buff *skb, void *saddr, void *daddr)
 {
-  return(0);
+	return protocol_pass_demultiplex(self, NULL, skb, NULL, NULL);
 }
 
-static int
-ppp_rebuild_header(void *buff, struct device *dev)
+static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
+			   int subid, void *saddr, void *daddr, void *opt)
 {
-  return(0);
+	if(skb->dev==NULL)
+	{
+		printk("ppp_dev_output: No device.\n");
+		kfree_skb(skb, FREE_WRITE);
+		return -1;
+	}
+	dev_queue_xmit(skb, skb->dev, skb->priority);
+	return 0;
 }
 
-static void
-ppp_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
+static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
 {
+	switch (protocol)
+	{
+	case htons (ETH_P_IP):
+	case htons (ETH_P_IPX):
+		return 0;
+
+	default:
+		break;
+	}
+
+	return -EAFNOSUPPORT;
 }
 
 #else
 
-static int
-ppp_header(struct sk_buff *skb, struct device *dev, unsigned short type,
-	   void *daddr, void *saddr, unsigned len)
-{
-  return(0);
-}
+#if USE_SKB_PROTOCOL == 0
+/*
+ * Called to enquire about the type of the frame in the buffer. Return
+ * ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame.
+ */
 
-static int
-ppp_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
-		   struct sk_buff *skb)
+static unsigned short
+ppp_dev_type (sk_buff *skb, struct device *dev)
 {
-  return(0);
+	return (htons (ETH_P_IP));
 }
 #endif
 
-static struct enet_statistics *
-ppp_get_stats (struct device *dev)
+#if USE_SKB_PROTOCOL == 0
+static int ppp_dev_header (unsigned char *buff, struct device *dev,
+			   unsigned short type, void *daddr, void *saddr,
+			   unsigned len, struct sk_buff *skb)
+#else
+static int ppp_dev_header (sk_buff *skb, struct device *dev,
+			   unsigned short type, void *daddr,
+			   void *saddr, unsigned len)
+#endif
 {
-  struct ppp *ppp = &ppp_ctrl[dev->base_addr];
-  static struct enet_statistics ppp_stats;
-
-  ppp_stats.rx_packets = ppp->stats.rcomp + ppp->stats.runcomp;
-  ppp_stats.rx_errors = ppp->stats.rerrors;
-  ppp_stats.rx_dropped = ppp->stats.tossed;
-  ppp_stats.rx_fifo_errors = 0;
-  ppp_stats.rx_length_errors = ppp->stats.runts;
-  ppp_stats.rx_over_errors = ppp->stats.roverrun;
-  ppp_stats.rx_crc_errors = 0;
-  ppp_stats.rx_frame_errors = 0;
-  ppp_stats.tx_packets = ppp->stats.scomp + ppp->stats.suncomp;
-  ppp_stats.tx_errors = ppp->stats.serrors;
-  ppp_stats.tx_dropped = 0;
-  ppp_stats.tx_fifo_errors = 0;
-  ppp_stats.collisions = ppp->stats.sbusy;
-  ppp_stats.tx_carrier_errors = 0;
-  ppp_stats.tx_aborted_errors = 0;
-  ppp_stats.tx_window_errors = 0;
-  ppp_stats.tx_heartbeat_errors = 0;
+	return (0);
+}
 
-  PRINTKN (3, (KERN_INFO "ppp_get_stats called"));
-  return &ppp_stats;
+static int
+ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
+		 sk_buff *skb)
+{
+	return (0);
 }
+#endif
 
 /*************************************************************
  * UTILITIES
  *    Miscellany called by various functions above.
  *************************************************************/
 
-#ifndef NEW_TTY_DRIVERS
-/* find a PPP channel given a TTY */
-struct ppp *
-ppp_find(struct tty_struct *tty)
-{
-  int i;
-  for (i = 0; i < PPP_NRUNIT; i++)
-    if (ppp_ctrl[i].inuse && (ppp_ctrl[i].tty == tty)) return &ppp_ctrl[i];
-
-  return NULL;
-}
-#endif
-
-/* allocate a PPP channel */
+/* allocate or create a PPP channel */
 static struct ppp *
-ppp_alloc(void)
+ppp_alloc (void)
 {
-  int i;
-  for (i = 0; i < PPP_NRUNIT; i++)
-    if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i];
-
-  return NULL;
-}
+	int		if_num;
+	int		status;
+	ppp_ctrl_t	*ctl;
+	struct device	*dev;
+	struct ppp	*ppp;
+
+	/* try to find an free device */
+	ctl      = ppp_list;
+	if_num   = 0;
+  
+	while (ctl) {
+		ppp = ctl2ppp (ctl);
+		if (!set_bit(0, &ppp->inuse))
+			return (ppp);
+		ctl = ctl->next;
+		if (++if_num == max_dev)
+			return (NULL);
+	}
+/*
+ * There are no available items. Allocate a device from the system pool
+ */
+	ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL);
+	if (ctl) {
+		(void) memset(ctl, 0, sizeof(ppp_ctrl_t));
+		ppp = ctl2ppp (ctl);
+		dev = ctl2dev (ctl);
+
+		/* initialize channel control data */
+		set_bit(0, &ppp->inuse);
+
+		ppp->line      = if_num;
+		ppp->tty       = NULL;
+		ppp->dev       = dev;
+    
+		dev->next      = NULL;
+		dev->init      = ppp_init_dev;
+		dev->name      = ctl->name;
+		dev->base_addr = (unsigned long) if_num;
+		dev->priv      = (void *) ppp;
 
-/* marks a PPP interface 'busy'.  user processes will wait, if
-   they try to write, and the network code will refrain from sending
-   return nonzero if succeeded in acquiring lock
-*/
+		sprintf (dev->name, "ppp%d", if_num);
+    
+		/* link in the new channel */
+		ctl->next      = ppp_list;
+		ppp_list       = ctl;
+
+/* register device so that we can be ifconfig'd */
+/* ppp_init_dev() will be called as a side-effect */
+
+		status = register_netdev (dev);
+		if (status == 0) {
+			printk ("registered device %s\n", dev->name);
+			return (ppp);
+		}
 
-static int
-ppp_lock(struct ppp *ppp)
-{
-  int flags, locked;
-  save_flags(flags);
-  cli();
-  locked = ppp->sending;
-  ppp->sending = 1;
-  if (ppp->dev->flags & IFF_UP)
-    ppp->dev->tbusy = 1;
-  restore_flags(flags);
-  return locked == 0;
+		printk (KERN_ERR
+		       "ppp_alloc - register_netdev(%s) = %d failure.\n",
+			dev->name, status);
+		/* This one will forever be busy as it is not initialized */
+	}
+	return (NULL);
 }
 
+/*
+ * Utility procedures to print a buffer in hex/ascii
+ */
+
 static void
-ppp_unlock(struct ppp *ppp)
+ppp_print_hex (register u_char * out, const u_char * in, int count)
 {
-  int flags;
-  save_flags(flags);
-  cli();
-  ppp->sending = 0;
-  if (ppp->dev->flags & IFF_UP)
-    ppp->dev->tbusy = 0;
-  restore_flags(flags);
-}
+	register u_char next_ch;
+	static char hex[] = "0123456789ABCDEF";
 
-/* FCS support functions */
+	while (count-- > 0) {
+		next_ch = *in++;
+		*out++ = hex[(next_ch >> 4) & 0x0F];
+		*out++ = hex[next_ch & 0x0F];
+		++out;
+	}
+}
 
 static void
-ppp_add_fcs(struct ppp *ppp)
+ppp_print_char (register u_char * out, const u_char * in, int count)
 {
-  unsigned short fcs = ppp->fcs;
+	register u_char next_ch;
+
+	while (count-- > 0) {
+		next_ch = *in++;
 
-  fcs ^= 0xffff;
-  ppp_stuff_char(ppp, fcs & 0x00ff);
-  ppp_stuff_char(ppp, (fcs & 0xff00) >> 8);
-  ASSERT (ppp->fcs == PPP_FCS_GOOD);
-  PRINTKN (4,(KERN_DEBUG "ppp_add_fcs: fcs is %lx\n",
-	      (long) (unsigned long) fcs));
+		if (next_ch < 0x20 || next_ch > 0x7e)
+			*out++ = '.';
+		else {
+			*out++ = next_ch;
+			if (next_ch == '%')   /* printk/syslogd has a bug !! */
+				*out++ = '%';
+		}
+	}
+	*out = '\0';
 }
 
-static int
-ppp_check_fcs(struct ppp *ppp)
+static void
+ppp_print_buffer (const u_char * name, const u_char * buf, int count)
 {
-  unsigned short fcs = PPP_FCS_INIT, msgfcs;
-  unsigned char *c = ppp->rbuff;
-  int i;
+	u_char line[44];
 
-  for (i = 0; i < ppp->rcount - 2; i++, c++)
-    fcs = (fcs >> 8) ^ fcstab[(fcs ^ *c) & 0xff];
+	if (name != (u_char *) NULL)
+		printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
+
+	while (count > 8) {
+		memset (line, 32, 44);
+		ppp_print_hex (line, buf, 8);
+		ppp_print_char (&line[8 * 3], buf, 8);
+		printk (KERN_DEBUG "%s\n", line);
+		count -= 8;
+		buf += 8;
+	}
 
-  fcs ^= 0xffff;
-  msgfcs = (c[1] << 8) + c[0];
-  PRINTKN (4,(KERN_INFO "ppp_check_fcs: got %lx want %lx\n",
-	      (unsigned long) msgfcs, (unsigned long) fcs));
-  return fcs == msgfcs;
+	if (count > 0) {
+		memset (line, 32, 44);
+		ppp_print_hex (line, buf, count);
+		ppp_print_char (&line[8 * 3], buf, count);
+		printk (KERN_DEBUG "%s\n", line);
+	}
 }
 
-static char hex[] = "0123456789ABCDEF";
+/*************************************************************
+ * Compressor module interface
+ *************************************************************/
+
+struct compressor_link {
+	struct compressor_link	*next;
+	struct compressor	*comp;
+};
+
+static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
 
-static inline void ppp_print_hex (register char *out, const char *in, int count)
+static struct compressor *find_compressor (int type)
 {
-  register unsigned char next_ch;
+	struct compressor_link *lnk;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
 
-  while (count-- > 0) {
-    next_ch = (unsigned char) get_user (in);
+	lnk = ppp_compressors;
+	while (lnk != (struct compressor_link *) 0) {
+		if ((int) (unsigned char) lnk->comp->compress_proto == type) {
+			restore_flags(flags);
+			return lnk->comp;
+		}
+		lnk = lnk->next;
+	}
 
-    *out++  = hex[(next_ch >> 4) & 0x0F];
-    *out++  = hex[next_ch        & 0x0F];
-    ++out;
-    ++in;
-  }
+	restore_flags(flags);
+	return (struct compressor *) 0;
 }
 
-static inline void ppp_print_char (register char *out, const char *in, int count)
+STATIC int ppp_register_compressor (struct compressor *cp)
 {
-  register unsigned char next_ch;
+	struct compressor_link *new;
+	unsigned long flags;
 
-  while (count-- > 0) {
-    next_ch = (unsigned char) get_user (in);
+	new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
 
-    if (next_ch < 0x20 || next_ch > 0x7e)
-      *out++ = '.';
-    else {
-      *out++ = next_ch;
-      if (next_ch == '%')	/* printk/syslogd has a bug !! */
-	*out++ = '%';
-    }
-    ++in;
-  }
-  *out = '\0';
-}
+	if (new == (struct compressor_link *) 0)
+	  	return 1;
 
-static void ppp_print_buffer(const char *name, const char *buf, int count, int seg)
-{
-  char line [44];
-  int  old_fs = get_fs();
+	save_flags(flags);
+	cli();
+
+	if (find_compressor (cp->compress_proto)) {
+		restore_flags(flags);
+	  	kfree (new);
+		return 0;
+	}
 
-  set_fs (seg);
+	new->next	= ppp_compressors;
+	new->comp	= cp;
+	ppp_compressors = new;
 
-  if (name != NULL)
-    PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count));
+	restore_flags(flags);
+	return 0;
+}
 
-  while (count > 8) {
-    memset         (line, ' ', sizeof (line));
-    ppp_print_hex  (line, buf, 8);
-    ppp_print_char (&line[8 * 3], buf, 8);
-    PRINTK ((KERN_DEBUG "%s\n", line));
-    count -= 8;
-    buf   += 8;
-  }
+STATIC void ppp_unregister_compressor (struct compressor *cp)
+{
+	struct compressor_link *prev = (struct compressor_link *) 0;
+	struct compressor_link *lnk;
+	unsigned long flags;
 
-  if (count > 0) {
-    memset         (line, ' ', sizeof (line));
-    ppp_print_hex  (line, buf, count);
-    ppp_print_char (&line[8 * 3], buf, count);
-    PRINTK ((KERN_DEBUG "%s\n", line));
-  }
+	save_flags(flags);
+	cli();
 
-  set_fs (old_fs);
+	lnk  = ppp_compressors;
+	while (lnk != (struct compressor_link *) 0) {
+		if (lnk->comp == cp) {
+		  	if (prev)
+				prev->next = lnk->next;
+			else
+				ppp_compressors = lnk->next;
+			kfree (lnk);
+			break;
+		}
+		prev = lnk;
+		lnk  = lnk->next;
+	}
+	restore_flags(flags);
 }
 
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
 
-static struct device dev_ppp[PPP_NRUNIT] = {
-	{
-		"ppp0",		/* ppp */
-		0, 0, 0, 0,	/* memory */
-		0, 0,		/* base, irq */
-		0, 0, 0, NULL, ppp_init,
-	}
-	, { "ppp1" , 0, 0, 0, 0,  1, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp2" , 0, 0, 0, 0,  2, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp3" , 0, 0, 0, 0,  3, 0, 0, 0, 0, NULL, ppp_init }
-
-#ifdef PPP_PPP_LOTS
-	, { "ppp4" , 0, 0, 0, 0,  4, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp5" , 0, 0, 0, 0,  5, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp6" , 0, 0, 0, 0,  6, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp7" , 0, 0, 0, 0,  7, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp8" , 0, 0, 0, 0,  8, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp9" , 0, 0, 0, 0,  9, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp10" , 0, 0, 0, 0, 10, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp11" , 0, 0, 0, 0, 11, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp12" , 0, 0, 0, 0, 12, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp13" , 0, 0, 0, 0, 13, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp14" , 0, 0, 0, 0, 14, 0, 0, 0, 0, NULL, ppp_init }
-	, { "ppp15" , 0, 0, 0, 0, 15, 0, 0, 0, 0, NULL, ppp_init }
-#endif
-};
-
 int
 init_module(void)
 {
-	int err;
-	int i,j;
+	int status;
 
-	for (i = 0; i < PPP_NRUNIT; i++)  {
-		if ((err = register_netdev(&dev_ppp[i])))  {
-			if (err == -EEXIST)  {
-				printk("PPP: devices already present. Module not loaded.\n");
-				/* we must unregister already registered units */
-				if(i>0) {
-					for(j = 0; j < i ; j++)
-						unregister_netdev(&dev_ppp[j]);
-					if ((j = tty_register_ldisc(N_PPP, NULL)))  {
-						printk("PPP: can't unregister line discipline (err = %d)\n", j);
-					}
-				}
-			}
-			return err;
-		}
-	}
-	return 0;
+	/* register our line disciplines */
+	status = ppp_first_time();
+	if (status != 0)
+		printk (KERN_INFO
+		       "PPP: ppp_init() failure %d\n", status);
+	return (status);
 }
 
 void
 cleanup_module(void)
 {
-	int i;
+	int status;
+	ppp_ctrl_t *ctl, *next_ctl;
+	struct device *dev;
+	struct ppp *ppp;
+	int busy_flag = MOD_IN_USE;
+/*
+ * Ensure that the devices are not in operation.
+ */
+	if (!busy_flag) {
+		ctl = ppp_list;
+		while (ctl) {
+			ppp = ctl2ppp (ctl);
+			if (ppp->inuse && ppp->tty != NULL) {
+				busy_flag = 1;
+				break;
+			}
 
-	if (MOD_IN_USE)  {
-		printk("PPP: device busy, remove delayed\n");
-		return;
+			dev = ctl2dev (ctl);
+			if (dev->start || dev->flags & IFF_UP) {
+				busy_flag = 1;
+				break;
+			}
+			ctl = ctl->next;
+		}
 	}
-	for (i = 0; i < PPP_NRUNIT; i++)  {
-		unregister_netdev(&dev_ppp[i]);
+/*
+ * Ensure that there are no compressor modules registered
+ */
+	if (busy_flag == 0 && ppp_compressors != NULL)
+		busy_flag = 1;
+
+	if (busy_flag) {
+		printk (KERN_INFO
+			"PPP: device busy, remove delayed\n");
+		return;
 	}
-	if ((i = tty_register_ldisc(N_PPP, NULL)))  {
-		printk("PPP: can't unregister line discipline (err = %d)\n", i);
+/*
+ * Release the tty registration of the line dicipline so that no new entries
+ * may be created.
+ */
+	status = tty_register_ldisc (N_PPP, NULL);
+	if (status != 0)
+		printk (KERN_INFO
+			"PPP: Unable to unregister ppp line discipline "
+			"(err = %d)\n", status);
+	else
+		printk (KERN_INFO
+		       "PPP: ppp line discipline successfully unregistered\n");
+/*
+ * Remove the symbol definitions
+ */
+	(void) register_symtab ((struct symbol_table *) 0);
+/*
+ * De-register the devices so that there is no problem with them
+ */	
+	next_ctl = ppp_list;
+	while (next_ctl) {
+		ctl      = next_ctl;
+		next_ctl = ctl->next;
+		ppp      = ctl2ppp (ctl);
+		dev      = ctl2dev (ctl);
+
+		ppp_release       (ppp);
+		unregister_netdev (dev);
+		kfree (ctl);
 	}
 }
-
 #endif
diff -u --recursive --new-file v1.3.32/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v1.3.32/linux/drivers/net/seeq8005.c	Sat Sep  9 15:26:53 1995
+++ linux/drivers/net/seeq8005.c	Tue Oct 10 15:45:27 1995
@@ -54,8 +54,6 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include "seeq8005.h"
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
-									unsigned long *mem_startp);
 
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
@@ -277,7 +275,7 @@
 
 	/* Allocate a new 'dev' if needed. */
 	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct net_local), 0);
+		dev = init_etherdev(0, sizeof(struct net_local));
 
 	if (net_debug  &&  version_printed++ == 0)
 		printk(version);
@@ -336,6 +334,8 @@
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
+	
+	dev->flags &= ~IFF_MULTICAST;
 
 	return 0;
 }
diff -u --recursive --new-file v1.3.32/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v1.3.32/linux/drivers/net/sk_g16.c	Sat Sep  9 15:26:53 1995
+++ linux/drivers/net/sk_g16.c	Tue Oct 10 15:45:27 1995
@@ -807,6 +807,8 @@
     /* Set the generic fields of the device structure */
 
     ether_setup(dev);
+    
+    dev->flags &= ~IFF_MULTICAST;
 
     /* Initialize private structure */
 
diff -u --recursive --new-file v1.3.32/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c
--- v1.3.32/linux/drivers/net/skeleton.c	Tue Aug 15 20:39:03 1995
+++ linux/drivers/net/skeleton.c	Tue Oct 10 14:03:45 1995
@@ -179,7 +179,7 @@
 		 * This makes it easier to free the memory when this driver
 		 * is used as a module.
 		 */
-		dev = init_etherdev(0, 0, 0);
+		dev = init_etherdev(0, 0);
 		if (dev == NULL)
 			return -ENOMEM;
 	}
diff -u --recursive --new-file v1.3.32/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v1.3.32/linux/drivers/net/smc-ultra.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/smc-ultra.c	Tue Oct 10 14:03:45 1995
@@ -139,7 +139,7 @@
 		return ENODEV;
 
 	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct ei_device), 0);
+		dev = init_etherdev(0, sizeof(struct ei_device));
 	if (dev == NULL) /* Still.. */
 		return ENOMEM; /* Out of memory ?? */
 
diff -u --recursive --new-file v1.3.32/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v1.3.32/linux/drivers/net/tulip.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/tulip.c	Tue Oct 10 14:21:31 1995
@@ -154,8 +154,7 @@
 	int pad0, pad1;						/* Used for 8-byte alignment */
 };
 
-static unsigned long tulip_probe1(unsigned long mem_start, int ioaddr,
-								  int irq);
+static void tulip_probe1(int ioaddr, int irq);
 static int tulip_open(struct device *dev);
 static void tulip_init_ring(struct device *dev);
 static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -174,7 +173,7 @@
    ourselves.  This is done by having the initialization occur before
    the 'kmalloc()' memory management system is started. */
 
-unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end)
+int dec21040_init(void)
 {
 
     if (pcibios_present()) {
@@ -195,11 +194,11 @@
 			if (tulip_debug > 2)
 				printk("Found DEC PCI Tulip at I/O %#lx, IRQ %d.\n",
 					   pci_ioaddr, pci_irq_line);
-			mem_start = tulip_probe1(mem_start, pci_ioaddr, pci_irq_line);
+			tulip_probe1(pci_ioaddr, pci_irq_line);
 		}
 	}
 
-	return mem_start;
+	return 0;
 }
 #endif
 #ifdef MODULE
@@ -210,7 +209,7 @@
 }
 #endif
 
-unsigned long tulip_probe1(unsigned long mem_start, int ioaddr, int irq)
+static void tulip_probe1(int ioaddr, int irq)
 {
 	static int did_version = 0;			/* Already printed version info. */
 	struct device *dev;
@@ -220,9 +219,7 @@
 	if (tulip_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
-	dev = init_etherdev(0, sizeof(struct tulip_private)
-						+ PKT_BUF_SZ*RX_RING_SIZE,
-						&mem_start);
+	dev = init_etherdev(0, 0);
 
 	printk("%s: DEC 21040 Tulip at %#3x,", dev->name, ioaddr);
 
@@ -252,9 +249,9 @@
 	dev->irq = irq;
 
 	/* Make certain the data structures are quadword aligned. */
-	dev->priv = (void *)(((int)dev->priv + 7) & ~7);
-	tp = (struct tulip_private *)dev->priv;
-	tp->rx_buffs = (long)dev->priv + sizeof(struct tulip_private);
+	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
+	dev->priv = tp;
+	tp->rx_buffs = kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_KERNEL | GFP_DMA);
 
 	/* The Tulip-specific entries in the device structure. */
 	dev->open = &tulip_open;
@@ -268,7 +265,7 @@
 	dev->set_mac_address = &set_mac_address;
 #endif
 
-	return mem_start;
+	return;
 }
 
 
diff -u --recursive --new-file v1.3.32/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v1.3.32/linux/drivers/net/wd.c	Wed Oct  4 14:14:31 1995
+++ linux/drivers/net/wd.c	Tue Oct 10 14:03:45 1995
@@ -119,7 +119,7 @@
 		return ENODEV;
 
 	if (dev == NULL)
-		dev = init_etherdev(0, sizeof(struct ei_device), 0);
+		dev = init_etherdev(0, sizeof(struct ei_device));
 
 	printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr);
 	for (i = 0; i < 6; i++)
diff -u --recursive --new-file v1.3.32/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v1.3.32/linux/drivers/net/znet.c	Fri Oct  6 14:35:15 1995
+++ linux/drivers/net/znet.c	Tue Oct 10 15:45:27 1995
@@ -640,11 +640,11 @@
 {
 	short ioaddr = dev->base_addr;
 
-	if (num_addrs < 0) {
+	if (num_addrs == -1) {
 		/* Enable promiscuous mode */
 		i593_init[7] &= ~3;		i593_init[7] |= 1;
 		i593_init[13] &= ~8;	i593_init[13] |= 8;
-	} else if (num_addrs > 0) {
+	} else if (num_addrs != 0) {
 		/* Enable accept-all-multicast mode */
 		i593_init[7] &= ~3;		i593_init[7] |= 0;
 		i593_init[13] &= ~8;	i593_init[13] |= 8;
diff -u --recursive --new-file v1.3.32/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.32/linux/drivers/scsi/scsi.c	Wed Sep 27 15:59:59 1995
+++ linux/drivers/scsi/scsi.c	Tue Oct 10 15:22:03 1995
@@ -2258,95 +2258,47 @@
     return 0;
 }
 
-/*
- * These are special functions that can be used to obtain memory at boot time.
- * They act line a malloc function, but they simply take memory from the pool 
- */
-
-static unsigned long scsi_init_memory_start = 0;
-static unsigned long scsi_memory_lower_value = 0;
-static unsigned long scsi_memory_upper_value = 0;
-int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
 
 void * scsi_init_malloc(unsigned int size, int priority)
 {
-    unsigned long retval;
-    int order, a_size;
+    void * retval;
     
-    /* Use the statically allocated memory instead of kmalloc  (DB) */
-#if defined(USE_STATIC_SCSI_MEMORY)
-    if(scsi_loadable_module_flag && !(priority & GFP_DMA))
-#else
-	if(scsi_loadable_module_flag)
-#endif
-	{
-	    /*
-	     * For buffers used by the DMA pool, we assume page aligned 
-	     * structures.
-	     */
-            if ((size % PAGE_SIZE) == 0) {
-                for (order = 0, a_size = PAGE_SIZE;
-                     a_size < size; order++, a_size <<= 1)
-                    ;
-                retval =
-                    (unsigned long) __get_dma_pages(priority & GFP_LEVEL_MASK,
-                                                    order);
-            }
-            else
-                retval = (unsigned long) kmalloc(size, priority);
-
-	} else {
-	    /*
-	     * Keep all memory aligned on 16-byte boundaries. Some host 
-	     * adaptors (e.g. BusLogic BT-445S) require DMA buffers to be 
-	     * aligned that way.
-	     */
-	    size = (size + 15) & ~15;
-	    
-	    if(scsi_loadable_module_flag &&
-	       (scsi_init_memory_start + size) > scsi_memory_upper_value) {
-		retval = 0;
-		printk("scsi_init_malloc: no more statically allocated memory.\n");
-	    }
-	    else {
-		retval = scsi_init_memory_start;
-		scsi_init_memory_start += size;
-	    }
-	}
+    /*
+     * For buffers used by the DMA pool, we assume page aligned 
+     * structures.
+     */
+    if ((size % PAGE_SIZE) == 0) {
+	int order, a_size;
+	for (order = 0, a_size = PAGE_SIZE;
+             a_size < size; order++, a_size <<= 1)
+            ;
+        retval = (void *) __get_dma_pages(priority & GFP_LEVEL_MASK,
+	                                            order);
+    } else
+        retval = kmalloc(size, priority);
+
     if (retval)
-	memset((void *) retval, 0, size);
-    return (void *) retval;
+	memset(retval, 0, size);
+    return retval;
 }
 
 
 void scsi_init_free(char * ptr, unsigned int size)
 { 
-    int order, a_size;
+    /*
+     * We need this special code here because the DMA pool assumes
+     * page aligned data.  Besides, it is wasteful to allocate
+     * page sized chunks with kmalloc.
+     */
+    if ((size % PAGE_SIZE) == 0) {
+    	int order, a_size;
 
-    /* We need to compare addresses to see whether this was kmalloc'd or not */
-    
-    if((unsigned long) ptr >= scsi_init_memory_start ||
-       (unsigned long) ptr <  scsi_memory_lower_value) {
-	/*
-	 * We need this special code here because the DMA pool assumes
-	 * page aligned data.  Besides, it is wasteful to allocate
-	 * page sized chunks with kmalloc.
-	 */
-        if ((size % PAGE_SIZE) == 0) {
-            for (order = 0, a_size = PAGE_SIZE;
-                 a_size < size; order++, a_size <<= 1)
-                ;
-            free_pages((unsigned long)ptr, order);
-        }
-        else
-            kfree(ptr);
-    } else {
-	/* Use the same alignment as scsi_init_malloc() */
-	size = (size + 15) & ~15;
-	
-	if(((unsigned long) ptr) + size == scsi_init_memory_start)
-	    scsi_init_memory_start = (unsigned long) ptr;
-    }
+	for (order = 0, a_size = PAGE_SIZE;
+	     a_size < size; order++, a_size <<= 1)
+	    ;
+	free_pages((unsigned long)ptr, order);
+    } else
+	kfree(ptr);
 }
 
 void scsi_build_commandblocks(Scsi_Device * SDpnt)
@@ -2382,11 +2334,10 @@
 
 /*
  * scsi_dev_init() is our initialization routine, which in turn calls host
- * initialization, bus scanning, and sd/st initialization routines.  It
- * should be called from main().
+ * initialization, bus scanning, and sd/st initialization routines. 
  */
 
-unsigned long scsi_dev_init (unsigned long memory_start, unsigned long memory_end)
+int scsi_dev_init(void)
 {
     struct Scsi_Host * host = NULL;
     Scsi_Device * SDpnt;
@@ -2400,13 +2351,6 @@
     /* Yes we're here... */
     dispatch_scsi_info_ptr = dispatch_scsi_info;
 
-    /* Init a few things so we can "malloc" memory. */
-    scsi_loadable_module_flag = 0;
-    
-    /* Align everything on 16-byte boundaries. */
-    scsi_init_memory_start = (memory_start + 15) & ~ 15;
-    scsi_memory_lower_value = scsi_init_memory_start;
-    
     timer_table[SCSI_TIMER].fn = scsi_main_timeout;
     timer_table[SCSI_TIMER].expires = 0;
 
@@ -2445,7 +2389,7 @@
     if (scsi_devicelist)
 	dma_sectors = 16;  /* Base value we use */
     
-    if (memory_end-1 > ISA_DMA_THRESHOLD)
+    if (high_memory-1 > ISA_DMA_THRESHOLD)
 	scsi_need_isa_bounce_buffers = 1;
     else
 	scsi_need_isa_bounce_buffers = 0;
@@ -2459,7 +2403,7 @@
 				 host->cmd_per_lun;
 	
 	if(host->unchecked_isa_dma &&
-	   memory_end - 1 > ISA_DMA_THRESHOLD &&
+	   high_memory - 1 > ISA_DMA_THRESHOLD &&
 	   SDpnt->type != TYPE_TAPE) {
 	    dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
 		host->cmd_per_lun;
@@ -2491,23 +2435,8 @@
     for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
 	if(sdtpnt->finish && sdtpnt->nr_dev)
 	    (*sdtpnt->finish)();
-    
-    scsi_loadable_module_flag = 1;
-    
-    /* This allocates statically some extra memory to be used for modules,
-     * until the kmalloc problem is fixed (DB) 
-     */
-    
-#if defined(USE_STATIC_SCSI_MEMORY)
-    scsi_memory_upper_value = scsi_init_memory_start + 256 * 1024;
-    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-    return scsi_memory_upper_value;
-#else
-    return scsi_init_memory_start;
-#endif
+
+    return 0;
 }
 
 static void print_inquiry(unsigned char *data)
@@ -2577,7 +2506,7 @@
 	while (HBA_ptr) {
 #if 0
 	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no, 
-                            HBA_ptr->hostt->procname);
+	                    HBA_ptr->hostt->procname);
 	    len += size; 
 	    pos = begin + len;
 #endif
@@ -2909,10 +2838,10 @@
 	if(shpnt->hostt == tpnt) {
 	    if(shpnt->loaded_as_module) {
 		pcount = next_scsi_host;
-                /* Remove the /proc/scsi directory entry */
+	        /* Remove the /proc/scsi directory entry */
 #if CONFIG_PROC_FS 
-                proc_scsi_unregister(tpnt->proc_dir, 
-                                     shpnt->host_no + PROC_SCSI_FILE);
+	        proc_scsi_unregister(tpnt->proc_dir, 
+	                             shpnt->host_no + PROC_SCSI_FILE);
 #endif   
 		if(tpnt->release)
 		    (*tpnt->release)(shpnt);
@@ -2991,7 +2920,7 @@
      * init function.
      */
     if(tpnt->init && tpnt->dev_noticed)
-        if ((*tpnt->init)()) return 1;
+	if ((*tpnt->init)()) return 1;
     
     /*
      * Now actually connect the devices to the new driver.
diff -u --recursive --new-file v1.3.32/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.32/linux/drivers/scsi/scsi.h	Wed Sep 27 15:59:59 1995
+++ linux/drivers/scsi/scsi.h	Tue Oct 10 15:52:46 1995
@@ -218,7 +218,7 @@
  *  Initializes all SCSI devices.  This scans all scsi busses.
  */ 
 
-extern unsigned long scsi_dev_init (unsigned long, unsigned long);
+extern int scsi_dev_init (void);
 
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
diff -u --recursive --new-file v1.3.32/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.3.32/linux/drivers/sound/soundcard.c	Mon Sep 25 12:26:22 1995
+++ linux/drivers/sound/soundcard.c	Tue Oct 10 10:15:35 1995
@@ -218,8 +218,8 @@
   sound_release
 };
 
-long
-soundcard_init (long mem_start)
+int
+soundcard_init (void)
 {
 #ifndef MODULE
   register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
@@ -227,31 +227,31 @@
 
   soundcard_configured = 1;
 
-  mem_start = sndtable_init (mem_start);	/* Initialize call tables and
-						 * detect cards */
+  sndtable_init ();		/* Initialize call tables and
+				 * detect cards */
 
   if (!(soundcards_installed = sndtable_get_cardcount ()))
-    return mem_start;		/* No cards detected */
+    return 0;			/* No cards detected */
 
 #ifndef EXCLUDE_AUDIO
   if (num_audiodevs)		/* Audio devices present */
     {
-      mem_start = DMAbuf_init (mem_start);
-      mem_start = audio_init (mem_start);
+      DMAbuf_init ();
+      audio_init ();
     }
 #endif
 
 #ifndef EXCLUDE_MIDI
   if (num_midis)
-    mem_start = MIDIbuf_init (mem_start);
+    MIDIbuf_init ();
 #endif
 
 #ifndef EXCLUDE_SEQUENCER
   if (num_midis + num_synths)
-    mem_start = sequencer_init (mem_start);
+    sequencer_init ();
 #endif
 
-  return mem_start;
+  return 0;
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.32/linux/fs/exec.c linux/fs/exec.c
--- v1.3.32/linux/fs/exec.c	Wed Sep 13 12:45:32 1995
+++ linux/fs/exec.c	Mon Oct  9 13:10:41 1995
@@ -171,6 +171,11 @@
 	char corefile[6+sizeof(current->comm)];
 	unsigned long dump_start, dump_size;
 	struct user dump;
+#ifdef __alpha__
+#       define START_DATA(u)	(u.start_data)
+#else
+#       define START_DATA(u)	(u.u_tsize << PAGE_SHIFT)
+#endif
 
 	if (!current->dumpable)
 		return 0;
@@ -211,7 +216,7 @@
 		goto close_coredump;
 	has_dumped = 1;
        	strncpy(dump.u_comm, current->comm, sizeof(current->comm));
-	dump.u_ar0 = (struct pt_regs *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
+	dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
 	dump.signal = signr;
 	dump_thread(regs, &dump);
 
@@ -228,7 +233,7 @@
 
 /* make sure we actually have a data and stack area to dump */
 	set_fs(USER_DS);
-	if (verify_area(VERIFY_READ, (void *) (dump.u_tsize << PAGE_SHIFT), dump.u_dsize << PAGE_SHIFT))
+	if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT))
 		dump.u_dsize = 0;
 	if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
 		dump.u_ssize = 0;
@@ -242,7 +247,7 @@
 	set_fs(USER_DS);
 /* Dump the data area */
 	if (dump.u_dsize != 0) {
-		dump_start = dump.u_tsize << PAGE_SHIFT;
+		dump_start = START_DATA(dump);
 		dump_size = dump.u_dsize << PAGE_SHIFT;
 		DUMP_WRITE(dump_start,dump_size);
 	}
@@ -456,16 +461,12 @@
 	return p;
 }
 
-unsigned long setup_arg_pages(unsigned long text_size,unsigned long * page)
+unsigned long setup_arg_pages(unsigned long text_size, unsigned long * page)
 {
-	unsigned long code_limit,data_limit,code_base,data_base;
+	unsigned long data_base;
 	int i;
 
-	code_limit = STACK_TOP;
-	data_limit = STACK_TOP;
-	code_base = data_base = 0;
-	current->mm->start_code = code_base;
-	data_base += data_limit;
+	data_base = STACK_TOP;
 	for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
 		data_base -= PAGE_SIZE;
 		if (page[i]) {
@@ -473,7 +474,7 @@
 			put_dirty_page(current,page[i],data_base);
 		}
 	}
-	return data_limit;
+	return STACK_TOP;
 }
 
 /*
diff -u --recursive --new-file v1.3.32/linux/fs/proc/array.c linux/fs/proc/array.c
--- v1.3.32/linux/fs/proc/array.c	Mon Sep 25 12:26:23 1995
+++ linux/fs/proc/array.c	Mon Oct  9 13:10:41 1995
@@ -61,10 +61,18 @@
 	int count1;
 	char * pnt;
 	struct user dump;
+#ifdef __i386__
+#	define FIRST_MAPPED	PAGE_SIZE	/* we don't have page 0 mapped on x86.. */
+#else
+#	define FIRST_MAPPED	0
+#endif
 
 	memset(&dump, 0, sizeof(struct user));
 	dump.magic = CMAGIC;
 	dump.u_dsize = MAP_NR(high_memory);
+#ifdef __alpha__
+	dump.start_data = PAGE_OFFSET;
+#endif
 
 	if (count < 0)
 		return -EINVAL;
@@ -87,14 +95,14 @@
 		read += count1;
 	}
 
-	while (p < 2*PAGE_SIZE && count > 0) {
+	while (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
 		put_user(0,buf);
 		buf++;
 		p++;
 		count--;
 		read++;
 	}
-	memcpy_tofs(buf,(void *) (PAGE_OFFSET + p - PAGE_SIZE),count);
+	memcpy_tofs(buf, (void *) (PAGE_OFFSET + p - PAGE_SIZE), count);
 	read += count;
 	file->f_pos += read;
 	return read;
diff -u --recursive --new-file v1.3.32/linux/include/asm-alpha/reg.h linux/include/asm-alpha/reg.h
--- v1.3.32/linux/include/asm-alpha/reg.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/reg.h	Mon Oct  9 13:10:41 1995
@@ -0,0 +1,52 @@
+#ifndef __reg_h__
+#define __reg_h__
+
+/*
+ * Exception frame offsets.
+ */
+#define EF_V0		0
+#define EF_T0		1
+#define EF_T1		2
+#define EF_T2		3
+#define EF_T3		4
+#define EF_T4		5
+#define EF_T5		6
+#define EF_T6		7
+#define EF_T7		8
+#define EF_S0		9
+#define EF_S1		10
+#define EF_S2		11
+#define EF_S3		12
+#define EF_S4		13
+#define EF_S5		14
+#define EF_S6		15
+#define EF_A3		16
+#define EF_A4		17
+#define EF_A5		18
+#define EF_T8		19
+#define EF_T9		20
+#define EF_T10		21
+#define EF_T11		22
+#define EF_RA		23
+#define EF_T12		24
+#define EF_AT		25
+#define EF_SP		26
+#define EF_PS		27
+#define EF_PC		28
+#define EF_GP		29
+#define EF_A0		30
+#define EF_A1		31
+#define EF_A2		32
+
+#define EF_SIZE		(33*8)
+#define HWEF_SIZE	(6*8)		/* size of PAL frame (PS-A2) */
+
+#define EF_SSIZE	(EF_SIZE - HWEF_SIZE)
+
+/*
+ * Map register number into core file offset.
+ */
+#define CORE_REG(reg, ubase) \
+	(((unsigned long *)((unsigned long)(ubase)))[reg])
+
+#endif /* __reg_h__ */
diff -u --recursive --new-file v1.3.32/linux/include/asm-alpha/signal.h linux/include/asm-alpha/signal.h
--- v1.3.32/linux/include/asm-alpha/signal.h	Wed Sep 27 16:00:00 1995
+++ linux/include/asm-alpha/signal.h	Sat Oct  7 14:53:43 1995
@@ -43,6 +43,8 @@
 #define SIGUSR2		31
 
 #define SIGPOLL	SIGIO
+#define SIGPWR	SIGINFO
+#define SIGIOT	SIGABRT
 
 /*
  * sa_flags values: SA_STACK is not currently supported, but will allow the
diff -u --recursive --new-file v1.3.32/linux/include/asm-alpha/user.h linux/include/asm-alpha/user.h
--- v1.3.32/linux/include/asm-alpha/user.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-alpha/user.h	Mon Oct  9 13:10:41 1995
@@ -0,0 +1,52 @@
+#ifndef _ALPHA_USER_H
+#define _ALPHA_USER_H
+
+#include <linux/ptrace.h>
+
+#include <asm/page.h>
+#include <asm/reg.h>
+
+/*
+ * Core file format: The core file is written in such a way that gdb
+ * can understand it and provide useful information to the user (under
+ * linux we use the `trad-core' bfd, NOT the osf-core).  The file contents
+ * are as follows:
+ *
+ *  upage: 1 page consisting of a user struct that tells gdb
+ *	what is present in the file.  Directly after this is a
+ *	copy of the task_struct, which is currently not used by gdb,
+ *	but it may come in handy at some point.  All of the registers
+ *	are stored as part of the upage.  The upage should always be
+ *	only one page long.
+ *  data: The data segment follows next.  We use current->end_text to
+ *	current->brk to pick up all of the user variables, plus any memory
+ *	that may have been sbrk'ed.  No attempt is made to determine if a
+ *	page is demand-zero or if a page is totally unused, we just cover
+ *	the entire range.  All of the addresses are rounded in such a way
+ *	that an integral number of pages is written.
+ *  stack: We need the stack information in order to get a meaningful
+ *	backtrace.  We need to write the data from usp to
+ *	current->start_stack, so we round each of these in order to be able
+ *	to write an integer number of pages.
+ */
+struct user {
+	unsigned long	regs[EF_SIZE/8+32];	/* integer and fp regs */
+	size_t		u_tsize;		/* text size (pages) */
+	size_t		u_dsize;		/* data size (pages) */
+	size_t		u_ssize;		/* stack size (pages) */
+	unsigned long	start_code;		/* text starting address */
+	unsigned long	start_data;		/* data starting address */
+	unsigned long	start_stack;		/* stack starting address */
+	long int	signal;			/* signal causing core dump */
+	struct regs *	u_ar0;			/* help gdb find registers */
+	unsigned long	magic;			/* identifies a core file */
+	char		u_comm[32];		/* user command name */
+};
+
+#define NBPG			PAGE_SIZE
+#define UPAGES			1
+#define HOST_TEXT_START_ADDR	(u.start_code)
+#define HOST_DATA_START_ADDR	(u.start_data)
+#define HOST_STACK_END_ADDR	(u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _ALPHA_USER_H */
diff -u --recursive --new-file v1.3.32/linux/include/asm-i386/segment.h linux/include/asm-i386/segment.h
--- v1.3.32/linux/include/asm-i386/segment.h	Fri Jul  7 08:54:53 1995
+++ linux/include/asm-i386/segment.h	Sun Oct  8 12:37:07 1995
@@ -81,7 +81,7 @@
 }
 
 /*
- * These are depracated..
+ * These are deprecated..
  */
 
 static inline unsigned char get_user_byte(const char * addr)
diff -u --recursive --new-file v1.3.32/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v1.3.32/linux/include/asm-i386/unistd.h	Wed Oct  4 14:14:34 1995
+++ linux/include/asm-i386/unistd.h	Tue Oct 10 08:53:08 1995
@@ -271,6 +271,34 @@
 	return waitpid(-1,wait_stat,0);
 }
 
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	long retval;
+
+	__asm__ __volatile__(
+		"int $0x80\n\t"		/* Linux/i386 system call */
+		"testl %0,%0\n\t"	/* child or parent? */
+		"jne 1f\n\t"		/* parent - jump */
+		"pushl %3\n\t"		/* push argument */
+		"call *%4\n\t"		/* call fn */
+		"movl %2,%0\n\t"	/* exit */
+		"int $0x80\n"
+		"1:\t"
+		:"=a" (retval)
+		:"0" (__NR_clone), "i" (__NR_exit),
+		 "r" (arg), "r" (fn),
+		 "b" (flags | CLONE_VM));
+	return retval;
+}
+
 #endif
 
 #endif /* _ASM_I386_UNISTD_H_ */
diff -u --recursive --new-file v1.3.32/linux/include/asm-i386/user.h linux/include/asm-i386/user.h
--- v1.3.32/linux/include/asm-i386/user.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-i386/user.h	Mon Oct  9 13:10:41 1995
@@ -0,0 +1,78 @@
+#ifndef _I386_USER_H
+#define _I386_USER_H
+
+#include <asm/page.h>
+#include <linux/ptrace.h>
+/* Core file format: The core file is written in such a way that gdb
+   can understand it and provide useful information to the user (under
+   linux we use the 'trad-core' bfd).  There are quite a number of
+   obstacles to being able to view the contents of the floating point
+   registers, and until these are solved you will not be able to view the
+   contents of them.  Actually, you can read in the core file and look at
+   the contents of the user struct to find out what the floating point
+   registers contain.
+   The actual file contents are as follows:
+   UPAGE: 1 page consisting of a user struct that tells gdb what is present
+   in the file.  Directly after this is a copy of the task_struct, which
+   is currently not used by gdb, but it may come in useful at some point.
+   All of the registers are stored as part of the upage.  The upage should
+   always be only one page.
+   DATA: The data area is stored.  We use current->end_text to
+   current->brk to pick up all of the user variables, plus any memory
+   that may have been malloced.  No attempt is made to determine if a page
+   is demand-zero or if a page is totally unused, we just cover the entire
+   range.  All of the addresses are rounded in such a way that an integral
+   number of pages is written.
+   STACK: We need the stack information in order to get a meaningful
+   backtrace.  We need to write the data from (esp) to
+   current->start_stack, so we round each of these off in order to be able
+   to write an integer number of pages.
+   The minimum core file size is 3 pages, or 12288 bytes.
+*/
+
+struct user_i387_struct {
+	long	cwd;
+	long	swd;
+	long	twd;
+	long	fip;
+	long	fcs;
+	long	foo;
+	long	fos;
+	long	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+   this will be used by gdb to figure out where the data and stack segments
+   are within the file, and what virtual addresses to use. */
+struct user{
+/* We start with the registers, to mimic the way that "memory" is returned
+   from the ptrace(3,...) function.  */
+  struct pt_regs regs;		/* Where the registers are actually stored */
+/* ptrace does not yet supply these.  Someday.... */
+  int u_fpvalid;		/* True if math co-processor being used. */
+                                /* for this mess. Not yet used. */
+  struct user_i387_struct i387;	/* Math Co-processor registers. */
+/* The rest of this junk is to help gdb figure out what goes where */
+  unsigned long int u_tsize;	/* Text segment size (pages). */
+  unsigned long int u_dsize;	/* Data segment size (pages). */
+  unsigned long int u_ssize;	/* Stack segment size (pages). */
+  unsigned long start_code;     /* Starting virtual address of text. */
+  unsigned long start_stack;	/* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  long int signal;     		/* Signal that caused the core dump. */
+  int reserved;			/* No longer used */
+  struct pt_regs * u_ar0;	/* Used by gdb to help find the values for */
+				/* the registers. */
+  struct user_i387_struct* u_fpstate;	/* Math Co-processor pointer. */
+  unsigned long magic;		/* To uniquely identify a core file */
+  char u_comm[32];		/* User command that was responsible */
+  int u_debugreg[8];
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _I386_USER_H */
diff -u --recursive --new-file v1.3.32/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h
--- v1.3.32/linux/include/linux/etherdevice.h	Wed Aug  9 14:55:42 1995
+++ linux/include/linux/etherdevice.h	Tue Oct 10 14:01:30 1995
@@ -37,7 +37,7 @@
 extern void 		eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
 extern void		eth_copy_and_sum(struct sk_buff *dest,
 				unsigned char *src, int length, int base);
-extern struct device	* init_etherdev(struct device *, int, unsigned long*);
+extern struct device	* init_etherdev(struct device *, int);
 
 #endif
 
diff -u --recursive --new-file v1.3.32/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v1.3.32/linux/include/linux/genhd.h	Tue Aug 15 20:39:04 1995
+++ linux/include/linux/genhd.h	Sun Oct  8 12:37:07 1995
@@ -14,8 +14,11 @@
 #ifdef __alpha__
 #define CONFIG_OSF_PARTITION 1
 #endif
-	
-#define EXTENDED_PARTITION 5
+
+/* These two have identical behaviour; use the second one if DOS fdisk gets
+   confused about extended/logical partitions starting past cylinder 1023. */	
+#define DOS_EXTENDED_PARTITION 5
+#define LINUX_EXTENDED_PARTITION 0x85
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
 #define EZD_PARTITION		0x55	/* EZ-DRIVE:  same as DM6 (we think) */
@@ -57,7 +60,6 @@
 	struct gendisk *next;
 };
 
-extern int NR_GENDISKS;			/* total */
 extern struct gendisk *gendisk_head;	/* linked list of disks */
 
 #endif
diff -u --recursive --new-file v1.3.32/linux/include/linux/if_ppp.h linux/include/linux/if_ppp.h
--- v1.3.32/linux/include/linux/if_ppp.h	Tue Jul 25 18:21:23 1995
+++ linux/include/linux/if_ppp.h	Mon Oct  9 09:17:54 1995
@@ -1,237 +1,143 @@
-#ifndef _LINUX_IF_PPP_H
-#define _LINUX_IF_PPP_H
+/*	$Id: if_ppp.h,v 1.3 1995/06/12 11:36:50 paulus Exp $	*/
 
-/* definitions for kernel PPP module
-   Michael Callahan <callahan@maths.ox.ac.uk>
-   Nov. 4 1993 */
-
-/* how many PPP units? */
-#ifdef CONFIG_PPP_LOTS
-#define PPP_NRUNIT     16
-#else
-#define PPP_NRUNIT     4
-#endif
-
-#define PPP_VERSION  "0.2.7"
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
 
-/* line discipline number */
-#define N_PPP	       3
+/*
+ *  ==FILEVERSION 3==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     if_ppp.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new if_ppp.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
 
-/* Magic value for the ppp structure */
-#define PPP_MAGIC 0x5002
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
 
-#define	PPPIOCGFLAGS	 0x5490	/* get configuration flags */
-#define	PPPIOCSFLAGS	 0x5491	/* set configuration flags */
-#define	PPPIOCGASYNCMAP	 0x5492	/* get async map */
-#define	PPPIOCSASYNCMAP	 0x5493	/* set async map */
-#define	PPPIOCGUNIT	 0x5494	/* get ppp unit number */
-#define PPPIOCSINPSIG	 0x5495	/* set input ready signal */
-#define PPPIOCSDEBUG	 0x5497	/* set debug level */
-#define PPPIOCGDEBUG	 0x5498	/* get debug level */
-#define PPPIOCGSTAT	 0x5499	/* read PPP statistic information */
-#define PPPIOCGTIME	 0x549A	/* read time delta information */
-#define	PPPIOCGXASYNCMAP 0x549B	/* get async table */
-#define	PPPIOCSXASYNCMAP 0x549C	/* set async table */
-#define PPPIOCSMRU	 0x549D	/* set receive unit size for PPP */
-#define PPPIOCRASYNCMAP	 0x549E	/* set receive async map */
-#define PPPIOCSMAXCID    0x549F /* set the maximum compression slot id */
-
-/* special characters in the framing protocol */
-#define	PPP_ALLSTATIONS	0xff	/* All-Stations broadcast address */
-#define	PPP_UI		0x03	/* Unnumbered Information */
-#define PPP_FLAG	0x7E	/* frame delimiter -- marks frame boundaries */
-#define PPP_ADDRESS	0xFF	/* first character of frame   <--  (may be   */
-#define PPP_CONTROL	0x03	/* second character of frame  <-- compressed)*/
-#define	PPP_TRANS	0x20	/* Asynchronous transparency modifier */
-#define PPP_ESC		0x7d	/* escape character -- next character is
-				   data, and the PPP_TRANS bit should be
-				   toggled. PPP_ESC PPP_FLAG is illegal */
-
-/* protocol numbers */
-#define PROTO_IP       0x0021
-#define PROTO_VJCOMP   0x002d
-#define PROTO_VJUNCOMP 0x002f
-
-/* FCS support */
-#define PPP_FCS_INIT   0xffff
-#define PPP_FCS_GOOD   0xf0b8
+/*
+ * Packet sizes
+ */
 
-/* initial MTU */
-#define PPP_MTU	       1500
+#define	PPP_MTU		1500	/* Default MTU (size of Info field) */
+#define PPP_MAXMRU	65000	/* Largest MRU we allow */
+#define PPP_VERSION	"2.2.0"
+#define PPP_MAGIC	0x5002	/* Magic value for the ppp structure */
+#define PROTO_IPX	0x002b	/* protocol numbers */
 
-/* initial MRU */
-#define PPP_MRU	       PPP_MTU
+/*
+ * Bit definitions for flags.
+ */
 
-/* flags */
 #define SC_COMP_PROT	0x00000001	/* protocol compression (output) */
 #define SC_COMP_AC	0x00000002	/* header compression (output) */
 #define	SC_COMP_TCP	0x00000004	/* TCP (VJ) compression (output) */
 #define SC_NO_TCP_CCID	0x00000008	/* disable VJ connection-id comp. */
 #define SC_REJ_COMP_AC	0x00000010	/* reject adrs/ctrl comp. on input */
 #define SC_REJ_COMP_TCP	0x00000020	/* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN	0x00000040	/* Look at CCP packets */
+#define SC_CCP_UP	0x00000080	/* May send/recv compressed packets */
 #define SC_ENABLE_IP	0x00000100	/* IP packets may be exchanged */
-#define SC_IP_DOWN	0x00000200	/* give ip frames to pppd */
-#define SC_IP_FLUSH	0x00000400	/* "next time" flag for IP_DOWN */
+#define SC_COMP_RUN	0x00001000	/* compressor has been inited */
+#define SC_DECOMP_RUN	0x00002000	/* decompressor has been inited */
 #define SC_DEBUG	0x00010000	/* enable debug messages */
 #define SC_LOG_INPKT	0x00020000	/* log contents of good pkts recvd */
 #define SC_LOG_OUTPKT	0x00040000	/* log contents of pkts sent */
 #define SC_LOG_RAWIN	0x00080000	/* log all chars received */
 #define SC_LOG_FLUSH	0x00100000	/* log all chars flushed */
+#define	SC_MASK		0x0fE0ffff	/* bits that user can change */
 
-/* Flag bits to determine state of input characters */
-#define SC_RCV_B7_0	0x01000000	/* have rcvd char with bit 7 = 0 */
-#define SC_RCV_B7_1	0x02000000	/* have rcvd char with bit 7 = 0 */
-#define SC_RCV_EVNP	0x04000000	/* have rcvd char with even parity */
-#define SC_RCV_ODDP	0x08000000	/* have rcvd char with odd parity */
-
-#define	SC_MASK		0x0fffffff	/* bits that user can change */
-
-/* flag for doing transmitter lockout */
+/* state bits */
+#define	SC_ESCAPED	0x80000000	/* saw a PPP_ESCAPE */
+#define	SC_FLUSH	0x40000000	/* flush input until next PPP_FLAG */
+#define SC_VJ_RESET	0x20000000	/* Need to reset the VJ decompressor */
 #define SC_XMIT_BUSY	0x10000000	/* ppp_write_wakeup is active */
+#define SC_RCV_ODDP	0x08000000	/* have rcvd char with odd parity */
+#define SC_RCV_EVNP	0x04000000	/* have rcvd char with even parity */
+#define SC_RCV_B7_1	0x02000000	/* have rcvd char with bit 7 = 1 */
+#define SC_RCV_B7_0	0x01000000	/* have rcvd char with bit 7 = 0 */
+#define SC_DC_FERROR	0x00800000	/* fatal decomp error detected */
+#define SC_DC_ERROR	0x00400000	/* non-fatal decomp error detected */
 
 /*
- * This is the format of the data buffer of a LQP packet. The packet data
- * is sent/received to the peer.
+ * Ioctl definitions.
  */
 
-struct ppp_lqp_packet_hdr {
-  __u32		LastOutLQRs;	/* Copied from PeerOutLQRs	 */
-  __u32		LastOutPackets; /* Copied from PeerOutPackets	 */
-  __u32		LastOutOctets;	/* Copied from PeerOutOctets	 */
-  __u32		PeerInLQRs;	/* Copied from SavedInLQRs	 */
-  __u32		PeerInPackets;	/* Copied from SavedInPackets	 */
-  __u32		PeerInDiscards; /* Copied from SavedInDiscards	 */
-  __u32		PeerInErrors;	/* Copied from SavedInErrors	 */
-  __u32		PeerInOctets;	/* Copied from SavedInOctets	 */
-  __u32		PeerOutLQRs;	/* Copied from OutLQRs, plus 1	 */
-  __u32		PeerOutPackets; /* Current ifOutUniPackets, + 1	 */
-  __u32		PeerOutOctets;	/* Current ifOutOctets + LQR	 */
-  };
-
-/*
- * This data is not sent to the remote. It is updated by the driver when
- * a packet is received.
- */
-
-struct ppp_lqp_packet_trailer {
-  __u32		SaveInLQRs;	/* Current InLQRs on reception	 */
-  __u32		SaveInPackets;	/* Current ifInUniPackets	 */
-  __u32		SaveInDiscards; /* Current ifInDiscards		 */
-  __u32		SaveInErrors;	/* Current ifInErrors		 */
-  __u32		SaveInOctets;	/* Current ifInOctects		 */
+struct npioctl {
+    int		protocol;	/* PPP procotol, e.g. PPP_IP */
+    enum NPmode	mode;
 };
 
-/*
- * PPP LQP packet. The packet is changed by the driver immediately prior
- * to transmission and updated upon reception with the current values.
- * So, it must be known to the driver as well as the pppd software.
- */
-
-struct ppp_lpq_packet {
-  __u32				magic;	/* current magic value		 */
-  struct ppp_lqp_packet_hdr	hdr;	/* Header fields for structure	 */
-  struct ppp_lqp_packet_trailer tail;	/* Trailer fields (not sent)	 */
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+	u_char	*ptr;
+	u_int	length;
+	int	transmit;
 };
 
-/*
- * PPP interface statistics. (used by LQP / pppstats)
- */
-
-struct ppp_stats {
-  __u32		rbytes;		/* bytes received		 */
-  __u32		rcomp;		/* compressed packets received	 */
-  __u32		runcomp;	/* uncompressed packets received */
-  __u32		rothers;	/* non-ip frames received	 */
-  __u32		rerrors;	/* received errors		 */
-  __u32		roverrun;	/* "buffer overrun" counter	 */
-  __u32		tossed;		/* packets discarded		 */
-  __u32		runts;		/* frames too short to process	 */
-  __u32		rgiants;	/* frames too large to process	 */
-  __u32		sbytes;		/* bytes sent			 */
-  __u32		scomp;		/* compressed packets sent	 */
-  __u32		suncomp;	/* uncompressed packets sent	 */
-  __u32		sothers;	/* non-ip frames sent		 */
-  __u32		serrors;	/* transmitter errors		 */
-  __u32		sbusy;		/* "transmitter busy" counter	 */
+struct ifpppstatsreq {
+  struct ifreq	   b;
+  struct ppp_stats stats;			/* statistic information */
 };
 
-/*
- * Demand dial fields
- */
-
-struct ppp_ddinfo {
-  unsigned long		ip_sjiffies;	/* time when last IP frame sent */
-  unsigned long		ip_rjiffies;	/* time when last IP frame recvd*/
-  unsigned long		nip_sjiffies;	/* time when last NON-IP sent	*/
-  unsigned long		nip_rjiffies;	/* time when last NON-IP recvd	*/
+struct ifpppcstatsreq {
+  struct ifreq		b;
+  struct ppp_comp_stats stats;
 };
 
-#ifdef __KERNEL__
-
-struct ppp {
-  int			magic;		/* magic value for structure	*/
-
-  /* Bitmapped flag fields. */
-  char			sending;	/* "channel busy" indicator	*/
-  char			escape;		/* 0x20 if prev char was PPP_ESC*/
-  char			toss;		/* toss this frame		*/
-  unsigned long		inuse;		/* are we allocated?		*/
-
-  unsigned int		flags;		/* miscellany			*/
-
-  __u32			xmit_async_map[8]; /* 1 bit means that given control 
-					   character is quoted on output*/
-
-  __u32			recv_async_map; /* 1 bit means that given control 
-					   character is ignored on input*/
-  int			mtu;		/* maximum xmit frame size	*/
-  int			mru;		/* maximum receive frame size	*/
-  unsigned short	fcs;		/* FCS field of current frame	*/
-
-  /* Various fields. */
-  int			line;		/* PPP channel number		*/
-  struct tty_struct	*tty;		/* ptr to TTY structure		*/
-  struct device		*dev;		/* easy for intr handling	*/
-  struct slcompress	*slcomp;	/* for header compression	*/
-  unsigned long		last_xmit;	/* time of last transmission	*/
-
-  /* These are pointers to the malloc()ed frame buffers.
-     These buffers are used while processing a packet.	If a packet
-     has to hang around for the user process to read it, it lingers in
-     the user buffers below. */
-  unsigned char		*rbuff;		/* receiver buffer		*/
-  unsigned char		*xbuff;		/* transmitter buffer		*/
-  unsigned char		*cbuff;		/* compression buffer		*/
-
-  /* These are the various pointers into the buffers. */
-  unsigned char		*rhead;		/* RECV buffer pointer (head)	*/
-  unsigned char		*rend;		/* RECV buffer pointer (end)	*/
-  int			rcount;		/* PPP receive counter		*/
-  unsigned char		*xhead;		/* XMIT buffer pointer (head)	*/
-  unsigned char 	*xtail;		/* XMIT buffer pointer (end) 	*/
-
-  /* Structures for interfacing with the user process. */
-#define RBUFSIZE 4000
-  unsigned char		*us_rbuff;	/* circular incoming packet buf.*/
-  unsigned char		*us_rbuff_end;	/* end of allocated space	*/
-  unsigned char		*us_rbuff_head; /* head of waiting packets	*/
-  unsigned char		*us_rbuff_tail; /* tail of waiting packets	*/
-  unsigned long		us_rbuff_lock;	/* lock: bit 0 head bit 1 tail	*/
-  int			inp_sig;	/* input ready signal for pgrp	*/
-  int			inp_sig_pid;	/* process to get notified	*/
-
-  /* items to support the select() function */
-  struct wait_queue	*write_wait;	/* queue for reading processes	*/
-  struct wait_queue	*read_wait;	/* queue for writing processes	*/
-
-  /* PPP interface statistics. */
-  struct ppp_stats	stats;		/* statistic information	*/
+#define ifr__name       b.ifr_ifrn.ifrn_name
+#define stats_ptr       b.ifr_ifru.ifru_data
 
-  /* PPP demand dial information. */
-  struct ppp_ddinfo	ddinfo;		/* demand dial information	*/
-};
+/*
+ * Ioctl definitions.
+ */
 
-#endif	/* __KERNEL__ */
-#endif	/* _LINUX_PPP_H */
+#define	PPPIOCGFLAGS	_IOR('t', 90, int)	/* get configuration flags */
+#define	PPPIOCSFLAGS	_IOW('t', 89, int)	/* set configuration flags */
+#define	PPPIOCGASYNCMAP	_IOR('t', 88, int)	/* get async map */
+#define	PPPIOCSASYNCMAP	_IOW('t', 87, int)	/* set async map */
+#define	PPPIOCGUNIT	_IOR('t', 86, int)	/* get ppp unit number */
+#define	PPPIOCGRASYNCMAP _IOR('t', 85, int)	/* get receive async map */
+#define	PPPIOCSRASYNCMAP _IOW('t', 84, int)	/* set receive async map */
+#define	PPPIOCGMRU	_IOR('t', 83, int)	/* get max receive unit */
+#define	PPPIOCSMRU	_IOW('t', 82, int)	/* set max receive unit */
+#define	PPPIOCSMAXCID	_IOW('t', 81, int)	/* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT	_IO('t', 78)		/* transfer PPP unit */
+#define PPPIOCSCOMPRESS	_IOW('t', 77, struct ppp_option_data)
+#define PPPIOCGNPMODE	_IOWR('t', 76, struct npioctl) /* get NP mode */
+#define PPPIOCSNPMODE	_IOW('t', 75, struct npioctl)  /* set NP mode */
+#define PPPIOCGDEBUG	_IOR('t', 65, int)	/* Read debug level */
+#define PPPIOCSDEBUG	_IOW('t', 64, int)	/* Set debug level */
+#define PPPIOCGIDLE	_IOR('t', 63, struct ppp_idle) /* get idle time */
+
+#define SIOCGPPPSTATS   (SIOCDEVPRIVATE + 0)
+#define SIOCGPPPVER     (SIOCDEVPRIVATE + 1)  /* NEVER change this!! */
+#define SIOCGPPPCSTATS  (SIOCDEVPRIVATE + 2)
 
+#if !defined(ifr_mtu)
+#define ifr_mtu	ifr_ifru.ifru_metric
+#endif
 
+#endif /* _IF_PPP_H_ */
diff -u --recursive --new-file v1.3.32/linux/include/linux/if_pppvar.h linux/include/linux/if_pppvar.h
--- v1.3.32/linux/include/linux/if_pppvar.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/if_pppvar.h	Mon Oct  9 09:17:54 1995
@@ -0,0 +1,156 @@
+/*	$Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $	*/
+/*
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ *  ==FILEVERSION 3==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     if_pppvar.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new if_pppvar.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+/*
+ * Supported network protocols.  These values are used for
+ * indexing sc_npmode.
+ */
+
+#define NP_IP	0		/* Internet Protocol */
+#define NUM_NP	1		/* Number of NPs. */
+
+/*
+ * Buffers for the PPP process have the following structure
+ */
+
+#define RBUFSIZE  2048           /* MUST be a power of 2 and be <= 4095 */
+
+struct ppp_buffer {
+  int			size;		/* Size of the buffer area	*/
+  int			count;		/* Count of characters in bufr	*/
+  int			head;		/* index to head of list	*/
+  int			tail;		/* index to tail of list	*/
+  unsigned long		locked;		/* Buffer is being sent		*/
+  int			type;		/* Type of the buffer		*/
+					/* =0, device read buffer	*/
+					/* =1, device write buffer	*/
+					/* =2, daemon write buffer	*/
+					/* =3, daemon read buffer	*/
+  unsigned short	fcs;		/* Frame Check Sequence (CRC)	*/
+  unsigned char         filler[4];      /* Extra space if needed        */
+};
+
+/* Given a pointer to the ppp_buffer then return base address of buffer */
+#define buf_base(buf) ((u_char *) (&buf[1]))
+
+/*
+ * Structure describing each ppp unit.
+ */
+
+struct ppp {
+	int		magic;		/* magic value for structure	*/
+
+  /* Bitmapped flag fields. */
+	char		inuse;		/* are we allocated?		*/
+	char		escape;		/* 0x20 if prev char was PPP_ESC*/
+	char		toss;		/* toss this frame		*/
+
+	unsigned int	flags;		/* miscellany			*/
+
+	ext_accm	xmit_async_map; /* 1 bit means that given control 
+					   character is quoted on output*/
+
+	__u32		recv_async_map; /* 1 bit means that given control 
+					   character is ignored on input*/
+	int			mtu;	/* maximum xmit frame size	*/
+	int			mru;	/* maximum receive frame size	*/
+
+  /* Information about the current tty data */
+	int			line;		/* PPP channel number	*/
+	struct tty_struct	*tty;		/* ptr to TTY structure	*/
+	int			bytes_sent;	/* Bytes sent on frame	*/
+	int			bytes_rcvd;	/* Bytes recvd on frame	*/
+
+  /* Interface to the network layer */
+	struct device		*dev;	/* easy for intr handling	*/
+
+  /* VJ Header compression data */
+	struct slcompress	*slcomp;/* for header compression	*/
+
+  /* Transmission information */
+	struct ppp_buffer *xbuf;	/* Buffer currently being sent  */
+	struct ppp_buffer *s1buf;	/* Pointer to daemon buffer	*/
+	struct ppp_buffer *s2buf;	/* Pointer to device buffer	*/
+
+	__u32		  last_xmit;	/* time of last transmission	*/
+
+  /* These are pointers to the malloc()ed frame buffers.
+     These buffers are used while processing a packet.	If a packet
+     has to hang around for the user process to read it, it lingers in
+     the user buffers below. */
+
+	struct ppp_buffer *wbuf;	/* Transmission information	*/
+	struct ppp_buffer *tbuf;	/* daemon transmission buffer	*/
+	struct ppp_buffer *rbuf;	/* Receive information		*/
+	struct ppp_buffer *ubuf;	/* User buffer information	*/
+	struct ppp_buffer *cbuf;	/* compression buffer		*/
+
+  /* Queues for select() functionality */
+	struct wait_queue *write_wait;	/* queue for reading processes	*/
+	struct wait_queue *read_wait;	/* queue for writing processes	*/
+
+  /* Statistic information */
+	struct pppstat        stats;	/* statistic information	*/
+	struct ppp_idle       ddinfo;	/* demand dial information	*/
+
+  /* PPP compression protocol information */
+	u_int	sc_bytessent;		  /* count of octets sent */
+	u_int	sc_bytesrcvd;		  /* count of octets received */
+	enum	NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
+	struct	compressor *sc_xcomp;	  /* transmit compressor */
+	void	*sc_xc_state;		  /* transmit compressor state */
+	struct	compressor *sc_rcomp;	  /* receive decompressor */
+	void	*sc_rc_state;		  /* receive decompressor state */
+};
diff -u --recursive --new-file v1.3.32/linux/include/linux/ip_fw.h linux/include/linux/ip_fw.h
--- v1.3.32/linux/include/linux/ip_fw.h	Wed Sep 13 12:45:32 1995
+++ linux/include/linux/ip_fw.h	Tue Oct 10 15:59:36 1995
@@ -140,10 +140,11 @@
 	struct timer_list timer;	/* Expiration timer */
 	__u16 		protocol;	/* Which protocol are we talking? */
 	__u32 		src, dst;	/* Source and destination IP addresses */
-	__u16		sport,dport;	/* Source and destoination ports */
+	__u16		sport,dport;	/* Source and destination ports */
 	__u16		mport;		/* Masquaraded port */
 	__u32		init_seq;	/* Add delta from this seq. on */
 	short		delta;		/* Delta in sequence numbers */
+	short		previous_delta;	/* Delta in sequence numbers before last resized PORT command */
 	char		sawfin;		/* Did we saw an FIN packet? */
 };
 extern struct ip_masq *ip_msq_hosts;
@@ -186,6 +187,7 @@
  
 #define PORT_MASQ_BEGIN	60000
 #define PORT_MASQ_END	(PORT_MASQ_BEGIN+4096)
+#define FTP_DPORT_TBD (PORT_MASQ_END+1) /* Avoid using hardcoded port 20 for ftp data connection */
 #endif
 
 #endif /* _IP_FW_H */
diff -u --recursive --new-file v1.3.32/linux/include/linux/keyboard.h linux/include/linux/keyboard.h
--- v1.3.32/linux/include/linux/keyboard.h	Fri Feb 24 21:38:27 1995
+++ linux/include/linux/keyboard.h	Sun Oct  8 12:37:07 1995
@@ -38,6 +38,7 @@
 #define KT_META		8
 #define KT_ASCII	9
 #define KT_LOCK		10
+#define KT_SLOCK	12
 
 #define K(t,v)		(((t)<<8)|(v))
 #define KTYP(x)		((x) >> 8)
@@ -406,6 +407,15 @@
 #define K_SHIFTRLOCK	K(KT_LOCK,KG_SHIFTR)
 #define K_CTRLLLOCK	K(KT_LOCK,KG_CTRLL)
 #define K_CTRLRLOCK	K(KT_LOCK,KG_CTRLR)
+
+#define K_SHIFT_SLOCK	K(KT_SLOCK,KG_SHIFT)
+#define K_CTRL_SLOCK	K(KT_SLOCK,KG_CTRL)
+#define K_ALT_SLOCK	K(KT_SLOCK,KG_ALT)
+#define K_ALTGR_SLOCK	K(KT_SLOCK,KG_ALTGR)
+#define K_SHIFTL_SLOCK	K(KT_SLOCK,KG_SHIFTL)
+#define K_SHIFTR_SLOCK	K(KT_SLOCK,KG_SHIFTR)
+#define K_CTRLL_SLOCK	K(KT_SLOCK,KG_CTRLL)
+#define K_CTRLR_SLOCK	K(KT_SLOCK,KG_CTRLR)
 
 #define NR_LOCK		8
 
diff -u --recursive --new-file v1.3.32/linux/include/linux/lp.h linux/include/linux/lp.h
--- v1.3.32/linux/include/linux/lp.h	Sun Aug 13 14:45:35 1995
+++ linux/include/linux/lp.h	Tue Oct 10 11:26:05 1995
@@ -161,6 +161,6 @@
  * function prototypes
  */
 
-extern long lp_init(long);
+extern int lp_init(void);
 
 #endif
diff -u --recursive --new-file v1.3.32/linux/include/linux/module.h linux/include/linux/module.h
--- v1.3.32/linux/include/linux/module.h	Mon Sep 18 14:54:09 1995
+++ linux/include/linux/module.h	Tue Oct 10 15:11:16 1995
@@ -95,8 +95,14 @@
 int Using_Versions; /* gcc will handle this global (used as a flag) correctly */
 #endif
 
+#ifdef MODULE
 #define MOD_INC_USE_COUNT      mod_use_count_++
 #define MOD_DEC_USE_COUNT      mod_use_count_--
 #define MOD_IN_USE	       (mod_use_count_ != 0)
+#else
+#define MOD_INC_USE_COUNT	do { } while (0)
+#define MOD_DEC_USE_COUNT	do { } while (0)
+#define MOD_IN_USE		1
+#endif
 
 #endif
diff -u --recursive --new-file v1.3.32/linux/include/linux/mouse.h linux/include/linux/mouse.h
--- v1.3.32/linux/include/linux/mouse.h	Fri Sep 15 11:13:02 1995
+++ linux/include/linux/mouse.h	Tue Oct 10 14:59:19 1995
@@ -6,7 +6,7 @@
 #define MS_BUSMOUSE_MINOR 2
 #define ATIXL_BUSMOUSE_MINOR 3
 
-unsigned long mouse_init(unsigned long);
+extern int mouse_init(void);
 
 struct mouse {
 	int minor;
diff -u --recursive --new-file v1.3.32/linux/include/linux/ppp-comp.h linux/include/linux/ppp-comp.h
--- v1.3.32/linux/include/linux/ppp-comp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/ppp-comp.h	Mon Oct  9 09:17:54 1995
@@ -0,0 +1,192 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id: ppp-comp.h,v 1.7 1995/05/01 01:43:37 paulus Exp $
+ */
+
+/*
+ *  ==FILEVERSION 3==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp-comp.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp-comp.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS	1	/* by default, include BSD-Compress */
+#endif
+
+#define DO_PREDICTOR_1	0
+#define DO_PREDICTOR_2	0
+#define DO_DEFLATE	0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+
+#ifdef PACKETPTR
+struct compressor {
+	int	compress_proto;	/* CCP compression protocol number */
+
+	/* Allocate space for a compressor (transmit side) */
+	void	*(*comp_alloc) (unsigned char *options, int opt_len);
+
+	/* Free space used by a compressor */
+	void	(*comp_free) (void *state);
+
+	/* Initialize a compressor */
+	int	(*comp_init) (void *state, unsigned char *options,
+			      int opt_len, int unit, int opthdr, int debug);
+
+	/* Reset a compressor */
+	void	(*comp_reset) (void *state);
+
+	/* Compress a packet */
+	int     (*compress) (void *state, unsigned char *rptr,
+			      unsigned char *obuf, int isize, int osize);
+
+	/* Return compression statistics */
+	void	(*comp_stat) (void *state, struct compstat *stats);
+
+	/* Allocate space for a decompressor (receive side) */
+	void	*(*decomp_alloc) (unsigned char *options, int opt_len);
+
+	/* Free space used by a decompressor */
+	void	(*decomp_free) (void *state);
+
+	/* Initialize a decompressor */
+	int	(*decomp_init) (void *state, unsigned char *options,
+				int opt_len, int unit, int opthdr, int mru,
+				int debug);
+
+	/* Reset a decompressor */
+	void	(*decomp_reset) (void *state);
+
+	/* Decompress a packet. */
+	int	(*decompress) (void *state, unsigned char *ibuf, int isize,
+				unsigned char *obuf, int osize);
+
+	/* Update state for an incompressible packet received */
+	void	(*incomp) (void *state, unsigned char *ibuf, int icnt);
+
+	/* Return decompression statistics */
+	void	(*decomp_stat) (void *state, struct compstat *stats);
+};
+#endif /* PACKETPTR */
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression.  This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+
+#define DECOMP_OK		0	/* everything went OK */
+#define DECOMP_ERROR		1	/* error detected before decomp. */
+#define DECOMP_FATALERROR	2	/* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+
+#define CCP_CONFREQ	1
+#define CCP_CONFACK	2
+#define CCP_TERMREQ	5
+#define CCP_TERMACK	6
+#define CCP_RESETREQ	14
+#define CCP_RESETACK	15
+
+/*
+ * Max # bytes for a CCP option
+ */
+
+#define CCP_MAX_OPTION_LENGTH	32
+
+/*
+ * Parts of a CCP packet.
+ */
+
+#define CCP_CODE(dp)		((dp)[0])
+#define CCP_ID(dp)		((dp)[1])
+#define CCP_LENGTH(dp)		(((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN		4
+
+#define CCP_OPT_CODE(dp)	((dp)[0])
+#define CCP_OPT_LENGTH(dp)	((dp)[1])
+#define CCP_OPT_MINLEN		2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+
+#define CI_BSD_COMPRESS		21	/* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS	3	/* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x)		((x) & 0x1F)	/* number of bits requested */
+#define BSD_VERSION(x)		((x) >> 5)	/* version of option format */
+#define BSD_CURRENT_VERSION	1		/* current version number */
+#define BSD_MAKE_OPT(v, n)	(((v) << 5) | (n))
+
+#define BSD_MIN_BITS		9	/* smallest code size supported */
+#define BSD_MAX_BITS		15	/* largest code size supported */
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+
+#define CI_PREDICTOR_1		1	/* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1	2	/* length of its config option */
+#define CI_PREDICTOR_2		2	/* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2	2	/* length of its config option */
+
+#define CI_DEFLATE		24	/* config option for Deflate */
+#define CILEN_DEFLATE		4	/* length of its config option */
+
+#define DEFLATE_MIN_SIZE	8
+#define DEFLATE_MAX_SIZE	15
+#define DEFLATE_METHOD_VAL	8
+#define DEFLATE_SIZE(x)		(((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)	((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)	((((w) - DEFLATE_MIN_SIZE) << 4) \
+				 + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE	0
+
+#endif /* _NET_PPP_COMP_H */
diff -u --recursive --new-file v1.3.32/linux/include/linux/ppp_defs.h linux/include/linux/ppp_defs.h
--- v1.3.32/linux/include/linux/ppp_defs.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/ppp_defs.h	Mon Oct  9 09:17:54 1995
@@ -0,0 +1,175 @@
+/*	$Id: ppp_defs.h,v 1.2 1994/09/21 01:31:06 paulus Exp $	*/
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+/*
+ *  ==FILEVERSION 4==
+ *
+ *  NOTE TO MAINTAINERS:
+ *     If you modify this file at all, increment the number above.
+ *     ppp_defs.h is shipped with a PPP distribution as well as with the kernel;
+ *     if everyone increases the FILEVERSION number above, then scripts
+ *     can do the right thing when deciding whether to install a new ppp_defs.h
+ *     file.  Don't change the format of that line otherwise, so the
+ *     installation script can recognize it.
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN	4	/* octets for standard ppp header */
+#define PPP_FCSLEN	2	/* octets for FCS */
+#define PPP_MRU		1500	/* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p)	(((u_char *)(p))[0])
+#define PPP_CONTROL(p)	(((u_char *)(p))[1])
+#define PPP_PROTOCOL(p)	((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define	PPP_ALLSTATIONS	0xff	/* All-Stations broadcast address */
+#define	PPP_UI		0x03	/* Unnumbered Information */
+#define	PPP_FLAG	0x7e	/* Flag Sequence */
+#define	PPP_ESCAPE	0x7d	/* Asynchronous Control Escape */
+#define	PPP_TRANS	0x20	/* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP		0x21	/* Internet Protocol */
+#define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
+#define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_IPCP	0x8021	/* IP Control Protocol */
+#define PPP_CCP		0x80fd	/* Compression Control Protocol */
+#define PPP_LCP		0xc021	/* Link Control Protocol */
+#define PPP_PAP		0xc023	/* Password Authentication Protocol */
+#define PPP_LQR		0xc025	/* Link Quality Report protocol */
+#define PPP_CHAP	0xc223	/* Cryptographic Handshake Auth. Protocol */
+
+/*
+ * A 32-bit unsigned integral type.
+ */
+#ifndef __BIT_TYPES_DEFINED__
+#ifdef	UINT32_T
+typedef UINT32_T	u_int32_t;
+#else
+typedef unsigned int	u_int32_t;
+#endif
+#endif
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_int32_t	ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+    NPMODE_PASS,		/* pass the packet through */
+    NPMODE_DROP,		/* silently drop the packet */
+    NPMODE_ERROR,		/* return an error */
+    NPMODE_QUEUE		/* save it up for later. */
+};
+
+/*
+ * Statistics for LQRP and pppstats
+ */
+struct pppstat	{
+    u_int	ppp_discards;	/* # frames discarded */
+
+    u_int	ppp_ibytes;	/* bytes received */
+    u_int	ppp_ioctects;	/* bytes received not in error */
+    u_int	ppp_ipackets;	/* packets received */
+    u_int	ppp_ierrors;	/* receive errors */
+    u_int	ppp_ilqrs;	/* # LQR frames received */
+
+    u_int	ppp_obytes;	/* raw bytes sent */
+    u_int	ppp_ooctects;	/* frame bytes sent */
+    u_int	ppp_opackets;	/* packets sent */
+    u_int	ppp_oerrors;	/* transmit errors */ 
+    u_int	ppp_olqrs;	/* # LQR frames sent */
+};
+
+struct vjstat {
+    u_int	vjs_packets;	/* outbound packets */
+    u_int	vjs_compressed;	/* outbound compressed packets */
+    u_int	vjs_searches;	/* searches for connection state */
+    u_int	vjs_misses;	/* times couldn't find conn. state */
+    u_int	vjs_uncompressedin; /* inbound uncompressed packets */
+    u_int	vjs_compressedin;   /* inbound compressed packets */
+    u_int	vjs_errorin;	/* inbound unknown type packets */
+    u_int	vjs_tossed;	/* inbound packets tossed because of error */
+};
+
+struct compstat {
+    u_int	unc_bytes;	/* total uncompressed bytes */
+    u_int	unc_packets;	/* total uncompressed packets */
+    u_int	comp_bytes;	/* compressed bytes */
+    u_int	comp_packets;	/* compressed packets */
+    u_int	inc_bytes;	/* incompressible bytes */
+    u_int	inc_packets;	/* incompressible packets */
+    /* the compression ratio is defined as in_count / bytes_out */
+    u_int       in_count;	/* Bytes received */
+    u_int       bytes_out;	/* Bytes transmitted */
+    double	ratio;		/* not computed in kernel. */
+};
+
+struct ppp_stats {
+    struct pppstat	p;	/* basic PPP statistics */
+    struct vjstat	vj;	/* VJ header compression statistics */
+};
+
+struct ppp_comp_stats {
+    struct compstat	c;	/* packet compression statistics */
+    struct compstat	d;	/* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+    time_t xmit_idle;		/* time since last NP packet sent */
+    time_t recv_idle;		/* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x)	x
+#else
+#define __P(x)	()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff -u --recursive --new-file v1.3.32/linux/include/linux/route.h linux/include/linux/route.h
--- v1.3.32/linux/include/linux/route.h	Wed Sep 13 12:45:32 1995
+++ linux/include/linux/route.h	Tue Oct 10 15:45:27 1995
@@ -8,6 +8,8 @@
  * Version:	@(#)route.h	1.0.3	05/27/93
  *
  * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ *		for the purposes of compatibility only.
+ *
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *
  *		This program is free software; you can redistribute it and/or
@@ -22,7 +24,8 @@
 
 
 /* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */
-struct rtentry {
+struct rtentry 
+{
 	unsigned long	rt_hash;	/* hash key for lookups		*/
 	struct sockaddr	rt_dst;		/* target address		*/
 	struct sockaddr	rt_gateway;	/* gateway addr (RTF_GATEWAY)	*/
@@ -50,4 +53,26 @@
 #define RTF_IRTT	0x0100		/* Initial round trip time	  */
 #define RTF_REJECT	0x0200		/* Reject route			  */
 
+/*
+ *	This structure is passed from the kernel to user space by netlink
+ *	routing/device announcements
+ */
+
+struct netlink_rtinfo
+{
+	unsigned long	rtmsg_type;
+	struct sockaddr rtmsg_dst;
+	struct sockaddr rtmsg_gateway;
+	struct sockaddr rtmsg_genmask;
+	short 		rtmsg_flags;
+	short		rtmsg_metric;
+	char		rtmsg_device[16];
+};
+
+#define RTMSG_NEWROUTE		0x01
+#define RTMSG_DELROUTE		0x02
+#define RTMSG_NEWDEVICE		0x11
+#define RTMSG_DELDEVICE		0x12
+
 #endif	/* _LINUX_ROUTE_H */
+
diff -u --recursive --new-file v1.3.32/linux/include/linux/scc.h linux/include/linux/scc.h
--- v1.3.32/linux/include/linux/scc.h	Sun Sep  3 12:27:03 1995
+++ linux/include/linux/scc.h	Tue Oct 10 11:26:32 1995
@@ -557,4 +557,4 @@
 
 /* global functions */
 
-extern long scc_init(long kmem_start);
+extern int scc_init(void);
diff -u --recursive --new-file v1.3.32/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.3.32/linux/include/linux/sched.h	Fri Oct  6 14:35:16 1995
+++ linux/include/linux/sched.h	Tue Oct 10 15:51:58 1995
@@ -33,6 +33,7 @@
 #define CLONE_FS	0x00000200	/* set if fs info shared between processes */
 #define CLONE_FILES	0x00000400	/* set if open files shared between processes */
 #define CLONE_SIGHAND	0x00000800	/* set if signal handlers shared */
+#define CLONE_PID	0x00001000	/* set if pid shared */
 
 /*
  * These are the constant used to fake the fixed-point load-average
diff -u --recursive --new-file v1.3.32/linux/include/linux/tpqic02.h linux/include/linux/tpqic02.h
--- v1.3.32/linux/include/linux/tpqic02.h	Fri Oct  6 14:35:16 1995
+++ linux/include/linux/tpqic02.h	Tue Oct 10 15:54:40 1995
@@ -657,7 +657,7 @@
 };
 
 
-extern long qic02_tape_init(long);			  /* for mem.c */
+extern int qic02_tape_init(void);			  /* for mem.c */
 
 
 #endif /* CONFIG_QIC02_TAPE */
diff -u --recursive --new-file v1.3.32/linux/include/linux/tty.h linux/include/linux/tty.h
--- v1.3.32/linux/include/linux/tty.h	Mon Sep 18 14:54:10 1995
+++ linux/include/linux/tty.h	Tue Oct 10 11:59:27 1995
@@ -272,20 +272,21 @@
 extern int fg_console;
 extern struct wait_queue * keypress_wait;
 
-extern long rs_init(long);
-extern long lp_init(long);
-extern long con_init(long);
-extern long pty_init(long);
-extern long tty_init(long);
-extern long vcs_init(long);
+extern unsigned long con_init(unsigned long);
+
+extern int rs_init(void);
+extern int lp_init(void);
+extern int pty_init(void);
+extern int tty_init(void);
+extern int vcs_init(void);
 #ifdef CONFIG_CYCLADES
-extern long cy_init(long);
+extern int cy_init(void);
 #endif
 #ifdef CONFIG_STALLION
-extern long stl_init(long);
+extern int stl_init(void);
 #endif
 #ifdef CONFIG_ISTALLION
-extern long stli_init(long);
+extern int stli_init(void);
 #endif
 
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
diff -u --recursive --new-file v1.3.32/linux/include/linux/user.h linux/include/linux/user.h
--- v1.3.32/linux/include/linux/user.h	Mon Sep 18 14:54:10 1995
+++ linux/include/linux/user.h	Mon Oct  9 13:10:41 1995
@@ -1,78 +1 @@
-#ifndef _LINUX_USER_H
-#define _LINUX_USER_H
-
-#include <asm/page.h>
-#include <linux/ptrace.h>
-/* Core file format: The core file is written in such a way that gdb
-   can understand it and provide useful information to the user (under
-   linux we use the 'trad-core' bfd).  There are quite a number of
-   obstacles to being able to view the contents of the floating point
-   registers, and until these are solved you will not be able to view the
-   contents of them.  Actually, you can read in the core file and look at
-   the contents of the user struct to find out what the floating point
-   registers contain.
-   The actual file contents are as follows:
-   UPAGE: 1 page consisting of a user struct that tells gdb what is present
-   in the file.  Directly after this is a copy of the task_struct, which
-   is currently not used by gdb, but it may come in useful at some point.
-   All of the registers are stored as part of the upage.  The upage should
-   always be only one page.
-   DATA: The data area is stored.  We use current->end_text to
-   current->brk to pick up all of the user variables, plus any memory
-   that may have been malloced.  No attempt is made to determine if a page
-   is demand-zero or if a page is totally unused, we just cover the entire
-   range.  All of the addresses are rounded in such a way that an integral
-   number of pages is written.
-   STACK: We need the stack information in order to get a meaningful
-   backtrace.  We need to write the data from (esp) to
-   current->start_stack, so we round each of these off in order to be able
-   to write an integer number of pages.
-   The minimum core file size is 3 pages, or 12288 bytes.
-*/
-
-struct user_i387_struct {
-	long	cwd;
-	long	swd;
-	long	twd;
-	long	fip;
-	long	fcs;
-	long	foo;
-	long	fos;
-	long	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
-};
-
-/* When the kernel dumps core, it starts by dumping the user struct -
-   this will be used by gdb to figure out where the data and stack segments
-   are within the file, and what virtual addresses to use. */
-struct user{
-/* We start with the registers, to mimic the way that "memory" is returned
-   from the ptrace(3,...) function.  */
-  struct pt_regs regs;		/* Where the registers are actually stored */
-/* ptrace does not yet supply these.  Someday.... */
-  int u_fpvalid;		/* True if math co-processor being used. */
-                                /* for this mess. Not yet used. */
-  struct user_i387_struct i387;	/* Math Co-processor registers. */
-/* The rest of this junk is to help gdb figure out what goes where */
-  unsigned long int u_tsize;	/* Text segment size (pages). */
-  unsigned long int u_dsize;	/* Data segment size (pages). */
-  unsigned long int u_ssize;	/* Stack segment size (pages). */
-  unsigned long start_code;     /* Starting virtual address of text. */
-  unsigned long start_stack;	/* Starting virtual address of stack area.
-				   This is actually the bottom of the stack,
-				   the top of the stack is always found in the
-				   esp register.  */
-  long int signal;     		/* Signal that caused the core dump. */
-  int reserved;			/* No longer used */
-  struct pt_regs * u_ar0;	/* Used by gdb to help find the values for */
-				/* the registers. */
-  struct user_i387_struct* u_fpstate;	/* Math Co-processor pointer. */
-  unsigned long magic;		/* To uniquely identify a core file */
-  char u_comm[32];		/* User command that was responsible */
-  int u_debugreg[8];
-};
-#define NBPG PAGE_SIZE
-#define UPAGES 1
-#define HOST_TEXT_START_ADDR (u.start_code)
-#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
-
-#endif
+#include <asm/user.h>
diff -u --recursive --new-file v1.3.32/linux/include/net/netlink.h linux/include/net/netlink.h
--- v1.3.32/linux/include/net/netlink.h	Wed Oct  4 14:14:34 1995
+++ linux/include/net/netlink.h	Tue Oct 10 15:45:27 1995
@@ -1,8 +1,11 @@
+#ifndef __NET_NETLINK_H
+#define __NET_NETLINK_H
 #define NET_MAJOR 18		/* Major 18 is reserved for networking 		*/
 #define MAX_LINKS 3		/* 18,0 for route updates, 18,1 for SKIP 	*/
 #define MAX_QBYTES 32768	/* Maximum bytes in the queue 			*/
 
 extern int netlink_attach(int unit, int (*function)(struct sk_buff *skb));
+extern int netlink_donothing(struct sk_buff *skb);
 extern void netlink_detach(int unit);
 extern int netlink_post(int unit, struct sk_buff *skb);
 extern void init_netlink(void);
@@ -10,4 +13,11 @@
 #define NETLINK_ROUTE		0	/* Routing/device hook				*/
 #define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
+#define NETLINK_FIREWALL	3	/* Firewalling hook				*/
 
+#ifdef CONFIG_RTNETLINK
+extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
+#else
+#define ip_netlink_msg(a,b,c,d,e,f,g)
+#endif
+#endif
diff -u --recursive --new-file v1.3.32/linux/init/main.c linux/init/main.c
--- v1.3.32/linux/init/main.c	Wed Oct  4 14:14:34 1995
+++ linux/init/main.c	Tue Oct 10 14:27:57 1995
@@ -36,16 +36,14 @@
 
 extern int console_loglevel;
 
-extern void init(void);
+static int init(void *);
+
 extern void init_IRQ(void);
 extern void init_modules(void);
 extern long console_init(long, long);
 extern long kmalloc_init(long,long);
-extern long blk_dev_init(long,long);
-extern long chr_dev_init(long,long);
 extern void sock_init(void);
 extern long rd_init(long mem_start, int length);
-unsigned long net_dev_init(unsigned long, unsigned long);
 extern long pci_init(long, long);
 
 extern void bmouse_setup(char *str, int *ints);
@@ -96,14 +94,11 @@
 #ifdef CONFIG_SJCD
 extern void sjcd_setup(char *str, int *ints);
 #endif CONFIG_SJCD
-void ramdisk_setup(char *str, int *ints);
+static void ramdisk_setup(char *str, int *ints);
 
 #ifdef CONFIG_SYSVIPC
 extern void ipc_init(void);
 #endif
-#ifdef CONFIG_SCSI
-extern unsigned long scsi_dev_init(unsigned long, unsigned long);
-#endif
 
 /*
  * Boot command-line arguments
@@ -255,7 +250,7 @@
 	{ 0, 0 }
 };
 
-void ramdisk_setup(char *str, int *ints)
+static void ramdisk_setup(char *str, int *ints)
 {
    if (ints[0] > 0 && ints[1] >= 0)
       ramdisk_size = ints[1];
@@ -419,8 +414,6 @@
 
 extern void setup_arch(char **, unsigned long *, unsigned long *);
 
-static char init_stack[PAGE_SIZE];
-
 #ifdef CONFIG_SMP
 /*
  *	Activate a secondary processor.
@@ -435,6 +428,12 @@
 		idle();
 }
 
+int smp_idle(void * unused)
+{
+	for (;;)
+		idle();
+}
+
 /*
  *	Called by CPU#0 to activate the rest.
  */
@@ -445,20 +444,12 @@
 	smp_boot_cpus();
 	
 	/*
-	 *	Create the slave init tasks. At this point
-	 *	fork will create them all ask task 0
+	 *	Create the slave init tasks as sharing pid 0.
 	 */
 
 	for(i=1;i<smp_num_cpus;i++)
 	{
-		fork();
-		/* We are forking multiple process 0's. This makes it harder
-		   to tell them apart than we would like ;) */
-		if(current!=task[0])
-		{
-			for(;;)
-				idle();
-		}
+		kernel_thread(smp_idle, NULL, CLONE_PID);
 		/*
 		 *	Assume linear processor numbering
 		 */
@@ -525,18 +516,11 @@
 	memory_start = kmalloc_init(memory_start,memory_end);
 	sti();
 	calibrate_delay();
-	memory_start = chr_dev_init(memory_start,memory_end);
-	memory_start = blk_dev_init(memory_start,memory_end);
-	sti();
-#ifdef CONFIG_SCSI
-	memory_start = scsi_dev_init(memory_start,memory_end);
-#endif
-#ifdef CONFIG_INET
-	memory_start = net_dev_init(memory_start,memory_end);
-#endif
 	memory_start = inode_init(memory_start,memory_end);
 	memory_start = file_table_init(memory_start,memory_end);
 	memory_start = name_cache_init(memory_start,memory_end);
+	if (ramdisk_size)
+		memory_start += rd_init(memory_start, ramdisk_size*1024);
 	mem_init(memory_start,memory_end);
 	buffer_init();
 	sock_init();
@@ -550,9 +534,8 @@
 #ifdef CONFIG_SMP	
 	smp_init();
 #endif
-	/* we count on the clone going ok */
-	if (!clone(CLONE_VM, init_stack+sizeof(init_stack)))
-		init();
+	/* we count on the initial thread going ok */
+	kernel_thread(init, NULL, 0);
 /*
  * task[0] is meant to be used as an "idle" task: it may not sleep, but
  * it might do some general things like count free pages or it could be
@@ -577,7 +560,15 @@
 	return i;
 }
 
-void init(void)
+static int do_shell(void * input)
+{
+	close(0);
+	if (open("/etc/rc",O_RDONLY,0))
+		return -1;
+	return execve("/bin/sh",argv_rc,envp_rc);
+}
+
+static int init(void * unused)
 {
 	int pid,i;
 
@@ -607,13 +598,7 @@
 	execve("/sbin/init",argv_init,envp_init);
 	/* if this fails, fall through to original stuff */
 
-	if (!(pid=fork())) {
-		close(0);
-		if (open("/etc/rc",O_RDONLY,0))
-			_exit(1);
-		execve("/bin/sh",argv_rc,envp_rc);
-		_exit(2);
-	}
+	pid = kernel_thread(do_shell, "/etc/rc", 0);
 	if (pid>0)
 		while (pid != wait(&i))
 			/* nothing */;
@@ -636,5 +621,5 @@
 		printf("\n\rchild %d died with code %04x\n\r",pid,i);
 		sync();
 	}
-	_exit(0);
+	return -1;
 }
diff -u --recursive --new-file v1.3.32/linux/kernel/fork.c linux/kernel/fork.c
--- v1.3.32/linux/kernel/fork.c	Wed Oct  4 14:14:34 1995
+++ linux/kernel/fork.c	Tue Oct 10 09:04:35 1995
@@ -29,35 +29,27 @@
 
 int nr_tasks=1;
 int nr_running=1;
-long last_pid=0;
 
 static int find_empty_process(void)
 {
 	int i;
-	int this_user_tasks;
 	struct task_struct *p;
 
 	if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) {
 		if (current->uid)
 			return -EAGAIN;
 	}
-repeat:
-	if(smp_threads_ready) {
-		if ((++last_pid) & 0xffff8000)
-			last_pid=1;
-	}
-	this_user_tasks = 0;
-	for_each_task (p) {
-		if (p->uid == current->uid)
-			this_user_tasks++;
-		if (smp_threads_ready && (p->pid == last_pid ||
-		    p->pgrp == last_pid ||
-		    p->session == last_pid))
-			goto repeat;
+	if (current->uid) {
+		long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur;
+
+		if (max_tasks < nr_tasks) {
+			for_each_task (p) {
+				if (p->uid == current->uid)
+					if (--max_tasks < 0)
+						return -EAGAIN;
+			}
+		}
 	}
-	if (this_user_tasks > current->rlim[RLIMIT_NPROC].rlim_cur)
-		if (current->uid)
-			return -EAGAIN;
 	for (i = 0 ; i < NR_TASKS ; i++) {
 		if (!task[i])
 			return i;
@@ -65,6 +57,25 @@
 	return -EAGAIN;
 }
 
+static int get_pid(unsigned long flags)
+{
+	static int last_pid = 0;
+	struct task_struct *p;
+
+	if (flags & CLONE_PID)
+		return current->pid;
+repeat:
+	if ((++last_pid) & 0xffff8000)
+		last_pid=1;
+	for_each_task (p) {
+		if (p->pid == last_pid ||
+		    p->pgrp == last_pid ||
+		    p->session == last_pid)
+			goto repeat;
+	}
+	return last_pid;
+}
+
 static int dup_mmap(struct mm_struct * mm)
 {
 	struct vm_area_struct * mpnt, **p, *tmp;
@@ -214,7 +225,7 @@
 	*(unsigned long *) p->kernel_stack_page = STACK_MAGIC;
 	p->state = TASK_UNINTERRUPTIBLE;
 	p->flags &= ~(PF_PTRACED|PF_TRACESYS);
-	p->pid = last_pid;
+	p->pid = get_pid(clone_flags);
 	p->next_run = NULL;
 	p->prev_run = NULL;
 	p->p_pptr = p->p_opptr = current;
diff -u --recursive --new-file v1.3.32/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.32/linux/kernel/ksyms.c	Wed Oct  4 14:14:34 1995
+++ linux/kernel/ksyms.c	Sun Oct  8 12:38:34 1995
@@ -349,6 +349,7 @@
 	X(unregister_netdev),
 	X(ether_setup),
 	X(eth_type_trans),
+	X(eth_copy_and_sum),
 	X(alloc_skb),
 	X(kfree_skb),
 	X(dev_alloc_skb),
diff -u --recursive --new-file v1.3.32/linux/net/Changes linux/net/Changes
--- v1.3.32/linux/net/Changes	Wed Oct  4 14:14:35 1995
+++ linux/net/Changes	Tue Oct 10 15:45:28 1995
@@ -242,6 +242,13 @@
 o	IFF_ALLMULTI support for 3c501,3c509,8390 and
 	tulip(SMC etherpower) boards			[IN]
 
+-------->>>>> 1.3.33 <<<<<<--------
+
+o	IFF_ALLMULTI causes an address check on ether	[IN]
+o	Added multicast ability readme file		[IN]
+o	Assorted driver/multicast fixes			[IN]
+o	IP routing change errors resemble BSD more	[IN]
+o	IP port masquerading fixes			[IN]
 
 ---------- Things I thought Linus had for a while and not merged ----------------
 
diff -u --recursive --new-file v1.3.32/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.32/linux/net/core/dev.c	Wed Sep 13 12:45:34 1995
+++ linux/net/core/dev.c	Tue Oct 10 15:45:28 1995
@@ -231,12 +231,6 @@
 		/*
 		 *	Initialise multicasting status 
 		 */
-#ifdef CONFIG_IP_MULTICAST
-		/* 
-		 *	Join the all host group 
-		 */
-		ip_mc_allhost(dev);
-#endif				
 		dev_mc_upload(dev);
 		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
 	}
@@ -367,7 +361,7 @@
 
 	save_flags(flags);
 	cli();	
-	if (/*dev_nit && */!where) 	/* Always keep order. It helps other hosts
+	if (!where)	 	/* Always keep order. It helps other hosts
 					   far more than it costs us */
 	{
 		skb_queue_tail(dev->buffs + pri,skb);
@@ -1314,12 +1308,30 @@
  *	present) and leaves us with a valid list of present and active devices.
  *
  */
- 
-void dev_init(void)
+extern int lance_init(void);
+extern int pi_init(void);
+extern int dec21040_init(void);
+
+int net_dev_init(void)
 {
 	struct device *dev, **dp;
 
 	/*
+	 * This is VeryUgly(tm).
+	 *
+	 * Some devices want to be initialized eary..
+	 */
+#if defined(CONFIG_LANCE)
+	lance_init();
+#endif
+#if defined(CONFIG_PI)
+	pi_init();
+#endif	
+#if defined(CONFIG_DEC_ELCP)
+	dec21040_init();
+#endif	
+
+	/*
 	 *	Add the devices.
 	 *	If the call to dev->init fails, the dev is removed
 	 *	from the chain disconnecting the device until the
@@ -1346,11 +1358,16 @@
 			dp = &dev->next;
 		}
 	}
+
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_DEV, 3, "dev",
 		S_IFREG | S_IRUGO, 1, 0, 0,
 		0, &proc_net_inode_operations,
 		dev_get_info
 	});
+
+	bh_base[NET_BH].routine = net_bh;
+	enable_bh(NET_BH);
+	return 0;
 }
 
diff -u --recursive --new-file v1.3.32/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v1.3.32/linux/net/ethernet/eth.c	Tue Aug 15 20:39:11 1995
+++ linux/net/ethernet/eth.c	Tue Oct 10 15:45:28 1995
@@ -27,6 +27,8 @@
  *		Greg Page	: 802.2 and SNAP stuff.
  *		Alan Cox	: MAC layer pointers/new format.
  *		Paul Gortmaker	: eth_copy_and_sum shouldn't csum padding.
+ *		Alan Cox	: Protect against forwarding explosions with
+ *				  older network drivers and IFF_ALLMULTI
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -184,7 +186,12 @@
 			skb->pkt_type=PACKET_MULTICAST;
 	}
 	
-	else if(dev->flags&IFF_PROMISC)
+	/*
+	 *	This ALLMULTI check should be redundant by 1.4
+	 *	so don't forget to remove it.
+	 */
+	 
+	else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
 	{
 		if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
 			skb->pkt_type=PACKET_OTHERHOST;
diff -u --recursive --new-file v1.3.32/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.32/linux/net/ipv4/af_inet.c	Wed Sep 27 16:00:01 1995
+++ linux/net/ipv4/af_inet.c	Tue Oct 10 15:45:28 1995
@@ -1615,6 +1615,7 @@
 #if defined(CONFIG_IP_MROUTE)
 	ip_mr_init();
 #endif
+
 	/*
 	 *	Create all the /proc entries.
 	 */
diff -u --recursive --new-file v1.3.32/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v1.3.32/linux/net/ipv4/devinet.c	Sun Sep  3 12:27:05 1995
+++ linux/net/ipv4/devinet.c	Tue Oct 10 15:45:28 1995
@@ -107,14 +107,14 @@
 	 
 	for (dev = dev_base; dev != NULL; dev = dev->next) 
 	{
-		if (!(dev->flags & IFF_UP))
+		if ((!(dev->flags & IFF_UP)) || dev->family!=AF_INET)
 			continue;
 		/*
 		 *	If the protocol address of the device is 0 this is special
 		 *	and means we are address hunting (eg bootp).
 		 */
 		 
-		if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
+		if (dev->pa_addr == 0)
 			return IS_MYADDR;
 		/*
 		 *	Is it the exact IP address? 
diff -u --recursive --new-file v1.3.32/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
--- v1.3.32/linux/net/ipv4/ip.c	Fri Oct  6 14:35:16 1995
+++ linux/net/ipv4/ip.c	Tue Oct 10 15:45:28 1995
@@ -151,6 +151,7 @@
 #include <linux/igmp.h>
 #include <linux/ip_fw.h>
 #include <linux/mroute.h>
+#include <net/netlink.h>
 
 #define CONFIG_IP_DEFRAG
 
@@ -1682,7 +1683,7 @@
 		 * If this fragment needs masquerading, make it so...
 		 * (Dont masquerade de-masqueraded fragments)
 		 */
-		if (!(is_frag&4) && fw_res==2)
+		if (!(is_frag&4) && fw_res==FW_MASQUERADE)
 			ip_fw_masquerade(&skb, dev2);
 #endif
 		IS_SKB(skb);
@@ -3562,14 +3563,60 @@
 	NULL,
 };
 
+#ifdef CONFIG_RTNETLINK
+
+/*
+ *	Netlink hooks for IP
+ */
+ 
+void ip_netlink_msg(unsigned long msg, __u32 daddr, __u32 gw, __u32 mask, short flags, short metric, char *name)
+{
+	struct sk_buff *skb=alloc_skb(sizeof(struct netlink_rtinfo), GFP_ATOMIC);
+	struct netlink_rtinfo *nrt;
+	struct sockaddr_in *s;
+	if(skb==NULL)
+		return;
+	nrt=(struct netlink_rtinfo *)skb_put(skb, sizeof(struct netlink_rtinfo));
+	nrt->rtmsg_type=msg;
+	s=(struct sockaddr_in *)&nrt->rtmsg_dst;
+	s->sin_family=AF_INET;
+	s->sin_addr.s_addr=daddr;
+	s=(struct sockaddr_in *)&nrt->rtmsg_gateway;
+	s->sin_family=AF_INET;
+	s->sin_addr.s_addr=gw;
+	s=(struct sockaddr_in *)&nrt->rtmsg_genmask;
+	s->sin_family=AF_INET;
+	s->sin_addr.s_addr=mask;
+	nrt->rtmsg_flags=flags;
+	nrt->rtmsg_metric=metric;
+	strcpy(nrt->rtmsg_device,name);
+	netlink_post(NETLINK_ROUTE, skb);
+}	
+
+#endif
+
 /*
  *	Device notifier
  */
  
 static int ip_rt_event(unsigned long event, void *ptr)
 {
+	struct device *dev=ptr;
 	if(event==NETDEV_DOWN)
-		ip_rt_flush(ptr);
+	{
+		ip_netlink_msg(RTMSG_DELDEVICE, 0,0,0,0,0,dev->name);
+		ip_rt_flush(dev);
+	}
+/*
+ *	Join the intial group if multicast.
+ */		
+	if(event==NETDEV_UP)
+	{
+#ifdef CONFIG_IP_MULTICAST	
+		ip_mc_allhost(dev);
+#endif		
+		ip_netlink_msg(RTMSG_NEWDEVICE, 0,0,0,0,0,dev->name);
+	}
 	return NOTIFY_DONE;
 }
 
diff -u --recursive --new-file v1.3.32/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.32/linux/net/ipv4/ip_fw.c	Wed Oct  4 14:14:35 1995
+++ linux/net/ipv4/ip_fw.c	Tue Oct 10 15:45:28 1995
@@ -41,6 +41,7 @@
  *	Thomas Quinot		:	Fixed port spoofing.
  *	Alan Cox		:	Cleaned up retransmits in spoofing.
  *	Alan Cox		:	Cleaned up length setting.
+ *	Wouter Gadeyne		:	Fixed masquerading support of ftp PORT commands
  *
  *	All the real work was done by .....
  *
@@ -586,15 +587,33 @@
 	struct ip_masq *ms;
 	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
 	int diff;
+	__u32 seq;
 	
 	/*
-	 * Adjust seq and ack_seq with delta-offset for
-	 * the packets AFTER this one...
+	 * Adjust seq with delta-offset for all packets after the most recent resized PORT command
+	 * and with previous_delta offset for all packets before most recent resized PORT
 	 */
-	if (ftp->delta && after(ftp->init_seq,th->seq)) 
+	
+	/*
+	 * seq & seq_ack are in network byte order; need conversion before comparing
+	 */
+	seq=ntohl(th->seq);
+	if (ftp->delta || ftp->previous_delta)
 	{
-		th->seq += ftp->delta;
-/* 		th->ack_seq += ftp->delta;*/
+		if(after(seq,ftp->init_seq) ) 
+		{
+			th->seq = htonl(seq + ftp->delta);
+#ifdef DEBUG_MASQ
+			printk("masq_revamp : added delta (%d) to seq\n",ftp->delta);
+#endif
+		}
+		else
+		{
+			th->seq = htonl(seq + ftp->previous_delta);
+#ifdef DEBUG_MASQ
+	 		printk("masq_revamp : added previous_delta (%d) to seq\n",ftp->previous_delta);
+#endif
+		}
 	}
 
 	while (skb->len - ((unsigned char *)data - skb->h.raw) > 18)
@@ -626,8 +645,9 @@
 
 		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
 		port = (p5<<8) | p6;
+#ifdef MASQ_DEBUG
 		printk("PORT %lX:%X detected\n",from,port);
-	
+#endif	
 		/*
 		 * Now create an masquerade entry for it
 		 */
@@ -638,7 +658,12 @@
 		ms->src      = htonl(from);	/* derived from PORT cmd */
 		ms->sport    = htons(port);	/* derived from PORT cmd */
 		ms->dst      = iph->daddr;
-		ms->dport    = htons(20);	/* ftp-data */
+		/*
+		 * Hardcoding 20 as dport is not always correct
+		 * At least 1 Windows ftpd uses a random port number instead of 20
+		 * Leave it undefined for now & wait for the first connection request to fill it out
+		 */ 
+		ms->dport    = htons(FTP_DPORT_TBD);	/* ftp-data */
 		ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
 		add_timer(&ms->timer);
 
@@ -666,7 +691,6 @@
 			/*
 			 * simple case, just replace the old PORT cmd
  			 */
- 			ftp->init_seq = 0;
  			memcpy(p,buf,strlen(buf));
  			return skb;
  		}
@@ -681,24 +705,27 @@
  		 *	FIXME: use ftp->init_seq_valid - 0 is a valid sequence.
  		 */
  		 
- 		if(!ftp->init_seq || after(ftp->init_seq,th->seq))
+ 		if(!ftp->init_seq || after(seq,ftp->init_seq) )
+ 		{
+ 			ftp->previous_delta=ftp->delta;
  			ftp->delta+=diff;
+ 			ftp->init_seq = seq;
+ 		}
+ 		
  		/*
  		 * Sizes differ, make a copy
  		 */
- printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",ftp->delta, skb->len);
- 		if (!ftp->init_seq)
- 			ftp->init_seq = th->seq;
- 
-		skb2 = alloc_skb(MAX_HEADER + skb->len+ftp->delta, GFP_ATOMIC);
+#ifdef DEBUG_MASQ
+                printk("MASQUERADE: resizing needed for %d bytes (%ld)\n",diff, skb->len);
+#endif
+		skb2 = alloc_skb(MAX_HEADER + skb->len+diff, GFP_ATOMIC);
  		if (skb2 == NULL) {
  			printk("MASQUERADE: No memory available\n");
  			return skb;
  		}
  		skb2->free = skb->free;
  		skb_reserve(skb2,MAX_HEADER);
- 		skb_put(skb2,skb->len + ftp->delta);
-/* 		skb2->h.raw = &skb2->data[skb->h.raw - skb->data];*/
+ 		skb_put(skb2,skb->len + diff);
 		skb2->h.raw = skb2->data + (skb->h.raw - skb->data);
 		iph=skb2->h.iph;
 		/*
@@ -718,6 +745,12 @@
 			skb->len - (data-(char *)skb->data));
 
 		/*
+		 * Update tot_len field in ip header !
+		 * Sequence numbers were allready modified in original packet
+		 */
+		iph->tot_len = htons(skb->len + diff);
+
+		/*
 		 * Problem, how to replace the new skb with old one,
 		 * preferably inplace, so all the pointers in the
 		 * calling tree keep ok :(
@@ -877,6 +910,7 @@
  		ntohl(iph->saddr), ntohs(portptr[0]),
  		ntohl(iph->daddr), ntohs(portptr[1]));
 #endif
+
  	/*
  	 * reroute to original host:port if found...
  	 *
@@ -891,13 +925,22 @@
  	{
  		if (iph->protocol==ms->protocol &&
 		    (iph->saddr==ms->dst || iph->protocol==IPPROTO_UDP) && 
- 		    portptr[0]==ms->dport &&
+ 		    (ms->dport==htons(FTP_DPORT_TBD) || portptr[0]==ms->dport) &&
  		    portptr[1]==ms->mport)
  		{
+ 		
  			int size = skb_ptr->len - ((unsigned char *)portptr - skb_ptr->h.raw);
  			iph->daddr = ms->src;
  			portptr[1] = ms->sport;
  			
+ 			if(ms->dport==htons(FTP_DPORT_TBD))
+ 			{
+ 				ms->dport=portptr[0];
+#ifdef DEBUG_MASQ
+	 			printk("demasq : Filled out dport entry (%d) based on initial connect attempt from FTP deamon\n",ntohs(ms->dport));
+#endif
+			}
+
  			/*
  			 * Yug! adjust UDP/TCP and IP checksums
  			 */
@@ -905,14 +948,32 @@
  				recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
  			else
  			{
+ 				__u32 ack_seq;
  				/*
-				 * Adjust seq and ack_seq with delta-offset for
-				 * the packets AFTER this one...
+				 * Adjust ack_seq with delta-offset for
+				 * the packets AFTER most recent PORT command has caused a shift
+				 * for packets before most recent PORT command, use previous_delta
 				 */
-				if (ms->delta && after(ms->init_seq,th->ack_seq)) 
+#ifdef DEBUG_MASQ
+	 			printk("demasq : delta=%d ; previous_delta=%d ; init_seq=%lX ; ack_seq=%lX ; after=%d\n",ms->delta,ms->previous_delta,ntohl(ms->init_seq),ntohl(th->ack_seq),after(ntohl(th->ack_seq),ntohl(ms->init_seq)));
+#endif
+				ack_seq=ntohl(th->ack_seq);
+				if (ms->delta || ms->previous_delta)
 				{
-/*					th->seq += ms->delta;*/
-			 		th->ack_seq -= ms->delta;
+					if(after(ack_seq,ms->init_seq))
+					{
+				 		th->ack_seq = htonl(ack_seq-ms->delta);
+#ifdef DEBUG_MASQ
+						printk("demasq : substracted delta (%d) from ack_seq\n",ms->delta);
+#endif
+					}
+					else
+					{
+				 		th->ack_seq = htonl(ack_seq-ms->previous_delta);
+#ifdef DEBUG_MASQ
+						printk("demasq : substracted previous_delta (%d) from ack_seq\n",ms->previous_delta);
+#endif
+					}
 				}
  				tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb_ptr->sk);
  			}
@@ -1568,7 +1629,7 @@
 	unsigned long flags;
 	int len=0;
 	
-	len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq Delta Expires\n"); 
+	len=sprintf(buffer,"Prc FromIP   FPrt ToIP     TPrt Masq Init-seq Delta PDelta Expires\n"); 
 	save_flags(flags);
 	cli();
 	
@@ -1578,12 +1639,12 @@
 		int timer_active = del_timer(&ms->timer);
 		if (!timer_active)
 			ms->timer.expires = jiffies;
-		len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %lu\n",
+		len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %5d %lu\n",
 			strProt[ms->protocol==IPPROTO_TCP],
 			ntohl(ms->src),ntohs(ms->sport),
 			ntohl(ms->dst),ntohs(ms->dport),
 			ntohs(ms->mport),
-			ms->init_seq,ms->delta,ms->timer.expires-jiffies);
+			ms->init_seq,ms->delta,ms->previous_delta,ms->timer.expires-jiffies);
 		if (timer_active)
 			add_timer(&ms->timer);
 
diff -u --recursive --new-file v1.3.32/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v1.3.32/linux/net/ipv4/ipmr.c	Wed Oct  4 14:14:35 1995
+++ linux/net/ipv4/ipmr.c	Tue Oct 10 15:45:28 1995
@@ -18,10 +18,9 @@
  *		Cache manager under test. Forwarding in vague test mode
  *	Todo:
  *		Flow control
- *		Tunnels
- *		Wipe cache on mrouted exit
+ *		Finish Tunnels
  *		Debug cache ttl handling properly
- *		Resolve IFF_ALLMULTI for most cards
+ *		Resolve IFF_ALLMULTI for rest of cards
  */
 
 #include <asm/system.h>
@@ -895,7 +894,7 @@
  
 void ip_mr_init(void)
 {
-	printk("Linux IP multicast router 0.02pre-working 8)\n");
+	printk("Linux IP multicast router 0.04-might-work 8)\n");
 	register_netdevice_notifier(&ip_mr_notifier);
 	proc_net_register(&(struct proc_dir_entry) {
 		PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif",
diff -u --recursive --new-file v1.3.32/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v1.3.32/linux/net/ipv4/route.c	Wed Sep 13 12:45:35 1995
+++ linux/net/ipv4/route.c	Tue Oct 10 15:45:28 1995
@@ -32,6 +32,9 @@
  *	Miquel van Smoorenburg	:	BSD API fixes.
  *	Miquel van Smoorenburg	:	Metrics.
  *		Alan Cox	:	Use __u32 properly
+ *		Alan Cox	:	Aligned routing errors more closely with BSD
+ *					our system is still very different.
+ *		Alan Cox	:	Faster /proc handling
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -59,6 +62,7 @@
 #include <linux/skbuff.h>
 #include <net/sock.h>
 #include <net/icmp.h>
+#include <net/netlink.h>
 
 /*
  *	The routing table list
@@ -75,14 +79,14 @@
 
 /*
  *	Remove a routing table entry.
- *	Should we return a status value here ?
  */
 
-static void rt_del(__u32 dst, __u32 mask,
+static int rt_del(__u32 dst, __u32 mask,
 		char *devname, __u32 gtw, short rt_flags, short metric)
 {
 	struct rtable *r, **rp;
 	unsigned long flags;
+	int found=0;
 
 	rp = &rt_base;
 	
@@ -117,11 +121,17 @@
 		 
 		if (rt_loopback == r)
 			rt_loopback = NULL;
+		ip_netlink_msg(RTMSG_DELROUTE, dst, gtw, mask, rt_flags, metric, r->rt_dev->name);
 		kfree_s(r, sizeof(struct rtable));
+		found=1;
 	} 
 	rt_stamp++;		/* New table revision */
 	
 	restore_flags(flags);
+	
+	if(found)
+		return 0;
+	return -ESRCH;
 }
 
 
@@ -342,6 +352,7 @@
 		*rp = r->rt_next;
 		if (rt_loopback == r)
 			rt_loopback = NULL;
+		ip_netlink_msg(RTMSG_DELROUTE, dst,gw, mask, flags, metric, rt->rt_dev->name);
 		kfree_s(r, sizeof(struct rtable));
 	}
 	
@@ -384,8 +395,9 @@
 	/*
 	 *	Restore the interrupts and return
 	 */
-	 
+
 	restore_flags(cpuflags);
+	ip_netlink_msg(RTMSG_NEWROUTE, dst,gw, mask, flags, metric, rt->rt_dev->name);
 	return;
 }
 
@@ -429,7 +441,7 @@
 		dev = dev_get(devname);
 		putname(devname);
 		if (!dev)
-			return -EINVAL;
+			return -ENODEV;
 	}
 	
 	/*
@@ -541,16 +553,23 @@
 	 * metric can become negative here if it wasn't filled in
 	 * but that's a fortunate accident; we really use that in rt_del.
 	 */
-	rt_del((__u32)trg->sin_addr.s_addr, (__u32)msk->sin_addr.s_addr, devname,
+	err=rt_del((__u32)trg->sin_addr.s_addr, (__u32)msk->sin_addr.s_addr, devname,
 		(__u32)gtw->sin_addr.s_addr, r->rt_flags, r->rt_metric - 1);
 	if ( devname != NULL )
 		putname(devname);
-	return 0;
+	return err;
 }
 
 
 /* 
  *	Called from the PROCfs module. This outputs /proc/net/route.
+ *
+ *	We preserve the old format but pad the buffers out. This means that
+ *	we can spin over the other entries as we read them. Remember the
+ *	gated BGP4 code could need to read 60,000+ routes on occasion (thats
+ *	about 7Mb of data). To do that ok we will need to also cache the
+ *	last route we got to (reads will generally be following on from
+ *	one another without gaps).
  */
  
 int rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
@@ -559,24 +578,32 @@
 	int len=0;
 	off_t pos=0;
 	off_t begin=0;
-	int size;
+	char temp[129];
 
-	len += sprintf(buffer,
-		 "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT\n");
-	pos=len;
-  
-	/*
-	 *	This isn't quite right -- r->rt_dst is a struct! 
-	 */
-	 
+	if(offset<128)
+	{
+		sprintf(buffer,"%-127s\n","Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
+		pos=128;
+  	}
+  	
 	for (r = rt_base; r != NULL; r = r->rt_next) 
 	{
-        	size = sprintf(buffer+len, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\t%u\n",
+		/*
+		 *	Spin through entries until we are ready
+		 */
+		if(pos+128<offset)
+		{
+			pos+=128;
+			continue;
+		}
+					
+        	sprintf(temp, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\t%d\t%lu\t%u",
 			r->rt_dev->name, (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
 			r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
 			(unsigned long)r->rt_mask, (int)r->rt_mss, r->rt_window, (int)r->rt_irtt);
-		len+=size;
-		pos+=size;
+		sprintf(buffer+len,"%-127s\n",temp);
+		len+=128;
+		pos+=128;
 		if(pos<offset)
 		{
 			len=0;
diff -u --recursive --new-file v1.3.32/linux/net/netlink.c linux/net/netlink.c
--- v1.3.32/linux/net/netlink.c	Wed Oct  4 14:14:35 1995
+++ linux/net/netlink.c	Tue Oct 10 15:45:28 1995
@@ -60,7 +60,18 @@
 	kfree_skb(skb, FREE_READ);
 	return -EUNATCH;
 }
- 
+
+/*
+ *	Exported do nothing receiver for one way
+ *	interfaces.
+ */
+  
+int netlink_donothing(struct sk_buff *skb)
+{
+	kfree_skb(skb, FREE_READ);
+	return -EINVAL;
+}
+
 /*
  *	Write a message to the kernel side of a communication link
  */
@@ -190,19 +201,22 @@
 int netlink_post(int unit, struct sk_buff *skb)
 {
 	unsigned long flags;
-	int ret;
-	save_flags(flags);
-	cli();
-	if(rdq_size[unit]+skb->len>MAX_QBYTES)
-		ret=-EWOULDBLOCK;
-	else
+	int ret=0;
+	if(open_map&(1<<unit))
 	{
-		skb_queue_tail(&skb_queue_rd[unit], skb);
-		rdq_size[unit]+=skb->len;
-		ret=0;
-		wake_up_interruptible(&read_space_wait[MAX_LINKS]);
+		save_flags(flags);
+		cli();
+		if(rdq_size[unit]+skb->len>MAX_QBYTES)
+			ret=-EWOULDBLOCK;
+		else
+		{	
+			skb_queue_tail(&skb_queue_rd[unit], skb);
+			rdq_size[unit]+=skb->len;
+			ret=0;
+			wake_up_interruptible(&read_space_wait[unit]);
+		}
+		restore_flags(flags);
 	}
-	restore_flags(flags);
 	return ret;
 }
 
@@ -213,7 +227,7 @@
 int init_module(void)
 {
 	int ct;
-	printk("Network Kernel/User communications module 0.01 ALPHA\n");
+	printk("Network Kernel/User communications module 0.03\n");
 	if (register_chrdev(NET_MAJOR,"netlink",&netlink_fops)) {
 		printk("netlink: unable to get major %d\n", NET_MAJOR);
 		return -EIO;
diff -u --recursive --new-file v1.3.32/linux/net/socket.c linux/net/socket.c
--- v1.3.32/linux/net/socket.c	Wed Oct  4 14:14:35 1995
+++ linux/net/socket.c	Tue Oct 10 15:45:28 1995
@@ -1302,27 +1302,19 @@
 #ifdef CONFIG_NETLINK
 	init_netlink();
 #endif		 
-
 	/*
-	 *	Initialize the protocols module. 
+	 *	Attach the routing/device information port.
 	 */
 
-	proto_init();
+#if defined(CONFIG_RTNETLINK)
+	netlink_attach(NETLINK_ROUTE, netlink_donothing);
+#endif
 
-#ifdef CONFIG_NET
-	/* 
-	 *	Initialize the DEV module. 
-	 */
-
-	dev_init();
-  
 	/*
-	 *	And the bottom half handler 
+	 *	Initialize the protocols module. 
 	 */
 
-	bh_base[NET_BH].routine= net_bh;
-	enable_bh(NET_BH);
-#endif  
+	proto_init();
 }
 
 int socket_get_info(char *buffer, char **start, off_t offset, int length)
