]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.51 1.3.51
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:27 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:27 +0000 (15:10 -0500)
56 files changed:
CREDITS
Documentation/Configure.help
Documentation/SMP.txt
Documentation/watchdog.txt [new file with mode: 0644]
Makefile
arch/i386/kernel/process.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
drivers/block/genhd.c
drivers/char/Config.in
drivers/char/Makefile
drivers/char/mem.c
drivers/char/mouse.c
drivers/char/softdog.c [new file with mode: 0644]
drivers/net/3c501.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/README.pt [new file with mode: 0644]
drivers/net/apricot.c
drivers/net/pt.c [new file with mode: 0644]
drivers/net/pt.h [new file with mode: 0644]
fs/Config.in
fs/Makefile
fs/buffer.c
fs/file_table.c
fs/inode.c
fs/nfs/rpcsock.c
fs/nfs/sock.c
fs/noquot.c [new file with mode: 0644]
fs/proc/array.c
include/asm-i386/byteorder.h
include/asm-i386/smp.h
include/asm-mips/asm.h
include/linux/fs.h
include/linux/net_alias.h
include/net/ip_alias.h
include/net/sock.h
init/main.c
kernel/ksyms.c
mm/filemap.c
mm/swap.c
net/Changes
net/TUNABLE [new file with mode: 0644]
net/core/dev.c
net/core/net_alias.c
net/core/sock.c
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/igmp.c
net/ipv4/ip_alias.c
net/ipv4/ip_input.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipx/af_ipx.c
net/socket.c
net/unix/af_unix.c

diff --git a/CREDITS b/CREDITS
index 33cb25067653ff84b339302142e20c4dcba83eeb..b9d9022b5a7cf7dd65fc8d6dee86b3fb9e30aad6 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -893,6 +893,15 @@ S: 24 Avon Place
 S: Arlington, Massachusetts 02174
 S: USA
 
+N: Craig Small
+E: csmall@triode.apana.org.au
+E: vk2xlz@gonzo.vk2xlz.ampr.org (packet radio)
+S: 10 Stockalls Place
+S: Minto, NSW, 2566
+S: Australia
+D: Gracilis PackeTwin device driver
+D: RSPF daemon 
+
 N: Chris Smith
 E: csmith@convex.com
 D: HPFS filesystem
index 91852f7a631a12ecd38b377ce8e10a880441558b..9e471bb6ce8eb5eb95ff17f64d40dfa367220e20 100644 (file)
@@ -439,7 +439,8 @@ CONFIG_NET_IPIP
   encapsulating protocol. This particular tunneling driver implements
   encapsulation of IP within IP, which sounds kind of pointless, but
   can be useful if you want to make your (or some other) machine
-  appear on a different network than it physically is. Enabling this
+  appear on a different network than it physically is, or to use the 
+  mobile IP facilities (which effectively are doing that). Enabling this
   option will produce two modules ( = code which can be inserted in
   and removed from the running kernel whenever you want), one
   encapsulator and one decapsulator.  This is still alpha code, which
@@ -488,7 +489,8 @@ PC/TCP compatibility mode
 CONFIG_INET_PCTCP
   If you have been having difficulties telneting to your Linux machine
   from a DOS system that uses (broken) PC/TCP networking software, try
-  enabling this option.  Everyone else says N.
+  enabling this option.  Everyone else says N. As of later 1.3.x kernels
+  nobody should need this option. Please report if it solves problems.
 
 Reverse ARP
 CONFIG_INET_RARP
@@ -509,7 +511,7 @@ CONFIG_INET_SNARL
   by Ethernet segments only, as this option optimizes network access
   for this special case. If there are other connections, e.g. SLIP
   links, between machines of your IP network, say N.  If in doubt, say
-  Y.
+  N. The PATH mtu discovery facility will cover most cases anyway.
 
 Disable Path MTU Discovery (normally enabled)
 CONFIG_NO_PATH_MTU_DISCOVERY
@@ -523,10 +525,10 @@ Disable NAGLE algorithm (normally enabled)
 CONFIG_TCP_NAGLE_OFF
   The NAGLE algorithm works by requiring an acknowledgment before
   sending small IP frames (= packets).  This keeps tiny telnet and
-  rlogin packets from congesting Wide Area Networks.  You may wish to
-  disable it if you run your X-server from across the network, or if
-  multiple byte key sequences are delayed. Most people strongly
-  recommend to say N here, though, thereby leaving NAGLE enabled.
+  rlogin packets from congesting Wide Area Networks.  Most people strongly
+  recommend to say N here, though, thereby leaving NAGLE enabled. Those
+  programs that benefit by disabling the facility should do it on a per
+  connection basis themselves anyway.
 
 IP: Drop source routed frames
 CONFIG_IP_NOSR
@@ -571,15 +573,15 @@ CONFIG_IPX
   the programs lynx, netscape or Mosaic). This driver would enlarge
   your kernel by about 5 kB. Unless you have Novell computers on your
   local network, say N.
+  BTW: Although it still doesn't work with this release of the kernel you 
+  can also find ncpfs (a free Novell client) on linux01.gwdg.de.
 
 Appletalk DDP
 CONFIG_ATALK
   Appletalk is the way Apple computers speak to each other on an
   Ethernet (Apple calls it EtherTalk) network. If your linux box is
   connected to such a network and you want to join the conversation,
-  say Y. You would have to give "appletalk" as the address family
-  argument to ifconfig ("man ifconfig") in order to do this. You will
-  also probably want to use the netatalk package so that your Linux
+  say Y. You will need to use the netatalk package so that your Linux
   box can act as a print and file server for macs as well as access
   appletalk printers. Check out
   http://www.cs.dartmouth.edu/~flowerpt/projects/linux-netatalk/ on
@@ -638,7 +640,7 @@ CONFIG_NETLINK
   This driver allows for two-way communication between certain parts
   of the kernel or modules and user processes; the user processes are
   able to read from and write to character special files in the /dev
-  directory having major mode 18. So far, the kernel uses it to
+  directory having major mode 36. So far, the kernel uses it to
   publish some network related information if you enable "Routing
   messages", below. Say Y if you want to experiment with it; this is
   ALPHA code, which means that it need not be completely stable; it
@@ -647,10 +649,9 @@ CONFIG_NETLINK
 Routing messages
 CONFIG_RTNETLINK
   If you enable this and create a character special file /dev/route
-  with major number 18 and minor number 0 using mknod ("man mknod"),
+  with major number 36 and minor number 0 using mknod ("man mknod"),
   you can read some network related routing information from that
-  file. Everything you write to that file will be discarded. Say Y,
-  because otherwise the network link driver is pointless.
+  file. Everything you write to that file will be discarded.
 
 SCSI support?
 CONFIG_SCSI
@@ -1091,15 +1092,13 @@ CONFIG_EQUALIZER
 
 Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
-  This is support for a certain type of Ethernet cards on Sun
-  workstations. The driver does not yet exist, so you might as well
-  say N.
+  This is support for lance ethernet cards on Sun workstations such as
+  the Sparcstation IPC (any Sparc with an 'le0' under SunOS basically).
 
 Sun Intel Ethernet support
 CONFIG_SUN_INTEL
-  This is support for a certain type of Ethernet cards on Sun
-  workstations. The driver does not yet exist, so you might as well
-  say N.
+  This is support for the intel ethernet cards on some Sun workstations
+  (all those with an ie0 interface under SunOS).
 
 Do you want to be offered ALPHA test drivers
 CONFIG_NET_ALPHA
@@ -1242,7 +1241,9 @@ CONFIG_EL3
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your card is not working
+  you may need to use the DOS setup disk to disable Plug & Play mode, and
+  to select the default media type.
 
 Other ISA cards
 CONFIG_NET_ISA
@@ -1399,6 +1400,16 @@ CONFIG_PI
   you should have said Y to "AX.25 support" above, because AX.25 is
   the protocol used for digital traffic over radio links.
 
+Gracilis PackeTwin support
+CONFIG_PT
+  This card is similar to the PI card (mentioned above).  It is used mainly
+  by amateur radio operators for packet radio.  You should of already said Y
+  to "AX.25 support" as this card uses that protocol. 
+  Other than the code and the PT user documentation, there is no other
+  information on this card.
+  NOTE: The card is capable of DMA and full duplex but neither of these have
+  been coded in the driver as yet.
+
 WaveLAN support
 CONFIG_WAVELAN
   These are cards for wireless ethernet-like networking. Supported are
@@ -1793,7 +1804,7 @@ CONFIG_MINIX_FS
   still used for root/boot and other floppies or ram disks since it is
   leaner. You don't want to use it on your harddisk because of certain
   built-in restrictions. This option will enlarge your kernel by about
-  25 kB. Everyone should say Y so that they are able to read this
+  25 kB. Everyone should say Y or M so that they are able to read this
   common floppy format.  If you want to compile this as a module
   however ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
@@ -2049,7 +2060,7 @@ CONFIG_PRINTER
   connecting the parallel ports of two local machines) or a ethernet
   network pocket adaptor attaching to the parallel port and a parallel
   printer as well, you should compile both drivers as modules because
-  the drivers don't like each other.
+  the drivers both want the same resources.
 
 Logitech busmouse support
 CONFIG_BUSMOUSE
@@ -2103,7 +2114,9 @@ CONFIG_MS_BUSMOUSE
   and read Documentation/modules.txt. If you are unsure, say N and
   read the HOWTO nevertheless: it will tell you what you have. Chances
   are that you have a regular serial MouseSystem or Microsoft mouse
-  plugging in a COM port which is supported automatically.
+  plugging in a COM port which is supported automatically. Also be aware
+  several vendors talk about 'Microsoft busmouse' and actually mean PS/2
+  busmouse - so count the pins on the connector.
 
 ATIXL busmouse support
 CONFIG_ATIXL_BUSMOUSE
index 1bb9a49e00912af5a4a1b47b90244af4834dfb4c..28fb0896485fb339ebb891b4a61b38e3c048a946 100644 (file)
@@ -1,20 +1,18 @@
-
-SMP support for Linux with up to 32 processors using the Intel MP
+SMP support for Linux with up to 16 processors using the Intel MP
 specification. 
 
 WARNING:
-       This is experimental. Back up your disks first.
+       This is experimental. Back up your disks first. Experience is that
+it is basically stable in its current (inefficient form).
 
 To fix:
 
 o      Fix sys_idle to exit/enter kernel state and do hlt's.
 o      Fix scheduler decisions to reschedule. Per cpu reschedule ?
-o      Scheduler ignores stick to CPU advantage. Critical for P6! [Done - FK]
 o      Clean up message pass.
 o      Test for B stepping processors.
 o      Clean up processor specific/independant split.
 o      Document it all.        [PARTLY DONE]
-o      Find the exception/crash bug.
 o      Halt other CPU's on reset/panic doesn't always work.
 o      Dont waste page at 4K - dont need it now.(watch the GDT code).
 o      Dump bootup pages once booted somehow.
@@ -25,4 +23,3 @@ o     Distribute irq's (locking present just needs the 82489 to be asked
        nicely).
 o      486 startup code.
 o      How to handle mixed FPU/non FPU processors.
-o      Support 4Mb page mode again     [TESTING]
diff --git a/Documentation/watchdog.txt b/Documentation/watchdog.txt
new file mode 100644 (file)
index 0000000..3254534
--- /dev/null
@@ -0,0 +1,67 @@
+       Watchdog Timer Interfaces For The Linux Operating System
+
+               Alan Cox <alan@lxorguk.ukuu.org.uk>
+
+           Custom Linux Driver And Program Development
+
+
+The following watchdog drivers are currently implemented:
+
+       IMS     WDT501-P
+       INS     WDT501-P (no fan tachometer)
+       IMS     WDT500-P
+       Software Only
+
+All four interfaces provide /dev/watchdog, which when open must be written
+to within a minute or the machine will reboot. Each write delays the reboot
+time another minute. In the case of the software watchdog the ability to 
+reboot will depend on the state of the machines and interrupts. The hardware
+boards physically pull the machine down off their own onboard timers and
+will reboot from almost anything.
+
+A second temperature monitoring interface is available on the WDT501P cards
+and provides /dev/temperature. This is the machine internal temperature in
+degrees farenheit. Each read returns a single byte giving the temperature.
+
+The third interface logs kernel messages on additional alert events.
+
+At the moment only the software watchdog is available in the standard
+kernel.
+
+Features
+--------
+               WDT501P         WDT500P         Software
+Reboot Timer      X               X                X
+External Reboot           X               X                o
+Temperature       X               o                o
+Fan Speed          X              o                o
+Power Under       X               o                o
+Power Over         X               o                o
+Overheat           X               o                o
+
+The external event interfaces on the WDT boards are not currently supported.
+
+
+Example Watchdog Driver
+-----------------------
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int main(int argc, const char *argv[])
+{
+       int fd=open("/dev/watchdog",O_WRONLY);
+       if(fd==-1)
+       {
+               perror("watchdog");
+               exit(1);
+       }
+       while(1)
+       {
+               write(fd,"\0",1);
+               sleep(10);
+       }
+}
+
+
index 99da275823f84eb85e6b6469aa4a6652e3e69f07..1ac63d53f9f50520708c81b20389e856b47ebd24 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 50
+SUBLEVEL = 51
 
 ARCH = i386
 
index 9075a4f4822bf5056656424e10937ec78554b137..91f5e9b1b6f06820367b755a5c6de1cef03ddb50 100644 (file)
@@ -8,6 +8,9 @@
  * This file handles the architecture-dependent parts of process handling..
  */
 
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -21,6 +24,7 @@
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
 #include <linux/config.h>
+#include <linux/unistd.h>
 
 #include <asm/segment.h>
 #include <asm/pgtable.h>
@@ -50,6 +54,8 @@ void enable_hlt(void)
        hlt_counter--;
 }
 
+#ifndef __SMP__
+
 static void hard_idle(void)
 {
        while (!need_resched) {
@@ -68,7 +74,8 @@ static void hard_idle(void)
                        __asm__("hlt");
 #endif
                }
-               if (need_resched) break;
+               if (need_resched) 
+                       break;
                schedule();
        }
 #ifdef CONFIG_APM
@@ -77,61 +84,73 @@ static void hard_idle(void)
 }
 
 /*
- * The idle loop on a i386..
+ * The idle loop on a uniprocessor i386..
  */
 asmlinkage int sys_idle(void)
 {
-#ifndef __SMP__
         unsigned long start_idle = 0;
-#endif
-               
+
        if (current->pid != 0)
-       {
-       /*      printk("Wrong process idled\n");        SMP bug check */
                return -EPERM;
-       }
-#ifdef __SMP__
-       /*
-        *      SMP locking sanity checker
-        */
-       if(smp_processor_id()!=active_kernel_processor)
-               panic("CPU is %d, kernel CPU is %d in sys_idle!\n",
-                       smp_processor_id(), active_kernel_processor);
-       if(syscall_count!=1)
-               printk("sys_idle: syscall count is not 1 (%ld)\n", syscall_count);
-       if(kernel_counter!=1)
-       {
-               printk("CPU %d, sys_idle, kernel_counter is %ld\n", smp_processor_id(), kernel_counter);
-               if(!kernel_counter)
-                       panic("kernel locking botch");
-       }
-       /*
-        *      Until we have C unlocking done
-        */
-       current->counter = -100;
-       schedule();
-       return 0;
-#endif 
        /* endless idle loop with no priority at all */
        current->counter = -100;
-       for (;;) {
-#ifdef __SMP__
-               if (cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
-                       __asm__("hlt");
-#else  
-               if (!start_idle) start_idle = jiffies;
-               if (jiffies - start_idle > HARD_IDLE_TIMEOUT) {
+       for (;;) 
+       {
+               /*
+                *      We are locked at this point. So we can safely call
+                *      the APM bios knowing only one CPU at a time will do
+                *      so.
+                */
+               if (!start_idle) 
+                       start_idle = jiffies;
+               if (jiffies - start_idle > HARD_IDLE_TIMEOUT) 
+               {
                        hard_idle();
-               } else {
+               } 
+               else 
+               {
                        if (hlt_works_ok && !hlt_counter && !need_resched)
                                __asm__("hlt");
                }
-               if (need_resched) start_idle = 0;
-#endif
+               if (need_resched) 
+                       start_idle = 0;
                schedule();
        }
 }
 
+#else
+
+/*
+ *     In the SMP world we hlt outside of kernel syscall rather than within
+ *     so as to get the right locking semantics.
+ */
+asmlinkage int sys_idle(void)
+{
+       if(current->pid != 0)
+               return -EPERM;
+       current->counter= -100;
+       schedule();
+       return 0;
+}
+
+/*
+ *     This is being executed in task 0 'user space'.
+ */
+
+int cpu_idle(void *unused)
+{
+       while(1)
+       {
+               if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
+                       __asm("hlt");
+               idle();
+       }
+}
+
+#endif
+
 /*
  * This routine reboots the machine by asking the keyboard
  * controller to pulse the reset-line low. We try that for a while,
@@ -186,6 +205,7 @@ void show_regs(struct pt_regs * regs)
 /*
  * Free current thread data structures etc..
  */
+
 void exit_thread(void)
 {
        /* forget lazy i387 state */
index 454ec091075f3fe9ef9553f93ea29a532d549603..115773df5d044d4cc4ab4dd7565adc41a13675b4 100644 (file)
@@ -245,8 +245,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
                eip = (unsigned long) sa->sa_handler;
                if (sa->sa_flags & SA_ONESHOT)
                        sa->sa_handler = NULL;
-/* force a supervisor-mode page-in of the signal handler to reduce races */
-               __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
                regs->cs = USER_CS; regs->ss = USER_DS;
                regs->ds = USER_DS; regs->es = USER_DS;
                regs->gs = USER_DS; regs->fs = USER_DS;
index 3289e9f27ae17d45ea2daf43064068ca29acebaf..0ec3a2d7350570ff7031ae6ffe1e69cdae3d3cb9 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/smp.h>
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
+#include <asm/pgtable.h>
 #include <asm/smp.h>
 
 extern void *vremap(unsigned long offset, unsigned long size); /* Linus hasnt put this in the headers yet */
@@ -611,7 +612,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         *      During boot up send no messages
         */
         
-       if(!smp_activated)
+       if(!smp_activated || !smp_commenced)
                return;
                
        
index 599ae16f8d05818640fe6ebe9329724e47f7d957..2024236927c3e48acff11c5095c92495eda1dc7d 100644 (file)
@@ -573,7 +573,6 @@ void device_setup(void)
                setup_dev(p);
                nr += p->nr_real;
        }
-
 #ifdef CONFIG_BLK_DEV_RAM
        rd_load();
 #endif
index 957c943c98d24395d8aa5f66366c54307b0a64f1..c265b442e26f529637b811e6dfc4e8d9427d35b7 100644 (file)
@@ -36,3 +36,12 @@ if [ "$CONFIG_APM" = "y" ]; then
   bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
   bool '   Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
 fi
+bool 'Watchdog Timer Support'  CONFIG_WATCHDOG
+if [ "$CONFIG_WATCHDOG" = "y" ]; then
+#  bool '   WDT501P Watchdog timer' CONFIG_WDT_501P
+#  if [ "$CONFIG_WDT_501P" = "y" ]; then
+#    bool '       Fan Tachomeeter' CONFIG_WDT_501P_TACHO
+#  fi
+#  bool '   WDT500P Watchdog timer' CONFIG_WDT_500P
+  bool '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+fi
index 95273e5171bcdfbbe5b6effd828209ebc42f8891..33fa7f454d75955fb74d00e5ace6a5a8243469ad 100644 (file)
@@ -92,6 +92,11 @@ else
   endif
 endif
 
+ifdef CONFIG_SOFT_WATCHDOG
+L_OBJS += softdog.o
+M = y
+endif
+
 ifdef CONFIG_QIC02_TAPE
 L_OBJS += tpqic02.o 
 endif
index accfd579553b32c71ba0b4bc1cea46811843bd00..066ff76e7ed83a7d50609c43cac1c8f5e0d688bf 100644 (file)
@@ -385,7 +385,7 @@ int chr_dev_init(void)
 #endif
 #if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_MOUSE) || \
     defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
-    defined (CONFIG_ATIXL_BUSMOUSE)
+    defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG)
        mouse_init();
 #endif
 #ifdef CONFIG_SOUND
index e3ab2f4d4656bd1fc4ea11f05340b68f28e784b2..dacc86aa1ed7516f7cde32304fdd629c26414f69 100644 (file)
@@ -119,6 +119,9 @@ int mouse_init(void)
 #ifdef CONFIG_ATIXL_BUSMOUSE
        atixl_busmouse_init();
 #endif
+#ifdef CONFIG_SOFT_WATCHDOG
+       watchdog_init();
+#endif 
 #endif /* !MODULE */
        if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) {
          printk("unable to get major %d for mouse devices\n",
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
new file mode 100644 (file)
index 0000000..b5db040
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *     SoftDog 0.02:   A Software Watchdog Device
+ *
+ *     (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ *     Email us for quotes on Linux software and driver development. 
+ *
+ *                     -----------------------
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *                     -----------------------
+ *
+ *     Software only watchdog driver. Unlike its big brother the WDT501P
+ *     driver this won't always recover a failed machine.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mouse.h>
+#define WATCHDOG_MINOR 130
+#define TIMER_MARGIN   (60*HZ)         /* Allow 1 minute */
+
+/*
+ *     Our timer
+ */
+struct timer_list watchdog_ticktock;
+static int timer_alive = 0;
+
+
+/*
+ *     If the timer expires..
+ */
+static void watchdog_fire(long data)
+{
+       extern void hard_reset_now(void);
+       hard_reset_now();
+       printk("WATCHDOG: Reboot didn't ?????\n");
+}
+
+/*
+ *     Allow only one person to hold it open
+ */
+static int softdog_open(struct inode *inode, struct file *file)
+{
+       if(timer_alive)
+               return -EBUSY;
+       /*
+        *      Activate timer
+        */
+       watchdog_ticktock.expires=jiffies+TIMER_MARGIN;
+       add_timer(&watchdog_ticktock);
+       return 0;
+}
+
+static void softdog_release(struct inode *inode, struct file *file)
+{
+       /*
+        *      Shut off the timer.
+        */
+       del_timer(&watchdog_ticktock);
+       timer_alive=0;
+}
+
+static int softdog_write(struct inode *inode, struct file *file, const char *data, int len)
+{
+       /*
+        *      Refresh the timer.
+        */
+       del_timer(&watchdog_ticktock);
+       watchdog_ticktock.expires=jiffies+TIMER_MARGIN;
+       add_timer(&watchdog_ticktock);
+       return 1;
+}
+
+/*
+ *     The mouse stuff ought to be renamed misc_register etc before 1.4...
+ */
+void watchdog_init(void)
+{
+       static struct file_operations softdog_fops=
+       {
+               NULL,           /* Seek */
+               NULL,           /* Read */
+               softdog_write,  /* Write */
+               NULL,           /* Readdir */
+               NULL,           /* Select */
+               NULL,           /* Ioctl */
+               NULL,           /* MMap */
+               softdog_open,
+               softdog_release,
+               NULL,           
+               NULL            /* Fasync */
+       };
+       static struct mouse softdog_mouse={
+               WATCHDOG_MINOR,
+               "softdog",
+               &softdog_fops
+       };
+
+       mouse_register(&softdog_mouse);
+       init_timer(&watchdog_ticktock);
+       watchdog_ticktock.function=watchdog_fire;
+       printk("Software Watchdog Timer: 0.02\n");
+}      
index 2a932e0d72ae7526f69e132a7c5403c7c7287d7f..6f8dceb62b265e3eb346dedcaf5773a23f15f3e4 100644 (file)
@@ -104,6 +104,8 @@ static const char *version =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
+#define BLOCKOUT_2
+
 /* A zero-terminated list of I/O addresses to be probed.
    The 3c501 can be at many locations, but here are the popular ones. */
 static unsigned int netcard_portlist[] =
@@ -128,7 +130,7 @@ static void set_multicast_list(struct device *dev);
 #define EL1_IO_EXTENT  16
 
 #ifndef EL_DEBUG
-#define EL_DEBUG  2    /* use 0 for production, 1 for devel., >2 for debug */
+#define EL_DEBUG  0    /* use 0 for production, 1 for devel., >2 for debug */
 #endif                 /* Anything above 5 is wordy death! */
 static int el_debug = EL_DEBUG;
  
@@ -377,6 +379,9 @@ static int el_start_xmit(struct sk_buff *skb, struct device *dev)
        struct net_local *lp = (struct net_local *)dev->priv;
        int ioaddr = dev->base_addr;
        unsigned long flags;
+       
+       if(dev->interrupt)              /* May be unloading, don't stamp on */
+               return 1;               /* the packet buffer this time      */
 
        if (dev->tbusy) 
        {
@@ -436,10 +441,13 @@ load_it_again_sam:
                 *      Command mode with status cleared should [in theory]
                 *      mean no more interrupts can be pending on the card.
                 */
-       
-               outb(AX_SYS, AX_CMD);
-               inb(RX_STATUS);
-               inb(TX_STATUS);
+                
+#ifdef BLOCKOUT_1
+               disable_irq(dev->irq);           
+#endif 
+               outb_p(AX_SYS, AX_CMD);
+               inb_p(RX_STATUS);
+               inb_p(TX_STATUS);
        
                lp->loading=1;
        
@@ -453,13 +461,19 @@ load_it_again_sam:
                outw(gp_start, GP_LOW);         /* aim - packet will be loaded into buffer start */
                outsb(DATAPORT,buf,skb->len);   /* load buffer (usual thing each byte increments the pointer) */
                outw(gp_start, GP_LOW);         /* the board reuses the same register */
+#ifndef BLOCKOUT_1             
                if(lp->loading==2)              /* A receive upset our load, despite our best efforts */
                {
                        if(el_debug>2)
                                printk("%s: burped during tx load.\n", dev->name);
                        goto load_it_again_sam; /* Sigh... */
                }
+#endif
                outb(AX_XMIT, AX_CMD);          /* fire ... Trigger xmit.  */
+               lp->loading=0;
+#ifdef BLOCKOUT_1              
+               enable_irq(dev->irq);
+#endif         
                dev->trans_start = jiffies;
        }
 
@@ -506,18 +520,37 @@ static void el_interrupt(int irq, struct pt_regs *regs)
        if (dev->interrupt)
                printk("%s: Reentering the interrupt driver!\n", dev->name);
        dev->interrupt = 1;
-    
+#ifndef BLOCKOUT_1    
+        if(lp->loading==1 && !dev->tbusy)
+               printk("%s: Inconsistent state loading while not in tx\n",
+                       dev->name);
+#endif                 
+#ifdef BLOCKOUT_3
        lp->loading=2;          /* So we can spot loading interruptions */
+#endif
 
        if (dev->tbusy) 
        {
     
                /*
-                *      Board in transmit mode.
+                *      Board in transmit mode. May be loading. If we are
+                *      loading we shouldn't have got this.
                 */
         
                int txsr = inb(TX_STATUS);
-
+#ifdef BLOCKOUT_2              
+               if(lp->loading==1)
+               {
+                       if(el_debug > 2)
+                       {
+                               printk("%s: Interrupt while loading [", dev->name);
+                               printk(" txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW));
+                       }
+                       lp->loading=2;          /* Force a reload */
+                       dev->interrupt = 0;
+                       return;
+               }
+#endif
                if (el_debug > 6)
                        printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW));
 
@@ -593,7 +626,7 @@ static void el_interrupt(int irq, struct pt_regs *regs)
                 */
                if (rxsr & RX_MISSED)
                        lp->stats.rx_missed_errors++;
-               if (rxsr & RX_RUNT) 
+               else if (rxsr & RX_RUNT) 
                {       /* Handled to avoid board lock-up. */
                        lp->stats.rx_length_errors++;
                        if (el_debug > 5) 
index 24cb2329dc43faa487f06e3472dc4226f6f1f087..eb70644fd944de297d7faf93d14ed8ec3e0debbd 100644 (file)
@@ -51,6 +51,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
   tristate 'NE2000/NE1000 support' CONFIG_NE2000
   if [ "$CONFIG_AX25" = "y" ]; then
     bool 'Ottawa PI and PI/2 support' CONFIG_PI
+    bool 'Gracilis PackeTwin support' CONFIG_PT
   fi
   bool 'SK_G16 support' CONFIG_SK_G16
 fi
index a5652c445fdc2d73bbb09820093c208995647f95..bf226b783c183bb25caf359c11876e7f98052ed9 100644 (file)
@@ -345,6 +345,9 @@ L_OBJS += pi2.o
 CONFIG_PI = CONFIG_PI
 endif
 
+ifeq ($(CONFIG_PT),y)
+L_OBJS += pt.o
+endif
 
 # If anything built-in uses slhc, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
diff --git a/drivers/net/README.pt b/drivers/net/README.pt
new file mode 100644 (file)
index 0000000..aec6b6e
--- /dev/null
@@ -0,0 +1,62 @@
+This is the README for the Gracilis Packetwin device driver, version 0.5
+ALPHA for Linux 1.3.43.
+
+These files will allow you to talk to the PackeTwin (now know as PT) and
+connect through it just like a pair of TNC's.  To do this you will also
+require the AX.25 code in the kernel enabled.
+
+There are four files in this archive; this readme, a patch file, a .c file
+and finally a .h file.  The two program files need to be put into the
+drivers/net directory in the Linux source tree, for me this is the
+directory /usr/src/linux/drivers/net.  The patch file needs to be patched in
+at the top of the Linux source tree (/usr/src/linux in my case).
+
+You will most probably have to edit the pt.c file to suit your own setup,
+this should just involve changing some of the defines at the top of the file. 
+Please note that if you run an external modem you must specify a speed of 0.
+
+The program is currently setup to run a 4800 baud external modem on port A
+and a Kantronics DE-9600 daughter board on port B so if you have this (or
+something similar) then you're right.
+
+To compile in the driver, put the files in the correct place and patch in
+the diff.  You will have to re-configure the kernel again before you
+recompile it. 
+
+The driver is not real good at the moment for finding the card.  You can
+'help' it by changing the order of the potiential addresses in the structure
+found in the pt_init() function so the address of where the card is is put
+first.
+
+After compiling, you have to get them going, they are pretty well like any
+other net device and just need ifconfig to get them going.
+As an example, here is my /etc/rc.net
+--------------------------
+
+#
+# Configure the PackeTwin, port A.
+/sbin/ifconfig pt0a 44.136.8.87 hw ax25 vk2xlz mtu 512 
+/sbin/ifconfig pt0a 44.136.8.87 broadcast 44.136.8.255 netmask 255.255.255.0
+/sbin/route add -net 44.136.8.0 netmask 255.255.255.0 dev pt0a
+/sbin/route add -net 44.0.0.0 netmask 255.0.0.0 gw 44.136.8.68 dev pt0a
+/sbin/route add -net 138.25.16.0 netmask 255.255.240.0 dev pt0a
+/sbin/route add -host 44.136.8.255 dev pt0a
+#
+# Configure the PackeTwin, port B.
+/sbin/ifconfig pt0b 44.136.8.87 hw ax25 vk2xlz-1 mtu 512
+/sbin/ifconfig pt0b 44.136.8.87 broadcast 44.255.255.255 netmask 255.0.0.0
+/sbin/route add -host 44.136.8.216 dev pt0b
+/sbin/route add -host 44.136.8.95  dev pt0b
+/sbin/route add -host 44.255.255.255 dev pt0b
+
+This version of the driver comes under the GNU GPL.  If you have one on my
+previous (non-GPL) versions of the driver, please update to this one.
+
+I hope that this all works well for you.  I would be pleased to hear how
+many people use the driver and if it does its job.
+
+  - Craig vk2xlz
+
+INET: csmall@acacia.itd.uts.edu.au  craig.small@eol.ieaust.org.au
+AMPR: vk2xlz@gonzo.vk2xlz.ampr.org
+AX25: vk2xlz@vk2gdm.nsw.aus.oc
index 577c78668f1cd69bfd221021a52c24567fd23ae4..130d77597a738b8d272d4910bab2d0efb46fe8cd 100644 (file)
@@ -960,7 +960,7 @@ static void set_multicast_list(struct device *dev)
        struct i596_cmd *cmd;
 
        if (i596_debug > 1)
-               printk ("%s: set multicast list %d\n", dev->name, num_addrs);
+               printk ("%s: set multicast list %d\n", dev->name, dev->mc_count);
 
        if (dev->mc_count > 0) 
        {
@@ -974,10 +974,10 @@ static void set_multicast_list(struct device *dev)
                }
                cmd->command = CmdMulticastList;
                *((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
-               cp=((char *)(cmd + 1))+2
+               cp=((char *)(cmd + 1))+2;
                for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
                {
-                       memcpy(cp, addr,6);
+                       memcpy(cp, dmi,6);
                        cp+=6;
                }
                print_eth (((char *)(cmd + 1)) + 2);
diff --git a/drivers/net/pt.c b/drivers/net/pt.c
new file mode 100644 (file)
index 0000000..0d4369a
--- /dev/null
@@ -0,0 +1,1830 @@
+#undef PT_DEBUG 1
+/*
+ * pt.c: Linux device driver for the Gracilis PackeTwin.
+ * Copyright (c) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge MA 02139, USA.
+ *
+ * This driver is largely based upon the PI driver by David Perry.
+ *
+ * Revision History
+ * 23/02/95 cs  Started again on driver, last one scrapped
+ * 27/02/95 cs  Program works, we have chan A only.  Tx stays on
+ * 28/02/95 cs  Fix Tx problem (& TxUIE instead of | )
+ *             Fix Chan B Tx timer problem, used TMR2 instead of TMR1
+ * 03/03/95 cs  Painfully found out (after 3 days) SERIAL_CFG is write only
+ *              created image of it and DMA_CFG
+ * 21/06/95 cs  Upgraded to suit PI driver 0.8 ALPHA
+ * 22/08/95    cs      Changed it all around to make it like pi driver
+ * 23/08/95 cs  It now works, got caught again by TMR2 and we must have
+ *                             auto-enables for daughter boards.
+ * 07/10/95 cs  Fixed for 1.3.30 (hopefully)
+ * 26/11/95 cs  Fixed for 1.3.43, ala 29/10 for pi2.c by ac
+ * 21/12/95 cs  Got rid of those nasty warnings when compiling, for 1.3.48
+ */
+/* 
+ * default configuration of the PackeTwin,
+ * ie What Craig uses his PT for.
+ */
+#define PT_DMA 3
+
+#define DEF_A_SPEED    4800            /* 4800 baud */
+#define DEF_A_TXDELAY  350             /* 350 mS */
+#define DEF_A_PERSIST  64              /* 25% persistance */
+#define DEF_A_SLOTIME  10              /* 10 mS */
+#define DEF_A_SQUELDELAY 30            /* 30 mS */
+#define DEF_A_CLOCKMODE        0               /* Normal clock mode */
+#define DEF_A_NRZI             1               /* NRZI mode */
+
+#define DEF_B_SPEED    0               /* 0 means external clock */
+#define DEF_B_TXDELAY  250             /* 250 mS */
+#define DEF_B_PERSIST  64              /* 25% */
+#define DEF_B_SLOTIME  10              /* 10 mS */
+#define DEF_B_SQUELDELAY 30            /* 30 mS */
+#define DEF_B_CLOCKMODE 0              /* Normal clock mode ?!? */
+#define DEF_B_NRZI             1               /* NRZI mode */
+
+
+#define        PARAM_TXDELAY   1
+#define        PARAM_PERSIST   2
+#define        PARAM_SLOTTIME  3
+#define        PARAM_FULLDUP   5
+#define        PARAM_HARDWARE  6
+#define        PARAM_RETURN    255
+
+#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/string.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/segment.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/if_arp.h>
+#include "pt.h"
+#include "z8530.h"
+#include <net/ax25.h>
+
+static char *version =
+"PT: 0.41 ALPHA 07 October 1995 Craig Small (vk2xlz@vk2xlz.ampr.org)\n";
+
+
+struct mbuf {
+    struct mbuf *next;
+    int cnt;
+    char data[0];
+};
+
+/*
+ * The actual PT devices we will use
+ */
+static int pt0_preprobe(struct device *dev) {return 0;} /* Dummy probe function */
+static struct device pt0a = { "pt0a", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe };
+static struct device pt0b = { "pt0b", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, pt0_preprobe };
+
+/* Ok, they shouldn't be here, but both channels share them */
+/* The Images of the Serial and DMA config registers */
+static unsigned char pt_sercfg = 0;
+static unsigned char pt_dmacfg = 0;
+
+/* The number of IO ports used by the card */
+#define PT_TOTAL_SIZE   16
+
+/* Index to functions, as function prototypes. */
+
+static int pt_probe(struct device *dev);
+static int pt_open(struct device *dev);
+static int pt_send_packet(struct sk_buff *skb, struct device *dev);
+static void pt_interrupt(int irq, struct pt_regs *regs);
+static int pt_close(struct device *dev);
+static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static struct enet_statistics *pt_get_stats(struct device *dev);
+static void pt_rts(struct pt_local *lp, int x);
+static void pt_rxisr(struct device *dev);
+static void pt_txisr(struct pt_local *lp);
+static void pt_exisr(struct pt_local *lp);
+static void pt_tmrisr(struct pt_local *lp);
+static char *get_dma_buffer(unsigned long *mem_ptr);
+static int valid_dma_page(unsigned long addr, unsigned long dev_buffsize);
+static int hw_probe(int ioaddr);
+static void tdelay(struct pt_local *lp, int time);
+static void empty_scc(struct pt_local *lp);
+static void chipset_init(struct device *dev);
+static void send_kiss(struct device *dev, unsigned char arg, unsigned char val);
+
+static char ax25_bcast[7] =
+{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
+static char ax25_test[7] =
+{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
+
+
+
+static int ext2_secrm_seed = 152;
+
+static inline unsigned char random(void)
+{
+    return (unsigned char) (ext2_secrm_seed = ext2_secrm_seed * 60691 + 1);
+}
+
+static inline void wrtscc(int cbase, int ctl, int sccreg, unsigned char val)
+{
+    outb_p(sccreg, ctl);        /* Select register */
+    outb_p(val, ctl);           /* Output value */
+}
+
+static inline unsigned char rdscc(int cbase, int ctl, int sccreg)
+{
+    unsigned char retval;
+
+    outb_p(sccreg, ctl);        /* Select register */
+    retval = inb_p(ctl);
+    return retval;
+}
+
+static void switchbuffers(struct pt_local *lp)
+{
+    if (lp->rcvbuf == lp->rxdmabuf1)
+       lp->rcvbuf = lp->rxdmabuf2;
+    else
+       lp->rcvbuf = lp->rxdmabuf1;
+}
+               
+static void hardware_send_packet(struct pt_local *lp, struct sk_buff *skb)
+{
+    char kickflag;
+    unsigned long flags;
+    char *ptr;
+    struct device *dev;
+
+       /* First, let's see if this packet is actually a KISS packet */
+       ptr = skb->data;
+       if (ptr[0] != 0 && skb->len >= 2)
+       {
+               printk("Rx KISS... Control = %d, value = %d.\n", ptr[0], (skb->len > 1? ptr[1] : -1));
+               /* Kludge to get device */
+               if ((struct pt_local*)(&pt0b.priv) == lp)
+                       dev = &pt0b;
+               else
+                       dev = &pt0a;
+               switch(ptr[0])
+               {
+
+                       case PARAM_TXDELAY:
+                               /*TxDelay is in 10mS increments */
+                               lp->txdelay = ptr[1] * 10;
+                               send_kiss(dev, PARAM_TXDELAY, (u_char)(lp->txdelay/10));
+                               break;
+                       case PARAM_PERSIST:
+                               lp->persist = ptr[1];
+                               send_kiss(dev, PARAM_PERSIST, (u_char)(lp->persist));
+                               break;
+                       case PARAM_SLOTTIME:
+                               lp->slotime = ptr[1];
+                               send_kiss(dev, PARAM_SLOTTIME, (u_char)(lp->slotime/10));
+                               break;
+                       case PARAM_FULLDUP:
+                               /* Yeah right, you wish!  Fullduplex is a little while to
+                                * go folks, but this is how you fire it up
+                                */
+                               send_kiss(dev, PARAM_FULLDUP, 0);
+                               break;
+                       /* Perhaps we should have txtail here?? */
+               } /*switch */
+               return;
+       }
+       
+    lp->stats.tx_packets++;
+
+    save_flags(flags);
+    cli();
+    kickflag = (skb_peek(&lp->sndq) == NULL) && (lp->sndbuf == NULL);
+    restore_flags(flags);
+
+#ifdef PT_DEBUG
+       printk("PTd hardware_send_packet(): kickflag = %d (%d).\n", kickflag, lp->base & CHANA);
+#endif 
+    skb_queue_tail(&lp->sndq, skb);
+    if (kickflag) {
+        /* Simulate interrupt to transmit */
+            if (lp->dmachan)
+            {  
+               pt_txisr(lp);
+            } else {
+               save_flags(flags);
+                       cli();
+               if (lp->tstate == IDLE)
+                       pt_txisr(lp); 
+               restore_flags(flags);
+            }
+    }
+} /* hardware_send_packet() */
+
+static void setup_rx_dma(struct pt_local *lp)
+{
+    unsigned long flags;
+    int cmd;
+    unsigned long dma_abs;
+    unsigned char dmachan;
+
+    save_flags(flags);
+    cli();
+
+    dma_abs = (unsigned long) (lp->rcvbuf->data);
+    dmachan = lp->dmachan;
+    cmd = lp->base + CTL;
+
+    if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))
+       panic("PI: RX buffer violates DMA boundary!");
+
+    /* Get ready for RX DMA */
+    wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+
+    disable_dma(dmachan);
+    clear_dma_ff(dmachan);
+
+    /* Set DMA mode register to single transfers, incrementing address,
+     *  auto init, writes
+     */
+    set_dma_mode(dmachan, DMA_MODE_READ | 0x10);
+    set_dma_addr(dmachan, dma_abs);
+    set_dma_count(dmachan, lp->bufsiz);
+    enable_dma(dmachan);
+
+    /* If a packet is already coming in, this line is supposed to
+          avoid receiving a partial packet.
+     */
+    wrtscc(lp->cardbase, cmd, R0, RES_Rx_CRC);
+
+    /* Enable RX dma */
+    wrtscc(lp->cardbase, cmd, R1,
+      WT_RDY_ENAB | WT_FN_RDYFN | WT_RDY_RT | INT_ERR_Rx | EXT_INT_ENAB);
+
+    restore_flags(flags);
+}
+
+static void setup_tx_dma(struct pt_local *lp, int length)
+{
+    unsigned long dma_abs;
+    unsigned long flags;
+    unsigned long dmachan;
+
+    save_flags(flags);
+    cli();
+
+    dmachan = lp->dmachan;
+    dma_abs = (unsigned long) (lp->txdmabuf);
+
+    if(!valid_dma_page(dma_abs, DMA_BUFF_SIZE + sizeof(struct mbuf)))
+       panic("PT: TX buffer violates DMA boundary!");
+
+    disable_dma(dmachan);
+    /* Set DMA mode register to single transfers, incrementing address,
+     *  no auto init, reads
+     */
+    set_dma_mode(dmachan, DMA_MODE_WRITE);
+    clear_dma_ff(dmachan);
+    set_dma_addr(dmachan, dma_abs);
+    /* output byte count */
+    set_dma_count(dmachan, length);
+
+    restore_flags(flags);
+}
+
+static void free_p(struct sk_buff *skb)
+{
+    dev_kfree_skb(skb, FREE_WRITE);
+}
+
+static void pt_loopback(struct pt_local *lp, int onoff)
+{
+    if (lp->base & CHANA) {
+        if (onoff == ON)
+            outb_p(pt_sercfg |= PT_LOOPA_ON, lp->cardbase + SERIAL_CFG);
+        else
+            outb_p(pt_sercfg &= ~PT_LOOPA_ON, lp->cardbase + SERIAL_CFG);
+    } else {    /* it's channel B */
+        if (onoff == ON)
+            outb_p(pt_sercfg |= PT_LOOPB_ON, lp->cardbase + SERIAL_CFG);
+        else
+            outb_p(pt_sercfg &= ~PT_LOOPB_ON, lp->cardbase + SERIAL_CFG);
+    }
+} /*pt_loopback */
+
+/* Fill in the MAC-level header */
+static int pt_header (struct sk_buff *skb, struct device *dev, unsigned short type,
+               void *daddr, void *saddr, unsigned len)
+{
+       return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+}
+
+
+/* Rebuild the MAC-level header */
+static int pt_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
+                               struct sk_buff *skb)
+{
+       return ax25_rebuild_header(buff, dev, raddr, skb);
+}
+
+                                       
+                                       
+
+
+/*
+ * This sets up all the registers in the SCC for the given channel
+ * based upon tsync_hwint()
+ */
+static void scc_init(struct device *dev)
+{
+    unsigned long flags;
+    struct pt_local *lp = (struct pt_local*) dev->priv;
+    register int cmd = lp->base + CTL;
+    int tc, br;
+
+#ifdef PT_DEBUG
+       printk("PTd scc_init(): (%d).\n", lp->base & CHANA);
+#endif 
+    save_flags(flags);
+    cli();
+
+    /* We may put something here to enable_escc */
+
+    if (cmd & CHANA)
+    {
+        wrtscc(lp->cardbase, cmd, R9, CHRA);           /* Reset channel A */
+        wrtscc(lp->cardbase, cmd, R2, 0xff);           /* Initialise interrupt vector */
+    } else {
+       wrtscc(lp->cardbase, cmd, R9, CHRB);            /* Reset channel B */
+    }
+    
+    /* Deselect all Rx and Tx interrupts */
+    wrtscc(lp->cardbase, cmd, R1, 0);
+    
+    /* Turn off external interrupts (like CTS/CD) */
+    wrtscc(lp->cardbase, cmd, R15, 0);
+           
+    /* X1 clock, SDLC mode */
+    wrtscc(lp->cardbase, cmd, R4, SDLC | X1CLK);
+       
+       /* Preset CRC and set mode */
+       if (lp->nrzi)
+       {
+       /* Preset Tx CRC, put into NRZI mode */
+       wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);           
+    } else {
+       /* Preset Tx CRC, put into NRZ mode */
+       wrtscc(lp->cardbase, cmd, R10, CRCPS);    
+    }
+    
+    /* Tx/Rx parameters */
+    if (lp->speed)             /* Use internal clocking */
+    {
+       /* Tx Clk from BRG. Rx Clk form DPLL, TRxC pin outputs DPLL */
+       wrtscc(lp->cardbase, cmd, R11, TCBR | RCDPLL | TRxCDP | TRxCOI);
+
+    } else {                   /* Use external clocking */
+           /* Tx Clk from TRxCL. Rx Clk from RTxCL, TRxC pin if input */
+           wrtscc(lp->cardbase, cmd, R11, TCTRxCP | RCRTxCP | TRxCBR);
+           wrtscc(lp->cardbase,cmd, R14, 0);   /* wiz1 */
+    }
+       
+    /* Null out SDLC start address */
+    wrtscc(lp->cardbase, cmd, R6, 0);
+
+    /* SDLC flag */
+    wrtscc(lp->cardbase, cmd, R7, FLAG);
+
+    /* Setup Tx but don't enable it */
+    wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);
+
+    /* Setup Rx */
+    wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);
+
+    /* Setup the BRG, turn it off first */
+    wrtscc(lp->cardbase, cmd, R14, BRSRC);
+
+    /* set the 32x time constant for the BRG in Rx mode */
+       if (lp->speed)
+       {
+               br = lp->speed;
+               tc = ((lp->xtal / 32) / (br * 2)) - 2;
+           wrtscc(lp->cardbase, cmd, R12, tc & 0xff);          /* lower byte */
+               wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff);       /* upper byte */                        
+       }
+
+       /* Turn transmitter off, to setup stuff */
+       pt_rts(lp, OFF);
+       
+       /* External clocking */
+       if (lp->speed)
+       {
+               /* DPLL frm BRG, BRG src PCLK */
+               wrtscc(lp->cardbase, cmd, R14, BRSRC | SSBR);
+               wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH); /* SEARCH mode, keep BRG src */
+           wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);    /* Enable the BRG */
+
+           /* Turn off external clock port */
+        if (lp->base & CHANA)
+            outb_p( (pt_sercfg &= ~PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
+        else
+            outb_p( (pt_sercfg &= ~PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );             
+    } else {
+               /* DPLL frm rtxc,BRG src PCLK */
+/*             wrtscc(lp->cardbase, cmd, R14, BRSRC | SSRTxC);*/
+        /* Turn on external clock port */
+        if (lp->base & CHANA)
+            outb_p( (pt_sercfg |= PT_EXTCLKA), (lp->cardbase + SERIAL_CFG) );
+        else
+            outb_p( (pt_sercfg |= PT_EXTCLKB), (lp->cardbase + SERIAL_CFG) );     
+    }
+
+    if (!lp->dmachan)  
+               wrtscc(lp->cardbase, cmd, R1, (INT_ALL_Rx | EXT_INT_ENAB));
+
+    wrtscc(lp->cardbase, cmd, R15, BRKIE);     /* ABORT int */
+       
+       /* Turn on the DTR to tell modem we're alive */
+       if (lp->base & CHANA)
+           outb_p( (pt_sercfg |= PT_DTRA_ON), (lp->cardbase + SERIAL_CFG) );
+       else
+       outb_p( (pt_sercfg |= PT_DTRB_ON), (lp->cardbase + SERIAL_CFG) );
+
+    /* Now, turn on the receiver and hunt for a flag */
+    wrtscc(lp->cardbase, cmd, R3, RxENABLE | RxCRC_ENAB | AUTO_ENAB | Rx8 );
+       
+       restore_flags(flags);
+
+} /* scc_init() */
+
+/* Resets the given channel and whole SCC if both channels off */
+static void chipset_init(struct device *dev)
+{
+
+       struct pt_local *lp = (struct pt_local*) dev->priv;
+#ifdef PT_DEBUG
+       printk("PTd chipset_init(): pt0a tstate = %d.\n", ((struct pt_local*)pt0a.priv)->tstate);
+       printk("PTd chipset_init(): pt0b tstate = %d.\n", ((struct pt_local*)pt0b.priv)->tstate);       
+#endif
+       /* Reset SCC if both channels are to be canned */
+       if ( ((lp->base & CHANA) && !(pt_sercfg & PT_DTRB_ON)) ||
+                       (!(lp->base & CHANA) && !(pt_sercfg & PT_DTRA_ON)) ) 
+       {
+               wrtscc(lp->cardbase, lp->base + CTL, R9, FHWRES);
+               /* Reset int and dma registers */
+               outb_p((pt_sercfg = 0), lp->cardbase + SERIAL_CFG);
+               outb_p((pt_dmacfg = 0), lp->cardbase + DMA_CFG);
+#ifdef PT_DEBUG
+               printk("PTd chipset_init() Resetting SCC, called by ch (%d).\n", lp->base & CHANA);
+#endif                         
+       }
+       /* Reset individual channel */
+       if (lp->base & CHANA) {
+               wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRA);
+               outb_p( (pt_sercfg &= ~PT_DTRA_ON), lp->cardbase + SERIAL_CFG);
+       } else {
+               wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | DLC | NV | CHRB);
+                       outb_p( (pt_sercfg &= ~PT_DTRB_ON), lp->cardbase + SERIAL_CFG);                  
+       }       
+} /* chipset_init() */ 
+       
+       
+
+int pt_init(void)
+{
+    int *port;
+    int ioaddr = 0;
+    int card_type = 0;
+    int ports[] =
+    { 0x230, 0x240, 0x250, 0x260, 0x270, 0x280, 0x290, 0x2a0,
+      0x2b0, 0x300, 0x330, 0x3f0,  0};
+
+    printk(version);
+
+    for (port = &ports[0]; *port && !card_type; port++) {
+        ioaddr = *port;
+
+        if (check_region(ioaddr, PT_TOTAL_SIZE) == 0) {
+            printk("PT: Probing for card at address %#3x\n", ioaddr);
+            card_type = hw_probe(ioaddr);
+        }
+    }
+    if (card_type) {
+        printk("PT: Found a PT at address %#3x\n",ioaddr);
+    } else {
+        printk("PT: ERROR: No card found.\n");
+        return -EIO;
+    }
+
+    /*
+     * Link a couple of device structres into the chain
+     *
+     * For the A port
+     * Allocate space for 4 buffers even though we only need 3,
+     * because one of them may cross a DMA page boundary and
+     * be rejected by get_dma_buffer().
+     */
+    register_netdev(&pt0a);
+
+    pt0a.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA);
+
+    pt0a.dma = 0;      /* wizzer - no dma yet */
+    pt0a.base_addr = ioaddr + CHANA;
+    pt0a.irq = 0;
+
+    /* And B port */
+    register_netdev(&pt0b);
+
+    pt0b.priv= kmalloc(sizeof(struct pt_local) + (DMA_BUFF_SIZE + sizeof(struct mbuf)) * 4, GFP_KERNEL | GFP_DMA);
+
+    pt0b.base_addr = ioaddr + CHANB;
+    pt0b.irq = 0;
+
+    /* Now initialise them */
+    pt_probe(&pt0a);
+    pt_probe(&pt0b);
+
+    pt0b.irq = pt0a.irq;       /* IRQ is shared */
+    
+    return 0;
+} /* pt_init() */
+
+/*
+ * Probe for PT card.  Also initialises the timers
+ */
+static int hw_probe(int ioaddr)
+{
+    int time = 1000;           /* Number of milliseconds to test */
+    int a = 1;
+    int b = 1;
+    unsigned long start_time, end_time;
+    
+    inb_p(ioaddr + TMR1CLR);
+    inb_p(ioaddr + TMR2CLR);
+
+    /* Timer counter channel 0, 1mS period */
+    outb_p(SC0 | LSB_MSB | MODE3, ioaddr + TMRCMD);
+    outb_p(0x00, ioaddr + TMR0);
+    outb_p(0x18, ioaddr + TMR0);
+
+    /* Setup timer control word for timer 1 */
+    outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD);
+    outb_p((time << 1) & 0xff, ioaddr + TMR1);
+    outb_p((time >> 7) & 0xff, ioaddr + TMR1);
+    
+    /* wait until counter reg is loaded */
+    do {
+        /* Latch count for reading */
+        outb_p(SC1, ioaddr + TMRCMD);
+        a = inb_p(ioaddr + TMR1);
+        b = inb_p(ioaddr + TMR1);
+    } while (b == 0);
+    start_time = jiffies;
+    while(b != 0)
+    {
+        /* Latch count for reading */
+        outb_p(SC1, ioaddr + TMRCMD);
+        a = inb_p(ioaddr + TMR1);
+        b = inb_p(ioaddr + TMR1);
+        end_time = jiffies;
+        /* Don't wait forever - there may be no card here */
+        if ((end_time - start_time) > 200)
+        {
+               inb_p(ioaddr + TMR1CLR);
+            return 0;
+        }
+    }
+    
+    /* Now fix the timers up for general operation */
+    
+    /* Clear the timers */
+    inb_p(ioaddr + TMR1CLR);
+    inb_p(ioaddr + TMR2CLR);
+    
+    outb_p(SC1 | LSB_MSB | MODE0, ioaddr + TMRCMD);
+    inb_p(ioaddr + TMR1CLR);
+    
+    outb_p(SC2 | LSB_MSB | MODE0, ioaddr + TMRCMD);
+    /* Should this be tmr1 or tmr2? wiz3*/
+    inb_p(ioaddr + TMR1CLR);
+    
+    return 1;
+} /* hw_probe() */
+
+
+static void pt_rts(struct pt_local *lp, int x)
+{
+       int tc;
+       long br;
+       int cmd = lp->base + CTL;
+#ifdef PT_DEBUG
+       printk("PTd pt_rts(): Transmitter status will be %d (%d).\n", x, lp->base & CHANA);
+#endif                 
+       if (x == ON) {
+           /* Ex ints off to avoid int */
+           wrtscc(lp->cardbase, cmd, R15, 0);
+           wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);     /* Rx off */
+           lp->rstate = IDLE;
+           
+           if(lp->dmachan)
+           {
+               /* Setup for Tx DMA */
+               wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB);
+           } else {
+               /* No interrupts */
+               wrtscc(lp->cardbase, cmd, R1, 0);
+           }
+       
+            if (!lp->clockmode)
+            {
+                if (lp->speed)
+                {
+                    br = lp->speed;
+                    tc = (lp->xtal / (br * 2)) - 2;
+                    wrtscc(lp->cardbase, cmd, R12, tc & 0xff);
+                    wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff);
+                }
+            }
+            /* Turn on Tx by raising RTS */
+            wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
+            /* Transmitter on now */
+        } else {               /* turning off Tx */
+            lp->tstate = IDLE;
+            
+            /* Turn off Tx by dropping RTS */
+            wrtscc(lp->cardbase, cmd, R5, Tx8 | DTR);
+            if (!lp->clockmode)
+            {
+                if (lp->speed)         /* internally clocked */
+                {
+                    /* Repogram BRG from 32x clock for Rx DPLL */
+                    /* BRG off, keep PClk source */
+                    wrtscc(lp->cardbase, cmd, R14, BRSRC);
+                    br = lp->speed;
+                    tc = ((lp->xtal / 32) / (br * 2)) - 2;
+                    wrtscc(lp->cardbase, cmd, R12, tc & 0xff);
+                    wrtscc(lp->cardbase, cmd, R13, (tc >> 8) & 0xff);
+                    
+                    /* SEARCH mode, BRG source */
+                    wrtscc(lp->cardbase, cmd, R14, BRSRC | SEARCH);
+                    /* Enalbe the BRG */
+                    wrtscc(lp->cardbase, cmd, R14, BRSRC | BRENABL);
+                }
+            }
+            /* Flush Rx fifo */
+            /* Turn Rx off */
+            wrtscc(lp->cardbase, cmd, R3, AUTO_ENAB | Rx8);
+            
+            /* Reset error latch */
+            wrtscc(lp->cardbase, cmd, R0, ERR_RES);
+            
+            /* get status byte from R1 */
+            (void) rdscc(lp->cardbase, cmd, R1);
+            
+            /* Read and dump data in queue */
+            (void) rdscc(lp->cardbase, cmd, R8);
+            (void) rdscc(lp->cardbase, cmd, R8);
+            (void) rdscc(lp->cardbase, cmd, R8);
+            
+            /* Now, turn on Rx and hunt for a flag */
+              wrtscc(lp->cardbase, cmd, R3, RxENABLE | AUTO_ENAB | Rx8 );
+              
+            lp->rstate = ACTIVE;
+            
+            if (lp->dmachan)
+            {
+                setup_rx_dma(lp);
+            } else {
+                /* Reset buffer pointers */
+                lp->rcp = lp->rcvbuf->data;
+                lp->rcvbuf->cnt = 0;
+                /* Allow aborts to interrupt us */
+                wrtscc(lp->cardbase, cmd, R1, INT_ALL_Rx | EXT_INT_ENAB);
+
+       }
+       wrtscc(lp->cardbase, cmd, R15, BRKIE );
+    }
+} /* pt_rts() */       
+               
+                               
+static int valid_dma_page(unsigned long addr, unsigned long dev_bufsize)
+{
+    if (((addr & 0xffff) + dev_bufsize) <= 0x10000)
+        return 1;
+    else
+        return 0;
+}
+
+static int pt_set_mac_address(struct device *dev, struct sockaddr *sa)
+{
+       memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);              /* addr is an AX.25 shifted ASCII */
+       return 0;               /* mac address */
+}
+       
+
+/* Allocate a buffer which does not cross a DMA page boundary */
+static char * get_dma_buffer(unsigned long *mem_ptr)
+{
+    char *ret;
+
+    ret = (char *) *mem_ptr;
+
+    if (!valid_dma_page(*mem_ptr, DMA_BUFF_SIZE + sizeof(struct mbuf))) {
+        *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf));
+        ret = (char *) *mem_ptr;
+    }
+    *mem_ptr += (DMA_BUFF_SIZE + sizeof(struct mbuf));
+    return (ret);
+} /* get_dma_buffer() */
+
+
+/*
+ * Sets up all the structures for the PT device
+ */
+static int pt_probe(struct device *dev)
+{
+    short ioaddr;
+    struct pt_local *lp;
+    int i;
+    unsigned long flags;
+    unsigned long mem_ptr;
+
+    ioaddr = dev->base_addr;
+
+    /*
+     * Initialise the device structure.
+     * Must be done before chipset_init()
+     * Make sure data structures used by  the PT are aligned
+     */
+    dev->priv = (void *) (((int) dev->priv + 7) & ~7);
+    lp = (struct pt_local*) dev->priv;
+
+    memset(dev->priv, 0, sizeof(struct pt_local));
+
+    /* Allocate some buffers which do not cross DMA boundaries */
+    mem_ptr = (unsigned long) dev->priv + sizeof(struct pt_local);
+    lp->txdmabuf = get_dma_buffer(&mem_ptr);
+    lp->rxdmabuf1 = (struct mbuf *) get_dma_buffer(&mem_ptr);
+    lp->rxdmabuf2 = (struct mbuf *) get_dma_buffer(&mem_ptr);
+
+    /* Initialise the Rx buffer */
+    lp->rcvbuf = lp->rxdmabuf1;
+    lp->rcp = lp->rcvbuf->data;
+    lp->rcvbuf->cnt = 0;
+
+    /* Initialise the transmit queue head structure */
+    skb_queue_head_init(&lp->sndq);
+
+    lp->base = dev->base_addr;
+    lp->cardbase = dev->base_addr & 0x3f0;
+       
+    /* These need to be initialsed before scc_init() is called.
+     */
+    lp->xtal = XTAL;
+    
+    if (dev->base_addr & CHANA) {
+        lp->speed = DEF_A_SPEED;
+        lp->txdelay = DEF_A_TXDELAY;
+        lp->persist = DEF_A_PERSIST;
+        lp->slotime = DEF_A_SLOTIME;
+        lp->squeldelay = DEF_A_SQUELDELAY;
+        lp->clockmode = DEF_A_CLOCKMODE;
+        lp->nrzi = DEF_A_NRZI;
+    } else {
+        lp->speed = DEF_B_SPEED;
+        lp->txdelay = DEF_B_TXDELAY;
+        lp->persist = DEF_B_PERSIST;
+        lp->slotime = DEF_B_SLOTIME;
+        lp->squeldelay = DEF_B_SQUELDELAY;
+        lp->clockmode = DEF_B_CLOCKMODE;
+        lp->nrzi = DEF_B_NRZI;
+    }
+    lp->bufsiz = DMA_BUFF_SIZE;
+    lp->tstate = IDLE;
+
+    chipset_init(dev);
+
+    if (dev->base_addr & CHANA) {
+        /* Note that a single IRQ services 2 devices (A and B channels)
+        */
+
+       /*
+        * We disable the dma for a while, we have to get ints working
+        * properly first!!
+        */
+       lp->dmachan = 0;
+       
+        if (dev->irq < 2) {
+            autoirq_setup(0);
+            
+            /* Turn on PT interrupts */
+            save_flags(flags);
+            cli();
+            outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG);
+            restore_flags(flags);
+
+            /* Set a timer interrupt */
+            tdelay(lp, 1);
+            dev->irq = autoirq_report(20);
+
+           /* Turn off PT interrupts */
+           save_flags(flags);
+           cli();
+            outb_p( (pt_sercfg  &= ~ PT_EI), lp->cardbase + INT_CFG);            
+            restore_flags(flags);
+
+            if (!dev->irq) {
+                printk("PT: ERROR: Failed to detect IRQ line, assuming IRQ7.\n");
+            }
+        }
+
+        printk("PT: Autodetected IRQ %d, assuming DMA %d\n", dev->irq, dev->dma);
+
+        /* This board has jumpered interrupts. Snarf the interrupt vector
+         * now.  There is no point in waiting since no other device can use
+         * the interrupt, and this marks the 'irqaction' as busy.
+         */
+        {
+            int irqval = request_irq(dev->irq, &pt_interrupt,0, "pt");
+            if (irqval) {
+                printk("PT: ERROR: Unable to get IRQ %d (irqval = %d).\n",
+                    dev->irq, irqval);
+                return EAGAIN;
+            }
+        }
+
+        /* Grab the region */
+        snarf_region(ioaddr & 0x3f0, PT_TOTAL_SIZE);
+    } /* A port */
+    dev->open = pt_open;
+    dev->stop = pt_close;
+    dev->do_ioctl = pt_ioctl;
+    dev->hard_start_xmit = pt_send_packet;
+    dev->get_stats = pt_get_stats;
+
+    /* Fill in the fields of the device structure */
+    for (i=0; i < DEV_NUMBUFFS; i++)
+        skb_queue_head_init(&dev->buffs[i]);
+
+    dev->hard_header = pt_header;
+    dev->rebuild_header = pt_rebuild_header;
+    dev->set_mac_address = pt_set_mac_address;
+
+    dev->type = ARPHRD_AX25;            /* AF_AX25 device */
+    dev->hard_header_len = 73;      /* We do digipeaters now */
+    dev->mtu = 1500;                /* eth_mtu is default */
+    dev->addr_len = 7;               /* sizeof an ax.25 address */
+    memcpy(dev->broadcast, ax25_bcast, 7);
+    memcpy(dev->dev_addr, ax25_test, 7);
+
+    /* New style flags */
+    dev->flags = 0;
+    dev->family = AF_INET;
+    dev->pa_addr = 0;
+    dev->pa_brdaddr = 0;
+    dev->pa_mask = 0;
+    dev->pa_alen = sizeof(unsigned long);
+
+    return 0;
+} /* pt_probe() */
+
+
+/* Open/initialise the board.  This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that 'should' only be set once at bott, so that there is
+ * a non-reboot way to recover if something goes wrong.
+ * derived from last half of tsync_attach()
+ */
+static int pt_open(struct device *dev)
+{
+    unsigned long flags;
+    struct pt_local *lp = dev->priv;
+    static first_time = 1;
+    
+    if (dev->base_addr & CHANA)
+    {
+        if (first_time)
+        {
+            if (request_dma(dev->dma, "pt"))
+            {
+                free_irq(dev->irq);
+                return -EAGAIN;
+            }
+        }
+       irq2dev_map[dev->irq] = dev;
+         /* Reset hardware */  
+         chipset_init(dev);
+     }
+     lp->tstate = IDLE;
+    
+     if (dev->base_addr & CHANA)
+     {
+         scc_init(dev);
+         scc_init(dev->next);
+     }
+     /* Save a copy of register RR0 for comparing with later on */
+     /* We always put 0 in zero count */
+     lp->saved_RR0 = rdscc(lp->cardbase, lp->base + CTL, R0) & ~ZCOUNT;
+    
+    /* master interrupt enable */
+    save_flags(flags);
+    cli();
+    wrtscc(lp->cardbase, lp->base + CTL, R9, MIE | NV);
+    outb_p( pt_sercfg |= PT_EI, lp->cardbase + INT_CFG);    
+    restore_flags(flags);
+
+    lp->open_time = jiffies;
+
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    dev->start = 1;
+    first_time = 0;
+       
+    return 0;
+} /* pt_open() */
+
+static int pt_send_packet(struct sk_buff *skb, struct device *dev)
+{
+       struct pt_local *lp = (struct pt_local *) dev->priv;
+
+#ifdef PT_DEBUG
+       printk("PTd pt_send_packet(): (%d)\n", lp->base & CHANA);
+#endif                 
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself.*/
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+       hardware_send_packet(lp, skb);
+       dev->trans_start = jiffies;
+       
+       return 0;
+}
+                                  
+          
+
+/* The inverse routine to pt_open() */
+static int pt_close(struct device *dev)
+{
+       unsigned long flags;
+       struct pt_local *lp = dev->priv;
+       struct sk_buff *ptr = NULL;
+       int cmd;
+
+       cmd = lp->base + CTL;
+               
+       save_flags(flags);
+       cli();
+       
+       /* Reset SCC or channel */
+       chipset_init(dev);      
+       disable_dma(lp->dmachan);
+
+       lp->open_time = 0;
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       /* Free any buffers left in the hardware transmit queue */
+       while ((ptr = skb_dequeue(&lp->sndq)) != NULL)
+               free_p(ptr);
+               
+       restore_flags(flags);
+       
+#ifdef PT_DEBUG
+       printk("PTd pt_close(): Closing down channel (%d).\n", lp->base & CHANA);       
+#endif 
+       
+       return 0;
+} /* pt_close() */
+
+
+static int pt_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+    unsigned long flags;
+    struct pt_req rq;
+    struct pt_local *lp = (struct pt_local *) dev->priv;
+
+    int ret = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct pt_req));
+    if (ret)
+       return ret;
+
+    if (cmd != SIOCDEVPRIVATE)
+        return -EINVAL;
+        
+    memcpy_fromfs(&rq, ifr->ifr_data, sizeof(struct pt_req));
+
+    switch (rq.cmd) {
+    case SIOCSPIPARAM:
+
+       if (!suser())
+           return -EPERM;
+       save_flags(flags);
+       cli();
+       lp->txdelay = rq.txdelay;
+       lp->persist = rq.persist;
+       lp->slotime = rq.slotime;
+       lp->squeldelay = rq.squeldelay;
+       lp->clockmode = rq.clockmode;
+       lp->speed = rq.speed;
+       pt_open(&pt0a);
+       restore_flags(flags);
+       ret = 0;
+       break;
+
+    case SIOCSPIDMA:
+
+       if (!suser())
+           return -EPERM;
+       ret = 0;
+       if (dev->base_addr & CHANA) {   /* if A channel */
+          if (rq.dmachan < 1 || rq.dmachan > 3)
+               return -EINVAL;
+          save_flags(flags);
+          cli();
+          pt_close(dev);
+          free_dma(lp->dmachan);
+          dev->dma = lp->dmachan = rq.dmachan;
+          if (request_dma(lp->dmachan,"pt")) 
+               ret = -EAGAIN;
+          pt_open(dev);
+          restore_flags(flags);
+       }
+       break;
+
+    case SIOCSPIIRQ:
+       ret = -EINVAL;      /* add this later */
+       break;
+
+    case SIOCGPIPARAM:
+    case SIOCGPIDMA:
+    case SIOCGPIIRQ:
+
+       rq.speed = lp->speed;
+       rq.txdelay = lp->txdelay;
+       rq.persist = lp->persist;
+       rq.slotime = lp->slotime;
+       rq.squeldelay = lp->squeldelay;
+       rq.clockmode = lp->clockmode;
+       rq.dmachan = lp->dmachan;
+       rq.irq = dev->irq;
+       memcpy_tofs(ifr->ifr_data, &rq, sizeof(struct pt_req));
+       ret = 0;
+       break;
+
+    default:
+       ret = -EINVAL;
+    }
+    return ret;
+}
+
+/* Get the current statistics. This may be called with the card open or
+   closed. */
+static struct netstats *
+ pt_get_stats(struct device *dev)
+{
+    struct pt_local *lp = (struct pt_local *) dev->priv;
+
+    return &lp->stats;
+}
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
+
+
+static void tdelay(struct pt_local *lp, int time)
+{
+       /* For some reason, we turn off the Tx interrupts here! */
+       if (!lp->dmachan)
+               wrtscc(lp->cardbase, lp->base + CTL, R1, INT_ALL_Rx | EXT_INT_ENAB);
+       
+    if (lp->base & CHANA) {
+        outb_p(time & 0xff, lp->cardbase + TMR1);
+        outb_p((time >> 8)&0xff, lp->cardbase + TMR1);
+    } else {
+        outb_p(time & 0xff, lp->cardbase + TMR2);
+        outb_p((time >> 8)&0xff, lp->cardbase + TMR2);
+    }
+} /* tdelay */
+
+
+static void pt_txisr(struct pt_local *lp)
+{
+       unsigned long flags;
+       int cmd;
+       unsigned char c;
+       
+       save_flags(flags);
+       cli();
+       cmd = lp->base + CTL;
+
+#ifdef PT_DEBUG
+       printk("PTd pt_txisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA);
+#endif 
+       
+       switch (lp->tstate) 
+       {
+       case CRCOUT:
+           lp->tstate = FLAGOUT;
+           tdelay(lp, lp->squeldelay);
+           restore_flags(flags);
+           return;
+           
+       case IDLE:
+           /* Transmitter idle. Find a frame for transmission */
+           if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL)
+           {
+               /* Nothing to send - return to receive mode
+                * Tx off now - flag should have gone
+                */
+               pt_rts(lp, OFF);
+               
+               restore_flags(flags);
+               return;
+           }
+           if (!lp->dmachan)
+           {
+                   lp->txptr = lp->sndbuf->data;
+                   lp->txptr++;                /* Ignore KISS control byte */
+                   lp->txcnt = (int) lp->sndbuf->len - 1;
+               }
+           /* If a buffer to send, drop though here */
+       
+       case DEFER:
+           /* Check DCD - debounce it */
+           /* See Intel Microcommunications Handbook p2-308 */
+           wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT);
+           wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT);
+           if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0)
+           {
+               lp->tstate = DEFER;
+               tdelay(lp, 100);
+               /* DEFER until DCD transistion or timeout */
+               wrtscc(lp->cardbase, cmd, R15, DCDIE);
+               restore_flags(flags);
+               return;
+           }
+           if (random() > lp->persist)
+           {
+               lp->tstate = DEFER;
+               tdelay(lp, lp->slotime);
+               restore_flags(flags);
+               return;
+           }
+           pt_rts(lp, ON);             /* Tx on */
+           if (lp->dmachan)
+               wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8);
+           lp->tstate = ST_TXDELAY;
+           tdelay(lp, lp->txdelay);
+           restore_flags(flags);
+           return;
+       
+       case ACTIVE:
+           /* Here we are actively sending a frame */
+           if (lp->txcnt--)
+           {
+               /* XLZ - checkout Gracilis PT code to see if the while 
+                * loop is better or not.
+                */
+               c = *lp->txptr++;
+               /* next char is gone */
+               wrtscc(lp->cardbase, cmd, R8, c);
+               /* stuffing a char satisfies interrupt condition */
+           } else {
+               /* No more to send */
+               free_p(lp->sndbuf);
+               lp->sndbuf = NULL;
+               if ((rdscc(lp->cardbase, cmd, R0) & TxEOM))
+               {
+                   /* Did we underrum */
+                   lp->stats.tx_errors++;
+                   lp->stats.tx_fifo_errors++;
+                   wrtscc(lp->cardbase, cmd, R0, SEND_ABORT);
+                   lp->tstate = FLAGOUT;
+                   tdelay(lp, lp->squeldelay);
+                   restore_flags(flags);
+                   return;
+               }
+               lp->tstate = UNDERRUN;
+               /* Send flags on underrun */
+              if (lp->nrzi)
+              {
+                  wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI);
+              } else {
+                  wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ);
+              }
+              /* Reset Tx interrupt pending */
+              wrtscc(lp->cardbase, cmd, R0, RES_Tx_P);
+          }
+          restore_flags(flags);
+          return;
+       default:
+               printk("PT: pt_txisr(): Invlaid tstate (%d) for chan %s.\n", lp->tstate, (cmd & CHANA? "A": "B") );
+               pt_rts(lp, OFF);
+               lp->tstate = IDLE;
+               break;          
+    }                          /*switch */
+    restore_flags(flags);
+}
+
+static void pt_rxisr(struct device *dev)
+{
+    struct pt_local *lp = (struct pt_local*) dev->priv;
+    int cmd = lp->base + CTL;
+    int bytecount;
+    unsigned long flags;
+    char rse;
+    struct sk_buff *skb;
+    int sksize, pkt_len;
+    struct mbuf *cur_buf;
+    unsigned char *cfix;
+
+    save_flags(flags);
+    cli();
+
+    /* Get status byte from R1 */
+    rse = rdscc(lp->cardbase, cmd, R1);
+    
+#ifdef PT_DEBUG
+    printk("PTd pt_rxisr(): R1 = %#3x. (%d)\n", rse, lp->base & CHANA);
+#endif        
+
+       if (lp->dmachan && (rse & Rx_OVR))
+               lp->rstate = RXERROR;
+               
+    if (rdscc(lp->cardbase, cmd, R0) & Rx_CH_AV && !lp->dmachan) 
+    {
+        /* There is a char to be stored
+         * Read special condition bits before reading the data char
+         */
+        if (rse & Rx_OVR)
+        {
+             /* Rx overrun - toss buffer */
+             /* wind back the pointers */
+             lp->rcp = lp->rcvbuf->data;
+             lp->rcvbuf->cnt = 0;
+             lp->rstate = RXERROR;
+             lp->stats.rx_errors++;
+             lp->stats.rx_fifo_errors++;
+         } else if (lp->rcvbuf->cnt >= lp->bufsiz)
+             {
+                 /* Too large packet
+                  * wind back Rx buffer pointers
+                  */
+                 lp->rcp = lp->rcvbuf->data;
+                 lp->rcvbuf->cnt = 0;
+                 lp->rstate = TOOBIG;
+             }
+         /* ok, we can store the Rx char if no errors */
+         if (lp->rstate == ACTIVE)
+         {
+             *lp->rcp++ = rdscc(lp->cardbase, cmd, R8);
+             lp->rcvbuf->cnt++;
+         } else {
+             /* we got an error, dump the FIFO */
+             (void) rdscc(lp->cardbase, cmd, R8);
+             (void) rdscc(lp->cardbase, cmd, R8);
+             (void) rdscc(lp->cardbase, cmd, R8);
+             
+             /* Reset error latch */
+             wrtscc(lp->cardbase, cmd, R0, ERR_RES);
+             lp->rstate = ACTIVE;
+             
+             /* Resync the SCC */
+             wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8);
+             
+         }
+     }
+     
+     if (rse & END_FR)
+     {
+#ifdef PT_DEBUG
+       printk("PTd pt_rxisr() Got end of a %u byte frame.\n", lp->rcvbuf->cnt);
+#endif      
+               if (lp->dmachan)
+               {
+                       clear_dma_ff(lp->dmachan);
+                       bytecount = lp->bufsiz - get_dma_residue(lp->dmachan);
+               } else {
+                       bytecount = lp->rcvbuf->cnt;
+               }
+                       
+         /* END OF FRAME - Make sure Rx was active */
+         if (lp->rcvbuf->cnt > 0 || lp->dmachan)
+         {
+             if ((rse & CRC_ERR) || (lp->rstate > ACTIVE) || (bytecount < 10))
+             {
+                 if ((bytecount >= 10) && (rse & CRC_ERR))
+                 {
+                     lp->stats.rx_crc_errors++;
+                 }
+                 if (lp->dmachan)
+                 {
+                       if (lp->rstate == RXERROR)
+                       {
+                               lp->stats.rx_errors++;
+                               lp->stats.rx_over_errors++;
+                       }
+                       lp->rstate = ACTIVE;
+                       setup_rx_dma(lp);
+                 } else {
+                        /* wind back Rx buffer pointers */
+                    lp->rcp = lp->rcvbuf->data;
+                        lp->rcvbuf->cnt = 0;
+
+                                       /* Re-sync the SCC */
+                                       wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8);                     
+                        
+                    }
+#ifdef PT_DEBUG
+       printk("PTd pt_rxisr() %s error.\n", (rse & CRC_ERR)? "CRC" : "state");
+#endif                 
+             } else {
+                 /* We have a valid frame */
+                 if (lp->dmachan)
+                 {
+                       pkt_len = lp->rcvbuf->cnt = bytecount - 2 +1;
+                                       /* Get buffer for next frame */
+                       cur_buf = lp->rcvbuf;
+                       switchbuffers(lp);
+                       setup_rx_dma(lp);                       
+                 } else {
+                        pkt_len = lp->rcvbuf->cnt -= 2;  /* Toss 2 CRC bytes */
+                    pkt_len += 1;      /* make room for KISS control byte */
+                       }         
+
+                 /* Malloc up new buffer */
+                 sksize = pkt_len;
+                 skb = dev_alloc_skb(sksize);
+                 if (skb == NULL)
+                 {
+                     printk("PT: %s: Memory squeze, dropping packet.\n", dev->name);
+                     lp->stats.rx_dropped++;
+                     restore_flags(flags);
+                     return;
+                 }
+                 skb->dev = dev;
+                 
+                 /* KISS kludge = prefix with a 0 byte */
+                 cfix=skb_put(skb,pkt_len);
+                 *cfix++=0;
+                 /* skb->data points to the start of sk_buff area */
+                 if (lp->dmachan)
+                       memcpy(cfix, (char*)cur_buf->data, pkt_len - 1);
+                 else
+                    memcpy(cfix, lp->rcvbuf->data, pkt_len - 1);
+                 skb->protocol = ntohs(ETH_P_AX25);
+                 skb->mac.raw=skb->data;
+                 IS_SKB(skb);
+                 netif_rx(skb);
+                 lp->stats.rx_packets++;
+                 if (!lp->dmachan)
+                 {
+                        /* packet queued - wind back buffer for next frame */
+                    lp->rcp = lp->rcvbuf->data;
+                        lp->rcvbuf->cnt = 0;
+                    }
+             } /* good frame */
+         } /* check active Rx */
+         /* Clear error status */
+         lp->rstate = ACTIVE;
+         /* Reset error latch */
+     } /* end EOF check */
+     wrtscc(lp->cardbase, cmd, R0, ERR_RES);
+     restore_flags(flags);
+} /* pt_rxisr() */
+
+/* Read the SCC channel till no more data in receiver */
+static void empty_scc(struct pt_local *lp)
+{
+    while( rdscc(lp->cardbase, lp->base + CTL, R0) & Rx_CH_AV) {
+        /* Get data from Rx buffer and toss it */
+        (void) inb_p(lp->base + DATA);
+    }
+} /* empty_scc()*/
+
+/*
+ * This handles the two timer interrupts.
+ * This is a real bugger, cause you have to rip it out of the pi's
+ * external status code.  They use the CTS line or something.
+ */
+static void pt_tmrisr(struct pt_local *lp)
+{
+    unsigned long flags;
+
+#ifdef PT_DEBUG
+       printk("PTd pt_tmrisr(): tstate = %d (%d).\n", lp->tstate, lp->base & CHANA);
+#endif         
+       
+    save_flags(flags);
+    cli();
+    
+    
+    switch (lp->tstate) 
+    {
+    /* Most of this stuff is in pt_exisr() */
+    case FLAGOUT:
+    case ST_TXDELAY:
+    case DEFER:
+/*    case ACTIVE:
+    case UNDERRUN:*/
+        pt_exisr(lp);
+        break; 
+      
+    default:
+       if (lp->base & CHANA)
+           printk("PT: pt_tmrisr(): Invalid tstate %d for Channel A\n", lp->tstate);
+       else
+           printk("PT: pt_tmrisr(): Invalid tstate %d for Channel B\n", lp->tstate);
+       break;          
+    } /* end switch */
+    restore_flags(flags);
+} /* pt_tmrisr() */
+
+       
+/*
+ * This routine is called by the kernel when there is an interrupt for the
+ * PT.
+ */
+static void pt_interrupt(int irq, struct pt_regs *regs)
+{
+    /* It's a tad dodgy here, but we assume pt0a until proven otherwise */
+    struct device *dev = &pt0a;
+    struct pt_local *lp = dev->priv;
+    unsigned char intreg;
+    unsigned char st;
+    register int cbase = dev->base_addr & 0x3f0;
+    unsigned long flags;
+    
+    /* Read the PT's interrupt register, this is not the SCC one! */
+    intreg = inb_p(cbase + INT_REG);
+    while(( intreg & 0x07) != 0x07) {
+        /* Read interrupt register pending from Channel A */
+        while ((st = rdscc(cbase, cbase + CHANA + CTL, R3)) != 0)
+        {
+               /* Read interrupt vector from R2, channel B */
+#ifdef PT_DEBUG
+               printk("PTd pt_interrupt(): R3 = %#3x", st);
+#endif                 
+/*             st = rdscc(lp->cardbase, cbase + CHANB + CTL, R2) & 0x0e;*/
+#ifdef PT_DEBUG
+               printk(" R2 = %#3x.\n", st);
+#endif 
+                       if (st & CHARxIP) {
+                           /* Channel A Rx */
+                   lp = (struct pt_local*)pt0a.priv;
+                   pt_rxisr(&pt0a);
+               } else if (st & CHATxIP) {
+                   /* Channel A Tx */
+                   lp = (struct pt_local*)pt0a.priv;
+                   pt_txisr(lp);
+               } else if (st & CHAEXT) {
+                       /* Channel A External Status */
+                       lp = (struct pt_local*)pt0a.priv;
+                       pt_exisr(lp);
+               } else if (st & CHBRxIP) {
+                       /* Channel B Rx */
+                   lp= (struct pt_local*)pt0b.priv;
+                   pt_rxisr(&pt0b);
+               } else if (st & CHBTxIP) {
+               /* Channel B Tx */
+                   lp = (struct pt_local*)pt0b.priv;
+                   pt_txisr(lp);
+                       } else if (st & CHBEXT) {
+                       /* Channel B External Status */
+                       lp = (struct pt_local*)pt0b.priv;
+                       pt_exisr(lp);
+               }
+            /* Reset highest interrupt under service */
+            save_flags(flags);
+            cli();
+            wrtscc(lp->cardbase, lp->base + CTL, R0, RES_H_IUS);
+            restore_flags(flags);
+        }  /* end of SCC ints */
+        
+        if (!(intreg & PT_TMR1_MSK))
+        {
+            /* Clear timer 1 */
+            inb_p(cbase + TMR1CLR);
+
+            pt_tmrisr( (struct pt_local*)pt0a.priv);
+        }
+
+        if (!(intreg & PT_TMR2_MSK))
+        {
+            /* Clear timer 2 */
+            inb_p(cbase + TMR2CLR);
+
+            pt_tmrisr( (struct pt_local*)pt0b.priv);
+        }
+
+        /* Get the next PT interrupt vector */
+        intreg = inb_p(cbase + INT_REG);
+    } /* while (intreg) */
+} /* pt_interrupt() */
+
+
+static void pt_exisr(struct pt_local *lp)
+{
+    unsigned long flags;
+    int cmd = lp->base + CTL;
+    unsigned char st;
+    char c;
+    int length;
+    
+    save_flags(flags);
+    cli();
+    
+    /* Get external status */
+    st = rdscc(lp->cardbase, cmd, R0);
+
+#ifdef PT_DEBUG
+       printk("PTd exisr(): R0 = %#3x tstate = %d (%d).\n", st, lp->tstate, lp->base & CHANA);
+#endif 
+    /* Reset external status latch */
+    wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT);
+    
+    if ((lp->rstate >= ACTIVE) && (st & BRK_ABRT) && lp->dmachan)
+    {
+       setup_rx_dma(lp);
+       lp->rstate = ACTIVE;
+    }
+
+    switch (lp->tstate)
+    {
+    case ACTIVE:               /* Unexpected underrun */
+#ifdef PT_DEBUG
+       printk("PTd exisr(): unexpected underrun detected.\n");
+#endif     
+        free_p(lp->sndbuf);
+        lp->sndbuf = NULL;
+        if (!lp->dmachan)
+        {
+               wrtscc(lp->cardbase, cmd, R0, SEND_ABORT);
+               lp->stats.tx_errors++;
+               lp->stats.tx_fifo_errors++;
+           }
+        lp->tstate = FLAGOUT;
+        tdelay(lp, lp->squeldelay);
+        restore_flags(flags);
+        return;
+    case UNDERRUN:             
+        lp->tstate = CRCOUT;
+        restore_flags(flags);
+        return;
+    case FLAGOUT:
+        /* squeldelay has timed out */
+        /* Find a frame for transmission */
+        if ((lp->sndbuf = skb_dequeue(&lp->sndq)) == NULL)
+        {
+            /* Nothing to send - return to Rx mode */
+            pt_rts(lp, OFF);
+            lp->tstate = IDLE;
+            restore_flags(flags);
+            return;
+        }
+        if (!lp->dmachan)
+        {
+               lp->txptr = lp->sndbuf->data;
+           lp->txptr++;                /* Ignore KISS control byte */
+               lp->txcnt = (int) lp->sndbuf->len - 1;
+           }
+        /* Fall through if we have a packet */
+    
+    case ST_TXDELAY:
+       if (lp->dmachan)
+       {
+               /* Disable DMA chan */
+               disable_dma(lp->dmachan);
+               
+               /* Set up for TX dma */
+               wrtscc(lp->cardbase, cmd, R1, WT_FN_RDYFN | EXT_INT_ENAB);
+               
+               length = lp->sndbuf->len - 1;
+               memcpy(lp->txdmabuf, &lp->sndbuf->data[1], length);
+               
+               /* Setup DMA controller for Tx */
+               setup_tx_dma(lp, length);
+               
+               enable_dma(lp->dmachan);
+               
+               /* Reset CRC, Txint pending */
+               wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC | RES_Tx_P);
+               
+               /* Allow underrun only */
+               wrtscc(lp->cardbase, cmd, R15, TxUIE);
+               
+               /* Enable TX DMA */
+               wrtscc(lp->cardbase, cmd, R1, WT_RDY_ENAB | WT_FN_RDYFN | EXT_INT_ENAB);
+               
+               /* Send CRC on underrun */
+               wrtscc(lp->cardbase, cmd, R0, RES_EOM_L);
+               
+               lp->tstate = ACTIVE;
+               break;
+       } 
+        /* Get first char to send */
+        lp->txcnt--;
+        c = *lp->txptr++;
+        /* Reset CRC for next frame */
+        wrtscc(lp->cardbase, cmd, R0, RES_Tx_CRC);
+        
+        /* send abort on underrun */
+        if (lp->nrzi)  
+        {
+            wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZI | ABUNDER);
+        } else {
+            wrtscc(lp->cardbase, cmd, R10, CRCPS | NRZ | ABUNDER);
+        }
+        /* send first char */
+        wrtscc(lp->cardbase, cmd, R8, c);
+        
+        /* Reset end of message latch */
+        wrtscc(lp->cardbase, cmd, R0, RES_EOM_L);
+        
+        /* stuff an extra one in */
+/*        while ((rdscc(lp->cardbase, cmd, R0) & Tx_BUF_EMP) && lp->txcnt)
+        {
+            lp->txcnt--;
+            c = *lp->txptr++;
+            wrtscc(lp->cardbase, cmd, R8, c);
+        }*/
+        
+        /* select Tx interrupts to enable */
+        /* Allow underrun int only */
+        wrtscc(lp->cardbase, cmd, R15, TxUIE);
+        
+        /* Reset external interrupts */
+        wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT);
+        
+        /* Tx and Rx ints enabled */
+        wrtscc(lp->cardbase, cmd, R1, TxINT_ENAB | EXT_INT_ENAB);
+        
+        lp->tstate = ACTIVE;
+        restore_flags(flags);
+        return;
+        
+        /* slotime has timed out */
+    case DEFER:
+        /* Check DCD - debounce it
+         * see Intel Micrommunications Handbook, p2-308
+         */
+        wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT);
+        wrtscc(lp->cardbase, cmd, R0, RES_EXT_INT);
+        if ((rdscc(lp->cardbase, cmd, R0) & DCD) != 0)
+        {
+            lp->tstate = DEFER;
+            tdelay(lp, 100);
+            /* DEFER until DCD transistion or timeout */
+            wrtscc(lp->cardbase, cmd, R15, DCDIE);
+            restore_flags(flags);
+            return;
+        }
+        if (random() > lp->persist)
+        {
+            lp->tstate = DEFER;
+            tdelay(lp, lp->slotime);
+            restore_flags(flags);
+            return;
+        }
+        if (lp->dmachan)
+               wrtscc(lp->cardbase, cmd, R5, TxCRC_ENAB | RTS | Tx8);
+        pt_rts(lp, ON);                        /* Tx on */
+        lp->tstate = ST_TXDELAY;
+        tdelay(lp, lp->txdelay);
+        restore_flags(flags);
+        return;
+       /* Only for int driven parts */
+       if (lp->dmachan)
+       {
+               restore_flags(flags);
+               return;
+       }
+       
+    } /* end switch */
+    /*
+     * Rx mode only
+     * This triggers when hunt mode is entered, & since an ABORT
+     * automatically enters hunt mode, we use that to clean up
+     * any waiting garbage
+     */
+    if ((lp->rstate == ACTIVE) && (st & BRK_ABRT) )
+    {
+#ifdef PT_DEBUG
+       printk("PTd exisr(): abort detected.\n");
+#endif        
+               /* read and dump all of SCC Rx FIFO */
+        (void) rdscc(lp->cardbase, cmd, R8);
+        (void) rdscc(lp->cardbase, cmd, R8);
+        (void) rdscc(lp->cardbase, cmd, R8);      
+        
+        lp->rcp = lp->rcvbuf->data;
+        lp->rcvbuf->cnt = 0;
+        
+               /* Re-sync the SCC */
+               wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8);                     
+
+    }
+    
+    /* Check for DCD transistions */
+    if ( (st & DCD) != (lp->saved_RR0 & DCD))
+    {
+#ifdef PT_DEBUG    
+        printk("PTd: pt_exisr(): DCD is now %s.\n", (st & DCD)? "ON" : "OFF" );
+#endif
+               if (st & DCD)
+               {
+                       /* Check that we don't already have some data */
+                       if (lp->rcvbuf->cnt > 0)
+                       {
+#ifdef PT_DEBUG
+                               printk("PTd pt_exisr() dumping %u bytes from buffer.\n", lp->rcvbuf->cnt);
+#endif                                 
+                               /* wind back buffers */
+                               lp->rcp = lp->rcvbuf->data;
+                               lp->rcvbuf->cnt = 0;
+                       }
+               } else {  /* DCD off */
+                       
+                       /* read and dump al SCC FIFO */
+                       (void)rdscc(lp->cardbase, cmd, R8);
+                       (void)rdscc(lp->cardbase, cmd, R8);
+                       (void)rdscc(lp->cardbase, cmd, R8);
+
+                       /* wind back buffers */
+                       lp->rcp = lp->rcvbuf->data;
+                       lp->rcvbuf->cnt = 0;
+                       
+                       /* Re-sync the SCC */
+                       wrtscc(lp->cardbase, cmd, R3, RxENABLE | ENT_HM | AUTO_ENAB | Rx8);                     
+               }               
+                       
+    }
+    /* Update the saved version of register RR) */
+    lp->saved_RR0 = st &~ ZCOUNT;
+    restore_flags(flags);
+
+} /* pt_exisr() */
+
+/* This function is used to send the KISS params back to the kernel itself,
+ * just like the TNCs do (I think)
+ * It's a (bit of a) kludge
+ */
+static void send_kiss(struct device *dev, unsigned char arg, unsigned char val)
+{
+       struct sk_buff *skb;
+       unsigned char *cfix;
+/*     struct pt_local *lp = (struct pt_local*)dev->priv;*/
+       
+       
+       skb = dev_alloc_skb(2);
+       if (skb == NULL)
+       {
+               printk("PT: send_kiss(): Memory squeeze, dropping KISS reply.\n");
+               return;
+       }
+       skb->dev = dev;
+       cfix = skb_put(skb, 2);
+       cfix[0]=arg;
+       cfix[1]=val;
+       skb->protocol=htons(ETH_P_AX25);
+       skb->mac.raw=skb->data;
+       IS_SKB(skb);
+       netif_rx(skb);
+}
+       
diff --git a/drivers/net/pt.h b/drivers/net/pt.h
new file mode 100644 (file)
index 0000000..d2cc106
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * pt.h: Linux device driver for the Gracilis PackeTwin
+ * Copyright (C) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.)
+ *
+ * Please read the notice appearing at the top of the file pt.c
+ */
+#define DMA_BUFF_SIZE 2200
+
+/* Network statistics, with the same names as 'struct enet_statistics'. */
+#define netstats enet_statistics
+
+#define ON 1
+#define OFF 0
+
+
+/* Register offset info, specific to the PT
+ * E.g., to read the data port on channel A, use
+ *  inportb(pichan[dev].base + CHANA + DATA)
+ */
+#define CHANB   0   /* Base of channel B regs */
+#define CHANA   2   /* Base of channel A regs */
+
+/* 8530 ports on each channel */
+#define CTL 0
+#define DATA    1
+
+#define DMAEN   0x8 /* Offset off DMA Enable register */
+
+/* Timer chip offsets */
+#define TMR0    0x4 /* Offset of timer 0 register */
+#define TMR1    0x5 /* Offset of timer 1 register */
+#define TMR2    0x6 /* Offset of timer 2 register */
+#define TMRCMD  0x7 /* Offset of timer command register */
+#define INT_REG        0x8
+#define TMR1CLR 0x9
+#define TMR2CLR 0xa
+
+/* Interrupt register equates */
+#define PT_SCC_MSK     0x1
+#define PT_TMR1_MSK    0x2
+#define PT_TMR2_MSK    0x4
+
+/* Serial/interrupt register equates */
+#define PT_DTRA_ON     0x1
+#define PT_DTRB_ON     0x2
+#define PT_EXTCLKA     0x4
+#define PT_EXTCLKB     0x8
+#define PT_LOOPA_ON    0x10
+#define PT_LOOPB_ON    0x20
+#define PT_EI          0x80
+
+/* Timer chip equates */
+#define SC0 0x00 /* Select counter 0 */
+#define SC1 0x40 /* Select counter 1 */
+#define SC2 0x80 /* Select counter 2 */
+#define CLATCH  0x00 /* Counter latching operation */
+#define MSB 0x20 /* Read/load MSB only */
+#define LSB 0x10 /* Read/load LSB only */
+#define LSB_MSB 0x30 /* Read/load LSB, then MSB */
+#define MODE0   0x00 /* Interrupt on terminal count */
+#define MODE1   0x02 /* Programmable one shot */
+#define MODE2   0x04 /* Rate generator */
+#define MODE3   0x06 /* Square wave rate generator */
+#define MODE4   0x08 /* Software triggered strobe */
+#define MODE5   0x0a /* Hardware triggered strobe */
+#define BCD 0x01 /* BCD counter */
+
+/* DMA controller registers */
+#define DMA_STAT    8   /* DMA controller status register */
+#define DMA_CMD     8   /* DMA controller command register */
+#define DMA_MASK        10  /* DMA controller mask register */
+#define DMA_MODE        11  /* DMA controller mode register */
+#define DMA_RESETFF 12  /* DMA controller first/last flip flop  */
+/* DMA data */
+#define DMA_DISABLE (0x04)  /* Disable channel n */
+#define DMA_ENABLE  (0x00)  /* Enable channel n */
+/* Single transfers, incr. address, auto init, writes, ch. n */
+#define DMA_RX_MODE (0x54)
+/* Single transfers, incr. address, no auto init, reads, ch. n */
+#define DMA_TX_MODE (0x48)
+
+/* Write registers */
+#define DMA_CFG                0x08
+#define SERIAL_CFG     0x09
+#define INT_CFG                0x09    /* shares with serial config */
+#define DMA_CLR_FF     0x0a
+
+#define SINGLE 3686400
+#define DOUBLE 7372800
+#define XTAL   ((long) 6144000L)
+
+#define SIOCGPIPARAM           0x5000  /* get PI parameters */
+#define SIOCSPIPARAM           0x5001  /* set */
+#define SIOCGPIBAUD            0x5002  /* get only baud rate */
+#define SIOCSPIBAUD            0x5003  
+#define SIOCGPIDMA             0x5004  /* get only DMA */
+#define SIOCSPIDMA             0x5005  
+#define SIOCGPIIRQ             0x5006  /* get only IRQ */
+#define SIOCSPIIRQ             0x5007  
+
+struct pt_req  {
+    int cmd;
+    int speed;
+    int clockmode;
+    int txdelay;
+    unsigned char persist;
+    int slotime; 
+    int squeldelay;
+    int dmachan;    
+    int irq;    
+};
+
+/* SCC Interrupt vectors, if we have set 'status low' */
+#define CHBTxIV                0x00
+#define CHBEXTIV       0x02
+#define CHBRxIV                0x04
+#define CHBSRCIV       0x06
+#define CHATxIV                0x08
+#define CHAEXTIV       0x0a
+#define CHARxIV                0x0c
+#define CHASRCIV       0x0e
+
+
+#ifdef __KERNEL__
+
+/* Information that needs to be kept for each channel. */
+struct pt_local {
+    struct netstats stats; /* %%%dp*/
+    long open_time;             /* Useless example local info. */
+    unsigned long xtal; 
+
+    struct mbuf *rcvbuf;/* Buffer for current rx packet */
+    struct mbuf *rxdmabuf1; /* DMA rx buffer */
+    struct mbuf *rxdmabuf2; /* DMA rx buffer */
+
+    int bufsiz;         /* Size of rcvbuf */
+    char *rcp;          /* Pointer into rcvbuf */
+
+    struct sk_buff_head sndq;  /* Packets awaiting transmission */
+    int sndcnt;         /* Number of packets on sndq */
+    struct sk_buff *sndbuf;/* Current buffer being transmitted */
+    char *txdmabuf;     /* Transmit DMA buffer */
+       char *txptr;            /* Used by B port tx */
+       int txcnt;                      
+    char tstate;        /* Transmitter state */
+#define IDLE    0       /* Transmitter off, no data pending */
+#define ACTIVE  1       /* Transmitter on, sending data */
+#define UNDERRUN 2      /* Transmitter on, flushing CRC */
+#define FLAGOUT 3       /* CRC sent - attempt to start next frame */
+#define DEFER 4         /* Receive Active - DEFER Transmit */
+#define ST_TXDELAY 5    /* Sending leading flags */
+#define CRCOUT 6
+    char rstate;        /* Set when !DCD goes to 0 (TRUE) */
+/* Normal state is ACTIVE if Receive enabled */
+#define RXERROR 2       /* Error -- Aborting current Frame */
+#define RXABORT 3       /* ABORT sequence detected */
+#define TOOBIG 4        /* too large a frame to store */
+       
+    int dev;            /* Device number */
+    int base;       /* Base of I/O registers */
+    int cardbase;     /* Base address of card */
+    int stata;        /* address of Channel A status regs */
+    int statb;        /* address of Channel B status regs */
+    int speed;        /* Line speed, bps */
+    int clockmode;    /* tapr 9600 modem clocking option */
+    int txdelay;      /* Transmit Delay 10 ms/cnt */
+    unsigned char persist;       /* Persistence (0-255) as a % */
+    int slotime;      /* Delay to wait on persistence hit */
+    int squeldelay;   /* Delay after XMTR OFF for squelch tail */
+    struct iface *iface;    /* Associated interface */
+    int dmachan;           /* DMA channel for this port */
+    char saved_RR0;    /* The saved version of RR) that we compare with */
+    int nrzi;                  /* Do we use NRZI (or NRZ) */
+};
+
+#endif
index bb61dcd6ad54efaefa573fb9fcc8e302eae72556..2b18627a7a3ba1a38813f25b4a471bcbaecf8629 100644 (file)
@@ -4,6 +4,7 @@
 mainmenu_option next_comment
 comment 'Filesystems'
 
+bool    'Quota support' CONFIG_QUOTA
 tristate 'Standard (minix) fs support' CONFIG_MINIX_FS
 tristate 'Extended fs support' CONFIG_EXT_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
@@ -22,4 +23,6 @@ fi
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-tristate 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS
+if [ "$CONFIG_INET" = "y" ]; then
+  tristate 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS
+fi
index d64c65fa3d2aff7e08732bda534eb8c03a5028fa..a8dd06b6667c9eae68ca3905867da04b823ce704 100644 (file)
@@ -13,11 +13,17 @@ O_TARGET := fs.o
 O_OBJS    = open.o read_write.o inode.o devices.o file_table.o buffer.o \
                super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
                ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-               dcache.o dquot.o $(BINFMTS) 
+               dcache.o $(BINFMTS) 
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv smbfs
 
+ifeq ($(CONFIG_QUOTA),y)
+O_OBJS += dquot.o
+else
+O_OBJS += noquot.o
+endif
+
 ifeq ($(CONFIG_MINIX_FS),y)
 SUB_DIRS += minix
 else
index 8847a7dd938ae62760d65024fa70e45cd77ea772..9730df4c7ba34e00119fa65741032fc28887b05b 100644 (file)
@@ -950,7 +950,7 @@ static void get_more_buffer_heads(void)
        if (unused_list)
                return;
 
-       if (!(bh = (struct buffer_head*) get_free_page(GFP_BUFFER)))
+       if (!(bh = (struct buffer_head*) get_free_page(GFP_KERNEL)))
                return;
 
        for (nr_buffer_heads+=i=PAGE_SIZE/sizeof*bh ; i>0; i--) {
@@ -1014,140 +1014,60 @@ no_grow:
 
 static void read_buffers(struct buffer_head * bh[], int nrbuf)
 {
-       int i;
-       int bhnum = 0;
-       struct buffer_head * bhr[MAX_BUF_PER_PAGE];
-
-       for (i = 0 ; i < nrbuf ; i++) {
-               if (bh[i] && !buffer_uptodate(bh[i]))
-                       bhr[bhnum++] = bh[i];
-       }
-       if (bhnum)
-               ll_rw_block(READ, bhnum, bhr);
-       for (i = nrbuf ; --i >= 0 ; ) {
-               if (bh[i]) {
-                       wait_on_buffer(bh[i]);
-               }
-       }
+       ll_rw_block(READ, nrbuf, bh);
+       bh += nrbuf;
+       do {
+               nrbuf--;
+               bh--;
+               wait_on_buffer(*bh);
+       } while (nrbuf > 0);
 }
 
-static int try_to_load_aligned(unsigned long address,
-       kdev_t dev, int b[], int size)
+int bread_page(unsigned long address, kdev_t dev, int b[], int size)
 {
-       struct buffer_head * bh, * tmp, * arr[MAX_BUF_PER_PAGE];
-       unsigned long offset;
-        int isize = BUFSIZE_INDEX(size);
-       int * p;
-       int block;
+       struct buffer_head *bh, *next, *arr[MAX_BUF_PER_PAGE];
+       int block, nr;
 
        bh = create_buffers(address, size);
        if (!bh)
-               return 0;
-       /* do any of the buffers already exist? punt if so.. */
-       p = b;
-       for (offset = 0 ; offset < PAGE_SIZE ; offset += size) {
-               block = *(p++);
-               if (!block)
-                       goto not_aligned;
-               if (find_buffer(dev, block, size))
-                       goto not_aligned;
-       }
-       tmp = bh;
-       p = b;
-       block = 0;
-       while (1) {
-               arr[block++] = bh;
-               bh->b_count = 1;
-               bh->b_flushtime = 0;
-               clear_bit(BH_Dirty, &bh->b_state);
-               clear_bit(BH_Uptodate, &bh->b_state);
-               clear_bit(BH_Req, &bh->b_state);
-               bh->b_dev = dev;
-               bh->b_blocknr = *(p++);
-               bh->b_list = BUF_CLEAN;
-               nr_buffers++;
-               nr_buffers_size[isize]++;
-               insert_into_queues(bh);
-               if (bh->b_this_page)
-                       bh = bh->b_this_page;
-               else
-                       break;
-       }
-       buffermem += PAGE_SIZE;
-       bh->b_this_page = tmp;
-       mem_map[MAP_NR(address)].count++;
-       buffer_pages[MAP_NR(address)] = bh;
-       read_buffers(arr,block);
-       while (block-- > 0)
-               brelse(arr[block]);
+               return -ENOMEM;
+       nr = 0;
+       next = bh;
+       do {
+               struct buffer_head * tmp;
+               block = *(b++);
+               if (!block) {
+                       memset(next->b_data, 0, size);
+                       continue;
+               }
+               tmp = get_hash_table(dev, block, size);
+               if (tmp) {
+                       memcpy(next->b_data, tmp->b_data, size);
+                       brelse(tmp);
+                       continue;
+               }
+               arr[nr++] = next;
+               next->b_dev = dev;
+               next->b_blocknr = block;
+               next->b_count = 1;
+               next->b_flushtime = 0;
+               clear_bit(BH_Dirty, &next->b_state);
+               clear_bit(BH_Uptodate, &next->b_state);
+               clear_bit(BH_Req, &next->b_state);
+               next->b_list = BUF_CLEAN;
+       } while ((next = next->b_this_page) != NULL);
+
+       if (nr)
+               read_buffers(arr,nr);
        ++current->maj_flt;
-       return 1;
-not_aligned:
-       while ((tmp = bh) != NULL) {
+
+       while ((next = bh) != NULL) {
                bh = bh->b_this_page;
-               put_unused_buffer_head(tmp);
+               put_unused_buffer_head(next);
        }
        return 0;
 }
 
-/*
- * Try-to-share-buffers tries to minimize memory use by trying to keep
- * both code pages and the buffer area in the same page. This is done by
- * trying to load them into memory the way we want them.
- *
- * This doesn't guarantee that the memory is shared, but should under most
- * circumstances work very well indeed (ie >90% sharing of code pages on
- * demand-loadable executables).
- */
-static inline int try_to_share_buffers(unsigned long address,
-       kdev_t dev, int *b, int size)
-{
-       struct buffer_head * bh;
-       int block;
-
-       block = b[0];
-       if (!block)
-               return 0;
-       bh = get_hash_table(dev, block, size);
-       if (!bh)
-               return try_to_load_aligned(address, dev, b, size);
-       brelse(bh);
-       return 0;
-}
-
-/*
- * bread_page reads four buffers into memory at the desired address. It's
- * a function of its own, as there is some speed to be got by reading them
- * all at the same time, not waiting for one to be read, and then another
- * etc. This also allows us to optimize memory usage by sharing code pages
- * and filesystem buffers..
- */
-void bread_page(unsigned long address, kdev_t dev, int b[], int size)
-{
-       struct buffer_head * bh[MAX_BUF_PER_PAGE];
-       unsigned long where;
-       int i, j;
-
-       if (try_to_share_buffers(address, dev, b, size))
-               return;
-       ++current->maj_flt;
-       for (i=0, j=0; j<PAGE_SIZE ; i++, j+= size) {
-               bh[i] = NULL;
-               if (b[i])
-                       bh[i] = getblk(dev, b[i], size);
-       }
-       read_buffers(bh,i);
-       where = address;
-       for (i=0, j=0; j<PAGE_SIZE ; i++, j += size, where += size) {
-               if (bh[i]) {
-                       if (buffer_uptodate(bh[i]))
-                               memcpy((void *) where, bh[i]->b_data, size);
-                       brelse(bh[i]);
-               } else
-                       memset((void *) where, 0, size);
-       }
-}
-
 #if 0
 /*
  * bwrite_page writes a page out to the buffer cache and/or the physical device.
@@ -1869,7 +1789,7 @@ int bdflush(void * unused) {
        in a few more things so "top" and /proc/2/{exe,root,cwd}
        display semi-sane things. Not real crucial though...  */
 
-       sprintf(current->comm, "bdflush - kernel");
+       sprintf(current->comm, "kernel bdflush");
 
        for (;;) {
 #ifdef DEBUG
index 30802aec618ba49cfe8a19efb1a11cdda3c4eff9..5daecf04ee585dff4d81c524a0d28932c93d9658 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -120,6 +121,8 @@ struct file * get_empty_filp(void)
        return NULL;
 }
 
+#ifdef CONFIG_QUOTA
+
 void add_dquot_ref(dev_t dev, short type)
 {
        struct file *filp;
@@ -149,3 +152,5 @@ void reset_dquot_ptrs(dev_t dev, short type)
                }
        }
 }
+
+#endif
index f6c00b11550ed5fa06e80a134aa18577e65e9e69..59edc8c368d6eb803bf71c3ab586182175dc05ed 100644 (file)
@@ -430,28 +430,38 @@ repeat:
        return;
 }
 
+static inline unsigned long value(struct inode * inode)
+{
+       if (inode->i_lock)  
+               return 1000;
+       if (inode->i_dirt)
+               return 1000;
+       return inode->i_nrpages;
+}
+
 struct inode * get_empty_inode(void)
 {
        static int ino = 0;
        struct inode * inode, * best;
+       unsigned long badness = ~0UL;
        int i;
 
-       if (nr_inodes < NR_INODE && nr_free_inodes < (nr_inodes >> 2))
+       if (nr_inodes < NR_INODE && nr_free_inodes < (nr_inodes >> 1))
                grow_inodes();
 repeat:
        inode = first_inode;
        best = NULL;
        for (i = 0; i<nr_inodes; inode = inode->i_next, i++) {
                if (!inode->i_count) {
-                       if (!best)
-                               best = inode;
-                       if (!inode->i_dirt && !inode->i_lock) {
+                       unsigned long i = value(inode);
+                       if (i < badness) {
                                best = inode;
-                               break;
+                               if ((badness = i) == 0)
+                                       break;
                        }
                }
        }
-       if (!best || best->i_dirt || best->i_lock)
+       if (badness > 20)
                if (nr_inodes < NR_INODE) {
                        grow_inodes();
                        goto repeat;
index ab4a9667d96eeb52b879c96b10fe18dc2d3c48b9..809c6357611733f4d1c7aef930bb2a688dfa57f3 100644 (file)
                          current->state = TASK_INTERRUPTIBLE; \
                          schedule(); \
                        }
-#define dprintk                if (0) printk
+                       
+#ifdef DEBUG_NFS                       
+#define dprintk(x)             printk(x)
+#else
+#define        dprintk(x)
+#endif
 
 static inline void
 rpc_insque(struct rpc_sock *rsock, struct rpc_wait *slot)
@@ -52,9 +57,9 @@ rpc_insque(struct rpc_sock *rsock, struct rpc_wait *slot)
        rsock->tail = slot;
        slot->prev = tmp;
        slot->next = NULL;
-       dprintk("RPC: inserted %08lx into queue.\n", (long)slot);
-       dprintk("RPC: head = %08lx, tail = %08lx.\n",
-                       (long) rsock->head, (long) rsock->tail);
+       dprintk(("RPC: inserted %08lx into queue.\n", (long)slot));
+       dprintk(("RPC: head = %08lx, tail = %08lx.\n",
+                       (long) rsock->head, (long) rsock->tail));
 }
 
 static inline void
@@ -71,9 +76,9 @@ rpc_remque(struct rpc_sock *rsock, struct rpc_wait *slot)
                next->prev = prev;
        else
                rsock->tail = prev;
-       dprintk("RPC: removed %08lx from queue.\n", (long)slot);
-       dprintk("RPC: head = %08lx, tail = %08lx.\n",
-                       (long) rsock->head, (long) rsock->tail);
+       dprintk(("RPC: removed %08lx from queue.\n", (long)slot));
+       dprintk(("RPC: head = %08lx, tail = %08lx.\n",
+                       (long) rsock->head, (long) rsock->tail));
 }
 
 static inline int
@@ -83,12 +88,12 @@ rpc_sendmsg(struct rpc_sock *rsock, struct msghdr *msg, int len)
        unsigned long   oldfs;
        int             result;
 
-       dprintk("RPC: sending %d bytes (buf %p)\n", len, msg->msg_iov[0].iov_base);
+       dprintk(("RPC: sending %d bytes (buf %p)\n", len, msg->msg_iov[0].iov_base));
        oldfs = get_fs();
        set_fs(get_ds());
        result = sock->ops->sendmsg(sock, msg, len, 0, 0);
        set_fs(oldfs);
-       dprintk("RPC: result = %d\n", result);
+       dprintk(("RPC: result = %d\n", result));
 
        return result;
 }
@@ -104,7 +109,7 @@ rpc_select(struct rpc_sock *rsock)
        struct file     *file = rsock->file;
        select_table    wait_table;
 
-       dprintk("RPC: selecting on socket...\n");
+       dprintk(("RPC: selecting on socket...\n"));
        wait_table.nr = 0;
        wait_table.entry = &entry;
        current->state = TASK_INTERRUPTIBLE;
@@ -120,7 +125,7 @@ rpc_select(struct rpc_sock *rsock)
        } else if (wait_table.nr)
                remove_wait_queue(entry.wait_address, &entry.wait);
        current->state = TASK_RUNNING;
-       dprintk("RPC: ...Okay, there appears to be some data.\n");
+       dprintk(("RPC: ...Okay, there appears to be some data.\n"));
        return 0;
 }
 
@@ -133,16 +138,16 @@ rpc_recvmsg(struct rpc_sock *rsock, struct msghdr *msg, int len,int flags)
        unsigned long   oldfs;
        int             result;
 
-       dprintk("RPC: receiving %d bytes max (buf %p)\n", len, msg->msg_iov[0].iov_base);
+       dprintk(("RPC: receiving %d bytes max (buf %p)\n", len, msg->msg_iov[0].iov_base));
        oldfs = get_fs();
        set_fs(get_ds());
        result = sock->ops->recvmsg(sock, msg, len, 1, flags, &alen);
        set_fs(oldfs);
-       dprintk("RPC: result = %d\n", result);
+       dprintk(("RPC: result = %d\n", result));
 
 #if 0
        if (alen != salen || memcmp(&sa, sap, alen)) {
-               dprintk("RPC: reply address mismatch... rejected.\n");
+               dprintk(("RPC: reply address mismatch... rejected.\n"));
                result = -EAGAIN;
        }
 #endif
@@ -173,11 +178,11 @@ rpc_call_one(struct rpc_sock *rsock, struct rpc_wait *slot,
        iov.iov_base    =       (void *)sndbuf;
        iov.iov_len     =       slen;
 
-       dprintk("RPC: placing one call, rsock = %08lx, slot = %08lx, "
+       dprintk(("RPC: placing one call, rsock = %08lx, slot = %08lx, "
                "sap = %08lx, salen = %d, "
                "sndbuf = %08lx, slen = %d, rcvbuf = %08lx, rlen = %d\n",
                (long) rsock, (long) slot, (long) sap, 
-               salen, (long) sndbuf, slen, (long) rcvbuf, rlen);
+               salen, (long) sndbuf, slen, (long) rcvbuf, rlen));
 
        result = rpc_sendmsg(rsock, &msg, slen);
        if (result < 0)
@@ -201,7 +206,7 @@ rpc_call_one(struct rpc_sock *rsock, struct rpc_wait *slot,
                /* wait for data to arrive */
                result = rpc_select(rsock);
                if (result < 0) {
-                       dprintk("RPC: select error = %d\n", result);
+                       dprintk(("RPC: select error = %d\n", result));
                        break;
                }
 
@@ -214,7 +219,7 @@ rpc_call_one(struct rpc_sock *rsock, struct rpc_wait *slot,
                        case EAGAIN: case ECONNREFUSED:
                                continue;
                        default:
-                               dprintk("rpc_call: recv error = %d\n", result);
+                               dprintk(("rpc_call: recv error = %d\n", result));
                        case ERESTARTSYS:
                                return result;
                        }
@@ -234,7 +239,7 @@ rpc_call_one(struct rpc_sock *rsock, struct rpc_wait *slot,
 
                if (!rovr || rovr->gotit) {
                        /* bad XID or duplicate reply, discard dgram */
-                       dprintk("RPC: bad XID or duplicate reply.\n");
+                       dprintk(("RPC: bad XID or duplicate reply.\n"));
                        iov.iov_base=(void *)&xid;
                        iov.iov_len=sizeof(xid);
                        rpc_recvmsg(rsock, &msg, sizeof(xid),0);
@@ -282,7 +287,7 @@ rpc_call(struct rpc_sock *rsock, struct sockaddr *sap, int addrlen,
        slot = NULL;
 
        do {
-               dprintk("RPC call TP1\n");
+               dprintk(("RPC call TP1\n"));
                current->timeout = jiffies + timeout;
                if (slot == NULL) {
                        while ((slot = rsock->free) == NULL) {
@@ -296,12 +301,12 @@ rpc_call(struct rpc_sock *rsock, struct sockaddr *sap, int addrlen,
                                        goto timedout;
                                }
                                if (rsock->shutdown) {
-                                       printk("RPC: aborting call due to shutdown.\n");
+                                       dprintk(("RPC: aborting call due to shutdown.\n"));
                                        current->timeout = 0;
                                        return -EIO;
                                }
                        }
-                       dprintk("RPC call TP2\n");
+                       dprintk(("RPC call TP2\n"));
                        slot->gotit = 0;
                        slot->xid = *(u32 *)sndbuf;
                        slot->buf = rcvbuf;
@@ -310,15 +315,15 @@ rpc_call(struct rpc_sock *rsock, struct sockaddr *sap, int addrlen,
                        rpc_insque(rsock, slot);
                }
 
-               dprintk("RPC call TP3\n");
+               dprintk(("RPC call TP3\n"));
                result = rpc_call_one(rsock, slot, sap, addrlen,
                                        sndbuf, slen, rcvbuf, rlen);
                if (result != -ETIMEDOUT)
                        break;
 
 timedout:
-               dprintk("RPC call TP4\n");
-               dprintk("RPC: rpc_call_one returned timeout.\n");
+               dprintk(("RPC call TP4\n"));
+               dprintk(("RPC: rpc_call_one returned timeout.\n"));
                if (strategy->exponential)
                        timeout <<= 1;
                else
@@ -329,10 +334,10 @@ timedout:
                        break;
        } while (1);
 
-       dprintk("RPC call TP5\n");
+       dprintk(("RPC call TP5\n"));
        current->timeout = 0;
        if (slot != NULL) {
-               dprintk("RPC call TP6\n");
+               dprintk(("RPC call TP6\n"));
                rpc_remque(rsock, slot);
                slot->next = rsock->free;
                rsock->free = slot;
@@ -356,7 +361,7 @@ rpc_makesock(struct file *file)
        struct rpc_wait *slot;
        int             i;
 
-       dprintk("RPC: make RPC socket...\n");
+       dprintk(("RPC: make RPC socket...\n"));
        if ((rsock = kmalloc(sizeof(struct rpc_sock), GFP_KERNEL)) == NULL)
                return NULL;
        memset(rsock, 0, sizeof(*rsock)); /* Nnnngh! */
@@ -377,7 +382,7 @@ rpc_makesock(struct file *file)
        rsock->shutdown = 0;
         */
 
-       dprintk("RPC: made socket %08lx", (long) rsock);
+       dprintk(("RPC: made socket %08lx", (long) rsock));
        return rsock;
 }
 
index 39875bc88e80485c354f005fbf4f88edaf11bcbc..11fc4490740daab85a39c69d238aefd6ba5c84d9 100644 (file)
@@ -92,7 +92,7 @@ nfs_rpc_call(struct nfs_server *server, int *start, int *end, int size)
                        }
                        if ((timeout.init_timeout <<= 1) >= maxtimeo)
                                timeout.init_timeout = maxtimeo;
-               } else if (result < 0) {
+               } else if (result < 0 && result != ERESTARTSYS) {
                        printk("NFS: notice message: result = %d.\n", result);
                }
        } while (result == -ETIMEDOUT && !(server->flags & NFS_MOUNT_SOFT));
diff --git a/fs/noquot.c b/fs/noquot.c
new file mode 100644 (file)
index 0000000..2e28a2e
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *     A Non implementation of disk quotas. Chainsawed from dquot.c by
+ *     Alan Cox <alan@lxorguk.ukuu.org.uk>. This saves us memory without
+ *     having zillions of #ifdefs (Or if it had been done right one
+ *     
+ *     QUOTA_OP(inode,func)
+ *
+ *     macro.)
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/mount.h>
+
+#include <asm/segment.h>
+
+#ifndef min
+#define min(a,b) ((a) < (b)) ? (a) : (b)
+#endif
+
+int sync_dquots(kdev_t dev, short type)
+{
+       return(0);
+}
+
+/*
+ * Trash the cache for a certain type on a device.
+ */
+
+void invalidate_dquots(kdev_t dev, short type)
+{
+}
+
+/*
+ * Initialize pointer in a inode to the right dquots.
+ */
+void dquot_initialize(struct inode *inode, short type)
+{
+}
+
+void dquot_drop(struct inode *inode)
+{
+}
+
+void dquot_init(void)
+{
+}
+
+/*
+ * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
+ */
+
+int quota_off(kdev_t dev, short type)
+{
+       return(0);
+}
+
+int quota_on(kdev_t dev, short type, char *path)
+{
+       return(-ENOPKG);
+}
+
+/*
+ * Ok this is the systemcall interface, this communicates with
+ * the userlevel programs. Currently this only supports diskquota
+ * calls. Maybe we need to add the process quotas etc in the future.
+ * But we probably better use rlimits for that.
+ */
+asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+       return(-ENOPKG);
+}
index 9d955f6b8c7af75e2e1a75f7c688fe2fd7e906fa..769df6d2c574f0c34b1403bc67a9e80875bd9888 100644 (file)
@@ -469,7 +469,7 @@ static int get_stat(int pid, char * buffer)
        else
                state = "RSDZTW"[tsk->state];
        vsize = eip = esp = 0;
-       if (tsk->mm) {
+       if (tsk->mm && tsk->mm != &init_mm) {
                struct vm_area_struct *vma = tsk->mm->mmap;
                while (vma) {
                        vsize += vma->vm_end - vma->vm_start;
@@ -628,7 +628,7 @@ static int get_statm(int pid, char * buffer)
 
        if (!p || (tsk = *p) == NULL)
                return 0;
-       if (tsk->mm) {
+       if (tsk->mm && tsk->mm != &init_mm) {
                struct vm_area_struct * vma = tsk->mm->mmap;
 
                while (vma) {
@@ -692,7 +692,7 @@ static int read_maps (int pid, struct file * file, char * buf, int count)
        if (!p || !*p)
                return -EINVAL;
 
-       if (!(*p)->mm || count == 0)
+       if (!(*p)->mm || (*p)->mm == &init_mm || count == 0)
                return 0;
 
        /* decode f_pos */
index 4364339c99ad2bb1e8e311fe96b22f7f601f9556..d4cbf29322748744544ed8185b82157adc1c7304 100644 (file)
@@ -27,11 +27,15 @@ extern __inline__ unsigned short int        __constant_ntohs(unsigned short int);
 extern __inline__ unsigned long int
 __ntohl(unsigned long int x)
 {
+#if defined(CONFIG_M486) && defined(__KERNEL__)
+       __asm__("bswap %0" : "=r" (x) : "0" (x));
+#else
        __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
                "rorl $16,%0\n\t"       /* swap words           */
                "xchgb %b0,%h0"         /* swap higher bytes    */
                :"=q" (x)
                : "0" (x));
+#endif 
        return x;
 }
 
index bd8a1f73c8adf1fc8e38db9af5180570b1067ba1..f70945d446deb09c5145f4496205327f0ebbf5ed 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef ASSEMBLY
 
 #include <asm/i82489.h>
+#include <asm/bitops.h>
 #include <linux/tasks.h>
 #include <linux/ptrace.h>
 
@@ -178,6 +179,8 @@ extern unsigned char *apic_reg;
 extern unsigned char *kernel_stacks[NR_CPUS];
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
+extern volatile unsigned long smp_invalidate_needed;
+extern volatile unsigned long smp_spins;
 extern void smp_invalidate(void);
 extern volatile unsigned long kernel_flag, kernel_counter;
 extern volatile unsigned char active_kernel_processor;
@@ -241,5 +244,6 @@ extern __inline int smp_processor_id(void)
  
 #define PROC_CHANGE_PENALTY    20              /* Schedule penalty */
 
+
 #endif
 #endif
index 7fc2bb9a59b896a51ee9a08779a49f8369c269c3..6d923f15b426e28a9bb3c507b9ad858a201d07b2 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995 by Ralf Baechle
  *
- * Some usefull macros for MIPS assembler code
+ * Some useful macros for MIPS assembler code
  *
  * Some of the routines below contain useless nops that will be optimized
  * away by gas in -O mode. These nops are however required to fill delay
index 88dd5d5e35ddb39ce09d2327ab38cfd30771dc0c..e93f2588473cc5e3741c50c75c73bb4f504a29c1 100644 (file)
@@ -574,7 +574,7 @@ extern inline void bforget(struct buffer_head *buf)
 }
 extern void set_blocksize(kdev_t dev, int size);
 extern struct buffer_head * bread(kdev_t dev, int block, int size);
-extern void bread_page(unsigned long addr,kdev_t dev,int b[],int size);
+extern int bread_page(unsigned long addr,kdev_t dev,int b[],int size);
 extern void bwrite_page(unsigned long addr,kdev_t dev,int b[],int size);
 extern struct buffer_head * breada(kdev_t dev,int block, int size, 
                                   unsigned int pos, unsigned int filesize);
index d8fba097054422af2d57f522e88edd612814e1b3..67a9f9beaa2c03fa55ffb7b4dd0cce0ab330985c 100644 (file)
@@ -1,12 +1,25 @@
+/*
+ *             NET_ALIAS network device aliasing definitions.
+ *
+ *
+ * Version:    @(#)net_alias.h 0.43   12/20/95
+ *
+ * Author:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *     
+ */
+
 #ifndef _NET_ALIAS_H
 #define _NET_ALIAS_H
 
 #include <linux/types.h>
 #include <linux/if.h>
 #include <linux/netdevice.h>
-#include <linux/inet.h>
-#include <linux/in.h>          /* for default IP behavior */
-
 
 /*
  * max. alias slot number allowed 
@@ -32,7 +45,7 @@ struct net_alias
   unsigned slot;               /* slot number */
   void *data;                  /* private data */
   struct device *main_dev;     /* pointer to main device */
-  struct net_alias_type *nat;  /* alias type bound */
+  struct net_alias_type *nat;  /* alias type object bound */
   struct net_alias *next;      /* next alias (hashed linked list) */
 };
 
@@ -61,15 +74,17 @@ struct net_alias_type
   int n_attach;                        /* number of aliases attached */
   char name[16];               /* af_name */
   __u32 (*get_addr32)          /* get __u32 addr 'representation'*/
-    (struct sockaddr*);        
-  int (*addr_chk)              /* address checking func: */
-    (struct device *, struct sockaddr *);
+    (struct net_alias_type *this, struct sockaddr*);   
+  int (*dev_addr_chk)          /* address checking func: */
+    (struct net_alias_type *this, struct device *, struct sockaddr *);
+  struct device * (*dev_select)        /* closest alias selector*/
+    (struct net_alias_type *this, struct device *, struct sockaddr *sa);
   int (*alias_init_1)          /* called after alias creation: */
-    (struct net_alias *alias, struct sockaddr *sa);
+    (struct net_alias_type *this,struct net_alias *alias, struct sockaddr *sa);
   int (*alias_done_1)          /* called before alias deletion */
-    (struct net_alias *alias);
+    (struct net_alias_type *this, struct net_alias *alias);
   int (*alias_print_1) 
-    (char *buf, int len, struct net_alias *alias);
+    (struct net_alias_type *this, struct net_alias *alias, char *buf, int len);
   struct net_alias_type *next; /* link */
 };
 
@@ -81,7 +96,7 @@ struct net_alias_type
 static __inline__ int
 net_alias_is(struct device *dev)
 {
-  return (dev->my_alias != 0);
+  return (dev->my_alias != NULL);
 }
 
 
@@ -92,14 +107,14 @@ net_alias_is(struct device *dev)
 static __inline__ int
 net_alias_has(struct device *dev)
 {
-  return (dev->alias_info != 0);
+  return (dev->alias_info != NULL);
 }
 
 
 extern void net_alias_init(void);
 
 extern struct device * net_alias_dev_get(char *dev_name, int aliasing_ok, int *err, struct sockaddr *sa, void *data);
-extern int net_alias_rehash(struct net_alias *alias, struct sockaddr *sa);
+extern int net_alias_dev_rehash(struct device *dev, struct sockaddr *sa);
 
 extern int net_alias_getinfo(char *buf, char **, off_t , int , int );
 extern int net_alias_types_getinfo(char *buf, char **, off_t , int , int );
@@ -107,8 +122,11 @@ extern int net_alias_types_getinfo(char *buf, char **, off_t , int , int );
 extern int register_net_alias_type(struct net_alias_type *nat, int type);
 extern int unregister_net_alias_type(struct net_alias_type *nat);
 
-extern struct device * net_alias_chk(struct device *dev, struct sockaddr *sa, int flags_1, int flags_0);
-extern struct device * net_alias_chk32(struct device *dev, int family, __u32 addr32, int flags_1, int flags_0);
+extern struct device * net_alias_dev_chk(struct device *main_dev, struct sockaddr *sa, int flags_on, int flags_off);
+extern struct device * net_alias_dev_chk32(struct device *main_dev, int family, __u32 addr32, int flags_on, int flags_off);
+
+extern struct device * net_alias_dev_rcv_sel(struct device *main_dev, struct sockaddr *sa_src, struct sockaddr *sa_dst);
+extern struct device * net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 dst);
 
 
 /*
@@ -151,26 +169,4 @@ net_alias_nextdev_set(struct device *dev, struct device *nextdev)
   return nextdev;
 }
 
-
-/*
- * addr_chk wrapper: check given generic address with (UP) aliases
- */
-
-static __inline__ struct device *
-net_alias_addr_chk(struct device *dev, struct sockaddr *sa)
-{
-  return net_alias_chk(dev, sa, IFF_UP, 0);
-}
-
-
-/*
- * addr_chk32 wrapper: check given u32 address with (UP) aliases
- */
-
-static __inline__ struct device *
-net_alias_addr_chk32(struct device *dev, int family, __u32 addr32)
-{
-  return net_alias_chk32(dev, family, addr32, IFF_UP, 0);
-}
-
 #endif  /* _NET_ALIAS_H */
index e2590a0a7a16e645d3e00684cec2510e585b4b7d..683a04276434ee4e50c9739eca17d6dc8e5394d6 100644 (file)
@@ -1,11 +1,21 @@
-#ifndef _IP_ALIAS_H
-#define _IP_ALIAS_H
-
-/* 
- * IP alias specific prototypes
+/*
+ *             IP_ALIAS (AF_INET) aliasing definitions.
+ *
+ *
+ * Version:    @(#)ip_alias.h  0.43   12/20/95
+ *
+ * Author:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *     
  */
 
-#include <linux/net_alias.h>
+#ifndef _IP_ALIAS_H
+#define _IP_ALIAS_H
 
 extern int ip_alias_init(void);
 extern int ip_alias_done(void);
index 23779c9c567a6a2c3d9583013378f3b4e123565b..ff4c43bcb4fe0cb0aab268bf5bbab81d836fe994 100644 (file)
@@ -174,7 +174,10 @@ struct sock
  */
  
        volatile unsigned short backoff;
-       volatile int            err;
+       volatile int            err, err_soft;  /* Soft holds errors that don't
+                                                  cause failure but are the cause
+                                                  of a persistent failure not just
+                                                  'timed out' */
        unsigned char           protocol;
        volatile unsigned char  state;
        volatile unsigned char  ack_backlog;
@@ -409,7 +412,7 @@ extern __inline__ int sock_error(struct sock *sk)
        int err=xchg(&sk->err,0);
        return -err;
 }
+
 /* 
  *     Declarations from timer.c 
  */
index 8f703c82920a46d10ba014ee30c449c3a154c1e7..59bfab2569fc51945f96458c87cfcf5e8dc10b7a 100644 (file)
@@ -488,9 +488,29 @@ static void parse_options(char *line)
        envp_init[envs+1] = NULL;
 }
 
+
 extern void setup_arch(char **, unsigned long *, unsigned long *);
 
-#ifdef __SMP__
+#ifndef __SMP__
+
+/*
+ *     Uniprocessor idle thread
+ */
+int cpu_idle(void *unused)
+{
+       for(;;)
+               idle();
+}
+
+#else
+
+/*
+ *     Multiprocessor idle thread is in arch/...
+ */
+extern int cpu_idle(void * unused);
+
 /*
  *     Activate a secondary processor.
  */
@@ -500,15 +520,10 @@ asmlinkage void start_secondary(void)
        trap_init();
        init_IRQ();
        smp_callin();
-       for(;;)
-               idle();
+       cpu_idle(NULL);
 }
 
-int smp_idle(void * unused)
-{
-       for (;;)
-               idle();
-}
+
 
 /*
  *     Called by CPU#0 to activate the rest.
@@ -525,7 +540,7 @@ static void smp_init(void)
 
        for(i=1;i<smp_num_cpus;i++)
        {
-               kernel_thread(smp_idle, NULL, CLONE_PID);
+               kernel_thread(cpu_idle, NULL, CLONE_PID);
                /*
                 *      Assume linear processor numbering
                 */
@@ -633,8 +648,7 @@ asmlinkage void start_kernel(void)
  *
  * Right now task[0] just does a infinite idle loop.
  */
-       for(;;)
-               idle();
+       cpu_idle(NULL);
 }
 
 static int printf(const char *fmt, ...)
index 7a3a8718edd68efeb1cdb6e2f452bbee1e8e6b83..72e5bfc827e10acdcb00694f34961fa101014be6 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/ext2_fs.h>
 #include <linux/random.h>
 
+extern unsigned char aux_device_present, kbd_read_mask;
+
 #ifdef __alpha__
 # include <asm/io.h>
 # include <asm/hwrpb.h>
@@ -62,6 +64,9 @@ extern void __remqu (void);
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/firewall.h>
+
+#include <linux/trdevice.h>
+
 #ifdef CONFIG_AX25
 #include <net/ax25.h>
 #endif
@@ -133,6 +138,11 @@ extern int (*rarp_ioctl_hook)(int,void*);
 
 extern void (* iABI_hook)(struct pt_regs * regs);
 
+#ifdef CONFIG_BINFMT_ELF
+#include <linux/elfcore.h>
+extern int dump_fpu(elf_fpregset_t *);
+#endif
+
 struct symbol_table symbol_table = {
 #include <linux/symtab_begin.h>
 #ifdef MODVERSIONS
@@ -558,6 +568,22 @@ struct symbol_table symbol_table = {
        X(proc_net_inode_operations),
        X(proc_net),
 #endif
+/* all busmice */
+       X(add_mouse_randomness),
+       X(fasync_helper),
+/* psaux mouse */
+       X(aux_device_present),
+       X(kbd_read_mask),
+
+#ifdef CONFIG_TR
+       X(tr_setup),
+       X(tr_type_trans),
+#endif
+
+#ifdef CONFIG_BINFMT_ELF
+       X(dump_fpu),
+#endif
+
        /********************************************************
         * Do not add anything below this line,
         * as the stacked modules depend on this!
index 4d9a662f22eac08d1a22e63470cbdb894230df6a..d229c523b6c6594c93f5e81f4e60731968e7989a 100644 (file)
@@ -78,7 +78,7 @@ int shrink_mmap(int priority, unsigned long limit)
        limit = MAP_NR(limit);
        if (clock >= limit)
                clock = 0;
-       priority = limit >> (2*priority);
+       priority = limit >> priority;
        page = mem_map + clock;
        while (priority-- > 0) {
                if (page->inode && page->count == 1) {
index 21463745215f2d234439fcbaf7d00d307386617c..ed77b2b3ebacd8cb58ad293e128c3f83118eef1d 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -46,7 +46,7 @@ swap_control_t swap_control = {
        20, 3, 1, 3,            /* Page aging */
        10, 2, 2, 0,            /* Buffer aging */
        32, 4,                  /* Aging cluster */
-       8192, 4096,             /* Pageout and bufferout weights */
+       8192, 8192,             /* Pageout and bufferout weights */
        -200,                   /* Buffer grace */
        1, 1,                   /* Buffs/pages to free */
        RCL_ROUND_ROBIN         /* Balancing policy */
index 19e3751e7ddbf469894778102afb24859b508e3f..15c1b6896dbf1f6d54f5677a920f53877ebd8481 100644 (file)
@@ -156,7 +156,7 @@ o   Minor bug fixes                                 [TESTED]
 
 o      Missing patches for device change in TCP        [TESTED]
 o      Device locking                                  [TESTED]
-o      Infinite slip devices                           [IN - BUG]
+o      Infinite slip devices                           [TESTED]
 o      New AF_UNIX sockets                             [TESTED]
 o      Sendmsg/recvmsg (for some stuff only)           [TESTED]
 o      Device unload loopholes fixed                   [TESTED]
@@ -209,7 +209,7 @@ o   Rewrote ICMP completely                         [TESTED]
 o      Moved most IP addresses to __u32                [TESTED]
 o      Cleaned up ICMP reporting                       [TESTED]
 o      Tidied remove_sock                              [TESTED]
-o      Added memory allocation type to ip_build_xmit   [IN]
+o      Added memory allocation type to ip_build_xmit   [TESTED]
 o      Cleaned up af_inet to use inet_error            [TESTED]
 o      Named firewall returns                          [TESTED]
 o      Added firewall output checks to ip_build_xmit   [TESTED]
@@ -218,7 +218,7 @@ o   Multicast router downs VIF's when their
 o      Reformatted ipv4/protocol.c, dropped frag field [TESTED]
 o      Fixed MSS for TCP                               [TESTED]
 o      Dropped sock_awaitconn                          [TESTED]
-o      Added ip_forward to ksyms for IPIP etc          [IN]
+o      Added ip_forward to ksyms for IPIP etc          [TESTED]
 o      Appletalk TIOCINQ/TIOCOUTQ bug fix              [TESTED]
 o      Rewrote the IFF_UP/IFF_DOWN handling code       [TESTED]
 
@@ -239,7 +239,7 @@ o   Kernel/user communication module (not used yet) [TESTED]
 -------->>>>> 1.3.31 <<<<<<-------
 
 o      IFF_ALLMULTI support for 3c501,3c509,8390 and
-       tulip(SMC etherpower) boards                    [IN]
+       tulip(SMC etherpower) boards                    [TESTED]
 
 -------->>>>> 1.3.33 <<<<<<--------
 
@@ -268,38 +268,52 @@ o ip udp/raw nonblock bug fixed                   [TESTED]
 o      ICMP lockup fix                                 [TESTED]
 o      Fundamental operations now only sendmsg/recvmsg [TESTED]
 o      bind() for SOCK_PACKET                          [IN]
-o      set_mac_addr fixed up                           [IN]
-o      BSD SIOCSIFADDR, AF_UNSPEC behaviour            [IN]
+o      set_mac_addr fixed up                           [TESTED]
+o      BSD SIOCSIFADDR, AF_UNSPEC behaviour            [TESTED]
 o      Updated this list                               [OK]
 o      Massive ARP/cache/routing rewrite [ANK]         [IN]
-o      AX.25 connect return fixed in using sock_error  [IN]
+o      AX.25 connect return fixed in using sock_error  [TESTED]
 o      Proper netlink device major(36)                 [TESTED]
 o      First parts of the SKIP support                 [IN, not useful]
-o      TCP ICMP (SOSS should work again)               [IN]
+o      TCP ICMP (SOSS should work again)               [TESTED]
 o      IPFW support for TOS changing (Al Longyear)     [IN]
 o      DECNET PPP test code [Steve]                    [IN]
-o      NFS root        [Miguel/Gero]                   [IN]
-o      Path MTU discovery [ANK]                        [IN]
+o      NFS root        [Miguel/Gero]                   [TESTED]
+o      Path MTU discovery [ANK]                        [TESTED]
 
 -------->>>>> 1.3.44 <<<<<<--------
 
-o      NFS root/ FPU clash fixed                       [IN]
-o      ARP lock bug fixed                              [IN]
-o      SO_BSDCOMPAT option(libbsd/ibcs2 ought to set)  [IN]
-o      Changed to new set_multicast_list()             [IN]
-o      ARP ioctl() call fixes  [Bernd]                 [IN]
+o      NFS root/ FPU clash fixed                       [TESTED]
+o      ARP lock bug fixed                              [TESTED]
+o      SO_BSDCOMPAT option(libbsd/ibcs2 ought to set)  [SEMIDONE]
+o      Changed to new set_multicast_list()             [TESTED]
+o      ARP ioctl() call fixes  [Bernd]                 [TESTED]
 o      Fixes to the name set functions (maybe fixes
-       netrom)         [Steve]                         [IN]
-o      Packet protocol labelling (not IPX yet)         [IN]
-o      Faster buffer copy/clone [Linus]                [IN]
+       netrom)         [Steve]                         [TESTED]
+o      Packet protocol labelling (not IPX yet)         [TESTED]
+o      Faster buffer copy/clone [Linus]                [TESTED]
 
 -------->>>>> 1.3.46 <<<<<<--------
 
-o      AX.25/NetROM fixes/changes [John Naylor]        [IN]
+o      AX.25/NetROM fixes/changes [John Naylor]        [TESTED]
 o      Further attempts to fix the IPX memory bug      [IN]
 o      ARP fixes (Assorted)                            [IN]
 o      Driver fixes for multicast lists                [IN]
 
+-------->>>>> 1.3.48 <<<<<<--------
+
+o      IPalias                                         [TESTED]
+
+-------->>>>> 1.3.50 <<<<<<--------
+
+o      TCP soft error support                          [IN]
+o      Further 3c501 tweaking                          [TESTED]
+o      Still trying to make IPX work right             [IN]
+o      Trap faulty boxes sending IGMP using 0.0.0.0    [IN]
+o      Only allow SMBFS selection with IP configured   [IN]
+o      Packetwin driver [Craig]                        [IN]
+o      Net alias changes [Juan]                        [IN]
+
 ---------- Things I thought Linus had for a while and not merged ----------------
 
 
@@ -310,7 +324,6 @@ o   Decnet pre pre pre pre pre Alpha 0.0.
 o      Chase Donald for new drivers, get people to sort out what net
        drivers should cease to be 'Alpha'.
 o      IPX PPP support
-o      IPalias
 
 ---------- Things pending for me to merge --------------
 
@@ -323,7 +336,7 @@ o   SPARC patches [Dave] [partly in]
 
 o      Forwarding queue control (+ fairness algorithms ??)
 o      IP forward flow control.
-o      IPX memory leak ?????
+o      IPX memory leak ?????                           [Done with luck]
 o      Clean up RAW AX.25 sockets.
 o      Finish IPIP bug fixes                           [Done hopefully]
 o      Multicast routing                               [STARTED BITS]
@@ -332,9 +345,23 @@ o  IPX for Lwared
 o      SKIP                                            [Available in user mode]
 o      AX.25/NetROM locking changes
 o      insw_and_csum
-o      IPAlias
 o      AF_UNIX fd passing
 
+-------------------------- Bugs to fix ------------------------------
+
+o      signal interrupting a unix domain connect can occasionally hang the 
+       machine ??
+o      IPX has a memory accounting bug.                [HOPE DONE]
+o      TCP socket cache gets things wrong very very occasionally under high 
+       load.                                           [TRYING THINGS]
+o      AX.25/NetROM needs more locking.
+o      IP mroute code Oopses still.                    [WAITING DIFF]
+o      Lance driver in a few rare systems is causing crashes in copy/checksum.
+o      NFS logs an error (-512) when interrupted.
+o      NFS flow control is needed with the new multirequest NFS support.
+o      Need to be able to turn off the intelligent arp refreshing as its not so
+       hot over AX.25 and upsets some people with very dumb ISDN bridges.
+
 0.2
 ---
 o      Fast checksum/copy on outgoing TCP
diff --git a/net/TUNABLE b/net/TUNABLE
new file mode 100644 (file)
index 0000000..d3f4b6a
--- /dev/null
@@ -0,0 +1,65 @@
+The following parameters should be tunable but aren't, until we get sysctl
+or similar schemes. For now you'll have to dig around. Various CONFIG_xxx
+items that should be configurable using sysctl omitted.
+
+This is far from complete
+
+Item                   Description
+----------------------------------------------------------------------------
+MAX_SOCKETS            Tunable on boot, maximum sockets we will allocate
+NUM_PROTO              Maximum loadable address family, will need recompile
+MAX_LINKS              Maximum number of netlink minor devices. (1-32)
+MAX_QBYTES             Size of a netlink device queue (tunable)
+RIF_TABLE_SIZE         Token ring RIF cache size (tunable)
+AARP_HASH_SIZE         Size of appletalk hash table (tunable)
+AX25_DEF_T1            AX.25 parameters. These are all tunable via
+AX25_DEF_T2            SIOCAX25SETPARMS
+AX25_DEF_T3            T1-T3,N2 have the meanings in the specification
+AX25_DEF_N2
+AX25_DEF_AXDEFMODE     8 = normal 128 is PE1CHL extended
+AX25_DEF_IPDEFMODE     'D' - datagram  'V' - virtual connection
+AX25_DEF_BACKOFF       'E'xponential 'L'inear
+AX25_DEF_NETROM                Allow netrom 1=Y
+AX25_DF_TEXT           Allow PID=Text 1=Y
+AX25_DEF_WINDOW                Window for normal mode
+AX25_DEF_EWINDOW       Window for PE1CHL mode
+AX25_DEF_DIGI          1 for inband 2 for cross band 3 for both
+AX25_DEF_CONMODE       Allow connected modes 1=Yes
+AX25_ROUTE_MAX         AX.25 route cache size - no currently tunable
+Unnamed (16)           Number of protocol hash slots (tunable)
+DEV_NUMBUFFS           Number of priority levels (not easily tunable)
+Unnamed (300)          Maximum packet backlog queue (tunable)
+MAX_IOVEC              Maximum number of iovecs in a message (tunable)
+MIN_WINDOW             Offered minimum window (tunable)
+MAX_WINDOW             Offered maximum window (tunable)
+MAX_HEADER             Largest physical header (tunable)
+MAX_ADDR_LEN           Largest physical address (tunable)
+SOCK_ARRAY_SIZE                IP socket array hash size (tunable)
+ARP_RES_TIME           Time we try and resolve (tunable)
+ARP_DEAD_RES_TIME      Time the entry stays dead (tunable)
+ARP_MAX_TRIES          Maximum tries (tunable)
+ARP_TIMEOUT            Timeout on an ARP (tunable)
+ARP_CHECK_INTERVAL     Check interval to refresh an arp (tunable)
+ARP_CONFIRM_INTERVAL   Confirm poll time (tunable)
+ARP_TABLE_SIZE         Hash table size for ARP (tunable)
+IP_MAX_MEMBERSHIPS     Largest number of groups per socket (BSD style)
+16                     Hard coded constant for amount of room allowed for
+                       cache align and faster forwarding (tunable)
+IPFRAG_HIGH_THRESH     Limit on fragments, we free fragments until we reach
+IPFRAG_LOW_THRESH      which provides some breathing space. (tunable)
+IP_FRAG_TIME           Time we hold a fragment for. (tunable)
+PORT_MASQ_BEGIN                First port reserved for masquerade (tunable)
+PORT_MASQ_END          Last port used for masquerade   (tunable)
+MASQUERADE_EXPIRE_TCP_FIN      Time we keep a masquerade for after a FIN
+MASUQERADE_EXPIRE_UDP  Time we keep a UDP masquerade for (tunable)
+MAXVIFS                        Maximum mrouted vifs (1-32)
+MFC_LINES              Lines in the multicast router cache (tunable)
+SK_RMEM_MAX            Max memory a socket owns for receive (tunable)
+SK_WMEM_MAX            Max memory a socket owns for send (tunable)
+
+NetROM parameters are tunable via an ioctl passing a struct
+
+4000                   Size a Unix domain socket malloc falls back to 
+                       (tunable) should be 8K - a bit for 8K machines like
+                       the ALPHA
+
index f1bbb2c94af12a35997144c63e0a8ed4161691c6..271b00201f17e7907fda2628c5155c48dbd48401 100644 (file)
@@ -1121,7 +1121,7 @@ static int dev_ifsioc(void *arg, unsigned int getset)
 
 #ifdef CONFIG_NET_ALIAS
                                if (net_alias_is(dev))
-                               net_alias_rehash(dev->my_alias,&ifr.ifr_addr);
+                               net_alias_dev_rehash(dev ,&ifr.ifr_addr);
 #endif
                                dev->pa_addr = (*(struct sockaddr_in *)
                                         &ifr.ifr_addr).sin_addr.s_addr;
@@ -1387,6 +1387,9 @@ int net_dev_init(void)
 #if defined(CONFIG_PI)
        pi_init();
 #endif 
+#if defined(CONFIG_PT)
+       pt_init();
+#endif
 #if defined(CONFIG_DEC_ELCP)
        dec21040_init();
 #endif 
index e423d34fecae4314da4d8ba15edaf076cec12f95..933ae84334b12b6519a51a6f6cbf718dd31f4aa5 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *             NET_ALIAS device aliasing module.
+ *             NET_ALIAS network device aliasing module.
  *
- * Version:    @(#)net_alias.c 0.42   12/11/95
+ *
+ * Version:    @(#)net_alias.c 0.43   12/20/95
  *
  * Authors:    Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *             Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
  *     -       fast hashed alias address lookup
  *     -       net_alias_type objs registration/unreg., module-ables.
  *     -       /proc/net/aliases & /proc/net/alias_types entries
+ * Fixes:
+ *     JJC     :       several net_alias_type func. renamed.
+ *     JJC     :       net_alias_type object methods now pass *this.
+ *     JJC     :       xxx_rcv device selection based on <src,dst> addrs
  *
  * FIXME:
  *     - User calls sleep/wake_up locking.
- *     - Define a way to select the "best" alias device for an incoming
- *       packet to allow xxx_rcv() device switching based ALSO on pkt's
- *       src address (this would require a routing query).
- *       Related stuff:
- *             IP: Test routing between aliases (possible ICMP redirects).
- *             IP: ARP proxy entries attached to aliases are not visible.
  *
  *
  *     This program is free software; you can redistribute it and/or
@@ -37,6 +36,7 @@
 #include <linux/notifier.h>
 #include <linux/if.h>
 #include <linux/inet.h>
+#include <linux/in.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 
@@ -68,7 +68,7 @@ static struct device *net_alias_dev_delete(struct device *main_dev, int slot, in
 static void net_alias_free(struct device *dev);
                                           
 /*
- * net_alias_type base array, will hold net_alias_type objects.
+ * net_alias_type base array, will hold net_alias_type obj hashed list heads.
  */
 
 struct net_alias_type *nat_base[16];
@@ -99,7 +99,7 @@ static __inline__ __u32
 nat_addr32(struct net_alias_type *nat, struct sockaddr *sa)
 {
   if (nat->get_addr32)
-    return nat->get_addr32(sa);
+    return nat->get_addr32(nat, sa);
   else
     return (*(struct sockaddr_in *)sa).sin_addr.s_addr;
 }
@@ -122,7 +122,7 @@ HASH(__u32 addr, int af)
 /*
  * get hash key for supplied net alias type and address
  * nat must be !NULL
- * the purpose here is to map an net_alias_type and a generic
+ * the purpose here is to map a net_alias_type and a generic
  * address to a hash code.
  */
 
@@ -166,33 +166,33 @@ nat_attach_chg(struct net_alias_type *nat, int delta)
 static __inline__ int
 nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa)
 {
-  if (nat->alias_init_1) nat->alias_init_1(alias, sa);
+  if (nat->alias_init_1) nat->alias_init_1(nat, alias, sa);
   return nat_attach_chg(nat, +1);
 }
 
 
 /*
- * unbind alias from type object and call 'done' hook
+ * unbind alias from type object and call alias destructor
  */
 
 static __inline__ int
 nat_unbind(struct net_alias_type *nat, struct net_alias *alias)
 {
-  if (nat->alias_done_1) nat->alias_done_1(alias);
+  if (nat->alias_done_1) nat->alias_done_1(nat, alias);
   return nat_attach_chg(nat, -1);
 }
 
 
 /*
- * compare device address with given. if NULL nat->addr_chk,
+ * compare device address with given. if NULL nat->dev_addr_chk,
  * compare dev->pa_addr with (sockaddr_in) 32 bits address (IP-ish)
  */
 
-static __inline__ int nat_addr_chk(struct net_alias_type *nat,
+static __inline__ int nat_dev_addr_chk_1(struct net_alias_type *nat,
                                   struct device *dev, struct sockaddr *sa)
 {
-  if (nat->addr_chk)
-    return nat->addr_chk(dev, sa);
+  if (nat->dev_addr_chk)
+    return nat->dev_addr_chk(nat, dev, sa);
   else
     return (dev->pa_addr == (*(struct sockaddr_in *)sa).sin_addr.s_addr);
 }
@@ -573,6 +573,81 @@ net_alias_dev_delete(struct device *main_dev, int slot, int *err)
   return NULL;
 }
 
+/*
+ * free all main device aliasing stuff
+ * will be called on dev_close(main_dev)
+ */
+
+static void
+net_alias_free(struct device *main_dev)
+{
+  struct net_alias_info *alias_info;
+  struct net_alias *alias;
+  struct net_alias_type *nat;
+  struct device *dev;
+  unsigned long flags;
+
+  /*
+   * do I really have aliases?
+   */
+  
+  if (!(alias_info = main_dev->alias_info))    return;
+
+  /*
+   * fast device link "short-circuit": set main_dev->next to
+   * device after last alias
+   */
+  
+  save_flags(flags);
+  cli();
+  
+  dev =  main_dev->next;
+  main_dev->next = alias_info->taildev->next;
+  main_dev->alias_info = NULL;
+  alias_info->taildev->next = NULL;
+  
+  restore_flags(flags);
+
+  /*
+   * loop over alias devices, free and dev_close()
+   */
+  
+  while (dev)
+  {
+    if (net_alias_is(dev))
+    {
+      alias = dev->my_alias;
+      if (alias->main_dev == main_dev)
+      {
+       /*
+        * unbind alias from alias_type object
+        */
+       
+       nat = alias->nat;
+       if (nat)
+       {
+         nat_unbind(nat, alias);
+       } /*  else error/printk ??? */
+       
+       dev_close(dev);
+       dev = dev->next;
+       
+       kfree_s(alias, sizeof(struct net_alias));
+       continue;
+      }
+      else
+       printk("net_alias_free(%s): '%s' is not my alias\n",
+              main_dev->name, alias->name);
+    }
+    else
+      printk("net_alias_free(%s): found a non-alias after device!\n",
+            main_dev->name);
+    dev = dev->next;
+  }
+  
+  kfree_s(alias_info, sizeof(alias_info));
+  return;
+}
 
 /*
  * dev_get() with added alias naming magic.
@@ -645,23 +720,26 @@ net_alias_dev_get(char *dev_name, int aliasing_ok, int *err,
 
 
 /*
- * rehash alias with address supplied. 
+ * rehash alias device with address supplied. 
  */
 
 int
-net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
+net_alias_dev_rehash(struct device *dev, struct sockaddr *sa)
 {
   struct net_alias_info *alias_info;
-  struct net_alias **aliasp;
-  struct device *dev;
+  struct net_alias *alias, **aliasp;
+  struct device *main_dev;
   unsigned long flags;
   struct net_alias_type *o_nat, *n_nat;
   unsigned n_hash;
-  
+
   /*
    * defensive ...
    */
   
+  if (dev == NULL) return -1;
+  if ( (alias = dev->my_alias) == NULL ) return -1;
+  
   if (!sa)
   {
     printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
@@ -671,8 +749,8 @@ net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
   /*
    * defensive. should not happen.
    */
-  
-  if (!(dev = alias->main_dev))
+
+  if ( (main_dev = alias->main_dev) == NULL )
   {
     printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
     return -1;
@@ -682,7 +760,7 @@ net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
    * defensive. should not happen.
    */
 
-  if (!(alias_info=dev->alias_info))
+  if (!(alias_info=main_dev->alias_info))
   {
     printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
     return -1;
@@ -747,7 +825,7 @@ net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
   cli();
   
   /*
-   * if type (family) changed unlink from old type object (o_nat)
+   * if type (family) changed, unlink from old type object (o_nat)
    * will call o_nat->alias_done_1()
    */
   
@@ -780,81 +858,6 @@ net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
 }
 
 
-/*
- * free all main device aliasing stuff
- * will be called on dev_close(main_dev)
- */
-
-static void
-net_alias_free(struct device *main_dev)
-{
-  struct net_alias_info *alias_info;
-  struct net_alias *alias;
-  struct net_alias_type *nat;
-  struct device *dev;
-  unsigned long flags;
-
-  /*
-   * do I really have aliases?
-   */
-  
-  if (!(alias_info = main_dev->alias_info))    return;
-
-  /*
-   * fast device link "short-circuit": set main_dev->next to
-   * device after last alias
-   */
-  
-  save_flags(flags);
-  cli();
-  
-  dev =  main_dev->next;
-  main_dev->next = alias_info->taildev->next;
-  main_dev->alias_info = NULL;
-  alias_info->taildev->next = NULL;
-  
-  restore_flags(flags);
-
-  /*
-   * loop over alias devices, free and dev_close()
-   */
-  
-  while (dev)
-  {
-    if (net_alias_is(dev))
-    {
-      alias = dev->my_alias;
-      if (alias->main_dev == main_dev)
-      {
-       /*
-        * unbind alias from alias_type object
-        */
-       
-       nat = alias->nat;
-       if (nat)
-       {
-         nat_unbind(nat, alias);
-       } /*  else error/printk ??? */
-       
-       dev_close(dev);
-       dev = dev->next;
-       
-       kfree_s(alias, sizeof(struct net_alias));
-       continue;
-      }
-      else
-       printk("net_alias_free(%s): '%s' is not my alias\n",
-              main_dev->name, alias->name);
-    }
-    else
-      printk("net_alias_free(%s): found a non-alias after device!\n",
-            main_dev->name);
-    dev = dev->next;
-  }
-  
-  kfree_s(alias_info, sizeof(alias_info));
-  return;
-}
 
 
 /*
@@ -898,7 +901,7 @@ int net_alias_types_getinfo(char *buffer, char **start, off_t offset, int length
  *
  */
 
-#define NAT_REC_SIZE 64
+#define NET_ALIASES_RECSIZ 64
 int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
 {
   off_t pos=0, begin=0;
@@ -908,7 +911,7 @@ int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int
   struct net_alias *alias;
   struct device *dev;
 
-  len=sprintf(buffer,"%-*s\n",NAT_REC_SIZE-1,"device           family address");
+  len=sprintf(buffer,"%-*s\n",NET_ALIASES_RECSIZ-1,"device           family address");
   for (dev = dev_base; dev ; dev = dev->next)
     if (net_alias_is(dev))
     {
@@ -921,7 +924,7 @@ int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int
        */
       
       if (nat->alias_print_1)
-       dlen += nat->alias_print_1(buffer+len+dlen, NAT_REC_SIZE - dlen, alias);
+       dlen += nat->alias_print_1(nat, alias, buffer+len+dlen, NET_ALIASES_RECSIZ - dlen);
       else
        dlen += sprintf(buffer+len+dlen, "-");
 
@@ -929,12 +932,12 @@ int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int
        * fill with spaces if needed 
        */
       
-      if (dlen < NAT_REC_SIZE) memset(buffer+len+dlen, ' ', NAT_REC_SIZE - dlen);
+      if (dlen < NET_ALIASES_RECSIZ) memset(buffer+len+dlen, ' ', NET_ALIASES_RECSIZ - dlen);
       /*
-       * truncate to NAT_REC_SIZE
+       * truncate to NET_ALIASES_RECSIZ
        */
       
-      len += NAT_REC_SIZE;
+      len += NET_ALIASES_RECSIZ;
       buffer[len-1] = '\n';
       
       pos=begin+len;
@@ -984,58 +987,39 @@ int net_alias_device_event(struct notifier_block *this, unsigned long event, voi
 
 
 /*
- * returns alias device with specified address AND flags_1 on AND flags_0 off.
- *   intended for main devices.
- *   typically called on xxx_rcv() to check if packet's dest address is one
- *   of main_dev's alias address.
+ * device aliases address comparison workhorse
+ * no checks for nat and alias_info, must be !NULL
  */
 
-struct device *
-net_alias_chk(struct device *dev, struct sockaddr *sa,int flags_1, int flags_0)
+static __inline__ struct device *
+nat_addr_chk(struct net_alias_type *nat, struct net_alias_info *alias_info, struct sockaddr *sa, int flags_on, int flags_off)
 {
-  struct net_alias_info *alias_info = dev->alias_info;
-  struct net_alias_type *nat;
   struct net_alias *alias;
-  
-  if (!alias_info) return NULL;        /* has aliases? */
-  
-  /*
-   * get alias_type object for sa->sa_family.
-   */
-  
-  nat = nat_getbytype(sa->sa_family);
-  if (!nat)
-    return 0;
-  
   for(alias = alias_info->hash_tab[nat_hash_key(nat,sa)];
       alias; alias = alias->next)
   {
     if (alias->dev.family != sa->sa_family) continue;
 
     /*
-     * nat_addr_chk will call type specific address cmp function.
+     * nat_dev_addr_chk_1 will call type specific address cmp function.
      */
     
-    if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
-       nat_addr_chk(nat,&alias->dev,sa))
+    if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
+       nat_dev_addr_chk_1(nat,&alias->dev,sa))
       return &alias->dev;
   }
   return NULL;
 }
 
 /*
- * addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
+ * nat_addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
+ * note that nat pointer is ignored because of static comparison.
  */
 
-struct device *
-net_alias_chk32(struct device *dev, int family, __u32 addr32,
-               int flags_1, int flags_0)
+static __inline__ struct device *
+nat_addr_chk32(struct net_alias_type *nat, struct net_alias_info *alias_info, int family, __u32 addr32, int flags_on, int flags_off)
 {
-  struct net_alias_info *alias_info = dev->alias_info;
   struct net_alias *alias;
-  
-  if (!alias_info) return NULL;        /* has aliases? */
-  
   for (alias=alias_info->hash_tab[HASH(addr32,family)];
        alias; alias=alias->next)
   {
@@ -1045,13 +1029,212 @@ net_alias_chk32(struct device *dev, int family, __u32 addr32,
      * "hard" (static) comparison between addr32 and pa_addr.
      */
     
-    if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
+    if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
        addr32 == alias->dev.pa_addr)
       return &alias->dev;
   }
   return NULL;
 }
 
+/*
+ * returns alias device with specified address AND flags_on AND flags_off,
+ * else NULL.
+ * intended for main devices.
+ */
+
+struct device *
+net_alias_dev_chk(struct device *main_dev, struct sockaddr *sa,int flags_on, int flags_off)
+{
+  struct net_alias_info *alias_info = main_dev->alias_info;
+  struct net_alias_type *nat;
+  
+  /*
+   * only if main_dev has aliases
+   */
+
+  if (!alias_info) return NULL;
+  
+  /*
+   * get alias_type object for sa->sa_family.
+   */
+  
+  nat = nat_getbytype(sa->sa_family);
+  if (!nat)
+    return NULL;
+
+  return nat_addr_chk(nat, alias_info, sa, flags_on, flags_off);
+}
+
+/*
+ * net_alias_dev_chk enough for protocols whose addr is (fully) stored
+ * at pa_addr.
+ */
+
+struct device *
+net_alias_dev_chk32(struct device *main_dev, int family, __u32 addr32,
+               int flags_on, int flags_off)
+{
+  struct net_alias_info *alias_info = main_dev->alias_info;
+  
+  /*
+   * only if main_dev has aliases
+   */
+
+  if (!alias_info) return NULL;
+  
+  return nat_addr_chk32(NULL, alias_info, family, addr32, flags_on, flags_off);
+}
+
+
+/*
+ * select closest (main or alias) device to <src,dst> addresses given. if no
+ * further info is available, return main_dev (for easier calling arrangment).
+ *
+ * Should be called early at xxx_rcv() time for device selection
+ */
+
+struct device *
+net_alias_dev_rcv_sel(struct device *main_dev, struct sockaddr *sa_src, struct sockaddr *sa_dst)
+{
+  int family;
+  struct net_alias_type *nat;
+  struct net_alias_info *alias_info;
+  struct device *dev;
+  
+  if (main_dev == NULL) return NULL;
+
+  /*
+   * if not aliased, dont bother any more
+   */
+
+  if ((alias_info = main_dev->alias_info) == NULL)
+    return main_dev;
+
+  /*
+   * find out family
+   */
+
+  family = (sa_src)? sa_src->sa_family : ((sa_dst)? sa_dst->sa_family : AF_UNSPEC);
+  if (family == AF_UNSPEC) return main_dev;
+
+  /*
+   * get net_alias_type object for this family
+   */
+
+  if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
+  
+  /*
+   * first step: find out if dst addr is main_dev's or one of its aliases'
+   */
+
+  if (sa_dst)
+  {
+    if (nat_dev_addr_chk_1(nat, main_dev,sa_dst))
+      return main_dev;
+
+    dev = nat_addr_chk(nat, alias_info, sa_dst, IFF_UP, 0);
+
+    if (dev != NULL) return dev;
+  }
+
+  /*
+   * second step: find the rcv addr 'closest' alias through nat method call
+   */
+
+  if ( sa_src == NULL || nat->dev_select == NULL) return main_dev;
+  dev = nat->dev_select(nat, main_dev, sa_src);
+
+  if (dev == NULL || dev->family != family) return main_dev;
+  
+  /*
+   * dev ok only if it is alias of main_dev
+   */
+  
+  dev = net_alias_is(dev)?
+    ( (dev->my_alias->main_dev == main_dev)? dev : NULL) : NULL;
+
+  /*
+   * do not return NULL.
+   */
+  
+  return (dev)? dev : main_dev;
+
+}
+
+/*
+ * dev_rcv_sel32: dev_rcv_sel for 'pa_addr' protocols.
+ */
+
+struct device *
+net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 dst)
+{
+  struct net_alias_type *nat;
+  struct net_alias_info *alias_info;
+  struct sockaddr_in sin_src;
+  struct device *dev;
+  
+  if (main_dev == NULL) return NULL;
+
+  /*
+   * if not aliased, dont bother any more
+   */
+
+  if ((alias_info = main_dev->alias_info) == NULL)
+    return main_dev;
+
+  /*
+   * early return if dst is main_dev's address
+   */
+  
+  if (dst == main_dev->pa_addr)
+    return main_dev;
+  
+  if (family == AF_UNSPEC) return main_dev;
+
+  /*
+   * get net_alias_type object for this family
+   */
+
+  if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
+  
+  /*
+   * first step: find out if dst address one of main_dev aliases'
+   */
+  
+  if (dst)
+  {
+    dev = nat_addr_chk32(nat, alias_info, family, dst, IFF_UP, 0);
+    if (dev) return dev;
+  }
+  
+  /*
+   * second step: find the rcv addr 'closest' alias through nat method call
+   */
+
+  if ( src == 0 || nat->dev_select == NULL) return main_dev;
+
+  sin_src.sin_family = family;
+  sin_src.sin_addr.s_addr = src;
+    
+  dev = nat->dev_select(nat, main_dev, (struct sockaddr *)&sin_src);
+
+  if (dev == NULL) return main_dev;
+  
+  /*
+   * dev ok only if it is alias of main_dev
+   */
+  
+  dev = net_alias_is(dev)?
+    ( (dev->my_alias->main_dev == main_dev)? dev : NULL) : NULL;
+
+  /*
+   * do not return NULL.
+   */
+  
+  return (dev)? dev : main_dev;
+  
+}
+
 
 /*
  * device event hook
@@ -1162,3 +1345,4 @@ int unregister_net_alias_type(struct net_alias_type *nat)
   printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
   return -EINVAL;
 }
+
index e0046cfffac74aca9b0552677a55d3928a088f10..dbaf42d5aedc586f758987d62de37383e903f1e1 100644 (file)
@@ -66,6 +66,7 @@
  *                                     (compatibility fix)
  *             Alan Cox        :       Added optimistic memory grabbing for AF_UNIX throughput.
  *             Alan Cox        :       Allocator for a socket is settable.
+ *             Alan Cox        :       SO_ERROR includes soft errors.
  *
  * To Fix:
  *
@@ -259,8 +260,9 @@ int sock_getsockopt(struct sock *sk, int level, int optname,
                        break;
 
                case SO_ERROR:
-                       val = sk->err;
-                       sk->err = 0;
+                       val = sock_error(sk);
+                       if(val==0)
+                               val=xchg(&sk->err_soft,0);
                        break;
 
                case SO_OOBINLINE:
index dad8d0bf1f653efd539a20e000a7ec2f62d41637..948e4b6868a52c8011e0da23493eb316b7bf4e27 100644 (file)
@@ -1471,7 +1471,7 @@ void inet_proto_init(struct net_proto *pro)
        int i;
 
 
-       printk("Swansea University Computer Society TCP/IP for NET3.032\n");
+       printk("Swansea University Computer Society TCP/IP for NET3.033\n");
 
        /*
         *      Tell SOCKET that we are alive... 
index 60422172f5277ee4205916edf724515a5524ea28..1d37646b8745af1d2d5fdacf094afaa2115ffa75 100644 (file)
@@ -895,15 +895,22 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
  */
 
 /*
- *     try to switch to alias device whose address is tip, if any
+ *     try to switch to alias device whose addr is tip or closest to sip.
  */
 
 #ifdef CONFIG_NET_ALIAS
-       if (net_alias_has(dev))
+       if (tip != dev->pa_addr && net_alias_has(skb->dev)) 
        {
-               struct device *adev;
-               adev = net_alias_chk32(dev,AF_INET,tip,IFF_UP,IFF_NOARP);
-               if (adev != NULL) dev = adev;
+               /*
+                *      net_alias_dev_rcv_sel32 returns main dev if it fails to found other.
+                */
+               dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip);
+
+               if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP)
+               {
+                       kfree_skb(skb, FREE_READ);
+                       return 0;
+               }
        }
 #endif
 
index 5501914fd07b6f1cbdde4fbf888894ab9b1b8cba..77168c7091e5a05c443d72217715cab45f7ccdbf 100644 (file)
@@ -2,9 +2,11 @@
  *     Linux NET3:     Internet Gateway Management Protocol  [IGMP]
  *
  *     This code implements the IGMP protocol as defined in RFC1122. There has
- *     been a further revision of this protocol since, but since it is not
- *     cleanly specified in any IETF standards we implement the old one properly
- *     rather than play a game of guess the BSD unofficial extensions.
+ *     been a further revision of this protocol since which is now supported.
+ *
+ *     If you have trouble with this module be careful what gcc you have used,
+ *     the older version didnt come out right using gcc 2.5.8, the newer one
+ *     seems to fall out with gcc 2.6.2.
  *
  *     Authors:
  *             Alan Cox <Alan.Cox@linux.org>
@@ -42,6 +44,8 @@
  *                                     and do what the IGMP version 2 specified.
  *             Chih-Jen Chang  :       Added a timer to revert to IGMP V2 router
  *             Tsu-Sheng Tsao          if the specified time expired.
+ *             Alan Cox        :       Stop IGMP from 0.0.0.0 being accepted.
+ *             Alan Cox        :       Use GFP_ATOMIC in the right places.
  */
 
 
@@ -107,7 +111,10 @@ static     struct  ip_router_info  *igmp_get_mrouter_info(struct device *dev)
        /*
         *  Not found. Create a new entry. The default is IGMP V2 router
         */
-       i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_KERNEL);
+        
+       i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_ATOMIC);
+       if(i==NULL)
+               return NULL;
        i->dev = dev;
        i->type = IGMP_NEW_ROUTER;
        i->time = IGMP_AGE_THRESHOLD;
@@ -153,7 +160,9 @@ static      struct  ip_router_info  *igmp_set_mrouter_info(struct device *dev,int type,
        /*
         *  Not found. Create a new entry.
         */
-       i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_KERNEL);
+       i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_ATOMIC);
+       if(i==NULL)
+               return NULL;
        i->dev = dev;
        i->type = type;
        i->time = time;
@@ -242,6 +251,8 @@ static void igmp_timer_expire(unsigned long data)
        struct ip_router_info *r;
        igmp_stop_timer(im);
        r=igmp_get_mrouter_info(im->interface);
+       if(r==NULL)
+               return;
        if(r->type==IGMP_NEW_ROUTER)
                igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
        else
@@ -277,7 +288,8 @@ static void igmp_heard_query(struct device *dev,unsigned char max_resp_time)
        {
                mrouter_type=IGMP_NEW_ROUTER;
 
-               igmp_set_mrouter_info(dev,mrouter_type,0);
+               if(igmp_set_mrouter_info(dev,mrouter_type,0)==NULL)
+                       return;
                /*
                 * - Start the timers in all of our membership records
                 *   that the query applies to for the interface on
@@ -310,7 +322,8 @@ static void igmp_heard_query(struct device *dev,unsigned char max_resp_time)
                mrouter_type=IGMP_OLD_ROUTER;
                max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE;
 
-               igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD);
+               if(igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD)==NULL)
+                       return;
 
                /*
                 * Start the timers in all of our membership records for
@@ -383,6 +396,8 @@ extern __inline__ void igmp_group_added(struct ip_mc_list *im)
        igmp_init_timer(im);
        ip_mc_filter_add(im->interface, im->multiaddr);
        r=igmp_get_mrouter_info(im->interface);
+       if(r==NULL)
+               return;
        if(r->type==IGMP_NEW_ROUTER)
                igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
        else
@@ -415,6 +430,18 @@ int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                kfree_skb(skb, FREE_READ);
                return 0;
        }
+       
+       /*
+        *      I have a report that someone does this!
+        */
+        
+       if(saddr==0)
+       {
+               printk("Broken multicast host using 0.0.0.0 heard on %s\n",
+                       dev->name);
+               kfree_skb(skb, FREE_READ);
+               return 0;
+       }
 
        if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
                igmp_heard_query(dev,ih->code);
index e8ea2b0924dc5a8410e68a319f7bfa6c514d22a9..18339851638d21292a5904589e7750ceb4b19b25 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ *             IP_ALIAS (AF_INET) aliasing module.
+ *
+ *
+ * Version:    @(#)ip_alias.c  0.43   12/20/95
+ *
+ * Author:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *
+ * Fixes:
+ *     JJC     :       ip_alias_dev_select method.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *     
+ */
+
 #include <linux/module.h>
 
 #include <linux/types.h>
@@ -5,6 +23,10 @@
 #include <linux/netdevice.h>
 #include <linux/if.h>
 #include <linux/inet.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/route.h>
+#include <net/route.h>
 
 #ifdef ALIAS_USER_LAND_DEBUG
 #include "net_alias.h"
@@ -19,7 +41,7 @@
  * AF_INET alias init
  */
 static int 
-ip_alias_init_1(struct net_alias *alias, struct sockaddr *sa)
+ip_alias_init_1(struct net_alias_type *this, struct net_alias *alias, struct sockaddr *sa)
 {
 #ifdef ALIAS_USER_LAND_DEBUG
   printk("alias_init(%s) called.\n", alias->name);
@@ -32,7 +54,7 @@ ip_alias_init_1(struct net_alias *alias, struct sockaddr *sa)
  * AF_INET alias done
  */
 static int
-ip_alias_done_1(struct net_alias *alias)
+ip_alias_done_1(struct net_alias_type *this, struct net_alias *alias)
 {
 #ifdef ALIAS_USER_LAND_DEBUG
   printk("alias_done(%s) called.\n", alias->name);
@@ -42,11 +64,11 @@ ip_alias_done_1(struct net_alias *alias)
 }
 
 /*
- * print address info
+ * print alias address info
  */
 
 int
-ip_alias_print_1(char *buf, int len, struct net_alias *alias)
+ip_alias_print_1(struct net_alias_type *this, struct net_alias *alias, char *buf, int len)
 {
   char *p;
 
@@ -55,6 +77,37 @@ ip_alias_print_1(char *buf, int len, struct net_alias *alias)
                 (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
 }
 
+struct device *
+ip_alias_dev_select(struct net_alias_type *this, struct device *main_dev, struct sockaddr *sa)
+{
+  __u32 addr;
+  struct rtable *rt;
+  
+  /*
+   * defensive...
+   */
+  
+  if (main_dev == NULL) return NULL;
+
+  /*
+   * get u32 address. 
+   */
+
+  addr =  (sa)? (*(struct sockaddr_in *)sa).sin_addr.s_addr : 0;
+
+  if (addr == 0) return NULL;
+
+  /*
+   * find 'closest' device to address given. any other suggestions? ...
+   * net_alias module will check if returned device is main_dev's alias
+   */
+
+  rt = ip_rt_route(addr, 0);
+
+  return (rt)? rt->rt_dev : NULL;
+
+}
+
 /*
  * net_alias AF_INET type defn.
  */
@@ -65,7 +118,8 @@ struct net_alias_type ip_alias_type =
   0,                           /* n_attach */
   "ip",                                /* name */
   NULL,                                /* get_addr32() */
-  NULL,                                /* addr_chk() */
+  NULL,                                /* dev_addr_chk() */
+  ip_alias_dev_select,         /* dev_select() */
   ip_alias_init_1,             /* alias_init_1() */
   ip_alias_done_1,             /* alias_done_1() */
   ip_alias_print_1,            /* alias_print_1() */
index 772ef8cb0e4f36d8283f8aaf995780ee85cf99d7..3e0f38ef1405259d9745bc328fe1213434ecbf3f 100644 (file)
@@ -272,6 +272,17 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 #endif                                 
        }
        
+       /*
+        *      Try to select closest <src,dst> alias device, if any.
+        *      net_alias_dev_rcv_sel32 returns main device if it 
+        *      fails to found other.
+        */
+
+#ifdef CONFIG_NET_ALIAS
+       if (iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) 
+               skb->dev = dev = net_alias_dev_rcv_sel32(skb->dev, AF_INET, iph->saddr, iph->daddr);
+#endif
+
        /*
         *      See if the firewall wants to dispose of the packet. 
         */
@@ -316,18 +327,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
         *      function entry.
         */
 
-       /*
-        *      also check device aliases address : will avoid
-        *      a full lookup over device chain
-        */
-
-#ifdef CONFIG_NET_ALIAS
-       if ( iph->daddr == skb->dev->pa_addr ||
-           ( net_alias_has(skb->dev) && net_alias_addr_chk32(skb->dev,AF_INET, iph->daddr )) ||
-           (brd = ip_chk_addr(iph->daddr)) != 0)
-#else
        if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0)
-#endif
        {
                if (opt && opt->srr) 
                {
index e6e768c98b50b6992826e02f3576fd84258e2b03..6c2c72d9d40d6840e78913c58611f03115f9f4fd 100644 (file)
@@ -220,11 +220,11 @@ static int raw_sendto(struct sock *sk, const unsigned char *from,
                if (sk->state != TCP_ESTABLISHED) 
                        return(-EINVAL);
                sin.sin_family = AF_INET;
-               sin.sin_port = sk->protocol;
+               sin.sin_port = sk->num;
                sin.sin_addr.s_addr = sk->daddr;
        }
        if (sin.sin_port == 0) 
-               sin.sin_port = sk->protocol;
+               sin.sin_port = sk->num;
   
        if (sin.sin_addr.s_addr == INADDR_ANY)
                sin.sin_addr.s_addr = ip_my_addr();
index cfd46a432ec2888037407b9a319d0ab20773c9fb..13f1f8471b0f1f9f9a4d0aeb5f1ea0a7abdabf1a 100644 (file)
  *             Alan Cox        :       Block double connect().
  *             Alan Cox        :       Small hooks for enSKIP.
  *             Alexey Kuznetsov:       Path MTU discovery.
+ *             Alan Cox        :       Support soft errors.
  *
  *
  * To Fix:
  *             RFC1323 - PAWS and window scaling. PAWS is required for IPv6 so we
  *             could do with it working on IPv4
  *             User settable/learned rtt/max window/mtu
- *             Cope with MTU/device switches when retransmitting in tcp.
  *             Fix the window handling to use PR's new code.
  *
  *             Change the fundamental structure to a single send queue maintained
  *   MUST implement receiver-side SWS. (does)
  *   
  * When to Send Data (4.2.3.4)
- *   MUST implement sender-side SWS. (does - imperfectly)
+ *   MUST implement sender-side SWS. (does)
  *   SHOULD implement Nagle algorithm. (does)
  * 
  * TCP Connection Failures (4.2.3.5)
  *  MUST handle excessive retransmissions "properly" (see the RFC). (does)
- *   SHOULD inform application layer of soft errors. (doesn't)
+ *   SHOULD inform application layer of soft errors. (does)
  *   
  * TCP Keep-Alives (4.2.3.6)
  *   MAY provide keep-alives. (does)
  *   MUST use same local address for all segments of a connection. (does)
  * 
  * IP Options (4.2.3.8)
- *   (I don't think the IP layer sees the IP options, yet.)
- *   MUST ignore unsupported IP options. (does, I guess 8*b)
- *   MAY support Time Stamp and Record Route. (doesn't)
- * **MUST allow application to specify a source route. (doesn't?)
- * **MUST allow receieved Source Route option to set route for all future
- *     segments on this connection. (doesn't, not that I think it's a
- *     huge problem)
+ *   MUST ignore unsupported IP options. (does)
+ *   MAY support Time Stamp and Record Route. (does)
+ *   MUST allow application to specify a source route. (does)
+ *   MUST allow receieved Source Route option to set route for all future
+ *     segments on this connection. (does not (security issues))
  * 
  * ICMP messages (4.2.3.9)
  *   MUST act on ICMP errors. (does)
  *     Unreachables (0, 1, 5), Time Exceededs and Parameter
  *     Problems. (doesn't)
  *   SHOULD report soft Destination Unreachables etc. to the
- *     application. (doesn't)
+ *     application. (does)
  *   SHOULD abort connection upon receipt of hard Destination Unreachable
  *     messages (2, 3, 4). (does)
  * 
@@ -696,7 +694,7 @@ void tcp_do_retransmit(struct sock *sk, int all)
                {
                        if(skb->sk)
                        {
-                               skb->sk->err=ENETUNREACH;
+                               skb->sk->err_soft=ENETUNREACH;
                                skb->sk->error_report(skb->sk);
                        }
                }
@@ -893,7 +891,10 @@ static int tcp_write_timeout(struct sock *sk)
         
        if(sk->retransmits > TCP_SYN_RETRIES && sk->state==TCP_SYN_SENT)
        {
-               sk->err=ETIMEDOUT;
+               if(sk->err_soft)
+                       sk->err=sk->err_soft;
+               else
+                       sk->err=ETIMEDOUT;
                sk->error_report(sk);
                del_timer(&sk->retransmit_timer);
                tcp_statistics.TcpAttemptFails++;       /* Is this right ??? - FIXME - */
@@ -907,7 +908,10 @@ static int tcp_write_timeout(struct sock *sk)
         */
        if (sk->retransmits > TCP_RETR2) 
        {
-               sk->err = ETIMEDOUT;
+               if(sk->err_soft)
+                       sk->err = sk->err_soft;
+               else
+                       sk->err = ETIMEDOUT;
                sk->error_report(sk);
                del_timer(&sk->retransmit_timer);
                /*
@@ -1113,17 +1117,21 @@ void tcp_err(int type, int code, unsigned char *header, __u32 daddr,
         * until we time out, or the user gives up.
         */
 
-       if (code < 13 && (icmp_err_convert[code].fatal || sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV))
-       {
-               sk->err = icmp_err_convert[code].errno;
-               if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) 
+       if (code < 13)
+       {       
+               if(icmp_err_convert[code].fatal || sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
                {
-                       tcp_statistics.TcpAttemptFails++;
-                       tcp_set_state(sk,TCP_CLOSE);
-                       sk->error_report(sk);           /* Wake people up to see the error (see connect in sock.c) */
+                       sk->err = icmp_err_convert[code].errno;
+                       if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) 
+                       {
+                               tcp_statistics.TcpAttemptFails++;
+                               tcp_set_state(sk,TCP_CLOSE);
+                               sk->error_report(sk);           /* Wake people up to see the error (see connect in sock.c) */
+                       }
                }
+               else    /* Only an error on timeout */
+                       sk->err_soft = icmp_err_convert[code].errno;
        }
-       return;
 }
 
 
@@ -3590,6 +3598,13 @@ extern __inline__ int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long
         */
         
        sk->rcv_ack_seq = ack;
+       
+       /*
+        *      We passed data and got it acked, remove any soft error
+        *      log. Something worked...
+        */
+        
+       sk->err_soft = 0;
 
        /*
         *      If this ack opens up a zero window, clear backoff.  It was
@@ -4809,7 +4824,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
         *      Find the socket, using the last hit cache if applicable.
         */
 
-       if(saddr==th_cache_saddr && daddr==th_cache_daddr && th->dest==th_cache_dport && th->source==th_cache_sport)
+       if(!redo && saddr==th_cache_saddr && daddr==th_cache_daddr && th->dest==th_cache_dport && th->source==th_cache_sport)
        {
                sk=(struct sock *)th_cache_sk;
                /*
@@ -5319,12 +5334,13 @@ static void tcp_write_wakeup(struct sock *sk)
                 *      Find the first data byte.
                 */
                 
-               tcp_data_start = skb->data + skb->dev->hard_header_len + 
-                               (iph->ihl << 2) + th->doff * 4;
+               tcp_data_start = skb->ip_hdr + 
+                               ((iph->ihl + th->doff) << 2);
 
                /*
                 *      Add it to our new buffer
                 */
+                
                memcpy(skb_put(buff,win_size), tcp_data_start, win_size);
                
                /*
@@ -5333,38 +5349,8 @@ static void tcp_write_wakeup(struct sock *sk)
                 
                buff->end_seq = sk->sent_seq + win_size;
                sk->sent_seq = buff->end_seq;           /* Hack */
-#if 0
-
-               /*
-                *      now: shrink the queue head segment 
-                */
-                
-               th->check = 0;
-               ow_size = skb->len - win_size - 
-                       ((unsigned long) (tcp_data_start - (void *) skb->data));
-
-               memmove(tcp_data_start, tcp_data_start + win_size, ow_size);
-               skb_trim(skb,skb->len-win_size);
-               sk->sent_seq += win_size;
-               th->seq = htonl(sk->sent_seq);
-               if (th->urg)
-               {
-                       unsigned short urg_ptr;
-       
-                       urg_ptr = ntohs(th->urg_ptr);
-                       if (urg_ptr <= win_size)
-                               th->urg = 0;
-                       else
-                       {
-                               urg_ptr -= win_size;
-                               th->urg_ptr = htons(urg_ptr);
-                               nth->urg_ptr = htons(win_size);
-                       }
-               }
-#else
                if(th->urg && ntohs(th->urg_ptr) < win_size)
                        nth->urg = 0;
-#endif         
 
                /*
                 *      Checksum the split buffer
index 13cb71e5e26091a8bf3b4e27600beb8ecb9a3290..b7560d7a869f30e2f1154b35e83d0938aeaa6973 100644 (file)
@@ -404,19 +404,8 @@ static int ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int c
         * that skb1 and skb2 point to it (them) so that it (they) can be 
         * demuxed to sock1 and/or sock2.  If we are unable to make enough
         * copies, we do as much as is possible.
-        *
-        * Firstly stop charging the sender for the space. We will
-        * charge the recipient or discard. If we are called from ipx_rcv
-        * this is ok as no socket owns an input buffer.
         */
         
-       if(skb->sk && !copy)
-       {
-               skb->sk->wmem_alloc -= skb->truesize;   /* Adjust */
-               skb->sk=NULL;                           /* Disown */
-       }
-
-        
        if (copy) 
        {
                skb1 = skb_clone(skb, GFP_ATOMIC);
@@ -499,7 +488,7 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
         */
         
        if ((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK)) 
-               send_to_wire = 0;
+               send_to_wire = 0;       /* No non looped */
 
        /*
         *      See if this should be demuxed to sockets on this interface 
@@ -514,12 +503,24 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
                 *      To our own node, loop and free the original.
                 */
                if (memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0) 
+               {
+                       /*
+                        *      Don't charge sender
+                        */
+                       if(skb->sk)
+                               skb->sk->wmem_alloc-=skb->truesize;
+                       /*
+                        *      Will charge receiver
+                        */
                        return ipxitf_demux_socket(intrfc, skb, 0);
+               }
                /*
                 *      Broadcast, loop and possibly keep to send on.
                 */
                if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) 
                {
+                       if (!send_to_wire && skb->sk)
+                               skb->sk->wmem_alloc-=skb->truesize;
                        ipxitf_demux_socket(intrfc, skb, send_to_wire);
                        if (!send_to_wire) 
                                return 0;
@@ -527,7 +528,9 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
        }
 
        /*
-        *      if the originating net is not equal to our net; this is routed 
+        *      If the originating net is not equal to our net; this is routed 
+        *      We are still charging the sender. Which is right - the driver
+        *      free will handle this fairly.
         */
         
        if (ipx->ipx_source.net != intrfc->if_netnum) 
index 2f7754716a3bc70a7383819a5f5fc96c12e7aa56..61ab750e992e41ea9b91495622ef06ea2ee3918f 100644 (file)
@@ -1341,7 +1341,7 @@ void sock_init(void)
 {
        int i;
 
-       printk("Swansea University Computer Society NET3.033 for Linux 1.3.38\n");
+       printk("Swansea University Computer Society NET3.033 for Linux 1.3.50\n");
 
        /*
         *      Initialize all address (protocol) families. 
index c40dea77855dac6b8ac26aadb115bed79dffaac7..08c8fd85777035ac98d39bf59661217702745183 100644 (file)
@@ -799,8 +799,9 @@ static int unix_sendmsg(struct socket *sock, struct msghdr *msg, int len, int no
 }
 
 /*
- * Sleep until data has arrive. But check for races..
+ *     Sleep until data has arrive. But check for races..
  */
 static void unix_data_wait(unix_socket * sk)
 {
        cli();
@@ -1035,7 +1036,7 @@ static struct proto_ops unix_proto_ops = {
 
 void unix_proto_init(struct net_proto *pro)
 {
-       printk("NET3: Unix domain sockets 0.10 BETA for Linux NET3.031.\n");
+       printk("NET3: Unix domain sockets 0.10 BETA for Linux NET3.033.\n");
        sock_register(unix_proto_ops.family, &unix_proto_ops);
        proc_net_register(&(struct proc_dir_entry) {
                PROC_NET_UNIX,  4, "unix",