diff -u --recursive --new-file v1.3.46/linux/CREDITS linux/CREDITS
--- v1.3.46/linux/CREDITS	Mon Dec 11 15:41:58 1995
+++ linux/CREDITS	Tue Dec 12 13:28:05 1995
@@ -134,6 +134,12 @@
 S: Baltimore, Maryland 21218
 S: USA
 
+N: Axel Boldt
+E: boldt@math.ucsb.edu
+W: http://math-www.uni-paderborn.de/~axel/
+D: Configuration help text support
+D: Linux CD and Support Giveaway List
+
 N: John Boyd
 E: boyd@cis.ohio-state.edu
 D: Co-author of wd7000 SCSI driver
@@ -214,7 +220,7 @@
 
 N: Ray Dassen
 E: jdassen@wi.LeidenUniv.nl
-U: http://www.wi.leidenuniv.nl/~jdassen/
+W: http://www.wi.leidenuniv.nl/~jdassen/
 D: Debian GNU/Linux: www.debian.org maintainer, FAQ co-maintainer,
 D: packages testing, nit-picking & fixing. Enjoying BugFree (TM) kernels.
 S: Zuidsingel 10A
diff -u --recursive --new-file v1.3.46/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.46/linux/Documentation/Configure.help	Fri Nov 17 08:42:23 1995
+++ linux/Documentation/Configure.help	Tue Dec 12 13:16:57 1995
@@ -1,4 +1,4 @@
-# LAST EDIT: Fri Oct 27 23:03:01 1995 by Axel Boldt (boldt@math.ucsb.edu) 
+# LAST EDIT: Thu Nov 30 22:39:07 1995 by Axel Boldt (boldt@math.ucsb.edu) 
 #
 # This version of the Linux kernel configuration help texts
 # corresponds to the kernel versions 1.3.x. Be aware that these
@@ -9,7 +9,7 @@
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
-# via anonymous ftp from sunsite.unc.edu in the directory
+# via ftp (user: anonymous) from sunsite.unc.edu in the directory
 # /pub/Linux/docs/HOWTO. 
 #
 # Format: description<nl>variable<nl>helptext<nl><nl>. The help texts
@@ -21,10 +21,7 @@
 # All this was shamelessly stolen from several different sources. Many
 # thanks to all the contributors.  Feel free to use these help texts
 # in your own kernel configuration tools. The texts are copyrighted
-# (c) 1995 by Axel Boldt and governed by our beloved little Copyleft
-# virus, the GNU Public License. This essentially means that you can
-# do with them whatever you want unless you try to restrict someone
-# else's right to do whatever they want.
+# (c) 1995 by Axel Boldt and governed by the GNU Public License.
 #
 # Send comments to Axel Boldt <boldt@math.ucsb.edu>.
 
@@ -82,26 +79,26 @@
 Use old (reliable) disk-only driver for primary i/f
 CONFIG_BLK_DEV_HD
   As you might have guessed, there are now two drivers for IDE
-  harddrives around: the old reliable one and the new improved
-  one. The new driver can also handle IDE/ATAPI CDROM drives (ATAPI =
-  AT Attachment Packet Interface is a new protocol currently used for
-  controlling CDROM and tape drives, similar to the SCSI
-  protocol. Some newer CDROM drives such as NEC 260 and MITSUMI
-  triple/quad speed drives use it, but most MITSUMI CDROM drives
-  don't). The old driver supports up to two hard drives, while the new
-  one can deal with any mix of up to eight hard drives and IDE/ATAPI
-  CDROMs, two per IDE interface. Using the old driver makes sense if
-  you have older MFM/RLL/ESDI drives, since it is smaller and these
-  drives don't benefit from the additional features of the new
-  driver. If you have more than one IDE interface (=controller), you
-  can use the old driver on the first and the new one on the others,
-  if you like.  In that case (or if you have just one interface and
-  don't want to use the new driver at all) you would say Y here,
-  thereby enlarging your kernel by about 4 kB. If you want to use the
-  new driver exclusively, say N and answer Y to the following
-  question(s). Useful information about how to use large (>504MB) IDE
-  harddrives is contained in drivers/block/README.ide. If unsure, say
-  N.
+  harddrives around: the old one and the new improved one. The old one
+  is not any longer more reliable than the new one. The new driver can
+  also handle IDE/ATAPI CDROM drives (ATAPI = AT Attachment Packet
+  Interface is a new protocol currently used for controlling CDROM and
+  tape drives, similar to the SCSI protocol. Some newer CDROM drives
+  such as NEC 260 and MITSUMI triple/quad speed drives use it, but
+  most MITSUMI CDROM drives don't). The old driver supports up to two
+  hard drives, while the new one can deal with any mix of up to eight
+  hard drives and IDE/ATAPI CDROMs, two per IDE interface. Using the
+  old driver makes sense if you have older MFM/RLL/ESDI drives, since
+  it is smaller and these drives don't benefit from the additional
+  features of the new driver. If you have more than one IDE interface
+  (=controller), you can use the old driver on the first and the new
+  one on the others, if you like.  In that case (or if you have just
+  one interface and don't want to use the new driver at all) you would
+  say Y here, thereby enlarging your kernel by about 4 kB. If you want
+  to use the new driver exclusively, say N and answer Y to the
+  following question(s). Useful information about how to use large
+  (>504MB) IDE harddrives is contained in drivers/block/README.ide. If
+  unsure, say N.
 
 Use new IDE driver for primary/secondary i/f 
 CONFIG_BLK_DEV_IDE 
@@ -173,11 +170,11 @@
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
-  This is support for floppy drives on Sun workstations. But this
-  support does not exist at this time, so you might as well say N.
+  This is support for floppy drives on Sun Sparc workstations. Say Y
+  if you have a floppy drive, otherwise N. Easy.
 
 Alpha system type
-CONFIG_ALPHA_JENSEN
+CONFIG_ALPHA_AVANTI
   Find out what type of Alpha system you are running. If you can't
   find one of the given names, then try "Noname". For this question,
   it suffices to give a unique prefix of the option you want to
@@ -204,6 +201,19 @@
 ##### Don't know what this is about.
 #####
 
+Echo console messages on /dev/ttyS1
+CONFIG_SERIAL_ECHO
+  If you enable this option, all kernel messages that would usually go
+  to the console will also be sent to the device /dev/ttyS1 which
+  corresponds to a serial port; this could be useful if you attached
+  a terminal or printer to that port.
+
+TGA Console Support
+CONFIG_TGA_CONSOLE
+#####
+##### Has something to do with Alpha.
+#####
+
 PCI bios support
 CONFIG_PCI
   Find out whether you have a PCI motherboard. PCI is the name of a
@@ -216,12 +226,9 @@
   valuable information about which PCI hardware works under Linux and
   which doesn't.  If some of PCI devices don't work and you get a
   warning during boot time, please follow the instructions at the top of
-  include/linux/pci.h. Information regarding the buggy PCTech RZ 1000 IDE
-  harddrive controller which is used in some PCI systems is on the WWW
-  at http://www.powerquest.com/hardware.html. (To browse the WWW, you
-  need to have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic). The new IDE driver detects this
-  controller and works around this bug, though.
+  include/linux/pci.h. The buggy PCTech RZ 1000 IDE
+  harddrive controller which is used in some PCI systems is detected
+  and correctly handled by this driver.
 
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
@@ -241,17 +248,19 @@
 
 System V IPC
 CONFIG_SYSVIPC
-  InterProcessCommunication is a suite of library functions and system
+  Inter Process Communication is a suite of library functions and system
   calls which let processes (= running programs) synchronize and
   exchange information. It is generally considered to be a good thing,
-  and some programs won't run unless you enable this. You can find
-  documentation about IPC in ipc.info, which is contained in
-  sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (available via ftp,
-  user: anonymous; extract with "tar xzvf filename"). These docs
-  are in the info format which is used to document GNU software and
-  can be read from within emacs ("Ctrl-h i") or with the program info
-  ("man info"). Enabling this option enlarges your kernel by about
-  7kB. Just say Y.
+  and some programs won't run unless you enable this. In particular,
+  if you want to run the DOS emulator dosemu under Linux (read the
+  DOSEMU-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO), you'll need to say Y here. You
+  can find documentation about IPC in ipc.info, which is contained in
+  sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (extract with "tar
+  xzvf filename"). These docs are in the info format which is used to
+  document GNU software and can be read from within emacs ("Ctrl-h i")
+  or with the program info ("man info"). Enabling this option enlarges
+  your kernel by about 7kB. Just say Y.
 
 Kernel support for ELF binaries
 CONFIG_BINFMT_ELF
@@ -291,27 +300,13 @@
   kernel in ELF by saying Y here and editing the variables CC
   and LD in the toplevel Makefile.
 
-Use -m486 flag for 486-specific optimizations
+Use 486-specific optimizations (does NOT work on i386)
 CONFIG_M486
-  If you have a 486 as opposed to a 386 or Pentium CPU, say Y here:
+  If you have a 486 or better, as opposed to a 386, say Y here:
   things will be slightly faster. However, it is not required: the
-  kernel will run on all CPUs with and without this option. If you are
-  not sure, say Y; apart from enlarging your kernel by about 6 kB, it
-  won't hurt.
-
-SMP Kernel (experimental - gcc2.5.8 only: see Documentation/SMP.txt)
-CONFIG_SMP
-  This is experimental support for multiprocessor Pentium machines
-  that agree with the Intel MP v1.1 specification. It can deal with up
-  to 32 processors. You can only compile it with gcc version 2.5.8
-  ("gcc -v"). For details, see Documentation/SMP.ez in the kernel
-  source (this document has been formatted using the ez andrew word
-  processor, available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/X11/andrew/auis63L3-wp.tgz) and
-  http://www.linux.org.uk/SMP/title.html on the WWW (to browse the
-  WWW, you need to have access to a machine on the Internet that has
-  one of the programs lynx, netscape or Mosaic). Please back up all
-  your harddrives before using kernels compiled with this option.
+  kernel will run on all CPUs without this option. If you are
+  not sure, say N; This option will make the kernel use some
+  instructions that are only available on 486+ machines.
 
 Set version information on all symbols for modules
 CONFIG_MODVERSIONS
@@ -384,8 +379,11 @@
   tables, require that this option be compiled in. You also need
   multicasting if you intend to participate in the MBONE, a high
   bandwidth network on top of the internet which carries audio and
-  video broadcasts. Information about the multicast capabilities of
-  the various network cards is contained in
+  video broadcasts. More information about the MBONE is on the WWW at
+  http://www.best.com/~prince/techinfo/mbone.html (to browse the WWW,
+  you need to have access to a machine on the Internet that has one of
+  the programs lynx, netscape or Mosaic). Information about the
+  multicast capabilities of the various network cards is contained in
   drivers/net/README.multicast. For most people, it's safe to say N.
 
 IP: firewalling
@@ -399,13 +397,14 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will have to use
   the ipfw tool from the net-tools package, available via ftp (user:
   anonymous) from
-  ftp.linux.org.uk:/pub/linux/Networking/PROGRAMS/NetTools. It allows
-  selective blocking of internet traffic based on type, origin and
-  destination.  You need to enable IP firewalling in order to be able
-  to use IP masquerading (i.e. IP traffic from one of the local
-  computers and destined for an outside host is changed by your box so
-  that it appears to come from you). Chances are that you don't want
-  this, so say N.
+  ftp.linux.org.uk:/pub/linux/Networking/PROGRAMS/NetTools, or
+  preferably ipfwadm from ftp.xos.nl:/pub/linux/ipfwadm/. These
+  programs allow selective blocking of internet traffic based on type,
+  origin and destination.  You need to enable IP firewalling in order
+  to be able to use IP masquerading (i.e. IP traffic from one of the
+  local computers and destined for an outside host is changed by your
+  box so that it appears to come from you). Chances are that you don't
+  want this, so say N.
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -487,7 +486,7 @@
   Since you asked: if there are diskless machines on your network that
   know their hardware ethernet address but don't know their IP
   addresses upon startup, they send out a Reverse
-  AddressResolutionProtocol request to find out their own IP
+  Address Resolution Protocol request to find out their own IP
   addresses. If you want your Linux box to be able to *answer* such
   requests, say Y here; you'd use the program rarp ("man rarp"). If
   you want to compile this as a module ( = code which can be inserted
@@ -503,13 +502,21 @@
   links, between machines of your IP network, say N.  If in doubt, say
   Y.
 
+Disable Path MTU Discovery (normally enabled)
+CONFIG_NO_PATH_MTU_DISCOVERY
+  MTU (maximal transfer unit) is the size of the chunks we send out
+  over the net. "Path MTU Discovery" means that, instead of always
+  sending very small chunks, we start out sending big ones and if we
+  then discover that some host along the way likes its chunks smaller,
+  we adjust to a smaller size. This is good, so say N.
+
 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 packets from
-  telnet and rlogin 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
+  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.
 
 IP: Drop source routed frames
@@ -542,17 +549,19 @@
 
 The IPX protocol
 CONFIG_IPX
-  This is support for the Novell networking protocol. You need it if
-  you want to access Novell Netware servers from within the Linux DOS
-  emulator dosemu (read the DOSEMU-HOWTO, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO). It's very
-  limited and won't make your Linux box into a Novell server. It would
-  enlarge your kernel by about 5 kB. General information about how to
-  connect Linux, Windows machines and Macs is on the WWW at
-  http://eats.com/linux_mac_win.html (to browse the WWW, you need to
-  have access to a machine on the Internet that has one of the
-  programs lynx, netscape or Mosaic). Unless you have Novell computers
-  on your local network, say N.
+  This is support for the Novell networking protocol, IPX. You need it
+  if you want to access Novell Netware servers from within the Linux
+  DOS emulator dosemu (read the DOSEMU-HOWTO, available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO). To
+  turn your Linux box into a fully featured Netware file server and
+  IPX router, say Y here and fetch lwared from
+  sunsite.unc.edu:/pub/Linux/system/Networking/daemons/. General
+  information about how to connect Linux, Windows machines and Macs is
+  on the WWW at http://eats.com/linux_mac_win.html (to browse the WWW,
+  you need to have access to a machine on the Internet that has one of
+  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.
 
 Appletalk DDP
 CONFIG_ATALK
@@ -617,22 +626,22 @@
 
 Kernel/User network link driver(ALPHA)
 CONFIG_NETLINK
-  This driver will allow for two-way communication between certain
-  parts of the kernel or modules and user processes; the user
-  processes will be able to read from and write to special files in
-  the /dev directory having major mode 18. So far, the kernel uses it
-  to publish some network related information if you enable "Routing
+  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
+  publish some network related information if you enable "Routing
   messages", below. Say Y if you want to experiment with it; this is
   ALPHA code, which means that it need not be completely stable; it
   has nothing to do with the computer architecture of the same name.
 
 Routing messages
 CONFIG_RTNETLINK
-  If you enable this and create a special file with major number 18
-  and minor number 0 with mknod ("man mknod"), you can read some
-  network related information from that file. Everything you write to
-  that file will be discarded. Say Y, because otherwise the network
-  link driver is pointless.
+  If you enable this and create a character special file /dev/route
+  with major number 18 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.
 
 SCSI support?
 CONFIG_SCSI
@@ -752,7 +761,9 @@
   the documentation in drivers/scsi/README.BusLogic for more information.
   BusLogic FlashPoint SCSI Host Adapters are not supported by this driver.
   If this driver does not work correctly without modification, please
-  consult the author.  This driver is not currently available as a module.
+  consult the author. This driver is not currently available as a module.
+  You might want to read the SCSI-HOWTO, available via ftp (user: 
+  anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
  
 EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support
 CONFIG_SCSI_EATA_DMA
@@ -948,7 +959,9 @@
   handy, the default is Y. It won't enlarge your kernel either. What a
   deal.  If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt.
+  say M here and read Documentation/modules.txt. If you want to use
+  more than one dummy device at a time, you need to compile it as a
+  module. 
   
 SLIP (serial line) support
 CONFIG_SLIP
@@ -1334,10 +1347,14 @@
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the Intel
-  EtherExpress card is generally regarded to be a very poor choice and
-  the driver is not very reliable. If you want to compile this as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
+  EtherExpress16 card is generally regarded to be a very poor choice
+  and the driver is not very reliable. (Roger Wolff
+  (R.E.Wolff@et.tudelft.nl) is attempting to do something about
+  this. At the moment he could use 1) one or more etherexpress16 cards
+  to test locally 2) Alpha testers: people to try new versions of the
+  driver to see if things improve...)  If you want to compile this
+  driver as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want), say M here and read
   Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
@@ -1503,6 +1520,19 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+ICL EtherTeam 16i/32 support
+CONFIG_ETH16I
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
+  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.
+
 Zenith Z-Note support
 CONFIG_ZNET
   The Zenith Z-Note notebook computer has a built-in network
@@ -1517,9 +1547,6 @@
   port ("pocket adaptors"). If you have one of those, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
-#####
-##### What should you say to CONFIG_PRINTER in order to use these?
-#####
   one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
   available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you
   want to plug a network card into the PCMCIA slot of your laptop
@@ -1530,9 +1557,11 @@
   will just cause this configure script to skip all the questions
   about this class of network devices.  If you say Y, you will be
   asked for your specific device in the following questions.  If you
-  plan to use more than one network card under linux, read the
+  plan to use more than one network device 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 you intend to use an
+  adaptor attaching to the parallel port as well as a parallel
+  printer, you should compile both drivers as modules (if possible).
 
 AT-LAN-TEC/RealTek pocket adaptor support
 CONFIG_ATP
@@ -1542,7 +1571,9 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. 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 you intend to use
+  this driver, you should have said N to the Parallel Printer support,
+  because the two drivers don't like each other.
 
 D-Link DE600 pocket adaptor support
 CONFIG_DE600
@@ -1552,10 +1583,11 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this.  If
   you want to compile this as a module ( = code which can be inserted
   in and removed from the running kernel whenever you want), say M
-  here and read Documentation/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.
+  here and read Documentation/modules.txt. If you intend to use this
+  pocket adaptor as well as a parallel printer, you should compile
+  both drivers as modules. 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.
 
 D-Link DE620 pocket adaptor support
 CONFIG_DE620
@@ -1565,10 +1597,11 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this.  If
   you want to compile this as a module ( = code which can be inserted
   in and removed from the running kernel whenever you want), say M
-  here and read Documentation/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.
+  here and read Documentation/modules.txt. If you intend to use this
+  pocket adaptor as well as a parallel printer, you should compile
+  both drivers as modules. 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.
  
 Token Ring driver support
 CONFIG_TR
@@ -1673,17 +1706,17 @@
 
 Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support
 CONFIG_AZTCD
-  If you have a CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 CDROM
-  drive, say Y here and also to "ISO9660 cdrom filesystem support"
-  below. This is NOT for CDROM drives with IDE interface, such as
-  Aztech CDA269-031SE. (If you have one of those, you should have said
-  Y to the new IDE driver above.) You want to read
-  Documentation/cdrom/aztcd and include/linux/aztcd.h in the kernel
-  source and the CDROM-HOWTO, available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If unsure, say N.  If you
-  want to compile this as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt.
+  If you have a CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 or
+  Conrad TXC CDROM drive, say Y here and also to "ISO9660 cdrom
+  filesystem support" below. This is NOT for CDROM drives with IDE
+  interface, such as Aztech CDA269-031SE. (If you have one of those,
+  you should have said Y to the new IDE driver above.) You want to
+  read Documentation/cdrom/aztcd and include/linux/aztcd.h in the
+  kernel source and the CDROM-HOWTO, available via ftp (user:
+  anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. If unsure,
+  say N.  If you want to compile this as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt.
 
 Sony CDU535 CDROM driver support
 CONFIG_CDU535
@@ -1790,13 +1823,13 @@
 
 xiafs filesystem support
 CONFIG_XIA_FS
-  This filesystem (= method to organize files on a harddisk partition
-  or a floppy disk) is only used rarely these days. This option would
-  enlarge your kernel by about 28 kB. Say N.  If you want to compile
-  this as a module ( = code which can be inserted in and removed from
-  the running kernel whenever you want), say M here and read
-  Documentation/modules.txt. Note that the filesystem of your root
-  partition cannot be compiled as a module.
+  This is an old filesystem (= method to organize files on a harddisk
+  partition or a floppy disk) and not in use anymore. This option
+  would enlarge your kernel by about 28 kB. Let's all kill this beast:
+  say N.  If you want to compile this as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. Note that the
+  filesystem of your root partition cannot be compiled as a module.
 
 msdos fs support
 CONFIG_MSDOS_FS
@@ -1847,31 +1880,29 @@
   them. Also, you cannot read the files with less or more: you need to
   use cat. The filesystem is explained in the Kernel Hacker's Guide,
   available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/LDP.  This option will enlarge your
-  kernel by about 18 kB. It's totally cool; for example, "cat
-  /proc/interrupts" gives information about what the different IRQs
-  are used for at the moment (there is a small number of Interrupt
-  ReQuest lines in your computer that are used by the periphery to
-  gain the CPU's attention - often a source of trouble if two devices
-  are mistakenly configured to use the same IRQ). Several programs
-  depend on this, so everyone should say Y here.
+  sunsite.unc.edu:/pub/Linux/docs/LDP and also on the proc(8) manpage
+  ("man 8 proc").  This option will enlarge your kernel by about 18
+  kB. It's totally cool; for example, "cat /proc/interrupts" gives
+  information about what the different IRQs are used for at the moment
+  (there is a small number of Interrupt ReQuest lines in your computer
+  that are used by the periphery to gain the CPU's attention - often a
+  source of trouble if two devices are mistakenly configured to use
+  the same IRQ). Several programs depend on this, so everyone should
+  say Y here.
   
 NFS filesystem support
 CONFIG_NFS_FS
-  If you are connected to a network (using SLIP, PPP or ethernet, not
-  term [term is a program which gives you almost full Internet
-  connectivity if you have a regular dial up shell account on some
-  Internet connected Unix computer. Read the Term-HOWTO, available via
-  ftp (user: anonymous) on sunsite.unc.edu:/pub/Linux/docs/HOWTO]) and
-  want to mount files residing on another UNIX computer (the NFS
-  server) using the NetworkFileSharing protocol, say Y. "Mounting
-  files" means that the client can access the files with usual UNIX
-  commands as if they were sitting on the client's harddisk. For this
-  to work, the server must run the programs nfsd and mountd (but does
-  not need to have NFS filesystem support enabled). NFS is explained
-  in the Network Administrator's Guide, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/LDP, and on its man
-  page: "man nfs". There is also a NFS-FAQ in
+  If you are connected to some other (usually local) Unix computer
+  (using SLIP, PLIP, PPP or ethernet) and want to mount files
+  residing on that computer (the NFS server) using the Network
+  File Sharing protocol, say Y. "Mounting files" means that the client
+  can access the files with usual UNIX commands as if they were
+  sitting on the client's harddisk. For this to work, the server must
+  run the programs nfsd and mountd (but does not need to have NFS
+  filesystem support enabled). NFS is explained in the Network
+  Administrator's Guide, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/LDP, and on its man page: "man
+  nfs". There is also a NFS-FAQ in
   sunsite.unc.edu:/pub/Linux/docs/faqs which presumes that you know
   the basics of NFS already. If you say Y here, you should have said Y
   to TCP/IP networking also. This option would enlarge your kernel by
@@ -1881,6 +1912,18 @@
   here and read Documentation/modules.txt. If you don't know what all
   this is about, say N.
 
+Root file system on NFS
+CONFIG_ROOT_NFS
+  If you want your Linux box to mount its whole root filesystem from
+  some other computer over the net via NFS (presumably because your
+  box doesn't have a harddisk), say Y here. You will then have to
+  specify the directory that should be remotely mounted with the
+  "root" kernel command line option. See the documentation of your
+  boot loader (lilo or loadlin) about how to pass options to the
+  kernel. The lilo procedure is also explained in the SCSI-HOWTO,
+  available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) Most people say N here.
+
 ISO9660 cdrom filesystem support
 CONFIG_ISO9660_FS
   If you have a CDROM and want to do more with it than just listen to
@@ -1909,25 +1952,27 @@
 CONFIG_SYSV_FS
   SCO, Xenix and Coherent are commercial Unix systems for intel
   machines. Enabling this option would allow you to read and write to
-  and from their floppies and harddisk partitions. You need this if
-  you want to run iBCS2 (iBCS2 [Intel Binary Compatibility Standard]
-  is a kernel module which lets you run SCO, Xenix, Wyse, Unix Ware,
-  Dell Unix and System V programs under Linux and is often needed to
-  run commercial software, most prominently WordPerfect. It's in
-  tsx-11.mit.edu:/pub/linux/BETA). If you only intend to mount files
-  from some other Unix over the network using NFS, you don't need this
-  (but you need nfs filesystem support obviously). Note that this
-  option is generally not needed for floppies, since a good portable
-  way to transport files between unixes (and even to other operating
-  systems) is given by the tar program ("man tar").  Note also that
-  this option has nothing to do whatsoever with the option "System V
-  IPC". Read about the System V filesystem in
-  Documentation/filesystems/sysv-fs.txt. This option will enlarge your
-  kernel by about 34 kB. If you want to compile this as a module
-  ( = code which can be inserted in and removed from the running
-  kernel whenever you want), say M here and read
+  and from their floppies and harddisk partitions. If you have a
+  floppy or harddisk partition like that, it is probable that they
+  contain binaries from those other Unix systems; in order to run
+  these binaries, you will want to install iBCS2 (iBCS2 [Intel Binary
+  Compatibility Standard] is a kernel module which lets you run SCO,
+  Xenix, Wyse, Unix Ware, Dell Unix and System V programs under Linux
+  and is often needed to run commercial software, most prominently
+  WordPerfect. It's in tsx-11.mit.edu:/pub/linux/BETA). If you only
+  intend to mount files from some other Unix over the network using
+  NFS, you don't need this (but you need nfs filesystem support
+  obviously). Note that this option is generally not needed for
+  floppies, since a good portable way to transport files between
+  unixes (and even to other operating systems) is given by the tar
+  program ("man tar").  Note also that this option has nothing to do
+  whatsoever with the option "System V IPC". Read about the System V
+  filesystem in Documentation/filesystems/sysv-fs.txt. This option
+  will enlarge your kernel by about 34 kB. If you want to compile this
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
   Documentation/modules.txt. If you haven't heard about all of this
-  before, it's safe to say N.  
+  before, it's safe to say N.
 
 SMB filesystem (to mount WfW shares etc..) support
 CONFIG_SMB_FS
@@ -1947,14 +1992,17 @@
   the programs lynx, netscape or Mosaic).  If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
-  Documentation/modules.txt. Most people say N here.
+  Documentation/modules.txt. Most people say N, however.
 
 Cyclades async mux support
 CONFIG_CYCLADES
   This is a card which gives you many serial ports. You would need
   something like this to connect more than two modems to your linux
-  box, for instance in order to become a BBS. If you haven't heard
-  about it, it's safe to say N.
+  box, for instance in order to become a BBS. If you want to compile
+  this as a module ( = code which can be inserted in and removed from
+  the running kernel whenever you want), say M here and read
+  Documentation/modules.txt. If you haven't heard about it, it's safe
+  to say N.
 
 Stallion multiport serial support 
 CONFIG_STALDRV
@@ -1989,9 +2037,10 @@
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. If you intend to use PLIP (Parallel Line
   Internet Protocol is mainly used to create a mini network by
-  connecting the parallel ports of two local machines) and a parallel
-  printer, you should compile both as modules because the drivers
-  don't like each other.
+  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.
 
 Logitech busmouse support
 CONFIG_BUSMOUSE
@@ -2163,12 +2212,12 @@
 # LocalWords:  cdrom harddisk diskless netboot nfs xzvf ATAPI MB harddrives ide
 # LocalWords:  HD harddisks CDROMs IDECD NEC MITSUMI filesystem XT XD PCI bios
 # LocalWords:  ISA EISA Microchannel VESA BIOSes bussystem IPC SYSVIPC ipc Ctrl
-# LocalWords:  InterProcessCommunication BINFMT Linkable http ac uk jo html GCC
+# LocalWords:  BINFMT Linkable http ac uk jo html GCC Sparc AVANTI CABRIOLET EB
 # LocalWords:  netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP
 # LocalWords:  genksyms INET loopback gatewaying ethernet internet PPP ARP Arp
 # LocalWords:  howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip
 # LocalWords:  proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS
-# LocalWords:  telneting AddressResolutionProtocol subnetted NAGLE rlogin NOSR
+# LocalWords:  telneting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl
 # LocalWords:  Mb SKB IPX Novell Netware dosemu Appletalk DDP ATALK tapedrive
 # LocalWords:  SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA
 # LocalWords:  buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
@@ -2196,5 +2245,7 @@
 # LocalWords:  Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
 # LocalWords:  Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
 # LocalWords:  carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
-# LocalWords:  pppd Zilog ZS soundcards SRM bootloader SMP smp ez mainmenu rarp
-# LocalWords:  RTNETLINK mknod
+# LocalWords:  pppd Zilog ZS soundcards SRM bootloader ez mainmenu rarp ipfwadm
+# LocalWords:  RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
+# LocalWords:  dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
+# LocalWords:  ICL EtherTeam ETH IDESCSI TXC
diff -u --recursive --new-file v1.3.46/linux/Makefile linux/Makefile
--- v1.3.46/linux/Makefile	Mon Dec 11 15:41:59 1995
+++ linux/Makefile	Mon Dec 11 15:41:43 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 46
+SUBLEVEL = 47
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.46/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.46/linux/arch/i386/config.in	Mon Dec 11 15:42:00 1995
+++ linux/arch/i386/config.in	Tue Dec 12 13:14:26 1995
@@ -19,9 +19,9 @@
 if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
   bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
 fi
-#bool 'Use -mpentium flag for Pentium-specific optimizations' CONFIG_M586
+#bool 'Use Pentium-specific optimizations (does NOT work on i386)' CONFIG_M586
 #if [ "$CONFIG_M586" = "n" ]; then
-bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486
+bool 'Use 486-specific optimizations (does NOT work on i386)' CONFIG_M486
 #fi
 
 mainmenu_option next_comment
diff -u --recursive --new-file v1.3.46/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v1.3.46/linux/arch/i386/defconfig	Mon Dec 11 15:42:00 1995
+++ linux/arch/i386/defconfig	Tue Dec 12 07:43:08 1995
@@ -41,6 +41,7 @@
 # Networking options
 #
 # CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
 CONFIG_INET=y
 # CONFIG_IP_FORWARD is not set
 # CONFIG_IP_MULTICAST is not set
@@ -122,10 +123,6 @@
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_APM is not set
-# CONFIG_APM_IGNORE_USER_SUSPEND is not set
-# CONFIG_APM_DO_ENABLE is not set
-CONFIG_APM_CPU_IDLE=y
-# CONFIG_APM_DISPLAY_BLANK is not set
 
 #
 # Sound
diff -u --recursive --new-file v1.3.46/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.46/linux/drivers/char/Makefile	Mon Dec 11 15:42:02 1995
+++ linux/drivers/char/Makefile	Tue Dec 12 09:44:55 1995
@@ -19,7 +19,6 @@
 L_OBJS   := tty_io.o n_tty.o console.o keyboard.o serial.o \
 	tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
 	defkeymap.o consolemap.o selection.o
-SYMTAB_OBJS :=
 
 ifeq ($(CONFIG_CYCLADES),y)
 L_OBJS += cyclades.o
@@ -98,8 +97,7 @@
 endif
 
 ifdef CONFIG_APM
-L_OBJS += apm_bios.o
-SYMTAB_OBJS += apm_bios.o
+LX_OBJS += apm_bios.o
 endif
 
 ifdef M
diff -u --recursive --new-file v1.3.46/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.3.46/linux/drivers/char/tty_io.c	Tue Nov 21 13:22:10 1995
+++ linux/drivers/char/tty_io.c	Tue Dec 12 07:16:36 1995
@@ -41,6 +41,9 @@
  *
  * New TIOCLINUX variants added.
  *	-- mj@k332.feld.cvut.cz, 19-Nov-95
+ * 
+ * Restrict vt switching via ioctl()
+ *      -- grif@cs.ucr.edu, 5-Dec-95
  */
 
 #include <linux/config.h>
@@ -97,6 +100,7 @@
 int kmsg_redirect = 0;
 struct tty_struct * redirect = NULL;
 struct wait_queue * keypress_wait = NULL;
+char vt_dont_switch = 0;
 
 static void initialize_tty_struct(struct tty_struct *tty);
 
@@ -523,7 +527,7 @@
 {
 	unsigned char old_vc_mode;
 
-        if (new_console == fg_console)
+        if ((new_console == fg_console) || (vt_dont_switch))
                 return;
         if (!vc_cons_allocated(new_console))
                 return;
@@ -594,7 +598,7 @@
  */
 void change_console(unsigned int new_console)
 {
-        if (new_console == fg_console)
+        if ((new_console == fg_console) || (vt_dont_switch))
                 return;
         if (!vc_cons_allocated(new_console))
 		return;
diff -u --recursive --new-file v1.3.46/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v1.3.46/linux/drivers/char/vt.c	Wed Sep 27 15:59:58 1995
+++ linux/drivers/char/vt.c	Tue Dec 12 07:16:36 1995
@@ -5,6 +5,7 @@
  *
  *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
  *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
+ *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
  */
 
 #include <linux/types.h>
@@ -28,6 +29,7 @@
 #include "diacr.h"
 #include "selection.h"
 
+extern char vt_dont_switch;
 extern struct tty_driver console_driver;
 
 #define VT_IS_IN_USE(i)	(console_driver.table[i] && console_driver.table[i]->count)
@@ -1094,7 +1096,16 @@
 		  return i;
 		return con_get_unimap(ct, &(ud->entry_ct), list);
 	      }
- 
+	case VT_LOCKSWITCH:
+		if (!suser())
+		   return -EPERM;
+		vt_dont_switch = 1;
+		return 0;
+	case VT_UNLOCKSWITCH:
+		if (!suser())
+		   return -EPERM;
+		vt_dont_switch = 0;
+		return 0;
 	default:
 		return -ENOIOCTLCMD;
 	}
diff -u --recursive --new-file v1.3.46/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v1.3.46/linux/drivers/net/3c503.c	Fri Nov 17 08:42:25 1995
+++ linux/drivers/net/3c503.c	Mon Dec 11 15:41:12 1995
@@ -477,7 +477,12 @@
     unsigned long hdr_start = dev->mem_start + ((ring_page - EL2_MB1_START_PG)<<8);
 
     if (dev->mem_start) {       /* Use the shared memory. */
+#ifdef notdef
+	/* Officially this is what we are doing, but the readl() is faster */
 	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+#else
+	((unsigned int*)hdr)[0] = readl(hdr_start);
+#endif
 	return;
     }
 
diff -u --recursive --new-file v1.3.46/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v1.3.46/linux/drivers/net/8390.c	Mon Nov 27 12:48:30 1995
+++ linux/drivers/net/8390.c	Mon Dec 11 15:41:12 1995
@@ -32,8 +32,6 @@
   Much of this code should have been cleaned up, but every attempt 
   has broken some clone part.
   
-  Doesn't currently work on all shared memory cards.
-  
   Sources:
   The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
   */
@@ -512,8 +510,9 @@
 	if (rx_pkt_count > high_water_mark)
 		high_water_mark = rx_pkt_count;
 
-    /* Bug alert!  Reset ENISR_OVER to avoid spurious overruns! */
-    outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR);
+    /* We used to also ack ENISR_OVER here, but that would sometimes mask
+    a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
+    outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
     return;
 }
 
@@ -550,7 +549,7 @@
     /* Remove packets right away. */
     ei_receive(dev);
     
-    outb_p(0xff, e8390_base+EN0_ISR);
+    outb_p(ENISR_OVER, e8390_base+EN0_ISR);
     /* Generic 8390 insns to start up again, same as in open_8390(). */
     outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
     outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
diff -u --recursive --new-file v1.3.46/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v1.3.46/linux/drivers/net/arcnet.c	Mon Dec 11 15:42:02 1995
+++ linux/drivers/net/arcnet.c	Wed Dec 13 07:20:43 1995
@@ -17,6 +17,19 @@
          
 	**********************
 
+	v2.22 (95/12/08)
+	  - IRQ is always printed as a decimal, instead of a hex number.
+	  - Replaced most remaining printk's with BUGMSG macros.
+	  - Moved variables for VERIFY_ACK from the Outgoing struct into
+	    the lp struct; Outgoing is really for packet-splitting info
+	    only.
+	  - Simplified INTMASK handling using a memory variable to keep a
+	    "running total."
+	  - Tracked down more (maybe the last?) "missed IRQ" messages caused
+	    by TX-done IRQ's occurring WHILE arcnet??_send_packet was in
+	    progress.  These were pretty obscure and mostly harmless.
+	  - Made an actual non-ALPHA release of the thing.
+
 	v2.21 ALPHA (95/11/29)
 	  - "Unknown protocol ID" messages now also indicate the station
 	    which sent the unrecognized packet, to aid in debugging network
@@ -146,12 +159,15 @@
            mainly a portability fix.  This will confuse autoprobe a bit, so
            test that too.
          - What about cards with shared memory that can be "turned off?"
-         - NFS mount freezes after several megabytes to SOSS for DOS. 
- 	   unmount/remount fixes it.  Is this arcnet-specific?  I don't know.
+           (or that have none at all, like the SMC PC500longboard)
          - Some newer ARCnets support promiscuous mode, supposedly.  If
            someone sends me information, I'll try to implement it.
          - Dump Linux 1.2 support and its ugly #ifdefs.
          - Add support for the new 1.3.x IP header cache features.
+         - Support printk's priority levels.
+         - Make arcnetE_send_packet use arcnet_prepare_tx for loading the
+           packet into ARCnet memory.
+         - Move the SKB and memory dump code into separate functions.
          - ATA protocol support?? 
          - Banyan VINES TCP/IP support??
 
@@ -162,17 +178,17 @@
 	 	Donald Becker - it didn't work :)
 	 - skeleton.c v0.05 dated 11/16/93 by Donald Becker
 	 	(from Linux Kernel 1.1.45)
+	 - RFC's 1201 and 1051 - re: TCP/IP over ARCnet
 	 - The official ARCnet data sheets (!) thanks to Ken Cornetet
 		<kcornete@nyx10.cs.du.edu>
-	 - RFC's 1201 and 1051 - re: TCP/IP over ARCnet
-	 - net/inet/eth.c (from kernel 1.1.50) for header-building info...
+	 - net/inet/eth.c (from kernel 1.1.50) for header-building info.
 	 - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
 	 - Textual information and more alternate source from Joachim Koenig
 	 	<jojo@repas.de>
 */
 
 static const char *version =
- "arcnet.c: v2.21 ALPHA 95/11/29 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.22 95/12/08 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -368,6 +384,8 @@
 #define COMMAND (ioaddr+1)	/* writable, returns random vals on read (?) */
 #define RESET  (ioaddr+8)		/* software reset writable */
 
+#define SETMASK outb(lp->intmask,INTMASK);
+
 	/* Time needed for various things (in clock ticks, 1/100 sec) */
 	/* We mostly don't bother with these - watch out. */
 #define RESETtime 40		/* reset */
@@ -396,12 +414,6 @@
 #define RES2flag        0x40            /* unused */
 #define NORXflag        0x80            /* receiver inhibited */
 
-#ifdef DETECT_RECONFIGS
-	#define RECON_flag RECONflag
-#else
-	#define RECON_flag 0
-#endif
-
        /* in the command register, the following bits have these meanings:
         *                0-2     command
         *                3-4     page number (for enable rcv/xmt command)
@@ -530,26 +542,26 @@
 	      segnum,			/* segment being sent */
 	      numsegs,			/* number of segments */
 	      seglen;			/* length of segment */
-#ifdef VERIFY_ACK
-	short lastload_dest,		/* can last loaded packet be acked? */
-	      lasttrans_dest;		/* can last TX'd packet be acked? */
-#endif
-	
 };
 
 
 /* Information that needs to be kept for each board. */
 struct arcnet_local {
 	struct enet_statistics stats;
-	u_char arcnum;		/* arcnet number - our 8-bit address */
 	u_short sequence;	/* sequence number (incs with each packet) */
-	u_char recbuf,		/* receive buffer # (0 or 1) */
-	       txbuf,		/* transmit buffer # (2 or 3) */
-	       txready;		/* buffer where a packet is ready to send */
+	u_char stationid,	/* our 8-bit station address */
+		recbuf,		/* receive buffer # (0 or 1) */
+		txbuf,		/* transmit buffer # (2 or 3) */
+		txready,	/* buffer where a packet is ready to send */
+		intmask;	/* current value of INTMASK register */
 	short intx,		/* in TX routine? */
 	      in_txhandler,	/* in TX_IRQ handler? */
 	      sending;		/* transmit in progress? */
-	short tx_left;		/* segments of split packet left to TX */
+
+#ifdef VERIFY_ACK
+	short lastload_dest,		/* can last loaded packet be acked? */
+	      lasttrans_dest;		/* can last TX'd packet be acked? */
+#endif
 
 #if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
 	time_t first_recon,	/* time of "first" RECON message to count */
@@ -685,7 +697,7 @@
 
 	printk(version);
 	
-#if 1
+#if 0
 	BUGLVL(D_NORMAL)
 	{
 		printk("arcnet: ***\n");
@@ -696,7 +708,7 @@
 		printk("arcnet: ***\n");
 	}
 #else
-	BUGLVL(D_INIT)
+	BUGLVL(D_EXTRA)
 	{
 		printk("arcnet: ***\n");
 		printk("arcnet: * Read README.arcnet for important release notes!\n");
@@ -707,7 +719,7 @@
 	}
 #endif
 
-	BUGMSG(D_INIT,"given: base %lXh, IRQ %Xh, shmem %lXh\n",
+	BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
 			dev->base_addr,dev->irq,dev->mem_start);
 
 #ifndef MODULE
@@ -758,11 +770,9 @@
 	if (!dev->base_addr || !dev->irq || !dev->mem_start 
 		|| !dev->rmem_start)
 	{
-		printk("%6s: loadable modules can't autoprobe!\n",dev->name);
-		printk("%6s:  try using io=, irqnum=, and shmem= on the insmod line.\n",
-			dev->name);
-		printk("%6s:  you may also need num= to change the device name. (ie. num=1 for arc1)\n",
-			dev->name);
+		BUGMSG(D_NORMAL,"loadable modules can't autoprobe!\n");
+		BUGMSG(D_NORMAL,"try using io=, irqnum=, and shmem= on the insmod line.\n");
+		BUGMSG(D_NORMAL,"you may also need num= to change the device name. (ie. num=1 for arc1)\n");
 		return ENODEV;
 	}
 #endif
@@ -771,8 +781,8 @@
 		int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
 			"arcnet");
 		if (irqval) {
-			printk("%6s: unable to get IRQ %d (irqval=%d).\n",
-				dev->name,dev->irq, irqval);
+			BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
+				dev->irq, irqval);
 			return EAGAIN;
 		}
 		
@@ -782,8 +792,8 @@
 	/* Grab the region so we can find another board if autoIRQ fails. */
 	request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
 	
-	printk("%6s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
-		dev->name, dev->base_addr, dev->irq, dev->mem_start);
+	BUGMSG(D_NORMAL,"ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", 
+		dev->base_addr, dev->irq, dev->mem_start);
 
 	/* Initialize the device structure. */
 	dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
@@ -819,14 +829,12 @@
 	arcnet_reset(dev);
 	JIFFER(50);
 	BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
-			lp->arcnum,lp->arcnum);
-	if (lp->arcnum==0)
-		printk("%6s: WARNING!  Station address 0 is reserved for broadcasts!\n",
-			dev->name);
-	if (lp->arcnum==255)
-		printk("%6s: WARNING!  Station address 255 may confuse DOS networking programs!\n",
-			dev->name);
-	dev->dev_addr[0]=lp->arcnum;
+			lp->stationid,lp->stationid);
+	if (lp->stationid==0)
+		BUGMSG(D_NORMAL,"WARNING!  Station address 0 is reserved for broadcasts!\n");
+	if (lp->stationid==255)
+		BUGMSG(D_NORMAL,"WARNING!  Station address 255 may confuse DOS networking programs!\n");
+	dev->dev_addr[0]=lp->stationid;
 	lp->sequence=1;
 	lp->recbuf=0;
 
@@ -907,9 +915,6 @@
 	/* if we do this, we're sure to get an IRQ since the card has
 	 * just reset and the NORXflag is on until we tell it to start
 	 * receiving.
-	 *
-	 * However, this could, theoretically, cause a lockup.  Maybe I'm just
-	 * not very good at theory! :)
 	 */
 	outb(NORXflag,INTMASK);
 	JIFFER(RESETtime);
@@ -919,8 +924,8 @@
 	outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
 
 	airq = autoirq_report(0);
-	BUGLVL(D_INIT) if (airq)
-		printk("%6s:  autoirq is %d\n", dev->name, airq);
+	if (airq)
+		BUGMSG(D_INIT," autoirq is %d\n", airq);
 
 	/* if there was no autoirq AND the user hasn't set any defaults,
 	 * give up.
@@ -1014,7 +1019,8 @@
 	int delayval,recbuf=lp->recbuf;
 	u_char *cardmem;
 	
-	outb(0,INTMASK);	/* no IRQ's, please! */
+	lp->intmask=0;
+	SETMASK;		/* no IRQ's, please! */
 	
 	BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
 			dev->name,inb(STATUS));
@@ -1034,7 +1040,7 @@
 		BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n");
 		return 1;
 	}
-	lp->arcnum=cardmem[1];  /* save address for later use */
+	lp->stationid=cardmem[1];  /* save address for later use */
 	
 	/* clear out status variables */
 	recbuf=lp->recbuf=0;
@@ -1051,7 +1057,11 @@
 	EnableReceiver();
 
 	/* re-enable interrupts */
-	outb(NORXflag|RECON_flag,INTMASK);
+	lp->intmask|=NORXflag;
+#ifdef DETECT_RECONFIGS
+	lp->intmask|=RECONflag;
+#endif
+	SETMASK;
 	
 	/* done!  return success. */
 	return 0;
@@ -1094,7 +1104,7 @@
 
 	ether_setup(dev); /* we're emulating ether here, not ARCnet */
 	dev->dev_addr[0]=0;
-	dev->dev_addr[5]=lp->arcnum;
+	dev->dev_addr[5]=lp->stationid;
 	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1;
 	dev->open=NULL;
 	dev->stop=NULL;
@@ -1114,7 +1124,7 @@
 	arcnet_setup(dev);
        
 	/* And now fill particular fields with arcnet values */
-	dev->dev_addr[0]=lp->arcnum;
+	dev->dev_addr[0]=lp->stationid;
 	dev->hard_header_len=sizeof(struct S_ClientData);
 	dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len
 		+ S_EXTRA_CLIENTDATA;
@@ -1204,11 +1214,11 @@
 	
 	/* make sure we're ready to receive IRQ's.
 	 * arcnet_reset sets this for us, but if we receive one before
-	 * START is set to 1, bad things happen.
+	 * START is set to 1, it could be ignored.
 	 */
 	outb(0,INTMASK);
 	JIFFER(ACKtime);
-	outb(NORXflag|RECON_flag,INTMASK);
+	SETMASK;
 	
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -1227,7 +1237,8 @@
 	START=0;
 
 	/* Flush TX and disable RX */
-	outb(0,INTMASK);	/* no IRQ's (except RESET, of course) */
+	lp->intmask=0;
+	SETMASK;	/* no IRQ's (except RESET, of course) */
 	outb(NOTXcmd,COMMAND);  /* stop transmit */
 	outb(NORXcmd,COMMAND);	/* disable receive */
 	
@@ -1309,20 +1320,21 @@
 			return 1;
 		}
 
-		outb(0,INTMASK);
-
+		lp->intmask &= ~TXFREEflag;
+		SETMASK;
+		
 		if (status&TXFREEflag)	/* transmit _DID_ finish */
 		{
-			BUGMSG(D_EXTRA,"tx timed out - missed IRQ? (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
-					status,lp->intx,
-					lp->in_txhandler,tickssofar);
+			BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, inTXh=%d, ticks=%d, mask=%Xh)\n",
+					status,lp->in_txhandler,tickssofar,
+					lp->intmask);
 			lp->stats.tx_errors++;
 		}
 		else
 		{
-			BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
-					status,lp->intx,
-					lp->in_txhandler,tickssofar);
+			BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTXh=%d, tickssofar=%d, intmask=%Xh)\n",
+					status,lp->in_txhandler,tickssofar,
+					lp->intmask);
 			lp->stats.tx_errors++;
 			lp->stats.tx_aborted_errors++;
 
@@ -1340,8 +1352,6 @@
 		lp->txready=0;
 		lp->sending=0;
 
-		outb(NORXflag|RECON_flag,INTMASK);
-
 		return 1;
 	}
 
@@ -1349,8 +1359,8 @@
 	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
 	   itself. */
 	if (skb == NULL) {
-		printk("%6s: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-			dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start);
+		BUGMSG(D_NORMAL,"tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
+			inb(STATUS),lp->intx,jiffies-dev->trans_start);
 		lp->stats.tx_errors++;
 		dev_tint(dev);
 		return 0;
@@ -1358,9 +1368,10 @@
 	
 	if (lp->txready)	/* transmit already in progress! */
 	{
-		printk("%6s: trying to start new packet while busy! (status=%Xh)\n",
-			dev->name,inb(STATUS));
-		outb(0,INTMASK);
+		BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n",
+			inb(STATUS));
+		lp->intmask &= ~TXFREEflag;
+		SETMASK;
 		outb(NOTXcmd,COMMAND); /* abort current send */
 		arcnet_inthandler(dev); /* fake an interrupt */
 		lp->stats.tx_errors++;
@@ -1374,8 +1385,8 @@
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
         if (set_bit(0, (void*)&dev->tbusy) != 0)
         {
-            printk("%6s: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
-            		dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start);
+            BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
+            		inb(STATUS),lp->intx,jiffies-dev->trans_start);
             lp->stats.tx_errors++;
             lp->stats.tx_fifo_errors++;
             return -EBUSY;
@@ -1394,9 +1405,6 @@
 	int ioaddr=dev->base_addr,bad;
 	struct Outgoing *out=&(lp->outgoing);
 
-	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
-			inb(STATUS),lp->intx);
-
 	lp->intx++;
 	
 	bad=arcnet_send_packet_bad(skb,dev);
@@ -1407,7 +1415,7 @@
 	}
 	
 	TBUSY=1;
-		
+	
 	out->length = 1 < skb->len ? skb->len : 1;
 	out->hdr=(struct ClientData*)skb->data;
 	out->skb=skb;
@@ -1415,9 +1423,9 @@
 	BUGLVL(D_SKB)
 	{
 		short i;
-		for( i=0; i< skb->len; i++)
+		for(i=0; i<skb->len; i++)
 		{
-			if( i%16 == 0 ) printk("\n[%04hX] ",i);
+			if(i%16 == 0) printk("\n[%04hX] ",i);
 			printk("%02hX ",((unsigned char*)skb->data)[i]);
 		}
 		printk("\n");
@@ -1425,16 +1433,14 @@
 
 	out->hdr->sequence=(lp->sequence++);
 	
-	/*arcnet_go_tx(dev);*/	/* Make sure buffers are clear */
-
 	/* fits in one packet? */
 	if (out->length-EXTRA_CLIENTDATA<=XMTU)
 	{
 		BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n",
 				out->length,out->hdr->split_flag);
-		BUGLVL(D_EXTRA) if (out->hdr->split_flag)
-			printk("%6s: short packet has split_flag set?! (split_flag=%d)\n",
-				dev->name,out->hdr->split_flag);
+		if (out->hdr->split_flag)
+			BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n",
+				out->hdr->split_flag);
 		out->numsegs=1;
 		out->segnum=1;
 		arcnetAS_prepare_tx(dev,
@@ -1463,9 +1469,8 @@
 				+ sizeof(struct ClientData);
 		out->dataleft=out->length-sizeof(struct ClientData);
 		out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
-				
 		out->segnum=0;
-			
+		
 		BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
 			out->length,out->numsegs);
 
@@ -1500,6 +1505,11 @@
 
 	dev->trans_start=jiffies;
 	lp->intx--;
+	
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
 	return 0;
 }
 
@@ -1510,14 +1520,12 @@
 arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int bad;
+	int ioaddr=dev->base_addr,bad;
 	union ArcPacket *arcpacket = 
 		(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
 	u_char *arcsoft,daddr;
 	short offset,length=skb->len+1;
 
-	BUGMSG(D_DURING,"in arcnetE_send_packet (skb=%p)\n",skb);
-		
 	lp->intx++;
 	
 	bad=arcnet_send_packet_bad(skb,dev);
@@ -1531,11 +1539,12 @@
 		
 	if (length>XMTU)
 	{
-		printk("%6s: MTU must be <= 493 for ethernet encap (length=%d).\n",
-			dev->name,length);
-		printk("%6s: transmit aborted.\n",dev->name);
+		BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
+			length);
+		BUGMSG(D_NORMAL,"transmit aborted.\n");
 
 		dev_kfree_skb(skb,FREE_WRITE);
+		lp->intx--;
 		return 0;
 	}
 		
@@ -1603,7 +1612,7 @@
 	}
 
 #ifdef VERIFY_ACK
-	lp->outgoing.lastload_dest=daddr;
+	lp->lastload_dest=daddr;
 #endif
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
 
@@ -1618,6 +1627,11 @@
 
 	dev->trans_start=jiffies;
 	lp->intx--;
+	
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
 	return 0;
 }
 
@@ -1633,9 +1647,6 @@
 
 	lp->intx++;
 	
-	BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
-			inb(STATUS),lp->intx);
-
 	bad=arcnet_send_packet_bad(skb,dev);
 	if (bad)
 	{
@@ -1652,15 +1663,12 @@
 		short i;
 		for(i=0; i<skb->len; i++)
 		{
-			if( i%16 == 0 ) printk("\n[%04hX] ",i);
+			if (i%16 == 0) printk("\n[%04hX] ",i);
 			printk("%02hX ",((unsigned char*)skb->data)[i]);
 		}
 		printk("\n");
 	}
 
-	/*if (lp->txready && inb(STATUS)&TXFREEflag)
-		arcnet_go_tx(dev);*/
-
 	/* fits in one packet? */
 	if (length-S_EXTRA_CLIENTDATA<=XMTU)
 	{
@@ -1683,7 +1691,7 @@
 	}
 	else			/* too big for one - not accepted */
 	{
-		printk("arcnetS: packet too long (length=%d)\n",
+		BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
 			length);
 		dev_kfree_skb(skb,FREE_WRITE);
 		lp->stats.tx_dropped++;
@@ -1693,6 +1701,11 @@
 
 	dev->trans_start=jiffies;
 	lp->intx--;
+
+	/* make sure we didn't ignore a TX IRQ while we were in here */
+	lp->intmask |= TXFREEflag;
+	SETMASK;
+
 	return 0;
 }
 
@@ -1704,20 +1717,22 @@
 static void arcnetA_continue_tx(struct device *dev)
 {
 	struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-	int maxsegsize=XMTU-4;
+	int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
 	struct Outgoing *out=&(lp->outgoing);
 	
+	BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
+		inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
+	
 	if (lp->txready)
 	{
-		printk("%6s: continue_tx: called with packet in buffer!\n",
-			dev->name);
+		BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
 		return;
 	}
-
+	
 	if (out->segnum>=out->numsegs)
 	{
-		printk("%6s: continue_tx: building segment %d of %d!\n",
-			dev->name,out->segnum+1,out->numsegs);
+		BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
+			out->segnum+1,out->numsegs);
 	}
 
 	if (!out->segnum)	/* first packet */
@@ -1840,13 +1855,20 @@
 	}
 
 #ifdef VERIFY_ACK
-	lp->outgoing.lastload_dest=daddr;
+	lp->lastload_dest=daddr;
 #endif
 	lp->txready=lp->txbuf;	/* packet is ready for sending */
 }
 
 /* Actually start transmitting a packet that was placed in the card's
  * buffer by arcnetAS_prepare_tx.  Returns 1 if a Tx is really started.
+ *
+ * This should probably always be called with the INTMASK register set to 0,
+ * so go_tx is not called recursively.
+ *
+ * The enable_irq flag determines whether to actually write INTMASK value
+ * to the card; TXFREEflag is always OR'ed into the memory variable either
+ * way.
  */
 static int
 arcnet_go_tx(struct device *dev,int enable_irq)
@@ -1854,19 +1876,15 @@
 	struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
 	int ioaddr=dev->base_addr;
 
-	BUGMSG(D_DURING,"go_tx: status=%Xh\n",
-			inb(STATUS));
-			
-	outb(0,INTMASK);
+	BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n",
+		inb(STATUS),lp->intmask,lp->txready,lp->sending);
 
 	if (lp->sending || !lp->txready)
 	{
-		if (enable_irq)
+		if (enable_irq && lp->sending)
 		{
-			if (lp->sending)
-				outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
-			else
-				outb(NORXflag|RECON_flag,INTMASK);
+			lp->intmask |= TXFREEflag;
+			SETMASK;
 		}
 		return 0;
 	}
@@ -1879,12 +1897,13 @@
 	lp->sending++;
 
 #ifdef VERIFY_ACK	
-	lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
-	lp->outgoing.lastload_dest=0;
+	lp->lasttrans_dest=lp->lastload_dest;
+	lp->lastload_dest=0;
 #endif
 
-	if (enable_irq)
-		outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
+	lp->intmask |= TXFREEflag;
+
+	if (enable_irq)	SETMASK;
 
 	return 1;
 }
@@ -1933,38 +1952,21 @@
 
 	if (IF_INTERRUPT)
 	{
-		printk("%6s: DRIVER PROBLEM!  Nested arcnet interrupts!\n",
-			dev->name);
+		BUGMSG(D_NORMAL,"DRIVER PROBLEM!  Nested arcnet interrupts!\n");
 		return;	/* don't even try. */
 	}
+	
 	outb(0,INTMASK);
 	INTERRUPT = 1;
 
-	BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh)\n",inb(STATUS));
+	BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
+		inb(STATUS),lp->intmask);
 
-#if 1 /* Whatever you do, don't set this to 0. */
 	do
 	{
 		status = inb(STATUS);
 		didsomething=0;
 	
-#if 0 /* no longer necessary - doing checking in arcnet_interrupt now */
-		if (!dev->start)
-		{
-			BUGMSG(D_DURING,"ARCnet not yet initialized.  irq ignored. (status=%Xh)\n",
-					status);
-			if (!(status&NORXflag))
-				outb(NORXflag|RECON_flag,INTMASK);
-
-			/* using dev->interrupt here instead of INTERRUPT
-			 * because if dev->start is 0, the other devices
-			 * probably do not exist.
-			 */
-			dev->interrupt=0;
-			return;
-		}
-#endif
-	
 		/* RESET flag was enabled - card is resetting and if RX
 		 * is disabled, it's NOT because we just got a packet.
 		 */
@@ -1975,7 +1977,7 @@
 					status);
 		}
 #ifdef DETECT_RECONFIGS
-		if (status & RECONflag)
+		if (status & (lp->intmask) & RECONflag)
 		{
 			outb(CFLAGScmd|CONFIGclear,COMMAND);
 			lp->stats.tx_carrier_errors++;
@@ -1991,8 +1993,7 @@
 				jiffies-lp->last_recon > HZ*10)
 			{
 				if (lp->network_down)
-					printk("%6s: reconfiguration detected: cabling restored?\n",
-						dev->name);
+					BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
 				lp->first_recon=lp->last_recon=jiffies;
 				lp->num_recons=lp->network_down=0;
 				
@@ -2020,8 +2021,7 @@
 				    && lp->num_recons >= RECON_THRESHOLD)
 				{
 					lp->network_down=1;
-					printk("%6s: many reconfigurations detected: cabling problem?\n",
-						dev->name);
+					BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
 				}
 				else if (!lp->network_down
 				    && lp->last_recon-lp->first_recon > HZ*60)
@@ -2039,7 +2039,7 @@
 		else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
 		{
 			if (lp->network_down)
-				printk("%6s: cabling restored?\n",dev->name);
+				BUGMSG(D_NORMAL,"cabling restored?\n");
 			lp->first_recon=lp->last_recon=0;
 			lp->num_recons=lp->network_down=0;
 			
@@ -2049,7 +2049,7 @@
 #endif /* DETECT_RECONFIGS */
 
 		/* RX is inhibited - we must have received something. */
-		if (status & NORXflag)
+		if (status & lp->intmask & NORXflag)
 		{
 			int recbuf=lp->recbuf=!lp->recbuf;
 
@@ -2065,24 +2065,27 @@
 		}
 		
 		/* it can only be an xmit-done irq if we're xmitting :) */
-		if (status&TXFREEflag && !lp->in_txhandler && lp->sending)
+		/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
+		if (status & lp->intmask & TXFREEflag)
 		{
 			struct Outgoing *out=&(lp->outgoing);
+			int was_sending=lp->sending;
 			
+			lp->intmask &= ~TXFREEflag;
+
 			lp->in_txhandler++;
-			lp->sending--;
-			
+			if (was_sending) lp->sending--;
+
 			BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
 					status,out->numsegs,out->segnum,out->skb);
 					
 #ifdef VERIFY_ACK
-			if (!(status&TXACKflag))
+			if (was_sending && !(status&TXACKflag))
 			{
-				if (lp->outgoing.lasttrans_dest != 0)
+				if (lp->lasttrans_dest != 0)
 				{
-					printk("%6s: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
-						dev->name,status,
-						lp->outgoing.lasttrans_dest);
+					BUGMSG(D_NORMAL,"transmit was not acknowledged! (status=%Xh, dest=%d)\n",
+						status,lp->lasttrans_dest);
 					lp->stats.tx_errors++;
 					lp->stats.tx_carrier_errors++;
 				}
@@ -2090,7 +2093,7 @@
 				{
 					BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
 							status,
-							lp->outgoing.lasttrans_dest);
+							lp->lasttrans_dest);
 				}
 			}
 #endif
@@ -2100,6 +2103,8 @@
 			
 			if (lp->intx)
 			{
+				BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
+					inb(STATUS),lp->intx);
 				lp->in_txhandler--;
 				continue;
 			}
@@ -2114,7 +2119,6 @@
 					TBUSY=0;
 					mark_bh(NET_BH);
 				}
-				
 				lp->in_txhandler--;
 				continue;
 			}
@@ -2145,7 +2149,7 @@
 				}
 			}
 			didsomething++;
-			
+
 			lp->in_txhandler--;
 		}
 		else if (lp->txready && !lp->sending && !lp->intx)
@@ -2160,17 +2164,7 @@
 	BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
 			inb(STATUS),boguscount);
 
-	if (dev->start && (lp->sending || (lp->txready && !lp->intx)))
-		outb(NORXflag|TXFREEflag|RECON_flag,INTMASK);
-	else
-		outb(NORXflag|RECON_flag,INTMASK);
-
-#else /* Disable everything */
-
-	outb(RXcmd|(0<<3)|RXbcasts,COMMAND);
-	outb(NORXflag,INTMASK);
-
-#endif
+	SETMASK;	/* put back interrupt mask */
 
 	INTERRUPT=0;
 }
@@ -2206,8 +2200,8 @@
 	/* if source is 0, it's a "used" packet! */
 	if (saddr==0)
 	{
-		printk("%6s: discarding old packet. (status=%Xh)\n",
-			dev->name,inb(STATUS));
+		BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
+			inb(STATUS));
 		lp->stats.rx_errors++;
 		return;
 	}
@@ -2249,8 +2243,8 @@
 		break;
 	case ARC_P_LANSOFT: /* don't understand.  fall through. */
 	default:
-		printk("%6s: received unknown protocol %d (%Xh) from station %d.\n",
-			dev->name,arcsoft[0],arcsoft[0],saddr);
+		BUGMSG(D_NORMAL,"received unknown protocol %d (%Xh) from station %d.\n",
+			arcsoft[0],arcsoft[0],saddr);
 		lp->stats.rx_errors++;
 		lp->stats.rx_crc_errors++;
 		break;
@@ -2324,7 +2318,7 @@
 			
 		if (in->skb)	/* already assembling one! */
         	{
-        		BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
+        		BUGMSG(D_NORMAL,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
         			in->sequence,arcsoft->split_flag,
         			arcsoft->sequence);
         		kfree_skb(in->skb,FREE_WRITE);
@@ -2337,8 +2331,7 @@
 
          	skb = alloc_skb(length, GFP_ATOMIC);
          	if (skb == NULL) {
-         		printk("%6s: Memory squeeze, dropping packet.\n",
-         			dev->name);
+         		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
          		lp->stats.rx_dropped++;
          		return;
          	}
@@ -2383,8 +2376,8 @@
          		}
          		else
          		{
-         			printk("%6s: funny-shaped ARP packet. (%Xh, %Xh)\n",
-         				dev->name,arp->ar_hln,arp->ar_pln);
+         			BUGMSG(D_NORMAL,"funny-shaped ARP packet. (%Xh, %Xh)\n",
+         				arp->ar_hln,arp->ar_pln);
          			lp->stats.rx_errors++;
          			lp->stats.rx_crc_errors++;
          		}
@@ -2393,7 +2386,7 @@
 		BUGLVL(D_SKB)
 		{
 	            short i;
-	               	for( i=0; i< skb->len; i++)
+	               	for(i=0; i< skb->len; i++)
                		{
                        		if( i%16 == 0 ) printk("\n[%04hX] ",i);
                        		printk("%02hX ",((unsigned char*)skb->data)[i]);
@@ -2433,8 +2426,8 @@
 
 		if (in->skb && in->sequence!=arcsoft->sequence)
 		{
-			BUGMSG(D_EXTRA,"wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",	
-				in->sequence,arcsoft->sequence,
+			BUGMSG(D_NORMAL,"wrong seq number, aborting assembly (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
+				saddr,in->sequence,arcsoft->sequence,
 				arcsoft->split_flag);
 	        	kfree_skb(in->skb,FREE_WRITE);
 	        	in->skb=NULL;
@@ -2449,7 +2442,7 @@
 	        		arcsoft->split_flag);
 	        	if (in->skb)	/* already assembling one! */
 	        	{
-	        		BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
+	        		BUGMSG(D_NORMAL,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
 	        			in->sequence,arcsoft->split_flag,
 	        			arcsoft->sequence);
 				lp->stats.rx_errors++;
@@ -2463,7 +2456,7 @@
 	        	
 	        	if (in->numpackets>16)
 	        	{
-	        		BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
+	        		BUGMSG(D_NORMAL,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
 	        			arcsoft->split_flag);
 	        		lp->stats.rx_errors++;
 	        		lp->stats.rx_length_errors++;
@@ -2474,8 +2467,7 @@
                 			+ sizeof(struct ClientData),
 	                		GFP_ATOMIC);
                 	if (skb == NULL) {
-                		printk("%6s: (split) memory squeeze, dropping packet.\n", 
-                			dev->name);
+                		BUGMSG(D_NORMAL,"(split) memory squeeze, dropping packet.\n");
                 		lp->stats.rx_dropped++;
                 		return;
                 	}
@@ -2504,7 +2496,7 @@
 			 */			
 			if (!in->skb)
 			{
-				BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n",
+				BUGMSG(D_NORMAL,"can't continue split without starting first! (splitflag=%d, seq=%d)\n",
 					arcsoft->split_flag,arcsoft->sequence);
 				lp->stats.rx_errors++;
 				lp->stats.rx_missed_errors++;
@@ -2517,7 +2509,7 @@
 				/* harmless duplicate? ignore. */
 				if (packetnum<=in->lastpacket-1)
 				{
-					BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n",
+					BUGMSG(D_NORMAL,"duplicate splitpacket ignored! (splitflag=%d)\n",
 						arcsoft->split_flag);
 					lp->stats.rx_errors++;
 					lp->stats.rx_frame_errors++;
@@ -2525,7 +2517,7 @@
 				}
 				
 				/* "bad" duplicate, kill reassembly */
-				BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",	
+				BUGMSG(D_NORMAL,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",	
 					in->sequence,arcsoft->split_flag,
 					arcsoft->sequence);
 	        		kfree_skb(in->skb,FREE_WRITE);
@@ -2555,8 +2547,8 @@
          	{
          		if (!skb || !in->skb)
          		{
-         			printk("%6s: ?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
-         				dev->name,skb,in->skb);
+         			BUGMSG(D_NORMAL,"?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
+         				skb,in->skb);
          		}
          		else
          		{
@@ -2565,7 +2557,7 @@
 			
 				BUGLVL(D_SKB)
 				{
-		        	    short i;
+					short i;
 		        	       	for(i=0; i<skb->len; i++)
                				{
                 		       		if( i%16 == 0 ) printk("\n[%04hX] ",i);
@@ -2600,7 +2592,7 @@
 
        	skb = alloc_skb(length, GFP_ATOMIC);
        	if (skb == NULL) {
-       		printk("%6s: Memory squeeze, dropping packet.\n",dev->name);
+       		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
        		lp->stats.rx_dropped++;
        		return;
        	}
@@ -2653,7 +2645,7 @@
 
          	skb = alloc_skb(length, GFP_ATOMIC);
          	if (skb == NULL) {
-         		printk("arcnetS: Memory squeeze, dropping packet.\n");
+         		BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
          		lp->stats.rx_dropped++;
          		return;
          	}
@@ -2780,8 +2772,8 @@
 		head->protocol_id=ARC_P_ATALK;
 		break;
 	default:
-		printk("%6s: I don't understand protocol %d (%Xh)\n",
-			dev->name,type,type);
+		BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
+			type,type);
 		lp->stats.tx_errors++;
 		lp->stats.tx_aborted_errors++;
 		return 0;
@@ -2850,7 +2842,7 @@
 		BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n");
 		break;
 	default:
-		printk("arcnetS: I don't understand protocol %d (%Xh)\n",
+		BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
 			type,type);
 		lp->stats.tx_errors++;
 		lp->stats.tx_aborted_errors++;
@@ -2901,8 +2893,8 @@
 	 
 	if(head->protocol_id != ARC_P_IP) 
 	{
-		printk("%6s: I don't understand protocol type %d (%Xh) addresses!\n",
-			dev->name,head->protocol_id,head->protocol_id);
+		BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
+			head->protocol_id,head->protocol_id);
 		lp->stats.tx_errors++;
 		lp->stats.tx_aborted_errors++;
 		head->daddr=0;
@@ -2938,7 +2930,7 @@
 	 
 	if(head->protocol_id != ARC_P_IP_RFC1051) 
 	{
-		printk("arcnetS: I don't understand protocol type %d (%Xh) addresses!\n",
+		BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
 			head->protocol_id,head->protocol_id);
 		lp->stats.tx_errors++;
 		lp->stats.tx_aborted_errors++;
@@ -2996,7 +2988,7 @@
 	case ARC_P_NOVELL_EC:
 		return htons(ETH_P_802_3);
 	default:
-		BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n",
+		BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
 				head->protocol_id,head->protocol_id);
 		lp->stats.rx_errors++;
 		lp->stats.rx_crc_errors++;
@@ -3037,8 +3029,8 @@
 	case ARC_P_ARP_RFC1051:	return htons(ETH_P_ARP);
 	case ARC_P_ATALK:   return htons(ETH_P_ATALK); /* untested appletalk */
 	default:
-		BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n",
-				head->protocol_id,head->protocol_id);
+		BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
+			head->protocol_id,head->protocol_id);
 		lp->stats.rx_errors++;
 		lp->stats.rx_crc_errors++;
 		return 0;
diff -u --recursive --new-file v1.3.46/linux/drivers/net/e2100.c linux/drivers/net/e2100.c
--- v1.3.46/linux/drivers/net/e2100.c	Fri Nov 17 08:42:25 1995
+++ linux/drivers/net/e2100.c	Mon Dec 11 15:41:12 1995
@@ -299,7 +299,12 @@
 
 	mem_on(ioaddr, shared_mem, ring_page);
 
+#ifdef notdef
+	/* Officially this is what we are doing, but the readl() is faster */
 	memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
+#else
+	((unsigned int*)hdr)[0] = readl(shared_mem);
+#endif
 
 	/* Turn off memory access: we would need to reprogram the window anyway. */
 	mem_off(ioaddr);
diff -u --recursive --new-file v1.3.46/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v1.3.46/linux/drivers/net/net_init.c	Fri Nov 17 08:42:26 1995
+++ linux/drivers/net/net_init.c	Tue Dec 12 07:05:07 1995
@@ -34,6 +34,9 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/trdevice.h>
+#ifdef CONFIG_NET_ALIAS
+#include <linux/net_alias.h>
+#endif
 
 /* The network devices currently exist only in the socket namespace, so these
    entries are unused.  The only ones that make sense are
@@ -293,6 +296,28 @@
 	/* else */
 	if (dev->start)
 		printk("ERROR '%s' busy and not MOD_IN_USE.\n", dev->name);
+
+	/*
+	 * 	must jump over main_device+aliases
+	 * 	avoid alias devices unregistration so that only
+	 * 	net_alias module manages them
+	 */
+#ifdef CONFIG_NET_ALIAS		
+	if (dev_base == dev)
+	  dev_base = net_alias_nextdev(dev);
+	else
+	{
+	    while(d && (net_alias_nextdev(d) != dev)) /* skip aliases */
+		    d = net_alias_nextdev(d);
+	  
+	    if (d && (net_alias_nextdev(d) == dev))
+		{
+    /*
+	 * 	critical: bypass by consider devices as blocks (maindev+aliases)
+	 */
+		    net_alias_nextdev_set(d, net_alias_nextdev(dev)); 
+		}
+#else
 	if (dev_base == dev)
 		dev_base = dev->next;
 	else 
@@ -304,6 +329,7 @@
 		{
 			d->next = dev->next;
 		}
+#endif
 		else 
 		{
 			printk("unregister_netdev: '%s' not found\n", dev->name);
diff -u --recursive --new-file v1.3.46/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v1.3.46/linux/drivers/net/smc-ultra.c	Fri Nov 17 08:42:26 1995
+++ linux/drivers/net/smc-ultra.c	Mon Dec 11 15:41:12 1995
@@ -270,7 +270,12 @@
 	unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8);
 
 	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);	/* shmem on */
+#ifdef notdef
+	/* Officially this is what we are doing, but the readl() is faster */
 	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+#else
+	((unsigned int*)hdr)[0] = readl(hdr_start);
+#endif
 	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */
 }
 
diff -u --recursive --new-file v1.3.46/linux/drivers/net/wd.c linux/drivers/net/wd.c
--- v1.3.46/linux/drivers/net/wd.c	Fri Nov 17 08:42:26 1995
+++ linux/drivers/net/wd.c	Mon Dec 11 15:41:12 1995
@@ -129,6 +129,13 @@
 		dev = init_etherdev(0, 0);
 	}
 
+	/* Check for semi-valid mem_start/end values if supplied. */
+	if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
+		printk(KERN_WARNING "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
+		dev->mem_start = 0;
+		dev->mem_end = 0;
+	}
+
 	if (ei_debug  &&  version_printed++ == 0)
 		printk(version);
 
@@ -246,7 +253,7 @@
 
 	/* Snarf the interrupt now.  There's no point in waiting since we cannot
 	   share and the board will usually be enabled. */
-	if (request_irq(dev->irq, ei_interrupt, 0, "wd")) {
+	if (request_irq(dev->irq, ei_interrupt, 0, model_name)) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
 		return EAGAIN;
 	}
@@ -259,7 +266,7 @@
 	}
 
 	/* OK, were are certain this is going to work.  Setup the device. */
-	request_region(ioaddr, WD_IO_EXTENT,"wd");
+	request_region(ioaddr, WD_IO_EXTENT, model_name);
 
 	ei_status.name = model_name;
 	ei_status.word16 = word16;
@@ -352,7 +359,12 @@
 	if (ei_status.word16)
 		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
 
+#ifdef notdef
+	/* Officially this is what we are doing, but the readl() is faster */
 	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+#else
+	((unsigned int*)hdr)[0] = readl(hdr_start);
+#endif
 }
 
 /* Block input and output are easy on shared memory ethercards, and trivial
diff -u --recursive --new-file v1.3.46/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v1.3.46/linux/drivers/scsi/aha152x.c	Wed Nov  8 07:11:34 1995
+++ linux/drivers/scsi/aha152x.c	Tue Dec 12 07:16:37 1995
@@ -918,7 +918,7 @@
 
       ptr->host_scribble = NULL;
       ptr->result = DID_ABORT << 16;
-      ptr->done(ptr);
+      ptr->scsi_done(ptr);
       return SCSI_ABORT_SUCCESS;
     }
 
@@ -942,7 +942,7 @@
     /* target entered bus free before COMMAND COMPLETE, nothing to abort */
     restore_flags(flags);
     current_SC->result = DID_ERROR << 16;
-    current_SC->done(current_SC);
+    current_SC->scsi_done(current_SC);
     current_SC = (Scsi_Cmnd *) NULL;
     return SCSI_ABORT_SUCCESS;
   }
@@ -1063,7 +1063,7 @@
 	 {
 	   current_SC->host_scribble = NULL;
 	   current_SC->result = DID_RESET << 16;
-	   current_SC->done(current_SC);
+	   current_SC->scsi_done(current_SC);
 	   current_SC=NULL;
 	 }
 
@@ -1083,7 +1083,7 @@
   
 	       ptr->host_scribble = NULL;
 	       ptr->result        = DID_RESET << 16;
-	       ptr->done(ptr);
+	       ptr->scsi_done(ptr);
   
 	       ptr = next; 
 	     }
diff -u --recursive --new-file v1.3.46/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c
--- v1.3.46/linux/drivers/scsi/constants.c	Sat Nov 11 17:41:33 1995
+++ linux/drivers/scsi/constants.c	Tue Dec 12 07:16:37 1995
@@ -23,6 +23,8 @@
 #define CONST_XSENSE    0x08
 #define CONST_CMND      0x10
 #define CONST_MSG       0x20
+#define CONST_HOST	0x40
+#define CONST_DRIVER	0x80
 
 static const char unknown[] = "UNKNOWN";
 
@@ -30,7 +32,8 @@
 #ifdef CONSTANTS
 #undef CONSTANTS
 #endif
-#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE | CONST_CMND | CONST_MSG)
+#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE \
+		   | CONST_CMND | CONST_MSG | CONST_HOST | CONST_DRIVER)
 #endif
 
 #if (CONSTANTS & CONST_COMMAND)
@@ -567,6 +570,64 @@
     printk("        command = ");
     print_command (cmd->cmnd);
 }
+
+#if (CONSTANTS & CONST_HOST)
+static const char * hostbyte_table[]={
+"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", 
+"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL};
+
+void print_hostbyte(int scsiresult)
+{   static int maxcode=0;
+    int i;
+   
+    if(!maxcode) {
+	for(i=0;hostbyte_table[i];i++) ;
+	maxcode=i-1;
+    }
+    printk("Hostbyte=0x%02x",host_byte(scsiresult));
+    if(host_byte(scsiresult)>maxcode) {
+	printk("is invalid "); 
+	return;
+    }
+    printk("(%s) ",hostbyte_table[host_byte(scsiresult)]);
+}
+#else
+void print_hostbyte(int scsiresult)
+{   printk("Hostbyte=0x%02x ",hostbyte(scsiresult));
+}
+#endif
+
+#if (CONSTANTS & CONST_DRIVER)
+static const char * driverbyte_table[]={
+"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT",  "DRIVER_MEDIA", "DRIVER_ERROR", 
+"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",NULL };
+
+static const char * driversuggest_table[]={"SUGGEST_OK",
+"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
+unknown,unknown,unknown, "SUGGEST_SENSE",NULL};
+
+
+void print_driverbyte(int scsiresult)
+{   static int driver_max=0,suggest_max=0;
+    int i,dr=driver_byte(scsiresult)&DRIVER_MASK, 
+	su=(driver_byte(scsiresult)&SUGGEST_MASK)>>4;
+
+    if(!driver_max) {
+        for(i=0;driverbyte_table[i];i++) ;
+        driver_max=i;
+	for(i=0;driversuggest_table[i];i++) ;
+	suggest_max=i;
+    }
+    printk("Driverbyte=0x%02x",driver_byte(scsiresult));
+    printk("(%s,%s) ",
+	dr<driver_max  ? driverbyte_table[dr]:"invalid",
+	su<suggest_max ? driversuggest_table[su]:"invalid");
+}
+#else
+void print_driverbyte(int scsiresult)
+{   printk("Driverbyte=0x%02x ",driver_byte(scsiresult));
+}
+#endif
 
 /*
  * Overrides for Emacs so that we almost follow Linus's tabbing style.
diff -u --recursive --new-file v1.3.46/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.46/linux/drivers/scsi/scsi.c	Mon Dec 11 15:42:03 1995
+++ linux/drivers/scsi/scsi.c	Tue Dec 12 07:16:37 1995
@@ -65,6 +65,7 @@
 static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
                  Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
                  struct Scsi_Host *shpnt, char * scsi_result);
+void scsi_build_commandblocks(Scsi_Device * SDpnt);
 
 
 static unsigned char * dma_malloc_freelist = NULL;
@@ -272,18 +273,6 @@
     return 0;
 }
 
-/*
- *  As the actual SCSI command runs in the background, we must set up a
- *  flag that tells scan_scsis() when the result it has is valid.
- *  scan_scsis can set the_result to -1, and watch for it to become the
- *  actual return code for that call.  the scan_scsis_done function() is
- *  our user specified completion function that is passed on to the
- *  scsi_do_cmd() function.
- */
-
-volatile int in_scan_scsis = 0;
-static int the_result;
-
 void scsi_make_blocked_list(void)  {
     int block_count = 0, index;
     unsigned int flags;
@@ -385,9 +374,10 @@
   int max_dev_lun;
   Scsi_Cmnd *SCpnt;
 
-  in_scan_scsis++;
   SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
   SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
+  memset (SCpnt, 0, sizeof (Scsi_Cmnd));
+
 
   /* Make sure we have something that is valid for DMA purposes */
   scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma)
@@ -398,9 +388,17 @@
     goto leave;
   }
 
-  shpnt->host_queue = SCpnt;    /* We need this so that commands can time out */
+  /* We must chain ourself in the host_queue, so commands can time out */
+  if(shpnt->host_queue)
+      shpnt->host_queue->prev = SCpnt;
+  SCpnt->next = shpnt->host_queue;
+  SCpnt->prev = NULL;
+  shpnt->host_queue = SCpnt;
+
 
   if (hardcoded == 1) {
+    Scsi_Device *oldSDpnt=SDpnt;
+    struct Scsi_Device_Template * sdtpnt;
     channel = hchannel;
     if(channel > shpnt->max_channel) goto leave;
     dev = hid;
@@ -409,11 +407,31 @@
     if(lun >= shpnt->max_lun) goto leave;
     scan_scsis_single (channel, dev, lun, &max_dev_lun,
                    &SDpnt, SCpnt, shpnt, scsi_result);
+    if(SDpnt!=oldSDpnt) {
+
+	/* it could happen the blockdevice hasn't yet been inited */
+    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+        if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+
+            oldSDpnt->scsi_request_fn = NULL;
+            for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+                if(sdtpnt->attach) {
+		  (*sdtpnt->attach)(oldSDpnt);
+                  if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);}
+	    resize_dma_pool();
+  
+        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+            if(sdtpnt->finish && sdtpnt->nr_dev)
+                {(*sdtpnt->finish)();}
+	}
+    }
+
   }
   else {
     for (channel = 0; channel <= shpnt->max_channel; channel++) {
       for (dev = 0; dev < shpnt->max_id; ++dev) {
         if (shpnt->this_id != dev) {
+
           /*
            * We need the for so our continue, etc. work fine. We put this in
            * a variable so that we can override it during the scan if we
@@ -421,20 +439,32 @@
            */
           max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
                          max_scsi_luns : shpnt->max_lun);
-
           for (lun = 0; lun < max_dev_lun; ++lun) {
-
             if (!scan_scsis_single (channel, dev, lun, &max_dev_lun,
                                     &SDpnt, SCpnt, shpnt, scsi_result))
-              break; /* break means don't probe for luns!=0 */
+              break; /* break means don't probe further for luns!=0 */
           }                     /* for lun ends */
         }                       /* if this_id != id ends */
       }                         /* for dev ends */
     }                           /* for channel ends */
+  } 				/* if/else hardcoded */
 
-leave:
-    shpnt->host_queue = NULL;   /* No longer needed here */
+  leave:
 
+  {/* Unchain SCpnt from host_queue */
+    Scsi_Cmnd *prev,*next,*hqptr;
+    for(hqptr=shpnt->host_queue; hqptr!=SCpnt; hqptr=hqptr->next) ;
+    if(hqptr) {
+      prev=hqptr->prev;
+      next=hqptr->next;
+      if(prev) 
+     	prev->next=next;
+      else 
+     	shpnt->host_queue=next;
+      if(next) next->prev=prev;
+    }
+  }
+ 
      /* Last device block does not exist.  Free memory. */
     if (SDpnt != NULL)
       scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device));
@@ -446,14 +476,12 @@
     if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
       scsi_free (scsi_result, 512);
 
-    in_scan_scsis--;
-  }
 }
 
 /*
  * The worker for scan_scsis.
  * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
- * Global variables used : scsi_devices(linked list), the_result
+ * Global variables used : scsi_devices(linked list)
  */
 int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
     Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt, 
@@ -490,7 +518,6 @@
   scsi_cmd[1] = lun << 5;
   scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
 
-  memset (SCpnt, 0, sizeof (Scsi_Cmnd));
   SCpnt->host = SDpnt->host;
   SCpnt->device = SDpnt;
   SCpnt->target = SDpnt->id;
@@ -507,8 +534,10 @@
   }
 
 #if defined(DEBUG) || defined(DEBUG_INIT)
-  printk ("scsi: scan_scsis_single id %d lun %d. Return code %d\n",
+  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
           dev, lun, SCpnt->result);
+  print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);
+  printk("\n");
 #endif
 
   if (SCpnt->result) {
@@ -546,13 +575,12 @@
     down (&sem);
   }
 
-  the_result = SCpnt->result;
 #if defined(DEBUG) || defined(DEBUG_INIT)
   printk ("scsi: INQUIRY %s with code 0x%x\n",
-          the_result ? "failed" : "successful", the->result);
+          SCpnt->result ? "failed" : "successful", SCpnt->result);
 #endif
 
-  if (the_result)
+  if (SCpnt->result)
     return 0;     /* assume no peripheral if any sort of error */
 
   /*
@@ -696,7 +724,7 @@
   SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
   *SDpnt2=SDpnt;
   if (!SDpnt)
-    printk ("scsi: scan_scsis_single: No memory\n");
+    printk ("scsi: scan_scsis_single: Cannot malloc\n");
 
 
   /*
@@ -750,7 +778,7 @@
     switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
     {
     case NORMAL_TIMEOUT:
-	if (!in_scan_scsis) {
+	{
 #ifdef DEBUG_TIMEOUT
 	    scsi_dump_status();
 #endif
@@ -1460,7 +1488,7 @@
 			printk ("Internal error %s %d \n", __FILE__,
 				__LINE__);
 		    }
-		}
+		} /* end WAS_SENSE */
 		else
 		{
 #ifdef DEBUG
@@ -1734,8 +1762,7 @@
 	    SCpnt->internal_timeout |= IN_ABORT;
 	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
 	    
-	    if ((SCpnt->flags & IS_RESETTING) &&
-		SCpnt->device->soft_reset) {
+	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
 		/* OK, this command must have died when we did the
 		 *  reset.  The device itself must have lied. 
 		 */
@@ -1797,6 +1824,8 @@
 		/* We should have already aborted this one.  No
 		 * need to adjust timeout 
 		 */
+                 SCpnt->internal_timeout &= ~IN_ABORT;
+                 return 0;
 	    case SCSI_ABORT_NOT_RUNNING:
 		SCpnt->internal_timeout &= ~IN_ABORT;
 		update_timeout(SCpnt, 0);
@@ -1837,10 +1866,8 @@
     Scsi_Cmnd * SCpnt1;
     struct Scsi_Host * host = SCpnt->host;
 
-#ifdef DEBUG
-    printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",
+    printk("SCSI bus is being reset for host %d.\n",
 	   host->host_no);
-#endif
  
     /*
      * First of all, we need to make a recommendation to the low-level
@@ -1862,10 +1889,8 @@
     SCpnt1 = host->host_queue;
     while(SCpnt1) {
 	if( SCpnt1->request.rq_status != RQ_INACTIVE
-	   && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
-	{
-            break;
-	}
+	    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
+            	break;
         SCpnt1 = SCpnt1->next;
  	}
     if( SCpnt1 == NULL ) {
@@ -2154,7 +2179,7 @@
     unsigned long flags;
     
 #ifdef DEBUG
-    printk("Sfree %p %d\n",obj, len);
+    printk("scsi_free %p %d\n",obj, len);
 #endif
     
     offset = -1;
@@ -2167,20 +2192,20 @@
 	    break;
 	}
     
-    if (page == (dma_sectors >> 3)) panic("Bad offset");
+    if (page == (dma_sectors >> 3)) panic("scsi_free:Bad offset");
     sector = offset >> 9;
-    if(sector >= dma_sectors) panic ("Bad page");
+    if(sector >= dma_sectors) panic ("scsi_free:Bad page");
     
     sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
     nbits = len >> 9;
     mask = (1 << nbits) - 1;
     
-    if ((mask << sector) > 0xffff) panic ("Bad memory alignment");
+    if ((mask << sector) > 0xffff) panic ("scsi_free:Bad memory alignment");
     
     save_flags(flags);
     cli();
     if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
-	panic("Trying to free unused memory");
+	panic("scsi_free:Trying to free unused memory");
     
     dma_free_sectors += nbits;
     dma_malloc_freelist[page] &= ~(mask << sector);
@@ -2438,8 +2463,13 @@
     /*
      * Usage: echo "scsi singledevice 0 1 2 3" >/proc/scsi/scsi
      * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
-     * Consider this feature ALPHA, as you can easily hang your
-     * scsi system (depending on your low level driver).
+     * Consider this feature BETA.
+     *     CAUTION: This is not for hotplugging your peripherals. As
+     *     SCSI was not designed for this you could damage your
+     *     hardware !  
+     * However perhaps it is legal to switch on an
+     * already connected device. It is perhaps not 
+     * guaranteed this device doesn't corrupt an ongoing data transfer.
      */
     if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
 	return(-EINVAL);
diff -u --recursive --new-file v1.3.46/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.46/linux/drivers/scsi/scsi.h	Mon Nov 27 12:48:31 1995
+++ linux/drivers/scsi/scsi.h	Wed Dec 13 08:05:03 1995
@@ -89,6 +89,7 @@
 #define DRIVER_INVALID      0x05
 #define DRIVER_TIMEOUT      0x06
 #define DRIVER_HARD         0x07
+#define DRIVER_SENSE	    0x08
 
 #define SUGGEST_RETRY       0x10
 #define SUGGEST_ABORT       0x20 
@@ -97,8 +98,6 @@
 #define SUGGEST_SENSE       0x80
 #define SUGGEST_IS_OK       0xff
 
-#define DRIVER_SENSE        0x08
-
 #define DRIVER_MASK         0x0f
 #define SUGGEST_MASK        0xf0
 
@@ -448,6 +447,8 @@
 
 extern void print_command(unsigned char *);
 extern void print_sense(const char *, Scsi_Cmnd *);
+extern void print_driverbyte(int scsiresult);
+extern void print_hostbyte(int scsiresult);
 
 extern void scsi_mark_host_bus_reset(struct Scsi_Host *Host);
 
diff -u --recursive --new-file v1.3.46/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c
--- v1.3.46/linux/drivers/scsi/scsi_syms.c	Mon Dec 11 15:42:03 1995
+++ linux/drivers/scsi/scsi_syms.c	Tue Dec 12 07:16:37 1995
@@ -59,7 +59,6 @@
     X(kernel_scsi_ioctl),
     X(need_isa_buffer),
     X(request_queueable),
-    X(in_scan_scsis),
 #if defined(CONFIG_PROC_FS)
     X(proc_print_scsidevice),
 #endif
diff -u --recursive --new-file v1.3.46/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.3.46/linux/drivers/scsi/sd.c	Mon Nov 13 12:36:46 1995
+++ linux/drivers/scsi/sd.c	Tue Dec 12 07:16:37 1995
@@ -1304,12 +1304,14 @@
 	if (!rscsi_disks[i].capacity && 
 	    rscsi_disks[i].device)
 	{
-	    i = sd_init_onedisk(i);
 	    if (MODULE_FLAG
 		&& !rscsi_disks[i].has_part_table) {
 		sd_sizes[i << 4] = rscsi_disks[i].capacity;
+		/* revalidate does sd_init_onedisk via MAYBE_REINIT*/
 		revalidate_scsidisk(MKDEV(MAJOR_NR, i << 4), 0);
 	    }
+	    else
+	    	i=sd_init_onedisk(i);
 	    rscsi_disks[i].has_part_table = 1;
 	}
     
diff -u --recursive --new-file v1.3.46/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v1.3.46/linux/fs/proc/mem.c	Mon Sep 25 12:26:23 1995
+++ linux/fs/proc/mem.c	Mon Dec 11 15:41:12 1995
@@ -297,7 +297,8 @@
 		dtmp += PAGE_SIZE;
 	}
 
-	invalidate();
+	invalidate_range(vma->vm_mm, vma->vm_start, vma->vm_end);
+	invalidate_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.46/linux/fs/super.c linux/fs/super.c
--- v1.3.46/linux/fs/super.c	Mon Dec 11 15:42:04 1995
+++ linux/fs/super.c	Wed Dec 13 07:57:04 1995
@@ -91,13 +91,13 @@
 	lptr->mnt_sem.count = 1;
 	if (dev_name && !getname(dev_name, &tmp)) {
 		if ((lptr->mnt_devname =
-		    (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL)
+		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
 			strcpy(lptr->mnt_devname, tmp);
 		putname(tmp);
 	}
 	if (dir_name && !getname(dir_name, &tmp)) {
 		if ((lptr->mnt_dirname =
-		    (char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL)
+		    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
 			strcpy(lptr->mnt_dirname, tmp);
 		putname(tmp);
 	}
diff -u --recursive --new-file v1.3.46/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v1.3.46/linux/include/asm-i386/pgtable.h	Mon Dec 11 15:42:05 1995
+++ linux/include/asm-i386/pgtable.h	Tue Dec 12 13:13:11 1995
@@ -26,32 +26,81 @@
  *  - invalidate_page(mm, vmaddr) invalidates one page
  *  - invalidate_range(mm, start, end) invalidates a range of pages
  *
- * ..but the i386 has somewhat limited invalidation capabilities.
+ * ..but the i386 has somewhat limited invalidation capabilities,
+ * and page-granular invalidates are available only on i486 and up.
  */
+
+#define __invalidate() \
+__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
+
+#ifdef __i486__
+#define __invalidate_one(addr) \
+__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
+#else
+#define __invalidate_one(addr) invalidate()
+#endif
  
 #ifndef __SMP__
-#define invalidate() \
-__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
+
+#define invalidate() __invalidate()
+#define invalidate_all() __invalidate()
+
+static inline void invalidate_mm(struct mm_struct *mm)
+{
+	if (mm == current->mm)
+		__invalidate();
+}
+
+static inline void invalidate_page(struct mm_struct *mm,
+	unsigned long addr)
+{
+	if (mm == current->mm)
+		__invalidate_one(addr);
+}
+
+static inline void invalidate_range(struct mm_struct *mm,
+	unsigned long start, unsigned long end)
+{
+	if (mm == current->mm)
+		__invalidate();
+}
+
 #else
+
+/*
+ * We aren't very clever about this yet -  SMP could certainly
+ * avoid some global invalidates..
+ */
+
 #include <asm/smp.h>
+
 #define local_invalidate() \
-__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
+	__invalidate()
+
 #define invalidate() \
-	smp_invalidate();
-#endif
+	smp_invalidate()
 
-/*
- * We aren't very clever about this yet. On a 486+ we could actually do
- * page-granularity invalidates for better performance in some cases.
- * And SMP could certainly avoid some global invalidates..
- */
 #define invalidate_all() invalidate()
-#define invalidate_mm(mm_struct) \
-do { if ((mm_struct) == current->mm) invalidate(); } while (0)
-#define invalidate_page(mm_struct,addr) \
-do { if ((mm_struct) == current->mm) invalidate(); } while (0)
-#define invalidate_range(mm_struct,start,end) \
-do { if ((mm_struct) == current->mm) invalidate(); } while (0)
+
+static inline void invalidate_mm(struct mm_struct *mm)
+{
+	invalidate();
+}
+
+static inline void invalidate_page(struct mm_struct *mm,
+	unsigned long addr)
+{
+	invalidate();
+}
+
+static inline void invalidate_range(struct mm_struct *mm,
+	unsigned long start, unsigned long end)
+{
+	invalidate();
+}
+
+#endif
+
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
diff -u --recursive --new-file v1.3.46/linux/include/linux/net_alias.h linux/include/linux/net_alias.h
--- v1.3.46/linux/include/linux/net_alias.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/net_alias.h	Wed Dec 13 08:05:03 1995
@@ -0,0 +1,176 @@
+#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 
+ */
+
+#define NET_ALIAS_MAX_SLOT  256
+
+struct net_alias;
+struct net_alias_info;
+struct net_alias_type;
+
+
+/*
+ * main alias structure
+ * note that *defines* dev & devname
+ */
+
+struct net_alias
+{
+  struct device dev;		/* alias device defn*/
+  char name[IFNAMSIZ];		/* device name defn */
+  unsigned hash;		/* my hash value: for quick rehash */
+  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 *next;	/* next alias (hashed linked list) */
+};
+
+
+/*
+ *  alias structure pointed by main device
+ *  it holds main device's alias hash table
+ */
+
+struct net_alias_info
+{
+  int n_aliases;		/* num aliases */
+  struct device *taildev;	/* my last (alias) device */
+  struct net_alias *hash_tab[16]; /* hashed alias table */
+};
+
+/*
+ * net_alias_type class
+ * declares a generic (AF_ independent) structure that will
+ * manage generic to family-specific behavior.
+ */
+
+struct net_alias_type
+{
+  int type;			/* aliasing type: address family */
+  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 *);
+  int (*alias_init_1)		/* called after alias creation: */
+    (struct net_alias *alias, struct sockaddr *sa);
+  int (*alias_done_1)		/* called before alias deletion */
+    (struct net_alias *alias);
+  int (*alias_print_1)	
+    (char *buf, int len, struct net_alias *alias);
+  struct net_alias_type *next;	/* link */
+};
+
+
+/*
+ * is dev an alias?
+ */
+
+static __inline__ int
+net_alias_is(struct device *dev)
+{
+  return (dev->my_alias != 0);
+}
+
+
+/*
+ * does dev have aliases?
+ */
+
+static __inline__ int
+net_alias_has(struct device *dev)
+{
+  return (dev->alias_info != 0);
+}
+
+
+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_getinfo(char *buf, char **, off_t , int , int );
+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);
+
+
+/*
+ * returns MY 'true' main device
+ * intended for alias devices
+ */
+
+static __inline__ struct device *net_alias_main_dev(struct device *dev)
+{
+  return (net_alias_is(dev))? dev->my_alias->main_dev : dev;
+}
+
+
+/*
+ * returns NEXT 'true' device
+ * intended for true devices
+ */
+
+static __inline__ struct device *
+net_alias_nextdev(struct device *dev)
+{
+  return (dev->alias_info)? dev->alias_info->taildev->next : dev->next;
+}
+
+
+/*
+ * sets NEXT 'true' device
+ * intended for main devices (treat main device as block: dev+aliases).
+ */
+
+static __inline__ struct device *
+net_alias_nextdev_set(struct device *dev, struct device *nextdev)
+{
+  struct device *pdev = dev;
+  if (net_alias_has(dev))
+  {
+    pdev = dev->alias_info->taildev; /* point to last dev alias */
+  }
+  pdev->next = 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 */
diff -u --recursive --new-file v1.3.46/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v1.3.46/linux/include/linux/netdevice.h	Sat Nov 25 19:04:56 1995
+++ linux/include/linux/netdevice.h	Wed Dec 13 08:05:03 1995
@@ -152,6 +152,8 @@
   
   unsigned long		   pkt_queue;	/* Packets queued */
   struct device		  *slave;	/* Slave device */
+  struct net_alias_info		*alias_info;	/* main dev alias info */
+  struct net_alias		*my_alias;	/* alias devs */
   
 
   /* Pointer to the interface buffers. */
diff -u --recursive --new-file v1.3.46/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.46/linux/include/linux/proc_fs.h	Mon Dec 11 15:42:05 1995
+++ linux/include/linux/proc_fs.h	Wed Dec 13 08:05:03 1995
@@ -89,6 +89,8 @@
 	PROC_NET_SOCKSTAT,
 	PROC_NET_RTCACHE,
 	PROC_NET_AX25_BPQETHER,
+	PROC_NET_ALIAS_TYPES,
+	PROC_NET_ALIASES,
 	PROC_NET_LAST
 };
 
diff -u --recursive --new-file v1.3.46/linux/include/linux/resource.h linux/include/linux/resource.h
--- v1.3.46/linux/include/linux/resource.h	Fri Oct  6 14:35:16 1995
+++ linux/include/linux/resource.h	Wed Dec 13 06:57:29 1995
@@ -44,8 +44,8 @@
 	long	rlim_max;
 };
 
-#define	PRIO_MIN	(-99)
-#define	PRIO_MAX	14
+#define	PRIO_MIN	(-20)
+#define	PRIO_MAX	20
 
 #define	PRIO_PROCESS	0
 #define	PRIO_PGRP	1
diff -u --recursive --new-file v1.3.46/linux/include/linux/vt.h linux/include/linux/vt.h
--- v1.3.46/linux/include/linux/vt.h	Tue Jun 20 09:10:32 1995
+++ linux/include/linux/vt.h	Tue Dec 12 07:16:36 1995
@@ -48,5 +48,7 @@
 	ushort v_ccol;		/* number of pixel columns per character */
 };
 #define VT_RESIZEX      0x560A  /* set kernel's idea of screensize + more */
+#define VT_LOCKSWITCH   0x560B  /* disallow vt switching */
+#define VT_UNLOCKSWITCH 0x560C  /* allow vt switching */
 
 #endif /* _LINUX_VT_H */
diff -u --recursive --new-file v1.3.46/linux/include/net/ip_alias.h linux/include/net/ip_alias.h
--- v1.3.46/linux/include/net/ip_alias.h	Thu Jan  1 02:00:00 1970
+++ linux/include/net/ip_alias.h	Wed Dec 13 08:13:41 1995
@@ -0,0 +1,13 @@
+#ifndef _IP_ALIAS_H
+#define _IP_ALIAS_H
+
+/* 
+ * IP alias specific prototypes
+ */
+
+#include <linux/net_alias.h>
+
+extern int ip_alias_init(void);
+extern int ip_alias_done(void);
+
+#endif  /* _IP_ALIAS_H */
diff -u --recursive --new-file v1.3.46/linux/ipc/shm.c linux/ipc/shm.c
--- v1.3.46/linux/ipc/shm.c	Tue Nov 21 13:22:14 1995
+++ linux/ipc/shm.c	Mon Dec 11 15:41:12 1995
@@ -445,7 +445,7 @@
 			return -ENOMEM;
 		set_pte(page_table, __pte(shm_sgn));
 	}
-	invalidate();
+	invalidate_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
 	return 0;
 }
 
@@ -680,7 +680,7 @@
 	struct vm_area_struct *shmd;
 	unsigned long swap_nr;
 	unsigned long id, idx;
-	int loop = 0, invalid = 0;
+	int loop = 0;
 	int counter;
 	
 	counter = shm_rss >> prio;
@@ -716,8 +716,6 @@
 
 	if (--counter < 0) { /* failed */
 		failed:
-		if (invalid)
-			invalidate();
 		swap_free (swap_nr);
 		return 0;
 	}
@@ -766,7 +764,7 @@
 		mem_map[MAP_NR(pte_page(pte))].count--;
 		if (shmd->vm_mm->rss > 0)
 			shmd->vm_mm->rss--;
-		invalid++;
+		invalidate_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
 	    /* continue looping through circular list */
 	    } while (0);
 	    if ((shmd = shmd->vm_next_share) == shp->attaches)
@@ -776,8 +774,6 @@
 	if (mem_map[MAP_NR(pte_page(page))].count != 1)
 		goto check_table;
 	shp->shm_pages[idx] = swap_nr;
-	if (invalid)
-		invalidate();
 	write_swap_page (swap_nr, (char *) pte_page(page));
 	free_page(pte_page(page));
 	swap_successes++;
diff -u --recursive --new-file v1.3.46/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.46/linux/kernel/ksyms.c	Mon Dec 11 15:42:06 1995
+++ linux/kernel/ksyms.c	Tue Dec 12 16:36:42 1995
@@ -76,6 +76,9 @@
 #include "../drivers/net/slhc.h"
 #endif
 #endif
+#ifdef CONFIG_NET_ALIAS
+#include <linux/net_alias.h>
+#endif
 #endif
 #ifdef CONFIG_PCI
 #include <linux/bios32.h>
@@ -412,6 +415,10 @@
 	/* Device callback registration */
 	X(register_netdevice_notifier),
 	X(unregister_netdevice_notifier),
+#ifdef CONFIG_NET_ALIAS
+	X(register_net_alias_type),
+	X(unregister_net_alias_type),
+#endif
 #endif
 
 	/* support for loadable net drivers */
@@ -452,11 +459,7 @@
  	 * So we add it here too.  There is a duplicate set in scsi.c
  	 * that is used when the entire scsi subsystem is a loadable
  	 * module.
-    	 * 
- 	 * in_scan_scsis is a hack, and should go away once the new 
-	 * memory allocation code is in the NCR driver 
 	 */
-    	X(in_scan_scsis),
 	X(scsi_register_module),
 	X(scsi_unregister_module),
 	X(scsi_free),
diff -u --recursive --new-file v1.3.46/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.46/linux/mm/filemap.c	Wed Nov  8 07:11:43 1995
+++ linux/mm/filemap.c	Mon Dec 11 15:41:12 1995
@@ -141,7 +141,8 @@
 	unsigned long entry = SWP_ENTRY(SHM_SWP_TYPE, MAP_NR(page));
 
 	set_pte(page_table, __pte(entry));
-	invalidate();
+	/* Yuck, perhaps a slightly modified swapout parameter set? */
+	invalidate_page(vma->vm_mm, (offset + vma->vm_start - vma->vm_offset));
 	error = filemap_write_page(vma, offset, page);
 	if (pte_val(*page_table) == entry)
 		pte_clear(page_table);
@@ -179,13 +180,14 @@
 		if (!pte_dirty(pte))
 			return 0;
 		set_pte(ptep, pte_mkclean(pte));
+		invalidate_page(vma->vm_mm, address);
 		page = pte_page(pte);
 		mem_map[MAP_NR(page)].count++;
 	} else {
 		if (pte_none(pte))
 			return 0;
 		pte_clear(ptep);
-		invalidate();
+		invalidate_page(vma->vm_mm, address);
 		if (!pte_present(pte)) {
 			swap_free(pte_val(pte));
 			return 0;
@@ -274,7 +276,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_range(vma->vm_mm, end - size, end);
 	return error;
 }
 
diff -u --recursive --new-file v1.3.46/linux/mm/memory.c linux/mm/memory.c
--- v1.3.46/linux/mm/memory.c	Mon Nov 27 12:48:36 1995
+++ linux/mm/memory.c	Mon Dec 11 15:41:12 1995
@@ -134,7 +134,7 @@
 	}
 	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
 		free_one_pgd(page_dir + i);
-	invalidate();
+	invalidate_mm(tsk->mm);
 }
 
 /*
@@ -153,12 +153,12 @@
 		printk("%s trying to free kernel page-directory: not good\n", tsk->comm);
 		return;
 	}
+	invalidate_mm(tsk->mm);
 	SET_PAGE_DIR(tsk, swapper_pg_dir);
 	tsk->mm->pgd = swapper_pg_dir;	/* or else... */
 	for (i = 0 ; i < PTRS_PER_PGD ; i++)
 		free_one_pgd(page_dir + i);
 	pgd_free(page_dir);
-	invalidate();
 }
 
 int new_page_tables(struct task_struct * tsk)
@@ -171,6 +171,7 @@
 	page_dir = pgd_offset(&init_mm, 0);
 	for (i = USER_PTRS_PER_PGD ; i < PTRS_PER_PGD ; i++)
 		new_pg[i] = page_dir[i];
+	invalidate_mm(tsk->mm);
 	SET_PAGE_DIR(tsk, new_pg);
 	tsk->mm->pgd = new_pg;
 	return 0;
@@ -285,7 +286,9 @@
 			break;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 	}
-	invalidate();
+	/* Note that the src ptes get c-o-w treatment, so they change too. */
+	invalidate_range(src, vma->vm_start, vma->vm_end);
+	invalidate_range(dst, vma->vm_start, vma->vm_end);
 	return error;
 }
 
@@ -369,7 +372,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_range(mm, end - size, end);
 	return 0;
 }
 
@@ -429,7 +432,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_range(current->mm, end - size, end);
 	return error;
 }
 
@@ -499,7 +502,7 @@
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_range(current->mm, from - size, from);
 	return error;
 }
 
@@ -514,7 +517,7 @@
 		return;
 	}
 /* no need for invalidate */
-	*page_table = pte;
+	set_pte(page_table, pte);
 }
 
 /*
@@ -547,7 +550,7 @@
 	if (!pte_none(*pte)) {
 		printk("put_dirty_page: page already exists\n");
 		pte_clear(pte);
-		invalidate();
+		invalidate_page(tsk->mm, address);
 	}
 	set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY))));
 /* no need for invalidate */
@@ -610,17 +613,17 @@
 			copy_page(old_page,new_page);
 			set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
 			free_page(old_page);
-			invalidate();
+			invalidate_page(vma->vm_mm, address);
 			return;
 		}
 		set_pte(page_table, BAD_PAGE);
 		free_page(old_page);
 		oom(tsk);
-		invalidate();
+		invalidate_page(vma->vm_mm, address);
 		return;
 	}
 	set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
-	invalidate();
+	invalidate_page(vma->vm_mm, address);
 	if (new_page)
 		free_page(new_page);
 	return;
@@ -842,7 +845,7 @@
 		return 1;
 /* ok, need to mark it read-only, so invalidate any possible old TB entry */
 	set_pte(from_table, pte_wrprotect(from));
-	invalidate();
+	invalidate_page(from_area->vm_mm, from_address);
 	return 1;
 }
 
diff -u --recursive --new-file v1.3.46/linux/mm/mprotect.c linux/mm/mprotect.c
--- v1.3.46/linux/mm/mprotect.c	Thu Sep  7 17:17:20 1995
+++ linux/mm/mprotect.c	Mon Dec 11 15:41:12 1995
@@ -72,6 +72,7 @@
 static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
 {
 	pgd_t *dir;
+	unsigned long beg = start;
 
 	dir = pgd_offset(current->mm, start);
 	while (start < end) {
@@ -79,7 +80,7 @@
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_range(current->mm, beg, end);
 	return;
 }
 
diff -u --recursive --new-file v1.3.46/linux/mm/swap.c linux/mm/swap.c
--- v1.3.46/linux/mm/swap.c	Tue Nov 21 13:22:14 1995
+++ linux/mm/swap.c	Mon Dec 11 15:41:12 1995
@@ -457,7 +457,7 @@
 				return 0;
 			vma->vm_mm->rss--;
 			set_pte(page_table, __pte(entry));
-			invalidate();
+			invalidate_page(vma->vm_mm, address);
 			tsk->nswap++;
 			write_swap_page(entry, (char *) page);
 		}
@@ -472,13 +472,13 @@
 		}
 		vma->vm_mm->rss--;
 		set_pte(page_table, __pte(entry));
-		invalidate();
+		invalidate_page(vma->vm_mm, address);
 		free_page(page);
 		return 1;
 	} 
 	vma->vm_mm->rss--;
 	pte_clear(page_table);
-	invalidate();
+	invalidate_page(vma->vm_mm, address);
 	entry = mem_map[MAP_NR(page)].count;
 	free_page(page);
 	return entry;
diff -u --recursive --new-file v1.3.46/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v1.3.46/linux/mm/vmalloc.c	Mon Sep 18 14:54:11 1995
+++ linux/mm/vmalloc.c	Mon Dec 11 15:41:12 1995
@@ -105,7 +105,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_all();
 }
 
 static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size)
@@ -166,7 +166,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_all();
 	return 0;
 }
 
@@ -227,7 +227,7 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	}
-	invalidate();
+	invalidate_all();
 	return 0;
 }
 
diff -u --recursive --new-file v1.3.46/linux/net/Config.in linux/net/Config.in
--- v1.3.46/linux/net/Config.in	Mon Dec 11 15:42:08 1995
+++ linux/net/Config.in	Tue Dec 12 07:05:07 1995
@@ -4,6 +4,7 @@
 mainmenu_option next_comment
 comment 'Networking options'
 bool 'Network firewalls' CONFIG_FIREWALL
+bool 'Network aliasing'  CONFIG_NET_ALIAS
 bool 'TCP/IP networking' CONFIG_INET
 if [ "$CONFIG_INET" = "y" ]; then
   source net/ipv4/Config.in
diff -u --recursive --new-file v1.3.46/linux/net/core/Makefile linux/net/core/Makefile
--- v1.3.46/linux/net/core/Makefile	Mon Oct 23 18:02:21 1995
+++ linux/net/core/Makefile	Tue Dec 12 07:05:07 1995
@@ -19,6 +19,10 @@
 O_OBJS += firewall.o
 endif
 
+ifdef CONFIG_NET_ALIAS
+O_OBJS += net_alias.o
+endif
+
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.46/linux/net/core/dev.c linux/net/core/dev.c
--- v1.3.46/linux/net/core/dev.c	Fri Nov 17 08:42:33 1995
+++ linux/net/core/dev.c	Tue Dec 12 07:05:07 1995
@@ -70,6 +70,9 @@
 #include <net/arp.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#ifdef CONFIG_NET_ALIAS
+#include <linux/net_alias.h>
+#endif
 
 /*
  *	The list of packet types we will receive (as opposed to discard)
@@ -356,6 +359,19 @@
 		return;
 	}
 
+	/*
+	 *
+	 * 	If dev is an alias, switch to its main device.
+	 *	"arp" resolution has been made with alias device, so
+	 *	arp entries refer to alias, not main.
+	 *
+	 */
+
+#ifdef CONFIG_NET_ALIAS
+	if (net_alias_is(dev))
+	  	skb->dev = dev = net_alias_main_dev(dev);
+#endif
+
 	save_flags(flags);
 	cli();	
 	if (!where)	 	/* Always keep order. It helps other hosts
@@ -561,7 +577,7 @@
 {
 	struct device *dev;
 
-	for (dev = dev_base; dev != NULL; dev = dev->next) 
+	for (dev = dev_base; dev != NULL; dev = dev->next)
 	{
 		if (dev->flags != 0 && !dev->tbusy) {
 			/*
@@ -753,6 +769,13 @@
 	struct sk_buff *skb;
 	unsigned long flags;
 	
+	/*
+	 * aliases do not trasmit (by now :)
+	 */
+
+#ifdef CONFIG_NET_ALIAS
+	if (net_alias_is(dev)) return;
+#endif
 	save_flags(flags);	
 	/*
 	 *	Work the queues in priority order
@@ -984,9 +1007,20 @@
 	 *	See which interface the caller is talking about. 
 	 */
 	 
+	/*
+	 *
+	 *	net_alias_dev_get(): dev_get() with added alias naming magic.
+	 *	only allow alias creation/deletion if (getset==SIOCSIFADDR)
+	 *
+	 */
+
+#ifdef CONFIG_NET_ALIAS
+	if ((dev = net_alias_dev_get(ifr.ifr_name, getset == SIOCSIFADDR, &err, NULL, NULL)) == NULL)
+		return(err);
+#else
 	if ((dev = dev_get(ifr.ifr_name)) == NULL) 
 		return(-ENODEV);
-
+#endif
 	switch(getset) 
 	{
 		case SIOCGIFFLAGS:	/* Get interface flags */
@@ -1079,6 +1113,16 @@
 			}
 			else
 			{
+
+				/*
+				 *	if dev is an alias, must rehash to update
+				 *	address change
+				 */
+
+#ifdef CONFIG_NET_ALIAS
+			  	if (net_alias_is(dev))
+			    	net_alias_rehash(dev->my_alias,&ifr.ifr_addr);
+#endif
 				dev->pa_addr = (*(struct sockaddr_in *)
 					 &ifr.ifr_addr).sin_addr.s_addr;
 				dev->family = ifr.ifr_addr.sa_family;
@@ -1381,6 +1425,18 @@
 		0, &proc_net_inode_operations,
 		dev_get_info
 	});
+
+	/*	
+	 *	Initialise net_alias engine 
+	 *
+	 *		- register net_alias device notifier
+	 *		- register proc entries:	/proc/net/alias_types
+	 *									/proc/net/aliases
+	 */
+
+#ifdef CONFIG_NET_ALIAS
+	net_alias_init();
+#endif
 
 	bh_base[NET_BH].routine = net_bh;
 	enable_bh(NET_BH);
diff -u --recursive --new-file v1.3.46/linux/net/core/net_alias.c linux/net/core/net_alias.c
--- v1.3.46/linux/net/core/net_alias.c	Thu Jan  1 02:00:00 1970
+++ linux/net/core/net_alias.c	Tue Dec 12 07:05:07 1995
@@ -0,0 +1,1164 @@
+/*
+ *		NET_ALIAS device aliasing module.
+ *
+ * Version:	@(#)net_alias.c	0.42   12/11/95
+ *
+ * Authors:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
+ *		Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
+ *
+ * Features:
+ *	-	AF_ independent: net_alias_type objects
+ *	-	AF_INET optimized
+ *	-	ACTUAL alias devices inserted in dev chain
+ *	-	fast hashed alias address lookup
+ *	-	net_alias_type objs registration/unreg., module-ables.
+ *	-	/proc/net/aliases & /proc/net/alias_types entries
+ *
+ * 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
+ *	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/types.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/notifier.h>
+#include <linux/if.h>
+#include <linux/inet.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#ifdef ALIAS_USER_LAND_DEBUG
+#include "net_alias.h"
+#include "user_stubs.h"
+#endif
+
+#include <linux/net_alias.h>
+
+/*
+ * Only allow the following flags to pass from main device to aliases
+ */
+
+#define  NET_ALIAS_IFF_MASK   (IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_NOARP|IFF_LOOPBACK|IFF_POINTOPOINT)
+
+static struct net_alias_type * nat_getbytype(int type);
+static int nat_attach_chg(struct net_alias_type *nat, int delta);
+static int nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa);
+static int nat_unbind(struct net_alias_type *nat, struct net_alias *alias);
+
+
+static int net_alias_devinit(struct device *dev);
+static int net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev);
+static int net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat, struct sockaddr *sa);
+static struct net_alias **net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias);
+static struct device *net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data);
+static struct device *net_alias_dev_delete(struct device *main_dev, int slot, int *err);
+static void net_alias_free(struct device *dev);
+					   
+/*
+ * net_alias_type base array, will hold net_alias_type objects.
+ */
+
+struct net_alias_type *nat_base[16];
+
+
+/*
+ * get net_alias_type ptr by type
+ */
+
+static __inline__ struct net_alias_type *
+nat_getbytype(int type)
+{
+  struct net_alias_type *nat;
+  for(nat = nat_base[type & 0x0f]; nat ; nat = nat->next)
+  {
+    if (nat->type == type) return nat;
+  }
+  return NULL;
+}
+
+
+/*
+ * get addr32 representation (pre-hashing) of address.
+ * if NULL nat->get_addr32, assume sockaddr_in struct (IP-ish).
+ */
+
+static __inline__ __u32
+nat_addr32(struct net_alias_type *nat, struct sockaddr *sa)
+{
+  if (nat->get_addr32)
+    return nat->get_addr32(sa);
+  else
+    return (*(struct sockaddr_in *)sa).sin_addr.s_addr;
+}
+
+
+/*
+ * hashing code for alias_info->hash_tab entries
+ * 4 bytes -> 1/2 byte using xor condimented by af
+ */
+
+static __inline__ unsigned
+HASH(__u32 addr, int af)
+{
+  unsigned tmp = addr ^ (addr>>16); /* 4 -> 2 */
+  tmp ^= (tmp>>8);                  /* 2 -> 1 */
+  return (tmp^(tmp>>4)^af) & 0x0f;	    /* 1 -> 1/2 */
+}
+
+
+/*
+ * 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
+ * address to a hash code.
+ */
+
+static __inline__ int
+nat_hash_key(struct net_alias_type *nat, struct sockaddr *sa)
+{
+  return HASH(nat_addr32(nat,sa), sa->sa_family);
+}
+
+
+/*
+ * change net_alias_type number of attachments (bindings)
+ */
+
+static int
+nat_attach_chg(struct net_alias_type *nat, int delta)
+{
+  unsigned long flags;
+  int n_at;
+  if (!nat) return -1;
+  save_flags(flags);
+  cli();
+  n_at = nat->n_attach + delta;
+  if (n_at < 0)
+  {
+    restore_flags(flags);
+    printk("net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
+	   nat->type);
+    return -1;
+  }
+  nat->n_attach = n_at;
+  restore_flags(flags);
+  return 0;
+}
+
+
+/*
+ * bind alias to its type (family) object and call initialization hook
+ */
+
+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);
+  return nat_attach_chg(nat, +1);
+}
+
+
+/*
+ * unbind alias from type object and call 'done' hook
+ */
+
+static __inline__ int
+nat_unbind(struct net_alias_type *nat, struct net_alias *alias)
+{
+  if (nat->alias_done_1) nat->alias_done_1(alias);
+  return nat_attach_chg(nat, -1);
+}
+
+
+/*
+ * compare device address with given. if NULL nat->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,
+				   struct device *dev, struct sockaddr *sa)
+{
+  if (nat->addr_chk)
+    return nat->addr_chk(dev, sa);
+  else
+    return (dev->pa_addr == (*(struct sockaddr_in *)sa).sin_addr.s_addr);
+}
+
+
+/*
+ * alias device init()
+ * do nothing.
+ */
+
+static int 
+net_alias_devinit(struct device *dev)
+{
+#ifdef ALIAS_USER_LAND_DEBUG
+  printk("net_alias_devinit(%s) called.\n", dev->name);
+#endif
+  return 0;
+}
+
+
+/*
+ * hard_start_xmit() should not be called.
+ * ignore ... but shout!.
+ */
+
+static int
+net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+  printk("net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
+  dev_kfree_skb(skb, FREE_WRITE);
+  return 0;
+}
+
+
+/*
+ * setups a new (alias) device 
+ */
+
+static int
+net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat,
+		struct sockaddr *sa)
+{
+  struct device *main_dev;
+  struct device *dev;
+  int family;
+  int i;
+
+  /*
+   *
+   * generic device setup based on main_dev info
+   *
+   * FIXME: is NULL bitwise 0 for all Linux platforms?
+   */
+  
+  main_dev = alias->main_dev;
+  dev = &alias->dev;
+  memset(dev, '\0', sizeof(struct device));
+  family = (sa)? sa->sa_family : main_dev->family;
+
+  dev->alias_info = NULL;	/* no aliasing recursion */
+  dev->my_alias = alias;	/* point to alias */
+  dev->name = alias->name;
+  dev->type = main_dev->type;
+  dev->hard_header_len = main_dev->hard_header_len;
+  memcpy(dev->broadcast, main_dev->broadcast, MAX_ADDR_LEN);
+  memcpy(dev->dev_addr, main_dev->dev_addr, MAX_ADDR_LEN);
+  dev->addr_len = main_dev->addr_len;
+  dev->init = net_alias_devinit;
+  dev->hard_start_xmit = net_alias_hard_start_xmit;
+  dev->flags = main_dev->flags & NET_ALIAS_IFF_MASK & ~IFF_UP;
+
+  /*
+   * only makes sense if same family
+   */
+  
+  if (family == main_dev->family)
+  {
+    dev->metric = main_dev->metric;
+    dev->mtu = main_dev->mtu;
+    dev->pa_alen = main_dev->pa_alen;
+    dev->hard_header = main_dev->hard_header;
+    dev->rebuild_header = main_dev->rebuild_header;
+  }
+  
+  /*
+   *	Fill in the generic fields of the device structure.
+   *    not actually used, avoids some dev.c #ifdef's
+   */
+  
+  for (i = 0; i < DEV_NUMBUFFS; i++)
+    skb_queue_head_init(&dev->buffs[i]);
+  
+  dev->family = family;
+  return 0;
+}
+
+
+/*
+ * slow alias find (parse the whole hash_tab)
+ * returns: alias' pointer address
+ */
+
+static struct net_alias **
+net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias)
+{
+  unsigned idx, n_aliases;
+  struct net_alias **aliasp;
+
+  /*
+   * for each alias_info's hash_tab entry, for every alias ...
+   */
+  
+  n_aliases = alias_info->n_aliases;
+  for (idx=0; idx < 16 ; idx++)
+    for (aliasp = &alias_info->hash_tab[idx];*aliasp;aliasp = &(*aliasp)->next)
+      if (*aliasp == alias)
+	return aliasp;
+      else
+	if (--n_aliases == 0) break; /* faster give up */
+  return NULL;
+}
+
+
+/*
+ * create alias device for main_dev with given slot num.
+ * if sa==NULL will create a same_family alias device 
+ */
+
+static struct device *
+net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data)
+{
+  struct net_alias_info *alias_info;
+  struct net_alias *alias, **aliasp;
+  struct net_alias_type *nat;
+  struct device *dev;
+  unsigned long flags;
+  int family;
+  __u32 addr32;
+  
+  /* FIXME: lock */
+  alias_info = main_dev->alias_info;
+
+  /*
+   * if NULL address given, take family from main_dev
+   */
+  
+  family = (sa)? sa->sa_family : main_dev->family;
+  
+  /*
+   * check if wanted family has a net_alias_type object registered
+   */
+  
+  nat = nat_getbytype(family);
+  if (!nat)
+  {
+    printk("net_alias_dev_create(%s:%d): unregistered family==%d\n",
+	   main_dev->name, slot, family);
+    /* *err = -EAFNOSUPPORT; */
+    *err = -EINVAL;
+    return NULL;
+  }
+  
+  /*
+   * do not allow creation over downed devices
+   */
+
+  *err = -EIO;
+  
+  if (! (main_dev->flags & IFF_UP) )
+    return NULL;
+  
+  /*
+   * if first alias, must also create alias_info
+   */
+      
+  *err = -ENOMEM;
+
+  if (!alias_info)
+  { 
+    alias_info = kmalloc(sizeof(struct net_alias_info), GFP_KERNEL);
+    if (!alias_info) return NULL; /* ENOMEM */
+    memset(alias_info, 0, sizeof(struct net_alias_info));
+  }
+  
+  if (!(alias = kmalloc(sizeof(struct net_alias), GFP_KERNEL)))
+    return NULL;		/* ENOMEM */
+
+  /*
+   * FIXME: is NULL bitwise 0 for all Linux platforms?
+   */
+  
+  memset(alias, 0, sizeof(struct net_alias));
+  alias->slot = slot;
+  alias->main_dev = main_dev;
+  alias->nat = nat;
+  alias->next = NULL;
+  alias->data = data;
+  sprintf(alias->name, "%s:%d", main_dev->name, slot);
+  
+  /*
+   * initialise alias' device structure
+   */
+  
+  net_alias_devsetup(alias, nat, sa);
+
+  dev = &alias->dev;
+  
+  save_flags(flags);
+  cli();
+
+  /*
+   * bind alias to its object type
+   * nat_bind calls nat->alias_init_1
+   */
+  
+  nat_bind(nat, alias, sa);
+
+  /*
+   * if no address passed, take from device (could have been
+   * set by nat->alias_init_1)
+   */
+  
+  addr32 = (sa)? nat_addr32(nat, sa) : alias->dev.pa_addr;
+  
+  /*
+   * store hash key in alias: will speed-up rehashing and deletion
+   */
+  
+  alias->hash = HASH(addr32, family);
+
+  /*
+   * insert alias in hashed linked list
+   */
+  
+  aliasp = &alias_info->hash_tab[alias->hash];
+  alias->next = *aliasp;	
+  *aliasp = alias;
+
+  /*
+   * if first alias ...
+   */
+  
+  if (!alias_info->n_aliases++)
+  {
+    alias_info->taildev = main_dev;
+    main_dev->alias_info = alias_info;
+  }
+  
+  /*
+   * add device at tail (just after last main_dev alias)
+   */
+  
+  dev->next = alias_info->taildev->next;
+  alias_info->taildev->next = dev;
+  alias_info->taildev = dev;
+  restore_flags(flags);
+  return dev;
+}
+
+
+/*
+ * delete one main_dev alias (referred by its slot num)
+ */
+
+static struct device *
+net_alias_dev_delete(struct device *main_dev, int slot, int *err)
+{
+  struct net_alias_info *alias_info;
+  struct net_alias *alias, **aliasp;
+  struct device *dev;
+  unsigned n_aliases;
+  unsigned long flags;
+  struct net_alias_type *nat;
+  struct device *prevdev;
+  
+  /* FIXME: lock */
+  *err = -ENODEV;
+  
+  if (main_dev == NULL) return NULL;
+
+  /*
+   * does main_dev have aliases?
+   */
+  
+  alias_info = main_dev->alias_info;
+  if (!alias_info) return NULL;	/* ENODEV */
+  
+  n_aliases = alias_info->n_aliases;
+  
+  /*
+   * find device that holds the same slot number (could also
+   * be strcmp() ala dev_get).
+   */
+  
+  for (prevdev=main_dev, alias = NULL;prevdev->next && n_aliases; prevdev = prevdev->next)
+  {
+    if (!(alias = prevdev->next->my_alias))
+    {
+      printk("ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
+      continue;			/* or should give up? */
+    }
+    if (alias->slot == slot) break;
+    alias = NULL;
+    n_aliases--;
+  }
+  
+  if (!alias) return NULL;	/* ENODEV */
+  
+  dev = &alias->dev;
+  
+  /*
+   * find alias hashed entry
+   */
+  
+  for(aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
+    if(*aliasp == alias) break;
+
+  /*
+   * if not found (???), try a full search
+   */
+  
+  if (*aliasp != alias)
+    if ((aliasp = net_alias_slow_findp(alias_info, alias)))
+      printk("net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
+    else
+    {
+      printk("ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
+      return NULL;		/* ENODEV */
+    }
+  
+  nat = alias->nat;
+
+  save_flags(flags);
+  cli();
+  
+  /*
+   * unbind alias from alias_type obj.
+   */
+  
+  nat_unbind(nat, alias);
+  
+  /*
+   * is alias at tail?
+   */
+  
+  if ( dev == alias_info->taildev )
+    alias_info->taildev = prevdev;
+  
+  /*
+   * unlink and close device
+   */
+  prevdev->next = dev->next;
+  dev_close(dev);
+  
+  /*
+   * unlink alias
+   */
+  
+  *aliasp = (*aliasp)->next;
+
+  if (--alias_info->n_aliases == 0) /* last alias */
+    main_dev->alias_info = NULL;
+  restore_flags(flags);
+
+  /*
+   * now free structures
+   */
+  
+  kfree_s(alias, sizeof(struct net_alias));
+  if (main_dev->alias_info == NULL)
+    kfree_s(alias_info, sizeof(struct net_alias_info));
+
+  /*
+   * deletion ok (*err=0), NULL device returned.
+   */
+  
+  *err = 0;
+  return NULL;
+}
+
+
+/*
+ * dev_get() with added alias naming magic.
+ */
+
+struct device *
+net_alias_dev_get(char *dev_name, int aliasing_ok, int *err,
+		  struct sockaddr *sa, void *data)
+{
+  struct device *dev;
+  char *sptr,*eptr;
+  int slot = 0;
+  int delete = 0;
+  
+  *err = -ENODEV;
+  if ((dev=dev_get(dev_name)))
+    return dev;
+
+  /*
+   * want alias naming magic?
+   */
+  
+  if (!aliasing_ok) return NULL;
+
+  if (!dev_name || !*dev_name)
+    return NULL;
+  
+  /*
+   * find the first ':' , must be followed by, at least, 1 char
+   */
+  
+  for (sptr=dev_name ; *sptr ; sptr++) if(*sptr==':') break;
+  if (!*sptr || !*(sptr+1))
+    return NULL;
+  
+  /*
+   * seems to be an alias name, fetch main device
+   */
+  
+  *sptr='\0';
+  if (!(dev=dev_get(dev_name)))
+    return NULL;
+  *sptr++=':';
+  
+  /*
+   * fetch slot number
+   */
+  
+  slot = simple_strtoul(sptr,&eptr,10);
+  if (slot >= NET_ALIAS_MAX_SLOT)
+    return NULL;
+
+  /*
+   * if last char is '-', it is a deletion request
+   */
+  
+  if (eptr[0] == '-' && !eptr[1] ) delete++;
+  else if (eptr[0])
+    return NULL;
+  
+  /*
+   * well... let's work.
+   */
+  
+  if (delete)
+    return net_alias_dev_delete(dev, slot, err);
+  else
+    return net_alias_dev_create(dev, slot, err, sa, data);
+}
+
+
+/*
+ * rehash alias with address supplied. 
+ */
+
+int
+net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
+{
+  struct net_alias_info *alias_info;
+  struct net_alias **aliasp;
+  struct device *dev;
+  unsigned long flags;
+  struct net_alias_type *o_nat, *n_nat;
+  unsigned n_hash;
+  
+  /*
+   * defensive ...
+   */
+  
+  if (!sa)
+  {
+    printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
+    return -1;
+  }
+
+  /*
+   * defensive. should not happen.
+   */
+  
+  if (!(dev = alias->main_dev))
+  {
+    printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
+    return -1;
+  }
+
+  /*
+   * defensive. should not happen.
+   */
+
+  if (!(alias_info=dev->alias_info))
+  {
+    printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
+    return -1;
+  }
+  
+  /*
+   * will the request also change device family?
+   */
+  
+  o_nat = alias->nat;
+  if (!o_nat)
+  {
+    printk("ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
+    return -1;
+  }
+
+  /*
+   * point to new alias_type obj.
+   */
+  
+  if (o_nat->type == sa->sa_family)
+    n_nat = o_nat;
+  else
+  {
+    n_nat = nat_getbytype(sa->sa_family);
+    if (!n_nat)
+    {
+      printk("ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
+      return -1;
+    }
+  }
+  
+  /*
+   * new hash key. if same as old AND same type (family) return;
+   */
+  
+  n_hash = nat_hash_key(n_nat, sa);
+  if (n_hash == alias->hash && o_nat == n_nat )
+    return 0;
+
+  /*
+   * find alias in hashed list
+   */
+  
+  for (aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
+    if (*aliasp == alias) break;
+  
+  /*
+   * not found (???). try a full search
+   */
+  
+  if(!*aliasp)
+    if ((aliasp = net_alias_slow_findp(alias_info, alias)))
+      printk("net_alias_rehash(%s): bad hashing recovered\n", alias->name);
+    else
+    {
+      printk("ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
+      return -1;
+    }
+  
+  save_flags(flags);
+  cli();
+  
+  /*
+   * if type (family) changed unlink from old type object (o_nat)
+   * will call o_nat->alias_done_1()
+   */
+  
+  if (o_nat != n_nat)
+    nat_unbind(o_nat, alias);
+
+  /*
+   * if diff hash key, change alias position in hashed list
+   */
+  
+  if (n_hash != alias->hash)
+  {
+    *aliasp = (*aliasp)->next;
+    alias->hash = n_hash;
+    aliasp = &alias_info->hash_tab[n_hash];
+    alias->next = *aliasp;
+    *aliasp = alias;
+  }
+  
+  /*
+   * if type (family) changed link to new type object (n_nat)
+   * will call n_nat->alias_init_1()
+   */
+  
+  if (o_nat != n_nat)
+    nat_bind(n_nat, alias, sa);
+  
+  restore_flags(flags);
+  return 0;
+}
+
+
+/*
+ * 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;
+}
+
+
+/*
+ *  implements /proc/net/alias_types entry
+ *  shows net_alias_type objects registered.
+ */
+
+int net_alias_types_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+  off_t pos=0, begin=0;
+  int len=0;
+  struct net_alias_type *nat;
+  unsigned idx;
+  len=sprintf(buffer,"type    name            n_attach\n");
+  for (idx=0 ; idx < 16 ; idx++)
+    for (nat = nat_base[idx]; nat ; nat = nat->next)
+    {
+      len += sprintf(buffer+len, "%-7d %-15s %-7d\n",
+		     nat->type, nat->name,nat->n_attach);
+      pos=begin+len;
+      if(pos<offset)
+      {
+	len=0;
+	begin=pos;
+      }
+      if(pos>offset+length)
+	break;
+    }
+  *start=buffer+(offset-begin);
+  len-=(offset-begin);
+  if(len>length)
+    len=length;	
+  return len;
+}
+
+
+/*
+ *  implements /proc/net/aliases entry, shows alias devices.
+ *   calls alias nat->alias_print_1 if not NULL and formats everything
+ *   to a fixed rec. size without using local (stack) buffers
+ *
+ */
+
+#define NAT_REC_SIZE 64
+int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+  off_t pos=0, begin=0;
+  int len=0;
+  int dlen;
+  struct net_alias_type *nat;
+  struct net_alias *alias;
+  struct device *dev;
+
+  len=sprintf(buffer,"%-*s\n",NAT_REC_SIZE-1,"device           family address");
+  for (dev = dev_base; dev ; dev = dev->next)
+    if (net_alias_is(dev))
+    {
+      alias = dev->my_alias;
+      nat = alias->nat;
+      dlen=sprintf(buffer+len, "%-16s %-6d ", alias->name, alias->dev.family);
+      
+      /*
+       * call alias_type specific print function.
+       */
+      
+      if (nat->alias_print_1)
+	dlen += nat->alias_print_1(buffer+len+dlen, NAT_REC_SIZE - dlen, alias);
+      else
+	dlen += sprintf(buffer+len+dlen, "-");
+
+      /*
+       * fill with spaces if needed 
+       */
+      
+      if (dlen < NAT_REC_SIZE) memset(buffer+len+dlen, ' ', NAT_REC_SIZE - dlen);
+      /*
+       * truncate to NAT_REC_SIZE
+       */
+      
+      len += NAT_REC_SIZE;
+      buffer[len-1] = '\n';
+      
+      pos=begin+len;
+      if(pos<offset)
+      {
+	len=0;
+	begin=pos;
+      }
+      if(pos>offset+length)
+	break;
+    }
+  *start=buffer+(offset-begin);
+  len-=(offset-begin);
+  if(len>length)
+    len=length;	
+  return len;
+}
+
+
+/*
+ * notifier for devices events
+ */
+
+int net_alias_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+  struct device *dev = ptr;
+
+  if (event == NETDEV_DOWN)
+  {
+#ifdef ALIAS_USER_LAND_DEBUG
+    printk("net_alias: NETDEV_DOWN for %s received\n", dev->name);
+#endif
+    if (net_alias_has(dev))
+      net_alias_free(dev);
+  }
+
+  if (event == NETDEV_UP)
+  {
+#ifdef ALIAS_USER_LAND_DEBUG
+    printk("net_alias: NETDEV_UP for %s received\n", dev->name);
+#endif
+    dev->alias_info = 0;
+  }
+
+  return NOTIFY_DONE;
+}
+
+
+/*
+ * 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.
+ */
+
+struct device *
+net_alias_chk(struct device *dev, struct sockaddr *sa,int flags_1, int flags_0)
+{
+  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.
+     */
+    
+    if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
+	nat_addr_chk(nat,&alias->dev,sa))
+      return &alias->dev;
+  }
+  return NULL;
+}
+
+/*
+ * addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
+ */
+
+struct device *
+net_alias_chk32(struct device *dev, int family, __u32 addr32,
+		int flags_1, int flags_0)
+{
+  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)
+  {
+    if (alias->dev.family != family) continue;
+    
+    /*
+     * "hard" (static) comparison between addr32 and pa_addr.
+     */
+    
+    if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
+	addr32 == alias->dev.pa_addr)
+      return &alias->dev;
+  }
+  return NULL;
+}
+
+
+/*
+ * device event hook
+ */
+
+static struct notifier_block net_alias_dev_notifier = {
+  net_alias_device_event,
+  NULL,
+  0
+};
+
+
+/*
+ * net_alias initialisation
+ * called from net_dev_init().
+ */
+
+void net_alias_init(void)
+{
+
+  /*
+   * register dev events notifier
+   */
+  
+  register_netdevice_notifier(&net_alias_dev_notifier);
+
+  /*
+   * register /proc/net entries
+   */
+  
+#ifndef ALIAS_USER_LAND_DEBUG
+  proc_net_register(&(struct proc_dir_entry) {
+    PROC_NET_ALIAS_TYPES, 11, "alias_types",
+    S_IFREG | S_IRUGO, 1, 0, 0,
+    0, &proc_net_inode_operations,
+    net_alias_types_getinfo
+  });
+  proc_net_register(&(struct proc_dir_entry) {
+    PROC_NET_ALIASES, 7, "aliases",
+    S_IFREG | S_IRUGO, 1, 0, 0,
+    0, &proc_net_inode_operations,
+    net_alias_getinfo
+  });
+#endif
+  
+}
+
+/*
+ * net_alias type object registering func.
+ */
+int register_net_alias_type(struct net_alias_type *nat, int type)
+{
+  unsigned hash;
+  unsigned long flags;
+  if (!nat)
+  {
+    printk("register_net_alias_type(): NULL arg\n");
+    return -EINVAL;
+  }
+  nat->type = type;
+  nat->n_attach = 0;
+  hash = nat->type & 0x0f;
+  save_flags(flags);
+  cli();
+  nat->next = nat_base[hash];
+  nat_base[hash] = nat;
+  restore_flags(flags);
+  return 0;
+}
+
+/*
+ * net_alias type object unreg.
+ */
+int unregister_net_alias_type(struct net_alias_type *nat)
+{
+  struct net_alias_type **natp;
+  unsigned hash;
+  unsigned long flags;
+  
+  if (!nat)
+  {
+    printk("unregister_net_alias_type(): NULL arg\n");
+    return -EINVAL;
+  }
+
+  /*
+   * only allow unregistration if it has no attachments
+   */
+  if (nat->n_attach)
+  {
+    printk("unregister_net_alias_type(): has %d attachments. failed\n",
+	   nat->n_attach);
+    return -EINVAL;
+  }
+  hash = nat->type & 0x0f;
+  save_flags(flags);
+  cli();
+  for (natp = &nat_base[hash]; *natp ; natp = &(*natp)->next)
+  {
+    if (nat==(*natp))
+    {
+      *natp = nat->next;
+      restore_flags(flags);
+      return 0;
+    }
+  }
+  restore_flags(flags);
+  printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
+  return -EINVAL;
+}
diff -u --recursive --new-file v1.3.46/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- v1.3.46/linux/net/ipv4/Config.in	Fri Nov 17 08:42:33 1995
+++ linux/net/ipv4/Config.in	Tue Dec 12 07:05:07 1995
@@ -17,6 +17,9 @@
     bool 'IP: multicast routing(in progress)' CONFIG_IP_MROUTE
   fi
 fi
+if [ "$CONFIG_NET_ALIAS" = "y" ]; then
+	tristate 'IP: aliasing support' CONFIG_IP_ALIAS
+fi
 comment '(it is safe to leave these untouched)'
 bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
 tristate 'IP: Reverse ARP' CONFIG_INET_RARP
diff -u --recursive --new-file v1.3.46/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v1.3.46/linux/net/ipv4/Makefile	Thu Nov  9 11:23:56 1995
+++ linux/net/ipv4/Makefile	Tue Dec 12 07:05:07 1995
@@ -36,6 +36,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_IP_ALIAS),y)
+IPV4_OBJS += ip_alias.o
+else
+  ifeq ($(CONFIG_IP_ALIAS),m)
+  M_OBJS += ip_alias.o
+  endif
+endif
+
 ifdef CONFIG_INET
 O_OBJS := $(IPV4_OBJS)
 endif
diff -u --recursive --new-file v1.3.46/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v1.3.46/linux/net/ipv4/af_inet.c	Sat Nov 25 19:04:57 1995
+++ linux/net/ipv4/af_inet.c	Tue Dec 12 07:05:07 1995
@@ -88,6 +88,9 @@
 #include <net/raw.h>
 #include <net/icmp.h>
 #include <linux/ip_fw.h>
+#ifdef CONFIG_IP_ALIAS
+#include <net/ip_alias.h>
+#endif
 
 #define min(a,b)	((a)<(b)?(a):(b))
 
@@ -1530,6 +1533,13 @@
 	ip_mr_init();
 #endif
 
+	/*
+	 *  Initialise AF_INET alias type (register net_alias_type)
+	 */
+
+#if defined(CONFIG_IP_ALIAS)
+	ip_alias_init();
+#endif
 	/*
 	 *	Create all the /proc entries.
 	 */
diff -u --recursive --new-file v1.3.46/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.46/linux/net/ipv4/arp.c	Mon Dec 11 15:42:10 1995
+++ linux/net/ipv4/arp.c	Tue Dec 12 07:05:07 1995
@@ -96,6 +96,9 @@
 #include <net/netrom.h>
 #endif
 #endif
+#ifdef CONFIG_NET_ALIAS
+#include <linux/net_alias.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -891,6 +894,19 @@
  *  cache.
  */
 
+/*
+ *	try to switch to alias device whose address is tip, if any
+ */
+
+#ifdef CONFIG_NET_ALIAS
+	if (net_alias_has(dev))
+	{
+		struct device *adev;
+		adev = net_alias_chk32(dev,AF_INET,tip,IFF_UP,IFF_NOARP);
+		if (adev != NULL) dev = adev;
+	}
+#endif
+
 	if (arp->ar_op == htons(ARPOP_REQUEST))
 	{ 
 /*
@@ -1019,7 +1035,15 @@
 		entry->timer.data = (unsigned long)entry;
 		memcpy(entry->ha, sha, dev->addr_len);
 		entry->last_updated = entry->last_used = jiffies;
+/*
+ *	make entry point to	'correct' device
+ */
+
+#ifdef CONFIG_NET_ALIAS
+		entry->dev = dev;
+#else
 		entry->dev = skb->dev;
+#endif
 		skb_queue_head_init(&entry->skb);
 		if (arp_lock == 1)
 		{
diff -u --recursive --new-file v1.3.46/linux/net/ipv4/ip_alias.c linux/net/ipv4/ip_alias.c
--- v1.3.46/linux/net/ipv4/ip_alias.c	Thu Jan  1 02:00:00 1970
+++ linux/net/ipv4/ip_alias.c	Tue Dec 12 07:45:59 1995
@@ -0,0 +1,108 @@
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/inet.h>
+
+#ifdef ALIAS_USER_LAND_DEBUG
+#include "net_alias.h"
+#include "ip_alias.h"
+#include "user_stubs.h"
+#endif
+
+#include <linux/net_alias.h>
+#include <net/ip_alias.h>
+
+/*
+ * AF_INET alias init
+ */
+static int 
+ip_alias_init_1(struct net_alias *alias, struct sockaddr *sa)
+{
+#ifdef ALIAS_USER_LAND_DEBUG
+  printk("alias_init(%s) called.\n", alias->name);
+#endif
+  MOD_INC_USE_COUNT;
+  return 0;
+}
+
+/*
+ * AF_INET alias done
+ */
+static int
+ip_alias_done_1(struct net_alias *alias)
+{
+#ifdef ALIAS_USER_LAND_DEBUG
+  printk("alias_done(%s) called.\n", alias->name);
+#endif
+  MOD_DEC_USE_COUNT;
+  return 0;
+}
+
+/*
+ * print address info
+ */
+
+int
+ip_alias_print_1(char *buf, int len, struct net_alias *alias)
+{
+  char *p;
+
+  p = (char *) &alias->dev.pa_addr;
+  return sprintf(buf, "%d.%d.%d.%d",
+		 (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
+}
+
+/*
+ * net_alias AF_INET type defn.
+ */
+
+struct net_alias_type ip_alias_type =
+{
+  AF_INET,			/* type */
+  0,				/* n_attach */
+  "ip",				/* name */
+  NULL,				/* get_addr32() */
+  NULL,				/* addr_chk() */
+  ip_alias_init_1,		/* alias_init_1() */
+  ip_alias_done_1,		/* alias_done_1() */
+  ip_alias_print_1,		/* alias_print_1() */
+  NULL				/* next */
+};
+
+/*
+ * ip_alias module initialization
+ */
+
+int ip_alias_init(void)
+{
+  return register_net_alias_type(&ip_alias_type, AF_INET);
+}
+
+/*
+ * ip_alias module done
+ */
+
+int ip_alias_done(void)
+{
+  return unregister_net_alias_type(&ip_alias_type);
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+  if (ip_alias_init() != 0)
+    return -EIO;
+  return 0;
+}
+
+void cleanup_module(void)
+{
+  if (ip_alias_done() != 0)
+    printk("ip_alias: can't remove module");
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v1.3.46/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v1.3.46/linux/net/ipv4/ip_input.c	Mon Oct 23 18:02:23 1995
+++ linux/net/ipv4/ip_input.c	Tue Dec 12 07:05:07 1995
@@ -151,6 +151,9 @@
 #include <linux/firewall.h>
 #include <linux/mroute.h>
 #include <net/netlink.h>
+#ifdef CONFIG_NET_ALIAS
+#include <linux/net_alias.h>
+#endif
 
 extern int last_retran;
 extern void sort_send(struct sock *sk);
@@ -313,7 +316,18 @@
 	 *	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) 
 	        {
diff -u --recursive --new-file v1.3.46/linux/scripts/Configure linux/scripts/Configure
--- v1.3.46/linux/scripts/Configure	Wed Nov  8 07:11:47 1995
+++ linux/scripts/Configure	Mon Dec 11 15:41:12 1995
@@ -20,6 +20,8 @@
 # 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for
 # use with a config.in modified for make menuconfig.
 #
+# 301195 (boldt@math.ucsb.edu) - added help text support
+#
 
 #
 # Make sure we're really running bash.
@@ -45,6 +47,37 @@
 }
 
 #
+# help prints the corresponding help text from Configure.help to stdout
+#
+#       help variable
+#
+function help () {
+  if [ -f Documentation/Configure.help ]
+  then
+     #first escape regexp special characters in the argument:
+     var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
+     #now pick out the right help text:
+     text=$(sed -n "/^$var[ 	]*\$/,\${
+                        /^$var[ 	]*\$/b
+                        /^#.*/b;/^[ 	]*\$/q
+                        p
+                    }" Documentation/Configure.help)
+     if [ -z "$text" ]
+     then
+          echo; echo "  Sorry, no help available for this option yet.";echo
+     else
+          (echo; echo "$text"; echo) | more
+     fi
+  else
+     echo;
+     echo "  Can't access the file Documentation/Configure.help which"
+     echo "  should contain the help texts."
+     echo
+  fi
+}
+
+
+#
 # readln reads a line into $ans.
 #
 #	readln prompt default
@@ -78,17 +111,17 @@
 #
 function define_bool () {
         case "$2" in
-         "y" | "Y")
+         "y")
 		echo "$1=y" >>$CONFIG
 		echo "#define $1 1" >>$CONFIG_H
 		;;
 
-         "m" | "M")
+         "m")
 		echo "$1=m" >>$CONFIG
 		echo "#undef  $1" >>$CONFIG_H
 		;;
 
-         "n" | "N")
+         "n")
 		echo "# $1 is not set" >>$CONFIG
 		echo "#undef  $1" >>$CONFIG_H
                 ;;
@@ -102,18 +135,24 @@
 #	bool question define
 #
 function bool () {
-	ans=""
 	def=$(eval echo "\${$2:-'n'}")
         case "$def" in
-         "y") defprompt="Y/n"
+         "y") defprompt="Y/n/?"
               ;;
-         "n") defprompt="N/y"
+         "n") defprompt="N/y/?"
               ;;
         esac
-	while [ "$ans" != "y" -a "$ans" != "n" ]; do
-		readln "$1 ($2) [$defprompt] " "$def" 
-	done
-	define_bool "$2" "$ans"
+        while :; do
+          readln "$1 ($2) [$defprompt] " "$def"
+          case "$ans" in
+            [yY] | [yY]es ) define_bool "$2" "y"
+                            break;;
+            [nN] | [nN]o )  define_bool "$2" "n"
+                            break;;
+            * )             help "$2"
+                            ;;
+          esac
+        done
 }
 
 #
@@ -122,20 +161,28 @@
 #	tristate question define
 #
 function tristate () {
-	ans=""
 	def=$(eval echo "\${$2:-'n'}")
         case "$def" in
-         "y") defprompt="Y/m/n"
+         "y") defprompt="Y/m/n/?"
               ;;
-         "m") defprompt="M/n/y"
+         "m") defprompt="M/n/y/?"
               ;;
-         "n") defprompt="N/y/m"
+         "n") defprompt="N/y/m/?"
               ;;
         esac
-	while [ "$ans" != "y" -a "$ans" != "n" -a "$ans" != "m" ]; do
-		readln "$1 ($2) [$defprompt] " "$def"
-	done
-	define_bool "$2" "$ans"
+        while :; do
+          readln "$1 ($2) [$defprompt] " "$def"
+          case "$ans" in
+            [yY] | [yY]es ) define_bool "$2" "y"
+                            break ;;
+            [nN] | [nN]o )  define_bool "$2" "n"
+                            break ;;
+            [mM] )          define_bool "$2" "m"
+                            break ;;
+	    * )             help "$2"
+                            ;;
+          esac
+        done
 }
 
 #
@@ -153,18 +200,32 @@
 	if [ "$3" != "m" ]; then
 		tristate "$1" "$2"
 	else
-		ans=""
 	        case "$def" in
-        	 "y" | "m") defprompt="M/n"
+        	 "y" | "m") defprompt="M/n/?"
 		      def="m"
         	      ;;
-        	 "n") defprompt="N/m"
+        	 "n") defprompt="N/m/?"
         	      ;;
 	        esac
-		while [ "$ans" != "n" -a "$ans" != "m" ]; do
-			readln "$1 ($2) [$defprompt] " "$def"
-		done
-		define_bool "$2" "$ans"
+                while :; do
+                  readln "$1 ($2) [$defprompt] " "$def"
+                  case "$ans" in
+                      [nN] | [nN]o )  define_bool "$2" "n"
+                                      break ;;
+                      [mM] )          define_bool "$2" "m"
+                                      break ;;
+                      [yY] | [yY]es ) echo 
+   echo "  This answer is not allowed, because it is not consistent with"
+   echo "  your other choices."
+   echo "  This driver depends on another one which you chose to compile"
+   echo "  as a module. This means that you can either compile this one"
+   echo "  as a module as well (with M) or leave it out altogether (N)."
+                                      echo
+                                      ;;
+                      * )             help "$2"
+                                      ;;
+                  esac
+                done
 	fi
 }
 
@@ -185,13 +246,17 @@
 #	int question define default
 #
 function int () {
-	# Slimier hack to get bash to rescan a line.
-	ans="x"
 	def=$(eval echo "\${$2:-$3}")
-	while [ $[$ans+0] != "$ans" ]; do
-		readln "$1 ($2) [$def] " "$def"
-	done
-	define_int "$2" "$ans"
+        while :; do
+          readln "$1 ($2) [$def] " "$def"
+          case "$ans" in
+             [1-9] | [1-9][0-9] | [1-9][0-9][0-9] | [1-9][0-9][0-9][0-9] ) 
+                 define_int "$2" "$ans"
+                 break;;
+             * ) help "$2"
+                 ;;
+          esac
+        done
 }
 
 #
@@ -216,6 +281,7 @@
 	# determine default answer:
 	names=""
 	set -- $choices
+        firstvar=$2
 	while [ -n "$2" ]; do
 		if [ -n "$names" ]; then
 			names="$names, $1"
@@ -230,29 +296,34 @@
 
 	val=""
 	while [ -z "$val" ]; do
+                ambg=n
 		readln "$question ($names) [$def] " "$def"
 		ans=$(echo $ans | tr a-z A-Z)
 		set -- $choices
-		val=""
 		while [ -n "$1" ]; do
 			name=$(echo $1 | tr a-z A-Z)
 			case "$name" in
-				${ans}*)
+				"$ans"* )
 					if [ "$name" = "$ans" ]; then
 						val="$2"
 						break	# stop on exact match
 					fi
 					if [ -n "$val" ]; then
-						echo \
+						echo;echo \
 		"  Sorry, \"$ans\" is ambiguous; please enter a longer string."
+                                                echo
 						val=""
+                                                ambg=y
 						break
 					else
 						val="$2"
 					fi;;
 			esac
 			shift; shift
-		done
+                done
+	        if [ "$val" = "" -a "$ambg" = "n" ]; then
+                        help "$firstvar"
+                fi
 	done
 	set -- $choices
 	while [ -n "$2" ]; do
