]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.30 2.1.30
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:01 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:01 +0000 (15:13 -0500)
346 files changed:
CREDITS
Documentation/Configure.help
MAINTAINERS
Makefile
Rules.make
arch/alpha/kernel/alpha_ksyms.c
arch/alpha/kernel/entry.S
arch/alpha/kernel/process.c
arch/i386/defconfig
arch/i386/kernel/entry.S
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/irq.c
arch/i386/kernel/process.c
arch/i386/kernel/smp.c
arch/i386/kernel/time.c
arch/i386/kernel/traps.c
arch/m68k/kernel/m68k_ksyms.c
arch/sparc/defconfig
arch/sparc/kernel/setup.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/unaligned.c
arch/sparc/lib/Makefile
arch/sparc/lib/clear_user.S [deleted file]
arch/sparc/mm/Makefile
arch/sparc/mm/fault.c
arch/sparc/mm/hypersparc.S [new file with mode: 0644]
arch/sparc/mm/srmmu.c
arch/sparc/prom/console.c
arch/sparc/prom/devops.c
arch/sparc/prom/init.c
arch/sparc/prom/memory.c
arch/sparc/prom/mp.c
arch/sparc/prom/tree.c
arch/sparc64/Makefile
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/auxio.c [new file with mode: 0644]
arch/sparc64/kernel/cpu.c [new file with mode: 0644]
arch/sparc64/kernel/devices.c [new file with mode: 0644]
arch/sparc64/kernel/entry.S [new file with mode: 0644]
arch/sparc64/kernel/etrap.S
arch/sparc64/kernel/hack.S
arch/sparc64/kernel/head.S
arch/sparc64/kernel/ioport.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/setup.c [new file with mode: 0644]
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/traps.c [new file with mode: 0644]
arch/sparc64/lib/Makefile
arch/sparc64/lib/checksum.S [new file with mode: 0644]
arch/sparc64/lib/locks.S [new file with mode: 0644]
arch/sparc64/lib/memcmp.S [new file with mode: 0644]
arch/sparc64/lib/memcpy.S [new file with mode: 0644]
arch/sparc64/lib/memscan.S [new file with mode: 0644]
arch/sparc64/lib/memset.S
arch/sparc64/lib/strlen.S [new file with mode: 0644]
arch/sparc64/lib/strlen_user.S [new file with mode: 0644]
arch/sparc64/lib/strncmp.S [new file with mode: 0644]
arch/sparc64/lib/strncpy_from_user.S [new file with mode: 0644]
arch/sparc64/mm/extable.c
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/prom/console.c
arch/sparc64/prom/init.c
arch/sparc64/prom/p1275.c
arch/sparc64/prom/printf.c
arch/sparc64/prom/ranges.c
arch/sparc64/vmlinux.lds
drivers/block/Config.in
drivers/block/README.hd [deleted file]
drivers/block/README.ide [deleted file]
drivers/block/floppy.c
drivers/block/ide-cd.c
drivers/block/ide-floppy.c
drivers/block/ide-tape.c
drivers/block/ide.c
drivers/block/ide.h
drivers/block/ll_rw_blk.c
drivers/block/triton.c
drivers/char/keyboard.c
drivers/char/misc.c
drivers/char/random.c
drivers/char/serial.c
drivers/char/softdog.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/vt.c
drivers/char/wdt.c
drivers/net/3c509.c
drivers/net/3c59x.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/bpqether.c
drivers/net/de4x5.c
drivers/net/hdlcdrv.c
drivers/net/lance.c
drivers/net/lance32.c [deleted file]
drivers/net/lapbether.c
drivers/net/ltpc.c
drivers/net/mkiss.c
drivers/net/myri_sbus.c
drivers/net/myri_sbus.h
drivers/net/pcnet32.c [new file with mode: 0644]
drivers/net/pi2.c
drivers/net/pi2.h [deleted file]
drivers/net/pt.c
drivers/net/pt.h [deleted file]
drivers/net/sk_g16.c
drivers/net/soundmodem/sm.c
drivers/net/soundmodem/sm_afsk1200.c
drivers/net/soundmodem/sm_sbc.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/sbus/char/bpp.c
drivers/sbus/char/bwtwo.c
drivers/sbus/char/cgthree.c
drivers/sbus/char/fb.h
drivers/sbus/char/suncons.c
drivers/sbus/char/sunfb.c
drivers/sbus/char/sunkbd.c
drivers/sbus/dvma.c
drivers/sbus/sbus.c
drivers/scsi/BusLogic.c
drivers/scsi/BusLogic.h
drivers/scsi/README.BusLogic
drivers/scsi/aha1740.c
drivers/scsi/aha1740.h
drivers/scsi/aic7xxx.c
drivers/scsi/seagate.c
fs/buffer.c
fs/inode.c
fs/msdos/msdosfs_syms.c
fs/namei.c
fs/proc/array.c
fs/proc/fd.c
fs/proc/generic.c
fs/proc/proc_tty.c
fs/smbfs/sock.c
fs/super.c
fs/umsdos/emd.c
include/asm-alpha/ide.h
include/asm-alpha/socket.h
include/asm-i386/atomic.h
include/asm-i386/bitops.h
include/asm-i386/hardirq.h [new file with mode: 0644]
include/asm-i386/ide.h
include/asm-i386/irq.h
include/asm-i386/smp_lock.h
include/asm-i386/socket.h
include/asm-i386/softirq.h [new file with mode: 0644]
include/asm-i386/spinlock.h [new file with mode: 0644]
include/asm-i386/system.h
include/asm-i386/termios.h
include/asm-m68k/ide.h
include/asm-m68k/socket.h
include/asm-m68k/termios.h
include/asm-mips/socket.h
include/asm-ppc/socket.h
include/asm-sparc/asm_offsets.h
include/asm-sparc/checksum.h
include/asm-sparc/dma.h
include/asm-sparc/init.h [new file with mode: 0644]
include/asm-sparc/kbio.h
include/asm-sparc/oplib.h
include/asm-sparc/pgtsrmmu.h
include/asm-sparc/ross.h
include/asm-sparc/semaphore.h
include/asm-sparc/socket.h
include/asm-sparc/system.h
include/asm-sparc64/auxio.h [new file with mode: 0644]
include/asm-sparc64/bitops.h
include/asm-sparc64/bpp.h [new file with mode: 0644]
include/asm-sparc64/byteorder.h
include/asm-sparc64/cache.h [new file with mode: 0644]
include/asm-sparc64/checksum.h
include/asm-sparc64/dma.h
include/asm-sparc64/floppy.h
include/asm-sparc64/head.h
include/asm-sparc64/init.h [new file with mode: 0644]
include/asm-sparc64/io.h
include/asm-sparc64/kbio.h
include/asm-sparc64/kdebug.h [new file with mode: 0644]
include/asm-sparc64/machines.h [new file with mode: 0644]
include/asm-sparc64/openprom.h
include/asm-sparc64/oplib.h
include/asm-sparc64/pgtable.h
include/asm-sparc64/processor.h
include/asm-sparc64/smp_lock.h
include/asm-sparc64/socket.h
include/asm-sparc64/system.h
include/asm-sparc64/termios.h
include/asm-sparc64/uaccess.h
include/asm-sparc64/unistd.h
include/asm-sparc64/vaddrs.h [new file with mode: 0644]
include/linux/blk.h
include/linux/elf.h
include/linux/etherdevice.h
include/linux/firewall.h
include/linux/hdlcdrv.h
include/linux/icmpv6.h
include/linux/in.h
include/linux/in6.h
include/linux/init.h
include/linux/interrupt.h
include/linux/ioport.h
include/linux/ipsec.h [new file with mode: 0644]
include/linux/ipv6_route.h
include/linux/mroute.h
include/linux/net.h
include/linux/netdevice.h
include/linux/notifier.h
include/linux/pi2.h [new file with mode: 0644]
include/linux/proc_fs.h
include/linux/pt.h [new file with mode: 0644]
include/linux/reboot.h [new file with mode: 0644]
include/linux/route.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/sysctl.h
include/linux/tqueue.h
include/net/addrconf.h
include/net/arp.h
include/net/ax25.h
include/net/br.h
include/net/dst.h
include/net/flow.h [new file with mode: 0644]
include/net/if_inet6.h
include/net/ip6_fib.h [new file with mode: 0644]
include/net/ip6_fw.h [new file with mode: 0644]
include/net/ip6_route.h [new file with mode: 0644]
include/net/ipv6.h
include/net/ipv6_route.h [deleted file]
include/net/ndisc.h
include/net/neighbour.h
include/net/netbeui.h
include/net/netlink.h
include/net/protocol.h
include/net/route.h
include/net/sock.h
include/net/tcp.h
init/main.c
kernel/exit.c
kernel/ksyms.c
kernel/panic.c
kernel/printk.c
kernel/resource.c
kernel/sched.c
kernel/signal.c
kernel/softirq.c
kernel/sys.c
kernel/time.c
mm/filemap.c
mm/kmalloc.c
mm/page_alloc.c
mm/slab.c
net/802/transit/timertr.h
net/Config.in
net/README
net/appletalk/ddp.c
net/ax25/Makefile
net/ax25/af_ax25.c
net/ax25/ax25_dev.c
net/ax25/ax25_ds_in.c [new file with mode: 0644]
net/ax25/ax25_ds_subr.c [new file with mode: 0644]
net/ax25/ax25_ds_timer.c [new file with mode: 0644]
net/ax25/ax25_in.c
net/ax25/ax25_ip.c
net/ax25/ax25_out.c
net/ax25/ax25_timer.c
net/ax25/sysctl_net_ax25.c
net/bridge/br.c
net/bridge/br_tree.c
net/core/dst.c
net/core/firewall.c
net/core/neighbour.c
net/core/skbuff.c
net/core/sock.c
net/ethernet/eth.c
net/ipv4/Makefile
net/ipv4/arp.c
net/ipv4/icmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_fw.c
net/ipv4/ip_input.c
net/ipv4/ip_masq_quake.c [new file with mode: 0644]
net/ipv4/ip_output.c
net/ipv4/ipip.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/timer.c
net/ipv4/udp.c
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/datagram.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/ip6_fib.c [new file with mode: 0644]
net/ipv6/ip6_fw.c [new file with mode: 0644]
net/ipv6/ip6_input.c [new file with mode: 0644]
net/ipv6/ip6_output.c [new file with mode: 0644]
net/ipv6/ipv6_input.c [deleted file]
net/ipv6/ipv6_output.c [deleted file]
net/ipv6/ipv6_route.c [deleted file]
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/proc.c [new file with mode: 0644]
net/ipv6/protocol.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c [new file with mode: 0644]
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipx/af_ipx.c
net/lapb/lapb_timer.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_route.c
net/netrom/nr_timer.c
net/netsyms.c
net/rose/af_rose.c
net/rose/rose_dev.c
net/rose/rose_link.c
net/rose/rose_route.c
net/rose/rose_timer.c
net/socket.c
net/unix/af_unix.c
net/x25/af_x25.c
net/x25/x25_dev.c
net/x25/x25_link.c
net/x25/x25_timer.c
scripts/mkdep.c

diff --git a/CREDITS b/CREDITS
index fbff7b2e9eb0d0d37f19ebf9157c60d06443553e..467930af4c599071d431a328f7c814791f1278ce 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -142,8 +142,8 @@ S: Trinity College
 S: Cambridge, UK. CB2 1TQ
 
 N: Thomas Bogendoerfer
-E: tsbogend@bigbug.franken.de
-D: Lance32 driver
+E: tsbogend@alpha.franken.de
+D: PCnet32 driver
 D: strace for Linux/Alpha
 S: Baumgartenweg 5
 S: 91452 Wilhermsdorf
index d0b019ab3b9a47ff899d41faa9ec1dd735e33ae4..36baccbf080dc21d22351acf7f7c7f540c566a38 100644 (file)
 # via ftp (user: anonymous) from sunsite.unc.edu in the directory
 # /pub/Linux/docs/HOWTO. 
 #
-# Format of this file: description<nl>variable<nl>helptext<nl><nl>. 
-# If the question being documented is of type "choice", we list
-# only the first occurring config variable. The help texts
-# must not contain empty lines. No variable should occur twice; if it
-# does, only the first occurrence will be used by Configure. The lines
-# in a help text should be indented two positions. Lines starting with
-# `#' are ignored. To be nice to menuconfig, limit your lines to 70
-# characters. Use emacs' kfill.el to edit this file or you lose.
+# Format of this file: description<nl>variable<nl>helptext<nl><nl>.
+# If the question being documented is of type "choice", we list only
+# the first occurring config variable. The help texts must not contain
+# empty lines. Order of the help texts does not matter, however, no
+# variable should be documented twice: if it is, only the first
+# occurrence will be used by Configure. It is not absolutely necessary
+# that the one-line descriptions of the variables used here are
+# exactly the same as the ones in the corresponding Config.in
+# scripts. The lines in a help text should be indented two
+# positions. Lines starting with `#' are ignored. To be nice to
+# menuconfig, limit your lines to 70 characters. Use emacs' kfill.el
+# to edit this file or you lose.
 #
 # If you add a help text to this file, please try to be as gentle as
 # possible. Don't use unexplained acronyms and generally write for the
@@ -187,8 +191,10 @@ CONFIG_BLK_DEV_IDEDISK
   old harddisk driver instead, say Y.  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. The module will be called ide-disk.o. If
-  unsure, say Y.
+  Documentation/modules.txt. The module will be called ide-disk.o. Do
+  not compile this driver as a module if your root filesystem (the one
+  containing the directory /) is located on the IDE disk. If unsure,
+  say Y.
 
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
@@ -287,10 +293,10 @@ CONFIG_BLK_DEV_TRITON
   and includes the Intel Triton I/II IDE interface chipset (i82371FB
   or i82371SB), you will want to enable this option to allow use of
   bus-mastering DMA data transfers. Read the comments at the beginning
-  of drivers/block/triton.c.  You can get the latest version of the
-  hdparm utility via ftp (user: anonymous) from
-  sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is used to
-  tune your harddisk. It is safe to say Y to this question.
+  of drivers/block/triton.c and Documentation/ide.txt.  You can get
+  the latest version of the hdparm utility via ftp (user: anonymous)
+  from sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is
+  used to tune your harddisk. It is safe to say Y to this question.
 
 Other IDE chipset support
 CONFIG_IDE_CHIPSETS
@@ -527,6 +533,12 @@ CONFIG_FIREWALL
   proxy server). Chances are that you should use this on every machine
   being run as a router and not on any regular host. If unsure, say N.
 
+Socket Security API Support (EXPERIMENTAL)
+CONFIG_NET_SECURITY
+  Enable use of the socket security API. Note that Linux does not include
+  any security protocols currently and that this option only really supports
+  security on IPv4 links at the moment.
+
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
   This is support for floppy drives on Sun Sparc workstations. Say Y
@@ -600,14 +612,22 @@ CONFIG_SERIAL_NONSTANDARD
   Say Y here if you have any non-standard serial boards --- boards
   which aren't supported using the standard "dumb" serial driver.
   This includes intelligent serial boards such as Cyclades,
-  Digiboards, etc.
+  Digiboards, etc. These are usually used for systems that need many
+  serial ports because they serve many terminals or dial-in
+  connections.  Note that the answer to this question won't directly
+  affect the kernel: saying N will just cause this configure script to
+  skip all the questions about non-standard serial boards. Most people
+  can say N here.
 
 Extended dumb serial driver options
 CONFIG_SERIAL_EXTENDED  
   If you wish to use any non-standard features of the standard "dumb"
   driver, say Y here.  This includes HUB6 support, shared serial
   interrupts, special multiport support, support for more than the
-  four COM 1/2/3/4 boards, etc.
+  four COM 1/2/3/4 boards, etc.  Note that the answer to this question
+  won't directly affect the kernel: saying N will just cause this
+  configure script to skip all the questions about serial driver
+  options. If unsure, say N.
 
 Support more than 4 serial ports
 CONFIG_SERIAL_MANY_PORTS
@@ -670,8 +690,9 @@ MCA support
 CONFIG_MCA
   MicroChannel Architecture is found in some IBM PS/2 machines and
   laptops. It is a bus system similar to PCI or ISA.  See
-  Documentation/mca.txt before attempting to build an MCA bus kernel.
-  Note that this is still experimental code.
+  Documentation/mca.txt (and especially the web page given there)
+  before attempting to build an MCA bus kernel.  Note that this is
+  still experimental code.
 
 System V IPC
 CONFIG_SYSVIPC
@@ -941,13 +962,12 @@ IP: accounting
 CONFIG_IP_ACCT
   This keeps track of your IP network traffic and produces some
   statistics. Usually, you only want to say Y here if your box will be
-  a router or a firewall for some local network, in which case you
-  naturally should have said Y to IP forwarding/gatewaying resp. IP
-  firewalling. The data is accessible with "cat /proc/net/ip_acct", so
-  you want to say Y to the /proc filesystem below, if you say Y
-  here. To specify what exactly should be recorded, you need the tool
-  ipfwadm (available via ftp (user: anonymous) from
-  ftp.xos.nl/pub/linux/ipfwadm/).
+  a router or a firewall for some local network. For the latter, you
+  need to say Y to IP firewalling. The data is accessible with "cat
+  /proc/net/ip_acct", so you want to say Y to the /proc filesystem
+  below, if you say Y here. To specify what exactly should be
+  recorded, you need the tool ipfwadm (available via ftp (user:
+  anonymous) from ftp.xos.nl/pub/linux/ipfwadm/).
 
 IP: tunneling
 CONFIG_NET_IPIP
@@ -962,9 +982,9 @@ CONFIG_NET_IPIP
   http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html). Saying Y
   to this option will produce two modules ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  one encapsulator and one decapsulator. The module will be called
+  one encapsulator called tunnel.o and one decapsulator called
   ipip.o. You can read details in drivers/net/README.tunnel. Most
-  people can say N.
+  people won't need this and can say N.
   
 IP: firewall packet logging
 CONFIG_IP_FIREWALL_VERBOSE
@@ -1259,7 +1279,7 @@ IP-over-DDP support
 CONFIG_IPDDP
   This allows IP networking for users who only have Appletalk
   networking available.  This feature is experimental. Please see
-  http://www.maths.unm.edu/~bradford/ltpc.html
+  http://www.maths.unm.edu/~bradford/ltpc.html for support software.
 
 LocalTalk PC card support
 CONFIG_LTPC
@@ -1443,7 +1463,10 @@ CONFIG_SCSI
   available as a module ( = code which can be inserted in and removed
   from the running kernel whenever you want). The module will be
   called scsi_mod.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt and Documentation/scsi.txt.
+  and read Documentation/modules.txt and
+  Documentation/scsi.txt. However, do not compile this as a module if
+  your root filesystem (the one containing the directory /) is located
+  on a SCSI disk.
 
 SCSI disk support
 CONFIG_BLK_DEV_SD
@@ -1455,7 +1478,10 @@ CONFIG_BLK_DEV_SD
   be inserted in and removed from the running kernel whenever you
   want). The module will be called sd_mod.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt and
-  Documentation/scsi.txt.
+  Documentation/scsi.txt. Do not compile this driver as a module if
+  your root filesystem (the one containing the directory /) is located
+  on a SCSI disk. In this case, do not compile the driver for your
+  SCSI host adapter (below) as a module either.
   
 SCSI tape support
 CONFIG_CHR_DEV_ST
@@ -1572,28 +1598,36 @@ CONFIG_SCSI_AIC7XXX
   drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
   (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it
   doesn't work out of the box, you may have to change some settings in
-  drivers/scsi/aic7xxx.h.  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. The module will be called aic7xxx.o.
+  drivers/scsi/aic7xxx.h. It has been reported that the "wide
+  negotiation" on these cards is not quite working and should be
+  disabled. Note that the AHA2920 SCSI host adapter is *not* supported
+  by this driver; choose "Future Domain 16xx SCSI support" instead. If
+  you want to compile this driver 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. The module will be
+  called aic7xxx.o.
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
-  This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters.
-  Consult the SCSI-HOWTO, available via anonymous ftp from sunsite.unc.edu in
-  /pub/Linux/docs/HOWTO, and the files README.BusLogic and README.FlashPoint in
-  drivers/scsi for more information.  If this driver does not work correctly
-  without modification, please contact the author, Leonard N. Zubkoff, by email
-  to lnz@dandelion.com.  You can also build this driver as a module ( = code
-  which can be inserted in and removed from the running kernel whenever you
-  want), but only a single instance may be loaded.  If you want to compile it
-  as a module, say M here and read Documentation/modules.txt.
+  This is support for BusLogic MultiMaster and FlashPoint SCSI Host
+  Adapters.  Consult the SCSI-HOWTO, available via anonymous ftp from
+  sunsite.unc.edu in /pub/Linux/docs/HOWTO, and the files
+  README.BusLogic and README.FlashPoint in drivers/scsi for more
+  information.  If this driver does not work correctly without
+  modification, please contact the author, Leonard N. Zubkoff, by
+  email to lnz@dandelion.com.  You can also build this driver as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), but only a single instance may be
+  loaded.  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The module will be called BusLogic.o.
 
 Omit BusLogic SCSI FlashPoint support
 CONFIG_SCSI_OMIT_FLASHPOINT
-  This option allows you to omit the FlashPoint support from the BusLogic
-  SCSI driver.  The FlashPoint SCCB Manager code is substantial, so users of
-  MultiMaster Host Adapters may wish to omit it.
+  This option allows you to omit the FlashPoint support from the
+  BusLogic SCSI driver.  The FlashPoint SCCB Manager code is
+  substantial, so users of MultiMaster Host Adapters may wish to omit
+  it.
+
 
 DTC3180/3280 SCSI support
 CONFIG_SCSI_DTC3280
@@ -1661,7 +1695,7 @@ CONFIG_SCSI_U14_34F_MAX_TAGS
   given SCSI device. Go with the default unless you know what you're
   doing. Minimum is 2 and maximum is 8.
 
-Future Domain 16xx SCSI support
+Future Domain 16xx SCSI/AHA 2920 support
 CONFIG_SCSI_FUTURE_DOMAIN
   This is support for Future Domain's 16-bit SCSI host adapters
   (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
@@ -1826,13 +1860,31 @@ CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
   This option must be set to N if your system has at least one 53C8XX based  
   scsi board with a vendor-specific BIOS (example: Tekram DC-390/U/W/F).
 
+assume boards are SYMBIOS compatible
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
+  This option allows you to enable some features depending on GPIO
+  wiring.  These General Purpose Input/Output pins can be used for
+  vendor specific features or implementation of the standard SYMBIOS
+  features.  Genuine SYMBIOS boards use GPIO0 in output for controller
+  LED and GPIO3 bit as a flag indicating singled-ended/differential
+  interface.
+  If all the boards of your system are genuine SYMBIOS boards or use
+  BIOS and drivers from SYMBIOS, you would want to enable this option,
+  obviously at your own risks.
+  The driver behaves correctly on my system with this option enabled.
+  (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
+  0x12).  This option must be set to N if your system has at least one
+  53C8XX based scsi board with a vendor-specific BIOS (example: Tekram
+  DC-390/U/W/F).  If unsure, say N.
+
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   If your computer sports an MCA bus system architecture (IBM PS/2)
-  with an SCSI harddrive, say Y here. This driver is also available as
-  a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). The module will be called
-  ibmmca.o. If you want to compile it as a module, say M here and read
+  with an SCSI harddrive, say Y here. Please read
+  Documentation/mca.txt. This driver is also available as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). The module will be called ibmmca.o. If you want
+  to compile it as a module, say M here and read
   Documentation/modules.txt.
 
 Always IN2000 SCSI support
@@ -2273,12 +2325,33 @@ CONFIG_SOUNDMODEM_AFSK1200
   compatible to popular modems using TCM3105 or AM7911. The demodulator
   requires about 12% of the CPU power of a Pentium 75 CPU per channel.
 
+Soundmodem 1200 baud AFSK using floating point
+CONFIG_SOUNDMODEM_AFSK1200_FP
+  This option enables floating point calculations to be used for the
+  AFSK1200 baud modem. The Intel Pentium is a perverted chip because
+  integer multiplications are, although easier to implement in silicon,
+  an order of magnitude slower than floating point calculations.
+  Enabling this option uses a highly optimized assembler routine for
+  correlations, modeled after the one published by Phil Karn, KA9Q.
+  This reduces the computing power needed on Intel Pentium chips to
+  about 50%. On the other hand, Pentium clones with faster integer
+  multiply and slower floating point multiply will probably take
+  longer with this option turned on. As a rule of thumb, enable it for
+  Intel Pentium and Pentium Pro processors, and disable it for
+  anything else.
+  I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
+  willing to give me a feedback, please compile the driver once with
+  this option enabled and once with it disabled, and send me the cycle
+  counter numbers obtained with both compilations, and your exact
+  chip. The cycle counter numbers can be obtained with a recent
+  sethdlc utility.
+
 Soundcard modem support for 4800 baud HAPN-1 modulation
 CONFIG_SOUNDMODEM_HAPN4800
-  This option enables the soundmodem driver 4800 baud HAPN-1 compatible
-  modem. This modulation seems to be widely used 'down under' and in
-  the netherlands. Here, nobody uses it, so I could not test if it works.
-  It is compatible to itself, however :-)
+  This option enables the soundmodem driver 4800 baud HAPN-1
+  compatible modem. This modulation seems to be widely used 'down
+  under' and in the Netherlands. Here, nobody uses it, so I could not
+  test if it works.  It is compatible to itself, however :-)
 
 Soundcard modem support for 9600 baud FSK G3RUH modulation
 CONFIG_SOUNDMODEM_FSK9600
@@ -2293,20 +2366,22 @@ Soundcard modem support using floating point arithmetic
 CONFIG_SOUNDMODEM_FLOAT
   This option enables floating point calculations to be used for the
   AFSK1200 baud modem. The Intel Pentium is a perverted chip because
-  integer multiplications are, altough easier to implement in silicon,
+  integer multiplications are, although easier to implement in silicon,
   an order of a magnitude slower than floating point calculations.
   Enabling this option uses a highly optimized assembler routine for
-  correlations, modelled after the one published by Phil Karn, KA9Q.
-  This reduces the computing power needed on Intel Pentium chips to about
-  50%. On the other hand, Pentium clones with faster integer multiply and
-  slower floating point multiply will probably take longer with this
-  option turned on. As a rule of thumb, enable it for Intel Pentium and
-  Pentium Pro processors, and disable it for anything else.
+  correlations, modeled after the one published by Phil Karn, KA9Q.
+  This reduces the computing power needed on Intel Pentium chips to
+  about 50%. On the other hand, Pentium clones with faster integer
+  multiply and slower floating point multiply will probably take
+  longer with this option turned on. As a rule of thumb, enable it for
+  Intel Pentium and Pentium Pro processors, and disable it for
+  anything else.
   I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
-  willing to give me a feedback, please compile the driver once with this
-  option enabled and once with it disabled, and send me the cycle counter
-  numbers obtained with both compilations, and your exact chip. The cycle
-  counter numbers can be optained by a recent sethdlc utility.
+  willing to give me a feedback, please compile the driver once with
+  this option enabled and once with it disabled, and send me the cycle
+  counter numbers obtained with both compilations, and your exact
+  chip. The cycle counter numbers can be obtained by a recent sethdlc
+  utility.
 
 Serial port KISS driver for AX.25
 CONFIG_MKISS
@@ -2429,18 +2504,19 @@ CONFIG_WAN_ROUTER
   achievable with commonly used asynchronous modem connections.
   Usually, a quite expensive external device called `WAN router' is
   needed to connect to a WAN.
-      As an alternative, WAN routing can be built into the Linux kernel. 
-  With relatively inexpensive WAN interface cards available on the
-  market, a perfectly usable router can be built for less than half the
-  price of an external router.  If you have one of those cards (with
-  appropriate WAN Link Driver) and wish to use your Linux box as a WAN
-  router, you may say 'Y' to this option.  You will also need a
-  wan-tools package available via FTP (user: anonymous) from
+      As an alternative, WAN routing can be built into the Linux
+  kernel.  With relatively inexpensive WAN interface cards available
+  on the market, a perfectly usable router can be built for less than
+  half the price of an external router.  If you have one of those
+  cards (with appropriate WAN Link Driver) and wish to use your Linux
+  box as a WAN router, you may say 'Y' to this option.  You will also
+  need a wan-tools package available via FTP (user: anonymous) from
   ftp.sangoma.com.  Read Documentation/networking/wan-router.txt for
   more information.
       WAN routing is always built as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  For general information about modules read Documentation/modules.txt.
+  The module will be called wanrouter.o.  For general information
+  about modules read Documentation/modules.txt.
 
 WAN Drivers
 CONFIG_WAN_DRIVERS
@@ -2457,35 +2533,39 @@ CONFIG_VENDOR_SANGOMA
   is a family of intelligent multiprotocol WAN adapters with data
   transfer rates up to T1 (1.544 Mbps).  They are also known as
   Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
-  or S508.  If you have one of these cards, say 'Y' to this option.
-      WANPIPE driver is always built as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  For general information about modules read Documentation/modules.txt.
+  or S508. These cards support the X.25, Frame Relay, and PPP
+  protocols. If you have one or more of these cards, say 'Y' to this
+  option.  The next questions will ask you about the protocols you
+  want the driver to support. The driver will be compiled as a module
+  ( = code which can be inserted in and removed from the running
+  kernel whenever you want).  The module will be called wanpipe.o.
+  For general information about modules read
+  Documentation/modules.txt.
 
 Maximum number of cards
 CONFIG_WANPIPE_CARDS
       Enter number of WANPIPE adapters installed in your machine.  The
-  driver can support up to 8 cards.  You may enter more that you
+  driver can support up to 8 cards.  You may enter more than you
   actually have if you plan to add more cards in the future without
   re-compiling the driver, but remember that in this case you'll waste
   some kernel memory (about 1K per card).
 
 WANPIPE X.25 support
 CONFIG_WANPIPE_X25
-      Say 'Y' to this option, if you are planning to connect WANPIPE
+      Say 'Y' to this option, if you are planning to connect WANPIPE
   card to an X.25 network.  If you say 'N', the X.25 support will not
   be included in the driver (saves about 16K of kernel memory).
 
 WANPIPE Frame Relay support
 CONFIG_WANPIPE_FR
-      Say 'Y' to this option, if you are planning to connect WANPIPE
+      Say 'Y' to this option, if you are planning to connect WANPIPE
   card to a frame relay network.  If you say 'N', the frame relay
   support will not be included in the driver (saves about 16K of
   kernel memory).
 
 WANPIPE PPP support
 CONFIG_WANPIPE_PPP
-      Say 'Y' to this option, if you are planning to connect WANPIPE
+      Say 'Y' to this option, if you are planning to connect WANPIPE
   card to a leased line using Point-to-Point protocol (PPP).  If you
   say 'N', the PPP support will not be included in the driver (saves
   about 16K of kernel memory).
@@ -2494,7 +2574,11 @@ Sun LANCE Ethernet support
 CONFIG_SUN_LANCE
   This is support for lance ethernet cards on Sun workstations such as
   the Sparcstation IPC (any Sparc with a network interface 'le0' under
-  SunOS basically).
+  SunOS basically). This driver is also available as a module ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). The module will be called lance.o. If you want
+  to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Sun Intel Ethernet support
 CONFIG_SUN_INTEL
@@ -2768,16 +2852,17 @@ CONFIG_E2100
 
 CS89x0 support
 CONFIG_CS89x0
-  Support for CS89x0 chipset based ethernet cards. 
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  Support for CS89x0 chipset based ethernet cards.  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 as well as
-  drivers/net/depca.c.  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 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
+  Documentation/networking/cs89x0.txt.  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 as well as
+  Documentation/networking/net-modules.txt. The module will be called
+  cs89x.o. 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.
 
 DEPCA support
@@ -3065,7 +3150,7 @@ CONFIG_APRICOT
   linux, read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
-DE425, DE434, DE435 support
+Generic DECchip & DIGITAL EtherWORKS PCI/EISA
 CONFIG_DE4X5
   This is support for the DIGITAL series of PCI/EISA ethernet
   cards. These include the DE425, DE434, DE435, DE450 and DE500
@@ -3088,9 +3173,9 @@ CONFIG_DEC_ELCP
   cards and also works with cards based on the DECchip
   21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are
   of this type. (If your card is NOT SMC EtherPower 10/100 PCI
-  (smc9332dst), you can also try the driver from "DE425, DE434, DE435
-  support", above.) However, most people with a network card of this
-  type will say Y here. Do read the Ethernet-HOWTO, available via ftp
+  (smc9332dst), you can also try the driver for "Generic DECchip"
+  cards, above. However, most people with a network card of this type
+  will say Y here.) Do read the Ethernet-HOWTO, available via ftp
   (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. More
   specific information is contained in
   Documentation/networking/tulip.txt. This driver is also available as
@@ -3914,7 +3999,7 @@ Stallion EasyIO or EC8/32 support
 CONFIG_STALLION
   If you have an EasyIO or EasyConnection 8/32 multiport Stallion
   card, then this is for you; say Y. Make sure to read
-  drivers/char/README.stallion. If you want to compile this as a
+  Documentation/stallion.txt. 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. The module will be called stallion.o.
@@ -3923,7 +4008,7 @@ Stallion EC8/64, ONboard, Brumby support
 CONFIG_ISTALLION
   If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
   serial multiport card, say Y here. Make sure to read
-  drivers/char/README.stallion. To compile it as a module ( = code
+  Documentation/stallion.txt. To compile it 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. The module will be called istallion.o.
@@ -4134,14 +4219,14 @@ CONFIG_APM
   things to try when experiencing seemingly random, "weird" problems:
    1) passing the "no-hlt" option to the kernel 
    2) passing the "no-387" option to the kernel 
-   3) passing the "mem=4M" option to the kernel (thereby disabling 
+   3) passing the "floppy=nodma" option to the kernel
+   4) passing the "mem=4M" option to the kernel (thereby disabling 
       all but the first 4M of RAM)
-   4) Reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
-   5) disabling the cache from your BIOS settings
-   6) installing a better fan
-   7) exchanging RAM chips 
-   8) exchanging the motherboard.
-
+   5) reading the sig11 FAQ at http://www.bitwizard.nl/sig11/
+   6) disabling the cache from your BIOS settings
+   7) installing a better fan
+   8) exchanging RAM chips 
+   9) exchanging the motherboard.
 
 Ignore USER SUSPEND
 CONFIG_APM_IGNORE_USER_SUSPEND
@@ -4279,9 +4364,9 @@ CONFIG_RTC
   /proc/rtc and its behaviour is set by various ioctls on
   /dev/rtc. People running SMP (= multiprocessor) versions of Linux
   should say Y here to read and set the RTC clock in a SMP compatible
-  fashion. If you think you have a use for such a device (such as
-  periodic data sampling), then say Y here, and go read the file
-  Documentation/rtc.txt for details.
+  fashion. (They should also read Documentation/smp.) If you think you
+  have a use for such a device (such as periodic data sampling), then
+  say Y here, and go read the file Documentation/rtc.txt for details.
 
 Sound card support
 CONFIG_SOUND
@@ -4537,8 +4622,8 @@ CONFIG_ISDN_AUDIO
   (mgetty+sendfax by gert@greenie.muc.de with an extension, available
   with the ISDN utility package for example), you will be able to use
   your Linux box as an ISDN-answering machine. Of course, this must be
-  supported by the lowlevel driver also. Currently, the Teles and HiSax
-  drivers are the only voice-supporting drivers. See
+  supported by the lowlevel driver also. Currently, the Teles and
+  HiSax drivers are the only voice-supporting drivers. See
   Documentation/isdn/README.audio for more information.
 
 ICN 2B and 4B support
@@ -4560,7 +4645,7 @@ CONFIG_ISDN_DRV_TELES
   and many compatibles.
   There is a new, heavily improved driver called HiSax which can be
   enabled in the next section. This driver will be removed soon. Please
-  use this driver only if you cannot get the HiSax driver working.
+  use this driver only if you cannot get the HiSax driver to work.
   By default, the driver is configured to support a 16.0-type using
   EDSS1-protocol. See Documentation/isdn/README on how to configure
   it using 16.3, a different D-channel protocol, or non-standard
@@ -4569,13 +4654,15 @@ CONFIG_ISDN_DRV_TELES
 HiSax SiemensChipSet driver support
 CONFIG_ISDN_DRV_HISAX
   This is an alternative driver supporting the Siemens chipset on
-  various ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, 
-  Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and 
-  many compatibles). It's a complete rewrite of the original Teles 
-  driver.  So you either say M or Y here and N in the above Teles 
-  section.
-  See Documentation/isdn/README.HiSax for further informations on
-  using this driver.
+  various ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0,
+  Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
+  compatibles). It's a complete rewrite of the original Teles driver.
+  So you either say M or Y here and N in the above Teles section. 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. The module will be called
+  hisax.o.  See Documentation/isdn/README.HiSax for further
+  informations on using this driver.
 
 HiSax Support for Teles 16.0/8.0
 CONFIG_HISAX_16_0
@@ -4617,14 +4704,14 @@ CONFIG_HISAX_IX1MICROR2
 
 HiSax Support for EURO/DSS1
 CONFIG_HISAX_EURO
-  You should choose your D-channel protocol your local
+  You should choose the D-channel protocol your local
   telephone service provider uses here by saying Y or N.
   NOTE: This is mutually exclusive with HiSax Support for
-  german 1TR6 if you have only one ISDN card installed.
+  German 1TR6 if you have only one ISDN card installed.
 
-HiSax Support for german 1TR6
+HiSax Support for German 1TR6
 CONFIG_HISAX_1TR6
-  You should choose your D-channel protocol your local
+  You should choose the D-channel protocol your local
   telephone service provider uses here by saying Y or N.
   NOTE: This is mutually exclusive with HiSax Support for
   EURO/DSS1 if you have only one ISDN card installed.
@@ -4643,10 +4730,12 @@ CONFIG_ISDN_DRV_PCBIT
 
 Spellcaster support (EXPERIMENTAL)
 CONFIG_ISDN_DRV_SC
-  This enables support for the Spellcaster BRI boards. This driver
-  currently builds in a modularized version only.
-  See Documentation/isdn/README.sc and http://www.spellcast.com
-  for more information.
+  This enables support for the Spellcaster BRI ISDN boards. This
+  driver currently builds only in a modularized version ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want, details in Documentation/modules.txt); the module will be
+  called sc.o.  See Documentation/isdn/README.sc and
+  http://www.spellcast.com for more information.
 
 Support for AP1000 multicomputer
 CONFIG_AP1000
@@ -5122,7 +5211,7 @@ CONFIG_MSDOS_PARTITION
 # LocalWords:  wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI
 # LocalWords:  QD qd UMC umc ALI ali lena fnet fr homepage azstarnet axplinux
 # LocalWords:  Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC
-# LocalWords:  AlphaPC uwaterloo cpbeaure mca AOUT OUTput PPro sipx gwdg lo nwe
+# LocalWords:  AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm
 # LocalWords:  Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT
 # LocalWords:  OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP
 # LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco
@@ -5177,5 +5266,10 @@ CONFIG_MSDOS_PARTITION
 # LocalWords:  ibmmca lapbether mkiss dlci sdla fmv eepro eexpress ni hp ne es
 # LocalWords:  ibmtr isofs ROMFS romfs pcxx cyclades istallion psaux msbusmouse
 # LocalWords:  atixlmouse sbin softdog pcwd USS Lite ACI miroSOUND PCM miroPCM
-# LocalWords:  microcontroller miro Voxware downloading teles acsi slm gvp
-# LocalWords:  atari ariadne amigamouse atarimouse builtin
+# LocalWords:  microcontroller miro Voxware downloading teles acsi slm gvp ltpc
+# LocalWords:  atari ariadne amigamouse atarimouse builtin IPDDP maths bradford
+# LocalWords:  LocalTalk AppleTalk Farallon PhoneNet Zubkoff lnz SCCB HAPN WANs
+# LocalWords:  wanrouter WANPIPE multiprotocol Mbps wanpipe EtherWORKS nodma SC
+# LocalWords:  smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR
+# LocalWords:  Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO
+# LocalWords:  SYMBIOS COMPAT SDMS rev ASUS Tekram
index 04fa92857dbaae3959fb18219d3e1aa0fa79f7ce..25d85352130af819ca3783dc461664e2f2e70251 100644 (file)
@@ -266,6 +266,14 @@ L: linux-net@vger.rutgers.edu
 W:     http://www.uk.linux.org/NetNews.html
 S:     Maintained
 
+NETWORKING [IPv4/IPv6]:
+P:     David S. Miller
+M:     davem@caip.rutgers.edu
+P:     Eric Schenk
+M:     Eric.Schenk@dna.lth.se
+L:     netdev@roxanne.nuclecu.unam.mx
+S:     Maintained
+
 PPP PROTOCOL DRIVERS AND COMPRESSORS
 P:     Al Longyear
 M:     longyear@pobox.com
@@ -304,8 +312,8 @@ L:  linux-smp@vger.rutgers.edu
 S:     Maintained
 
 SPARC:
-P:     Eddie C. Dost
-M:     ecd@skynet.be
+P:     David S. Miller
+M:     davem@caip.rutgers.edu
 L:     sparclinux@vger.rutgers.edu
 S:     Maintained
 
@@ -369,9 +377,9 @@ P:  Jens Maurer
 M:     jmaurer@cck.uni-kl.de
 S:     Maintained
 
-LANCE AND LANCE32 NETWORK DRIVER
+PCNET32 NETWORK DRIVER
 P:     Thomas Bogendoerfer
-M:     tsbogend@bigbug.franken.de
+M:     tsbogend@alpha.franken.de
 L:     linux-net@vger.rutgers.edu
 S:     Maintained
 
index a658673df39cddf9ae08a05916d64eb4e1a78258..13a8ff98cb34719408fe5b0dda2331f75293d2ca 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 29
+SUBLEVEL = 30
 
 ARCH = i386
 
index 87a0d671dec7f223cb0b7b7f37a428d86c420863..41ff419f0850b6245d92f6584061c5705491067f 100644 (file)
@@ -82,8 +82,7 @@ endif
 # This make dependencies quickly
 #
 fastdep: dummy
-       if [ -n "$(wildcard *.[chS])" ]; then \
-       $(TOPDIR)/scripts/mkdep *.[chS] > .depend; fi
+       $(TOPDIR)/scripts/mkdep *.[chS] > .depend
 ifdef ALL_SUB_DIRS
        set -e; for i in $(ALL_SUB_DIRS); do $(MAKE) -C $$i fastdep; done
 endif
index 446eda06270fcb3f8f872b4ea622ae285abb1781..6debc025370049cea3f22fc0d695d15e0054805a 100644 (file)
@@ -81,9 +81,11 @@ EXPORT_SYMBOL(wrusp);
 EXPORT_SYMBOL(__kernel_thread);
 EXPORT_SYMBOL(start_thread);
 
+/* Networking helper routines. */
 EXPORT_SYMBOL(csum_tcpudp_magic);
 EXPORT_SYMBOL(ip_fast_csum);
 EXPORT_SYMBOL(ip_compute_csum);
+EXPORT_SYMBOL(csum_partial_copy);
 
 /*
  * The following are specially called from the uaccess assembly stubs.
index 77b73ab14f9a7e1da6aa23f64a9e551b12415a7d..acfc29c616e8f7a4ee49d859097afdbec26ebdf5 100644 (file)
@@ -526,14 +526,9 @@ entSys:
 ret_from_sys_call:
        cmovne  $26,0,$19               /* $19 = 0 => non-restartable */
        /* check bottom half interrupts */
-       lda     $0,intr_count
-       ldl     $1,0($0)
        bne     $1,ret_from_handle_bh
-       lda     $2,bh_active
-       ldq     $3,0($2)
-       lda     $2,bh_mask
-       ldq     $4,0($2)
-       addq    $1,1,$1
+       ldq     $3,bh_active
+       ldq     $4,bh_mask
        and     $3,$4,$2
        bne     $2,handle_bottom_half
 ret_from_handle_bh:
@@ -618,20 +613,13 @@ strace_error:
 
        .align 3
 handle_bottom_half:
-       /*
-        * We're called with $0 containing the address of
-        * 'intr_count' and $1 containing 'intr_count+1'
-        */
-       stl     $1,0($0)        /* intr_count = 1 */
        subq    $30,16,$30
        stq     $19,0($30)      /* save syscall nr */
        stq     $20,8($30)      /* and error indication (a3) */
        jsr     $26,do_bottom_half
-       lda     $0,intr_count
        ldq     $19,0($30)
        ldq     $20,8($30)
        addq    $30,16,$30
-       stl     $31,0($0)       /* intr_count = 0 */
        br      $31,ret_from_handle_bh
 
        .align 3
index 370f25aca67d6fd8b31cac9544fd4b94a8898e67..7bcb8dc9725950fff10d0d4c96e604a6034c679e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/stat.h>
 #include <linux/mman.h>
 #include <linux/elfcore.h>
+#include <linux/reboot.h>
 
 #include <asm/reg.h>
 #include <asm/uaccess.h>
@@ -63,7 +64,7 @@ out:
        return ret;
 }
 
-void hard_reset_now(void)
+void machine_restart(char * __unused)
 {
 #if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
        /* who said DEC engineer's have no sense of humor? ;-)) */
@@ -73,6 +74,14 @@ void hard_reset_now(void)
        halt();
 }
 
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+}
+
 void show_regs(struct pt_regs * regs)
 {
        printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc);
index 6867c2b80a1fddb8fb35ea21fc1180e1336ecf74..43e8a792f434072590cab1afb07dddd756601049 100644 (file)
@@ -152,6 +152,7 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_DE4X5=y
index 69dd1f3f1cd511debc9a37513638ead494dcd7ec..9473705e64efdd06019833e8759c1e907c707606 100644 (file)
@@ -153,12 +153,8 @@ ENTRY(lcall7)
        ALIGN
        .globl  ret_from_smpfork
 ret_from_smpfork:
-       GET_CURRENT(%ebx)
-       movl    $NO_PROC_ID, SYMBOL_NAME(active_kernel_processor)
-       lock
-       btrl    $0, SYMBOL_NAME(kernel_flag)
-       sti
-       jmp     9f
+       btrl    $0, SYMBOL_NAME(scheduler_lock)
+       jmp     ret_from_sys_call
 #endif /* __SMP__ */
 
        ALIGN
@@ -187,13 +183,7 @@ ENTRY(system_call)
 ret_from_intr:
 ret_from_sys_call:
        GET_CURRENT(%ebx)
-       cmpl $0,SYMBOL_NAME(intr_count)
-#ifdef __SMP__
-       jne 2f
-#else
-       jne 1f
-#endif
-9:     movl SYMBOL_NAME(bh_mask),%eax
+       movl SYMBOL_NAME(bh_mask),%eax
        andl SYMBOL_NAME(bh_active),%eax
        jne handle_bottom_half
 2:     movl EFLAGS(%esp),%eax          # mix EFLAGS and CS
index 0b4f04c76078601ee37172e07e3fac448a0d2ab4..2e03409860c001dd59b04581bd7366f6282d8408 100644 (file)
@@ -5,10 +5,12 @@
 #include <linux/elfcore.h>
 #include <linux/mca.h>
 #include <linux/sched.h>
+#include <linux/in6.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 #include <asm/io.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
@@ -25,8 +27,12 @@ EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
 
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy);
+
 #ifdef __SMP__
 EXPORT_SYMBOL(apic_reg);       /* Needed internally for the I386 inlines */
 EXPORT_SYMBOL(cpu_data);
index d927921986907d99f5d063835447c5982b662abd..d91110007850059414dce64875560d1409371bd9 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/smp.h>
+#include <asm/pgtable.h>
 
 #define CR0_NE 32
 
@@ -126,15 +127,14 @@ BUILD_IRQ(SECOND,9,0x02)
 BUILD_IRQ(SECOND,10,0x04)
 BUILD_IRQ(SECOND,11,0x08)
 BUILD_IRQ(SECOND,12,0x10)
-#ifdef __SMP__
-BUILD_MSGIRQ(SECOND,13,0x20)
-#else
 BUILD_IRQ(SECOND,13,0x20)
-#endif
 BUILD_IRQ(SECOND,14,0x40)
 BUILD_IRQ(SECOND,15,0x80)
+
 #ifdef __SMP__
-BUILD_RESCHEDIRQ(16)
+BUILD_SMP_INTERRUPT(reschedule_interrupt)
+BUILD_SMP_INTERRUPT(invalidate_interrupt)
+BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
 #endif
 
 /*
@@ -146,9 +146,6 @@ static void (*interrupt[17])(void) = {
        IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
        IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
        IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt      
-#ifdef __SMP__ 
-       ,IRQ16_interrupt
-#endif
 };
 
 static void (*fast_interrupt[16])(void) = {
@@ -179,15 +176,6 @@ static void (*bad_interrupt[16])(void) = {
 
 static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 
-#ifdef __SMP__
-
-/*
- * On SMP boards, irq13 is used for interprocessor interrupts (IPI's).
- */
-static struct irqaction irq13 = { smp_message_irq, SA_INTERRUPT, 0, "IPI", NULL, NULL };
-
-#else
-
 /*
  * Note that on a 486, we don't want to do a SIGFPE on an irq13
  * as the irq is unreliable, and exception 16 works correctly
@@ -211,8 +199,6 @@ static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
 
 static struct irqaction irq13 = { math_error_irq, 0, 0, "math error", NULL, NULL };
 
-#endif
-
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
  */
@@ -335,6 +321,174 @@ int get_smp_prof_list(char *buf) {
 #endif 
 
 
+/*
+ * Global interrupt locks for SMP. Allow interrupts to come in on any
+ * CPU, yet make cli/sti act globally to protect critical regions..
+ */
+#ifdef __SMP__
+unsigned char global_irq_holder = NO_PROC_ID;
+unsigned volatile int global_irq_lock;
+unsigned volatile int global_irq_count;
+unsigned int local_irq_count[NR_CPUS];
+
+#define irq_active(cpu) \
+       (global_irq_count != local_irq_count[cpu])
+
+#define INIT_STUCK 10000000
+
+#define STUCK(x) \
+if (!--stuck) {printk(#x " stuck at %08lx, waiting for %08lx\n", where, previous); stuck = INIT_STUCK;}
+
+/*
+ * "global_cli()" is a special case, in that it can hold the
+ * interrupts disabled for a longish time, and also because
+ * we may be doing TLB invalidates when holding the global
+ * IRQ lock for historical reasons. Thus we may need to check
+ * SMP invalidate events specially by hand here (but not in
+ * any normal spinlocks)
+ */
+static inline void check_smp_invalidate(int cpu)
+{
+       if (test_bit(cpu, &smp_invalidate_needed)) {
+               clear_bit(cpu, &smp_invalidate_needed);
+               local_flush_tlb();
+       }
+}
+
+static inline void get_irqlock(int cpu, unsigned long where)
+{
+static unsigned long previous;
+       int local_count;
+       int stuck = INIT_STUCK;
+
+       if (set_bit(0,&global_irq_lock)) {
+               /* do we already hold the lock? */
+               if ((unsigned char) cpu == global_irq_holder)
+                       return;
+               /* Uhhuh.. Somebody else got it. Wait.. */
+               do {
+                       do {
+                               STUCK(irqlock1);
+                               check_smp_invalidate(cpu);
+                       } while (test_bit(0,&global_irq_lock));
+               } while (set_bit(0,&global_irq_lock));          
+       }
+       /*
+        * Ok, we got the lock bit.
+        * But that's actually just the easy part.. Now
+        * we need to make sure that nobody else is running
+        * in an interrupt context. 
+        */
+       local_count = local_irq_count[cpu];
+
+       /* Are we the only one in an interrupt context? */
+       while (local_count != global_irq_count) {
+               /*
+                * No such luck. Now we need to release the lock,
+                * _and_ release our interrupt context, because
+                * otherwise we'd have dead-locks and live-locks
+                * and other fun things.
+                */
+               atomic_sub(local_count, &global_irq_count);
+               global_irq_lock = 0;
+
+               /*
+                * Wait for everybody else to go away and release
+                * their things before trying to get the lock again.
+                */
+               for (;;) {
+                       STUCK(irqlock2);
+                       check_smp_invalidate(cpu);
+                       if (global_irq_count)
+                               continue;
+                       if (global_irq_lock)
+                               continue;
+                       if (!set_bit(0,&global_irq_lock))
+                               break;
+               }
+               atomic_add(local_count, &global_irq_count);
+       }
+
+       /*
+        * Finally.
+        */
+       global_irq_holder = cpu;
+       previous = where;
+}
+
+void __global_cli(void)
+{
+       int cpu = smp_processor_id();
+       unsigned long where;
+
+       __asm__("movl 12(%%esp),%0":"=r" (where));
+       __cli();
+       get_irqlock(cpu, where);
+}
+
+void __global_sti(void)
+{
+       release_irqlock(smp_processor_id());
+       __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+       return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+       switch (flags) {
+       case 0:
+               __global_sti();
+               break;
+       case 1:
+               __global_cli();
+               break;
+       default:
+               printk("global_restore_flags: %08lx (%08lx)\n",
+                       flags, (&flags)[-1]);
+       }
+}
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
+static inline void irq_enter(int cpu, int irq)
+{
+       int stuck = INIT_STUCK;
+
+       hardirq_enter(cpu);
+       while (test_bit(0,&global_irq_lock)) {
+               if ((unsigned char) cpu == global_irq_holder) {
+                       printk("BAD! Local interrupts enabled, global disabled\n");
+                       break;
+               }
+               STUCK;
+               /* nothing */;
+       }
+       atomic_inc(&intr_count);
+}
+
+static inline void irq_exit(int cpu, int irq)
+{
+       __cli();
+       atomic_dec(&intr_count);
+       hardirq_exit(cpu);
+       release_irqlock(cpu);
+}
+
+#else
+
+#define irq_enter(cpu, irq)    do { } while (0)
+#define irq_exit(cpu, irq)     do { } while (0)
+
+#endif
 
 /*
  * do_IRQ handles IRQ's that have been installed without the
@@ -345,20 +499,16 @@ int get_smp_prof_list(char *buf) {
  */
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
 {
-       struct irqaction * action = *(irq + irq_action);
-       int do_random = 0;
-
-       lock_kernel();
-       atomic_inc(&intr_count);
-#ifdef __SMP__
-       if(smp_threads_ready && active_kernel_processor!=smp_processor_id())
-               panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
-#endif
+       struct irqaction * action;
+       int do_random, cpu = smp_processor_id();
 
+       irq_enter(cpu, irq);
        kstat.interrupts[irq]++;
-#ifdef __SMP_PROF__
-       int_count[smp_processor_id()][irq]++;
-#endif
+
+       /* slow interrupts run with interrupts enabled */
+       __sti();
+       action = *(irq + irq_action);
+       do_random = 0;
        while (action) {
                do_random |= action->flags;
                action->handler(irq, action->dev_id, regs);
@@ -366,8 +516,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
        }
        if (do_random & SA_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
-       atomic_dec(&intr_count);
-       unlock_kernel();
+       irq_exit(cpu, irq);
 }
 
 /*
@@ -377,21 +526,13 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
  */
 asmlinkage void do_fast_IRQ(int irq)
 {
-       struct irqaction * action = *(irq + irq_action);
-       int do_random = 0;
-       
-       lock_kernel();
-       intr_count++;
-#ifdef __SMP__
-       /* IRQ 13 is allowed - that's a flush tlb */
-       if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
-               panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
-#endif
+       struct irqaction * action;
+       int do_random, cpu = smp_processor_id();
 
+       irq_enter(cpu, irq);
        kstat.interrupts[irq]++;
-#ifdef __SMP_PROF__
-       int_count[smp_processor_id()][irq]++;
-#endif
+       action = *(irq + irq_action);
+       do_random = 0;
        while (action) {
                do_random |= action->flags;
                action->handler(irq, action->dev_id, NULL);
@@ -399,8 +540,7 @@ asmlinkage void do_fast_IRQ(int irq)
        }
        if (do_random & SA_SAMPLE_RANDOM)
                add_interrupt_randomness(irq);
-       intr_count--;
-       unlock_kernel();
+       irq_exit(cpu, irq);
 }
 
 int setup_x86_irq(int irq, struct irqaction * new)
@@ -561,7 +701,9 @@ void init_IRQ(void)
        /* This bit is a hack because we don't send timer messages to all processors yet */
        /* It has to be here .. it doesn't work if you put it down the bottom - assembler explodes 8) */
 #ifdef __SMP__ 
-       set_intr_gate(0x20+i, interrupt[i]);    /* IRQ '16' - IPI for rescheduling */
+       set_intr_gate(0x20+i, reschedule_interrupt);    /* IRQ '16' - IPI for rescheduling */
+       set_intr_gate(0x21+i, invalidate_interrupt);    /* IRQ '17' - IPI for invalidation */
+       set_intr_gate(0x22+i, stop_cpu_interrupt);      /* IRQ '18' - IPI for CPU halt */
 #endif 
        request_region(0x20,0x20,"pic1");
        request_region(0xa0,0x20,"pic2");
index 92a2fff9b6d722b705ae643ea9fc657b78d0d3c8..21a93eed1b8f313d1ad8423a931909e2f2375322 100644 (file)
 #include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
+#include <linux/reboot.h>
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+#include <linux/apm_bios.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -122,6 +126,7 @@ asmlinkage int sys_idle(void)
                        if (hlt_works_ok && !hlt_counter && !need_resched)
                                __asm__("hlt");
                }
+               run_task_queue(&tq_scheduler);
                if (need_resched) 
                        start_idle = 0;
                schedule();
@@ -134,30 +139,6 @@ out:
 
 #else
 
-/*
- *     In the SMP world we hlt outside of kernel syscall rather than within
- *     so as to get the right locking semantics.
- */
-asmlinkage int sys_idle(void)
-{
-       int ret = -EPERM;
-
-       lock_kernel();
-       if(current->pid != 0)
-               goto out;
-#ifdef __SMP_PROF__
-       smp_spins_sys_idle[smp_processor_id()]+=
-         smp_spins_syscall_cur[smp_processor_id()];
-#endif
-       current->counter= -100;
-       schedule();
-       ret = 0;
-out:
-       unlock_kernel();
-       return ret;
-}
-
 /*
  *     This is being executed in task 0 'user space'.
  */
@@ -168,32 +149,17 @@ int cpu_idle(void *unused)
        {
                if(cpu_data[smp_processor_id()].hlt_works_ok && !hlt_counter && !need_resched)
                        __asm("hlt");
-                if(0==(read_smp_counter(&smp_process_available))) 
-                       continue;
-                while(0x80000000 & smp_process_available)
-                       ;
-               cli();
-                while(set_bit(31,&smp_process_available))
-                       while(test_bit(31,&smp_process_available))
-                {
-                       /*
-                        *      Oops.. This is kind of important in some cases...
-                        */
-                       if(clear_bit(smp_processor_id(), &smp_invalidate_needed))
-                               local_flush_tlb();
-                }
-                if (0==(read_smp_counter(&smp_process_available))) {
-                        clear_bit(31,&smp_process_available);
-                        sti();
-                        continue;
-                }
-                smp_process_available--;
-                clear_bit(31,&smp_process_available);
-                sti();
-               idle();
+               run_task_queue(&tq_scheduler);
+               schedule();
        }
 }
 
+asmlinkage int sys_idle(void)
+{
+       cpu_idle(NULL);
+       return 0;
+}
+
 #endif
 
 /*
@@ -297,11 +263,13 @@ static inline void kb_wait(void)
                        break;
 }
 
-void hard_reset_now (void)
+void machine_restart(char * __unused)
 {
 
        if(!reboot_thru_bios) {
+#if 0
                sti();
+#endif
                /* rebooting needs to touch the page at absolute addr 0 */
                *((unsigned short *)__va(0x472)) = reboot_mode;
                for (;;) {
@@ -399,6 +367,18 @@ void hard_reset_now (void)
                                : "i" ((void *) (0x1000 - sizeof (real_mode_switch))));
 }
 
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
+       apm_set_power_state(APM_STATE_OFF);
+#endif
+}
+
+
 void show_regs(struct pt_regs * regs)
 {
        printk("\n");
index 6e595055fc42dde7bef8308e11036df47478f05f..2e50d068ba46ac77445468f1727ff9d1bd757fe5 100644 (file)
@@ -44,6 +44,8 @@
 #include <asm/smp.h>
 #include <asm/io.h>
 
+extern unsigned long start_kernel, _etext;
+
 /*
  *     Some notes on processor bugs:
  *
@@ -122,9 +124,6 @@ unsigned long apic_retval;                          /* Just debugging the assembler..                       */
 unsigned char *kernel_stacks[NR_CPUS];                 /* Kernel stack pointers for CPU's (debugging)          */
 
 static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; /* True if this processor is sending an IPI             */
-static volatile unsigned long smp_msg_data;            /* IPI data pointer                                     */
-static volatile int smp_src_cpu;                       /* IPI sender processor                                 */
-static volatile int smp_msg_id;                                /* Message being sent                                   */
 
 volatile unsigned long kernel_flag=0;                  /* Kernel spinlock                                      */
 volatile unsigned char active_kernel_processor = NO_PROC_ID;   /* Processor holding kernel spinlock            */
@@ -491,6 +490,7 @@ int smp_scan_config(unsigned long base, unsigned long length)
                                 */
                                nlong = boot_cpu_id<<24;        /* Dummy 'self' for bootup */
                                cpu_logical_map[0] = boot_cpu_id;
+                               global_irq_holder = boot_cpu_id;
 
                                printk("Processors: %d\n", num_processors);
                                /*
@@ -1051,7 +1051,6 @@ void smp_boot_cpus(void)
        SMP_PRINTK(("Boot done.\n"));
 }
 
-
 /*
  *     A non wait message cannot pass data or cpu source info. This current setup
  *     is only safe because the kernel lock owner is the only person who can send a message.
@@ -1070,9 +1069,8 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
        unsigned long cfg;
        unsigned long target_map;
        int p=smp_processor_id();
-       int irq=0x2d;                                                           /* IRQ 13 */
+       int irq;
        int ct=0;
-       static volatile int message_cpu = NO_PROC_ID;
 
        /*
         *      During boot up send no messages
@@ -1087,11 +1085,24 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         *      message at this time. The reschedule cannot wait
         *      but is not critical.
         */
-       
-       if(msg==MSG_RESCHEDULE)                                                 /* Reschedules we do via trap 0x30 */
-       {
-               irq=0x30;
-               if(smp_cpu_in_msg[p])
+
+       switch (msg) {
+               case MSG_RESCHEDULE:    
+                       irq = 0x30;
+                       if (smp_cpu_in_msg[p])
+                               return;
+                       break;
+
+               case MSG_INVALIDATE_TLB:
+                       irq = 0x31;
+                       break;
+
+               case MSG_STOP_CPU:
+                       irq = 0x32;
+                       break;
+
+               default:
+                       printk("Unknown SMP message %d\n", msg);
                        return;
        }
 
@@ -1103,31 +1114,12 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         *      I got to notice this bug...
         */
         
-       if(message_cpu!=NO_PROC_ID && msg!=MSG_STOP_CPU && msg!=MSG_RESCHEDULE)
-       {
-               panic("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
-                       smp_processor_id(),msg,message_cpu, smp_msg_id);
-       }
-
-       message_cpu=smp_processor_id();
-       
        /*
         *      We are busy
         */
                
        smp_cpu_in_msg[p]++;
        
-       /*
-        *      Reschedule is currently special
-        */
-        
-       if(msg!=MSG_RESCHEDULE)
-       {
-               smp_src_cpu=p;
-               smp_msg_id=msg;
-               smp_msg_data=data;
-       }
-       
 /*     printk("SMP message pass #%d to %d of %d\n",
                p, msg, target);*/
        
@@ -1150,7 +1142,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         */
         
        if(ct==1000)
-               printk("CPU #%d: previous IPI still not cleared after 10mS", smp_processor_id());
+               printk("CPU #%d: previous IPI still not cleared after 10mS", p);
                
        /*
         *      Program the APIC to deliver the IPI
@@ -1171,7 +1163,7 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
        {
                cfg|=APIC_DEST_ALLBUT;
                target_map=cpu_present_map;
-               cpu_callin_map[0]=(1<<smp_src_cpu);
+               cpu_callin_map[0]=(1<<p);
        }
        else if(target==MSG_ALL)
        {
@@ -1197,11 +1189,30 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         
        switch(wait)
        {
+               int stuck;
                case 1:
-                       while(cpu_callin_map[0]!=target_map);           /* Spin on the pass             */
+                       stuck = 50000000;
+                       while(cpu_callin_map[0]!=target_map) {
+                               --stuck;
+                               if (!stuck) {
+                                       printk("stuck on target_map IPI wait\n");
+                                       break;
+                               }
+                       }
                        break;
                case 2:
-                       while(smp_invalidate_needed);                   /* Wait for invalidate map to clear */
+                       stuck = 50000000;
+                       /* Wait for invalidate map to clear */
+                       while (smp_invalidate_needed) {
+                               /* Take care of "crossing" invalidates */
+                               if (test_bit(p, &smp_invalidate_needed))
+                                       clear_bit(p, &smp_invalidate_needed);
+                               --stuck;
+                               if (!stuck) {
+                                       printk("stuck on smp_invalidate_needed IPI wait\n");
+                                       break;
+                               }
+                       }
                        break;
        }
        
@@ -1210,7 +1221,6 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
         */
         
        smp_cpu_in_msg[p]--;
-       message_cpu=NO_PROC_ID;
 }
 
 /*
@@ -1233,15 +1243,15 @@ void smp_flush_tlb(void)
         *      bus locked or.
         */
        
-       smp_invalidate_needed=cpu_present_map&~(1<<smp_processor_id());
+       smp_invalidate_needed=cpu_present_map;
        
        /*
         *      Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
         *      ensure they don't do a spurious flush tlb or miss one.
         */
         
-       save_flags(flags);
-       cli();
+       __save_flags(flags);
+       __cli();
        smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
        
        /*
@@ -1250,7 +1260,7 @@ void smp_flush_tlb(void)
         
        local_flush_tlb();
        
-       restore_flags(flags);
+       __restore_flags(flags);
        
        /*
         *      Completed.
@@ -1262,69 +1272,34 @@ void smp_flush_tlb(void)
 /*     
  *     Reschedule call back
  */
-
-void smp_reschedule_irq(int cpl, struct pt_regs *regs)
+asmlinkage void smp_reschedule_interrupt(void)
 {
-       lock_kernel();
-       intr_count++;
-       if(smp_processor_id()!=active_kernel_processor)
-               panic("SMP Reschedule on CPU #%d, but #%d is active.\n",
-                       smp_processor_id(), active_kernel_processor);
-
        need_resched=1;
 
        /* Clear the IPI */
        apic_read(APIC_SPIV);           /* Dummy read */
        apic_write(APIC_EOI, 0);        /* Docs say use 0 for future compatibility */
-
-       intr_count--;
-       unlock_kernel();
-}      
+}
 
 /*
- *     Message call back.
+ * Invalidate call-back
  */
-void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs)
+asmlinkage void smp_invalidate_interrupt(void)
 {
-       int i=smp_processor_id();
-/*     static int n=0;
-       if(n++<NR_CPUS)
-               printk("IPI %d->%d(%d,%ld)\n",smp_src_cpu,i,smp_msg_id,smp_msg_data);*/
-       switch(smp_msg_id)
-       {
-               case 0: /* IRQ 13 testing - boring */
-                       return;
-                       
-               /*
-                *      A TLB flush is needed.
-                */
-                
-               case MSG_INVALIDATE_TLB:
-                       if(clear_bit(i,(unsigned long *)&smp_invalidate_needed))
-                               local_flush_tlb();
-                       set_bit(i, (unsigned long *)&cpu_callin_map[0]);
-               /*      cpu_callin_map[0]|=1<<smp_processor_id();*/
-                       break;
-                       
-               /*
-                *      Halt other CPU's for a panic or reboot
-                */
-               case MSG_STOP_CPU:
-                       while(1)
-                       {
-                               if(cpu_data[smp_processor_id()].hlt_works_ok)
-                                       __asm__("hlt");
-                       }
-               default:
-                       printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
-                               smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
-                       break;
-       }
-       /*
-        *      Clear the IPI, so we can receive future IPI's
-        */
-        
+       if (clear_bit(smp_processor_id(), &smp_invalidate_needed))
+               local_flush_tlb();
+
+       /* Clear the IPI */
        apic_read(APIC_SPIV);           /* Dummy read */
        apic_write(APIC_EOI, 0);        /* Docs say use 0 for future compatibility */
+}      
+
+/*
+ *     CPU halt call-back
+ */
+asmlinkage void smp_stop_cpu_interrupt(void)
+{
+       if (cpu_data[smp_processor_id()].hlt_works_ok)
+               for(;;) __asm__("hlt");
+       for  (;;) ;
 }
index a15ba441de208ba051a6e4e7180e42996466064a..627cea05d01e1ebc49c51955b0ef2a42844d9d9f 100644 (file)
@@ -388,7 +388,7 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
           basically because we don't yet share IRQ's around. This message is
           rigged to be safe on the 386 - basically it's a hack, so don't look
           closely for now.. */
-       /*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
+       smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
            
 #ifdef CONFIG_MCA
        if( MCA_bus ) {
index ec69095486448e1947ca28b3d27e0c2cbf727b9d..2803a83677eff56ed83d83abe3bb1534261ad692 100644 (file)
@@ -231,7 +231,6 @@ out:
 
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
-       lock_kernel();
 #ifdef CONFIG_SMP_NMI_INVAL
        smp_flush_tlb_rcv();
 #else
@@ -241,7 +240,6 @@ asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
        printk("power saving mode enabled.\n");
 #endif 
 #endif
-       unlock_kernel();
 }
 
 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
@@ -305,18 +303,14 @@ out:
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
-       lock_kernel();
        ignore_irq13 = 1;
        math_error();
-       unlock_kernel();
 }
 
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
                                          long error_code)
 {
-       lock_kernel();
        printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
-       unlock_kernel();
 }
 
 /*
@@ -328,7 +322,6 @@ asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
  */
 asmlinkage void math_state_restore(void)
 {
-       lock_kernel();
        __asm__ __volatile__("clts");           /* Allow maths ops (or we recurse) */
 
 /*
@@ -341,7 +334,7 @@ asmlinkage void math_state_restore(void)
  */
 #ifndef __SMP__
        if (last_task_used_math == current)
-               goto out;
+               return;
        if (last_task_used_math)
                __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
        else
@@ -360,10 +353,6 @@ asmlinkage void math_state_restore(void)
                current->used_math = 1;
        }
        current->flags|=PF_USEDFPU;             /* So we fnsave on switch_to() */
-#ifndef __SMP__
-out:
-#endif
-       unlock_kernel();
 }
 
 #ifndef CONFIG_MATH_EMULATION
index 6231f7c8b234a0f36ed72d20bba64dcc7f594df7..a34e94cb14d1d20af9165810ed1d3bb0d9b1cd54 100644 (file)
@@ -48,4 +48,5 @@ EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
+EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
index 8a61ea8cad1e7cd1708afcf1b6efc433accade26..339f73b3312b31fa59fc6dcc844775701f338799 100644 (file)
@@ -78,6 +78,7 @@ CONFIG_BLK_DEV_LOOP=m
 CONFIG_NETLINK=y
 CONFIG_RTNETLINK=y
 CONFIG_FIREWALL=y
+# CONFIG_NET_SECURITY is not set
 CONFIG_NET_ALIAS=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
index 047bdb04d775feb1358827fae0690310609bb642..02b729a9e3cf70c5948b77fd608bb97b1d3767d2 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.81 1997/01/29 10:32:55 davem Exp $
+/*  $Id: setup.c,v 1.82 1997/03/08 08:27:04 ecd Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -115,6 +115,7 @@ unsigned int boot_flags;
 extern char *console_fb_path;
 static int console_fb = 0;
 #endif
+static unsigned long memory_size = 0;
 
 void kernel_enter_debugger(void)
 {
@@ -215,8 +216,23 @@ __initfunc(static void boot_flags_init(char *commands))
                                        console_fb = 1;
                                        console_fb_path = commands;
                                }
-                       }
+                       } else
 #endif
+                       if (!strncmp(commands, "mem=", 4)) {
+                               /*
+                                * "mem=XXX[kKmM] overrides the PROM-reported
+                                * memory size.
+                                */
+                               memory_size = simple_strtoul(commands + 4,
+                                                            &commands, 0);
+                               if (*commands == 'K' || *commands == 'k') {
+                                       memory_size <<= 10;
+                                       commands++;
+                               } else if (*commands=='M' || *commands=='m') {
+                                       memory_size <<= 20;
+                                       commands++;
+                               }
+                       }
                        while (*commands && *commands != ' ')
                                commands++;
                }
@@ -337,15 +353,35 @@ __initfunc(void setup_arch(char **cmdline_p,
        *memory_start_p = (((unsigned long) &end));
 
        if(!packed) {
-               for(i=0; sp_banks[i].num_bytes != 0; i++)
+               for(i=0; sp_banks[i].num_bytes != 0; i++) {
                        end_of_phys_memory = sp_banks[i].base_addr +
-                               sp_banks[i].num_bytes;
+                                            sp_banks[i].num_bytes;
+                       if (memory_size) {
+                               if (end_of_phys_memory > memory_size) {
+                                       sp_banks[i].num_bytes -=
+                                           (end_of_phys_memory - memory_size);
+                                       end_of_phys_memory = memory_size;
+                                       sp_banks[++i].base_addr = 0xdeadbeef;
+                                       sp_banks[i].num_bytes = 0;
+                               }
+                       }
+               }
        } else {
                unsigned int sum = 0;
 
-               for(i = 0; sp_banks[i].num_bytes != 0; i++)
+               for(i = 0; sp_banks[i].num_bytes != 0; i++) {
                        sum += sp_banks[i].num_bytes;
-
+                       if (memory_size) {
+                               if (sum > memory_size) {
+                                       sp_banks[i].num_bytes -=
+                                                       (sum - memory_size);
+                                       sum = memory_size;
+                                       sp_banks[++i].base_addr = 0xdeadbeef;
+                                       sp_banks[i].num_bytes = 0;
+                                       break;
+                               }
+                       }
+               }
                end_of_phys_memory = sum;
        }
 
index 02a48af103c7119db1127ad3c3e5b0376cd5ebd2..57460591381aff4e131311de3a0d01500821af01 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.47 1997/03/03 16:51:41 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.49 1997/03/15 07:47:45 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/in6.h>
 
 #include <asm/oplib.h>
 #include <asm/delay.h>
@@ -27,6 +28,7 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 #ifdef CONFIG_SBUS
 #include <asm/sbus.h>
 #include <asm/dma.h>
@@ -52,7 +54,6 @@ extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
@@ -183,12 +184,14 @@ EXPORT_SYMBOL(__memcmp);
 EXPORT_SYMBOL(__strncmp);
 EXPORT_SYMBOL(__memmove);
 
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
-
 /* Moving data to/from userspace. */
 EXPORT_SYMBOL(__copy_user);
 EXPORT_SYMBOL(__strncpy_from_user);
 
+/* Networking helper routines. */
+/* XXX This is NOVERS because C_LABEL_STR doesn't get the version number. -DaveM */
+EXPORT_SYMBOL_NOVERS(__csum_partial_copy_sparc_generic);
+
 /* No version information on this, heavily used in inline asm,
  * and will always be 'void __ret_efault(void)'.
  */
index bc4f165c69f1016855508a29cd8b1e136da53b89..76136f9dc3418c98431f86bd1a5b65787873d3a9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.15 1997/01/16 14:14:42 davem Exp $
+/* $Id: unaligned.c,v 1.16 1997/03/18 17:53:44 jj Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -19,8 +19,6 @@
 
 /* #define DEBUG_MNA */
 
-extern void die_if_kernel(char *, struct pt_regs *);
-
 enum direction {
        load,    /* ld, ldd, ldh, ldsh */
        store,   /* st, std, sth, stsh */
index 71126ea45ddd53998ff6565e0e07961e607978bb..a7a67b8b2ea456a597999fd27b07b52e319f8adb 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.21 1997/01/25 06:48:43 davem Exp $
+# $Id: Makefile,v 1.22 1997/03/14 21:04:17 jj Exp $
 # Makefile for Sparc library files..
 #
 
@@ -7,7 +7,7 @@ CFLAGS := $(CFLAGS) -ansi
 OBJS  = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
         strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
        strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
-       copy_user.o clear_user.o locks.o atomic.o bitops.o
+       copy_user.o locks.o atomic.o bitops.o
 
 lib.a: $(OBJS)
        $(AR) rcs lib.a $(OBJS)
@@ -37,9 +37,6 @@ strlen_user.o: strlen_user.S
 copy_user.o: copy_user.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o copy_user.o copy_user.S
 
-clear_user.o: clear_user.S
-       $(CC) -D__ASSEMBLY__ -ansi -c -o clear_user.o clear_user.S
-
 blockops.o: blockops.S
        $(CC) -ansi -c -o blockops.o blockops.S
 
diff --git a/arch/sparc/lib/clear_user.S b/arch/sparc/lib/clear_user.S
deleted file mode 100644 (file)
index 7240521..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/* linux/arch/sparc/lib/clear_user.S: Sparc optimized clear_user code
- *
- * Zero %o1 bytes at user %o0, handling exceptions as we go.
- * Returns 0 if successfull, # of bytes still not cleared otherwise
- *
- * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/cprefix.h>
-#include <asm/ptrace.h>
-
-#define EX(x,y,a,b,z)                          \
-98:    x,y;                                    \
-       .section .fixup,z##alloc,z##execinstr;  \
-       .align  4;                              \
-99:    retl;                                   \
-        a, b, %o0;                             \
-       .section __ex_table,z##alloc;           \
-       .align  4;                              \
-       .word   98b, 99b;                       \
-       .text;                                  \
-       .align  4
-
-#define EXT(start,end,handler,z)               \
-       .section __ex_table,z##alloc;           \
-       .align  4;                              \
-       .word   start, 0, end, handler;         \
-       .text;                                  \
-       .align  4
-
-/* Please don't change these macros, unless you change the login
- * in the .fixup section below as well */
-/* Store 64 bytes at (BASE + OFFSET) using value SOURCE. */
-#define ZERO_BIG_BLOCK(base, offset, source)    \
-       std     source, [base + offset + 0x00]; \
-       std     source, [base + offset + 0x08]; \
-       std     source, [base + offset + 0x10]; \
-       std     source, [base + offset + 0x18]; \
-       std     source, [base + offset + 0x20]; \
-       std     source, [base + offset + 0x28]; \
-       std     source, [base + offset + 0x30]; \
-       std     source, [base + offset + 0x38];
-
-#define ZERO_LAST_BLOCKS(base, offset, source) \
-       std     source, [base - offset - 0x38]; \
-       std     source, [base - offset - 0x30]; \
-       std     source, [base - offset - 0x28]; \
-       std     source, [base - offset - 0x20]; \
-       std     source, [base - offset - 0x18]; \
-       std     source, [base - offset - 0x10]; \
-       std     source, [base - offset - 0x08]; \
-       std     source, [base - offset - 0x00];
-
-       .text
-       .align 4
-
-       .globl  C_LABEL(__clear_user)
-3:
-       cmp     %o2, 3
-       be      2f
-        EX(stb %g0, [%o0], sub %o1, 0,#)
-
-       cmp     %o2, 2
-       be      2f
-        EX(stb %g0, [%o0 + 0x01], sub %o1, 1,#)
-
-       EX(stb  %g0, [%o0 + 0x02], sub %o1, 2,#)
-2:
-       sub     %o2, 4, %o2
-       add     %o1, %o2, %o1
-       b       4f
-        sub    %o0, %o2, %o0
-
-C_LABEL(__clear_user):
-       cmp     %o1, 7
-       bleu    7f
-        andcc  %o0, 3, %o2
-       bne     3b
-4:
-        andcc  %o0, 4, %g0
-
-       be      2f
-        mov    %g0, %g1
-
-       EX(st   %g0, [%o0], sub %o1, 0,#)
-       sub     %o1, 4, %o1
-       add     %o0, 4, %o0
-2:
-       andcc   %o1, 0xffffff80, %o3    ! Now everything is 8 aligned and o1 is len to run
-       be      9f
-        andcc  %o1, 0x78, %o2
-10:
-       ZERO_BIG_BLOCK(%o0, 0x00, %g0)
-       subcc   %o3, 128, %o3
-       ZERO_BIG_BLOCK(%o0, 0x40, %g0)
-11:
-       EXT(10b, 11b, 20f,#)
-       bne     10b
-        add    %o0, 128, %o0
-
-       orcc    %o2, %g0, %g0
-9:
-       be      13f
-        andcc  %o1, 7, %o1
-
-       srl     %o2, 1, %o3
-       set     13f, %o4
-       sub     %o4, %o3, %o4
-       jmp     %o4
-        add    %o0, %o2, %o0
-
-12:
-       ZERO_LAST_BLOCKS(%o0, 0x48, %g0)
-       ZERO_LAST_BLOCKS(%o0, 0x08, %g0)
-13:
-       EXT(12b, 13b, 21f,#)
-       be      8f
-        andcc  %o1, 4, %g0
-
-       be      1f
-        andcc  %o1, 2, %g0
-
-       EX(st   %g0, [%o0], and %o1, 7,#)
-       add     %o0, 4, %o0
-1:
-       be      1f
-        andcc  %o1, 1, %g0
-
-       EX(sth  %g0, [%o0], and %o1, 3,#)
-       add     %o0, 2, %o0
-1:
-       bne,a   8f
-        EX(stb %g0, [%o0], add %g0, 1,#)
-8:
-       retl
-        clr    %o0
-7:
-       be      13b
-        orcc   %o1, 0, %g0
-
-       andcc   %o1, 4, %g0
-       be      1f
-        andcc  %o1, 2, %g0
-
-       EX(stb  %g0, [%o0 + 0], sub %o1, 0,#)
-       EX(stb  %g0, [%o0 + 1], sub %o1, 1,#)
-       EX(stb  %g0, [%o0 + 2], sub %o1, 2,#)
-       EX(stb  %g0, [%o0 + 3], sub %o1, 3,#)
-       add     %o0, 4, %o0
-1:
-       be      1f
-        andcc  %o1, 1, %o2
-
-       EX(stb  %g0, [%o0 + 0], add %o2, 2,#)
-       EX(stb  %g0, [%o0 + 1], add %o2, 1,#)
-       add     %o0, 2, %o0
-1:
-       bne,a   8b
-        EX(stb %g0, [%o0], add %g0, 1,#)
-
-       retl
-        clr    %o0
-
-       .section .fixup,#alloc,#execinstr
-       .align  4
-20:
-       cmp     %g2, 8
-       bleu    1f
-        and    %o1, 0x7f, %o1
-       sub     %g2, 9, %g2
-       add     %o3, 64, %o3
-1:
-       sll     %g2, 3, %g2
-       add     %o3, %o1, %o0
-       retl
-        sub    %o0, %g2, %o0
-21:
-       mov     8, %o0
-       and     %o1, 7, %o1
-       sub     %o0, %g2, %o0
-       sll     %o0, 3, %o0
-       retl
-        add    %o0, %o1, %o0
index 37427160b9eb5509630737d85f51826ee56b6665..1d778e3fd52bf469b8b3468d89c51d30d727340d 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.22 1996/11/22 11:57:03 ecd Exp $
+# $Id: Makefile,v 1.23 1997/03/10 09:16:52 davem Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -8,7 +8,10 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS   := fault.o init.o sun4c.o srmmu.o loadmmu.o generic.o asyncd.o \
-           extable.o
+O_OBJS   := fault.o init.o sun4c.o srmmu.o hypersparc.o loadmmu.o \
+           generic.o asyncd.o extable.o
 
 include $(TOPDIR)/Rules.make
+
+hypersparc.o: hypersparc.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o hypersparc.o hypersparc.S
index c54426d619a43ea348d50ecbdde8a5dff0d59ee9..cfac6bcc23d5b0179bd98f3b66c7af30439c3d81 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.89 1997/03/04 16:26:46 jj Exp $
+/* $Id: fault.c,v 1.91 1997/03/18 17:56:00 jj Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -36,8 +36,6 @@
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 extern int prom_node_root;
 
-extern void die_if_kernel(char *,struct pt_regs *);
-
 struct linux_romvec *romvec;
 
 /* At boot time we determine these two values necessary for setting
@@ -134,7 +132,10 @@ asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
        prom_halt();
 }
 
-void unhandled_fault(unsigned long address, struct task_struct *tsk,
+static void unhandled_fault(unsigned long, struct task_struct *,
+               struct pt_regs *) __attribute__ ((noreturn));
+
+static void unhandled_fault(unsigned long address, struct task_struct *tsk,
                      struct pt_regs *regs)
 {
        if((unsigned long) address < PAGE_SIZE) {
@@ -165,10 +166,10 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
        case 3: return 3;
        /* store will be handled by fixup, load will bump out */
        /* for _to_ macros */
-       case 1: insn = (unsigned *)pc; if ((insn >> 21) & 1) return 1; break;
+       case 1: insn = (unsigned)pc; if ((insn >> 21) & 1) return 1; break;
        /* load will be handled by fixup, store will bump out */
        /* for _from_ macros */
-       case 2: insn = (unsigned *)pc; 
+       case 2: insn = (unsigned)pc; 
                if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; 
                break; 
        default: break;
diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S
new file mode 100644 (file)
index 0000000..5f3206c
--- /dev/null
@@ -0,0 +1,335 @@
+/* $Id: hypersparc.S,v 1.1 1997/03/10 09:16:52 davem Exp $
+ * hypersparc.S: High speed Hypersparc mmu/cache operations.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtsrmmu.h>
+
+#define WINDOW_FLUSH(tmp1, tmp2)                                       \
+       mov     0, tmp1;                                                \
+98:    ld      [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2;     \
+       orcc    %g0, tmp2, %g0;                                         \
+       add     tmp1, 1, tmp1;                                          \
+       bne     98b;                                                    \
+        save   %sp, -64, %sp;                                          \
+99:    subcc   tmp1, 1, tmp1;                                          \
+       bne     99b;                                                    \
+        restore %g0, %g0, %g0;
+
+       .text
+       .align  4
+
+       .globl  hypersparc_flush_cache_all, hypersparc_flush_cache_mm
+       .globl  hypersparc_flush_cache_range, hypersparc_flush_cache_page
+       .globl  hypersparc_flush_page_to_ram, hypersparc_flush_chunk
+       .globl  hypersparc_flush_page_for_dma, hypersparc_flush_sig_insns
+       .globl  hypersparc_flush_tlb_all, hypersparc_flush_tlb_mm
+       .globl  hypersparc_flush_tlb_range, hypersparc_flush_tlb_page
+
+       /* Verified... */
+hypersparc_flush_cache_all:
+       WINDOW_FLUSH(%g4, %g5)
+       sethi   %hi(vac_cache_size), %g4
+       ld      [%g4 + %lo(vac_cache_size)], %g5
+       sethi   %hi(vac_line_size), %g1
+       ld      [%g1 + %lo(vac_line_size)], %g2
+1:     
+       subcc   %g5, %g2, %g5                   ! hyper_flush_unconditional_combined
+       bne     1b
+        sta    %g0, [%g5] ASI_M_FLUSH_CTX
+       retl
+        sta    %g0, [%g0] ASI_M_FLUSH_IWHOLE   ! hyper_flush_whole_icache
+
+       /* We expand the window flush to get maximum performance. */
+       /* Verified... */
+hypersparc_flush_cache_mm:
+#ifndef __SMP__
+       ld      [%o0 + AOFF_mm_context], %g1
+       cmp     %g1, -1
+       be      hypersparc_flush_cache_mm_out
+#endif
+       WINDOW_FLUSH(%g4, %g5)
+
+       sethi   %hi(vac_line_size), %g1
+       ld      [%g1 + %lo(vac_line_size)], %o1
+       sethi   %hi(vac_cache_size), %g2
+       ld      [%g2 + %lo(vac_cache_size)], %o0
+       add     %o1, %o1, %g1
+       add     %o1, %g1, %g2
+       add     %o1, %g2, %g3
+       add     %o1, %g3, %g4
+       add     %o1, %g4, %g5
+       add     %o1, %g5, %o4
+       add     %o1, %o4, %o5
+
+       /* BLAMMO! */
+1:
+       subcc   %o0, %o5, %o0                           ! hyper_flush_cache_user
+       sta     %g0, [%o0 + %g0] ASI_M_FLUSH_USER
+       sta     %g0, [%o0 + %o1] ASI_M_FLUSH_USER
+       sta     %g0, [%o0 + %g1] ASI_M_FLUSH_USER
+       sta     %g0, [%o0 + %g2] ASI_M_FLUSH_USER
+       sta     %g0, [%o0 + %g3] ASI_M_FLUSH_USER
+       sta     %g0, [%o0 + %g4] ASI_M_FLUSH_USER
+       sta     %g0, [%o0 + %g5] ASI_M_FLUSH_USER
+       bne     1b
+        sta    %g0, [%o0 + %o4] ASI_M_FLUSH_USER
+hypersparc_flush_cache_mm_out:
+       retl
+        sta    %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE     ! hyper_flush_whole_icache
+
+       /* The things we do for performance... */
+       /* Verified... */
+hypersparc_flush_cache_range:
+#ifndef __SMP__
+       ld      [%o0 + AOFF_mm_context], %g1
+       cmp     %g1, -1
+       be      hypersparc_flush_cache_range_out
+#endif
+       WINDOW_FLUSH(%g4, %g5)
+
+       sethi   %hi(vac_line_size), %g1
+       ld      [%g1 + %lo(vac_line_size)], %o4
+       sethi   %hi(vac_cache_size), %g2
+       ld      [%g2 + %lo(vac_cache_size)], %o3
+
+       /* Here comes the fun part... */
+       add     %o2, (PAGE_SIZE - 1), %o2
+       andn    %o1, (PAGE_SIZE - 1), %o1
+       add     %o4, %o4, %o5
+       andn    %o2, (PAGE_SIZE - 1), %o2
+       add     %o4, %o5, %g1
+       sub     %o2, %o1, %g4
+       add     %o4, %g1, %g2
+       sll     %o3, 2, %g5
+       add     %o4, %g2, %g3
+       cmp     %g4, %g5
+       add     %o4, %g3, %g4
+       blu     0f
+        add    %o4, %g4, %g5
+       add     %o4, %g5, %g7
+
+       /* Flush entire user space, believe it or not this is quicker
+        * than page at a time flushings for range > (cache_size<<2).
+        */
+1:
+       subcc   %o3, %g7, %o3
+       sta     %g0, [%o3 + %g0] ASI_M_FLUSH_USER
+       sta     %g0, [%o3 + %o4] ASI_M_FLUSH_USER
+       sta     %g0, [%o3 + %o5] ASI_M_FLUSH_USER
+       sta     %g0, [%o3 + %g1] ASI_M_FLUSH_USER
+       sta     %g0, [%o3 + %g2] ASI_M_FLUSH_USER
+       sta     %g0, [%o3 + %g3] ASI_M_FLUSH_USER
+       sta     %g0, [%o3 + %g4] ASI_M_FLUSH_USER
+       bne     1b
+        sta    %g0, [%o3 + %g5] ASI_M_FLUSH_USER
+       retl
+        sta    %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+
+       /* Below our threshold, flush one page at a time. */
+0:
+       ld      [%o0 + AOFF_mm_context], %o0
+       mov     SRMMU_CTX_REG, %g7
+       lda     [%g7] ASI_M_MMUREGS, %o3
+       sta     %o0, [%g7] ASI_M_MMUREGS
+       sethi   %hi(PAGE_SIZE), %g7             /* XXX ick, stupid stalls... */
+       sub     %o2, %g7, %o0
+1:
+       or      %o0, 0x400, %g7
+       lda     [%g7] ASI_M_FLUSH_PROBE, %g7
+       orcc    %g7, 0, %g0
+       be,a    3f
+        mov    %o0, %o2
+       add     %o4, %g5, %g7
+2:
+       sub     %o2, %g7, %o2
+       sta     %g0, [%o2 + %g0] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o2 + %o4] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o2 + %o5] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o2 + %g1] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o2 + %g2] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o2 + %g3] ASI_M_FLUSH_PAGE
+       andcc   %o2, 0xffc, %g0
+       sta     %g0, [%o2 + %g4] ASI_M_FLUSH_PAGE
+       bne     2b
+        sta    %g0, [%o2 + %g5] ASI_M_FLUSH_PAGE
+3:
+       sethi   %hi(PAGE_SIZE), %g7
+       cmp     %o2, %o1
+       bne     1b
+        sub    %o2, %g7, %o0
+       mov     SRMMU_FAULT_STATUS, %g5
+       lda     [%g5] ASI_M_MMUREGS, %g0
+       mov     SRMMU_CTX_REG, %g7
+       sta     %o3, [%g7] ASI_M_MMUREGS
+hypersparc_flush_cache_range_out:
+       retl
+        sta    %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+
+       /* HyperSparc requires a valid mapping where we are about to flush
+        * in order to check for a physical tag match during the flush.
+        */
+       /* Verified... */
+hypersparc_flush_cache_page:
+       ld      [%o0 + 0x0], %o0                /* XXX vma->vm_mm, GROSS XXX */
+#ifndef __SMP__
+       ld      [%o0 + AOFF_mm_context], %g1
+       cmp     %g1, -1
+       be      hypersparc_flush_cache_page_out
+#endif
+       WINDOW_FLUSH(%g4, %g5)
+
+       sethi   %hi(vac_line_size), %g1
+       ld      [%g1 + %lo(vac_line_size)], %o4
+       mov     SRMMU_CTX_REG, %o3
+       andn    %o1, (PAGE_SIZE - 1), %o1
+       lda     [%o3] ASI_M_MMUREGS, %o2
+       sta     %g1, [%o3] ASI_M_MMUREGS
+       or      %o1, 0x400, %o5
+       lda     [%o5] ASI_M_FLUSH_PROBE, %g1
+       orcc    %g0, %g1, %g0
+       sethi   %hi(PAGE_SIZE), %g7
+       be      2f
+        add    %o4, %o4, %o5
+       add     %o1, %g7, %o1
+       add     %o4, %o5, %g1
+       add     %o4, %g1, %g2
+       add     %o4, %g2, %g3
+       add     %o4, %g3, %g4
+       add     %o4, %g4, %g5
+       add     %o4, %g5, %g7
+
+       /* BLAMMO! */
+1:
+       sub     %o1, %g7, %o1
+       sta     %g0, [%o1 + %g0] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o4] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %o5] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g1] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g2] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o1 + %g3] ASI_M_FLUSH_PAGE
+       andcc   %o1, 0xffc, %g0
+       sta     %g0, [%o1 + %g4] ASI_M_FLUSH_PAGE
+       bne     1b
+        sta    %g0, [%o1 + %g5] ASI_M_FLUSH_PAGE
+2:
+       mov     SRMMU_FAULT_STATUS, %g7
+       mov     SRMMU_CTX_REG, %g4
+       lda     [%g7] ASI_M_MMUREGS, %g0
+       sta     %o2, [%g4] ASI_M_MMUREGS
+hypersparc_flush_cache_page_out:
+hypersparc_flush_sig_insns:            /* This is "neat"... */
+       retl
+        sta    %g0, [%g0 + %g0] ASI_M_FLUSH_IWHOLE
+
+       /* HyperSparc is copy-back. */
+       /* Verified... */
+hypersparc_flush_page_to_ram:
+hypersparc_flush_chunk:
+       sethi   %hi(vac_line_size), %g1
+       ld      [%g1 + %lo(vac_line_size)], %o4
+       andn    %o0, (PAGE_SIZE - 1), %o0
+       add     %o4, %o4, %o5
+       or      %o0, 0x400, %g7
+       lda     [%g7] ASI_M_FLUSH_PROBE, %g5
+       add     %o4, %o5, %g1
+       orcc    %g5, 0, %g0
+       be      2f
+        add    %o4, %g1, %g2
+       sethi   %hi(PAGE_SIZE), %g5
+       add     %o4, %g2, %g3
+       add     %o0, %g5, %o0
+       add     %o4, %g3, %g4
+       add     %o4, %g4, %g5
+       add     %o4, %g5, %g7
+
+       /* BLAMMO! */
+1:
+       sub     %o0, %g7, %o0
+       sta     %g0, [%o0 + %g0] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o0 + %o4] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o0 + %o5] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o0 + %g1] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o0 + %g2] ASI_M_FLUSH_PAGE
+       sta     %g0, [%o0 + %g3] ASI_M_FLUSH_PAGE
+       andcc   %o0, 0xffc, %g0
+       sta     %g0, [%o0 + %g4] ASI_M_FLUSH_PAGE
+       bne     1b
+        sta    %g0, [%o0 + %g5] ASI_M_FLUSH_PAGE
+2:
+       mov     SRMMU_FAULT_STATUS, %g1
+       retl
+        lda    [%g1] ASI_M_MMUREGS, %g0
+
+       /* HyperSparc is IO cache coherent. */
+hypersparc_flush_page_for_dma:
+       retl
+        nop
+
+       /* Verified... */
+hypersparc_flush_tlb_all:
+       mov     0x400, %g1
+       retl
+        sta    %g0, [%g1] ASI_M_FLUSH_PROBE
+
+       /* Verified... */
+hypersparc_flush_tlb_mm:
+       mov     SRMMU_CTX_REG, %g1
+       ld      [%o0 + AOFF_mm_context], %o1
+       lda     [%g1] ASI_M_MMUREGS, %g5
+#ifndef __SMP__
+       cmp     %o1, -1
+       be      hypersparc_flush_tlb_mm_out
+#endif
+       mov     0x300, %g2
+       sta     %o1, [%g1] ASI_M_MMUREGS
+       sta     %g0, [%g2] ASI_M_FLUSH_PROBE
+hypersparc_flush_tlb_mm_out:
+       retl
+        sta    %g5, [%g1] ASI_M_MMUREGS
+
+       /* Verified... */
+hypersparc_flush_tlb_range:
+       mov     SRMMU_CTX_REG, %g1
+       ld      [%o0 + AOFF_mm_context], %o3
+       lda     [%g1] ASI_M_MMUREGS, %g5
+#ifndef __SMP__
+       cmp     %o3, -1
+       be      hypersparc_flush_tlb_range_out
+#endif
+       srl     %o1, SRMMU_PGDIR_SHIFT, %o1
+       sta     %o3, [%g1] ASI_M_MMUREGS
+       sll     %o1, SRMMU_PGDIR_SHIFT, %o1
+       sethi   %hi(1 << SRMMU_PGDIR_SHIFT), %o4
+       add     %o1, 0x200, %o1
+       sta     %g0, [%o1] ASI_M_FLUSH_PROBE
+1:
+       add     %o1, %o4, %o1
+       cmp     %o1, %o2
+       blu,a   1b
+        sta    %g0, [%o1] ASI_M_FLUSH_PROBE
+hypersparc_flush_tlb_range_out:
+       retl
+        sta    %g5, [%g1] ASI_M_MMUREGS
+
+       /* Verified... */
+hypersparc_flush_tlb_page:
+       ld      [%o0 + 0x00], %o0       /* XXX vma->vm_mm GROSS XXX */
+       mov     SRMMU_CTX_REG, %g1
+       ld      [%o0 + AOFF_mm_context], %o3
+       andn    %o1, (PAGE_SIZE - 1), %o1
+       lda     [%g1] ASI_M_MMUREGS, %g5
+#ifndef __SMP__
+       cmp     %o3, -1
+       be      hypersparc_flush_tlb_page_out
+#endif
+       sta     %o3, [%g1] ASI_M_MMUREGS
+       sta     %g0, [%o1] ASI_M_FLUSH_PROBE
+hypersparc_flush_tlb_page_out:
+       retl
+        sta    %g5, [%g1] ASI_M_MMUREGS
index 5b3ae7e734c8c0eb87b0013730b35faf6ab65887..4df1d315b1527ea128dc11e1f0615bb3f6302255 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.130 1997/02/10 23:33:49 davem Exp $
+/* $Id: srmmu.c,v 1.132 1997/03/18 17:56:47 jj Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -53,20 +53,13 @@ extern unsigned long sparc_iobase_vaddr;
 #define FLUSH_END      }
 #endif
 
-#define USE_CHUNK_ALLOC 1
-
-static unsigned long (*mmu_getpage)(void);
 static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
 static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep);
 
 static void (*flush_page_for_dma)(unsigned long page);
-static void (*flush_cache_page_to_uncache)(unsigned long page);
-static void (*flush_tlb_page_for_cbit)(unsigned long page);
 static void (*flush_chunk)(unsigned long chunk);
 #ifdef __SMP__
 static void (*local_flush_page_for_dma)(unsigned long page);
-static void (*local_flush_cache_page_to_uncache)(unsigned long page);
-static void (*local_flush_tlb_page_for_cbit)(unsigned long page);
 #endif
 
 static struct srmmu_stats {
@@ -282,18 +275,11 @@ static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
        }
 }
 
-static unsigned long srmmu_getpage(void)
-{
-       return get_free_page(GFP_KERNEL);
-}
-
 static inline void srmmu_putpage(unsigned long page)
 {
        free_page(page);
 }
 
-#ifdef USE_CHUNK_ALLOC
-
 #define LC_HIGH_WATER  128
 #define BC_HIGH_WATER  32
 
@@ -536,18 +522,6 @@ static inline void free_big_chunk(unsigned long *it)
 #define FREE_PMD(chunk) free_small_chunk((unsigned long *)(chunk))
 #define FREE_PTE(chunk) free_small_chunk((unsigned long *)(chunk))
 
-#else
-
-/* The easy versions. */
-#define NEW_PGD() (pgd_t *) mmu_getpage()
-#define NEW_PMD() (pmd_t *) mmu_getpage()
-#define NEW_PTE() (pte_t *) mmu_getpage()
-#define FREE_PGD(chunk) srmmu_putpage((unsigned long)(chunk))
-#define FREE_PMD(chunk) srmmu_putpage((unsigned long)(chunk))
-#define FREE_PTE(chunk) srmmu_putpage((unsigned long)(chunk))
-
-#endif
-
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
@@ -753,7 +727,6 @@ static void srmmu_quick_kernel_fault(unsigned long address)
               smp_processor_id(), address);
        while (1) ;
 #else
-       extern void die_if_kernel(char *str, struct pt_regs *regs);
        printk("Kernel faults at addr=0x%08lx\n", address);
        printk("PTE=%08lx\n", srmmu_hwprobe((address & PAGE_MASK)));
        die_if_kernel("SRMMU bolixed...", current->tss.kregs);
@@ -948,11 +921,6 @@ static void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long p
        FLUSH_END
 }
 
-static void tsunami_flush_cache_page_to_uncache(unsigned long page)
-{
-       tsunami_flush_dcache();
-}
-
 /* Tsunami does not have a Copy-back style virtual cache. */
 static void tsunami_flush_page_to_ram(unsigned long page)
 {
@@ -1018,11 +986,6 @@ static void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long pag
        FLUSH_END
 }
 
-static void tsunami_flush_tlb_page_for_cbit(unsigned long page)
-{
-       srmmu_flush_tlb_page(page);
-}
-
 /* Swift flushes.  It has the recommended SRMMU specification flushing
  * facilities, so we can do things in a more fine grained fashion than we
  * could on the tsunami.  Let's watch out for HARDWARE BUGS...
@@ -1080,11 +1043,6 @@ static void swift_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
        swift_flush_icache();
 }
 
-static void swift_flush_cache_page_to_uncache(unsigned long page)
-{
-       swift_flush_dcache();
-}
-
 static void swift_flush_chunk(unsigned long chunk)
 {
 }
@@ -1119,11 +1077,6 @@ static void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
        FLUSH_END
 }
 
-static void swift_flush_tlb_page_for_cbit(unsigned long page)
-{
-       srmmu_flush_whole_tlb();
-}
-
 /* The following are all MBUS based SRMMU modules, and therefore could
  * be found in a multiprocessor configuration.  On the whole, these
  * chips seems to be much more touchy about DVMA and page tables
@@ -1267,14 +1220,6 @@ static void viking_flush_page_for_dma(unsigned long page)
 {
 }
 
-static unsigned long viking_no_mxcc_getpage(void)
-{
-       unsigned long page = get_free_page(GFP_KERNEL);
-
-       viking_no_mxcc_flush_page(page);
-       return page;
-}
-
 static void viking_flush_tlb_all(void)
 {
        register int ctr asm("g5");
@@ -1387,11 +1332,6 @@ static void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page
        FLUSH_END
 }
 
-static void viking_flush_tlb_page_for_cbit(unsigned long page)
-{
-       srmmu_flush_tlb_page(page);
-}
-
 /* Cypress flushes. */
 static void cypress_flush_cache_all(void)
 {
@@ -1573,62 +1513,6 @@ static void cypress_flush_sig_insns(struct mm_struct *mm, unsigned long insn_add
 {
 }
 
-static void cypress_flush_page_to_uncache(unsigned long page)
-{
-       register unsigned long a, b, c, d, e, f, g;
-       unsigned long line;
-
-       a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
-       page &= PAGE_MASK;
-       line = (page + PAGE_SIZE) - 0x100;
-       goto inside;
-       do {
-               line -= 0x100;
-       inside:
-               __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
-                                    "sta %%g0, [%0 + %2] %1\n\t"
-                                    "sta %%g0, [%0 + %3] %1\n\t"
-                                    "sta %%g0, [%0 + %4] %1\n\t"
-                                    "sta %%g0, [%0 + %5] %1\n\t"
-                                    "sta %%g0, [%0 + %6] %1\n\t"
-                                    "sta %%g0, [%0 + %7] %1\n\t"
-                                    "sta %%g0, [%0 + %8] %1\n\t" : :
-                                    "r" (line),
-                                    "i" (ASI_M_FLUSH_PAGE),
-                                    "r" (a), "r" (b), "r" (c), "r" (d),
-                                    "r" (e), "r" (f), "r" (g));
-       } while(line != page);
-}
-
-static unsigned long cypress_getpage(void)
-{
-       register unsigned long a, b, c, d, e, f, g;
-       unsigned long page = get_free_page(GFP_KERNEL);
-       unsigned long line;
-
-       a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
-       page &= PAGE_MASK;
-       line = (page + PAGE_SIZE) - 0x100;
-       goto inside;
-       do {
-               line -= 0x100;
-       inside:
-               __asm__ __volatile__("sta %%g0, [%0] %1\n\t"
-                                    "sta %%g0, [%0 + %2] %1\n\t"
-                                    "sta %%g0, [%0 + %3] %1\n\t"
-                                    "sta %%g0, [%0 + %4] %1\n\t"
-                                    "sta %%g0, [%0 + %5] %1\n\t"
-                                    "sta %%g0, [%0 + %6] %1\n\t"
-                                    "sta %%g0, [%0 + %7] %1\n\t"
-                                    "sta %%g0, [%0 + %8] %1\n\t" : :
-                                    "r" (line),
-                                    "i" (ASI_M_FLUSH_PAGE),
-                                    "r" (a), "r" (b), "r" (c), "r" (d),
-                                    "r" (e), "r" (f), "r" (g));
-       } while(line != page);
-       return page;
-}
-
 static void cypress_flush_tlb_all(void)
 {
        srmmu_flush_whole_tlb();
@@ -1692,456 +1576,19 @@ static void cypress_flush_tlb_page(struct vm_area_struct *vma, unsigned long pag
        FLUSH_END
 }
 
-static void cypress_flush_tlb_page_for_cbit(unsigned long page)
-{
-       srmmu_flush_tlb_page(page);
-}
-
-/* Hypersparc flushes.  Very nice chip... */
-static void hypersparc_flush_cache_all(void)
-{
-       register int ctr asm("g5");
-       unsigned long tmp1;
-
-       ctr = 0;
-       __asm__ __volatile__("
-       1:      ld      [%%g6 + %6], %%g4       ! flush user windows
-               orcc    %%g0, %%g4, %%g0
-               add     %1, 1, %1
-               bne     1b
-                save   %%sp, -64, %%sp
-       2:      subcc   %1, 1, %1
-               bne     2b
-                restore %%g0, %%g0, %%g0
-       1:      subcc   %0, %3, %0              ! hyper_flush_unconditional_combined
-               bne     1b
-                sta    %%g0, [%0] %4
-               sta     %%g0, [%%g0] %5         ! hyper_flush_whole_icache"
-       : "=&r" (tmp1), "=&r" (ctr)
-       : "0" (vac_cache_size), "r" (vac_line_size),
-         "i" (ASI_M_FLUSH_CTX), "i" (ASI_M_FLUSH_IWHOLE),
-         "i" (UWINMASK_OFFSET), "1" (ctr)
-       : "g4");
-}
-
-static void hypersparc_flush_cache_mm(struct mm_struct *mm)
-{
-       register int ctr asm("g5");
-
-       FLUSH_BEGIN(mm)
-       ctr = 0;
-       __asm__ __volatile__("
-       1:      ld      [%%g6 + %2], %%g4       ! flush user windows
-               orcc    %%g0, %%g4, %%g0
-               add     %0, 1, %0
-               bne     1b
-                save   %%sp, -64, %%sp
-       2:      subcc   %0, 1, %0
-               bne     2b
-                restore %%g0, %%g0, %%g0"
-       : "=&r" (ctr)
-       : "0" (ctr), "i" (UWINMASK_OFFSET)
-       : "g4");
-
-       /* Gcc can bite me... */
-#if !defined(__svr4__) && !defined(__ELF__)
-       __asm__ __volatile__("
-       sethi   %hi(_vac_line_size), %g1
-       ld      [%g1 + %lo(_vac_line_size)], %o1
-       sethi   %hi(_vac_cache_size), %g2
-       ld      [%g2 + %lo(_vac_cache_size)], %o0");
-#else
-       __asm__ __volatile__("
-       sethi   %hi(vac_line_size), %g1
-       ld      [%g1 + %lo(vac_line_size)], %o1
-       sethi   %hi(vac_cache_size), %g2
-       ld      [%g2 + %lo(vac_cache_size)], %o0");
-#endif
-
-       __asm__ __volatile__("
-               add     %%o1, %%o1, %%g1
-               add     %%o1, %%g1, %%g2
-               add     %%o1, %%g2, %%g3
-               add     %%o1, %%g3, %%g4
-               add     %%o1, %%g4, %%g5
-               add     %%o1, %%g5, %%o4
-               add     %%o1, %%o4, %%o5
-       1:      subcc   %%o0, %%o5, %%o0                ! hyper_flush_cache_user
-               sta     %%g0, [%%o0 + %%g0] %0
-               sta     %%g0, [%%o0 + %%o1] %0
-               sta     %%g0, [%%o0 + %%g1] %0
-               sta     %%g0, [%%o0 + %%g2] %0
-               sta     %%g0, [%%o0 + %%g3] %0
-               sta     %%g0, [%%o0 + %%g4] %0
-               sta     %%g0, [%%o0 + %%g5] %0
-               bne     1b
-                sta    %%g0, [%%o0 + %%o4] %0
-               sta     %%g0, [%%g0 + %%g0] %1          ! hyper_flush_whole_icache"
-       : : "i" (ASI_M_FLUSH_USER), "i" (ASI_M_FLUSH_IWHOLE));
-       FLUSH_END
-}
-
-/* The things we do for performance... */
-static void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-       FLUSH_BEGIN(mm)
-       __asm__ __volatile__("
-       mov     0, %%g5
-1:     ld      [%%g6 + %0], %%g4
-       orcc    %%g0, %%g4, %%g0
-       add     %%g5, 1, %%g5
-       bne     1b
-        save   %%sp, -64, %%sp
-2:     subcc   %%g5, 1, %%g5
-       bne     2b
-        restore %%g0, %%g0, %%g0
-       " : : "i" (UWINMASK_OFFSET));
-#if !defined(__svr4__) && !defined(__ELF__)
-       __asm__ __volatile__("
-       sethi   %hi(_vac_line_size), %g1
-       ld      [%g1 + %lo(_vac_line_size)], %o4
-       sethi   %hi(_vac_cache_size), %g2
-       ld      [%g2 + %lo(_vac_cache_size)], %o3");
-#else
-       __asm__ __volatile__("
-       sethi   %hi(vac_line_size), %g1
-       ld      [%g1 + %lo(vac_line_size)], %o4
-       sethi   %hi(vac_cache_size), %g2
-       ld      [%g2 + %lo(vac_cache_size)], %o3");
-#endif
-       /* Close your eyes... */
-       __asm__ __volatile__("
-       add     %%o2, (%0 - 1), %%o2
-       andn    %%o1, (%0 - 1), %%o1
-       add     %%o4, %%o4, %%o5
-       andn    %%o2, (%0 - 1), %%o2
-       add     %%o4, %%o5, %%g1
-       sub     %%o2, %%o1, %%g4
-       add     %%o4, %%g1, %%g2
-       sll     %%o3, 2, %%g5
-       add     %%o4, %%g2, %%g3
-       cmp     %%g4, %%g5
-       add     %%o4, %%g3, %%g4
-       blu     0f
-        add    %%o4, %%g4, %%g5
-       add     %%o4, %%g5, %%g7
-1:     subcc   %%o3, %%g7, %%o3
-       sta     %%g0, [%%o3 + %%g0] %1
-       sta     %%g0, [%%o3 + %%o4] %1
-       sta     %%g0, [%%o3 + %%o5] %1
-       sta     %%g0, [%%o3 + %%g1] %1
-       sta     %%g0, [%%o3 + %%g2] %1
-       sta     %%g0, [%%o3 + %%g3] %1
-       sta     %%g0, [%%o3 + %%g4] %1
-       bne     1b
-        sta    %%g0, [%%o3 + %%g5] %1
-       b,a     9f
-0:     ld      [%%o0 + %3], %%o0
-       mov     %2, %%g7
-       lda     [%%g7] %4, %%o3
-       sta     %%o0, [%%g7] %4
-       sethi   %%hi(%0), %%g7
-       sub     %%o2, %%g7, %%o0
-1:     or      %%o0, 0x400, %%g7
-       lda     [%%g7] %5, %%g7
-       orcc    %%g7, 0x0, %%g0
-       be,a    3f
-        mov    %%o0, %%o2
-       add     %%o4, %%g5, %%g7
-2:     sub     %%o2, %%g7, %%o2
-       sta     %%g0, [%%o2 + %%g0] %6
-       sta     %%g0, [%%o2 + %%o4] %6
-       sta     %%g0, [%%o2 + %%o5] %6
-       sta     %%g0, [%%o2 + %%g1] %6
-       sta     %%g0, [%%o2 + %%g2] %6
-       sta     %%g0, [%%o2 + %%g3] %6
-       andcc   %%o2, 0xffc, %%g0
-       sta     %%g0, [%%o2 + %%g4] %6
-       bne     2b
-        sta    %%g0, [%%o2 + %%g5] %6
-3:     sethi   %%hi(%0), %%g7
-       cmp     %%o2, %%o1
-       bne     1b
-        sub    %%o2, %%g7, %%o0
-       mov     %8, %%g5
-       lda     [%%g5] %4, %%g0
-       mov     %2, %%g7
-       sta     %%o3, [%%g7] %4
-9:     sta     %%g0, [%%g0 + %%g0] %7
-"      : : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_USER), "i" (SRMMU_CTX_REG),
-           "i" ((const unsigned long)(&(((struct mm_struct *)0)->context))),
-           "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE), "i" (ASI_M_FLUSH_PAGE),
-           "i" (ASI_M_FLUSH_IWHOLE), "i" (SRMMU_FAULT_STATUS));
-       FLUSH_END
-}
-
-/* HyperSparc requires a valid mapping where we are about to flush
- * in order to check for a physical tag match during the flush.
- */
-static void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
-       __asm__ __volatile__("
-       ld      [%%o0 + %0], %%g4
-       ld      [%%g4 + %1], %%o0
-"      : : "i" ((const unsigned long)(&(((struct vm_area_struct *)0)->vm_mm))),
-           "i" ((const unsigned long)(&(((struct mm_struct *)0)->context))));
-#ifndef __SMP__
-       __asm__ __volatile__("
-       cmp     %o0, -1
-       bne     1f
-        mov    0, %g5
-       retl");
-#else
-       __asm__ __volatile__("mov       0, %g5");       /* else we die a horrible death */
-#endif
-       __asm__ __volatile__("
-1:      ld     [%%g6 + %0], %%g4       ! flush user windows
-       orcc    %%g0, %%g4, %%g0
-       add     %%g5, 1, %%g5
-       bne     1b
-        save   %%sp, -64, %%sp
-2:     subcc   %%g5, 1, %%g5
-       bne     2b
-        restore %%g0, %%g0, %%g0"
-       : : "i" (UWINMASK_OFFSET));
-#if !defined(__svr4__) && !defined(__ELF__)
-       __asm__ __volatile__("
-       sethi   %hi(_vac_line_size), %g1
-       ld      [%g1 + %lo(_vac_line_size)], %o4");
-#else
-       __asm__ __volatile__("
-       sethi   %hi(vac_line_size), %g1
-       ld      [%g1 + %lo(vac_line_size)], %o4");
-#endif
-       __asm__ __volatile__("
-       mov     %0, %%o3
-       andn    %%o1, (%4 - 1), %%o1
-       lda     [%%o3] %1, %%o2
-       sta     %%o0, [%%o3] %1
-       or      %%o1, 0x400, %%o5
-       lda     [%%o5] %3, %%o5
-       orcc    %%o5, 0x0, %%g0
-       be      2f
-        sethi  %%hi(%4), %%g7
-       add     %%o4, %%o4, %%o5
-       add     %%o1, %%g7, %%o1
-       add     %%o4, %%o5, %%g1
-       add     %%o4, %%g1, %%g2
-       add     %%o4, %%g2, %%g3
-       add     %%o4, %%g3, %%g4
-       add     %%o4, %%g4, %%g5
-       add     %%o4, %%g5, %%g7
-1:     sub     %%o1, %%g7, %%o1                ! hyper_flush_cache_page
-       sta     %%g0, [%%o1 + %%g0] %5
-       sta     %%g0, [%%o1 + %%o4] %5
-       sta     %%g0, [%%o1 + %%o5] %5
-       sta     %%g0, [%%o1 + %%g1] %5
-       sta     %%g0, [%%o1 + %%g2] %5
-       sta     %%g0, [%%o1 + %%g3] %5
-       andcc   %%o1, 0xffc, %%g0
-       sta     %%g0, [%%o1 + %%g4] %5
-       bne     1b
-        sta    %%g0, [%%o1 + %%g5] %5
-       sta     %%g0, [%%g0 + %%g0] %6
-2:     mov     %0, %%g4
-       sta     %%o2, [%%g4] %1
-       mov     %2, %%g7
-       retl
-        lda    [%%g7] %1, %%g0
-"      : : "i" (SRMMU_CTX_REG), "i" (ASI_M_MMUREGS), "i" (SRMMU_FAULT_STATUS),
-           "i" (ASI_M_FLUSH_PROBE), "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE),
-           "i" (ASI_M_FLUSH_IWHOLE));
-}
-
-/* HyperSparc is copy-back. */
-static void hypersparc_flush_page_to_ram(unsigned long page)
-{
-#if !defined(__svr4__) && !defined(__ELF__)
-       __asm__ __volatile__("
-       sethi   %hi(_vac_line_size), %g1
-       ld      [%g1 + %lo(_vac_line_size)], %o4");
-#else
-       __asm__ __volatile__("
-       sethi   %hi(vac_line_size), %g1
-       ld      [%g1 + %lo(vac_line_size)], %o4");
-#endif
-       __asm__ __volatile__("
-       andn    %%o0, (%0 - 1), %%o0
-       add     %%o4, %%o4, %%o5
-       or      %%o0, 0x400, %%g7
-       lda     [%%g7] %2, %%g5
-       add     %%o4, %%o5, %%g1
-       orcc    %%g5, 0x0, %%g0
-       be      2f
-        add    %%o4, %%g1, %%g2
-       sethi   %%hi(%0), %%g5
-       add     %%o4, %%g2, %%g3
-       add     %%o0, %%g5, %%o0
-       add     %%o4, %%g3, %%g4
-       add     %%o4, %%g4, %%g5
-       add     %%o4, %%g5, %%g7
-1:     sub     %%o0, %%g7, %%o0
-       sta     %%g0, [%%o0 + %%g0] %1
-       sta     %%g0, [%%o0 + %%o4] %1
-       sta     %%g0, [%%o0 + %%o5] %1
-       sta     %%g0, [%%o0 + %%g1] %1
-       sta     %%g0, [%%o0 + %%g2] %1
-       sta     %%g0, [%%o0 + %%g3] %1
-       andcc   %%o0, 0xffc, %%g0
-       sta     %%g0, [%%o0 + %%g4] %1
-       bne     1b
-        sta    %%g0, [%%o0 + %%g5] %1
-2:     mov     %3, %%g1
-       lda     [%%g1] %4, %%g0"
-       : /* no outputs */
-       : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE), "i" (ASI_M_FLUSH_PROBE),
-         "i" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS));
-}
-
-static void hypersparc_flush_chunk(unsigned long chunk)
-{
-       hypersparc_flush_page_to_ram(chunk);
-}
-
-/* HyperSparc is IO cache coherent. */
-static void hypersparc_flush_page_for_dma(unsigned long page)
-{
-}
-
-/* HyperSparc has unified I/D L2 cache, however it posseses a small on-chip
- * ICACHE which must be flushed for the new style signals.
- */
-static void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
-{
-       hyper_flush_whole_icache();
-}
-
-static void hypersparc_flush_cache_page_to_uncache(unsigned long page)
-{
-       page &= PAGE_MASK;
-       __asm__ __volatile__("
-       lda     [%0] %2, %%g4
-       orcc    %%g4, 0x0, %%g0
-       be      2f
-        sethi  %%hi(%7), %%g5
-1:     subcc   %%g5, %6, %%g5          ! hyper_flush_cache_page
-       bne     1b
-        sta    %%g0, [%1 + %%g5] %3
-2:     lda     [%4] %5, %%g0"
-       : /* no outputs */
-       : "r" (page | 0x400), "r" (page), "i" (ASI_M_FLUSH_PROBE),
-         "i" (ASI_M_FLUSH_PAGE), "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS),
-         "r" (vac_line_size), "i" (PAGE_SIZE)
-       : "g4", "g5");
-}
-
-static unsigned long hypersparc_getpage(void)
-{
-       register unsigned long page asm("i0");
-
-       page = get_free_page(GFP_KERNEL);
-#if !defined(__svr4__) && !defined(__ELF__)
-       __asm__ __volatile__("
-       sethi   %hi(_vac_line_size), %g1
-       ld      [%g1 + %lo(_vac_line_size)], %o4");
-#else
-       __asm__ __volatile__("
-       sethi   %hi(vac_line_size), %g1
-       ld      [%g1 + %lo(vac_line_size)], %o4");
-#endif
-       __asm__ __volatile__("
-       sethi   %%hi(%0), %%g5
-       add     %%o4, %%o4, %%o5
-       add     %%o4, %%o5, %%g1
-       add     %%o4, %%g1, %%g2
-       add     %%o4, %%g2, %%g3
-       add     %%i0, %%g5, %%o0
-       add     %%o4, %%g3, %%g4
-       add     %%o4, %%g4, %%g5
-       add     %%o4, %%g5, %%g7
-1:     sub     %%o0, %%g7, %%o0
-       sta     %%g0, [%%o0 + %%g0] %1
-       sta     %%g0, [%%o0 + %%o4] %1
-       sta     %%g0, [%%o0 + %%o5] %1
-       sta     %%g0, [%%o0 + %%g1] %1
-       sta     %%g0, [%%o0 + %%g2] %1
-       sta     %%g0, [%%o0 + %%g3] %1
-       andcc   %%o0, 0xffc, %%g0
-       sta     %%g0, [%%o0 + %%g4] %1
-       bne     1b
-        sta    %%g0, [%%o0 + %%g5] %1"
-       : /* no outputs */
-       : "i" (PAGE_SIZE), "i" (ASI_M_FLUSH_PAGE));
-       return page;
-}
-
-static void hypersparc_flush_tlb_all(void)
-{
-       srmmu_flush_whole_tlb();
-       module_stats.invall++;
-}
-
-static void hypersparc_flush_tlb_mm(struct mm_struct *mm)
-{
-       FLUSH_BEGIN(mm)
-       __asm__ __volatile__("
-       lda     [%0] %3, %%g5
-       sta     %2, [%0] %3
-       sta     %%g0, [%1] %4
-       sta     %%g5, [%0] %3"
-       : /* no outputs */
-       : "r" (SRMMU_CTX_REG), "r" (0x300), "r" (mm->context),
-         "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE)
-       : "g5");
-       module_stats.invmm++;
-       FLUSH_END
-}
-
-static void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-       unsigned long size;
-
-       FLUSH_BEGIN(mm)
-       start &= SRMMU_PGDIR_MASK;
-       size = SRMMU_PGDIR_ALIGN(end) - start;
-       __asm__ __volatile__("
-               lda     [%0] %5, %%g5
-               sta     %1, [%0] %5
-       1:      subcc   %3, %4, %3
-               bne     1b
-                sta    %%g0, [%2 + %3] %6
-               sta     %%g5, [%0] %5"
-       : /* no outputs */
-       : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200),
-         "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS),
-         "i" (ASI_M_FLUSH_PROBE)
-       : "g5");
-       module_stats.invrnge++;
-       FLUSH_END
-}
-
-static void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-       struct mm_struct *mm = vma->vm_mm;
-
-       FLUSH_BEGIN(mm)
-       __asm__ __volatile__("
-       lda     [%0] %3, %%g5
-       sta     %1, [%0] %3
-       sta     %%g0, [%2] %4
-       sta     %%g5, [%0] %3"
-       : /* no outputs */
-       : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK),
-         "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE)
-       : "g5");
-       module_stats.invpg++;
-       FLUSH_END
-}
-
-static void hypersparc_flush_tlb_page_for_cbit(unsigned long page)
-{
-       srmmu_flush_tlb_page(page);
-}
+/* hypersparc.S */
+extern void hypersparc_flush_cache_all(void);
+extern void hypersparc_flush_cache_mm(struct mm_struct *mm);
+extern void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page);
+extern void hypersparc_flush_page_to_ram(unsigned long page);
+extern void hypersparc_flush_chunk(unsigned long chunk);
+extern void hypersparc_flush_page_for_dma(unsigned long page);
+extern void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
+extern void hypersparc_flush_tlb_all(void);
+extern void hypersparc_flush_tlb_mm(struct mm_struct *mm);
+extern void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end);
+extern void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
 static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
 {
@@ -3234,7 +2681,6 @@ __initfunc(static void init_hypersparc(void))
        init_vac_layout();
 
        set_pte = srmmu_set_pte_nocache_hyper;
-       mmu_getpage = hypersparc_getpage;
        flush_cache_all = hypersparc_flush_cache_all;
        flush_cache_mm = hypersparc_flush_cache_mm;
        flush_cache_range = hypersparc_flush_cache_range;
@@ -3248,8 +2694,6 @@ __initfunc(static void init_hypersparc(void))
        flush_page_to_ram = hypersparc_flush_page_to_ram;
        flush_sig_insns = hypersparc_flush_sig_insns;
        flush_page_for_dma = hypersparc_flush_page_for_dma;
-       flush_cache_page_to_uncache = hypersparc_flush_cache_page_to_uncache;
-       flush_tlb_page_for_cbit = hypersparc_flush_tlb_page_for_cbit;
 
        flush_chunk = hypersparc_flush_chunk; /* local flush _only_ */
 
@@ -3306,7 +2750,6 @@ __initfunc(static void init_cypress_common(void))
        init_vac_layout();
 
        set_pte = srmmu_set_pte_nocache_cypress;
-       mmu_getpage = cypress_getpage;
        flush_cache_all = cypress_flush_cache_all;
        flush_cache_mm = cypress_flush_cache_mm;
        flush_cache_range = cypress_flush_cache_range;
@@ -3322,8 +2765,6 @@ __initfunc(static void init_cypress_common(void))
        flush_page_to_ram = cypress_flush_page_to_ram;
        flush_sig_insns = cypress_flush_sig_insns;
        flush_page_for_dma = cypress_flush_page_for_dma;
-       flush_cache_page_to_uncache = cypress_flush_page_to_uncache;
-       flush_tlb_page_for_cbit = cypress_flush_tlb_page_for_cbit;
        sparc_update_rootmmu_dir = cypress_update_rootmmu_dir;
 
        update_mmu_cache = srmmu_vac_update_mmu_cache;
@@ -3437,8 +2878,6 @@ __initfunc(static void init_swift(void))
        flush_page_to_ram = swift_flush_page_to_ram;
        flush_sig_insns = swift_flush_sig_insns;
        flush_page_for_dma = swift_flush_page_for_dma;
-       flush_cache_page_to_uncache = swift_flush_cache_page_to_uncache;
-       flush_tlb_page_for_cbit = swift_flush_tlb_page_for_cbit;
 
        /* Are you now convinced that the Swift is one of the
         * biggest VLSI abortions of all time?  Bravo Fujitsu!
@@ -3485,8 +2924,6 @@ __initfunc(static void init_tsunami(void))
        flush_page_to_ram = tsunami_flush_page_to_ram;
        flush_sig_insns = tsunami_flush_sig_insns;
        flush_page_for_dma = tsunami_flush_page_for_dma;
-       flush_cache_page_to_uncache = tsunami_flush_cache_page_to_uncache;
-       flush_tlb_page_for_cbit = tsunami_flush_tlb_page_for_cbit;
 
        poke_srmmu = poke_tsunami;
 }
@@ -3539,9 +2976,6 @@ static void poke_viking(void)
        flush_page_to_ram = local_flush_page_to_ram;
        flush_sig_insns = local_flush_sig_insns;
        flush_page_for_dma = local_flush_page_for_dma;
-       if (viking_mxcc_present) {
-               flush_cache_page_to_uncache = local_flush_cache_page_to_uncache;
-       }
 #endif
 }
 
@@ -3562,12 +2996,9 @@ __initfunc(static void init_viking(void))
 
                msi_set_sync();
 
-               mmu_getpage = viking_no_mxcc_getpage;
                set_pte = srmmu_set_pte_nocache_nomxccvik;
                sparc_update_rootmmu_dir = viking_no_mxcc_update_rootmmu_dir;
 
-               flush_cache_page_to_uncache = viking_no_mxcc_flush_page;
-
                flush_chunk = viking_nomxcc_flush_chunk; /* local flush _only_ */
 
                /* We need this to make sure old viking takes no hits
@@ -3580,7 +3011,6 @@ __initfunc(static void init_viking(void))
        } else {
                srmmu_name = "TI Viking/MXCC";
                viking_mxcc_present = 1;
-               flush_cache_page_to_uncache = viking_mxcc_flush_page;
 
                flush_chunk = viking_mxcc_flush_chunk; /* local flush _only_ */
 
@@ -3600,7 +3030,6 @@ __initfunc(static void init_viking(void))
 
        flush_page_to_ram = viking_flush_page_to_ram;
        flush_sig_insns = viking_flush_sig_insns;
-       flush_tlb_page_for_cbit = viking_flush_tlb_page_for_cbit;
 
        poke_srmmu = poke_viking;
 }
@@ -3708,15 +3137,6 @@ static void smp_flush_page_for_dma(unsigned long page)
        xc1((smpfunc_t) local_flush_page_for_dma, page);
 }
 
-static void smp_flush_cache_page_to_uncache(unsigned long page)
-{
-       xc1((smpfunc_t) local_flush_cache_page_to_uncache, page);
-}
-
-static void smp_flush_tlb_page_for_cbit(unsigned long page)
-{
-       xc1((smpfunc_t) local_flush_tlb_page_for_cbit, page);
-}
 #endif
 
 /* Load up routines and constants for sun4m mmu */
@@ -3742,7 +3162,6 @@ __initfunc(void ld_mmu_srmmu(void))
        pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
            
        /* Functions */
-       mmu_getpage = srmmu_getpage;
        set_pte = srmmu_set_pte_cacheable;
        init_new_context = srmmu_init_new_context;
        switch_to_context = srmmu_switch_to_context;
@@ -3845,8 +3264,6 @@ __initfunc(void ld_mmu_srmmu(void))
        local_flush_page_to_ram = flush_page_to_ram;
        local_flush_sig_insns = flush_sig_insns;
        local_flush_page_for_dma = flush_page_for_dma;
-       local_flush_cache_page_to_uncache = flush_cache_page_to_uncache;
-       local_flush_tlb_page_for_cbit = flush_tlb_page_for_cbit;
 
        flush_cache_all = smp_flush_cache_all;
        flush_cache_mm = smp_flush_cache_mm;
@@ -3859,7 +3276,5 @@ __initfunc(void ld_mmu_srmmu(void))
        flush_page_to_ram = smp_flush_page_to_ram;
        flush_sig_insns = smp_flush_sig_insns;
        flush_page_for_dma = smp_flush_page_for_dma;
-       flush_cache_page_to_uncache = smp_flush_cache_page_to_uncache;
-       flush_tlb_page_for_cbit = smp_flush_tlb_page_for_cbit;
 #endif
 }
index c401e4cb4ccb018d1b53e2bab3fa408f7bfdfaaa..9551094d0948e13fb922f6be2d1b5628582b32a6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.10 1996/12/18 06:46:54 tridge Exp $
+/* $Id: console.c,v 1.11 1997/03/18 17:58:10 jj Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -31,7 +31,6 @@ prom_nbgetchar(void)
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1) {
                        i = inc;
                } else {
@@ -66,7 +65,6 @@ prom_nbputchar(char c)
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                outc = c;
                if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1)
                        i = 0;
@@ -129,7 +127,6 @@ prom_query_input_device()
                        return PROMDEV_I_UNK;
                };
        case PROM_V3:
-       case PROM_P1275:
                save_flags(flags); cli();
                st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
                __asm__ __volatile__("ld [%0], %%g6\n\t" : :
@@ -177,7 +174,6 @@ prom_query_output_device()
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                save_flags(flags); cli();
                st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
                __asm__ __volatile__("ld [%0], %%g6\n\t" : :
index 69803c31be5db46a2998781d43249670a22f633f..2b33dd2b74b036646209a564f656181667430123 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: devops.c,v 1.6 1996/10/12 12:37:38 davem Exp $
+/* $Id: devops.c,v 1.7 1997/03/18 17:58:19 jj Exp $
  * devops.c:  Device operations using the PROM.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -27,7 +27,6 @@ prom_devopen(char *dstr)
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
                break;
         case PROM_AP1000:
@@ -55,7 +54,6 @@ prom_devclose(int dhandle)
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                (*(romvec->pv_v2devops.v2_dev_close))(dhandle);
                break;
         case PROM_AP1000:
@@ -82,7 +80,6 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
                break;
         case PROM_AP1000:
index 1b730d2347d606d45f6e0a5a860c632d8c0f02db..6f691464aae1610bde99345c1322fb01af313031 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.9 1996/12/18 06:46:55 tridge Exp $
+/* $Id: init.c,v 1.11 1997/03/18 17:58:24 jj Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -19,6 +19,8 @@ unsigned int prom_rev, prom_prev;
 /* The root node of the prom device tree. */
 int prom_root_node;
 
+int prom_stdin, prom_stdout;
+
 /* Pointer to the device tree operations structure. */
 struct linux_nodeops *prom_nodeops;
 
@@ -49,11 +51,6 @@ __initfunc(void prom_init(struct linux_romvec *rp))
        case 3:
                prom_vers = PROM_V3;
                break;
-       case 4:
-               prom_vers = PROM_P1275;
-               prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
-               prom_halt();
-               break;
        case 42: /* why not :-) */
                prom_vers = PROM_AP1000;
                break;
@@ -77,6 +74,11 @@ __initfunc(void prom_init(struct linux_romvec *rp))
           (((unsigned long) prom_nodeops) == -1))
                prom_halt();
 
+       if(prom_vers == PROM_V2 || prom_vers == PROM_V3) {
+               prom_stdout = *romvec->pv_v2bootargs.fd_stdout;
+               prom_stdin  = *romvec->pv_v2bootargs.fd_stdin;
+       }
+       
        prom_meminit();
 
        prom_ranges_init();
index b6356185aa8744d1f1de446f191a2d56ce5f4380..e2a809017f529ba91ee97b75209c1cfe499b56a1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.9 1996/11/13 05:10:09 davem Exp $
+/* $Id: memory.c,v 1.10 1997/03/18 17:58:27 jj Exp $
  * memory.c: Prom routine for acquiring various bits of information
  *           about RAM on the machine, both virtual and physical.
  *
@@ -107,7 +107,6 @@ __initfunc(void prom_meminit(void))
                break;
        case PROM_V2:
        case PROM_V3:
-       case PROM_P1275:
                /* Grrr, have to traverse the prom device tree ;( */
                node = prom_getchild(prom_root_node);
                node = prom_searchsiblings(node, "memory");
index f046db55acf0bd70359c6f9563a1e6530a6a3e2d..cf71cca605b7c855f5fd7ec883f3907e220e8a71 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mp.c,v 1.6 1996/09/19 20:27:25 davem Exp $
+/* $Id: mp.c,v 1.7 1997/03/18 17:58:23 jj Exp $
  * mp.c:  OpenBoot Prom Multiprocessor support routines.  Don't call
  *        these on a UP or else you will halt and catch fire. ;)
  *
@@ -32,7 +32,6 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha
                ret = -1;
                break;
        case PROM_V3:
-       case PROM_P1275:
                ret = (*(romvec->v3_cpustart))(cpunode, (int) ctable_reg, ctx, pc);
                break;
        };
@@ -62,7 +61,6 @@ prom_stopcpu(int cpunode)
                ret = -1;
                break;
        case PROM_V3:
-       case PROM_P1275:
                ret = (*(romvec->v3_cpustop))(cpunode);
                break;
        };
@@ -92,7 +90,6 @@ prom_idlecpu(int cpunode)
                ret = -1;
                break;
        case PROM_V3:
-       case PROM_P1275:
                ret = (*(romvec->v3_cpuidle))(cpunode);
                break;
        };
@@ -122,7 +119,6 @@ prom_restartcpu(int cpunode)
                ret = -1;
                break;
        case PROM_V3:
-       case PROM_P1275:
                ret = (*(romvec->v3_cpuresume))(cpunode);
                break;
        };
index 87b7c44d7a05915585c779c45b4ea60c3999786c..e5e2ceb3de6b0e35c639cae3e08df9ecc85ab97f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.15 1997/01/31 00:17:04 tdyas Exp $
+/* $Id: tree.c,v 1.16 1997/03/19 14:53:16 davem Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -259,6 +259,33 @@ char * prom_nextprop(int node, char *oprop)
        return ret;
 }
 
+int prom_finddevice(char *name)
+{
+       int topnd = prom_getchild(prom_root_node);
+       int srch;
+
+       if(name[0] == '/')
+               name++;
+       if(sparc_cpu_model == sun4d) {
+               if(!strcmp(name, "sbus"))
+                       name = "sbi";
+               if((srch = prom_searchsiblings(topnd, "io-unit")) == 0 ||
+                  (srch = prom_getchild(srch)) == 0 ||
+                  (srch = prom_searchsiblings(srch, name)) == 0) {
+                       prom_printf("%s prom node not found.\n", name);
+                       prom_halt();
+               }
+       } else if((srch = prom_searchsiblings(topnd, name)) == 0) {
+               if((srch = prom_searchsiblings(topnd, "iommu")) == 0 ||
+                  (srch = prom_getchild(srch)) == 0 ||
+                  (srch = prom_searchsiblings(srch, name)) == 0) {
+                       prom_printf("Cannot find node %s\n", name);
+                       prom_halt();
+               }
+       }
+       return srch;
+}
+
 int prom_node_has_property(int node, char *prop)
 {
        char *current_property = "";
index 92b29b325baa2420d8bf3b6f0c8bc68cd4a6b192..17f3c3ebb4c6445edf4f272df85d3177bc20c9c7 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.6 1997/03/04 16:27:18 jj Exp $
+# $Id: Makefile,v 1.9 1997/03/14 21:04:39 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -41,15 +41,5 @@ archclean:
 
 archdep:
 
-# <hack> Temporary hack, until we get a clean compile of everything...
-vmlinux64: $(CONFIGURATION) init/main.o init/version.o
-       set -e; for i in arch/sparc64/kernel arch/sparc64/lib arch/sparc64/prom lib; do $(MAKE) -C $$i; done
-       $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
-               arch/sparc64/kernel/kernel.o \
-               lib/lib.a arch/sparc64/prom/promlib.a arch/sparc64/lib/lib.a \
-               -o vmlinux
-       $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)\|\(\.\.ng$$\)' | sort > System.map
-# </hack>
-
 check_asm:
        $(MAKE) -C arch/sparc64/kernel check_asm
index 6998745c1599788fd2d6ae10384001dacb583486..8a61ea8cad1e7cd1708afcf1b6efc433accade26 100644 (file)
@@ -10,7 +10,9 @@ CONFIG_EXPERIMENTAL=y
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
 
 #
 # General setup
@@ -38,22 +40,26 @@ SUN_FB_CGFOURTEEN=y
 SUN_FB_BWTWO=y
 SUN_FB_LEO=y
 TADPOLE_FB_WEITEK=y
-SUN_FB_FAST_ONE=y
-SUN_FB_FAST_TWO=y
-SUN_FB_FAST_MONO=y
-SUN_FB_GENERIC=y
 
 #
 # Misc Linux/SPARC drivers
 #
-CONFIG_SUN_OPENPROMIO=y
+CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
-CONFIG_SUN_OPENPROMFS=y
+# CONFIG_SUN_BPP is not set
+
+#
+# Linux/SPARC audio subsystem (EXPERIMENTAL)
+#
+# CONFIG_SPARCAUDIO is not set
+# CONFIG_SPARCAUDIO_AMD7930 is not set
+# CONFIG_SPARCAUDIO_CS4231 is not set
+CONFIG_SUN_OPENPROMFS=m
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_JAVA=y
+CONFIG_BINFMT_JAVA=m
 
 #
 # Floppy, IDE, and other block devices
@@ -64,7 +70,7 @@ CONFIG_MD_LINEAR=y
 CONFIG_MD_STRIPED=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP=m
 
 #
 # Networking options
@@ -74,7 +80,6 @@ CONFIG_RTNETLINK=y
 CONFIG_FIREWALL=y
 CONFIG_NET_ALIAS=y
 CONFIG_INET=y
-CONFIG_IP_FORWARD=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_FIREWALL=y
 # CONFIG_IP_FIREWALL_NETLINK is not set
@@ -88,32 +93,35 @@ CONFIG_IP_MASQUERADE=y
 # CONFIG_IP_ALWAYS_DEFRAG is not set
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
-CONFIG_NET_IPIP=y
+# CONFIG_NET_IPIP is not set
 # CONFIG_IP_MROUTE is not set
-CONFIG_IP_ALIAS=y
+CONFIG_IP_ALIAS=m
 # CONFIG_ARPD is not set
 
 #
 # (it is safe to leave these untouched)
 #
 # CONFIG_INET_PCTCP is not set
-CONFIG_INET_RARP=y
+CONFIG_INET_RARP=m
 # CONFIG_PATH_MTU_DISCOVERY is not set
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
-CONFIG_IPV6=y
+CONFIG_IPV6=m
 
 #
 #  
 #
-CONFIG_IPX=y
+CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_IPX_PPROP_ROUTING is not set
-CONFIG_ATALK=y
+CONFIG_ATALK=m
+# CONFIG_IPDDP is not set
 # CONFIG_AX25 is not set
-CONFIG_X25=y
+CONFIG_X25=m
+# CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
 
 #
 # SCSI support
@@ -139,51 +147,50 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI low-level drivers
 #
 CONFIG_SCSI_SUNESP=y
-CONFIG_SCSI_QLOGICPTI=y
+CONFIG_SCSI_QLOGICPTI=m
 
 #
 # Network device support
 #
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_PPP=y
+CONFIG_DUMMY=m
+CONFIG_PPP=m
 
 #
 # CCP compressors for PPP are only built as modules.
 #
-CONFIG_SLIP=y
+CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
 # CONFIG_SLIP_MODE_SLIP6 is not set
 CONFIG_SUNLANCE=y
-CONFIG_HAPPYMEAL=y
-CONFIG_SUNQE=y
-CONFIG_MYRI_SBUS=y
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNQE=m
+CONFIG_MYRI_SBUS=m
 
 #
 # Filesystems
 #
 CONFIG_QUOTA=y
-CONFIG_MINIX_FS=y
-CONFIG_EXT_FS=y
+CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
-CONFIG_XIA_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_UMSDOS_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_UMSDOS_FS=m
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
 CONFIG_ROOT_NFS=y
 CONFIG_RNFS_BOOTP=y
 CONFIG_RNFS_RARP=y
-CONFIG_SMB_FS=y
+CONFIG_SMB_FS=m
 CONFIG_SMB_WIN95=y
-CONFIG_NCP_FS=y
+CONFIG_NCP_FS=m
 CONFIG_ISO9660_FS=y
-CONFIG_HPFS_FS=y
-CONFIG_SYSV_FS=y
-CONFIG_AFFS_FS=y
+CONFIG_HPFS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ROMFS_FS=m
 CONFIG_AMIGA_PARTITION=y
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
index fb4a242f25349fd240a5b1f323b33d2d87d8c6f2..74802bf19a8961d7304a67a34af4b90939b16298 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 1997/03/04 16:26:54 jj Exp $
+# $Id: Makefile,v 1.7 1997/03/18 17:59:15 jj Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -16,7 +16,7 @@
 all: kernel.o head.o
 
 O_TARGET := kernel.o
-O_OBJS   := etrap.o rtrap.o hack.o process.o # signal32.o
+O_OBJS   := etrap.o rtrap.o hack.o process.o setup.o cpu.o idprom.o systbls.o traps.o entry.o devices.o auxio.o ioport.o # signal32.o
 OX_OBJS  := sparc64_ksyms.o
 
 head.o: head.S
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
new file mode 100644 (file)
index 0000000..6c3ff91
--- /dev/null
@@ -0,0 +1,42 @@
+/* auxio.c: Probing for the Sparc AUXIO register at boot time.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/auxio.h>
+#include <asm/sbus.h>
+
+/* Probe and map in the Auxiliary I/O register */
+unsigned char *auxio_register;
+
+__initfunc(void auxio_probe(void))
+{
+        struct linux_sbus *bus;
+        struct linux_sbus_device *sdev = 0;
+       struct linux_prom_registers auxregs[1];
+
+        for_each_sbus(bus) {
+                for_each_sbusdev(sdev, bus) {
+                        if(!strcmp(sdev->prom_name, "auxio")) {
+                               break;
+                        }
+                }
+        }
+
+       if (!sdev) {
+               prom_printf("Cannot find auxio node, cannot continue...\n");
+               prom_halt();
+       }
+       prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
+       prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
+       /* Map the register both read and write */
+       auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0,
+                                                         auxregs[0].reg_size,
+                                                         "auxiliaryIO",
+                                                         auxregs[0].which_io, 0x0);
+       TURN_ON_LED;
+}
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
new file mode 100644 (file)
index 0000000..b569e2b
--- /dev/null
@@ -0,0 +1,86 @@
+/* cpu.c: Dinky routines to look for the kind of Sparc cpu
+ *        we are on.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/system.h>
+
+struct cpu_iu_info {
+  short manuf;
+  short impl;
+  char* cpu_name;   /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+  short manuf;
+  short impl;
+  char fpu_vers;
+  char* fp_name;
+};
+
+/* In order to get the fpu type correct, you need to take the IDPROM's
+ * machine type value into consideration too.  I will fix this.
+ */
+struct cpu_fp_info linux_sparc_fpu[] = {
+  { 0x17, 0x10, 0, "FIXME: UltraSparc I FPU"},
+};
+
+#define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
+
+struct cpu_iu_info linux_sparc_chips[] = {
+  { 0x17, 0x10, "FIXME: UltraSparc I"},
+};
+
+#define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
+
+char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+
+unsigned int fsr_storage;
+
+__initfunc(void cpu_probe(void))
+{
+       int manuf, impl;
+       unsigned i, cpuid;
+       long ver, fpu_vers;
+
+       cpuid = get_cpuid();
+       
+       __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]" : "=r" (ver) : "r" (&fpu_vers));
+
+       manuf = ((ver >> 48)&0xffff);
+       impl = ((ver >> 32)&0xffff);
+
+       fpu_vers = ((fpu_vers>>17)&0x7);
+
+       for(i = 0; i<NSPARCCHIPS; i++) {
+               if(linux_sparc_chips[i].manuf == manuf)
+                       if(linux_sparc_chips[i].impl == impl) {
+                               sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
+                               break;
+                       }
+       }
+
+       if(i==NSPARCCHIPS) {
+               printk("DEBUG: manuf = 0x%x   impl = 0x%x\n", manuf, 
+                           impl);
+               sparc_cpu_type[cpuid] = "Unknow CPU";
+       }
+
+       for(i = 0; i<NSPARCFPU; i++) {
+               if(linux_sparc_fpu[i].manuf == manuf && linux_sparc_fpu[i].impl == impl)
+                       if(linux_sparc_fpu[i].fpu_vers == fpu_vers) {
+                               sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
+                               break;
+                       }
+       }
+
+       if(i == NSPARCFPU) {
+               printk("DEBUG: manuf = 0x%x  impl = 0x%x fsr.vers = 0x%x\n", manuf, impl,
+                           (unsigned)fpu_vers);
+               sparc_fpu_type[cpuid] = "Unknown FPU";
+       }
+}
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
new file mode 100644 (file)
index 0000000..ad444fa
--- /dev/null
@@ -0,0 +1,65 @@
+/* devices.c: Initial scan of the prom device tree for important
+ *            Sparc device nodes which we need to find.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/tasks.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+
+struct prom_cpuinfo linux_cpus[NCPUS];
+int linux_num_cpus;
+
+extern void cpu_probe(void);
+
+__initfunc(unsigned long
+device_scan(unsigned long mem_start))
+{
+       char node_str[128];
+       int nd, prom_node_cpu, thismid;
+       int cpu_nds[NCPUS];  /* One node for each cpu */
+       int cpu_ctr = 0;
+
+       prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+
+       if(strcmp(node_str, "cpu") == 0) {
+               cpu_nds[0] = prom_root_node;
+               cpu_ctr++;
+       } else {
+               int scan;
+               scan = prom_getchild(prom_root_node);
+               prom_printf("root child is %08x\n", (unsigned) scan);
+               nd = 0;
+               while((scan = prom_getsibling(scan)) != 0) {
+                       prom_getstring(scan, "device_type", node_str, sizeof(node_str));
+                       if(strcmp(node_str, "cpu") == 0) {
+                               cpu_nds[cpu_ctr] = scan;
+                               linux_cpus[cpu_ctr].prom_node = scan;
+                               prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+                               linux_cpus[cpu_ctr].mid = thismid;
+                               prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
+                                           cpu_ctr, (unsigned) scan,
+                                           thismid);
+                               cpu_ctr++;
+                       }
+               };
+               if(cpu_ctr == 0) {
+                       printk("No CPU nodes found, cannot continue.\n");
+                       halt();
+               }
+               printk("Found %d CPU prom device tree node(s).\n", cpu_ctr);
+       };
+       prom_node_cpu = cpu_nds[0];
+
+       linux_num_cpus = cpu_ctr;
+
+       cpu_probe();
+       return mem_start;
+}
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
new file mode 100644 (file)
index 0000000..1353cd8
--- /dev/null
@@ -0,0 +1,130 @@
+/* $Id: entry.S,v 1.1 1997/03/18 17:58:59 jj Exp $
+ * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996,1997 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+
+#define curptr      g6
+
+#define NR_SYSCALLS 256      /* Each OS is different... */
+
+       .text
+        .align  4
+linux_sparc_ni_syscall:
+       sethi   %hi(sys_ni_syscall), %l7
+       or      %l7, %lo(sys_ni_syscall), %l7
+       ba,pt   %xcc,syscall_is_too_hard
+        add    %l7, %g4, %l7
+
+linux_fast_syscall:
+       andn    %l7, 3, %l7
+       mov     %i0, %o0
+       mov     %i1, %o1
+       mov     %i2, %o2
+       jmpl    %l7 + %g0, %g0
+        mov    %i3, %o3
+
+linux_syscall_trace:
+       call    syscall_trace
+        nop
+       mov     %i0, %o0
+       mov     %i1, %o1
+       mov     %i2, %o2
+       mov     %i3, %o3
+       ba,pt   %xcc, 2f
+        mov    %i4, %o4
+
+       .globl  ret_from_syscall
+ret_from_syscall:
+       ba,pt   %xcc, ret_sys_call
+        ldx    [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %o0
+
+       /* Linux native and SunOS system calls enter here... */
+       .align  4
+       .globl  linux_sparc_syscall
+linux_sparc_syscall:
+       /* Direct access to user regs, must faster. */
+       cmp     %g1, NR_SYSCALLS
+       add     %l7, %g4, %l7
+       bgeu,pn %xcc, linux_sparc_ni_syscall
+        sll    %g1, 3, %l4
+       ldx     [%l7 + %l4], %l7
+       andcc   %l7, 1, %g0
+       bne,pn  %icc, linux_fast_syscall
+        /* Just do the next insn in the delay slot */
+
+       .globl  syscall_is_too_hard
+syscall_is_too_hard:
+       mov     %i0, %o0
+       mov     %i1, %o1
+       mov     %i2, %o2
+
+       ldx     [%curptr + AOFF_task_flags], %l5
+       mov     %i3, %o3
+       mov     %i4, %o4
+       andcc   %l5, 0x20, %g0
+       bne,pn  %icc, linux_syscall_trace
+        mov    %i0, %l5
+2:
+       call    %l7
+        mov    %i5, %o5
+
+       stx     %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+
+       .globl  ret_sys_call
+ret_sys_call:
+       ldx     [%curptr + AOFF_task_flags], %l6
+       mov     %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %g3
+       cmp     %o0, -ENOIOCTLCMD
+       sllx    %g2, 32, %g2
+       bgeu,pn %xcc, 1f
+        andcc  %l6, 0x20, %l6  
+
+       /* System call success, clear Carry condition code. */
+       andn    %g3, %g2, %g3
+       clr     %l6
+       stx     %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE] 
+       bne,pn  %icc, linux_syscall_trace2
+        ldx    [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+       add     %l1, 0x4, %l2                                 /* npc = npc+4 */
+       stx     %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+       ba,pt   %xcc, rtrap
+        stx    %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+1:
+       /* System call failure, set Carry condition code.
+        * Also, get abs(errno) to return to the process.
+        */
+       sub     %g0, %o0, %o0
+       or      %g3, %g2, %g3
+       stx     %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_I0]
+       mov     1, %l6
+       stx     %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE]
+       bne,pn  %icc, linux_syscall_trace2
+        ldx    [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %l1 /* pc = npc */
+       add     %l1, 0x4, %l2                                 /* npc = npc+4 */
+       stx     %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+       ba,pt   %xcc, rtrap
+        stx    %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+
+linux_syscall_trace2:
+       call    syscall_trace
+        add    %l1, 0x4, %l2                   /* npc = npc+4 */
+       stx     %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC]
+       ba,pt   %xcc, rtrap
+        stx    %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC]
+
+/* End of entry.S */
index 64b7667ea75a5ffcc6220e9fa58df9ccff15e10e..256b61174ae10588a4a0049075e5308fe7071d7e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.4 1997/03/04 16:26:58 jj Exp $
+/* $Id: etrap.S,v 1.5 1997/03/13 08:24:01 jj Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -18,16 +18,17 @@ etrap:
        rdpr    %tstate, %g1
        be,pn   %xcc, 1f                /* What happens more often? etrap when already in priv or from userland? */
         sllx   %g6, 32, %g6
+       /* Just when going from userland to privileged mode, we have to change this stuff. */
        sll     %g2, 3, %g2
        wrpr    %g2, %wstate
+       rdpr    %canrestore, %g5
+       wrpr    %g0, 0, %canrestore
+       wrpr    %g5, 0, %otherwin
 1:
        sethi   %hi(current_set), %g4
        or      %g4, %lo(current_set), %g4
        rdpr    %tpc, %g2
-       rdpr    %canrestore, %g5
        rdpr    %tnpc, %g3
-       wrpr    %g5, 0, %otherwin
-       wrpr    %g0, 0, %canrestore
        ldx     [%g6 + %g4], %g6
 #ifdef __SMP__
 /* FIXME: Fix the above insn for SMP */
index 5602103ee86367aa068a31df6cac438c4647cea7..6acaf3b3b3b9cd6f919aacee98d7266ed3cadf30 100644 (file)
    Hopefully will disappear quickly, once we get everything
    to compile... */
        .text
-       .globl ROOT_DEV
-ROOT_DEV:
-       nop
-       .globl ___lock_kernel
-___lock_kernel:
-       nop
-       .globl ___unlock_kernel
-___unlock_kernel:
-       nop
-       .globl __memcpy
-__memcpy:
-       nop
-       .globl __strncmp
-__strncmp:
-       nop
-       .globl _ctype
-_ctype:
-       nop
-       .globl _stext
-_stext:
-       nop
-       .globl bad_trap
-bad_trap:
-       nop
-       .globl bad_trap_tl1
-bad_trap_tl1:
-       nop
-       .globl bdflush
-bdflush:
-       nop
-       .globl breakpoint_trap
-breakpoint_trap:
-       nop
-       .globl buff_setup
-buff_setup:
-       nop
-       .globl buffer_init
-buffer_init:
-       nop
-       .globl change_root
-change_root:
-       nop
-       .globl console_init
-console_init:
-       nop
-       .globl console_loglevel
-console_loglevel:
-       nop
-       .globl console_restore_palette
-console_restore_palette:
-       nop
-       .globl current_set
-current_set:
-       nop
-       .globl do_cee
-do_cee:
-       nop
-       .globl do_cee_tl1
-do_cee_tl1:
-       nop
-       .globl do_dae
-do_dae:
-       nop
-       .globl do_dae_tl1
-do_dae_tl1:
-       nop
-       .globl do_dax
-do_dax:
-       nop
-       .globl do_dax_tl1
-do_dax_tl1:
-       nop
-       .globl do_div0
-do_div0:
-       nop
-       .globl do_div0_tl1
-do_div0_tl1:
-       nop
-       .globl do_fpdis
-do_fpdis:
-       nop
-       .globl do_fpdis_tl1
-do_fpdis_tl1:
-       nop
-       .globl do_fpieee
-do_fpieee:
-       nop
-       .globl do_fpieee_tl1
-do_fpieee_tl1:
-       nop
-       .globl do_fpother
-do_fpother:
-       nop
-       .globl do_fpother_tl1
-do_fpother_tl1:
-       nop
-       .globl do_iae
-do_iae:
-       nop
-       .globl do_iae_tl1
-do_iae_tl1:
-       nop
-       .globl do_iax
-do_iax:
-       nop
-       .globl do_iax_tl1
-do_iax_tl1:
-       nop
-       .globl do_ill
-do_ill:
-       nop
-       .globl do_ill_tl1
-do_ill_tl1:
-       nop
-       .globl do_irq
-do_irq:
-       nop
-       .globl do_irq_tl1
-do_irq_tl1:
-       nop
-       .globl do_ivec
-do_ivec:
-       nop
-       .globl do_ivec_tl1
-do_ivec_tl1:
-       nop
-       .globl do_lddfmna
-do_lddfmna:
-       nop
-       .globl do_lddfmna_tl1
-do_lddfmna_tl1:
-       nop
-       .globl do_mna
-do_mna:
-       nop
-       .globl do_mna_tl1
-do_mna_tl1:
-       nop
-       .globl do_paw
-do_paw:
-       nop
-       .globl do_paw_tl1
-do_paw_tl1:
-       nop
-       .globl do_privact
-do_privact:
-       nop
-       .globl do_privop
-do_privop:
-       nop
-       .globl do_stdfmna
-do_stdfmna:
-       nop
-       .globl do_stdfmna_tl1
-do_stdfmna_tl1:
-       nop
-       .globl do_tof
-do_tof:
-       nop
-       .globl do_tof_tl1
-do_tof_tl1:
-       nop
-       .globl do_vaw
-do_vaw:
-       nop
-       .globl do_vaw_tl1
-do_vaw_tl1:
-       nop
-       .globl dquot_init
-dquot_init:
-       nop
-       .globl errno
-errno:
-       nop
-       .globl eth_setup
-eth_setup:
-       nop
-       .globl file_table_init
-file_table_init:
-       nop
-       .globl floppy_setup
-floppy_setup:
-       nop
-       .globl getcc
-getcc:
-       nop
-       .globl indirect_syscall
-indirect_syscall:
-       nop
-       .globl init_IRQ
-init_IRQ:
-       nop
-       .globl init_task
-init_task:
-       nop
-       .globl initrd_below_start_ok
-initrd_below_start_ok:
-       nop
-       .globl initrd_start
-initrd_start:
-       nop
-       .globl inode_init
-inode_init:
-       nop
-       .globl install_linux_ticker
-install_linux_ticker:
-       nop
-       .globl install_obp_ticker
-install_obp_ticker:
-       nop
-       .globl ipc_init
-ipc_init:
-       nop
-       .globl jiffies
-jiffies:
-       nop
-       .globl kernel_enter_debugger
-kernel_enter_debugger:
-       nop
-       .globl kmalloc_init
-kmalloc_init:
-       nop
-       .globl kmem_cache_init
-kmem_cache_init:
-       nop
-       .globl kmem_cache_sizes_init
-kmem_cache_sizes_init:
-       nop
-       .globl kswapd
-kswapd:
-       nop
-       .globl linux32_syscall
-linux32_syscall:
-       nop
-       .globl linux64_syscall
-linux64_syscall:
-       nop
-       .globl lookup_fault
-lookup_fault:
-       nop
-       .globl mem_init
-mem_init:
-       nop
-       .globl memcpy
-memcpy:
-       nop
-       .globl mount_initrd
-mount_initrd:
-       nop
-       .globl name_cache_init
-name_cache_init:
-       nop
-       .globl netbsd_syscall
-netbsd_syscall:
-       nop
-       .globl no_scroll
-no_scroll:
-       nop
-       .globl paging_init
-paging_init:
-       nop
-       .globl panic
-panic:
-       nop
-       .globl panic_setup
-panic_setup:
-       nop
-       .globl printk
-printk:
-       nop
-       .globl prof_buffer
-prof_buffer:
-       nop
-       .globl prof_len
-prof_len:
-       nop
-       .globl prof_shift
-prof_shift:
-       nop
-       .globl pseudo_root
-pseudo_root:
-       nop
-       .globl rd_doload
-rd_doload:
-       nop
-       .globl rd_image_start
-rd_image_start:
-       nop
-       .globl rd_prompt
-rd_prompt:
-       nop
-       .globl rd_size
-rd_size:
-       nop
-       .globl reboot_command
-reboot_command:
-       nop
-       .globl reserve_setup
-reserve_setup:
-       nop
-       .globl sbus_init
-sbus_init:
-       nop
-       .globl sched_init
-sched_init:
-       nop
-       .globl scsi_luns_setup
-scsi_luns_setup:
-       nop
-       .globl serial_console
-serial_console:
-       nop
-       .globl set_palette
-set_palette:
-       nop
-       .globl setcc
-setcc:
-       nop
-       .globl setup_arch
-setup_arch:
-       nop
-       .globl simple_strtoul
-simple_strtoul:
-       nop
-       .globl sock_init
-sock_init:
-       nop
-       .globl solaris_syscall
-solaris_syscall:
-       nop
-       .globl sparc64_dtlb_fault
-sparc64_dtlb_fault:
-       nop
-       .globl sparc64_dtlb_refbit_catch
-sparc64_dtlb_refbit_catch:
-       nop
-       .globl sparc64_itlb_refbit_catch
-sparc64_itlb_refbit_catch:
-       nop
-       .globl sprintf
-sprintf:
-       nop
-       .globl st_setup
-st_setup:
-       nop
-       .globl strchr
-strchr:
-       nop
-       .globl strcmp
-strcmp:
-       nop
-       .globl strcpy
-strcpy:
-       nop
-       .globl strlen
-strlen:
-       nop
-       .globl strncpy
-strncpy:
-       nop
-       .globl sunos_syscall
-sunos_syscall:
-       nop
-       .globl swap_setup
-swap_setup:
-       nop
-       .globl sysctl_init
-sysctl_init:
-       nop
-       .globl time_init
-time_init:
-       nop
-       .globl trap_init
-trap_init:
-       nop
-       .globl vma_init
-vma_init:
-       nop
-       .globl vsprintf
-vsprintf:
-       nop
-       .globl schedule
-schedule:
-       nop
-       .globl getname
-getname:
-       nop
-       .globl do_execve
-do_execve:
-       nop
-       .globl putname
-putname:
-       nop
+       .align  8
+       .globl  __copy_user
+__copy_user:   retl;nop
+       .globl  __csum_partial_copy_sparc_generic
+__csum_partial_copy_sparc_generic:     retl;nop
+       .globl  _sigpause_common
+_sigpause_common:      retl;nop
+       .globl  _stext
+_stext:        retl;nop
+       .globl  auxio_register
+auxio_register:        retl;nop
+       .globl  bad_trap
+bad_trap:      retl;nop
+       .globl  bad_trap_tl1
+bad_trap_tl1:  retl;nop
+       .globl  breakpoint
+breakpoint:    retl;nop
+       .globl  breakpoint_trap
+breakpoint_trap:       retl;nop
+       .globl  csum_partial
+csum_partial:  retl;nop
+       .globl  ctx_free
+ctx_free:      .skip   32
+       .globl  ctx_list_pool
+ctx_list_pool: .skip   32
+       .globl  ctx_used
+ctx_used:      .skip   32
+       .globl  destroy_context
+destroy_context:       retl;nop
+       .globl  disable_irq
+disable_irq:   retl;nop
+       .globl  do_cee
+do_cee:        retl;nop
+       .globl  do_cee_tl1
+do_cee_tl1:    retl;nop
+       .globl  do_dae
+do_dae:        retl;nop
+       .globl  do_dae_tl1
+do_dae_tl1:    retl;nop
+       .globl  do_dax
+do_dax:        retl;nop
+       .globl  do_dax_tl1
+do_dax_tl1:    retl;nop
+       .globl  do_div0
+do_div0:       retl;nop
+       .globl  do_div0_tl1
+do_div0_tl1:   retl;nop
+       .globl  do_fpdis
+do_fpdis:      retl;nop
+       .globl  do_fpdis_tl1
+do_fpdis_tl1:  retl;nop
+       .globl  do_fpieee
+do_fpieee:     retl;nop
+       .globl  do_fpieee_tl1
+do_fpieee_tl1: retl;nop
+       .globl  do_fpother
+do_fpother:    retl;nop
+       .globl  do_fpother_tl1
+do_fpother_tl1:        retl;nop
+       .globl  do_gettimeofday
+do_gettimeofday:       retl;nop
+       .globl  do_iae
+do_iae:        retl;nop
+       .globl  do_iae_tl1
+do_iae_tl1:    retl;nop
+       .globl  do_iax
+do_iax:        retl;nop
+       .globl  do_iax_tl1
+do_iax_tl1:    retl;nop
+       .globl  do_ill
+do_ill:        retl;nop
+       .globl  do_ill_tl1
+do_ill_tl1:    retl;nop
+       .globl  do_irq
+do_irq:        retl;nop
+       .globl  do_irq_tl1
+do_irq_tl1:    retl;nop
+       .globl  do_ivec
+do_ivec:       retl;nop
+       .globl  do_ivec_tl1
+do_ivec_tl1:   retl;nop
+       .globl  do_lddfmna
+do_lddfmna:    retl;nop
+       .globl  do_lddfmna_tl1
+do_lddfmna_tl1:        retl;nop
+       .globl  do_mna
+do_mna:        retl;nop
+       .globl  do_mna_tl1
+do_mna_tl1:    retl;nop
+       .globl  do_paw
+do_paw:        retl;nop
+       .globl  do_paw_tl1
+do_paw_tl1:    retl;nop
+       .globl  do_privact
+do_privact:    retl;nop
+       .globl  do_privop
+do_privop:     retl;nop
+       .globl  do_settimeofday
+do_settimeofday:       retl;nop
+       .globl  do_signal
+do_signal:     retl;nop
+       .globl  do_stdfmna
+do_stdfmna:    retl;nop
+       .globl  do_stdfmna_tl1
+do_stdfmna_tl1:        retl;nop
+       .globl  do_tof
+do_tof:        retl;nop
+       .globl  do_tof_tl1
+do_tof_tl1:    retl;nop
+       .globl  do_vaw
+do_vaw:        retl;nop
+       .globl  do_vaw_tl1
+do_vaw_tl1:    retl;nop
+       .globl  enable_irq
+enable_irq:    retl;nop
+       .globl  floppy_hardint
+floppy_hardint:        retl;nop
+       .globl  flush_user_windows
+flush_user_windows:    retl;nop
+       .globl  free_irq
+free_irq:      retl;nop
+       .globl  get_cpuid
+get_cpuid:     retl;nop
+       .globl  get_irq_list
+get_irq_list:  retl;nop
+       .globl  getcc
+getcc: retl;nop
+       .globl  halt
+halt:  retl;nop
+       .globl  indirect_syscall
+indirect_syscall:      retl;nop
+       .globl  init_IRQ
+init_IRQ:      retl;nop
+       .globl  install_linux_ticker
+install_linux_ticker:  retl;nop
+       .globl  install_obp_ticker
+install_obp_ticker:    retl;nop
+       .globl  iommu_init
+iommu_init:    retl;nop
+       .globl  linux32_syscall
+linux32_syscall:       retl;nop
+       .globl  linux64_syscall
+linux64_syscall:       retl;nop
+       .globl  linux_dbvec
+linux_dbvec:   retl;nop
+       .globl  linux_num_cpus
+linux_num_cpus:        retl;nop
+       .globl  load_mmu
+load_mmu:      retl;nop
+       .globl  mmu_get_scsi_one
+mmu_get_scsi_one:      retl;nop
+       .globl  mmu_get_scsi_sgl
+mmu_get_scsi_sgl:      retl;nop
+       .globl  mmu_info
+mmu_info:      retl;nop
+       .globl  mmu_lockarea
+mmu_lockarea:  retl;nop
+       .globl  mmu_release_scsi_one
+mmu_release_scsi_one:  retl;nop
+       .globl  mmu_release_scsi_sgl
+mmu_release_scsi_sgl:  retl;nop
+       .globl  mmu_unlockarea
+mmu_unlockarea:        retl;nop
+       .globl  mstk48t02_regs
+mstk48t02_regs:        retl;nop
+       .globl  netbsd_syscall
+netbsd_syscall:        retl;nop
+       .globl  probe_irq_off
+probe_irq_off: retl;nop
+       .globl  probe_irq_on
+probe_irq_on:  retl;nop
+       .globl  request_fast_irq
+request_fast_irq:      retl;nop
+       .globl  request_irq
+request_irq:   retl;nop
+       .globl  setcc
+setcc: retl;nop
+       .globl  solaris_syscall
+solaris_syscall:       retl;nop
+       .globl  sparc64_dtlb_fault
+sparc64_dtlb_fault:    retl;nop
+       .globl  sparc64_dtlb_refbit_catch
+sparc64_dtlb_refbit_catch:     retl;nop
+       .globl  sparc64_itlb_refbit_catch
+sparc64_itlb_refbit_catch:     retl;nop
+       .globl  spitfire_get_new_context
+spitfire_get_new_context:      retl;nop
+       .globl  sunos_mmap
+sunos_mmap:    retl;nop
+       .globl  sunos_syscall
+sunos_syscall: retl;nop
+       .globl  svr4_getcontext
+svr4_getcontext:       retl;nop
+       .globl  svr4_setcontext
+svr4_setcontext:       retl;nop
+       .globl  swapper_pg_dir
+swapper_pg_dir:        retl;nop
+       .globl  switch_to
+switch_to:     retl;nop
+       .globl  sys_call_table
+sys_call_table:        retl;nop
+       .globl  time_init
+time_init:     retl;nop
+       .globl  translate_namei
+translate_namei:       retl;nop
+       .globl  translate_open_namei
+translate_open_namei:  retl;nop
+       .globl  sparc_brk
+sparc_brk:     retl;nop
+       .globl  sparc_sigaction
+sparc_sigaction:       retl;nop
+       .globl  sunos_accept
+sunos_accept:  retl;nop
+       .globl  sunos_audit
+sunos_audit:   retl;nop
+       .globl  sunos_brk
+sunos_brk:     retl;nop
+       .globl  sunos_execv
+sunos_execv:   retl;nop
+       .globl  sunos_fpathconf
+sunos_fpathconf:       retl;nop
+       .globl  sunos_getdents
+sunos_getdents:        retl;nop
+       .globl  sunos_getdirentries
+sunos_getdirentries:   retl;nop
+       .globl  sunos_getdomainname
+sunos_getdomainname:   retl;nop
+       .globl  sunos_getdtablesize
+sunos_getdtablesize:   retl;nop
+       .globl  sunos_getgid
+sunos_getgid:  retl;nop
+       .globl  sunos_gethostid
+sunos_gethostid:       retl;nop
+       .globl  sunos_getpid
+sunos_getpid:  retl;nop
+       .globl  sunos_getsockopt
+sunos_getsockopt:      retl;nop
+       .globl  sunos_getuid
+sunos_getuid:  retl;nop
+       .globl  sunos_indir
+sunos_indir:   retl;nop
+       .globl  sunos_ioctl
+sunos_ioctl:   retl;nop
+       .globl  sunos_killpg
+sunos_killpg:  retl;nop
+       .globl  sunos_madvise
+sunos_madvise: retl;nop
+       .globl  sunos_mctl
+sunos_mctl:    retl;nop
+       .globl  sunos_mincore
+sunos_mincore: retl;nop
+       .globl  sunos_mount
+sunos_mount:   retl;nop
+       .globl  sunos_nop
+sunos_nop:     retl;nop
+       .globl  sunos_nosys
+sunos_nosys:   retl;nop
+       .globl  sunos_open
+sunos_open:    retl;nop
+       .globl  sunos_pathconf
+sunos_pathconf:        retl;nop
+       .globl  sunos_poll
+sunos_poll:    retl;nop
+       .globl  sunos_read
+sunos_read:    retl;nop
+       .globl  sunos_readv
+sunos_readv:   retl;nop
+       .globl  sunos_recv
+sunos_recv:    retl;nop
+       .globl  sunos_sbrk
+sunos_sbrk:    retl;nop
+       .globl  sunos_select
+sunos_select:  retl;nop
+       .globl  sunos_semsys
+sunos_semsys:  retl;nop
+       .globl  sunos_send
+sunos_send:    retl;nop
+       .globl  sunos_setpgrp
+sunos_setpgrp: retl;nop
+       .globl  sunos_setsockopt
+sunos_setsockopt:      retl;nop
+       .globl  sunos_shmsys
+sunos_shmsys:  retl;nop
+       .globl  sunos_sigaction
+sunos_sigaction:       retl;nop
+       .globl  sunos_sigblock
+sunos_sigblock:        retl;nop
+       .globl  sunos_sigsetmask
+sunos_sigsetmask:      retl;nop
+       .globl  sunos_sstk
+sunos_sstk:    retl;nop
+       .globl  sunos_sysconf
+sunos_sysconf: retl;nop
+       .globl  sunos_uname
+sunos_uname:   retl;nop
+       .globl  sunos_vadvise
+sunos_vadvise: retl;nop
+       .globl  sunos_wait4
+sunos_wait4:   retl;nop
+       .globl  sunos_write
+sunos_write:   retl;nop
+       .globl  sunos_writev
+sunos_writev:  retl;nop
+       .globl  sys_aplib
+sys_aplib:     retl;nop
+       .globl  sys_clone
+sys_clone:     retl;nop
+       .globl  sys_execve
+sys_execve:    retl;nop
+       .globl  sys_fork
+sys_fork:      retl;nop
+       .globl  sys_getpagesize
+sys_getpagesize:       retl;nop
+       .globl  sys_ipc
+sys_ipc:       retl;nop
+       .globl  sys_mmap
+sys_mmap:      retl;nop
+       .globl  sys_nis_syscall
+sys_nis_syscall:       retl;nop
+       .globl  sys_pipe
+sys_pipe:      retl;nop
+       .globl  sys_ptrace
+sys_ptrace:    retl;nop
+       .globl  sys_sigpause
+sys_sigpause:  retl;nop
+       .globl  sys_sigreturn
+sys_sigreturn: retl;nop
+       .globl  sys_sigstack
+sys_sigstack:  retl;nop
+       .globl  sys_sigsuspend
+sys_sigsuspend:        retl;nop
+       .globl  sys_vfork
+sys_vfork:     retl;nop
+       .globl  syscall_trace
+syscall_trace: retl;nop
+       .globl  sparc_ultra_mapioaddr
+sparc_ultra_mapioaddr: retl;nop
+       .globl  sparc_ultra_unmapioaddr
+sparc_ultra_unmapioaddr:       retl;nop
+       .globl  mmu_map_dma_area
+mmu_map_dma_area:      retl;nop
index bf55f453c0d511cd8b07e2f89f31f18ec7fa1f0e..20e6e27817240bacc7370e47ae29febc4edf4bbb 100644 (file)
@@ -1,8 +1,10 @@
-/* $Id: head.S,v 1.9 1997/02/26 11:09:25 jj Exp $
+/* $Id: head.S,v 1.17 1997/03/18 17:59:37 jj Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  */
 
 #include <linux/version.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/errno.h>
-
+#include <asm/lsu.h>
+       
 /* This section from from _start to sparc64_boot_end should fit into
-   0xfffff80000004000 to 0xfffff80000008000 and will be sharing space
-   with bootup_user_stack, which is from 0xfffff80000004000 to
-   0xfffff80000006000 and bootup_kernel_stack, which is from
-   0xfffff80000006000 to 0xfffff80000008000. */
+ * 0xffff.f800.0000.4000 to 0xffff.f800.0000.8000 and will be sharing space
+ * with bootup_user_stack, which is from 0xffff.f800.0000.4000 to
+ * 0xffff.f800.0000.6000 and bootup_kernel_stack, which is from
+ * 0xffff.f800.0000.6000 to 0xffff.f800.0000.8000. 
+ */
 
        .text
        .globl  start, _start
@@ -26,12 +30,15 @@ start:
 bootup_user_stack:
 ! 0xfffff80000004000
        b       sparc64_boot
-        rdpr   %ver, %g1                       /* Get VERSION register.        */
+        flushw                                 /* Flush register file.      */
 
 /* This stuff has to be in sync with SILO and other potential boot loaders
  * Fields should be kept upward compatible and whenever any change is made,
  * HdrS version should be incremented.
  */
+        .global root_flags, ram_flags, root_dev
+        .global ramdisk_image, ramdisk_size
+
         .ascii  "HdrS"
         .word   LINUX_VERSION_CODE
         .half   0x0201          /* HdrS version */
@@ -47,59 +54,80 @@ ramdisk_size:
         .word   0
         .word   reboot_command
 
-sparc64_boot:
        /* We must be careful, 32-bit OpenBOOT will get confused if it
         * tries to save away a register window to a 64-bit kernel
         * stack address.  Flush all windows, disable interrupts,
         * remap if necessary, jump onto kernel trap table, then kernel
         * stack, or else we die.
+        *
+        * PROM entry point is on %o4
         */
-       flushw                                  /* Flush register file.      */
+sparc64_boot:
+       mov     (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
+       stxa    %g1, [%g0] ASI_LSU_CONTROL
+
+       /*
+        * Make sure we are in privileged mode, have address masking,
+         * using the ordinary globals and have enabled floating
+         * point.
+         */                                                                                
+
        wrpr    %g0, 0xf, %pil                  /* Interrupts off.           */
+       wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF), %pstate
 
-       /* Remap ourselves to upper 64-bit addresses if necessary.
+       /* Check if we are mapped where we expect to be in virtual
+        * memory.  The Solaris /boot elf format bootloader
+        * will peek into our elf header and load us where
+        * we want to be, otherwise we have to re-map.
         */
-       sethi   %uhi(PAGE_OFFSET), %g4
 current_pc:
-       rd      %pc, %g2
+       rd      %pc, %g3
+       sethi   %uhi(KERNBASE), %g4
        sllx    %g4, 32, %g4
-       sethi   %hi(current_pc), %g3
-       or      %g3, %lo(current_pc), %g3
-       add     %g4, %g3, %g3
-       cmp     %g3, %g2
-       be      go_to_highmem
+
+       /* Check the run time program counter. */
+
+       set     current_pc, %g5
+       add     %g5, %g4, %g5
+       cmp     %g3, %g5
+       be      %xcc,sun4u_init
         nop
 
-       /* Remap ourselves into high addresses. */
-       sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
-       sllx    %g5, 32, %g5
-       or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G | _PAGE_L), %g5
+create_mappings:
+       /* %g5 holds the tlb data */
+        sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+        sllx    %g5, 32, %g5
+        or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
 
-       /* Be real fucking anal... */
-       stxa    %g0, [%g4] ASI_IMMU_DEMAP
-       stxa    %g0, [%g4] ASI_DMMU_DEMAP
-       membar  #Sync
-       flush   %g4
+       /* We aren't mapped in at KERNBASE, so we need to create
+        * an I and D tlb entry to map KERNBASE to 0.  Both entries
+        * are 4 Megs mappings and are locked in.
+        */
+       set     TLB_TAG_ACCESS, %g3           /* 0x30 */
 
-       mov     TLB_TAG_ACCESS, %g6
-       stxa    %g4, [%g6] ASI_IMMU
-       stxa    %g5, [%g0] ASI_ITLB_DATA_IN
-       membar  #Sync
-       flush   %g4
+       stxa    %g4, [%g3] ASI_IMMU           /* 0x50 */
+       stxa    %g5, [%g0] ASI_ITLB_DATA_IN   /* 0x54 */
+       membar  #Sync
 
-       stxa    %g4, [%g6] ASI_DMMU
-       stxa    %g5, [%g0] ASI_DTLB_DATA_IN
-       membar  #Sync
-       flush   %g4
+       /* Put KERNBASE into the I/D Tag Access Register (TAR) */
+       stxa    %g4, [%g3] ASI_DMMU           /* 0x58 */
+       stxa    %g5, [%g0] ASI_DTLB_DATA_IN
+       membar  #Sync
 
-/* FIXME: Should clean here the page @ phys. 0 and map one page @ */
+       nop
+       nop     
+       membar  #Sync
+       
+       ba,pt   %xcc, go_to_highmem
+        nop
 
+/* Now do a non-relative jump so that PC is in high-memory */
 go_to_highmem:
-       jmpl    %g3 + (execute_in_high_mem - current_pc), %g0
+       set     sun4u_init, %g1
+       jmpl     %g1 + %g4, %g0
         nop
 
-execute_in_high_mem:
-
+sun4u_init:
        /* Remap our prom interface code */
        sethi   %hi(__p1275_loc), %g7
        or      %g7, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W | _PAGE_G | _PAGE_L), %g7
@@ -114,29 +142,40 @@ execute_in_high_mem:
        stxa    %g3, [%g6] ASI_IMMU
        stxa    %g5, [%g0] ASI_ITLB_DATA_IN
        membar  #Sync
-       flush   %g3
+
        stxa    %g3, [%g6] ASI_DMMU
        stxa    %g5, [%g0] ASI_DTLB_DATA_IN
        membar  #Sync
        flush   %g3
 
-       sethi   %hi(nwindows), %g7
-       and     %g1, VERS_MAXWIN, %g5
-       add     %g7, %lo(nwindows), %g7
+       nop
+       nop
+       membar  #Sync
+       
+       /* Compute the number of windows in this machine
+        * store this in nwindows and nwindowsm1
+        */
+       rdpr    %ver, %g1                       /* Get VERSION register.        */
+       sethi   %hi(nwindows), %g2
+       and     %g1, VERS_MAXWIN, %g5
+       or      %g2,%lo(nwindows),%g2
        add     %g5, 1, %g6
-       add     %g7, (nwindows - nwindowsm1), %g3
-       stx     %g6, [%g7 + %g4]
-       stx     %g5, [%g3 + %g4]
-       mov     %sp, %o1                        ! second argument to prom_init
+       add     %g2, (nwindows - nwindowsm1), %g3
+       stx     %g6, [%g2 + %g4]
+       stx     %g5, [%g3 + %g4]
+
        sethi   %hi(init_task), %g6
        or      %g6, %lo(init_task), %g6
        add     %g6, %g4, %g6                   ! g6 usage is fixed as well
+       mov     %sp, %l6
+       mov     %o4, %l7
 
-/* FIXME: Initialize MMU globals??? */
-
+#if 0
+/* This is to dangerous for now... To many traps unfilled yet... */
        sethi   %hi(sparc64_ttable_tl0), %g5
        add     %g5, %g4, %g5
        wrpr    %g5, %tba
+#endif
 
        sethi   %hi(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
        or      %g5, %lo(bootup_kernel_stack + 0x2000 - STACK_BIAS - REGWIN_SZ), %g5
@@ -145,9 +184,36 @@ execute_in_high_mem:
        wrpr    %g0, PSTATE_PEF | PSTATE_PRIV, %pstate
        wrpr    %g0, 0, %wstate
        wrpr    %g0, 0x0, %tl
-
+       fzero   %f48
+       fzero   %f50
+       fzero   %f52
+       fzero   %f54
+       fzero   %f56
+       fzero   %f58
+       fzero   %f60
+       fzero   %f62
+
+       /* Clear the bss */
+       sethi   %hi(8191), %l2
+       or      %l2, %lo(8191), %l2
+       sethi   %hi(__bss_start), %l0
+       or      %l0, %lo(__bss_start), %l0
+       sethi   %hi(_end), %l1
+       or      %l1, %lo(_end), %l1
+       add     %l1, %l2, %l1
+       andn    %l1, %l2, %l1
+       add     %l2, 1, %l2
+       add     %l0, %g4, %o0
+1:
+       call    bzero_1page
+        add    %l0, %l2, %l0
+       cmp     %l0, %l1
+       blu,pt  %xcc, 1b
+        add    %l0, %g4, %o0
+
+       mov     %l6, %o1                        ! OpenPROM stack
        call    prom_init
-        mov    %o4, %o0                        ! OpenPROM cif handler
+        mov    %l7, %o0                        ! OpenPROM cif handler
 
        /* Off we go.... */
        call    start_kernel
@@ -165,18 +231,11 @@ bootup_kernel_stack:
 
 #include "ttable.S"
 
-        .global root_flags
-        .global ram_flags
-        .global root_dev
-        .global ramdisk_image
-        .global ramdisk_size
-
        .data
        .align  8
        .globl  nwindows, nwindowsm1 
 nwindows:      .xword  0
 nwindowsm1:    .xword  0
-
        .section        ".fixup",#alloc,#execinstr
        .globl  __ret_efault
 __ret_efault:
index c775d81405f2b241e1698d2d10f7ec36cfb4c51b..10dda3ea5c6c521c0e21d2b9c08b258787bc5b06 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.1 1996/12/28 18:39:39 davem Exp $
+/* $Id: ioport.c,v 1.2 1997/03/18 17:59:31 jj Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -29,21 +29,21 @@ unsigned long sparc_iobase_vaddr = IOBASE_VADDR;
  * to use your own mapping, but in practice this should not be used.
  *
  * Input:
- *  address: the obio address to map
+ *  address: Physical address to map
  *  virtual: if non zero, specifies a fixed virtual address where
  *           the mapping should take place.
  *  len:     the length of the mapping
- *  bus_type: The bus on which this io area sits.
+ *  bus_type: Optional high word of physical address.
  *
  * Returns:
  *  The virtual address where the mapping actually took place.
  */
 
 void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
-                     int bus_type, int rdonly)
+                     unsigned bus_type, int rdonly)
 {
        unsigned long vaddr, base_address;
-       unsigned long addr = (unsigned long) address;
+       unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
        unsigned long offset = (addr & (~PAGE_MASK));
 
        if (virtual) {
@@ -74,7 +74,7 @@ void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
        base_address = vaddr;
        /* Do the actual mapping */
        for (; len > 0; len -= PAGE_SIZE) {
-               mapioaddr(addr, vaddr, bus_type, rdonly);
+               mapioaddr(addr, vaddr, rdonly);
                vaddr += PAGE_SIZE;
                addr += PAGE_SIZE;
        }
index 21cd52a1bcfadd5fbb547d4e15740bb3cb37350d..58f202cfe75018bafb6cbdd8570620fcb16fc4fb 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: rtrap.S,v 1.2 1997/02/26 11:09:25 jj Exp $
- * rtrap.S: Preparing for entry into the kernel on Sparc V9.
+/* $Id: rtrap.S,v 1.4 1997/03/13 16:24:55 jj Exp $
+ * rtrap.S: Preparing for return from trap on Sparc V9.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <asm/pstate.h>
        .align  4
        .globl  rtrap
 rtrap:
-       /*not*/ done /*yet*/
+       sethi   %hi(intr_count), %l0
+       or      %l0, %lo(intr_count), %l0
+       ld      [%l0 + %g4], %l1
+       sethi   %hi(bh_active), %l2
+       brz,pt  %l1, 2f
+        or     %l2, %lo(bh_active), %l2
+       sethi   %hi(bh_mask), %l1
+       or      %l1, %lo(bh_mask), %l1
+1:
+       ldx     [%l2 + %g4], %l3
+       ldx     [%l1 + %g4], %l4
+       andcc   %l3, %l4, %g0
+       be,pt   %xcc, 2f
+        mov    1, %l7
+       call    do_bottom_half
+        st     %l7, [%l0 + %g4]
+       ba,pt   %xcc, 1b
+        st     %g0, [%l0 + %g4]        
+2:
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_TSTATE], %l1
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_TPC], %l2
+       andcc   %l1, TSTATE_PRIV, %l3
+       rdpr    %pstate, %l7
+       be,pt   %icc, to_user
+        andn   %l7, PSTATE_IE, %l7
+3:
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G1], %g1
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G2], %g2
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G3], %g3
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G4], %g4
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G5], %g5
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G6], %g6
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_G7], %g7
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I0], %i0
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I1], %i1
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I2], %i2
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I3], %i3
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I4], %i4
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I5], %i5
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I6], %i6
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_I7], %i7
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_Y], %o3
+       ldx     [%sp + STACK_BIAS + REGWIN_SZ + PT_TNPC], %o2
+       wr      %o3, %g0, %y
+       wrpr    %l7, %g0, %pstate
+       wrpr    %g0, 1, %tl
+       wrpr    %l1, %g0, %tstate
+       wrpr    %l2, %g0, %tpc
+       brnz,pn %l3, 1f
+        wrpr   %o2, %g0, %tnpc
+       /* we came here from to_user, ie. we have now AG */
+       restore
+       rdpr    %wstate, %g1
+       rdpr    %otherwin, %g2
+       srl     %g1, 3, %g1
+       wrpr    %g2, %g0, %canrestore
+       wrpr    %g1, %g0, %wstate
+       wrpr    %g0, %g0, %otherwin
+       retry
+1:
+       restore
+       retry
+to_user:
+       sethi   %hi(need_resched), %l0
+       or      %l0, %lo(need_resched), %l0
+       ld      [%l0 + %g4], %l0
+       wrpr    %o4, PSTATE_IE, %pstate
+       brz,pt  %l0, 1f
+        ldx    [%g6 + AOFF_task_signal], %l0
+       call    schedule
+        nop
+1:
+       ldx     [%g6 + AOFF_task_blocked], %o0
+       or      %l7, PSTATE_AG, %l7             ! Will need this for setting back wstate
+       andcc   %l0, %o0, %g0
+       be,pt   %xcc, 3b
+        mov    %l5, %o2  
+       mov     %l6, %o3
+       add     %sp, STACK_BIAS + REGWIN_SZ, %o1
+       call    do_signal
+        add    %o7, 3b-.-4, %o7
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
new file mode 100644 (file)
index 0000000..26d7c65
--- /dev/null
@@ -0,0 +1,416 @@
+/*  $Id: setup.c,v 1.1 1997/03/11 17:37:04 jj Exp $
+ *  linux/arch/sparc64/kernel/setup.c
+ *
+ *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1997       Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <asm/smp.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/idprom.h>
+
+struct screen_info screen_info = {
+       0, 0,                   /* orig-x, orig-y */
+       { 0, 0, },              /* unused */
+       0,                      /* orig-video-page */
+       0,                      /* orig-video-mode */
+       128,                    /* orig-video-cols */
+       0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+       54,                     /* orig-video-lines */
+       0,                      /* orig-video-isVGA */
+       16                      /* orig-video-points */
+};
+
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+       return memory_start;
+}
+
+/* Typing sync at the prom prompt calls the function pointed to by
+ * the sync callback which I set to the following function.
+ * This should sync all filesystems and return, for now it just
+ * prints out pretty messages and returns.
+ */
+
+extern unsigned long sparc64_ttable_tl0;
+extern void breakpoint(void);
+#if CONFIG_SUN_CONSOLE
+extern void console_restore_palette(void);
+#endif
+asmlinkage void sys_sync(void);        /* it's really int */
+
+/* Pretty sick eh? */
+void prom_sync_me(long *args)
+{
+       unsigned long prom_tba, flags;
+
+       save_and_cli(flags);
+       __asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba));
+       __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0));
+
+#ifdef CONFIG_SUN_CONSOLE
+        console_restore_palette ();
+#endif
+       prom_printf("PROM SYNC COMMAND...\n");
+       show_free_areas();
+       if(current->pid != 0) {
+               sti();
+               sys_sync();
+               cli();
+       }
+       prom_printf("Returning to prom\n");
+
+       __asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba));
+       restore_flags(flags);
+
+       return;
+}
+
+extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */
+
+unsigned int boot_flags;
+#define BOOTME_DEBUG  0x1
+#define BOOTME_SINGLE 0x2
+#define BOOTME_KGDB   0x4
+
+#ifdef CONFIG_SUN_CONSOLE
+extern char *console_fb_path;
+static int console_fb = 0;
+#endif
+static unsigned long memory_size = 0;
+
+void kernel_enter_debugger(void)
+{
+       if (boot_flags & BOOTME_KGDB) {
+               printk("KGDB: Entered\n");
+               breakpoint();
+       }
+}
+
+int obp_system_intr(void)
+{
+       if (boot_flags & BOOTME_KGDB) {
+               printk("KGDB: system interrupted\n");
+               breakpoint();
+               return 1;
+       }
+       if (boot_flags & BOOTME_DEBUG) {
+               printk("OBP: system interrupted\n");
+               prom_halt();
+               return 1;
+       }
+       return 0;
+}
+
+/* 
+ * Process kernel command line switches that are specific to the
+ * SPARC or that require special low-level processing.
+ */
+__initfunc(static void process_switch(char c))
+{
+       switch (c) {
+       case 'd':
+               boot_flags |= BOOTME_DEBUG;
+               break;
+       case 's':
+               boot_flags |= BOOTME_SINGLE;
+               break;
+       case 'h':
+               prom_printf("boot_flags_init: Halt!\n");
+               halt();
+               break;
+       default:
+               printk("Unknown boot switch (-%c)\n", c);
+               break;
+       }
+}
+
+__initfunc(static void boot_flags_init(char *commands))
+{
+       while (*commands) {
+               /* Move to the start of the next "argument". */
+               while (*commands && *commands == ' ')
+                       commands++;
+
+               /* Process any command switches, otherwise skip it. */
+               if (*commands == '\0')
+                       break;
+               else if (*commands == '-') {
+                       commands++;
+                       while (*commands && *commands != ' ')
+                               process_switch(*commands++);
+               } else if (strlen(commands) >= 9
+                          && !strncmp(commands, "kgdb=tty", 8)) {
+                       boot_flags |= BOOTME_KGDB;
+                       switch (commands[8]) {
+#ifdef CONFIG_SUN_SERIAL
+                       case 'a':
+                               rs_kgdb_hook(0);
+                               prom_printf("KGDB: Using serial line /dev/ttya.\n");
+                               break;
+                       case 'b':
+                               rs_kgdb_hook(1);
+                               prom_printf("KGDB: Using serial line /dev/ttyb.\n");
+                               break;
+#endif
+                       default:
+                               printk("KGDB: Unknown tty line.\n");
+                               boot_flags &= ~BOOTME_KGDB;
+                               break;
+                       }
+                       commands += 9;
+               } else {
+#if CONFIG_SUN_CONSOLE
+                       if (!strncmp(commands, "console=", 8)) {
+                               commands += 8;
+                               if (!strncmp (commands, "ttya", 4)) {
+                                       console_fb = 2;
+                                       prom_printf ("Using /dev/ttya as console.\n");
+                               } else if (!strncmp (commands, "ttyb", 4)) {
+                                       console_fb = 3;
+                                       prom_printf ("Using /dev/ttyb as console.\n");
+                               } else {
+                                       console_fb = 1;
+                                       console_fb_path = commands;
+                               }
+                       } else
+#endif
+                       if (!strncmp(commands, "mem=", 4)) {
+                               /*
+                                * "mem=XXX[kKmM] overrides the PROM-reported
+                                * memory size.
+                                */
+                               memory_size = simple_strtoul(commands + 4,
+                                                            &commands, 0);
+                               if (*commands == 'K' || *commands == 'k') {
+                                       memory_size <<= 10;
+                                       commands++;
+                               } else if (*commands=='M' || *commands=='m') {
+                                       memory_size <<= 20;
+                                       commands++;
+                               }
+                       }
+                       while (*commands && *commands != ' ')
+                               commands++;
+               }
+       }
+}
+
+extern int prom_probe_memory(void);
+extern unsigned long start, end;
+extern void panic_setup(char *, int *);
+extern unsigned long sun_serial_setup(unsigned long);
+
+extern unsigned short root_flags;
+extern unsigned short root_dev;
+extern unsigned short ram_flags;
+extern unsigned ramdisk_image;
+extern unsigned ramdisk_size;
+#define RAMDISK_IMAGE_START_MASK       0x07FF
+#define RAMDISK_PROMPT_FLAG            0x8000
+#define RAMDISK_LOAD_FLAG              0x4000
+
+extern int root_mountflags;
+
+extern void register_console(void (*proc)(const char *));
+
+char saved_command_line[256];
+char reboot_command[256];
+
+__initfunc(void setup_arch(char **cmdline_p,
+       unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+       int total, i;
+
+       /* Initialize PROM console and command line. */
+       *cmdline_p = prom_getbootargs();
+       strcpy(saved_command_line, *cmdline_p);
+
+       printk("ARCH: SUN4U\n");
+
+       boot_flags_init(*cmdline_p);
+#if 0  
+       if((boot_flags&BOOTME_DEBUG) && (linux_dbvec!=0) && 
+          ((*(short *)linux_dbvec) != -1)) {
+               printk("Booted under KADB. Syncing trap table.\n");
+               (*(linux_dbvec->teach_debugger))();
+       }
+       if((boot_flags & BOOTME_KGDB)) {
+               set_debug_traps();
+               prom_printf ("Breakpoint!\n");
+               breakpoint();
+       }
+#endif 
+
+       idprom_init();
+       load_mmu();
+       total = prom_probe_memory();
+       *memory_start_p = (((unsigned long) &end));
+
+       for(i=0; sp_banks[i].num_bytes != 0; i++) {
+               end_of_phys_memory = sp_banks[i].base_addr +
+                       sp_banks[i].num_bytes;
+               if (memory_size) {
+                       if (end_of_phys_memory > memory_size) {
+                               sp_banks[i].num_bytes -=
+                                       (end_of_phys_memory - memory_size);
+                               end_of_phys_memory = memory_size;
+                               sp_banks[++i].base_addr = 0xdeadbeef;
+                               sp_banks[i].num_bytes = 0;
+                       }
+               }
+       }
+       prom_setsync(prom_sync_me);
+
+       *memory_end_p = (end_of_phys_memory + KERNBASE);
+       if (!root_flags)
+               root_mountflags &= ~MS_RDONLY;
+       ROOT_DEV = to_kdev_t(root_dev);
+#ifdef CONFIG_BLK_DEV_RAM
+       rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
+       rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
+       rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);     
+#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (ramdisk_image) {
+               initrd_start = ramdisk_image;
+               if (initrd_start < KERNBASE) initrd_start += KERNBASE;
+               initrd_end = initrd_start + ramdisk_size;
+               if (initrd_end > *memory_end_p) {
+                       printk(KERN_CRIT "initrd extends beyond end of memory "
+                                        "(0x%016lx > 0x%016lx)\ndisabling initrd\n",
+                                        initrd_end,*memory_end_p);
+                       initrd_start = 0;
+               }
+               if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) {
+                       initrd_below_start_ok = 1;
+                       *memory_start_p = PAGE_ALIGN (initrd_end);
+               }
+       }
+#endif 
+
+       /* Due to stack alignment restrictions and assumptions... */
+#if 0  
+       init_task.mm->mmap->vm_page_prot = PAGE_SHARED;
+       init_task.mm->mmap->vm_start = KERNBASE;
+       init_task.mm->mmap->vm_end = *memory_end_p;
+       init_task.mm->context = (unsigned long) NO_CONTEXT;
+#endif 
+
+#ifdef CONFIG_SUN_SERIAL
+       *memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
+#endif
+       {
+               extern int serial_console;  /* in console.c, of course */
+#if !CONFIG_SUN_SERIAL
+               serial_console = 0;
+#else
+               switch (console_fb) {
+               case 0: /* Let get our io devices from prom */
+                       {
+                               int idev = prom_query_input_device();
+                               int odev = prom_query_output_device();
+                               if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
+                                       serial_console = 0;
+                               } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
+                                       serial_console = 1;
+                               } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
+                                       serial_console = 2;
+                               } else {
+                                       prom_printf("Inconsistent console\n");
+                                       prom_halt();
+                               }
+                       }
+                       break;
+               case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
+               case 2: serial_console = 1; break; /* Force ttya as console */
+               case 3: serial_console = 2; break; /* Force ttyb as console */
+               }
+#endif
+       }
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+       return -EIO;
+}
+
+/* BUFFER is PAGE_SIZE bytes long. */
+
+extern char *sparc_cpu_type[];
+extern char *sparc_fpu_type[];
+
+extern char *smp_info(void);
+extern char *mmu_info(void);
+
+int get_cpuinfo(char *buffer)
+{
+       int cpuid=get_cpuid();
+
+       return sprintf(buffer, "cpu\t\t: %s\n"
+            "fpu\t\t: %s\n"
+            "promlib\t\t: Version 3 Revision %d\n"
+            "prom\t\t: %d.%d.%d\n"
+            "type\t\t: sun4u\n"
+           "ncpus probed\t: %d\n"
+           "ncpus active\t: %d\n"
+#ifndef __SMP__
+            "BogoMips\t: %lu.%02lu\n"
+#else
+           "Cpu0Bogo\t: %lu.%02lu\n"
+           "Cpu1Bogo\t: %lu.%02lu\n"
+           "Cpu2Bogo\t: %lu.%02lu\n"
+           "Cpu3Bogo\t: %lu.%02lu\n"
+#endif
+           "%s"
+#ifdef __SMP__
+           "%s"
+#endif
+           ,
+            sparc_cpu_type[cpuid],
+            sparc_fpu_type[cpuid],
+            prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
+           linux_num_cpus, smp_num_cpus,
+#ifndef __SMP__
+            loops_per_sec/500000, (loops_per_sec/5000) % 100,
+#else
+           cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100,
+           cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100,
+           cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100,
+           cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100,
+#endif
+           mmu_info()
+#ifdef __SMP__
+           , smp_info()
+#endif
+            );
+
+}
index 8796f59c888302e0bddf1b41a5e69013c821ce10..4b791e86eb874ef22a8d39b2f64ab845d4a8740e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.1 1997/03/03 16:51:45 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.3 1997/03/18 17:59:10 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -74,24 +74,25 @@ EXPORT_SYMBOL(klock_info);
 #endif
 EXPORT_SYMBOL_PRIVATE(_lock_kernel);
 EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
-EXPORT_SYMBOL(page_offset);
-EXPORT_SYMBOL(stack_top);
 
 EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
+#if 0
 EXPORT_SYMBOL(io_remap_page_range);
-EXPORT_SYMBOL(mmu_v2p);
 EXPORT_SYMBOL(mmu_unlockarea);
 EXPORT_SYMBOL(mmu_lockarea);
 EXPORT_SYMBOL(mmu_get_scsi_sgl);
 EXPORT_SYMBOL(mmu_get_scsi_one);
 EXPORT_SYMBOL(mmu_release_scsi_sgl);
 EXPORT_SYMBOL(mmu_release_scsi_one);
+#endif
 EXPORT_SYMBOL(sparc_dvma_malloc);
+#if 0
 EXPORT_SYMBOL(sun4c_unmapioaddr);
 EXPORT_SYMBOL(srmmu_unmapioaddr);
+#endif
 #if CONFIG_SBUS
 EXPORT_SYMBOL(SBus_chain);
 EXPORT_SYMBOL(dma_chain);
@@ -119,14 +120,12 @@ EXPORT_SYMBOL(prom_getproperty);
 EXPORT_SYMBOL(prom_node_has_property);
 EXPORT_SYMBOL(prom_setprop);
 EXPORT_SYMBOL(prom_getbootargs);
-EXPORT_SYMBOL(prom_apply_obio_ranges);
 EXPORT_SYMBOL(prom_getname);
 EXPORT_SYMBOL(prom_feval);
 EXPORT_SYMBOL(prom_getstring);
 EXPORT_SYMBOL(prom_apply_sbus_ranges);
 EXPORT_SYMBOL(prom_getint);
 EXPORT_SYMBOL(prom_getintdefault);
-EXPORT_SYMBOL(romvec);
 EXPORT_SYMBOL(__prom_getchild);
 EXPORT_SYMBOL(__prom_getsibling);
 
@@ -176,4 +175,3 @@ EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL_NOVERS(__ashrdi3);
index ffc2715de2ddd89811a00baf28a9b218868e497d..cb21ef6d1443773ebbec164dac4ae2e9cb4038cb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.1 1996/12/28 18:39:36 davem Exp $
+/* $Id: systbls.S,v 1.2 1997/03/18 17:59:03 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
 
        /* First, the 32-bit Linux native syscall table. */
 
-       .globl C_LABEL(sys_call_table32)
-C_LABEL(sys_call_table32):
-/*0*/  .xword C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork)
-       .xword C_LABEL(sys_read), C_LABEL(sys_write)
-/*5*/  .xword C_LABEL(sys_open), C_LABEL(sys_close), C_LABEL(sys_wait4)
-       .xword C_LABEL(sys_creat), C_LABEL(sys_link)
-/*10*/  .xword C_LABEL(sys_unlink), C_LABEL(sunos_execv), C_LABEL(sys_chdir)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_mknod)
-/*15*/ .xword C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sparc_brk)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_lseek)
-/*20*/ .xword C_LABEL(sys_getpid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_setuid), C_LABEL(sys_getuid)
-/*25*/ .xword C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_pause)
-/*30*/ .xword C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty)
-       .xword C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime)
-       .xword C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
-       .xword C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
-       .xword C_LABEL(sys_signal), C_LABEL(sys_geteuid)
-/*50*/ .xword C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
-       .xword C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
-       .xword C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap)
-       .xword C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups)
-       .xword C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_setitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_swapon)
-       .xword C_LABEL(sys_getitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_sethostname)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_dup2), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/        .xword C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_readv)
-       .xword C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
-       .xword C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid)
-       .xword C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
-       .xword C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
-       .xword C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*150*/        .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
-       .xword C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_setdomainname)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid)
-       .xword C_LABEL(sys_fchdir), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_sigpending), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
-       .xword C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
-       .xword C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
-       .xword C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
-/*200*/        .xword C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
-       .xword C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
-       .xword C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask)
-       .xword C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
-       .xword C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
-       .xword C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid)
-       .xword C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
-       /* "We are the Knights of the Forest of Ni!!" */
-       .xword C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall)
-       .xword C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam)
-       .xword C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min)
-       .xword C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep)
-/*250*/        .xword C_LABEL(sys_mremap)
-       .xword C_LABEL(sys_sysctl)
-       .xword C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall)
+       .globl sys_call_table32
+sys_call_table32:
+/*0*/  .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/  .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/  .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+       .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+       .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+       .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+       .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+       .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+       .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+       .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/        .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/        .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+       .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/        .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+       .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+       .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+       .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_nis_syscall
+       .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/        .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+       .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/        .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
+       .xword sys_nis_syscall, sys_socketcall, sys_syslog, sys_olduname, sys_nis_syscall
+/*210*/        .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+       .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/        .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+       .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/        .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+       .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/        .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/        .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
+       .xword sys_aplib, sys_nis_syscall
 
        /* Now the 64-bit native Linux syscall table. */
 
-       .globl C_LABEL(sys_call_table64)
-C_LABEL(sys_call_table64):
-/*0*/  .xword C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork)
-       .xword C_LABEL(sys_read), C_LABEL(sys_write)
-/*5*/  .xword C_LABEL(sys_open), C_LABEL(sys_close), C_LABEL(sys_wait4)
-       .xword C_LABEL(sys_creat), C_LABEL(sys_link)
-/*10*/  .xword C_LABEL(sys_unlink), C_LABEL(sunos_execv), C_LABEL(sys_chdir)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_mknod)
-/*15*/ .xword C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sparc_brk)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_lseek)
-/*20*/ .xword C_LABEL(sys_getpid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_setuid), C_LABEL(sys_getuid)
-/*25*/ .xword C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_pause)
-/*30*/ .xword C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty)
-       .xword C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime)
-       .xword C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
-       .xword C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_profil)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
-       .xword C_LABEL(sys_signal), C_LABEL(sys_geteuid)
-/*50*/ .xword C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
-       .xword C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
-       .xword C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_vfork), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap)
-       .xword C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups)
-       .xword C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_setitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_swapon)
-       .xword C_LABEL(sys_getitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_sethostname)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_dup2), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/        .xword C_LABEL(sys_getpriority), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_readv)
-       .xword C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
-       .xword C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid)
-       .xword C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
-       .xword C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
-       .xword C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*150*/        .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
-       .xword C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_setdomainname)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid)
-       .xword C_LABEL(sys_fchdir), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_sigpending), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
-       .xword C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
-       .xword C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
-       .xword C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
-/*200*/        .xword C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
-       .xword C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
-       .xword C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask)
-       .xword C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
-       .xword C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
-       .xword C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid)
-       .xword C_LABEL(sys_setfsgid), C_LABEL(sys_llseek), C_LABEL(sys_time)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
-       /* "We are the Knights of the Forest of Ni!!" */
-       .xword C_LABEL(sys_mlock), C_LABEL(sys_munlock), C_LABEL(sys_mlockall)
-       .xword C_LABEL(sys_munlockall), C_LABEL(sys_sched_setparam)
-       .xword C_LABEL(sys_sched_getparam), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_sched_get_priority_max), C_LABEL(sys_sched_get_priority_min)
-       .xword C_LABEL(sys_sched_rr_get_interval), C_LABEL(sys_nanosleep)
-/*250*/        .xword C_LABEL(sys_mremap)
-       .xword C_LABEL(sys_sysctl)
-       .xword C_LABEL(sys_getsid), C_LABEL(sys_fdatasync), C_LABEL(sys_nis_syscall)
-       .xword C_LABEL(sys_aplib), C_LABEL(sys_nis_syscall)
+       .globl sys_call_table64
+sys_call_table64:
+/*0*/  .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/  .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/  .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+       .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+       .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+       .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+       .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+       .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+       .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+       .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/        .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/        .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+       .xword sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/        .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+       .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+       .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+       .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/        .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_nis_syscall
+       .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/        .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+       .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/        .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
+       .xword sys_nis_syscall, sys_socketcall, sys_syslog, sys_olduname, sys_nis_syscall
+/*210*/        .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+       .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/        .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+       .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/        .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+       .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/        .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+       .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/        .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
+       .xword sys_aplib, sys_nis_syscall
 
        /* Now the 32-bit SunOS syscall table. */
 
        .align 4
-       .globl C_LABEL(sunos_sys_table)
-C_LABEL(sunos_sys_table):
-/*0*/  .xword C_LABEL(sunos_indir), C_LABEL(sys_exit), C_LABEL(sys_fork)
-       .xword C_LABEL(sunos_read), C_LABEL(sunos_write), C_LABEL(sunos_open)
-       .xword C_LABEL(sys_close), C_LABEL(sunos_wait4), C_LABEL(sys_creat)
-       .xword C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv)
-       .xword C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod)
-       .xword C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
-       .xword C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*50*/ .xword C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_mctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
-       .xword C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
-       .xword C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), C_LABEL(sys_getpagesize)
-       .xword C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_sbrk), C_LABEL(sunos_sstk)
-       .xword C_LABEL(sunos_mmap), C_LABEL(sunos_vadvise), C_LABEL(sys_munmap)
-       .xword C_LABEL(sys_mprotect), C_LABEL(sunos_madvise), C_LABEL(sys_vhangup)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_mincore), C_LABEL(sys_getgroups)
-       .xword C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sunos_setpgrp)
-       .xword C_LABEL(sys_setitimer), C_LABEL(sunos_nosys), C_LABEL(sys_swapon)
-       .xword C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname)
-       .xword C_LABEL(sunos_getdtablesize), C_LABEL(sys_dup2), C_LABEL(sunos_nop)
-       .xword C_LABEL(sys_fcntl), C_LABEL(sunos_select), C_LABEL(sunos_nop)
-       .xword C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_socket)
-       .xword C_LABEL(sys_connect), C_LABEL(sunos_accept)
-/*100*/        .xword C_LABEL(sys_getpriority), C_LABEL(sunos_send), C_LABEL(sunos_recv)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sunos_setsockopt)
-       .xword C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sunos_sigaction)
-       .xword C_LABEL(sunos_sigblock), C_LABEL(sunos_sigsetmask), C_LABEL(sys_sigpause)
-       .xword C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
-       .xword C_LABEL(sunos_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sunos_readv)
-       .xword C_LABEL(sunos_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
-       .xword C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid)
-       .xword C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
-       .xword C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sys_sendto), C_LABEL(sys_shutdown), C_LABEL(sys_socketpair)
-       .xword C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
-       .xword C_LABEL(sys_sigreturn), C_LABEL(sunos_nosys), C_LABEL(sys_getpeername)
-       .xword C_LABEL(sunos_gethostid), C_LABEL(sunos_nosys), C_LABEL(sys_getrlimit)
-       .xword C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*150*/        .xword C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
-       .xword C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
-       .xword C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sys_sigpending), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sys_setpgid), C_LABEL(sunos_pathconf), C_LABEL(sunos_fpathconf)
-       .xword C_LABEL(sunos_sysconf), C_LABEL(sunos_uname), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*200*/        .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*250*/        .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .xword C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib)
+       .globl sunos_sys_table
+sunos_sys_table:
+/*0*/  .xword sunos_indir, sys_exit, sys_fork
+       .xword sunos_read, sunos_write, sunos_open
+       .xword sys_close, sunos_wait4, sys_creat
+       .xword sys_link, sys_unlink, sunos_execv
+       .xword sys_chdir, sunos_nosys, sys_mknod
+       .xword sys_chmod, sys_chown, sunos_brk
+       .xword sunos_nosys, sys_lseek, sunos_getpid
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_getuid, sunos_nosys, sys_ptrace
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sys_access, sunos_nosys, sunos_nosys
+       .xword sys_sync, sys_kill, sys_newstat
+       .xword sunos_nosys, sys_newlstat, sys_dup
+       .xword sys_pipe, sunos_nosys, sys_profil
+       .xword sunos_nosys, sunos_nosys, sunos_getgid
+       .xword sunos_nosys, sunos_nosys
+/*50*/ .xword sunos_nosys, sys_acct, sunos_nosys
+       .xword sunos_mctl, sunos_ioctl, sys_reboot
+       .xword sunos_nosys, sys_symlink, sys_readlink
+       .xword sys_execve, sys_umask, sys_chroot
+       .xword sys_newfstat, sunos_nosys, sys_getpagesize
+       .xword sys_msync, sys_vfork, sunos_nosys
+       .xword sunos_nosys, sunos_sbrk, sunos_sstk
+       .xword sunos_mmap, sunos_vadvise, sys_munmap
+       .xword sys_mprotect, sunos_madvise, sys_vhangup
+       .xword sunos_nosys, sunos_mincore, sys_getgroups
+       .xword sys_setgroups, sys_getpgrp, sunos_setpgrp
+       .xword sys_setitimer, sunos_nosys, sys_swapon
+       .xword sys_getitimer, sys_gethostname, sys_sethostname
+       .xword sunos_getdtablesize, sys_dup2, sunos_nop
+       .xword sys_fcntl, sunos_select, sunos_nop
+       .xword sys_fsync, sys_setpriority, sys_socket
+       .xword sys_connect, sunos_accept
+/*100*/        .xword sys_getpriority, sunos_send, sunos_recv
+       .xword sunos_nosys, sys_bind, sunos_setsockopt
+       .xword sys_listen, sunos_nosys, sunos_sigaction
+       .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
+       .xword sys_sigstack, sys_recvmsg, sys_sendmsg
+       .xword sunos_nosys, sys_gettimeofday, sys_getrusage
+       .xword sunos_getsockopt, sunos_nosys, sunos_readv
+       .xword sunos_writev, sys_settimeofday, sys_fchown
+       .xword sys_fchmod, sys_recvfrom, sys_setreuid
+       .xword sys_setregid, sys_rename, sys_truncate
+       .xword sys_ftruncate, sys_flock, sunos_nosys
+       .xword sys_sendto, sys_shutdown, sys_socketpair
+       .xword sys_mkdir, sys_rmdir, sys_utimes
+       .xword sys_sigreturn, sunos_nosys, sys_getpeername
+       .xword sunos_gethostid, sunos_nosys, sys_getrlimit
+       .xword sys_setrlimit, sunos_killpg, sunos_nosys
+       .xword sunos_nosys, sunos_nosys
+/*150*/        .xword sys_getsockname, sunos_nosys, sunos_nosys
+       .xword sunos_poll, sunos_nosys, sunos_nosys
+       .xword sunos_getdirentries, sys_statfs, sys_fstatfs
+       .xword sys_umount, sunos_nosys, sunos_nosys
+       .xword sunos_getdomainname, sys_setdomainname
+       .xword sunos_nosys, sys_quotactl, sunos_nosys
+       .xword sunos_mount, sys_ustat, sunos_semsys
+       .xword sunos_nosys, sunos_shmsys, sunos_audit
+       .xword sunos_nosys, sunos_getdents, sys_setsid
+       .xword sys_fchdir, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sys_sigpending, sunos_nosys
+       .xword sys_setpgid, sunos_pathconf, sunos_fpathconf
+       .xword sunos_sysconf, sunos_uname, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/        .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys
+/*250*/        .xword sunos_nosys, sunos_nosys, sunos_nosys
+       .xword sunos_nosys, sunos_nosys, sys_aplib
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
new file mode 100644 (file)
index 0000000..402e8d8
--- /dev/null
@@ -0,0 +1,138 @@
+/* $Id: traps.c,v 1.1 1997/03/18 17:59:12 jj Exp $
+ * arch/sparc/kernel/traps.c
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/*
+ * I hate traps on the sparc, grrr...
+ */
+
+#include <linux/sched.h>  /* for jiffies */
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/delay.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/oplib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/unistd.h>
+
+/* #define TRAP_DEBUG */
+
+struct trap_trace_entry {
+       unsigned long pc;
+       unsigned long type;
+};
+
+int trap_curbuf = 0;
+struct trap_trace_entry trapbuf[1024];
+
+void syscall_trace_entry(struct pt_regs *regs)
+{
+       printk("%s[%d]: ", current->comm, current->pid);
+       printk("scall<%ld> (could be %ld)\n", (long) regs->u_regs[UREG_G1],
+              (long) regs->u_regs[UREG_I0]);
+}
+
+void syscall_trace_exit(struct pt_regs *regs)
+{
+}
+
+void instruction_dump (unsigned int *pc)
+{
+       int i;
+       
+       if((((unsigned long) pc) & 3))
+                return;
+
+       for(i = -3; i < 6; i++)
+               printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
+       printk("\n");
+}
+
+void die_if_kernel(char *str, struct pt_regs *regs)
+{
+       /* Amuse the user. */
+       printk(
+"              \\|/ ____ \\|/\n"
+"              \"@'/ .` \\`@\"\n"
+"              /_| \\__/ |_\\\n"
+"                 \\__U_/\n");
+
+       printk("%s(%d): %s\n", current->comm, current->pid, str);
+       show_regs(regs);
+       printk("Instruction DUMP:");
+       instruction_dump ((unsigned int *) regs->tpc);
+       if(regs->tstate & TSTATE_PRIV)
+               do_exit(SIGKILL);
+       do_exit(SIGSEGV);
+}
+
+void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                           unsigned long tstate)
+{
+       lock_kernel();
+       if(tstate & TSTATE_PRIV)
+               die_if_kernel("Kernel illegal instruction", regs);
+#ifdef TRAP_DEBUG
+       printk("Ill instr. at pc=%016lx instruction is %08x\n",
+              regs->tpc, *(unsigned int *)regs->tpc);
+#endif
+       current->tss.sig_address = pc;
+       current->tss.sig_desc = SUBSIG_ILLINST;
+       send_sig(SIGILL, current, 1);
+       unlock_kernel();
+}
+
+void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                        unsigned long tstate)
+{
+       lock_kernel();
+       if(tstate & TSTATE_PRIV)
+               die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
+       current->tss.sig_address = pc;
+       current->tss.sig_desc = SUBSIG_PRIVINST;
+       send_sig(SIGILL, current, 1);
+       unlock_kernel();
+}
+
+/* XXX User may want to be allowed to do this. XXX */
+
+void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                           unsigned long tstate)
+{
+       lock_kernel();
+       if(regs->tstate & TSTATE_PRIV) {
+               printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
+                      regs->u_regs[UREG_RETPC]);
+               die_if_kernel("BOGUS", regs);
+               /* die_if_kernel("Kernel MNA access", regs); */
+       }
+       current->tss.sig_address = pc;
+       current->tss.sig_desc = SUBSIG_PRIVINST;
+#if 0
+       show_regs (regs);
+       instruction_dump ((unsigned long *) regs->tpc);
+       printk ("do_MNA!\n");
+#endif
+       send_sig(SIGBUS, current, 1);
+       unlock_kernel();
+}
+
+void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
+                      unsigned long psr)
+{
+       lock_kernel();
+       send_sig(SIGILL, current, 1);
+       unlock_kernel();
+}
+
+void trap_init(void)
+{
+}
index 1b92ac161152eec59aedb12918502b5935e8fb6d..40421953ff11cc3b8e46c77943fbc8f658ff49ee 100644 (file)
@@ -1,10 +1,11 @@
-# $Id: Makefile,v 1.1 1996/12/27 17:28:35 davem Exp $
+# $Id: Makefile,v 1.5 1997/03/14 21:04:27 jj Exp $
 # Makefile for Sparc library files..
 #
 
 CFLAGS := $(CFLAGS) -ansi
 
-OBJS  = memset.o blockops.o
+OBJS  = memset.o blockops.o locks.o memcpy.o strlen.o strncmp.o \
+       memscan.o strncpy_from_user.o strlen_user.o memcmp.o
 
 lib.a: $(OBJS)
        $(AR) rcs lib.a $(OBJS)
@@ -16,6 +17,30 @@ blockops.o: blockops.S
 memset.o: memset.S
        $(CC) -D__ASSEMBLY__ -ansi -c -o memset.o memset.S
 
+memcpy.o: memcpy.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o memcpy.o memcpy.S
+
+strlen.o: strlen.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o strlen.o strlen.S
+
+strncmp.o: strncmp.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o strncmp.o strncmp.S
+
+memcmp.o: memcmp.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o memcmp.o memcmp.S
+
+locks.o: locks.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o locks.o locks.S
+
+memscan.o: memscan.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o memscan.o memscan.S
+
+strncpy_from_user.o: strncpy_from_user.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o strncpy_from_user.o strncpy_from_user.S
+
+strlen_user.o: strlen_user.S
+       $(CC) -D__ASSEMBLY__ -ansi -c -o strlen_user.o strlen_user.S
+
 dep:
 
 include $(TOPDIR)/Rules.make
diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S
new file mode 100644 (file)
index 0000000..2940463
--- /dev/null
@@ -0,0 +1,567 @@
+/* checksum.S: Sparc V9 optimized checksum code.
+ *
+ *  Copyright(C) 1995 Linus Torvalds
+ *  Copyright(C) 1995 Miguel de Icaza
+ *  Copyright(C) 1996 David S. Miller
+ *  Copyright(C) 1997 Jakub Jelinek
+ *
+ * derived from:
+ *     Linux/Alpha checksum c-code
+ *      Linux/ix86 inline checksum assembly
+ *      RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ *     David Mosberger-Tang for optimized reference c-code
+ *     BSD4.4 portable checksum routine
+ */
+
+#include <asm/errno.h>
+#include <asm/head.h>
+
+#define CSUM_BIGCHUNK(buf, offset, sum, t0, t1, t2, t3, t4, t5)        \
+       ldd     [buf + offset + 0x00], t0;                      \
+       ldd     [buf + offset + 0x08], t2;                      \
+       addccc  t0, sum, sum;                                   \
+       addccc  t1, sum, sum;                                   \
+       ldd     [buf + offset + 0x10], t4;                      \
+       addccc  t2, sum, sum;                                   \
+       addccc  t3, sum, sum;                                   \
+       ldd     [buf + offset + 0x18], t0;                      \
+       addccc  t4, sum, sum;                                   \
+       addccc  t5, sum, sum;                                   \
+       addccc  t0, sum, sum;                                   \
+       addccc  t1, sum, sum;
+
+#define CSUM_LASTCHUNK(buf, offset, sum, t0, t1, t2, t3)       \
+       ldd     [buf - offset - 0x08], t0;                      \
+       ldd     [buf - offset - 0x00], t2;                      \
+       addccc  t0, sum, sum;                                   \
+       addccc  t1, sum, sum;                                   \
+       addccc  t2, sum, sum;                                   \
+       addccc  t3, sum, sum;
+
+       /* Do end cruft out of band to get better cache patterns. */
+csum_partial_end_cruft:
+       andcc   %o1, 8, %g0                     ! check how much
+       be,pn   %icc, 1f                        ! caller asks %o1 & 0x8
+        and    %o1, 4, %g3                     ! nope, check for word remaining
+       ldd     [%o0], %g2                      ! load two
+       addcc   %g2, %o2, %o2                   ! add first word to sum
+       addccc  %g3, %o2, %o2                   ! add second word as well
+       add     %o0, 8, %o0                     ! advance buf ptr
+       addc    %g0, %o2, %o2                   ! add in final carry
+1:     brz,pn  %g3, 1f                         ! nope, skip this code
+        andcc  %o1, 3, %o1                     ! check for trailing bytes
+       ld      [%o0], %g2                      ! load it
+       addcc   %g2, %o2, %o2                   ! add to sum
+       add     %o0, 4, %o0                     ! advance buf ptr
+       addc    %g0, %o2, %o2                   ! add in final carry
+1:     brz,pn  %o1, 1f                         ! no trailing bytes, return
+        addcc  %o1, -1, %g0                    ! only one byte remains?
+       bne,pn  %icc, 2f                        ! at least two bytes more
+        subcc  %o1, 2, %o1                     ! only two bytes more?
+       ba,pt   %xcc, 4f                        ! only one byte remains
+        clr    %o4                             ! clear fake hword value
+2:     lduh    [%o0], %o4                      ! get hword
+       be,pn   %icc, 6f                        ! jmp if only hword remains
+        add    %o0, 2, %o0                     ! advance buf ptr either way
+       sll     %o4, 16, %o4                    ! create upper hword
+4:     ldub    [%o0], %o5                      ! get final byte
+       sll     %o5, 8, %o5                     ! put into place
+       or      %o5, %o4, %o4                   ! coalese with hword (if any)
+6:     addcc   %o4, %o2, %o2                   ! add to sum
+1:     sllx    %g4, 32, %g4                    ! give gfp back
+       retl                                    ! get outta here
+        addc   %g0, %o2, %o0                   ! add final carry into retval
+
+       /* Also do alignment out of band to get better cache patterns. */
+csum_partial_fix_alignment:
+
+       /* The common case is to get called with a nicely aligned
+        * buffer of size 0x20.  Follow the code path for that case.
+        */
+       .globl  C_LABEL(csum_partial)
+C_LABEL(csum_partial):                 /* %o0=buf, %o1=len, %o2=sum */
+       andcc   %o0, 0x7, %g0                           ! alignment problems?
+       be,pt   %icc, csum_partial_fix_aligned          ! yep, handle it
+        andn   %o1, 0x7f, %o3                          ! num loop iterations
+       cmp     %o1, 6
+       bl,pn   %icc, cpte - 0x4
+        andcc  %o0, 0x2, %g0
+       be,pn   %icc, 1f
+        and    %o0, 0x4, %g7
+       lduh    [%o0 + 0x00], %g2
+       sub     %o1, 2, %o1
+       add     %o0, 2, %o0
+       sll     %g2, 16, %g2
+       addcc   %g2, %o2, %o2
+       srl     %o2, 16, %g3
+       addc    %g0, %g3, %g2
+       sll     %o2, 16, %o2
+       sll     %g2, 16, %g3
+       srl     %o2, 16, %o2
+       or      %g3, %o2, %o2
+1:     brz,pn  %g7, csum_partial_fix_aligned
+        nop
+       ld      [%o0 + 0x00], %g2
+       sub     %o1, 4, %o1
+       addcc   %g2, %o2, %o2
+       add     %o0, 4, %o0
+       addc    %g0, %o2, %o2
+csum_partial_fix_aligned:
+       brz,pt  %o3, 3f                                 ! none to do
+        andcc  %o1, 0x70, %g1                          ! clears carry flag too
+5:     CSUM_BIGCHUNK(%o0, 0x00, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+       CSUM_BIGCHUNK(%o0, 0x20, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+       CSUM_BIGCHUNK(%o0, 0x40, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+       CSUM_BIGCHUNK(%o0, 0x60, %o2, %o4, %o5, %g2, %g3, %g4, %g5)
+       sub     %o3, 128, %o3                           ! detract from loop iters
+       addc    %g0, %o2, %o2                           ! sink in final carry
+       brnz,pt %o3, 5b                                 ! more to do
+        add    %o0, 128, %o0                           ! advance buf ptr
+3:     brz,pn  %g1, cpte                               ! nope
+        andcc  %o1, 0xf, %o3                           ! anything left at all?
+10:    rd      %pc, %g7                                ! get pc
+       srl     %g1, 1, %o4                             ! compute offset
+       sub     %g7, %g1, %g7                           ! adjust jmp ptr
+       sub     %g7, %o4, %g7                           ! final jmp ptr adjust
+       jmp     %g7 + (cpte - 8 - 10b)                  ! enter the table
+        add    %o0, %g1, %o0                           ! advance buf ptr
+cptbl: CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3, %g4, %g5)
+       CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3, %g4, %g5)
+       CSUM_LASTCHUNK(%o0, 0x48, %o2, %g2, %g3, %g4, %g5)
+       CSUM_LASTCHUNK(%o0, 0x38, %o2, %g2, %g3, %g4, %g5)
+       CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3, %g4, %g5)
+       CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3, %g4, %g5)
+       CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3, %g4, %g5)
+       addc    %g0, %o2, %o2                           ! fetch final carry
+       andcc   %o1, 0xf, %g0                           ! anything left at all?
+cpte:  brnz,pn %o3, csum_partial_end_cruft             ! yep, handle it
+        sethi  %uhi(KERNBASE), %g4
+       mov     %o2, %o0                                ! return computed csum
+       retl                                            ! get outta here
+        sllx   %g4, 32, %g4                            ! give gfp back
+
+       .globl C_LABEL(__csum_partial_copy_start), C_LABEL(__csum_partial_copy_end)
+C_LABEL(__csum_partial_copy_start):
+
+#define EX(x,y,a,b,z)                           \
+98:     x,y;                                    \
+        .section .fixup,z##alloc,z##execinstr;  \
+        .align  4;                              \
+99:     ba,pt %xcc, 30f;                        \
+         a, b, %o3;                             \
+        .section __ex_table,z##alloc;           \
+        .align  4;                              \
+        .word   98b, 99b;                       \
+        .text;                                  \
+        .align  4
+
+#define EX2(x,y,z)                             \
+98:     x,y;                                    \
+        .section __ex_table,z##alloc;           \
+        .align  4;                              \
+        .word   98b, 30f;                       \
+        .text;                                  \
+        .align  4
+
+#define EX3(x,y,z)                             \
+98:     x,y;                                    \
+        .section __ex_table,z##alloc;           \
+        .align  4;                              \
+        .word   98b, 96f;                       \
+        .text;                                  \
+        .align  4
+
+#define EXT(start,end,handler,z)                \
+        .section __ex_table,z##alloc;           \
+        .align  4;                              \
+        .word   start, 0, end, handler;         \
+        .text;                                  \
+        .align  4
+
+       /* This aligned version executes typically in 8.5 superscalar cycles, this
+        * is the best I can do.  I say 8.5 because the final add will pair with
+        * the next ldd in the main unrolled loop.  Thus the pipe is always full.
+        * If you change these macros (including order of instructions),
+        * please check the fixup code below as well.
+        */
+#define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)  \
+       ldd     [src + off + 0x00], t0;                                                 \
+       ldd     [src + off + 0x08], t2;                                                 \
+       addccc  t0, sum, sum;                                                           \
+       ldd     [src + off + 0x10], t4;                                                 \
+       addccc  t1, sum, sum;                                                           \
+       ldd     [src + off + 0x18], t6;                                                 \
+       addccc  t2, sum, sum;                                                           \
+       std     t0, [dst + off + 0x00];                                                 \
+       addccc  t3, sum, sum;                                                           \
+       std     t2, [dst + off + 0x08];                                                 \
+       addccc  t4, sum, sum;                                                           \
+       std     t4, [dst + off + 0x10];                                                 \
+       addccc  t5, sum, sum;                                                           \
+       std     t6, [dst + off + 0x18];                                                 \
+       addccc  t6, sum, sum;                                                           \
+       addccc  t7, sum, sum;
+
+       /* 12 superscalar cycles seems to be the limit for this case,
+        * because of this we thus do all the ldd's together to get
+        * Viking MXCC into streaming mode.  Ho hum...
+        */
+#define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)  \
+       ldd     [src + off + 0x00], t0;                                         \
+       ldd     [src + off + 0x08], t2;                                         \
+       ldd     [src + off + 0x10], t4;                                         \
+       ldd     [src + off + 0x18], t6;                                         \
+       st      t0, [dst + off + 0x00];                                         \
+       addccc  t0, sum, sum;                                                   \
+       st      t1, [dst + off + 0x04];                                         \
+       addccc  t1, sum, sum;                                                   \
+       st      t2, [dst + off + 0x08];                                         \
+       addccc  t2, sum, sum;                                                   \
+       st      t3, [dst + off + 0x0c];                                         \
+       addccc  t3, sum, sum;                                                   \
+       st      t4, [dst + off + 0x10];                                         \
+       addccc  t4, sum, sum;                                                   \
+       st      t5, [dst + off + 0x14];                                         \
+       addccc  t5, sum, sum;                                                   \
+       st      t6, [dst + off + 0x18];                                         \
+       addccc  t6, sum, sum;                                                   \
+       st      t7, [dst + off + 0x1c];                                         \
+       addccc  t7, sum, sum;
+
+       /* Yuck, 6 superscalar cycles... */
+#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3) \
+       ldd     [src - off - 0x08], t0;                         \
+       ldd     [src - off - 0x00], t2;                         \
+       addccc  t0, sum, sum;                                   \
+       st      t0, [dst - off - 0x08];                         \
+       addccc  t1, sum, sum;                                   \
+       st      t1, [dst - off - 0x04];                         \
+       addccc  t2, sum, sum;                                   \
+       st      t2, [dst - off - 0x00];                         \
+       addccc  t3, sum, sum;                                   \
+       st      t3, [dst - off + 0x04];
+
+       /* Handle the end cruft code out of band for better cache patterns. */
+cc_end_cruft:
+       andcc   %o3, 8, %g0             ! begin checks for that code
+       be,pn   %icc, 1f
+        and    %o3, 4, %g5
+       EX(ldd  [%o0 + 0x00], %g2, and %o3, 0xf,#)
+       add     %o1, 8, %o1
+       addcc   %g2, %g7, %g7
+       add     %o0, 8, %o0
+       addccc  %g3, %g7, %g7
+       EX2(st  %g2, [%o1 - 0x08],#)
+       addc    %g0, %g7, %g7
+       EX2(st  %g3, [%o1 - 0x04],#)
+1:     brz,pt  %g5, 1f
+        andcc  %o3, 3, %o3
+       EX(ld   [%o0 + 0x00], %g2, add %o3, 4,#)
+       add     %o1, 4, %o1
+       addcc   %g2, %g7, %g7
+       EX2(st  %g2, [%o1 - 0x04],#)
+       addc    %g0, %g7, %g7
+       add     %o0, 4, %o0
+1:     brz,pn  %o3, 1f
+        addcc  %o3, -1, %g0
+       bne,pn  %icc, 2f
+        subcc  %o3, 2, %o3
+       ba,pt   %xcc, 4f
+        clr    %o4
+2:     EX(lduh [%o0 + 0x00], %o4, add %o3, 2,#)
+       add     %o0, 2, %o0
+       EX2(sth %o4, [%o1 + 0x00],#)
+       be,pn   %icc, 6f
+        add    %o1, 2, %o1
+       sll     %o4, 16, %o4
+4:     EX(ldub [%o0 + 0x00], %o5, add %g0, 1,#)
+       EX2(stb %o5, [%o1 + 0x00],#)
+       sll     %o5, 8, %o5
+       or      %o5, %o4, %o4
+6:     addcc   %o4, %g7, %g7
+1:     sllx    %g4, 32, %g4
+       retl
+        addc   %g0, %g7, %o0
+
+       /* Sun, you just can't beat me, you just can't.  Stop trying,
+        * give up.  I'm serious, I am going to kick the living shit
+        * out of you, game over, lights out.
+        */
+       .align  8
+       .globl  C_LABEL(__csum_partial_copy_sparc_generic)
+C_LABEL(__csum_partial_copy_sparc_generic):
+                                       /* %o0=src, %o1=dest, %g1=len, %g7=sum */
+       xor     %o0, %o1, %o4           ! get changing bits
+       andcc   %o4, 3, %g0             ! check for mismatched alignment
+       bne,pn  %icc, ccslow            ! better this than unaligned/fixups
+        andcc  %o0, 7, %g0             ! need to align things?
+       be,pt   %icc, cc_dword_aligned  ! yes, we check for short lengths there
+        andn   %g1, 0x7f, %g2          ! can we use unrolled loop?
+       cmp     %g1, 6
+       bl,a,pn %icc, ccte
+        andcc  %g1, 0xf, %o3
+       andcc   %o0, 0x1, %g0
+       bne,pn  %icc, ccslow
+        andcc  %o0, 0x2, %g0
+       be,pn   %icc, 1f
+        andcc  %o0, 0x4, %g0
+       EX(lduh [%o0 + 0x00], %g4, add %g1, 0,#)
+       sub     %g1, 2, %g1
+       EX2(sth %g4, [%o1 + 0x00],#)
+       add     %o0, 2, %o0
+       sll     %g4, 16, %g4
+       addcc   %g4, %g7, %g7
+       add     %o1, 2, %o1
+       srl     %g7, 16, %g3
+       addc    %g0, %g3, %g4
+       sll     %g7, 16, %g7
+       sll     %g4, 16, %g3
+       srl     %g7, 16, %g7
+       andcc   %o0, 0x4, %g0
+       or      %g3, %g7, %g7
+1:     be,pt   %icc, 3f
+        andn   %g1, 0x7f, %g0
+       EX(ld   [%o0 + 0x00], %g4, add %g1, 0,#)
+       sub     %g1, 4, %g1
+       EX2(st  %g4, [%o1 + 0x00],#)
+       add     %o0, 4, %o0
+       addcc   %g4, %g7, %g7
+       add     %o1, 4, %o1
+       addc    %g0, %g7, %g7
+cc_dword_aligned:
+3:     brz,pn  %g2, 3f                 ! nope, less than one loop remains
+        andcc  %o1, 4, %g0             ! dest aligned on 4 or 8 byte boundry?
+       be,pn   %icc, ccdbl + 4         ! 8 byte aligned, kick ass
+5:     CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+       CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+       CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+       CSUMCOPY_BIGCHUNK(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+10:    EXT(5b, 10b, 20f,#)             ! note for exception handling
+       sub     %g1, 128, %g1           ! detract from length
+       addc    %g0, %g7, %g7           ! add in last carry bit
+       andncc  %g1, 0x7f, %g0          ! more to csum?
+       add     %o0, 128, %o0           ! advance src ptr
+       bne,pt  %icc, 5b                ! we did not go negative, continue looping
+        add    %o1, 128, %o1           ! advance dest ptr
+3:     andcc   %g1, 0x70, %o2          ! can use table?
+ccmerge:be,pn  %icc, ccte              ! nope, go and check for end cruft
+        andcc  %g1, 0xf, %o3           ! get low bits of length (clears carry btw)
+       srl     %o2, 1, %o4             ! begin negative offset computation
+13:    rd      %pc, %o5                ! set up table ptr end
+       add     %o0, %o2, %o0           ! advance src ptr
+       sub     %o5, %o4, %o5           ! continue table calculation
+       sll     %o2, 1, %g2             ! constant multiplies are fun...
+       sub     %o5, %g2, %o5           ! some more adjustments
+       jmpl    %o5 + (12f-13b), %g0    ! jump into it, duff style, wheee...
+        add    %o1, %o2, %o1           ! advance dest ptr (carry is clear btw)
+cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3,%g4,%g5)
+       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3,%g4,%g5)
+       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3,%g4,%g5)
+       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3,%g4,%g5)
+       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3,%g4,%g5)
+       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3,%g4,%g5)
+       CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3,%g4,%g5)
+12:    EXT(cctbl, 12b, 22f,#)          ! note for exception table handling
+       addc    %g0, %g7, %g7
+       andcc   %o3, 0xf, %g0           ! check for low bits set
+ccte:  bne,pn  %icc, cc_end_cruft      ! something left, handle it out of band
+        sethi  %uhi(KERNBASE), %g4     ! restore gfp
+       mov     %g7, %o0                ! give em the computed checksum
+       retl                            ! return
+        sllx   %g4, 32, %g4            ! finish gfp restoration
+ccdbl: CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+       CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+       CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+       CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x60,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+11:    EXT(ccdbl, 11b, 21f,#)          ! note for exception table handling
+       sub     %g1, 128, %g1           ! detract from length
+       addc    %g0, %g7, %g7           ! add in last carry bit
+       andncc  %g1, 0x7f, %g0          ! more to csum?
+       add     %o0, 128, %o0           ! advance src ptr
+       bne,pt  %icc, ccdbl             ! we did not go negative, continue looping
+        add    %o1, 128, %o1           ! advance dest ptr
+       ba,pt   %xcc, ccmerge           ! finish it off, above
+        andcc  %g1, 0x70, %o2          ! can use table? (clears carry btw)
+
+ccslow:        mov     0, %g5
+       brlez,pn %g1, 4f
+        andcc  %o0, 1, %o5             
+       be,a,pt %icc, 1f
+        srl    %g1, 1, %o3             
+       sub     %g1, 1, %g1     
+       EX(ldub [%o0], %g5, add %g1, 1,#)
+       add     %o0, 1, %o0     
+       EX2(stb %g5, [%o1],#)
+       srl     %g1, 1, %o3
+       add     %o1, 1, %o1
+1:     brz,a,pn %o3, 3f
+        andcc  %g1, 1, %g0
+       andcc   %o0, 2, %g0     
+       be,a,pt %icc, 1f
+        srl    %o3, 1, %o3
+       EX(lduh [%o0], %o4, add %g1, 0,#)
+       sub     %g1, 2, %g1     
+       srl     %o4, 8, %g2
+       sub     %o3, 1, %o3     
+       EX2(stb %g2, [%o1],#)
+       add     %o4, %g5, %g5
+       EX2(stb %o4, [%o1 + 1],#)
+       add     %o0, 2, %o0     
+       srl     %o3, 1, %o3
+       add     %o1, 2, %o1
+1:     brz,a,pn %o3, 2f                
+        andcc  %g1, 2, %g0
+       EX3(ld  [%o0], %o4,#)
+5:     srl     %o4, 24, %g2
+       srl     %o4, 16, %g3
+       EX2(stb %g2, [%o1],#)
+       srl     %o4, 8, %g2
+       EX2(stb %g3, [%o1 + 1],#)
+       add     %o0, 4, %o0
+       EX2(stb %g2, [%o1 + 2],#)
+       addcc   %o4, %g5, %g5
+       EX2(stb %o4, [%o1 + 3],#)
+       addc    %g5, %g0, %g5   ! I am now to lazy to optimize this (question is if it
+       add     %o1, 4, %o1     ! is worthy). Maybe some day - with the sll/srl
+       subcc   %o3, 1, %o3     ! tricks
+       bne,a,pt %icc, 5b
+        EX3(ld [%o0], %o4,#)
+       sll     %g5, 16, %g2
+       srl     %g5, 16, %g5
+       srl     %g2, 16, %g2
+       andcc   %g1, 2, %g0
+       add     %g2, %g5, %g5 
+2:     be,a,pt %icc, 3f                
+        andcc  %g1, 1, %g0
+       EX(lduh [%o0], %o4, and %g1, 3,#)
+       andcc   %g1, 1, %g0
+       srl     %o4, 8, %g2
+       add     %o0, 2, %o0     
+       EX2(stb %g2, [%o1],#)
+       add     %g5, %o4, %g5
+       EX2(stb %o4, [%o1 + 1],#)
+       add     %o1, 2, %o1
+3:     be,a,pt %icc, 1f                
+        sll    %g5, 16, %o4
+       EX(ldub [%o0], %g2, add %g0, 1,#)
+       sll     %g2, 8, %o4     
+       EX2(stb %g2, [%o1],#)
+       add     %g5, %o4, %g5
+       sll     %g5, 16, %o4
+1:     addcc   %o4, %g5, %g5
+       srl     %g5, 16, %o4
+       addc    %g0, %o4, %g5
+       brz,pt  %o5, 4f
+        srl    %g5, 8, %o4
+       and     %g5, 0xff, %g2
+       and     %o4, 0xff, %o4
+       sll     %g2, 8, %g2
+       or      %g2, %o4, %g5
+4:     addcc   %g7, %g5, %g7
+       retl    
+        addc   %g0, %g7, %o0
+C_LABEL(__csum_partial_copy_end):
+
+        .section .fixup,#alloc,#execinstr
+        .align  4
+/* We do these strange calculations for the csum_*_from_user case only, ie.
+ * we only bother with faults on loads... */
+
+/* o2 = ((g2%20)&3)*8
+ * o3 = g1 - (g2/20)*32 - o2 */
+20:
+       cmp     %g2, 20
+       blu,a,pn %icc, 1f
+        and    %g2, 3, %o2
+       sub     %g1, 32, %g1
+       ba,pt   %xcc, 20b
+        sub    %g2, 20, %g2
+1:
+       sll     %o2, 3, %o2
+       ba,pt   %xcc, 31f
+        sub    %g1, %o2, %o3
+
+/* o2 = (!(g2 & 15) ? 0 : (((g2 & 15) + 1) & ~1)*8)
+ * o3 = g1 - (g2/16)*32 - o2 */
+21:
+       andcc   %g2, 15, %o3
+       srl     %g2, 4, %g2
+       be,a,pn %icc, 1f
+        clr    %o2
+       add     %o3, 1, %o3
+       and     %o3, 14, %o3
+       sll     %o3, 3, %o2
+1:
+       sll     %g2, 5, %g2
+       sub     %g1, %g2, %o3
+       ba,pt   %xcc, 31f
+        sub    %o3, %o2, %o3
+
+/* o0 += (g2/10)*16 - 0x70
+ * 01 += (g2/10)*16 - 0x70
+ * o2 = (g2 % 10) ? 8 : 0
+ * o3 += 0x70 - (g2/10)*16 - o2 */
+22:
+       cmp     %g2, 10
+       blu,a,pt %xcc, 1f
+        sub    %o0, 0x70, %o0
+       add     %o0, 16, %o0
+       add     %o1, 16, %o1
+       sub     %o3, 16, %o3
+       ba,pt   %xcc, 22b
+        sub    %g2, 10, %g2
+1:
+       sub     %o1, 0x70, %o1
+       add     %o3, 0x70, %o3
+       clr     %o2
+       movne   %g2, 8, %o2
+       ba,pt   %xcc, 31f
+        sub    %o3, %o2, %o3
+96:
+       and     %g1, 3, %g1
+       sll     %o3, 2, %o3
+       add     %g1, %o3, %o3
+30:
+/* %o1 is dst
+ * %o3 is # bytes to zero out
+ * %o4 is faulting address
+ * %o5 is %pc where fault occured */
+       clr     %o2
+31:
+/* %o0 is src
+ * %o1 is dst
+ * %o2 is # of bytes to copy from src to dst
+ * %o3 is # bytes to zero out
+ * %o4 is faulting address
+ * %o5 is %pc where fault occured */
+       save    %sp, -136, %sp
+        mov     %i5, %o0
+        mov     %i7, %o1
+        mov    %i4, %o2
+        call    C_LABEL(lookup_fault)
+        mov    %g7, %i4
+       cmp     %o0, 2
+       bne,pn  %icc, 1f
+        add    %g0, -EFAULT, %i5
+       brz,pn  %i2, 2f
+        mov    %i0, %o1
+       mov     %i1, %o0
+5:
+       call    C_LABEL(__memcpy)
+        mov    %i2, %o2
+       brnz,a,pn %o0, 2f
+        add    %i3, %i2, %i3
+       add     %i1, %i2, %i1
+2:
+       mov     %i1, %o0
+       call    C_LABEL(__bzero)
+        mov    %i3, %o1
+1:
+       ldx     [%sp + 264], %o2                ! struct_ptr of parent
+       st      %i5, [%o2]
+       ret
+        restore
+
+        .section __ex_table,#alloc
+        .align 4
+        .word 5b,2
diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S
new file mode 100644 (file)
index 0000000..a1154cb
--- /dev/null
@@ -0,0 +1,77 @@
+/* $Id: locks.S,v 1.2 1997/03/10 12:28:02 jj Exp $
+ * locks.S: SMP low-level lock primitives on Sparc64.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/ptrace.h>
+
+       .text
+       .align  4
+
+       .globl  __spinlock_waitfor
+__spinlock_waitfor:
+1:     orcc    %g2, 0x0, %g0
+       bne     1b
+        ldub   [%g1], %g2
+       ldstub  [%g1], %g2
+       jmpl    %o7 - 12, %g0
+        mov    %g5, %o7
+
+       .globl  ___become_idt
+___become_idt:
+#if 0 /* Don't know how to do this on the Ultra yet... */
+#endif
+       jmpl    %o7 + 8, %g0
+        mov    %g5, %o7
+
+___lk_busy_spin:
+       orcc    %g2, 0, %g0
+       bne     ___lk_busy_spin
+        ldub   [%g1 + 0], %g2
+       b       1f
+        ldstub [%g1 + 0], %g2
+
+       .globl  ___lock_kernel
+___lock_kernel:
+       addcc   %g2, -1, %g2
+       rdpr    %pil, %g3
+       bcs,a   9f
+        st     %g2, [%g6 + AOFF_task_lock_depth]
+       wrpr    15, %pil
+       ldstub  [%g1 + 0], %g2
+1:     orcc    %g2, 0, %g0
+       bne,a   ___lk_busy_spin
+        ldub   [%g1 + 0], %g2
+       ldub    [%g1 + 2], %g2
+       cmp     %g2, %g5
+       be      2f
+        stb    %g5, [%g1 + 1]
+       stb     %g5, [%g1 + 2]
+#ifdef __SMP__
+       /* XXX Figure out how to become interrupt receiver in SMP system. */
+#endif
+2:     mov     -1, %g2
+       st      %g2, [%g6 + AOFF_task_lock_depth]
+       wrpr    %g3, %pil
+9:     jmpl    %o7 + 0x8, %g0
+        mov    %g5, %o7
+
+#undef NO_PROC_ID
+#define NO_PROC_ID     0xff
+
+       .globl  ___unlock_kernel
+___unlock_kernel:
+       addcc   %g2, 1, %g2
+       rdpr    %pil, %g3
+       bne,a   1f
+        st     %g2, [%g6 + AOFF_task_lock_depth]
+       wrpr    15, %pil
+       mov     NO_PROC_ID, %g2
+       stb     %g2, [%g1 + 1]
+       stb     %g0, [%g1 + 0]
+       st      %g0, [%g6 + AOFF_task_lock_depth]
+       wrpr    %g3, %pil
+1:     jmpl    %o7 + 0x8, %g0
+        mov    %g5, %o7
+       
diff --git a/arch/sparc64/lib/memcmp.S b/arch/sparc64/lib/memcmp.S
new file mode 100644 (file)
index 0000000..76eaf5c
--- /dev/null
@@ -0,0 +1,29 @@
+/* $Id: memcmp.S,v 1.1 1997/03/14 21:04:23 jj Exp $
+ * Sparc64 optimized memcmp code.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+       .text
+       .align 4
+       .globl __memcmp, memcmp
+__memcmp:
+memcmp:
+       brlez,pn %o2, 2f
+        sub    %g0, %o2, %o3
+       add     %o0, %o2, %o0
+       add     %o1, %o2, %o1
+       ldub    [%o0 + %o3], %o4
+1:
+       ldub    [%o1 + %o3], %o5
+       sub     %o4, %o5, %o4
+       brnz,pn %o4, 3f
+        addcc  %o3, 1, %o3
+       bne,a,pt %xcc, 1b
+        ldub   [%o0 + %o3], %o5
+2:
+       retl
+        clr    %o0
+3:
+       retl
+        mov    %o4, %o0
diff --git a/arch/sparc64/lib/memcpy.S b/arch/sparc64/lib/memcpy.S
new file mode 100644 (file)
index 0000000..df7e3c8
--- /dev/null
@@ -0,0 +1,526 @@
+/* memcpy.S: Sparc optimized memcpy, bcopy and memmove code
+ * Hand optimized from GNU libc's memcpy, bcopy and memmove
+ * for UltraSparc
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi)
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/asi.h>
+#include <asm/head.h>
+
+#ifdef __KERNEL__
+
+#define FUNC(x)                                                                                        \
+       .globl  x;                                                                                      \
+       .type   x,@function;                                                                            \
+       .align  4;                                                                                      \
+x:
+
+#define FASTER_ALIGNED
+
+/* In kernel these functions don't return a value.
+ * One should use macros in asm/string.h for that purpose.
+ * We return 0, so that bugs are more apparent.
+ */
+#define SETUP_RETL
+#define PRE_RETL       sethi   %uhi(KERNBASE), %g4; clr %o0
+#define RETL_INSN      sllx    %g4, 32, %g4
+
+#else
+
+/* libc */
+
+#define FASTER_ALIGNED
+
+#ifdef DEBUG
+#define FUNC(x)                                                                                        \
+       .globl  jj##x##1;                                                                               \
+       .type   jj##x##1,@function;                                                                     \
+       .align  4;                                                                                      \
+jj##x##1:
+#else
+#include "DEFS.h"
+#endif
+
+#define SETUP_RETL     mov     %o0, %g6
+#define PRE_RETL
+#define RETL_INSN      mov     %g6, %o0
+
+#endif
+
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7)                                \
+       ldd     [%src + offset + 0x00], %t0;                                                            \
+       ldd     [%src + offset + 0x08], %t2;                                                            \
+       ldd     [%src + offset + 0x10], %t4;                                                            \
+       ldd     [%src + offset + 0x18], %t6;                                                            \
+       stw     %t0, [%dst + offset + 0x00];                                                            \
+       stw     %t1, [%dst + offset + 0x04];                                                            \
+       stw     %t2, [%dst + offset + 0x08];                                                            \
+       stw     %t3, [%dst + offset + 0x0c];                                                            \
+       stw     %t4, [%dst + offset + 0x10];                                                            \
+       stw     %t5, [%dst + offset + 0x14];                                                            \
+       stw     %t6, [%dst + offset + 0x18];                                                            \
+       stw     %t7, [%dst + offset + 0x1c];
+
+#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7)                           \
+       ldx     [%src + offset + 0x00], %t0;                                                            \
+       ldx     [%src + offset + 0x08], %t1;                                                            \
+       ldx     [%src + offset + 0x10], %t2;                                                            \
+       ldx     [%src + offset + 0x18], %t3;                                                            \
+       ldx     [%src + offset + 0x20], %t4;                                                            \
+       ldx     [%src + offset + 0x28], %t5;                                                            \
+       ldx     [%src + offset + 0x30], %t6;                                                            \
+       ldx     [%src + offset + 0x38], %t7;                                                            \
+       stx     %t0, [%dst + offset + 0x00];                                                            \
+       stx     %t1, [%dst + offset + 0x08];                                                            \
+       stx     %t2, [%dst + offset + 0x10];                                                            \
+       stx     %t3, [%dst + offset + 0x18];                                                            \
+       stx     %t4, [%dst + offset + 0x20];                                                            \
+       stx     %t5, [%dst + offset + 0x28];                                                            \
+       stx     %t6, [%dst + offset + 0x30];                                                            \
+       stx     %t7, [%dst + offset + 0x38];
+
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3)                                               \
+       ldd     [%src - offset - 0x10], %t0;                                                            \
+       ldd     [%src - offset - 0x08], %t2;                                                            \
+       stw     %t0, [%dst - offset - 0x10];                                                            \
+       stw     %t1, [%dst - offset - 0x0c];                                                            \
+       stw     %t2, [%dst - offset - 0x08];                                                            \
+       stw     %t3, [%dst - offset - 0x04];
+
+#define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1)                                                  \
+       ldx     [%src - offset - 0x10], %t0;                                                            \
+       ldx     [%src - offset - 0x08], %t1;                                                            \
+       stx     %t0, [%dst - offset - 0x10];                                                            \
+       stx     %t1, [%dst - offset - 0x08];
+
+#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1)                                                      \
+       ldub    [%src - offset - 0x02], %t0;                                                            \
+       ldub    [%src - offset - 0x01], %t1;                                                            \
+       stb     %t0, [%dst - offset - 0x02];                                                            \
+       stb     %t1, [%dst - offset - 0x01];
+
+       .text
+       .align  4
+
+FUNC(bcopy)
+
+       mov             %o0, %o3
+       mov             %o1, %o0
+       mov             %o3, %o1
+       brgez,a,pt      %o2, 1f
+        cmp            %o0, %o1
+
+       retl
+        nop            ! Only bcopy returns here and it retuns void...
+
+#ifdef __KERNEL__
+FUNC(amemmove)
+FUNC(__memmove)
+#endif
+FUNC(memmove)
+
+       cmp             %o0, %o1
+1:
+       SETUP_RETL
+       bleu,pt         %xcc, 9f
+        sub            %o0, %o1, %o4
+
+       add             %o1, %o2, %o3
+       cmp             %o3, %o0
+       bleu,pt         %xcc, 0f
+        andcc          %o4, 3, %o5
+
+       add             %o1, %o2, %o1
+       add             %o0, %o2, %o0
+       sub             %o1, 1, %o1
+       sub             %o0, 1, %o0
+       
+1:
+       ldub            [%o1], %o4
+       subcc           %o2, 1, %o2
+       sub             %o1, 1, %o1
+       stb             %o4, [%o0]
+       bne,pt          %icc, 1b
+        sub            %o0, 1, %o0
+
+       PRE_RETL
+       retl
+        RETL_INSN
+
+#ifdef __KERNEL__
+FUNC(__memcpy)
+#endif
+FUNC(memcpy)   /* %o0=dst %o1=src %o2=len */
+
+       sub             %o0, %o1, %o4
+       SETUP_RETL
+9:
+       andcc           %o4, 3, %o5
+0:
+       bne,pn          %icc, 86f
+        cmp            %o2, 15
+
+       bleu,pn         %xcc, 90f
+        andcc          %o1, 3, %g0
+
+       be,a,pt         %icc, 3f                ! check if we need to align
+        andcc          %o1, 4, %g0
+
+       andcc           %o1, 1, %g0
+       be,pn           %icc, 4f
+        andcc          %o1, 2, %g0
+
+       ldub            [%o1], %g2
+       add             %o1, 1, %o1
+       sub             %o2, 1, %o2
+       stb             %g2, [%o0]
+       bne,pn          %icc, 5f
+        add            %o0, 1, %o0
+4:
+       lduh            [%o1], %g2
+       add             %o1, 2, %o1
+       sub             %o2, 2, %o2
+       sth             %g2, [%o0]
+       add             %o0, 2, %o0
+5:
+       andcc           %o1, 4, %g0
+3:
+       be,pn           %icc, 2f
+        mov            %o2, %g1
+
+       lduw            [%o1], %o4
+       sub             %g1, 4, %g1
+       stw             %o4, [%o0]
+       add             %o1, 4, %o1
+       add             %o0, 4, %o0
+2:
+       andcc           %g1, -128, %g7
+       be,pn           %xcc, 3f
+        andcc          %o0, 4, %g0
+
+       be,a,pn         %icc, 82f + 4
+        ldx            [%o1], %o2
+5:
+       MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+       MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+       MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+       MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+       subcc           %g7, 128, %g7
+       add             %o1, 128, %o1
+       bne,pt          %xcc, 5b
+        add            %o0, 128, %o0
+3:
+       andcc           %g1, 0x70, %g7
+       be,pn           %icc, 80f
+        andcc          %g1, 8, %g0
+79:
+       rd              %pc, %o5
+       srl             %g7, 1, %o4
+       add             %g7, %o4, %o4
+       add             %o1, %g7, %o1
+       sub             %o5, %o4, %o5
+       jmpl            %o5 + %lo(80f-79b), %g0
+        add            %o0, %g7, %o0
+
+       MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+       MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+       MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+       MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+       MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+       MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+       MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+
+80:    /* memcpy_table_end */
+       be,pt           %icc, 81f
+        andcc          %g1, 4, %g0
+
+       ldd             [%o1], %g2
+       add             %o0, 8, %o0
+       stw             %g2, [%o0 - 0x08]
+       add             %o1, 8, %o1
+       stw             %g3, [%o0 - 0x04]
+
+81:    /* memcpy_last7 */
+
+       be,pt           %icc, 1f
+        andcc          %g1, 2, %g0
+
+       lduw            [%o1], %g2
+       add             %o1, 4, %o1
+       stw             %g2, [%o0]
+       add             %o0, 4, %o0
+1:
+       be,pt           %icc, 1f
+        andcc          %g1, 1, %g0
+
+       lduh            [%o1], %g2
+       add             %o1, 2, %o1
+       sth             %g2, [%o0]
+       add             %o0, 2, %o0
+1:
+       be,pt           %icc, 1f
+        nop
+
+       ldub            [%o1], %g2
+       stb             %g2, [%o0]
+1:
+       PRE_RETL
+       retl
+        RETL_INSN
+
+82:    /* ldx_stx */
+       MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+       MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+       subcc           %g7, 128, %g7
+       add             %o1, 128, %o1
+       bne,pt          %xcc, 82b
+        add            %o0, 128, %o0
+
+#ifndef FASTER_ALIGNED
+
+       andcc           %g1, 0x70, %g7
+       be,pn           %icc, 80b
+        andcc          %g1, 8, %g0
+83:
+       rd              %pc, %o5
+       srl             %g7, 1, %o4
+       add             %g7, %o4, %o4
+       add             %o1, %g7, %o1
+       sub             %o5, %o4, %o5
+       jmpl            %o5 + %lo(80b - 83b), %g0
+        add            %o0, %g7, %o0
+
+#else /* FASTER_ALIGNED */
+
+       andcc           %g1, 0x70, %g7
+       be,pn           %icc, 84f
+        andcc          %g1, 8, %g0
+83:
+       rd              %pc, %o5
+       add             %o1, %g7, %o1
+       sub             %o5, %g7, %o5
+       jmpl            %o5 + %lo(84f - 83b), %g0
+        add            %o0, %g7, %o0
+
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3)
+       MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3)
+
+84:    /* amemcpy_table_end */
+       be,pt           %icc, 85f
+        andcc          %g1, 4, %g0
+
+       ldx             [%o1], %g2
+       add             %o1, 8, %o1
+       stx             %g2, [%o0]
+       add             %o0, 8, %o0
+85:    /* amemcpy_last7 */
+       be,pt           %icc, 1f
+        andcc          %g1, 2, %g0
+
+       lduw            [%o1], %g2
+       add             %o1, 4, %o1
+       stw             %g2, [%o0]
+       add             %o0, 4, %o0
+1:
+       be,pt           %icc, 1f
+        andcc          %g1, 1, %g0
+
+       lduh            [%o1], %g2
+       add             %o1, 2, %o1
+       sth             %g2, [%o0]
+       add             %o0, 2, %o0
+1:
+       be,pt           %icc, 1f
+        nop
+
+       ldub            [%o1], %g2
+       stb             %g2, [%o0]
+1:
+       PRE_RETL
+       retl
+        RETL_INSN
+
+#endif /* FASTER_ALIGNED */
+
+86:    /* non_aligned */
+       cmp             %o2, 15
+       bleu,pn         %xcc, 88f
+
+        andcc          %o0, 3, %g0
+       be,pn           %icc, 61f
+        andcc          %o0, 1, %g0
+       be,pn           %icc, 60f
+        andcc          %o0, 2, %g0
+
+       ldub            [%o1], %g5
+       add             %o1, 1, %o1
+       stb             %g5, [%o0]
+       sub             %o2, 1, %o2
+       bne,pn          %icc, 61f
+        add            %o0, 1, %o0
+60:
+       ldub            [%o1], %g3
+       add             %o1, 2, %o1
+       stb             %g3, [%o0]
+       sub             %o2, 2, %o2
+       ldub            [%o1 - 1], %g3
+       add             %o0, 2, %o0
+       stb             %g3, [%o0 - 1]
+61:
+       and             %o1, 3, %g2
+       and             %o2, 0xc, %g3
+       and             %o1, -4, %o1
+       cmp             %g3, 4
+       sll             %g2, 3, %g4
+       mov             32, %g2
+       be,pn           %icc, 4f
+        sub            %g2, %g4, %g7
+       
+       blu,pn          %icc, 3f
+        cmp            %g3, 0x8
+
+       be,pn           %icc, 2f
+        srl            %o2, 2, %g3
+
+       lduw            [%o1], %o3
+       add             %o0, -8, %o0
+       lduw            [%o1 + 4], %o4
+       b               8f
+        add            %g3, 1, %g3
+2:
+       lduw            [%o1], %o4
+       add             %o0, -12, %o0
+       lduw            [%o1 + 4], %o5
+       add             %g3, 2, %g3
+       b               9f
+        add            %o1, -4, %o1
+3:
+       lduw            [%o1], %g1
+       add             %o0, -4, %o0
+       lduw            [%o1 + 4], %o3
+       srl             %o2, 2, %g3
+       b               7f
+        add            %o1, 4, %o1
+4:
+       lduw            [%o1], %o5
+       cmp             %o2, 7
+       lduw            [%o1 + 4], %g1
+       srl             %o2, 2, %g3
+       bleu,pn         %xcc, 10f
+        add            %o1, 8, %o1
+
+       lduw            [%o1], %o3
+       add             %g3, -1, %g3
+5:
+       sll             %o5, %g4, %g2
+       srl             %g1, %g7, %g5
+       or              %g2, %g5, %g2
+       stw             %g2, [%o0]
+7:
+       lduw            [%o1 + 4], %o4
+       sll             %g1, %g4, %g2
+       srl             %o3, %g7, %g5
+       or              %g2, %g5, %g2
+       stw             %g2, [%o0 + 4]
+8:
+       lduw            [%o1 + 8], %o5
+       sll             %o3, %g4, %g2
+       srl             %o4, %g7, %g5
+       or              %g2, %g5, %g2
+       stw             %g2, [%o0 + 8]
+9:
+       lduw            [%o1 + 12], %g1
+       sll             %o4, %g4, %g2
+       srl             %o5, %g7, %g5
+       addcc           %g3, -4, %g3
+       or              %g2, %g5, %g2
+       add             %o1, 16, %o1
+       stw             %g2, [%o0 + 12]
+       add             %o0, 16, %o0
+       bne,a,pt        %xcc, 5b
+        lduw           [%o1], %o3
+10:
+       sll             %o5, %g4, %g2
+       srl             %g1, %g7, %g5
+       srl             %g7, 3, %g3
+       or              %g2, %g5, %g2
+       sub             %o1, %g3, %o1
+       andcc           %o2, 2, %g0
+       stw             %g2, [%o0]
+       be,pt           %icc, 1f
+        andcc          %o2, 1, %g0
+
+       ldub            [%o1], %g2
+       add             %o1, 2, %o1
+       stb             %g2, [%o0 + 4]
+       add             %o0, 2, %o0
+       ldub            [%o1 - 1], %g2
+       stb             %g2, [%o0 + 3]
+1:
+       be,pt           %icc, 1f
+        nop
+
+       ldub            [%o1], %g2
+       stb             %g2, [%o0 + 4]
+1:
+       PRE_RETL
+       retl
+        RETL_INSN
+
+88:    /* short_end */
+
+       and             %o2, 0xe, %o3
+20:
+       rd              %pc, %o5
+       sll             %o3, 3, %o4
+       add             %o0, %o3, %o0
+       sub             %o5, %o4, %o5
+       add             %o1, %o3, %o1
+       jmpl            %o5 + %lo(89f - 20b), %g0
+        andcc          %o2, 1, %g0
+
+       MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+       MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+       MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+       MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+       MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+       MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+       MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+
+89:    /* short_table_end */
+
+       be,pt           %icc, 1f
+        nop
+
+       ldub            [%o1], %g2
+       stb             %g2, [%o0]
+1:
+       PRE_RETL
+       retl
+        RETL_INSN
+
+90:    /* short_aligned_end */
+       bne,pn          %xcc, 88b
+        andcc          %o2, 8, %g0
+
+       be,pt           %icc, 1f
+        andcc          %o2, 4, %g0
+
+       lduw            [%o1 + 0x00], %g2
+       lduw            [%o1 + 0x04], %g3
+       add             %o1, 8, %o1
+       stw             %g2, [%o0 + 0x00]
+       stw             %g3, [%o0 + 0x04]
+       add             %o0, 8, %o0
+1:
+       b               81b
+        mov            %o2, %g1
diff --git a/arch/sparc64/lib/memscan.S b/arch/sparc64/lib/memscan.S
new file mode 100644 (file)
index 0000000..83abe40
--- /dev/null
@@ -0,0 +1,116 @@
+/* $Id: memscan.S,v 1.1 1997/03/14 21:04:24 jj Exp $
+ * memscan.S: Optimized memscan for the Sparc64.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+/* In essence, this is just a fancy strlen. */
+
+#define LO_MAGIC 0x01010101
+#define HI_MAGIC 0x80808080
+
+       .text
+       .align  4
+       .globl  __memscan_zero, __memscan_generic
+       .globl  memscan
+__memscan_zero:
+       /* %o0 = addr, %o1 = size */
+       brlez,pn %o1, 0f
+        andcc  %o0, 3, %g0
+       be,pt   %icc, 9f
+        sethi  %hi(HI_MAGIC), %o4
+       ldub    [%o0], %o5
+       subcc   %o1, 1, %o1
+       brz,pn  %o5, 10f
+        add    %o0, 1, %o0
+       be,pn   %xcc, 0f
+        andcc  %o0, 3, %g0
+       be,pn   %icc, 4f
+        or     %o4, %lo(HI_MAGIC), %o3
+       ldub    [%o0], %o5
+       subcc   %o1, 1, %o1
+       brz,pn  %o5, 10f
+        add    %o0, 1, %o0
+       be,pn   %xcc, 0f
+        andcc  %o0, 3, %g0
+       be,pt   %icc, 5f
+        sethi  %hi(LO_MAGIC), %o4
+       ldub    [%o0], %o5
+       subcc   %o1, 1, %o1
+       brz,pn  %o5, 10f
+        add    %o0, 1, %o0
+       be,pn   %xcc, 0f
+        or     %o4, %lo(LO_MAGIC), %o2
+       ba,pt   %xcc, 2f
+        ld     [%o0], %o5
+9:
+       or      %o4, %lo(HI_MAGIC), %o3
+4:
+       sethi   %hi(LO_MAGIC), %o4
+5:
+       or      %o4, %lo(LO_MAGIC), %o2
+       ld      [%o0], %o5
+2:
+       sub     %o5, %o2, %o4
+       sub     %o1, 4, %o1
+       andcc   %o4, %o3, %g0
+       be,pn   %icc, 1f
+        add    %o0, 4, %o0
+       brgz,pt %o1, 2b
+        ld     [%o0], %o5
+
+       retl
+        add    %o0, %o1, %o0
+1:
+       /* Check every byte. */
+       srl     %o5, 24, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o0, -4, %o4
+       srl     %o5, 16, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       srl     %o5, 8, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       andcc   %o5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       brgz,pt %o1, 2b
+        ld     [%o0], %o5
+1:
+       add     %o0, %o1, %o0
+       cmp     %o4, %o0
+       retl
+        movle  %xcc, %o4, %o0
+0:
+       retl
+        nop
+10:
+       retl
+        sub    %o0, 1, %o0
+
+memscan:
+__memscan_generic:
+       /* %o0 = addr, %o1 = c, %o2 = size */
+       brz,pn  %o2, 3f
+        add    %o0, %o2, %o3
+       ldub    [%o0], %o5
+       sub     %g0, %o2, %o4
+1:
+       cmp     %o5, %o1
+       be,pn   %icc, 2f
+        addcc  %o4, 1, %o4
+       bne,a,pt %xcc, 1b
+        ldub   [%o3 + %o4], %o5
+       retl
+       /* The delay slot is the same as the next insn, this is just to make it look more awful */
+2:
+        add    %o3, %o4, %o0
+       retl
+        sub    %o0, 1, %o0
+3:
+       retl
+        nop
index 609ee1a781829936b41827d54fd722916ec6662a..14859b3a95ac11231137f3e4a1b08a9881bd7369 100644 (file)
@@ -54,7 +54,7 @@
        .text
        .align 4
 
-       .globl  __bzero, __memset
+       .globl  __bzero, __memset
        .globl  memset, __memset_start, __memset_end
 __memset_start:
 __memset:
diff --git a/arch/sparc64/lib/strlen.S b/arch/sparc64/lib/strlen.S
new file mode 100644 (file)
index 0000000..5f2ec6b
--- /dev/null
@@ -0,0 +1,77 @@
+/* strlen.S: Sparc64 optimized strlen code
+ * Hand optimized from GNU libc's strlen
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#define LO_MAGIC 0x01010101
+#define HI_MAGIC 0x80808080
+
+       .align 4
+       .global strlen
+strlen:
+       mov     %o0, %o1
+       andcc   %o0, 3, %g0
+       be,pt   %icc, 9f
+        sethi  %hi(HI_MAGIC), %o4
+       ldub    [%o0], %o5
+       brz,pn  %o5, 11f
+        add    %o0, 1, %o0
+       andcc   %o0, 3, %g0
+       be,pn   %icc, 4f
+        or     %o4, %lo(HI_MAGIC), %o3
+       ldub    [%o0], %o5
+       brz,pn  %o5, 12f
+        add    %o0, 1, %o0
+       andcc   %o0, 3, %g0
+       be,pt   %icc, 5f
+        sethi  %hi(LO_MAGIC), %o4
+       ldub    [%o0], %o5
+       brz,pn  %o5, 13f
+        add    %o0, 1, %o0
+       ba,pt   %icc, 8f
+        or     %o4, %lo(LO_MAGIC), %o2
+9:
+       or      %o4, %lo(HI_MAGIC), %o3
+4:
+       sethi   %hi(LO_MAGIC), %o4
+5:
+       or      %o4, %lo(LO_MAGIC), %o2
+8:
+       ld      [%o0], %o5
+2:
+       sub     %o5, %o2, %o4
+       andcc   %o4, %o3, %g0
+       be,pt   %icc, 8b
+        add    %o0, 4, %o0
+
+       /* Check every byte. */
+       srl     %o5, 24, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o0, -4, %o4
+       srl     %o5, 16, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       srl     %o5, 8, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       andcc   %o5, 0xff, %g0
+       bne,a,pt %icc, 2b
+        ld     [%o0], %o5
+       add     %o4, 1, %o4
+1:
+       retl
+        sub    %o4, %o1, %o0
+11:
+       retl
+        mov    0, %o0
+12:
+       retl
+        mov    1, %o0
+13:
+       retl
+        mov    2, %o0
diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S
new file mode 100644 (file)
index 0000000..24bea73
--- /dev/null
@@ -0,0 +1,99 @@
+/* strlen_user.S: Sparc64 optimized strlen_user code
+ *
+ * Return length of string in userspace including terminating 0
+ * or 0 for error
+ *
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#define LO_MAGIC 0x01010101
+#define HI_MAGIC 0x80808080
+
+       .align 4
+       .global __strlen_user
+__strlen_user:
+       mov     %o0, %o1
+       andcc   %o0, 3, %g0
+       be,pt   %icc, 9f
+        sethi  %hi(HI_MAGIC), %o4
+10:
+       ldub    [%o0], %o5
+       brz,pn  %o5, 21f
+        add    %o0, 1, %o0
+       andcc   %o0, 3, %g0
+       be,pn   %icc, 4f
+        or     %o4, %lo(HI_MAGIC), %o3
+11:
+       ldub    [%o0], %o5
+       brz,pn  %o5, 22f
+        add    %o0, 1, %o0
+       andcc   %o0, 3, %g0
+       be,pt   %icc, 5f
+        sethi  %hi(LO_MAGIC), %o4
+12:
+       ldub    [%o0], %o5
+       brz,pn  %o5, 23f
+        add    %o0, 1, %o0
+       ba,pt   %icc, 13f
+        or     %o4, %lo(LO_MAGIC), %o2
+9:
+       or      %o4, %lo(HI_MAGIC), %o3
+4:
+       sethi   %hi(LO_MAGIC), %o4
+5:
+       or      %o4, %lo(LO_MAGIC), %o2
+13:
+       ld      [%o0], %o5
+2:
+       sub     %o5, %o2, %o4
+       andcc   %o4, %o3, %g0
+       be,pt   %icc, 13b
+        add    %o0, 4, %o0
+
+       /* Check every byte. */
+       srl     %o5, 24, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o0, -3, %o4
+       srl     %o5, 16, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       srl     %o5, 8, %g5
+       andcc   %g5, 0xff, %g0
+       be,pn   %icc, 1f
+        add    %o4, 1, %o4
+       andcc   %o5, 0xff, %g0
+       bne,a,pt %icc, 2b
+14:
+        ld     [%o0], %o5
+       add     %o4, 1, %o4
+1:
+       retl
+        sub    %o4, %o1, %o0
+21:
+       retl
+        mov    1, %o0
+22:
+       retl
+        mov    2, %o0
+23:
+       retl
+        mov    3, %o0
+
+        .section .fixup,#alloc,#execinstr
+        .align  4
+30:
+        retl
+         clr    %o0
+
+       .section __ex_table,#alloc
+       .align  4
+
+       .word   10b, 30b
+       .word   11b, 30b
+       .word   12b, 30b
+       .word   13b, 30b
+       .word   14b, 30b
diff --git a/arch/sparc64/lib/strncmp.S b/arch/sparc64/lib/strncmp.S
new file mode 100644 (file)
index 0000000..474ba72
--- /dev/null
@@ -0,0 +1,31 @@
+/* $Id: strncmp.S,v 1.2 1997/03/11 17:51:44 jj Exp $
+ * Sparc64 optimized strncmp code.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/asi.h>
+
+       .text
+       .align 4
+       .global __strncmp, strncmp
+__strncmp:
+strncmp:
+       brlez,pn %o2, 3f
+        lduba  [%o0] (ASI_PNF), %o3
+1:
+       add     %o0, 1, %o0
+       ldub    [%o1], %o4
+       brz,pn  %o3, 2f
+        add    %o1, 1, %o1
+       cmp     %o3, %o4
+       bne,pn  %icc, 2f
+        subcc  %o2, 1, %o2
+       bne,a,pt %xcc, 1b
+        ldub   [%o0], %o3
+2:
+       retl
+        sub    %o3, %o4, %o0
+3:
+       retl
+        clr    %o0
diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S
new file mode 100644 (file)
index 0000000..05a48eb
--- /dev/null
@@ -0,0 +1,54 @@
+/* strncpy_from_user.S: Sparc64 strncpy from userspace.
+ *
+ *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/asi.h>
+#include <asm/errno.h>
+
+       .text
+       .align  4
+
+       /* Must return:
+        *
+        * -EFAULT              for an exception
+        * count                if we hit the buffer limit
+        * bytes copied         if we hit a null byte
+        */
+
+       .globl  __strncpy_from_user
+__strncpy_from_user:
+       /* %o0=dest, %o1=src, %o2=count */
+       brlez,pn %o2, 3f
+        add    %o1, %o2, %o1
+       sub     %g0, %o2, %o3
+       add     %o0, %o2, %o0
+10:
+       ldub    [%o1 + %o3], %o4
+1:
+       brz,pn  %o4, 2f
+        stb    %o4, [%o0 + %o3]
+       addcc   %o3, 1, %o3
+       bne,pt  %xcc, 1b
+11:
+        ldub   [%o1 + %o3], %o4
+       retl
+        mov    %o2, %o0
+2:
+       add     %o3, 1, %o3
+       retl
+        add    %o2, %o3, %o0
+3:
+       retl
+        clr    %o0
+
+       .section .fixup,#alloc,#execinstr
+       .align  4
+4:
+       retl
+        mov    -EFAULT, %o0
+
+       .section __ex_table,#alloc
+       .align  4
+       .word   10b, 4b
+       .word   11b, 4b
index 006296fe06b65069ba79603a171abedb660aec7b..b2df0e169ac0763a96e4be2010eacab967cf644a 100644 (file)
@@ -1,5 +1,5 @@
-/* $Id: extable.c,v 1.1 1996/12/26 10:24:24 davem Exp $
- * linux/arch/sparc/mm/extable.c
+/*
+ * linux/arch/sparc64/mm/extable.c
  */
 
 #include <linux/config.h>
@@ -31,12 +31,13 @@ search_one_table(const struct exception_table_entry *start,
                 else
                         last = mid-1;
         }
-        if (last->insn < value && !last->fixup && (last + 1)->insn > value) {
+        if (last->insn < value && !last->fixup && last[1].insn > value) {
                *g2 = (value - last->insn)/4;
-               return (last + 1)->fixup;
+               return last[1].fixup;
         }
-        if (first > start && (first-1)->insn < value && !(first-1)->fixup && first->insn < value) {
-               *g2 = (value - (first-1)->insn)/4;
+        if (first > start && first[-1].insn < value
+           && !first[-1].fixup && first->insn < value) {
+               *g2 = (value - first[-1].insn)/4;
                return first->fixup;
         }
         return 0;
@@ -46,25 +47,23 @@ unsigned long
 search_exception_table(unsigned long addr, unsigned long *g2)
 {
        unsigned long ret;
-#ifdef CONFIG_MODULES
-       struct module *mp;
-#endif
 
-       /* Search the kernel's table first.  */
+#ifndef CONFIG_MODULES
+       /* There is only the kernel to search.  */
        ret = search_one_table(__start___ex_table,
                               __stop___ex_table-1, addr, g2);
-       if (ret)
-               return ret;
-
-#ifdef CONFIG_MODULES
+       if (ret) return ret;
+#else
+       /* The kernel is the last "module" -- no need to treat it special.  */
+       struct module *mp;
        for (mp = module_list; mp != NULL; mp = mp->next) {
-               if (mp->exceptinfo.start != NULL) {
-                       ret = search_one_table(mp->exceptinfo.start,
-                               mp->exceptinfo.stop-1, addr, g2);
-                       if (ret)
-                               return ret;
-               }
+               if (mp->ex_table_start == NULL)
+                       continue;
+               ret = search_one_table(mp->ex_table_start,
+                                      mp->ex_table_end-1, addr, g2);
+               if (ret) return ret;
        }
 #endif
+
        return 0;
 }
index 9c6e61e9de533995ee3ace5451f9b87245bf5de1..0dd118c8ee11ab6d589c30797092088a763b8f01 100644 (file)
@@ -1,24 +1,39 @@
-/* $Id: fault.c,v 1.3 1997/03/04 16:27:02 jj Exp $
+/* $Id: fault.c,v 1.4 1997/03/11 17:37:07 jj Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <asm/head.h>
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+
 #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
 
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
-extern int prom_node_root;
 
 /* Nice, simple, prom library does all the sweating for us. ;) */
-unsigned int prom_probe_memory (void)
+unsigned long prom_probe_memory (void)
 {
-       register struct linux_mlist_v0 *mlist;
-       register unsigned int bytes, base_paddr, tally;
+       register struct linux_mlist_p1275 *mlist;
+       register unsigned long bytes, base_paddr, tally;
        register int i;
 
        i = 0;
-       mlist= *prom_meminfo()->v0_available;
+       mlist = *prom_meminfo()->p1275_available;
        bytes = tally = mlist->num_bytes;
        base_paddr = (unsigned int) mlist->start_adr;
   
@@ -40,7 +55,7 @@ unsigned int prom_probe_memory (void)
                        break;
                }
     
-               sp_banks[i].base_addr = (unsigned int) mlist->start_adr;
+               sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
                sp_banks[i].num_bytes = mlist->num_bytes;
        }
 
@@ -60,10 +75,10 @@ unsigned int prom_probe_memory (void)
 /* Traverse the memory lists in the prom to see how much physical we
  * have.
  */
-unsigned int
+unsigned long
 probe_memory(void)
 {
-       unsigned int total;
+       unsigned long total;
 
        total = prom_probe_memory();
 
@@ -102,17 +117,17 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
        case 3: return 3;
        /* store will be handled by fixup, load will bump out */
        /* for _to_ macros */
-       case 1: insn = (unsigned *)pc; if ((insn >> 21) & 1) return 1; break;
+       case 1: insn = *(unsigned *)pc; if ((insn >> 21) & 1) return 1; break;
        /* load will be handled by fixup, store will bump out */
        /* for _from_ macros */
-       case 2: insn = (unsigned *)pc; 
+       case 2: insn = *(unsigned *)pc; 
                if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; 
                break; 
        default: break;
        }
        memset (&regs, 0, sizeof (regs));
-       regs.pc = pc;
-       regs.npc = pc + 4;
+       regs.tpc = pc;
+       regs.tnpc = pc + 4;
        /* FIXME: Should set up regs->tstate? */
        unhandled_fault (address, current, &regs);
        /* Not reached */
@@ -125,7 +140,7 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write
        struct vm_area_struct *vma;
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
-       unsigned int fixup;
+       unsigned long fixup;
        unsigned long g2;
        int from_user = !(regs->tstate & TSTATE_PRIV);
 
@@ -165,20 +180,16 @@ bad_area:
        /* Is this in ex_table? */
        
        g2 = regs->u_regs[UREG_G2];
-       if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
-               printk("Exception: PC<%016lx> faddr<%016lx>\n", regs->pc, address);
+       if (!from_user && (fixup = search_exception_table (regs->tpc, &g2))) {
+               printk("Exception: PC<%016lx> faddr<%016lx>\n", regs->tpc, address);
                printk("EX_TABLE: insn<%016lx> fixup<%016lx> g2<%016lx>\n",
-                       regs->pc, fixup, g2);
-               regs->pc = fixup;
-               regs->npc = regs->pc + 4;
+                       regs->tpc, fixup, g2);
+               regs->tpc = fixup;
+               regs->tnpc = regs->tpc + 4;
                regs->u_regs[UREG_G2] = g2;
                goto out;
        }
        if(from_user) {
-#if 0
-               printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
-                      tsk->comm, tsk->pid, address, regs->pc);
-#endif
                tsk->tss.sig_address = address;
                tsk->tss.sig_desc = SUBSIG_NOMAPPING;
                send_sig(SIGSEGV, tsk, 1);
index 16852cb2d3146f37af5551e5795fefa24cd7b8ef..94244b890cac2ab2eb0a633c0f3f01c0f8e38472 100644 (file)
@@ -1,10 +1,21 @@
-/*  $Id: init.c,v 1.2 1997/01/02 14:14:42 jj Exp $
+/*  $Id: init.c,v 1.4 1997/03/18 17:59:48 jj Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/swap.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
 extern void show_net_buffers(void);
+extern unsigned long device_scan(unsigned long);
 
 struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 
@@ -21,10 +32,10 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-pte_t *__bad_pagetable(void)
+pmd_t *__bad_pagetable(void)
 {
        memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
-       return (pte_t *) EMPTY_PGT;
+       return (pmd_t *) EMPTY_PGT;
 }
 
 pte_t __bad_page(void)
@@ -67,7 +78,8 @@ __initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx)
 
        ctx_list_pool = (struct ctx_list *) start_mem;
        start_mem += (numctx * sizeof(struct ctx_list));
-       for(ctx = 0; ctx < numctx; ctx++) {
+       /* Context 0 is reserved for PROM and uaccess stuff */
+       for(ctx = 1; ctx < numctx; ctx++) {
                struct ctx_list *clist;
 
                clist = (ctx_list_pool + ctx);
@@ -76,7 +88,7 @@ __initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx)
        }
        ctx_free.next = ctx_free.prev = &ctx_free;
        ctx_used.next = ctx_used.prev = &ctx_used;
-       for(ctx = 0; ctx < numctx; ctx++)
+       for(ctx = 1; ctx < numctx; ctx++)
                add_to_free_ctxlist(ctx_list_pool + ctx);
        return start_mem;
 }
@@ -86,6 +98,7 @@ __initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx)
 __initfunc(unsigned long 
 paging_init(unsigned long start_mem, unsigned long end_mem))
 {
+       return device_scan (start_mem);
 }
 
 extern int min_free_pages;
@@ -182,7 +195,7 @@ void free_initmem (void)
                mem_map[MAP_NR(addr)].count = 1;
                free_page(addr);
        }
-       printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+       printk ("Freeing unused kernel memory: %dk freed\n", (unsigned)((&__init_end - &__init_begin) >> 10));
 }
 
 void si_meminfo(struct sysinfo *val)
index 017094cd074a84a79a5613745fb0a1453e2b68ba..a4aea63b84504faa72ccaeeec79582158f02a8b4 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.4 1997/03/04 16:27:07 jj Exp $
+/* $Id: console.c,v 1.6 1997/03/18 17:59:59 jj Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -43,7 +43,7 @@ prom_nbputchar(char c)
        outc = c;
        if (p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
                               P1275_INOUT(3,1),
-                              prom_stdin, &outc, P1275_SIZE(1)) == 1)
+                              prom_stdout, &outc, P1275_SIZE(1)) == 1)
                return 0;
        else
                return -1;
@@ -62,10 +62,18 @@ prom_getchar(void)
 void
 prom_putchar(char c)
 {
-       while(prom_nbputchar(c) == -1) ;
+       prom_nbputchar(c);
        return;
 }
 
+void
+prom_puts(char *s, int len)
+{
+       p1275_cmd("write", P1275_ARG(1,P1275_ARG_IN_BUF)|
+                          P1275_INOUT(3,1),
+                          prom_stdout, s, P1275_SIZE(len));
+}
+
 /* Query for input device type */
 enum prom_input_device
 prom_query_input_device()
index 952ae1ed9aec4a674923cc6cb0a7a65fe9ccdf5c..129afc4c7b8611bc3d69cc98db78afaaa519ca40 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.4 1997/03/04 16:27:09 jj Exp $
+/* $Id: init.c,v 1.6 1997/03/11 17:37:11 jj Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -55,17 +55,22 @@ __initfunc(void prom_init(void *cif_handler, void *cif_stack))
                prom_halt();
                
        prom_getstring (node, "version", buffer, sizeof (buffer));
-       if (strncmp (buffer, "OPB ", 4) || buffer[5] != '.' || buffer[7] != '.') {
-               prom_printf ("Strange OPB version.\n");
+       
+       prom_printf ("\n");
+       
+       if (strncmp (buffer, "OBP ", 4) || buffer[5] != '.' || buffer[7] != '.') {
+               prom_printf ("Strange OBP version `%s'.\n", buffer);
                prom_halt ();
        }
-       /* Version field is expected to be 'OPB x.y.z date...' */
+       /* Version field is expected to be 'OBP x.y.z date...' */
        
        prom_rev = buffer[6] - '0';
        prom_prev = ((buffer[4] - '0') << 16) | 
                    ((buffer[6] - '0') << 8) |
                    (buffer[8] - '0');
                    
+       prom_printf ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + 4);
+       
        prom_meminit();
 
        prom_ranges_init();
index 6523593f3bc018a79ac7b8e6a30d376004600292..cf041d49fd80df71ac33d135bf862bb1be700fc1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.4 1997/03/04 16:27:12 jj Exp $
+/* $Id: p1275.c,v 1.7 1997/03/18 17:59:55 jj Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #include <asm/oplib.h>
 #include <asm/spitfire.h>
 #include <asm/system.h>
+#include <asm/pstate.h>
 
 /* If you change layout of this structure, please change the prom_doit
    function below as well. */
 typedef struct {
-       unsigned prom_doit_code [16];
-       void (*prom_cif_handler)(long *);
-       unsigned long prom_cif_stack;
-       unsigned long prom_args [23];
-       char prom_buffer [7928];
+       unsigned prom_doit_code [24];           /* 0x8000 */
+       long prom_sync_routine;                 /* 0x8060 */
+       void (*prom_cif_handler)(long *);       /* 0x8068 */
+       unsigned long prom_cif_stack;           /* 0x8070 */
+       unsigned long prom_args [23];           /* 0x8078 */
+       char prom_buffer [7888];
 } at0x8000;
 
 static void (*prom_do_it)(void);
 
 void prom_cif_interface (void) __attribute__ ((__section__ (".p1275")));
 
-/* At most 16 insns (including the retl; nop; afterwards) */
+/* At most 14 insns */
 void prom_cif_interface (void)
 {
        __asm__ __volatile__ ("
-       sethi   %hi(0x8000), %o0
-       ldx     [%o0 + 0x048], %o1      ! prom_cif_stack
-       save    %o1, -0xc0, %sp
-       ldx     [%i0 + 0x040], %l2      ! prom_cif_handler
-       mov     %g4, %l0
-       mov     %g6, %l1
-       call    %l2
-        or     %i0, 0x050, %o0         ! prom_args
-       mov     %l0, %g4
-       mov     %l1, %g6
-       restore
-       ");
+       sethi   %%hi(0x8000), %%o0
+       ldx     [%%o0 + 0x070], %%o1    ! prom_cif_stack
+       save    %%o1, -0xc0, %%sp
+       ldx     [%%i0 + 0x068], %%l2    ! prom_cif_handler
+       rdpr    %%pstate, %%l4
+       mov     %%g4, %%l0
+       mov     %%g6, %%l1
+       wrpr    %%l4, %0, %%pstate      ! turn on address masking
+       call    %%l2
+        or     %%i0, 0x078, %%o0       ! prom_args
+       wrpr    %%l4, 0, %%pstate       ! put pstate back
+       mov     %%l0, %%g4
+       ret
+        restore %%l1, 0, %%g6
+       save    %%sp, -0xc0, %%sp       ! If you change the offset of the save 
+       rdpr    %%pstate, %%l4          ! here, please change the 0x8038 
+       andn    %%l4, %0, %%l3          ! constant below as well
+       wrpr    %%l3, %%pstate
+       ldx     [%%o0 + 0x060], %%l2
+       call    %%l2
+        nop
+       wrpr    %%l4, 0, %%pstate
+       ret
+        restore
+       " : : "i" (PSTATE_AM));
 }
 
 long p1275_cmd (char *service, long fmt, ...)
@@ -64,26 +79,26 @@ long p1275_cmd (char *service, long fmt, ...)
        }
        low->prom_args[0] = (unsigned long)p;                   /* service */
        strcpy (p, service);
-       p = strchr (p, 0) + 1;
+       p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
        low->prom_args[1] = nargs = (fmt & 0x0f);               /* nargs */
        low->prom_args[2] = nrets = ((fmt & 0xf0) >> 4);        /* nrets */
-       attrs = (fmt & (~0xff));
+       attrs = fmt >> 8;
        va_start(list, fmt);
        for (i = 0; i < nargs; i++, attrs >>= 3) {
                switch (attrs & 0x7) {
                case P1275_ARG_NUMBER:
-                       low->prom_args[i + 3] = va_arg(list, long); break;
+                       low->prom_args[i + 3] = (unsigned)va_arg(list, long); break;
                case P1275_ARG_IN_STRING:
                        strcpy (p, va_arg(list, char *));
                        low->prom_args[i + 3] = (unsigned long)p;
-                       p = strchr (p, 0) + 1;
+                       p = (char *)(((long)(strchr (p, 0) + 8)) & ~7);
                        break;
                case P1275_ARG_OUT_BUF:
                        (void) va_arg(list, char *);
                        low->prom_args[i + 3] = (unsigned long)p;
                        x = va_arg(list, long);
                        i++; attrs >>= 3;
-                       p += (int)x;
+                       p = (char *)(((long)(p + (int)x + 7)) & ~7);
                        low->prom_args[i + 3] = x;
                        break;
                case P1275_ARG_IN_BUF:
@@ -91,8 +106,8 @@ long p1275_cmd (char *service, long fmt, ...)
                        low->prom_args[i + 3] = (unsigned long)p;
                        x = va_arg(list, long);
                        i++; attrs >>= 3;
-                       p += (int)x;
                        memcpy (p, q, (int)x);
+                       p = (char *)(((long)(p + (int)x + 7)) & ~7);
                        low->prom_args[i + 3] = x;
                        break;
                case P1275_ARG_OUT_32B:
@@ -101,23 +116,28 @@ long p1275_cmd (char *service, long fmt, ...)
                        p += 32;
                        break;
                case P1275_ARG_IN_FUNCTION:
-                       /* FIXME: This should make a function in our <4G
-                        * section, which will call the argument,
-                        * so that PROM can call it.
-                        */
-                       low->prom_args[i + 3] = va_arg(list, long); break;
+                       low->prom_args[i + 3] = 0x8038;
+                       low->prom_sync_routine = va_arg(list, long); break;
                }
        }
        va_end(list);
+       
        (*prom_do_it)();
-       attrs = fmt & (~0xff);
+
+       attrs = fmt >> 8;
        va_start(list, fmt);
        for (i = 0; i < nargs; i++, attrs >>= 3) {
                switch (attrs & 0x7) {
                case P1275_ARG_NUMBER:
+                       (void) va_arg(list, long); break;
                case P1275_ARG_IN_STRING:
+                       (void) va_arg(list, char *); break;
                case P1275_ARG_IN_FUNCTION:
+                       (void) va_arg(list, long); break;
                case P1275_ARG_IN_BUF:
+                       (void) va_arg(list, char *);
+                       (void) va_arg(list, long);
+                       i++; attrs >>= 3;
                        break;
                case P1275_ARG_OUT_BUF:
                        p = va_arg(list, char *);
@@ -133,6 +153,7 @@ long p1275_cmd (char *service, long fmt, ...)
        }
        va_end(list);
        x = low->prom_args [nargs + 3];
+       
        if (ctx)
                spitfire_set_primary_context (ctx);
        restore_flags(flags);
@@ -142,7 +163,7 @@ long p1275_cmd (char *service, long fmt, ...)
 void prom_cif_init(void *cif_handler, void *cif_stack)
 {
        at0x8000 *low = (at0x8000 *)(0x8000);
-       
+
        low->prom_cif_handler = (void (*)(long *))cif_handler;
        low->prom_cif_stack = (unsigned long)cif_stack;
         prom_do_it = (void (*)(void))(0x8000);
index efe4e1facb181307dcb7ef149a3ddcfe94d6c4fd..33428e9f621f19cc7c4f12fdeca5e5e71b5e3743 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: printf.c,v 1.2 1997/03/04 16:27:13 jj Exp $
+/* $Id: printf.c,v 1.3 1997/03/18 18:00:00 jj Exp $
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 /* This routine is internal to the prom library, no one else should know
 
 static char ppbuf[1024];
 
+extern void prom_puts (char *, int);
+
 void
 prom_printf(char *fmt, ...)
 {
        va_list args;
-       char ch, *bptr;
+       char ch, *bptr, *last;
        int i;
 
        va_start(args, fmt);
        i = vsprintf(ppbuf, fmt, args);
 
        bptr = ppbuf;
+       last = ppbuf;
 
        while((ch = *(bptr++)) != 0) {
-               if(ch == '\n')
+               if(ch == '\n') {
+                       if (last < bptr - 1)
+                               prom_puts (last, bptr - 1 - last);
                        prom_putchar('\r');
-
-               prom_putchar(ch);
+                       last = bptr - 1;
+               }
        }
+       if (last < bptr - 1)
+               prom_puts (last, bptr - 1 - last);
        va_end(args);
        return;
 }
index 5b2e697ec4a744cabef44c79784d2be0f713e708..f19207a7a4b36c3367beb938dba541be63126e73 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ranges.c,v 1.1 1997/02/25 12:40:28 jj Exp $
+/* $Id: ranges.c,v 1.2 1997/03/18 17:59:57 jj Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -66,7 +66,7 @@ __initfunc(void prom_ranges_init(void))
 {
 }
 
-__initfunc(void prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus))
+__initfunc(void prom_sbus_ranges_init(struct linux_sbus *sbus))
 {
        int success;
        
index fee68208a59dcf8c6aac70eabafb6ed046d53f10..6779ea8cacd68243570abf4c285fe00ee4adcafd 100644 (file)
@@ -5,6 +5,8 @@ ENTRY(_start)
 
 SECTIONS
 {
+  empty_zero_page = 0xfffff80000000000;
+  empty_bad_page =  0xfffff80000002000;
   . = 0x4000;
   .text 0xfffff80000004000 :
   {
@@ -30,6 +32,7 @@ SECTIONS
   __start___ksymtab = .;
   __ksymtab  : { *(__ksymtab) }
   __stop___ksymtab = .;
+  __kstrtab  : { *(.kstrtab) }
   . = ALIGN(8192);
   __init_begin = .;
   .text.init : { *(.text.init) }
@@ -49,6 +52,9 @@ SECTIONS
    *(.dynbss)
    *(.bss)
    *(COMMON)
+   . = ALIGN(8192);
+   empty_bad_page_table = .;
+   . += 8192;
   }
   _end = . ;
   PROVIDE (end = .);
index 7f73e102252e0b9cbd8f1255778c3c1570c20659..56052e31352482015ca5259177d5732dc304003b 100644 (file)
@@ -23,7 +23,7 @@ else
     fi
     if [ "$CONFIG_PCI" = "y" ]; then
       bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
-      bool '   Intel 82371 PIIX (Triton I/II) DMA support' CONFIG_BLK_DEV_TRITON
+      bool '   Intel PIIX/PIIX3 (Triton 430FX/HX/VX, 440FX) DMA support' CONFIG_BLK_DEV_TRITON
     fi
     bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
     if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
diff --git a/drivers/block/README.hd b/drivers/block/README.hd
deleted file mode 100644 (file)
index ba21874..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-This hard disk driver (hd.c) includes support for IDE Multiple Mode
-and IRQ-unmasking during I/O (both disabled by default), as well as
-support for drives where the BIOS reports "more than 16 heads".
-
-The hdparm.c program for controlling various features is now packaged
-separately.  Look for it on your favorite linux FTP site.
-
--mlord@pobox.com
diff --git a/drivers/block/README.ide b/drivers/block/README.ide
deleted file mode 100644 (file)
index d15e058..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-The IDE driver Documentation is now in the linux/Documentation directory.
-
--mlord@pobox.com
index 05bf6464534680e3340673db71e4f7293d6c9f61..63b2176b7d23912b4d73fe663ca6f8dca7dd560b 100644 (file)
@@ -260,7 +260,7 @@ static inline int DRIVE(kdev_t x) {
  * current disk size is unknown.
  * [Now it is rather a minimum]
  */
-#define MAX_DISK_SIZE 2 /* 3984*/
+#define MAX_DISK_SIZE 4 /* 3984*/
 
 #define K_64   0x10000         /* 64KB */
 
@@ -681,7 +681,7 @@ static int disk_change(int drive)
                                DPRINT("Disk type is undefined after "
                                       "disk change\n");
                        current_type[drive] = NULL;
-                       floppy_sizes[TOMINOR(current_drive)] = MAX_DISK_SIZE;
+                       floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE;
                }
 
                /*USETF(FD_DISK_NEWCHANGE);*/
@@ -905,7 +905,7 @@ static struct tq_struct floppy_tq =
 static void schedule_bh( void (*handler)(void*) )
 {
        floppy_tq.routine = (void *)(void *) handler;
-       queue_task_irq(&floppy_tq, &tq_immediate);
+       queue_task(&floppy_tq, &tq_immediate);
        mark_bh(IMMEDIATE_BH);
 }
 
@@ -1042,7 +1042,7 @@ static void setup_DMA(void)
        floppy_disable_hlt();
 }
 
-void show_floppy(void);
+static void show_floppy(void);
 
 /* waits until the fdc becomes ready */
 static int wait_til_ready(void)
@@ -1631,7 +1631,7 @@ static void print_result(char *message, int inr)
        printk("\n");
 }
 
-/* interrupt handler */
+/* interrupt handler. Note that this can be called externally on the Sparc */
 void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        void (*handler)(void) = DEVICE_INTR;
@@ -1734,7 +1734,7 @@ static void reset_fdc(void)
        }
 }
 
-void show_floppy(void)
+static void show_floppy(void)
 {
        int i;
 
@@ -3152,7 +3152,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
 }
 
 /* handle obsolete ioctl's */
-int ioctl_table[]= {
+static int ioctl_table[]= {
        FDCLRPRM,
        FDSETPRM,
        FDDEFPRM,
@@ -3800,7 +3800,7 @@ static char get_fdc_version(void)
 
 /* lilo configuration */
 
-void floppy_set_flags(int *ints,int param, int param2)
+static void floppy_set_flags(int *ints,int param, int param2)
 {
        int i;
 
index c2c480648d7b26918a89e58dc6a3932736adb7ed..53ee1a13f489d917661893edb9ad27a99dd201a2 100644 (file)
@@ -395,14 +395,6 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive)
 {
        struct request *rq = HWGROUP(drive)->rq;
 
-       /* The code in blk.h can screw us up on error recovery if the block
-          size is larger than 1k.  Fix that up here. */
-       if (!uptodate && rq->bh != 0) {
-               int adj = rq->current_nr_sectors - 1;
-               rq->current_nr_sectors -= adj;
-               rq->sector += adj;
-       }
-
        if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {
                struct packet_command *pc = (struct packet_command *)
                                              rq->buffer;
@@ -737,10 +729,8 @@ static void cdrom_read_intr (ide_drive_t *drive)
        /* Check for errors. */
        if (dma) {
                info->dma = 0;
-               if ((dma_error = HWIF(drive)->dmaproc(ide_dma_status_bad, drive))) {
-                       printk ("%s: disabled DMA\n", drive->name);
-                       drive->using_dma = 0;
-               }
+               if ((dma_error = HWIF(drive)->dmaproc(ide_dma_status_bad, drive)))
+                       HWIF(drive)->dmaproc(ide_dma_off, drive);
                (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
        }
 
index 58092646fbc734f9622f4d3a7f99e9a0654de3af..d362dfab4082dee2aab63bb531729ddb2d36b1b3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/block/ide-floppy.c    Version 0.4 - ALPHA     Jan  26, 1997
+ * linux/drivers/block/ide-floppy.c    Version 0.5 - ALPHA     Feb  21, 1997
  *
  * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
  */
  * Ver 0.2   Oct 31 96   Minor changes.
  * Ver 0.3   Dec  2 96   Fixed error recovery bug.
  * Ver 0.4   Jan 26 97   Add support for the HDIO_GETGEO ioctl.
+ * Ver 0.5   Feb 21 97   Add partitions support.
+ *                       Use the minimum of the LBA and CHS capacities.
+ *                       Avoid hwgroup->rq == NULL on the last irq.
+ *                       Fix potential null dereferencing with DEBUG_LOG.
  */
 
 #include <linux/config.h>
@@ -481,25 +485,23 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns
        struct request *rq = pc->rq;
        struct buffer_head *bh = rq->bh;
        int count;
-       
+
        while (bcount) {
-#if IDEFLOPPY_DEBUG_BUGS
+               if (pc->b_count == bh->b_size) {
+                       rq->sector += rq->current_nr_sectors;
+                       rq->nr_sectors -= rq->current_nr_sectors;
+                       idefloppy_end_request (1, HWGROUP(drive));
+                       if ((bh = rq->bh) != NULL)
+                               pc->b_count = 0;
+               }
                if (bh == NULL) {
                        printk (KERN_ERR "%s: bh == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
                        idefloppy_discard_data (drive, bcount);
                        return;
                }
-#endif /* IDEFLOPPY_DEBUG_BUGS */
                count = IDEFLOPPY_MIN (bh->b_size - pc->b_count, bcount);
                atapi_input_bytes (drive, bh->b_data + pc->b_count, count);
                bcount -= count; pc->b_count += count;
-               if (pc->b_count == bh->b_size) {
-                       rq->sector += rq->current_nr_sectors;
-                       rq->nr_sectors -= rq->current_nr_sectors;
-                       idefloppy_end_request (1, HWGROUP(drive));
-                       if ((bh = rq->bh) != NULL)
-                               pc->b_count = 0;
-               }
        }
 }
 
@@ -510,16 +512,6 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un
        int count;
        
        while (bcount) {
-#if IDEFLOPPY_DEBUG_BUGS
-               if (bh == NULL) {
-                       printk (KERN_ERR "%s: bh == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
-                       idefloppy_write_zeros (drive, bcount);
-                       return;
-               }
-#endif /* IDEFLOPPY_DEBUG_BUGS */
-               count = IDEFLOPPY_MIN (pc->b_count, bcount);
-               atapi_output_bytes (drive, pc->b_data, count);
-               bcount -= count; pc->b_data += count; pc->b_count -= count;
                if (!pc->b_count) {
                        rq->sector += rq->current_nr_sectors;
                        rq->nr_sectors -= rq->current_nr_sectors;
@@ -529,6 +521,14 @@ static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, un
                                pc->b_count = bh->b_size;
                        }
                }
+               if (bh == NULL) {
+                       printk (KERN_ERR "%s: bh == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
+                       idefloppy_write_zeros (drive, bcount);
+                       return;
+               }
+               count = IDEFLOPPY_MIN (pc->b_count, bcount);
+               atapi_output_bytes (drive, pc->b_data, count);
+               bcount -= count; pc->b_data += count; pc->b_count -= count;
        }
 }
 
@@ -584,7 +584,10 @@ static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_
 
        floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
 #if IDEFLOPPY_DEBUG_LOG
-       printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
+       if (floppy->failed_pc)
+               printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
+       else
+               printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
@@ -726,7 +729,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
        if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
                printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
                printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
-               drive->using_dma=0;
+               HWIF(drive)->dmaproc(ide_dma_off, drive);
                ide_do_reset (drive);
                return;
        }
@@ -841,7 +844,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 #ifdef CONFIG_BLK_DEV_TRITON
        if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
                printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
-               drive->using_dma=0;
+               HWIF(drive)->dmaproc(ide_dma_off, drive);
        }
        if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
                dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -875,6 +878,7 @@ static void idefloppy_rw_callback (ide_drive_t *drive)
        printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
+       idefloppy_end_request(1, HWGROUP(drive));
        return;
 }
 
@@ -930,9 +934,9 @@ static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
        pc->c[4] = start;
 }
 
-static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq)
+static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
 {
-       int block = rq->sector / floppy->bs_factor;
+       int block = sector / floppy->bs_factor;
        int blocks = rq->nr_sectors / floppy->bs_factor;
        
 #if IDEFLOPPY_DEBUG_LOG
@@ -991,7 +995,7 @@ static void idefloppy_do_request (ide_drive_t *drive, struct request *rq, unsign
                                return;
                        }
                        pc = idefloppy_next_pc_storage (drive);
-                       idefloppy_create_rw_cmd (floppy, pc, rq);
+                       idefloppy_create_rw_cmd (floppy, pc, rq, block);
                        break;
                case IDEFLOPPY_PC_RQ:
                        pc = (idefloppy_pc_t *) rq->buffer;
@@ -1029,7 +1033,7 @@ static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
        idefloppy_pc_t pc;
        idefloppy_mode_parameter_header_t *header;
        idefloppy_flexible_disk_page_t *page;
-       int capacity;
+       int capacity, lba_capacity;
 
        idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
        if (idefloppy_queue_pc_tail (drive,&pc)) {
@@ -1044,17 +1048,21 @@ static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
        page->cyls = ntohs (page->cyls);
        page->rpm = ntohs (page->rpm);
        capacity = page->cyls * page->heads * page->sectors * page->sector_size;
-       if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t))) {
+       if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
                printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n",
                        drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
                        page->transfer_rate / 8, page->sector_size, page->rpm);
-               floppy->flexible_disk_page = *page;
-               drive->bios_cyl = page->cyls;
-               drive->bios_head = page->heads;
-               drive->bios_sect = page->sectors;
-               if (capacity != floppy->blocks * floppy->block_size)
-                       printk (KERN_NOTICE "%s: The drive reports both %d and %d bytes as its capacity\n",
-                               drive->name, capacity, floppy->blocks * floppy->block_size);
+
+       floppy->flexible_disk_page = *page;
+       drive->bios_cyl = page->cyls;
+       drive->bios_head = page->heads;
+       drive->bios_sect = page->sectors;
+       lba_capacity = floppy->blocks * floppy->block_size;
+       if (capacity != lba_capacity) {
+               printk (KERN_NOTICE "%s: The drive reports both %d and %d bytes as its capacity\n",
+                       drive->name, capacity, lba_capacity);
+               capacity = IDEFLOPPY_MIN(capacity, lba_capacity);
+               floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
        }
        return 0;
 }
@@ -1071,6 +1079,11 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
        idefloppy_capacity_descriptor_t *descriptor;
        int i, descriptors, rc = 1, blocks, length;
        
+       drive->bios_cyl = 0;
+       drive->bios_head = drive->bios_sect = 0;
+       floppy->blocks = floppy->bs_factor = 0;
+       drive->part[0].nr_sects = 0;
+
        idefloppy_create_read_capacity_cmd (&pc);
        if (idefloppy_queue_pc_tail (drive, &pc)) {
                printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
@@ -1083,10 +1096,9 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
                blocks = descriptor->blocks = ntohl (descriptor->blocks);
                length = descriptor->length = ntohs (descriptor->length);
                if (!i && descriptor->dc == CAPACITY_CURRENT) {
-                       if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) {
+                       if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
                                printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length);
-                               floppy->capacity = *descriptor;
-                       }
+                       floppy->capacity = *descriptor;
                        if (!length || length % 512)
                                printk (KERN_ERR "%s: %d bytes block size not supported\n", drive->name, length);
                        else {
@@ -1094,9 +1106,6 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
                                floppy->block_size = length;
                                if ((floppy->bs_factor = length / 512) != 1)
                                        printk (KERN_NOTICE "%s: warning: non 512 bytes block size not fully supported\n", drive->name);
-                               drive->part[0].nr_sects = blocks * floppy->bs_factor;
-                               if (length > BLOCK_SIZE)
-                                       blksize_size[HWIF(drive)->major][drive->select.b.unit << PARTN_BITS] = length;
                                rc = 0;
                        }
                }
@@ -1106,6 +1115,7 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
 #endif /* IDEFLOPPY_DEBUG_INFO */
        }
        (void) idefloppy_get_flexible_disk_page (drive);
+       drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor;
        return rc;
 }
 
@@ -1183,7 +1193,7 @@ static unsigned long idefloppy_capacity (ide_drive_t *drive)
        idefloppy_floppy_t *floppy = drive->driver_data;
        unsigned long capacity = floppy->blocks * floppy->bs_factor;
 
-       return capacity ? capacity : 0x7fffffff;
+       return capacity;
 }
 
 /*
index 908bd6ef9fd63765f2ddf1754f7f08a74504f62a..38888dc992c7dbaee36dbb8933a4976d7f563af0 100644 (file)
@@ -1780,7 +1780,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
        if (clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
                printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
                printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-               drive->using_dma=0;
+               HWIF(drive)->dmaproc(ide_dma_off, drive);
                ide_do_reset (drive);
                return;
        }
@@ -1918,7 +1918,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 #ifdef CONFIG_BLK_DEV_TRITON
        if (clear_bit (PC_DMA_ERROR, &pc->flags)) {
                printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-               drive->using_dma=0;
+               HWIF(drive)->dmaproc(ide_dma_off, drive);
        }
        if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
                dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
index be8d666f1416cca189d301389f4e9741343367b3..862e834d3046497b63efe1a607ea0d49b440b3a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 6.01  Jan  26, 1997
+ *  linux/drivers/block/ide.c  Version 6.02  Mar  11, 1997
  *
  *  Copyright (C) 1994-1997  Linus Torvalds & authors (see below)
  */
  *                     don't flush leftover data for ATAPI devices
  * Version 6.01                clear hwgroup->active while the hwgroup sleeps
  *                     support HDIO_GETGEO for floppies
+ * Version 6.02                fix ide_ack_intr() call
+ *                     check partition table on floppies
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -632,7 +634,8 @@ void ide_geninit (struct gendisk *gd)
                ide_drive_t *drive = &hwif->drives[unit];
 
                drive->part[0].nr_sects = current_capacity(drive);
-               if (!drive->present || drive->media != ide_disk || drive->driver == NULL)
+               if (!drive->present || (drive->media != ide_disk && drive->media != ide_floppy) ||
+                   drive->driver == NULL || !drive->part[0].nr_sects)
                        drive->part[0].start_sect = -1; /* skip partition check */
        }
 }
@@ -722,10 +725,8 @@ static void pre_reset (ide_drive_t *drive)
        if (!drive->keep_settings) {
                drive->unmask = 0;
                drive->io_32bit = 0;
-               if (drive->using_dma) {
-                       drive->using_dma = 0;
-                       printk("%s: disabled DMA\n", drive->name);
-               }
+               if (drive->using_dma)
+                       HWIF(drive)->dmaproc(ide_dma_off, drive);
        }
        if (drive->driver != NULL)
                DRIVER(drive)->pre_reset(drive);
@@ -1449,7 +1450,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
        ide_hwgroup_t *hwgroup = dev_id;
        ide_handler_t *handler;
 
-       if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_DATA_OFFSET],
+       if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_STATUS_OFFSET],
                           hwgroup->hwif->io_ports[IDE_IRQ_OFFSET]))
                return;
 
@@ -1620,7 +1621,8 @@ int ide_revalidate_disk(kdev_t i_rdev)
        };
 
        drive->part[0].nr_sects = current_capacity(drive);
-       if (drive->media != ide_disk || drive->driver == NULL)
+       if ((drive->media != ide_disk && drive->media != ide_floppy) ||
+            drive->driver == NULL || !drive->part[0].nr_sects)
                drive->part[0].start_sect = -1;
        resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
 
@@ -1969,7 +1971,10 @@ static int ide_ioctl (struct inode *inode, struct file *file,
                                                restore_flags(flags);
                                                return -EPERM;
                                        }
-                                       drive->using_dma = arg;
+                                       if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) {
+                                               restore_flags(flags);
+                                               return -EIO;
+                                       }
                                        break;
                                case HDIO_SET_KEEPSETTINGS:
                                        drive->keep_settings = arg;
index 3c8d350853c75a17b307567574fda148ff090fb7..2eb6eb13a5895c60e2bed814e44d50875506a1fc 100644 (file)
@@ -266,7 +266,8 @@ typedef struct ide_drive_s {
 typedef enum { ide_dma_read = 0,       ide_dma_write = 1,
                ide_dma_abort = 2,      ide_dma_check = 3,
                ide_dma_status_bad = 4, ide_dma_transferred = 5,
-               ide_dma_begin = 6 }
+               ide_dma_begin = 6,      ide_dma_on = 7,
+               ide_dma_off = 8 }
        ide_dma_action_t;
 
 typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
@@ -583,6 +584,7 @@ void ide_init_subdrivers (void);
 extern struct file_operations ide_fops[];
 #endif
 
+#ifdef _IDE_C
 #ifdef CONFIG_BLK_DEV_IDEDISK
 int idedisk_init (void);
 #endif /* CONFIG_BLK_DEV_IDEDISK */
@@ -598,6 +600,7 @@ int idefloppy_init (void);
 #ifdef CONFIG_BLK_DEV_IDESCSI
 int idescsi_init (void);
 #endif /* CONFIG_BLK_DEV_IDESCSI */
+#endif /* _IDE_C */
 
 int ide_register_module (ide_module_t *module);
 void ide_unregister_module (ide_module_t *module);
index cda6eb85c76f2531035838db5bc268d296d5c933..faad205adddc988485e3c7bc673323914a3201f8 100644 (file)
@@ -124,7 +124,7 @@ static inline void plug_device(struct blk_dev_struct * dev)
        if (dev->current_request)
                return;
        dev->current_request = &dev->plug;
-       queue_task_irq_off(&dev->plug_tq, &tq_disk);
+       queue_task(&dev->plug_tq, &tq_disk);
 }
 
 /*
index f6ef31512f5718288fd1560725b451b057acb1b0..bf9269dc5d54d45e9fe81d19a90be918f7062abb 100644 (file)
@@ -1,28 +1,34 @@
 /*
- *  linux/drivers/block/triton.c       Version 1.20  Jan 27, 1997
+ *  linux/drivers/block/triton.c       Version 2.00  March 9, 1997
  *
  *  Copyright (c) 1995-1997  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
- * This module provides support for the Bus Master IDE DMA function
- * of the Intel PCI Triton I/II chipsets (i82371FB or i82371SB).
+ * This module provides support for the bus-master IDE DMA function
+ * of the Intel PCI Triton chipset families, which use the PIIX (i82371FB,
+ * for the 430 FX chipset), and the enhanced PIIX3 (i82371SB for the 430 HX/VX
+ * and 440 chipsets).
  *
- * Pretty much the same code will work for the OPTi "Viper" chipset.
- * Look for DMA support for this in linux kernel 2.1.xx, when it appears.
+ * "PIIX" stands for "PCI ISA IDE Xcellerator".
  *
- * Up to four drives may be enabled for DMA, and the Triton chipset will
- * (hopefully) arbitrate the PCI bus among them.  Note that the i82371 chip
+ * Pretty much the same code could work for other IDE PCI bus-mastering chipsets.
+ * Look for DMA support for this someday in the not too distant future.
+ *
+ * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
+ *
+ * Up to four drives may be enabled for DMA, and the PIIX/PIIX3 chips
+ * will arbitrate the PCI bus among them.  Note that the PIIX/PIIX3
  * provides a single "line buffer" for the BM IDE function, so performance of
  * multiple (two) drives doing DMA simultaneously will suffer somewhat,
  * as they contest for that resource bottleneck.  This is handled transparently
- * inside the i82371 chip.
+ * inside the PIIX/PIIX3.
  *
  * By default, DMA support is prepared for use, but is currently enabled only
- * for drives which support multi-word DMA mode2 (mword2), or which are
+ * for drives which support DMA mode2 (multi/single word), or which are
  * recognized as "good" (see table below).  Drives with only mode0 or mode1
- * (single or multi) DMA should also work with this chipset/driver (eg. MC2112A)
+ * (multi/single word) DMA should also work with this chipset/driver (eg. MC2112A)
  * but are not enabled by default.  Use "hdparm -i" to view modes supported
  * by a given drive.
  *
  * the "hdparm -X" feature.  There is seldom a need to do this, as drives
  * normally power-up with their "best" PIO/DMA modes enabled.
  *
- * Testing was done with an ASUS P55TP4XE/100 system and the following drives:
- *
- *   Quantum Fireball 1080A (1Gig w/83kB buffer), DMA mode2, PIO mode4.
- *     - DMA mode2 works well (7.4MB/sec), despite the tiny on-drive buffer.
- *     - This drive also does PIO mode4, at about the same speed as DMA mode2.
- *       An awesome drive for the price!
- *
- *   Fujitsu M1606TA (1Gig w/256kB buffer), DMA mode2, PIO mode4.
- *     - DMA mode2 gives horrible performance (1.6MB/sec), despite the good
- *       size of the on-drive buffer and a boasted 10ms average access time.
- *     - PIO mode4 was better, but peaked at a mere 4.5MB/sec.
- *
- *   Micropolis MC2112A (1Gig w/508kB buffer), drive pre-dates EIDE and ATA2.
- *     - DMA works fine (2.2MB/sec), probably due to the large on-drive buffer.
- *     - This older drive can also be tweaked for fastPIO (3.7MB/sec) by using
- *       maximum clock settings (5,4) and setting all flags except prefetch.
- *
- *   Western Digital AC31000H (1Gig w/128kB buffer), DMA mode1, PIO mode3.
- *     - DMA does not work reliably.  The drive appears to be somewhat tardy
- *       in deasserting DMARQ at the end of a sector.  This is evident in
- *       the observation that WRITEs work most of the time, depending on
- *       cache-buffer occupancy, but multi-sector reads seldom work.
- *
- * Testing was done with a Gigabyte GA-586 ATE system and the following drive:
- * (Uwe Bonnes - bon@elektron.ikp.physik.th-darmstadt.de)
- *
- *   Western Digital AC31600H (1.6Gig w/128kB buffer), DMA mode2, PIO mode4.
- *     - much better than its 1Gig cousin, this drive is reported to work
- *       very well with DMA (7.3MB/sec).
+ * Testing has been done with a rather extensive number of drives,
+ * with Quantum & Western Digital models generally outperforming the pack,
+ * and Fujitsu & Conner (and some Seagate which are really Conner) drives
+ * showing more lackluster throughput.
  *
- * Other drives:
- *
- *   Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
- *     - a budget drive, with budget performance, around 3MB/sec.
- *
- *   Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
- *     - another "caviar" drive, similar to the AC31000, except that this one
- *       worked with DMA in at least one system.  Throughput is about 3.8MB/sec
- *       for both DMA and PIO.
- *
- *   Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
- *     - like most Conner models, this drive proves that even a fast interface
- *       cannot improve slow media.  Both DMA and PIO peak around 3.5MB/sec.
- *
- *   Maxtor 71260AT (1204Meg w/256kB buffer), DMA mword0/sword2, PIO mode3.
- *     - works with DMA, on some systems (but not always on others, eg. Dell),
- *     giving 3-4MB/sec performance, about the same as mode3.
- *
- * If you have any drive models to add, email your results to:  mlord@pobox.com
  * Keep an eye on /var/adm/messages for "DMA disabled" messages.
  *
  * Some people have reported trouble with Intel Zappa motherboards.
@@ -98,7 +60,7 @@
  * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for fixing the
  * problem with some (all?) ACER motherboards/BIOSs.
  *
- * And, yes, Intel Zappa boards really *do* use the Triton IDE ports.
+ * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
  */
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <asm/dma.h>
 
 #include "ide.h"
+#include "ide_modes.h"
 
-#undef DISPLAY_TRITON_TIMINGS  /* define this to display timings */
+#define DISPLAY_PIIX_TIMINGS   /* define this to display timings */
 
 /*
  * good_dma_drives() lists the model names (from "hdparm -i")
- * of drives which do not support mword2 DMA but which are
+ * of drives which do not support mode2 DMA but which are
  * known to work fine with this interface under Linux.
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
                                 "CONNER CTMA 4000",
-                                "CONNER CTT8000-A",
                                 NULL};
 
 /*
@@ -152,6 +114,37 @@ const char *good_dma_drives[] = {"Micropolis 2112A",
  */
 static unsigned int piix_key;
 
+#define PIIX_FLAGS_FAST_PIO    1
+#define PIIX_FLAGS_USE_IORDY   2
+#define PIIX_FLAGS_PREFETCH    4
+#define PIIX_FLAGS_FAST_DMA    8
+
+typedef struct {
+       unsigned d0_flags       :4;
+       unsigned d1_flags       :4;
+       unsigned recovery       :2;
+       unsigned reserved       :2;
+       unsigned sample         :2;
+       unsigned sidetim_enabled:1;
+       unsigned ports_enabled  :1;
+} piix_timing_t;
+
+typedef struct {
+       unsigned pri_recovery   :2;
+       unsigned pri_sample     :2;
+       unsigned sec_recovery   :2;
+       unsigned sec_sample     :2;
+} piix_sidetim_t;
+
+
+/*
+ * We currently can handle only one PIIX chip here
+ */
+static piix_pci_bus = 0;
+static piix_pci_fn  = 0;
+
+static int config_drive_for_dma (ide_drive_t *);
+
 /*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
@@ -240,31 +233,8 @@ static int build_dmatable (ide_drive_t *drive)
        return 1;       /* let the PIO routines handle this weirdness */
 }
 
-static int config_drive_for_dma (ide_drive_t *drive)
-{
-       const char **list;
-
-       struct hd_driveid *id = drive->id;
-       if (id && (id->capability & 1)) {
-               /* Enable DMA on any drive that supports mword2 DMA */
-               if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
-                       drive->using_dma = 1;
-                       return 0;               /* DMA enabled */
-               }
-               /* Consult the list of known "good" drives */
-               list = good_dma_drives;
-               while (*list) {
-                       if (!strcmp(*list++,id->model)) {
-                               drive->using_dma = 1;
-                               return 0;       /* DMA enabled */
-                       }
-               }
-       }
-       return 1;       /* DMA not enabled */
-}
-
 /*
- * triton_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ * piix_dmaproc() initiates/aborts DMA read/write operations on a drive.
  *
  * The caller is assumed to have selected the drive and programmed the drive's
  * sector address using CHS or LBA.  All that remains is to prepare for DMA
@@ -278,12 +248,40 @@ static int config_drive_for_dma (ide_drive_t *drive)
  * Returns 1 if DMA read/write could not be started, in which case
  * the caller should revert to PIO for the current request.
  */
-static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+static int piix_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
        unsigned long dma_base = HWIF(drive)->dma_base;
        unsigned int reading = (1 << 3);
+       piix_timing_t timing;
+       unsigned short reg;
+       byte dflags;
 
        switch (func) {
+               case ide_dma_off:
+                       printk("%s: DMA disabled\n", drive->name);
+               case ide_dma_on:
+                       drive->using_dma = (func == ide_dma_on);
+                       reg = (HWIF(drive)->io_ports[IDE_DATA_OFFSET] == 0x170) ? 0x42 : 0x40;
+                       if (pcibios_read_config_word(piix_pci_bus, piix_pci_fn, reg, (short *)&timing)) {
+                               printk("%s: pcibios read failed\n", HWIF(drive)->name);
+                               return 1;
+                       }
+                       dflags = drive->select.b.unit ? timing.d1_flags : timing.d0_flags;
+                       if (dflags & PIIX_FLAGS_FAST_PIO) {
+                               if (func == ide_dma_on && drive->media == ide_disk)
+                                       dflags |= PIIX_FLAGS_FAST_DMA;
+                               else
+                                       dflags &= ~PIIX_FLAGS_FAST_DMA;
+                               if (drive->select.b.unit == 0)
+                                       timing.d0_flags = dflags;
+                               else
+                                       timing.d1_flags = dflags;
+                               if (pcibios_write_config_word(piix_pci_bus, piix_pci_fn, reg, *(short *)&timing)) {
+                                       printk("%s: pcibios write failed\n", HWIF(drive)->name);
+                                       return 1;
+                               }
+                       }
+                       return 0;
                case ide_dma_abort:
                        outb(inb(dma_base)&~1, dma_base);       /* stop DMA */
                        return 0;
@@ -305,7 +303,7 @@ static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
                        outb(inb(dma_base)|1, dma_base);        /* begin DMA */
                        return 0;
                default:
-                       printk("triton_dmaproc: unsupported func: %d\n", func);
+                       printk("piix_dmaproc: unsupported func: %d\n", func);
                        return 1;
        }
        if (build_dmatable (drive))
@@ -321,31 +319,42 @@ static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
        return 0;
 }
 
-#ifdef DISPLAY_TRITON_TIMINGS
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+       const char **list;
+
+       struct hd_driveid *id = drive->id;
+       if (id && (id->capability & 1)) {
+               /* Enable DMA on any drive that supports mode2 (multi/single word) DMA */
+               if (id->field_valid & 2)
+                       if  ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
+                               return piix_dmaproc(ide_dma_on, drive);
+               /* Consult the list of known "good" drives */
+               list = good_dma_drives;
+               while (*list) {
+                       if (!strcmp(*list++,id->model))
+                               return piix_dmaproc(ide_dma_on, drive);
+               }
+       }
+       return piix_dmaproc(ide_dma_off, drive);
+}
+
+#ifdef DISPLAY_PIIX_TIMINGS
 /*
- * print_triton_drive_flags() displays the currently programmed options
- * in the i82371 (Triton) for a given drive.
- *
- *     If fastDMA  is "no", then slow ISA timings are used for DMA data xfers.
- *     If fastPIO  is "no", then slow ISA timings are used for PIO data xfers.
- *     If IORDY    is "no", then IORDY is assumed to always be asserted.
- *     If PreFetch is "no", then data pre-fetch/post are not used.
- *
- * When "fastPIO" and/or "fastDMA" are "yes", then faster PCI timings and
- * back-to-back 16-bit data transfers are enabled, using the sample_CLKs
- * and recovery_CLKs (PCI clock cycles) timing parameters for that interface.
+ * print_piix_drive_flags() displays the currently programmed options
+ * in the PIIX/PIIX3 for a given drive.
  */
-static void print_triton_drive_flags (unsigned int unit, byte flags)
+static void print_piix_drive_flags (const char *unit, byte dflags)
 {
-       printk("         %s ", unit ? "slave :" : "master:");
-       printk( "fastDMA=%s",   (flags&9)       ? "on " : "off");
-       printk(" PreFetch=%s",  (flags&4)       ? "on " : "off");
-       printk(" IORDY=%s",     (flags&2)       ? "on " : "off");
-       printk(" fastPIO=%s\n", ((flags&9)==1)  ? "on " : "off");
+       printk("         %s ", unit);
+       printk( "fastDMA=%s",   (dflags & PIIX_FLAGS_FAST_PIO)  ? "yes" : "no ");
+       printk(" PreFetch=%s",  (dflags & PIIX_FLAGS_PREFETCH)  ? "on " : "off");
+       printk(" IORDY=%s",     (dflags & PIIX_FLAGS_USE_IORDY) ? "on " : "off");
+       printk(" fastPIO=%s\n", ((dflags & (PIIX_FLAGS_FAST_PIO|PIIX_FLAGS_FAST_DMA)) == PIIX_FLAGS_FAST_PIO) ? "on " : "off");
 }
-#endif /* DISPLAY_TRITON_TIMINGS */
+#endif /* DISPLAY_PIIX_TIMINGS */
 
-static void init_triton_dma (ide_hwif_t *hwif, unsigned short base)
+static void init_piix_dma (ide_hwif_t *hwif, unsigned short base)
 {
        static unsigned long dmatable = 0;
 
@@ -367,7 +376,7 @@ static void init_triton_dma (ide_hwif_t *hwif, unsigned short base)
                        hwif->dmatable = (unsigned long *) dmatable;
                        dmatable += (PRD_ENTRIES * PRD_BYTES);
                        outl(virt_to_bus(hwif->dmatable), base + 4);
-                       hwif->dmaproc  = &triton_dmaproc;
+                       hwif->dmaproc  = &piix_dmaproc;
                }
        }
        printk("\n");
@@ -429,10 +438,16 @@ void ide_init_triton (byte bus, byte fn)
 {
        int rc = 0, h;
        int dma_enabled = 0;
-       unsigned short pcicmd;
-       unsigned int bmiba, timings;
+       unsigned short pcicmd, devid;
+       unsigned int bmiba;
+       const char *chipset = "ide";
+       piix_timing_t timings[2];
 
-       printk("ide: i82371 PIIX (Triton) on PCI bus %d function %d\n", bus, fn);
+       if (pcibios_read_config_word(piix_pci_bus, piix_pci_fn, 0x02, &devid))
+               goto quit;
+       chipset = (devid == PCI_DEVICE_ID_INTEL_82371SB_1) ? "PIIX3" : "PIIX";
+
+       printk("%s: bus-master IDE device on PCI bus %d function %d\n", chipset, bus, fn);
 
        /*
         * See if IDE ports are enabled
@@ -440,21 +455,26 @@ void ide_init_triton (byte bus, byte fn)
        if ((rc = pcibios_read_config_word(bus, fn, 0x04, &pcicmd)))
                goto quit;
        if ((pcicmd & 1) == 0)  {
-               printk("ide: ports are not enabled (BIOS)\n");
+               printk("%s: IDE ports are not enabled (BIOS)\n", chipset);
                goto quit;
        }
-       if ((rc = pcibios_read_config_dword(bus, fn, 0x40, &timings)))
+       if ((rc = pcibios_read_config_word(bus, fn, 0x40, (short *)&timings[0])))
+               goto quit;
+       if ((rc = pcibios_read_config_word(bus, fn, 0x42, (short *)&timings[1])))
                goto quit;
-       if (!(timings & 0x80008000)) {
-               printk("ide: neither port is enabled\n");
+       if ((!timings[0].ports_enabled) || (!timings[1].ports_enabled)) {
+               printk("%s: neither IDE port is enabled\n", chipset);
                goto quit;
        }
 
+       piix_pci_bus = bus;
+       piix_pci_fn  = fn;
+
        /*
         * See if Bus-Mastered DMA is enabled
         */
        if ((pcicmd & 4) == 0) {
-               printk("ide: BM-DMA feature is not enabled (BIOS)\n");
+               printk("%s: bus-master DMA feature is not enabled (BIOS)\n", chipset);
        } else {
                /*
                 * Get the bmiba base address
@@ -466,10 +486,10 @@ void ide_init_triton (byte bus, byte fn)
                        dma_enabled = 1;
                } else {
                        unsigned short base;
-                       printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
+                       printk("%s: bus-master base address is invalid (0x%04x, BIOS problem)\n", chipset, bmiba);
                        base = find_free_region(16);
                        if (base) {
-                               printk("ide: bypassing BIOS; setting BMIBA to 0x%04x\n", base);
+                               printk("%s: bypassing BIOS; setting bus-master base address to 0x%04x\n", chipset, base);
                                piix_key = 0x80000000 + (fn * 0x100);
                                put_piix_reg(0x04,get_piix_reg(0x04)&~5);
                                put_piix_reg(0x20,(get_piix_reg(0x20)&0xFFFF000F)|base|1);
@@ -478,8 +498,10 @@ void ide_init_triton (byte bus, byte fn)
                                if (bmiba == base && (get_piix_reg(0x04) & 5) == 5)
                                        dma_enabled = 1;
                                else
-                                       printk("ide: no such luck; DMA disabled\n");
+                                       printk("%s: operation failed\n", chipset);
                        }
+                       if (!dma_enabled)
+                               printk("%s: DMA is disabled (BIOS)\n", chipset);
                }
        }
 
@@ -487,56 +509,51 @@ void ide_init_triton (byte bus, byte fn)
         * Save the dma_base port addr for each interface
         */
        for (h = 0; h < MAX_HWIFS; ++h) {
-#ifdef DISPLAY_TRITON_TIMINGS
-               byte s_clks, r_clks;
-               unsigned short devid;
-#endif /* DISPLAY_TRITON_TIMINGS */
+               unsigned int pri_sec;
+               piix_timing_t timing;
                ide_hwif_t *hwif = &ide_hwifs[h];
-               unsigned short time;
-               if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0) {
-                       time = timings & 0xffff;
-                       if ((time & 0x8000) == 0)       /* interface enabled? */
-                               continue;
-                       hwif->chipset = ide_triton;
-                       if (dma_enabled)
-                               init_triton_dma(hwif, bmiba);
-               } else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170) {
-                       time = timings >> 16;
-                       if ((time & 0x8000) == 0)       /* interface enabled? */
-                               continue;
-                       hwif->chipset = ide_triton;
-                       if (dma_enabled)
-                               init_triton_dma(hwif, bmiba + 8);
-               } else
+               switch (hwif->io_ports[IDE_DATA_OFFSET]) {
+                       case 0x1f0:     pri_sec = 0; break;
+                       case 0x170:     pri_sec = 1; break;
+                       default:        continue;
+               }
+               timing = timings[pri_sec];
+               if (!timing.ports_enabled)      /* interface disabled? */
                        continue;
-#ifdef DISPLAY_TRITON_TIMINGS
-               s_clks = ((~time >> 12) & 3) + 2;
-               r_clks = ((~time >>  8) & 3) + 1;
-               printk("    %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n",
-                hwif->name, time, s_clks, r_clks);
-               if ((time & 0x40) && !pcibios_read_config_word(bus, fn, 0x02, &devid)
-                && devid == PCI_DEVICE_ID_INTEL_82371SB_1)
+               hwif->chipset = ide_triton;
+               if (dma_enabled)
+                       init_piix_dma(hwif, bmiba + (pri_sec ? 8 : 0));
+#ifdef DISPLAY_PIIX_TIMINGS
+               /*
+                * Display drive timings/modes
+                */
                {
-                       byte stime;
-                       if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) {
-                               if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0) {
-                                       s_clks = ~stime >> 6;
-                                       r_clks = ~stime >> 4;
+                       const char *slave;
+                       piix_sidetim_t sidetim;
+                       byte sample   = 5 - timing.sample;
+                       byte recovery = 4 - timing.recovery;
+                       if (devid == PCI_DEVICE_ID_INTEL_82371SB_1
+                        && timing.sidetim_enabled
+                        && !pcibios_read_config_byte(piix_pci_bus, piix_pci_fn, 0x44, (byte *) &sidetim))
+                               slave = "";             /* PIIX3 */
+                       else
+                               slave = "/slave";       /* PIIX, or PIIX3 in compatibility mode */
+                       printk("    %s master%s: sample_CLKs=%d, recovery_CLKs=%d\n", hwif->name, slave, sample, recovery);
+                       print_piix_drive_flags ("master:", timing.d0_flags);
+                       if (!*slave) {
+                               if (pri_sec == 0) {
+                                       sample   = 5 - sidetim.pri_sample;
+                                       recovery = 4 - sidetim.pri_recovery;
                                } else {
-                                       s_clks = ~stime >> 2;
-                                       r_clks = ~stime;
+                                       sample   = 5 - sidetim.sec_sample;
+                                       recovery = 4 - sidetim.sec_recovery;
                                }
-                               s_clks = (s_clks & 3) + 2;
-                               r_clks = (r_clks & 3) + 1;
-                               printk("                   slave: sample_CLKs=%d, recovery_CLKs=%d\n",
-                                       s_clks, r_clks);
+                               printk("         slave : sample_CLKs=%d, recovery_CLKs=%d\n", sample, recovery);
                        }
+                       print_piix_drive_flags ("slave :", timing.d1_flags);
                }
-               print_triton_drive_flags (0, time & 0xf);
-               print_triton_drive_flags (1, (time >> 4) & 0xf);
-#endif /* DISPLAY_TRITON_TIMINGS */
+#endif /* DISPLAY_PIIX_TIMINGS */
        }
 
-quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc));
+quit: if (rc) printk("%s: pcibios access failed - %s\n", chipset, pcibios_strerror(rc));
 }
-
index 858232f4ae91c58fc4df59c828de3f841648e277..949cfd33f3f9b243f809af4d16487cea7b6c4667 100644 (file)
@@ -1,4 +1,3 @@
-extern void allow_interrupts(void);
 /*
  * linux/drivers/char/keyboard.c
  *
@@ -1081,7 +1080,6 @@ static int send_data(unsigned char data)
                reply_expected = 1;
                outb_p(data, 0x60);
                for(i=0; i<0x200000; i++) {
-                       allow_interrupts();
                        inb_p(0x64);            /* just as a delay */
                        if (acknowledge)
                                return 1;
index 977669343e2bf8d422b4872ed7f2b9165f953238..a83c5d3b146ff6c57e63f40e85d7b9ad260cb6be 100644 (file)
@@ -80,9 +80,10 @@ static int misc_read_proc(char *buf, char **start, off_t offset,
        struct miscdevice *p;
 
        len=0;
-       for (p = misc_list.next; p != &misc_list; p = p->next)
+       for (p = misc_list.next; p != &misc_list && len < 4000; p = p->next)
                len += sprintf(buf+len, "%3i %s\n",p->minor, p->name ?: "");
-       return len;
+       *start = buf + offset;
+       return len > offset ? len - offset : 0;
 }
 
 #endif /* PROC_FS */
index f5ba6362cee2283f227f004c31f45f5400ffdf10..9620589904be42e56a39807017b85483ffa88b8a 100644 (file)
@@ -1162,7 +1162,7 @@ random_write(struct inode * inode, struct file * file,
                p += bytes;
                ret += bytes;
                
-               i = (c+sizeof(__u32)-1) / sizeof(__u32);
+               i = (bytes+sizeof(__u32)-1) / sizeof(__u32);
                while (i--)
                        add_entropy_word(&random_state, buf[i]);
        }
index a505e93f51167972a94c1b59a2520226bafec73f..e2844389bfd7767e76a5deb6cff88aae75d31d4f 100644 (file)
@@ -458,7 +458,7 @@ static _INLINE_ void rs_sched_event(struct async_struct *info,
                                  int event)
 {
        info->event |= 1 << event;
-       queue_task_irq_off(&info->tqueue, &tq_serial);
+       queue_task(&info->tqueue, &tq_serial);
        mark_bh(SERIAL_BH);
 }
 
@@ -540,7 +540,7 @@ static _INLINE_ void receive_chars(struct async_struct *info,
        ignore_char:
                *status = serial_inp(info, UART_LSR);
        } while (*status & UART_LSR_DR);
-       queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+       queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
 static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
@@ -625,7 +625,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
 #ifdef SERIAL_DEBUG_OPEN
                        printk("scheduling hangup...");
 #endif
-                       queue_task_irq_off(&info->tqueue_hangup,
+                       queue_task(&info->tqueue_hangup,
                                           &tq_scheduler);
                }
        }
index da5af96253b7091ce5dc848c3208d79cd0048a66..b58311c72a8ceb576b6fb46aca5d4f87ef4b23c4 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
+#include <linux/reboot.h>
 #include <asm/uaccess.h>
 
 #define WATCHDOG_MINOR 130
@@ -54,12 +55,11 @@ static int timer_alive = 0;
  
 static void watchdog_fire(unsigned long data)
 {
-       extern void hard_reset_now(void);
 #ifdef ONLY_TESTING
                printk(KERN_CRIT "SOFTDOG: Would Reboot.\n");
 #else
        printk(KERN_CRIT "SOFTDOG: Initiating system reboot.\n");
-       hard_reset_now();
+       machine_restart(NULL);
        printk("WATCHDOG: Reboot didn't ?????\n");
 #endif
 }
index 4866b080f3a498a588f032bafbee97a6c913ba7c..47e65b453dd32b26f9cdde09241ca29f038747ad 100644 (file)
@@ -520,12 +520,27 @@ static struct wait_queue *vt_activate_queue = NULL;
 
 /*
  * Sleeps until a vt is activated, or the task is interrupted. Returns
- * 0 if activation, -1 if interrupted.
+ * 0 if activation, -EINTR if interrupted.
  */
-int vt_waitactive(void)
+int vt_waitactive(int vt)
 {
-       interruptible_sleep_on(&vt_activate_queue);
-       return (current->signal & ~current->blocked) ? -1 : 0;
+       int retval;
+       struct wait_queue wait = { current, NULL };
+
+       add_wait_queue(&vt_activate_queue, &wait);
+       for (;;) {
+               current->state = TASK_INTERRUPTIBLE;
+               retval = 0;
+               if (vt == fg_console)
+                       break;
+               retval = -EINTR;
+               if (current->signal & ~current->blocked)
+                       break;
+               schedule();
+       }
+       remove_wait_queue(&vt_activate_queue, &wait);
+       current->state = TASK_RUNNING;
+       return retval;
 }
 
 #define vt_wake_waitactive() wake_up(&vt_activate_queue)
@@ -1210,7 +1225,7 @@ static void release_dev(struct file * filp)
         * Make sure that the tty's task queue isn't activated.  If it
         * is, take it out of the linked list.
         */
-       cli();
+       spin_lock_irq(&tqueue_lock);
        if (tty->flip.tqueue.sync) {
                struct tq_struct *tq, *prev;
 
@@ -1224,7 +1239,7 @@ static void release_dev(struct file * filp)
                        }
                }
        }
-       sti();
+       spin_unlock_irq(&tqueue_lock);
        tty->magic = 0;
        (*tty->driver.refcount)--;
        free_page((unsigned long) tty);
index 6872bafa4d35031c932ccbee36db4e98b6a5998e..c14babf6dfc1eba8c6fe15895a5bd23e34ab29fa 100644 (file)
@@ -157,16 +157,12 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
                return retval;
 
        if (opt & TERMIOS_TERMIO) {
-               retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
-               if (retval)
-                       return retval;
                memcpy(&tmp_termios, tty->termios, sizeof(struct termios));
-               user_termio_to_kernel_termios(&tmp_termios, (struct termio *) arg);
+               if (user_termio_to_kernel_termios(&tmp_termios, (struct termio *) arg))
+                       return -EFAULT;
        } else {
-               retval = user_termios_to_kernel_termios
-                       (&tmp_termios, (struct termios *) arg);
-               if (retval)
-                       return retval;
+               if (user_termios_to_kernel_termios(&tmp_termios, (struct termios *) arg))
+                       return -EFAULT;
        }
 
        if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
@@ -184,12 +180,8 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
 
 static int get_termio(struct tty_struct * tty, struct termio * termio)
 {
-       int i;
-
-       i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
-       if (i)
-               return i;
-       kernel_termios_to_user_termio(termio, tty->termios);
+       if (kernel_termios_to_user_termio(termio, tty->termios))
+               return -EFAULT;
        return 0;
 }
 
@@ -411,9 +403,9 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                        return set_ltchars(real_tty, (struct ltchars *) arg);
 #endif
                case TCGETS:
-                       return kernel_termios_to_user_termios
-                               ((struct termios *)arg,
-                                real_tty->termios);
+                       if (kernel_termios_to_user_termios((struct termios *)arg, real_tty->termios))
+                               return -EFAULT;
+                       return 0;
                case TCSETSF:
                        opt |= TERMIOS_FLUSH;
                case TCSETSW:
@@ -488,15 +480,17 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
                                retval = inq_canon(tty);
                        return put_user(retval, (unsigned int *) arg);
                case TIOCGLCKTRMIOS:
-                       return kernel_termios_to_user_termios
-                               ((struct termios *)arg,
-                                real_tty->termios_locked);
+                       if (kernel_termios_to_user_termios((struct termios *)arg, real_tty->termios_locked))
+                               return -EFAULT;
+                       return 0;
+
                case TIOCSLCKTRMIOS:
                        if (!suser())
                                return -EPERM;
-                       return user_termios_to_kernel_termios
-                               (real_tty->termios_locked,
-                                (struct termios *) arg);
+                       if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios *) arg))
+                               return -EFAULT;
+                       return 0;
+
                case TIOCPKT:
                {
                        int pktmode;
index 5b49791a4246604ebbb0ad896a31c868793c4637..c967681d5755ddebce665e670cece52ed0c70939 100644 (file)
@@ -58,7 +58,7 @@ extern int getkeycode(unsigned int scancode);
 extern int setkeycode(unsigned int scancode, unsigned int keycode);
 extern void compute_shiftstate(void);
 extern void complete_change_console(unsigned int new_console);
-extern int vt_waitactive(void);
+extern int vt_waitactive(int vt);
 extern void do_blank_screen(int nopowersave);
 
 extern unsigned int keymap_count;
@@ -807,13 +807,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                        return -EPERM;
                if (arg == 0 || arg > MAX_NR_CONSOLES)
                        return -ENXIO;
-               arg--;
-               while (fg_console != arg)
-               {
-                       if (vt_waitactive() < 0)
-                               return -EINTR;
-               }
-               return 0;
+               return vt_waitactive(arg-1);
 
        /*
         * If a vt is under process control, the kernel will not switch to it
index 957df12999f2d8a6226d017cc3daa8939e794547..ee732571459a83d11aa4203b9333349a0f52b19d 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/notifier.h>
+#include <linux/reboot.h>
 
 static int wdt_is_open=0;
 
@@ -145,7 +146,7 @@ void wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                printk(KERN_CRIT "Would Reboot.\n");
 #else          
                printk(KERN_CRIT "Initiating system reboot.\n");
-               hard_reset_now();
+               machine_restart(NULL);
 #endif         
 #else
                printk(KERN_CRIT "Reset in 5ms.\n");
index 5560405d2512747c1d8220be5192bd294e2cd9a3..2c571299eef52a7b4f2b87d4101cb9af7267ac91 100644 (file)
@@ -53,9 +53,9 @@ static char *version = "3c509.c:1.07 6/15/95 becker@cesdis.gsfc.nasa.gov\n";
 #include <asm/io.h>
 
 #ifdef EL3_DEBUG
-int el3_debug = EL3_DEBUG;
+static int el3_debug = EL3_DEBUG;
 #else
-int el3_debug = 2;
+static int el3_debug = 2;
 #endif
 
 /* To minimize the size of the driver source I only define operating
index cf84a0f3d7a03c86072984973b101ce0d8e76419..f66f30d1bb5f5f9512bdbcf36325a647f4aea739 100644 (file)
@@ -24,7 +24,7 @@ static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n";
    Tx process.  Bus master transfers are always disabled by default, but
    iff this is set they may be turned on using 'options'. */
 #define VORTEX_BUS_MASTER
-
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -78,9 +78,9 @@ struct netdev_entry tc59x_drv =
 #endif
 
 #ifdef VORTEX_DEBUG
-int vortex_debug = VORTEX_DEBUG;
+static int vortex_debug = VORTEX_DEBUG;
 #else
-int vortex_debug = 1;
+static int vortex_debug = 1;
 #endif
 
 #ifdef CONFIG_PCI
index 73025c10a3e425488dd9ae008563e4aa923df56d..0f224e63fa812074caa69ed868589c5097bf2086 100644 (file)
@@ -30,9 +30,6 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
     tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX
   fi
   bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE
-  if [ "$CONFIG_LANCE" = "y" ]; then
-    bool 'AMD PCInet32 (VLB and PCI) support' CONFIG_LANCE32
-  fi  
   bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
   if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
     tristate 'WD80*3 support' CONFIG_WD80x3
@@ -72,9 +69,11 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   fi
   bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
   if [ "$CONFIG_NET_EISA" = "y" ]; then
+    bool 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
+    
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
     tristate 'CS89x0 support' CONFIG_CS89x0
     tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
index 6d3f136604e8166c8e0980c496677402679847c1..998f211305286690d1053d0322fd0ee0bb4b479e 100644 (file)
@@ -255,15 +255,16 @@ ifeq ($(CONFIG_AT1500),y)
 L_OBJS += lance.o
 endif
 
-ifeq ($(CONFIG_DEFXX),y)
-L_OBJS += defxx.o
-endif
-
 ifeq ($(CONFIG_LANCE),y)
 L_OBJS += lance.o
-  ifeq ($(CONFIG_LANCE32),y)
-  L_OBJS += lance32.o
-  endif
+endif
+
+ifeq ($(CONFIG_PCNET32),y)
+L_OBJS += pcnet32.o
+endif
+
+ifeq ($(CONFIG_DEFXX),y)
+L_OBJS += defxx.o
 endif
 
 ifeq ($(CONFIG_SUNLANCE),y)
index f0cce96bebcb765af142e47d9f5e2eaafe71b7cd..0823c8a69db0a174c1d7f79d99e22391afe5782d 100644 (file)
@@ -52,6 +52,7 @@ extern int express_probe(struct device *);
 extern int eepro_probe(struct device *);
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
+extern int pcnet32_probe(struct device *);
 extern int at1700_probe(struct device *);
 extern int fmv18x_probe(struct device *);
 extern int eth16i_probe(struct device *);
@@ -153,6 +154,9 @@ static int ethif_probe(struct device *dev)
 #ifdef CONFIG_CS89x0
        && cs89x0_probe(dev)
 #endif
+#ifdef CONFIG_PCNET32
+       && pcnet32_probe(dev)
+#endif 
 #ifdef CONFIG_AT1700
        && at1700_probe(dev)
 #endif
index 134bf569dfb9b37d5d7de1f6f9eaaae7ac0032f9..0f8b29b36f7f5e1749aa3584a68ed4056d486f6b 100644 (file)
@@ -325,7 +325,9 @@ static int bpq_xmit(struct sk_buff *skb, struct device *dev)
        skb->dev = dev;
        dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
 
-       return dev->hard_start_xmit(skb, dev);
+       dev_queue_xmit(skb);
+
+       return 0;
 }
 
 /*
index 7c6ce635fea71226a318d5a2230a0798faa264ee..fc26f78cab1fbafa01929e346f5369bd1dad51db 100644 (file)
@@ -1380,6 +1380,8 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                   dev->name, sts);
            return;
        }
+if (sts & (STS_AIS | STS_UNF | STS_SE | STS_LNF | STS_RWT | STS_RU | STS_TJT))
+       printk("STS=%08x\n",sts);
     }
 
     /* Load the TX ring with any locally stored packets */
@@ -1563,7 +1565,10 @@ de4x5_txur(struct device *dev)
        if ((omr & OMR_TR) < OMR_TR) {
            omr += 0x4000;
        } else {
-           omr |= OMR_SF;
+           if (omr & OMR_TTM)
+               omr &= ~OMR_TTM;
+           else
+               omr |= OMR_SF;
        }
        outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
     }
index 84acaeba1fde43069eb115678ae84d41b8fb7864..70039edfe199de867962091da260ca851e434b70 100644 (file)
@@ -31,6 +31,7 @@
  *        18.10.96  Changed to new user space access routines 
  *                  (copy_{to,from}_user)
  *   0.2  21.11.96  various small changes
+ *   0.3  03.03.97  fixed (hopefully) IP not working with ax.25 as a module
  */
 
 /*****************************************************************************/
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/hdlcdrv.h>
-#ifdef CONFIG_AX25
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 /* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
-#endif /* CONFIG_AX25 */
+#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
 
 /* make genksyms happy */
 #include <linux/ip.h>
@@ -745,7 +746,19 @@ static int hdlcdrv_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
                bi.data.cs.ptt = hdlcdrv_ptt(s);
                bi.data.cs.dcd = s->hdlcrx.dcd;
                bi.data.cs.ptt_keyed = s->ptt_keyed;
-               bi.data.cs.stats = s->stats;
+               bi.data.cs.tx_packets = s->stats.tx_packets;
+               bi.data.cs.tx_errors = s->stats.tx_errors;
+               bi.data.cs.rx_packets = s->stats.rx_packets;
+               bi.data.cs.rx_errors = s->stats.rx_errors;
+               break;          
+
+       case HDLCDRVCTL_OLDGETSTAT:
+               bi.data.ocs.ptt = hdlcdrv_ptt(s);
+               bi.data.ocs.dcd = s->hdlcrx.dcd;
+               bi.data.ocs.ptt_keyed = s->ptt_keyed;
+#if LINUX_VERSION_CODE < 0x20100
+               bi.data.ocs.stats = s->stats;
+#endif
                break;          
 
        case HDLCDRVCTL_CALIBRATE:
@@ -858,13 +871,13 @@ static int hdlcdrv_probe(struct device *dev)
 
        skb_queue_head_init(&s->send_queue);
        
-#ifdef CONFIG_AX25
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
        dev->hard_header = ax25_encapsulate;
        dev->rebuild_header = ax25_rebuild_header;
-#else /* CONFIG_AX25 */
+#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
        dev->hard_header = NULL;
        dev->rebuild_header = NULL;
-#endif /* CONFIG_AX25 */
+#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
        dev->set_mac_address = hdlcdrv_set_mac_address;
        
        dev->type = ARPHRD_AX25;           /* AF_AX25 device */
@@ -989,8 +1002,7 @@ MODULE_DESCRIPTION("Packet Radio network interface HDLC encoder/decoder");
 int init_module(void)
 {
        printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
-       printk(KERN_INFO "hdlcdrv: version 0.2 compiled %s %s\n", 
-              __TIME__, __DATE__);
+       printk(KERN_INFO "hdlcdrv: version 0.3 compiled " __TIME__ " " __DATE__ "\n");
 #if LINUX_VERSION_CODE < 0x20115
         register_symtab(&hdlcdrv_syms);
 #endif
index caeaa30131f03e24f5d3aa0667fa756a583b3afc..4483a1fe9e9919f46d2d113cddd47a3d823c11cb 100644 (file)
@@ -162,11 +162,13 @@ tx_full and tbusy flags.
 
 /*
  * Changes:
- *     Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
+ *     Thomas Bogendoerfer (tsbogend@alpha.franken.de):
  *     - added support for Linux/Alpha, but removed most of it, because
  *        it worked only for the PCI chip. 
  *      - added hook for the 32bit lance driver
  *      - added PCnetPCI II (79C970A) to chip table
+ *      - made 32bit driver standalone
+ *      - changed setting of autoselect bit
  *
  *     Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
  *     - hopefully fix above so Linux/Alpha can use ISA cards too.
@@ -245,6 +247,7 @@ struct lance_private {
 #define LANCE_MUST_REINIT_RING  0x00000004
 #define LANCE_MUST_UNRESET      0x00000008
 #define LANCE_HAS_MISSED_FRAME  0x00000010
+#define PCNET32_POSSIBLE        0x00000020
 
 /* A mapping from the chip ID number to the part number and features.
    These are from the datasheets -- in real life the '970 version
@@ -264,15 +267,15 @@ static struct lance_chip_type {
                        LANCE_HAS_MISSED_FRAME},
        {0x2420, "PCnet/PCI 79C970",            /* 79C970 or 79C974 PCnet-SCSI, PCI. */
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                       LANCE_HAS_MISSED_FRAME},
+                       LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
        /* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
                it the PCnet32. */
        {0x2430, "PCnet32",                                     /* 79C965 PCnet for VL bus. */
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                       LANCE_HAS_MISSED_FRAME},
+                       LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
         {0x2621, "PCnet/PCI-II 79C970A",        /* 79C970A PCInetPCI II. */
                 LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                        LANCE_HAS_MISSED_FRAME},
+                        LANCE_HAS_MISSED_FRAME + PCNET32_POSSIBLE},
        {0x0,    "PCnet (unknown)",
                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
                        LANCE_HAS_MISSED_FRAME},
@@ -312,7 +315,7 @@ int lance_init(void)
        if (virt_to_bus(high_memory) <= 16*1024*1024)
                lance_need_isa_bounce_buffers = 0;
 
-#if defined(CONFIG_PCI)
+#if defined(CONFIG_PCI) && !defined(CONFIG_PCNET32)
     if (pcibios_present()) {
            int pci_index;
                if (lance_debug > 1)
@@ -427,6 +430,15 @@ void lance_probe1(int ioaddr)
                                break;
                }
        }
+    
+#ifdef CONFIG_PCNET32
+        /*
+        * if pcnet32 is configured and the chip is capable of 32bit mode
+        * leave the card alone
+        */
+        if (chip_table[lance_version].flags & PCNET32_POSSIBLE)
+          return;
+#endif    
 
        dev = init_etherdev(0, 0);
        dev->open = lance_open_fail;
@@ -441,15 +453,6 @@ void lance_probe1(int ioaddr)
        dev->base_addr = ioaddr;
        request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
-#ifdef CONFIG_LANCE32
-        /* look if it's a PCI or VLB chip */
-        if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) {
-           extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line);
-           
-           lance32_probe1 (dev, chipname, pci_irq_line);
-           return;
-       }
-#endif    
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
        lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
                                                                                   GFP_DMA | GFP_KERNEL)+7) & ~7);
@@ -606,7 +609,8 @@ void lance_probe1(int ioaddr)
                /* Turn on auto-select of media (10baseT or BNC) so that the user
                   can watch the LEDs even if the board isn't opened. */
                outw(0x0002, ioaddr+LANCE_ADDR);
-               outw(0x0002, ioaddr+LANCE_BUS_IF);
+               /* set autoselect and clean xmausel */
+               outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF);
        }
 
        if (lance_debug > 0  &&  did_version++ == 0)
@@ -663,7 +667,8 @@ lance_open(struct device *dev)
        if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
                /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
                outw(0x0002, ioaddr+LANCE_ADDR);
-               outw(0x0002, ioaddr+LANCE_BUS_IF);
+               /* set autoselect and clean xmausel */
+               outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF);
        }
 
        if (lance_debug > 1)
diff --git a/drivers/net/lance32.c b/drivers/net/lance32.c
deleted file mode 100644 (file)
index 6d58d92..0000000
+++ /dev/null
@@ -1,841 +0,0 @@
-/* lance32.c: An AMD PCnet32 ethernet driver for linux. */
-/*
- *      Copyright 1996 Thomas Bogendoerfer
- * 
- *     Derived from the lance driver written 1993,1994,1995 by Donald Becker.
- * 
- *     Copyright 1993 United States Government as represented by the
- *     Director, National Security Agency.
- * 
- *     This software may be used and distributed according to the terms
- *     of the GNU Public License, incorporated herein by reference.
- *
- *     This driver is for PCnet32 and PCnetPCI based ethercards
- */
-
-static const char *version = "lance32.c:v0.10 28.4.96 tsbogend@bigbug.franken.de\n";
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/bios32.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#ifdef LANCE32_DEBUG
-int lance32_debug = LANCE32_DEBUG;
-#else
-int lance32_debug = 1;
-#endif
-
-/*
- *                             Theory of Operation
- * 
- * This driver uses the same software structure as the normal lance
- * driver. So look for a verbose description in lance.c. The differences
- * to the normal lance driver is the use of the 32bit mode of PCnet32
- * and PCnetPCI chips. Because these chips are 32bit chips, there is no
- * 16MB limitation and we don't need bounce buffers.
- */
-/*
- * History:
- * v0.01:  Initial version
- *         only tested on Alpha Noname Board
- * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
- *         tested on a ASUS SP3G
- * v0.10:  fixed an odd problem with the 79C794 in a Compaq Deskpro XL
- *         looks like the 974 doesn't like stopping and restarting in a
- *         short period of time; now we do a reinit of the lance; the
- *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
- *         and hangs the machine (thanks to Klaus Liedl for debugging)
- */
-
-
-/*
- * Set the number of Tx and Rx buffers, using Log_2(# buffers).
- * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
- * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
- */
-#ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 4
-#define LANCE_LOG_RX_BUFFERS 4
-#endif
-
-#define TX_RING_SIZE                   (1 << (LANCE_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK               (TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS               ((LANCE_LOG_TX_BUFFERS) << 12)
-
-#define RX_RING_SIZE                   (1 << (LANCE_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK               (RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS               ((LANCE_LOG_RX_BUFFERS) << 4)
-
-#define PKT_BUF_SZ             1544
-
-/* Offsets from base I/O address. */
-#define LANCE_DATA 0x10
-#define LANCE_ADDR 0x12
-#define LANCE_RESET 0x14
-#define LANCE_BUS_IF 0x16
-#define LANCE_TOTAL_SIZE 0x18
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance32_rx_head {
-       u32 base;
-       s16 buf_length;
-        s16 status;    
-       u32 msg_length;
-       u32 reserved;
-};
-       
-struct lance32_tx_head {
-       u32 base;
-       s16 length;
-        s16 status;
-       u32 misc;
-       u32 reserved;
-};
-
-
-/* The LANCE 32-Bit initialization block, described in databook. */
-struct lance32_init_block {
-       u16 mode;
-       u16 tlen_rlen;
-       u8  phys_addr[6];
-       u16 reserved;
-       u32 filter[2];
-       /* Receive and transmit ring base, along with extra bits. */    
-       u32 rx_ring;
-       u32 tx_ring;
-};
-
-struct lance32_private {
-       /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
-       struct lance32_rx_head   rx_ring[RX_RING_SIZE];
-       struct lance32_tx_head   tx_ring[TX_RING_SIZE];
-       struct lance32_init_block       init_block;
-       const char *name;
-       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-       struct sk_buff* tx_skbuff[TX_RING_SIZE];
-       unsigned long rx_buffs;                 /* Address of Rx and Tx buffers. */
-       int cur_rx, cur_tx;                     /* The next free ring entry */
-       int dirty_rx, dirty_tx;                 /* The ring entries to be free()ed. */
-       int dma;
-       struct net_device_stats stats;
-       char tx_full;
-       unsigned long lock;
-};
-
-static int lance32_open(struct device *dev);
-static void lance32_init_ring(struct device *dev);
-static int lance32_start_xmit(struct sk_buff *skb, struct device *dev);
-static int lance32_rx(struct device *dev);
-static void lance32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int lance32_close(struct device *dev);
-static struct net_device_stats *lance32_get_stats(struct device *dev);
-static void lance32_set_multicast_list(struct device *dev);
-
-\f
-
-/* lance32_probe1 */
-void lance32_probe1(struct device *dev, char *chipname, int pci_irq_line)
-{
-       struct lance32_private *lp;
-        int ioaddr = dev->base_addr;
-       short dma_channels;                                     /* Mark spuriously-busy DMA channels */    
-        int i;
-    
-       /* Make certain the data structures used by the LANCE are 16byte aligned and DMAble. */
-       lp = (struct lance32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
-      
-       memset(lp, 0, sizeof(*lp));
-       dev->priv = lp;
-       lp->name = chipname;
-       lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
-
-       lp->init_block.mode = 0x0003;           /* Disable Rx and Tx. */
-        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;    
-       for (i = 0; i < 6; i++)
-               lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       lp->init_block.filter[0] = 0x00000000;
-       lp->init_block.filter[1] = 0x00000000;
-       lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
-       lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
-    
-       /* switch lance to 32bit mode */
-       outw(0x0014, ioaddr+LANCE_ADDR);
-       outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-       outw(0x0001, ioaddr+LANCE_ADDR);
-       inw(ioaddr+LANCE_ADDR);
-       outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
-       outw(0x0002, ioaddr+LANCE_ADDR);
-       inw(ioaddr+LANCE_ADDR);
-       outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
-       outw(0x0000, ioaddr+LANCE_ADDR);
-       inw(ioaddr+LANCE_ADDR);
-    
-       if (pci_irq_line) {
-               dev->dma = 4;                   /* Native bus-master, no DMA channel needed. */
-               dev->irq = pci_irq_line;
-       } else {
-               /* The DMA channel may be passed in PARAM1. */
-               if (dev->mem_start & 0x07)
-                       dev->dma = dev->mem_start & 0x07;
-       }
-
-       if (dev->dma == 0) {
-               /* Read the DMA channel status register, so that we can avoid
-                  stuck DMA channels in the DMA detection below. */
-               dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
-                       (inb(DMA2_STAT_REG) & 0xf0);
-       }
-       if (dev->irq >= 2)
-               printk(" assigned IRQ %d", dev->irq);
-       else {
-               /* To auto-IRQ we enable the initialization-done and DMA error
-                  interrupts. For ISA boards we get a DMA error, but VLB and PCI
-                  boards will work. */
-               autoirq_setup(0);
-
-               /* Trigger an initialization just for the interrupt. */
-               outw(0x0041, ioaddr+LANCE_DATA);
-
-               dev->irq = autoirq_report(1);
-               if (dev->irq)
-                       printk(", probed IRQ %d", dev->irq);
-               else {
-                       printk(", failed to detect IRQ line.\n");
-                       return;
-               }
-
-               /* Check for the initialization done bit, 0x0100, which means
-                  that we don't need a DMA channel. */
-               if (inw(ioaddr+LANCE_DATA) & 0x0100)
-                       dev->dma = 4;
-       }
-
-       if (dev->dma == 4) {
-               printk(", no DMA needed.\n");
-       } else if (dev->dma) {
-               if (request_dma(dev->dma, chipname)) {
-                       printk("DMA %d allocation failed.\n", dev->dma);
-                       return;
-               } else
-                       printk(", assigned DMA %d.\n", dev->dma);
-       } else {                        /* OK, we have to auto-DMA. */
-               for (i = 0; i < 4; i++) {
-                       static const char dmas[] = { 5, 6, 7, 3 };
-                       int dma = dmas[i];
-                       int boguscnt;
-
-                       /* Don't enable a permanently busy DMA channel, or the machine
-                          will hang. */
-                       if (test_bit(dma, &dma_channels))
-                               continue;
-                       outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
-                       if (request_dma(dma, chipname))
-                               continue;
-                       set_dma_mode(dma, DMA_MODE_CASCADE);
-                       enable_dma(dma);
-
-                       /* Trigger an initialization. */
-                       outw(0x0001, ioaddr+LANCE_DATA);
-                       for (boguscnt = 100; boguscnt > 0; --boguscnt)
-                               if (inw(ioaddr+LANCE_DATA) & 0x0900)
-                                       break;
-                       if (inw(ioaddr+LANCE_DATA) & 0x0100) {
-                               dev->dma = dma;
-                               printk(", DMA %d.\n", dev->dma);
-                               break;
-                       } else {
-                               disable_dma(dma);
-                               free_dma(dma);
-                       }
-               }
-               if (i == 4) {                   /* Failure: bail. */
-                       printk("DMA detection failed.\n");
-                       return;
-               }
-       }
-    
-        outw(0x0002, ioaddr+LANCE_ADDR);
-       outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-       if (lance32_debug > 0)
-               printk(version);
-
-       /* The LANCE-specific entries in the device structure. */
-       dev->open = &lance32_open;
-       dev->hard_start_xmit = &lance32_start_xmit;
-       dev->stop = &lance32_close;
-       dev->get_stats = &lance32_get_stats;
-       dev->set_multicast_list = &lance32_set_multicast_list;
-
-       return;
-}
-
-\f
-static int
-lance32_open(struct device *dev)
-{
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-       int ioaddr = dev->base_addr;
-       int i;
-
-       if (dev->irq == 0 ||
-               request_irq(dev->irq, &lance32_interrupt, 0, lp->name, (void *)dev)) {
-               return -EAGAIN;
-       }
-
-       irq2dev_map[dev->irq] = dev;
-
-       /* Reset the LANCE */
-       inw(ioaddr+LANCE_RESET);
-
-       /* switch lance to 32bit mode */
-       outw(0x0014, ioaddr+LANCE_ADDR);
-       outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-       /* The DMA controller is used as a no-operation slave, "cascade mode". */
-       if (dev->dma != 4) {
-               enable_dma(dev->dma);
-               set_dma_mode(dev->dma, DMA_MODE_CASCADE);
-       }
-
-       /* Turn on auto-select of media (AUI, BNC). */
-       outw(0x0002, ioaddr+LANCE_ADDR);
-       outw(0x0002, ioaddr+LANCE_BUS_IF);
-
-       if (lance32_debug > 1)
-               printk("%s: lance32_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
-                          dev->name, dev->irq, dev->dma,
-                          (u32) virt_to_bus(lp->tx_ring),
-                          (u32) virt_to_bus(lp->rx_ring),
-                          (u32) virt_to_bus(&lp->init_block));
-
-       lp->init_block.mode = 0x0000;
-       lp->init_block.filter[0] = 0x00000000;
-       lp->init_block.filter[1] = 0x00000000;
-       lance32_init_ring(dev);
-    
-       /* Re-initialize the LANCE, and start it when done. */
-       outw(0x0001, ioaddr+LANCE_ADDR);
-       outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
-       outw(0x0002, ioaddr+LANCE_ADDR);
-       outw(((u32)virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
-
-       outw(0x0004, ioaddr+LANCE_ADDR);
-       outw(0x0915, ioaddr+LANCE_DATA);
-
-       outw(0x0000, ioaddr+LANCE_ADDR);
-       outw(0x0001, ioaddr+LANCE_DATA);
-
-       dev->tbusy = 0;
-       dev->interrupt = 0;
-       dev->start = 1;
-       i = 0;
-       while (i++ < 100)
-               if (inw(ioaddr+LANCE_DATA) & 0x0100)
-                       break;
-       /* 
-        * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
-        * reports that doing so triggers a bug in the '974.
-        */
-       outw(0x0042, ioaddr+LANCE_DATA);
-
-       if (lance32_debug > 2)
-               printk("%s: LANCE32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-                          dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA));
-
-       return 0;                                       /* Always succeed */
-}
-
-/*
- * The LANCE has been halted for one reason or another (busmaster memory
- * arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
- * etc.).  Modern LANCE variants always reload their ring-buffer
- * configuration when restarted, so we must reinitialize our ring
- * context before restarting.  As part of this reinitialization,
- * find all packets still on the Tx ring and pretend that they had been
- * sent (in effect, drop the packets on the floor) - the higher-level
- * protocols will time out and retransmit.  It'd be better to shuffle
- * these skbs to a temp list and then actually re-Tx them after
- * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
- */
-
-static void 
-lance32_purge_tx_ring(struct device *dev)
-{
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-       int i;
-
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               if (lp->tx_skbuff[i]) {
-                       dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE);
-                       lp->tx_skbuff[i] = NULL;
-               }
-       }
-}
-
-
-/* Initialize the LANCE Rx and Tx rings. */
-static void
-lance32_init_ring(struct device *dev)
-{
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-       int i;
-
-       lp->lock = 0, lp->tx_full = 0;
-       lp->cur_rx = lp->cur_tx = 0;
-       lp->dirty_rx = lp->dirty_tx = 0;
-
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               lp->rx_ring[i].base = (u32)virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ);
-               lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
-               lp->rx_ring[i].status = 0x8000;     
-       }
-       /* The Tx buffer address is filled in as needed, but we do need to clear
-          the upper ownership bit. */
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               lp->tx_ring[i].base = 0;
-               lp->tx_ring[i].status = 0;
-       }
-
-        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
-       for (i = 0; i < 6; i++)
-               lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
-       lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
-}
-
-static void
-lance32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
-{
-        int i;
-       int ioaddr = dev->base_addr;
-    
-       lance32_purge_tx_ring(dev);
-       lance32_init_ring(dev);
-    
-       outw(0x0000, ioaddr + LANCE_ADDR);
-        /* ReInit Ring */
-        outw(0x0001, ioaddr + LANCE_DATA);
-       i = 0;
-       while (i++ < 100)
-               if (inw(ioaddr+LANCE_DATA) & 0x0100)
-                       break;
-
-       outw(csr0_bits, ioaddr + LANCE_DATA);
-}
-
-static int
-lance32_start_xmit(struct sk_buff *skb, struct device *dev)
-{
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-       int ioaddr = dev->base_addr;
-       int entry;
-       unsigned long flags;
-
-       /* Transmitter timeout, serious problems. */
-       if (dev->tbusy) {
-               int tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < 20)
-                       return 1;
-               outw(0, ioaddr+LANCE_ADDR);
-               printk("%s: transmit timed out, status %4.4x, resetting.\n",
-                          dev->name, inw(ioaddr+LANCE_DATA));
-               outw(0x0004, ioaddr+LANCE_DATA);
-               lp->stats.tx_errors++;
-#ifndef final_version
-               {
-                       int i;
-                       printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-                                  lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-                                  lp->cur_rx);
-                       for (i = 0 ; i < RX_RING_SIZE; i++)
-                               printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
-                                          lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-                                          lp->rx_ring[i].msg_length);
-                       for (i = 0 ; i < TX_RING_SIZE; i++)
-                               printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
-                                          lp->tx_ring[i].base, -lp->tx_ring[i].length,
-                                          lp->tx_ring[i].misc);
-                       printk("\n");
-               }
-#endif
-               lance32_restart(dev, 0x0042, 1);
-
-               dev->tbusy=0;
-               dev->trans_start = jiffies;
-
-               return 0;
-       }
-
-       if (skb == NULL) {
-               dev_tint(dev);
-               return 0;
-       }
-
-       if (skb->len <= 0)
-               return 0;
-
-       if (lance32_debug > 3) {
-               outw(0x0000, ioaddr+LANCE_ADDR);
-               printk("%s: lance32_start_xmit() called, csr0 %4.4x.\n", dev->name,
-                          inw(ioaddr+LANCE_DATA));
-               outw(0x0000, ioaddr+LANCE_DATA);
-       }
-
-       /* Block a timer-based transmit from overlapping.  This could better be
-          done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-       if (set_bit(0, (void*)&dev->tbusy) != 0) {
-               printk("%s: Transmitter access conflict.\n", dev->name);
-               return 1;
-       }
-
-       if (set_bit(0, (void*)&lp->lock) != 0) {
-               if (lance32_debug > 0)
-                       printk("%s: tx queue lock!.\n", dev->name);
-               /* don't clear dev->tbusy flag. */
-               return 1;
-       }
-
-       /* Fill in a Tx ring entry */
-
-       /* Mask to ring buffer boundary. */
-       entry = lp->cur_tx & TX_RING_MOD_MASK;
-
-       /* Caution: the write order is important here, set the base address
-          with the "ownership" bits last. */
-
-       lp->tx_ring[entry].length = -skb->len;
-
-       lp->tx_ring[entry].misc = 0x00000000;
-
-       lp->tx_skbuff[entry] = skb;
-       lp->tx_ring[entry].base = (u32)virt_to_bus(skb->data);
-        lp->tx_ring[entry].status = 0x8300;
-
-       lp->cur_tx++;
-
-       /* Trigger an immediate send poll. */
-       outw(0x0000, ioaddr+LANCE_ADDR);
-       outw(0x0048, ioaddr+LANCE_DATA);
-
-       dev->trans_start = jiffies;
-
-       save_flags(flags);
-       cli();
-       lp->lock = 0;
-       if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
-               dev->tbusy=0;
-       else
-               lp->tx_full = 1;
-       restore_flags(flags);
-
-       return 0;
-}
-
-/* The LANCE32 interrupt handler. */
-static void
-lance32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-       struct device *dev = (struct device *)dev_id;
-       struct lance32_private *lp;
-       int csr0, ioaddr, boguscnt=10;
-       int must_restart;
-
-       if (dev == NULL) {
-               printk ("lance32_interrupt(): irq %d for unknown device.\n", irq);
-               return;
-       }
-
-       ioaddr = dev->base_addr;
-       lp = (struct lance32_private *)dev->priv;
-       if (dev->interrupt)
-               printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
-       dev->interrupt = 1;
-
-       outw(0x00, dev->base_addr + LANCE_ADDR);
-       while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600
-                  && --boguscnt >= 0) {
-               /* Acknowledge all of the current interrupt sources ASAP. */
-               outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);
-
-               must_restart = 0;
-
-               if (lance32_debug > 5)
-                       printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
-                                  dev->name, csr0, inw(dev->base_addr + LANCE_DATA));
-
-               if (csr0 & 0x0400)                      /* Rx interrupt */
-                       lance32_rx(dev);
-
-               if (csr0 & 0x0200) {            /* Tx-done interrupt */
-                       int dirty_tx = lp->dirty_tx;
-
-                       while (dirty_tx < lp->cur_tx) {
-                               int entry = dirty_tx & TX_RING_MOD_MASK;
-                               int status = lp->tx_ring[entry].status;
-                       
-                               if (status < 0)
-                                       break;                  /* It still hasn't been Txed */
-
-                               lp->tx_ring[entry].base = 0;
-
-                               if (status & 0x4000) {
-                                       /* There was an major error, log it. */
-                                       int err_status = lp->tx_ring[entry].misc;
-                                       lp->stats.tx_errors++;
-                                       if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
-                                       if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
-                                       if (err_status & 0x10000000) lp->stats.tx_window_errors++;
-                                       if (err_status & 0x40000000) {
-                                               /* Ackk!  On FIFO errors the Tx unit is turned off! */
-                                               lp->stats.tx_fifo_errors++;
-                                               /* Remove this verbosity later! */
-                                               printk("%s: Tx FIFO error! Status %4.4x.\n",
-                                                          dev->name, csr0);
-                                               /* Restart the chip. */
-                                               must_restart = 1;
-                                       }
-                               } else {
-                                       if (status & 0x1800)
-                                               lp->stats.collisions++;
-                                       lp->stats.tx_packets++;
-                               }
-
-                               /* We must free the original skb */
-                               if (lp->tx_skbuff[entry]) {
-                                       dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE);
-                                       lp->tx_skbuff[entry] = 0;
-                               }
-                               dirty_tx++;
-                       }
-
-#ifndef final_version
-                       if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-                               printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-                                          dirty_tx, lp->cur_tx, lp->tx_full);
-                               dirty_tx += TX_RING_SIZE;
-                       }
-#endif
-
-                       if (lp->tx_full && dev->tbusy
-                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
-                               /* The ring is no longer full, clear tbusy. */
-                               lp->tx_full = 0;
-                               dev->tbusy = 0;
-                               mark_bh(NET_BH);
-                       }
-
-                       lp->dirty_tx = dirty_tx;
-               }
-
-               /* Log misc errors. */
-               if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
-               if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
-               if (csr0 & 0x0800) {
-                       printk("%s: Bus master arbitration failure, status %4.4x.\n",
-                                  dev->name, csr0);
-                       /* Restart the chip. */
-                       must_restart = 1;
-               }
-
-               if (must_restart) {
-                       /* stop the chip to clear the error condition, then restart */
-                       outw(0x0000, dev->base_addr + LANCE_ADDR);
-                       outw(0x0004, dev->base_addr + LANCE_DATA);
-                       lance32_restart(dev, 0x0002, 0);
-               }
-       }
-
-    /* Clear any other interrupt, and set interrupt enable. */
-    outw(0x0000, dev->base_addr + LANCE_ADDR);
-    outw(0x7940, dev->base_addr + LANCE_DATA);
-
-       if (lance32_debug > 4)
-               printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
-                          dev->name, inw(ioaddr + LANCE_ADDR),
-                          inw(dev->base_addr + LANCE_DATA));
-
-       dev->interrupt = 0;
-       return;
-}
-
-static int
-lance32_rx(struct device *dev)
-{
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-       int entry = lp->cur_rx & RX_RING_MOD_MASK;
-       int i;
-               
-       /* If we own the next entry, it's a new packet. Send it up. */
-       while (lp->rx_ring[entry].status >= 0) {
-               int status = lp->rx_ring[entry].status >> 8;
-
-               if (status != 0x03) {                   /* There was an error. */
-                       /* There is a tricky error noted by John Murphy,
-                          <murf@perftech.com> to Russ Nelson: Even with full-sized
-                          buffers it's possible for a jabber packet to use two
-                          buffers, with only the last correctly noting the error. */
-                       if (status & 0x01)      /* Only count a general error at the */
-                               lp->stats.rx_errors++; /* end of a packet.*/
-                       if (status & 0x20) lp->stats.rx_frame_errors++;
-                       if (status & 0x10) lp->stats.rx_over_errors++;
-                       if (status & 0x08) lp->stats.rx_crc_errors++;
-                       if (status & 0x04) lp->stats.rx_fifo_errors++;
-                       lp->rx_ring[entry].status &= 0x03ff;
-               }
-               else 
-               {
-                       /* Malloc up new buffer, compatible with net-2e. */
-                       short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
-                       struct sk_buff *skb;
-                       
-                       if(pkt_len<60)
-                       {
-                               printk("%s: Runt packet!\n",dev->name);
-                               lp->stats.rx_errors++;
-                       }
-                       else
-                       {
-                               skb = dev_alloc_skb(pkt_len+2);
-                               if (skb == NULL) 
-                               {
-                                       printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-                                       for (i=0; i < RX_RING_SIZE; i++)
-                                               if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status < 0)
-                                                       break;
-
-                                       if (i > RX_RING_SIZE -2) 
-                                       {
-                                               lp->stats.rx_dropped++;
-                                               lp->rx_ring[entry].status |= 0x8000;
-                                               lp->cur_rx++;
-                                       }
-                                       break;
-                               }
-                               skb->dev = dev;
-                               skb_reserve(skb,2);     /* 16 byte align */
-                               skb_put(skb,pkt_len);   /* Make room */
-                               eth_copy_and_sum(skb,
-                                       (unsigned char *)bus_to_virt(lp->rx_ring[entry].base),
-                                       pkt_len,0);
-                               skb->protocol=eth_type_trans(skb,dev);
-                               netif_rx(skb);
-                               lp->stats.rx_packets++;
-                       }
-               }
-               /* The docs say that the buffer length isn't touched, but Andrew Boyd
-                  of QNX reports that some revs of the 79C965 clear it. */
-               lp->rx_ring[entry].buf_length = -PKT_BUF_SZ;
-               lp->rx_ring[entry].status |= 0x8000;
-               entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
-       }
-
-       /* We should check that at least two ring entries are free.      If not,
-          we should free one and mark stats->rx_dropped++. */
-
-       return 0;
-}
-
-static int
-lance32_close(struct device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-
-       dev->start = 0;
-       dev->tbusy = 1;
-
-       outw(112, ioaddr+LANCE_ADDR);
-       lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
-
-       outw(0, ioaddr+LANCE_ADDR);
-
-       if (lance32_debug > 1)
-               printk("%s: Shutting down ethercard, status was %2.2x.\n",
-                          dev->name, inw(ioaddr+LANCE_DATA));
-
-       /* We stop the LANCE here -- it occasionally polls
-          memory if we don't. */
-       outw(0x0004, ioaddr+LANCE_DATA);
-
-       if (dev->dma != 4)
-               disable_dma(dev->dma);
-
-       free_irq(dev->irq, dev);
-
-       irq2dev_map[dev->irq] = 0;
-
-       return 0;
-}
-
-static struct net_device_stats *lance32_get_stats(struct device *dev)
-{
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;
-       int ioaddr = dev->base_addr;
-       unsigned short saved_addr;
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       saved_addr = inw(ioaddr+LANCE_ADDR);
-       outw(112, ioaddr+LANCE_ADDR);
-       lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
-       outw(saved_addr, ioaddr+LANCE_ADDR);
-       restore_flags(flags);
-
-       return &lp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-
-static void lance32_set_multicast_list(struct device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct lance32_private *lp = (struct lance32_private *)dev->priv;    
-
-       if (dev->flags&IFF_PROMISC) {
-               /* Log any net taps. */
-               printk("%s: Promiscuous mode enabled.\n", dev->name);
-               lp->init_block.mode = 0x8000;
-       } else {
-               int num_addrs=dev->mc_count;
-               if(dev->flags&IFF_ALLMULTI)
-                       num_addrs=1;
-               /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
-               memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
-               lp->init_block.mode = 0x0000;           
-       }
-    
-       outw(0, ioaddr+LANCE_ADDR);
-       outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.  */
-
-       lance32_restart(dev, 0x0042, 0); /*  Resume normal operation */
-
-}
-
-\f
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance32.c"
- *  c-indent-level: 4
- *  tab-width: 4
- * End:
- */
index f35cf2c460ea2149e89bca350a0e0081126438eb..0ddc6da5b2a02b193d9be5f6a73113ee0e07250c 100644 (file)
@@ -280,7 +280,7 @@ static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
 
        dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
-       dev->hard_start_xmit(skb, dev);
+       dev_queue_xmit(skb);
 }
 
 static void lapbeth_connected(void *token, int reason)
index 82180b335f4e1ea5c1e85b38c6002d0a7f8e460e..a64adf1007cb2a85b195b2299e549ed80959f4c4 100644 (file)
@@ -316,9 +316,9 @@ static int wait_timeout(struct device *dev, int c)
        int i;
        int timeout;
 
-       /* ten second or so total */
+       /* twenty second or so total */
 
-       for(i=0;i<10000;i++) {
+       for(i=0;i<20000;i++) {
                if ( c != inb_p(dev->base_addr+6) ) return 0;
                for(timeout=loops_per_sec/1000; timeout > 0; timeout--) ;
        }
index 2b14474066805a2ab4754ccfc789c8d7d2ec77b0..3ed1b8f6700d2d5559a272caba539cff50102156 100644 (file)
@@ -833,6 +833,7 @@ int mkiss_init_ctrl_dev(void)
        /* Fill in our line protocol discipline, and register it */
        memset(&ax_ldisc, 0, sizeof(ax_ldisc));
        ax_ldisc.magic  = TTY_LDISC_MAGIC;
+       ax_ldisc.name   = "mkiss";
        ax_ldisc.flags  = 0;
        ax_ldisc.open   = ax25_open;
        ax_ldisc.close  = ax25_close;
index f8180cf3c0a91337c29fd4b638f3c78317083e79..637e19e487db72179ec094b424e40148549cb000 100644 (file)
@@ -1,4 +1,4 @@
-/* myri_sbus.h: MyriCOM Gigabit Ethernet SBUS card driver.
+/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
@@ -43,11 +43,6 @@ static char *version =
 #include <net/sock.h>
 #include <net/ipv6.h>
 
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-#include <linux/in6.h>
-#include <net/ndisc.h>
-#endif
-
 #include <asm/checksum.h>
 
 #include "myri_sbus.h"
@@ -707,6 +702,7 @@ static int myri_rebuild_header(struct sk_buff *skb)
        unsigned char *pad = (unsigned char *)skb->data;
        struct ethhdr *eth = (struct ethhdr *)(pad + MYRI_PAD_LEN);
        struct device *dev = skb->dev;
+       struct neighbour *neigh = NULL;
 
 #ifdef DEBUG_HEADER
        DHDR(("myri_rebuild_header: pad[%02x,%02x] ", pad[0], pad[1]));
@@ -721,29 +717,19 @@ static int myri_rebuild_header(struct sk_buff *skb)
         *      Only ARP/IP and NDISC/IPv6 are currently supported
         */
        
+       if (skb->dst)
+               neigh = skb->dst->neighbour;
+       if (neigh)
+               return neigh->ops->resolve(eth->h_dest, skb);
        switch (eth->h_proto)
        {
 #ifdef CONFIG_INET
        case __constant_htons(ETH_P_IP):
-
-               /*
-                *      Try to get ARP to resolve the header.
-                */
-
-               return arp_find(eth->h_dest, skb) ? 1 : 0;
-               break;
+               return arp_find(eth->h_dest, skb);
 #endif
 
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-       case __constant_htons(ETH_P_IPV6):
-#ifdef CONFIG_IPV6
-               return (ndisc_eth_resolv(eth->h_dest, dev, skb));
-#else
-               if (ndisc_eth_hook)
-                       return (ndisc_eth_hook(eth->h_dest, dev, skb));
-#endif
-               break;
-#endif 
        default:
                printk(KERN_DEBUG 
                       "%s: unable to resolve type %X addresses.\n", 
@@ -757,7 +743,7 @@ static int myri_rebuild_header(struct sk_buff *skb)
        return 0;       
 }
 
-int myri_header_cache(struct dst_entry *dst, struct dst_entry *neigh,
+int myri_header_cache(struct dst_entry *dst, struct neighbour *neigh,
                       struct hh_cache *hh)
 {
        unsigned short type = hh->hh_type;
@@ -920,7 +906,7 @@ static int myri_ether_init(struct device *dev, struct linux_sbus_device *sdev, i
        if(version_printed++ == 0)
                printk(version);
 
-       printk("%s: MyriCOM Gigabit Ethernet ", dev->name);
+       printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
        dev->base_addr = (long) sdev;
 
        mp = (struct myri_eth *) dev->priv;
@@ -1112,6 +1098,7 @@ static int myri_ether_init(struct device *dev, struct linux_sbus_device *sdev, i
        myri_load_lanai(mp);
 
 #ifdef MODULE
+       dev->ifindex = dev_new_index();
        mp->next_module = root_myri_dev;
        root_myri_dev = mp;
 #endif
@@ -1135,7 +1122,7 @@ int myri_sbus_probe(struct device *dev)
                        if(!strcmp(sdev->prom_name, "MYRICOM,mlanai") ||
                           !strcmp(sdev->prom_name, "myri")) {
                                cards++;
-                               DET(("Found myricom gigabit as %s\n", sdev->prom_name));
+                               DET(("Found myricom myrinet as %s\n", sdev->prom_name));
                                if((v = myri_ether_init(dev, sdev, (cards - 1))))
                                        return v;
                        }
index 2de6a46fa83a62d5b4a3c28d262b7b659a5333ba..ddadd80f25062702b964cd62a7d71d8bf56abcaa 100644 (file)
@@ -1,4 +1,4 @@
-/* myri_sbus.h: Defines for MyriCOM Gigabit Ethernet SBUS card driver.
+/* myri_sbus.h: Defines for MyriCOM MyriNET SBUS card driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
new file mode 100644 (file)
index 0000000..2d59189
--- /dev/null
@@ -0,0 +1,931 @@
+/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
+/*
+ *      Copyright 1996,97 Thomas Bogendoerfer
+ * 
+ *     Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ * 
+ *     Copyright 1993 United States Government as represented by the
+ *     Director, National Security Agency.
+ * 
+ *     This software may be used and distributed according to the terms
+ *     of the GNU Public License, incorporated herein by reference.
+ *
+ *     This driver is for PCnet32 and PCnetPCI based ethercards
+ */
+
+static const char *version = "pcnet32.c:v0.23 8.2.97 tsbogend@alpha.franken.de\n";
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+static unsigned int pcnet32_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
+
+#ifdef PCNET32_DEBUG
+int pcnet32_debug = PCNET32_DEBUG;
+#else
+int pcnet32_debug = 1;
+#endif
+
+/*
+ *                             Theory of Operation
+ * 
+ * This driver uses the same software structure as the normal lance
+ * driver. So look for a verbose description in lance.c. The differences
+ * to the normal lance driver is the use of the 32bit mode of PCnet32
+ * and PCnetPCI chips. Because these chips are 32bit chips, there is no
+ * 16MB limitation and we don't need bounce buffers.
+ */
+/*
+ * History:
+ * v0.01:  Initial version
+ *         only tested on Alpha Noname Board
+ * v0.02:  changed IRQ handling for new interrupt scheme (dev_id)
+ *         tested on a ASUS SP3G
+ * v0.10:  fixed an odd problem with the 79C794 in a Compaq Deskpro XL
+ *         looks like the 974 doesn't like stopping and restarting in a
+ *         short period of time; now we do a reinit of the lance; the
+ *         bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
+ *         and hangs the machine (thanks to Klaus Liedl for debugging)
+ * v0.12:  by suggestion from Donald Becker: Renamed driver to pcnet32,
+ *         made it standalone (no need for lance.c)
+ * v0.13:  added additional PCI detecting for special PCI devices (Compaq)
+ * v0.14:  stripped down additional PCI probe (thanks to David C Niemi
+ *         and sveneric@xs4all.nl for testing this on their Compaq boxes)
+ * v0.15:  added 79C965 (VLB) probe
+ *         added interrupt sharing for PCI chips
+ * v0.16:  fixed set_multicast_list on Alpha machines
+ * v0.17:  removed hack from dev.c; now pcnet32 uses ethif_probe in Space.c
+ * v0.19:  changed setting of autoselect bit
+ * v0.20:  removed additional Compaq PCI probe; there is now a working one
+ *        in arch/i386/bios32.c
+ * v0.21:  added endian conversion for ppc, from work by cort@cs.nmt.edu
+ * v0.22:  added printing of status to ring dump
+ * v0.23:  changed enet_statistics to net_devive_stats
+ */
+
+
+/*
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * Reasonable default values are 4 Tx buffers, and 16 Rx buffers.
+ * That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4).
+ */
+#ifndef PCNET32_LOG_TX_BUFFERS
+#define PCNET32_LOG_TX_BUFFERS 4
+#define PCNET32_LOG_RX_BUFFERS 4
+#endif
+
+#define TX_RING_SIZE                   (1 << (PCNET32_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK               (TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS               ((PCNET32_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE                   (1 << (PCNET32_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK               (RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS               ((PCNET32_LOG_RX_BUFFERS) << 4)
+
+#define PKT_BUF_SZ             1544
+
+/* Offsets from base I/O address. */
+#define PCNET32_DATA 0x10
+#define PCNET32_ADDR 0x12
+#define PCNET32_RESET 0x14
+#define PCNET32_BUS_IF 0x16
+#define PCNET32_TOTAL_SIZE 0x18
+
+/* The PCNET32 Rx and Tx ring descriptors. */
+struct pcnet32_rx_head {
+       u32 base;
+       s16 buf_length;
+        s16 status;    
+       u32 msg_length;
+       u32 reserved;
+};
+       
+struct pcnet32_tx_head {
+       u32 base;
+       s16 length;
+        s16 status;
+       u32 misc;
+       u32 reserved;
+};
+
+
+/* The PCNET32 32-Bit initialization block, described in databook. */
+struct pcnet32_init_block {
+       u16 mode;
+       u16 tlen_rlen;
+       u8  phys_addr[6];
+       u16 reserved;
+       u32 filter[2];
+       /* Receive and transmit ring base, along with extra bits. */    
+       u32 rx_ring;
+       u32 tx_ring;
+};
+
+struct pcnet32_private {
+       /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
+       struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
+       struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
+       struct pcnet32_init_block       init_block;
+       const char *name;
+       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+       struct sk_buff* tx_skbuff[TX_RING_SIZE];
+       unsigned long rx_buffs;                 /* Address of Rx and Tx buffers. */
+       int cur_rx, cur_tx;                     /* The next free ring entry */
+       int dirty_rx, dirty_tx;                 /* The ring entries to be free()ed. */
+       struct net_device_stats stats;
+       char tx_full;
+       unsigned long lock;
+        char shared_irq;                         /* shared irq possible */
+};
+
+int  pcnet32_probe(struct device *dev);
+static int  pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared);
+static int  pcnet32_open(struct device *dev);
+static void pcnet32_init_ring(struct device *dev);
+static int  pcnet32_start_xmit(struct sk_buff *skb, struct device *dev);
+static int  pcnet32_rx(struct device *dev);
+static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  pcnet32_close(struct device *dev);
+static struct net_device_stats *pcnet32_get_stats(struct device *dev);
+static void pcnet32_set_multicast_list(struct device *dev);
+
+\f
+
+int pcnet32_probe (struct device *dev)
+{
+    unsigned int  ioaddr = dev ? dev->base_addr: 0;
+    unsigned char irq_line = dev ? dev->irq : 0;
+    int *port;
+    
+    if (ioaddr > 0x1ff)
+      return pcnet32_probe1(dev, ioaddr, irq_line, 0);
+    else if(ioaddr != 0)
+      return ENXIO;
+    
+#if defined(CONFIG_PCI)
+    if (pcibios_present()) {
+       int pci_index;
+       
+       printk("pcnet32.c: PCI bios is present, checking for devices...\n");
+       for (pci_index = 0; pci_index < 8; pci_index++) {
+           unsigned char pci_bus, pci_device_fn;
+           unsigned short pci_command;
+
+           if (pcibios_find_device (PCI_VENDOR_ID_AMD,
+                                    PCI_DEVICE_ID_AMD_LANCE, pci_index,
+                                    &pci_bus, &pci_device_fn) != 0)
+             break;
+           pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                    PCI_INTERRUPT_LINE, &irq_line);
+           pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                     PCI_BASE_ADDRESS_0, &ioaddr);
+           /* Remove I/O space marker in bit 0. */
+           ioaddr &= ~3;
+           /* PCI Spec 2.1 states that it is either the driver or PCI card's
+            * responsibility to set the PCI Master Enable Bit if needed.
+            *  (From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
+            */
+           pcibios_read_config_word(pci_bus, pci_device_fn,
+                                    PCI_COMMAND, &pci_command);
+           
+           /* Avoid already found cards from previous pcnet32_probe() calls */
+           if (check_region(ioaddr, PCNET32_TOTAL_SIZE))
+             continue;
+
+           if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+               printk("PCI Master Bit has not been set. Setting...\n");
+               pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+               pcibios_write_config_word(pci_bus, pci_device_fn,
+                                         PCI_COMMAND, pci_command);
+           }
+#ifdef __powerpc__
+           irq_line = 15;
+#endif
+           
+           printk("Found PCnet/PCI at %#x, irq %d.\n",
+                  ioaddr, irq_line);
+           
+           if (pcnet32_probe1(dev, ioaddr, irq_line, 1) != 0) {        /* Shouldn't happen. */
+               printk(KERN_ERR "pcnet32.c: Probe of PCI card at %#x failed.\n", ioaddr);
+               break;
+           }
+           return 0;
+       }
+    } else 
+#endif  /* defined(CONFIG_PCI) */
+    
+    /* now look for PCnet32 VLB cards */
+    for (port = pcnet32_portlist; *port; port++) {
+       unsigned int ioaddr = *port;
+       
+       if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
+           if (pcnet32_probe1(dev, ioaddr, 0, 0) == 0)
+             return 0;
+       }
+    }
+    
+    return ENODEV;
+}
+
+
+/* pcnet32_probe1 */
+int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared)
+{
+    struct pcnet32_private *lp;
+    int i;
+    char *chipname;
+
+    /* check if there is really a pcnet chip on that ioaddr */
+    if ((inb(ioaddr + 14) != 0x57) || (inb(ioaddr + 15) != 0x57))
+      return ENODEV; 
+    
+    inw(ioaddr+PCNET32_RESET); /* Reset the PCNET32 */
+
+    outw(0x0000, ioaddr+PCNET32_ADDR); /* Switch to window 0 */
+    if (inw(ioaddr+PCNET32_DATA) != 0x0004)
+      return ENODEV;
+
+    /* Get the version of the chip. */
+    outw(88, ioaddr+PCNET32_ADDR);
+    if (inw(ioaddr+PCNET32_ADDR) != 88) {
+       /* should never happen */
+       return ENODEV;
+    } else {                   /* Good, it's a newer chip. */
+       int chip_version = inw(ioaddr+PCNET32_DATA);
+       outw(89, ioaddr+PCNET32_ADDR);
+       chip_version |= inw(ioaddr+PCNET32_DATA) << 16;
+       if (pcnet32_debug > 2)
+         printk("  PCnet chip version is %#x.\n", chip_version);
+       if ((chip_version & 0xfff) != 0x003)
+         return ENODEV;
+       chip_version = (chip_version >> 12) & 0xffff;
+       switch (chip_version) {
+        case 0x2420:
+           chipname = "PCnet/PCI 79C970";
+           break;
+        case 0x2430:
+           chipname = "PCnet32";
+           break;
+        case 0x2621:
+           chipname = "PCnet/PCI II 79C970A";
+           break;
+        default:
+           printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+           return ENODEV;
+       }
+    }
+    
+    /* We should have a "dev" from Space.c or the static module table. */
+    if (dev == NULL) {
+       printk(KERN_ERR "pcnet32.c: Passed a NULL device.\n");
+       dev = init_etherdev(0, 0);
+    }
+
+    printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+
+    /* There is a 16 byte station address PROM at the base address.
+     The first six bytes are the station address. */
+    for (i = 0; i < 6; i++)
+      printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+
+    dev->base_addr = ioaddr;
+    request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
+    
+    /* Make certain the data structures used by the PCnet32 are 16byte aligned and DMAble. */
+    lp = (struct pcnet32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
+      
+    memset(lp, 0, sizeof(*lp));
+    dev->priv = lp;
+    lp->name = chipname;
+    lp->shared_irq = shared;
+    lp->rx_buffs = (unsigned long) kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL);
+
+    lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
+    lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS); 
+    for (i = 0; i < 6; i++)
+      lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    lp->init_block.filter[0] = 0x00000000;
+    lp->init_block.filter[1] = 0x00000000;
+    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    
+    /* switch pcnet32 to 32bit mode */
+    outw(0x0014, ioaddr+PCNET32_ADDR);
+    outw(0x0002, ioaddr+PCNET32_BUS_IF);
+
+    outw(0x0001, ioaddr+PCNET32_ADDR);
+    inw(ioaddr+PCNET32_ADDR);
+    outw(virt_to_bus(&lp->init_block) & 0xffff, ioaddr+PCNET32_DATA);
+    outw(0x0002, ioaddr+PCNET32_ADDR);
+    inw(ioaddr+PCNET32_ADDR);
+    outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
+    outw(0x0000, ioaddr+PCNET32_ADDR);
+    inw(ioaddr+PCNET32_ADDR);
+    
+    if (irq_line) {
+       dev->irq = irq_line;
+    }
+    
+    if (dev->irq >= 2)
+      printk(" assigned IRQ %d.\n", dev->irq);
+    else {
+       /*
+        * To auto-IRQ we enable the initialization-done and DMA error
+        * interrupts. For ISA boards we get a DMA error, but VLB and PCI
+        * boards will work.
+        */
+       autoirq_setup(0);
+       
+       /* Trigger an initialization just for the interrupt. */
+       outw(0x0041, ioaddr+PCNET32_DATA);
+
+       dev->irq = autoirq_report(1);
+       if (dev->irq)
+         printk(", probed IRQ %d.\n", dev->irq);
+       else {
+           printk(", failed to detect IRQ line.\n");
+           return ENODEV;
+       }
+    }
+
+    outw(0x0002, ioaddr+PCNET32_ADDR);
+    /* only touch autoselect bit */
+    outw(inw(ioaddr+PCNET32_BUS_IF) | 0x0002, ioaddr+PCNET32_BUS_IF);
+
+
+    if (pcnet32_debug > 0)
+      printk(version);
+    
+    /* The PCNET32-specific entries in the device structure. */
+    dev->open = &pcnet32_open;
+    dev->hard_start_xmit = &pcnet32_start_xmit;
+    dev->stop = &pcnet32_close;
+    dev->get_stats = &pcnet32_get_stats;
+    dev->set_multicast_list = &pcnet32_set_multicast_list;
+
+    /* Fill in the generic fields of the device structure. */
+    ether_setup(dev);
+    return 0;
+}
+
+\f
+static int
+pcnet32_open(struct device *dev)
+{
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+       unsigned int ioaddr = dev->base_addr;
+       int i;
+
+       if (dev->irq == 0 ||
+               request_irq(dev->irq, &pcnet32_interrupt,
+                           lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
+               return -EAGAIN;
+       }
+
+       /* Reset the PCNET32 */
+       inw(ioaddr+PCNET32_RESET);
+
+       /* switch pcnet32 to 32bit mode */
+       outw(0x0014, ioaddr+PCNET32_ADDR);
+       outw(0x0002, ioaddr+PCNET32_BUS_IF);
+
+       /* Turn on auto-select of media (AUI, BNC). */
+       outw(0x0002, ioaddr+PCNET32_ADDR);
+       /* only touch autoselect bit */
+       outw(inw(ioaddr+PCNET32_BUS_IF) | 0x0002, ioaddr+PCNET32_BUS_IF);
+
+       if (pcnet32_debug > 1)
+               printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
+                          dev->name, dev->irq,
+                          (u32) virt_to_bus(lp->tx_ring),
+                          (u32) virt_to_bus(lp->rx_ring),
+                          (u32) virt_to_bus(&lp->init_block));
+
+       lp->init_block.mode = 0x0000;
+       lp->init_block.filter[0] = 0x00000000;
+       lp->init_block.filter[1] = 0x00000000;
+       pcnet32_init_ring(dev);
+    
+       /* Re-initialize the PCNET32, and start it when done. */
+       outw(0x0001, ioaddr+PCNET32_ADDR);
+       outw(virt_to_bus(&lp->init_block) &0xffff, ioaddr+PCNET32_DATA);
+       outw(0x0002, ioaddr+PCNET32_ADDR);
+       outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
+
+       outw(0x0004, ioaddr+PCNET32_ADDR);
+       outw(0x0915, ioaddr+PCNET32_DATA);
+
+       outw(0x0000, ioaddr+PCNET32_ADDR);
+       outw(0x0001, ioaddr+PCNET32_DATA);
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+       i = 0;
+       while (i++ < 100)
+               if (inw(ioaddr+PCNET32_DATA) & 0x0100)
+                       break;
+       /* 
+        * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+        * reports that doing so triggers a bug in the '974.
+        */
+       outw(0x0042, ioaddr+PCNET32_DATA);
+
+       if (pcnet32_debug > 2)
+               printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+                          dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA));
+
+       return 0;                                       /* Always succeed */
+}
+
+/*
+ * The LANCE has been halted for one reason or another (busmaster memory
+ * arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
+ * etc.).  Modern LANCE variants always reload their ring-buffer
+ * configuration when restarted, so we must reinitialize our ring
+ * context before restarting.  As part of this reinitialization,
+ * find all packets still on the Tx ring and pretend that they had been
+ * sent (in effect, drop the packets on the floor) - the higher-level
+ * protocols will time out and retransmit.  It'd be better to shuffle
+ * these skbs to a temp list and then actually re-Tx them after
+ * restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
+ */
+
+static void 
+pcnet32_purge_tx_ring(struct device *dev)
+{
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+       int i;
+
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               if (lp->tx_skbuff[i]) {
+                       dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE);
+                       lp->tx_skbuff[i] = NULL;
+               }
+       }
+}
+
+
+/* Initialize the PCNET32 Rx and Tx rings. */
+static void
+pcnet32_init_ring(struct device *dev)
+{
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+       int i;
+
+       lp->lock = 0, lp->tx_full = 0;
+       lp->cur_rx = lp->cur_tx = 0;
+       lp->dirty_rx = lp->dirty_tx = 0;
+
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus((char *)lp->rx_buffs + i*PKT_BUF_SZ));
+               lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+               lp->rx_ring[i].status = le16_to_cpu(0x8000);        
+       }
+       /* The Tx buffer address is filled in as needed, but we do need to clear
+          the upper ownership bit. */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               lp->tx_ring[i].base = 0;
+               lp->tx_ring[i].status = 0;
+       }
+
+        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
+       for (i = 0; i < 6; i++)
+               lp->init_block.phys_addr[i] = dev->dev_addr[i];
+       lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
+       lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+}
+
+static void
+pcnet32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
+{
+        int i;
+       unsigned int ioaddr = dev->base_addr;
+    
+       pcnet32_purge_tx_ring(dev);
+       pcnet32_init_ring(dev);
+    
+       outw(0x0000, ioaddr + PCNET32_ADDR);
+        /* ReInit Ring */
+        outw(0x0001, ioaddr + PCNET32_DATA);
+       i = 0;
+       while (i++ < 100)
+               if (inw(ioaddr+PCNET32_DATA) & 0x0100)
+                       break;
+
+       outw(csr0_bits, ioaddr + PCNET32_DATA);
+}
+
+static int
+pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+       unsigned int ioaddr = dev->base_addr;
+       int entry;
+       unsigned long flags;
+
+       /* Transmitter timeout, serious problems. */
+       if (dev->tbusy) {
+               int tickssofar = jiffies - dev->trans_start;
+               if (tickssofar < 20)
+                       return 1;
+               outw(0, ioaddr+PCNET32_ADDR);
+               printk("%s: transmit timed out, status %4.4x, resetting.\n",
+                          dev->name, inw(ioaddr+PCNET32_DATA));
+               outw(0x0004, ioaddr+PCNET32_DATA);
+               lp->stats.tx_errors++;
+#ifndef final_version
+               {
+                       int i;
+                       printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+                                  lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+                                  lp->cur_rx);
+                       for (i = 0 ; i < RX_RING_SIZE; i++)
+                               printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+                                          lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+                                          lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+                       for (i = 0 ; i < TX_RING_SIZE; i++)
+                               printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+                                          lp->tx_ring[i].base, -lp->tx_ring[i].length,
+                                          lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+                       printk("\n");
+               }
+#endif
+               pcnet32_restart(dev, 0x0042, 1);
+
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+
+               return 0;
+       }
+
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (skb->len <= 0)
+               return 0;
+
+       if (pcnet32_debug > 3) {
+               outw(0x0000, ioaddr+PCNET32_ADDR);
+               printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name,
+                          inw(ioaddr+PCNET32_DATA));
+               outw(0x0000, ioaddr+PCNET32_DATA);
+       }
+
+       /* Block a timer-based transmit from overlapping.  This could better be
+          done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+       if (set_bit(0, (void*)&dev->tbusy) != 0) {
+               printk("%s: Transmitter access conflict.\n", dev->name);
+               return 1;
+       }
+
+       if (set_bit(0, (void*)&lp->lock) != 0) {
+               if (pcnet32_debug > 0)
+                       printk("%s: tx queue lock!.\n", dev->name);
+               /* don't clear dev->tbusy flag. */
+               return 1;
+       }
+
+       /* Fill in a Tx ring entry */
+
+       /* Mask to ring buffer boundary. */
+       entry = lp->cur_tx & TX_RING_MOD_MASK;
+
+       /* Caution: the write order is important here, set the base address
+          with the "ownership" bits last. */
+
+       lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+
+       lp->tx_ring[entry].misc = 0x00000000;
+
+       lp->tx_skbuff[entry] = skb;
+       lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
+        lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+
+       lp->cur_tx++;
+
+       /* Trigger an immediate send poll. */
+       outw(0x0000, ioaddr+PCNET32_ADDR);
+       outw(0x0048, ioaddr+PCNET32_DATA);
+
+       dev->trans_start = jiffies;
+
+       save_flags(flags);
+       cli();
+       lp->lock = 0;
+       if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
+               dev->tbusy=0;
+       else
+               lp->tx_full = 1;
+       restore_flags(flags);
+
+       return 0;
+}
+
+/* The PCNET32 interrupt handler. */
+static void
+pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct device *dev = (struct device *)dev_id;
+       struct pcnet32_private *lp;
+       unsigned int csr0, ioaddr;
+       int boguscnt=10;
+       int must_restart;
+
+       if (dev == NULL) {
+               printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+
+       ioaddr = dev->base_addr;
+       lp = (struct pcnet32_private *)dev->priv;
+       if (dev->interrupt)
+               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+       dev->interrupt = 1;
+
+       outw(0x00, dev->base_addr + PCNET32_ADDR);
+       while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600
+                  && --boguscnt >= 0) {
+               /* Acknowledge all of the current interrupt sources ASAP. */
+               outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA);
+
+               must_restart = 0;
+
+               if (pcnet32_debug > 5)
+                       printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+                                  dev->name, csr0, inw(dev->base_addr + PCNET32_DATA));
+
+               if (csr0 & 0x0400)                      /* Rx interrupt */
+                       pcnet32_rx(dev);
+
+               if (csr0 & 0x0200) {            /* Tx-done interrupt */
+                       int dirty_tx = lp->dirty_tx;
+
+                       while (dirty_tx < lp->cur_tx) {
+                               int entry = dirty_tx & TX_RING_MOD_MASK;
+                               int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+                       
+                               if (status < 0)
+                                       break;                  /* It still hasn't been Txed */
+
+                               lp->tx_ring[entry].base = 0;
+
+                               if (status & 0x4000) {
+                                       /* There was an major error, log it. */
+                                       int err_status = le16_to_cpu(lp->tx_ring[entry].misc);
+                                       lp->stats.tx_errors++;
+                                       if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
+                                       if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
+                                       if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+                                       if (err_status & 0x40000000) {
+                                               /* Ackk!  On FIFO errors the Tx unit is turned off! */
+                                               lp->stats.tx_fifo_errors++;
+                                               /* Remove this verbosity later! */
+                                               printk("%s: Tx FIFO error! Status %4.4x.\n",
+                                                          dev->name, csr0);
+                                               /* Restart the chip. */
+                                               must_restart = 1;
+                                       }
+                               } else {
+                                       if (status & 0x1800)
+                                               lp->stats.collisions++;
+                                       lp->stats.tx_packets++;
+                               }
+
+                               /* We must free the original skb */
+                               if (lp->tx_skbuff[entry]) {
+                                       dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE);
+                                       lp->tx_skbuff[entry] = 0;
+                               }
+                               dirty_tx++;
+                       }
+
+#ifndef final_version
+                       if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+                               printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+                                          dirty_tx, lp->cur_tx, lp->tx_full);
+                               dirty_tx += TX_RING_SIZE;
+                       }
+#endif
+
+                       if (lp->tx_full && dev->tbusy
+                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+                               /* The ring is no longer full, clear tbusy. */
+                               lp->tx_full = 0;
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);
+                       }
+
+                       lp->dirty_tx = dirty_tx;
+               }
+
+               /* Log misc errors. */
+               if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
+               if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */
+               if (csr0 & 0x0800) {
+                       printk("%s: Bus master arbitration failure, status %4.4x.\n",
+                                  dev->name, csr0);
+                       /* Restart the chip. */
+                       must_restart = 1;
+               }
+
+               if (must_restart) {
+                       /* stop the chip to clear the error condition, then restart */
+                       outw(0x0000, dev->base_addr + PCNET32_ADDR);
+                       outw(0x0004, dev->base_addr + PCNET32_DATA);
+                       pcnet32_restart(dev, 0x0002, 0);
+               }
+       }
+
+    /* Clear any other interrupt, and set interrupt enable. */
+    outw(0x0000, dev->base_addr + PCNET32_ADDR);
+    outw(0x7940, dev->base_addr + PCNET32_DATA);
+
+       if (pcnet32_debug > 4)
+               printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+                          dev->name, inw(ioaddr + PCNET32_ADDR),
+                          inw(dev->base_addr + PCNET32_DATA));
+
+       dev->interrupt = 0;
+       return;
+}
+
+static int
+pcnet32_rx(struct device *dev)
+{
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+       int entry = lp->cur_rx & RX_RING_MOD_MASK;
+       int i;
+               
+       /* If we own the next entry, it's a new packet. Send it up. */
+       while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+               int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+
+               if (status != 0x03) {                   /* There was an error. */
+                       /* There is a tricky error noted by John Murphy,
+                          <murf@perftech.com> to Russ Nelson: Even with full-sized
+                          buffers it's possible for a jabber packet to use two
+                          buffers, with only the last correctly noting the error. */
+                       if (status & 0x01)      /* Only count a general error at the */
+                               lp->stats.rx_errors++; /* end of a packet.*/
+                       if (status & 0x20) lp->stats.rx_frame_errors++;
+                       if (status & 0x10) lp->stats.rx_over_errors++;
+                       if (status & 0x08) lp->stats.rx_crc_errors++;
+                       if (status & 0x04) lp->stats.rx_fifo_errors++;
+                       lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+               }
+               else 
+               {
+                       /* Malloc up new buffer, compatible with net-2e. */
+                       short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
+                       struct sk_buff *skb;
+                       
+                       if(pkt_len<60)
+                       {
+                               printk("%s: Runt packet!\n",dev->name);
+                               lp->stats.rx_errors++;
+                       }
+                       else
+                       {
+                               skb = dev_alloc_skb(pkt_len+2);
+                               if (skb == NULL) 
+                               {
+                                       printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+                                       for (i=0; i < RX_RING_SIZE; i++)
+                                               if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
+                                                       break;
+
+                                       if (i > RX_RING_SIZE -2) 
+                                       {
+                                               lp->stats.rx_dropped++;
+                                               lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+                                               lp->cur_rx++;
+                                       }
+                                       break;
+                               }
+                               skb->dev = dev;
+                               skb_reserve(skb,2);     /* 16 byte align */
+                               skb_put(skb,pkt_len);   /* Make room */
+                               eth_copy_and_sum(skb,
+                                       (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
+                                       pkt_len,0);
+                               skb->protocol=eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                               lp->stats.rx_packets++;
+                       }
+               }
+               /* The docs say that the buffer length isn't touched, but Andrew Boyd
+                  of QNX reports that some revs of the 79C965 clear it. */
+               lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+               lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+               entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+       }
+
+       /* We should check that at least two ring entries are free.      If not,
+          we should free one and mark stats->rx_dropped++. */
+
+       return 0;
+}
+
+static int
+pcnet32_close(struct device *dev)
+{
+       unsigned int ioaddr = dev->base_addr;
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+
+       dev->start = 0;
+       dev->tbusy = 1;
+
+       outw(112, ioaddr+PCNET32_ADDR);
+       lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
+
+       outw(0, ioaddr+PCNET32_ADDR);
+
+       if (pcnet32_debug > 1)
+               printk("%s: Shutting down ethercard, status was %2.2x.\n",
+                          dev->name, inw(ioaddr+PCNET32_DATA));
+
+       /* We stop the PCNET32 here -- it occasionally polls
+          memory if we don't. */
+       outw(0x0004, ioaddr+PCNET32_DATA);
+
+       free_irq(dev->irq, dev);
+
+       return 0;
+}
+
+static struct net_device_stats *
+pcnet32_get_stats(struct device *dev)
+{
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+       unsigned int ioaddr = dev->base_addr;
+       unsigned short saved_addr;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       saved_addr = inw(ioaddr+PCNET32_ADDR);
+       outw(112, ioaddr+PCNET32_ADDR);
+       lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
+       outw(saved_addr, ioaddr+PCNET32_ADDR);
+       restore_flags(flags);
+
+       return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ */
+
+static void pcnet32_set_multicast_list(struct device *dev)
+{
+       unsigned int ioaddr = dev->base_addr;
+       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+
+       if (dev->flags&IFF_PROMISC) {
+               /* Log any net taps. */
+               printk("%s: Promiscuous mode enabled.\n", dev->name);
+               lp->init_block.mode = 0x8000;
+       } else {
+               int num_addrs=dev->mc_count;
+               if(dev->flags&IFF_ALLMULTI)
+                       num_addrs=1;
+               /* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
+               memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
+               lp->init_block.mode = 0x0000;           
+       }
+    
+       outw(0, ioaddr+PCNET32_ADDR);
+       outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance.        */
+
+       pcnet32_restart(dev, 0x0042, 0); /*  Resume normal operation */
+
+}
+
+\f
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c"
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
index b4e4e56a3f677b658b8a0a6a00218d690447814d..38b50ab4fdd446f6107890612dd1ac56b4c18361 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/timer.h>
 #include <linux/if_arp.h>
-#include "pi2.h"
+#include <linux/pi2.h>
 #include "z8530.h"
 #include <net/ax25.h>
 
diff --git a/drivers/net/pi2.h b/drivers/net/pi2.h
deleted file mode 100644 (file)
index 1740cc0..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-
-#define DMA_BUFF_SIZE 2200
-
-#define ON 1
-#define OFF 0
-
-
-/* Register offset info, specific to the PI
- * E.g., to read the data port on channel A, use
- *  inportb(pichan[dev].base + CHANA + DATA)
- */
-#define CHANB   0   /* Base of channel B regs */
-#define CHANA   2   /* Base of channel A regs */
-
-/* 8530 ports on each channel */
-#define CTL 0
-#define DATA    1
-
-#define DMAEN   0x4 /* Offset off DMA Enable register */
-
-/* Timer chip offsets */
-#define TMR0    0x8 /* Offset of timer 0 register */
-#define TMR1    0x9 /* Offset of timer 1 register */
-#define TMR2    0xA /* Offset of timer 2 register */
-#define TMRCMD  0xB /* Offset of timer command register */
-
-/* Timer chip equates */
-#define SC0 0x00 /* Select counter 0 */
-#define SC1 0x40 /* Select counter 1 */
-#define SC2 0x80 /* Select counter 2 */
-#define CLATCH  0x00 /* Counter latching operation */
-#define MSB 0x20 /* Read/load MSB only */
-#define LSB 0x10 /* Read/load LSB only */
-#define LSB_MSB 0x30 /* Read/load LSB, then MSB */
-#define MODE0   0x00 /* Interrupt on terminal count */
-#define MODE1   0x02 /* Programmable one shot */
-#define MODE2   0x04 /* Rate generator */
-#define MODE3   0x06 /* Square wave rate generator */
-#define MODE4   0x08 /* Software triggered strobe */
-#define MODE5   0x0a /* Hardware triggered strobe */
-#define BCD 0x01 /* BCD counter */
-
-/* DMA controller registers */
-#define DMA_STAT    8   /* DMA controller status register */
-#define DMA_CMD     8   /* DMA controller command register */
-#define DMA_MASK        10  /* DMA controller mask register */
-#define DMA_MODE        11  /* DMA controller mode register */
-#define DMA_RESETFF 12  /* DMA controller first/last flip flop  */
-/* DMA data */
-#define DMA_DISABLE (0x04)  /* Disable channel n */
-#define DMA_ENABLE  (0x00)  /* Enable channel n */
-/* Single transfers, incr. address, auto init, writes, ch. n */
-#define DMA_RX_MODE (0x54)
-/* Single transfers, incr. address, no auto init, reads, ch. n */
-#define DMA_TX_MODE (0x48)
-
-#define SINGLE 3686400
-#define DOUBLE 7372800
-
-#define SIOCGPIPARAM           0x5000  /* get PI parameters */
-#define SIOCSPIPARAM           0x5001  /* set */
-#define SIOCGPIBAUD            0x5002  /* get only baud rate */
-#define SIOCSPIBAUD            0x5003  
-#define SIOCGPIDMA             0x5004  /* get only DMA */
-#define SIOCSPIDMA             0x5005  
-#define SIOCGPIIRQ             0x5006  /* get only IRQ */
-#define SIOCSPIIRQ             0x5007  
-
-struct pi_req  {
-    int cmd;
-    int speed;
-    int clockmode;
-    int txdelay;
-    unsigned char persist;
-    int slotime; 
-    int squeldelay;
-    int dmachan;    
-    int irq;    
-};
-
-#ifdef __KERNEL__
-
-/* Information that needs to be kept for each channel. */
-struct pi_local {
-    struct net_device_stats stats; 
-    long open_time;             /* Useless example local info. */
-    unsigned long xtal; 
-
-    struct mbuf *rcvbuf;/* Buffer for current rx packet */
-    struct mbuf *rxdmabuf1; /* DMA rx buffer */
-    struct mbuf *rxdmabuf2; /* DMA rx buffer */
-
-    int bufsiz;         /* Size of rcvbuf */
-    char *rcp;          /* Pointer into rcvbuf */
-
-    struct sk_buff_head sndq;  /* Packets awaiting transmission */
-    int sndcnt;         /* Number of packets on sndq */
-    struct sk_buff *sndbuf;    /* Current buffer being transmitted */
-    char *txdmabuf;     /* Transmit DMA buffer */
-       char *txptr;            /* Used by B port tx */
-       int txcnt;                      
-    char tstate;        /* Transmitter state */
-#define IDLE    0       /* Transmitter off, no data pending */
-#define ACTIVE  1       /* Transmitter on, sending data */
-#define UNDERRUN 2      /* Transmitter on, flushing CRC */
-#define FLAGOUT 3       /* CRC sent - attempt to start next frame */
-#define DEFER 4         /* Receive Active - DEFER Transmit */
-#define ST_TXDELAY 5    /* Sending leading flags */
-#define CRCOUT 6
-    char rstate;        /* Set when !DCD goes to 0 (TRUE) */
-/* Normal state is ACTIVE if Receive enabled */
-#define RXERROR 2       /* Error -- Aborting current Frame */
-#define RXABORT 3       /* ABORT sequence detected */
-#define TOOBIG 4        /* too large a frame to store */
-    int dev;            /* Device number */
-    int base;       /* Base of I/O registers */
-    int cardbase;     /* Base address of card */
-    int stata;        /* address of Channel A status regs */
-    int statb;        /* address of Channel B status regs */
-    int speed;        /* Line speed, bps */
-    int clockmode;    /* tapr 9600 modem clocking option */
-    int txdelay;      /* Transmit Delay 10 ms/cnt */
-    unsigned char persist;       /* Persistence (0-255) as a % */
-    int slotime;      /* Delay to wait on persistence hit */
-    int squeldelay;   /* Delay after XMTR OFF for squelch tail */
-    struct iface *iface;    /* Associated interface */
-    int dmachan;           /* DMA channel for this port */
-};
-
-#endif
index 8be502656972d2a4f2a7cdedc58c4d40e0621c90..cd516155b95201fe2e7b06d1e3f655947f601a00 100644 (file)
@@ -91,7 +91,7 @@
 #include <linux/skbuff.h>
 #include <linux/timer.h>
 #include <linux/if_arp.h>
-#include "pt.h"
+#include <linux/pt.h>
 #include "z8530.h"
 #include <net/ax25.h>
 
diff --git a/drivers/net/pt.h b/drivers/net/pt.h
deleted file mode 100644 (file)
index 9ab17f5..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * pt.h: Linux device driver for the Gracilis PackeTwin
- * Copyright (C) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.)
- *
- * Please read the notice appearing at the top of the file pt.c
- */
-#define DMA_BUFF_SIZE 2200
-
-#define ON 1
-#define OFF 0
-
-
-/* Register offset info, specific to the PT
- * E.g., to read the data port on channel A, use
- *  inportb(pichan[dev].base + CHANA + DATA)
- */
-#define CHANB   0   /* Base of channel B regs */
-#define CHANA   2   /* Base of channel A regs */
-
-/* 8530 ports on each channel */
-#define CTL 0
-#define DATA    1
-
-#define DMAEN   0x8 /* Offset off DMA Enable register */
-
-/* Timer chip offsets */
-#define TMR0    0x4 /* Offset of timer 0 register */
-#define TMR1    0x5 /* Offset of timer 1 register */
-#define TMR2    0x6 /* Offset of timer 2 register */
-#define TMRCMD  0x7 /* Offset of timer command register */
-#define INT_REG        0x8
-#define TMR1CLR 0x9
-#define TMR2CLR 0xa
-
-/* Interrupt register equates */
-#define PT_SCC_MSK     0x1
-#define PT_TMR1_MSK    0x2
-#define PT_TMR2_MSK    0x4
-
-/* Serial/interrupt register equates */
-#define PT_DTRA_ON     0x1
-#define PT_DTRB_ON     0x2
-#define PT_EXTCLKA     0x4
-#define PT_EXTCLKB     0x8
-#define PT_LOOPA_ON    0x10
-#define PT_LOOPB_ON    0x20
-#define PT_EI          0x80
-
-/* Timer chip equates */
-#define SC0 0x00 /* Select counter 0 */
-#define SC1 0x40 /* Select counter 1 */
-#define SC2 0x80 /* Select counter 2 */
-#define CLATCH  0x00 /* Counter latching operation */
-#define MSB 0x20 /* Read/load MSB only */
-#define LSB 0x10 /* Read/load LSB only */
-#define LSB_MSB 0x30 /* Read/load LSB, then MSB */
-#define MODE0   0x00 /* Interrupt on terminal count */
-#define MODE1   0x02 /* Programmable one shot */
-#define MODE2   0x04 /* Rate generator */
-#define MODE3   0x06 /* Square wave rate generator */
-#define MODE4   0x08 /* Software triggered strobe */
-#define MODE5   0x0a /* Hardware triggered strobe */
-#define BCD 0x01 /* BCD counter */
-
-/* DMA controller registers */
-#define DMA_STAT    8   /* DMA controller status register */
-#define DMA_CMD     8   /* DMA controller command register */
-#define DMA_MASK        10  /* DMA controller mask register */
-#define DMA_MODE        11  /* DMA controller mode register */
-#define DMA_RESETFF 12  /* DMA controller first/last flip flop  */
-/* DMA data */
-#define DMA_DISABLE (0x04)  /* Disable channel n */
-#define DMA_ENABLE  (0x00)  /* Enable channel n */
-/* Single transfers, incr. address, auto init, writes, ch. n */
-#define DMA_RX_MODE (0x54)
-/* Single transfers, incr. address, no auto init, reads, ch. n */
-#define DMA_TX_MODE (0x48)
-
-/* Write registers */
-#define DMA_CFG                0x08
-#define SERIAL_CFG     0x09
-#define INT_CFG                0x09    /* shares with serial config */
-#define DMA_CLR_FF     0x0a
-
-#define SINGLE 3686400
-#define DOUBLE 7372800
-#define XTAL   ((long) 6144000L)
-
-#define SIOCGPIPARAM           0x5000  /* get PI parameters */
-#define SIOCSPIPARAM           0x5001  /* set */
-#define SIOCGPIBAUD            0x5002  /* get only baud rate */
-#define SIOCSPIBAUD            0x5003  
-#define SIOCGPIDMA             0x5004  /* get only DMA */
-#define SIOCSPIDMA             0x5005  
-#define SIOCGPIIRQ             0x5006  /* get only IRQ */
-#define SIOCSPIIRQ             0x5007  
-
-struct pt_req
-{
-       int cmd;
-       int speed;
-       int clockmode;
-       int txdelay;
-       unsigned char persist;
-       int slotime; 
-       int squeldelay;
-       int dmachan;    
-       int irq;    
-};
-
-/* SCC Interrupt vectors, if we have set 'status low' */
-#define CHBTxIV                0x00
-#define CHBEXTIV       0x02
-#define CHBRxIV                0x04
-#define CHBSRCIV       0x06
-#define CHATxIV                0x08
-#define CHAEXTIV       0x0a
-#define CHARxIV                0x0c
-#define CHASRCIV       0x0e
-
-
-#ifdef __KERNEL__
-
-/* Information that needs to be kept for each channel. */
-struct pt_local
-{
-       struct net_device_stats stats; /* %%%dp*/
-       long open_time;             /* Useless example local info. */
-       unsigned long xtal; 
-
-       struct mbuf *rcvbuf;/* Buffer for current rx packet */
-       struct mbuf *rxdmabuf1; /* DMA rx buffer */
-       struct mbuf *rxdmabuf2; /* DMA rx buffer */
-
-       int bufsiz;                     /* Size of rcvbuf                       */
-       char *rcp;                      /* Pointer into rcvbuf                  */
-       struct sk_buff_head sndq;       /* Packets awaiting transmission        */
-       int sndcnt;                     /* Number of packets on sndq            */
-       struct sk_buff *sndbuf;         /* Current buffer being transmitted     */
-       char *txdmabuf;                 /* Transmit DMA buffer                  */
-       char *txptr;                    /* Used by B port tx                    */
-       int txcnt;                      
-       char tstate;                    /* Transmitter state                    */
-#define IDLE    0       /* Transmitter off, no data pending            */
-#define ACTIVE  1       /* Transmitter on, sending data                */
-#define UNDERRUN 2      /* Transmitter on, flushing CRC                        */
-#define FLAGOUT 3       /* CRC sent - attempt to start next frame      */
-#define DEFER 4         /* Receive Active - DEFER Transmit             */
-#define ST_TXDELAY 5    /* Sending leading flags                       */
-#define CRCOUT 6
-       char rstate;        /* Set when !DCD goes to 0 (TRUE)           */
-/* Normal state is ACTIVE if Receive enabled */
-#define RXERROR 2       /* Error -- Aborting current Frame             */
-#define RXABORT 3       /* ABORT sequence detected                     */
-#define TOOBIG 4        /* too large a frame to store                  */
-       
-       int dev;                /* Device number */
-       int base;               /* Base of I/O registers */
-       int cardbase;           /* Base address of card */
-       int stata;              /* address of Channel A status regs */
-       int statb;              /* address of Channel B status regs */
-       int speed;              /* Line speed, bps */
-       int clockmode;          /* tapr 9600 modem clocking option */
-       int txdelay;            /* Transmit Delay 10 ms/cnt */
-       unsigned char persist;  /* Persistence (0-255) as a % */
-       int slotime;            /* Delay to wait on persistence hit */
-       int squeldelay;         /* Delay after XMTR OFF for squelch tail */
-       struct iface *iface;    /* Associated interface */
-       int dmachan;            /* DMA channel for this port */
-       char saved_RR0;         /* The saved version of RR) that we compare with */
-       int nrzi;               /* Do we use NRZI (or NRZ) */
-};
-
-#endif
index abf4ef380d90e27ee1bcf0df7fbcd5ed5ce18940..d32d3d57b9b73bf819b7fcc718a2c52741adc1a9 100644 (file)
@@ -16,6 +16,8 @@
  * Description    : Schneider & Koch G16 Ethernet Device Driver for
  *                  Linux Kernel >= 1.1.22
  * Update History :
+ *                  Paul Gortmaker, 03/97: Fix for v2.1.x to use read{b,w}
+ *                  write{b,w} and memcpy -> memcpy_{to,from}io
  *
 -*/
 
@@ -64,6 +66,7 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
 #include <linux/string.h> 
+#include <linux/delay.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/bitops.h> 
@@ -754,7 +757,7 @@ int SK_probe(struct device *dev, short ioaddr)
     /* Read in station address */
     for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2)
     {
-       dev->dev_addr[i] = board->rom[j];          
+       dev->dev_addr[i] = readb(board->rom+j);          
     }
 
     /* Check for manufacturer code */
@@ -1253,8 +1256,7 @@ static int SK_send_packet(struct sk_buff *skb, struct device *dev)
 
        /* Copy data into dual ported ram */
 
-       memcpy((char *) (tmdp->u.buffer & 0x00ffffff), (char *)skb->data,
-              skb->len);
+       memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len);
 
        tmdp->blen = -len;            /* set length to transmit */
 
@@ -1598,8 +1600,7 @@ static void SK_rxintr(struct device *dev)
             * ignore status fields) 
             */
 
-           memcpy(skb_put(skb,len), (unsigned char *) (rmdp->u.buffer & 0x00ffffff),
-                  len);
+           memcpy_fromio(skb_put(skb,len), (rmdp->u.buffer & 0x00ffffff), len);
 
 
            /* 
@@ -1775,7 +1776,7 @@ unsigned int SK_rom_addr(void)
     int rom_found = 0;
     unsigned int rom_location[] = SK_BOOT_ROM_LOCATIONS;
     unsigned char rom_id[] = SK_BOOT_ROM_ID;
-    unsigned char *test_byte;
+    unsigned char test_byte;
 
     /* Autodetect Boot_ROM */
     PRINTK(("## %s: Autodetection of Boot_ROM\n", SK_NAME));
@@ -1788,10 +1789,10 @@ unsigned int SK_rom_addr(void)
        rom_found = 1; 
        for (j = 0; j < 6; j++)
        {
-           test_byte = (unsigned char *) (rom_location[i]+j);
+           test_byte = readb(rom_location[i]+j);
            PRINTK((" %02x ", *test_byte));
 
-           if(!(*test_byte == rom_id[j]))
+           if(test_byte != rom_id[j])
            {
                rom_found = 0;
            } 
@@ -1842,12 +1843,9 @@ unsigned int SK_rom_addr(void)
 
 void SK_reset_board(void)
 {
-    int i;
-
-    SK_PORT = 0x00;           /* Reset active */
-    for (i = 0; i < 10 ; i++) /* Delay min 5ms */
-       ;
-    SK_PORT = SK_RESET;       /* Set back to normal operation */
+    writeb(0x00, SK_PORT);       /* Reset active */
+    udelay(5000);                /* Delay min 5ms */
+    writeb(SK_RESET, SK_PORT);   /* Set back to normal operation */
 
 } /* End of SK_reset_board() */
 
@@ -1870,12 +1868,12 @@ void SK_reset_board(void)
 
 void SK_set_RAP(int reg_number)
 {
-    SK_IOREG = reg_number;
-    SK_PORT  = SK_RESET | SK_RAP | SK_WREG;
-    SK_IOCOM = SK_DOIO;
+    writew(reg_number, SK_IOREG);
+    writeb(SK_RESET | SK_RAP | SK_WREG, SK_PORT);
+    writeb(SK_DOIO, SK_IOCOM);
 
-    while (SK_PORT & SK_IORUN) 
-       ;
+    while (readb(SK_PORT) & SK_IORUN) 
+       barrier();
 } /* End of SK_set_RAP() */
 
 \f
@@ -1898,12 +1896,12 @@ int SK_read_reg(int reg_number)
 {
     SK_set_RAP(reg_number);
 
-    SK_PORT  = SK_RESET | SK_RDATA | SK_RREG;
-    SK_IOCOM = SK_DOIO;
+    writeb(SK_RESET | SK_RDATA | SK_RREG, SK_PORT);
+    writeb(SK_DOIO, SK_IOCOM);
 
-    while (SK_PORT & SK_IORUN)
-       ;
-    return (SK_IOREG);
+    while (readb(SK_PORT) & SK_IORUN)
+       barrier();
+    return (readw(SK_IOREG));
 
 } /* End of SK_read_reg() */
 
@@ -1927,13 +1925,13 @@ int SK_read_reg(int reg_number)
 
 int SK_rread_reg(void)
 {
-    SK_PORT  = SK_RESET | SK_RDATA | SK_RREG;
+    writeb(SK_RESET | SK_RDATA | SK_RREG, SK_PORT);
 
-    SK_IOCOM = SK_DOIO;
+    writeb(SK_DOIO, SK_IOCOM);
 
-    while (SK_PORT & SK_IORUN)
-       ;
-    return (SK_IOREG);
+    while (readb(SK_PORT) & SK_IORUN)
+       barrier();
+    return (readw(SK_IOREG));
 
 } /* End of SK_rread_reg() */
 
@@ -1961,12 +1959,12 @@ void SK_write_reg(int reg_number, int value)
 {
     SK_set_RAP(reg_number);
 
-    SK_IOREG = value;
-    SK_PORT  = SK_RESET | SK_RDATA | SK_WREG;
-    SK_IOCOM = SK_DOIO;
+    writew(value, SK_IOREG);
+    writeb(SK_RESET | SK_RDATA | SK_WREG, SK_PORT);
+    writeb(SK_DOIO, SK_IOCOM);
 
-    while (SK_PORT & SK_IORUN)
-       ;
+    while (readb(SK_PORT) & SK_IORUN)
+       barrier();
 } /* End of SK_write_reg */
 
 \f
index ed9a51f70b0521abc48e6398311c51e62cc9bc50..77be412f7428a8eb42e29ade72509a671ab7f058 100644 (file)
@@ -37,6 +37,7 @@
  *   0.1  21.09.96  Started
  *        18.10.96  Changed to new user space access routines (copy_{to,from}_user)
  *   0.4  21.01.97  Separately compileable soundcard/modem modules
+ *   0.5  03.03.97  fixed LPT probing (check_lpt result was interpreted the wrong way round)
  */
 
 /*****************************************************************************/
@@ -101,13 +102,13 @@ extern inline int copy_to_user(void *to, const void *from, unsigned long n)
 
 /* --------------------------------------------------------------------- */
 
-static const char sm_drvname[] = "soundmodem";
+const char sm_drvname[] = "soundmodem";
 static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.4 compiled " __TIME__ " " __DATE__ "\n";
+KERN_INFO "soundmodem: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
-static const struct modem_tx_info *sm_modem_tx_table[] = {
+const struct modem_tx_info *sm_modem_tx_table[] = {
 #ifdef CONFIG_SOUNDMODEM_AFSK1200
        &sm_afsk1200_tx,
 #endif /* CONFIG_SOUNDMODEM_AFSK1200 */
@@ -130,7 +131,7 @@ static const struct modem_tx_info *sm_modem_tx_table[] = {
        NULL
 };
 
-static const struct modem_rx_info *sm_modem_rx_table[] = {
+const struct modem_rx_info *sm_modem_rx_table[] = {
 #ifdef CONFIG_SOUNDMODEM_AFSK1200
        &sm_afsk1200_rx,
 #endif /* CONFIG_SOUNDMODEM_AFSK1200 */
@@ -229,6 +230,11 @@ static struct {
  * ===================== port checking routines ========================
  */
 
+/*
+ * returns 0 if ok and != 0 on error;
+ * the same behaviour as par96_check_lpt in baycom.c
+ */
+
 static int check_lpt(unsigned int iobase)
 {
        unsigned char b1,b2;
@@ -367,7 +373,7 @@ static void sm_output_open(struct sm_state *sm)
        }
        if (sm->hdrv.ptt_out.pariobase > 0 &&
            sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT &&
-           check_lpt(sm->hdrv.ptt_out.pariobase)) {
+           !check_lpt(sm->hdrv.ptt_out.pariobase)) {
                sm->hdrv.ptt_out.flags |= SP_PAR;
                request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt");
        }
index 8eb57a31a7078589f99ea868b04da01a62c6ba29..6c8aa0c4ac33b0dba5c9fc00e8ee9a5113b8999d 100644 (file)
@@ -81,8 +81,6 @@ static void modulator_1200(struct sm_state *sm, unsigned char *buf, int buflen)
  */
 
 
-
-
 #if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686))
 
 
@@ -143,10 +141,10 @@ static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char ne
        memmove(st->filt.f+1, st->filt.f,sizeof(st->filt.f) - sizeof(st->filt.f[0]));
        st->filt.f[0] = (((int)newval)-0x80);
 
-       sum = convolution8(st->filt.f, afsk12_tx_lo_i);
-       sum += convolution8(st->filt.f, afsk12_tx_lo_q);
-       sum -= convolution8(st->filt.f, afsk12_tx_hi_i);
-       sum -= convolution8(st->filt.f, afsk12_tx_hi_q);
+       sum = convolution8(st->filt.f, afsk12_tx_lo_i_f);
+       sum += convolution8(st->filt.f, afsk12_tx_lo_q_f);
+       sum -= convolution8(st->filt.f, afsk12_tx_hi_i_f);
+       sum -= convolution8(st->filt.f, afsk12_tx_hi_q_f);
        return sum;
 }
 
index 4695f2038044a32707e5d33bd1826beb05cbfbe0..4421418e44d0c419388dd3684898173df4d2aabc 100644 (file)
@@ -456,6 +456,7 @@ static int sbc_ioctl(struct device *dev, struct sm_state *sm, struct ifreq *ifr,
                i = 0;
                bi.data.mix.sample_rate = sm->mode_rx->srate;
                bi.data.mix.bit_rate = sm->hdrv.par.bitrate;
+               bi.data.mix.mixer_type = SM_MIXER_INVALID;
                switch (SCSTATE->revhi) {
                case 2:
                        bi.data.mix.mixer_type = SM_MIXER_CT1335;
index f9356c9e62e9a547eccf5b8e7a7578f4da3327ca..98ebc016ad0bcce21cc1957e6c2a1d00c3e0c7a0 100644 (file)
@@ -2190,6 +2190,7 @@ static int happy_meal_ether_init(struct device *dev, struct linux_sbus_device *s
        /* We are home free at this point, link us in to the happy
         * module device list.
         */
+       dev->ifindex = dev_new_index();
        hp->next_module = root_happy_dev;
        root_happy_dev = hp;
 #endif
index ca8656c62257527151113e2efe23490f02063b62..e72695b3d51f066c735b9e136a610ac854f4fb9d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.55 1997/02/07 09:41:07 ecd Exp $
+/* $Id: sunlance.c,v 1.56 1997/03/14 21:04:45 jj Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *     Written 1995, 1996 by Miguel de Icaza
@@ -255,7 +255,7 @@ int sparc_lance_debug = 2;
  * zero on the lebuffer PIO area. -davem
  */
 
-#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
+#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
 
 #ifdef MODULE
 static struct lance_private *root_lance_dev = NULL;
index 48da24beac480f79707db32b45038af9487076b7..55a74f49aadfa4b742f77b92bbeb488c2c6445a4 100644 (file)
@@ -1116,6 +1116,8 @@ static int qec_ether_init(struct device *dev, struct linux_sbus_device *sdev)
        /* We are home free at this point, link the qe's into
         * the master list for later module unloading.
         */
+       for(i = 0; i < 4; i++)
+               qe_devs[i]->ifindex = dev_new_index();
        qecp->next_module = root_qec_dev;
        root_qec_dev = qecp;
 #endif
index 20e803d19476e6d0494021f048d3a6ad5c78a0ec..ba537014c36e8458ee3f9731249a0f95df75530a 100644 (file)
  */
 
 
-# include  <linux/kernel.h>
-# include  <linux/module.h>
-# include  <linux/version.h>
-# include  <linux/fs.h>
-# include  <linux/errno.h>
-# include  <linux/sched.h>
-# include  <linux/timer.h>
-# include  <linux/ioport.h>
-
-# include  <asm/uaccess.h>
-
-# if defined(__i386__)
-# include  <asm/io.h>
-# include  <asm/system.h>
-# include  <asm/segment.h>
-# endif
-
-# if defined(__sparc__)
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+
+#include  <asm/uaccess.h>
+
+#if defined(__i386__)
+# include <asm/io.h>
+# include <asm/system.h>
+# include <asm/segment.h>
+#endif
+
+#if defined(__sparc__)
 # include <linux/delay.h>         /* udelay() */
 
 # include <asm/oplib.h>           /* OpenProm Library */
 # include <asm/sbus.h>            /* struct linux_sbus *SBus_chain */
 # include <asm/io.h>              /* sparc_alloc_io() */
-# endif
+#endif
 
-# include <asm/bpp.h>
+#include <asm/bpp.h>
 
 #define BPP_PROBE_CODE 0x55
 #define BPP_DELAY 100
 
-static const unsigned  BPP_MAJOR = 32;
+static const unsigned  BPP_MAJOR = LP_MAJOR;
 static const char* dev_name = "bpp";
 
 /* When switching from compatability to a mode where I can read, try
@@ -324,7 +325,7 @@ static void bpp_wake_up(unsigned long val)
 
 static void snooze(unsigned long snooze_time, unsigned minor)
 {
-      instances[minor].timer_list.expires = snooze_time+1;
+      instances[minor].timer_list.expires = jiffies + snooze_time + 1;
       instances[minor].timer_list.data    = minor;
       add_timer(&instances[minor].timer_list);
       sleep_on (&instances[minor].wait_queue);
@@ -457,7 +458,7 @@ static int terminate(unsigned minor)
 /*
  * Allow only one process to open the device at a time.
  */
-static int open(struct inode *inode, struct file *f)
+static int bpp_open(struct inode *inode, struct file *f)
 {
       unsigned minor = MINOR(inode->i_rdev);
       if (minor >= BPP_NO) return -ENODEV;
@@ -475,7 +476,7 @@ static int open(struct inode *inode, struct file *f)
  * mode as this is a reasonable place to clean up from messes made by
  * ioctls, or other mayhem.
  */
-static void release(struct inode *inode, struct file *f)
+static void bpp_release(struct inode *inode, struct file *f)
 {
       unsigned minor = MINOR(inode->i_rdev);
       instances[minor].opened = 0;
@@ -629,7 +630,7 @@ static long read_ecp(unsigned minor, char *c, unsigned long cnt)
       return cnt - remaining;
 }
 
-static long read(struct inode *inode, struct file *f,
+static long bpp_read(struct inode *inode, struct file *f,
                 char *c, unsigned long cnt)
 {
       long rc;
@@ -779,7 +780,7 @@ static long write_ecp(unsigned minor, const char *c, unsigned long cnt)
  * that. Otherwise, terminate and do my writing in compat mode. This
  * is the safest course as any device can handle it.
  */
-static long write(struct inode *inode, struct file *f,
+static long bpp_write(struct inode *inode, struct file *f,
                  const char *c, unsigned long cnt)
 {
       long errno = 0;
@@ -804,7 +805,7 @@ static long write(struct inode *inode, struct file *f,
       return errno;
 }
 
-static int ioctl(struct inode *inode, struct file *f, unsigned int cmd,
+static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
                 unsigned long arg)
 {
       int errno = 0;
@@ -856,19 +857,15 @@ static int ioctl(struct inode *inode, struct file *f, unsigned int cmd,
 }
 
 static struct file_operations bpp_fops = {
-      0,
-      read, /* read */
-      write, /* write */
-      0,
-      0,
-      ioctl,
-      0, /* mmap */
-      open,
-      release,
-      0,
-      0,
-      0,
-      0
+       NULL,           /* bpp_lseek */
+       bpp_read,
+       bpp_write,
+       NULL,           /* bpp_readdir */
+       NULL,           /* bpp_select */
+       bpp_ioctl,
+       NULL,           /* bpp_mmap */
+       bpp_open,
+       bpp_release,
 };
 
 #if defined(__i386__)
index 0416ec0db397fd3909861e939c1b10c6be45a380..763fc3cb924db456bdd7b4f6332a406e0324dcef 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: bwtwo.c,v 1.9 1996/12/23 10:15:57 ecd Exp $
+/* $Id: bwtwo.c,v 1.10 1997/03/12 23:25:15 ecd Exp $
  * bwtwo.c: bwtwo console driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
  */
 
 #include <linux/kd.h>
@@ -29,9 +30,30 @@ struct bwtwo_regs {
        __volatile__ __u8               status;
        __volatile__ __u8               cursor_start;
        __volatile__ __u8               cursor_end;
-       __volatile__ __u8               vcontrol[12];
+       __volatile__ __u8               h_blank_start;
+       __volatile__ __u8               h_blank_end;
+       __volatile__ __u8               h_sync_start;
+       __volatile__ __u8               h_sync_end;
+       __volatile__ __u8               comp_sync_end;
+       __volatile__ __u8               v_blank_start_high;
+       __volatile__ __u8               v_blank_start_low;
+       __volatile__ __u8               v_blank_end;
+       __volatile__ __u8               v_sync_start;
+       __volatile__ __u8               v_sync_end;
+       __volatile__ __u8               xfer_holdoff_start;
+       __volatile__ __u8               xfer_holdoff_end;
 };
 
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK      0x70
+#define BWTWO_SR_1600_1280     0x50
+#define BWTWO_SR_1152_900_76_A 0x40
+#define BWTWO_SR_1152_900_76_B 0x60
+#define BWTWO_SR_ID_MASK       0x0f
+#define BWTWO_SR_ID_MONO       0x02
+#define BWTWO_SR_ID_MONO_ECL   0x03
+#define BWTWO_SR_ID_MSYNC      0x04
+
 /* Control Register Constants */
 #define BWTWO_CTL_ENABLE_INTS   0x80
 #define BWTWO_CTL_ENABLE_VIDEO  0x40
@@ -85,7 +107,44 @@ bwtwo_unblank (fbinfo_t *fb)
        fb->info.bwtwo.regs->control |= BWTWO_CTL_ENABLE_VIDEO;
 }
 
-__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, uint bwtwo, int bw2_io))
+
+static u8 bw2regs_1600[] __initdata = {
+       0x14, 0x8b,     0x15, 0x28,     0x16, 0x03,     0x17, 0x13,
+       0x18, 0x7b,     0x19, 0x05,     0x1a, 0x34,     0x1b, 0x2e,
+       0x1c, 0x00,     0x1d, 0x0a,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x21,     0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+       0x14, 0x65,     0x15, 0x1e,     0x16, 0x04,     0x17, 0x0c,
+       0x18, 0x5e,     0x19, 0x03,     0x1a, 0xa7,     0x1b, 0x23,
+       0x1c, 0x00,     0x1d, 0x08,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+       0x14, 0xbb,     0x15, 0x2b,     0x16, 0x03,     0x17, 0x13,
+       0x18, 0xb0,     0x19, 0x03,     0x1a, 0xa6,     0x1b, 0x22,
+       0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+       0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
+       0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x24,     0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+       0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
+       0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, uint bwtwo, int bw2_io,
+                            struct linux_sbus_device *sbdp))
 {
        printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
        fb->type.fb_cmsize = 0;
@@ -95,9 +154,51 @@ __initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, uint bwtwo, int bw2_io))
        fb->reset = 0;
        fb->blank = bwtwo_blank;
        fb->unblank = bwtwo_unblank;
+
        fb->info.bwtwo.regs = sparc_alloc_io ((void *)bwtwo +
                BWTWO_REGISTER_OFFSET, 0, sizeof (struct bwtwo_regs),
                "bwtwo_regs", bw2_io, 0);
+
+       if (!prom_getbool(sbdp->prom_node, "width")) {
+               /* Ugh, broken PROM didn't initialize us.
+                * Let's deal with this ourselves.
+                */
+               u8 status, mon;
+               u8 *p;
+
+               status = fb->info.bwtwo.regs->status;
+               mon = status & BWTWO_SR_RES_MASK;
+               switch (status & BWTWO_SR_ID_MASK) {
+                       case BWTWO_SR_ID_MONO_ECL:
+                               if (mon == BWTWO_SR_1600_1280) {
+                                       p = bw2regs_1600;
+                                       fb->type.fb_width = 1600;
+                                       fb->type.fb_height = 1280;
+                               } else {
+                                       p = bw2regs_ecl;
+                               }
+                               break;
+                       case BWTWO_SR_ID_MONO:
+                               p = bw2regs_analog;
+                               break;
+                       case BWTWO_SR_ID_MSYNC:
+                               if (mon == BWTWO_SR_1152_900_76_A ||
+                                   mon == BWTWO_SR_1152_900_76_B) {
+                                       p = bw2regs_76hz;
+                               } else {
+                                       p = bw2regs_66hz;
+                               }
+                               break;
+                       default:
+                               prom_printf("bwtwo: can't handle SR %02x\n",
+                                           status);
+                               prom_halt();
+                               return; /* fool gcc. */
+               }
+               for ( ; *p; p += 2)
+                       ((u8 *)fb->info.bwtwo.regs)[p[0]] = p[1];
+       }
+
        if(!fb->base)
                fb->base = (unsigned long) sparc_alloc_io((void *)bwtwo, 0,
                  ((fb->type.fb_depth*fb->type.fb_height*fb->type.fb_width)/8),
index d09940fb61850d4066c2f9a8502aa9b0a15a9904..ae74e8acfaee080a3d5e822918343fb7d92c2438 100644 (file)
@@ -1,7 +1,9 @@
-/* $Id: cgthree.c,v 1.10 1996/12/23 10:16:07 ecd Exp $
+/* $Id: cgthree.c,v 1.12 1997/03/11 23:44:24 ecd Exp $
  * cgtree.c: cg3 frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
  *
  * Support for cgRDI added, Nov/96, jj.
  */
 #include "fb.h"
 #include "cg_common.h"
 
+
+#define CG3_SR_RES_MASK                0x70
+#define CG3_SR_1152_900_76_A   0x40
+#define CG3_SR_1152_900_76_B   0x60
+#define CG3_SR_ID_MASK         0x0f
+#define CG3_SR_ID_COLOR                0x01
+#define CG3_SR_ID_MONO         0x02
+#define CG3_SR_ID_MONO_ECL     0x03
+
+
+enum cg3_type {
+       CG3_AT_66HZ = 0,
+       CG3_AT_76HZ,
+       CG3_RDI
+};
+
+
+struct cg3_regs {
+       struct bt_regs  cmap;
+       volatile u8     control;
+       volatile u8     status;
+       volatile u8     cursor_start;
+       volatile u8     cursor_end;
+       volatile u8     h_blank_start;
+       volatile u8     h_blank_end;
+       volatile u8     h_sync_start;
+       volatile u8     h_sync_end;
+       volatile u8     comp_sync_end;
+       volatile u8     v_blank_start_high;
+       volatile u8     v_blank_start_low;
+       volatile u8     v_blank_end;
+       volatile u8     v_sync_start;
+       volatile u8     v_sync_end;
+       volatile u8     xfer_holdoff_start;
+       volatile u8     xfer_holdoff_end;
+};
+
 /* The cg3 palette is loaded with 4 color values at each time  */
 /* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
 static void
 cg3_loadcmap (fbinfo_t *fb, int index, int count)
 {
-       struct bt_regs *bt = fb->info.cg3.bt;
+       struct bt_regs *bt = &fb->info.cg3.regs->cmap;
        int *i, steps;
 
        i = (((int *)fb->color_map) + D4M3(index));
        steps = D4M3(index+count-1) - D4M3(index)+3;
-#if 0  
-       if (fb->info.cg3.cgrdi) {
-               *(volatile u8 *)bt->addr = (u8)(D4M4(index));
-       } else
-#endif 
-       bt->addr = D4M4(index);
+
+       *(volatile u8 *)&bt->addr = (u8)D4M4(index);
        while (steps--)
                bt->color_map = *i++;
 }
@@ -90,7 +125,38 @@ cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
         return 0;
 }
 
-__initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io, struct linux_sbus_device *sbdp))
+static u8 cg3regvals_66hz[] __initdata = {     /* 1152 x 900, 66 Hz */
+       0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
+       0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x20,     0
+};
+
+static u8 cg3regvals_76hz[] __initdata = {     /* 1152 x 900, 76 Hz */
+       0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
+       0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
+       0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x24,     0
+};
+
+static u8 cg3regvals_rdi[] __initdata = {      /* 640 x 480, cgRDI */
+       0x14, 0x70,     0x15, 0x20,     0x16, 0x08,     0x17, 0x10,
+       0x18, 0x06,     0x19, 0x02,     0x1a, 0x31,     0x1b, 0x51,
+       0x1c, 0x06,     0x1d, 0x0c,     0x1e, 0xff,     0x1f, 0x01,
+       0x10, 0x22,     0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+       cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+       4, 0xff,        5, 0x00,        6, 0x70,        7, 0x00,        0
+};
+
+
+__initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io,
+                          struct linux_sbus_device *sbdp))
 {
        struct cg3_info *cg3info = (struct cg3_info *) &fb->info.cg3;
 
@@ -99,7 +165,8 @@ __initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io, struct
                char *p;
                int w, h;
                
-               prom_getstring (sbdp->prom_node, "params", buffer, sizeof(buffer));
+               prom_getstring (sbdp->prom_node, "params",
+                               buffer, sizeof(buffer));
                if (*buffer) {
                        w = simple_strtoul (buffer, &p, 10);
                        if (w && *p == 'x') {
@@ -126,11 +193,45 @@ __initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io, struct
        fb->reset = 0;
 
        /* Map the card registers */
-       cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
-                sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
-       /* cgRDI actually has 32 bytes of regs, but I don't understand
-          those bitfields yet (guess it is some interrupt stuff etc. */
-       
+       cg3info->regs = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
+                sizeof (struct cg3_regs),"cg3_regs", cg3_io, 0);
+
+       if (!prom_getbool(sbdp->prom_node, "width")) {
+               /* Ugh, broken PROM didn't initialize us.
+                * Let's deal with this ourselves.
+                */
+               u8 status, mon;
+               enum cg3_type type;
+               u8 *p;
+
+               if (cg3info->cgrdi) {
+                       type = CG3_RDI;
+               } else {
+                       status = cg3info->regs->status;
+                       if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+                               mon = status & CG3_SR_RES_MASK;
+                               if (mon == CG3_SR_1152_900_76_A ||
+                                   mon == CG3_SR_1152_900_76_B)
+                                       type = CG3_AT_76HZ;
+                               else
+                                       type = CG3_AT_66HZ;
+                       } else {
+                               prom_printf("cgthree: can't handle SR %02x\n",
+                                           status);
+                               prom_halt();
+                               return; /* fool gcc. */
+                       }
+               }
+
+               for (p = cg3_regvals[type]; *p; p += 2)
+                       ((u8 *)cg3info->regs)[p[0]] = p[1];
+
+               for (p = cg3_dacvals; *p; p += 2) {
+                       *(volatile u8 *)&cg3info->regs->cmap.addr = p[0];
+                       *(volatile u8 *)&cg3info->regs->cmap.control = p[1];
+               }
+       }
+
        if (!fb->base){
                fb->base=(uint) sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
                                    fb->type.fb_size, "cg3_ram", cg3_io, 0);
index b4adc08d53e52fd54697b7102278b3bb940a647d..8343568b3eab20322c5e6e29b7344f59a281dcdf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fb.h,v 1.21 1997/02/02 02:12:43 ecd Exp $
+/* $Id: fb.h,v 1.23 1997/03/12 23:25:16 ecd Exp $
  * fb.h: contains the definitions of the structures that various sun
  *       frame buffer can use to do console driver stuff.
  *
@@ -77,7 +77,7 @@ struct bwtwo_info {
 };
 
 struct cg3_info {
-       struct bt_regs *bt;     /* brooktree (color) registers */
+       struct cg3_regs *regs;  /* brooktree (color) registers, and more */
        int cgrdi;              /* 1 if this is a cgRDI */
 };
 
@@ -200,7 +200,8 @@ extern unsigned long sun_cg_postsetup(fbinfo_t *, unsigned long);
 extern void cg3_setup (fbinfo_t *, int, uint, int, struct linux_sbus_device *);
 extern void cg6_setup (fbinfo_t *, int, uint, int);
 extern void cg14_setup (fbinfo_t *, int, int, uint, int);
-extern void bwtwo_setup (fbinfo_t *, int, uint, int);
+extern void bwtwo_setup (fbinfo_t *, int, uint, int,
+                        struct linux_sbus_device *);
 extern void leo_setup (fbinfo_t *, int, uint, int);
 extern void tcx_setup (fbinfo_t *, int, int, uint, struct linux_sbus_device *);
 
index 8a11678ea165cd0f0233180dffa0e5ac628f2dd4..ea5816a7ed85be2875b16930c07213e6cce7dc24 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.50 1997/02/26 08:55:22 ecd Exp $
+/* $Id: suncons.c,v 1.53 1997/03/15 07:47:50 davem Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -758,26 +758,16 @@ console_restore_palette (void)
                (*fb_restore_palette) (&fbinfo[0]);
 }
 
-/* This routine should be moved to srmmu.c */
-static __inline__ uint
-srmmu_get_pte (unsigned long addr)
-{
-       register unsigned long entry;
-
-       __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
-                            "=r" (entry):
-                            "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
-       return entry;
-}
-
-uint
-get_phys (uint addr)
+unsigned int
+get_phys (unsigned int addr)
 {
        switch (sparc_cpu_model){
        case sun4c:
                return sun4c_get_pte (addr) << PAGE_SHIFT;
        case sun4m:
                return ((srmmu_get_pte (addr) & 0xffffff00) << 4);
+       case sun4u:
+               /* FIXME: */ return 0;
        default:
                panic ("get_phys called for unsupported cpu model\n");
                return 0;
@@ -785,13 +775,15 @@ get_phys (uint addr)
 }
 
 int
-get_iospace (uint addr)
+get_iospace (unsigned int addr)
 {
        switch (sparc_cpu_model){
        case sun4c:
                return -1; /* Don't check iospace on sun4c */
        case sun4m:
                return (srmmu_get_pte (addr) >> 28);
+       case sun4u:
+               /* FIXME: */ return 0;
        default:
                panic ("get_iospace called for unsupported cpu model\n");
                return -1;
@@ -927,7 +919,7 @@ __initfunc(static void
 #endif
 #ifdef SUN_FB_BWTWO
        case FBTYPE_SUN2BW:
-               bwtwo_setup (&fbinfo [n], n, base, io);
+               bwtwo_setup (&fbinfo [n], n, base, io, sbdp);
                break;
 #endif
 #ifdef SUN_FB_CGFOURTEEN
@@ -1082,13 +1074,13 @@ __initfunc(static int sparc_console_probe(void))
                        default_node = prom_pathtoinode(console_fb_path);
                        if (default_node) {
                                prom_printf ("Using %s for console\n", console_fb_path);
-                               prom_console_node = prom_inst2pkg(*romvec->pv_v2bootargs.fd_stdout);
+                               prom_console_node = prom_inst2pkg(prom_stdout);
                                if (prom_console_node == default_node)
                                        prom_console_node = 0;
                        }
                }
                if (!default_node)
-                       default_node = prom_inst2pkg(*romvec->pv_v2bootargs.fd_stdout);
+                       default_node = prom_inst2pkg(prom_stdout);
                propl = prom_getproperty(default_node, "device_type",
                                         prop, sizeof (prop));
                if (propl < 0) {
index 65a16c81352e27379740ed19f0a49398b451a11a..a40d54943c76731482521472f16e2514e0e6cfd5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.20 1997/01/26 07:13:40 davem Exp $
+/* $Id: sunfb.c,v 1.21 1997/03/14 21:04:53 jj Exp $
  * sunfb.c: Sun generic frame buffer support.
  *
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -32,7 +32,6 @@
 #include <asm/sbus.h>
 #include <asm/fbio.h>
 #include <asm/io.h>
-#include <asm/pgtsun4c.h>      /* for the sun4c_nocache */
 
 #include "../../char/kbd_kern.h"
 #include "../../char/vt_kern.h"
index db418092719b73304c3ca8345344211c54c76abc..87119ec5d6c96c793f7afe6c1a4d3c93d3250ba5 100644 (file)
@@ -96,6 +96,8 @@ static struct tty_struct **ttytab;
 static struct kbd_struct * kbd = kbd_table;
 static struct tty_struct * tty = NULL;
 static int compose_led_on = 0;
+static int kbd_delay_ticks = HZ / 5;
+static int kbd_rate_ticks = HZ / 20;
 
 extern void compute_shiftstate(void);
 
@@ -393,8 +395,10 @@ keyboard_timer (unsigned long ignored)
        /* Auto repeat: send regs = 0 to indicate autorepeat */
        sunkbd_inchar (last_keycode, 0, 0);
        del_timer (&auto_repeat_timer);
-       auto_repeat_timer.expires = jiffies + HZ/20;
-       add_timer (&auto_repeat_timer);
+       if (kbd_rate_ticks) {
+               auto_repeat_timer.expires = jiffies + kbd_rate_ticks;
+               add_timer (&auto_repeat_timer);
+       }
        restore_flags(flags);
 }
 
@@ -470,8 +474,11 @@ void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs)
                clear_bit(keycode, key_down);
        } else {
                if (!norepeat_keys[keycode]) {
-                       auto_repeat_timer.expires = jiffies+HZ/5;
-                       add_timer (&auto_repeat_timer);
+                       if (kbd_rate_ticks) {
+                               auto_repeat_timer.expires =
+                                               jiffies + kbd_delay_ticks;
+                               add_timer (&auto_repeat_timer);
+                       }
                }
                rep = set_bit(keycode, key_down);
        }
@@ -1177,6 +1184,7 @@ int kbd_init(void)
 static Firm_event kbd_queue [KBD_QSIZE];
 static int kbd_head, kbd_tail;
 char kbd_opened;
+static int kbd_active = 0;
 static struct wait_queue *kbd_wait;
 static struct fasync_struct *kb_fasync;
 
@@ -1311,6 +1319,41 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
        case KIOCGLED:
                put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT);
                break;
+       case KIOCGRATE:
+       {
+               struct kbd_rate rate;
+
+               rate.delay = kbd_delay_ticks;
+               if (kbd_rate_ticks)
+                       rate.rate = HZ / kbd_rate_ticks;
+               else
+                       rate.rate = 0;
+
+               copy_to_user_ret((struct kbd_rate *)arg, &rate,
+                                sizeof(struct kbd_rate), -EFAULT);
+
+               return 0;
+       }
+       case KIOCSRATE:
+       {
+               struct kbd_rate rate;
+
+               if (verify_area(VERIFY_READ, (void *)arg,
+                               sizeof(struct kbd_rate)))
+                       return -EFAULT;
+               copy_from_user(&rate, (struct kbd_rate *)arg,
+                              sizeof(struct kbd_rate));
+
+               if (rate.rate > 50)
+                       return -EINVAL;
+               if (rate.rate == 0)
+                       kbd_rate_ticks = 0;
+               else
+                       kbd_rate_ticks = HZ / rate.rate;
+               kbd_delay_ticks = rate.delay;
+
+               return 0;
+       }
        case FIONREAD:          /* return number of bytes in kbd queue */
        {
                int count;
@@ -1329,8 +1372,11 @@ kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
 static int
 kbd_open (struct inode *i, struct file *f)
 {
+       kbd_active++;
+
        if (kbd_opened)
                return 0;
+
        kbd_opened = fg_console + 1;
        kbd_head = kbd_tail = 0;
        return 0;
@@ -1339,8 +1385,12 @@ kbd_open (struct inode *i, struct file *f)
 static void
 kbd_close (struct inode *i, struct file *f)
 {
+       if (--kbd_active)
+               return;
+
        if (kbd_redirected)
                kbd_table [kbd_opened-1].kbdmode = VC_XLATE;
+
        kbd_redirected = 0;
        kbd_opened = 0;
 
index 1a3705b11b71c0e59c156c5d14bd9ec61f96f741..5e5324a616b0fb5304e0403c03c9abf68badc1ad 100644 (file)
@@ -8,24 +8,19 @@
 #include <linux/init.h>
 
 #include <asm/oplib.h>
-#include <asm/contregs.h>
-#include <asm/sysen.h>
 #include <asm/delay.h>
-#include <asm/machines.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/sbus.h>
-#include <asm/vac-ops.h>
-#include <asm/vaddrs.h>
 
 struct Linux_SBus_DMA *dma_chain;
 
 /* Print out the current values in the DMA control registers */
-void
+static __inline__ void
 dump_dma_regs(struct sparc_dma_registers *dregs)
 {
        printk("DMA CONTROL<%08lx>  ADDR<%08lx> CNT<%08lx> TEST<%08lx>\n",
-              dregs->cond_reg,
+              (unsigned long) dregs->cond_reg,
               (unsigned long) dregs->st_addr,
               (unsigned long) dregs->cnt,
               (unsigned long) dregs->dma_test);
index 2d3730ff29a0ada6ee4745ef9d242ed060884b90..703069abf2e796213504cb9def6749933284cae9 100644 (file)
@@ -149,9 +149,6 @@ extern int openprom_init(void);
 #ifdef CONFIG_SUN_MOSTEK_RTC
 extern int rtc_init(void);
 #endif
-#ifdef CONFIG_SPARCAUDIO
-extern int sparcaudio_init(void);
-#endif
 
 __initfunc(static unsigned long 
 sbus_do_child_siblings(unsigned long memory_start, int start_node,
@@ -339,9 +336,6 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
 #ifdef CONFIG_SUN_MOSTEK_RTC
        rtc_init();
 #endif
-#ifdef CONFIG_SPARCAUDIO
-       sparcaudio_init();
-#endif
 #ifdef CONFIG_SUN_BPP
        bpp_init();
 #endif
index 145d0377108d99a87dd5cc934336dd9117b2065e..5cedbcc50768ab30262527923004745431b4cc97 100644 (file)
@@ -27,8 +27,8 @@
 */
 
 
-#define BusLogic_DriverVersion         "2.0.7"
-#define BusLogic_DriverDate            "23 February 1997"
+#define BusLogic_DriverVersion         "2.0.8"
+#define BusLogic_DriverDate            "17 March 1997"
 
 
 #include <linux/module.h>
@@ -1086,9 +1086,9 @@ static int BusLogic_InitializeFlashPointProbeInfo(void)
   interrogating the PCI Configuration Space on PCI machines as well as from the
   list of standard BusLogic MultiMaster ISA I/O Addresses.  By default, if both
   FlashPoint and PCI MultiMaster Host Adapters are present, this driver will
-  probe for PCI MultiMaster Host Adapters first unless the BIOS primary disk is
-  not controlled by the first PCI MultiMaster Host Adapter, in which case
-  FlashPoint Host Adapters will be probed first.  The Kernel Command Line 
+  probe for FlashPoint Host Adapters first unless the BIOS primary disk is
+  controlled by the first PCI MultiMaster Host Adapter, in which case
+  MultiMaster Host Adapters will be probed first.  The Kernel Command Line
   options "MultiMasterFirst" and "FlashPointFirst" can be used to force a
   particular probe order.
 */
@@ -1118,11 +1118,12 @@ static void BusLogic_InitializeProbeInfoList(void)
        }
       else
        {
-         int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo();
          int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo();
-         if (PCIMultiMasterCount > 0 && FlashPointCount > 0)
+         int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo();
+         if (FlashPointCount > 0 && PCIMultiMasterCount > 0)
            {
-             BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[0];
+             BusLogic_ProbeInfo_T *ProbeInfo =
+               &BusLogic_ProbeInfoList[FlashPointCount];
              BusLogic_HostAdapter_T HostAdapterPrototype;
              BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
              BusLogic_FetchHostAdapterLocalRAMRequest_T
@@ -1142,27 +1143,26 @@ static void BusLogic_InitializeProbeInfoList(void)
                               &Drive0MapByte, sizeof(Drive0MapByte));
              /*
                If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0
-               is not controlled by this PCI MultiMaster Host Adapter, then
-               reverse the probe order so that FlashPoint Host Adapters are
-               probed before MultiMaster Host Adapters.
+               is controlled by this PCI MultiMaster Host Adapter, then
+               reverse the probe order so that MultiMaster Host Adapters are
+               probed before FlashPoint Host Adapters.
              */
-             if (Drive0MapByte.DiskGeometry ==
+             if (Drive0MapByte.DiskGeometry !=
                  BusLogic_BIOS_Disk_Not_Installed)
                {
                  BusLogic_ProbeInfo_T
                    SavedProbeInfo[BusLogic_MaxHostAdapters];
                  int MultiMasterCount =
                    BusLogic_ProbeInfoCount - FlashPointCount;
-                 memcpy(&SavedProbeInfo[0],
-                        &BusLogic_ProbeInfoList[0],
-                        BusLogic_ProbeInfoCount
-                        * sizeof(BusLogic_ProbeInfo_T));
+                 memcpy(SavedProbeInfo,
+                        BusLogic_ProbeInfoList,
+                        sizeof(BusLogic_ProbeInfoList));
                  memcpy(&BusLogic_ProbeInfoList[0],
-                        &SavedProbeInfo[MultiMasterCount],
-                        FlashPointCount * sizeof(BusLogic_ProbeInfo_T));
-                 memcpy(&BusLogic_ProbeInfoList[FlashPointCount],
-                        &SavedProbeInfo[0],
+                        &SavedProbeInfo[FlashPointCount],
                         MultiMasterCount * sizeof(BusLogic_ProbeInfo_T));
+                 memcpy(&BusLogic_ProbeInfoList[MultiMasterCount],
+                        &SavedProbeInfo[0],
+                        FlashPointCount * sizeof(BusLogic_ProbeInfo_T));
                }
            }
        }
@@ -1223,9 +1223,14 @@ static boolean BusLogic_ProbeHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
            FlashPointInfo->Present))
        {
          scsi_init_free((char *) FlashPointInfo, sizeof(FlashPoint_Info_T));
-         if (BusLogic_GlobalOptions.Bits.TraceProbe)
-           BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Not Found\n",
-                           HostAdapter, HostAdapter->IO_Address);
+         BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
+                        "PCI Bus %d Device %d\n", HostAdapter,
+                        HostAdapter->Bus, HostAdapter->Device);
+         BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, "
+                        "but FlashPoint\n", HostAdapter,
+                        HostAdapter->IO_Address, HostAdapter->PCI_Address);
+         BusLogic_Error("BusLogic: Probe Function failed to validate it.\n",
+                        HostAdapter);
          return false;
        }
       HostAdapter->FlashPointInfo = FlashPointInfo;
@@ -3006,6 +3011,7 @@ static void BusLogic_ProcessCompletedCCBs(void)
                          .BusDeviceResetsCompleted);
          HostAdapter->CommandsSinceReset[TargetID] = 0;
          HostAdapter->TaggedQueuingActive[TargetID] = false;
+         HostAdapter->LastResetCompleted[TargetID] = jiffies;
          /*
            Place CCB back on the Host Adapter's free list.
          */
@@ -3325,9 +3331,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
       int Segment;
       CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
       CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T);
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
       if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
        CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
       else CCB->DataPointer = (BusLogic_BusAddress_T) CCB->ScatterGatherList;
+#else
+      CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
+#endif
       for (Segment = 0; Segment < SegmentCount; Segment++)
        {
          CCB->ScatterGatherList[Segment].SegmentByteCount =
@@ -3739,7 +3749,10 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
          }
       }
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
-    HostAdapter->LastResetTime[TargetID] = jiffies;
+    {
+      HostAdapter->LastResetAttempted[TargetID] = jiffies;
+      HostAdapter->LastResetCompleted[TargetID] = jiffies;
+    }
   Result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
   /*
     Release exclusive access to Host Adapter.
@@ -3907,7 +3920,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
   BusLogic_IncrementErrorCounter(
     &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted);
   HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB;
-  HostAdapter->LastResetTime[TargetID] = jiffies;
+  HostAdapter->LastResetAttempted[TargetID] = jiffies;
   for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll)
     if (XCCB->Status == BusLogic_CCB_Active && XCCB->TargetID == TargetID)
       XCCB->Status = BusLogic_CCB_Reset;
@@ -3955,7 +3968,7 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
     the system was initialized if no prior resets have occurred.
   */
   if (HostAdapter->TaggedQueuingActive[TargetID] &&
-      jiffies - HostAdapter->LastResetTime[TargetID] < 10*60*HZ)
+      jiffies - HostAdapter->LastResetCompleted[TargetID] < 10*60*HZ)
     {
       HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
       HostAdapter->TaggedQueuingActive[TargetID] = false;
@@ -3980,7 +3993,7 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
        clear the error condition.
       */
       if (HostAdapter->CommandSuccessfulFlag[TargetID] ||
-         jiffies - HostAdapter->LastResetTime[TargetID] < HZ/10)
+         jiffies - HostAdapter->LastResetAttempted[TargetID] < HZ/10)
        {
          HostAdapter->CommandSuccessfulFlag[TargetID] = false;
          return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags);
@@ -4428,19 +4441,19 @@ static void BusLogic_Message(BusLogic_MessageLevel_T MessageLevel,
 
   MultiMasterFirst     By default, if both FlashPoint and PCI MultiMaster
                        Host Adapters are present, this driver will probe for
-                       PCI MultiMaster Host Adapters first unless the BIOS
-                       primary disk is not controlled by the first PCI
-                       MultiMaster Host Adapter, in which case FlashPoint
-                       Host Adapters will be probed first.  This option
-                       forces MultiMaster Host Adapters to be probed first.
+                       FlashPoint Host Adapters first unless the BIOS primary
+                       disk is controlled by the first PCI MultiMaster Host
+                       Adapter, in which case MultiMaster Host Adapters will
+                       be probed first.  This option forces MultiMaster Host
+                       Adapters to be probed first.
 
   FlashPointFirst      By default, if both FlashPoint and PCI MultiMaster
                        Host Adapters are present, this driver will probe for
-                       PCI MultiMaster Host Adapters first unless the BIOS
-                       primary disk is not controlled by the first PCI
-                       MultiMaster Host Adapter, in which case FlashPoint
-                       Host Adapters will be probed first.  This option
-                       forces FlashPoint Host Adapters to be probed first.
+                       FlashPoint Host Adapters first unless the BIOS primary
+                       disk is controlled by the first PCI MultiMaster Host
+                       Adapter, in which case MultiMaster Host Adapters will
+                       be probed first.  This option forces FlashPoint Host
+                       Adapters to be probed first.
 
   Debug                        Sets all the tracing bits in BusLogic_GlobalOptions.
 
index f41408467e3d29e1864b2470c848cf1ab88111cf..15c24f68a650ab8a89a39405eca6eb9e4690f5ce 100644 (file)
@@ -1346,7 +1346,8 @@ typedef struct BusLogic_HostAdapter
   unsigned char ActiveCommands[BusLogic_MaxTargetDevices];
   unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices];
   unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
-  unsigned long LastResetTime[BusLogic_MaxTargetDevices];
+  unsigned long LastResetAttempted[BusLogic_MaxTargetDevices];
+  unsigned long LastResetCompleted[BusLogic_MaxTargetDevices];
   BusLogic_OutgoingMailbox_T *FirstOutgoingMailbox;
   BusLogic_OutgoingMailbox_T *LastOutgoingMailbox;
   BusLogic_OutgoingMailbox_T *NextOutgoingMailbox;
@@ -1604,11 +1605,24 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T
 
 #undef CONFIG_SCSI_OMIT_FLASHPOINT
 #define CONFIG_SCSI_OMIT_FLASHPOINT
+
 #define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList
 
 #endif
 
 
+/*
+  FlashPoint support is only available for the Intel x86 Architecture.
+*/
+
+#ifndef __i386__
+
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+
+#endif
+
+
 /*
   Define macros for testing the Host Adapter Type.
 */
index a6d1a64e6314ce8feafa8ca6a2bcdd151a51625b..4b01cf487ae717a57842c8dbbedefd8bdcf049e1 100644 (file)
@@ -1,10 +1,10 @@
           BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
 
-                         Version 2.0.7 for Linux 2.0
+                         Version 2.0.8 for Linux 2.0
 
                              PRODUCTION RELEASE
 
-                              23 February 1997
+                                17 March 1997
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -319,17 +319,17 @@ file "BusLogic.c".  The following examples may be useful as a starting point:
   "BusLogic=MultiMasterFirst"
 
     By default, if both FlashPoint and PCI MultiMaster Host Adapters are
-    present, this driver will probe for PCI MultiMaster Host Adapters first
-    unless the BIOS primary disk is not controlled by the first PCI MultiMaster
-    Host Adapter, in which case FlashPoint Host Adapters will be probed first.
+    present, this driver will probe for FlashPoint Host Adapters first unless
+    the BIOS primary disk is controlled by the first PCI MultiMaster Host
+    Adapter, in which case MultiMaster Host Adapters will be probed first.
     This option forces MultiMaster Host Adapters to be probed first.
 
   "BusLogic=FlashPointFirst"
 
     By default, if both FlashPoint and PCI MultiMaster Host Adapters are
-    present, this driver will probe for PCI MultiMaster Host Adapters first
-    unless the BIOS primary disk is not controlled by the first PCI MultiMaster
-    Host Adapter, in which case FlashPoint Host Adapters will be probed first.
+    present, this driver will probe for FlashPoint Host Adapters first unless
+    the BIOS primary disk is controlled by the first PCI MultiMaster Host
+    Adapter, in which case MultiMaster Host Adapters will be probed first.
     This option forces FlashPoint Host Adapters to be probed first.
 
   "BusLogic=0x330"
@@ -380,7 +380,7 @@ To install the new BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf BusLogic-2.0.7.tar.gz
+  tar -xvzf BusLogic-2.0.8.tar.gz
   mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
   patch -p < BusLogic.patch
   cd linux
index e13dd1b12eef6c2f9ed2857a3ac4d3f8346fae29..802dd3fba2701b504338c0f69358dd5c9b0c833d 100644 (file)
  *  for proper handling of multiple devices courteously
  *  provided by Michael Weller, March, 1993
  *
+ *  Multiple adapter support, extended translation detection,
+ *  update to current scsi subsystem changes, proc fs support,
+ *  working (!) module support based on patches from Andreas Arens,
+ *  by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997
+ *
  * aha1740_makecode may still need even more work
  * if it doesn't work for your devices, take a look.
  */
@@ -59,12 +64,52 @@ struct proc_dir_entry proc_scsi_aha1740 = {
 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
 */
 
-static unsigned int slot, base;
-static unsigned char irq_level;
+struct aha1740_hostdata {
+    unsigned int slot;
+    unsigned int translation;
+    unsigned int last_ecb_used;
+    struct ecb ecb[AHA1740_ECBS];
+};
+
+#define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
 
-static struct ecb ecb[AHA1740_ECBS];   /* One for each queued operation */
+/* One for each IRQ level (9-15) */
+static struct Scsi_Host * aha_host[8] = {NULL, };
+
+int aha1740_proc_info(char *buffer, char **start, off_t offset,
+                     int length, int hostno, int inout)
+{
+    int len;
+    struct Scsi_Host * shpnt;
+    struct aha1740_hostdata *host;
+
+    if (inout)
+       return(-ENOSYS);
+
+    for (len = 0; len < 8; len++) {
+       shpnt = aha_host[len];
+       if (shpnt && shpnt->host_no == hostno)
+           break;
+    }
+    host = HOSTDATA(shpnt);
+
+    len = sprintf(buffer, "aha174x at IO:%x, IRQ %d, SLOT %d.\n"
+                 "Extended translation %sabled.\n",
+                 shpnt->io_port, shpnt->irq, host->slot,
+                 host->translation ? "en" : "dis");
+
+    if (offset > len) {
+       *start = buffer;
+       return 0;
+    }
+
+    *start = buffer + offset;
+    len -= offset;
+    if (len > length)
+       len = length;
+    return len;
+}
 
-static int aha1740_last_ecb_used  = 0; /* optimization */
 
 int aha1740_makecode(unchar *sense, unchar *status)
 {
@@ -88,8 +133,9 @@ int aha1740_makecode(unchar *sense, unchar *status)
 
     status_word = * (struct statusword *) status;
 #ifdef DEBUG
-printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3],
-sense[0],sense[1],sense[2],sense[3]);
+    printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
+          status[0], status[1], status[2], status[3],
+          sense[0], sense[1], sense[2], sense[3]);
 #endif
     if (!status_word.don) /* Anything abnormal was detected */
     {
@@ -113,8 +159,8 @@ sense[0],sense[1],sense[2],sense[3]);
                break;
            case 0x04:
            case 0x05:
-               retval=DID_ABORT; /* Either by this driver or the AHA1740
-                                        itself */
+               retval=DID_ABORT;
+               /* Either by this driver or the AHA1740 itself */
                break;
            default:
                retval=DID_ERROR; /* No further diagnostics possible */
@@ -141,35 +187,35 @@ sense[0],sense[1],sense[2],sense[3]);
     return status[3] | retval << 16;
 }
 
-int aha1740_test_port(void)
+int aha1740_test_port(unsigned int base)
 {
-    char    name[4],tmp;
+    char name[4], tmp;
 
     /* Okay, look for the EISA ID's */
-    name[0]= 'A' -1 + ((tmp = inb(HID0)) >> 2); /* First character */
+    name[0]= 'A' -1 + ((tmp = inb(HID0(base))) >> 2); /* First character */
     name[1]= 'A' -1 + ((tmp & 3) << 3);
-    name[1]+= ((tmp = inb(HID1)) >> 5)&0x7;    /* Second Character */
+    name[1]+= ((tmp = inb(HID1(base))) >> 5)&0x7;      /* Second Character */
     name[2]= 'A' -1 + (tmp & 0x1f);            /* Third Character */
     name[3]=0;
-    tmp = inb(HID2);
-    if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD )
+    tmp = inb(HID2(base));
+    if ( strcmp ( name, HID_MFG ) || inb(HID2(base)) != HID_PRD )
        return 0;   /* Not an Adaptec 174x */
 
-/*  if ( inb(HID3) != HID_REV )
-       printk("aha1740: Warning; board revision of %d; expected %d\n",
-           inb(HID3),HID_REV); */
+/*  if ( inb(HID3(base)) != HID_REV )
+       printk("aha174x: Warning; board revision of %d; expected %d\n",
+           inb(HID3(base)),HID_REV); */
 
-    if ( inb(EBCNTRL) != EBCNTRL_VALUE )
+    if ( inb(EBCNTRL(base)) != EBCNTRL_VALUE )
     {
-       printk("aha1740: Board detected, but EBCNTRL = %x, so disabled it.\n",
-           inb(EBCNTRL));
+       printk("aha174x: Board detected, but EBCNTRL = %x, so disabled it.\n",
+           inb(EBCNTRL(base)));
        return 0;
     }
 
-    if ( inb(PORTADR) & PORTADDR_ENH )
+    if ( inb(PORTADR(base)) & PORTADDR_ENH )
        return 1;   /* Okay, we're all set */
        
-    printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n");
+    printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
     return 0;
 }
 
@@ -181,49 +227,58 @@ void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
     int number_serviced;
     struct ecb *ecbptr;
     Scsi_Cmnd *SCtmp;
+    unsigned int base;
 
+    if (!aha_host[irq - 9])
+       panic("aha1740.c: Irq from unknown host!\n");
+    base = aha_host[irq - 9]->io_port;
     number_serviced = 0;
 
-    while(inb(G2STAT) & G2STAT_INTPEND)
+    while(inb(G2STAT(base)) & G2STAT_INTPEND)
     {
        DEB(printk("aha1740_intr top of loop.\n"));
-       adapstat = inb(G2INTST);
-       ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0));
-       outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
+       adapstat = inb(G2INTST(base));
+       ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0(base)));
+       outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */
       
        switch ( adapstat & G2INTST_MASK )
        {
        case    G2INTST_CCBRETRY:
        case    G2INTST_CCBERROR:
        case    G2INTST_CCBGOOD:
-           outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
+           /* Host Ready -> Mailbox in complete */
+           outb(G2CNTRL_HRDY,G2CNTRL(base));
            if (!ecbptr)
            {
                printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
-                       inb(G2STAT),adapstat,inb(G2INTST),number_serviced++);
+                      inb(G2STAT(base)),adapstat,
+                      inb(G2INTST(base)), number_serviced++);
                continue;
            }
            SCtmp = ecbptr->SCpnt;
            if (!SCtmp)
            {
                printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
-                       inb(G2STAT),adapstat,inb(G2INTST),number_serviced++);
+                      inb(G2STAT(base)),adapstat,
+                      inb(G2INTST(base)), number_serviced++);
                continue;
            }
            if (SCtmp->host_scribble)
                scsi_free(SCtmp->host_scribble, 512);
-         /* Fetch the sense data, and tuck it away, in the required slot.  The
-            Adaptec automatically fetches it, and there is no guarantee that
-            we will still have it in the cdb when we come back */
+           /* Fetch the sense data, and tuck it away, in the required slot.
+              The Adaptec automatically fetches it, and there is no
+              guarantee that we will still have it in the cdb when we come
+              back */
            if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR )
-             {
+           {
                memcpy(SCtmp->sense_buffer, ecbptr->sense, 
                       sizeof(SCtmp->sense_buffer));
                errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
-             }
+           }
            else
                errstatus = 0;
-           DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus));
+           DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n",
+                                     errstatus));
            SCtmp->result = errstatus;
            my_done = ecbptr->done;
            memset(ecbptr,0,sizeof(struct ecb)); 
@@ -231,12 +286,14 @@ void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
                my_done(SCtmp);
            break;
        case    G2INTST_HARDFAIL:
-           printk("aha1740 hardware failure!\n");
+           printk(KERN_ALERT "aha1740 hardware failure!\n");
            panic("aha1740.c"); /* Goodbye */
        case    G2INTST_ASNEVENT:
-           printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat,
-               inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */
-           outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */
+           printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
+                  adapstat, inb(MBOXIN0(base)), inb(MBOXIN1(base)),
+                  inb(MBOXIN2(base)), inb(MBOXIN3(base))); /* Say What? */
+           /* Host Ready -> Mailbox in complete */
+           outb(G2CNTRL_HRDY,G2CNTRL(base));
            break;
        case    G2INTST_CMDGOOD:
            /* set immediate command success flag here: */
@@ -245,7 +302,7 @@ void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
            /* Set immediate command failure flag here: */
            break;
        }
-      number_serviced++;
+       number_serviced++;
     }
 }
 
@@ -254,18 +311,19 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     unchar direction;
     unchar *cmd = (unchar *) SCpnt->cmnd;
     unchar target = SCpnt->target;
+    struct aha1740_hostdata *host = HOSTDATA(SCpnt->host);
     unsigned long flags;
     void *buff = SCpnt->request_buffer;
     int bufflen = SCpnt->request_bufflen;
     int ecbno;
     DEB(int i);
 
-    
     if(*cmd == REQUEST_SENSE)
     {
        if (bufflen != sizeof(SCpnt->sense_buffer))
        {
-           printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
+           printk("Wrong buffer length supplied for request sense (%d)\n",
+                  bufflen);
        }
        SCpnt->result = 0;
        done(SCpnt); 
@@ -279,39 +337,41 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
        i = scsi2int(cmd+2);
     else
        i = -1;
-    printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+    printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
+          target, *cmd, i, bufflen);
     printk("scsi cmd:");
     for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
     printk("\n");
 #endif
 
     /* locate an available ecb */
-
     save_flags(flags);
     cli();
-    ecbno = aha1740_last_ecb_used + 1;         /* An optimization */
-    if (ecbno >= AHA1740_ECBS) ecbno = 0;
-
-    do{
-      if( ! ecb[ecbno].cmdw )
-       break;
-      ecbno++;
-      if (ecbno >= AHA1740_ECBS ) ecbno = 0;
-    } while (ecbno != aha1740_last_ecb_used);
+    ecbno = host->last_ecb_used + 1;           /* An optimization */
+    if (ecbno >= AHA1740_ECBS)
+       ecbno = 0;
+    do {
+       if (!host->ecb[ecbno].cmdw)
+           break;
+       ecbno++;
+       if (ecbno >= AHA1740_ECBS)
+           ecbno = 0;
+    } while (ecbno != host->last_ecb_used);
 
-    if( ecb[ecbno].cmdw )
-      panic("Unable to find empty ecb for aha1740.\n");
+    if (host->ecb[ecbno].cmdw)
+       panic("Unable to find empty ecb for aha1740.\n");
 
-    ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command doubles as reserved flag */
+    host->ecb[ecbno].cmdw = AHA1740CMD_INIT;   /* SCSI Initiator Command
+                                                  doubles as reserved flag */
 
-    aha1740_last_ecb_used = ecbno;    
+    host->last_ecb_used = ecbno;    
     restore_flags(flags);
 
 #ifdef DEBUG
-    printk("Sending command (%d %x)...",ecbno, done);
+    printk("Sending command (%d %x)...", ecbno, done);
 #endif
 
-    ecb[ecbno].cdblen = SCpnt->cmd_len;        /* SCSI Command Descriptor Block Length */
+    host->ecb[ecbno].cdblen = SCpnt->cmd_len;  /* SCSI Command Descriptor Block Length */
 
     direction = 0;
     if (*cmd == READ_10 || *cmd == READ_6)
@@ -319,17 +379,16 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     else if (*cmd == WRITE_10 || *cmd == WRITE_6)
        direction = 0;
 
-    memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen);
+    memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
 
     if (SCpnt->use_sg)
     {
        struct scatterlist * sgpnt;
        struct aha1740_chain * cptr;
        int i;
-#ifdef DEBUG
-       unsigned char * ptr;
-#endif
-       ecb[ecbno].sg = 1;        /* SCSI Initiator Command  w/scatter-gather*/
+       DEB(unsigned char * ptr);
+
+       host->ecb[ecbno].sg = 1;  /* SCSI Initiator Command  w/scatter-gather*/
        SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
        sgpnt = (struct scatterlist *) SCpnt->request_buffer;
        cptr = (struct aha1740_chain *) SCpnt->host_scribble; 
@@ -339,8 +398,8 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
            cptr[i].datalen = sgpnt[i].length;
            cptr[i].dataptr = virt_to_bus(sgpnt[i].address);
        }
-       ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
-       ecb[ecbno].dataptr = virt_to_bus(cptr);
+       host->ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
+       host->ecb[ecbno].dataptr = virt_to_bus(cptr);
 #ifdef DEBUG
        printk("cptr %x: ",cptr);
        ptr = (unsigned char *) cptr;
@@ -350,144 +409,161 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
     else
     {
        SCpnt->host_scribble = NULL;
-       ecb[ecbno].datalen = bufflen;
-       ecb[ecbno].dataptr = virt_to_bus(buff);
+       host->ecb[ecbno].datalen = bufflen;
+       host->ecb[ecbno].dataptr = virt_to_bus(buff);
     }
-    ecb[ecbno].lun = SCpnt->lun;
-    ecb[ecbno].ses = 1;        /* Suppress underrun errors */
-    ecb[ecbno].dir= direction;
-    ecb[ecbno].ars=1;  /* Yes, get the sense on an error */
-    ecb[ecbno].senselen = 12;
-    ecb[ecbno].senseptr = virt_to_bus(ecb[ecbno].sense);
-    ecb[ecbno].statusptr = virt_to_bus(ecb[ecbno].status);
-    ecb[ecbno].done = done;
-    ecb[ecbno].SCpnt = SCpnt;
+    host->ecb[ecbno].lun = SCpnt->lun;
+    host->ecb[ecbno].ses = 1;  /* Suppress underrun errors */
+    host->ecb[ecbno].dir = direction;
+    host->ecb[ecbno].ars = 1;  /* Yes, get the sense on an error */
+    host->ecb[ecbno].senselen = 12;
+    host->ecb[ecbno].senseptr = virt_to_bus(host->ecb[ecbno].sense);
+    host->ecb[ecbno].statusptr = virt_to_bus(host->ecb[ecbno].status);
+    host->ecb[ecbno].done = done;
+    host->ecb[ecbno].SCpnt = SCpnt;
 #ifdef DEBUG
     {
        int i;
        printk("aha1740_command: sending.. ");
-       for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
-           printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
+       for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
+           printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
     }
     printk("\n");
 #endif
     if (done)
-    { /*  You may question the code below, which contains potentially
-         non-terminating while loops with interrupts disabled.  So did
-         I when I wrote it, but the Adaptec Spec says the card is so fast,
-         that this problem virtually never occurs so I've kept it.  We
-         do printk a warning first, so that you'll know if it happens.
-         In practice the only time we've seen this message is when some-
-         thing else is in the driver was broken, like _makecode(), or
-         when a scsi device hung the scsi bus.  Even under these conditions,
-         The loop actually only cycled < 3 times (we instrumented it). */
-
+    { /*  The Adaptec Spec says the card is so fast that the loops will
+         only be executed once in the code below. Even if this was true
+         with the fastest processors when the spec was written, it doesn't
+         seem to be true with todays fast processors. We print a warning
+         if the code is executed more often than LOOPCNT_WARN. If this
+         happens, it should be investigated. If the count reaches
+         LOOPCNT_MAX, we assume something is broken; since there is no
+         way to return an error (the return value is ignored by the
+         mid-level scsi layer) we have to panic (and maybe that's the
+         best thing we can do then anyhow). */
+
+#define LOOPCNT_WARN 10                /* excessive mbxout wait -> syslog-msg */
+#define LOOPCNT_MAX 1000000    /* mbxout deadlock -> panic() after ~ 2 sec. */
+       int loopcnt;
+       unsigned int base = SCpnt->host->io_port;
        DEB(printk("aha1740[%d] critical section\n",ecbno));
        save_flags(flags);
        cli();
-       if ( ! (inb(G2STAT) & G2STAT_MBXOUT) )
-       {
-           printk("aha1740[%d]_mbxout wait!\n",ecbno);
-           cli(); /* printk may have done a sti()! */
+       for (loopcnt = 0; ; loopcnt++) {
+           if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
+           if (loopcnt == LOOPCNT_WARN) {
+               printk("aha1740[%d]_mbxout wait!\n",ecbno);
+               cli(); /* printk may have done a sti()! */
+           }
+           if (loopcnt == LOOPCNT_MAX)
+               panic("aha1740.c: mbxout busy!\n");
        }
-       mb();
-       while ( ! (inb(G2STAT) & G2STAT_MBXOUT) );      /* Oh Well. */
-       outl(virt_to_bus(ecb+ecbno), MBOXOUT0);
-       if ( inb(G2STAT) & G2STAT_BUSY )
-       {
-           printk("aha1740[%d]_attn wait!\n",ecbno);
-           cli();
+       outl(virt_to_bus(host->ecb + ecbno), MBOXOUT0(base));
+       for (loopcnt = 0; ; loopcnt++) {
+           if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
+           if (loopcnt == LOOPCNT_WARN) {
+               printk("aha1740[%d]_attn wait!\n",ecbno);
+               cli();
+           }
+           if (loopcnt == LOOPCNT_MAX)
+               panic("aha1740.c: attn wait failed!\n");
        }
-       while ( inb(G2STAT) & G2STAT_BUSY );            /* And Again! */
-       outb(ATTN_START | (target & 7), ATTN);  /* Start it up */
+       outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
        restore_flags(flags);
        DEB(printk("aha1740[%d] request queued.\n",ecbno));
     }
     else
-      printk("aha1740_queuecommand: done can't be NULL\n");
-    
+       printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
     return 0;
 }
 
-static volatile int internal_done_flag = 0;
-static volatile int internal_done_errcode = 0;
-
 static void internal_done(Scsi_Cmnd * SCpnt)
 {
-    internal_done_errcode = SCpnt->result;
-    ++internal_done_flag;
+    SCpnt->SCp.Status++;
 }
 
 int aha1740_command(Scsi_Cmnd * SCpnt)
 {
     aha1740_queuecommand(SCpnt, internal_done);
-
-    while (!internal_done_flag);
-    internal_done_flag = 0;
-    return internal_done_errcode;
+    SCpnt->SCp.Status = 0;
+    while (!SCpnt->SCp.Status)
+       barrier();
+    return SCpnt->result;
 }
 
 /* Query the board for its irq_level.  Nothing else matters
    in enhanced mode on an EISA bus. */
 
-void aha1740_getconfig(void)
+void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
+                      unsigned int *translation)
 {
-  static int intab[] = { 9,10,11,12,0,14,15,0 };
+    static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
 
-  irq_level = intab [ inb(INTDEF)&0x7 ];
-  outb(inb(INTDEF) | 0x10, INTDEF);
+    *irq_level = intab[inb(INTDEF(base)) & 0x7];
+    *translation = inb(RESV1(base)) & 0x1;
+    outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
 }
 
 int aha1740_detect(Scsi_Host_Template * tpnt)
 {
-    tpnt->proc_dir = &proc_scsi_aha1740;
+    int count = 0, slot;
 
-    memset(&ecb, 0, sizeof(struct ecb));
     DEB(printk("aha1740_detect: \n"));
-    
+
     for ( slot=MINEISA; slot <= MAXEISA; slot++ )
     {
-       base = SLOTBASE(slot);
+       int slotbase;
+       unsigned int irq_level, translation;
+       struct Scsi_Host *shpnt;
+       struct aha1740_hostdata *host;
+       slotbase = SLOTBASE(slot);
        /*
         * The ioports for eisa boards are generally beyond that used in the
         * check/allocate region code, but this may change at some point,
         * so we go through the motions.
         */
-       if(check_region(base, 0x5c)) continue;  /* See if in use */
-       if ( aha1740_test_port())  break;
-    }
-    if ( slot > MAXEISA )
-       return 0;
-
-    aha1740_getconfig();
-
-    if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
-    {  /* If the card isn't ready, hard reset it */
-       outb(G2CNTRL_HRST,G2CNTRL);
-       outb(0,G2CNTRL);    
-    }
-
-    printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
-          irq_level);
-
-    DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level));
-
-    if (request_irq(irq_level,aha1740_intr_handle, 0, "aha1740", NULL))
-    {
-       printk("Unable to allocate IRQ for adaptec controller.\n");
-       return 0;
+       if (check_region(slotbase, SLOTSIZE))  /* See if in use */
+           continue;
+       if (!aha1740_test_port(slotbase))
+           continue;
+       aha1740_getconfig(slotbase,&irq_level,&translation);
+       if ((inb(G2STAT(slotbase)) &
+            (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT)
+       {       /* If the card isn't ready, hard reset it */
+           outb(G2CNTRL_HRST, G2CNTRL(slotbase));
+           outb(0, G2CNTRL(slotbase));
+       }
+       printk("Configuring aha174x at IO:%x, IRQ %d\n", slotbase, irq_level);
+       printk("aha174x: Extended translation %sabled.\n",
+              translation ? "en" : "dis");
+       DEB(printk("aha1740_detect: enable interrupt channel %d\n",irq_level));
+       if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",NULL)) {
+           printk("Unable to allocate IRQ for adaptec controller.\n");
+           continue;
+       }
+       shpnt = scsi_register(tpnt, sizeof(struct aha1740_hostdata));
+       request_region(slotbase, SLOTSIZE, "aha1740");
+       shpnt->base = 0;
+       shpnt->io_port = slotbase;
+       shpnt->n_io_port = SLOTSIZE;
+       shpnt->irq = irq_level;
+       shpnt->dma_channel = 0xff;
+       host = HOSTDATA(shpnt);
+       host->slot = slot;
+       host->translation = translation;
+       aha_host[irq_level - 9] = shpnt;
+       count++;
     }
-    request_region(base, 0x5c,"aha1740");  /* Reserve the space that we need to use */
-    return 1;
+    return count;
 }
 
 /* Note:  They following two functions do not apply very well to the Adaptec,
-which basically manages its own affairs quite well without our interference,
-so I haven't put anything into them.  I can faintly imagine someone with a
-*very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
-but it hasn't happened yet, and doing aborts brings the Adaptec to its
-knees.  I cannot (at this moment in time) think of any reason to reset the
-card once it's running.  So there. */
+   which basically manages its own affairs quite well without our interference,
+   so I haven't put anything into them.  I can faintly imagine someone with a
+   *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
+   but it hasn't happened yet, and doing aborts brings the Adaptec to its
+   knees.  I cannot (at this moment in time) think of any reason to reset the
+   card once it's running.  So there. */
 
 int aha1740_abort(Scsi_Cmnd * SCpnt)
 {
@@ -507,13 +583,23 @@ int aha1740_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
 
 int aha1740_biosparam(Disk * disk, kdev_t dev, int* ip)
 {
-  int size = disk->capacity;
-DEB(printk("aha1740_biosparam\n"));
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-/*  if (ip[2] >= 1024) ip[2] = 1024; */
-  return 0;
+    int size = disk->capacity;
+    int extended = HOSTDATA(disk->device->host)->translation;
+
+    DEB(printk("aha1740_biosparam\n"));
+    if (extended && (ip[2] > 1024))
+    {
+       ip[0] = 255;
+       ip[1] = 63;
+       ip[2] = size / (255 * 63);
+    }
+    else
+    {
+       ip[0] = 64;
+       ip[1] = 32;
+       ip[2] = size >> 11;
+    }
+    return 0;
 }
 
 #ifdef MODULE
index 206cf03b71b8a97e61319dd6b4566e576048fafa..cd38a894b3c905b41e242361787e79295873075d 100644 (file)
 #define MINEISA 1   /* I don't have an EISA Spec to know these ranges, so I */
 #define MAXEISA 8   /* Just took my machine's specifications.  Adjust to fit.*/
                    /* I just saw an ad, and bumped this from 6 to 8 */
-#define        SLOTBASE(x)     ((x << 12)+ 0xc80 )
-#define        BASE            (base)
+#define        SLOTBASE(x)     ((x << 12) + 0xc80)
+#define SLOTSIZE       0x5c
 
 /* EISA configuration registers & values */
-#define        HID0    (base + 0x0)
-#define        HID1    (base + 0x1)
-#define HID2   (base + 0x2)
-#define        HID3    (base + 0x3)
-#define        EBCNTRL (base + 0x4)
-#define        PORTADR (base + 0x40)
-#define BIOSADR (base + 0x41)
-#define INTDEF (base + 0x42)
-#define SCSIDEF (base + 0x43)
-#define BUSDEF (base + 0x44)
-#define        RESV0   (base + 0x45)
-#define RESV1  (base + 0x46)
-#define        RESV2   (base + 0x47)
+#define        HID0(base)      (base + 0x0)
+#define        HID1(base)      (base + 0x1)
+#define HID2(base)     (base + 0x2)
+#define        HID3(base)      (base + 0x3)
+#define        EBCNTRL(base)   (base + 0x4)
+#define        PORTADR(base)   (base + 0x40)
+#define BIOSADR(base)  (base + 0x41)
+#define INTDEF(base)   (base + 0x42)
+#define SCSIDEF(base)  (base + 0x43)
+#define BUSDEF(base)   (base + 0x44)
+#define        RESV0(base)     (base + 0x45)
+#define RESV1(base)    (base + 0x46)
+#define        RESV2(base)     (base + 0x47)
 
 #define        HID_MFG "ADP"
 #define        HID_PRD 0
 #define EBCNTRL_VALUE 1
 #define PORTADDR_ENH 0x80
 /* READ */
-#define        G2INTST (BASE + 0x56)
-#define G2STAT (BASE + 0x57)
-#define        MBOXIN0 (BASE + 0x58)
-#define        MBOXIN1 (BASE + 0x59)
-#define        MBOXIN2 (BASE + 0x5a)
-#define        MBOXIN3 (BASE + 0x5b)
-#define G2STAT2        (BASE + 0x5c)
+#define        G2INTST(base)   (base + 0x56)
+#define G2STAT(base)   (base + 0x57)
+#define        MBOXIN0(base)   (base + 0x58)
+#define        MBOXIN1(base)   (base + 0x59)
+#define        MBOXIN2(base)   (base + 0x5a)
+#define        MBOXIN3(base)   (base + 0x5b)
+#define G2STAT2(base)  (base + 0x5c)
 
 #define G2INTST_MASK           0xf0    /* isolate the status */
 #define        G2INTST_CCBGOOD         0x10    /* CCB Completed */
 #define G2STAT2_READY  0       /* Host Ready Bit */
 
 /* WRITE (and ReadBack) */
-#define        MBOXOUT0        (BASE + 0x50)
-#define        MBOXOUT1        (BASE + 0x51)
-#define        MBOXOUT2        (BASE + 0x52)
-#define        MBOXOUT3        (BASE + 0x53)
-#define        ATTN            (BASE + 0x54)
-#define G2CNTRL                (BASE + 0x55)
+#define        MBOXOUT0(base)  (base + 0x50)
+#define        MBOXOUT1(base)  (base + 0x51)
+#define        MBOXOUT2(base)  (base + 0x52)
+#define        MBOXOUT3(base)  (base + 0x53)
+#define        ATTN(base)      (base + 0x54)
+#define G2CNTRL(base)  (base + 0x55)
 
 #define        ATTN_IMMED      0x10    /* Immediate Command */
 #define        ATTN_START      0x40    /* Start CCB */
@@ -159,18 +159,22 @@ int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int aha1740_abort(Scsi_Cmnd *);
 int aha1740_reset(Scsi_Cmnd *, unsigned int);
 int aha1740_biosparam(Disk *, kdev_t, int*);
+int aha1740_proc_info(char *buffer, char **start, off_t offset,
+                               int length, int hostno, int inout);
 
 #define AHA1740_ECBS 32
 #define AHA1740_SCATTER 16
+#define AHA1740_CMDLUN 1
 
 #ifndef NULL
-#define NULL 0
+       #define NULL 0
 #endif
 
+extern struct proc_dir_entry proc_scsi_aha1740;
 
 #define AHA1740 {NULL, NULL,                           \
-                   NULL,                                \
-                  NULL,                                \
+                   &proc_scsi_aha1740,                 \
+                  aha1740_proc_info,                   \
                   "Adaptec 174x (EISA)",               \
                   aha1740_detect,                      \
                   NULL,                                \
@@ -184,10 +188,9 @@ int aha1740_biosparam(Disk *, kdev_t, int*);
                   AHA1740_ECBS,                        \
                   7,                                   \
                   AHA1740_SCATTER,                     \
-                  1,                                   \
+                  AHA1740_CMDLUN,                      \
                   0,                                   \
                   0,                                   \
                   ENABLE_CLUSTERING}
 
 #endif
-
index f0982dc8a6ad7c539fdc3f7c5acaa1c4eb96ded9..1acc73f33c68398e437955df1161848e3dd4e456 100644 (file)
@@ -79,7 +79,7 @@
  */
 #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
 
-struct proc_dir_entry proc_scsi_aic7xxx = {
+static struct proc_dir_entry proc_scsi_aic7xxx = {
     PROC_SCSI_AIC7XXX, 7, "aic7xxx",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
@@ -1089,7 +1089,7 @@ aic7xxx_delay(int seconds)
  *   Return a string containing just the RCS version number from either
  *   an Id or Revision RCS clause.
  *-F*************************************************************************/
-const char *
+static const char *
 rcs_version(const char *version_info)
 {
   static char buf[10];
index d084923f11ea8edbdfc36a0e92e7a41a80903ef1..498293c230ea4ae0334f5154f32060e7451875e0 100644 (file)
 #include "sd.h"
 #include <scsi/scsi_ioctl.h>
 
-struct proc_dir_entry proc_scsi_seagate =
+static struct proc_dir_entry proc_scsi_seagate =
 {
   PROC_SCSI_SEAGATE, 7, "seagate",
   S_IFDIR | S_IRUGO | S_IXUGO, 2
index e7270eae94f2961c3f4b554ce4123ddb1f7ac4b2..eb4dbaf30c8d697fa849d7bb37011114701dda54 100644 (file)
@@ -1,4 +1,3 @@
-extern void allow_interrupts(void);
 /*
  *  linux/fs/buffer.c
  *
@@ -626,7 +625,6 @@ static void refill_freelist(int size)
        }
 
 repeat:
-       allow_interrupts();
        /* OK, we cannot grow the buffer cache, now try to get some
           from the lru list */
 
@@ -708,7 +706,6 @@ struct buffer_head * getblk(kdev_t dev, int block, int size)
           now so as to ensure that there are still clean buffers available
           for user processes to use (and dirty) */
 repeat:
-       allow_interrupts();
        bh = get_hash_table(dev, block, size);
        if (bh) {
                if (!buffer_dirty(bh)) {
@@ -721,7 +718,6 @@ repeat:
        }
 
        while(!free_list[isize]) {
-               allow_interrupts();
                refill_freelist(size);
        }
        
@@ -1516,7 +1512,6 @@ asmlinkage int sync_old_buffers(void)
                ndirty = 0;
                nwritten = 0;
        repeat:
-               allow_interrupts();
        
                bh = lru_list[nlist];
                if(bh) 
@@ -1659,7 +1654,6 @@ int bdflush(void * unused)
                         ndirty = 0;
                         refilled = 0;
                 repeat:
-                       allow_interrupts();
                        
                         bh = lru_list[nlist];
                         if(bh) 
index 127c3d681b241fe3520ebab27f6f38c63d09d19b..9324df239fe12892814d6e149590f700fba89425 100644 (file)
@@ -489,7 +489,7 @@ repeat:
        inode = first_inode;
        best = NULL;
        badness = 1000;
-       for (i = nr_inodes/2; i > 0; i--,inode = inode->i_next) {
+       for (i = nr_inodes/2; i > 0; i--,inode = inode->i_prev) {
                if (!inode->i_count) {
                        unsigned long i = 999;
                        if (!(inode->i_lock | inode->i_dirt))
index 512e77b18bf3c8ffbae4602ebb5e3f6653cf0118..bdcc0a518478488d0bb03143b1ff5c134ac23234 100644 (file)
@@ -29,7 +29,7 @@ EXPORT_SYMBOL(msdos_read_super);
 EXPORT_SYMBOL(msdos_put_super);
 
 
-struct file_system_type msdos_fs_type = {
+static struct file_system_type msdos_fs_type = {
        msdos_read_super, "msdos", 1, NULL
 };
 
index 827a0ab73d7e3dc1e64fdf81a186618f74adfd76..fd5304ecc1bea0152da1ed8efadff8e374c0ee5d 100644 (file)
@@ -652,7 +652,10 @@ static int do_rmdir(const char * name)
        }
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
-       return dir->i_op->rmdir(dir,basename,namelen);
+       down(&dir->i_sem);
+       error = dir->i_op->rmdir(dir,basename,namelen);
+       up(&dir->i_sem);
+       return error;
 }
 
 asmlinkage int sys_rmdir(const char * pathname)
@@ -705,7 +708,10 @@ static int do_unlink(const char * name)
        }
        if (dir->i_sb && dir->i_sb->dq_op)
                dir->i_sb->dq_op->initialize(dir, -1);
-       return dir->i_op->unlink(dir,basename,namelen);
+       down(&dir->i_sem);
+       error = dir->i_op->unlink(dir,basename,namelen);
+       up(&dir->i_sem);
+       return error;
 }
 
 asmlinkage int sys_unlink(const char * pathname)
index 799903eb26934a4a6ea00ae97acd61bc2b249662..00b526708b1b1dabf3d2d9963fd54d04667b8d0b 100644 (file)
@@ -505,6 +505,9 @@ static unsigned long get_wchan(struct task_struct *p)
              eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc;    \
         eip; })
 #define        KSTK_ESP(tsk)   ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined (__sparc_v9__)
+# define KSTK_EIP(tsk)  ((tsk)->tss.kregs->tpc)
+# define KSTK_ESP(tsk)  ((tsk)->tss.kregs->u_regs[UREG_FP])
 #elif defined(__sparc__)
 # define KSTK_EIP(tsk)  ((tsk)->tss.kregs->pc)
 # define KSTK_ESP(tsk)  ((tsk)->tss.kregs->u_regs[UREG_FP])
index a0db8223a57bdf03d3f9341d44f636c7b9ecb5ae..e5e4fd9a894245ceeed7055c722a267372dd87f7 100644 (file)
@@ -106,7 +106,13 @@ static int proc_lookupfd(struct inode * dir, const char * name, int len,
        if (!pid || i >= NR_TASKS)
                return -ENOENT;
 
-       if (fd >= NR_OPEN || !p->files->fd[fd] || !p->files->fd[fd]->f_inode)
+       /*
+        *      File handle is invalid if it is out of range, if the process
+        *      has no files (Zombie) if the file is closed, or if its inode
+        *      is NULL
+        */
+
+       if (fd >= NR_OPEN || !p->files || !p->files->fd[fd] || !p->files->fd[fd]->f_inode)
          return -ENOENT;
 
        ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
index 46720b1768a8f7dcb4fde1be8cf9c2257777b604..6e80e829837a1d284b135cc20357836c0a22f613 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
-#include <linux/config.h>
 #include <asm/bitops.h>
 
 static long proc_file_read(struct inode * inode, struct file * file,
index 5d61ae793e18d8e66511312bbbe74385f723d581..470b7bffb8169f459e44d52f697750f1a1585da1 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/tty.h>
-#include <linux/config.h>
 #include <asm/bitops.h>
 
 extern struct tty_driver *tty_drivers; /* linked list of tty drivers */
index a9c822aa45b3a86d0abcda6542c9931802b687cb..1189c0c729614e76532ab82fdb6fc4ee5a331b22 100644 (file)
 
 static int
 _recvfrom(struct socket *sock, unsigned char *ubuf, int size,
-         int noblock, unsigned flags, struct sockaddr_in *sa)
+         int noblock, unsigned flags)
 {
        struct iovec iov;
        struct msghdr msg;
        struct scm_cookie scm;
 
-       memset(&scm, 0, sizeof(scm));
-       
-       iov.iov_base = ubuf;
-       iov.iov_len = size;
-
-       msg.msg_name = (void *) sa;
+       msg.msg_name = NULL;
        msg.msg_namelen = 0;
-       if (sa)
-               msg.msg_namelen = sizeof(struct sockaddr_in);
-       msg.msg_control = NULL;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
-
+       msg.msg_control = NULL;
+       iov.iov_base = ubuf;
+       iov.iov_len = size;
+       
        if (noblock) {
                flags |= MSG_DONTWAIT;
        }
-
-       return sock->ops->recvmsg(sock, &msg, size, flags, &scm);
+       memset(&scm, 0,sizeof(scm));
+       size=sock->ops->recvmsg(sock, &msg, size, flags, &scm);
+       if(size>=0)
+               scm_recv(sock,&msg,&scm,flags);
+       return size;
 }
 
 static int
@@ -61,27 +59,26 @@ _send(struct socket *sock, const void *buff, int len,
        struct msghdr msg;
        struct scm_cookie scm;
        int err;
-       
-
-       iov.iov_base = (void *) buff;
-       iov.iov_len = len;
 
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
-       msg.msg_control = NULL;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+       
+       iov.iov_base = (void *)buff;
+       iov.iov_len = len;
+       
 
-       if (noblock) {
+       if (noblock) 
                flags |= MSG_DONTWAIT;
-       }
 
        msg.msg_flags = flags;
 
        err = scm_send(sock, &msg, &scm);
         if (err < 0)
                 return err;
-       
        err = sock->ops->sendmsg(sock, &msg, len, &scm);
        scm_destroy(&scm);
        return err;
@@ -101,14 +98,12 @@ smb_data_callback(struct sock *sk, int len)
                fs = get_fs();
                set_fs(get_ds());
 
-               result = _recvfrom(sock, (void *) peek_buf, 1, 1,
-                                  MSG_PEEK, NULL);
+               result = _recvfrom(sock, (void *) peek_buf, 1, 1, MSG_PEEK);
 
                while ((result != -EAGAIN) && (peek_buf[0] == 0x85))
                {
                        /* got SESSION KEEP ALIVE */
-                       result = _recvfrom(sock, (void *) peek_buf,
-                                          4, 1, 0, NULL);
+                       result = _recvfrom(sock, (void *) peek_buf, 4, 1, 0);
 
                        DDPRINTK("smb_data_callback:"
                                 " got SESSION KEEP ALIVE\n");
@@ -118,7 +113,7 @@ smb_data_callback(struct sock *sk, int len)
                                break;
                        }
                        result = _recvfrom(sock, (void *) peek_buf,
-                                          1, 1, MSG_PEEK, NULL);
+                                          1, 1, MSG_PEEK);
                }
                set_fs(fs);
 
@@ -265,7 +260,7 @@ smb_receive_raw(struct socket *sock, unsigned char *target, int length)
        {
                result = _recvfrom(sock,
                                   (void *) (target + already_read),
-                                  length - already_read, 0, 0, NULL);
+                                  length - already_read, 0, 0);
 
                if (result == 0)
                {
@@ -665,6 +660,15 @@ smb_send_trans2(struct smb_server *server, __u16 trans2_command,
        *p++ = 'D';             /* this was added because OS/2 does it */
        *p++ = ' ';
 
+
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_control = NULL;
+       msg.msg_controllen = 0;
+       msg.msg_iov = iov;
+       msg.msg_iovlen = 4;
+       msg.msg_flags = 0;
+       
        iov[0].iov_base = (void *) server->packet;
        iov[0].iov_len = oparam;
        iov[1].iov_base = (param == NULL) ? padding : param;
@@ -674,12 +678,6 @@ smb_send_trans2(struct smb_server *server, __u16 trans2_command,
        iov[3].iov_base = (data == NULL) ? padding : data;
        iov[3].iov_len = ldata;
 
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
-       msg.msg_control = NULL;
-       msg.msg_iov = iov;
-       msg.msg_iovlen = 4;
-
        err = scm_send(sock, &msg, &scm);
         if (err < 0)
                 return err;
index f979c972a23f0174d7bef0fa80d8794318510e88..fde713b6efb23d69e09520c11e8a74851fe67a88 100644 (file)
@@ -760,6 +760,7 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
                if (!fs_may_remount_ro(sb->s_dev))
                        return -EBUSY;
+       sb->s_flags = (flags & ~MS_RDONLY) | (sb->s_flags & MS_RDONLY);
        if (sb->s_op && sb->s_op->remount_fs) {
                retval = sb->s_op->remount_fs(sb, &flags, data);
                if (retval)
index 6295d0a9846046d0d8aa33ec9ee33efb3b0dbeb5..0d4a89298b7e8a122943b96496ca5820b8640b79 100644 (file)
@@ -64,8 +64,31 @@ long umsdos_emd_dir_write (struct inode *emd_dir,
        unsigned long count)
 {
        int written;
+#ifdef __BIG_ENDIAN
+       struct umsdos_dirent *d = (struct umsdos_dirent *)buf;
+#endif
        filp->f_flags = 0;
+#ifdef __BIG_ENDIAN    
+       d->nlink = cpu_to_le16 (d->nlink);
+       d->uid = cpu_to_le16 (d->uid);
+       d->gid = cpu_to_le16 (d->gid);
+       d->atime = cpu_to_le32 (d->atime);
+       d->mtime = cpu_to_le32 (d->mtime);
+       d->ctime = cpu_to_le32 (d->ctime);
+       d->rdev = cpu_to_le16 (d->rdev);
+       d->mode = cpu_to_le16 (d->mode);
+#endif 
        written = umsdos_file_write_kmem (emd_dir,filp,buf,count);
+#ifdef __BIG_ENDIAN    
+       d->nlink = le16_to_cpu (d->nlink);
+       d->uid = le16_to_cpu (d->uid);
+       d->gid = le16_to_cpu (d->gid);
+       d->atime = le32_to_cpu (d->atime);
+       d->mtime = le32_to_cpu (d->mtime);
+       d->ctime = le32_to_cpu (d->ctime);
+       d->rdev = le16_to_cpu (d->rdev);
+       d->mode = le16_to_cpu (d->mode);
+#endif 
        return written != count ? -EIO : 0;
 }
 /*
@@ -80,6 +103,9 @@ long umsdos_emd_dir_read (struct inode *emd_dir,
 {
        long int ret = 0;
        int sizeread;
+#ifdef __BIG_ENDIAN
+       struct umsdos_dirent *d = (struct umsdos_dirent *)buf;
+#endif
        filp->f_flags = 0;
        sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count);
        if (sizeread != count){
@@ -87,6 +113,16 @@ long umsdos_emd_dir_read (struct inode *emd_dir,
                        ,filp->f_pos,sizeread,count);
                ret = -EIO;
        }
+#ifdef __BIG_ENDIAN    
+       d->nlink = le16_to_cpu (d->nlink);
+       d->uid = le16_to_cpu (d->uid);
+       d->gid = le16_to_cpu (d->gid);
+       d->atime = le32_to_cpu (d->atime);
+       d->mtime = le32_to_cpu (d->mtime);
+       d->ctime = le32_to_cpu (d->ctime);
+       d->rdev = le16_to_cpu (d->rdev);
+       d->mode = le16_to_cpu (d->mode);
+#endif 
        return ret;
 
 }
index 6ad91b1d741afa16e99280605a8decdf66b41b40..bef18652908ad22d235d42014bd2abee3e3f0868 100644 (file)
@@ -97,7 +97,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 /*
  * The following are not needed for the non-m68k ports
  */
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port)
 {
        return(1);
 }
index f30b3c77ca6409bf2bbc61ca0bd69322b8648023..43a9d6d4705b81a4d5c7e0320c7b5bb6f9dda3de 100644 (file)
@@ -40,4 +40,9 @@
 #define SO_PASSCRED    17
 #define SO_PEERCRED    18
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             19
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       20
+#define SO_SECURITY_ENCRYPTION_NETWORK         21
+
 #endif /* _ASM_SOCKET_H */
index 1b9d99f7655083b9cb37af856f8197d77245b19a..879750434acd5b9a7b756b5e2c4177a6b5bcced1 100644 (file)
@@ -21,7 +21,7 @@
 
 typedef int atomic_t;
 
-static __inline__ void atomic_add(atomic_t i, atomic_t *v)
+static __inline__ void atomic_add(atomic_t i, volatile atomic_t *v)
 {
        __asm__ __volatile__(
                LOCK "addl %1,%0"
@@ -29,7 +29,7 @@ static __inline__ void atomic_add(atomic_t i, atomic_t *v)
                :"ir" (i), "m" (__atomic_fool_gcc(v)));
 }
 
-static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
+static __inline__ void atomic_sub(atomic_t i, volatile atomic_t *v)
 {
        __asm__ __volatile__(
                LOCK "subl %1,%0"
@@ -37,7 +37,7 @@ static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
                :"ir" (i), "m" (__atomic_fool_gcc(v)));
 }
 
-static __inline__ void atomic_inc(atomic_t *v)
+static __inline__ void atomic_inc(volatile atomic_t *v)
 {
        __asm__ __volatile__(
                LOCK "incl %0"
@@ -45,7 +45,7 @@ static __inline__ void atomic_inc(atomic_t *v)
                :"m" (__atomic_fool_gcc(v)));
 }
 
-static __inline__ void atomic_dec(atomic_t *v)
+static __inline__ void atomic_dec(volatile atomic_t *v)
 {
        __asm__ __volatile__(
                LOCK "decl %0"
@@ -53,7 +53,7 @@ static __inline__ void atomic_dec(atomic_t *v)
                :"m" (__atomic_fool_gcc(v)));
 }
 
-static __inline__ int atomic_dec_and_test(atomic_t *v)
+static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
        unsigned char c;
 
@@ -64,4 +64,13 @@ static __inline__ int atomic_dec_and_test(atomic_t *v)
        return c != 0;
 }
 
+/* These are x86-specific, used by some header files */
+#define atomic_clear_mask(mask, addr) \
+__asm__ __volatile__(LOCK "andl %0,%1" \
+: : "r" (~(mask)),"m" (__atomic_fool_gcc(addr)) : "memory")
+
+#define atomic_set_mask(mask, addr) \
+__asm__ __volatile__(LOCK "orl %0,%1" \
+: : "r" (mask),"m" (__atomic_fool_gcc(addr)) : "memory")
+
 #endif
index 766a6257708f0b268ea03ec90e4e157f846dc735..ea765a82176fd3fc297298e4d22563fa3cf93c98 100644 (file)
 
 #ifdef __SMP__
 #define LOCK_PREFIX "lock ; "
-#define SMPVOL volatile
 #else
 #define LOCK_PREFIX ""
-#define SMPVOL
 #endif
 
 /*
@@ -28,7 +26,7 @@ struct __dummy { unsigned long a[100]; };
 #define ADDR (*(struct __dummy *) addr)
 #define CONST_ADDR (*(const struct __dummy *) addr)
 
-extern __inline__ int set_bit(int nr, SMPVOL void * addr)
+extern __inline__ int set_bit(int nr, volatile void * addr)
 {
        int oldbit;
 
@@ -39,7 +37,7 @@ extern __inline__ int set_bit(int nr, SMPVOL void * addr)
        return oldbit;
 }
 
-extern __inline__ int clear_bit(int nr, SMPVOL void * addr)
+extern __inline__ int clear_bit(int nr, volatile void * addr)
 {
        int oldbit;
 
@@ -50,7 +48,7 @@ extern __inline__ int clear_bit(int nr, SMPVOL void * addr)
        return oldbit;
 }
 
-extern __inline__ int change_bit(int nr, SMPVOL void * addr)
+extern __inline__ int change_bit(int nr, volatile void * addr)
 {
        int oldbit;
 
@@ -64,11 +62,27 @@ extern __inline__ int change_bit(int nr, SMPVOL void * addr)
 /*
  * This routine doesn't need to be atomic.
  */
-extern __inline__ int test_bit(int nr, const SMPVOL void * addr)
+extern __inline__ int __constant_test_bit(int nr, const volatile void * addr)
 {
-       return ((1UL << (nr & 31)) & (((const unsigned int *) addr)[nr >> 5])) != 0;
+       return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
 }
 
+extern __inline__ int __test_bit(int nr, volatile void * addr)
+{
+       int oldbit;
+
+       __asm__ __volatile__(
+               "btl %2,%1\n\tsbbl %0,%0"
+               :"=r" (oldbit)
+               :"m" (ADDR),"ir" (nr));
+       return oldbit;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ __constant_test_bit((nr),(addr)) : \
+ __test_bit((nr),(addr)))
+
 /*
  * Find-bit routines..
  */
diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
new file mode 100644 (file)
index 0000000..3442bea
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+
+#ifndef __SMP__
+
+#define hardirq_trylock(cpu)   ((cpu)==0)      /* always true */
+#define hardirq_endlock(cpu)   do { } while (0)
+
+#define hardirq_enter(cpu)     (local_irq_count[cpu]++)
+#define hardirq_exit(cpu)      (local_irq_count[cpu]--)
+
+#else
+
+extern unsigned char global_irq_holder;
+extern unsigned volatile int global_irq_lock;
+extern unsigned volatile int global_irq_count;
+
+static inline void release_irqlock(int cpu)
+{
+       /* if we didn't own the irq lock, just ignore.. */
+       if (global_irq_holder == (unsigned char) cpu) {
+               global_irq_holder = NO_PROC_ID;
+               global_irq_lock = 0;
+       }
+}
+
+static inline void hardirq_enter(int cpu)
+{
+       ++local_irq_count[cpu];
+       atomic_inc(&global_irq_count);
+}
+
+static inline void hardirq_exit(int cpu)
+{
+       atomic_dec(&global_irq_count);
+       --local_irq_count[cpu];
+}
+
+static inline int hardirq_trylock(int cpu)
+{
+       unsigned long flags;
+
+       __save_flags(flags);
+       __cli();
+       atomic_inc(&global_irq_count);
+       if (global_irq_count != 1 || test_bit(0,&global_irq_lock)) {
+               atomic_dec(&global_irq_count);
+               __restore_flags(flags);
+               return 0;
+       }
+       ++local_irq_count[cpu];
+       __sti();
+       return 1;
+}
+
+static inline void hardirq_endlock(int cpu)
+{
+       __cli();
+       hardirq_exit(cpu);
+       __sti();
+}      
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_HARDIRQ_H */
index a2d7970377b300737bf9340157433f1763f6ee94..b1c21cc62206f47287f475589fa2f70c8322ec88 100644 (file)
@@ -97,7 +97,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 /*
  * The following are not needed for the non-m68k ports
  */
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port)
 {
        return(1);
 }
index d9d0b68b72c3dc7f7adb4c969d25a8333bb5a5d5..0fb03a1a175caf17a2a4f2e562101b6f2b496cb6 100644 (file)
@@ -143,58 +143,17 @@ extern void enable_irq(unsigned int);
 #ifdef __SMP__
 
 /*
- *     Message pass must be a fast IRQ..
+ *     SMP has a few special interrupts for IPI messages
  */
 
-#define BUILD_MSGIRQ(chip,nr,mask) \
-asmlinkage void IRQ_NAME(nr); \
-asmlinkage void FAST_IRQ_NAME(nr); \
-asmlinkage void BAD_IRQ_NAME(nr); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-       "pushl $-"#nr"-2\n\t" \
-       SAVE_ALL \
-       ACK_##chip(mask,(nr&7)) \
-       "sti\n\t" \
-       "movl %esp,%eax\n\t" \
-       "pushl %eax\n\t" \
-       "pushl $" #nr "\n\t" \
-       "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
-       "addl $8,%esp\n\t" \
-       "cli\n\t" \
-       UNBLK_##chip(mask) \
-       "jmp ret_from_intr\n" \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
-       SAVE_MOST \
-       ACK_##chip(mask,(nr&7)) \
-       "pushl $" #nr "\n\t" \
-       "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
-       "addl $4,%esp\n\t" \
-       "cli\n\t" \
-       UNBLK_##chip(mask) \
-       RESTORE_MOST \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
-       SAVE_MOST \
-       ACK_##chip(mask,(nr&7)) \
-       RESTORE_MOST);
-
-#define BUILD_RESCHEDIRQ(nr) \
-asmlinkage void IRQ_NAME(nr); \
+#define BUILD_SMP_INTERRUPT(x) \
+asmlinkage void x(void); \
 __asm__( \
 "\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
-       "pushl $-"#nr"-2\n\t" \
+SYMBOL_NAME_STR(x) ":\n\t" \
+       "pushl $-1\n\t" \
        SAVE_ALL \
-       "sti\n\t" \
-       "movl %esp,%eax\n\t" \
-       "pushl %eax\n\t" \
-       "pushl $" #nr "\n\t" \
-       "call "SYMBOL_NAME_STR(smp_reschedule_irq)"\n\t" \
-       "addl $8,%esp\n\t" \
-       "cli\n\t" \
+       "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
        "jmp ret_from_intr\n");
 
 #endif /* __SMP__ */
@@ -209,13 +168,11 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        "pushl $-"#nr"-2\n\t" \
        SAVE_ALL \
        ACK_##chip(mask,(nr&7)) \
-       "sti\n\t" \
        "movl %esp,%eax\n\t" \
        "pushl %eax\n\t" \
        "pushl $" #nr "\n\t" \
        "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
        "addl $8,%esp\n\t" \
-       "cli\n\t" \
        UNBLK_##chip(mask) \
        "jmp ret_from_intr\n" \
 "\n"__ALIGN_STR"\n" \
@@ -225,7 +182,6 @@ SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
        "pushl $" #nr "\n\t" \
        "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
        "addl $4,%esp\n\t" \
-       "cli\n\t" \
        UNBLK_##chip(mask) \
        RESTORE_MOST \
 "\n"__ALIGN_STR"\n" \
@@ -251,7 +207,6 @@ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        "pushl $" #nr "\n\t" \
        "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
        "addl $8,%esp\n\t" \
-       "cli\n\t" \
        UNBLK_##chip(mask) \
        "jmp ret_from_intr\n");
 
index 587e3356c0bf025837e50bc1226ae3651704da71..47854e116e5199f622c7283fe96509dced82bffd 100644 (file)
@@ -3,33 +3,58 @@
 
 #ifndef __SMP__
 
-#define lock_kernel()          do { } while(0)
-#define unlock_kernel()                do { } while(0)
-
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED
-
-#define spin_lock_init(lock)   do { } while(0)
-#define spin_lock(lock)                do { } while(0)
-#define spin_trylock(lock)     do { } while(0)
-#define spin_unlock(lock)      do { } while(0)
-
-#define spin_lock_cli(lock)            \
-({     unsigned long flags;            \
-       save_flags(flags); cli();       \
-       return flags;                   \
-})
-
-#define spin_unlock_restore(lock, flags)       restore_flags(flags)
+#define lock_kernel()                          do { } while(0)
+#define unlock_kernel()                                do { } while(0)
+#define release_kernel_lock(task, cpu, depth)  ((depth) = 1)
+#define reaquire_kernel_lock(task, cpu, depth) do { } while(0)
 
 #else
-#include <asm/pgtable.h>
+
+#include <asm/hardirq.h>
+
+/* Release global kernel lock and global interrupt lock */
+#define release_kernel_lock(task, cpu, depth) \
+do { \
+       if ((depth = (task)->lock_depth) != 0) { \
+               __cli(); \
+               (task)->lock_depth = 0; \
+               active_kernel_processor = NO_PROC_ID; \
+               clear_bit(0,&kernel_flag); \
+       } \
+       release_irqlock(cpu); \
+       __sti(); \
+} while (0)
+
+/* Re-aquire the kernel lock */
+#define reaquire_kernel_lock(task, cpu, depth) \
+do { if (depth) __asm__ __volatile__( \
+       "cli\n\t" \
+       "movl $0f,%%eax\n\t" \
+       "jmp __lock_kernel\n" \
+       "0:\t" \
+       "movl %2,%0\n\t" \
+       "sti" \
+       : "=m" (task->lock_depth) \
+       : "d" (cpu), "c" (depth) \
+       : "ax"); \
+} while (0)
+       
 
 /* Locking the kernel */
 extern __inline__ void lock_kernel(void)
 {
        int cpu = smp_processor_id();
 
+       if (local_irq_count[cpu]) {
+               __label__ l1;
+l1:            printk("lock from interrupt context at %p\n", &&l1);
+       }
+       if (cpu == global_irq_holder) {
+               __label__ l2;
+l2:            printk("Ugh at %p\n", &&l2);
+               sti();
+       }
+
        __asm__ __volatile__("
        pushfl
        cli
@@ -62,92 +87,6 @@ extern __inline__ void unlock_kernel(void)
        : "ax", "memory");
 }
 
-/* Simple spin lock operations.  There are two variants, one clears IRQ's
- * on the local processor, one does not.
- *
- * We make no fairness assumptions. They have a cost.
- *
- *     NOT YET TESTED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- */
-
-typedef unsigned char spinlock_t;
-
-/* Arse backwards is faster for us on Intel (trylock is a clock faster) */
-
-#define SPIN_LOCK_UNLOCKED     1
-
-extern __inline__ void __spinlock_waitfor(spinlock_t *lock)
-{
-       int cpu=smp_processor_id();
-       do
-       {
-               /* Spin reading and let the MESI cache do the right stuff
-                  without us thrashing the bus */
-               while(lock)
-               {
-                       /*
-                        *      Not a race, the interrupt will pick up
-                        *      the exiting case that looks suspicious.
-                        *      (The test_bit is not locked so won't
-                        *       thrash the bus either).
-                        */
-                       if(test_bit(cpu,&smp_invalidate_needed))
-                       {
-                               local_flush_tlb();
-                               clear_bit(cpu,&smp_invalidate_needed);
-                       }
-               }
-       }
-       while(clear_bit(0,lock));
-}
-
-extern __inline__ void spin_lock_init(spinlock_t *lock)
-{
-       *lock = 1;      /* We assume init does not need to be itself SMP safe */
-}
-
-extern __inline__ void spin_lock(spinlock_t *lock)
-{
-       /* Returns the old value. If we get 1 then we got the lock */
-       if(clear_bit(0,lock))
-       {
-               __spinlock_waitfor(lock);
-       }
-}
-
-extern __inline__ int spin_trylock(spinlock_t *lock)
-{
-       return clear_bit(0,lock);
-}
-
-extern __inline__ void spin_unlock(spinlock_t *lock)
-{
-       set_bit(0,lock);
-}
-
-/* These variants clear interrupts and return save_flags() style flags
- * to the caller when acquiring a lock.  To release the lock you must
- * pass the lock pointer as well as the flags returned from the acquisition
- * routine when releasing the lock.
- */
-extern __inline__ unsigned long spin_lock_cli(spinlock_t *lock)
-{
-       unsigned long flags;
-       save_flags(flags);
-       cli();
-       if(clear_bit(0,lock))
-               __spinlock_waitfor(lock);
-       return flags;
-}
-
-extern __inline__ void spin_unlock_restore(spinlock_t *lock, unsigned long flags)
-{
-       set_bit(0,lock);        /* Locked operation to keep it serialized with
-                                  the popfl */
-       restore_flags(flags);
-}
-
-
 #endif /* __SMP__ */
 
 #endif /* __I386_SMPLOCK_H */
index 9afcb2b4c5626aa5003de45e8db90608bc704cf4..22aa27cc7ebc21f55f06145bd4a0485b3c2b435d 100644 (file)
@@ -28,4 +28,9 @@
 #define SO_RCVTIMEO    20
 #define SO_SNDTIMEO    21
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
 #endif /* _ASM_SOCKET_H */
diff --git a/include/asm-i386/softirq.h b/include/asm-i386/softirq.h
new file mode 100644 (file)
index 0000000..e05ca77
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+/*
+ * Software interrupts..
+ */
+#define get_active_bhs()       (bh_mask & bh_active)
+#define clear_active_bhs(x)    atomic_clear_mask((x),&bh_active)
+
+#ifdef __SMP__
+
+/* These are for the irq's testing the lock */
+static inline int softirq_trylock(void)
+{
+       atomic_inc(&intr_count);
+       if (intr_count != 1) {
+               atomic_dec(&intr_count);
+               return 0;
+       }
+       return 1;
+}
+
+#define softirq_endlock()      atomic_dec(&intr_count)
+
+#else
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock()      (intr_count ? 0 : ((intr_count=1),1))
+#define softirq_endlock()      (intr_count = 0)
+
+
+#endif
+
+#endif
diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h
new file mode 100644 (file)
index 0000000..a2d3d1a
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#ifndef __SMP__
+
+typedef struct { } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#define spin_lock_init(lock)   do { } while(0)
+#define spin_lock(lock)                do { } while(0)
+#define spin_trylock(lock)     do { } while(0)
+#define spin_unlock(lock)      do { } while(0)
+#define spin_lock_irq(lock)    cli()
+#define spin_unlock_irq(lock)  sti()
+
+#define spin_lock_irqsave(lock, flags) \
+       do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+       restore_flags(flags)
+
+#else
+
+/* Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+typedef struct {
+       volatile unsigned int lock;
+       unsigned long previous;
+} spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED { 0, 0 }
+
+typedef struct { unsigned long a[100]; } __dummy_lock_t;
+#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
+
+#define spin_lock(lock) \
+__asm__ __volatile__( \
+       "jmp 2f\n" \
+       "1:\t" \
+       "testb $1,%0\n\t" \
+       "jne 1b\n" \
+       "2:\t" \
+       "lock ; btsl $0,%0\n\t" \
+       "jc 1b" \
+       :"=m" (__dummy_lock(lock)))
+
+#define spin_unlock(lock) \
+__asm__ __volatile__( \
+       "lock ; btrl $0,%0" \
+       :"=m" (__dummy_lock(lock)))
+
+#undef spin_lock
+static inline void spin_lock(spinlock_t * lock)
+{
+       __label__ l1;
+       int stuck = 10000000;
+l1:
+       __asm__ __volatile__(
+               "jmp 2f\n"
+               "1:\t"
+               "decl %1\n\t"
+               "je 3f\n\t"
+               "testb $1,%0\n\t"
+               "jne 1b\n"
+               "2:\t"
+               "lock ; btsl $0,%0\n\t"
+               "jc 1b\n"
+               "3:"
+               :"=m" (__dummy_lock(lock)),
+                "=r" (stuck)
+               :"1" (stuck));
+       if (!stuck) {
+               printk("spinlock stuck at %p (%lx)\n",&&l1,lock->previous);
+       } else
+               lock->previous = (unsigned long) &&l1;
+}
+
+#define spin_trylock(lock) (!set_bit(0,(lock)))
+
+#define spin_lock_irq(lock) \
+       do { __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irq(lock) \
+       do { spin_unlock(lock); __sti(); } while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+       do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags) \
+       do { spin_unlock(lock); __restore_flags(flags); } while (0)
+
+#endif /* SMP */
+#endif /* __ASM_SPINLOCK_H */
index ab5739be3d0a3c0f00921fb8c7922afb1a4b2f12..a4fbca3dda9dea13ee45cb0a7e7710ecb71b4069 100644 (file)
@@ -67,22 +67,15 @@ __asm__("str %%ax\n\t" \
         */
 
 #define switch_to(prev,next) do { \
-       cli();\
        if(prev->flags&PF_USEDFPU) \
        { \
                __asm__ __volatile__("fnsave %0":"=m" (prev->tss.i387.hard)); \
                __asm__ __volatile__("fwait"); \
                prev->flags&=~PF_USEDFPU;        \
        } \
-__asm__("pushl %%edx\n\t" \
-       "movl "SYMBOL_NAME_STR(apic_reg)",%%edx\n\t" \
-       "movl 0x20(%%edx), %%edx\n\t" \
-       "shrl $22,%%edx\n\t" \
-       "and  $0x3C,%%edx\n\t" \
-       "movl %%ecx,"SYMBOL_NAME_STR(current_set)"(,%%edx)\n\t" \
-       "popl %%edx\n\t" \
-       "ljmp %0\n\t" \
-       "sti\n\t" \
+       prev->processor = NO_PROC_ID; \
+       current_set[this_cpu] = next; \
+__asm__("ljmp %0\n\t" \
        : /* no output */ \
        :"m" (*(((char *)&next->tss.tr)-4)), \
         "c" (next)); \
@@ -220,16 +213,35 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 }
 
 #define mb()  __asm__ __volatile__ (""   : : :"memory")
-#define sti() __asm__ __volatile__ ("sti": : :"memory")
-#define cli() __asm__ __volatile__ ("cli": : :"memory")
 
-#define save_flags(x) \
+/* interrupt control.. */
+#define __sti() __asm__ __volatile__ ("sti": : :"memory")
+#define __cli() __asm__ __volatile__ ("cli": : :"memory")
+#define __save_flags(x) \
 __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
-
-#define restore_flags(x) \
+#define __restore_flags(x) \
 __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
 
-#define iret() __asm__ __volatile__ ("iret": : :"memory")
+
+#ifdef __SMP__
+
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern unsigned long __global_save_flags(void);
+extern void __global_restore_flags(unsigned long);
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define save_flags(x) ((x)=__global_save_flags())
+#define restore_flags(x) __global_restore_flags(x)
+
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+
+#endif
 
 #define _set_gate(gate_addr,type,dpl,addr) \
 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
index 90c78808f1e6538e603aa2ee3db4ec149d188c0a..24ac3dfae963a107962e18261c550656618946e0 100644 (file)
@@ -66,26 +66,26 @@ struct termio {
 }
 
 #define user_termio_to_kernel_termios(termios, termio) \
-do { \
+({ \
        SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
        SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
        SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
        SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
        copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-} while(0)
+})
 
 /*
  * Translate a "termios" structure into a "termio". Ugh.
  */
 #define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
        put_user((termios)->c_iflag, &(termio)->c_iflag); \
        put_user((termios)->c_oflag, &(termio)->c_oflag); \
        put_user((termios)->c_cflag, &(termio)->c_cflag); \
        put_user((termios)->c_lflag, &(termio)->c_lflag); \
        put_user((termios)->c_line,  &(termio)->c_line); \
        copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
-} while(0)
+})
 
 #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
index ab5aaf2610c65242ca88f4a2a06d1ecedf132690..b06eb38138599fd1f02ba0c6a6d436a6858f066c 100644 (file)
@@ -362,7 +362,7 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
 
 #endif /* CONFIG_ATARI */
 
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+static __inline__ int ide_ack_intr (ide_ioreg_t status_port, ide_ioreg_t irq_port)
 {
 #ifdef CONFIG_AMIGA
        if (MACH_IS_AMIGA) {
@@ -371,7 +371,7 @@ static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
                if (!(ch & 0x80))
                        return(0);
                if (AMIGAHW_PRESENT(A1200_IDE)) {
-                       (void) inb(base_port);
+                       (void) inb(status_port);
                        outb(0x7c | (ch & 0x03), irq_port);
                }
        }
index 9afcb2b4c5626aa5003de45e8db90608bc704cf4..22aa27cc7ebc21f55f06145bd4a0485b3c2b435d 100644 (file)
@@ -28,4 +28,9 @@
 #define SO_RCVTIMEO    20
 #define SO_SNDTIMEO    21
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
 #endif /* _ASM_SOCKET_H */
index 4541aabe874f62508d2aea438d9df8500368edce..134623f86e8142a41422cab693beeff1114459bb 100644 (file)
@@ -60,7 +60,7 @@ struct termio {
  * Translate a "termio" structure into a "termios". Ugh.
  */
 #define user_termio_to_kernel_termios(termios, termio) \
-do { \
+({ \
        unsigned short tmp; \
        get_user(tmp, &(termio)->c_iflag); \
        (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
@@ -72,20 +72,20 @@ do { \
        (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
        get_user((termios)->c_line, &(termio)->c_line); \
        copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-} while(0)
+})
 
 /*
  * Translate a "termios" structure into a "termio". Ugh.
  */
 #define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
        put_user((termios)->c_iflag, &(termio)->c_iflag); \
        put_user((termios)->c_oflag, &(termio)->c_oflag); \
        put_user((termios)->c_cflag, &(termio)->c_cflag); \
        put_user((termios)->c_lflag, &(termio)->c_lflag); \
        put_user((termios)->c_line,  &(termio)->c_line); \
        copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
-} while(0)
+})
 
 #define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
index 0e69633d355821b9a3dacef9eb2ab5f4707c051e..ff829a8649c68725c43e09e692eb9a1ae408b39c 100644 (file)
@@ -55,4 +55,9 @@
                                        /* other similar things on the  */
                                        /* user level.                  */
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
 #endif /* __ASM_MIPS_SOCKET_H */
index dd595ecf4412c191874f827b45a6c77a752c1683..d0947469628e2669296b85f296314a4a763f7eff 100644 (file)
@@ -32,4 +32,9 @@
 #define SO_RCVTIMEO    18
 #define SO_SNDTIMEO    19
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             20
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       21
+#define SO_SECURITY_ENCRYPTION_NETWORK         22
+
 #endif /* _ASM_SOCKET_H */
index 30802fb69f65df2eaf8599910174ce19203e5810..3b0abf580ce2d4281e3a98ba8a6d0438c7fb4aba 100644 (file)
 #define AOFF_task_ldt  0x000001d8
 #define ASIZ_task_ldt  0x00000004
 #define AOFF_task_tss  0x000001e0
-#define ASIZ_task_tss  0x000003a0
-#define AOFF_task_fs   0x00000580
+#define ASIZ_task_tss  0x00000390
+#define AOFF_task_fs   0x00000570
 #define ASIZ_task_fs   0x00000004
-#define AOFF_task_files        0x00000584
+#define AOFF_task_files        0x00000574
 #define ASIZ_task_files        0x00000004
-#define AOFF_task_mm   0x00000588
+#define AOFF_task_mm   0x00000578
 #define ASIZ_task_mm   0x00000004
-#define AOFF_task_sig  0x0000058c
+#define AOFF_task_sig  0x0000057c
 #define ASIZ_task_sig  0x00000004
-#define AOFF_task_processor    0x00000590
+#define AOFF_task_processor    0x00000580
 #define ASIZ_task_processor    0x00000004
-#define AOFF_task_last_processor       0x00000594
+#define AOFF_task_last_processor       0x00000584
 #define ASIZ_task_last_processor       0x00000004
-#define AOFF_task_lock_depth   0x00000598
+#define AOFF_task_lock_depth   0x00000588
 #define ASIZ_task_lock_depth   0x00000004
 #define AOFF_mm_count  0x00000000
 #define ASIZ_mm_count  0x00000004
 #define ASIZ_thread_sstk_info  0x00000008
 #define AOFF_thread_flags      0x00000360
 #define ASIZ_thread_flags      0x00000004
-#define AOFF_thread_ex 0x00000368
-#define ASIZ_thread_ex 0x00000010
-#define AOFF_thread_current_ds 0x00000378
+#define AOFF_thread_current_ds 0x00000364
 #define ASIZ_thread_current_ds 0x00000004
-#define AOFF_thread_core_exec  0x0000037c
+#define AOFF_thread_core_exec  0x00000368
 #define ASIZ_thread_core_exec  0x00000020
-#define AOFF_thread_new_signal 0x0000039c
+#define AOFF_thread_new_signal 0x00000388
 #define ASIZ_thread_new_signal 0x00000004
 
 #endif /* __ASM_OFFSETS_H__ */
index 19151a1e6eb5e3a9fb525c69217712c22936e86f..66d613673ac5ee4ae6bbc32be4cdcd435070a3d8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.25 1997/02/19 15:51:19 jj Exp $ */
+/* $Id: checksum.h,v 1.26 1997/03/14 07:54:47 davem Exp $ */
 #ifndef __SPARC_CHECKSUM_H
 #define __SPARC_CHECKSUM_H
 
@@ -45,6 +45,8 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum
 #define csum_partial_copy_fromuser(s, d, l, w)  \
                          csum_partial_copy((char *) (s), (d), (l), (w))
   
+extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
+
 extern __inline__ unsigned int 
 csum_partial_copy_nocheck (const char *src, char *dst, int len, 
                           unsigned int sum)
index a86379a71c2506dea9feca537d2ee2e3c3b0fc3a..e9ed1a4dd331911a08a6ffe9aca014fba02964cf 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.22 1996/10/17 05:29:01 davem Exp $
+/* $Id: dma.h,v 1.23 1997/03/14 21:05:20 jj Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -74,7 +74,6 @@ extern struct Linux_SBus_DMA *dma_chain;
 #define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
 
 /* Main routines in dma.c */
-extern void dump_dma_regs(struct sparc_dma_registers *);
 extern unsigned long dvma_init(struct linux_sbus *, unsigned long);
 
 /* Fields in the cond_reg register */
diff --git a/include/asm-sparc/init.h b/include/asm-sparc/init.h
new file mode 100644 (file)
index 0000000..d45b33a
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _SPARC_INIT_H
+#define _SPARC_INIT_H
+
+#ifndef __init
+#if (defined (__svr4__) || defined (__ELF__)) && !defined (MODULE)
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+       __arginit __init; \
+       __arginit
+/* For assembly routines */
+#define __INIT         .section        ".text.init",#alloc,#execinstr
+#define __FINIT        .previous
+#define __INITDATA     .section        ".data.init",#alloc,#write
+#else
+#define        __init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+/* For assembly routines */
+#define __INIT
+#define __FINIT
+#define __INITDATA
+#endif
+#endif
+
+#endif
index 7382d396fd685d4c7257392564e67966dee32722..3cf496bdf399a44b7fcfde6b9d86a4cb73587f2a 100644 (file)
@@ -32,6 +32,18 @@ enum {
 /* Get keyboard leds */
 #define KIOCGLED    _IOR('k', 15, unsigned char)
 
+/* Used by KIOC[GS]RATE */
+struct kbd_rate {
+       unsigned char delay;    /* Delay in Hz before first repeat.     */
+       unsigned char rate;     /* In characters per second (0..50).    */
+};
+
+/* Set keyboard rate */
+#define KIOCSRATE   _IOW('k', 40, struct kbd_rate)
+
+/* Get keyboard rate */
+#define KIOCGRATE   _IOW('k', 41, struct kbd_rate)
+
 /* Top bit records if the key is up or down */
 #define KBD_UP      0x80
 
index 6623296665d87e1be17dfd0b1fcdff6544a322a6..40c6de10b41988343cf62cb651acb34f3a08d141 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.13 1997/01/31 00:16:52 tdyas Exp $
+/* $Id: oplib.h,v 1.15 1997/03/18 18:00:18 jj Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -31,6 +31,9 @@ extern unsigned int prom_rev, prom_prev;
  */
 extern int prom_root_node;
 
+/* PROM stdin and stdout */
+extern int prom_stdin, prom_stdout;
+
 /* Pointer to prom structure containing the device tree traversal
  * and usage utility functions.  Only prom-lib should use these,
  * users use the interface defined by the library only!
@@ -108,7 +111,7 @@ extern void prom_cmdline(void);
 /* Enter the prom, with no chance of continuation for the stand-alone
  * which calls this.
  */
-extern void prom_halt(void);
+extern void prom_halt(void) __attribute__ ((noreturn));
 
 /* Set the PROM 'sync' callback function to the passed function pointer.
  * When the user gives the 'sync' command at the prom prompt while the
index 664faa2a347041bb8fa12cf426eaf4c186e254c8..fac1df5edcdb5dd39c5d921466235310d7e36154 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtsrmmu.h,v 1.25 1996/12/18 06:56:07 tridge Exp $
+/* $Id: pgtsrmmu.h,v 1.28 1997/03/15 07:47:52 davem Exp $
  * pgtsrmmu.h:  SRMMU page table defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -87,6 +87,8 @@
 #define SRMMU_FAULT_STATUS       0x00000300
 #define SRMMU_FAULT_ADDR         0x00000400
 
+#ifndef __ASSEMBLY__
+
 /* Accessing the MMU control register. */
 extern __inline__ unsigned int srmmu_get_mmureg(void)
 {
@@ -219,7 +221,20 @@ extern __inline__ unsigned long srmmu_hwprobe(unsigned long vaddr)
        return retval;
 }
 
+extern __inline__ int
+srmmu_get_pte (unsigned long addr)
+{
+       register unsigned long entry;
+        
+       __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" :
+                               "=r" (entry):
+                               "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE));
+       return entry;
+}
+
 extern unsigned long (*srmmu_read_physical)(unsigned long paddr);
 extern void (*srmmu_write_physical)(unsigned long paddr, unsigned long word);
 
+#endif /* !(__ASSEMBLY__) */
+
 #endif /* !(_SPARC_PGTSRMMU_H) */
index e6b0ddc2621ef0f167b11dca8b23703bebc96a2c..7b270883fe02379d101cc85ca0d1e5fd3fa518f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ross.h,v 1.11 1996/08/29 09:48:40 davem Exp $
+/* $Id: ross.h,v 1.12 1997/03/10 09:16:57 davem Exp $
  * ross.h: Ross module specific definitions and defines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -93,6 +93,8 @@
 #define HYPERSPARC_ICCR_FTD     0x00000002
 #define HYPERSPARC_ICCR_ICE     0x00000001
 
+#ifndef __ASSEMBLY__
+
 extern __inline__ unsigned int get_ross_icr(void)
 {
        unsigned int icreg;
@@ -171,4 +173,6 @@ extern __inline__ void hyper_flush_cache_page(unsigned long page)
        }
 }
 
+#endif /* !(__ASSEMBLY__) */
+
 #endif /* !(_SPARC_ROSS_H) */
index 577c4b4a2aab837c3c2e7211ab475a72156855dd..fbf3a2753fe2f5293ad065ddc7d039208ab8a211 100644 (file)
@@ -3,6 +3,8 @@
 
 /* Dinky, good for nothing, just barely irq safe, Sparc semaphores. */
 
+#ifdef __KERNEL__
+
 #include <asm/atomic.h>
 
 struct semaphore {
@@ -41,4 +43,6 @@ extern inline void up(struct semaphore * sem)
                __up(sem);
 }      
 
+#endif /* __KERNEL__ */
+
 #endif /* !(_SPARC_SEMAPHORE_H) */
index 87c4166ef2c389b734771e3deebdf6dc8b5080bb..f5205550d3ffbd14d799471d7726e4f2aeefbc95 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: socket.h,v 1.8 1996/12/12 19:21:43 davem Exp $ */
+/* $Id: socket.h,v 1.9 1997/03/17 04:50:50 davem Exp $ */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
@@ -35,4 +35,9 @@
 #define SO_NO_CHECK    0x000b
 #define SO_PRIORITY    0x000c
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             0x000d
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       0x000e
+#define SO_SECURITY_ENCRYPTION_NETWORK         0x000f
+
 #endif /* _ASM_SOCKET_H */
index 8965ffb51715ba7a5a688ce1d8d02cf89ee91372..53e73b25b45e111208dcc3a9b52bc70351708dc6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.51 1997/01/25 01:33:05 davem Exp $ */
+/* $Id: system.h,v 1.53 1997/03/19 14:53:43 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/oplib.h>
 #include <asm/psr.h>
+#include <asm/ptrace.h>
 #endif
 
 #define EMPTY_PGT       (&empty_bad_page)
@@ -265,6 +266,8 @@ static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
        return x;
 }
 
+extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* !(__SPARC_SYSTEM_H) */
diff --git a/include/asm-sparc64/auxio.h b/include/asm-sparc64/auxio.h
new file mode 100644 (file)
index 0000000..53360bc
--- /dev/null
@@ -0,0 +1,72 @@
+/* $Id: auxio.h,v 1.1 1997/03/14 21:05:27 jj Exp $
+ * auxio.h:  Definitions and code for the Auxiliary I/O register.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC64_AUXIO_H
+#define _SPARC64_AUXIO_H
+
+#include <asm/system.h>
+
+/* FIXME: All of this should be checked for sun4u. It has /sbus/auxio, but
+   I don't know whether it is the same and don't have a floppy */
+
+extern unsigned char *auxio_register;
+
+/* This register is an unsigned char in IO space.  It does two things.
+ * First, it is used to control the front panel LED light on machines
+ * that have it (good for testing entry points to trap handlers and irq's)
+ * Secondly, it controls various floppy drive parameters.
+ */
+#define AUXIO_ORMEIN      0xf0    /* All writes must set these bits. */
+#define AUXIO_ORMEIN4M    0xc0    /* sun4m - All writes must set these bits. */
+#define AUXIO_FLPY_DENS   0x20    /* Floppy density, high if set. Read only. */
+#define AUXIO_FLPY_DCHG   0x10    /* A disk change occurred.  Read only. */
+#define AUXIO_EDGE_ON     0x10    /* sun4m - On means Jumper block is in. */
+#define AUXIO_FLPY_DSEL   0x08    /* Drive select/start-motor. Write only. */
+#define AUXIO_LINK_TEST   0x08    /* sun4m - On means TPE Carrier detect. */
+
+/* Set the following to one, then zero, after doing a pseudo DMA transfer. */
+#define AUXIO_FLPY_TCNT   0x04    /* Floppy terminal count. Write only. */
+
+/* Set the following to zero to eject the floppy. */
+#define AUXIO_FLPY_EJCT   0x02    /* Eject floppy disk.  Write only. */
+#define AUXIO_LED         0x01    /* On if set, off if unset. Read/Write */
+
+#define AUXREG   ((volatile unsigned char *)(auxio_register))
+
+/* These are available on sun4c */
+#define TURN_ON_LED   if (AUXREG) *AUXREG = (*AUXREG | AUXIO_ORMEIN | AUXIO_LED)
+#define TURN_OFF_LED  if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_LED))
+#define FLIP_LED      if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) ^ AUXIO_LED)
+#define FLPY_MOTORON  if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) | AUXIO_FLPY_DSEL)
+#define FLPY_MOTOROFF if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_FLPY_DSEL))
+#define FLPY_TCNTON   if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) | AUXIO_FLPY_TCNT)
+#define FLPY_TCNTOFF  if (AUXREG) *AUXREG = ((*AUXREG | AUXIO_ORMEIN) & (~AUXIO_FLPY_TCNT))
+
+#ifndef __ASSEMBLY__
+extern __inline__ void set_auxio(unsigned char bits_on, unsigned char bits_off)
+{
+       unsigned char regval;
+       unsigned long flags;
+
+       save_flags(flags); cli();
+
+       if(AUXREG) {
+               regval = *AUXREG;
+               *AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
+       }
+       restore_flags(flags);
+}
+#endif /* !(__ASSEMBLY__) */
+
+
+/* AUXIO2 (Power Off Control) */
+extern __volatile__ unsigned char * auxio_power_register;
+
+#define        AUXIO_POWER_DETECT_FAILURE      32
+#define        AUXIO_POWER_CLEAR_FAILURE       2
+#define        AUXIO_POWER_OFF                 1
+
+
+#endif /* !(_SPARC_AUXIO_H) */
index 23666a685bdaf3291547cbca2588f90ba88b8b86..611287b79042d7222158c2fb171174a66f1d23b5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.6 1996/12/26 15:36:49 davem Exp $
+/* $Id: bitops.h,v 1.7 1997/03/14 21:05:38 jj Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -154,18 +154,18 @@ extern __inline__ int set_le_bit(int nr,void * addr)
        unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
        __asm__ __volatile__("
-       lduwa           [%2] %5, %0
+       lduwa           [%2] %6, %0
 1:
        andcc           %0, %4, %3
        bne,pn          %%icc, 2f
         xor            %0, %4, %1
-       casa            [%2] %5, %0, %1
+       casa            [%2] %6, %0, %1
        cmp             %0, %1
        bne,a,pn        %%icc, 1b
-        lduwa          [%2] %5, %0
+        lduwa          [%2] %6, %0
 2:
 "      : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-       : "ir" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL));
+       : "ir" (1UL << (nr & 31)), "2" (m), "i" (ASI_PL));
        return oldbit != 0;
 }
 
@@ -176,18 +176,18 @@ extern __inline__ int clear_le_bit(int nr, void * addr)
        unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
 
        __asm__ __volatile__("
-       lduwa           [%2] %5, %0
+       lduwa           [%2] %6, %0
 1:
        andcc           %0, %4, %3
        be,pn           %%icc, 2f
         xor            %0, %4, %1
-       casa            [%2] %5, %0, %1
+       casa            [%2] %6, %0, %1
        cmp             %0, %1
        bne,a,pn        %%icc, 1b
-        lduwa          [%2] %5, %0
+        lduwa          [%2] %6, %0
 2:
 "      : "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
-       : "ir" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL));
+       : "ir" (1UL << (nr & 31)), "2" (m), "i" (ASI_PL));
        return oldbit != 0;
 }
 
diff --git a/include/asm-sparc64/bpp.h b/include/asm-sparc64/bpp.h
new file mode 100644 (file)
index 0000000..4b36c92
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _SPARC64_BPP_H
+#define _SPARC64_BPP_H
+
+/*
+ * Copyright (c) 1995 Picture Elements
+ *     Stephen Williams
+ *     Gus Baldauf
+ *
+ * Linux/SPARC port by Peter Zaitcev.
+ * Integration into SPARC tree by Tom Dyas.
+ */
+
+#include  <linux/ioctl.h>
+
+/*
+ * This is a driver that supports IEEE Std 1284-1994 communications
+ * with compliant or compatible devices. It will use whatever features
+ * the device supports, prefering those that are typically faster.
+ *
+ * When the device is opened, it is left in COMPATABILITY mode, and
+ * writes work like any printer device. The driver only attempt to
+ * negotiate 1284 modes when needed so that plugs can be pulled,
+ * switch boxes switched, etc., without disrupting things. It will
+ * also leave the device in compatibility mode when closed.
+ */
+
+
+
+/*
+ * This driver also supplies ioctls to manually manipulate the
+ * pins. This is great for testing devices, or writing code to deal
+ * with bizzarro-mode of the ACME Special TurboThingy Plus.
+ *
+ * NOTE: These ioctl currently do not interact well with
+ * read/write. Caveat emptor.
+ *
+ * PUT_PINS allows us to assign the sense of all the pins, including
+ * the data pins if being driven by the host. The GET_PINS returns the
+ * pins that the peripheral drives, including data if appropriate.
+ */
+
+# define BPP_PUT_PINS _IOW('B', 1, int)
+# define BPP_GET_PINS _IOR('B', 2, void)
+# define BPP_PUT_DATA _IOW('B', 3, int)
+# define BPP_GET_DATA _IOR('B', 4, void)
+
+/*
+ * Set the data bus to input mode. Disengage the data bin driver and
+ * be prepared to read values from the peripheral. If the arg is 0,
+ * then revert the bus to output mode.
+ */
+# define BPP_SET_INPUT _IOW('B', 5, int)
+
+/*
+ * These bits apply to the PUT operation...
+ */
+# define BPP_PP_nStrobe   0x0001
+# define BPP_PP_nAutoFd   0x0002
+# define BPP_PP_nInit     0x0004
+# define BPP_PP_nSelectIn 0x0008
+
+/*
+ * These apply to the GET operation, which also reads the current value
+ * of the previously put values. A bit mask of these will be returned
+ * as a bit mask in the return code of the ioctl().
+ */
+# define BPP_GP_nAck   0x0100
+# define BPP_GP_Busy   0x0200
+# define BPP_GP_PError 0x0400
+# define BPP_GP_Select 0x0800
+# define BPP_GP_nFault 0x1000
+
+
+/*
+ * Prototype for the initialization routine.
+ */
+
+#ifdef __KERNEL__
+extern int bpp_init(void);
+#endif
+
+#endif
index 95a26dfa84c7b672ef46ac5b2a794c0f3c131ebe..4ff1717fd946df7a677040ab960c5cc1ed0763bf 100644 (file)
@@ -1,17 +1,17 @@
-/* $Id: byteorder.h,v 1.2 1996/12/26 13:25:23 davem Exp $ */
+/* $Id: byteorder.h,v 1.3 1997/03/14 21:05:31 jj Exp $ */
 #ifndef _SPARC64_BYTEORDER_H
 #define _SPARC64_BYTEORDER_H
 
-extern __inline__ unsigned long int ntohl(unsigned long int x) { return x; }
-extern __inline__ unsigned short int ntohs(unsigned short int x) { return x; }
-extern __inline__ unsigned long int htonl(unsigned long int x) { return x; }
-extern __inline__ unsigned short int htons(unsigned short int x) { return x; }
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
 
 /* Some programs depend upon these being around. */
-extern __inline__ unsigned long int __constant_ntohl(unsigned long int x) { return x; }
-extern __inline__ unsigned short int __constant_ntohs(unsigned short int x) { return x; }
-extern __inline__ unsigned long int __constant_htonl(unsigned long int x) { return x; }
-extern __inline__ unsigned short int __constant_htons(unsigned short int x) { return x; }
+#define __constant_ntohl(x) (x)
+#define __constant_ntohs(x) (x)
+#define __constant_htonl(x) (x)
+#define __constant_htons(x) (x)
 
 #ifndef __BIG_ENDIAN
 #define __BIG_ENDIAN 4321
diff --git a/include/asm-sparc64/cache.h b/include/asm-sparc64/cache.h
new file mode 100644 (file)
index 0000000..3d2198c
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * include/asm-sparc64/cache.h
+ */
+#ifndef __ARCH_SPARC64_CACHE_H
+#define __ARCH_SPARC64_CACHE_H
+
+/* FIXME: Should look at this soon */
+/* bytes per L1 cache line */
+#define        L1_CACHE_BYTES  32      /* a guess */
+
+#define        L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
+
+#endif
index a9fa89ae396220024f7b9e9a4ada31b4dfa9be85..e55d12a4cf079b5afb79f4991bcc44c86b026700 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.3 1996/12/12 15:39:13 davem Exp $ */
+/* $Id: checksum.h,v 1.5 1997/03/18 18:00:28 jj Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -8,6 +8,7 @@
  *  Copyright(C) 1995 Miguel de Icaza
  *  Copyright(C) 1996 David S. Miller
  *  Copyright(C) 1996 Eddie C. Dost
+ *  Copyright(C) 1997 Jakub Jelinek
  *
  * derived from:
  *     Alpha checksum c-code
@@ -15,6 +16,8 @@
  *      RFC1071 Computing the Internet Checksum
  */
 
+#include <asm/uaccess.h> 
+
 /* computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
  *
@@ -34,11 +37,83 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
  */
-extern unsigned int csum_partial_copy(char *src, char *dst, int len, int sum);
-
+/* FIXME: Remove these macros ASAP */
+#define csum_partial_copy(src, dst, len, sum) \
+                       csum_partial_copy_nocheck(src,dst,len,sum)
 #define csum_partial_copy_fromuser(s, d, l, w)  \
-                       csum_partial_copy((char *) (s), (d), (l), (w))
+                       csum_partial_copy((char *) (s), (d), (l), (w))
+                       
+extern __inline__ unsigned int 
+csum_partial_copy_nocheck (const char *src, char *dst, int len, 
+                          unsigned int sum)
+{
+       register unsigned long ret asm("o0") = (unsigned long)src;
+       register char *d asm("o1") = dst;
+       register unsigned long l asm("g1") = len;
+       
+       __asm__ __volatile__ ("
+               call __csum_partial_copy_sparc_generic
+                mov %4, %%g7
+       " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) :
+       "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+       return (unsigned int)ret;
+}
+
+extern __inline__ unsigned int 
+csum_partial_copy_from_user(const char *src, char *dst, int len, 
+                           unsigned int sum, int *err)
+{
+       if (!access_ok (VERIFY_READ, src, len)) {
+               *err = -EFAULT;
+               memset (dst, 0, len);
+               return sum;
+       } else {
+               register unsigned long ret asm("o0") = (unsigned long)src;
+               register char *d asm("o1") = dst;
+               register unsigned long l asm("g1") = len;
+               register unsigned long s asm("g7") = sum;
 
+               __asm__ __volatile__ ("
+               .section __ex_table,#alloc
+               .align 4
+               .word 1f,2
+               .previous
+1:
+               call __csum_partial_copy_sparc_generic
+                stx %5, [%%sp + 0x7ff + 128]
+               " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
+               "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+               return (unsigned int)ret;
+       }
+}
+  
+extern __inline__ unsigned int 
+csum_partial_copy_to_user(const char *src, char *dst, int len, 
+                         unsigned int sum, int *err)
+{
+       if (!access_ok (VERIFY_WRITE, dst, len)) {
+               *err = -EFAULT;
+               return sum;
+       } else {
+               register unsigned long ret asm("o0") = (unsigned long)src;
+               register char *d asm("o1") = dst;
+               register unsigned long l asm("g1") = len;
+               register unsigned long s asm("g7") = sum;
+
+               __asm__ __volatile__ ("
+               .section __ex_table,#alloc
+               .align 4
+               .word 1f,1
+               .previous
+1:
+               call __csum_partial_copy_sparc_generic
+                stx %5, [%%sp + 0x7ff + 128]
+               " : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
+               "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+               return (unsigned int)ret;
+       }
+}
+  
 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  * the majority of the time.
  */
@@ -52,7 +127,7 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
         *       both operands.
         */
        __asm__ __volatile__("
-       sub             %2, 4, %%g4
+       sub             %2, 4, %%g7
        lduw            [%1 + 0x00], %0
        lduw            [%1 + 0x04], %%g2
        lduw            [%1 + 0x08], %%g3
@@ -66,10 +141,10 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
        addcc           %%g3, %0, %0
        add             %1, 4, %1
        addccc          %0, %%g0, %0
-       subcc           %%g4, 1, %%g4
+       subcc           %%g7, 1, %%g7
        be,a,pt         %%icc, 2f
         sll            %0, 16, %%g2
-       ba,pt           1b
+       ba,pt           %%xcc, 1b
         lduw           [%1 + 0x10], %%g3
 2:
        addcc           %0, %%g2, %%g2
@@ -78,7 +153,7 @@ extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
        xnor            %%g0, %0, %0
 "      : "=r" (sum), "=&r" (iph)
        : "r" (ihl), "1" (iph)
-       : "g2", "g3", "g4");
+       : "g2", "g3", "g7");
        return sum;
 }
 
@@ -130,29 +205,29 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
                                                     unsigned int sum) 
 {
        __asm__ __volatile__ ("
-       addcc           %3, %4, %%g4
-       addccc          %5, %%g4, %%g4
+       addcc           %3, %4, %%g7
+       addccc          %5, %%g7, %%g7
        lduw            [%2 + 0x0c], %%g2
        lduw            [%2 + 0x08], %%g3
-       addccc          %%g2, %%g4, %%g4
+       addccc          %%g2, %%g7, %%g7
        lduw            [%2 + 0x04], %%g2
-       addccc          %%g3, %%g4, %%g4
+       addccc          %%g3, %%g7, %%g7
        lduw            [%2 + 0x00], %%g3
-       addccc          %%g2, %%g4, %%g4
+       addccc          %%g2, %%g7, %%g7
        lduw            [%1 + 0x0c], %%g2
-       addccc          %%g3, %%g4, %%g4
+       addccc          %%g3, %%g7, %%g7
        lduw            [%1 + 0x08], %%g3
-       addccc          %%g2, %%g4, %%g4
+       addccc          %%g2, %%g7, %%g7
        lduw            [%1 + 0x04], %%g2
-       addccc          %%g3, %%g4, %%g4
+       addccc          %%g3, %%g7, %%g7
        lduw            [%1 + 0x00], %%g3
-       addccc          %%g2, %%g4, %%g4
-       addccc          %%g3, %%g4, %0
+       addccc          %%g2, %%g7, %%g7
+       addccc          %%g3, %%g7, %0
        addc            0, %0, %0
 "      : "=&r" (sum)
        : "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))),
          "r"(htonl(proto)), "r"(sum)
-       : "g2", "g3", "g4");
+       : "g2", "g3", "g7");
 
        return csum_fold(sum);
 }
index 813128d0ee43c84ff09dbe41f3f3773d61e1c569..5a35285fec2382f41a02e4eb26f063fa4dfc0f2a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.2 1996/12/26 13:25:24 davem Exp $
+/* $Id: dma.h,v 1.3 1997/03/14 21:05:36 jj Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -73,7 +73,6 @@ extern struct Linux_SBus_DMA *dma_chain;
 #define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
 
 /* Main routines in dma.c */
-extern void dump_dma_regs(struct sparc_dma_registers *);
 extern unsigned long dvma_init(struct linux_sbus *, unsigned long);
 
 /* Fields in the cond_reg register */
index a8de05ddb2bcff1d4741e57a8eb75fe42e70a6a6..c7aa7cc8110b17a0f0a3b486935875c19089f9e3 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: floppy.h,v 1.1 1996/11/20 15:31:07 davem Exp $
+/* $Id: floppy.h,v 1.2 1997/03/14 21:05:25 jj Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #ifndef __ASM_SPARC64_FLOPPY_H
@@ -11,9 +12,9 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/idprom.h>
-#include <asm/machines.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
+#include <asm/sbus.h>
 #include <asm/irq.h>
 
 /* References:
@@ -278,43 +279,24 @@ static struct linux_prom_registers fd_regs[2];
 static int sun_floppy_init(void)
 {
        char state[128];
-       int tnode, fd_node, num_regs;
+       int fd_node, num_regs;
+       struct linux_sbus *bus;
+       struct linux_sbus_device *sdev;
 
        use_virtual_dma = 1;
        
        FLOPPY_IRQ = 11;
-       /* Forget it if we aren't on a machine that could possibly
-        * ever have a floppy drive.
-        */
-       if((sparc_cpu_model != sun4c && sparc_cpu_model != sun4m) ||
-          ((idprom->id_machtype == (SM_SUN4C | SM_4C_SLC)) ||
-           (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC)))) {
-               /* We certainly don't have a floppy controller. */
-               goto no_sun_fdc;
-       }
-       /* Well, try to find one. */
-       tnode = prom_getchild(prom_root_node);
-       fd_node = prom_searchsiblings(tnode, "obio");
-       if(fd_node != 0) {
-               tnode = prom_getchild(fd_node);
-               fd_node = prom_searchsiblings(tnode, "SUNW,fdtwo");
-       } else {
-               fd_node = prom_searchsiblings(tnode, "fd");
-       }
-       if(fd_node == 0) {
-               goto no_sun_fdc;
-       }
-
-       /* The sun4m lets us know if the controller is actually usable. */
-       if(sparc_cpu_model == sun4m) {
-               prom_getproperty(fd_node, "status", state, sizeof(state));
-               if(!strcmp(state, "disabled")) {
-                       goto no_sun_fdc;
-               }
+       for_all_sbusdev (sdev, bus) {
+               if (!strcmp(sdev->prom_name, "SUNW,fdtwo")) 
+                       break;
        }
+       if (!bus) return -1;
+       fd_node = sdev->prom_node;
+       prom_getproperty(fd_node, "status", state, sizeof(state));
+       if(!strcmp(state, "disabled")) return -1;
        num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs, sizeof(fd_regs));
        num_regs = (num_regs / sizeof(fd_regs[0]));
-       prom_apply_obio_ranges(fd_regs, num_regs);
+       prom_apply_sbus_ranges(sdev->my_bus, fd_regs, num_regs, sdev);
        sun_fdc = (struct sun_flpy_controller *) sparc_alloc_io(fd_regs[0].phys_addr,
                                                                0x0,
                                                                fd_regs[0].reg_size,
@@ -324,26 +306,16 @@ static int sun_floppy_init(void)
        /* Last minute sanity check... */
        if(sun_fdc->status_82072 == 0xff) {
                sun_fdc = NULL;
-               goto no_sun_fdc;
+               return -1;
        }
 
-        if(sparc_cpu_model == sun4c) {
-                sun_fdops.fd_inb = sun_82072_fd_inb;
-                sun_fdops.fd_outb = sun_82072_fd_outb;
-                fdc_status = &sun_fdc->status_82072;
-                /* printk("AUXIO @0x%p\n", auxio_register); */ /* P3 */
-        } else {
-                sun_fdops.fd_inb = sun_82077_fd_inb;
-                sun_fdops.fd_outb = sun_82077_fd_outb;
-                fdc_status = &sun_fdc->status_82077;
-                /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */
-       }
+        sun_fdops.fd_inb = sun_82077_fd_inb;
+        sun_fdops.fd_outb = sun_82077_fd_outb;
+        fdc_status = &sun_fdc->status_82077;
+        /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */
 
        /* Success... */
        return (int) sun_fdc;
-
-no_sun_fdc:
-       return -1;
 }
 
 static int sparc_eject(void)
index c4029aebc097433744f89b7fe32883a6dcfe5a4a..1bd621c278ab883bc3d4369d47e58feb2a58abe7 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: head.h,v 1.4 1997/02/25 20:00:32 jj Exp $ */
+/* $Id: head.h,v 1.7 1997/03/18 18:00:36 jj Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
+#define KERNBASE    0xfffff80000000000
 #define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
 
 #define CLEAN_WINDOW                                                   \
        nop;            nop;            nop;            nop;
 
 #define TRAP(routine)                                  \
-       b       etrap;                                  \
+       ba,pt   %xcc, etrap;                            \
         rd     %pc, %g7;                               \
        call    routine;                                \
         add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       b       rtrap;                                  \
-        subcc  %g0, %o0, %g0;                          \
+       ba,pt   %xcc, rtrap;                            \
+        nop;                                           \
        nop;                                            \
        nop;
 
 #define TRAP_ARG(routine, arg)                         \
-       b       etrap;                                  \
+       ba,pt   %xcc, etrap;                            \
         rd     %pc, %g7;                               \
        add     %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
        call    routine;                                \
         mov    arg, %o1;                               \
-       b       rtrap;                                  \
-        subcc  %g0, %o0, %g0;                          \
+       ba,pt   %xcc, rtrap;                            \
+        nop;                                           \
        nop;
+       
+#define SYSCALL_TRAP(routine, systbl)                  \
+       ba,pt   %xcc, etrap;                            \
+        rd     %pc, %g7;                               \
+       sethi   %hi(systbl), %l7;                       \
+       call    routine;                                \
+        or     %l7, %lo(systbl), %l7;                  \
+       nop; nop; nop;
+       
 
+#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
+#define        LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
+#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
 /* FIXME: Write these actually */      
-#define SUNOS_SYSCALL_TRAP TRAP(sunos_syscall)
-#define        LINUX_32BIT_SYSCALL_TRAP TRAP(linux32_syscall)
-#define LINUX_64BIT_SYSCALL_TRAP TRAP(linux64_syscall)
 #define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
 #define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
 #define BREAKPOINT_TRAP TRAP(breakpoint_trap)
diff --git a/include/asm-sparc64/init.h b/include/asm-sparc64/init.h
new file mode 100644 (file)
index 0000000..766caee
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _SPARC64_INIT_H
+#define _SPARC64_INIT_H
+
+#ifndef __init
+/* 'cause of buggy linker, we don't use this for now... */
+#if 0 && !defined (MODULE)
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+       __arginit __init; \
+       __arginit
+/* For assembly routines */
+#define __INIT         .section        ".text.init",#alloc,#execinstr
+#define __FINIT        .previous
+#define __INITDATA     .section        ".data.init",#alloc,#write
+#else
+#define        __init
+#define __initdata
+#define __initfunc(__arginit) __arginit
+/* For assembly routines */
+#define __INIT
+#define __FINIT
+#define __INITDATA
+#endif
+#endif
+
+#endif
index 01f81c2596d13872c076671e09bf9e91791fe02c..3afb4f3bf10cb4e3f287586aa4950fdffa585e0d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.3 1997/03/03 16:51:53 jj Exp $ */
+/* $Id: io.h,v 1.5 1997/03/18 18:04:00 jj Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
@@ -7,12 +7,88 @@
 #include <asm/page.h>      /* IO address mapping routines need this */
 #include <asm/system.h>
 
-extern void sparc_ultra_mapioaddr   (unsigned long physaddr, unsigned long virt_addr, int bus, int rdonly);
+extern __inline__ unsigned long inb_local(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ void outb_local(unsigned char b, unsigned long addr)
+{
+       return;
+}
+
+extern __inline__ unsigned long inb(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ unsigned long inw(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ unsigned long inl(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ void outb(unsigned char b, unsigned long addr)
+{
+       return;
+}
+
+extern __inline__ void outw(unsigned short b, unsigned long addr)
+{
+       return;
+}
+
+extern __inline__ void outl(unsigned int b, unsigned long addr)
+{
+       return;
+}
+
+/*
+ * Memory functions
+ */
+extern __inline__ unsigned long readb(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ unsigned long readw(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ unsigned long readl(unsigned long addr)
+{
+       return 0;
+}
+
+extern __inline__ void writeb(unsigned short b, unsigned long addr)
+{
+       return;
+}
+
+extern __inline__ void writew(unsigned short b, unsigned long addr)
+{
+       return;
+}
+
+extern __inline__ void writel(unsigned int b, unsigned long addr)
+{
+       return;
+}
+
+#define inb_p inb
+#define outb_p outb
+
+extern void sparc_ultra_mapioaddr   (unsigned long physaddr, unsigned long virt_addr, int rdonly);
 extern void sparc_ultra_unmapioaddr (unsigned long virt_addr);
 
-extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr, int bus, int rdonly)
+extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr, int rdonly)
 {
-       sparc_ultra_mapioaddr (physaddr, virt_addr, bus, rdonly);
+       sparc_ultra_mapioaddr (physaddr, virt_addr, rdonly);
        return;
 }
 
@@ -22,7 +98,7 @@ extern __inline__ void unmapioaddr(unsigned long virt_addr)
        return;
 }
 
-extern void *sparc_alloc_io (void *, void *, int, char *, int, int);
+extern void *sparc_alloc_io (void *, void *, int, char *, unsigned, int);
 extern void sparc_free_io (void *, int);
 extern void *sparc_dvma_malloc (int, char *);
 
index 427a8c7ea6be5be8a38fd9f1f6032d76be01b399..3cf496bdf399a44b7fcfde6b9d86a4cb73587f2a 100644 (file)
@@ -1,4 +1,3 @@
-/* $Id: kbio.h,v 1.1 1996/12/02 00:06:41 davem Exp $ */
 #ifndef __LINUX_KBIO_H
 #define __LINUX_KBIO_H
 
@@ -33,6 +32,18 @@ enum {
 /* Get keyboard leds */
 #define KIOCGLED    _IOR('k', 15, unsigned char)
 
+/* Used by KIOC[GS]RATE */
+struct kbd_rate {
+       unsigned char delay;    /* Delay in Hz before first repeat.     */
+       unsigned char rate;     /* In characters per second (0..50).    */
+};
+
+/* Set keyboard rate */
+#define KIOCSRATE   _IOW('k', 40, struct kbd_rate)
+
+/* Get keyboard rate */
+#define KIOCGRATE   _IOW('k', 41, struct kbd_rate)
+
 /* Top bit records if the key is up or down */
 #define KBD_UP      0x80
 
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
new file mode 100644 (file)
index 0000000..75d3b9c
--- /dev/null
@@ -0,0 +1,79 @@
+/* $Id: kdebug.h,v 1.1 1997/03/14 21:05:34 jj Exp $
+ * kdebug.h:  Defines and definitions for debugging the Linux kernel
+ *            under various kernel debuggers.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC64_KDEBUG_H
+#define _SPARC64_KDEBUG_H
+
+#include <asm/openprom.h>
+
+/* The debugger lives in 1MB of virtual address space right underneath
+ * the boot prom.
+ */
+
+#define DEBUG_FIRSTVADDR       0xffc00000
+#define DEBUG_LASTVADDR        LINUX_OPPROM_BEGVM
+
+/* Breakpoints are enter through trap table entry 126.  So in sparc assembly
+ * if you want to drop into the debugger you do:
+ *
+ * t DEBUG_BP_TRAP
+ */
+
+#define DEBUG_BP_TRAP     126
+
+#ifndef __ASSEMBLY__
+/* The debug vector is passed in %o1 at boot time.  It is a pointer to
+ * a structure in the debuggers address space.  Here is its format.
+ */
+
+typedef unsigned int (*debugger_funct)(void);
+
+struct kernel_debug {
+       /* First the entry point into the debugger.  You jump here
+        * to give control over to the debugger.
+        */
+       unsigned long kdebug_entry;
+       unsigned long kdebug_trapme;   /* Figure out later... */
+       /* The following is the number of pages that the debugger has
+        * taken from to total pool.
+        */
+       unsigned long *kdebug_stolen_pages;
+       /* Ok, after you remap yourself and/or change the trap table
+        * from what you were left with at boot time you have to call
+        * this synchronization function so the debugger can check out
+        * what you have done.
+        */
+       debugger_funct teach_debugger;
+}; /* I think that is it... */
+
+extern struct kernel_debug *linux_dbvec;
+
+/* Use this macro in C-code to enter the debugger. */
+extern __inline__ void sp_enter_debugger(void)
+{
+       __asm__ __volatile__("jmpl %0, %%o7\n\t"
+                            "nop\n\t" : :
+                            "r" (linux_dbvec) : "o7", "memory");
+}
+
+#define SP_ENTER_DEBUGGER do { \
+            if((linux_dbvec!=0) && ((*(short *)linux_dbvec)!=-1)) \
+              sp_enter_debugger(); \
+                      } while(0)
+
+#endif /* !(__ASSEMBLY__) */
+
+/* Some nice offset defines for assembler code. */
+#define KDEBUG_ENTRY_OFF    0x0
+#define KDEBUG_DUNNO_OFF    0x4
+#define KDEBUG_DUNNO2_OFF   0x8
+#define KDEBUG_TEACH_OFF    0xc
+
+/* ugh... */
+#define TRAP_TRACE(reg1, reg2) \
+     
+
+#endif /* !(_SPARC64_KDEBUG_H) */
diff --git a/include/asm-sparc64/machines.h b/include/asm-sparc64/machines.h
new file mode 100644 (file)
index 0000000..33d35ba
--- /dev/null
@@ -0,0 +1,69 @@
+/* $Id: machines.h,v 1.1 1997/03/14 21:05:37 jj Exp $
+ * machines.h:  Defines for taking apart the machine type value in the
+ *              idprom and determining the kind of machine we are on.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _SPARC64_MACHINES_H
+#define _SPARC64_MACHINES_H
+
+struct Sun_Machine_Models {
+       char *name;
+       unsigned char id_machtype;
+};
+
+/* Current number of machines we know about that has an IDPROM
+ * machtype entry including one entry for the 0x80 OBP machines.
+ */
+#define NUM_SUN_MACHINES   15
+
+extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
+
+/* The machine type in the idprom area looks like this:
+ *
+ * ---------------
+ * | ARCH | MACH |
+ * ---------------
+ *  7    4 3    0
+ *
+ * The ARCH field determines the architecture line (sun4, sun4c, etc).
+ * The MACH field determines the machine make within that architecture.
+ */
+
+#define SM_ARCH_MASK  0xf0
+#define SM_SUN4       0x20
+#define SM_SUN4C      0x50
+#define SM_SUN4M      0x70
+#define SM_SUN4M_OBP  0x80
+
+#define SM_TYP_MASK   0x0f
+/* Sun4 machines */
+#define SM_4_260      0x01    /* Sun 4/200 series */
+#define SM_4_110      0x02    /* Sun 4/100 series */
+#define SM_4_330      0x03    /* Sun 4/300 series */
+#define SM_4_470      0x04    /* Sun 4/400 series */
+
+/* Sun4c machines                Full Name              - PROM NAME */
+#define SM_4C_SS1     0x01    /* Sun4c SparcStation 1   - Sun 4/60  */
+#define SM_4C_IPC     0x02    /* Sun4c SparcStation IPC - Sun 4/40  */
+#define SM_4C_SS1PLUS 0x03    /* Sun4c SparcStation 1+  - Sun 4/65  */
+#define SM_4C_SLC     0x04    /* Sun4c SparcStation SLC - Sun 4/20  */
+#define SM_4C_SS2     0x05    /* Sun4c SparcStation 2   - Sun 4/75  */
+#define SM_4C_ELC     0x06    /* Sun4c SparcStation ELC - Sun 4/25  */
+#define SM_4C_IPX     0x07    /* Sun4c SparcStation IPX - Sun 4/50  */
+
+/* Sun4m machines, these predate the OpenBoot.  These values only mean
+ * something if the value in the ARCH field is SM_SUN4M, if it is
+ * SM_SUN4M_OBP then you have the following situation:
+ * 1) You either have a sun4d, a sun4e, or a recently made sun4m.
+ * 2) You have to consult OpenBoot to determine which machine this is.
+ */
+#define SM_4M_SS60    0x01    /* Sun4m SparcSystem 600                  */
+#define SM_4M_SS50    0x02    /* Sun4m SparcStation 10                  */
+#define SM_4M_SS40    0x03    /* Sun4m SparcStation 5                   */
+
+/* Sun4d machines -- N/A */
+/* Sun4e machines -- N/A */
+/* Sun4u machines -- N/A */
+
+#endif /* !(_SPARC64_MACHINES_H) */
index 4864e2ba9a5df8eb7e20a9aa9a0b0f4727fa58f6..00ad82bd9c359bcb2e2822e17eaa498cc2f418c3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.2 1997/02/25 12:40:41 jj Exp $ */
+/* $Id: openprom.h,v 1.3 1997/03/18 18:03:20 jj Exp $ */
 #ifndef __SPARC64_OPENPROM_H
 #define __SPARC64_OPENPROM_H
 
@@ -186,7 +186,7 @@ struct linux_nodeops {
 #define PROMINTR_MAX    15
 
 struct linux_prom_registers {
-       int which_io;         /* is this in OBIO space? */
+       unsigned which_io;         /* hi part of physical address */
        unsigned phys_addr;   /* The physical address of this register */
        int reg_size;         /* How many bytes does this register take up? */
 };
index 9bb273df4f4560d4e99b869e66393fb8f04ce744..09bc58426353b97093f2f9d301cde0eee42bd6b3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.4 1997/02/25 20:00:34 jj Exp $
+/* $Id: oplib.h,v 1.6 1997/03/18 18:01:30 jj Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -29,6 +29,9 @@ extern unsigned int prom_rev, prom_prev;
  */
 extern int prom_root_node;
 
+/* PROM stdin and stdout */
+extern int prom_stdin, prom_stdout;
+
 /* /chosen node of the prom device tree, this stays constant after
  * initialization is complete.
  */
@@ -107,7 +110,7 @@ extern void prom_cmdline(void);
 /* Enter the prom, with no chance of continuation for the stand-alone
  * which calls this.
  */
-extern void prom_halt(void);
+extern void prom_halt(void) __attribute__ ((noreturn));
 
 /* Set the PROM 'sync' callback function to the passed function pointer.
  * When the user gives the 'sync' command at the prom prompt while the
@@ -190,6 +193,16 @@ extern int prom_restartcpu(int cpunode);
 
 /* PROM device tree traversal functions... */
 
+#ifdef PROMLIB_INTERNAL
+
+/* Internal version of prom_getchild. */
+extern int __prom_getchild(int parent_node);
+
+/* Internal version of prom_getsibling. */
+extern int __prom_getsibling(int node);
+
+#endif
+
 /* Get the child node of the given node, or zero if no child exists. */
 extern int prom_getchild(int parent_node);
 
index 7649541269fefcdd2e72ee02a0a24a6b39f6a90d..d3ee824c4585d851adab6be5c235c28991888950 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.10 1997/03/03 16:51:54 jj Exp $
+/* $Id: pgtable.h,v 1.13 1997/03/13 16:25:05 jj Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
 #define __DIRTY_BITS   (_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W)
 #define __ACCESS_BITS  (_PAGE_ACCESSED | _PAGE_READ | _PAGE_R)
 
+/* David: Please FIXME these. I just define them somehow to get it compile. jj */
+#define PAGE_NONE      __pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_P | _PAGE_G | __ACCESS_BITS)
+#define PAGE_SHARED    __pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_G | __ACCESS_BITS | _PAGE_W | _PAGE_WRITE)
+#define PAGE_COPY      __pgprot (_PAGE_VALID | _PAGE_CACHE | __ACCESS_BITS)
+#define PAGE_READONLY  __pgprot (_PAGE_VALID | _PAGE_CACHE | __ACCESS_BITS)
+#define PAGE_KERNEL    __pgprot (_PAGE_VALID | _PAGE_CACHE | _PAGE_P | __ACCESS_BITS | __DIRTY_BITS)
+#define PAGE_INVALID   __pgprot (0)
+
 #define _PFN_MASK      _PAGE_PADDR
 
 #define _PAGE_CHG_MASK (_PFN_MASK | _PAGE_MODIFIED | _PAGE_ACCESSED)
 
-#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_CACHE)
-#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | __ACCESS_BITS | \
-                                _PAGE_WRITE | _PAGE_CACHE)
-#define PAGE_COPY      __pgprot(_PAGE_PRESENT | __ACCESS_BITS | _PAGE_CACHE)
-#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | __ACCESS_BITS | _PAGE_CACHE)
-#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_VALID | _PAGE_W| \
-                                _PAGE_CACHE | _PAGE_P | _PAGE_G)
+/* FIXME: Define this correctly to io page protection. Has to include side effects. */
+#define pg_iobits (_PAGE_VALID | _PAGE_P | __ACCESS_BITS | _PAGE_E)
 
 #define __P000 PAGE_NONE
 #define __P001 PAGE_READONLY
@@ -373,13 +376,13 @@ extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
        paddr = ((unsigned long) pgdir) - PAGE_OFFSET;
 
        if(tsk->mm == current->mm) {
-               __asm__ __volatile__("
-                       rdpr            %%pstate, %%g1
-                       wrpr            %%g1, %2, %%pstate
+               __asm__ __volatile__ ("
+                       rdpr            %%pstate, %%o4
+                       wrpr            %%o4, %1, %%pstate
                        mov             %0, %%g7
-                       wrpr            %%g1, 0x0, %%pstate
+                       wrpr            %%o4, 0x0, %%pstate
                " : : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
-                 : "g1", "g2");
+                 : "o4");
        }
 }
 
@@ -575,10 +578,43 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 { pte_t pte; pte_val(pte) = (type) | (offset << 8); return pte; }
 
+extern inline pte_t mk_pte_io(unsigned long page, pgprot_t prot, int space)
+/* FIXME. How is space added to the address??? */
+{ pte_t pte; pte_val(pte) = (page) | pgprot_val(prot); return pte; }
+
+
 #define SWP_TYPE(entry)                (((entry) & 0xff))
 #define SWP_OFFSET(entry)      ((entry) >> 8)
 #define SWP_ENTRY(type,offset) pte_val(mk_swap_pte((type),(offset)))
 
+struct ctx_list {
+       struct ctx_list *next;
+       struct ctx_list *prev;
+       unsigned int ctx_number;
+       struct mm_struct *ctx_mm;
+};
+
+extern struct ctx_list *ctx_list_pool;  /* Dynamically allocated */
+extern struct ctx_list ctx_free;        /* Head of free list */
+extern struct ctx_list ctx_used;        /* Head of used contexts list */
+
+#define NO_CONTEXT     -1
+
+extern __inline__ void remove_from_ctx_list(struct ctx_list *entry)
+{
+       entry->next->prev = entry->prev;
+       entry->prev->next = entry->next;
+}
+
+extern __inline__ void add_to_ctx_list(struct ctx_list *head, struct ctx_list *entry)
+{
+       entry->next = head;
+       (entry->prev = head->prev)->next = entry;
+       head->prev = entry;
+}
+#define add_to_free_ctxlist(entry) add_to_ctx_list(&ctx_free, entry)
+#define add_to_used_ctxlist(entry) add_to_ctx_list(&ctx_used, entry)
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
index 0bfe141c47940c507423cea378c0ba9ff7b57495..32da305f8c60915b4a65e17cd3b769f11790bf12 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.8 1997/03/04 16:27:33 jj Exp $
+/* $Id: processor.h,v 1.10 1997/03/14 21:05:39 jj Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -59,7 +59,7 @@ struct thread_struct {
        struct reg_window reg_window[NSWINS] __attribute__ ((aligned (16)));
        unsigned long rwbuf_stkptrs[NSWINS] __attribute__ ((aligned (8)));
        unsigned long w_saved;
-
+       
        /* Arch-specific task state flags, see below. */
        unsigned long flags;
 
@@ -69,6 +69,9 @@ struct thread_struct {
 
        struct sigstack sstk_info;
        int current_ds, new_signal;
+       
+       struct pt_regs *kregs;
+       
        struct exec core_exec;     /* just what it says. */
 };
 
@@ -90,7 +93,7 @@ struct thread_struct {
 /* FPU status, FPU qdepth, FPU queue */                                \
    0,          0,          { { 0, 0, }, },                             \
 /* user_globals */                                                     \
-   { 0, 0, 0, 0, 0, 0, 0, 0, 0 },                                      \
+   { 0, 0, 0, 0, 0, 0, 0, 0 },                                                 \
 /* ksp, kpc */                                                                 \
    0,   0,                                                             \
 /* reg_window */                                                       \
@@ -105,8 +108,8 @@ struct thread_struct {
    0,           0,                                                     \
 /* ex,     sstk_info, current_ds, */                                   \
    { 0, 0, }, USER_DS,                                                 \
-/* new_signal */                                                       \
-  0,                                                                   \
+/* new_signal, kregs */                                                        \
+  0,           0,                                                      \
 /* core_exec */                                                                \
 { 0, },                                                                        \
 }
index d1e01de0b44320bd63a390c8f74c6228b9c154e7..9cc4288084898dce94251ed6e30953271c4a81c0 100644 (file)
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
-#ifdef __SMP__
+#ifndef __SMP__
+#define lock_kernel()           do { } while(0)
+#define unlock_kernel()         do { } while(0)
+#else
 
 extern __inline__ __volatile__ unsigned char ldstub(volatile unsigned char *lock)
 {
index 4b597fefb43307fbeb41c96d5c6ea0f8db33e60d..c216fe6a76ad68665d37821f25b08b2d2e7c7d1b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: socket.h,v 1.1 1996/12/26 14:22:39 davem Exp $ */
+/* $Id: socket.h,v 1.2 1997/03/17 04:50:55 davem Exp $ */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
@@ -35,4 +35,9 @@
 #define SO_NO_CHECK    0x000b
 #define SO_PRIORITY    0x000c
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             0x000d
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       0x000e
+#define SO_SECURITY_ENCRYPTION_NETWORK         0x000f
+
 #endif /* _ASM_SOCKET_H */
index d3c8a31a37c3f3e1cb194c28b254c7f90cdeabd5..01389cf9d6bf089c8eb66a87680d7bd2dc03c700 100644 (file)
@@ -1,10 +1,38 @@
-/* $Id: system.h,v 1.4 1996/12/28 18:39:56 davem Exp $ */
+/* $Id: system.h,v 1.7 1997/03/18 18:02:41 jj Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 
+#define NCPUS  4       /* No SMP yet */
+
+#define EMPTY_PGT       (&empty_bad_page)
+#define EMPTY_PGE       (&empty_bad_page_table)
+
+#ifndef __ASSEMBLY__
+/*
+ * Sparc (general) CPU types
+ */
+enum sparc_cpu {
+  sun4        = 0x00,
+  sun4c       = 0x01,
+  sun4m       = 0x02,
+  sun4d       = 0x03,
+  sun4e       = 0x04,
+  sun4u       = 0x05, /* V8 ploos ploos */
+  sun_unknown = 0x06,
+  ap1000      = 0x07, /* almost a sun4m */
+};
+                  
+#define sparc_cpu_model sun4u
+                  
+
+extern unsigned long empty_bad_page;
+extern unsigned long empty_bad_page_table;
+extern unsigned long empty_zero_page;
+#endif
+
 #define setipl(__new_ipl) \
        __asm__ __volatile__("wrpr      %0, %%pil"  : : "r" (__new_ipl) : "memory")
 
@@ -112,6 +140,8 @@ static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
        return x;
 }
 
+extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC64_SYSTEM_H) */
index f56f0d159589a93e8186ffbbc8512ac479dd5b73..3d7c5c2f44ee067d3afd0c6f2a65f1ac5f3ff945 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.3 1996/12/31 22:35:49 davem Exp $ */
+/* $Id: termios.h,v 1.4 1997/03/14 21:05:26 jj Exp $ */
 #ifndef _SPARC64_TERMIOS_H
 #define _SPARC64_TERMIOS_H
 
@@ -87,7 +87,7 @@ struct winsize {
  * Translate a "termio" structure into a "termios". Ugh.
  */
 #define user_termio_to_kernel_termios(termios, termio) \
-do { \
+({ \
        unsigned short tmp; \
        get_user(tmp, &(termio)->c_iflag); \
        (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
@@ -98,7 +98,8 @@ do { \
        get_user(tmp, &(termio)->c_lflag); \
        (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
        copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-} while(0)
+       0; \
+})
 
 /*
  * Translate a "termios" structure into a "termio". Ugh.
@@ -106,7 +107,7 @@ do { \
  * Note the "fun" _VMIN overloading.
  */
 #define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
        put_user((termios)->c_iflag, &(termio)->c_iflag); \
        put_user((termios)->c_oflag, &(termio)->c_oflag); \
        put_user((termios)->c_cflag, &(termio)->c_cflag); \
@@ -117,10 +118,11 @@ do { \
                put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
                put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
        } \
-} while(0)
+       0; \
+})
 
 #define user_termios_to_kernel_termios(k, u) \
-do { \
+({ \
        get_user((k)->c_iflag, &(u)->c_iflag); \
        get_user((k)->c_oflag, &(u)->c_oflag); \
        get_user((k)->c_cflag, &(u)->c_cflag); \
@@ -134,10 +136,11 @@ do { \
                get_user((k)->c_cc[VMIN],  &(u)->c_cc[_VMIN]); \
                get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
        } \
-} while(0)
+       0; \
+})
 
 #define kernel_termios_to_user_termios(u, k) \
-do { \
+({ \
        put_user((k)->c_iflag, &(u)->c_iflag); \
        put_user((k)->c_oflag, &(u)->c_oflag); \
        put_user((k)->c_cflag, &(u)->c_cflag); \
@@ -151,7 +154,8 @@ do { \
                put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
                put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
        } \
-} while(0)
+       0; \
+})
 
 #endif /* __KERNEL__ */
 
index e858513afbdfb0c4d374521e953cef87915fb5c9..4929a125346346d00de9ddd29dbc4c32e93f3ea9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.6 1997/03/03 16:51:54 jj Exp $ */
+/* $Id: uaccess.h,v 1.8 1997/03/14 21:05:33 jj Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -36,7 +36,7 @@
  */
 #define __user_ok(addr,size) ((addr) < PAGE_OFFSET)
 #define __kernel_ok (get_fs() == KERNEL_DS)
-#define __access_ok(addr,size) (__user_ok((addr) & get_fs(),(size)))
+#define __access_ok(addr,size) (__user_ok(((unsigned long)(addr)) & get_fs(),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
 extern inline int verify_area(int type, const void * addr, unsigned long size)
@@ -312,8 +312,8 @@ if (copy_to_user(to,from,n)) \
 })
 
 #define __copy_to_user(to,from,n)              \
-       __copy_user((unsigned long)(to),        \
-                   (unsigned long)(from), n)
+       __copy_user((void *)(to),       \
+                   (void *)(from), n)
 
 #define __copy_to_user_ret(to,from,n,retval) ({ \
 if (__copy_to_user(to,from,n)) \
@@ -335,20 +335,36 @@ if (copy_from_user(to,from,n)) \
 })
 
 #define __copy_from_user(to,from,n)            \
-       __copy_user((unsigned long)(to),        \
-                   (unsigned long)(from), n)
+       __copy_user((void *)(to),       \
+                   (void *)(from), n)
 
 #define __copy_from_user_ret(to,from,n,retval) ({ \
 if (__copy_from_user(to,from,n)) \
        return retval; \
 })
 
-extern int __clear_user(unsigned long addr, int size);
+extern __inline__ __kernel_size_t __clear_user(void *addr, __kernel_size_t size)
+{
+  __kernel_size_t ret;
+  __asm__ __volatile__ ("
+       .section __ex_table,#alloc
+       .align 4
+       .word 1f,3
+       .previous
+1:
+       mov %2, %%o1
+       call __bzero
+        mov %1, %%o0
+       mov %%o0, %0
+       " : "=r" (ret) : "r" (addr), "r" (size) :
+       "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+  return ret;
+}
 
 #define clear_user(addr,n) ({ \
-unsigned long __clear_addr = (unsigned long) (addr); \
-int __clear_size = (int) (n); \
-int __clear_res; \
+void *__clear_addr = (void *) (addr); \
+__kernel_size_t __clear_size = (__kernel_size_t) (n); \
+__kernel_size_t __clear_res; \
 if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
 __clear_res = __clear_user(__clear_addr, __clear_size); \
 } else __clear_res = __clear_size; \
index f51ae6c8c1baef81001c5ff0e0df29e56b2bc29a..0bd6372d5b1a641e2f132962d31cdd4f735b8255 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.1 1996/12/26 14:22:43 davem Exp $ */
+/* $Id: unistd.h,v 1.2 1997/03/18 18:00:26 jj Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
 type name(void) \
 { \
 long __res; \
-__asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \
-                     "t 0x10\n\t" \
-                     "bcc 1f\n\t" \
-                     "or %%g0, %%o0, %0\n\t" \
+__asm__ __volatile__ ("mov %0, %%g1\n\t" \
+                     "t 0x11\n\t" \
                      "sub %%g0, %%o0, %0\n\t" \
-                     "1:\n\t" \
+                     "movcc %%xcc, %%o0, %0\n\t" \
                      : "=r" (__res)\
                      : "0" (__NR_##name) \
                      : "g1", "o0"); \
@@ -296,13 +294,11 @@ return -1; \
 type name(type1 arg1) \
 { \
 long __res; \
-__asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \
-                     "or %%g0, %1, %%o0\n\t" \
-                     "t 0x10\n\t" \
-                     "bcc 1f\n\t" \
-                     "or %%g0, %%o0, %0\n\t" \
+__asm__ __volatile__ ("mov %0, %%g1\n\t" \
+                     "mov %1, %%o0\n\t" \
+                     "t 0x11\n\t" \
                      "sub %%g0, %%o0, %0\n\t" \
-                     "1:\n\t" \
+                     "movcc %%xcc, %%o0, %0\n\t" \
                      : "=r" (__res), "=r" ((long)(arg1)) \
                      : "0" (__NR_##name),"1" ((long)(arg1)) \
                      : "g1", "o0"); \
@@ -316,14 +312,12 @@ return -1; \
 type name(type1 arg1,type2 arg2) \
 { \
 long __res; \
-__asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \
-                     "or %%g0, %1, %%o0\n\t" \
-                     "or %%g0, %2, %%o1\n\t" \
-                     "t 0x10\n\t" \
-                     "bcc 1f\n\t" \
-                     "or %%g0, %%o0, %0\n\t" \
+__asm__ __volatile__ ("mov %0, %%g1\n\t" \
+                     "mov %1, %%o0\n\t" \
+                     "mov %2, %%o1\n\t" \
+                     "t 0x11\n\t" \
                      "sub %%g0, %%o0, %0\n\t" \
-                     "1:\n\t" \
+                     "movcc %%xcc, %%o0, %0\n\t" \
                      : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)) \
                      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)) \
                      : "g1", "o0", "o1"); \
@@ -337,15 +331,13 @@ return -1; \
 type name(type1 arg1,type2 arg2,type3 arg3) \
 { \
 long __res; \
-__asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \
-                     "or %%g0, %1, %%o0\n\t" \
-                     "or %%g0, %2, %%o1\n\t" \
-                     "or %%g0, %3, %%o2\n\t" \
-                     "t 0x10\n\t" \
-                     "bcc 1f\n\t" \
-                     "or %%g0, %%o0, %0\n\t" \
+__asm__ __volatile__ ("mov %0, %%g1\n\t" \
+                     "mov %1, %%o0\n\t" \
+                     "mov %2, %%o1\n\t" \
+                     "mov %3, %%o2\n\t" \
+                     "t 0x11\n\t" \
                      "sub %%g0, %%o0, %0\n\t" \
-                     "1:\n\t" \
+                     "movcc %%xcc, %%o0, %0\n\t" \
                      : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                        "=r" ((long)(arg3)) \
                      : "0" (__NR_##name), "1" ((long)(arg1)), "2" ((long)(arg2)), \
@@ -361,16 +353,14 @@ return -1; \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
 { \
 long __res; \
-__asm__ __volatile__ ("or %%g0, %0, %%g1\n\t" \
-                     "or %%g0, %1, %%o0\n\t" \
-                     "or %%g0, %2, %%o1\n\t" \
-                     "or %%g0, %3, %%o2\n\t" \
-                     "or %%g0, %4, %%o3\n\t" \
-                     "t 0x10\n\t" \
-                     "bcc 1f\n\t" \
-                     "or %%g0, %%o0, %0\n\t" \
+__asm__ __volatile__ ("mov %0, %%g1\n\t" \
+                     "mov %1, %%o0\n\t" \
+                     "mov %2, %%o1\n\t" \
+                     "mov %3, %%o2\n\t" \
+                     "mov %4, %%o3\n\t" \
+                     "t 0x11\n\t" \
                      "sub %%g0,%%o0, %0\n\t" \
-                     "1:\n\t" \
+                     "movcc %%xcc, %%o0, %0\n\t" \
                      : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \
                        "=r" ((long)(arg3)), "=r" ((long)(arg4)) \
                      : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \
@@ -388,17 +378,15 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
 { \
       long __res; \
 \
-__asm__ __volatile__ ("or %%g0, %1, %%o0\n\t" \
-                     "or %%g0, %2, %%o1\n\t" \
-                     "or %%g0, %3, %%o2\n\t" \
-                     "or %%g0, %4, %%o3\n\t" \
-                     "or %%g0, %5, %%o4\n\t" \
-                     "or %%g0, %6, %%g1\n\t" \
-                     "t 0x10\n\t" \
-                     "bcc 1f\n\t" \
-                     "or %%g0, %%o0, %0\n\t" \
+__asm__ __volatile__ ("mov %1, %%o0\n\t" \
+                     "mov %2, %%o1\n\t" \
+                     "mov %3, %%o2\n\t" \
+                     "mov %4, %%o3\n\t" \
+                     "mov %5, %%o4\n\t" \
+                     "mov %6, %%g1\n\t" \
+                     "t 0x11\n\t" \
                      "sub %%g0, %%o0, %0\n\t" \
-                     "1:\n\t" \
+                     "movcc %%xcc, %%o0, %0\n\t" \
                      : "=r" (__res) \
                      : "r" ((long)(arg1)),"r" ((long)(arg2)), \
                        "r" ((long)(arg3)),"r" ((long)(arg4)),"r" ((long)(arg5)), \
@@ -461,16 +449,15 @@ static __inline__ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned lo
                           "mov %1, %%g1\n\t"
                           "mov %2, %%o0\n\t"    /* Clone flags. */
                           "mov 0, %%o1\n\t"     /* usp arg == 0 */
-                          "t 0x10\n\t"          /* Linux/Sparc clone(). */
-                          "cmp %%o1, 0\n\t"
-                          "be 1f\n\t"           /* The parent, just return. */
-                          " nop\n\t"            /* Delay slot. */
+                          "t 0x11\n\t"          /* Linux/Sparc clone(). */
+                          "brz,a,pn %%o1, 1f\n\t"           /* The parent, just return. */
+                          " mov %%o0, %0\n\t"
                           "jmpl %%g2, %%o7\n\t" /* Call the function. */
                           " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */
                           "mov %3, %%g1\n\t"
-                          "t 0x10\n\t"          /* Linux/Sparc exit(). */
+                          "t 0x11\n\t"          /* Linux/Sparc exit(). */
                           /* Notreached by child. */
-                          "1: mov %%o0, %0\n\t" :
+                          "1:" :
                           "=r" (retval) :
                           "i" (__NR_clone), "r" (flags | CLONE_VM),
                           "i" (__NR_exit),  "r" (fn), "r" (arg) :
diff --git a/include/asm-sparc64/vaddrs.h b/include/asm-sparc64/vaddrs.h
new file mode 100644 (file)
index 0000000..567ba78
--- /dev/null
@@ -0,0 +1,27 @@
+/* $Id: vaddrs.h,v 1.1 1997/03/18 18:03:43 jj Exp $ */
+#ifndef _SPARC64_VADDRS_H
+#define _SPARC64_VADDRS_H
+
+#include <asm/head.h>
+
+/* asm-sparc64/vaddrs.h:  Here will be define the virtual addresses at
+ *                      which important I/O addresses will be mapped.
+ *                      For instance the timer register virtual address
+ *                      is defined here.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* I can see only one reason why we should have statically defined
+ * mappings for devices and is the speedup improvements of not loading
+ * a pointer and then the value in the assembly code
+ */
+#define  IOBASE_VADDR   0xfffffd0000000000ULL  /* Base for mapping pages */
+#define  IOBASE_LEN     0x0000008000000000ULL  /* Length of the IO area */
+#define  IOBASE_END     0xfffffd8000000000ULL
+#define  DVMA_VADDR     0xfffffd8000000000ULL  /* Base area of the DVMA on suns */
+#define  DVMA_LEN       0x0000004000000000ULL  /* Size of the DVMA address space */
+#define  DVMA_END       0xfffffdc000000000ULL
+
+#endif /* !(_SPARC_VADDRS_H) */
+
index 845ae77c012451e2b06f3cc841457617bf9e72b1..412f0c1c3a799ba1d883071244e3be680674792e 100644 (file)
@@ -440,15 +440,19 @@ static void end_request(int uptodate) {
        struct request *req = CURRENT;
 #endif /* IDE_DRIVER */
        struct buffer_head * bh;
+       int nsect;
 
        req->errors = 0;
        if (!uptodate) {
                printk("end_request: I/O error, dev %s, sector %lu\n",
                        kdevname(req->rq_dev), req->sector);
-               req->nr_sectors--;
-               req->nr_sectors &= ~SECTOR_MASK;
-               req->sector += (BLOCK_SIZE / 512);
-               req->sector &= ~SECTOR_MASK;            
+               if ((bh = req->bh) != NULL) {
+                       nsect = bh->b_size >> 9;
+                       req->nr_sectors--;
+                       req->nr_sectors &= ~(nsect - 1);
+                       req->sector += nsect;
+                       req->sector &= ~(nsect - 1);
+               }
        }
 
        if ((bh = req->bh) != NULL) {
index 549db65fec9ba95a5ad3707a7f6f8a2df5b9b037..6c556ab673a81e0ec2e2e9c554707dd6a68ede29 100644 (file)
@@ -179,7 +179,19 @@ typedef struct {
 #define        R_SPARC_JMP_SLOT        21
 #define        R_SPARC_RELATIVE        22
 #define        R_SPARC_UA32            23
-#define        R_SPARC_NUM             24
+#define R_SPARC_PLT32          24
+#define R_SPARC_HIPLT22                25
+#define R_SPARC_LOPLT10                26
+#define R_SPARC_PCPLT32                27
+#define R_SPARC_PCPLT22                28
+#define R_SPARC_PCPLT10                29
+#define R_SPARC_10             30
+#define R_SPARC_11             31
+#define R_SPARC_WDISP16                40
+#define R_SPARC_WDISP19                41
+#define R_SPARC_7              43
+#define R_SPARC_5              44
+#define R_SPARC_6              45
 
 /*
  * 68k ELF relocation types
index 59da08849b920c1bc6e97c9600f1953e01c8ecd7..e0a3ab3c577920df11ac68d430165687fcc5422b 100644 (file)
@@ -35,7 +35,8 @@ extern int            eth_rebuild_header(struct sk_buff *skb);
 extern unsigned short  eth_type_trans(struct sk_buff *skb, struct device *dev);
 extern void            eth_header_cache_update(struct hh_cache *hh, struct device *dev,
                                                unsigned char * haddr);
-extern int             eth_header_cache(struct dst_entry *dst, struct dst_entry *neigh,
+extern int             eth_header_cache(struct dst_entry *dst,
+                                        struct neighbour *neigh,
                                         struct hh_cache *hh);
 extern struct device   * init_etherdev(struct device *, int);
 
index e2d1f25e3c22a9d2a98f5585350831f85f9a15dd..1747f38116440cf8bd830052a3f5492ec614bc5e 100644 (file)
@@ -1,26 +1,29 @@
 #ifndef __LINUX_FIREWALL_H
 #define __LINUX_FIREWALL_H
 
+#include <linux/config.h>
+
 /*
  *     Definitions for loadable firewall modules
  */
 
-#define FW_BLOCK       0
-#define FW_ACCEPT      1
+#define FW_QUEUE       0
+#define FW_BLOCK       1
+#define FW_ACCEPT      2
 #define FW_REJECT      (-1)
-#define FW_REDIRECT    2
-#define FW_MASQUERADE  3
-#define FW_SKIP                4
+#define FW_REDIRECT    3
+#define FW_MASQUERADE  4
+#define FW_SKIP                5
 
 struct firewall_ops
 {
        struct firewall_ops *next;
        int (*fw_forward)(struct firewall_ops *this, int pf, 
-                       struct device *dev, void *phdr, void *arg);
+                       struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
        int (*fw_input)(struct firewall_ops *this, int pf, 
-                       struct device *dev, void *phdr, void *arg);
+                       struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
        int (*fw_output)(struct firewall_ops *this, int pf, 
-                       struct device *dev, void *phdr, void *arg);
+                       struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
        /* Data falling in the second 486 cache line isn't used directly
           during a firewall call and scan, only by insert/delete and other
           unusual cases
@@ -32,10 +35,27 @@ struct firewall_ops
 #ifdef __KERNEL__
 extern int register_firewall(int pf, struct firewall_ops *fw);
 extern int unregister_firewall(int pf, struct firewall_ops *fw);
-extern int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg);
-extern int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg);
-extern int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg);
 extern void fwchain_init(void);
-#endif
+#ifdef CONFIG_FIREWALL
+extern int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+extern int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+extern int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
+#else
+extern __inline__ int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+       return FW_ACCEPT;
+}
+
+extern __inline__ int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+       return FW_ACCEPT;
+}
 
+extern __inline__ int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
+{
+       return FW_ACCEPT;
+}
+
+#endif
+#endif
 #endif
index 41f890817b7ba24445873335deff08d01dc7a845..0a6b9c735803abddcd28ff62b403bdf92f9bc86e 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef _HDLCDRV_H
 #define _HDLCDRV_H
 
+#include <linux/version.h>
 #include <linux/sockios.h>
 #include <linux/version.h>
 #if LINUX_VERSION_CODE < 0x20119
@@ -38,23 +39,32 @@ struct hdlcdrv_channel_params {
                       /* this just makes them send even if DCD is on */
 };     
 
-struct hdlcdrv_channel_state {
-       int ptt;
-       int dcd;
-       int ptt_keyed;
-#if LINUX_VERSION_CODE < 0x20119
-       struct enet_statistics stats;
-#else
-       struct net_device_stats stats;
+struct hdlcdrv_old_channel_state {
+       int ptt;
+       int dcd;
+       int ptt_keyed;
+#if LINUX_VERSION_CODE < 0x20100
+       struct enet_statistics stats;
 #endif
 };
 
+struct hdlcdrv_channel_state {
+       int ptt;
+       int dcd;
+       int ptt_keyed;
+       unsigned long tx_packets;
+       unsigned long tx_errors;
+       unsigned long rx_packets;
+       unsigned long rx_errors;
+};
+
 struct hdlcdrv_ioctl {
        int cmd;
        union {
                struct hdlcdrv_params mp;
                struct hdlcdrv_channel_params cp;
                struct hdlcdrv_channel_state cs;
+               struct hdlcdrv_old_channel_state ocs;
                unsigned int calibrate;
                unsigned char bits;
                char modename[128];
@@ -72,8 +82,9 @@ struct hdlcdrv_ioctl {
 #define HDLCDRVCTL_MODEMPARMASK      2  /* not handled by hdlcdrv */
 #define HDLCDRVCTL_GETCHANNELPAR    10
 #define HDLCDRVCTL_SETCHANNELPAR    11
-#define HDLCDRVCTL_GETSTAT          20
+#define HDLCDRVCTL_OLDGETSTAT       20
 #define HDLCDRVCTL_CALIBRATE        21
+#define HDLCDRVCTL_GETSTAT          22
 
 /*
  * these are mainly for debugging purposes
index fb073e041070cd4ed92aaf47440ca3da0226a93b..a582e37b58bfed99d5b165bf15746aa40275f480 100644 (file)
@@ -3,21 +3,22 @@
 
 #include <asm/byteorder.h>
 
-struct icmpv6hdr {
+struct icmp6hdr {
 
-       __u8            type;
-       __u8            code;
-       __u16           checksum;
+       __u8            icmp6_type;
+       __u8            icmp6_code;
+       __u16           icmp6_cksum;
 
 
        union {
+               __u32                   un_data32[1];
+               __u16                   un_data16[2];
+               __u8                    un_data8[4];
+
                struct icmpv6_echo {
                        __u16           identifier;
                        __u16           sequence;
                } u_echo;
-               __u32                   pointer;
-               __u32                   mtu;
-               __u32                   unused;
 
                 struct icmpv6_nd_advt {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
@@ -53,34 +54,37 @@ struct icmpv6hdr {
                        __u16           rt_lifetime;
                 } u_nd_ra;
 
-       } u;
-
-#define icmp6_identifier       u.u_echo.identifier
-#define icmp6_sequence         u.u_echo.sequence
-#define icmp6_pointer          u.pointer
-#define icmp6_mtu              u.mtu
-#define icmp6_unused           u.unused
-#define icmp6_router           u.u_nd_advt.router
-#define icmp6_solicited                u.u_nd_advt.solicited
-#define icmp6_override         u.u_nd_advt.override
-#define icmp6_ndiscreserved    u.u_nd_advt.reserved
-#define icmp6_hop_limit                u.u_nd_ra.hop_limit
-#define icmp6_addrconf_managed u.u_nd_ra.managed
-#define icmp6_addrconf_other   u.u_nd_ra.other
-#define icmp6_rt_lifetime      u.u_nd_ra.rt_lifetime
+       } icmp6_dataun;
+
+#define icmp6_identifier       icmp6_dataun.u_echo.identifier
+#define icmp6_sequence         icmp6_dataun.u_echo.sequence
+#define icmp6_pointer          icmp6_dataun.un_data32[0]
+#define icmp6_mtu              icmp6_dataun.un_data32[0]
+#define icmp6_unused           icmp6_dataun.un_data32[0]
+#define icmp6_maxdelay         icmp6_dataun.un_data16[0]
+#define icmp6_router           icmp6_dataun.u_nd_advt.router
+#define icmp6_solicited                icmp6_dataun.u_nd_advt.solicited
+#define icmp6_override         icmp6_dataun.u_nd_advt.override
+#define icmp6_ndiscreserved    icmp6_dataun.u_nd_advt.reserved
+#define icmp6_hop_limit                icmp6_dataun.u_nd_ra.hop_limit
+#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
+#define icmp6_addrconf_other   icmp6_dataun.u_nd_ra.other
+#define icmp6_rt_lifetime      icmp6_dataun.u_nd_ra.rt_lifetime
 };
 
 
 #define ICMPV6_DEST_UNREACH            1
 #define ICMPV6_PKT_TOOBIG              2
-#define ICMPV6_TIME_EXCEEDED           3
-#define ICMPV6_PARAMETER_PROB          4
+#define ICMPV6_TIME_EXCEED             3
+#define ICMPV6_PARAMPROB               4
+
+#define ICMPV6_INFOMSG_MASK            0x80
 
 #define ICMPV6_ECHO_REQUEST            128
 #define ICMPV6_ECHO_REPLY              129
-#define ICMPV6_MEMBERSHIP_QUERY                130
-#define ICMPV6_MEMBERSHIP_REPORT               131
-#define ICMPV6_MEMBERSHIP_REDUCTION            132
+#define ICMPV6_MGM_QUERY               130
+#define ICMPV6_MGM_REPORT              131
+#define ICMPV6_MGM_REDUCTION           132
 
 /*
  *     Codes for Destination Unreachable
index 5383ed6f1ddc3fbeafc482387e5ab56685b8a068..0b77670e1323c71d9244e4d3c039a491fb4387ce 100644 (file)
@@ -33,7 +33,6 @@ enum {
   IPPROTO_IDP = 22,            /* XNS IDP protocol                     */
 
   IPPROTO_IPV6  = 41,          /* IPv6-in-IPv4 tunnelling              */
-  IPPROTO_ICMPV6 = 58,         /* ICMPv6                               */
 
   IPPROTO_RAW   = 255,         /* Raw IP packets                       */
   IPPROTO_MAX
index 23552fb32ba7fc0a6f3457c76870f4ea1532255a..9a6954c2943ef894c3030c528fa2dab3200ff4e9 100644 (file)
@@ -87,6 +87,18 @@ struct ipv6_mreq {
 #define IPV6_PRIORITY_14               0x0e00
 #define IPV6_PRIORITY_15               0x0f00
 
+/*
+ *     IPV6 extension headers
+ */
+#define IPPROTO_HOPOPTS                0       /* IPv6 hop-by-hop options      */
+#define IPPROTO_ROUTING                43      /* IPv6 routing header          */
+#define IPPROTO_FRAGMENT       44      /* IPv6 fragmentation header    */
+#define IPPROTO_ESP            50      /* encapsulating security payload */
+#define IPPROTO_AH             51      /* authentication header        */
+#define IPPROTO_ICMPV6         58      /* ICMPv6                       */
+#define IPPROTO_NONE           59      /* IPv6 no next header          */
+#define IPPROTO_DSTOPTS                60      /* IPv6 destination options     */
+
 /*
  *     IPV6 socket options
  */
index a5d4b04e0aa6f44f690bc89cd25cf33214e3d202..4c9a8495bd955cf531f4307ca3aa41aadd033b4d 100644 (file)
  * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
  */
 
-#ifndef __init
-#if (defined (__svr4__) || defined (__ELF__)) && !defined (MODULE)
-#define __init __attribute__ ((__section__ (".text.init")))
-#define __initdata __attribute__ ((__section__ (".data.init")))
-#define __initfunc(__arginit) \
-       __arginit __init; \
-       __arginit
-/* For assembly routines */
-#define __INIT         .section        ".text.init",#alloc,#execinstr
-#define __FINIT        .previous
-#define __INITDATA     .section        ".data.init",#alloc,#write
-#else
-#define        __init
-#define __initdata
-#define __initfunc(__arginit) __arginit
-/* For assembly routines */
-#define __INIT
-#define __FINIT
-#define __INITDATA
-#endif
-#endif
+#include <asm/init.h>
 
 #endif
index 9c32356f339aaa24b6c0452a59c42738e4d57ce8..cd7d1b896edfc08471788c58e1cc716e8da8ef0d 100644 (file)
@@ -16,6 +16,7 @@ struct irqaction {
 };
 
 extern atomic_t intr_count;
+extern volatile unsigned char bh_running;
 
 extern int bh_mask_count[32];
 extern unsigned long bh_active;
@@ -76,8 +77,9 @@ extern inline void enable_bh(int nr)
  */
 extern inline void start_bh_atomic(void)
 {
+       cli();
        atomic_inc(&intr_count);
-       barrier();
+       sti();
 }
 
 extern inline void end_bh_atomic(void)
index 0edaf80c7becfd8d11df9caf76b9d3aa54693aad..ee8a0bb62b96d3167358e328cc8c286cd1d49f68 100644 (file)
  * If you unload the driver, use release_region to free ports.
  */
 extern void reserve_setup(char *str, int *ints);
-extern int check_region(unsigned int from, unsigned int extent);
-extern void request_region(unsigned int from, unsigned int extent,const char *name);
-extern void release_region(unsigned int from, unsigned int extent);
+extern int check_region(unsigned long from, unsigned long extent);
+extern void request_region(unsigned long from, unsigned long extent,const char *name);
+extern void release_region(unsigned long from, unsigned long extent);
 extern int get_ioport_list(char *);
 
 #ifdef __sparc__
-extern unsigned int occupy_region(unsigned int base, unsigned int end,
-                                 unsigned int num, unsigned int align,
+extern unsigned int occupy_region(unsigned long base, unsigned long end,
+                                 unsigned long num, unsigned int align,
                                  const char *name);
 #endif
 
diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h
new file mode 100644 (file)
index 0000000..b9d7bcc
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *     Definitions for the SECurity layer
+ *
+ *     Author:
+ *             Robert Muchsel <muchsel@acm.org>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IPSEC_H
+#define _LINUX_IPSEC_H
+
+#include <linux/config.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <linux/skbuff.h>
+
+/* Values for the set/getsockopt calls */
+
+/* These defines are compatible with NRL IPv6, however their semantics
+   is different */
+
+#define IPSEC_LEVEL_NONE       -1      /* send plaintext, accept any */
+#define IPSEC_LEVEL_DEFAULT    0       /* encrypt/authenticate if possible */
+                                       /* the default MUST be 0, because a */
+                                       /* socket is initialized with 0's */
+#define IPSEC_LEVEL_USE                1       /* use outbound, don't require inbound */
+#define IPSEC_LEVEL_REQUIRE    2       /* require both directions */
+#define IPSEC_LEVEL_UNIQUE     2       /* for compatibility only */
+
+#ifdef __KERNEL__
+
+/* skb bit flags set on packet input processing */
+
+#define RCV_SEC                        0x0f    /* options on receive */
+#define RCV_AUTH               0x01    /* was authenticated */
+#define RCV_CRYPT              0x02    /* was encrypted */
+#define RCV_TUNNEL             0x04    /* was tunneled */
+#define SND_SEC                        0xf0    /* options on send, these are */
+#define SND_AUTH               0x10    /* currently unused */
+#define SND_CRYPT              0x20
+#define SND_TUNNEL             0x40
+
+/*
+ *     FIXME: ignores network encryption for now..
+ */
+#ifdef CONFIG_NET_SECURITY
+extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+{
+       return ((sk->authentication < IPSEC_LEVEL_REQUIRE) ||
+               (skb->security & RCV_AUTH)) &&
+               ((sk->encryption < IPSEC_LEVEL_REQUIRE) ||
+               (skb->security & RCV_CRYPT));
+}
+
+#else
+
+extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+{
+       return 1;
+}
+#endif /* CONFIG */
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_IPSEC_H */
index 6f5fa66b66fafe3514d892906a6651a6a31fedbe..97e63e3621afbe01743a4491353290da7dc8b590 100644 (file)
 #ifndef _LINUX_IPV6_ROUTE_H
 #define _LINUX_IPV6_ROUTE_H
 
-#define RTI_DEVRT      0x00010000      /* route lookup, dev must match */
-#define RTI_ALLONLINK  0x00020000      /* all destinations on link     */
-#define RTI_DCACHE     RTF_DCACHE      /* rt6_info is a dcache entry   */
-#define RTI_INVALID    RTF_INVALID     /* invalid route/dcache entry   */
 
-#define RTI_DYNAMIC    RTF_DYNAMIC     /* rt6_info created dynamicly   */
-#define RTI_GATEWAY    RTF_GATEWAY
-#define RTI_DYNMOD     RTF_MODIFIED    /* more specific route may exist*/
+#define RTF_DEFAULT    0x00010000      /* default - learned via ND     */
+#define RTF_ALLONLINK  0x00020000      /* fallback, no routers on link */
+#define RTF_ADDRCONF   0x00040000      /* addrconf route - RA          */
 
-#define DCF_PMTU       RTF_MSS         /* dest cache has valid PMTU    */
-#define DCF_INVALID    RTF_INVALID
+#define RTF_LINKRT     0x00100000      /* link specific - device match */
+#define RTF_NONEXTHOP  0x00200000      /* route with no nexthop        */
+
+#define RTF_CACHE      0x01000000      /* cache entry                  */
+#define RTF_FLOW       0x02000000      /* flow significant route       */
+#define RTF_POLICY     0x04000000      /* policy route                 */
 
 struct in6_rtmsg {
        struct in6_addr         rtmsg_dst;
+       struct in6_addr         rtmsg_src;
        struct in6_addr         rtmsg_gateway;
        __u32                   rtmsg_type;
-       __u16                   rtmsg_prefixlen;
-       __u16                   rtmsg_metric;
+       __u16                   rtmsg_dst_len;
+       __u16                   rtmsg_src_len;
+       __u32                   rtmsg_metric;
        unsigned long           rtmsg_info;
         __u32                  rtmsg_flags;
        int                     rtmsg_ifindex;
index 0877bd332075d24dabb82ef86b3f98a1995a93c7..c0dc052b2e8cb7203fa88dbcea1e8d29b7ece794 100644 (file)
 #define MRT_DEL_MFC    (MRT_BASE+5)    /* Delete a multicast forwarding entry  */
 #define MRT_VERSION    (MRT_BASE+6)    /* Get the kernel multicast version     */
 #define MRT_ASSERT     (MRT_BASE+7)    /* Activate PIM assert mode             */
+#define MRT_PIM                (MRT_BASE+8)    /* enable PIM code      */
 
 #define SIOCGETVIFCNT  SIOCPROTOPRIVATE        /* IP protocol privates */
 #define SIOCGETSGCNT   (SIOCPROTOPRIVATE+1)
+#define SIOCGETRPF     (SIOCPROTOPRIVATE+2)
 
 #define MAXVIFS                32      
 typedef unsigned long vifbitmap_t;     /* User mode code depends on this lot */
@@ -56,10 +58,18 @@ struct vifctl {
 };
 
 #define VIFF_TUNNEL    0x1             /* IPIP tunnel */
-#define VIFF_SRCRT     0x02            /* NI */
+#define VIFF_SRCRT     0x2             /* NI */
+
+
+/* PIM Vif Flags */
+#define VIFF_DR                 0x0010          /* designated router    */
+#define VIFF_NOMRT              0x0020          /* no neighbor on vif   */
+#define VIFF_DOWN               0x0040          /* interface is down    */
+#define VIFF_DISABLED           0x0080          /* disabled interafce   */
+#define VIFF_REGISTER           0x00A0          /* MIssing cap@di.fc.ul.pt */
 
 /*
- *     Cache manipulation structures for mrouted
+ *     Cache manipulation structures for mrouted and PIMd
  */
  
 struct mfcctl
@@ -68,6 +78,10 @@ struct mfcctl
        struct in_addr mfcc_mcastgrp;           /* Group in question    */
        vifi_t  mfcc_parent;                    /* Where it arrived     */
        unsigned char mfcc_ttls[MAXVIFS];       /* Where it is going    */
+       unsigned int mfcc_pkt_cnt;              /* pkt count for src-grp */
+       unsigned int mfcc_byte_cnt;
+       unsigned int mfcc_wrong_if;
+       int          mfcc_expire;
 };
 
 /* 
@@ -96,6 +110,16 @@ struct sioc_vif_req
        unsigned long obytes;   /* Out bytes */
 };
 
+/*
+ *     To get RPF from unicast routing table (PIM: cap@di.fc.ul.pt)
+ */
+struct sioc_rpf_req
+{
+       unsigned long   source;        /* Source address */
+       unsigned long   rpfneighbor;   /* RPF */
+        vifi_t  iif;                  /* Incoming Interface */
+};
+
 /*
  *     This is the format the mroute daemon expects to see IGMP control
  *     data. Magically happens to be like an IP packet as per the original
@@ -138,6 +162,7 @@ struct vif_device
        unsigned char   threshold;              /* TTL threshold                */
        unsigned short  flags;                  /* Control flags                */
        unsigned long   local,remote;           /* Addresses(remote for tunnels)*/
+       unsigned long   uptime;
 };
 
 struct mfc_cache 
@@ -153,6 +178,8 @@ struct mfc_cache
        unsigned mfc_last_assert;
        int mfc_minvif;
        int mfc_maxvif;
+       unsigned long uptime;
+       unsigned long expire;
        unsigned long mfc_bytes;
        unsigned long mfc_pkt;
        unsigned long mfc_wrong_if;
@@ -180,7 +207,8 @@ struct mfc_cache
  *     Pseudo messages used by mrouted
  */
 
-#define IGMPMSG_NOCACHE                1               /* Kernel cache fill request to mrouted */
+#define IGMPMSG_NOCACHE                1               /* Kern cache fill request to mrouted */
 #define IGMPMSG_WRONGVIF       2               /* For PIM assert processing (unused) */
+#define IGMPMSG_WHOLEPKT       3               /* For PIM Register processing */
 
 #endif
index 260dc8ac52f65b509529210d96a15ede100e0858..e180ab00f95fa9d0f66050bdcc01ad0901c5dc10 100644 (file)
@@ -108,16 +108,24 @@ struct proto_ops {
   int   (*recvmsg)     (struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
 };
 
-struct net_proto_family {
+struct net_proto_family 
+{
        int     family;
        int     (*create)(struct socket *sock, int protocol);
+       /* These are counters for the number of different methods of
+          each we support */
+       short   authentication;
+       short   encryption;
+       short   encrypt_net;
 };
 
-struct net_proto {
+struct net_proto 
+{
        const char *name;               /* Protocol name */
        void (*init_func)(struct net_proto *);  /* Bootstrap */
 };
 
+extern struct net_proto_family *net_families[];
 extern int     sock_wake_async(struct socket *sk, int how);
 extern int     sock_register(struct net_proto_family *fam);
 extern int     sock_unregister(int family);
index 9e0beacc7d3ee3bbbe89ddff705b9673671f1731..5d164c98d418233c685763b79a9cbd0eb453e12c 100644 (file)
@@ -69,6 +69,8 @@
 #define IFF_IP_MASK_OK 2
 #define IFF_IP_BRD_OK  4
 
+struct neighbour;
+
 /*
  *     We tag multicasts with these structures.
  */
@@ -264,7 +266,7 @@ struct device
                                              struct ifmap *map);
 #define HAVE_HEADER_CACHE
        int                     (*hard_header_cache)(struct dst_entry *dst,
-                                                    struct dst_entry *neigh,
+                                                    struct neighbour *neigh,
                                                     struct hh_cache *hh);
        void                    (*header_cache_update)(struct hh_cache *hh,
                                                       struct device *dev,
index 4ac590f0296a97a6047bcf943cc0be2e978fcb09..16f7a582a606fe400e3492807d0fe614eaee5391 100644 (file)
@@ -99,7 +99,9 @@ extern __inline__ int notifier_call_chain(struct notifier_block **n, unsigned lo
 #define NETDEV_CHANGEADDR      0x0008
 
 #define SYS_DOWN       0x0001  /* Notify of system down */
+#define SYS_RESTART    SYS_DOWN
 #define SYS_HALT       0x0002  /* Notify of system halt */
+#define SYS_POWER_OFF  0x0003  /* Notify of system power off */
 
 /*
  *     Publically visible notifier objects
diff --git a/include/linux/pi2.h b/include/linux/pi2.h
new file mode 100644 (file)
index 0000000..1740cc0
--- /dev/null
@@ -0,0 +1,130 @@
+
+#define DMA_BUFF_SIZE 2200
+
+#define ON 1
+#define OFF 0
+
+
+/* Register offset info, specific to the PI
+ * E.g., to read the data port on channel A, use
+ *  inportb(pichan[dev].base + CHANA + DATA)
+ */
+#define CHANB   0   /* Base of channel B regs */
+#define CHANA   2   /* Base of channel A regs */
+
+/* 8530 ports on each channel */
+#define CTL 0
+#define DATA    1
+
+#define DMAEN   0x4 /* Offset off DMA Enable register */
+
+/* Timer chip offsets */
+#define TMR0    0x8 /* Offset of timer 0 register */
+#define TMR1    0x9 /* Offset of timer 1 register */
+#define TMR2    0xA /* Offset of timer 2 register */
+#define TMRCMD  0xB /* Offset of timer command register */
+
+/* Timer chip equates */
+#define SC0 0x00 /* Select counter 0 */
+#define SC1 0x40 /* Select counter 1 */
+#define SC2 0x80 /* Select counter 2 */
+#define CLATCH  0x00 /* Counter latching operation */
+#define MSB 0x20 /* Read/load MSB only */
+#define LSB 0x10 /* Read/load LSB only */
+#define LSB_MSB 0x30 /* Read/load LSB, then MSB */
+#define MODE0   0x00 /* Interrupt on terminal count */
+#define MODE1   0x02 /* Programmable one shot */
+#define MODE2   0x04 /* Rate generator */
+#define MODE3   0x06 /* Square wave rate generator */
+#define MODE4   0x08 /* Software triggered strobe */
+#define MODE5   0x0a /* Hardware triggered strobe */
+#define BCD 0x01 /* BCD counter */
+
+/* DMA controller registers */
+#define DMA_STAT    8   /* DMA controller status register */
+#define DMA_CMD     8   /* DMA controller command register */
+#define DMA_MASK        10  /* DMA controller mask register */
+#define DMA_MODE        11  /* DMA controller mode register */
+#define DMA_RESETFF 12  /* DMA controller first/last flip flop  */
+/* DMA data */
+#define DMA_DISABLE (0x04)  /* Disable channel n */
+#define DMA_ENABLE  (0x00)  /* Enable channel n */
+/* Single transfers, incr. address, auto init, writes, ch. n */
+#define DMA_RX_MODE (0x54)
+/* Single transfers, incr. address, no auto init, reads, ch. n */
+#define DMA_TX_MODE (0x48)
+
+#define SINGLE 3686400
+#define DOUBLE 7372800
+
+#define SIOCGPIPARAM           0x5000  /* get PI parameters */
+#define SIOCSPIPARAM           0x5001  /* set */
+#define SIOCGPIBAUD            0x5002  /* get only baud rate */
+#define SIOCSPIBAUD            0x5003  
+#define SIOCGPIDMA             0x5004  /* get only DMA */
+#define SIOCSPIDMA             0x5005  
+#define SIOCGPIIRQ             0x5006  /* get only IRQ */
+#define SIOCSPIIRQ             0x5007  
+
+struct pi_req  {
+    int cmd;
+    int speed;
+    int clockmode;
+    int txdelay;
+    unsigned char persist;
+    int slotime; 
+    int squeldelay;
+    int dmachan;    
+    int irq;    
+};
+
+#ifdef __KERNEL__
+
+/* Information that needs to be kept for each channel. */
+struct pi_local {
+    struct net_device_stats stats; 
+    long open_time;             /* Useless example local info. */
+    unsigned long xtal; 
+
+    struct mbuf *rcvbuf;/* Buffer for current rx packet */
+    struct mbuf *rxdmabuf1; /* DMA rx buffer */
+    struct mbuf *rxdmabuf2; /* DMA rx buffer */
+
+    int bufsiz;         /* Size of rcvbuf */
+    char *rcp;          /* Pointer into rcvbuf */
+
+    struct sk_buff_head sndq;  /* Packets awaiting transmission */
+    int sndcnt;         /* Number of packets on sndq */
+    struct sk_buff *sndbuf;    /* Current buffer being transmitted */
+    char *txdmabuf;     /* Transmit DMA buffer */
+       char *txptr;            /* Used by B port tx */
+       int txcnt;                      
+    char tstate;        /* Transmitter state */
+#define IDLE    0       /* Transmitter off, no data pending */
+#define ACTIVE  1       /* Transmitter on, sending data */
+#define UNDERRUN 2      /* Transmitter on, flushing CRC */
+#define FLAGOUT 3       /* CRC sent - attempt to start next frame */
+#define DEFER 4         /* Receive Active - DEFER Transmit */
+#define ST_TXDELAY 5    /* Sending leading flags */
+#define CRCOUT 6
+    char rstate;        /* Set when !DCD goes to 0 (TRUE) */
+/* Normal state is ACTIVE if Receive enabled */
+#define RXERROR 2       /* Error -- Aborting current Frame */
+#define RXABORT 3       /* ABORT sequence detected */
+#define TOOBIG 4        /* too large a frame to store */
+    int dev;            /* Device number */
+    int base;       /* Base of I/O registers */
+    int cardbase;     /* Base address of card */
+    int stata;        /* address of Channel A status regs */
+    int statb;        /* address of Channel B status regs */
+    int speed;        /* Line speed, bps */
+    int clockmode;    /* tapr 9600 modem clocking option */
+    int txdelay;      /* Transmit Delay 10 ms/cnt */
+    unsigned char persist;       /* Persistence (0-255) as a % */
+    int slotime;      /* Delay to wait on persistence hit */
+    int squeldelay;   /* Delay after XMTR OFF for squelch tail */
+    struct iface *iface;    /* Associated interface */
+    int dmachan;           /* DMA channel for this port */
+};
+
+#endif
index a764dc9910258e39f8c74d0417815efcf6dc9323..c396c39ce41d517b41a658e500e7d1e290b44907 100644 (file)
@@ -82,8 +82,11 @@ enum net_directory_inos {
        PROC_NET_RTRULES,
        PROC_NET_DEV,
        PROC_NET_RAW,
+       PROC_NET_RAW6,
        PROC_NET_TCP,
+       PROC_NET_TCP6,
        PROC_NET_UDP,
+       PROC_NET_UDP6,
        PROC_NET_SNMP,
        PROC_NET_RARP,
        PROC_NET_IGMP,
@@ -108,12 +111,14 @@ enum net_directory_inos {
        PROC_NET_NR_NEIGH,
        PROC_NET_NR,
        PROC_NET_SOCKSTAT,
+       PROC_NET_SOCKSTAT6,
        PROC_NET_RTCACHE,
        PROC_NET_AX25_BPQETHER,
        PROC_NET_ALIAS_TYPES,
        PROC_NET_ALIASES,
        PROC_NET_IP_MASQ_APP,
        PROC_NET_RT6,
+       PROC_NET_RT6_TREE,
        PROC_NET_RT6_STATS,
        PROC_NET_NDISC,
        PROC_NET_STRIP_STATUS,
diff --git a/include/linux/pt.h b/include/linux/pt.h
new file mode 100644 (file)
index 0000000..9ab17f5
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * pt.h: Linux device driver for the Gracilis PackeTwin
+ * Copyright (C) 1995 Craig Small VK2XLZ (vk2xlz@vk2xlz.ampr.org.)
+ *
+ * Please read the notice appearing at the top of the file pt.c
+ */
+#define DMA_BUFF_SIZE 2200
+
+#define ON 1
+#define OFF 0
+
+
+/* Register offset info, specific to the PT
+ * E.g., to read the data port on channel A, use
+ *  inportb(pichan[dev].base + CHANA + DATA)
+ */
+#define CHANB   0   /* Base of channel B regs */
+#define CHANA   2   /* Base of channel A regs */
+
+/* 8530 ports on each channel */
+#define CTL 0
+#define DATA    1
+
+#define DMAEN   0x8 /* Offset off DMA Enable register */
+
+/* Timer chip offsets */
+#define TMR0    0x4 /* Offset of timer 0 register */
+#define TMR1    0x5 /* Offset of timer 1 register */
+#define TMR2    0x6 /* Offset of timer 2 register */
+#define TMRCMD  0x7 /* Offset of timer command register */
+#define INT_REG        0x8
+#define TMR1CLR 0x9
+#define TMR2CLR 0xa
+
+/* Interrupt register equates */
+#define PT_SCC_MSK     0x1
+#define PT_TMR1_MSK    0x2
+#define PT_TMR2_MSK    0x4
+
+/* Serial/interrupt register equates */
+#define PT_DTRA_ON     0x1
+#define PT_DTRB_ON     0x2
+#define PT_EXTCLKA     0x4
+#define PT_EXTCLKB     0x8
+#define PT_LOOPA_ON    0x10
+#define PT_LOOPB_ON    0x20
+#define PT_EI          0x80
+
+/* Timer chip equates */
+#define SC0 0x00 /* Select counter 0 */
+#define SC1 0x40 /* Select counter 1 */
+#define SC2 0x80 /* Select counter 2 */
+#define CLATCH  0x00 /* Counter latching operation */
+#define MSB 0x20 /* Read/load MSB only */
+#define LSB 0x10 /* Read/load LSB only */
+#define LSB_MSB 0x30 /* Read/load LSB, then MSB */
+#define MODE0   0x00 /* Interrupt on terminal count */
+#define MODE1   0x02 /* Programmable one shot */
+#define MODE2   0x04 /* Rate generator */
+#define MODE3   0x06 /* Square wave rate generator */
+#define MODE4   0x08 /* Software triggered strobe */
+#define MODE5   0x0a /* Hardware triggered strobe */
+#define BCD 0x01 /* BCD counter */
+
+/* DMA controller registers */
+#define DMA_STAT    8   /* DMA controller status register */
+#define DMA_CMD     8   /* DMA controller command register */
+#define DMA_MASK        10  /* DMA controller mask register */
+#define DMA_MODE        11  /* DMA controller mode register */
+#define DMA_RESETFF 12  /* DMA controller first/last flip flop  */
+/* DMA data */
+#define DMA_DISABLE (0x04)  /* Disable channel n */
+#define DMA_ENABLE  (0x00)  /* Enable channel n */
+/* Single transfers, incr. address, auto init, writes, ch. n */
+#define DMA_RX_MODE (0x54)
+/* Single transfers, incr. address, no auto init, reads, ch. n */
+#define DMA_TX_MODE (0x48)
+
+/* Write registers */
+#define DMA_CFG                0x08
+#define SERIAL_CFG     0x09
+#define INT_CFG                0x09    /* shares with serial config */
+#define DMA_CLR_FF     0x0a
+
+#define SINGLE 3686400
+#define DOUBLE 7372800
+#define XTAL   ((long) 6144000L)
+
+#define SIOCGPIPARAM           0x5000  /* get PI parameters */
+#define SIOCSPIPARAM           0x5001  /* set */
+#define SIOCGPIBAUD            0x5002  /* get only baud rate */
+#define SIOCSPIBAUD            0x5003  
+#define SIOCGPIDMA             0x5004  /* get only DMA */
+#define SIOCSPIDMA             0x5005  
+#define SIOCGPIIRQ             0x5006  /* get only IRQ */
+#define SIOCSPIIRQ             0x5007  
+
+struct pt_req
+{
+       int cmd;
+       int speed;
+       int clockmode;
+       int txdelay;
+       unsigned char persist;
+       int slotime; 
+       int squeldelay;
+       int dmachan;    
+       int irq;    
+};
+
+/* SCC Interrupt vectors, if we have set 'status low' */
+#define CHBTxIV                0x00
+#define CHBEXTIV       0x02
+#define CHBRxIV                0x04
+#define CHBSRCIV       0x06
+#define CHATxIV                0x08
+#define CHAEXTIV       0x0a
+#define CHARxIV                0x0c
+#define CHASRCIV       0x0e
+
+
+#ifdef __KERNEL__
+
+/* Information that needs to be kept for each channel. */
+struct pt_local
+{
+       struct net_device_stats stats; /* %%%dp*/
+       long open_time;             /* Useless example local info. */
+       unsigned long xtal; 
+
+       struct mbuf *rcvbuf;/* Buffer for current rx packet */
+       struct mbuf *rxdmabuf1; /* DMA rx buffer */
+       struct mbuf *rxdmabuf2; /* DMA rx buffer */
+
+       int bufsiz;                     /* Size of rcvbuf                       */
+       char *rcp;                      /* Pointer into rcvbuf                  */
+       struct sk_buff_head sndq;       /* Packets awaiting transmission        */
+       int sndcnt;                     /* Number of packets on sndq            */
+       struct sk_buff *sndbuf;         /* Current buffer being transmitted     */
+       char *txdmabuf;                 /* Transmit DMA buffer                  */
+       char *txptr;                    /* Used by B port tx                    */
+       int txcnt;                      
+       char tstate;                    /* Transmitter state                    */
+#define IDLE    0       /* Transmitter off, no data pending            */
+#define ACTIVE  1       /* Transmitter on, sending data                */
+#define UNDERRUN 2      /* Transmitter on, flushing CRC                        */
+#define FLAGOUT 3       /* CRC sent - attempt to start next frame      */
+#define DEFER 4         /* Receive Active - DEFER Transmit             */
+#define ST_TXDELAY 5    /* Sending leading flags                       */
+#define CRCOUT 6
+       char rstate;        /* Set when !DCD goes to 0 (TRUE)           */
+/* Normal state is ACTIVE if Receive enabled */
+#define RXERROR 2       /* Error -- Aborting current Frame             */
+#define RXABORT 3       /* ABORT sequence detected                     */
+#define TOOBIG 4        /* too large a frame to store                  */
+       
+       int dev;                /* Device number */
+       int base;               /* Base of I/O registers */
+       int cardbase;           /* Base address of card */
+       int stata;              /* address of Channel A status regs */
+       int statb;              /* address of Channel B status regs */
+       int speed;              /* Line speed, bps */
+       int clockmode;          /* tapr 9600 modem clocking option */
+       int txdelay;            /* Transmit Delay 10 ms/cnt */
+       unsigned char persist;  /* Persistence (0-255) as a % */
+       int slotime;            /* Delay to wait on persistence hit */
+       int squeldelay;         /* Delay after XMTR OFF for squelch tail */
+       struct iface *iface;    /* Associated interface */
+       int dmachan;            /* DMA channel for this port */
+       char saved_RR0;         /* The saved version of RR) that we compare with */
+       int nrzi;               /* Do we use NRZI (or NRZ) */
+};
+
+#endif
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
new file mode 100644 (file)
index 0000000..7dd5316
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _LINUX_REBOOT_H
+#define _LINUX_REBOOT_H
+
+/*
+ * Magic values required to use _reboot() system call.
+ */
+
+#define        LINUX_REBOOT_MAGIC1     0xfee1dead
+#define        LINUX_REBOOT_MAGIC2     672274793
+#define        LINUX_REBOOT_MAGIC2A    85072278
+
+
+/*
+ * Commands accepted by the _reboot() system call.
+ *
+ * RESTART     Restart system using default command and mode.
+ * HALT        Stop OS and give system control to ROM monitor, if any.
+ * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
+ * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
+ * POWER_OFF   Stop OS and remove all power from system, if possible.
+ * RESTART2    Restart system using given command string.
+ */
+
+#define        LINUX_REBOOT_CMD_RESTART        0x01234567
+#define        LINUX_REBOOT_CMD_HALT           0xCDEF0123
+#define        LINUX_REBOOT_CMD_CAD_ON         0x89ABCDEF
+#define        LINUX_REBOOT_CMD_CAD_OFF        0x00000000
+#define        LINUX_REBOOT_CMD_POWER_OFF      0x4321FEDC
+#define        LINUX_REBOOT_CMD_RESTART2       0xA1B2C3D4
+
+
+#ifdef __KERNEL__
+
+#include <linux/notifier.h>
+
+extern struct notifier_block *reboot_notifier_list;
+extern int register_reboot_notifier(struct notifier_block *);
+extern int unregister_reboot_notifier(struct notifier_block *);
+
+
+/*
+ * Architecture-specific implementations of sys_reboot commands.
+ */
+
+extern void machine_restart(char *cmd);
+extern void machine_halt(void);
+extern void machine_power_off(void);
+
+#endif
+
+#endif /* _LINUX_REBOOT_H */
index 3214294c878714cd59f3f95a2e799a89eda46c85..4432d190052540fa33042d4fa6be88c99e00584c 100644 (file)
@@ -66,19 +66,14 @@ struct rtentry
 #define RTF_THROW      0x2000          /* Go to next class             */
 #define RTF_NOPMTUDISC  0x4000         /* Do not send packets with DF  */
 
-/* Bad idea. IPv6 should not use broken IPv4 interface */
-
-#define RTF_ADDRCONF   0x0800          /* announced on link prefix       */
-#define RTF_INVALID    0x1000
-#define RTF_DCACHE     0x2000
-#define RTF_DEFAULT    0x4000          /* Route is a default route       */
-#define RTF_NEXTHOP    0x8000          /* Non gateway route with nexthop */
-
-
-#define RTF_MAGIC      0x10000         /* Route added/deleted authomatically,
+#define RTF_MAGIC      0x8000          /* Route added/deleted authomatically,
                                         * when interface changes its state.
                                         */
 
+/*
+ *     <linux/ipv6_route.h> uses RTF values >= 64k
+ */
+
 #define RTCF_VALVE     0x00200000
 #define RTCF_MASQ      0x00400000
 #define RTCF_NAT       0x00800000
index af19cbed636e463285b10a5ae47bd602919d9b43..6b930da0c8288994c151e7eef18e68402599ed54 100644 (file)
@@ -410,14 +410,15 @@ extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue *
        wait->next = next;
 }
 
+extern spinlock_t waitqueue_lock;
+
 extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&waitqueue_lock, flags);
        __add_wait_queue(p, wait);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&waitqueue_lock, flags);
 }
 
 extern inline void __remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
@@ -438,10 +439,9 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&waitqueue_lock, flags);
        __remove_wait_queue(p, wait);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&waitqueue_lock, flags); 
 }
 
 extern inline void poll_wait(struct wait_queue ** wait_address, poll_table * p)
index cd9a1fe628774fa5a95b19c6609d3e01299b0bf7..907b2e84ed8eabd8c3f754ae6816fcf7431afaaa 100644 (file)
@@ -86,12 +86,6 @@ struct sk_buff
                unsigned char   *raw;
        } mac;
 
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-       /*
-        *      Generic "neighbour" information
-        */
-       struct neighbour *nexthop;
-#endif         
        struct  dst_entry *dst;
        char            cb[32];
 
@@ -117,6 +111,7 @@ struct sk_buff
 #define PACKET_NDISC           17              /* Outgoing NDISC packet                        */
        atomic_t        users;                  /* User count - see datagram.c,tcp.c            */
        unsigned short  protocol;               /* Packet protocol from driver.                 */
+       unsigned short  security;               /* Security level of packet                     */
        unsigned int    truesize;               /* Buffer size                                  */
 
        atomic_t        count;                  /* reference count                              */
index b048acb871fd9004f900b0bffba13900b250ad21..a75919bf9997b2a943a222e921dd31d87ee5a3fd 100644 (file)
@@ -147,6 +147,7 @@ struct ucred
 #define AF_ROSE                11      /* Amateur Radio X.25 PLP       */
 #define AF_DECNET      12      /* Reserved for DECnet project  */
 #define AF_NETBEUI     13      /* Reserved for 802.2LLC project*/
+#define AF_SECURITY    14      /* Security callback pseudo AF */
 #define AF_MAX         32      /* For now.. */
 
 /* Protocol families, same as address families. */
@@ -165,6 +166,7 @@ struct ucred
 #define PF_ROSE                AF_ROSE
 #define PF_DECNET      AF_DECNET
 #define PF_NETBEUI     AF_NETBEUI
+#define PF_SECURITY    AF_SECURITY
 
 #define PF_MAX         AF_MAX
 
index 878359acbbdf973fc36062ca3121524ddf9848f6..199d28968df931f46ac40d80b0c7f8897619a286 100644 (file)
@@ -123,8 +123,26 @@ enum
 
 
 /* /proc/sys/net/ipv6 */
-#define NET_IPV6_FORWARDING            1
-#define NET_IPV6_HOPLIMIT              2
+enum {
+       NET_IPV6_FORWARDING = 1,
+       NET_IPV6_HOPLIMIT,
+
+       NET_IPV6_ACCEPT_RA,
+       NET_IPV6_ACCEPT_REDIRECTS,
+
+       NET_IPV6_ND_MAX_MCAST_SOLICIT,
+       NET_IPV6_ND_MAX_UCAST_SOLICIT,
+       NET_IPV6_ND_RETRANS_TIME,
+       NET_IPV6_ND_REACHABLE_TIME,
+       NET_IPV6_ND_DELAY_PROBE_TIME,
+
+       NET_IPV6_AUTOCONF,
+       NET_IPV6_DAD_TRANSMITS,
+       NET_IPV6_RTR_SOLICITS,
+       NET_IPV6_RTR_SOLICIT_INTERVAL,
+       NET_IPV6_RTR_SOLICIT_DELAY,
+};
+
 /* /proc/sys/net/ipx */
 
 /* /proc/sys/net/appletalk */
@@ -158,7 +176,8 @@ enum {
        NET_AX25_IDLE_TIMEOUT,
        NET_AX25_N2,
        NET_AX25_PACLEN,
-       NET_AX25_PROTOCOL
+       NET_AX25_PROTOCOL,
+       NET_AX25_DAMA_SLAVE_TIMEOUT
 };
 
 /* /proc/sys/net/rose */
index 8bd4e7f306ae2d952ae2a6d39e029f27f755c2e5..acebad9f260914ff99716149447a3b99c4c353fc 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <asm/bitops.h>
 #include <asm/system.h>
+#include <asm/spinlock.h>
 
 /*
  * New proposed "bottom half" handlers:
@@ -74,48 +75,20 @@ extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;
  * interrupt.
  */
 
-/*
- * queue_task_irq: put the bottom half handler "bh_pointer" on the list
- * "bh_list".  You may call this function only from an interrupt
- * handler or a bottom half handler.
- */
-extern __inline__ void queue_task_irq(struct tq_struct *bh_pointer,
-                              task_queue *bh_list)
-{
-       if (!set_bit(0,&bh_pointer->sync)) {
-               bh_pointer->next = *bh_list;
-               *bh_list = bh_pointer;
-       }
-}
-
-/*
- * queue_task_irq_off: put the bottom half handler "bh_pointer" on the list
- * "bh_list".  You may call this function only when interrupts are off.
- */
-extern __inline__ void queue_task_irq_off(struct tq_struct *bh_pointer,
-                                task_queue *bh_list)
-{
-       if (!(bh_pointer->sync & 1)) {
-               bh_pointer->sync = 1;
-               bh_pointer->next = *bh_list;
-               *bh_list = bh_pointer;
-       }
-}
-
+extern spinlock_t tqueue_lock;
 
 /*
- * queue_task: as queue_task_irq, but can be called from anywhere.
+ * queue_task
  */
 extern __inline__ void queue_task(struct tq_struct *bh_pointer,
                           task_queue *bh_list)
 {
        if (!set_bit(0,&bh_pointer->sync)) {
                unsigned long flags;
-               save_flags(flags);
-               cli();
+               spin_lock_irqsave(&tqueue_lock, flags);
                bh_pointer->next = *bh_list;
                *bh_list = bh_pointer;
-               restore_flags(flags);
+               spin_unlock_irqrestore(&tqueue_lock, flags);
        }
 }
 
index 03f9982bde2964de968ab58715b8fefc61c29ff0..6a9c00c2a80c1b12087665c148f61dec21105e0a 100644 (file)
@@ -38,9 +38,11 @@ struct prefix_info {
 #include <linux/netdevice.h>
 #include <net/if_inet6.h>
 
-extern struct inet6_ifaddr     *inet6_addr_lst[16];
-extern struct ipv6_mc_list     *inet6_mcast_lst[16];
-extern struct inet6_dev                *inet6_dev_lst;
+#define IN6_ADDR_HSIZE         16
+
+extern struct inet6_ifaddr     *inet6_addr_lst[IN6_ADDR_HSIZE];
+extern struct ifmcaddr6                *inet6_mcast_lst[IN6_ADDR_HSIZE];
+extern struct inet6_dev                *inet6_dev_lst[IN6_ADDR_HSIZE];
 
 extern void                    addrconf_init(void);
 extern void                    addrconf_cleanup(void);
@@ -51,10 +53,9 @@ extern int                   addrconf_notify(struct notifier_block *this,
 
 extern int                     addrconf_add_ifaddr(void *arg);
 extern int                     addrconf_set_dstaddr(void *arg);
-extern int                     addrconf_get_ifindex(void *arg);
 
 extern struct inet6_ifaddr *   ipv6_chk_addr(struct in6_addr *addr);
-extern struct inet6_ifaddr *   ipv6_get_saddr(struct rt6_info *rt, 
+extern struct inet6_ifaddr *   ipv6_get_saddr(struct dst_entry *dst, 
                                               struct in6_addr *daddr);
 extern struct inet6_ifaddr *   ipv6_get_lladdr(struct device *dev);
 
@@ -80,7 +81,6 @@ extern int                    ipv6_chk_mcast_addr(struct device *dev,
 extern void                    addrconf_prefix_rcv(struct device *dev,
                                                    u8 *opt, int len);
 
-extern struct inet6_dev *      ipv6_dev_by_index(int index);
 extern struct inet6_dev *      ipv6_get_idev(struct device *dev);
 
 extern void                    addrconf_forwarding_on(void);
@@ -105,6 +105,11 @@ static __inline__ u8 ipv6_addr_hash(struct in6_addr *addr)
        return ((tmp ^ (tmp >> 4)) & 0x0f);
 }
 
+static __inline__ int ipv6_devindex_hash(int ifindex)
+{
+       return ifindex & (IN6_ADDR_HSIZE - 1);
+}
+
 /*
  *     compute link-local solicited-node multicast address
  */
index e02b388c20be5c8833e71446d70b634cd221d753..dbd0c1281c7236cf2ea670c4213cd305ccccb765 100644 (file)
@@ -3,12 +3,39 @@
 #define _ARP_H
 
 #include <linux/if_arp.h>
+#include <net/neighbour.h>
+/*
+ *     This structure defines the ARP mapping cache.
+ */
+
+struct arp_table
+{
+       union {
+               struct neighbour        neigh;
+               struct arp_table        *next;
+       } u;
+
+       u32                             ip;
+
+       unsigned long                   last_updated;           /* For expiry                   */
+       unsigned int                    flags;                  /* Control status               */
+
+       u32                             mask;                   /* netmask - used for generalised proxy arps (tridge)           */
+       int                             hatype;
+
+       /*
+        *      The following entries are only used for unresolved hw addresses.
+        */
+       struct timer_list               timer;                  /* expire timer                 */
+       int                             retries;                /* remaining retries            */
+};
 
 extern void    arp_init(void);
 extern int     arp_rcv(struct sk_buff *skb, struct device *dev,
                        struct packet_type *pt);
 extern int     arp_find(unsigned char *haddr, struct sk_buff *skb);
-extern int     arp_find_1(unsigned char *haddr, struct dst_entry* dst, struct dst_entry *neigh);
+extern int     arp_find_1(unsigned char *haddr, struct dst_entry* dst,
+                          struct neighbour *neigh);
 extern int     arp_ioctl(unsigned int cmd, void *arg);
 extern void     arp_send(int type, int ptype, u32 dest_ip, 
                         struct device *dev, u32 src_ip, 
@@ -17,5 +44,5 @@ extern int    arp_req_set(struct arpreq *r, struct device *dev);
 extern int     arp_req_delete(struct arpreq *r, struct device *dev);
 extern int     arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short type, __u32 daddr);
 extern int     arp_update_cache(struct hh_cache * hh);
-extern struct dst_entry *arp_find_neighbour(struct dst_entry *dst, int);
+extern struct neighbour *arp_find_neighbour(struct dst_entry *dst, int);
 #endif /* _ARP_H */
index 0c1dcd5bb18f0f1e060be030d3fb641f675a8226..71d7fb0b2ad468882fc94df9841d45b323e9aa6d 100644 (file)
@@ -6,6 +6,7 @@
  
 #ifndef _AX25_H
 #define _AX25_H 
+#include <linux/config.h>
 #include <linux/ax25.h>
 
 #define AX25_SLOWHZ                    10      /* Run timing at 1/10 second - gives us better resolution for 56kbit links */
@@ -113,9 +114,12 @@ enum {
 #define AX25_MODULUS           8       /*  Standard AX.25 modulus */
 #define        AX25_EMODULUS           128     /*  Extended AX.25 modulus */
 
-#define        AX25_PROTO_STD          0
-#define        AX25_PROTO_DAMA_SLAVE   1
-#define        AX25_PROTO_DAMA_MASTER  2
+enum {
+       AX25_PROTO_STD_SIMPLEX,
+       AX25_PROTO_STD_DUPLEX,
+       AX25_PROTO_DAMA_SLAVE,
+       AX25_PROTO_DAMA_MASTER
+};
 
 enum {
        AX25_VALUES_IPDEFMODE,  /* 0=DG 1=VC */
@@ -131,6 +135,7 @@ enum {
        AX25_VALUES_N2,         /* Default N2 value */
        AX25_VALUES_PACLEN,     /* AX.25 MTU */
        AX25_VALUES_PROTOCOL,   /* Std AX.25, DAMA Slave, DAMA Master */
+       AX25_VALUES_DS_TIMEOUT, /* DAMA Slave timeout */
        AX25_MAX_VALUES         /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */
 };
 
@@ -146,7 +151,8 @@ enum {
 #define        AX25_DEF_N2             10                      /* N2=10 */
 #define AX25_DEF_IDLE          (20 * 60 * AX25_SLOWHZ) /* Idle=20 mins */              
 #define AX25_DEF_PACLEN                256                     /* Paclen=256 */
-#define        AX25_DEF_PROTOCOL       AX25_PROTO_STD          /* Standard AX.25 */
+#define        AX25_DEF_PROTOCOL       AX25_PROTO_STD_SIMPLEX  /* Standard AX.25 */
+#define AX25_DEF_DS_TIMEOUT    (3 * 60 * AX25_SLOWHZ)  /* DAMA timeout 3 minutes */
 
 typedef struct ax25_uid_assoc {
        struct ax25_uid_assoc   *next;
@@ -169,6 +175,12 @@ typedef struct ax25_route {
        char                    ip_mode;
 } ax25_route;
 
+typedef struct {
+       char                    slave;                  /* slave_mode?   */
+       struct timer_list       slave_timer;            /* timeout timer */
+       unsigned short          slave_timeout;          /* when? */
+} ax25_dama_info;
+
 #ifndef _LINUX_SYSCTL_H
 #include <linux/sysctl.h>
 #endif
@@ -179,6 +191,9 @@ typedef struct ax25_dev {
        struct device           *forward;
        struct ctl_table        systable[AX25_MAX_VALUES+1];
        int                     values[AX25_MAX_VALUES];
+#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
+       ax25_dama_info          dama;
+#endif
 } ax25_dev;
 
 typedef struct ax25_cb {
@@ -191,6 +206,9 @@ typedef struct ax25_cb {
        unsigned short          vs, vr, va;
        unsigned char           condition, backoff;
        unsigned char           n2, n2count;
+#ifdef CONFIG_AX25_DAMA_SLAVE
+       unsigned char           dama_slave;
+#endif
        unsigned short          t1, t2, t3, idle, rtt;
        unsigned short          t1timer, t2timer, t3timer, idletimer;
        unsigned short          paclen;
@@ -247,10 +265,14 @@ extern int  ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int);
 extern void ax25_ds_nr_error_recovery(ax25_cb *);
 extern void ax25_ds_enquiry_response(ax25_cb *);
 extern void ax25_ds_establish_data_link(ax25_cb *);
+extern void ax25_dev_dama_on(ax25_dev *);
+extern void ax25_dev_dama_off(ax25_dev *);
 extern void ax25_dama_on(ax25_cb *);
 extern void ax25_dama_off(ax25_cb *);
 
 /* ax25_ds_timer.c */
+extern void ax25_ds_set_timer(ax25_dev *);
+extern void ax25_ds_del_timer(ax25_dev *);
 extern void ax25_ds_timer(ax25_cb *);
 extern void ax25_ds_t1_timeout(ax25_cb *);
 
index a1d3fa3092ab6bffd97d1a68a5d6fcb12412a2d0..3b4ccf0945104f561412156b1d48c74ec2ec6ad9 100644 (file)
@@ -208,84 +208,19 @@ struct br_cf {
 #define BRCMD_DISABLE_PROT_STATS 14
 #define BRCMD_ZERO_PROT_STATS  15
 
-/* prototypes of all bridging functions... */
-
-void transmit_config(int port_no);
-int root_bridge(void);
-int supersedes_port_info(int port_no, Config_bpdu *config);
-void record_config_information(int port_no, Config_bpdu *config);
-void record_config_timeout_values(Config_bpdu *config);
-void config_bpdu_generation(void);
-int designated_port(int port_no);
-void reply(int port_no);
-void transmit_tcn(void);
-void configuration_update(void);
-void root_selection(void);
-void designated_port_selection(void);
-void become_designated_port(int port_no);
-void port_state_selection(void);
-void make_forwarding(int port_no);
-void topology_change_detection(void);
-void topology_change_acknowledged(void);
-void acknowledge_topology_change(int port_no);
-void make_blocking(int port_no);
-void set_port_state(int port_no, int state);
-void received_config_bpdu(int port_no, Config_bpdu *config);
-void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn);
-void hello_timer_expiry(void);
-void message_age_timer_expiry(int port_no);
-void forward_delay_timer_expiry(int port_no);
-int designated_for_some_port(void);
-void tcn_timer_expiry(void);
-void topology_change_timer_expiry(void);
-void hold_timer_expiry(int port_no);
-void br_init(void);
-void br_init_port(int port_no);
-void enable_port(int port_no);
-void disable_port(int port_no);
-void set_bridge_priority(bridge_id_t *new_bridge_id);
-void set_port_priority(int port_no, unsigned short new_port_id);
-void set_path_cost(int port_no, unsigned short path_cost);
-void start_hello_timer(void);
-void stop_hello_timer(void);
-int hello_timer_expired(void);
-void start_tcn_timer(void);
-void stop_tcn_timer(void);
-int tcn_timer_expired(void);
-void start_topology_change_timer(void);
-void stop_topology_change_timer(void);
-int topology_change_timer_expired(void);
-void start_message_age_timer(int port_no, unsigned short message_age);
-void stop_message_age_timer(int port_no);
-int message_age_timer_expired(int port_no);
-void start_forward_delay_timer(int port_no);
-void stop_forward_delay_timer(int port_no);
-int forward_delay_timer_expired(int port_no);
-void start_hold_timer(int port_no);
-void stop_hold_timer(int port_no);
-int hold_timer_expired(int port_no);
-
-struct fdb *br_avl_find_addr(unsigned char addr[6]);
-int br_avl_insert (struct fdb * new_node);
-int br_avl_remove (struct fdb * node_to_delete);
-
-int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu);
-int send_config_bpdu(int port_no, Config_bpdu *config_bpdu);
-int find_port(struct device *dev);
-int br_flood(struct sk_buff *skb, int port);
-int br_drop(struct sk_buff *skb);
-int br_learn(struct sk_buff *skb, int port);   /* 3.8 */
+/* prototypes of exported bridging functions... */
 
+void br_init(void);
 int br_receive_frame(struct sk_buff *skb);     /* 3.5 */
 int br_tx_frame(struct sk_buff *skb);
 int br_ioctl(unsigned int cmd, void *arg);
-
 int br_protocol_ok(unsigned short protocol);
 
-void free_fdb(struct fdb *);
-struct fdb *get_fdb(void);
+struct fdb *br_avl_find_addr(unsigned char addr[6]);
+int br_avl_insert (struct fdb * new_node);
 
 /* externs */
 
 extern struct br_stat br_stats;
 
+
index 8d594359e8b82d7f17e96cb1db593e0fb0881f0c..e01b56c8d9c8d1d4be56e4f6561da36863056c83 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _NET_DST_H
 #define _NET_DST_H
 
+#include <net/neighbour.h>
+
 /*
  * 0 - no debugging messages
  * 1 - rare events and bugs (default)
@@ -28,8 +30,8 @@ struct sk_buff;
 struct dst_entry
 {
        struct dst_entry        *next;
-       atomic_t                refcnt;
-       atomic_t                use;
+       atomic_t                refcnt;         /* tree/hash references */
+       atomic_t                use;            /* client references    */
        struct device           *dev;
        char                    obsolete;
        char                    priority;
@@ -40,7 +42,7 @@ struct dst_entry
        unsigned                rtt;
        int                     error;
 
-       struct dst_entry        *neighbour;
+       struct neighbour        *neighbour;
        struct hh_cache         *hh;
 
        int                     (*input)(struct sk_buff*);
@@ -55,8 +57,9 @@ struct dst_entry
 struct dst_ops
 {
        unsigned short          family;
-       struct dst_entry *      (*check)(struct dst_entry *);
-       struct dst_entry *      (*reroute)(struct dst_entry *);
+       struct dst_entry *      (*check)(struct dst_entry *, u32 cookie);
+       struct dst_entry *      (*reroute)(struct dst_entry *,
+                                          struct sk_buff *);
        void                    (*destroy)(struct dst_entry *);
 };
 
@@ -67,7 +70,7 @@ static __inline__
 struct dst_entry * dst_clone(struct dst_entry * dst)
 {
        if (dst)
-               atomic_inc(&dst->refcnt);
+               atomic_inc(&dst->use);
        return dst;
 }
 
@@ -75,24 +78,24 @@ static __inline__
 void dst_release(struct dst_entry * dst)
 {
        if (dst)
-               atomic_dec(&dst->refcnt);
+               atomic_dec(&dst->use);
 }
 
 static __inline__
-struct dst_entry * dst_check(struct dst_entry ** dst_p)
+struct dst_entry * dst_check(struct dst_entry ** dst_p, u32 cookie)
 {
        struct dst_entry * dst = *dst_p;
        if (dst && dst->obsolete)
-               dst = dst->ops->check(dst);
+               dst = dst->ops->check(dst, cookie);
        return (*dst_p = dst);
 }
 
 static __inline__
-struct dst_entry * dst_reroute(struct dst_entry ** dst_p)
+struct dst_entry * dst_reroute(struct dst_entry ** dst_p, struct sk_buff *skb)
 {
        struct dst_entry * dst = *dst_p;
        if (dst && dst->obsolete)
-               dst = dst->ops->reroute(dst);
+               dst = dst->ops->reroute(dst, skb);
        return (*dst_p = dst);
 }
 
@@ -100,7 +103,7 @@ static __inline__
 void dst_destroy(struct dst_entry * dst)
 {
        if (dst->neighbour)
-               dst_release(dst->neighbour);
+               neigh_release(dst->neighbour);
        if (dst->ops->destroy)
                dst->ops->destroy(dst);
        kfree(dst);
@@ -113,7 +116,7 @@ extern void __dst_free(struct dst_entry * dst);
 static __inline__
 void dst_free(struct dst_entry * dst)
 {
-       if (!dst->refcnt) {
+       if (!dst->use) {
                dst_destroy(dst);
                return;
        }
diff --git a/include/net/flow.h b/include/net/flow.h
new file mode 100644 (file)
index 0000000..dff77fc
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *
+ *     Flow based forwarding rules (usage: firewalling, etc)
+ *
+ */
+
+#ifndef _NET_FLOW_H
+#define _NET_FLOW_H
+
+struct flowi {
+       int     proto;          /*      {TCP, UDP, ICMP}        */
+
+       union {
+               struct {
+                       __u32                   daddr;
+                       __u32                   saddr;
+               } ip4_u;
+               
+               struct {
+                       struct in6_addr *       daddr;
+                       struct in6_addr *       saddr;
+               } ip6_u;
+       } nl_u;
+
+       struct device   *dev;
+
+       union {
+               struct {
+                       __u16   sport;
+                       __u16   dport;
+               } ports;
+
+               struct {
+                       __u8    type;
+                       __u8    code;
+               } icmpt;
+
+               unsigned long   data;
+       } uli_u;
+};
+
+#define FLOWR_NODECISION       0       /* rule not appliable to flow   */
+#define FLOWR_SELECT           1       /* flow must follow this rule   */
+#define FLOWR_CLEAR            2       /* priority level clears flow   */
+#define FLOWR_ERROR            3
+
+struct fl_acc_args {
+       int     type;
+
+
+#define FL_ARG_FORWARD 1
+#define FL_ARG_ORIGIN  2
+
+       union {
+               struct sk_buff          *skb;
+               struct {
+                       struct sock     *sk;
+                       struct flowi    *flow;
+               } fl_o;
+       } fl_u;
+};
+
+
+struct pkt_filter {
+       atomic_t                refcnt;
+       unsigned int            offset;
+       __u32                   value;
+       __u32                   mask;
+       struct pkt_filter       *next;
+};
+
+#define FLR_INPUT              1
+#define FLR_OUTPUT             2
+
+struct flow_filter {
+       int                             type;
+       union {
+               struct pkt_filter       *filter;
+               struct sock             *sk;
+       } u;
+};
+
+struct flow_rule {
+       struct flow_rule_ops            *ops;
+       unsigned char                   private[0];
+};
+
+struct flow_rule_ops {
+       int                     (*accept)(struct rt6_info *rt,
+                                         struct rt6_info *rule,
+                                         struct fl_acc_args *args,
+                                         struct rt6_info **nrt);
+};
+
+#endif
index 048243c335cd829ac22ae57daaf300846c932bc7..281c2f099724980697df175621e5df4636a92ff5 100644 (file)
@@ -59,14 +59,17 @@ struct ipv6_mc_socklist {
        struct ipv6_mc_socklist *next;
 };
 
-struct ipv6_mc_list {
-       struct in6_addr         addr;
+#define MAF_TIMER_RUNNING      0x01
+#define MAF_LAST_REPORTER      0x02
+
+struct ifmcaddr6 {
+       struct in6_addr         mca_addr;
        struct device           *dev;
-       struct ipv6_mc_list     *next;
-       struct ipv6_mc_list     *if_next;
-       struct timer_list       timer;
-        int                    tm_running;
-        atomic_t               users;  
+       struct ifmcaddr6        *next;
+       struct ifmcaddr6        *if_next;
+       struct timer_list       mca_timer;
+       unsigned long           mca_flags;
+       atomic_t                mca_users;      
 };
 
 #define        IFA_HOST        IPV6_ADDR_LOOPBACK
@@ -81,9 +84,8 @@ struct inet6_dev
        struct device           *dev;
 
        struct inet6_ifaddr     *addr_list;
-       struct ipv6_mc_list     *mc_list;
+       struct ifmcaddr6        *mc_list;
 
-       __u32                   if_index;
        __u32                   if_flags;
        __u32                   router:1,
                                unused:31;
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
new file mode 100644 (file)
index 0000000..482c7c7
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ *     Linux INET6 implementation 
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *
+ *     This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _IP6_FIB_H
+#define _IP6_FIB_H
+
+#ifdef __KERNEL__
+
+#include <linux/ipv6_route.h>
+
+#include <net/dst.h>
+#include <net/flow.h>
+
+struct rt6_info;
+
+struct fib6_node {
+       struct fib6_node        *parent;
+       struct fib6_node        *left;
+       struct fib6_node        *right;
+
+       struct fib6_node        *subtree;
+
+       struct rt6_info         *leaf;
+
+       __u16                   fn_bit;         /* bit key */
+       __u16                   fn_flags;
+       __u32                   fn_sernum;
+};
+
+
+/*
+ *     routing information
+ *
+ */
+
+struct rt6key {
+       struct in6_addr addr;
+       int             plen;
+};
+
+struct rt6_info {
+       union {
+               struct dst_entry        dst;
+               struct rt6_info         *next;
+       } u;
+
+#define rt6i_dev                       u.dst.dev
+#define rt6i_nexthop                   u.dst.neighbour
+#define rt6i_use                       u.dst.use
+#define rt6i_ref                       u.dst.refcnt
+
+#define rt6i_tstamp                    u.dst.lastuse
+
+       struct fib6_node                *rt6i_node;
+
+       struct in6_addr                 rt6i_gateway;
+       
+       int                             rt6i_keylen;
+
+       unsigned long                   rt6i_flags;
+       unsigned long                   rt6i_metric;
+       unsigned long                   rt6i_expires;
+
+       union {
+               struct flow_rule        *rt6iu_flowr;
+               struct flow_filter      *rt6iu_filter;
+       } flow_u;
+
+#define rt6i_flowr                     flow_u.rt6iu_flowr
+#define rt6i_filter                    flow_u.rt6iu_filter
+
+       struct rt6key                   rt6i_dst;
+       struct rt6key                   rt6i_src;
+};
+
+
+struct rt6_statistics {
+       __u32           fib_nodes;
+       __u32           fib_route_nodes;
+       __u32           fib_rt_alloc;           /* permanet routes      */
+       __u32           fib_rt_entries;         /* rt entries in table  */
+       __u32           fib_rt_cache;           /* cache routes         */
+};
+
+#define RTN_TL_ROOT    0x0001
+#define RTN_ROOT       0x0002          /* tree root node               */
+#define RTN_RTINFO     0x0004          /* node with valid routing info */
+
+#define RTN_TAG                0x0100
+
+/*
+ *     priority levels (or metrics)
+ *
+ */
+
+#define RTPRI_FIREWALL 8               /* Firewall control information */
+#define RTPRI_FLOW     16              /* Flow based forwarding rules  */
+#define RTPRI_KERN_CTL 32              /* Kernel control routes        */
+
+#define RTPRI_USER_MIN 256             /* Mimimum user priority        */
+#define RTPRI_USER_MAX 1024            /* Maximum user priority        */
+
+#define RTPRI_KERN_DFLT        4096            /* Kernel default routes        */
+
+#define        MAX_FLOW_BACKTRACE      32
+
+
+typedef void                   (*f_pnode)(struct fib6_node *fn, void *);
+
+extern struct fib6_node                ip6_routing_table;
+
+/*
+ *     exported functions
+ */
+
+extern struct fib6_node                *fib6_lookup(struct fib6_node *root,
+                                            struct in6_addr *daddr,
+                                            struct in6_addr *saddr);
+
+#define RT6_FILTER_RTNODES     1
+
+extern void                    fib6_walk_tree(struct fib6_node *root,
+                                              f_pnode func, void *arg,
+                                              int filter);
+
+extern int                     fib6_add(struct fib6_node *root,
+                                        struct rt6_info *rt);
+
+extern int                     fib6_del(struct rt6_info *rt);
+
+/*
+ *     auxiliary functions
+ */
+extern __inline__ void rt6_release(struct rt6_info *rt)
+{
+       struct dst_entry *dst = (struct dst_entry *) rt;
+       if (atomic_dec_and_test(&dst->refcnt))
+               dst_destroy(dst);
+}
+
+extern void                    rt6_ins(struct rt6_info *rt);
+
+#endif
+#endif
diff --git a/include/net/ip6_fw.h b/include/net/ip6_fw.h
new file mode 100644 (file)
index 0000000..7866273
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __NET_IP6_FW_H
+#define __NET_IP6_FW_H
+
+#define IP6_FW_LISTHEAD                0x1000
+#define IP6_FW_ACCEPT          0x0001
+#define IP6_FW_REJECT          0x0002
+
+#define IP6_FW_DEBUG   2
+
+#define IP6_FW_MSG_ADD         1
+#define IP6_FW_MSG_DEL         2
+#define IP6_FW_MSG_REPORT      3
+
+
+/*
+ *     Fast "hack" user interface
+ */
+struct ip6_fw_msg {
+       struct in6_addr         dst;
+       struct in6_addr         src;
+       int                     dst_len;
+       int                     src_len;
+       int                     action;
+       int                     policy;
+       int                     proto;
+       union {
+               struct {
+                       __u16   sport;
+                       __u16   dport;
+               } transp;
+
+               unsigned long   data;
+
+               int             icmp_type;
+       } u;
+
+       int                     msg_len;
+};
+
+#ifdef __KERNEL__
+
+#include <net/flow.h>
+
+struct ip6_fw_rule {
+       struct flow_rule        flowr;
+       struct ip6_fw_rule      *next;
+       struct ip6_fw_rule      *prev;
+       struct flowi            info;
+       unsigned long           policy;
+};
+
+#endif
+
+#endif
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
new file mode 100644 (file)
index 0000000..bdbe5c5
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef _NET_IP6_ROUTE_H
+#define _NET_IP6_ROUTE_H
+
+#define IP6_RT_PRIO_FW         16
+#define IP6_RT_PRIO_USER       1024
+#define IP6_RT_PRIO_ADDRCONF   256
+#define IP6_RT_PRIO_KERN       512
+#define IP6_RT_FLOW_MASK       0x00ff
+
+#ifdef __KERNEL__
+
+#include <net/flow.h>
+#include <net/ip6_fib.h>
+
+/*
+ *     Structure for assync processing of operations on the routing
+ *     table
+ */
+
+struct rt6_req {
+       int                     operation;
+       struct rt6_info         *ptr;
+
+       struct rt6_req          *next;
+       struct rt6_req          *prev;
+
+#define RT_OPER_ADD            1
+#define RT_OPER_DEL            2
+};
+
+
+struct pol_chain {
+       int                     type;
+       int                     priority;
+       struct fib6_node        *rules;
+       struct pol_chain        *next;
+};
+
+extern struct rt6_info ip6_null_entry;
+
+extern void                    ip6_route_input(struct sk_buff *skb);
+
+extern struct dst_entry *      ip6_route_output(struct sock *sk,
+                                                struct flowi *fl);
+
+extern void                    ip6_route_init(void);
+extern void                    ip6_route_cleanup(void);
+
+extern int                     ipv6_route_ioctl(unsigned int cmd, void *arg);
+
+extern struct rt6_info *       ip6_route_add(struct in6_rtmsg *rtmsg,
+                                             int *err);
+extern int                     ip6_del_rt(struct rt6_info *);
+
+extern int                     ip6_rt_addr_add(struct in6_addr *addr,
+                                               struct device *dev);
+
+extern void                    rt6_sndmsg(int type, struct in6_addr *dst,
+                                          struct in6_addr *src,
+                                          struct in6_addr *gw,
+                                          struct device *dev, 
+                                          int dstlen, int srclen,
+                                          int metric, __u32 flags);
+
+extern struct rt6_info         *rt6_lookup(struct in6_addr *daddr,
+                                           struct in6_addr *saddr,
+                                           struct device *dev, int flags);
+
+/*
+ *     support functions for ND
+ *
+ */
+extern struct rt6_info *       rt6_get_dflt_router(struct in6_addr *addr,
+                                                   struct device *dev);
+extern struct rt6_info *       rt6_add_dflt_router(struct in6_addr *gwaddr,
+                                                   struct device *dev);
+
+extern void                    rt6_purge_dflt_routers(int lst_resort);
+
+extern struct rt6_info *       rt6_redirect(struct in6_addr *dest,
+                                            struct in6_addr *saddr,
+                                            struct in6_addr *target,
+                                            struct device *dev,
+                                            int on_link);
+
+extern void                    rt6_pmtu_discovery(struct in6_addr *addr,
+                                                  struct device *dev,
+                                                  int pmtu);
+
+extern struct rt6_info *       ip6_rt_copy(struct rt6_info *rt);
+
+/*
+ *     Store a destination cache entry in a socket
+ *     For UDP/RAW sockets this is done on udp_connect.
+ */
+
+extern __inline__ void ip6_dst_store(struct sock *sk, struct dst_entry *dst)
+{
+       struct ipv6_pinfo *np;
+       struct rt6_info *rt;
+               
+       np = &sk->net_pinfo.af_inet6;
+       np->dst = dst;
+       
+       rt = (struct rt6_info *) dst;
+       
+       np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+}
+
+#endif
+#endif
index da3389e8f843edaecf159c1a5ec4e3aa3799e0fe..f40fb730e8522dd6ac4c1c62f4bbc4ce2a129566 100644 (file)
@@ -4,7 +4,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *
- *     $Id: ipv6.h,v 1.19 1996/09/24 17:04:20 roque Exp $
+ *     $Id: ipv6.h,v 1.5 1997/03/18 18:24:10 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -17,6 +17,7 @@
 
 #include <linux/ipv6.h>
 #include <net/ndisc.h>
+#include <net/flow.h>
 
 /*
  *     NextHeader field of IPv6 header
@@ -86,8 +87,29 @@ struct frag_hdr {
 
 extern struct ipv6_mib ipv6_statistics;
 
-extern int             ipv6_forwarding;        /* host/router switch */
-extern int             ipv6_hop_limit;         /* default hop limit */
+struct ipv6_config {
+       int             forwarding;
+       int             hop_limit;
+       int             accept_ra;
+       int             accept_redirects;
+       
+       int             nd_max_mcast_solicit;
+       int             nd_max_ucast_solicit;
+       int             nd_retrans_time;
+       int             nd_base_reachable_time;
+       int             nd_delay_probe_time;
+
+       int             autoconf;
+       int             dad_transmits;
+       int             rtr_solicits;
+       int             rtr_solicit_interval;
+       int             rtr_solicit_delay;
+
+       int             rt_cache_timeout;
+       int             rt_gc_period;
+};
+
+extern struct ipv6_config ipv6_config;
 
 struct ipv6_frag {
        __u16                   offset;
@@ -141,6 +163,11 @@ typedef int                (*inet_getfrag_t) (const void *data,
 
 extern int             ipv6_addr_type(struct in6_addr *addr);
 
+extern __inline__ int ipv6_addr_scope(struct in6_addr *addr)
+{
+       return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK;
+}
+
 extern __inline__ int ipv6_addr_cmp(struct in6_addr *a1, struct in6_addr *a2)
 {
        return memcmp((void *) a1, (void *) a2, sizeof(struct in6_addr));
@@ -169,54 +196,18 @@ extern __inline__ int ipv6_addr_any(struct in6_addr *a)
                 a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
 }
 
+extern __inline__ int gfp_any(void)
+{
+       int pri = GFP_KERNEL;
+       if (intr_count)
+               pri = GFP_ATOMIC;
+       return pri;
+}
+
 /*
  *     Prototypes exported by ipv6
  */
 
-#if 0
-extern int                     ipv6_build_header(struct sk_buff *skb,
-                                                 struct device *dev,
-                                                 struct in6_addr *saddr_in, 
-                                                 struct in6_addr *daddr_in,
-                                                 int proto, int len, 
-                                                 struct ipv6_pinfo *np);
-#endif
-
-extern void                    ipv6_redo_mac_hdr(struct sk_buff *skb,
-                                                 struct neighbour *neigh,
-                                                 int len);
-
-extern int                     ipv6_bld_hdr_2(struct sock *sk,
-                                              struct sk_buff *skb,
-                                              struct device *dev,
-                                              struct neighbour *neigh,
-                                              struct in6_addr *saddr,
-                                              struct in6_addr *daddr,
-                                              int proto, int len);
-
-extern int                     ipv6_xmit(struct sock *sk,
-                                         struct sk_buff *skb,
-                                         struct in6_addr *saddr,
-                                         struct in6_addr *daddr,
-                                         struct ipv6_options *opt,
-                                         int proto);
-
-extern void                    ipv6_queue_xmit(struct sock *sk,
-                                               struct device *dev,
-                                               struct sk_buff *skb,
-                                               int free);
-
-extern int                     ipv6_build_xmit(struct sock *sk,
-                                               inet_getfrag_t getfrag,
-                                               const void * data,
-                                               struct in6_addr * daddr,
-                                               unsigned short int length,
-                                               struct in6_addr * saddr,
-                                               struct device *dev,
-                                               struct ipv6_options *opt,
-                                               int proto, int hlimit,
-                                               int noblock);
-
 /*
  *     rcv function (called from netdevice level)
  */
@@ -225,16 +216,41 @@ extern int                        ipv6_rcv(struct sk_buff *skb,
                                         struct device *dev, 
                                         struct packet_type *pt);
 
-extern void                    ipv6_forward(struct sk_buff *skb,
-                                            struct device *dev,
-                                            int flags);
+/*
+ *     upper-layer output functions
+ */
+extern int                     ip6_xmit(struct sock *sk,
+                                        struct sk_buff *skb,
+                                        struct flowi *fl,
+                                        struct ipv6_options *opt);
+
+extern int                     ip6_nd_hdr(struct sock *sk,
+                                          struct sk_buff *skb,
+                                          struct device *dev,
+                                          struct in6_addr *saddr,
+                                          struct in6_addr *daddr,
+                                          int proto, int len);
+
+extern int                     ip6_build_xmit(struct sock *sk,
+                                              inet_getfrag_t getfrag,
+                                              const void *data,
+                                              struct flowi *fl,
+                                              unsigned short length,
+                                              struct ipv6_options *opt,
+                                              int hlimit, int flags);
+
+/*
+ *     skb processing functions
+ */
 
-#define IP6_FW_SRCRT   0x1
-#define        IP6_FW_STRICT   0x2
+extern int                     ip6_forward(struct sk_buff *skb);
+extern int                     ip6_input(struct sk_buff *skb);
+extern int                     ip6_mc_input(struct sk_buff *skb);
 
 /*
  *     Extension header (options) processing
  */
+
 extern int                     ipv6opt_bld_rthdr(struct sk_buff *skb,
                                                  struct ipv6_options *opt,
                                                  struct in6_addr *addr,
@@ -255,27 +271,6 @@ extern int                 ipv6opt_srt_tosin(struct ipv6_options *opt,
 extern void                    ipv6opt_free(struct ipv6_options *opt);
 
 
-/*
- *     socket lookup (af_inet6.c)
- */
-
-extern struct sock *           inet6_get_sock(struct proto *prot, 
-                                              struct in6_addr *loc_addr, 
-                                              struct in6_addr *rmt_addr,
-                                              unsigned short loc_port,
-                                              unsigned short rmt_port);
-
-extern struct sock *           inet6_get_sock_raw(struct sock *sk, 
-                                                  unsigned short num,
-                                                  struct in6_addr *loc_addr, 
-                                                  struct in6_addr *rmt_addr);
-
-extern struct sock *           inet6_get_sock_mcast(struct sock *sk, 
-                                                    unsigned short num,
-                                                    unsigned short rmt_port,
-                                                    struct in6_addr *loc_addr, 
-                                                    struct in6_addr *rmt_addr);
-
 /*
  *     socket options (ipv6_sockglue.c)
  */
diff --git a/include/net/ipv6_route.h b/include/net/ipv6_route.h
deleted file mode 100644 (file)
index 6f495d6..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- *     Linux INET6 implementation 
- *
- *     Authors:
- *     Pedro Roque             <roque@di.fc.ul.pt>     
- *
- *     This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-
-#ifndef _NET_IPV6_ROUTE_H
-#define _NET_IPV6_ROUTE_H
-
-#include <linux/ipv6_route.h>
-
-
-#ifdef __KERNEL__
-
-
-struct fib6_node {
-       struct fib6_node        *parent;
-       struct fib6_node        *left;
-       struct fib6_node        *right;
-
-       struct rt6_info         *leaf;
-
-       __u16                   fn_bit;         /* bit key */
-       __u16                   fn_flags;
-       __u32                   fn_sernum;
-};
-
-
-struct rt6_info;
-
-typedef void (*rt6_output_method_t) (struct sk_buff *skb, struct rt6_info *rt);
-
-struct rt6_info {
-       struct fib6_node        *fib_node;
-       struct rt6_info         *next;
-
-       struct in6_addr         rt_dst;
-       
-       atomic_t                rt_use;         /* dcache references    */
-       atomic_t                rt_ref;         /* fib references       */
-
-       struct neighbour        *rt_nexthop;
-       struct device           *rt_dev;
-       
-       rt6_output_method_t     rt_output_method;
-
-       __u16                   rt_metric;
-       __u16                   rt_prefixlen;
-       __u32                   rt_flags;
-       unsigned long           rt_expires;
-};
-
-extern struct rt6_info         *default_rt_list;
-extern struct rt6_info         *last_resort_rt;
-
-struct dest_entry {
-       struct rt6_info         rt;
-
-       __u32                   dc_irtt;
-       __u32                   dc_window;
-       __u16                   dc_pmtu;
-
-       unsigned long           dc_tstamp;      /* for garbage collection */
-
-#define dc_addr                        rt.rt_dst
-#define dc_usecnt              rt.rt_use
-#define dc_nexthop             rt.rt_nexthop
-#define dc_flags               rt.rt_flags
-};
-
-/*
- *     Structure for assync processing of operations on the routing
- *     table
- */
-
-struct rt6_req {
-       int                     operation;
-       struct rt6_info         *ptr;
-
-       struct rt6_req          *next;
-       struct rt6_req          *prev;
-
-#define RT_OPER_ADD            1
-#define RT_OPER_DEL            2
-};
-
-struct rt6_statistics {
-       __u32           fib_nodes;
-       __u32           fib_route_nodes;
-       __u32           fib_rt_alloc;
-       __u32           fib_rt_entries;
-       __u32           fib_dc_alloc;
-};
-
-#define RTN_ROOT       0x0001          /* root node                    */
-#define RTN_BACKTRACK  0x0002          /* backtrack point              */
-#define RTN_TAG                0x0010
-
-/*
- *     Values for destination cache garbage colection
- *     These are wild guesses for now...
- */
-
-#define        DC_WATER_MARK           512
-#define DC_SHORT_TIMEOUT       (5*HZ)
-#define DC_LONG_TIMEOUT                (15*HZ)
-
-#define DC_TIME_RUN            (5*HZ)
-#define DC_TIME_RETRY          HZ
-
-#define RT6_FILTER_NONE                0
-#define RT6_FILTER_RTNODES     1
-/*
- *     Prototypes
- */
-
-/*
- *     check/obtain destination cache from routing table
- */
-
-extern struct dest_entry *     ipv6_dst_check(struct dest_entry *dc, 
-                                              struct in6_addr * daddr,
-                                              __u32 sernum, int flags);
-
-extern struct dest_entry *     ipv6_dst_route(struct in6_addr * daddr,
-                                              struct device *src_dev,
-                                              int flags);
-
-extern void                    ipv6_dst_unlock(struct dest_entry *dest);
-
-extern struct rt6_info *       fibv6_lookup(struct in6_addr *addr,
-                                            struct device *dev,
-                                            int flags);
-
-/*
- *     user space set/del route
- */
-
-extern int                     ipv6_route_ioctl(unsigned int cmd, void *arg);
-
-
-extern void                    ipv6_route_init(void);
-extern void                    ipv6_route_cleanup(void);
-
-extern void                    rt6_ifdown(struct device *dev);
-
-extern int                     ipv6_route_add(struct in6_rtmsg *rt);
-
-extern int                     fib6_del_rt(struct rt6_info *rt);
-
-extern void                    rt6_sndmsg(__u32 type, struct in6_addr *dst,
-                                          struct in6_addr *gw, __u16 plen,
-                                          struct device *dev,
-                                          __u16 metric, __u16 flags);
-/*
- *     ICMP interface
- */
-
-extern struct rt6_info *       ipv6_rt_redirect(struct device *dev,
-                                                struct in6_addr *dest,
-                                                struct in6_addr *target,
-                                                int on_link);
-
-extern void                    rt6_handle_pmtu(struct in6_addr *addr,
-                                               int pmtu);
-/*
- *
- */
-
-extern struct fib6_node                routing_table;
-extern struct rt6_statistics   rt6_stats;
-
-static __inline__ void rt_release(struct rt6_info *rt)
-{
-       atomic_dec(&rt->rt_ref);
-       if ((rt->rt_use | rt->rt_ref) == 0)
-       {
-               if (rt->rt_nexthop)
-               {
-                       neighbour_unlock(rt->rt_nexthop);
-               }
-
-               if (rt->rt_flags & RTI_DCACHE)
-               {
-                       rt6_stats.fib_dc_alloc--;
-               }
-               rt6_stats.fib_rt_alloc--;
-               kfree(rt);
-       }
-}
-
-#endif
-
-#endif
index 0043b4fcf6c6ae50b6aedddb60992d202d7acbb1..9173a0eae6dd1ce3b55294000ca4ad72e88f3d1a 100644 (file)
@@ -91,8 +91,8 @@ struct nd_neigh {
 };
 
 struct nd_msg {
-        struct icmpv6hdr icmph;
-        struct in6_addr target;
+        struct icmp6hdr        icmph;
+        struct in6_addr        target;
         struct {
                 __u8   opt_type;
                 __u8   opt_len;
@@ -101,7 +101,7 @@ struct nd_msg {
 };
 
 struct ra_msg {
-        struct icmpv6hdr       icmph;
+        struct icmp6hdr                icmph;
        __u32                   reachable_time;
        __u32                   retrans_timer;
 };
@@ -147,12 +147,9 @@ extern void                        ndisc_send_rs(struct device *dev,
                                              struct in6_addr *saddr,
                                              struct in6_addr *daddr);
 
-extern int                     (*ndisc_eth_hook) (unsigned char *,
-                                                  struct device *,
-                                                  struct sk_buff *);
 extern int                     ndisc_eth_resolv(unsigned char *,
-                                               struct device *,
                                                struct sk_buff *);
+
 extern void                    ndisc_forwarding_on(void);
 extern void                    ndisc_forwarding_off(void);
 
@@ -163,7 +160,20 @@ extern void                        ndisc_send_redirect(struct sk_buff *skb,
 struct rt6_info *              dflt_rt_lookup(void);
 
 extern unsigned long   nd_rand_seed;
-extern int             ipv6_random(void);
+extern unsigned long   ipv6_random(void);
+
+/*
+ *     IGMP
+ */
+extern void                    igmp6_init(struct net_proto_family *ops);
+
+extern int                     igmp6_event_query(struct sk_buff *skb,
+                                                 struct icmp6hdr *hdr,
+                                                 int len);
+
+extern int                     igmp6_event_report(struct sk_buff *skb,
+                                                  struct icmp6hdr *hdr,
+                                                  int len);
 
 #endif /* __KERNEL__ */
 
index c0af9b1269dfb193105bcd2c2718877e0fc48a23..4e890362da3e617ee77220fdcab341a6c3564b03 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <asm/atomic.h>
 #include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
 
 /*
  *     flags
@@ -30,6 +28,7 @@ struct neighbour {
        unsigned long           lastused;
        unsigned long           flags;
        unsigned char           ha[MAX_ADDR_LEN];
+       struct hh_cache         *hh;
        atomic_t                refcnt;
        struct neigh_ops        *ops;
        struct sk_buff_head     arp_queue;
@@ -40,12 +39,11 @@ struct neigh_ops {
        int                     family;
        unsigned int            (*hash)(void *primary_key);
        int                     (*resolve)(unsigned char *h_dest,
-                                          struct device *dev,
                                           struct sk_buff *skb);
        void                    (*destructor)(struct neighbour *);
 };
 
-extern struct neighbour                *neigh_alloc(int size, int priority);
+extern struct neighbour                *neigh_alloc(int size, struct neigh_ops *);
 
 /*
  *     Neighbour references
@@ -63,7 +61,7 @@ extern struct neighbour               *neigh_alloc(int size, int priority);
  */
 
 
-static __inline__ void neighbour_unlock(struct neighbour *neigh)
+static __inline__ void neigh_release(struct neighbour *neigh)
 {
        if (atomic_dec_and_test(&neigh->refcnt))
                neigh->lastused = jiffies;
@@ -112,6 +110,8 @@ extern struct neighbour *   neigh_lookup(struct neigh_table *tbl,
                                             void *pkey, int key_len,
                                             struct device *dev);
 
+extern void                    neigh_destroy(struct neighbour *neigh);
+
 static __inline__ void neigh_insert(struct neigh_table *tbl,
                                    struct neighbour *neigh)
 {
index c981d7531a290125fa646d3da9f4dccab6810141..417a27e2cb22d324ef2f91291c38ff741f1b320e 100644 (file)
@@ -5,6 +5,9 @@
 #ifndef __NET_NETBEUI_H
 #define __NET_NETBEUI_H
 
+
+#define NB_NAME_LEN    16
+
 /*
  *     Used to keep lists of netbeui sessions
  */
@@ -51,12 +54,15 @@ struct nb_name
 #define NB_NAME_COLLIDE                2       /* Name collided - we failed */
 #define NB_OURS                        3       /* We own the name      */
 #define NB_NAME_OTHER          4       /* Name found - owned by other */
+#define NB_NAME_GET            5       /* Trying to allocate a name */
+#define NB_STATE               7       /* State bits */
+#define NB_NAME_GROUP          8       /* Group name bit */
        int ours;                       /* We own this name */
        int users;                      /* Number of nb_ses's to this name */
        struct timer_list       timer;  /* Our timer */
        int timer_mode;                 /* Timer mode */
 #define NB_TIMER_ACQUIRE       1       /* Expiry means we got our name */
-#define NB_TIMER_COLLIDE       2       /* Expire a collded record */
+#define NB_TIMER_COLLIDE       2       /* Expire a collided record */
 #define NB_TIMER_DROP          3       /* Drop a learned record */     
 };
 
@@ -78,5 +84,67 @@ extern struct nb_name *netbeui_add_name(char *name, int ours);
 extern struct nb_name *netbeui_lookup_name(char *name);
 extern int nb_delete_name(struct nb_name *name);
 
+/*
+ *     NetBEUI Protocol items
+ */
+
+#define ADD_GROUP_NAME_QUERY   0x00
+#define ADD_NAME_QUERY         0x01
+#define NAME_IN_CONFLICT       0x02
+#define STATUS_QUERY           0x03
+#define TERMINATE_TRACE                0x07
+#define DATAGRAM               0x08
+#define DATAGRAM_BROADCAST     0x09
+#define NAME_QUERY             0x0A
+#define ADD_NAME_RESPONSE      0x0D
+#define NAME_RECOGNIZED                0x0E
+#define STATUS_RESPONSE                0x0F
+#define TERMINATE_TRACE2       0x13
+#define DATA_ACK               0x14
+#define DATA_FIRST_MIDDLE      0x15
+#define DATA_ONLY_LAST         0x16
+#define SESSION_CONFIRM                0x17
+#define SESSION_END            0x18
+#define SESSION_INITIALIZE     0x19
+#define NO_RECEIVE             0x1A
+#define RECEIVE_OUTSTANDING    0x1B
+#define RECEIVE_CONTINUE       0x1C
+#define SESSION_ALIVE          0x1F
+
+#define NB_TRANSMIT_COUNT      6
+#define NB_TRANSMIT_TIMEOUT    (HZ/2)
+
+#define NB_DESCRIM_1           0xEF
+#define NB_DESCRIM_2           0xFF
+
+struct nb_dgram_pkt
+{
+       __u16   length;
+       __u8    descrim1;
+       __u8    descrim2;
+       __u8    command;
+       __u8    option1;
+       __u16   option2;
+       __u16   tx_seq;
+       __u16   rx_seq;
+       __u8    dest[NB_NAME_LEN];
+       __u8    src[NB_NAME_LEN];
+};
+
+struct nb_sess_pkt
+{
+       __u16   length;
+       __u8    descrim1;
+       __u8    descrim2;
+       __u8    command;
+       __u8    option1;
+       __u16   option2;
+       __u16   tx_seq;
+       __u16   rx_seq;
+       __u8    dnum;
+       __u8    snum;
+};
+
+#define NO_SEQ 0
 
 #endif
index 8a6c2d9e2f078c7626dd5658af29a30953c2bae7..b9e91a3d317e84a550ad05a2fe6f232a8b66a172 100644 (file)
@@ -66,6 +66,7 @@ extern __inline__ void nlmsg_ack(struct nlmsg_ctl* ctl, unsigned long seq,
 #define NETLINK_ARPD           8
 #define NETLINK_IPSEC          10      /* IPSEC */
 #define NETLINK_ROUTE6         11      /* af_inet6 route comm channel */
+#define NETLINK_IP6_FW         13
 /* Wouldn't this suffice instead of the confusion at the top of
    this file?  i.e. 3 is firewall or ppp... */
 /* #define MAX_LINKS           16 */
index 42190c8b806e73e3ffb8aeb0dcbbd222864ef8ef..3e60c1b313bc84795665ddbf9b36d52fb99a31df 100644 (file)
 
 
 /* This is used to register protocols. */
-struct inet_protocol {
-  int                  (*handler)(struct sk_buff *skb, unsigned short len);
-  void                 (*err_handler)(struct sk_buff *skb, unsigned char *dp);
-  struct inet_protocol *next;
-  unsigned char                protocol;
-  unsigned char                copy:1;
-  void                 *data;
-  const char           *name;
+struct inet_protocol 
+{
+       int                     (*handler)(struct sk_buff *skb, unsigned short len);
+       void                    (*err_handler)(struct sk_buff *skb, unsigned char *dp);
+       struct inet_protocol    *next;
+       unsigned char           protocol;
+       unsigned char           copy:1;
+       void                    *data;
+       const char              *name;
 };
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-struct inet6_protocol {
-  int                  (*handler)(struct sk_buff *skb, struct device *dev,
-                                  struct in6_addr *saddr,
-                                  struct in6_addr *daddr,
-                                  struct ipv6_options *opt, 
-                                  unsigned short len,
-                                  int redo, struct inet6_protocol *protocol);
+struct inet6_protocol 
+{
+       int     (*handler)(struct sk_buff *skb, struct device *dev,
+                       struct in6_addr *saddr,
+                       struct in6_addr *daddr,
+                       struct ipv6_options *opt, 
+                       unsigned short len,
+                       int redo, struct inet6_protocol *protocol);
 
-  void                 (*err_handler)(int type, int code, unsigned char *buff,
-                                      __u32 info, struct in6_addr *saddr,
-                                      struct in6_addr *daddr,
-                                      struct inet6_protocol *protocol);
-  struct inet6_protocol *next;
-  unsigned char                protocol;
-  unsigned char                copy:1;
-  void                 *data;
-  const char           *name;
+       void    (*err_handler)(int type, int code, unsigned char *buff,
+                       __u32 info, struct in6_addr *saddr,
+                       struct in6_addr *daddr,
+                       struct inet6_protocol *protocol);
+       struct inet6_protocol *next;
+       unsigned char   protocol;
+       unsigned char   copy:1;
+       void            *data;
+       const char      *name;
 };
 #endif
 
@@ -73,12 +75,12 @@ extern struct inet6_protocol *inet6_protocol_base;
 extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
 #endif
 
-extern void            inet_add_protocol(struct inet_protocol *prot);
-extern int             inet_del_protocol(struct inet_protocol *prot);
+extern void    inet_add_protocol(struct inet_protocol *prot);
+extern int     inet_del_protocol(struct inet_protocol *prot);
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-extern void            inet6_add_protocol(struct inet6_protocol *prot);
-extern int             inet6_del_protocol(struct inet6_protocol *prot);
+extern void    inet6_add_protocol(struct inet6_protocol *prot);
+extern int     inet6_del_protocol(struct inet6_protocol *prot);
 #endif
 
 #endif /* _PROTOCOL_H */
index f5cafb8ab98861c790badb6c2900f62eacb9fa32..d309ab63f04761d43c7c8f913cb8769b97b72298 100644 (file)
@@ -100,7 +100,7 @@ struct rtable
 /*
  *     Flags not visible at user level.
  */
-#define RTF_INTERNAL   0xFFFF0000
+#define RTF_INTERNAL   0xFFFF8000      /* to get RTF_MAGIC as well... */
 
 /*
  *     Flags saved in FIB.
index f262f00d16b4cb37a6cdf6442093773aa718ca58..d37a7a3555a337f010d473506ed562b2abb4c331 100644 (file)
@@ -152,9 +152,9 @@ struct ipv6_pinfo
                                mc_loop:1,
                                 unused:2;
 
-       /* device for outgoing mcast packets */
+       /* device for outgoing packets */
 
-       struct device           *mc_if;
+       struct device           *oif;
 
        struct ipv6_mc_socklist *ipv6_mc_list;
        /* 
@@ -164,8 +164,8 @@ struct ipv6_pinfo
         * (ex. PMTU)
         */
        
-       struct dest_entry       *dest;
-       __u32                   dc_sernum;
+       struct dst_entry        *dst;
+       __u32                   dst_cookie;
 
        struct ipv6_options     *opt;
 };
@@ -317,7 +317,7 @@ struct sock
        __u32                   syn_seq;
        __u32                   urg_seq;
        __u32                   urg_data;
-       int                     users;                  /* user count */
+       int                     sock_readers;           /* user count */
 
        unsigned char           delayed_acks,
                                dup_acks;
@@ -328,7 +328,6 @@ struct sock
        volatile char           dead,
                                urginline,
                                intr,
-                               blog,
                                done,
                                reuse,
                                keepopen,
@@ -343,14 +342,15 @@ struct sock
        unsigned long           lingertime;
        int                     proc;
 
-       struct sock             **hashtable;
-       int                     hashent;
        struct sock             *next;
+       struct sock             **pprev;
+       struct sock             *bind_next;
+       struct sock             **bind_pprev;
        struct sock             *prev;
+       int                     hashent;
        struct sock             *pair;
 
        struct sk_buff          * send_head;
-       struct sk_buff          * send_tail;
 
        struct sk_buff_head     back_log;
        struct sk_buff          *partial;
@@ -426,7 +426,10 @@ struct sock
        unsigned short          type;
        unsigned char           localroute;     /* Route locally only */
        struct ucred            peercred;
-  
+       /* What the user has tried to set with the security API */
+       short                   authentication;
+       short                   encryption;  
+       short                   encrypt_net;
 /*
  *     This is where all the private (optional) areas that don't
  *     overlap will eventually live. 
@@ -511,19 +514,6 @@ struct sock
                                                struct sk_buff *skb);  
 };
 
-#if 0
-/*
- *     Inet protocol options
- */
-struct inet_options {
-       __u8                            version;
-       union {
-               struct options          opt_v4;
-               struct ipv6_options     opt_v6;
-       } u;
-};
-#endif
-
 /*
  *     IP protocol blocks we attach to sockets.
  *     socket layer -> transport layer interface
@@ -665,14 +655,27 @@ static inline void lock_sock(struct sock *sk)
 #if 0
 /* debugging code: the test isn't even 100% correct, but it can catch bugs */
 /* Note that a double lock is ok in theory - it's just _usually_ a bug */
-       if (sk->users) {
+       if (sk->sock_readers) {
                __label__ here;
                printk("double lock on socket at %p\n", &&here);
 here:
        }
 #endif
-       sk->users++;
+#ifdef __SMP__
+       /*
+        * This is a very broken bottom half synchronization mechanism.
+        * You don't want to know..
+        */
+       { unsigned long flags;
+       save_flags(flags);
+       cli();
+       sk->sock_readers++;
+       restore_flags(flags);
+       }
+#else
+       sk->sock_readers++;
        barrier();
+#endif
 }
 
 static inline void release_sock(struct sock *sk)
@@ -680,14 +683,14 @@ static inline void release_sock(struct sock *sk)
        barrier();
 #if 0
 /* debugging code: remove me when ok */
-       if (sk->users == 0) {
+       if (sk->sock_readers == 0) {
                __label__ here;
-               sk->users = 1;
+               sk->sock_readers = 1;
                printk("trying to unlock unlocked socket at %p\n", &&here);
 here:
        }
 #endif
-       if ((sk->users = sk->users-1) == 0)
+       if ((sk->sock_readers = sk->sock_readers-1) == 0)
                __release_sock(sk);
 }
 
@@ -738,6 +741,7 @@ extern struct sk_buff               *sock_alloc_send_skb(struct sock *sk,
                                                     unsigned long fallback,
                                                     int noblock,
                                                     int *errcode);
+
 extern int                     sock_no_fcntl(struct socket *, unsigned int, unsigned long);
 extern int                     sock_no_getsockopt(struct socket *, int , int,
                                                   char *, int *);
index b112394130a45344465ab7ab7dcbd2f017577dc5..07f32c01960a3082bdd62f634cbc036299ebd482 100644 (file)
 #include <net/checksum.h>
 
 /* This is for all connections with a full identity, no wildcards. */
-#define TCP_HTABLE_SIZE                128
+#define TCP_HTABLE_SIZE                256
 
 /* This is for listening sockets, thus all sockets which possess wildcards. */
-#define TCP_LHTABLE_SIZE       16      /* Yes, really, this is all you need. */
+#define TCP_LHTABLE_SIZE       32      /* Yes, really, this is all you need. */
 
 /* This is for all sockets, to keep track of the local port allocations. */
 #define TCP_BHTABLE_SIZE       64
@@ -71,23 +71,19 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
 static __inline__ void tcp_sk_bindify(struct sock *sk)
 {
        int hashent = tcp_sk_bhashfn(sk);
+       struct sock **htable = &tcp_bound_hash[hashent];
 
-       sk->prev = tcp_bound_hash[hashent];
-       tcp_bound_hash[hashent] = sk;
+       if((sk->bind_next = *htable) != NULL)
+               (*htable)->bind_pprev = &sk->bind_next;
+       *htable = sk;
+       sk->bind_pprev = htable;
 }
 
 static __inline__ void tcp_sk_unbindify(struct sock *sk)
 {
-       int hashent = tcp_sk_bhashfn(sk);
-       struct sock **htable = &tcp_bound_hash[hashent];
-
-       while(*htable) {
-               if(*htable == sk) {
-                       *htable = sk->prev;
-                       break;
-               }
-               htable = &((*htable)->prev);
-       }
+       if(sk->bind_next)
+               sk->bind_next->bind_pprev = sk->bind_pprev;
+       *(sk->bind_pprev) = sk->bind_next;
 }
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -315,7 +311,7 @@ extern int                  tcp_v4_rcv(struct sk_buff *skb,
 
 extern int                     tcp_do_sendmsg(struct sock *sk, 
                                               int iovlen, struct iovec *iov,
-                                              int len, int flags);
+                                              int flags);
 
 extern int                     tcp_ioctl(struct sock *sk, 
                                          int cmd, 
@@ -371,8 +367,9 @@ extern struct sock *                tcp_v4_syn_recv_sock(struct sock *sk,
                                                     struct sk_buff *skb,
                                                     struct open_request *req);
 
-extern int                     tcp_v4_backlog_rcv(struct sock *sk,
-                                                  struct sk_buff *skb);
+extern int                     tcp_v4_do_rcv(struct sock *sk,
+                                             struct sk_buff *skb);
+
 extern int                     tcp_v4_connect(struct sock *sk,
                                               struct sockaddr *uaddr,
                                               int addr_len);
index 1e70c377093bab499ed814a027a73e0d8057e647..b080ebfc4c44ad2ec37f11f73514128c23c2095b 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/fs.h>
+#include <linux/proc_fs.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/utsname.h>
@@ -887,7 +888,9 @@ asmlinkage void start_kernel(void)
        }
 #endif
        mem_init(memory_start,memory_end);
+#ifdef CONFIG_PROC_FS
        proc_root_init();
+#endif
        kmem_cache_sizes_init();
        vma_init();
        buffer_init();
index 0a78e836d393e017dfc61b444639642c8f3fab71..c21506d7de0bdecc628a99ec359c0667f736b567 100644 (file)
@@ -577,7 +577,7 @@ static void exit_notify(void)
 
 NORET_TYPE void do_exit(long code)
 {
-       if (intr_count) {
+       if (0 && intr_count) {
                printk("Aiee, killing interrupt handler\n");
                intr_count = 0;
        }
index 18f8025f3f2b05806273426e360ddcb014f5470c..e636942e84cd7ba5aca14d4a7f8a4146457fa6f9 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/random.h>
+#include <linux/reboot.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/sysctl.h>
@@ -81,8 +82,6 @@ extern int sys_tz;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 
-extern void hard_reset_now(void);
-
 #ifdef MODVERSIONS
 const struct module_symbol __export_Using_Versions
 __attribute__((section("__ksymtab"))) = {
@@ -302,7 +301,11 @@ EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(simple_strtoul);
 EXPORT_SYMBOL(system_utsname);
 EXPORT_SYMBOL(sys_call_table);
-EXPORT_SYMBOL(hard_reset_now);
+EXPORT_SYMBOL(machine_restart);
+EXPORT_SYMBOL(machine_halt);
+EXPORT_SYMBOL(machine_power_off);
+EXPORT_SYMBOL(register_reboot_notifier);
+EXPORT_SYMBOL(unregister_reboot_notifier);
 EXPORT_SYMBOL(_ctype);
 EXPORT_SYMBOL(secure_tcp_sequence_number);
 
index 3d7ad954064933e5f2244ce338d7e0e14801b48d..9932c953195abf26e030a94c5b1b4a5947e60726 100644 (file)
@@ -14,9 +14,9 @@
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
+#include <linux/reboot.h>
 
 asmlinkage void sys_sync(void);        /* it's really int */
-extern void hard_reset_now(void);
 extern void do_unblank_screen(void);
 extern int C_A_D;
 
@@ -62,7 +62,7 @@ NORET_TYPE void panic(const char * fmt, ...)
                 *      choosing not too. It might crash, be corrupt or do
                 *      more harm than good for other reasons.
                 */
-               hard_reset_now();
+               machine_restart(NULL);
        }
 #ifdef __sparc__
        printk("Press L1-A to return to the boot prom\n");
index b0ea9c5216839edcf1f3857edcef850560cadb12..fd63c906e373fed1c7fe5692617d671790c70b94 100644 (file)
@@ -174,8 +174,8 @@ asmlinkage int printk(const char *fmt, ...)
        static signed char msg_level = -1;
        long flags;
 
-       save_flags(flags);
-       cli();
+       __save_flags(flags);
+       __cli();
        va_start(args, fmt);
        i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
        buf_end = buf + 3 + i;
@@ -218,7 +218,7 @@ asmlinkage int printk(const char *fmt, ...)
                if (*p == '\n')
                        msg_level = -1;
        }
-       restore_flags(flags);
+       __restore_flags(flags);
        wake_up_interruptible(&log_wait);
        return i;
 }
index 09ba07bb18a7de74c76342d15240fb11ea65180d..bd83b34d273260d7d20f830e8a36fdad90f30a53 100644 (file)
@@ -69,7 +69,7 @@ static resource_entry_t *find_gap(resource_entry_t *root,
 /*
  * Call this from the device driver to register the ioport region.
  */
-void request_region(unsigned int from, unsigned int num, const char *name)
+void request_region(unsigned long from, unsigned long num, const char *name)
 {
        resource_entry_t *p;
        int i;
@@ -95,7 +95,7 @@ void request_region(unsigned int from, unsigned int num, const char *name)
 /* 
  * Call this when the device driver is unloaded
  */
-void release_region(unsigned int from, unsigned int num)
+void release_region(unsigned long from, unsigned long num)
 {
        resource_entry_t *p, *q;
 
@@ -114,7 +114,7 @@ void release_region(unsigned int from, unsigned int num)
 /*
  * Call this to check the ioport region before probing
  */
-int check_region(unsigned int from, unsigned int num)
+int check_region(unsigned long from, unsigned long num)
 {
        return (find_gap(&iolist, from, num) == NULL) ? -EBUSY : 0;
 }
@@ -123,10 +123,10 @@ int check_region(unsigned int from, unsigned int num)
 /*
  * This is for architectures with MMU-managed ports (sparc).
  */
-unsigned int occupy_region(unsigned int base, unsigned int end,
-                       unsigned int num, unsigned int align, const char *name)
+unsigned int occupy_region(unsigned long base, unsigned long end,
+                       unsigned long num, unsigned int align, const char *name)
 {
-       unsigned int from = 0, till;
+       unsigned long from = 0, till;
        unsigned long flags;
        int i;
        resource_entry_t *p;            /* Scanning ptr */
index 55fa2d88776e4edf96c00819025f302a6dd02a05..baebd79de4b4e1317d3b4fd23a1994649821e95d 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
+#include <asm/spinlock.h>
 
 #include <linux/timex.h>
 
@@ -125,7 +126,7 @@ static inline void add_to_runqueue(struct task_struct * p)
        (p->prev_run = init_task.prev_run)->next_run = p;
        p->next_run = &init_task;
        init_task.prev_run = p;
-#ifdef __SMP__
+#if 0 /* def __SMP__ */
        /* this is safe only if called with cli()*/
        inc_smp_counter(&smp_process_available);
        if ((0!=p->pid) && smp_threads_ready)
@@ -185,6 +186,18 @@ static inline void move_last_runqueue(struct task_struct * p)
        prev->next_run = p;
 }
 
+/*
+ * The scheduler lock is protecting against multiple entry
+ * into the scheduling code, and doesn't need to worry
+ * about interrupts (because interrupts cannot call the
+ * scheduler).
+ *
+ * The run-queue lock locks the parts that actually access
+ * and change the run-queues, and have to be interrupt-safe.
+ */
+spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;
+
 /*
  * Wake up a process. Put it on the run-queue if it's not
  * already there.  The "current" process is always on the
@@ -197,12 +210,11 @@ inline void wake_up_process(struct task_struct * p)
 {
        unsigned long flags;
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&runqueue_lock, flags);
        p->state = TASK_RUNNING;
        if (!p->next_run)
                add_to_runqueue(p);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&runqueue_lock, flags);
 }
 
 static void process_timeout(unsigned long __data)
@@ -230,17 +242,6 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in
 {
        int weight;
 
-#ifdef __SMP__ 
-       /* We are not permitted to run a task someone else is running */
-       if (p->processor != NO_PROC_ID)
-               return -1000;
-#ifdef PAST_2_0                
-       /* This process is locked to a processor group */
-       if (p->processor_mask && !(p->processor_mask & (1<<this_cpu))
-               return -1000;
-#endif         
-#endif
-
        /*
         * Realtime process, select the first one on the
         * runqueue (taking priorities within processes
@@ -274,24 +275,17 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in
        return weight;
 }
 
-void allow_interrupts(void)
-{
-#if defined(__SMP__) && defined(__i386__)
-/* UGH UGH UGH. Damn broken IRQ handling test-fix for x86.. */
-       int this_cpu=smp_processor_id();
-       int lock_depth = current_set[this_cpu]->lock_depth;
-       if (lock_depth) {
-               cli();
-               current_set[this_cpu]->lock_depth = 0;
-               active_kernel_processor = NO_PROC_ID;
-               __asm__ __volatile__("lock ; btrl    $0, kernel_flag");
-               sti();
-               /* interrupts should work here */
-               lock_kernel();
-               current_set[this_cpu]->lock_depth += lock_depth-1;
-       }
+#ifdef __SMP__
+
+#define idle_task (task[cpu_number_map[this_cpu]])
+#define can_schedule(p)        ((p)->processor == NO_PROC_ID)
+
+#else
+
+#define idle_task (&init_task)
+#define can_schedule(p) (1)
+
 #endif
-}              
 
 /*
  *  'schedule()' is the scheduler function. It's a very simple and nice
@@ -305,31 +299,28 @@ void allow_interrupts(void)
  */
 asmlinkage void schedule(void)
 {
-       int c;
-       struct task_struct * p;
+       static int need_recalculate = 0;
+       int lock_depth;
        struct task_struct * prev, * next;
-       unsigned long timeout = 0;
-       int this_cpu=smp_processor_id();
-
-/* check alarm, wake up any interruptible tasks that have got a signal */
-       allow_interrupts();
-       lock_kernel();
-       if (intr_count)
-               goto scheduling_in_interrupt;
+       unsigned long timeout;
+       int this_cpu;
 
+       need_resched = 0;
+       this_cpu = smp_processor_id();
+       prev = current;
+       release_kernel_lock(prev, this_cpu, lock_depth);
        if (bh_active & bh_mask)
                do_bottom_half();
 
-       run_task_queue(&tq_scheduler);
+       spin_lock(&scheduler_lock);
+       spin_lock_irq(&runqueue_lock);
 
-       need_resched = 0;
-       prev = current;
-       cli();
        /* move an exhausted RR process to be last.. */
        if (!prev->counter && prev->policy == SCHED_RR) {
                prev->counter = prev->priority;
                move_last_runqueue(prev);
        }
+       timeout = 0;
        switch (prev->state) {
                case TASK_INTERRUPTIBLE:
                        if (prev->signal & ~prev->blocked)
@@ -346,54 +337,44 @@ asmlinkage void schedule(void)
                        del_from_runqueue(prev);
                case TASK_RUNNING:
        }
-       p = init_task.next_run;
-       sti();
+       {
+               struct task_struct * p = init_task.next_run;
+               /*
+                * This is subtle.
+                * Note how we can enable interrupts here, even
+                * though interrupts can add processes to the run-
+                * queue. This is because any new processes will
+                * be added to the front of the queue, so "p" above
+                * is a safe starting point.
+                * run-queue deletion and re-ordering is protected by
+                * the scheduler lock
+                */
+               spin_unlock_irq(&runqueue_lock);
        
-#ifdef __SMP__
-       /*
-        *      This is safe as we do not permit re-entry of schedule()
-        */
-       prev->processor = NO_PROC_ID;
-#define idle_task (task[cpu_number_map[this_cpu]])
-#else
-#define idle_task (&init_task)
-#endif 
-
 /*
  * Note! there may appear new tasks on the run-queue during this, as
  * interrupts are enabled. However, they will be put on front of the
  * list, so our list starting at "p" is essentially fixed.
  */
 /* this is the scheduler proper: */
-       c = -1000;
-       next = idle_task;
-       while (p != &init_task) {
-               int weight = goodness(p, prev, this_cpu);
-               if (weight > c)
-                       c = weight, next = p;
-               p = p->next_run;
+               {
+                       int c = -1000;
+                       next = idle_task;
+                       while (p != &init_task) {
+                               if (can_schedule(p)) {
+                                       int weight = goodness(p, prev, this_cpu);
+                                       if (weight > c)
+                                               c = weight, next = p;
+                               }
+                               p = p->next_run;
+                       }
+                       need_recalculate = !c;
+               }
        }
 
-       /* if all runnable processes have "counter == 0", re-calculate counters */
-       if (!c) {
-               for_each_task(p)
-                       p->counter = (p->counter >> 1) + p->priority;
-       }
-#ifdef __SMP__
-       /*
-        *      Allocate process to CPU
-        */
-        
-        next->processor = this_cpu;
-        next->last_processor = this_cpu;
-#endif  
-#ifdef __SMP_PROF__ 
-       /* mark processor running an idle thread */
-       if (0==next->pid)
-               set_bit(this_cpu,&smp_idle_map);
-       else
-               clear_bit(this_cpu,&smp_idle_map);
-#endif
+       next->processor = this_cpu;
+       next->last_processor = this_cpu;
+
        if (prev != next) {
                struct timer_list timer;
 
@@ -407,16 +388,22 @@ asmlinkage void schedule(void)
                }
                get_mmu_context(next);
                switch_to(prev,next);
+
                if (timeout)
                        del_timer(&timer);
        }
-       goto out;
+       spin_unlock(&scheduler_lock);
 
-scheduling_in_interrupt:
-       printk("Aiee: scheduling in interrupt %p\n",
-               __builtin_return_address(0));
-out:
-       unlock_kernel();
+       if (lock_depth) {
+               reaquire_kernel_lock(prev, smp_processor_id(), lock_depth);
+
+               /* Do we need to re-calculate counters? */
+               if (need_recalculate) {
+                       struct task_struct *p;
+                       for_each_task(p)
+                               p->counter = (p->counter >> 1) + p->priority;
+               }
+       }
 }
 
 #ifndef __alpha__
@@ -436,68 +423,69 @@ asmlinkage int sys_pause(void)
 
 #endif
 
+spinlock_t waitqueue_lock;
+
 /*
  * wake_up doesn't wake up stopped processes - they have to be awakened
  * with signals or similar.
- *
- * Note that this doesn't need cli-sti pairs: interrupts may not change
- * the wait-queue structures directly, but only call wake_up() to wake
- * a process. The process itself must remove the queue once it has woken.
  */
 void wake_up(struct wait_queue **q)
 {
+       unsigned long flags;
        struct wait_queue *next;
        struct wait_queue *head;
 
-       if (!q || !(next = *q))
-               return;
-       head = WAIT_QUEUE_HEAD(q);
-       while (next != head) {
-               struct task_struct *p = next->task;
-               next = next->next;
-               if (p != NULL) {
-                       if ((p->state == TASK_UNINTERRUPTIBLE) ||
-                           (p->state == TASK_INTERRUPTIBLE))
-                               wake_up_process(p);
+       spin_lock_irqsave(&waitqueue_lock, flags);
+       if (q && (next = *q)) {
+               head = WAIT_QUEUE_HEAD(q);
+               while (next != head) {
+                       struct task_struct *p = next->task;
+                       next = next->next;
+                       if (p != NULL) {
+                               if ((p->state == TASK_UNINTERRUPTIBLE) ||
+                                   (p->state == TASK_INTERRUPTIBLE))
+                                       wake_up_process(p);
+                       }
+                       if (next)
+                               continue;
+                       printk("wait_queue is bad (eip = %p)\n",
+                               __builtin_return_address(0));
+                       printk("        q = %p\n",q);
+                       printk("       *q = %p\n",*q);
+                       break;
                }
-               if (!next)
-                       goto bad;
        }
-       return;
-bad:
-       printk("wait_queue is bad (eip = %p)\n",
-               __builtin_return_address(0));
-       printk("        q = %p\n",q);
-       printk("       *q = %p\n",*q);
+       spin_unlock_irqrestore(&waitqueue_lock, flags);
 }
 
 void wake_up_interruptible(struct wait_queue **q)
 {
+       unsigned long flags;
        struct wait_queue *next;
        struct wait_queue *head;
 
-       if (!q || !(next = *q))
-               return;
-       head = WAIT_QUEUE_HEAD(q);
-       while (next != head) {
-               struct task_struct *p = next->task;
-               next = next->next;
-               if (p != NULL) {
-                       if (p->state == TASK_INTERRUPTIBLE)
-                               wake_up_process(p);
+       spin_lock_irqsave(&waitqueue_lock, flags);
+       if (q && (next = *q)) {
+               head = WAIT_QUEUE_HEAD(q);
+               while (next != head) {
+                       struct task_struct *p = next->task;
+                       next = next->next;
+                       if (p != NULL) {
+                               if (p->state == TASK_INTERRUPTIBLE)
+                                       wake_up_process(p);
+                       }
+                       if (next)
+                               continue;
+                       printk("wait_queue is bad (eip = %p)\n",
+                               __builtin_return_address(0));
+                       printk("        q = %p\n",q);
+                       printk("       *q = %p\n",*q);
+                       break;
                }
-               if (!next)
-                       goto bad;
        }
-       return;
-bad:
-       printk("wait_queue is bad (eip = %p)\n",
-               __builtin_return_address(0));
-       printk("        q = %p\n",q);
-       printk("       *q = %p\n",*q);
+       spin_unlock_irqrestore(&waitqueue_lock, flags);
 }
 
-
 /*
  * Semaphores are implemented using a two-way counter:
  * The "count" variable is decremented for each process
@@ -635,14 +623,14 @@ static inline void __sleep_on(struct wait_queue **p, int state)
        if (current == task[0])
                panic("task[0] trying to sleep");
        current->state = state;
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&waitqueue_lock, flags);
        __add_wait_queue(p, &wait);
+       spin_unlock(&waitqueue_lock);
        sti();
        schedule();
-       cli();
+       spin_lock_irq(&waitqueue_lock);
        __remove_wait_queue(p, &wait);
-       restore_flags(flags);
+       spin_unlock_irqrestore(&waitqueue_lock, flags);
 }
 
 void interruptible_sleep_on(struct wait_queue **p)
@@ -718,8 +706,10 @@ static inline void internal_add_timer(struct timer_list *timer)
        } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
                int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
                insert_timer(timer, tv4.vec, i);
-       } else if ((idx + 1UL) == 0UL) {
-               /* can happen if you add a timer with expires == jiffies */
+       } else if (expires < timer_jiffies) {
+               /* can happen if you add a timer with expires == jiffies,
+                * or you set a timer to go off in the past
+                */
                insert_timer(timer, tv1.vec, tv1.index);
        } else if (idx < 0xffffffffUL) {
                int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
@@ -730,11 +720,13 @@ static inline void internal_add_timer(struct timer_list *timer)
        }
 }
 
+static spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
+
 void add_timer(struct timer_list *timer)
 {
        unsigned long flags;
-       save_flags(flags);
-       cli();
+
+       spin_lock_irqsave(&timerlist_lock, flags);
 #if SLOW_BUT_DEBUGGING_TIMERS
         if (timer->next || timer->prev) {
                 printk("add_timer() called with non-zero list from %p\n",
@@ -746,7 +738,7 @@ void add_timer(struct timer_list *timer)
 #if SLOW_BUT_DEBUGGING_TIMERS
 out:
 #endif
-       restore_flags(flags);
+       spin_unlock_irqrestore(&timerlist_lock, flags);
 }
 
 static inline int detach_timer(struct timer_list *timer)
@@ -770,11 +762,11 @@ int del_timer(struct timer_list * timer)
 {
        int ret;
        unsigned long flags;
-       save_flags(flags);
-       cli();
+
+       spin_lock_irqsave(&timerlist_lock, flags);
        ret = detach_timer(timer);
        timer->next = timer->prev = 0;
-       restore_flags(flags);
+       spin_unlock_irqrestore(&timerlist_lock, flags);
        return ret;
 }
 
@@ -798,7 +790,7 @@ static inline void cascade_timers(struct timer_vec *tv)
 
 static inline void run_timer_list(void)
 {
-       cli();
+       spin_lock_irq(&timerlist_lock);
        while ((long)(jiffies - timer_jiffies) >= 0) {
                struct timer_list *timer;
                if (!tv1.index) {
@@ -812,14 +804,14 @@ static inline void run_timer_list(void)
                        unsigned long data = timer->data;
                        detach_timer(timer);
                        timer->next = timer->prev = NULL;
-                       sti();
+                       spin_unlock_irq(&timerlist_lock);
                        fn(data);
-                       cli();
+                       spin_lock_irq(&timerlist_lock);
                }
                ++timer_jiffies; 
                tv1.index = (tv1.index + 1) & TVR_MASK;
        }
-       sti();
+       spin_unlock_irq(&timerlist_lock);
 }
 
 
@@ -841,6 +833,8 @@ static inline void run_old_timers(void)
        }
 }
 
+spinlock_t tqueue_lock;
+
 void tqueue_bh(void)
 {
        run_task_queue(&tq_timer);
@@ -1484,12 +1478,13 @@ static int setscheduler(pid_t pid, int policy,
 
        p->policy = policy;
        p->rt_priority = lp.sched_priority;
-       cli();
+       spin_lock(&scheduler_lock);
+       spin_lock_irq(&runqueue_lock);
        if (p->next_run)
                move_last_runqueue(p);
-       sti();
-       schedule();
-
+       spin_unlock_irq(&runqueue_lock);
+       spin_unlock(&scheduler_lock);
+       need_resched = 1;
        return 0;
 }
 
@@ -1558,11 +1553,12 @@ out:
 
 asmlinkage int sys_sched_yield(void)
 {
-       lock_kernel();
-       cli();
+       spin_unlock(&scheduler_lock);
+       spin_lock_irq(&runqueue_lock);
        move_last_runqueue(current);
-       sti();
-       unlock_kernel();
+       spin_unlock_irq(&runqueue_lock);
+       spin_lock(&scheduler_lock);
+       need_resched = 1;
        return 0;
 }
 
@@ -1570,7 +1566,6 @@ asmlinkage int sys_sched_get_priority_max(int policy)
 {
        int ret = -EINVAL;
 
-       lock_kernel();
        switch (policy) {
        case SCHED_FIFO:
        case SCHED_RR:
@@ -1580,7 +1575,6 @@ asmlinkage int sys_sched_get_priority_max(int policy)
                ret = 0;
                break;
        }
-       unlock_kernel();
        return ret;
 }
 
@@ -1588,7 +1582,6 @@ asmlinkage int sys_sched_get_priority_min(int policy)
 {
        int ret = -EINVAL;
 
-       lock_kernel();
        switch (policy) {
        case SCHED_FIFO:
        case SCHED_RR:
@@ -1597,23 +1590,18 @@ asmlinkage int sys_sched_get_priority_min(int policy)
        case SCHED_OTHER:
                ret = 0;
        }
-       unlock_kernel();
        return ret;
 }
 
 asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
 {
        struct timespec t;
-       int ret;
 
-       lock_kernel();
        t.tv_sec = 0;
-       t.tv_nsec = 0;            /* <-- Linus, please fill correct value in here */
-       ret = -ENOSYS; goto out;  /* and then delete this line. Thanks!           */
-       ret = copy_to_user(interval, &t, sizeof(struct timespec)) ? -EFAULT : 0;
-out:
-       unlock_kernel();
-       return ret;
+       t.tv_nsec = 150000;
+       if (copy_to_user(interval, &t, sizeof(struct timespec)))
+               return -EFAULT;
+       return 0;
 }
 
 /*
index 3dfcb85fd1aea89218e64ac997f2f993f8177d64..9a8915391559f0cc86f203fef76abfc41036ea67 100644 (file)
@@ -170,40 +170,24 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
        struct sigaction * oldaction)
 {
        struct sigaction new_sa, *p;
-       int ret = -EINVAL;
 
-       lock_kernel();
        if (signum<1 || signum>32)
-               goto out;
+               return -EINVAL;
        p = signum - 1 + current->sig->action;
        if (action) {
-               ret = verify_area(VERIFY_READ, action, sizeof(*action));
-               if (ret)
-                       goto out;
-               ret = -EINVAL;
-               if (signum==SIGKILL || signum==SIGSTOP)
-                       goto out;
-               ret = -EFAULT;
                if (copy_from_user(&new_sa, action, sizeof(struct sigaction)))
-                       goto out;
-               if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
-                       ret = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
-                       if (ret)
-                               goto out;
-               }
+                       return -EFAULT;
+               if (signum==SIGKILL || signum==SIGSTOP)
+                       return -EINVAL;
        }
-       ret = -EFAULT;
        if (oldaction) {
                if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
-                       goto out;       
+                       return -EFAULT;
        }
        if (action) {
                *p = new_sa;
                check_pending(signum);
        }
-       ret = 0;
-out:
-       unlock_kernel();
-       return ret;
+       return 0;
 }
 #endif
index e60265a3e2ccf749a00aa54aa8cb733ee7c6c43f..50e61b6ef4a43947e485ca8b760664a3301de8ad 100644 (file)
@@ -23,6 +23,8 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
 
 atomic_t intr_count = 0;
 
@@ -48,36 +50,28 @@ void (*bh_base[32])(void);
 static inline void run_bottom_halves(void)
 {
        unsigned long active;
-       unsigned long mask, left;
        void (**bh)(void);
 
-       cli();
-       active = bh_active & bh_mask;
-       bh_active &= ~active;
-       sti();
+       active = get_active_bhs();
+       clear_active_bhs(active);
        bh = bh_base;
-       for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
-               if (mask & active) {
+       do {
+               if (active & 1)
                        (*bh)();
-               }
-       }
+               bh++;
+               active >>= 1;
+       } while (active);
 }
 
-/*
- * We really shouldn't need to get the kernel lock here,
- * but we do it the easy way for now (the scheduler gets
- * upset if somebody messes with intr_count without having
- * the kernel lock).
- *
- * Get rid of the kernel lock here at the same time we
- * make interrupt handling sane. 
- */
 asmlinkage void do_bottom_half(void)
 {
-       lock_kernel();
-       atomic_inc(&intr_count);
-       if (intr_count == 1)
-               run_bottom_halves();
-       atomic_dec(&intr_count);
-       unlock_kernel();
+       int cpu = smp_processor_id();
+
+       if (hardirq_trylock(cpu)) {
+               if (softirq_trylock()) {
+                       run_bottom_halves();
+                       softirq_endlock();
+               }
+               hardirq_endlock(cpu);
+       }
 }
index 94b6cc0fe0969a6b2707a6cb93337b5b614f85c0..9bd1062ded2f7babf410e9f717a8c489d41c9421 100644 (file)
@@ -4,7 +4,6 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
-#include <linux/apm_bios.h>
-#endif
 #include <linux/notifier.h>
+#include <linux/reboot.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
 int C_A_D = 1;
 
+
 /*
- *     List of functions to call at shutdown. This is used to stop any
- *     idling DMA operations and the like. 
+ *     Notifier list for kernel code which wants to be called
+ *     at shutdown. This is used to stop any idling DMA operations
+ *     and the like. 
  */
-struct notifier_block *boot_notifier_list=NULL;
+
+struct notifier_block *reboot_notifier_list = NULL;
+
+int register_reboot_notifier(struct notifier_block * nb)
+{
+       return notifier_chain_register(&reboot_notifier_list, nb);
+}
+
+int unregister_reboot_notifier(struct notifier_block * nb)
+{
+       return notifier_chain_unregister(&reboot_notifier_list, nb);
+}
+
+
 
 extern void adjust_clock(void);
 
@@ -189,10 +200,6 @@ asmlinkage int sys_prof(void)
 
 #endif
 
-extern void hard_reset_now(void);
-#ifdef __sparc__
-extern void halt_now(void);
-#endif
 extern asmlinkage int sys_kill(int, int);
 
 /*
@@ -202,42 +209,69 @@ extern asmlinkage int sys_kill(int, int);
  * You can also set the meaning of the ctrl-alt-del-key here.
  *
  * reboot doesn't sync: do that yourself before calling this.
+ *
  */
-asmlinkage int sys_reboot(int magic, int magic_too, int flag)
+asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg)
 {
+       char buffer[256];
+
+       /* We only trust the superuser with rebooting the system. */
        if (!suser())
                return -EPERM;
-       if (magic != 0xfee1dead || 
-           (magic_too != 672274793 && magic_too != 85072278))
-               return -EINVAL;
 
+       /* For safety, we require "magic" arguments. */
+       if (magic1 != LINUX_REBOOT_MAGIC1 ||
+           (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A))
+               return -EINVAL;
 
-       if (flag == 0x01234567)
-       {
-               /* SMP: We need to lock during the shutdown still */
-               lock_kernel();
-               notifier_call_chain(&boot_notifier_list, SYS_DOWN, NULL);
-               hard_reset_now();
-       }
-       else if (flag == 0x89ABCDEF)
+       lock_kernel();
+       switch (cmd) {
+       case LINUX_REBOOT_CMD_RESTART:
+               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+               printk(KERN_EMERG "Restarting system.\n");
+               machine_restart(NULL);
+               break;
+
+       case LINUX_REBOOT_CMD_CAD_ON:
                C_A_D = 1;
-       else if (!flag)
+               break;
+
+       case LINUX_REBOOT_CMD_CAD_OFF:
                C_A_D = 0;
-       else if (flag == 0xCDEF0123) {
-               /* SMP: We need to lock during the shutdown still */
-               lock_kernel();
-               printk(KERN_EMERG "System halted\n");
-#ifdef __sparc__
-               halt_now();
-#endif 
-               sys_kill(-1, SIGKILL);
-#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
-               apm_set_power_state(APM_STATE_OFF);
-#endif
-               notifier_call_chain(&boot_notifier_list, SYS_HALT, NULL);
+               break;
+
+       case LINUX_REBOOT_CMD_HALT:
+               notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
+               printk(KERN_EMERG "System halted.\n");
+               machine_halt();
                do_exit(0);
-       } else
+               break;
+
+       case LINUX_REBOOT_CMD_POWER_OFF:
+               notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+               printk(KERN_EMERG "Power down.\n");
+               machine_power_off();
+               do_exit(0);
+               break;
+
+       case LINUX_REBOOT_CMD_RESTART2:
+               if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
+                       unlock_kernel();
+                       return -EFAULT;
+               }
+               buffer[sizeof(buffer) - 1] = '\0';
+
+               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
+               printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
+               machine_restart(buffer);
+               break;
+
+       default:
+               unlock_kernel();
                return -EINVAL;
+               break;
+       };
+       unlock_kernel();
        return 0;
 }
 
@@ -248,12 +282,10 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
  */
 void ctrl_alt_del(void)
 {
-       if (C_A_D)
-       {
-               notifier_call_chain(&boot_notifier_list, SYS_DOWN, NULL);
-               hard_reset_now();
-       }
-       else
+       if (C_A_D) {
+               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+               machine_restart(NULL);
+       } else
                kill_proc(1, SIGINT, 1);
 }
        
index 7c0540729aa5135628293e09a98057095917a3c1..0e6e3b5fbba1f3a001c4d808d515d273b6501b03 100644 (file)
@@ -91,11 +91,6 @@ asmlinkage int sys_stime(int * tptr)
                return -EPERM;
        if (get_user(value, tptr))
                return -EFAULT;
-       /*
-        *      SMP: We need to lock out everything for the time update
-        *      the new cli/sti semantics will let us drop this lock soon.
-        */
-       lock_kernel();
        cli();
        xtime.tv_sec = value;
        xtime.tv_usec = 0;
@@ -103,7 +98,6 @@ asmlinkage int sys_stime(int * tptr)
        time_maxerror = MAXPHASE;
        time_esterror = MAXPHASE;
        sti();
-       unlock_kernel();
        return 0;
 }
 
@@ -111,23 +105,17 @@ asmlinkage int sys_stime(int * tptr)
 
 asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
-       int err = -EFAULT;
-
-       lock_kernel();
        if (tv) {
                struct timeval ktv;
                do_gettimeofday(&ktv);
                if (copy_to_user(tv, &ktv, sizeof(ktv)))
-                       goto out;
+                       return -EFAULT;
        }
        if (tz) {
                if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
-                       goto out;
+                       return -EFAULT;
        }
-       err = 0;
-out:
-       unlock_kernel();
-       return err;
+       return 0;
 }
 
 /*
index fb439fbd8adbab328b2f0d08ddab0013953841e3..e25db950d42c06e9868ad5094b9101d872e68061 100644 (file)
@@ -753,7 +753,7 @@ page_read_error:
        filp->f_reada = 1;
        if (page_cache)
                free_page(page_cache);
-       if (!IS_RDONLY(inode)) {
+       if (DO_UPDATE_ATIME(inode)) {
                inode->i_atime = CURRENT_TIME;
                inode->i_dirt = 1;
        }
@@ -1188,7 +1188,7 @@ int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_s
                return -EACCES;
        if (!inode->i_op || !inode->i_op->readpage)
                return -ENOEXEC;
-       if (!IS_RDONLY(inode)) {
+       if (DO_UPDATE_ATIME(inode)) {
                inode->i_atime = CURRENT_TIME;
                inode->i_dirt = 1;
        }
index 16fceb8e5b52b35d8a98adea57766eb6ef575f10..f7f94b7fd0576181fcf35b19939a346f4a3a7771 100644 (file)
@@ -266,6 +266,7 @@ void *kmalloc(size_t size, int priority)
        priority &= GFP_LEVEL_MASK;
 
 /* Sanity check... */
+#if 0  /* no longer valid */
        if (intr_count && priority != GFP_ATOMIC) {
                static int count = 0;
                if (++count < 5) {
@@ -274,7 +275,7 @@ void *kmalloc(size_t size, int priority)
                        priority = GFP_ATOMIC;
                }
        }
-
+#endif
        save_flags(flags);
        cli();
        page = *pg;
index 0b76eea08c9096eee3945fcf523116d33a59d529..1d79ed729a7fd1442d875d904e18a02647ef4337 100644 (file)
@@ -201,6 +201,7 @@ unsigned long __get_free_pages(int priority, unsigned long order, int dma)
 
        if (order >= NR_MEM_LISTS)
                return 0;
+#if 0
        if (intr_count && priority != GFP_ATOMIC) {
                static int count = 0;
                if (++count < 5) {
@@ -209,6 +210,7 @@ unsigned long __get_free_pages(int priority, unsigned long order, int dma)
                        priority = GFP_ATOMIC;
                }
        }
+#endif
        reserved_pages = 5;
        if (priority != GFP_NFS)
                reserved_pages = min_free_pages;
index 8b8ee2d932b03ed3946e540c2c0fc9c5e77c5c30..4b4ddea88ec8e985ea7b3c41b8070755b467c6b5 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -478,7 +478,7 @@ kmem_cache_create(const char *name, unsigned long size, unsigned long align,
                printk(KERN_ERR "%sNULL ptr\n", func_nm);
                return NULL;
        }
-       if (intr_count) {
+       if (0 && intr_count) {
                printk(KERN_ERR "%sCalled during int - %s\n", func_nm, name);
                return NULL;
        }
@@ -743,7 +743,7 @@ kmem_cache_destroy(kmem_cache_t *cachep)
                goto err_end;
        }
 
-       if (intr_count) {
+       if (0 && intr_count) {
                printk(KERN_ERR "kmem_dest: Called during int - %s\n", cachep->c_name);
 err_end:
                return 1;
@@ -809,7 +809,7 @@ kmem_cache_shrink(kmem_cache_t *cachep, int wait)
                goto end;
        }
 
-       if (intr_count) {
+       if (0 && intr_count) {
                printk(KERN_ERR "kmem_shrink: Called during int - %s\n", cachep->c_name);
                goto end;
        }
@@ -951,7 +951,7 @@ kmem_cache_grow(kmem_cache_t *cachep, unsigned long flags)
         * in kmem_cache_alloc().  If a caller is slightly mis-behaving,
         * will eventually be caught here (where it matters)
         */
-       if (intr_count && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) {
+       if (0 && intr_count && (flags & SLAB_LEVEL_MASK) != SLAB_ATOMIC) {
                static int count = 0;
                if (count < 8) {
                        printk(KERN_ERR "kmem_grow: Called nonatomically from "
index e987bd2c80b2f711f8fff9a75dddd6f789613f36..9b9403b5a42b0f8187dc12918be08a8608ddf07e 100644 (file)
@@ -1,5 +1,5 @@
 
-/* this file was generated on Wed Dec 18 23:01:37 GMT 1996  */
+/* this file was generated on Mon Mar 10 22:45:36 GMT 1997  */
 
 
 /* size of transition table is 898 bytes */
index b5b0bdf68b4ed50aaac03d0d3a01e8dfc76293bf..97441ad6cc724b2a71d66fe1e3304cf415cd8f27 100644 (file)
@@ -8,12 +8,17 @@ if [ "$CONFIG_NETLINK" = "y" ]; then
   bool 'Routing messages' CONFIG_RTNETLINK
 fi
 bool 'Network firewalls' CONFIG_FIREWALL
+if [ "$CONFIG_FIREWALL" = "y" ]; then
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'Socket Security API Support (EXPERIMENTAL)' CONFIG_NET_SECURITY
+  fi
+fi
 bool 'Network aliasing'  CONFIG_NET_ALIAS
 bool 'TCP/IP networking' CONFIG_INET
 if [ "$CONFIG_INET" = "y" ]; then
   source net/ipv4/Config.in
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'The IPv6 protocol' CONFIG_IPV6
+    tristate 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6
   fi
 fi
 
@@ -31,7 +36,7 @@ if [ "$CONFIG_ATALK" != "n" ]; then
 fi
 tristate 'Amateur Radio AX.25 Level 2' CONFIG_AX25
 if [ "$CONFIG_AX25" != "n" ]; then
-# bool 'AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE
+  bool 'AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE
 # bool 'AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER
   dep_tristate 'Amateur Radio NET/ROM' CONFIG_NETROM $CONFIG_AX25
   dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25
@@ -40,7 +45,10 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
-  bool '802.2 LLC (VERY EXPERIMENTAL)' CONFIG_LLC
+  bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
+#  if [ "$CONFIG_LLC" = "y" ]; then
+#   bool 'Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
+#  fi
   tristate 'WAN router' CONFIG_WAN_ROUTER
 fi
 endmenu
index ef287f128d93b181ffe6414bfa5680db256819c1..09327483c7a9ae7019cf4deeeb51316ff8093853 100644 (file)
@@ -9,7 +9,8 @@ appletalk               alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
 ax25                   jsn@cs.nott.ac.uk
 core                   alan@lxorguk.ukuu.org.uk
 ethernet               alan@lxorguk.ukuu.org.uk
-ipv4                   alan@lxorguk.ukuu.org.uk
+ipv4                   davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
+ipv6                   davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
 ipx                    alan@lxorguk.ukuu.org.uk,greg@caldera.com
 lapb                   jsn@cs.nott.ac.uk
 netrom                 jsn@cs.nott.ac.uk
index 8a79c6a3798eb60f511e9bda1b781785ef9a7a55..9f125cd4327b3e0c1e937e116d6366c004b47e4b 100644 (file)
@@ -410,14 +410,11 @@ static struct at_addr *atalk_find_primary(void)
 
 static struct atalk_iface *atalk_find_anynet(int node, struct device *dev)
 {
-       struct atalk_iface *iface;
-       for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
-       {
-               if ( iface->dev != dev || ( iface->status & ATIF_PROBE ))
-                       continue;
-               if ( node == ATADDR_BCAST || iface->address.s_node == node )
-                       return iface;
-       }
+       struct atalk_iface *iface=dev->atalk_ptr;
+       if (iface==NULL || ( iface->status & ATIF_PROBE ))
+               return NULL;
+       if ( node == ATADDR_BCAST || iface->address.s_node == node || node == ATADDR_ANYNODE)
+               return iface;
        return NULL;
 }
 
@@ -1184,7 +1181,8 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
 #define SIOCDELIPDDPRT SIOCDEVPRIVATE+1
 #define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2
 
-struct ipddp_route {
+struct ipddp_route 
+{
        struct device *dev;             /* Carrier device */
        __u32 ip;                       /* IP address */
        struct at_addr at;              /* Gateway appletalk address */
@@ -1215,6 +1213,7 @@ int ipddp_xmit(struct sk_buff *skb, struct device *dev)
        skb_pull(skb,4);
        
        ((struct net_device_stats *) dev->priv)->tx_packets++;
+       ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
 
        /* printk("ipddp_xmit called with headroom %d\n",skb_headroom(skb)); */
 
@@ -1226,7 +1225,7 @@ int ipddp_xmit(struct sk_buff *skb, struct device *dev)
 
 struct net_device_stats *ipddp_get_stats(struct device *dev)
 {
-       return (struct enet_statistics *) dev->priv;
+       return (struct net_device_stats *) dev->priv;
 }
 
 int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
@@ -1443,16 +1442,12 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                return(0);
        }
 
-#ifdef CONFIG_FIREWALL
-
-       if(call_in_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT)
+       if(call_in_firewall(AF_APPLETALK, skb->dev, ddp, NULL,&skb)!=FW_ACCEPT)
        {
                kfree_skb(skb, FREE_READ);
                return 0;
        }
 
-#endif
-
        /* Check the packet is aimed at us */
 
        if(ddp->deh_dnet == 0)  /* Net 0 is 'this network' */
@@ -1474,17 +1469,16 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
                        return(0);
                }
 
-#ifdef CONFIG_FIREWALL
                /*
                 *      Check firewall allows this routing
                 */
 
-               if(call_fw_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT)
+               if(call_fw_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb)!=FW_ACCEPT)
                {
                        kfree_skb(skb, FREE_READ);
                        return(0);
                }
-#endif
+
                ta.s_net=ddp->deh_dnet;
                ta.s_node=ddp->deh_dnode;
 
@@ -1546,9 +1540,10 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
         *      Check if IP-over-DDP
         */
 
-       if(skb->data[12]==22) {
-               struct enet_statistics *estats = 
-                       (struct enet_statistics *) dev_ipddp.priv;
+       if(skb->data[12]==22) 
+       {
+               struct net_device_stats *estats = 
+                       (struct net_device_stats *) dev_ipddp.priv;
                skb->protocol=htons(ETH_P_IP);
                skb_pull(skb,13);
                skb->dev=&dev_ipddp;
@@ -1558,6 +1553,7 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
         *              ntohs(skb->h.iph->tot_len),skb->len);
         */
                estats->rx_packets++;
+               estats->rx_bytes+=skb->len+13;
                netif_rx(skb);
                return 0;
        }
@@ -1762,16 +1758,12 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
        else
                ddp->deh_sum=atalk_checksum(ddp, len+sizeof(*ddp));
 
-#ifdef CONFIG_FIREWALL
-
-       if(call_out_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT)
+       if(call_out_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb)!=FW_ACCEPT)
        {
                kfree_skb(skb, FREE_WRITE);
                return -EPERM;
        }
 
-#endif
-
        /*
         *      Loopback broadcast packets to non gateway targets (ie routes
         *      to group we are in)
index b2bd04ae54562fbba792a3a4e0a4f7acc5b798aa..cec1b09d17d96be65d0b76e8d9eeb26e72c8b0c4 100644 (file)
@@ -16,6 +16,10 @@ M_OBJS   := $(O_TARGET)
 
 OX_OBJS  += af_ax25.o
 
+ifeq ($(CONFIG_AX25_DAMA_SLAVE),y)
+O_OBJS += ax25_ds_in.o ax25_ds_subr.o ax25_ds_timer.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 tar:
index a61c722f4e0d501d43ab8714f956fd08b37a98cc..efe8a9a7066dbdcf5241d2c5fe4a75941ccfa794 100644 (file)
@@ -93,6 +93,7 @@
  *                     Frederic(F1OAT)         Support for pseudo-digipeating.
  *                     Jonathan(G4KLX)         Support for packet forwarding.
  *     AX.25 036       Jonathan(G4KLX)         Major restructuring.
+ *                     Joerg(DL1BKE)           Fixed DAMA Slave.
  */
 
 #include <linux/config.h>
@@ -461,8 +462,12 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                case AX25_KILL:
                        ax25_clear_queues(ax25);
                        ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-
                        ax25->state = AX25_STATE_0;
+#ifdef CONFIG_AX25_DAMA_SLAVE
+                       if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
+                               ax25_dama_off(ax25);
+#endif
+
                        if (ax25->sk != NULL) {
                                ax25->sk->state     = TCP_CLOSE;
                                ax25->sk->err       = ENETRESET;
@@ -472,10 +477,6 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                                ax25->sk->dead  = 1;
                        }
 
-#ifdef CONFIG_AX25_DAMA_SLAVE
-                       if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
-                               ax25_dama_off(ax25);
-#endif
                        ax25_set_timer(ax25);
                        break;
 
@@ -634,14 +635,13 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
        if (level != SOL_AX25)
                return -ENOPROTOOPT;
 
-       if(optlen<sizeof(int))
+       if (optlen < sizeof(int))
                return -EINVAL;
-               
-       if(get_user(opt, (int *)optval))
+
+       if (get_user(opt, (int *)optval))
                return -EFAULT;
 
-       switch (optname) 
-       {
+       switch (optname) {
                case AX25_WINDOW:
                        if (sk->protinfo.ax25->modulus == AX25_MODULUS) {
                                if (opt < 1 || opt > 7)
@@ -716,13 +716,12 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
 {
        struct sock *sk = sock->sk;
        int val = 0;
-       int err;
        int len;
 
        if (level != SOL_AX25)
                return -ENOPROTOOPT;
 
-       if(get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
 
        switch (optname) {
@@ -774,11 +773,14 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
                        return -ENOPROTOOPT;
        }
 
-       len=min(len,sizeof(int));
-       if(put_user(len, optlen))
+       len = min(len, sizeof(int));
+
+       if (put_user(len, optlen))
                return -EFAULT;
-       if(copy_to_user(optval, &val, len))
+
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
+
        return 0;
 }
 
@@ -976,13 +978,14 @@ static int ax25_release(struct socket *sock, struct socket *peer)
                                ax25_clear_queues(sk->protinfo.ax25);
                                sk->protinfo.ax25->n2count = 0;
                                switch (sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-                                       case AX25_PROTO_STD:
+                                       case AX25_PROTO_STD_SIMPLEX:
+                                       case AX25_PROTO_STD_DUPLEX:
                                                ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
                                                sk->protinfo.ax25->t3timer = 0;
                                                break;
 #ifdef AX25_CONFIG_DAMA_SLAVE
                                        case AX25_PROTO_DAMA_SLAVE:
-                                               sk->protinfo.ax25->t3timer = sk->protinfo.ax25->t3;     /* DAMA slave timeout */
+                                               sk->protinfo.ax25->t3timer = 0;
                                                break;
 #endif
                                }
@@ -1168,12 +1171,17 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
        sk->state          = TCP_SYN_SENT;
 
        switch (sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-               case AX25_PROTO_STD:
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
                        ax25_std_establish_data_link(sk->protinfo.ax25);
                        break;
+
 #ifdef CONFIG_AX25_DAMA_SLAVE
                case AX25_PROTO_DAMA_SLAVE:
-                       ax25_ds_establish_data_link(sk->protinfo.ax25);
+                       if (sk->protinfo.ax25->ax25_dev->dama.slave)
+                               ax25_ds_establish_data_link(sk->protinfo.ax25);
+                       else
+                               ax25_std_establish_data_link(sk->protinfo.ax25);
                        break;
 #endif
        }
index dcd1ecd6fa24717cc357c3a674324eb30fd60821..418537162959e2ed0254b04aa9e35e48228fad2e 100644 (file)
@@ -83,6 +83,8 @@ void ax25_dev_device_up(struct device *dev)
 
        ax25_unregister_sysctl();
 
+       memset(ax25_dev, 0x00, sizeof(*ax25_dev));
+
        ax25_dev->dev     = dev;
        ax25_dev->forward = NULL;
 
@@ -98,7 +100,12 @@ void ax25_dev_device_up(struct device *dev)
        ax25_dev->values[AX25_VALUES_IDLE]      = AX25_DEF_IDLE;
        ax25_dev->values[AX25_VALUES_N2]        = AX25_DEF_N2;
        ax25_dev->values[AX25_VALUES_PACLEN]    = AX25_DEF_PACLEN;
+#ifdef CONFIG_AX25_DAMA_SLAVE
+       ax25_dev->values[AX25_VALUES_PROTOCOL]  = AX25_PROTO_DAMA_SLAVE;
+#else
        ax25_dev->values[AX25_VALUES_PROTOCOL]  = AX25_DEF_PROTOCOL;
+#endif
+       ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
 
        save_flags(flags); cli();
        ax25_dev->next = ax25_dev_list;
@@ -120,6 +127,10 @@ void ax25_dev_device_down(struct device *dev)
 
        save_flags(flags); cli();
 
+#ifdef CONFIG_AX25_DAMA_SLAVE
+       ax25_ds_del_timer(ax25_dev);
+#endif
+
        /*
         *      Remove any packet forwarding that points to this device.
         */
diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
new file mode 100644 (file)
index 0000000..6af2ba9
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ *     AX.25 release 036
+ *
+ *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *     releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *     This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *     This module:
+ *             This module 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.
+ *
+ *     Most of this code is based on the SDL diagrams published in the 7th
+ *     ARRL Computer Networking Conference papers. The diagrams have mistakes
+ *     in them, but are mostly correct. Before you modify the code could you
+ *     read the SDL diagrams as the code is not obvious and probably very
+ *     easy to break;
+ *
+ *     History
+ *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_in.c
+ *                     Joerg(DL1BKE)   Fixed it.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_AX25_DAMA_SLAVE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <net/ax25.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/ip.h>                    /* For ip_rcv */
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+/*
+ *     State machine for state 1, Awaiting Connection State.
+ *     The handling of the timer(s) is in file ax25_timer.c.
+ *     Handling of state 0 and connection release is in ax25.c.
+ */
+static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
+{
+       switch (frametype) {
+               case AX25_SABM:
+                       ax25->modulus = AX25_MODULUS;
+                       ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       break;
+
+               case AX25_SABME:
+                       ax25->modulus = AX25_EMODULUS;
+                       ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       break;
+
+               case AX25_DISC:
+                       ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+                       break;
+
+               case AX25_UA:
+                       ax25_calculate_rtt(ax25);
+                       ax25->t1timer = 0;
+                       ax25->t3timer = ax25->t3;
+                       ax25->idletimer = ax25->idle;
+                       ax25->vs      = 0;
+                       ax25->va      = 0;
+                       ax25->vr      = 0;
+                       ax25->state   = AX25_STATE_3;
+                       ax25->n2count = 0;
+                       if (ax25->sk != NULL) {
+                               ax25->sk->state = TCP_ESTABLISHED;
+                               /* For WAIT_SABM connections we will produce an accept ready socket here */
+                               if (!ax25->sk->dead)
+                                       ax25->sk->state_change(ax25->sk);
+                       }
+                       ax25_dama_on(ax25);
+
+                       /* according to DK4EG´s spec we are required to
+                        * send a RR RESPONSE FINAL NR=0. Please mail
+                        * <jr@lykos.oche.de> if this causes problems
+                        * with the TheNetNode DAMA Master implementation.
+                        */ 
+
+                       ax25_std_enquiry_response(ax25);
+                       break;
+
+               case AX25_DM:
+                       if (pf) {
+                               if (ax25->modulus == AX25_MODULUS) {
+                                       ax25_clear_queues(ax25);
+                                       ax25->state = AX25_STATE_0;
+                                       if (ax25->sk != NULL) {
+                                               ax25->sk->state     = TCP_CLOSE;
+                                               ax25->sk->err       = ECONNREFUSED;
+                                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                                               if (!ax25->sk->dead)
+                                                       ax25->sk->state_change(ax25->sk);
+                                               ax25->sk->dead      = 1;
+                                       }
+                               } else {
+                                       ax25->modulus = AX25_MODULUS;
+                                       ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+                               }
+                       }
+                       break;
+
+               default:
+                       if (pf)
+                               ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+                       break;
+       }
+
+       return 0;
+}
+
+/*
+ *     State machine for state 2, Awaiting Release State.
+ *     The handling of the timer(s) is in file ax25_timer.c
+ *     Handling of state 0 and connection release is in ax25.c.
+ */
+static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
+{
+       switch (frametype) {
+               case AX25_SABM:
+               case AX25_SABME:
+                       ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+                       ax25->dama_slave = 0;
+                       ax25_dama_off(ax25);
+                       break;
+
+               case AX25_DISC:
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25->state = AX25_STATE_0;
+                       ax25_dama_off(ax25);
+
+                       if (ax25->sk != NULL) {
+                               ax25->sk->state     = TCP_CLOSE;
+                               ax25->sk->err       = 0;
+                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                               if (!ax25->sk->dead)
+                                       ax25->sk->state_change(ax25->sk);
+                               ax25->sk->dead      = 1;
+                       }
+                       break;
+
+               case AX25_DM:
+               case AX25_UA:
+                       if (pf) {
+                               ax25->state = AX25_STATE_0;
+                               ax25_dama_off(ax25);
+
+                               if (ax25->sk != NULL) {
+                                       ax25->sk->state     = TCP_CLOSE;
+                                       ax25->sk->err       = 0;
+                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
+                                       if (!ax25->sk->dead)
+                                               ax25->sk->state_change(ax25->sk);
+                                       ax25->sk->dead      = 1;
+                               }
+                       }
+                       break;
+
+               case AX25_I:
+               case AX25_REJ:
+               case AX25_RNR:
+               case AX25_RR:
+                       if (pf) {
+                               ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+                               ax25->dama_slave = 0;
+                               ax25_dama_off(ax25);
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
+/*
+ *     State machine for state 3, Connected State.
+ *     The handling of the timer(s) is in file ax25_timer.c
+ *     Handling of state 0 and connection release is in ax25.c.
+ */
+static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
+{
+       int queued = 0;
+
+       switch (frametype) {
+               case AX25_SABM:
+               case AX25_SABME:
+                       if (frametype == AX25_SABM) {
+                               ax25->modulus = AX25_MODULUS;
+                               ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+                       } else {
+                               ax25->modulus = AX25_EMODULUS;
+                               ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+                       }
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25->condition = 0x00;
+                       ax25->t1timer   = 0;
+                       ax25->t3timer   = ax25->t3;
+                       ax25->idletimer = ax25->idle;
+                       ax25->vs        = 0;
+                       ax25->va        = 0;
+                       ax25->vr        = 0;
+                       ax25_requeue_frames(ax25);
+                       ax25_dama_on(ax25);
+                       break;
+
+               case AX25_DISC:
+                       ax25_clear_queues(ax25);
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25->t3timer = 0;
+                       ax25->state   = AX25_STATE_0;
+                       ax25_dama_off(ax25);
+
+                       if (ax25->sk != NULL) {
+                               ax25->sk->state     = TCP_CLOSE;
+                               ax25->sk->err       = 0;
+                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                               if (!ax25->sk->dead)
+                                       ax25->sk->state_change(ax25->sk);
+                               ax25->sk->dead      = 1;
+                       }
+                       break;
+
+               case AX25_DM:
+                       ax25_clear_queues(ax25);
+                       ax25->t3timer = 0;
+                       ax25->state   = AX25_STATE_0;
+                       ax25_dama_off(ax25);
+
+                       if (ax25->sk != NULL) {
+                               ax25->sk->state     = TCP_CLOSE;
+                               ax25->sk->err       = ECONNRESET;
+                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                               if (!ax25->sk->dead)
+                                       ax25->sk->state_change(ax25->sk);
+                               ax25->sk->dead      = 1;
+                       }
+                       break;
+
+               case AX25_RR:
+               case AX25_RNR:
+                       if (frametype == AX25_RR)
+                               ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+                       else
+                               ax25->condition |= AX25_COND_PEER_RX_BUSY;
+                       if (ax25_validate_nr(ax25, nr)) {
+                               ax25_check_iframes_acked(ax25, nr);
+                               if (type == AX25_COMMAND && pf)
+                                       ax25_ds_enquiry_response(ax25);
+                       } else {
+                               ax25_ds_nr_error_recovery(ax25);
+                               ax25->state = AX25_STATE_1;
+                       }
+                       break;
+
+               case AX25_REJ:
+                       ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+                       if (ax25_validate_nr(ax25, nr)) {
+                               ax25_frames_acked(ax25, nr);
+                               ax25_calculate_rtt(ax25);
+                               ax25->n2count = 0;
+                               ax25->t1timer = 0;
+                               ax25->t3timer = ax25->t3;
+                               ax25_requeue_frames(ax25);
+                               if (type == AX25_COMMAND && pf)
+                                       ax25_ds_enquiry_response(ax25);
+                       } else {
+                               ax25_ds_nr_error_recovery(ax25);
+                               ax25->state = AX25_STATE_1;
+                       }
+                       break;
+
+               case AX25_I:
+                       if (!ax25_validate_nr(ax25, nr)) {
+                               ax25_ds_nr_error_recovery(ax25);
+                               ax25->state = AX25_STATE_1;
+                               break;
+                       }
+                       if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
+                               ax25_frames_acked(ax25, nr);
+                               ax25->n2count = 0;
+                       } else {
+                               ax25_check_iframes_acked(ax25, nr);
+                       }
+                       if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                               if (pf) ax25_ds_enquiry_response(ax25);
+                               break;
+                       }
+                       if (ns == ax25->vr) {
+                               ax25->vr = (ax25->vr + 1) % ax25->modulus;
+                               queued = ax25_rx_iframe(ax25, skb);
+                               if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                                       ax25->vr = ns;  /* ax25->vr - 1 */
+                                       if (pf) ax25_ds_enquiry_response(ax25);
+                                       break;
+                               }
+                               ax25->condition &= ~AX25_COND_REJECT;
+                               if (pf) {
+                                       ax25_ds_enquiry_response(ax25);
+                               } else {
+                                       if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+                                               ax25->t2timer = ax25->t2;
+                                               ax25->condition |= AX25_COND_ACK_PENDING;
+                                       }
+                               }
+                       } else {
+                               if (ax25->condition & AX25_COND_REJECT) {
+                                       if (pf) ax25_ds_enquiry_response(ax25);
+                               } else {
+                                       ax25->condition |= AX25_COND_REJECT;
+                                       ax25_ds_enquiry_response(ax25);
+                                       ax25->condition &= ~AX25_COND_ACK_PENDING;
+                               }
+                       }
+                       break;
+
+               case AX25_FRMR:
+               case AX25_ILLEGAL:
+                       ax25_ds_establish_data_link(ax25);
+                       ax25->state = AX25_STATE_1;
+                       break;
+
+               default:
+                       break;
+       }
+
+       return queued;
+}
+
+/*
+ *     State machine for state 4, Timer Recovery State.
+ *     The handling of the timer(s) is in file ax25_timer.c
+ *     Handling of state 0 and connection release is in ax25.c.
+ */
+static int ax25_ds_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
+{
+       int queued = 0;
+
+       switch (frametype) {
+               case AX25_SABM:
+               case AX25_SABME:
+                       if (frametype == AX25_SABM) {
+                               ax25->modulus = AX25_MODULUS;
+                               ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+                       } else {
+                               ax25->modulus = AX25_EMODULUS;
+                               ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+                       }
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25->condition = 0x00;
+                       ax25->t1timer   = 0;
+                       ax25->t3timer   = ax25->t3;
+                       ax25->idletimer = ax25->idle;
+                       ax25->vs        = 0;
+                       ax25->va        = 0;
+                       ax25->vr        = 0;
+                       ax25->state     = AX25_STATE_3;
+                       ax25->n2count   = 0;
+                       ax25_requeue_frames(ax25);
+                       ax25_dama_on(ax25);
+                       break;
+
+               case AX25_DISC:
+                       ax25_clear_queues(ax25);
+                       ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+                       ax25->t3timer = 0;
+                       ax25->state   = AX25_STATE_0;
+                       ax25_dama_off(ax25);
+
+                       if (ax25->sk != NULL) {
+                               ax25->sk->state     = TCP_CLOSE;
+                               ax25->sk->err       = 0;
+                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                               if (!ax25->sk->dead)
+                                       ax25->sk->state_change(ax25->sk);
+                               ax25->sk->dead      = 1;
+                       }
+                       break;
+
+               case AX25_DM:
+                       ax25_clear_queues(ax25);
+                       ax25->t3timer = 0;
+                       ax25->state   = AX25_STATE_0;
+                       ax25_dama_off(ax25);
+
+                       if (ax25->sk != NULL) {
+                               ax25->sk->state     = TCP_CLOSE;
+                               ax25->sk->err       = ECONNRESET;
+                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                               if (!ax25->sk->dead)
+                                       ax25->sk->state_change(ax25->sk);
+                               ax25->sk->dead      = 1;
+                       }
+                       break;
+
+               case AX25_RR:
+               case AX25_RNR:
+                       if (frametype == AX25_RR)
+                               ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+                       else
+                               ax25->condition |= AX25_COND_PEER_RX_BUSY;
+                       if (type == AX25_RESPONSE && pf) {
+                               ax25->t1timer = 0;
+                               if (ax25_validate_nr(ax25, nr)) {
+                                       ax25_frames_acked(ax25, nr);
+                                       ax25->n2count = 0;
+                                       if (ax25->vs == ax25->va) {
+                                               ax25->t3timer = ax25->t3;
+                                               ax25->state   = AX25_STATE_3;
+                                       } else {
+                                               ax25_requeue_frames(ax25);
+                                       }
+                               } else {
+                                       ax25_ds_nr_error_recovery(ax25);
+                                       ax25->state = AX25_STATE_1;
+                               }
+                               break;
+                       }
+                       if (ax25_validate_nr(ax25, nr)) {
+                               ax25_frames_acked(ax25, nr);
+                               ax25->n2count = 0;
+                               if (type == AX25_COMMAND && pf)
+                                       ax25_ds_enquiry_response(ax25);
+                       } else {
+                               ax25_ds_nr_error_recovery(ax25);
+                               ax25->state = AX25_STATE_1;
+                       }
+                       break;
+
+               case AX25_REJ:
+                       ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+                       if (pf) {
+                               ax25->t1timer = 0;
+                               if (ax25_validate_nr(ax25, nr)) {
+                                       ax25_frames_acked(ax25, nr);
+                                       ax25->n2count = 0;
+                                       if (ax25->vs == ax25->va) {
+                                               ax25->t3timer = ax25->t3;
+                                               ax25->state   = AX25_STATE_3;
+                                       } else {
+                                               ax25_requeue_frames(ax25);
+                                       }
+                                       if (type == AX25_COMMAND && pf)
+                                               ax25_ds_enquiry_response(ax25);
+                               } else {
+                                       ax25_ds_nr_error_recovery(ax25);
+                                       ax25->state = AX25_STATE_1;
+                               }
+                               break;
+                       }
+                       if (ax25_validate_nr(ax25, nr)) {
+                               ax25_frames_acked(ax25, nr);
+                               ax25->n2count = 0;
+                               ax25_requeue_frames(ax25);
+                               if (type == AX25_COMMAND && pf)
+                                       ax25_ds_enquiry_response(ax25);
+                       } else {
+                               ax25_ds_nr_error_recovery(ax25);
+                               ax25->state = AX25_STATE_1;
+                       }
+                       break;
+
+               case AX25_I:
+                       if (!ax25_validate_nr(ax25, nr)) {
+                               ax25_ds_nr_error_recovery(ax25);
+                               ax25->state = AX25_STATE_1;
+                               break;
+                       }
+                       ax25_frames_acked(ax25, nr);
+                       ax25->n2count = 0;
+                       if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                               if (pf) ax25_ds_enquiry_response(ax25);
+                               break;
+                       }
+                       if (ns == ax25->vr) {
+                               ax25->vr = (ax25->vr + 1) % ax25->modulus;
+                               queued = ax25_rx_iframe(ax25, skb);
+                               if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+                                       ax25->vr = ns;  /* ax25->vr - 1 */
+                                       if (pf) ax25_ds_enquiry_response(ax25);
+                                       break;
+                               }
+                               ax25->condition &= ~AX25_COND_REJECT;
+                               if (pf) {
+                                       ax25_ds_enquiry_response(ax25);
+                               } else {
+                                       if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+                                               ax25->t2timer = ax25->t2;
+                                               ax25->condition |= AX25_COND_ACK_PENDING;
+                                       }
+                               }
+                       } else {
+                               if (ax25->condition & AX25_COND_REJECT) {
+                                       if (pf) ax25_ds_enquiry_response(ax25);
+                               } else {
+                                       ax25->condition |= AX25_COND_REJECT;
+                                       ax25_ds_enquiry_response(ax25);
+                                       ax25->condition &= ~AX25_COND_ACK_PENDING;
+                               }
+                       }
+                       break;
+
+               case AX25_FRMR:
+               case AX25_ILLEGAL:
+                       ax25_ds_establish_data_link(ax25);
+                       ax25->state = AX25_STATE_1;
+                       break;
+
+               default:
+                       break;
+       }
+
+       return queued;
+}
+
+/*
+ *     Higher level upcall for a LAPB frame
+ */
+int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
+{
+       int queued = 0, frametype, ns, nr, pf;
+
+       frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
+
+       switch (ax25->state) {
+               case AX25_STATE_1:
+                       queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
+                       break;
+               case AX25_STATE_2:
+                       queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
+                       break;
+               case AX25_STATE_3:
+                       queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
+                       break;
+               case AX25_STATE_4:
+                       queued = ax25_ds_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
+                       break;
+       }
+
+       return queued;
+}
+
+#endif
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
new file mode 100644 (file)
index 0000000..cc15542
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ *     AX.25 release 036
+ *
+ *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *     releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *     This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *     This module:
+ *             This module 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.
+ *
+ *     Most of this code is based on the SDL diagrams published in the 7th
+ *     ARRL Computer Networking Conference papers. The diagrams have mistakes
+ *     in them, but are mostly correct. Before you modify the code could you
+ *     read the SDL diagrams as the code is not obvious and probably very
+ *     easy to break;
+ *
+ *     History
+ *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c.
+ *                     Joerg(DL1BKE)   Changed ax25_ds_enquiry_response(),
+ *                                     fixed ax25_dama_on() and ax25_dama_off().
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_AX25_DAMA_SLAVE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <net/ax25.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+void ax25_ds_nr_error_recovery(ax25_cb *ax25)
+{
+       ax25_ds_establish_data_link(ax25);
+}
+
+/*
+ *     dl1bke 960114: transmit I frames on DAMA poll
+ */
+void ax25_ds_enquiry_response(ax25_cb *ax25)
+{
+       ax25_cb *ax25o;
+
+       /* Please note that neither DK4EG´s nor DG2FEF´s
+        * DAMA spec mention the following behaviour as seen
+        * with TheFirmware:
+        *
+        *      DB0ACH->DL1BKE <RR C P R0> [DAMA]
+        *      DL1BKE->DB0ACH <I NR=0 NS=0>
+        *      DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
+        *      DL1BKE->DB0ACH <RR R F R0>
+        *
+        * The Flexnet DAMA Master implementation apparently
+        * insists on the "proper" AX.25 behaviour:
+        *
+        *      DB0ACH->DL1BKE <RR C P R0> [DAMA]
+        *      DL1BKE->DB0ACH <RR R F R0>
+        *      DL1BKE->DB0ACH <I NR=0 NS=0>
+        *      DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
+        *
+        * Flexnet refuses to send us *any* I frame if we send
+        * a REJ in case AX25_COND_REJECT is set. It is superfluous in 
+        * this mode anyway (a RR or RNR invokes the retransmission).
+        * Is this a Flexnet bug?
+        */
+
+       ax25_std_enquiry_response(ax25);
+
+       if (!(ax25->condition & AX25_COND_PEER_RX_BUSY)) {
+               ax25_requeue_frames(ax25);
+               ax25_kick(ax25);
+       }
+
+       if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2 || skb_peek(&ax25->ack_queue) != NULL)
+               ax25_ds_t1_timeout(ax25);
+       else
+               ax25->n2count = 0;
+
+       ax25->t3timer = ax25->t3;
+       ax25_ds_set_timer(ax25->ax25_dev);
+
+       for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
+               if (ax25o == ax25)
+                       continue;
+
+               if (ax25o->ax25_dev != ax25->ax25_dev)
+                       continue;
+
+               if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2) {
+                       ax25_ds_t1_timeout(ax25o);
+                       continue;
+               }
+
+               if (!(ax25o->condition & AX25_COND_PEER_RX_BUSY) && 
+                   (ax25o->state == AX25_STATE_3 || 
+                   (ax25o->state == AX25_STATE_4 && ax25o->t1timer == 0))) {
+                       ax25_requeue_frames(ax25o);
+                       ax25_kick(ax25o);
+               }
+
+               if (ax25o->state == AX25_STATE_1 || ax25o->state == AX25_STATE_2 || skb_peek(&ax25o->ack_queue) != NULL)
+                       ax25_ds_t1_timeout(ax25o);
+
+               ax25o->t3timer = ax25o->t3;
+       }
+}
+
+void ax25_ds_establish_data_link(ax25_cb *ax25)
+{
+       ax25->condition = 0x00;
+       ax25->n2count   = 0;
+
+       ax25->t3timer = ax25->t3;
+       ax25->t2timer = 0;
+       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+}
+
+/*
+ *     :::FIXME:::
+ *     This is a kludge. Not all drivers recognize kiss commands. 
+ *     We need a driver level  request to switch duplex mode, that does 
+ *     either SCC changing, PI config or KISS as required. Currently
+ *     this request isn't reliable.
+ *
+ */
+static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char param)
+{
+       struct sk_buff *skb;
+       unsigned char *p;
+
+       if (ax25_dev->dev == NULL)
+               return;
+
+       if ((skb = alloc_skb(2, GFP_ATOMIC)) == NULL)
+               return;
+
+       p = skb_put(skb, 2);
+
+       *p++ = cmd;
+       *p++ = param;
+
+       skb->arp      = 1;
+       skb->dev      = ax25_dev->dev;
+       skb->priority = SOPRI_NORMAL;
+       skb->protocol = htons(ETH_P_AX25);
+
+       dev_queue_xmit(skb);
+}
+
+/*
+ *     A nasty problem arises if we count the number of DAMA connections
+ *     wrong, especially when connections on the device already existed
+ *     and our network node (or the sysop) decides to turn on DAMA Master
+ *     mode. We thus flag the 'real' slave connections with 
+ *     ax25->dama_slave=1 and look on every disconnect if still slave
+ *     connections exist.
+ */
+
+static int ax25_check_dama_slave(ax25_dev *ax25_dev)
+{
+       ax25_cb *ax25;
+
+       for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next)
+               if (ax25->ax25_dev == ax25_dev && ax25->dama_slave && ax25->state > AX25_STATE_1)
+                       return 1;
+
+       return 0;
+}
+
+void ax25_dev_dama_on(ax25_dev *ax25_dev)
+{
+       if (ax25_dev == NULL)
+               return;
+
+       if (ax25_dev->dama.slave == 0)
+               ax25_kiss_cmd(ax25_dev, 5, 1);
+
+       ax25_dev->dama.slave = 1;
+       ax25_ds_set_timer(ax25_dev);
+}
+
+void ax25_dev_dama_off(ax25_dev *ax25_dev)
+{
+       if (ax25_dev == NULL)
+               return;
+
+       if (ax25_dev->dama.slave && !ax25_check_dama_slave(ax25_dev))
+       {
+               ax25_kiss_cmd(ax25_dev, 5, 0);
+               ax25_dev->dama.slave = 0;
+               ax25_ds_del_timer(ax25_dev);
+       }
+}
+
+void ax25_dama_on(ax25_cb *ax25)
+{
+       ax25_dev_dama_on(ax25->ax25_dev);
+       ax25->dama_slave = 1;
+}
+
+void ax25_dama_off(ax25_cb *ax25)
+{
+       ax25_dev_dama_off(ax25->ax25_dev);
+       ax25->dama_slave = 0;
+}
+
+#endif
diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
new file mode 100644 (file)
index 0000000..2b5eb99
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ *     AX.25 release 036
+ *
+ *     This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *     releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *     This code REQUIRES 2.1.15 or higher/ NET3.038
+ *
+ *     This module:
+ *             This module 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.
+ *
+ *     History
+ *     AX.25 036       Jonathan(G4KLX) Cloned from ax25_timer.c.
+ *                     Joerg(DL1BKE)   Added DAMA Slave Timeout timer
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_AX25_DAMA_SLAVE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <net/ax25.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+static void ax25_ds_timeout(unsigned long);
+
+/*
+ *     Add DAMA slave timeout timer to timer list.
+ *     Unlike the connection based timers the timeout function gets 
+ *     triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
+ *     (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
+ *     1/10th of a second.
+ */
+
+static void ax25_ds_add_timer(ax25_dev *ax25_dev)
+{
+       struct timer_list *t = &ax25_dev->dama.slave_timer;
+       t->data         = (unsigned long) ax25_dev;
+       t->function     = &ax25_ds_timeout;
+       t->expires      = jiffies + HZ;
+       add_timer(t);
+}
+
+void ax25_ds_del_timer(ax25_dev *ax25_dev)
+{
+       if (ax25_dev) del_timer(&ax25_dev->dama.slave_timer);
+}
+
+void ax25_ds_set_timer(ax25_dev *ax25_dev)
+{
+       if (ax25_dev == NULL)           /* paranoia */
+               return;
+
+       del_timer(&ax25_dev->dama.slave_timer);
+       ax25_dev->dama.slave_timeout = ax25_dev->values[AX25_VALUES_DS_TIMEOUT] / 10;
+       ax25_ds_add_timer(ax25_dev);
+}
+
+/*
+ *     DAMA Slave Timeout
+ *     Silently discard all (slave) connections in case our master forgot us...
+ */
+
+static void ax25_ds_timeout(unsigned long arg)
+{
+       ax25_dev *ax25_dev = (struct ax25_dev *) arg;
+       ax25_cb *ax25;
+       
+       if (ax25_dev == NULL || !ax25_dev->dama.slave)
+               return;                 /* Yikes! */
+       
+       if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout)
+       {
+               ax25_ds_set_timer(ax25_dev);
+               return;
+       }
+       
+       for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next)
+       {
+               if (ax25->ax25_dev != ax25_dev || !ax25->dama_slave)
+                       continue;
+
+               ax25_link_failed(&ax25->dest_addr, ax25_dev->dev);
+               ax25_clear_queues(ax25);
+               ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+               ax25->state = AX25_STATE_0;
+
+               if (ax25->sk != NULL)
+               {
+                       SOCK_DEBUG(ax25->sk, "AX.25 DAMA Slave Timeout\n");
+                       ax25->sk->state     = TCP_CLOSE;
+                       ax25->sk->err       = ETIMEDOUT;
+                       ax25->sk->shutdown |= SEND_SHUTDOWN;
+                       if (!ax25->sk->dead)
+                               ax25->sk->state_change(ax25->sk);
+                       ax25->sk->dead      = 1;
+               }
+               
+               ax25_set_timer(ax25);   /* notify socket... */
+       }
+       
+       ax25_dev_dama_off(ax25_dev);
+}
+
+
+/*
+ *     AX.25 TIMER 
+ *
+ *     This routine is called every 100ms. Decrement timer by this
+ *     amount - if expired then process the event.
+ */
+void ax25_ds_timer(ax25_cb *ax25)
+{
+       switch (ax25->state) {
+               case AX25_STATE_0:
+                       /* Magic here: If we listen() and a new link dies before it
+                          is accepted() it isn't 'dead' so doesn't get removed. */
+                       if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
+                               del_timer(&ax25->timer);
+                               ax25_destroy_socket(ax25);
+                               return;
+                       }
+                       break;
+
+               case AX25_STATE_3:
+               case AX25_STATE_4:
+                       /*
+                        * Check the state of the receive buffer.
+                        */
+                       if (ax25->sk != NULL) {
+                               if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+                                       ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+                                       break;
+                               }
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+       
+       /* dl1bke 960114: T3 works much like the IDLE timeout, but
+        *                gets reloaded with every frame for this
+        *                connection.
+        */
+
+       if (ax25->t3timer > 0 && --ax25->t3timer == 0) {
+               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
+               ax25_clear_queues(ax25);
+               ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+
+               ax25->state = AX25_STATE_0;
+               ax25_dama_off(ax25);
+
+               if (ax25->sk != NULL) {
+                       SOCK_DEBUG(ax25->sk, "AX.25 T3 Timeout\n");
+                       ax25->sk->state     = TCP_CLOSE;
+                       ax25->sk->err       = ETIMEDOUT;
+                       ax25->sk->shutdown |= SEND_SHUTDOWN;
+                       if (!ax25->sk->dead)
+                               ax25->sk->state_change(ax25->sk);
+                       ax25->sk->dead      = 1;
+               }
+
+               ax25_set_timer(ax25);
+
+               return;
+       }
+
+       /* dl1bke 960228: close the connection when IDLE expires.
+        *                unlike T3 this timer gets reloaded only on
+        *                I frames.
+        */
+
+       if (ax25->idletimer > 0 && --ax25->idletimer == 0) {
+               ax25_clear_queues(ax25);
+
+               ax25->n2count = 0;
+               ax25->t3timer = ax25->t3;
+
+               /* state 1 or 2 should not happen, but... */
+
+               if (ax25->state == AX25_STATE_1 || ax25->state == AX25_STATE_2)
+                       ax25->state = AX25_STATE_0;
+               else
+                       ax25->state = AX25_STATE_2;
+
+               ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+
+               if (ax25->sk != NULL) {
+                       ax25->sk->state     = TCP_CLOSE;
+                       ax25->sk->err       = 0;
+                       ax25->sk->shutdown |= SEND_SHUTDOWN;
+                       if (!ax25->sk->dead)
+                               ax25->sk->state_change(ax25->sk);
+                       ax25->sk->dead      = 1;
+                       ax25->sk->destroy   = 1;
+               }
+       }
+
+       ax25_set_timer(ax25);
+}
+
+/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
+ *                within the poll of any connected channel. Remember 
+ *                that we are not allowed to send anything unless we
+ *                get polled by the Master.
+ *
+ *                Thus we'll have to do parts of our T1 handling in
+ *                ax25_enquiry_response().
+ */
+void ax25_ds_t1_timeout(ax25_cb *ax25)
+{      
+       switch (ax25->state) {
+               case AX25_STATE_1: 
+                       if (ax25->n2count == ax25->n2) {
+                               if (ax25->modulus == AX25_MODULUS) {
+                                       ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
+                                       ax25_clear_queues(ax25);
+                                       ax25->state = AX25_STATE_0;
+                                       if (ax25->sk != NULL) {
+                                               ax25->sk->state     = TCP_CLOSE;
+                                               ax25->sk->err       = ETIMEDOUT;
+                                               ax25->sk->shutdown |= SEND_SHUTDOWN;
+                                               if (!ax25->sk->dead)
+                                                       ax25->sk->state_change(ax25->sk);
+                                               ax25->sk->dead      = 1;
+                                       }
+                               } else {
+                                       ax25->modulus = AX25_MODULUS;
+                                       ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+                                       ax25->n2count = 0;
+                                       ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
+                               }
+                       } else {
+                               ax25->n2count++;
+                               if (ax25->modulus == AX25_MODULUS)
+                                       ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
+                               else
+                                       ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
+                       }
+                       break;
+
+               case AX25_STATE_2:
+                       if (ax25->n2count == ax25->n2) {
+                               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
+                               ax25_clear_queues(ax25);
+                               ax25->state = AX25_STATE_0;
+                               ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+
+                               if (ax25->sk != NULL) {
+                                       ax25->sk->state     = TCP_CLOSE;
+                                       ax25->sk->err       = ETIMEDOUT;
+                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
+                                       if (!ax25->sk->dead)
+                                               ax25->sk->state_change(ax25->sk);
+                                       ax25->sk->dead      = 1;
+                               }
+                       } else {
+                               ax25->n2count++;
+                       }
+                       break;
+
+               case AX25_STATE_3: 
+                       ax25->n2count = 1;
+                       ax25->state   = AX25_STATE_4;
+                       break;
+
+               case AX25_STATE_4:
+                       if (ax25->n2count == ax25->n2) {
+                               ax25_link_failed(&ax25->dest_addr, ax25->ax25_dev->dev);
+                               ax25_clear_queues(ax25);
+                               ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+                               ax25->state = AX25_STATE_0;
+                               if (ax25->sk != NULL) {
+                                       SOCK_DEBUG(ax25->sk, "AX.25 link Failure\n");
+                                       ax25->sk->state     = TCP_CLOSE;
+                                       ax25->sk->err       = ETIMEDOUT;
+                                       ax25->sk->shutdown |= SEND_SHUTDOWN;
+                                       if (!ax25->sk->dead)
+                                               ax25->sk->state_change(ax25->sk);
+                                       ax25->sk->dead      = 1;
+                               }
+                       } else {
+                               ax25->n2count++;
+                       }
+                       break;
+       }
+
+       ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
+
+       ax25_set_timer(ax25);
+}
+
+#endif
index 3f76893bd50ddf4ff929a54a17391fc5b72b42cf..40ef03152afdb1b63a9b9f2befc939abc23f4dd4 100644 (file)
@@ -37,6 +37,7 @@
  *                                     Modularisation changes.
  *     AX.25 035       Hans(PE1AYX)    Fixed interface to IP layer.
  *     AX.25 036       Jonathan(G4KLX) Move DAMA code into own file.
+ *                     Joerg(DL1BKE)   Fixed DAMA Slave.
  */
 
 #include <linux/config.h>
@@ -158,6 +159,16 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
 
 #ifdef CONFIG_INET
        if (pid == AX25_P_IP) {
+               /* working around a TCP bug to keep additional listeners 
+                * happy. TCP re-uses the buffer and destroys the original
+                * content.
+                */
+               struct sk_buff *skbn = skb_copy(skb, GFP_ATOMIC);
+               if (skbn != NULL) {
+                       kfree_skb(skb, FREE_READ);
+                       skb = skbn;
+               }
+
                skb_pull(skb, 1);       /* Remove PID */
                skb->h.raw    = skb->data;
                skb->nh.raw   = skb->data;
@@ -190,7 +201,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
 /*
  *     Higher level upcall for a LAPB frame
  */
-static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type)
+static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, int dama)
 {
        int queued = 0;
 
@@ -200,12 +211,17 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type)
        del_timer(&ax25->timer);
 
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-               case AX25_PROTO_STD:
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
                        queued = ax25_std_frame_in(ax25, skb, type);
                        break;
+
 #ifdef CONFIG_AX25_DAMA_SLAVE
                case AX25_PROTO_DAMA_SLAVE:
-                       queued = ax25_ds_frame_in(ax25, skb, type);
+                       if (dama || ax25->ax25_dev->dama.slave)
+                               queued = ax25_ds_frame_in(ax25, skb, type);
+                       else
+                               queued = ax25_std_frame_in(ax25, skb, type);
                        break;
 #endif
        }
@@ -240,12 +256,10 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                return 0;
        }
 
-#ifdef CONFIG_FIREWALL
-       if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL) != FW_ACCEPT) {
+       if (call_in_firewall(PF_AX25, skb->dev, skb->h.raw, NULL,&skb) != FW_ACCEPT) {
                kfree_skb(skb, FREE_READ);
                return 0;
        }
-#endif
 
        /*
         *      Parse the address header.
@@ -356,7 +370,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                 *      free it immediately. This routine itself wakes the user context layers so we
                 *      do no further work
                 */
-               if (ax25_process_rx_frame(ax25, skb, type) == 0)
+               if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
                        kfree_skb(skb, FREE_READ);
 
                return 0;
@@ -450,7 +464,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
        ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE);
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-       if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
+       if (dama && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
                ax25_dama_on(ax25);
 #endif
 
index f8bc3f633198c441b4cb5d03800b84b2c50c98c7..ec882c50d4585cef96d52f62c53be20dec2892ac 100644 (file)
@@ -123,7 +123,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
                mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev);
                if (mode == 'V' || (mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
                        /*
-                        *      We clone the buffer and release the original thereby
+                        *      We copy the buffer and release the original thereby
                         *      keeping it straight
                         *
                         *      Note: we report 1 back so the caller will
@@ -131,8 +131,13 @@ int ax25_rebuild_header(struct sk_buff *skb)
                         *      We don't want that to happen. (It won't be upset
                         *      as we have pulled the frame from the queue by
                         *      freeing it).
+                        *
+                        *      NB: TCP modifies buffers that are still
+                        *      on a device queue, thus we use skb_copy()
+                        *      instead of using skb_clone() unless this
+                        *      gets fixed.
                         */
-                       if ((ourskb = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+                       if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
                                dev_kfree_skb(skb, FREE_WRITE);
                                return 1;
                        }
index 8ce7e407541357ef1ef0bd212ee98d277c2e3f9e..7072c632e34ac3fff17bb1c37127b82cb485862b 100644 (file)
@@ -94,12 +94,17 @@ int ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_add
        }
 
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-               case AX25_PROTO_STD:
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
                        ax25_std_establish_data_link(ax25);
                        break;
-#ifdef AX25_CONFIG_DAMA_SLAVE
+
+#ifdef CONFIG_AX25_DAMA_SLAVE
                case AX25_PROTO_DAMA_SLAVE:
-                       ax25_ds_establish_data_link(ax25);
+                       if (ax25_dev->dama.slave)
+                               ax25_ds_establish_data_link(ax25);
+                       else
+                               ax25_std_establish_data_link(ax25);
                        break;
 #endif
        }
@@ -192,7 +197,8 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
                skb_queue_tail(&ax25->write_queue, skb);          /* Throw it on the queue */
        }
 
-       if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD) {
+       if (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_SIMPLEX ||
+           ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_STD_DUPLEX) {
                if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
                        ax25_kick(ax25);
        }
@@ -274,9 +280,11 @@ void ax25_kick(ax25_cb *ax25)
                         * in DAMA mode.
                         */
                        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-                               case AX25_PROTO_STD:
+                               case AX25_PROTO_STD_SIMPLEX:
+                               case AX25_PROTO_STD_DUPLEX:
                                        ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
                                        break;
+
 #ifdef CONFIG_AX25_DAMA_SLAVE
                                case AX25_PROTO_DAMA_SLAVE:
                                        ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
@@ -343,12 +351,10 @@ void ax25_queue_xmit(struct sk_buff *skb)
 {
        unsigned char *ptr;
 
-#ifdef CONFIG_FIREWALL
-       if (call_out_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) {
+       if (call_out_firewall(PF_AX25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) {
                dev_kfree_skb(skb, FREE_WRITE);
                return;
        }
-#endif
 
        skb->protocol = htons(ETH_P_AX25);
        skb->dev      = ax25_fwd_dev(skb->dev);
index bec766a53b462fc4ee4faf381d546e9579dc5824..a99a02b4a12991d0e566217b32ef237003a4b4cc 100644 (file)
@@ -22,6 +22,8 @@
  *     AX.25 033       Jonathan(G4KLX) Modularisation functions.
  *     AX.25 035       Frederic(F1OAT) Support for pseudo-digipeating.
  *     AX.25 036       Jonathan(G4KLX) Split Standard and DAMA code into seperate files.
+ *                     Joerg(DL1BKE)   Fixed DAMA Slave. We are *required* to start with
+ *                                     standard AX.25 mode.
  */
 
 #include <linux/config.h>
@@ -62,7 +64,7 @@ void ax25_set_timer(ax25_cb *ax25)
 
        ax25->timer.data     = (unsigned long)ax25;
        ax25->timer.function = &ax25_timer;
-       ax25->timer.expires  = jiffies + 10;
+       ax25->timer.expires  = jiffies + (HZ / 10);
 
        add_timer(&ax25->timer);
 }
@@ -78,12 +80,17 @@ static void ax25_timer(unsigned long param)
        ax25_cb *ax25 = (ax25_cb *)param;
 
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-               case AX25_PROTO_STD:
+               case AX25_PROTO_STD_SIMPLEX:
+               case AX25_PROTO_STD_DUPLEX:
                        ax25_std_timer(ax25);
                        break;
+
 #ifdef CONFIG_AX25_DAMA_SLAVE
                case AX25_PROTO_DAMA_SLAVE:
-                       ax25_ds_timer(ax25);
+                       if (ax25->ax25_dev->dama.slave)
+                               ax25_ds_timer(ax25);
+                       else
+                               ax25_std_timer(ax25);
                        break;
 #endif
        }
index ee3e6aaf106b0c9d31518079d36bffdf9810a701..377c98833e54883336bb18291b7dfded49e11127 100644 (file)
@@ -21,7 +21,8 @@ static int min_t3[] = {0},            max_t3[] = {3600 * AX25_SLOWHZ};
 static int min_idle[] = {0},           max_idle[] = {65535 * AX25_SLOWHZ};
 static int min_n2[] = {1},             max_n2[] = {31};
 static int min_paclen[] = {1},         max_paclen[] = {512};
-static int min_proto[] = {0},          max_proto[] = {2};
+static int min_proto[] = {0},          max_proto[] = {3};
+static int min_ds_timeout[] = {0},     max_ds_timeout[] = {65535 * AX25_SLOWHZ};
 
 static struct ctl_table_header *ax25_table_header;
 
@@ -91,6 +92,10 @@ static const ctl_table ax25_param_table[] = {
         NULL, sizeof(int), 0644, NULL,
         &proc_dointvec_minmax, &sysctl_intvec, NULL,
         &min_proto, &max_proto},
+       {NET_AX25_DAMA_SLAVE_TIMEOUT, "dama_slave_timeout",
+        NULL, sizeof(int), 0644, NULL,
+        &proc_dointvec_minmax, &sysctl_intvec, NULL,
+        &min_ds_timeout, &max_ds_timeout},
        {0}     /* that's all, folks! */
 };
 
@@ -117,6 +122,16 @@ void ax25_register_sysctl(void)
                ax25_table[n].proc_handler = NULL;
 
                memcpy(ax25_dev->systable, ax25_param_table, sizeof(ax25_dev->systable));
+               
+#ifndef CONFIG_AX25_DAMA_SLAVE
+               /* 
+                * We do not wish to have a representation of this parameter
+                * in /proc/sys/ when configured *not* to include the
+                * AX.25 DAMA slave code, do we?
+                */
+
+               ax25_dev->systable[AX25_VALUES_DS_TIMEOUT].procname = NULL;
+#endif
 
                ax25_dev->systable[AX25_MAX_VALUES].ctl_name = 0;       /* just in case... */
 
index 95485857fdd5c623ef46f05fbf7fc12021720909..67230ceed7bce16b71920ba7ccf12fb7d04b9ef4 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/in.h>
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <asm/system.h>
 #include <net/br.h>
 
+static void transmit_config(int port_no);
+static int root_bridge(void);
+static int supersedes_port_info(int port_no, Config_bpdu *config);
+static void record_config_information(int port_no, Config_bpdu *config);
+static void record_config_timeout_values(Config_bpdu *config);
+static void config_bpdu_generation(void);
+static int designated_port(int port_no);
+static void reply(int port_no);
+static void transmit_tcn(void);
+static void configuration_update(void);
+static void root_selection(void);
+static void designated_port_selection(void);
+static void become_designated_port(int port_no);
+static void port_state_selection(void);
+static void make_forwarding(int port_no);
+static void topology_change_detection(void);
+static void topology_change_acknowledged(void);
+static void acknowledge_topology_change(int port_no);
+static void make_blocking(int port_no);
+static void set_port_state(int port_no, int state);
+static void received_config_bpdu(int port_no, Config_bpdu *config);
+static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn);
+static void hello_timer_expiry(void);
+static void message_age_timer_expiry(int port_no);
+static void forward_delay_timer_expiry(int port_no);
+static int designated_for_some_port(void);
+static void tcn_timer_expiry(void);
+static void topology_change_timer_expiry(void);
+static void hold_timer_expiry(int port_no);
+static void br_init_port(int port_no);
+static void enable_port(int port_no);
+static void disable_port(int port_no);
+static void set_bridge_priority(bridge_id_t *new_bridge_id);
+static void set_port_priority(int port_no, unsigned short new_port_id);
+static void set_path_cost(int port_no, unsigned short path_cost);
+static void start_hello_timer(void);
+static void stop_hello_timer(void);
+static int hello_timer_expired(void);
+static void start_tcn_timer(void);
+static void stop_tcn_timer(void);
+static int tcn_timer_expired(void);
+static void start_topology_change_timer(void);
+static void stop_topology_change_timer(void);
+static int topology_change_timer_expired(void);
+static void start_message_age_timer(int port_no, unsigned short message_age);
+static void stop_message_age_timer(int port_no);
+static int message_age_timer_expired(int port_no);
+static void start_forward_delay_timer(int port_no);
+static void stop_forward_delay_timer(int port_no);
+static int forward_delay_timer_expired(int port_no);
+static void start_hold_timer(int port_no);
+static void stop_hold_timer(int port_no);
+static int hold_timer_expired(int port_no);
 static int br_device_event(struct notifier_block *dnot, unsigned long event, void *ptr);
 static void br_tick(unsigned long arg);
-int br_forward(struct sk_buff *skb, int port); /* 3.7 */
-int br_port_cost(struct device *dev);  /* 4.10.2 */
-void br_bpdu(struct sk_buff *skb); /* consumes skb */
-int br_tx_frame(struct sk_buff *skb);
-int br_cmp(unsigned int *a, unsigned int *b);
-
-unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-
-Bridge_data     bridge_info;                     /* (4.5.3)     */
+static int br_forward(struct sk_buff *skb, int port);  /* 3.7 */
+static int br_port_cost(struct device *dev);   /* 4.10.2 */
+static void br_bpdu(struct sk_buff *skb); /* consumes skb */
+static int br_cmp(unsigned int *a, unsigned int *b);
+static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu);
+static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu);
+static int find_port(struct device *dev);
+static int br_flood(struct sk_buff *skb, int port);
+static int br_drop(struct sk_buff *skb);
+static int br_learn(struct sk_buff *skb, int port);    /* 3.8 */
+
+static unsigned char bridge_ula[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+static Bridge_data     bridge_info;                      /* (4.5.3)     */
 Port_data       port_info[All_ports];            /* (4.5.5)     */
 Config_bpdu     config_bpdu[All_ports];
 Tcn_bpdu        tcn_bpdu[All_ports];
-Timer           hello_timer;                     /* (4.5.4.1)   */
-Timer           tcn_timer;                       /* (4.5.4.2)   */
-Timer           topology_change_timer;           /* (4.5.4.3)   */
-Timer           message_age_timer[All_ports];    /* (4.5.6.1)   */
-Timer           forward_delay_timer[All_ports];          /* (4.5.6.2)   */
-Timer           hold_timer[All_ports];           /* (4.5.6.3)   */
+static Timer    hello_timer;                     /* (4.5.4.1)   */
+static Timer    tcn_timer;                       /* (4.5.4.2)   */
+static Timer    topology_change_timer;           /* (4.5.4.3)   */
+static Timer    message_age_timer[All_ports];    /* (4.5.6.1)   */
+static Timer    forward_delay_timer[All_ports];          /* (4.5.6.2)   */
+static Timer    hold_timer[All_ports];           /* (4.5.6.3)   */
 
 /* entries timeout after this many seconds */
 unsigned int fdb_aging_time = FDB_TIMEOUT; 
@@ -118,7 +176,7 @@ int br_protocol_ok(unsigned short protocol)
 
 /* Add a protocol to be handled opposite to the standard policy of the bridge */
 
-int br_add_exempt_protocol(unsigned short p)
+static int br_add_exempt_protocol(unsigned short p)
 {
        unsigned x;
        if (p == 0) return -EINVAL;
@@ -134,7 +192,7 @@ int br_add_exempt_protocol(unsigned short p)
 }
 
 /* Valid Policies are 0=No Protocols bridged 1=Bridge all protocols */
-int br_set_policy(int policy)
+static int br_set_policy(int policy)
 {
        if (policy>1) return -EINVAL;
        br_stats.policy=policy;
@@ -155,7 +213,7 @@ int br_set_policy(int policy)
  * 802.1d bridging protocol.
  */
 
-void transmit_config(int port_no)                        /* (4.6.1)     */
+static void transmit_config(int port_no)         /* (4.6.1)     */
 {
        if (hold_timer[port_no].active) {         /* (4.6.1.3.1)         */
                port_info[port_no].config_pending = TRUE;       /* (4.6.1.3.1)   */
@@ -198,13 +256,13 @@ void transmit_config(int port_no)                   /* (4.6.1)     */
        }
 }
 
-int root_bridge(void)
+static int root_bridge(void)
 {
        return (br_cmp(bridge_info.designated_root.BRIDGE_ID,
                 bridge_info.bridge_id.BRIDGE_ID)?FALSE:TRUE);
 }
 
-int supersedes_port_info(int port_no, Config_bpdu *config)       /* (4.6.2.2)   */
+static int supersedes_port_info(int port_no, Config_bpdu *config)        /* (4.6.2.2)   */
 {
        return (
                (br_cmp(config->root_id.BRIDGE_ID,
@@ -241,7 +299,7 @@ int supersedes_port_info(int port_no, Config_bpdu *config)    /* (4.6.2.2)   */
                );
 }
 
-void record_config_information(int port_no, Config_bpdu *config)         /* (4.6.2)     */
+static void record_config_information(int port_no, Config_bpdu *config)          /* (4.6.2)     */
 {
        port_info[port_no].designated_root = config->root_id;   /* (4.6.2.3.1)   */
        port_info[port_no].designated_cost = config->root_path_cost;
@@ -250,7 +308,7 @@ void record_config_information(int port_no, Config_bpdu *config)      /* (4.6.2)     *
        start_message_age_timer(port_no, config->message_age);  /* (4.6.2.3.2)   */
 }
 
-void record_config_timeout_values(Config_bpdu *config)           /* (4.6.3)     */
+static void record_config_timeout_values(Config_bpdu *config)            /* (4.6.3)     */
 {
        bridge_info.max_age = config->max_age;    /* (4.6.3.3)   */
        bridge_info.hello_time = config->hello_time;
@@ -259,7 +317,7 @@ void record_config_timeout_values(Config_bpdu *config)                /* (4.6.3)     */
                bridge_info.top_change = 1;
 }
 
-void config_bpdu_generation(void)
+static void config_bpdu_generation(void)
 {                                                /* (4.6.4)     */
        int             port_no;
        for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.4.3) */
@@ -272,7 +330,7 @@ void config_bpdu_generation(void)
        }
 }
 
-int designated_port(int port_no)
+static int designated_port(int port_no)
 {
        return ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
                 bridge_info.bridge_id.BRIDGE_ID) == 0
@@ -284,12 +342,12 @@ int designated_port(int port_no)
                );
 }
 
-void reply(int port_no)                                          /* (4.6.5)     */
+static void reply(int port_no)                                   /* (4.6.5)     */
 {
        transmit_config(port_no);                 /* (4.6.5.3)   */
 }
 
-void transmit_tcn(void)
+static void transmit_tcn(void)
 {                                                /* (4.6.6)     */
        int             port_no;
 
@@ -298,7 +356,7 @@ void transmit_tcn(void)
        send_tcn_bpdu(port_no, &tcn_bpdu[bridge_info.root_port]);       /* (4.6.6.3)     */
 }
 
-void configuration_update(void)        /* (4.6.7) */
+static void configuration_update(void) /* (4.6.7) */
 {
        root_selection();                         /* (4.6.7.3.1)         */
        /* (4.6.8.2)     */
@@ -306,7 +364,7 @@ void configuration_update(void)     /* (4.6.7) */
        /* (4.6.9.2)     */
 }
 
-void root_selection(void)
+static void root_selection(void)
 {                                                /* (4.6.8) */
        int             root_port;
        int             port_no;
@@ -386,7 +444,7 @@ void root_selection(void)
        }
 }
 
-void designated_port_selection(void)
+static void designated_port_selection(void)
 {                                                /* (4.6.9)     */
        int             port_no;
 
@@ -423,7 +481,7 @@ void designated_port_selection(void)
        }
 }
 
-void become_designated_port(int port_no)
+static void become_designated_port(int port_no)
 {                                                /* (4.6.10)    */
 
        /* (4.6.10.3.1) */
@@ -436,7 +494,7 @@ void become_designated_port(int port_no)
        port_info[port_no].designated_port = port_info[port_no].port_id;
 }
 
-void port_state_selection(void)
+static void port_state_selection(void)
 {                                                /* (4.6.11) */
        int             port_no;
        for (port_no = One; port_no <= No_of_ports; port_no++) {
@@ -456,7 +514,7 @@ void port_state_selection(void)
 
 }
 
-void make_forwarding(int port_no)
+static void make_forwarding(int port_no)
 {                                                /* (4.6.12) */
        if (port_info[port_no].state == Blocking) {     /* (4.6.12.3) */
                set_port_state(port_no, Listening);     /* (4.6.12.3.1) */
@@ -464,7 +522,7 @@ void make_forwarding(int port_no)
        }
 }
 
-void topology_change_detection(void)
+static void topology_change_detection(void)
 {                                                /* (4.6.14)       */
        if (root_bridge()) {                      /* (4.6.14.3.1)   */
                bridge_info.top_change = 1;
@@ -476,19 +534,19 @@ void topology_change_detection(void)
        bridge_info.top_change = 1;
 }
 
-void topology_change_acknowledged(void)
+static void topology_change_acknowledged(void)
 {                                                /* (4.6.15) */
        bridge_info.top_change_detected = 0;
        stop_tcn_timer();                         /* (4.6.15.3.2) */
 }
 
-void acknowledge_topology_change(int port_no)
+static void acknowledge_topology_change(int port_no)
 {                                                /* (4.6.16) */
        port_info[port_no].top_change_ack = 1;
        transmit_config(port_no);                 /* (4.6.16.3.2) */
 }
 
-void make_blocking(int port_no)                                  /* (4.6.13)    */
+static void make_blocking(int port_no)                           /* (4.6.13)    */
 {
 
        if ((port_info[port_no].state != Disabled)
@@ -508,12 +566,12 @@ void make_blocking(int port_no)                             /* (4.6.13)    */
        }
 }
 
-void set_port_state(int port_no, int state)
+static void set_port_state(int port_no, int state)
 {
        port_info[port_no].state = state;
 }
 
-void received_config_bpdu(int port_no, Config_bpdu *config)              /* (4.7.1)     */
+static void received_config_bpdu(int port_no, Config_bpdu *config)               /* (4.7.1)     */
 {
        int         root;
 
@@ -550,7 +608,7 @@ void received_config_bpdu(int port_no, Config_bpdu *config)           /* (4.7.1)     */
        }
 }
 
-void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                       /* (4.7.2)     */
+static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                        /* (4.7.2)     */
 {
        if (port_info[port_no].state != Disabled) {
                if (designated_port(port_no)) {
@@ -561,13 +619,13 @@ void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn)                          /* (4.7.2)     */
        }
 }
 
-void hello_timer_expiry(void)
+static void hello_timer_expiry(void)
 {                                                /* (4.7.3)     */
        config_bpdu_generation();                 /* (4.6.4.2.2)         */
        start_hello_timer();
 }
 
-void message_age_timer_expiry(int port_no)               /* (4.7.4)     */
+static void message_age_timer_expiry(int port_no) /* (4.7.4)    */
 {
        int         root;
        root = root_bridge();
@@ -592,7 +650,7 @@ void message_age_timer_expiry(int port_no)            /* (4.7.4)     */
        }
 }
 
-void forward_delay_timer_expiry(int port_no)             /* (4.7.5)     */
+static void forward_delay_timer_expiry(int port_no)    /* (4.7.5)       */
 {
        if (port_info[port_no].state == Listening) {    /* (4.7.5.1)     */
                set_port_state(port_no, Learning);      /* (4.7.5.1.1)   */
@@ -606,7 +664,7 @@ void forward_delay_timer_expiry(int port_no)                  /* (4.7.5)     */
        }
 }
 
-int designated_for_some_port(void)
+static int designated_for_some_port(void)
 {
        int             port_no;
 
@@ -621,20 +679,20 @@ int designated_for_some_port(void)
        return (FALSE);
 }
 
-void tcn_timer_expiry(void)
+static void tcn_timer_expiry(void)
 {                                                /* (4.7.6)     */
        transmit_tcn();                           /* (4.7.6.1)   */
        start_tcn_timer();                        /* (4.7.6.2)   */
 }
 
-void topology_change_timer_expiry(void)
+static void topology_change_timer_expiry(void)
 {                                                /* (4.7.7)     */
        bridge_info.top_change_detected = 0;
        bridge_info.top_change = 0;
          /* (4.7.7.2)   */
 }
 
-void hold_timer_expiry(int port_no)                      /* (4.7.8)     */
+static void hold_timer_expiry(int port_no)       /* (4.7.8)     */
 {
        if (port_info[port_no].config_pending) {
                transmit_config(port_no);         /* (4.7.8.1)   */
@@ -682,7 +740,7 @@ void br_init(void)
        /*start_hello_timer();*/
 }
 
-void br_init_port(int port_no)
+static void br_init_port(int port_no)
 {
        become_designated_port(port_no);          /* (4.8.1.4.1) */
        set_port_state(port_no, Blocking);        /* (4.8.1.4.2)    */
@@ -693,13 +751,13 @@ void br_init_port(int port_no)
        stop_hold_timer(port_no);                 /* (4.8.1.4.7)         */
 }
 
-void enable_port(int port_no)                            /* (4.8.2)     */
+static void enable_port(int port_no)                             /* (4.8.2)     */
 {
        br_init_port(port_no);
        port_state_selection();                   /* (4.8.2.7)   */
 }                                                /* */
 
-void disable_port(int port_no)                           /* (4.8.3)     */
+static void disable_port(int port_no)                            /* (4.8.3)     */
 {
        int         root;
 
@@ -724,7 +782,8 @@ void disable_port(int port_no)                                /* (4.8.3)     */
 }
 
 
-void set_bridge_priority(bridge_id_t *new_bridge_id)             /* (4.8.4)     */
+static void set_bridge_priority(bridge_id_t *new_bridge_id)
+                                                 /* (4.8.4)     */
 {
 
        int         root;
@@ -750,7 +809,8 @@ void set_bridge_priority(bridge_id_t *new_bridge_id)                  /* (4.8.4)     */
        }
 }
 
-void set_port_priority(int port_no, unsigned short new_port_id)                  /* (4.8.5)     */
+static void set_port_priority(int port_no, unsigned short new_port_id)
+                                                 /* (4.8.5)     */
 {
        if (designated_port(port_no)) {           /* (4.8.5.2)   */
                port_info[port_no].designated_port = new_port_id;
@@ -770,7 +830,8 @@ void set_port_priority(int port_no, unsigned short new_port_id)               /* (4.8.5)     *
        }
 }
 
-void set_path_cost(int port_no, unsigned short path_cost)                /* (4.8.6)     */
+static void set_path_cost(int port_no, unsigned short path_cost)
+                                                  /* (4.8.6)    */
 {
        port_info[port_no].path_cost = path_cost; /* (4.8.6.1)   */
        configuration_update();                   /* (4.8.6.2)   */
@@ -807,18 +868,18 @@ static void br_tick(unsigned long arg)
        add_timer(&tl);
 }
 
-void start_hello_timer(void)
+static void start_hello_timer(void)
 {
        hello_timer.value = 0;
        hello_timer.active = TRUE;
 }
 
-void stop_hello_timer(void)
+static void stop_hello_timer(void)
 {
        hello_timer.active = FALSE;
 }
 
-int hello_timer_expired(void)
+static int hello_timer_expired(void)
 {
        if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) {
                hello_timer.active = FALSE;
@@ -827,18 +888,18 @@ int hello_timer_expired(void)
        return (FALSE);
 }
 
-void start_tcn_timer(void)
+static void start_tcn_timer(void)
 {
        tcn_timer.value = 0;
        tcn_timer.active = TRUE;
 }
 
-void stop_tcn_timer(void)
+static void stop_tcn_timer(void)
 {
        tcn_timer.active = FALSE;
 }
 
-int tcn_timer_expired(void)
+static int tcn_timer_expired(void)
 {
        if (tcn_timer.active && (++tcn_timer.value >=
                                 bridge_info.bridge_hello_time)) {
@@ -849,18 +910,18 @@ int tcn_timer_expired(void)
 
 }
 
-void start_topology_change_timer(void)
+static void start_topology_change_timer(void)
 {
        topology_change_timer.value = 0;
        topology_change_timer.active = TRUE;
 }
 
-void stop_topology_change_timer(void)
+static void stop_topology_change_timer(void)
 {
        topology_change_timer.active = FALSE;
 }
 
-int topology_change_timer_expired(void)
+static int topology_change_timer_expired(void)
 {
        if (topology_change_timer.active
                        && (++topology_change_timer.value
@@ -872,18 +933,18 @@ int topology_change_timer_expired(void)
        return (FALSE);
 }
 
-void start_message_age_timer(int port_no, unsigned short message_age)
+static void start_message_age_timer(int port_no, unsigned short message_age)
 {
        message_age_timer[port_no].value = message_age;
        message_age_timer[port_no].active = TRUE;
 }
 
-void stop_message_age_timer(int port_no)
+static void stop_message_age_timer(int port_no)
 {
        message_age_timer[port_no].active = FALSE;
 }
 
-int message_age_timer_expired(int port_no)
+static int message_age_timer_expired(int port_no)
 {
        if (message_age_timer[port_no].active &&
              (++message_age_timer[port_no].value >= bridge_info.max_age)) {
@@ -893,18 +954,18 @@ int message_age_timer_expired(int port_no)
        return (FALSE);
 }
 
-void start_forward_delay_timer(int port_no)
+static void start_forward_delay_timer(int port_no)
 {
        forward_delay_timer[port_no].value = 0;
        forward_delay_timer[port_no].active = TRUE;
 }
 
-void stop_forward_delay_timer(int port_no)
+static void stop_forward_delay_timer(int port_no)
 {
        forward_delay_timer[port_no].active = FALSE;
 }
 
-int forward_delay_timer_expired(int port_no)
+static int forward_delay_timer_expired(int port_no)
 {
                if (forward_delay_timer[port_no].active &&
                                (++forward_delay_timer[port_no].value >= bridge_info.forward_delay)) {
@@ -914,19 +975,18 @@ int forward_delay_timer_expired(int port_no)
                return (FALSE);
 }
 
-void start_hold_timer(int port_no)
+static void start_hold_timer(int port_no)
 {
        hold_timer[port_no].value = 0;
        hold_timer[port_no].active = TRUE;
 }
 
-void stop_hold_timer(int port_no)
+static void stop_hold_timer(int port_no)
 {
        hold_timer[port_no].active = FALSE;
 }
 
-
-int hold_timer_expired(int port_no)
+static int hold_timer_expired(int port_no)
 {
        if (hold_timer[port_no].active &&
                   (++hold_timer[port_no].value >= bridge_info.hold_time)) {
@@ -937,7 +997,7 @@ int hold_timer_expired(int port_no)
 
 }
 
-int send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
+static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
 {
 struct sk_buff *skb;
 struct device *dev = port_info[port_no].dev;
@@ -996,7 +1056,7 @@ struct ethhdr *eth;
        return(0);
 }
 
-int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu)
+static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu)
 {
 struct sk_buff *skb;
 struct device *dev = port_info[port_no].dev;
@@ -1281,7 +1341,7 @@ int br_tx_frame(struct sk_buff *skb)      /* 3.5 */
  * state or lack of resources...
  */
 
-int br_learn(struct sk_buff *skb, int port)    /* 3.8 */
+static int br_learn(struct sk_buff *skb, int port)     /* 3.8 */
 {
        struct fdb *f;
 
@@ -1330,7 +1390,7 @@ int br_learn(struct sk_buff *skb, int port)       /* 3.8 */
  * this routine always consumes the frame
  */
 
-int br_drop(struct sk_buff *skb)
+static int br_drop(struct sk_buff *skb)
 {
        kfree_skb(skb, 0);
        return(1);
@@ -1340,7 +1400,7 @@ int br_drop(struct sk_buff *skb)
  * this routine always consumes the frame
  */
 
-int br_dev_drop(struct sk_buff *skb)
+static int br_dev_drop(struct sk_buff *skb)
 {
        dev_kfree_skb(skb, 0);
        return(1);
@@ -1355,7 +1415,7 @@ int br_dev_drop(struct sk_buff *skb)
  * if not...
  */
 
-int br_forward(struct sk_buff *skb, int port)  /* 3.7 */
+static int br_forward(struct sk_buff *skb, int port)   /* 3.7 */
 {
        struct fdb *f;
        
@@ -1438,7 +1498,7 @@ int br_forward(struct sk_buff *skb, int port)     /* 3.7 */
  * consumes the original frame.
  */
        
-int br_flood(struct sk_buff *skb, int port)
+static int br_flood(struct sk_buff *skb, int port)
 {
        int i;
        struct sk_buff *nskb;
@@ -1469,7 +1529,7 @@ int br_flood(struct sk_buff *skb, int port)
        return(0);
 }
 
-int find_port(struct device *dev)
+static int find_port(struct device *dev)
 {
        int i;
 
@@ -1480,7 +1540,7 @@ int find_port(struct device *dev)
        return(0);
 }
 
-int br_port_cost(struct device *dev)   /* 4.10.2 */
+static int br_port_cost(struct device *dev)    /* 4.10.2 */
 {
        if (strncmp(dev->name, "eth", 3) == 0)  /* ethernet */
                return(100);
@@ -1495,7 +1555,7 @@ int br_port_cost(struct device *dev)      /* 4.10.2 */
  * this routine always consumes the skb 
  */
 
-void br_bpdu(struct sk_buff *skb) /* consumes skb */
+static void br_bpdu(struct sk_buff *skb) /* consumes skb */
 {
        Tcn_bpdu *bpdu;
        int port;
@@ -1624,7 +1684,7 @@ int br_ioctl(unsigned int cmd, void *arg)
        return 0;
 }
 
-int br_cmp(unsigned int *a, unsigned int *b)
+static int br_cmp(unsigned int *a, unsigned int *b)
 {
        int i;  
        for (i=0; i<2; i++) 
@@ -1638,4 +1698,3 @@ int br_cmp(unsigned int *a, unsigned int *b)
        }
        return(0);
 }
-
index a1965d49874baeab1d978da16a57bd5004c4f973..8234249c5094cd4d25527dd7f2d5d297394c472f 100644 (file)
  * <hayes@netplumbing.com>
  */
 
-struct fdb fdb_head;
-struct fdb *fhp = &fdb_head;
-struct fdb **fhpp = &fhp;
+static struct fdb fdb_head;
+static struct fdb *fhp = &fdb_head;
+static struct fdb **fhpp = &fhp;
 static int fdb_inited = 0;
 
-int addr_cmp(unsigned char *a1, unsigned char *a2);
+static int addr_cmp(unsigned char *a1, unsigned char *a2);
 
 /*
  * fdb_head is the AVL tree corresponding to fdb
@@ -50,7 +50,7 @@ int addr_cmp(unsigned char *a1, unsigned char *a2);
  *    foreach node in tree->fdb_avl_right: node->fdb_avl_key >= tree->fdb_avl_key.
  */
 
-int
+static int
 fdb_init(void)
 {
        fdb_head.fdb_avl_height = 0;
@@ -60,8 +60,7 @@ fdb_init(void)
        return(0);
 }
 
-struct fdb *
-br_avl_find_addr(unsigned char addr[6])
+struct fdb *br_avl_find_addr(unsigned char addr[6])
 {
        struct fdb * result = NULL;
        struct fdb * tree;
@@ -109,14 +108,15 @@ br_avl_find_addr(unsigned char addr[6])
        }
 }
 
+
+#if (0)
 /*
  * Rebalance a tree.
  * After inserting or deleting a node of a tree we have a sequence of subtrees
  * nodes[0]..nodes[k-1] such that
  * nodes[0] is the root and nodes[i+1] = nodes[i]->{fdb_avl_left|fdb_avl_right}.
  */
-static void 
-br_avl_rebalance (struct fdb *** nodeplaces_ptr, int count)
+static void br_avl_rebalance (struct fdb *** nodeplaces_ptr, int count)
 {
        if (!fdb_inited)
                fdb_init();
@@ -196,10 +196,10 @@ br_avl_rebalance (struct fdb *** nodeplaces_ptr, int count)
        printk_avl(&fdb_head);
 #endif /* DEBUG_AVL */
 }
+#endif /* (0) */
 
 /* Insert a node into a tree. */
-int 
-br_avl_insert (struct fdb * new_node)
+int br_avl_insert (struct fdb * new_node)
 {
        struct fdb ** nodeplace = fhpp;
        struct fdb ** stack[avl_maxheight];
@@ -248,9 +248,10 @@ br_avl_insert (struct fdb * new_node)
        return(1);
 }
 
+
+#if (0)
 /* Removes a node out of a tree. */
-int
-br_avl_remove (struct fdb * node_to_delete)
+static int br_avl_remove (struct fdb * node_to_delete)
 {
        struct fdb ** nodeplace = fhpp;
        struct fdb ** stack[avl_maxheight];
@@ -301,6 +302,7 @@ br_avl_remove (struct fdb * node_to_delete)
        br_avl_rebalance(stack_ptr,stack_count);
        return(0);
 }
+#endif /* (0) */
 
 #ifdef DEBUG_AVL
 
@@ -388,8 +390,7 @@ static void avl_checkorder (struct fdb * tree)
 #endif /* (0) */
 #endif /* DEBUG_AVL */
 
-int
-addr_cmp(unsigned char a1[], unsigned char a2[])
+static int addr_cmp(unsigned char a1[], unsigned char a2[])
 {
        int i;
 
index b28d3ab55cbc45a1381c7ab52818e43936a1dce6..fe76738c55b60109fa2ac38e3027d50a4adb514d 100644 (file)
@@ -41,7 +41,7 @@ static void dst_run_gc(unsigned long dummy)
        del_timer(&dst_gc_timer);
        dstp = &dst_garbage_list;
        while ((dst = *dstp) != NULL) {
-               if (dst->refcnt) {
+               if (dst->use) {
                        dstp = &dst->next;
                        delayed++;
                        continue;
index c47076a0c6987c0624e826d893db6daefd9aa825..32cf52655bf1f00df916a101e47eef8feb391e79 100644 (file)
@@ -97,13 +97,13 @@ int unregister_firewall(int pf, struct firewall_ops *fw)
        return -ENOENT;
 }
 
-int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg)
+int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
 {
        struct firewall_ops *fw=firewall_chain[pf];
 
        while(fw!=NULL)
        {
-               int rc=fw->fw_forward(fw,pf,dev,phdr,arg);
+               int rc=fw->fw_forward(fw,pf,dev,phdr,arg,skb);
                if(rc!=FW_SKIP)
                        return rc;
                fw=fw->next;
@@ -115,13 +115,13 @@ int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg)
  *     Actual invocation of the chains
  */
 
-int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg)
+int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
 {
        struct firewall_ops *fw=firewall_chain[pf];
 
        while(fw!=NULL)
        {
-               int rc=fw->fw_input(fw,pf,dev,phdr,arg);
+               int rc=fw->fw_input(fw,pf,dev,phdr,arg,skb);
                if(rc!=FW_SKIP)
                        return rc;
                fw=fw->next;
@@ -129,13 +129,13 @@ int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg)
        return firewall_policy[pf];
 }
 
-int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg)
+int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb)
 {
        struct firewall_ops *fw=firewall_chain[pf];
 
        while(fw!=NULL)
        {
-               int rc=fw->fw_output(fw,pf,dev,phdr,arg);
+               int rc=fw->fw_output(fw,pf,dev,phdr,arg,skb);
                if(rc!=FW_SKIP)
                        return rc;
                fw=fw->next;
index 0650d7da6c8907c4d8752b88208a077abf34cd95..4271892343a48a5a2d5c4f7b5a58962d93566e09 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/socket.h>
 #include <linux/sched.h>
+#include <linux/netdevice.h>
 #include <net/neighbour.h>
 
 
@@ -44,11 +45,11 @@ void neigh_table_init(struct neigh_table *tbl, struct neigh_ops *ops, int size)
        memset(tbl->hash_buckets, 0, bmemlen);
 }
 
-struct neighbour *neigh_alloc(int size, int priority)
+struct neighbour *neigh_alloc(int size, struct neigh_ops *ops)
 {
        struct neighbour *neigh;
        
-       neigh = kmalloc(size, priority);
+       neigh = kmalloc(size, GFP_ATOMIC);
        if (neigh == NULL)
        {
                return NULL;
@@ -57,7 +58,7 @@ struct neighbour *neigh_alloc(int size, int priority)
        memset(neigh, 0, size);
        
        skb_queue_head_init(&neigh->arp_queue);
-
+       neigh->ops = ops;
        return neigh;
 }
 
@@ -96,7 +97,6 @@ void neigh_table_ins(struct neigh_table *tbl, struct neighbour *neigh)
        hash_val = tbl->neigh_ops->hash(neigh->primary_key) % tbl->tbl_size;
        
        neigh->tbl = tbl;
-       neigh->ops = tbl->neigh_ops;
        
        head = &tbl->hash_buckets[hash_val];
        
@@ -143,7 +143,7 @@ struct neighbour * neigh_lookup(struct neigh_table *tbl, void *pkey,
                                        return neigh;
                        }
                        neigh = neigh->next;
-                       
+
                } while (neigh != head);
        }
 
@@ -156,8 +156,6 @@ struct neighbour * neigh_lookup(struct neigh_table *tbl, void *pkey,
  */
 void neigh_destroy(struct neighbour *neigh)
 {      
-       unsigned long flags;
-
        if (neigh->tbl)
        {
                printk(KERN_DEBUG "neigh_destroy: neighbour still in table. "
@@ -171,10 +169,6 @@ void neigh_destroy(struct neighbour *neigh)
 
        neigh_purge_send_q(neigh);
 
-       save_flags(flags);
-       cli();
-       restore_flags(flags);
-       
        kfree(neigh);
 }
 
@@ -185,14 +179,14 @@ void neigh_unlink(struct neighbour *neigh)
        unsigned int hash_val;
        struct neighbour *next, *prev;
        
-       tbl = neigh->tbl;       
+       tbl = neigh->tbl;
        neigh->tbl = NULL;
-       
+
        hash_val = neigh->ops->hash(neigh->primary_key) % tbl->tbl_size;
 
        head = &tbl->hash_buckets[hash_val];
        tbl->tbl_entries--;
-       
+
        next = neigh->next;
        if (neigh == (*head))
        {
@@ -220,21 +214,21 @@ void ntbl_walk_table(struct neigh_table *tbl, ntbl_examine_t func,
                     unsigned long filter, int max, void *args)
 {
        int i;
-       
+
        if (max == 0)
                max = tbl->tbl_size;
-       
+
        for (i=0; i < max; i++)
        {
                struct neighbour **head;
                struct neighbour *entry;
-               
+
                head = &tbl->hash_buckets[i];
                entry = *head;
 
                if (!entry)
                        continue;
-               
+
                do {
                        if (entry->flags & (~filter))
                        {
@@ -247,10 +241,10 @@ void ntbl_walk_table(struct neigh_table *tbl, ntbl_examine_t func,
 
                                        curp = entry;
                                        entry = curp->next;
-                                       
+
                                        neigh_unlink(curp);
                                        neigh_destroy(curp);
-                                       
+
                                        if ((*head) == NULL)
                                                break;
                                        continue;
index 98d06802744e97db5193e66d91d8249eb216496a..fc7b9856be4af6564c7523950318a350d373c06f 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/skbuff.h>
 
 #include <net/ip.h>
-#include <net/ipv6.h>
 #include <net/protocol.h>
 #include <net/dst.h>
 #include <net/tcp.h>
@@ -607,7 +606,7 @@ struct sk_buff *alloc_skb(unsigned int size,int priority)
        int len;
        unsigned char *bptr;
 
-       if (intr_count && priority!=GFP_ATOMIC) 
+       if (0 && intr_count && priority!=GFP_ATOMIC) 
        {
                static int count = 0;
                if (++count < 5) {
@@ -663,6 +662,7 @@ struct sk_buff *alloc_skb(unsigned int size,int priority)
        skb->truesize=size;
        skb->stamp.tv_sec=0;    /* No idea about time */
        skb->ip_summed = 0;
+       skb->security = 0;      /* By default packets are insecure */
        skb->dst = NULL;
        skb->destructor = NULL;
        memset(skb->cb, 0, sizeof(skb->cb));
@@ -799,9 +799,6 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int priority)
        n->h.raw=skb->h.raw+offset;
        n->nh.raw=skb->nh.raw+offset;
        n->mac.raw=skb->mac.raw+offset;
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-       n->nexthop = skb->nexthop;
-#endif
        n->seq=skb->seq;
        n->end_seq=skb->end_seq;
        n->ack_seq=skb->ack_seq;
@@ -813,9 +810,8 @@ struct sk_buff *skb_copy(struct sk_buff *skb, int priority)
        n->users=1;
        n->pkt_type=skb->pkt_type;
        n->stamp=skb->stamp;
-       n->arp=skb->arp;
        n->destructor = NULL;
-       
+       n->security=skb->security;
        IS_SKB(n);
        return n;
 }
@@ -859,9 +855,6 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom)
        n->nh.raw=skb->nh.raw+offset;
        n->mac.raw=skb->mac.raw+offset;
        memcpy(n->cb, skb->cb, sizeof(skb->cb));
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-       n->nexthop = skb->nexthop;
-#endif
        n->seq=skb->seq;
        n->end_seq=skb->end_seq;
        n->ack_seq=skb->ack_seq;
@@ -873,7 +866,8 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, int newheadroom)
        n->pkt_type=skb->pkt_type;
        n->stamp=skb->stamp;
        n->destructor = NULL;
-       
+       n->security=skb->security;
+
        IS_SKB(n);
        return n;
 }
index 819c0ae8be839686c925536708824ec1f863288d..7a604ae550a7ba8c4df5640806fd81c55e45f5b0 100644 (file)
 #include <net/sock.h>
 #include <net/raw.h>
 #include <net/icmp.h>
+#include <linux/ipsec.h>
 
 #define min(a,b)       ((a)<(b)?(a):(b))
 
@@ -131,7 +132,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
        int err;
        struct linger ling;
        int ret = 0;
-
+       
        /*
         *      Options without arguments
         */
@@ -145,8 +146,13 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
        }
 #endif 
                
-       if(optlen<sizeof(int))
+       if(optlen<sizeof(int)) {
+#if 1 /* DaveM Debugging */
+               printk("sock_setsockopt: optlen is %d, going on anyways.\n", optlen);
+#else
                return(-EINVAL);
+#endif
+       }
        
        err = get_user(val, (int *)optval);
        if (err)
@@ -178,12 +184,19 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        sk->broadcast=valbool;
                        break;
                case SO_SNDBUF:
-                       if(val > SK_WMEM_MAX*2)
-                               val = SK_WMEM_MAX*2;
-                       if(val < 256)
-                               val = 256;
+                       /*
+                        *      The spec isnt clear if ENOBUFS or EINVAL
+                        *      is best
+                        */
+                        
+                       if(val > SK_WMEM_MAX*2 || val < 2048)
+                               return -EINVAL;
+                       /*
+                        *      Once this is all 32bit values we can
+                        *      drop this check.
+                        */
                        if(val > 65535)
-                               val = 65535;
+                               return -EINVAL;
                        sk->sndbuf = val;
                        /*
                         *      Wake up sending tasks if we
@@ -193,12 +206,11 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        break;
 
                case SO_RCVBUF:
-                       if(val > SK_RMEM_MAX*2)
-                               val = SK_RMEM_MAX*2;
-                       if(val < 256)
-                               val = 256;
+                       if(val > SK_RMEM_MAX*2 || val < 256)
+                               return -EINVAL;
+                       /* Can go soon: FIXME */
                        if(val > 65535)
-                               val = 65535;
+                               return -EINVAL;
                        sk->rcvbuf = val;
                        break;
 
@@ -253,7 +265,50 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                case SO_PASSCRED:
                        sock->passcred = valbool;
                        break;
-
+                       
+                       
+#ifdef CONFIG_NET_SECURITY                     
+               /*
+                *      FIXME: make these error things that are not
+                *      available!
+                */
+                
+               case SO_SECURITY_AUTHENTICATION:
+                       if(val<=IPSEC_LEVEL_DEFAULT)
+                       {
+                               sk->authentication=val;
+                               return 0;
+                       }
+                       if(net_families[sock->ops->family]->authentication)
+                               sk->authentication=val;
+                       else
+                               return -EINVAL;
+                       break;
+                       
+               case SO_SECURITY_ENCRYPTION_TRANSPORT:
+                       if(val<=IPSEC_LEVEL_DEFAULT)
+                       {
+                               sk->encryption=val;
+                               return 0;
+                       }
+                       if(net_families[sock->ops->family]->encryption)
+                               sk->encryption = val;
+                       else
+                               return -EINVAL;
+                       break;
+                       
+               case SO_SECURITY_ENCRYPTION_NETWORK:
+                       if(val<=IPSEC_LEVEL_DEFAULT)
+                       {
+                               sk->encrypt_net=val;
+                               return 0;
+                       }
+                       if(net_families[sock->ops->family]->encrypt_net)
+                               sk->encrypt_net = val;
+                       else
+                               return -EINVAL;
+                       break;
+#endif
                /* We implement the SO_SNDLOWAT etc to
                   not be settable (1003.1g 5.3) */
                default:
@@ -368,6 +423,19 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                        if(copy_to_user((void*)optval, &sk->peercred, len))
                                return -EFAULT;
                        return 0;
+                       
+               case SO_SECURITY_AUTHENTICATION:
+                       val = sk->authentication;
+                       break;
+                       
+               case SO_SECURITY_ENCRYPTION_TRANSPORT:
+                       val = sk->encryption;
+                       break;
+                       
+               case SO_SECURITY_ENCRYPTION_NETWORK:
+                       val = sk->encrypt_net;
+                       break;
+                       
                default:
                        return(-ENOPROTOOPT);
        }
index 8f008a3a09ae6b1329f0be2e183d660171e3e1da..b03bea8f1ca4275cdcd79a041b7d8790941c3b26 100644 (file)
 #include <net/sock.h>
 #include <net/ipv6.h>
 
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-#include <linux/in6.h>
-#include <net/ndisc.h>
-#endif
 
 #include <asm/checksum.h>
 
 
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-int (*ndisc_eth_hook) (unsigned char *, struct device *, 
-                      struct sk_buff *) = NULL;
-#endif
-
 void eth_setup(char *str, int *ints)
 {
        struct device *d = dev_base;
@@ -156,36 +147,26 @@ int eth_rebuild_header(struct sk_buff *skb)
 {
        struct ethhdr *eth = (struct ethhdr *)skb->data;
        struct device *dev = skb->dev;
+       struct neighbour *neigh = NULL;
 
        /*
         *      Only ARP/IP and NDISC/IPv6 are currently supported
         */
        
+       if (skb->dst)
+               neigh = skb->dst->neighbour;
+       if (neigh)
+               return neigh->ops->resolve(eth->h_dest, skb);
        switch (eth->h_proto)
        {
 #ifdef CONFIG_INET
        case __constant_htons(ETH_P_IP):
-
-               /*
-                *      Try to get ARP to resolve the header.
-                */
-
-               return arp_find(eth->h_dest, skb) ? 1 : 0;
-               break;
-#endif
-
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
-       case __constant_htons(ETH_P_IPV6):
-#ifdef CONFIG_IPV6
-               return (ndisc_eth_resolv(eth->h_dest, dev, skb));
-#else
-               if (ndisc_eth_hook)
-                       return (ndisc_eth_hook(eth->h_dest, dev, skb));
-#endif
-               break;
+               return arp_find(eth->h_dest, skb);
 #endif 
        default:
-               printk(KERN_DEBUG 
+               printk(KERN_DEBUG
                       "%s: unable to resolve type %X addresses.\n", 
                       dev->name, (int)eth->h_proto);
                
@@ -252,7 +233,8 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
        return htons(ETH_P_802_2);
 }
 
-int eth_header_cache(struct dst_entry *dst, struct dst_entry *neigh, struct hh_cache *hh)
+int eth_header_cache(struct dst_entry *dst, struct neighbour *neigh,
+                    struct hh_cache *hh)
 {
        unsigned short type = hh->hh_type;
        struct ethhdr *eth = (struct ethhdr*)hh->hh_data;
index 84c7c2063f1b339c699df13cf2fc80d828635537..9ce538dc41a936ecb13eac6b682e8d5729929751 100644 (file)
@@ -41,7 +41,7 @@ endif
 
 ifeq ($(CONFIG_IP_MASQUERADE),y)
 IPV4X_OBJS += ip_masq.o ip_masq_app.o
-M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o
+M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o
 endif
 
 ifeq ($(CONFIG_IP_ALIAS),y)
index bf45d901bd3fd15e1b171c78cc1d1ba5ccd46f2a..deb03f2a6e84534f4fb29c88a4594349f8721abf 100644 (file)
@@ -230,30 +230,6 @@ int sysctl_arp_max_pings = ARP_MAX_PINGS;
 
 int sysctl_arp_dead_res_time = ARP_DEAD_RES_TIME;
 
-/*
- *     This structure defines the ARP mapping cache.
- */
-
-struct arp_table
-{
-       union {
-               struct dst_entry        dst;
-               struct arp_table        *next;
-       } u;
-       unsigned long                   last_updated;           /* For expiry                   */
-       unsigned int                    flags;                  /* Control status               */
-       u32                             ip;
-       u32                             mask;                   /* netmask - used for generalised proxy arps (tridge)           */
-       int                             hatype;
-       unsigned char                   ha[MAX_ADDR_LEN];       /* Hardware address             */
-
-       /*
-        *      The following entries are only used for unresolved hw addresses.
-        */
-       struct timer_list               timer;                  /* expire timer                 */
-       int                             retries;                /* remaining retries            */
-       struct sk_buff_head             skb;                    /* list of queued packets       */
-};
 
 #if RT_CACHE_DEBUG >= 1
 #define ASSERT_BH() if (!intr_count) printk(KERN_CRIT __FUNCTION__ " called from SPL=0\n");
@@ -261,28 +237,17 @@ struct arp_table
 #define ASSERT_BH()
 #endif
 
+static void arp_neigh_destroy(struct neighbour *neigh);
+
 /*
- *     Interface to generic destionation cache.
+ *     Interface to generic neighbour cache.
  */
 
-static void arp_dst_destroy(struct dst_entry * dst);
-static struct dst_entry * arp_dst_check(struct dst_entry * dst)
-{
-       return dst;
-}
-
-static struct dst_entry * arp_dst_reroute(struct dst_entry * dst)
-{
-       return dst;
-}
-
-
-struct dst_ops arp_dst_ops =
-{
-       AF_UNSPEC,
-       arp_dst_check,
-       arp_dst_reroute,
-       arp_dst_destroy
+struct neigh_ops arp_neigh_ops = {
+       AF_INET,
+       NULL,
+       arp_find,
+       arp_neigh_destroy
 };
 
 
@@ -342,17 +307,17 @@ static __inline__ void arp_update_hhs(struct arp_table * entry)
 {
        struct hh_cache *hh;
        void (*update)(struct hh_cache*, struct device*, unsigned char*) =
-               entry->u.dst.dev->header_cache_update;
+               entry->u.neigh.dev->header_cache_update;
 
 #if RT_CACHE_DEBUG >= 1
-       if (!update && entry->u.dst.hh)
+       if (!update && entry->u.neigh.hh)
        {
-               printk(KERN_DEBUG "arp_update_hhs: no update callback for %s\n", entry->u.dst.dev->name);
+               printk(KERN_DEBUG "arp_update_hhs: no update callback for %s\n", entry->u.neigh.dev->name);
                return;
        }
 #endif
-       for (hh=entry->u.dst.hh; hh; hh=hh->hh_next)
-               update(hh, entry->u.dst.dev, entry->ha);
+       for (hh=entry->u.neigh.hh; hh; hh=hh->hh_next)
+               update(hh, entry->u.neigh.dev, entry->u.neigh.ha);
 }
 
 /*
@@ -363,7 +328,7 @@ static __inline__ void arp_invalidate_hhs(struct arp_table * entry)
 {
        struct hh_cache *hh;
 
-       for (hh=entry->u.dst.hh; hh; hh=hh->hh_next)
+       for (hh=entry->u.neigh.hh; hh; hh=hh->hh_next)
                hh->hh_uptodate = 0;
 }
 
@@ -378,7 +343,7 @@ static void arp_purge_send_q(struct arp_table *entry)
        ASSERT_BH();
 
        /* Release the list of `skb' pointers. */
-       while ((skb = skb_dequeue(&entry->skb)) != NULL)
+       while ((skb = skb_dequeue(&entry->u.neigh.arp_queue)) != NULL)
                kfree_skb(skb, FREE_WRITE);
        return;
 }
@@ -399,13 +364,13 @@ static void __inline__ arp_free(struct arp_table **entryp)
        arp_purge_send_q(entry);
        arp_invalidate_hhs(entry);
 
-       dst_free(&entry->u.dst);
+       neigh_destroy(&entry->u.neigh);
 }
 
 
-static void arp_dst_destroy(struct dst_entry * dst)
+static void arp_neigh_destroy(struct neighbour *neigh)
 {
-       struct arp_table *entry = (struct arp_table*)dst;
+       struct arp_table *entry = (struct arp_table*)neigh;
        struct hh_cache *hh, *next;
 
        ASSERT_BH();
@@ -413,8 +378,8 @@ static void arp_dst_destroy(struct dst_entry * dst)
        del_timer(&entry->timer);
        arp_purge_send_q(entry);
 
-       hh = entry->u.dst.hh;
-       entry->u.dst.hh = NULL;
+       hh = entry->u.neigh.hh;
+       entry->u.neigh.hh = NULL;
 
        for ( ; hh; hh = next)
        {
@@ -459,7 +424,7 @@ static void arpd_send(int req, u32 addr, struct device * dev, char *ha,
        arpreq->stamp = arpd_stamp;
        arpreq->updated = updated;
        if (ha)
-               memcpy(arpreq->ha, ha, sizeof(arpreq->ha));
+               memcpy(arpreq->u.neigh.ha, ha, sizeof(arpreq->u.neigh.ha));
 
        retval = netlink_post(NETLINK_ARPD, skb);
        if (retval)
@@ -538,7 +503,7 @@ static int arpd_callback(int minor, struct sk_buff *skb)
        else
        {
                start_bh_atomic();
-               arp_update(retreq->ip, retreq->ha, dev, retreq->updated, 0);
+               arp_update(retreq->ip, retreq->u.neigh.ha, dev, retreq->updated, 0);
                end_bh_atomic();
        }
 
@@ -576,7 +541,7 @@ static int arp_force_expire(void)
        unsigned long now = jiffies;
        int result = 0;
 
-       static int last_index;
+       static last_index;
 
        if (last_index >= ARP_TABLE_SIZE)
                last_index = 0;
@@ -589,8 +554,8 @@ static int arp_force_expire(void)
                {
                        if (!(entry->flags & ATF_PERM))
                        {
-                               if (!entry->u.dst.refcnt &&
-                                   now - entry->u.dst.lastuse > sysctl_arp_timeout)
+                               if (!entry->u.neigh.refcnt &&
+                                   now - entry->u.neigh.lastused > sysctl_arp_timeout)
                                {
 #if RT_CACHE_DEBUG >= 2
                                        printk("arp_force_expire: %08x expired\n", entry->ip);
@@ -601,11 +566,11 @@ static int arp_force_expire(void)
                                                goto done;
                                        continue;
                                }
-                               if (!entry->u.dst.refcnt &&
-                                   entry->u.dst.lastuse < oldest_used)
+                               if (!entry->u.neigh.refcnt &&
+                                   entry->u.neigh.lastused < oldest_used)
                                {
                                        oldest_entry = pentry;
-                                       oldest_used = entry->u.dst.lastuse;
+                                       oldest_used = entry->u.neigh.lastused;
                                }
                        }
                        pentry = &entry->u.next;
@@ -637,7 +602,7 @@ static void arp_unres_expire(void)
                            (entry->retries < sysctl_arp_max_tries ||
                             entry->timer.expires - now <
                             sysctl_arp_res_time - sysctl_arp_res_time/32)) {
-                               if (!entry->u.dst.refcnt) {
+                               if (!entry->u.neigh.refcnt) {
 #if RT_CACHE_DEBUG >= 2
                                        printk("arp_unres_expire: %08x discarded\n", entry->ip);
 #endif
@@ -688,8 +653,8 @@ static void arp_check_expire(unsigned long dummy)
                                continue;
                        }
 
-                       if (!entry->u.dst.refcnt &&
-                           now - entry->u.dst.lastuse > sysctl_arp_timeout)
+                       if (!entry->u.neigh.refcnt &&
+                           now - entry->u.neigh.lastused > sysctl_arp_timeout)
                        {
 #if RT_CACHE_DEBUG >= 2
                                printk("arp_expire: %08x expired\n", entry->ip);
@@ -700,13 +665,13 @@ static void arp_check_expire(unsigned long dummy)
                        if (entry->last_updated &&
                            now - entry->last_updated > sysctl_arp_confirm_interval)
                        {
-                               struct device * dev = entry->u.dst.dev;
+                               struct device * dev = entry->u.neigh.dev;
                                entry->retries = sysctl_arp_max_tries+sysctl_arp_max_pings;
                                del_timer(&entry->timer);
                                entry->timer.expires = jiffies + ARP_CONFIRM_TIMEOUT;
                                add_timer(&entry->timer);
                                arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip,
-                                        dev, dev->pa_addr, entry->ha,
+                                        dev, dev->pa_addr, entry->u.neigh.ha,
                                         dev->dev_addr, NULL);
 #if RT_CACHE_DEBUG >= 2
                                printk("arp_expire: %08x requires confirmation\n", entry->ip);
@@ -750,7 +715,7 @@ static void arp_expire_request (unsigned long arg)
 
        if (entry->last_updated && --entry->retries > 0)
        {
-               struct device *dev = entry->u.dst.dev;
+               struct device *dev = entry->u.neigh.dev;
 
 #if RT_CACHE_DEBUG >= 2
                printk("arp_expire_request: %08x timed out\n", entry->ip);
@@ -759,7 +724,7 @@ static void arp_expire_request (unsigned long arg)
                entry->timer.expires = jiffies + sysctl_arp_res_time;
                add_timer(&entry->timer);
                arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr,
-                        entry->retries > sysctl_arp_max_tries ? entry->ha : NULL,
+                        entry->retries > sysctl_arp_max_tries ? entry->u.neigh.ha : NULL,
                         dev->dev_addr, NULL);
                return;
        }
@@ -770,7 +735,7 @@ static void arp_expire_request (unsigned long arg)
 
        arp_purge_send_q(entry);
 
-       if (entry->u.dst.refcnt)
+       if (entry->u.neigh.refcnt)
        {
                /*
                 *      The host is dead, but someone refers to it.
@@ -780,7 +745,7 @@ static void arp_expire_request (unsigned long arg)
                 *      to ARP_DEAD_RES_TIME.
                 */
 
-               struct device *dev = entry->u.dst.dev;
+               struct device *dev = entry->u.neigh.dev;
 #if RT_CACHE_DEBUG >= 2
                printk("arp_expire_request: %08x is dead\n", entry->ip);
 #endif
@@ -842,7 +807,9 @@ static struct arp_table * arp_alloc(int how)
                }
        }
 
-       entry = (struct arp_table *)dst_alloc(sizeof(struct arp_table), &arp_dst_ops);
+       entry = (struct arp_table *)neigh_alloc(sizeof(struct arp_table),
+                                               &arp_neigh_ops);
+       entry->u.neigh.refcnt = 1;
 
        if (entry != NULL)
        {
@@ -854,7 +821,6 @@ static struct arp_table * arp_alloc(int how)
                entry->timer.function = arp_expire_request;
                entry->timer.data = (unsigned long)entry;
                entry->last_updated = jiffies;
-               skb_queue_head_init(&entry->skb);
        }
        return entry;
 }
@@ -887,7 +853,7 @@ int arp_device_event(struct notifier_block *this, unsigned long event, void *ptr
 
                while ((entry = *pentry) != NULL)
                {
-                       if (entry->u.dst.dev != dev)
+                       if (entry->u.neigh.dev != dev)
                        {
                                pentry = &entry->u.next;
                                continue;
@@ -912,7 +878,7 @@ static void arp_send_q(struct arp_table *entry)
 
        ASSERT_BH();
 
-       while((skb = skb_dequeue(&entry->skb)) != NULL) {
+       while((skb = skb_dequeue(&entry->u.neigh.arp_queue)) != NULL) {
                dev_queue_xmit(skb);
        }
 }
@@ -934,7 +900,7 @@ arp_update (u32 sip, char *sha, struct device * dev,
        hash = HASH(sip);
 
        for (entry=arp_tables[hash]; entry; entry = entry->u.next)
-               if (entry->ip == sip && entry->u.dst.dev == dev)
+               if (entry->ip == sip && entry->u.neigh.dev == dev)
                        break;
 
        if (entry)
@@ -946,9 +912,9 @@ arp_update (u32 sip, char *sha, struct device * dev,
                {
                        del_timer(&entry->timer);
                        entry->last_updated = updated;
-                       if (memcmp(entry->ha, sha, dev->addr_len) != 0)
+                       if (memcmp(entry->u.neigh.ha, sha, dev->addr_len) != 0)
                        {
-                               memcpy(entry->ha, sha, dev->addr_len);
+                               memcpy(entry->u.neigh.ha, sha, dev->addr_len);
                                if (entry->flags & ATF_COM)
                                        arp_update_hhs(entry);
                        }
@@ -982,14 +948,14 @@ arp_update (u32 sip, char *sha, struct device * dev,
 
        entry->ip = sip;
        entry->flags = ATF_COM;
-       memcpy(entry->ha, sha, dev->addr_len);
-       entry->u.dst.dev = dev;
+       memcpy(entry->u.neigh.ha, sha, dev->addr_len);
+       entry->u.neigh.dev = dev;
        entry->hatype = dev->type;
        entry->last_updated = updated;
 
        entry->u.next = arp_tables[hash];
        arp_tables[hash] = entry;
-       dst_release(&entry->u.dst);
+       neigh_release(&entry->u.neigh);
        return 0;
 }
 
@@ -1000,7 +966,7 @@ static __inline__ struct arp_table *arp_lookup(u32 paddr, struct device * dev)
        struct arp_table *entry;
 
        for (entry = arp_tables[HASH(paddr)]; entry != NULL; entry = entry->u.next)
-               if (entry->ip == paddr && entry->u.dst.dev == dev)
+               if (entry->ip == paddr && entry->u.neigh.dev == dev)
                        return entry;
        return NULL;
 }
@@ -1043,7 +1009,7 @@ static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, s
 
 static void arp_start_resolution(struct arp_table *entry)
 {
-       struct device * dev = entry->u.dst.dev;
+       struct device * dev = entry->u.neigh.dev;
 
        del_timer(&entry->timer);
        entry->timer.expires = jiffies + sysctl_arp_res_time;
@@ -1072,17 +1038,17 @@ struct arp_table * arp_new_entry(u32 paddr, struct device *dev, struct sk_buff *
        if (entry != NULL)
        {
                entry->ip = paddr;
-               entry->u.dst.dev = dev;
+               entry->u.neigh.dev = dev;
                entry->hatype = dev->type;
 
                if (skb != NULL)
-                       skb_queue_tail(&entry->skb, skb);
+                       skb_queue_tail(&entry->u.neigh.arp_queue, skb);
 
                atomic_inc(&arp_unres_size);
                entry->u.next = arp_tables[hash];
                arp_tables[hash] = entry;
                arp_start_resolution(entry);
-               dst_release(&entry->u.dst);
+               neigh_release(&entry->u.neigh);
        }
        return entry;
 }
@@ -1125,8 +1091,8 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
        {
                if (entry->flags & ATF_COM)
                {
-                       entry->u.dst.lastuse = jiffies;
-                       memcpy(haddr, entry->ha, dev->addr_len);
+                       entry->u.neigh.lastused = jiffies;
+                       memcpy(haddr, entry->u.neigh.ha, dev->addr_len);
                        if (skb)
                                skb->arp = 1;
                        end_bh_atomic();
@@ -1142,8 +1108,8 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
                {
                        if (entry->last_updated)
                        {
-                               if (entry->skb.qlen < ARP_MAX_UNRES_PACKETS)
-                                       skb_queue_tail(&entry->skb, skb);
+                               if (entry->u.neigh.arp_queue.qlen < ARP_MAX_UNRES_PACKETS)
+                                       skb_queue_tail(&entry->u.neigh.arp_queue, skb);
                                else
                                        kfree_skb(skb, FREE_WRITE);
                        }
@@ -1171,7 +1137,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
 }
 
 int arp_find_1(unsigned char *haddr, struct dst_entry *dst,
-              struct dst_entry *neigh)
+              struct neighbour *neigh)
 {
        struct rtable *rt = (struct rtable*)dst;
        struct device *dev = dst->dev;
@@ -1218,8 +1184,8 @@ int arp_find_1(unsigned char *haddr, struct dst_entry *dst,
 
        if (entry->flags & ATF_COM)
        {
-               entry->u.dst.lastuse = jiffies;
-               memcpy(haddr, entry->ha, dev->addr_len);
+               entry->u.neigh.lastused = jiffies;
+               memcpy(haddr, entry->u.neigh.ha, dev->addr_len);
                end_bh_atomic();
                return 1;
        }
@@ -1229,7 +1195,7 @@ int arp_find_1(unsigned char *haddr, struct dst_entry *dst,
 }
 
 
-struct dst_entry* arp_find_neighbour(struct dst_entry *dst, int resolve)
+struct neighbour* arp_find_neighbour(struct dst_entry *dst, int resolve)
 {
        struct rtable *rt = (struct rtable*)dst;
        struct device *dev = rt->u.dst.dev;
@@ -1255,10 +1221,10 @@ struct dst_entry* arp_find_neighbour(struct dst_entry *dst, int resolve)
 
        if (entry != NULL)      /* It exists */
        {
-               atomic_inc(&entry->u.dst.refcnt);
+               atomic_inc(&entry->u.neigh.refcnt);
                end_bh_atomic();
-               entry->u.dst.lastuse = jiffies;
-               return (struct dst_entry*)entry;
+               entry->u.neigh.lastused = jiffies;
+               return (struct neighbour*)entry;
        }
 
        if (!resolve)
@@ -1267,11 +1233,11 @@ struct dst_entry* arp_find_neighbour(struct dst_entry *dst, int resolve)
        entry = arp_new_entry(paddr, dev, NULL);
 
        if (entry)
-               atomic_inc(&entry->u.dst.refcnt);
+               atomic_inc(&entry->u.neigh.refcnt);
 
        end_bh_atomic();
 
-       return (struct dst_entry*)entry;
+       return (struct neighbour*)entry;
 }
 
 /*
@@ -1526,14 +1492,14 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 
                for (entry = arp_proxy_list; entry; entry = entry->u.next) {
                        if (!((entry->ip^tip)&entry->mask) &&
-                           ((!entry->u.dst.dev &&
+                           ((!entry->u.neigh.dev &&
                              (!(entry->flags & ATF_COM) || entry->hatype == dev->type))
-                            || entry->u.dst.dev == dev) )
+                            || entry->u.neigh.dev == dev) )
                                break;
                }
 
                if (entry && !(entry->flags & ATF_DONTPUB)) {
-                       char *ha = (entry->flags & ATF_COM) ? entry->ha : dev->dev_addr;
+                       char *ha = (entry->flags & ATF_COM) ? entry->u.neigh.ha : dev->dev_addr;
 
                        if (rt->rt_flags&(RTF_LOCAL|RTF_NAT) ||
                            (!(rt->rt_flags&RTCF_DOREDIRECT) &&
@@ -1651,7 +1617,7 @@ int arp_req_set(struct arpreq *r, struct device * dev)
        while ((entry = *entryp) != NULL && entry->mask == mask &&
               entry->ip == ip)
        {
-               if (!entry->u.dst.dev || entry->u.dst.dev == dev)
+               if (!entry->u.neigh.dev || entry->u.neigh.dev == dev)
                        break;
                entryp = &entry->u.next;
        }
@@ -1659,7 +1625,7 @@ int arp_req_set(struct arpreq *r, struct device * dev)
        while ((entry = *entryp) != NULL)
        {
                if (entry->ip != ip || entry->mask != mask ||
-                   entry->u.dst.dev != dev)
+                   entry->u.neigh.dev != dev)
                {
                        entry = NULL;
                        break;
@@ -1672,7 +1638,7 @@ int arp_req_set(struct arpreq *r, struct device * dev)
        }
 
        if (entry)
-               atomic_inc(&entry->u.dst.refcnt);
+               atomic_inc(&entry->u.neigh.refcnt);
        else
        {
                entry = arp_alloc(r->arp_flags&ATF_PUBL ? 0 : 1);
@@ -1682,7 +1648,7 @@ int arp_req_set(struct arpreq *r, struct device * dev)
                        return -ENOMEM;
                }
                entry->ip = ip;
-               entry->u.dst.dev = dev;
+               entry->u.neigh.dev = dev;
                entry->mask = mask;
 
                if (dev)
@@ -1709,24 +1675,24 @@ int arp_req_set(struct arpreq *r, struct device * dev)
                ha = r->arp_ha.sa_data;
 
        if (ha)
-               memcpy(entry->ha, ha, dev ? dev->addr_len : MAX_ADDR_LEN);
+               memcpy(entry->u.neigh.ha, ha, dev ? dev->addr_len : MAX_ADDR_LEN);
        else
-               memset(entry->ha, 0, MAX_ADDR_LEN);
+               memset(entry->u.neigh.ha, 0, MAX_ADDR_LEN);
 
-       entry->last_updated = entry->u.dst.lastuse = jiffies;
+       entry->last_updated = entry->u.neigh.lastused = jiffies;
        
        if (!(entry->flags & ATF_PUBL))
        {
                if (entry->flags & ATF_COM)
                {
-                       arpd_update(entry->ip, entry->u.dst.dev, ha);
+                       arpd_update(entry->ip, entry->u.neigh.dev, ha);
                        arp_update_hhs(entry);
                }
                else
                        arp_start_resolution(entry);
        }
 
-       dst_release(&entry->u.dst);
+       neigh_release(&entry->u.neigh);
        end_bh_atomic();
        return 0;
 }
@@ -1761,14 +1727,14 @@ static int arp_req_get(struct arpreq *r, struct device *dev)
                if (entry->ip == si->sin_addr.s_addr &&
                    (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask) &&
                    ( (r->arp_flags&ATF_PUBL) ?
-                     (entry->u.dst.dev == dev && entry->hatype == r->arp_ha.sa_family)
-                    : (entry->u.dst.dev == dev || !dev)))
+                     (entry->u.neigh.dev == dev && entry->hatype == r->arp_ha.sa_family)
+                    : (entry->u.neigh.dev == dev || !dev)))
                {
-                       if (entry->u.dst.dev)
+                       if (entry->u.neigh.dev)
                        {
-                               memcpy(r->arp_ha.sa_data, entry->ha, entry->u.dst.dev->addr_len);
-                               r->arp_ha.sa_family = entry->u.dst.dev->type;
-                               strncpy(r->arp_dev, entry->u.dst.dev->name, sizeof(r->arp_dev));
+                               memcpy(r->arp_ha.sa_data, entry->u.neigh.ha, entry->u.neigh.dev->addr_len);
+                               r->arp_ha.sa_family = entry->u.neigh.dev->type;
+                               strncpy(r->arp_dev, entry->u.neigh.dev->name, sizeof(r->arp_dev));
                        }
                        else
                        {
@@ -1811,10 +1777,10 @@ int arp_req_delete(struct arpreq *r, struct device * dev)
        {
                if (entry->ip == si->sin_addr.s_addr
                    && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask)
-                   && (entry->u.dst.dev == dev || (!(r->arp_flags&ATF_PUBL) && !dev))
+                   && (entry->u.neigh.dev == dev || (!(r->arp_flags&ATF_PUBL) && !dev))
                    && (!(r->arp_flags&ATF_MAGIC) || r->arp_flags == entry->flags))
                {
-                       if (!entry->u.dst.refcnt)
+                       if (!entry->u.neigh.refcnt)
                        {
                                arp_free(entryp);
                                retval = 0;
@@ -1971,21 +1937,21 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
                        if (entry->hatype == ARPHRD_AX25 || entry->hatype == ARPHRD_NETROM)
-                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+                            strcpy(hbuffer,ax2asc((ax25_address *)entry->u.neigh.ha));
                        else {
 #else
                        if(entry->hatype==ARPHRD_AX25)
-                            strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+                            strcpy(hbuffer,ax2asc((ax25_address *)entry->u.neigh.ha));
                        else {
 #endif
 #endif
                                
-                       if (entry->u.dst.dev)
+                       if (entry->u.neigh.dev)
                        {
-                               for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->u.dst.dev->addr_len;j++)
+                               for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->u.neigh.dev->addr_len;j++)
                                {
-                                       hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
-                                       hbuffer[k++]=hexbuf[  entry->ha[j]&15     ];
+                                       hbuffer[k++]=hexbuf[ (entry->u.neigh.ha[j]>>4)&15 ];
+                                       hbuffer[k++]=hexbuf[  entry->u.neigh.ha[j]&15     ];
                                        hbuffer[k++]=':';
                                }
                                hbuffer[--k]=0;
@@ -2008,16 +1974,16 @@ int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy
                                 "     %-17s %s\n",
                                 entry->mask==DEF_ARP_NETMASK ?
                                 "*" : in_ntoa(entry->mask),
-                                       entry->u.dst.dev ? entry->u.dst.dev->name : "*");
+                                       entry->u.neigh.dev ? entry->u.neigh.dev->name : "*");
 #else
                        size += sprintf(buffer+len+size,
                                 "     %-17s %s\t%d\t%d\t%1d\n",
                                 entry->mask==DEF_ARP_NETMASK ?
                                 "*" : in_ntoa(entry->mask),
-                                entry->u.dst.dev ? entry->u.dst.dev->name : "*", 
-                                entry->u.dst.refcnt,
-                                entry->u.dst.hh ? entry->u.dst.hh->hh_refcnt : -1,
-                                entry->u.dst.hh ? entry->u.dst.hh->hh_uptodate : 0);
+                                entry->u.neigh.dev ? entry->u.neigh.dev->name : "*", 
+                                entry->u.neigh.refcnt,
+                                entry->u.neigh.hh ? entry->u.neigh.hh->hh_refcnt : -1,
+                                entry->u.neigh.hh ? entry->u.neigh.hh->hh_uptodate : 0);
 #endif
        
                        len += size;
index 666302fc9376428940378f1a9a0eb0ebcc160cf3..b6db1eb7a6d967809fba877ecc64aeb941e134fd 100644 (file)
@@ -687,6 +687,16 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
        unsigned char *dp;
        struct sock *raw_sk;
        
+       /*
+        *      Incomplete header ?
+        */
+        
+       if(skb->len<sizeof(struct iphdr)+8)
+       {
+               kfree_skb(skb, FREE_READ);
+               return;
+       }
+       
        iph = (struct iphdr *) (icmph + 1);
        dp = (unsigned char*)iph;
        
@@ -733,15 +743,32 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
         *      RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.
         *      RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.
         */
+        
+       /*
+        *      Check the other end isnt violating RFC 1122. Some routers send
+        *      bogus responses to broadcast frames. If you see this message
+        *      first check your netmask matches at both ends, if it does then
+        *      get the other vendor to fix their kit.
+        */
+        
+       if(__ip_chk_addr(iph->daddr)==IS_BROADCAST)
+       {
+               printk("%s sent an invalid ICMP error to a broadcast.\n",
+                       in_ntoa(iph->daddr));
+               kfree_skb(skb, FREE_READ);
+       }
 
-       /* Deliver ICMP message to raw sockets. Pretty useless feature?
+       /*
+        *      Deliver ICMP message to raw sockets. Pretty useless feature?
         */
 
        /* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
        hash = iph->protocol & (MAX_INET_PROTOS - 1);
-       if ((raw_sk = raw_v4_htable[hash]) != NULL) {
+       if ((raw_sk = raw_v4_htable[hash]) != NULL) 
+       {
                raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr);
-               while (raw_sk) {
+               while (raw_sk) 
+               {
                        raw_err(raw_sk, skb);
                        raw_sk = raw_v4_lookup(raw_sk->next, iph->protocol,
                                               iph->saddr, iph->daddr);
@@ -750,8 +777,6 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
 
        /*
         *      This can't change while we are doing it. 
-        *
-        *      FIXME: Deliver to appropriate raw sockets too.
         */
 
        ipprot = (struct inet_protocol *) inet_protos[hash];
index 731de734671657509324b93ec771d9179d9d7ac0..f1202514ec4b2e44ebdaa1fafd61689298d6f87b 100644 (file)
@@ -71,6 +71,7 @@ int ip_forward(struct sk_buff *skb)
        struct iphdr *iph;      /* Our header */
        struct rtable *rt;      /* Route we use */
        struct ip_options * opt = &(IPCB(skb)->opt);
+       unsigned short mtu;
 #if defined(CONFIG_FIREWALL) || defined(CONFIG_IP_MASQUERADE)
        int fw_res = 0;
 #endif
@@ -118,7 +119,12 @@ int ip_forward(struct sk_buff *skb)
 
        skb->priority = rt->u.dst.priority;
        dev2 = rt->u.dst.dev;
+       mtu = dev2->mtu;
 
+#ifdef CONFIG_NET_SECURITY
+       call_fw_firewall(PF_SECURITY, dev2, NULL, &mtu, NULL);
+#endif 
+       
        /*
         *      In IP you never have to forward a frame on the interface that it 
         *      arrived upon. We now generate an ICMP HOST REDIRECT giving the route
@@ -133,9 +139,9 @@ int ip_forward(struct sk_buff *skb)
         */
 
        if (dev2->flags & IFF_UP) {
-               if (skb->len > dev2->mtu && (ntohs(iph->frag_off) & IP_DF)) {
+               if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF)) {
                        ip_statistics.IpFragFails++;
-                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(dev2->mtu));
+                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
                        kfree_skb(skb, FREE_WRITE);
                        return -1;
                }
@@ -175,7 +181,7 @@ int ip_forward(struct sk_buff *skb)
                                goto skip_call_fw_firewall;
 #endif
 #ifdef CONFIG_FIREWALL
-               fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL);
+               fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL, &skb);
                switch (fw_res) {
                case FW_ACCEPT:
                case FW_MASQUERADE:
@@ -220,7 +226,7 @@ skip_call_fw_firewall:
                }
 
 #ifdef CONFIG_FIREWALL
-               if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL)) < FW_ACCEPT) {
+               if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL,&skb)) < FW_ACCEPT) {
                        /* FW_ACCEPT and FW_MASQUERADE are treated equal:
                           masquerading is only supported via forward rules */
                        if (fw_res == FW_REJECT)
index 0c922f27a646917ddea3dc199103df62dbf53920..3b690f0f3efac16d5854b4a49c0b19f38f7f3f83 100644 (file)
@@ -562,7 +562,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb)
                        else
                                qp->fragments = tmp->next;
 
-                       if (tfp->next != NULL)
+                       if (tmp->next != NULL)
                                tmp->next->prev = tmp->prev;
                        
                        next=tfp;       /* We have killed the original next frame */
index 1ba0b8f6ab6d8871f9b5299705f6b3e874840b44..e516a2baafcb6c95fd9528f0ea4bf6624602b632 100644 (file)
@@ -1196,17 +1196,17 @@ static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
  *     Interface to the generic firewall chains.
  */
  
-int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg)
+int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb)
 {
        return ip_fw_chk(phdr, dev, arg, ip_fw_in_chain, ip_fw_in_policy, IP_FW_MODE_FW);
 }
 
-int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg)
+int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb)
 {
        return ip_fw_chk(phdr, dev, arg, ip_fw_out_chain, ip_fw_out_policy, IP_FW_MODE_FW);
 }
 
-int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg)
+int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb)
 {
        return ip_fw_chk(phdr, dev, arg, ip_fw_fwd_chain, ip_fw_fwd_policy, IP_FW_MODE_FW);
 }
index d0e691ac1d51e49a9561fdef197783a74dd38f5e..2642832e3d287ff21852e2aee5dfbfe03e8225a1 100644 (file)
 #include <linux/mroute.h>
 #include <net/netlink.h>
 #include <linux/net_alias.h>
+#include <linux/ipsec.h>
 
 /*
  *     SNMP management statistics
@@ -266,7 +267,12 @@ int ip_local_deliver(struct sk_buff *skb)
                                else
                                        break;  /* One pending raw socket left */
                                if(skb1)
-                                       raw_rcv(raw_sk, skb1);
+                               {
+                                       if(ipsec_sk_policy(raw_sk,skb1))        
+                                               raw_rcv(raw_sk, skb1);
+                                       else
+                                               kfree_skb(skb1, FREE_WRITE);
+                               }
                                raw_sk = sknext;
                        } while(raw_sk!=NULL);
                                
@@ -323,7 +329,12 @@ int ip_local_deliver(struct sk_buff *skb)
         */
 
        if(raw_sk!=NULL)        /* Shift to last raw user */
-               raw_rcv(raw_sk, skb);
+       {
+               if(ipsec_sk_policy(raw_sk, skb))
+                       raw_rcv(raw_sk, skb);
+               else
+                       kfree_skb(skb, FREE_WRITE);
+       }
        else if (!flag)         /* Free and report errors */
        {
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);        
@@ -434,7 +445,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                int fwres;
                u16 rport;
 
-               if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport))<FW_ACCEPT) {
+               if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport, &skb))<FW_ACCEPT) {
                        if (fwres==FW_REJECT)
                                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
                        goto drop;
diff --git a/net/ipv4/ip_masq_quake.c b/net/ipv4/ip_masq_quake.c
new file mode 100644 (file)
index 0000000..3614f0c
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ *             IP_MASQ_QUAKE quake masquerading module
+ *
+ *
+ * Version:    @(#)ip_masq_quake.c 0.02   22/02/97
+ *
+ * Author:     Harald Hoyer mailto:HarryH@Royal.Net
+ *             
+ *
+ * Fixes: 
+ *      Harald Hoyer            :       Unofficial Quake Specs found at 
+ *                                 http://www.gamers.org/dEngine/quake/spec/ 
+ *      Harald Hoyer            :       Check for QUAKE-STRING
+ *
+ *     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/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/protocol.h>
+#include <net/udp.h>
+#include <net/ip_masq.h>
+
+#define DEBUG_CONFIG_IP_MASQ_QUAKE 0
+
+typedef struct
+{ 
+        __u16 type;     // (Little Endian) Type of message.
+       __u16 length;   // (Little Endian) Length of message, header included. 
+       char  message[0];  // The contents of the message.
+} QUAKEHEADER;
+
+struct quake_priv_data {
+       /* Have we seen a client connect message */
+       char    cl_connect;
+};
+
+static int
+masq_quake_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+        MOD_INC_USE_COUNT;
+       if ((ms->app_data = kmalloc(sizeof(struct quake_priv_data),
+                                   GFP_ATOMIC)) == NULL) 
+               printk(KERN_INFO "Quake: No memory for application data\n");
+       else 
+       {
+               struct quake_priv_data *priv = 
+                       (struct quake_priv_data *)ms->app_data;
+               priv->cl_connect = 0;
+       }
+        return 0;
+}
+
+static int
+masq_quake_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
+{
+       MOD_DEC_USE_COUNT;
+       if (ms->app_data)
+               kfree_s(ms->app_data, sizeof(struct quake_priv_data));
+       return 0;
+}
+
+int
+masq_quake_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+       struct sk_buff *skb;
+       struct iphdr *iph;
+       struct udphdr *uh;
+       QUAKEHEADER *qh;
+       __u16 udp_port;
+       char *data;
+       unsigned char code;
+       struct quake_priv_data *priv = (struct quake_priv_data *)ms->app_data;
+        
+       if(priv->cl_connect == -1)
+         return 0;
+
+       skb = *skb_p;
+
+       iph = skb->nh.iph;
+       uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+
+       /* Check for lenght */
+       if(ntohs(uh->len) < 5)
+         return 0;
+       
+       qh = (QUAKEHEADER *)&uh[1];
+
+       if(qh->type != 0x0080)
+         return 0;
+
+       
+       code = qh->message[0];
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+         printk("Quake_in: code = %d \n", (int)code);
+#endif
+
+       switch(code) {
+       case 0x01:
+         /* Connection Request */
+
+         if(ntohs(qh->length) < 0x0c) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+           printk("Quake_in: length < 0xc \n");
+#endif
+           return 0;
+         }
+
+         data = &qh->message[1];
+
+         /* Check for stomping string */
+         if(memcmp(data,"QUAKE\0\3",7)) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+           printk("Quake_out: memcmp failed \n");
+#endif
+           return 0;
+         }
+         else {
+           priv->cl_connect = 1;
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+           printk("Quake_out: memcmp ok \n");
+#endif
+         }
+         break;
+
+       case 0x81:
+         /* Accept Connection */
+         if((ntohs(qh->length) < 0x09) || (priv->cl_connect == 0))
+           return 0;
+         data = &qh->message[1];
+
+         memcpy(&udp_port, data, 2);
+
+         ms->dport = htons(udp_port);
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+         printk("Quake_in: in_rewrote UDP port %d \n", udp_port);
+#endif
+         priv->cl_connect = -1;
+
+         break;
+       }
+        
+       return 0;
+}
+
+int
+masq_quake_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, struct device *dev)
+{
+       struct sk_buff *skb;
+       struct iphdr *iph;
+       struct udphdr *uh;
+       QUAKEHEADER *qh;
+       __u16 udp_port;
+       char *data;
+       unsigned char code;
+       struct ip_masq *n_ms;
+       struct quake_priv_data *priv = (struct quake_priv_data *)ms->app_data;
+
+       if(priv->cl_connect == -1)
+         return 0;
+        
+       skb = *skb_p;
+
+       iph = skb->nh.iph;
+       uh = (struct udphdr *)&(((char *)iph)[iph->ihl*4]);
+
+       /* Check for lenght */
+       if(ntohs(uh->len) < 5)
+         return 0;
+       
+       qh = (QUAKEHEADER *)&uh[1];
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+         printk("Quake_out: qh->type = %d \n", (int)qh->type);
+#endif
+
+       if(qh->type != 0x0080)
+         return 0;
+       
+       code = qh->message[0];
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+         printk("Quake_out: code = %d \n", (int)code);
+#endif
+
+       switch(code) {
+       case 0x01:
+         /* Connection Request */
+
+         if(ntohs(qh->length) < 0x0c) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+           printk("Quake_out: length < 0xc \n");
+#endif
+           return 0;
+         }
+
+         data = &qh->message[1];
+
+         /* Check for stomping string */
+         if(memcmp(data,"QUAKE\0\3",7)) {
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+           printk("Quake_out: memcmp failed \n");
+#endif
+           return 0;
+         }
+         else {
+           priv->cl_connect = 1;
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+           printk("Quake_out: memcmp ok \n");
+#endif
+         }
+         break;
+
+       case 0x81:
+         /* Accept Connection */
+         if((ntohs(qh->length) < 0x09) || (priv->cl_connect == 0))
+           return 0;
+
+         data = &qh->message[1];
+
+         memcpy(&udp_port, data, 2);
+         
+         n_ms = ip_masq_new(dev, IPPROTO_UDP,
+                            ms->saddr, htons(udp_port),
+                            ms->daddr, ms->dport,
+                            0);
+
+         if (n_ms==NULL)
+           return 0;
+
+#if DEBUG_CONFIG_IP_MASQ_QUAKE
+         printk("Quake_out: out_rewrote UDP port %d -> %d\n",
+                udp_port, ntohs(n_ms->mport));
+#endif
+         udp_port = ntohs(n_ms->mport);
+         memcpy(data, &udp_port, 2);
+
+         break;
+       }
+        
+       return 0;
+}
+
+struct ip_masq_app ip_masq_quake = {
+        NULL,                  /* next */
+       "Quake_26",             /* name */
+        0,                      /* type */
+        0,                      /* n_attach */
+        masq_quake_init_1,      /* ip_masq_init_1 */
+        masq_quake_done_1,      /* ip_masq_done_1 */
+        masq_quake_out,         /* pkt_out */
+        masq_quake_in           /* pkt_in */
+};
+struct ip_masq_app ip_masq_quakenew = {
+        NULL,                  /* next */
+       "Quake_27",             /* name */
+        0,                      /* type */
+        0,                      /* n_attach */
+        masq_quake_init_1,      /* ip_masq_init_1 */
+        masq_quake_done_1,      /* ip_masq_done_1 */
+        masq_quake_out,         /* pkt_out */
+        masq_quake_in           /* pkt_in */
+};
+
+/*
+ *     ip_masq_quake initialization
+ */
+
+int ip_masq_quake_init(void)
+{
+        return (register_ip_masq_app(&ip_masq_quake, IPPROTO_UDP, 26000) +
+               register_ip_masq_app(&ip_masq_quakenew, IPPROTO_UDP, 27000));
+}
+
+/*
+ *     ip_masq_quake fin.
+ */
+
+int ip_masq_quake_done(void)
+{
+        return (unregister_ip_masq_app(&ip_masq_quake) +
+                unregister_ip_masq_app(&ip_masq_quakenew));
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+        if (ip_masq_quake_init() != 0)
+                return -EIO;
+        return 0;
+}
+
+void cleanup_module(void)
+{
+        if (ip_masq_quake_done() != 0)
+                printk("ip_masq_quake: can't remove module");
+}
+
+#endif /* MODULE */
+
+
index 244438d3319136d516d093a6553c85f60ba31a51..e4a34a39c685598ad7b7064a7ad225cdaea7868c 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/firewall.h>
 #include <linux/mroute.h>
 #include <net/netlink.h>
+#include <linux/ipsec.h>
 
 static void __inline__ ip_ll_header_reserve(struct sk_buff *skb)
 {
@@ -356,11 +357,27 @@ void ip_queue_xmit(struct sk_buff *skb)
        iph->tot_len = htons(tot_len);
        iph->id = htons(ip_id_count++);
 
-#ifdef CONFIG_FIREWALL
-       if (call_out_firewall(PF_INET, dev, iph, NULL) < FW_ACCEPT) {
+       if (call_out_firewall(PF_INET, dev, iph, NULL,&skb) < FW_ACCEPT) {
                kfree_skb(skb, FREE_WRITE);
                return;
        }
+       
+#ifdef CONFIG_NET_SECURITY     
+       /*
+        *      Add an IP checksum (must do this before SECurity because
+        *      of possible tunneling)
+        */
+
+       ip_send_check(iph);
+
+       if (call_out_firewall(PF_SECURITY, NULL, NULL, (void *) 4, &skb)<FW_ACCEPT)
+       {
+               kfree_skb(skb, FREE_WRITE);
+               return;
+       }
+       
+       iph = skb->nh.iph;
+       /* don't update tot_len, as the dev->mtu is already decreased */        
 #endif
 
        if (skb_headroom(skb) < dev->hard_header_len && dev->hard_header) {
@@ -458,7 +475,9 @@ int ip_build_xmit(struct sock *sk,
        struct ip_options *opt = ipc->opt;
        struct device *dev = rt->u.dst.dev;
        int df = htons(IP_DF);
-       
+#ifdef CONFIG_NET_SECURITY
+       int fw_res;
+#endif 
 
        if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
            (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
@@ -517,9 +536,17 @@ int ip_build_xmit(struct sock *sk,
                if (err)
                        err = -EFAULT;
 
-#ifdef CONFIG_FIREWALL
-               if(!err && call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT)
+               if(!err && call_out_firewall(PF_INET, skb->dev, iph, NULL, &skb) < FW_ACCEPT)
                        err = -EPERM;
+#ifdef CONFIG_NET_SECURITY
+               if ((fw_res=call_out_firewall(PF_SECURITY, NULL, NULL, (void *) 5, &skb))<FW_ACCEPT)
+               {
+                       kfree_skb(skb, FREE_WRITE);
+                       if (fw_res != FW_QUEUE)
+                               return -EPERM;
+                       else
+                               return 0;
+               }
 #endif
 
                if (err)
@@ -679,9 +706,14 @@ int ip_build_xmit(struct sock *sk,
                 *      Account for the fragment.
                 */
                 
-#ifdef CONFIG_FIREWALL
-               if(!err && !offset && call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT)
+               if(!err && !offset && call_out_firewall(PF_INET, skb->dev, iph, NULL, &skb) < FW_ACCEPT)
                        err = -EPERM;
+#ifdef CONFIG_NET_SECURITY
+               if ((fw_res=call_out_firewall(PF_SECURITY, NULL, NULL, (void *) 6, &skb))<FW_ACCEPT)
+               {
+                       if (fw_res != FW_QUEUE)
+                               err= -EPERM;
+               }
 #endif         
                if (err)
                {
index 7672b20b68ce6978d4cf3b3db4fdf4c7613435cb..75346d6dc3704369855ea9f56f3a5f16e9009417 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/in.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
-#include <linux/firewall.h>
 #include <linux/if_arp.h>
 #include <linux/mroute.h>
 
index 9bf813ee00d16d329b67b1bd63801077a4b1be1c..18553a03d49b08cd36a9f5a05e628ffebc462561 100644 (file)
@@ -79,7 +79,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
  *     a memory timer destroy. Instead of playing with timers we just
  *     concede defeat and cli().
  */
-       start_bh_atomic();
+       SOCKHASH_LOCK();
        sp = pro->sklist_next;
        while(sp != (struct sock *)pro) {
                pos += 128;
@@ -128,7 +128,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
                sp = sp->sklist_next;
                i++;
        }
-       end_bh_atomic();
+       SOCKHASH_UNLOCK();
 
        begin = len - (pos - offset);
        *start = buffer + begin;
@@ -138,25 +138,21 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
        return len;
 } 
 
-
 int tcp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
        return get__netinfo(&tcp_prot, buffer,0, start, offset, length);
 }
 
-
 int udp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
        return get__netinfo(&udp_prot, buffer,1, start, offset, length);
 }
 
-
 int raw_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
        return get__netinfo(&raw_prot, buffer,1, start, offset, length);
 }
 
-
 /*
  *     Report socket allocation statistics [mea@utu.fi]
  */
index ca781d6b9ce0efca70fff9b3c99467c6606ff031..4463449c377be09494e1d3aed7e8b07ea2812dda 100644 (file)
@@ -151,7 +151,7 @@ void raw_err (struct sock *sk, struct sk_buff *skb)
        int type = skb->h.icmph->type;
        int code = skb->h.icmph->code;
 
-       if (sk->ip_recverr && !sk->users) {
+       if (sk->ip_recverr && !sk->sock_readers) {
                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                if (skb2 && sock_queue_err_skb(sk, skb2))
                        kfree_skb(skb, FREE_READ);
@@ -193,7 +193,7 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb)
        
        skb->h.raw = skb->nh.raw;
 
-       if (sk->users) {
+       if (sk->sock_readers) {
                __skb_queue_tail(&sk->back_log, skb);
                return 0;
        }
index a39d256f406708d16029b99ea7d59ac23efddf1a..87793d0e1ac4c4c018a600fe58af99e2b7039625 100644 (file)
@@ -93,8 +93,9 @@ static struct timer_list rt_flush_timer =
  */
 
 static void ipv4_dst_destroy(struct dst_entry * dst);
-static struct dst_entry * ipv4_dst_check(struct dst_entry * dst);
-static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst);
+static struct dst_entry * ipv4_dst_check(struct dst_entry * dst, u32);
+static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst,
+                                          struct sk_buff *);
 
 
 struct dst_ops ipv4_dst_ops =
@@ -212,7 +213,7 @@ void ip_rt_check_expire()
                         * Cleanup aged off entries.
                         */
 
-                       if (!rth->u.dst.refcnt && now - rth->u.dst.lastuse > RT_CACHE_TIMEOUT) {
+                       if (!rth->u.dst.use && now - rth->u.dst.lastuse > RT_CACHE_TIMEOUT) {
                                *rthp = rth_next;
                                atomic_dec(&rt_cache_size);
 #if RT_CACHE_DEBUG >= 2
@@ -337,7 +338,7 @@ static void rt_garbage_collect(void)
                if (!rt_hash_table[i])
                        continue;
                for (rthp=&rt_hash_table[i]; (rth=*rthp); rthp=&rth->u.rt_next) {
-                       if (rth->u.dst.refcnt || now - rth->u.dst.lastuse > expire)
+                       if (rth->u.dst.use || now - rth->u.dst.lastuse > expire)
                                continue;
                        atomic_dec(&rt_cache_size);
                        *rthp = rth->u.rt_next;
@@ -357,7 +358,7 @@ static void rt_garbage_collect(void)
 
 static int rt_ll_bind(struct rtable *rt)
 {
-       struct dst_entry *neigh;
+       struct neighbour *neigh;
        struct hh_cache *hh = NULL;
 
        if (rt->u.dst.dev && rt->u.dst.dev->hard_header_cache) {
@@ -754,12 +755,13 @@ static void ipv4_dst_destroy(struct dst_entry * dst)
        }
 }
 
-static struct dst_entry * ipv4_dst_check(struct dst_entry * dst)
+static struct dst_entry * ipv4_dst_check(struct dst_entry * dst, u32 cookie)
 {
        return NULL;
 }
 
-static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst)
+static struct dst_entry * ipv4_dst_reroute(struct dst_entry * dst,
+                                          struct sk_buff *skb)
 {
        return NULL;
 }
index 5b263ab67f05420377c0d758cc846be7cdb532f7..954956d86f4860a2436cd55dd51ffb9cd915cbba 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    @(#)tcp.c       1.0.16  05/25/93
+ * Version:    $Id: tcp.c,v 1.50 1997/03/16 03:25:59 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *                                     improvement.
  *     Stefan Magdalinski      :       adjusted tcp_readable() to fix FIONREAD
  *     Willy Konynenberg       :       Transparent proxying support.
+ *             Keith Owens     :       Do proper meging with partial SKB's in
+ *                                     tcp_do_sendmsg to avoid burstiness.
  *                                     
  * To Fix:
  *             Fast path the code. Two things here - fix the window calculation
@@ -525,6 +527,7 @@ static int tcp_readable(struct sock *sk)
        unsigned long flags;
 
        SOCK_DEBUG(sk, "tcp_readable: %p - ",sk);
+
        save_flags(flags);
        cli();
        if (sk == NULL || (skb = skb_peek(&sk->receive_queue)) == NULL)
@@ -772,11 +775,11 @@ static int tcp_append_tail(struct sock *sk, struct sk_buff *skb, u8 *from,
 
        copy = min(sk->mss - tcp_size, skb_tailroom(skb));
        copy = min(copy, seglen);
-       
+
        tcp_size += copy;
-       
+
        fault = copy_from_user(skb->tail, from, copy);
-       
+
        if (fault)
        {
                return -1;
@@ -796,8 +799,7 @@ static int tcp_append_tail(struct sock *sk, struct sk_buff *skb, u8 *from,
  *     and starts the transmit system.
  */
 
-int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
-                  int len, int flags)
+int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
 {
        int err = 0;
        int copied  = 0;
@@ -808,16 +810,14 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
         */
        while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
        {
-               
                if (copied)
                        return copied;
-               
-               if (sk->err) 
+
+               if (sk->err)
                        return sock_error(sk);
-               
+
                if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
                {
-                       printk("tcp_do_sendmsg1: EPIPE dude...\n");
                        if (sk->keepopen)
                                send_sig(SIGPIPE, current, 0);
                        return -EPIPE;
@@ -831,22 +831,21 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                
                wait_for_tcp_connect(sk);
        }
-       
-       
+
        /*
         *      Ok commence sending
         */
-       
+
        while(--iovlen >= 0)
        {
                int seglen=iov->iov_len;
                unsigned char * from=iov->iov_base;
-               u32 actual_win;
 
                iov++;
 
-               while(seglen > 0) 
+               while(seglen > 0)
                {
+                       unsigned int actual_win;
                        int copy;
                        int tmp;
                        struct sk_buff *skb;
@@ -870,7 +869,6 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                        {
                                if (copied)
                                        return copied;
-                               printk("tcp_do_sendmsg2: SEND_SHUTDOWN, EPIPE...\n");
                                send_sig(SIGPIPE,current,0);
                                return -EPIPE;
                        }
@@ -885,11 +883,11 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                                int tcp_size;
 
                                /* Tail */
-                               
+
                                skb = sk->write_queue.prev;
-                               tcp_size = skb->tail - 
+                               tcp_size = skb->tail -
                                        (unsigned char *)(skb->h.th + 1);
-                                       
+
                                /*
                                 * This window_seq test is somewhat dangerous
                                 * If the remote does SWS avoidance we should
@@ -901,7 +899,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
 
                                if (skb->end > skb->tail &&
                                    sk->mss - tcp_size > 0 &&
-                                   skb->end_seq < tp->snd_una + tp->snd_wnd
+                                   tp->snd_nxt < skb->end_seq
                                {
                                        int tcopy;
                                        
@@ -912,12 +910,11 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                                        {
                                                return -EFAULT;
                                        }
-                                       
+
                                        from += tcopy;
                                        copied += tcopy;
-                                       len -= tcopy;
                                        seglen -= tcopy;
-                                       
+
                                        /*
                                         *      FIXME: if we're nagling we
                                         *      should send here.
@@ -944,7 +941,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                        actual_win = tp->snd_wnd - (tp->snd_nxt - tp->snd_una);
 
                        if (copy > actual_win &&
-                           (((long) actual_win) >= (sk->max_window >> 1))
+                           (((int) actual_win) >= (sk->max_window >> 1))
                            && actual_win)
                        {
                                copy = actual_win;
@@ -974,12 +971,12 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
                        }
 
                        skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
-       
+
                        /*
-                        *      If we didn't get any memory, we need to sleep. 
+                        *      If we didn't get any memory, we need to sleep.
                         */
-       
-                       if (skb == NULL) 
+
+                       if (skb == NULL)
                        {
                                sk->socket->flags |= SO_NOSPACE;
                                if (flags&MSG_DONTWAIT)
@@ -1037,13 +1034,16 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov,
 
                        skb->csum = csum_partial_copy_from_user(from,
                                        skb_put(skb, copy), copy, 0, &err);
-               
+
                        from += copy;
                        copied += copy;
-                       len -= copy;
+
                        sk->write_seq += copy;
                
                        tcp_send_skb(sk, skb);
+
+                       release_sock(sk);
+                       lock_sock(sk);
                }
        }
 
@@ -1181,14 +1181,14 @@ static void cleanup_rbuf(struct sock *sk)
                        break;
                tcp_eat_skb(sk, skb);
        }
-       
+
        SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
-       
+
        /*
-        *  We send a ACK if the sender is blocked
-        *  else let tcp_data deal with the acking policy.
+        *      We send a ACK if the sender is blocked
+        *      else let tcp_data deal with the acking policy.
         */
-  
+
        if (sk->delayed_acks)
        {
                struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
@@ -1464,7 +1464,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                                               msg->msg_name);       
        }
        if(addr_len)
-               *addr_len= tp->af_specific->sockaddr_len;
+               *addr_len = tp->af_specific->sockaddr_len;
 
        remove_wait_queue(sk->sleep, &wait);
        current->state = TASK_RUNNING;
index b868605cd33fca1528378bcb9b91bf1dc34bdf04..82d8724cead7e5a7c8a5487bf074220fc5746faa 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    @(#)tcp_input.c 1.0.16  05/25/93
+ * Version:    $Id: tcp_input.c,v 1.39 1997/03/17 04:49:35 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Eric Schenk     :       Yet another double ACK bug.
  *             Eric Schenk     :       Delayed ACK bug fixes.
  *             Eric Schenk     :       Floyd style fast retrans war avoidance.
+ *             David S. Miller :       Don't allow zero congestion window.
  */
 
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <net/tcp.h>
-
-
+#include <linux/ipsec.h>
 
 typedef void                   (*tcp_sys_cong_ctl_t)(struct sock *sk,
                                                      u32 seq, u32 ack,
@@ -159,34 +159,37 @@ extern __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
 
        tp->backoff = 0;
 }
+
+static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
+{
+       u32 end_window;
+
+       end_window = tp->rcv_wup + tp->rcv_wnd;
+
+       if (tp->rcv_wnd)
+       {
+               if (!before(seq, tp->rcv_nxt) && before(seq, end_window))
+                       return 1;
+
+               if ((end_seq - seq) && after(end_seq, tp->rcv_nxt) &&
+                   !after(end_seq, end_window))
+                       return 1;
+       }
+
+       return 0;
+}
 
 /*
  *     This functions checks to see if the tcp header is actually acceptable. 
  */
  
-extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 seg_nxt)
+extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
 {
-       u32 end_window = tp->rcv_wup + tp->rcv_wnd;
-       u32 end_seq = seg_nxt;
-
-       /*
-        *      When the window is open (most common case)
-        *      we want to accept segments if they have yet unseen data
-        *      or in the case of a dataless segment if seg.seq == rcv.nxt
-        *      this means:
-        *
-        *      if (seq == end_seq)
-        *              end_seq >= rcv.nxt
-        *      else
-        *              end_seq >  rcv.nxt
-        */
-
-       if (seq == end_seq)
-               end_seq++;
-
-       return ((before(seq, end_window) && after(end_seq, tp->rcv_nxt)) ||
-               (seq == end_window && seq == end_seq));
+       if (seq == tp->rcv_nxt)
+       {
+               return (tp->rcv_wnd || (end_seq == seq));
+       }
+       return __tcp_sequence(tp, seq, end_seq);
 }
 
 /*
@@ -253,9 +256,9 @@ int tcp_parse_options(struct tcphdr *th)
        unsigned char *ptr;
        int length=(th->doff*4)-sizeof(struct tcphdr);
        int mss = 0;
-    
+
        ptr = (unsigned char *)(th + 1);
-  
+
        while(length>0)
        {
                int opcode=*ptr++;
@@ -295,7 +298,7 @@ int tcp_parse_options(struct tcphdr *th)
  *  See draft-stevens-tcpca-spec-01 for documentation.
  */
 
-static void tcp_fast_retrans(struct sock *sk, u32 seq, u32 ack, int not_dup)
+static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
 {
        struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 
@@ -318,7 +321,7 @@ static void tcp_fast_retrans(struct sock *sk, u32 seq, u32 ack, int not_dup)
                 * than two segments. Retransmit the missing segment.
                 */
 
-               if (tp->high_seq == 0 || after(seq, tp->high_seq))
+               if (tp->high_seq == 0 || after(ack, tp->high_seq))
                {
                        sk->dup_acks++;
 
@@ -354,7 +357,7 @@ static void tcp_fast_retrans(struct sock *sk, u32 seq, u32 ack, int not_dup)
                if (sk->dup_acks >= 3)
                {
                        tp->retrans_head = NULL;
-                       sk->cong_window = sk->ssthresh;
+                       sk->cong_window = max(sk->ssthresh, 1);
                        sk->retransmits = 0;
                }
                sk->dup_acks = 0;
@@ -374,28 +377,27 @@ static void tcp_fast_retrans(struct sock *sk, u32 seq, u32 ack, int not_dup)
 static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
                                 u32 seq_rtt)
 {
+       struct tcp_opt * tp;
+       unsigned int actual, expected;
+       unsigned int inv_rtt, inv_basertt, inv_basebd;
+       u32 snt_bytes;
+
        /*
         *      From:
         *      TCP Vegas: New Techniques for Congestion 
         *      Detection and Avoidance.
-        *              
+        *
         *
         *      Warning: This code is a scratch implementation taken
         *      from the paper only. The code they distribute seams
         *      to have improved several things over the initial spec.
         */
 
-       struct tcp_opt * tp;
-       unsigned int Actual, Expected;
-       unsigned int inv_rtt, inv_basertt; 
-       u32 snt_bytes;
-       
-
        tp = &(sk->tp_pinfo.af_tcp);
 
        if (!seq_rtt)
                seq_rtt = 1;
-       
+
        if (tp->basertt)
                tp->basertt = min(seq_rtt, tp->basertt);
        else
@@ -403,18 +405,21 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
 
        /*
         * 
-        *      Actual   = throughput for this segment.
-        *      Expected = number_of_bytes in transit / BaseRTT
+        *      actual   = throughput for this segment.
+        *      expected = number_of_bytes in transit / BaseRTT
         * 
         */
 
-       snt_bytes = (ack - seq) << SHIFT_FACTOR;
-       inv_rtt = (1 << SHIFT_FACTOR) / seq_rtt;
-       
-       Actual =  snt_bytes * inv_rtt;
+       snt_bytes = ack - seq;
 
+       inv_rtt = (1 << SHIFT_FACTOR) / seq_rtt;
        inv_basertt = (1 << SHIFT_FACTOR) / tp->basertt;
-       Expected = ((tp->snd_nxt - tp->snd_una) << SHIFT_FACTOR) * inv_basertt;
+
+       actual =  snt_bytes * inv_rtt;
+
+       expected = (tp->snd_nxt - tp->snd_una) * inv_basertt;
+
+       inv_basebd = sk->mss * inv_basertt;
 
        /*
         *      Slow Start
@@ -422,17 +427,14 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
        
        if (sk->cong_window < sk->ssthresh &&
            (seq == tp->snd_nxt ||
-             (((Expected - Actual) <=
-               ((TCP_VEGAS_GAMMA << SHIFT_FACTOR) * sk->mss * inv_basertt))
-              )
-            ))
+            (expected - actual <= TCP_VEGAS_GAMMA * inv_basebd)))
        {
                /*
                 * "Vegas allows exponential growth only every other
                 *  RTT"
                 */
                        
-               if (!(sk->cong_count++))
+               if (sk->cong_count++)
                {
                        sk->cong_window++;
                        sk->cong_count = 0;
@@ -443,9 +445,8 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
                /*
                 *      Congestion Avoidance
                 */
-                       
-               if (Expected - Actual <=
-                   ((TCP_VEGAS_ALPHA << SHIFT_FACTOR) * sk->mss * inv_basertt))
+
+               if (expected - actual <= TCP_VEGAS_ALPHA * inv_basebd)
                {
                        /* Increase Linearly */
                                
@@ -455,18 +456,17 @@ static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
                                sk->cong_count = 0;
                        }
                }
-                       
-               if (Expected - Actual >=
-                   ((TCP_VEGAS_BETA << SHIFT_FACTOR) * sk->mss * inv_basertt))
+
+               if (expected - actual >= TCP_VEGAS_BETA * inv_basebd)
                {
                        /* Decrease Linearly */
-                               
+
                        if (sk->cong_count++ >= sk->cong_window)
                        {
                                sk->cong_window--;
                                sk->cong_count = 0;
                        }
-                       
+
                        /* Never less than 2 segments */
                        if (sk->cong_window < 2)
                                sk->cong_window = 2;
@@ -523,7 +523,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq,
        struct sk_buff *skb;
        unsigned long now = jiffies;
        int acked = 0;
-       
+
        while((skb=skb_peek(&sk->write_queue)) && (skb != tp->send_head))
        {
 
@@ -545,16 +545,18 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq,
                 
                if (after(skb->end_seq, ack))
                        break;
-               
-               SOCK_DEBUG(sk, "removing seg %x-%x from retransmit queue\n", skb->seq, skb->end_seq);
+
+               SOCK_DEBUG(sk, "removing seg %x-%x from retransmit queue\n",
+                          skb->seq, skb->end_seq);
+
                acked = FLAG_DATA_ACKED;
                
                atomic_dec(&sk->packets_out);
 
                *seq = skb->seq;
                *seq_rtt = now - skb->when;
-                               
-               skb_unlink(skb);                
+
+               skb_unlink(skb);
                
                kfree_skb(skb, FREE_WRITE);
        }
@@ -565,7 +567,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __u32 ack, __u32 *seq,
                if (!sk->dead)
                        sk->write_space(sk);
        }
-       
+
        return acked;
 }
 
@@ -616,7 +618,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
        if(sk->zapped)
                return(1);      /* Dead, can't ack any more so why bother */
 
-       if (tp->pending == TIME_KEEPOPEN) 
+       if (tp->pending == TIME_KEEPOPEN)
        {
                tp->probes_out = 0;
        }
@@ -754,19 +756,22 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th,
        }
        else
                tcp_clear_xmit_timer(sk, TIME_RETRANS);
-       
-       tcp_fast_retrans(sk, ack_seq, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE)));
+
+
+       tcp_fast_retrans(sk, ack, (flag & (FLAG_DATA|FLAG_WIN_UPDATE)));
 
        /*
         *      Remember the highest ack received.
         */
-        
+
        tp->snd_una = ack;
+
        return 1;
 
 uninteresting_ack:
 
-       SOCK_DEBUG(sk, "Ack ignored %u %u\n",ack,tp->snd_nxt);
+       SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
+
        return 0;
 }
 
@@ -888,10 +893,11 @@ static void  tcp_ofo_queue(struct sock *sk)
                        SOCK_DEBUG(sk, "ofo packet was allready received \n");
                        skb_unlink(skb);
                        kfree_skb(skb, FREE_READ);
-                       
+
                        continue;
                }
-               SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
+               SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n",
+                          tp->rcv_nxt, skb->seq, skb->end_seq);
 
                skb_unlink(skb);
                 
@@ -946,6 +952,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                 * force an imediate ack
                 */
                SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq);
+
                sk->delayed_acks = MAX_DELAY_ACK;
                kfree_skb(skb, FREE_READ);
 
@@ -959,7 +966,9 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                 * Partial packet
                 * seq < rcv_next < end_seq
                 */
-               SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
+               SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n",
+                          tp->rcv_nxt, skb->seq, skb->end_seq);
+
                skb_queue_tail(&sk->receive_queue, skb);
 
                tp->rcv_nxt = skb->end_seq;
@@ -986,7 +995,8 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 
        tp->pred_flags = 0;
 
-       SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", tp->rcv_nxt, skb->seq, skb->end_seq);
+       SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n",
+                  tp->rcv_nxt, skb->seq, skb->end_seq);
 
        if (skb_peek(&sk->out_of_order_queue) == NULL) {
                skb_queue_head(&sk->out_of_order_queue,skb);
@@ -1064,16 +1074,16 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
        }
 
        sk->delayed_acks++;
-       
+
        /*
         *      Now tell the user we may have some data. 
         */
-        
-       if (!sk->dead) 
+
+       if (!sk->dead)
        {
                SOCK_DEBUG(sk, "Data wakeup.\n");
                sk->data_ready(sk,0);
-       } 
+       }
        return(1);
 }
 
@@ -1314,10 +1324,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                {
                        if (after(skb->seq, tp->rcv_nxt))
                        {
-                               printk(KERN_DEBUG "->seq:%d end:%d "
-                                      "wup:%d wnd:%d\n",
-                                      skb->seq, skb->end_seq, 
-                                      tp->rcv_wup, tp->rcv_wnd);
+                               SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
+                                          skb->seq, skb->end_seq,
+                                          tp->rcv_wup, tp->rcv_wnd);
                        }
                        tcp_send_ack(sk);
                        kfree_skb(skb, FREE_READ);
@@ -1327,6 +1336,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 
        if(th->syn && skb->seq != sk->syn_seq)
        {
+               printk(KERN_DEBUG "syn in established state\n");
                tcp_reset(sk, skb);
                kfree_skb(skb, FREE_READ);
                return 1;
@@ -1586,7 +1596,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
                        sk = tp->af_specific->get_sock(skb, th);
 
-                       if (sk == NULL)
+                       if (sk == NULL || !ipsec_sk_policy(sk,skb))
                                goto discard;
 
                        skb_set_owner_r(skb, sk);
index b30b17dbcdbb106698af22193e53f1ffc307f02e..d9e1b2010a2e1ca943927b3587fbc14949f0b536 100644 (file)
@@ -5,6 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
+ * Version:    $Id: tcp_ipv4.c,v 1.23 1997/03/17 04:49:38 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -32,6 +33,7 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/random.h>
+#include <linux/ipsec.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -84,7 +86,7 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
 
        SOCKHASH_LOCK();
        sk2 = tcp_bound_hash[tcp_bhashfn(snum)];
-       for(; sk2 != NULL; sk2 = sk2->prev) {
+       for(; sk2 != NULL; sk2 = sk2->bind_next) {
                if((sk2->num == snum) && (sk2 != sk)) {
                        unsigned char state = sk2->state;
                        int sk2_reuse = sk2->reuse;
@@ -92,7 +94,7 @@ static int tcp_v4_verify_bind(struct sock *sk, unsigned short snum)
                        if(!sk2->rcv_saddr || !sk->rcv_saddr) {
                                if((!sk2_reuse)                 ||
                                   (!sk_reuse)                  ||
-                                  (state != TCP_LISTEN)) {
+                                  (state == TCP_LISTEN)) {
                                        retval = 1;
                                        break;
                                }
@@ -115,7 +117,7 @@ static __inline__ int tcp_lport_inuse(int num)
 {
        struct sock *sk = tcp_bound_hash[tcp_bhashfn(num)];
 
-       for(; sk != NULL; sk = sk->prev) {
+       for(; sk != NULL; sk = sk->bind_next) {
                if(sk->num == num)
                        return 1;
        }
@@ -156,7 +158,7 @@ unsigned short tcp_good_socknum(void)
                        goto done;
                } else {
                        int j = 0;
-                       do { sk = sk->prev; } while(++j < size && sk);
+                       do { sk = sk->bind_next; } while(++j < size && sk);
                        if(j < size) {
                                best = (start + i);
                                size = j;
@@ -196,18 +198,17 @@ static void tcp_v4_hash(struct sock *sk)
        SOCKHASH_LOCK();
        state = sk->state;
        if(state != TCP_CLOSE || !sk->dead) {
-               struct sock **htable;
+               struct sock **skp;
 
-               if(state == TCP_LISTEN) {
-                       sk->hashent = tcp_sk_listen_hashfn(sk);
-                       htable = &tcp_listening_hash[0];
-               } else {
-                       sk->hashent = tcp_sk_hashfn(sk);
-                       htable = &tcp_established_hash[0];
-               }
-               sk->next = htable[sk->hashent];
-               htable[sk->hashent] = sk;
-               sk->hashtable = htable;
+               if(state == TCP_LISTEN)
+                       skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+               else
+                       skp = &tcp_established_hash[tcp_sk_hashfn(sk)];
+
+               if((sk->next = *skp) != NULL)
+                       (*skp)->pprev = &sk->next;
+               *skp = sk;
+               sk->pprev = skp;
                tcp_sk_bindify(sk);
        }
        SOCKHASH_UNLOCK();
@@ -215,57 +216,44 @@ static void tcp_v4_hash(struct sock *sk)
 
 static void tcp_v4_unhash(struct sock *sk)
 {
-       struct sock **htable;
-
        SOCKHASH_LOCK();
-       htable = sk->hashtable;
-       if(htable) {
-               struct sock **skp = &(htable[sk->hashent]);
-               while(*skp != NULL) {
-                       if(*skp == sk) {
-                               *skp = sk->next;
-                               break;
-                       }
-                       skp = &((*skp)->next);
-               }
-               sk->hashtable = NULL;
+       if(sk->pprev) {
+               if(sk->next)
+                       sk->next->pprev = sk->pprev;
+               *sk->pprev = sk->next;
+               sk->pprev = NULL;
+               tcp_sk_unbindify(sk);
        }
-       tcp_sk_unbindify(sk);
        SOCKHASH_UNLOCK();
 }
 
 static void tcp_v4_rehash(struct sock *sk)
 {
-       struct sock **htable;
        unsigned char state;
 
        SOCKHASH_LOCK();
-       htable = &(sk->hashtable[sk->hashent]);
        state = sk->state;
-       if(htable) {
-               while(*htable != NULL) {
-                       if(*htable == sk) {
-                               *htable = sk->next;
-                               break;
-                       }
-                       htable = &((*htable)->next);
-               }
+       if(sk->pprev) {
+               if(sk->next)
+                       sk->next->pprev = sk->pprev;
+               *sk->pprev = sk->next;
+               sk->pprev = NULL;
                tcp_sk_unbindify(sk);
        }
-       htable = NULL;
        if(state != TCP_CLOSE || !sk->dead) {
-               if(state == TCP_LISTEN) {
-                       sk->hashent = tcp_sk_listen_hashfn(sk);
-                       htable = &tcp_listening_hash[0];
-               } else {
-                       sk->hashent = tcp_sk_hashfn(sk);
-                       htable = &tcp_established_hash[0];
-               }
-               sk->next = htable[sk->hashent];
-               htable[sk->hashent] = sk;
+               struct sock **skp;
+
+               if(state == TCP_LISTEN)
+                       skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+               else
+                       skp = &tcp_established_hash[tcp_sk_hashfn(sk)];
+
+               if((sk->next = *skp) != NULL)
+                       (*skp)->pprev = &sk->next;
+               *skp = sk;
+               sk->pprev = skp;
                tcp_sk_bindify(sk);
        }
-       sk->hashtable = htable;
        SOCKHASH_UNLOCK();
 }
 
@@ -343,7 +331,7 @@ __inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport
        secondlist((hpnum), tcp_bound_hash[tcp_bhashfn(hnum)],(fpass))
 
 #define tcp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \
-       secondlist((hpnum),(sk)->next,(fpass))
+       secondlist((hpnum),(sk)->bind_next,(fpass))
 
 struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
                                 unsigned short rnum, unsigned long laddr,
@@ -457,11 +445,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        /*
         *      Don't allow a double connect.
         */
-               
+
        if (sk->daddr)
                return -EINVAL;
-       
-       if (addr_len < sizeof(struct sockaddr_in)) 
+
+       if (addr_len < sizeof(struct sockaddr_in))
                return(-EINVAL);
 
        if (usin->sin_family != AF_INET) {
@@ -476,7 +464,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                dst_release(sk->dst_cache);
                sk->dst_cache = NULL;
        }
-                 
+
        tmp = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr,
                               RT_TOS(sk->ip_tos)|(sk->localroute || 0));
        if (tmp < 0)
@@ -517,7 +505,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        sk->err = 0;
        
        buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL);
-       if (buff == NULL) 
+       if (buff == NULL)
        {
                release_sock(sk);
                return(-ENOBUFS);
@@ -526,10 +514,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        /*
         *      Put in the IP header and routing stuff.
         */
-       
+
        tmp = ip_build_header(buff, sk);
 
-       if (tmp < 0) 
+       if (tmp < 0)
        {
                kfree_skb(buff, FREE_WRITE);
                release_sock(sk);
@@ -566,7 +554,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (sk->user_mss)
                sk->mss = sk->user_mss;
        else
-               sk->mss = (sk->mtu - sizeof(struct iphdr) - 
+               sk->mss = (sk->mtu - sizeof(struct iphdr) -
                           sizeof(struct tcphdr));
 
        /*
@@ -591,7 +579,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        tp->rto = rt->u.dst.rtt;
 
        tcp_init_xmit_timers(sk);
-       
+
        /* Now works the right way instead of a hacked initial setting */
        sk->retransmits = 0;
 
@@ -601,7 +589,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        buff->when = jiffies;
 
        skb1 = skb_clone(buff, GFP_KERNEL);
-       ip_queue_xmit(skb1);  
+       ip_queue_xmit(skb1);
 
        /* Timer for repeating the SYN until an answer  */
        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
@@ -641,7 +629,7 @@ static int tcp_v4_sendmsg(struct sock *sk, struct msghdr *msg, int len)
 
        lock_sock(sk);
        retval = tcp_do_sendmsg(sk, msg->msg_iovlen, msg->msg_iov,
-                               len, msg->msg_flags);
+                               msg->msg_flags);
 
        release_sock(sk);
 
@@ -741,7 +729,7 @@ void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
  *             arrived with segment.
  *     Exception: precedence violation. We do not implement it in any case.
  */
+
 static void tcp_v4_send_reset(struct sk_buff *skb)
 {
        struct tcphdr  *th = skb->h.th;
@@ -750,7 +738,7 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
 
        if (th->rst)
                return;
-  
+
        skb1 = ip_reply(skb, sizeof(struct tcphdr));
        if (skb1 == NULL)
                return;
@@ -759,14 +747,14 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
        memset(th1, 0, sizeof(*th1));
 
        /*
-        *      Swap the send and the receive. 
+        *      Swap the send and the receive.
         */
+
        th1->dest = th->source;
        th1->source = th->dest;
        th1->doff = sizeof(*th1)/4;
        th1->rst = 1;
-   
+
        if (th->ack)
                th1->seq = th->ack_seq;
        else {
@@ -776,7 +764,7 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
                else
                        th1->ack_seq = htonl(ntohl(th->seq)+1);
        }
+
        skb1->csum = csum_partial((u8 *) th1, sizeof(*th1), 0);
        th1->check = tcp_v4_check(th1, sizeof(*th1), skb1->nh.iph->saddr,
                                  skb1->nh.iph->daddr, skb1->csum);
@@ -821,7 +809,7 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
        int tmp;
 
        skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
-       
+
        if (skb == NULL)
        {
                return;
@@ -839,27 +827,27 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
        mss = skb->dst->pmtu;
 
        mss -= sizeof(struct iphdr) + sizeof(struct tcphdr);
-       
+
        if (sk->user_mss)
                mss = min(mss, sk->user_mss);
-       
+
        th =(struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
        skb->h.th = th;
        memset(th, 0, sizeof(struct tcphdr));
-       
+
        th->syn = 1;
        th->ack = 1;
 
        th->source = sk->dummy_th.source;
        th->dest = req->rmt_port;
-              
+
        skb->seq = req->snt_isn;
        skb->end_seq = skb->seq + 1;
 
        th->seq = ntohl(skb->seq);
        th->ack_seq = htonl(req->rcv_isn + 1);
        th->doff = sizeof(*th)/4 + 1;
-       
+
        th->window = ntohs(tp->rcv_wnd);
 
        ptr = skb_put(skb, TCPOLEN_MSS);
@@ -870,14 +858,12 @@ static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
        skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
 
        th->check = tcp_v4_check(th, sizeof(*th) + TCPOLEN_MSS,
-                                af_req->loc_addr, 
+                                af_req->loc_addr,
                                 af_req->rmt_addr,
                                 csum_partial((char *)th, sizeof(*th), skb->csum));
 
        ip_queue_xmit(skb);
        tcp_statistics.TcpOutSegs++;
-                                             
-
 }
 
 static void tcp_v4_or_free(struct open_request *req)
@@ -886,7 +872,7 @@ static void tcp_v4_or_free(struct open_request *req)
 
        if (af_req->req.sk)
                return;
-       
+
        if (af_req->opt)
                kfree_s(af_req->opt, sizeof(struct options) + af_req->opt->optlen);
 }
@@ -915,14 +901,14 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
        {
                SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);
                tcp_statistics.TcpAttemptFails++;
-               return -ENOTCONN;               
+               return -ENOTCONN;
        }
 
-       if (sk->ack_backlog >= sk->max_ack_backlog || 
+       if (sk->ack_backlog >= sk->max_ack_backlog ||
            tcp_v4_syn_filter(sk, skb, saddr))
        {
-               printk(KERN_DEBUG "dropping syn ack:%d max:%d\n",
-                      sk->ack_backlog, sk->max_ack_backlog);
+               SOCK_DEBUG(sk, "dropping syn ack:%d max:%d\n", sk->ack_backlog,
+                          sk->max_ack_backlog);
 #ifdef CONFIG_IP_TCPSF
                tcp_v4_random_drop(sk);
 #endif
@@ -930,7 +916,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
                goto exit;
        }
 
-
        af_req = kmalloc(sizeof(struct tcp_v4_open_req), GFP_ATOMIC);
 
        if (af_req == NULL)
@@ -959,7 +944,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
 
        af_req->loc_addr = daddr;
        af_req->rmt_addr = saddr;
-       
+
        /*
         *      options
         */
@@ -968,11 +953,11 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
        {
                af_req->opt = (struct ip_options*) kmalloc(sizeof(struct ip_options) +
                                                           opt->optlen, GFP_ATOMIC);
-               if (af_req->opt) 
+               if (af_req->opt)
                {
                        if (ip_options_echo(af_req->opt, skb))
                        {
-                               kfree_s(af_req->opt, sizeof(struct options) + 
+                               kfree_s(af_req->opt, sizeof(struct options) +
                                        opt->optlen);
                                af_req->opt = NULL;
                        }
@@ -982,7 +967,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr, __u32 i
        req->class = &or_ipv4;
 
        tcp_v4_send_synack(sk, req);
-       
+
        req->expires = jiffies + TCP_TIMEOUT_INIT;
        tcp_inc_slow_timer(TCP_SLT_SYNACK);
        tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
@@ -1019,13 +1004,12 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        skb_queue_head_init(&newsk->receive_queue);
        skb_queue_head_init(&newsk->out_of_order_queue);
        skb_queue_head_init(&newsk->error_queue);
-       
+
        /*
         *      Unused
         */
 
        newsk->send_head = NULL;
-       newsk->send_tail = NULL;
 
        newtp = &(newsk->tp_pinfo.af_tcp);
        newtp->send_head = NULL;
@@ -1040,7 +1024,6 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newsk->cong_count = 0;
        newsk->ssthresh = 0;
        newtp->backoff = 0;
-       newsk->blog = 0;
        newsk->intr = 0;
        newsk->proc = 0;
        newsk->done = 0;
@@ -1084,8 +1067,8 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        newsk->dummy_th.source = sk->dummy_th.source;
        newsk->dummy_th.dest = req->rmt_port;
-       newsk->users=0;
-       
+       newsk->sock_readers=0;
+
        newtp->rcv_nxt = req->rcv_isn + 1;
        newtp->rcv_wup = req->rcv_isn + 1;
        newsk->copied_seq = req->rcv_isn + 1;
@@ -1095,7 +1078,7 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newsk->daddr = af_req->rmt_addr;
        newsk->saddr = af_req->loc_addr;
        newsk->rcv_saddr = af_req->loc_addr;
-       
+
        /*
         *      options / mss / route_cache
         */
@@ -1109,10 +1092,10 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 
        newsk->dst_cache = &rt->u.dst;
-       
+
        newsk->window_clamp = rt->u.dst.window;
        snd_mss = rt->u.dst.pmtu;
-       
+
        newsk->mtu = snd_mss;
        /* sanity check */
        if (newsk->mtu < 64)
@@ -1126,9 +1109,9 @@ struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        {
                snd_mss = min(snd_mss, sk->user_mss);
        }
-       
+
        newsk->mss = min(req->mss, snd_mss);
-       
+
        tcp_v4_hash(newsk);
        add_to_prot_sklist(newsk);
        return newsk;
@@ -1139,21 +1122,19 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        struct open_request *req;
 
-
        /*
         *      assumption: the socket is not in use.
         *      as we checked the user count on tcp_rcv and we're
         *      running from a soft interrupt.
         */
-               
+
        req = tp->syn_wait_queue;
-       
 
        if (!req)
        {
                return sk;
        }
-       
+
        do {
                struct tcp_v4_open_req *af_req;
 
@@ -1164,11 +1145,15 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
                    req->rmt_port == skb->h.th->source)
                {
                        u32 flg;
-                               
+
                        if (req->sk)
                        {
-                               printk(KERN_DEBUG "BUG: syn_recv:"
-                                      "socket exists\n");
+                               /*
+                                *      socket already created but not
+                                *      yet accepted()...
+                                */
+
+                               sk = req->sk;
                                break;
                        }
 
@@ -1179,7 +1164,7 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
                         */
                        flg = *(((u32 *)skb->h.th) + 3);
                        flg &= __constant_htonl(0x002f0000);
-                               
+
                        if ((flg == __constant_htonl(0x00020000)) &&
                            (!after(skb->seq, req->rcv_isn)))
                        {
@@ -1190,7 +1175,6 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
                                return NULL;
                        }
 
-                       skb_orphan(skb);
                        sk = tp->af_specific->syn_recv_sock(sk, skb, req);
 
                        tcp_dec_slow_timer(TCP_SLT_SYNACK);
@@ -1200,7 +1184,6 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
                                return NULL;
                        }
 
-                       skb_set_owner_r(skb, sk);
                        req->expires = 0UL;
                        req->sk = sk;
                        break;
@@ -1208,40 +1191,53 @@ struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb)
 
                req = req->dl_next;
        } while (req != tp->syn_wait_queue);
-       
 
+       skb_orphan(skb);
+       skb_set_owner_r(skb, sk);
        return sk;
 }
 
-static int __inline__ tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
+int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
        skb_set_owner_r(skb, sk);
 
+       /*
+        *      socket locking is here for SMP purposes as backlog rcv
+        *      is currently called with bh processing disabled.
+        */
+       lock_sock(sk);
+
        if (sk->state == TCP_ESTABLISHED)
        {
                if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
                        goto reset;
-               return 0;
+               goto ok;
        }
 
        if (sk->state == TCP_LISTEN)
        {
+               struct sock *nsk;
+
                /*
                 *      find possible connection requests
                 */
-               sk = tcp_v4_check_req(sk, skb);
 
-               if (sk == NULL)
+               nsk = tcp_v4_check_req(sk, skb);
+
+               if (nsk == NULL)
                {
                        goto discard_it;
                }
+
+               release_sock(sk);
+               lock_sock(nsk);
+               sk = nsk;
        }
-       
+
        if (tcp_rcv_state_process(sk, skb, skb->h.th, NULL, skb->len) == 0)
-               return 0;
+               goto ok;
 
 reset:
-       
        tcp_v4_send_reset(skb);
 
 discard_it:
@@ -1249,12 +1245,10 @@ discard_it:
         *      Discard frame
         */
        kfree_skb(skb, FREE_READ);
-       return 0;
-}
 
-int __inline__ tcp_v4_backlog_rcv(struct sock *sk, struct sk_buff *skb)
-{
-       return tcp_v4_do_rcv(sk, skb);
+ok:
+       release_sock(sk);
+       return 0;
 }
 
 /*
@@ -1263,7 +1257,7 @@ int __inline__ tcp_v4_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 
 int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
 {
-       struct tcphdr *th;      
+       struct tcphdr *th;
        struct sock *sk;
        u32     saddr = skb->nh.iph->saddr;
        u32     daddr = skb->nh.iph->daddr;
@@ -1276,14 +1270,14 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
        /*
         *      Pull up the IP header.
         */
-       
+
        skb_pull(skb, skb->h.raw-skb->data);
 
        /*
         *      Try to use the device checksum if provided.
         */
-               
-       switch (skb->ip_summed) 
+
+       switch (skb->ip_summed)
        {
        case CHECKSUM_NONE:
                skb->csum = csum_partial((char *)th, len, 0);
@@ -1297,8 +1291,8 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
                }
        default:
                /* CHECKSUM_UNNECESSARY */
-       }
-       
+       };
+
        tcp_statistics.TcpInSegs++;
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
@@ -1310,15 +1304,17 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
        sk = __tcp_v4_lookup(th, saddr, th->source, daddr, th->dest);
        if (!sk)
                goto no_tcp_socket;
+       if(!ipsec_sk_policy(sk,skb))
+               goto discard_it;
 
        skb->seq = ntohl(th->seq);
        skb->end_seq = skb->seq + th->syn + th->fin + len - th->doff*4;
        skb->ack_seq = ntohl(th->ack_seq);
-               
+
        skb->acked = 0;
        skb->used = 0;
 
-       if (!sk->users)
+       if (!sk->sock_readers)
                return tcp_v4_do_rcv(sk, skb);
 
        __skb_queue_tail(&sk->back_log, skb);
@@ -1334,7 +1330,6 @@ discard_it:
        kfree_skb(skb, FREE_READ);
        return 0;
 }
-  
 
 int tcp_v4_build_header(struct sock *sk, struct sk_buff *skb)
 {
@@ -1342,7 +1337,7 @@ int tcp_v4_build_header(struct sock *sk, struct sk_buff *skb)
 }
 
 int tcp_v4_rebuild_header(struct sock *sk, struct sk_buff *skb)
-{      
+{
        struct rtable *rt;
        struct iphdr *iph;
        struct tcphdr *th;
@@ -1362,18 +1357,18 @@ int tcp_v4_rebuild_header(struct sock *sk, struct sk_buff *skb)
                dst_release(skb->dst);
                skb->dst = &rt->u.dst;
        }
-  
+
        /*
         *      Discard the surplus MAC header
         */
-       
+
        skb_pull(skb, skb->nh.raw-skb->data);
 
        iph = skb->nh.iph;
        th = skb->h.th;
        size = skb->tail - skb->h.raw;
 
-       return 0;       
+       return 0;
 }
 
 static struct sock * tcp_v4_get_sock(struct sk_buff *skb, struct tcphdr *th)
@@ -1385,11 +1380,10 @@ static struct sock * tcp_v4_get_sock(struct sk_buff *skb, struct tcphdr *th)
 static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
 {
        struct sockaddr_in *sin = (struct sockaddr_in *) uaddr;
-       
+
        sin->sin_family         = AF_INET;
        sin->sin_addr.s_addr    = sk->daddr;
        sin->sin_port           = sk->dummy_th.dest;
-
 }
 
 struct tcp_func ipv4_specific = {
@@ -1430,26 +1424,23 @@ static int tcp_v4_init_sock(struct sock *sk)
         */
        sk->cong_window = 1;
        sk->ssthresh = 0x7fffffff;
-       
+
        sk->priority = 1;
        sk->state = TCP_CLOSE;
 
        /* this is how many unacked bytes we will accept for this socket.  */
        sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
        sk->max_ack_backlog = SOMAXCONN;
-       
+
        sk->mtu = 576;
        sk->mss = 536;
 
-       sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
-       
-
        /*
-        *      Speed up by setting some standard state for the dummy_th
-        *      if TCP uses it (maybe move to tcp_init later)
+        *      Speed up by setting some standard state for the dummy_th.
         */
-       
-       sk->dummy_th.ack=1;     
+
+       sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
+       sk->dummy_th.ack=1;
        sk->dummy_th.doff=sizeof(struct tcphdr)>>2;
 
        sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific;
@@ -1467,11 +1458,11 @@ static int tcp_v4_destroy_sock(struct sock *sk)
        {
                tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
        }
-       
+
        /*
-        *      Cleanup up the write buffer. 
+        *      Cleanup up the write buffer.
         */
-        
+
        while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
                IS_SKB(skb);
                kfree_skb(skb, FREE_WRITE);
@@ -1508,7 +1499,7 @@ struct proto tcp_prot = {
        tcp_v4_sendmsg,                 /* sendmsg */
        tcp_recvmsg,                    /* recvmsg */
        NULL,                           /* bind */
-       tcp_v4_backlog_rcv,             /* backlog_rcv */
+       tcp_v4_do_rcv,                  /* backlog_rcv */
        tcp_v4_hash,                    /* hash */
        tcp_v4_unhash,                  /* unhash */
        tcp_v4_rehash,                  /* rehash */
index b0c2a314670139c6c18a110c1899b0fc3621ec3c..f4e32595f7d3b6b055ec896232e95af980eca174 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    @(#)tcp_input.c 1.0.16  05/25/93
+ * Version:    $Id: tcp_output.c,v 1.31 1997/03/16 07:03:07 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -103,13 +103,13 @@ int tcp_send_skb(struct sock *sk, struct sk_buff *skb)
        /*
         *      length of packet (not counting length of pre-tcp headers) 
         */
-        
+
        size = skb->len - ((unsigned char *) th - skb->data);
 
        /*
-        *      Sanity check it.. 
+        *      Sanity check it..
         */
-        
+
        if (size < sizeof(struct tcphdr) || size > skb->len) 
        {
                printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %u)\n",
@@ -122,8 +122,8 @@ int tcp_send_skb(struct sock *sk, struct sk_buff *skb)
         *      If we have queued a header size packet.. (these crash a few
         *      tcp stacks if ack is not set)
         */
-        
-       if (size == sizeof(struct tcphdr)) 
+
+       if (size == sizeof(struct tcphdr))
        {
                /* 
                  * If it's got a syn or fin discard
@@ -136,35 +136,15 @@ int tcp_send_skb(struct sock *sk, struct sk_buff *skb)
                }
        }
 
-
        /*
         *      Actual processing.
         */
-        
-       tcp_statistics.TcpOutSegs++;  
        skb->seq = ntohl(th->seq);
        skb->end_seq = skb->seq + size - 4*th->doff;
 
-       
-       if (tp->send_head || !tcp_snd_test(sk, skb))
-       {
-               /* 
-                * Remember where we must start sending
-                */
-
-               if (tp->send_head == NULL)
-                       tp->send_head = skb;
-
-               skb_queue_tail(&sk->write_queue, skb);
-
-               if (sk->packets_out == 0 && !tp->pending)
-               {
-                       tp->pending = TIME_PROBE0;
-                       tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
-               }
+       skb_queue_tail(&sk->write_queue, skb);
 
-       }
-       else
+       if (tp->send_head == NULL && tcp_snd_test(sk, skb))
        {
                struct sk_buff * buff;
 
@@ -172,28 +152,47 @@ int tcp_send_skb(struct sock *sk, struct sk_buff *skb)
                 *      This is going straight out
                 */
 
-               skb_queue_tail(&sk->write_queue, skb);
-
-               clear_delayed_acks(sk);
-                
                th->ack_seq = htonl(tp->rcv_nxt);
                th->window = htons(tcp_select_window(sk));
 
                tp->af_specific->send_check(sk, th, size, skb);
 
-               tp->snd_nxt = skb->end_seq;
+               buff = skb_clone(skb, GFP_KERNEL);
+
+               if (buff == NULL)
+               {
+                       goto queue;
+               }
                
+               clear_delayed_acks(sk);
+               skb_set_owner_w(buff, sk);
+
+               tp->snd_nxt = skb->end_seq;
                atomic_inc(&sk->packets_out);
 
                skb->when = jiffies;
-               
-               buff = skb_clone(skb, GFP_ATOMIC);
-               skb_set_owner_w(buff, sk);
 
+               tcp_statistics.TcpOutSegs++;
                tp->af_specific->queue_xmit(buff);
 
                if (!tcp_timer_is_set(sk, TIME_RETRANS))
                        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+
+               return 0;
+       }
+
+queue:
+       /* 
+        *      Remember where we must start sending
+        */
+
+       if (tp->send_head == NULL)
+               tp->send_head = skb;
+
+       if (sk->packets_out == 0 && !tp->pending)
+       {
+               tp->pending = TIME_PROBE0;
+               tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
        }
 
        return 0;
@@ -327,9 +326,9 @@ static int tcp_wrxmit_frag(struct sock *sk, struct sk_buff *skb, int size)
 {
        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
        
-       printk(KERN_DEBUG "tcp_write_xmit: frag needed size=%d mss=%d\n", 
-              size, sk->mss);
-                               
+       SOCK_DEBUG(sk, "tcp_write_xmit: frag needed size=%d mss=%d\n",
+                  size, sk->mss);
+
        if (tcp_fragment(sk, skb, sk->mss))
        {
                /* !tcp_frament Failed! */
@@ -358,13 +357,13 @@ static int tcp_wrxmit_frag(struct sock *sk, struct sk_buff *skb, int size)
 void tcp_write_xmit(struct sock *sk)
 {
        struct sk_buff *skb;
-       struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;      
+       struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
        u16 rcv_wnd;
        int sent_pkts = 0;
 
        /*
         *      The bytes will have to remain here. In time closedown will
-        *      empty the write queue and all will be happy 
+        *      empty the write queue and all will be happy
         */
 
        if(sk->zapped)
@@ -379,10 +378,8 @@ void tcp_write_xmit(struct sock *sk)
         *      c) not retransmiting [Nagle]
         */
 
-       lock_sock(sk);
-
        rcv_wnd = htons(tcp_select_window(sk));
-       
+
        while((skb = tp->send_head) && tcp_snd_test(sk, skb))
        {
                struct tcphdr *th;
@@ -392,34 +389,26 @@ void tcp_write_xmit(struct sock *sk)
                IS_SKB(skb);
 
                /*
-                *      See if we really need to send the packet. 
+                *      See if we really need to send the packet.
+                *      (debugging code)
                 */
-                
-               if (!after(skb->end_seq, tp->snd_una)) 
+
+               if (!after(skb->end_seq, tp->snd_una))
                {
                        tcp_wrxmit_prob(sk, skb);
                        continue;
                } 
 
 
-               /* 
-                * Advance the send_head
-                * This one is going out.
+               /*
+                *      Put in the ack seq and window at this point rather
+                *      than earlier, in order to keep them monotonic.
+                *      We really want to avoid taking back window allocations.
+                *      That's legal, but RFC1122 says it's frowned on.
+                *      Ack and window will in general have changed since
+                *      this packet was put on the write queue.
                 */
 
-               update_send_head(sk);
-
-               atomic_inc(&sk->packets_out);
-
-
-/*
- * put in the ack seq and window at this point rather than earlier,
- * in order to keep them monotonic.  We really want to avoid taking
- * back window allocations.  That's legal, but RFC1122 says it's frowned on.
- * Ack and window will in general have changed since this packet was put
- * on the write queue.
- */
-
                th = skb->h.th;
                size = skb->len - (((unsigned char *) th) - skb->data);
 
@@ -438,27 +427,36 @@ void tcp_write_xmit(struct sock *sk)
                if (before(skb->end_seq, tp->snd_nxt))
                        printk(KERN_DEBUG "tcp_write_xmit:"
                               " sending already sent seq\n");
-#endif         
+#endif
 
-               tp->snd_nxt = skb->end_seq;
+               buff = skb_clone(skb, GFP_ATOMIC);
 
-               skb->when = jiffies;
+               if (buff == NULL)
+                       break;
+
+               /*
+                *      Advance the send_head. This one is going out.
+                */
+
+               update_send_head(sk);
                clear_delayed_acks(sk);
 
-               buff = skb_clone(skb, GFP_ATOMIC);
+               atomic_inc(&sk->packets_out);
                skb_set_owner_w(buff, sk);
 
+               tp->snd_nxt = skb->end_seq;
+
+               skb->when = jiffies;
+
                sent_pkts = 1;
                tp->af_specific->queue_xmit(buff);
 
        }
-       
+
        if (sent_pkts && !tcp_timer_is_set(sk, TIME_RETRANS))
        {
                tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
        }
-
-       release_sock(sk);
 }
 
 
@@ -639,8 +637,6 @@ void tcp_do_retransmit(struct sock *sk, int all)
        int ct=0;
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-       lock_sock(sk);
-
        if (tp->retrans_head == NULL)
                tp->retrans_head = skb_peek(&sk->write_queue);
 
@@ -651,7 +647,7 @@ void tcp_do_retransmit(struct sock *sk, int all)
        {
                struct sk_buff *buff;
                struct tcphdr *th;
-               int tcp_size;                   
+               int tcp_size;
                int size;
 
                IS_SKB(skb);
@@ -696,6 +692,7 @@ void tcp_do_retransmit(struct sock *sk, int all)
                }
 
                SOCK_DEBUG(sk, "retransmit sending\n");
+
                /*
                 *      update ack and window
                 */
@@ -707,7 +704,11 @@ void tcp_do_retransmit(struct sock *sk, int all)
                tp->af_specific->send_check(sk, th, size, skb);
 
                skb->when = jiffies;
+
                buff = skb_clone(skb, GFP_ATOMIC);
+
+               if (buff == NULL)
+                       break;
                skb_set_owner_w(buff, sk);
 
                clear_delayed_acks(sk);
@@ -749,8 +750,6 @@ void tcp_do_retransmit(struct sock *sk, int all)
                        tp->retrans_head = NULL;
                }
        }
-
-       release_sock(sk);
 }
 
 /*
@@ -825,7 +824,7 @@ void tcp_send_fin(struct sock *sk)
        tp->af_specific->send_check(sk, t1, sizeof(*t1), buff);
 
        /*
-        * The fin can only be transmited after the data.
+        *      The fin can only be transmited after the data.
         */
        
        skb_queue_tail(&sk->write_queue, buff);
@@ -839,9 +838,12 @@ void tcp_send_fin(struct sock *sk)
                buff->when = jiffies;
 
                skb1 = skb_clone(buff, GFP_KERNEL);
-               skb_set_owner_w(skb1, sk);
 
-               tp->af_specific->queue_xmit(skb1);
+               if (skb1)
+               {
+                       skb_set_owner_w(skb1, sk);
+                       tp->af_specific->queue_xmit(skb1);
+               }
 
                 if (!tcp_timer_is_set(sk, TIME_RETRANS))
                        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
@@ -901,20 +903,21 @@ int tcp_send_synack(struct sock *sk)
        tp->af_specific->send_check(sk, th, sizeof(*th)+4, skb);
 
        skb_queue_tail(&sk->write_queue, skb);
-
-       atomic_inc(&sk->packets_out);
        
-       skb->when = jiffies;
        buff = skb_clone(skb, GFP_ATOMIC);
 
-       skb_set_owner_w(buff, sk);
-
-       tp->af_specific->queue_xmit(buff);
+       if (buff)
+       {
+               skb_set_owner_w(buff, sk);
 
-       tcp_reset_xmit_timer(sk, TIME_RETRANS, TCP_TIMEOUT_INIT);
+               atomic_inc(&sk->packets_out);
+               skb->when = jiffies;
 
-       tcp_statistics.TcpOutSegs++;
+               tp->af_specific->queue_xmit(buff);
+               tcp_statistics.TcpOutSegs++;
 
+               tcp_reset_xmit_timer(sk, TIME_RETRANS, TCP_TIMEOUT_INIT);
+       }
        return 0;
 }
 
@@ -1029,8 +1032,11 @@ void tcp_send_ack(struct sock *sk)
 
        tp->af_specific->send_check(sk, th, sizeof(struct tcphdr), buff);
 
-       SOCK_DEBUG(sk, "\rtcp_send_ack: seq %x ack %x\n", tp->snd_nxt, tp->rcv_nxt);
+       SOCK_DEBUG(sk, "\rtcp_send_ack: seq %x ack %x\n",
+                  tp->snd_nxt, tp->rcv_nxt);
+
        tp->af_specific->queue_xmit(buff);
+
        tcp_statistics.TcpOutSegs++;
 }
 
@@ -1096,7 +1102,10 @@ void tcp_write_wakeup(struct sock *sk)
                                            skb);
 
                buff = skb_clone(skb, GFP_ATOMIC);
-
+               if (buff == NULL)
+               {
+                       return;
+               }
                skb_set_owner_w(buff, sk);
                atomic_inc(&sk->packets_out);
 
@@ -1122,10 +1131,10 @@ void tcp_write_wakeup(struct sock *sk)
                /*
                 *      Put in the IP header and routing stuff. 
                 */
-                
+
                tmp = tp->af_specific->build_net_header(sk, buff);
 
-               if (tmp < 0) 
+               if (tmp < 0)
                {
                        kfree_skb(buff, FREE_WRITE);
                        return;
@@ -1143,9 +1152,9 @@ void tcp_write_wakeup(struct sock *sk)
 /*             t1->fin = 0;    -- We are sending a 'previous' sequence, and 0 bytes of data - thus no FIN bit */
                t1->ack_seq = htonl(tp->rcv_nxt);
                t1->window = htons(tcp_select_window(sk));
-               
+
                tp->af_specific->send_check(sk, t1, sizeof(*t1), buff);
-       }               
+       }
 
        /*
         *      Send it.
index 337ff5413c22c7ee1b4bf1fd319e2f7e28e6cc85..ca6c584e9d1ecb256dd473e8862b7cef2438edac 100644 (file)
@@ -255,7 +255,7 @@ void tcp_probe_timer(unsigned long data) {
                return;
        }
        
-       if (sk->users) 
+       if (sk->sock_readers) 
        {
                /* 
                 * Try again in second 
@@ -401,6 +401,8 @@ void tcp_retransmit_timer(unsigned long data)
                return;
        }
 
+       lock_sock(sk);
+
        /*
         * Clear delay ack timer
         */
@@ -412,16 +414,15 @@ void tcp_retransmit_timer(unsigned long data)
         */
 
        tp->retrans_head = NULL;
-       
 
        if (sk->retransmits == 0)
        {
-               /* 
-                * remember window where we lost 
+               /*
+                * remember window where we lost
                 * "one half of the current window but at least 2 segments"
                 */
-               
-               sk->ssthresh = max(sk->cong_window >> 1, 2); 
+
+               sk->ssthresh = max(sk->cong_window >> 1, 2);
                sk->cong_count = 0;
                sk->cong_window = 1;
        }
@@ -452,6 +453,8 @@ void tcp_retransmit_timer(unsigned long data)
        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
 
        tcp_write_timeout(sk);
+
+       release_sock(sk);
 }
 
 /*
@@ -472,7 +475,7 @@ static void tcp_syn_recv_timer(unsigned long data)
                        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
                        
                        /* TCP_LISTEN is implied. */
-                       if (!sk->users && tp->syn_wait_queue) {
+                       if (!sk->sock_readers && tp->syn_wait_queue) {
                                struct open_request *req;
 
                                req = tp->syn_wait_queue;
index 664d8116707eafb69ad969985523f051fd75bbc6..1df77b85cb98736d8b7741860bab2c127fd8f3b4 100644 (file)
@@ -92,7 +92,7 @@ void net_timer (unsigned long data)
         * only process if socket is not in use
         */
 
-       if (sk->users)
+       if (sk->sock_readers)
        {
                sk->timer.expires = jiffies+HZ;
                add_timer(&sk->timer);
index 18766b030fa009162fe5278c1ef3aa95bcba5568..6fc24f077ba99601f3f8764f11122537ca755470 100644 (file)
 #include <net/icmp.h>
 #include <net/route.h>
 #include <net/checksum.h>
+#include <linux/ipsec.h>
 
 /*
  *     Snmp MIB for the UDP layer
@@ -123,21 +124,28 @@ struct sock *udp_hash[UDP_HTABLE_SIZE];
 static int udp_v4_verify_bind(struct sock *sk, unsigned short snum)
 {
        struct sock *sk2;
-       int retval = 0;
+       int retval = 0, sk_reuse = sk->reuse;
 
        SOCKHASH_LOCK();
        for(sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; sk2 = sk2->next) {
                if((sk2->num == snum) && (sk2 != sk)) {
+                       unsigned char state = sk2->state;
+                       int sk2_reuse = sk2->reuse;
+
                        if(!sk2->rcv_saddr || !sk->rcv_saddr) {
-                               if(sk->reuse && sk->reuse && (sk2->state != TCP_LISTEN))
-                                       continue;
-                               retval = 1;
-                               break;
-                       }
-                       if((sk2->rcv_saddr == sk->rcv_saddr) &&
-                          (!sk->reuse || !sk2->reuse || (sk2->state == TCP_LISTEN))) {
-                               retval = 1;
-                               break;
+                               if((!sk2_reuse)                 ||
+                                  (!sk_reuse)                  ||
+                                  (state == TCP_LISTEN)) {
+                                       retval = 1;
+                                       break;
+                               }
+                       } else if(sk2->rcv_saddr == sk->rcv_saddr) {
+                               if((!sk_reuse)                  ||
+                                  (!sk2_reuse)                 ||
+                                  (state == TCP_LISTEN)) {
+                                       retval = 1;
+                                       break;
+                               }
                        }
                }
        }
@@ -431,7 +439,7 @@ void udp_err(struct sk_buff *skb, unsigned char *dp)
        if (sk == NULL)
                return; /* No socket for error */
 
-       if (sk->ip_recverr && !sk->users) {
+       if (sk->ip_recverr && !sk->sock_readers) {
                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                if (skb2 && sock_queue_err_skb(sk, skb2))
                        kfree_skb(skb2, FREE_READ);
@@ -928,6 +936,16 @@ static void udp_close(struct sock *sk, unsigned long timeout)
 
 static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
+       /*
+        *      Check the security clearance
+        */
+        
+       if(!ipsec_sk_policy(sk,skb))
+       {       
+               kfree_skb(skb, FREE_WRITE);
+               return(0);
+       }
+        
        /*
         *      Charge it to the socket, dropping if the queue is full.
         */
@@ -946,7 +964,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 
 static inline void udp_deliver(struct sock *sk, struct sk_buff *skb)
 {
-       if (sk->users) {
+       if (sk->sock_readers) {
                __skb_queue_tail(&sk->back_log, skb);
                return;
        }
index e11c5eee749dda1d7fc454a5f4872bbfbb9d4239..15ef93ac6dec86807bb5cc626d954eac26459e83 100644 (file)
@@ -8,12 +8,18 @@
 
 
 O_TARGET := ipv6.o
-O_OBJS   := af_inet6.o ipv6_output.o ipv6_input.o addrconf.o sit.o \
-           ipv6_route.o ipv6_sockglue.o ndisc.o udp.o raw.o \
-           protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
-           exthdrs.o sysctl_net_ipv6.o datagram.o
+IPV6_OBJS :=   af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \
+               route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
+               protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
+               exthdrs.o sysctl_net_ipv6.o datagram.o proc.o
 
 MOD_LIST_NAME := IPV6_MODULES
 M_OBJS   := $(O_TARGET)
 
+#ifeq ($(CONFIG_IPV6_FIREWALL),y)
+#  IPV6_OBJS += ip6_fw.o
+#endif
+
+O_OBJS := $(IPV6_OBJS)
+
 include $(TOPDIR)/Rules.make
index ed6c4081bd8dea6aeb83054ac0c75640eb6c9cd9..f2bb896117af9c13c34a0f08d083a22334235a64 100644 (file)
@@ -5,12 +5,14 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
+ *     $Id: addrconf.c,v 1.15 1997/03/18 18:24:23 davem Exp $
  *
  *     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.
  */
+
 /*
  *     Changes:
  *
 #include <net/ipv6.h>
 #include <net/protocol.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/sit.h>
 
 #include <asm/uaccess.h>
 
-#define HASH_SIZE              16
+/* Set to 3 to get tracing... */
+#define ACONF_DEBUG 2
+
+#if ACONF_DEBUG >= 3
+#define ADBG(x) printk x
+#else
+#define ADBG(x)
+#endif
+
 /*
  *     Configured unicast address list
  */
-struct inet6_ifaddr            *inet6_addr_lst[HASH_SIZE];
+struct inet6_ifaddr            *inet6_addr_lst[IN6_ADDR_HSIZE];
 
 /*
  *     Hash list of configured multicast addresses
  */
-struct ipv6_mc_list            *inet6_mcast_lst[HASH_SIZE];
+struct ifmcaddr6               *inet6_mcast_lst[IN6_ADDR_HSIZE];
 
 /*
  *     AF_INET6 device list
  */
-struct inet6_dev               *inet6_dev_lst;
+struct inet6_dev               *inet6_dev_lst[IN6_ADDR_HSIZE];
 
 atomic_t                       addr_list_lock = 0;
 
@@ -67,15 +77,11 @@ static struct timer_list addr_chk_timer = {
        0, 0, addrconf_verify
 };
 
-
-int DupAddrDetectTransmits = 1;
-
-/*
- *     /proc/sys switch for autoconf (enabled by default)
- */
-int addrconf_sys_autoconf  = 1;
+static int addrconf_ifdown(struct device *dev);
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp);
+static void addrconf_dad_timer(unsigned long data);
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
 static void addrconf_rs_timer(unsigned long data);
 
 int ipv6_addr_type(struct in6_addr *addr)
@@ -89,58 +95,41 @@ int ipv6_addr_type(struct in6_addr *addr)
         * 0x4/3
         */
 
-       if ((st & __constant_htonl(0xE0000000)) == 
-           __constant_htonl(0x40000000))
-       {
+       if ((st & __constant_htonl(0xE0000000)) == __constant_htonl(0x40000000))
                return IPV6_ADDR_UNICAST;
-       }
 
-       if ((st & __constant_htonl(0xFF000000)) == 
-           __constant_htonl(0xFF000000))
-       {
+       if ((st & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000)) {
                int type = IPV6_ADDR_MULTICAST;
 
-               switch((st >> 16) & 0x0f)
-               {
-                       case 0x01:
+               switch((st & __constant_htonl(0x00FF0000))) {
+                       case __constant_htonl(0x00010000):
                                type |= IPV6_ADDR_LOOPBACK;
                                break;
-                       case 0x02:
+
+                       case __constant_htonl(0x00020000):
                                type |= IPV6_ADDR_LINKLOCAL;
                                break;
-                       case 0x05:
+
+                       case __constant_htonl(0x00050000):
                                type |= IPV6_ADDR_SITELOCAL;
                                break;
-               }
+               };
                return type;
        }
        
-       if ((st & __constant_htonl(0xFFC00000)) == 
-           __constant_htonl(0xFE800000))
-       {
+       if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFE800000))
                return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST);
-       }
 
-       if ((st & __constant_htonl(0xFFC00000)) == 
-           __constant_htonl(0xFEC00000))
-       {
+       if ((st & __constant_htonl(0xFFC00000)) == __constant_htonl(0xFEC00000))
                return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST);
-       }
 
-       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0)
-       {
-               if (addr->s6_addr32[2] == 0)
-               {
+       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
+               if (addr->s6_addr32[2] == 0) {
                        if (addr->in6_u.u6_addr32[3] == 0)
-                       {
                                return IPV6_ADDR_ANY;
-                       }
 
                        if (addr->s6_addr32[3] == __constant_htonl(0x00000001))
-                       {
-                               return (IPV6_ADDR_LOOPBACK | 
-                                       IPV6_ADDR_UNICAST);
-                       }
+                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST);
 
                        return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST);
                }
@@ -152,81 +141,64 @@ int ipv6_addr_type(struct in6_addr *addr)
        return IPV6_ADDR_RESERVED;
 }
 
-struct inet6_dev * ipv6_add_dev(struct device *dev)
+static struct inet6_dev * ipv6_add_dev(struct device *dev)
 {
-       struct inet6_dev *dev6;
-
-       /*
-        *      called by netdev notifier from a syscall
-        */
-       dev6 = (struct inet6_dev *) kmalloc(sizeof(struct inet6_dev), 
-                                           GFP_ATOMIC);
-
-       if (dev6 == NULL)
-               return NULL;
-
-       memset(dev6, 0, sizeof(struct inet6_dev));
-       dev6->dev = dev;
-       dev6->if_index = dev->ifindex;
+       struct inet6_dev *ndev, **bptr, *iter;
+       int hash;
 
-       /*
-        *      insert at head.
-        */
+       ndev = kmalloc(sizeof(struct inet6_dev), gfp_any());
 
-       dev6->next = inet6_dev_lst;
-       inet6_dev_lst = dev6;
+       if (ndev) {
+               memset(ndev, 0, sizeof(struct inet6_dev));
 
-       return dev6;
-}
+               ndev->dev = dev;
+               hash = ipv6_devindex_hash(dev->ifindex);
+               bptr = &inet6_dev_lst[hash];
+               iter = *bptr;
 
-struct inet6_dev * ipv6_dev_by_index(int index)
-{
-       struct inet6_dev *in6_dev;
+               for (; iter; iter = iter->next)
+                       bptr = &iter->next;
 
-       for (in6_dev = inet6_dev_lst; in6_dev; in6_dev = in6_dev->next)
-       {
-               if (in6_dev->if_index == index)
-                       return in6_dev;
+               *bptr = ndev;
        }
-
-       return NULL;
+       return ndev;
 }
 
 void addrconf_forwarding_on(void)
 {
-       struct inet6_dev *in6_dev;
-       struct in6_addr maddr;
+       struct inet6_dev *idev;
+       int i;
 
-       for (in6_dev = inet6_dev_lst; in6_dev; in6_dev = in6_dev->next)
-       {
-               printk(KERN_DEBUG "dev %s\n", in6_dev->dev->name);
+       for (i = 0; i < IN6_ADDR_HSIZE; i++) {
+               for (idev = inet6_dev_lst[i]; idev; idev = idev->next) {
+#if ACONF_DEBUG >= 2
+                       printk(KERN_DEBUG "dev %s\n", idev->dev->name);
+#endif
 
-               if (in6_dev->dev->type == ARPHRD_ETHER)
-               {
-                       printk(KERN_DEBUG "joining all-routers\n");
-                       in6_dev->router = 1;
-                       ipv6_addr_all_routers(&maddr);
-                       ipv6_dev_mc_inc(in6_dev->dev, &maddr);          
-               }
-       }
+                       if (idev->dev->type == ARPHRD_ETHER) {
+                               struct in6_addr maddr;
 
-       if (last_resort_rt && (last_resort_rt->rt_flags & RTI_ALLONLINK))
-       {
-               rt_release(last_resort_rt);
-               last_resort_rt = NULL;
+#if ACONF_DEBUG >= 2
+                               printk(KERN_DEBUG "joining all-routers\n");
+#endif
+                               idev->router = 1;
+                               ipv6_addr_all_routers(&maddr);
+                               ipv6_dev_mc_inc(idev->dev, &maddr);
+                       }
+               }
        }
 }
 
 struct inet6_dev * ipv6_get_idev(struct device *dev)
 {
-       struct inet6_dev *in6_dev;
+       struct inet6_dev *idev;
+       int hash;
 
-       for (in6_dev = inet6_dev_lst; in6_dev; in6_dev = in6_dev->next)
-       {
-               if (in6_dev->dev == dev)
-               {
-                       return in6_dev;
-               }
+       hash = ipv6_devindex_hash(dev->ifindex);
+
+       for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) {
+               if (idev->dev == dev)
+                       return idev;
        }
        return NULL;
 }
@@ -234,45 +206,34 @@ struct inet6_dev * ipv6_get_idev(struct device *dev)
 struct inet6_ifaddr * ipv6_add_addr(struct inet6_dev *idev, 
                                    struct in6_addr *addr, int scope)
 {
-       struct inet6_ifaddr * ifaddr;
+       struct inet6_ifaddr *ifa;
        int hash;
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
 
-       ifaddr = (struct inet6_ifaddr *) kmalloc(sizeof(struct inet6_ifaddr), 
-                                                GFP_ATOMIC);
+       ifa = kmalloc(sizeof(struct inet6_ifaddr), gfp_any());
 
-       if (ifaddr == NULL)
-       {
-               printk(KERN_DEBUG "ipv6_add_addr: malloc failed\n");
-               restore_flags(flags);
+       if (ifa == NULL) {
+               ADBG(("ipv6_add_addr: malloc failed\n"));
                return NULL;
        }
 
-       memset(ifaddr, 0, sizeof(struct inet6_ifaddr));
-       memcpy(&ifaddr->addr, addr, sizeof(struct in6_addr));
-
-       ifaddr->scope = scope;
-       ifaddr->idev = idev;
-       
+       memset(ifa, 0, sizeof(struct inet6_ifaddr));
+       memcpy(&ifa->addr, addr, sizeof(struct in6_addr));
 
-       /* add to list */
+       init_timer(&ifa->timer);
+       ifa->scope = scope;
+       ifa->idev = idev;
 
+       /* Add to list. */
        hash = ipv6_addr_hash(addr);
 
-       ifaddr->lst_next = inet6_addr_lst[hash];
-       inet6_addr_lst[hash] = ifaddr;
+       ifa->lst_next = inet6_addr_lst[hash];
+       inet6_addr_lst[hash] = ifa;
 
+       /* Add to inet6_dev unicast addr list. */
+       ifa->if_next = idev->addr_list;
+       idev->addr_list = ifa;
 
-       /* add to inet6_dev unicast addr list */
-       ifaddr->if_next = idev->addr_list;
-       idev->addr_list = ifaddr;
-
-       restore_flags(flags);
-       return ifaddr;
-       
+       return ifa;
 }
 
 void ipv6_del_addr(struct inet6_ifaddr *ifp)
@@ -280,8 +241,7 @@ void ipv6_del_addr(struct inet6_ifaddr *ifp)
        struct inet6_ifaddr *iter, **back;
        int hash;
 
-       if (addr_list_lock)
-       {
+       if (addr_list_lock) {
                ifp->flags |= ADDR_INVALID;
                return;
        }
@@ -291,10 +251,8 @@ void ipv6_del_addr(struct inet6_ifaddr *ifp)
        iter = inet6_addr_lst[hash];
        back = &inet6_addr_lst[hash];
 
-       for (; iter; iter = iter->lst_next)
-       {
-               if (iter == ifp)
-               {
+       for (; iter; iter = iter->lst_next) {
+               if (iter == ifp) {
                        *back = ifp->lst_next;
                        ifp->lst_next = NULL;
                        break;
@@ -305,10 +263,8 @@ void ipv6_del_addr(struct inet6_ifaddr *ifp)
        iter = ifp->idev->addr_list;
        back = &ifp->idev->addr_list;
 
-       for (; iter; iter = iter->if_next)
-       {
-               if (iter == ifp)
-               {
+       for (; iter; iter = iter->if_next) {
+               if (iter == ifp) {
                        *back = ifp->if_next;
                        ifp->if_next = NULL;
                        break;
@@ -327,30 +283,26 @@ void ipv6_del_addr(struct inet6_ifaddr *ifp)
  *             an address of the attached interface 
  *     iii)    don't use deprecated addresses
  *
- *     at the moment i believe only iii) is missing.
+ *     at the moment I believe only iii) is missing.
  */
-struct inet6_ifaddr * ipv6_get_saddr(struct rt6_info *rt, struct in6_addr *daddr)
+struct inet6_ifaddr * ipv6_get_saddr(struct dst_entry *dst,
+                                    struct in6_addr *daddr)
 {
        int scope;
-       struct inet6_ifaddr * ifp = NULL;
-       struct inet6_dev    * i6dev;
-       struct inet6_ifaddr * match = NULL;
+       struct inet6_ifaddr *ifp = NULL;
+       struct inet6_ifaddr *match = NULL;
        struct device *dev = NULL;
+       struct rt6_info *rt;
        int i;
 
+       rt = (struct rt6_info *) dst;
        if (rt)
-       {
-               dev = rt->rt_dev;
-       }
+               dev = rt->rt6i_dev;
        
        atomic_inc(&addr_list_lock);
 
-       scope = ipv6_addr_type(daddr);
-
-       scope &= IPV6_ADDR_SCOPE_MASK;
-
-       if (rt && (rt->rt_flags & RTI_ALLONLINK))
-       {
+       scope = ipv6_addr_scope(daddr);
+       if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
                /*
                 *      route for the "all destinations on link" rule
                 *      when no routers are present
@@ -363,30 +315,23 @@ struct inet6_ifaddr * ipv6_get_saddr(struct rt6_info *rt, struct in6_addr *daddr
         *      search dev and walk through dev addresses
         */
 
-       if (dev)
-       {
+       if (dev) {
+               struct inet6_dev *idev;
+               int hash;
+
                if (dev->flags & IFF_LOOPBACK)
-               {
                        scope = IFA_HOST;
-               }
 
-               for (i6dev = inet6_dev_lst; i6dev; i6dev=i6dev->next)
-               {
-                       if (i6dev->dev == dev)
-                       {
-                               for (ifp=i6dev->addr_list; ifp; 
-                                    ifp=ifp->if_next)
-                               {
-                                       if (ifp->scope == scope)
-                                       {
+               hash = ipv6_devindex_hash(dev->ifindex);
+               for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
+                       if (idev->dev == dev) {
+                               for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+                                       if (ifp->scope == scope) {
                                                if (!(ifp->flags & ADDR_STATUS))
-                                               {
                                                        goto out;
-                                               }
+
                                                if (!(ifp->flags & ADDR_INVALID))
-                                               {
                                                        match = ifp;
-                                               }
                                        }
                                }
                                break;
@@ -395,37 +340,27 @@ struct inet6_ifaddr * ipv6_get_saddr(struct rt6_info *rt, struct in6_addr *daddr
        }
 
        if (scope == IFA_LINK)
-       {
                goto out;
-       }
 
        /*
         *      dev == NULL or search failed for specified dev
         */
 
-       for (i=0; i < HASH_SIZE; i++)
-       {
-               for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next)
-               {
-                       if (ifp->scope == scope)
-                       {
+       for (i=0; i < IN6_ADDR_HSIZE; i++) {
+               for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
+                       if (ifp->scope == scope) {
                                if (!(ifp->flags & ADDR_STATUS))
-                               {
                                        goto out;
-                               }
+
                                if (!(ifp->flags & ADDR_INVALID))
-                               {
                                        match = ifp;
-                               }
                        }
                }
        }
 
-  out:
+out:
        if (ifp == NULL && match)
-       {
                ifp = match;
-       }
        atomic_dec(&addr_list_lock);
        return ifp;
 }
@@ -433,14 +368,14 @@ struct inet6_ifaddr * ipv6_get_saddr(struct rt6_info *rt, struct in6_addr *daddr
 struct inet6_ifaddr * ipv6_get_lladdr(struct device *dev)
 {
        struct inet6_ifaddr *ifp;
-       struct inet6_dev *i6dev;
-
-       for (i6dev = inet6_dev_lst; i6dev; i6dev=i6dev->next)
-       {
-               if (i6dev->dev == dev)
-               {
-                       for (ifp=i6dev->addr_list; ifp; ifp=ifp->if_next)
-                       {
+       struct inet6_dev *idev;
+       int hash;
+
+       hash = ipv6_devindex_hash(dev->ifindex);
+
+       for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
+               if (idev->dev == dev) {
+                       for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
                                if (ifp->scope == IFA_LINK)
                                        return ifp;
                        }
@@ -464,154 +399,15 @@ struct inet6_ifaddr * ipv6_chk_addr(struct in6_addr *addr)
        atomic_inc(&addr_list_lock);
 
        hash = ipv6_addr_hash(addr);
-
-       for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next)
-       {
+       for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
                if (ipv6_addr_cmp(&ifp->addr, addr) == 0)
-               {
                        break;
-               }
        }
 
        atomic_dec(&addr_list_lock);
        return ifp;     
 }
 
-static void sit_route_add(struct inet6_dev *idev)
-{
-       struct in6_rtmsg rtmsg;
-       struct device *dev = idev->dev;
-       int err;
-
-       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
-
-       memset(&rtmsg.rtmsg_dst, 0, sizeof(struct in6_addr));
-       memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
-
-       if (dev->pa_dstaddr == 0)
-       {
-               /* prefix length - 96 bytes "::d.d.d.d" */
-               rtmsg.rtmsg_prefixlen = 96;
-               rtmsg.rtmsg_metric = 1;
-               rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_UP;
-       }
-       else
-       {
-               rtmsg.rtmsg_prefixlen = 10;
-               rtmsg.rtmsg_dst.s6_addr32[0] = __constant_htonl(0xfe800000);
-               rtmsg.rtmsg_dst.s6_addr32[3] = dev->pa_dstaddr;
-               rtmsg.rtmsg_metric = 1;
-               rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_UP;
-       }
-
-       rtmsg.rtmsg_ifindex = idev->if_index; 
-
-       err = ipv6_route_add(&rtmsg);
-
-       if (err)
-       {
-               printk(KERN_DEBUG "sit_route_add: error in route_add\n");
-       }
-}
-
-static void init_loopback(struct device *dev)
-{
-       struct in6_addr addr;
-       struct inet6_dev  *idev;
-       struct inet6_ifaddr * ifp;
-       struct in6_rtmsg rtmsg;
-       int err;
-
-       /* ::1 */
-
-       memset(&addr, 0, sizeof(struct in6_addr));
-       addr.s6_addr[15] = 1;
-
-       idev = ipv6_add_dev(dev);
-
-       if (idev == NULL)
-       {
-               printk(KERN_DEBUG "init loopback: add_dev failed\n");
-               return;
-       }
-
-       ifp = ipv6_add_addr(idev, &addr, IFA_HOST);
-
-       if (ifp == NULL)
-       {
-               printk(KERN_DEBUG "init_loopback: add_addr failed\n");
-               return;
-       }
-
-       ifp->flags |= ADDR_PERMANENT;
-
-       memcpy(&rtmsg.rtmsg_dst, &addr, sizeof(struct in6_addr));
-       memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
-
-       rtmsg.rtmsg_prefixlen = 128;
-       rtmsg.rtmsg_metric = 1;
-       rtmsg.rtmsg_ifindex = idev->if_index;
-
-       rtmsg.rtmsg_flags = RTF_NEXTHOP|RTF_HOST|RTF_UP;
-
-       err = ipv6_route_add(&rtmsg);
-
-       if (err)
-       {
-               printk(KERN_DEBUG "init_loopback: error in route_add\n");
-       }
-
-       /* add route for ::127.0.0.1 */
-}
-
-static void addrconf_eth_config(struct device *dev)
-{
-       struct in6_addr addr;
-       struct in6_addr maddr;
-       struct inet6_ifaddr * ifp;
-       struct inet6_dev    * idev;
-
-       memset(&addr, 0, sizeof(struct in6_addr));
-
-       /* generate link local address*/
-       addr.s6_addr[0] = 0xFE;
-       addr.s6_addr[1] = 0x80;
-
-       memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len), 
-              dev->dev_addr, dev->addr_len);
-
-       idev = ipv6_add_dev(dev);
-                       
-       if (idev == NULL)
-               return;
-       
-       ifp = ipv6_add_addr(idev, &addr, IFA_LINK);
-                       
-       if (ifp == NULL)
-               return;
-
-       ifp->flags |= (DAD_INCOMPLETE | ADDR_PERMANENT);
-       ifp->prefix_len = 10;
-
-       /* join to all nodes multicast group */
-       ipv6_addr_all_nodes(&maddr);
-       ipv6_dev_mc_inc(dev, &maddr);
-       
-       if (ipv6_forwarding)
-       {
-               idev->router = 1;
-               ipv6_addr_all_routers(&maddr);
-               ipv6_dev_mc_inc(dev, &maddr);           
-       }
-
-       /* join to solicited addr multicast group */
-       addrconf_addr_solict_mult(&addr, &maddr);
-       ipv6_dev_mc_inc(dev, &maddr);
-                       
-       /* start dad */
-       addrconf_dad_start(ifp);
-}
-
 void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
 {
        struct prefix_info *pinfo;
@@ -623,9 +419,8 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
 
        pinfo = (struct prefix_info *) opt;
        
-       if (len < sizeof(struct prefix_info))
-       {
-               printk(KERN_DEBUG "addrconf: prefix option too short\n");
+       if (len < sizeof(struct prefix_info)) {
+               ADBG(("addrconf: prefix option too short\n"));
                return;
        }
        
@@ -636,17 +431,13 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
        addr_type = ipv6_addr_type(&pinfo->prefix);
 
        if (addr_type & IPV6_ADDR_LINKLOCAL)
-       {
                return;
-       }
 
        valid_lft = ntohl(pinfo->valid);
        prefered_lft = ntohl(pinfo->prefered);
 
-       if (prefered_lft > valid_lft)
-       {
-               printk(KERN_WARNING
-                      "addrconf: prefix option has invalid lifetime\n");
+       if (prefered_lft > valid_lft) {
+               printk(KERN_WARNING "addrconf: prefix option has invalid lifetime\n");
                return;
        }
 
@@ -655,11 +446,7 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
         *      delete it
         */
 
-       if (last_resort_rt && (last_resort_rt->rt_flags & RTI_ALLONLINK))
-       {
-               rt_release(last_resort_rt);
-               last_resort_rt = NULL;
-       }
+       rt6_purge_dflt_routers(RTF_ALLONLINK);
 
        /*
         *      Two things going on here:
@@ -669,178 +456,86 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
 
        rt_expires = jiffies + valid_lft * HZ;
        if (rt_expires < jiffies)
-       {
                rt_expires = ~0;
-       }
 
-       rt = fibv6_lookup(&pinfo->prefix, dev, RTI_DYNAMIC|RTI_GATEWAY);
-               
-       if (rt)
-       {
-               if (pinfo->onlink == 0 || valid_lft == 0)
-               {
-                       /*
-                        *      delete route
-                        */
-                       fib6_del_rt(rt);
+       rt = rt6_lookup(&pinfo->prefix, NULL, dev, RTF_LINKRT);
+
+       if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+               if (pinfo->onlink == 0 || valid_lft == 0) {
+                       ip6_del_rt(rt);
                        rt = NULL;
+               } else {
+                       rt->rt6i_expires = rt_expires;
                }
-               else
-               {
-                       rt->rt_expires = rt_expires;
-               }
-       }
-       else if (pinfo->onlink && valid_lft)
-       {
+       } else if (pinfo->onlink && valid_lft) {
                struct in6_rtmsg rtmsg;
-               struct inet6_dev *idev;
+               int err;
+
+               memset(&rtmsg, 0, sizeof(rtmsg));
                
                printk(KERN_DEBUG "adding on link route\n");
-               ipv6_addr_copy(&rtmsg.rtmsg_dst, &pinfo->prefix);
-               memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
 
-               rtmsg.rtmsg_prefixlen = pinfo->prefix_len;
-               rtmsg.rtmsg_metric = 1;
-               
-               if ((idev = ipv6_get_idev(dev)))
-               {
-                       rtmsg.rtmsg_ifindex = idev->if_index;
-               }
-               rtmsg.rtmsg_flags = RTF_UP | RTF_ADDRCONF;
-               rtmsg.rtmsg_info = rt_expires;
+               ipv6_addr_copy(&rtmsg.rtmsg_dst, &pinfo->prefix);
+               rtmsg.rtmsg_dst_len     = pinfo->prefix_len;
+               rtmsg.rtmsg_metric      = IP6_RT_PRIO_ADDRCONF;
+               rtmsg.rtmsg_ifindex     = dev->ifindex;
+               rtmsg.rtmsg_flags       = RTF_UP | RTF_ADDRCONF;
+               rtmsg.rtmsg_info        = rt_expires;
 
-               ipv6_route_add(&rtmsg);
+               ip6_route_add(&rtmsg, &err);
        }
 
-       if (pinfo->autoconf && addrconf_sys_autoconf)
-       {
+       if (pinfo->autoconf && ipv6_config.autoconf) {
                struct inet6_ifaddr * ifp;
                struct in6_addr addr;
                int plen;
 
                plen = pinfo->prefix_len >> 3;
 
-               if (plen + dev->addr_len == sizeof(struct in6_addr))
-               {
+               if (plen + dev->addr_len == sizeof(struct in6_addr)) {
                        memcpy(&addr, &pinfo->prefix, plen);
                        memcpy(addr.s6_addr + plen, dev->dev_addr,
                               dev->addr_len);
-               }
-               else
-               {
-                       printk(KERN_DEBUG
-                              "addrconf: prefix_len invalid\n");
+               } else {
+                       ADBG(("addrconf: prefix_len invalid\n"));
                        return;
                }
 
                ifp = ipv6_chk_addr(&addr);
 
-               if (ifp == NULL && valid_lft)
-               {
-                       /* create */
-
-                       struct inet6_dev *in6_dev;
-
-                       in6_dev = ipv6_get_idev(dev);
+               if (ifp == NULL && valid_lft) {
+                       struct inet6_dev *in6_dev = ipv6_get_idev(dev);
 
                        if (in6_dev == NULL)
-                       {
-                               printk(KERN_DEBUG
-                                      "addrconf: device not configured\n");
-                       }
+                               ADBG(("addrconf: device not configured\n"));
                        
                        ifp = ipv6_add_addr(in6_dev, &addr,
                                            addr_type & IPV6_ADDR_SCOPE_MASK);
 
-                       if (dev->flags & IFF_MULTICAST)
-                       {
+                       if (dev->flags & IFF_MULTICAST) {
                                struct in6_addr maddr;
 
-                               /* join to solicited addr multicast group */
+                               /* Join to solicited addr multicast group. */
                                addrconf_addr_solict_mult(&addr, &maddr);
                                ipv6_dev_mc_inc(dev, &maddr);
                        }
 
-                       ifp->flags |= DAD_INCOMPLETE;
                        ifp->prefix_len = pinfo->prefix_len;
 
                        addrconf_dad_start(ifp);
-                       
                }
 
-               if (ifp && valid_lft == 0)
-               {
+               if (ifp && valid_lft == 0) {
                        ipv6_del_addr(ifp);
                        ifp = NULL;
                }
 
-               if (ifp)
-               {
+               if (ifp) {
                        ifp->valid_lft = valid_lft;
                        ifp->prefered_lft = prefered_lft;
                        ifp->tstamp = jiffies;
                }
        }
-
-}
-
-static int addrconf_ifdown(struct device *dev)
-{
-       struct inet6_dev *idev, **bidev;
-       struct inet6_ifaddr *ifa, **bifa;
-       int i;
-
-       start_bh_atomic();
-
-       bidev = &inet6_dev_lst;
-
-       for (idev = inet6_dev_lst; idev; idev = idev->next)
-       {
-               if (idev->dev == dev)
-               {
-                       *bidev = idev->next;
-                       break;
-               }
-               bidev = &idev;
-       }
-
-       if (idev == NULL)
-       {
-               printk(KERN_DEBUG "addrconf_ifdown: device not found\n");
-               end_bh_atomic();
-               return -ENODEV;
-       }
-       
-       /*
-        *      FIXME: clear multicast group membership
-        */
-
-       /*
-        *      clean addr_list
-        */
-
-       for (i=0; i<16; i++)
-       {
-               bifa = &inet6_addr_lst[i];
-               
-               for (ifa=inet6_addr_lst[i]; ifa; )
-               {
-                       if (ifa->idev == idev)
-                       {
-                               *bifa = ifa->lst_next;
-                               del_timer(&ifa->timer);
-                               kfree(ifa);
-                               ifa = *bifa;
-                               continue;
-                       }
-                       bifa = &ifa;
-                       ifa = ifa->lst_next;
-               }
-       }
-
-       kfree(idev);
-       end_bh_atomic();
-       return 0;
 }
 
 /*
@@ -851,41 +546,31 @@ static int addrconf_ifdown(struct device *dev)
 int addrconf_set_dstaddr(void *arg)
 {
        struct in6_ifreq ireq;
-       struct inet6_dev *idev;
        struct device *dev;
        int err = -EINVAL;
 
-       if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
-       {
+       if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) {
                err = -EFAULT;
                goto err_exit;
        }
 
-       idev = ipv6_dev_by_index(ireq.ifr6_ifindex);
+       dev = dev_get_by_index(ireq.ifr6_ifindex);
 
-       if (idev == NULL)
-       {
+       if (dev == NULL) {
                err = -ENODEV;
                goto err_exit;
        }
 
-       dev = idev->dev;
-
-       if (dev->type == ARPHRD_SIT)
-       {
+       if (dev->type == ARPHRD_SIT) {
                struct device *dev;
                
                if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4))
-               {
                        return -EADDRNOTAVAIL;
-               }
                
                dev = sit_add_tunnel(ireq.ifr6_addr.s6_addr32[3]);
                
                if (dev == NULL)
-               {
                        err = -ENODEV;
-               }
                else
                        err = 0;
        }
@@ -899,87 +584,141 @@ err_exit:
  */
 int addrconf_add_ifaddr(void *arg)
 {
-       struct inet6_dev *in6_dev;
+       struct inet6_dev *idev;
        struct in6_ifreq ireq;
        struct inet6_ifaddr *ifp;
        struct device *dev;
-       int addr_type;
-       int err;
+       int scope;
        
        if (!suser())
                return -EPERM;
        
-       err = copy_from_user(&ireq, arg, sizeof(struct in6_ifreq));
-       if (err)
+       if(copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
                return -EFAULT;
 
-       in6_dev = ipv6_dev_by_index(ireq.ifr6_ifindex);
+       if((dev = dev_get_by_index(ireq.ifr6_ifindex)) == NULL)
+               return -EINVAL;
 
-       if (in6_dev == NULL)
+       if ((idev = ipv6_get_idev(dev)) == NULL)
                return -EINVAL;
 
-       dev = in6_dev->dev;
-       
-       addr_type  = ipv6_addr_type(&ireq.ifr6_addr);
-       addr_type &= IPV6_ADDR_SCOPE_MASK;
-       
-       ifp = ipv6_add_addr(in6_dev, &ireq.ifr6_addr, addr_type);
+       scope = ipv6_addr_scope(&ireq.ifr6_addr);
 
-       if (ifp == NULL)
+       if((ifp = ipv6_add_addr(idev, &ireq.ifr6_addr, scope)) == NULL)
                return -ENOMEM;
 
        ifp->prefix_len = 128;
 
-       if (dev->flags & IFF_MULTICAST)
-       {
+       if (dev->flags & IFF_MULTICAST) {
                struct in6_addr maddr;
 
-               /* join to solicited addr multicast group */
+               /* Join to solicited addr multicast group. */
                addrconf_addr_solict_mult(&ireq.ifr6_addr, &maddr);
                ipv6_dev_mc_inc(dev, &maddr);
        }
 
-
        ifp->prefix_len = ireq.ifr6_prefixlen;
        ifp->flags |= ADDR_PERMANENT;
 
        if (!(dev->flags & (IFF_NOARP|IFF_LOOPBACK)))
-       {
-               ifp->flags |= DAD_INCOMPLETE;
                addrconf_dad_start(ifp);
-       }
+       else
+               ip6_rt_addr_add(&ifp->addr, dev);
+
        return 0;
 }
 
-static void sit_add_v4_addrs(struct inet6_dev *idev)
+static void sit_route_add(struct device *dev)
 {
-       struct inet6_ifaddr * ifp;
-       struct in6_addr addr;
-       struct device *dev;
-       int scope;
-
+       struct in6_rtmsg rtmsg;
+       struct rt6_info *rt;
+       int err;
+
+       ADBG(("sit_route_add(%s): ", dev->name));
+       memset(&rtmsg, 0, sizeof(rtmsg));
+
+       rtmsg.rtmsg_type                        = RTMSG_NEWROUTE;
+       rtmsg.rtmsg_metric                      = IP6_RT_PRIO_ADDRCONF;
+
+       if (dev->pa_dstaddr == 0) {
+               ADBG(("pa_dstaddr=0, "));
+               /* prefix length - 96 bytes "::d.d.d.d" */
+               rtmsg.rtmsg_dst_len             = 96;
+               rtmsg.rtmsg_flags               = RTF_NONEXTHOP|RTF_UP;
+       } else {
+               ADBG(("pa_dstaddr=%08x, ", dev->pa_dstaddr));
+               rtmsg.rtmsg_dst_len             = 10;
+               rtmsg.rtmsg_dst.s6_addr32[0]    = __constant_htonl(0xfe800000);
+               rtmsg.rtmsg_dst.s6_addr32[3]    = dev->pa_dstaddr;
+               rtmsg.rtmsg_gateway.s6_addr32[3]= dev->pa_dstaddr;
+               rtmsg.rtmsg_flags               = RTF_UP;
+       }
+
+       rtmsg.rtmsg_ifindex                     = dev->ifindex; 
+       ADBG(("doing ip6_route_add()\n"));
+       rt = ip6_route_add(&rtmsg, &err);
+       
+       if (err) {
+#if ACONF_DEBUG >= 1
+               printk(KERN_DEBUG "sit_route_add: error %d in route_add\n", err);
+#endif
+       }
+
+       ADBG(("sit_route_add(cont): "));
+       if (dev->pa_dstaddr) {
+               struct rt6_info *mrt;
+
+               ADBG(("pa_dstaddr != 0, "));
+               rt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_gateway);
+               if (rt->rt6i_nexthop == NULL) {
+                       ADBG(("can't get neighbour\n"));
+                       printk(KERN_DEBUG "sit_route: get_neigh failed\n");
+               }
+
+               /*
+                *      Add multicast route.
+                */
+               ADBG(("add MULT, "));
+               ipv6_addr_set(&rtmsg.rtmsg_dst, __constant_htonl(0xFF000000), 0, 0, 0);
+
+               rtmsg.rtmsg_dst_len = 8;
+               rtmsg.rtmsg_flags = RTF_UP;
+               rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+
+               memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
+               ADBG(("doing ip6_route_add()\n"));
+               mrt = ip6_route_add(&rtmsg, &err);
+
+               if (mrt)
+                       mrt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+       } else {
+               ADBG(("pa_dstaddr==0\n"));
+       }
+}
+
+static void sit_add_v4_addrs(struct inet6_dev *idev)
+{
+       struct inet6_ifaddr * ifp;
+       struct in6_addr addr;
+       struct device *dev;
+       int scope;
+
        memset(&addr, 0, sizeof(struct in6_addr));
 
-       if (idev->dev->pa_dstaddr)
-       {
+       if (idev->dev->pa_dstaddr) {
                addr.s6_addr32[0] = __constant_htonl(0xfe800000);
                scope = IFA_LINK;
-       }
-       else
-       {
+       } else {
                scope = IPV6_ADDR_COMPATv4;
        }
 
-        for (dev = dev_base; dev != NULL; dev = dev->next) 
-        {
-               if (dev->family == AF_INET && (dev->flags & IFF_UP))
-               {
+        for (dev = dev_base; dev != NULL; dev = dev->next) {
+               if (dev->family == AF_INET && (dev->flags & IFF_UP)) {
                        int flag = scope;
                        
                        addr.s6_addr32[3] = dev->pa_addr;
 
-                       if (dev->flags & IFF_LOOPBACK)
-                       {
+                       if (dev->flags & IFF_LOOPBACK) {
                                if (idev->dev->pa_dstaddr)
                                        continue;
                                
@@ -987,15 +726,94 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
                        }
 
                        ifp = ipv6_add_addr(idev, &addr, flag);
-                       
+
                        if (ifp == NULL)
                                continue;
 
                        ifp->flags |= ADDR_PERMANENT;
+                       ip6_rt_addr_add(&ifp->addr, dev);
                }
         }
 }
 
+static void init_loopback(struct device *dev)
+{
+       struct in6_addr addr;
+       struct inet6_dev  *idev;
+       struct inet6_ifaddr * ifp;
+       int err;
+
+       /* ::1 */
+
+       memset(&addr, 0, sizeof(struct in6_addr));
+       addr.s6_addr[15] = 1;
+
+       idev = ipv6_add_dev(dev);
+
+       if (idev == NULL) {
+               printk(KERN_DEBUG "init loopback: add_dev failed\n");
+               return;
+       }
+
+       ifp = ipv6_add_addr(idev, &addr, IFA_HOST);
+
+       if (ifp == NULL) {
+               printk(KERN_DEBUG "init_loopback: add_addr failed\n");
+               return;
+       }
+
+       ifp->flags |= ADDR_PERMANENT;
+
+       err = ip6_rt_addr_add(&addr, dev);
+       if (err)
+               printk(KERN_DEBUG "init_loopback: error in route_add\n");
+}
+
+static void addrconf_eth_config(struct device *dev)
+{
+       struct in6_addr addr;
+       struct in6_addr maddr;
+       struct inet6_ifaddr * ifp;
+       struct inet6_dev    * idev;
+
+       memset(&addr, 0, sizeof(struct in6_addr));
+
+       /* Generate link local address. */
+       addr.s6_addr[0] = 0xFE;
+       addr.s6_addr[1] = 0x80;
+
+       memcpy(addr.s6_addr + (sizeof(struct in6_addr) - dev->addr_len), 
+              dev->dev_addr, dev->addr_len);
+
+       idev = ipv6_add_dev(dev);
+       if (idev == NULL)
+               return;
+       
+       ifp = ipv6_add_addr(idev, &addr, IFA_LINK);
+       if (ifp == NULL)
+               return;
+
+       ifp->flags = ADDR_PERMANENT;
+       ifp->prefix_len = 10;
+
+       /* Join to all nodes multicast group. */
+       ipv6_addr_all_nodes(&maddr);
+       ipv6_dev_mc_inc(dev, &maddr);
+
+       if (ipv6_config.forwarding) {
+               idev->router = 1;
+               ipv6_addr_all_routers(&maddr);
+               ipv6_dev_mc_inc(dev, &maddr);
+       }
+
+       /* Join to solicited addr multicast group. */
+       addrconf_addr_solict_mult(&addr, &maddr);
+       ipv6_dev_mc_inc(dev, &maddr);
+
+       /* Start duplicate address detection. */
+       addrconf_dad_start(ifp);
+}
+
 int addrconf_notify(struct notifier_block *this, unsigned long event, 
                    void * data)
 {
@@ -1026,7 +844,7 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
                         *  route.
                         */
 
-                       sit_route_add(idev);
+                       sit_route_add(dev);
                        break;
 
                case ARPHRD_LOOPBACK:
@@ -1034,12 +852,12 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
                        break;
 
                case ARPHRD_ETHER:
-
                        printk(KERN_DEBUG "Configuring eth interface\n");
                        addrconf_eth_config(dev);
                        break;
-               }
-               rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, dev, 0, 0);
+               };
+
+               rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);
                break;
 
        case NETDEV_DOWN:
@@ -1047,104 +865,72 @@ int addrconf_notify(struct notifier_block *this, unsigned long event,
                 *      Remove all addresses from this interface
                 *      and take the interface out of the list.
                 */
-               if (addrconf_ifdown(dev) == 0)
-               {
+               if (addrconf_ifdown(dev) == 0) {
+#if 0
                        rt6_ifdown(dev);
-                       rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, 0, dev, 0, 0);
+#endif
+                       rt6_sndmsg(RTMSG_DELDEVICE, NULL, NULL, NULL, dev, 0, 0, 0, 0);
                }
 
                break;
-       }
+       };
        
        return NOTIFY_OK;
 }
 
-static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
-{
-       struct in6_rtmsg rtmsg;
-       struct device *dev;
-       int err;
-
-
-       if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
-       {
-               struct in6_addr all_routers;
-
-               /*
-                *      1) configure a link route for this interface
-                *      2) send a (delayed) router solicitation
-                */
-
-               memcpy(&rtmsg.rtmsg_dst, &ifp->addr, sizeof(struct in6_addr));
-               memset(&rtmsg.rtmsg_gateway, 0, sizeof(struct in6_addr));
-
-               dev = ifp->idev->dev;
-
-               rtmsg.rtmsg_prefixlen = ifp->prefix_len;
-               rtmsg.rtmsg_metric = 1;
-               rtmsg.rtmsg_ifindex = ifp->idev->if_index;
 
-               rtmsg.rtmsg_flags = RTF_UP;
-
-               err = ipv6_route_add(&rtmsg);
-               
-               if (err)
-               {
-                       printk(KERN_DEBUG "dad_complete: error in route_add\n");
-               }
+static int addrconf_ifdown(struct device *dev)
+{
+       struct inet6_dev *idev, **bidev;
+       struct inet6_ifaddr *ifa, **bifa;
+       int i, hash;
 
-               if (ipv6_forwarding == 0)
-               {
-                       ipv6_addr_set(&all_routers,
-                                     __constant_htonl(0xff020000U), 0, 0,
-                                     __constant_htonl(0x2U));
+       start_bh_atomic();
 
-                       /*
-                        *      If a host as already performed a random delay
-                        *      [...] as part of DAD [...] there is no need
-                        *      to delay again before sending the first RS
-                        */
-                       ndisc_send_rs(ifp->idev->dev, &ifp->addr,
-                                     &all_routers);
+       hash = ipv6_devindex_hash(dev->ifindex);
+       bidev = &inet6_dev_lst[hash];
 
-                       ifp->probes = 1;
-                       ifp->timer.function = addrconf_rs_timer;
-                       ifp->timer.expires = (jiffies + 
-                                             RTR_SOLICITATION_INTERVAL);
-                       ifp->idev->if_flags |= IF_RS_SENT;
-                       add_timer(&ifp->timer);
+       for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) {
+               if (idev->dev == dev) {
+                       *bidev = idev->next;
+                       break;
                }
+               bidev = &idev->next;
        }
 
-}
+       if (idev == NULL) {
+               printk(KERN_DEBUG "addrconf_ifdown: device not found\n");
+               end_bh_atomic();
+               return -ENODEV;
+       }
 
-static void addrconf_dad_timer(unsigned long data)
-{
-       struct inet6_ifaddr *ifp;
-       struct in6_addr unspec;
-       struct in6_addr mcaddr;
+       /*
+        *      FIXME: clear multicast group membership
+        */
 
-       ifp = (struct inet6_ifaddr *) data;
+       /*
+        *      clean addr_list
+        */
 
-       if (--ifp->probes == 0)
-       {
-               /*
-                * DAD was successful
-                */
+       for (i=0; i<16; i++) {
+               bifa = &inet6_addr_lst[i];
 
-               ifp->flags &= ~DAD_INCOMPLETE;
-               addrconf_dad_completed(ifp);
-               return;
+               for (ifa=inet6_addr_lst[i]; ifa; ) {
+                       if (ifa->idev == idev) {
+                               *bifa = ifa->lst_next;
+                               del_timer(&ifa->timer);
+                               kfree(ifa);
+                               ifa = *bifa;
+                               continue;
+                       }
+                       ifa = ifa->lst_next;
+                       bifa = &ifa->lst_next;
+               }
        }
 
-       /* send a neighbour solicitation for our addr */
-       memset(&unspec, 0, sizeof(unspec));
-       addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
-
-       ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
-
-       ifp->timer.expires = jiffies + RETRANS_TIMER;
-       add_timer(&ifp->timer);
+       kfree(idev);
+       end_bh_atomic();
+       return 0;
 }
 
 static void addrconf_rs_timer(unsigned long data)
@@ -1153,11 +939,10 @@ static void addrconf_rs_timer(unsigned long data)
 
        ifp = (struct inet6_ifaddr *) data;
 
-       if (ipv6_forwarding)
+       if (ipv6_config.forwarding)
                return;
 
-       if (ifp->idev->if_flags & IF_RA_RCVD)
-       {
+       if (ifp->idev->if_flags & IF_RA_RCVD) {
                /*
                 *      Announcement received after solicitation
                 *      was sent
@@ -1165,8 +950,7 @@ static void addrconf_rs_timer(unsigned long data)
                return;
        }
 
-       if (ifp->probes++ <= MAX_RTR_SOLICITATIONS)
-       {
+       if (ifp->probes++ <= ipv6_config.rtr_solicits) {
                struct in6_addr all_routers;
 
                ipv6_addr_set(&all_routers,
@@ -1175,54 +959,77 @@ static void addrconf_rs_timer(unsigned long data)
 
                ndisc_send_rs(ifp->idev->dev, &ifp->addr,
                              &all_routers);
-       
                
                ifp->timer.function = addrconf_rs_timer;
-               ifp->timer.expires = jiffies + RTR_SOLICITATION_INTERVAL;
+               ifp->timer.expires = (jiffies + 
+                                     ipv6_config.rtr_solicit_interval);
                add_timer(&ifp->timer);
-       }
-       else
-       {
+       } else {
+               struct in6_rtmsg rtmsg;
+               int err;
+
+#if ACONF_DEBUG >= 2
                printk(KERN_DEBUG "%s: no IPv6 routers present\n",
                       ifp->idev->dev->name);
+#endif
 
-               if (!default_rt_list && !last_resort_rt)
-               {
-                       struct rt6_info *rt;
+               memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
+               rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+               rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+               rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF | 
+                                    RTF_DEFAULT | RTF_UP);
 
-                       /*
-                        *      create a last resort route with all
-                        *      destinations on link
-                        */
-                       rt = kmalloc(sizeof(struct rt6_info), GFP_ATOMIC);
-
-                       if (rt)
-                       {
-                               memset(rt, 0, sizeof(struct rt6_info));
-                               rt->rt_dev = ifp->idev->dev;
-                               rt->rt_ref = 1;
-                               rt->rt_flags = (RTI_ALLONLINK | RTF_UP);
-                               last_resort_rt = rt;
-                       }
-               }
+               rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
+
+               ip6_route_add(&rtmsg, &err);
        }
 }
 
+/*
+ *     Duplicate Address Detection
+ */
 static void addrconf_dad_start(struct inet6_ifaddr *ifp)
 {
        static int rand_seed = 1;
-       int rand_num;
+       struct device *dev;
+       unsigned long rand_num;
+
+       dev = ifp->idev->dev;
 
-       if (rand_seed)
-       {
+       if (dev->flags & IFF_MULTICAST) {
+               struct in6_rtmsg rtmsg;
+               struct rt6_info *mrt;
+               int err;
+
+               memset(&rtmsg, 0, sizeof(rtmsg));
+               ipv6_addr_set(&rtmsg.rtmsg_dst,
+                             __constant_htonl(0xFF000000), 0, 0, 0);
+
+               rtmsg.rtmsg_dst_len = 8;
+               rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+               rtmsg.rtmsg_ifindex = dev->ifindex;
+
+               rtmsg.rtmsg_flags = RTF_UP;
+
+               mrt = ip6_route_add(&rtmsg, &err);
+
+               if (err)
+                       printk(KERN_DEBUG "dad_start: mcast route add failed\n");
+               else
+                       mrt->rt6i_nexthop = ndisc_get_neigh(dev, &rtmsg.rtmsg_dst);
+       }
+
+       if (rand_seed) {
                rand_seed = 0;
                nd_rand_seed = ifp->addr.s6_addr32[3];
        }
 
        init_timer(&ifp->timer);
-       ifp->probes = DupAddrDetectTransmits;
 
-       rand_num = ipv6_random() % MAX_RTR_SOLICITATION_DELAY;
+       ifp->probes = ipv6_config.dad_transmits;
+       ifp->flags |= DAD_INCOMPLETE;
+
+       rand_num = ipv6_random() % ipv6_config.rtr_solicit_delay;
 
        ifp->timer.function = addrconf_dad_timer;
        ifp->timer.data = (unsigned long) ifp;
@@ -1231,6 +1038,97 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp)
        add_timer(&ifp->timer);
 }
 
+static void addrconf_dad_timer(unsigned long data)
+{
+       struct inet6_ifaddr *ifp;
+       struct in6_addr unspec;
+       struct in6_addr mcaddr;
+
+       ifp = (struct inet6_ifaddr *) data;
+
+       if (ifp->probes == 0) {
+               /*
+                * DAD was successful
+                */
+
+               ifp->flags &= ~DAD_INCOMPLETE;
+               addrconf_dad_completed(ifp);
+               return;
+       }
+
+       ifp->probes--;
+
+       /* send a neighbour solicitation for our addr */
+       memset(&unspec, 0, sizeof(unspec));
+       addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
+
+       ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
+
+       ifp->timer.expires = jiffies + ipv6_config.rtr_solicit_interval;
+       add_timer(&ifp->timer);
+}
+
+static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
+{
+       struct device *dev;
+       int err;
+
+       dev = ifp->idev->dev;
+
+       if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL) {
+               struct in6_rtmsg rtmsg;
+               struct in6_addr all_routers;
+
+               /*
+                *      1) configure a link route for this interface
+                *      2) send a (delayed) router solicitation
+                */
+
+               memset(&rtmsg, 0, sizeof(rtmsg));
+               
+               memcpy(&rtmsg.rtmsg_dst, &ifp->addr, sizeof(struct in6_addr));
+
+               rtmsg.rtmsg_dst_len = ifp->prefix_len;
+               rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
+               rtmsg.rtmsg_ifindex = dev->ifindex;
+
+               rtmsg.rtmsg_flags = RTF_UP;
+
+               ip6_route_add(&rtmsg, &err);
+               
+               if (err)
+                       printk(KERN_DEBUG "dad_complete: error in route_add\n");
+
+               if (ipv6_config.forwarding == 0) {
+                       ipv6_addr_set(&all_routers,
+                                     __constant_htonl(0xff020000U), 0, 0,
+                                     __constant_htonl(0x2U));
+
+                       /*
+                        *      If a host as already performed a random delay
+                        *      [...] as part of DAD [...] there is no need
+                        *      to delay again before sending the first RS
+                        */
+                       ndisc_send_rs(ifp->idev->dev, &ifp->addr,
+                                     &all_routers);
+
+                       ifp->probes = 1;
+                       ifp->timer.function = addrconf_rs_timer;
+                       ifp->timer.expires = (jiffies +
+                                             ipv6_config.rtr_solicit_interval);
+                       ifp->idev->if_flags |= IF_RS_SENT;
+                       add_timer(&ifp->timer);
+               }
+       }
+       
+       /*
+        *      configure the address for reception
+        */
+
+       ip6_rt_addr_add(&ifp->addr, dev);
+}
+
+#ifdef CONFIG_PROC_FS
 static int iface_proc_info(char *buffer, char **start, off_t offset,
                           int length, int dummy)
 {
@@ -1238,13 +1136,11 @@ static int iface_proc_info(char *buffer, char **start, off_t offset,
        int i;
        int len = 0;
 
-       for (i=0; i < HASH_SIZE; i++)
-               for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next)
-               {
+       for (i=0; i < IN6_ADDR_HSIZE; i++)
+               for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
                        int j;
 
-                       for (j=0; j<16; j++)
-                       {
+                       for (j=0; j<16; j++) {
                                sprintf(buffer + len, "%02x",
                                        ifp->addr.s6_addr[j]);
                                len += 2;
@@ -1252,7 +1148,7 @@ static int iface_proc_info(char *buffer, char **start, off_t offset,
 
                        len += sprintf(buffer + len,
                                       " %02x %02x %02x %02x %8s\n",
-                                      ifp->idev->if_index,
+                                      ifp->idev->dev->ifindex,
                                       ifp->prefix_len,
                                       ifp->scope,
                                       ifp->flags,
@@ -1275,7 +1171,7 @@ struct proc_dir_entry iface_proc_entry =
         0, NULL,
         &iface_proc_info
 };
-
+#endif /* CONFIG_PROC_FS */
 
 /*
  *     Periodic address status verification
@@ -1287,29 +1183,23 @@ void addrconf_verify(unsigned long foo)
        unsigned long now = jiffies;
        int i;
 
-       for (i=0; i < HASH_SIZE; i++)
-       {
-               for (ifp=inet6_addr_lst[i]; ifp;)
-               {
-                       if (!(ifp->flags & ADDR_PERMANENT))
-                       {
+       for (i=0; i < IN6_ADDR_HSIZE; i++) {
+               for (ifp=inet6_addr_lst[i]; ifp;) {
+                       if (!(ifp->flags & ADDR_PERMANENT)) {
                                struct inet6_ifaddr *bp;
                                unsigned long age;
 
                                age = (now - ifp->tstamp) / HZ;
 
                                if (age > ifp->prefered_lft)
-                               {
                                        ifp->flags |= ADDR_DEPRECATED;
-                               }
 
                                bp = ifp;
                                ifp=ifp->lst_next;
                                
                                if (age > bp->valid_lft)
-                               {
                                        ipv6_del_addr(bp);
-                               }
+
                                continue;
                        }
                        ifp=ifp->lst_next;
@@ -1320,18 +1210,25 @@ void addrconf_verify(unsigned long foo)
        add_timer(&addr_chk_timer);     
 }
 
+/*
+ *     Init / cleanup code
+ */
+
 void addrconf_init()
 {
        struct device *dev;
 
-       /* init addr hash list */         
-       memset(inet6_addr_lst, 0, 16 * sizeof(struct inet6_ifaddr *));
+       /*
+        *      init address and device hash lists
+        */
 
-       memset(inet6_mcast_lst,   0, 16 * sizeof(struct ipv6_mc_list *));
+       memset(inet6_addr_lst, 0, IN6_ADDR_HSIZE * sizeof(struct inet6_ifaddr *));
 
-       inet6_dev_lst = NULL;
+       memset(inet6_mcast_lst, 0, IN6_ADDR_HSIZE * sizeof(struct ifmcaddr6 *));
 
-       /* 
+       memset(inet6_dev_lst, 0, IN6_ADDR_HSIZE * sizeof(struct inet6_dev *));
+
+       /*
         *      Init loopback device
         */
 
@@ -1350,16 +1247,19 @@ void addrconf_init()
        if (dev && (dev->flags & IFF_UP))
                addrconf_eth_config(dev);
        
-       proc_register(&proc_net, &iface_proc_entry);
+#ifdef CONFIG_PROC_FS
+       proc_net_register(&iface_proc_entry);
+#endif
        
        addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
        add_timer(&addr_chk_timer);
 }
 
+#ifdef MODULE
 void addrconf_cleanup(void)
 {
-       struct inet6_dev *idev, *bidev;
-       struct inet6_ifaddr *ifa, *bifa;
+       struct inet6_dev *idev;
+       struct inet6_ifaddr *ifa;
        int i;
 
        del_timer(&addr_chk_timer);
@@ -1368,26 +1268,32 @@ void addrconf_cleanup(void)
         *      clean dev list.
         */
 
-       for (idev = inet6_dev_lst; idev; )
-       {
-               bidev = idev;
-               idev = idev->next;
-               kfree(bidev);
+       for (i=0; i < IN6_ADDR_HSIZE; i++) {
+               for (idev = inet6_dev_lst[i]; idev; ) {
+                       struct inet6_dev *back;
+
+                       back = idev;
+                       idev = idev->next;
+                       kfree(back);
+               }
        }
 
        /*
         *      clean addr_list
         */
 
-       for (i=0; i<16; i++)
-       {
-               for (ifa=inet6_addr_lst[i]; ifa; )
-               {
+       for (i=0; i < IN6_ADDR_HSIZE; i++) {
+               for (ifa=inet6_addr_lst[i]; ifa; ) {
+                       struct inet6_ifaddr *bifa;
+
                        bifa = ifa;
                        ifa = ifa->lst_next;
                        kfree(bifa);
                }
        }
 
-       proc_unregister(&proc_net, iface_proc_entry.low_ino);
+#ifdef CONFIG_PROC_FS
+       proc_net_unregister(iface_proc_entry.low_ino);
+#endif
 }
+#endif /* MODULE */
index 1ec58d856304ba37443fb6a94cb82c024d38f017..0f6bbf4de09e9c6287fa0ada797e787326b42e8d 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     $Id: af_inet6.c,v 1.12 1997/03/02 06:14:44 davem Exp $
+ *     $Id: af_inet6.c,v 1.16 1997/03/18 18:24:26 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/icmpv6.h>
+
 #include <net/ip.h>
 #include <net/ipv6.h>
-#include <net/protocol.h>
-#include <net/arp.h>
-#include <net/rarp.h>
-#include <net/route.h>
-#include <net/tcp.h>
 #include <net/udp.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/raw.h>
-#include <net/icmp.h>
-#include <linux/icmpv6.h>
+#include <net/tcp.h>
+#include <net/sit.h>
+#include <net/protocol.h>
 #include <net/inet_common.h>
 #include <net/transp_v6.h>
-#include <net/ndisc.h>
-#include <net/ipv6_route.h>
-#include <net/sit.h>
-#include <linux/ip_fw.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
 extern struct proto_ops inet6_stream_ops;
 extern struct proto_ops inet6_dgram_ops;
 
+/* IPv6 procfs goodies... */
+
+#ifdef CONFIG_PROC_FS
+extern int raw6_get_info(char *, char **, off_t, int, int);
+extern int tcp6_get_info(char *, char **, off_t, int, int);
+extern int udp6_get_info(char *, char **, off_t, int, int);
+extern int afinet6_get_info(char *, char **, off_t, int, int);
+#endif
+
 static int inet6_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
@@ -101,32 +102,31 @@ static int inet6_create(struct socket *sock, int protocol)
                goto free_and_badtype;
        }
        
-       sock_init_data(sock,sk);
-       sk->zapped=0;
+       sock_init_data(sock, sk);
 
-       sk->family = AF_INET6;
-       sk->protocol = protocol;
+       sk->zapped              = 0;
+       sk->family              = AF_INET6;
+       sk->protocol            = protocol;
 
-       sk->prot = prot;
-       sk->backlog_rcv = prot->backlog_rcv;
+       sk->prot                = prot;
+       sk->backlog_rcv         = prot->backlog_rcv;
 
-       sk->timer.data = (unsigned long)sk;
-       sk->timer.function = &net_timer;
-       init_timer(&sk->timer);
+       sk->timer.data          = (unsigned long)sk;
+       sk->timer.function      = &net_timer;
 
-       sk->net_pinfo.af_inet6.hop_limit  = ipv6_hop_limit;
+       sk->net_pinfo.af_inet6.hop_limit  = ipv6_config.hop_limit;
        sk->net_pinfo.af_inet6.mcast_hops = IPV6_DEFAULT_MCASTHOPS;
        sk->net_pinfo.af_inet6.mc_loop    = 1;
 
        /* Init the ipv4 part of the socket since we can have sockets
         * using v6 API for ipv4.
         */
-       sk->ip_ttl=64;
+       sk->ip_ttl      = 64;
 
-       sk->ip_mc_loop=1;
-       sk->ip_mc_ttl=1;
-       sk->ip_mc_index=0;
-       sk->ip_mc_list=NULL;
+       sk->ip_mc_loop  = 1;
+       sk->ip_mc_ttl   = 1;
+       sk->ip_mc_index = 0;
+       sk->ip_mc_list  = NULL;
 
        if (sk->type==SOCK_RAW && protocol==IPPROTO_RAW)
                sk->ip_hdrincl=1;
@@ -429,7 +429,32 @@ struct net_proto_family inet6_family_ops = {
        inet6_create
 };
 
-
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry proc_net_raw6 = {
+       PROC_NET_RAW6, 4, "raw6",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       raw6_get_info
+};
+static struct proc_dir_entry proc_net_tcp6 = {
+       PROC_NET_TCP6, 4, "tcp6",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       tcp6_get_info
+};
+static struct proc_dir_entry proc_net_udp6 = {
+       PROC_NET_RAW6, 4, "udp6",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       udp6_get_info
+};
+static struct proc_dir_entry proc_net_sockstat6 = {
+       PROC_NET_SOCKSTAT6, 9, "sockstat6",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       afinet6_get_info
+};
+#endif /* CONFIG_PROC_FS */
 
 #ifdef MODULE
 int init_module(void)
@@ -439,12 +464,16 @@ void inet6_proto_init(struct net_proto *pro)
 {
        struct sk_buff *dummy_skb;
 
-       printk(KERN_INFO "IPv6 v0.1 for NET3.037\n");
+       printk(KERN_INFO "IPv6 v0.2 for NET3.037\n");
 
        if (sizeof(struct ipv6_options) > sizeof(dummy_skb->cb))
        {
                printk(KERN_CRIT "inet6_proto_init: size fault\n");
+#ifdef MODULE
                return -EINVAL;
+#else
+               return;
+#endif
        }
 
        (void) sock_register(&inet6_family_ops);
@@ -459,7 +488,6 @@ void inet6_proto_init(struct net_proto *pro)
        ipv6_init();
 
        icmpv6_init(&inet6_family_ops);
-       ndisc_init(&inet6_family_ops);
 
         addrconf_init();
  
@@ -472,6 +500,14 @@ void inet6_proto_init(struct net_proto *pro)
 
        tcpv6_init();
 
+       /* Create /proc/foo6 entries. */
+#ifdef CONFIG_PROC_FS
+       proc_net_register(&proc_net_raw6);
+       proc_net_register(&proc_net_tcp6);
+       proc_net_register(&proc_net_udp6);
+       proc_net_register(&proc_net_sockstat6);
+#endif
+
 #ifdef MODULE
        return 0;
 #endif
@@ -483,6 +519,11 @@ void cleanup_module(void)
        sit_cleanup();
        ipv6_cleanup();
        sock_unregister(AF_INET6);
-}
+#ifdef CONFIG_PROC_FS
+       proc_net_unregister(proc_net_raw6.low_ino);
+       proc_net_unregister(proc_net_tcp6.low_ino);
+       proc_net_unregister(proc_net_udp6.low_ino);
+       proc_net_unregister(proc_net_sockstat6.low_ino);
 #endif
-
+}
+#endif /* MODULE */
index ce292e6a0702f97fd8c031f6a443473cf90fefde..1147cd956ee0f3ac3f964c78f33fcc3592af3bd2 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: datagram.c,v 1.3 1996/10/11 16:03:05 roque Exp $
+ *     $Id: datagram.c,v 1.8 1997/03/18 18:24:28 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 
 #include <net/ipv6.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
 #include <net/addrconf.h>
 #include <net/transp_v6.h>
 
-
 int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
        struct ipv6_options *opt = (struct ipv6_options *) skb->cb;
        
-       if (np->rxinfo)
-       {
+       if (np->rxinfo) {
                struct in6_pktinfo src_info;
 
                src_info.ipi6_ifindex = skb->dev->ifindex;
@@ -42,14 +39,12 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
                put_cmsg(msg, SOL_IPV6, IPV6_RXINFO, sizeof(src_info), &src_info);
        }
 
-       if (np->rxhlim)
-       {
+       if (np->rxhlim) {
                int hlim = skb->nh.ipv6h->hop_limit;
                put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
        }
 
-       if (opt->srcrt)
-       {
+       if (opt->srcrt) {
                int hdrlen = sizeof(struct rt0_hdr) + (opt->srcrt->hdrlen << 3);
 
                put_cmsg(msg, SOL_IPV6, IPV6_RXSRCRT, hdrlen, opt->srcrt);
@@ -61,17 +56,14 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
                      struct in6_addr **src_addr, struct ipv6_options *opt, 
                      int *hlimit)
 {
-       struct inet6_dev *in6_dev = NULL;
        struct in6_pktinfo *src_info;
        struct cmsghdr *cmsg;
        struct ipv6_rt_hdr *rthdr;
        int len;
        int err = 0;
 
-       for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg))
-       {
-               if (cmsg->cmsg_level != SOL_IPV6)
-               {
+       for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               if (cmsg->cmsg_level != SOL_IPV6) {
                        printk(KERN_DEBUG "cmsg_level %d\n", cmsg->cmsg_level);
                        continue;
                }
@@ -80,34 +72,25 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
 
                case IPV6_TXINFO:
                        if (cmsg->cmsg_len < (sizeof(struct cmsghdr) +
-                                             sizeof(struct in6_pktinfo)))
-                       {
+                                             sizeof(struct in6_pktinfo))) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        src_info = (struct in6_pktinfo *) cmsg->cmsg_data;
                        
-                       if (src_info->ipi6_ifindex)
-                       {
-                               in6_dev = ipv6_dev_by_index(src_info->ipi6_ifindex);
-                               if (in6_dev == NULL)
-                               {
-                                       err = -ENODEV;
-                                       goto exit_f;
-                               }
+                       if (src_info->ipi6_ifindex) {
+                               int index = src_info->ipi6_ifindex;
 
-                               *src_dev = in6_dev->dev;
+                               *src_dev = dev_get_by_index(index);
                        }
                        
-                       if (!ipv6_addr_any(&src_info->ipi6_addr))
-                       {
+                       if (!ipv6_addr_any(&src_info->ipi6_addr)) {
                                struct inet6_ifaddr *ifp;
 
                                ifp = ipv6_chk_addr(&src_info->ipi6_addr);
 
-                               if ( ifp == NULL)
-                               {
+                               if (ifp == NULL) {
                                        err = -EINVAL;
                                        goto exit_f;
                                }
@@ -124,8 +107,7 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
                        len -= sizeof(struct cmsghdr);
 
                        /* validate option length */
-                       if (len < sizeof(struct ipv6_rt_hdr))
-                       {
+                       if (len < sizeof(struct ipv6_rt_hdr)) {
                                err = -EINVAL;
                                goto exit_f;
                        }
@@ -135,21 +117,18 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
                        /*
                         *      TYPE 0
                         */
-                       if (rthdr->type)
-                       {
+                       if (rthdr->type) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
-                       if (((rthdr->hdrlen + 1) << 3) < len)
-                       {       
+                       if (((rthdr->hdrlen + 1) << 3) < len) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        /* segments left must also match */
-                       if ((rthdr->hdrlen >> 1) != rthdr->segments_left)
-                       {
+                       if ((rthdr->hdrlen >> 1) != rthdr->segments_left) {
                                err = -EINVAL;
                                goto exit_f;
                        }
@@ -160,27 +139,26 @@ int datagram_send_ctl(struct msghdr *msg, struct device **src_dev,
                        break;
                        
                case IPV6_HOPLIMIT:
-                       
+
                        len = cmsg->cmsg_len;
                        len -= sizeof(struct cmsghdr);
                        
-                       if (len < sizeof(int))
-                       {
+                       if (len < sizeof(int)) {
                                err = -EINVAL;
                                goto exit_f;
                        }
 
                        *hlimit = *((int *) cmsg->cmsg_data);
                        break;
-                       
+
                default:
                        printk(KERN_DEBUG "invalid cmsg type: %d\n",
                               cmsg->cmsg_type);
                        err = -EINVAL;
                        break;
-               }
+               };
        }
 
-  exit_f:
+exit_f:
        return err;
 }
index 7afb7312477e104a1c899d6ca060b31d0c11edaa..b2380fb78fed99cd4cc518f5175a3921ec683102 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *
- *     $Id: exthdrs.c,v 1.7 1996/09/12 18:44:18 roque Exp $
+ *     $Id: exthdrs.c,v 1.4 1997/03/18 18:24:29 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 #include <net/transp_v6.h>
 #include <net/rawv6.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 
 /*
  *     inbound
  */
-
+#if 0
 int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev,
                        __u8 *nhptr, struct ipv6_options *opt)
 {
@@ -53,8 +53,7 @@ int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev,
        struct ipv6_rt_hdr *hdr = (struct ipv6_rt_hdr *) skb->h.raw;
        struct rt0_hdr *rthdr;
 
-       if (hdr->segments_left == 0)
-       {
+       if (hdr->segments_left == 0) {
                struct ipv6_options *opt;
 
                opt = (struct ipv6_options *) skb->cb;
@@ -65,8 +64,7 @@ int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev,
        }
 
        if (hdr->type != IPV6_SRCRT_TYPE_0 || hdr->hdrlen & 0x01 ||
-           hdr->hdrlen > 46)
-       {
+           hdr->hdrlen > 46) {
                 /* 
                 *      Discard 
                 */
@@ -90,8 +88,7 @@ int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev,
 
        n = hdr->hdrlen >> 1;
 
-       if (hdr->segments_left > n)
-       {
+       if (hdr->segments_left > n) {
                pos = (__u8 *) hdr - (__u8 *) skb->nh.ipv6h + 2;
 
                pos += 3;
@@ -109,8 +106,7 @@ int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev,
 
        addr_type = ipv6_addr_type(addr);
 
-       if (addr_type == IPV6_ADDR_MULTICAST)
-       {
+       if (addr_type == IPV6_ADDR_MULTICAST) {
                kfree_skb(skb, FREE_READ);
                return 0;
        }
@@ -126,9 +122,7 @@ int ipv6_routing_header(struct sk_buff **skb_ptr, struct device *dev,
        bit_map = ntohl(rthdr->bitmap);
 
        if ((bit_map & (1 << i)) == IPV6_SRCRT_STRICT)
-       {
                strict = 1;
-       }
 
        ipv6_forward(skb, dev, (strict ? IP6_FW_STRICT : 0) | IP6_FW_SRCRT);
 
@@ -154,10 +148,8 @@ int ipv6opt_bld_rthdr(struct sk_buff *skb, struct ipv6_options *opt,
        hops = ihdr->rt_hdr.hdrlen >> 1;
        
        if (hops > 1)
-       {
                memcpy(phdr->addr, ihdr->addr + 1,
                       (hops - 1) * sizeof(struct in6_addr));
-       }
 
        ipv6_addr_copy(phdr->addr + (hops - 1), addr);
        
@@ -165,9 +157,4 @@ int ipv6opt_bld_rthdr(struct sk_buff *skb, struct ipv6_options *opt,
 
        return NEXTHDR_ROUTING;
 }
-
-/*
- * Local variables:
- * c-file-style: "Linux"
- * End:
- */
+#endif
index c1aeaa2e9585ed7517f59b96a46f57908d957bc0..37bd7f814c858b162a75f0130911de7dbdb931f3 100644 (file)
@@ -5,6 +5,8 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *
+ *     $Id: icmp.c,v 1.8 1997/03/18 18:24:30 davem Exp $
+ *
  *     Based on net/ipv4/icmp.c
  *
  *     RFC 1885
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
 #include <linux/skbuff.h>
 
 #include <linux/inet.h>
 #include <net/sock.h>
 
 #include <net/ipv6.h>
+#include <net/checksum.h>
 #include <net/protocol.h>
-#include <net/route.h>
-#include <net/ndisc.h>
 #include <net/raw.h>
-#include <net/inet_common.h>
+#include <net/rawv6.h>
 #include <net/transp_v6.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
-#include <net/rawv6.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -88,7 +80,7 @@ static struct inet6_protocol icmpv6_protocol =
 
 
 struct icmpv6_msg {
-       struct icmpv6hdr        icmph;
+       struct icmp6hdr         icmph;
        __u8                    *data;
        struct in6_addr         *daddr;
        int                     len;
@@ -106,7 +98,7 @@ static int icmpv6_getfrag(const void *data, struct in6_addr *saddr,
                           char *buff, unsigned int offset, unsigned int len)
 {
        struct icmpv6_msg *msg = (struct icmpv6_msg *) data;
-       struct icmpv6hdr *icmph;
+       struct icmp6hdr *icmph;
        __u32 csum;
 
        /* 
@@ -115,26 +107,25 @@ static int icmpv6_getfrag(const void *data, struct in6_addr *saddr,
         *      on an echo reply. (those are the rules on RFC 1883)
         */
 
-       if (offset)
-       {
+       if (offset) {
                csum = csum_partial_copy((void *) msg->data +
-                                        offset - sizeof(struct icmpv6hdr), 
+                                        offset - sizeof(struct icmp6hdr), 
                                         buff, len, msg->csum);
                msg->csum = csum;
                return 0;
        }
 
        csum = csum_partial_copy((void *) &msg->icmph, buff,
-                                sizeof(struct icmpv6hdr), msg->csum);
+                                sizeof(struct icmp6hdr), msg->csum);
 
        csum = csum_partial_copy((void *) msg->data, 
-                                buff + sizeof(struct icmpv6hdr),
-                                len - sizeof(struct icmpv6hdr), csum);
+                                buff + sizeof(struct icmp6hdr),
+                                len - sizeof(struct icmp6hdr), csum);
 
-       icmph = (struct icmpv6hdr *) buff;
+       icmph = (struct icmp6hdr *) buff;
 
-       icmph->checksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
-                                         IPPROTO_ICMPV6, csum);
+       icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
+                                            IPPROTO_ICMPV6, csum);
        return 0; 
 }
 
@@ -163,6 +154,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
        struct in6_addr *saddr = NULL;
        struct device *src_dev = NULL;
        struct icmpv6_msg msg;
+       struct flowi fl;
        int addr_type = 0;
        int optlen;
        int len;
@@ -171,9 +163,8 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
         *      sanity check pointer in case of parameter problem
         */
 
-       if (type == ICMPV6_PARAMETER_PROB && 
-           (info > (skb->tail - ((unsigned char *) hdr))))
-       {
+       if (type == ICMPV6_PARAMPROB && 
+           (info > (skb->tail - ((unsigned char *) hdr)))) {
                printk(KERN_DEBUG "icmpv6_send: bug! pointer > skb\n");
                return;
        }
@@ -188,23 +179,18 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
        addr_type = ipv6_addr_type(&hdr->daddr);
 
        if (ipv6_chk_addr(&hdr->daddr))
-       {
                saddr = &hdr->daddr;
-       }
 
        /*
         *      Dest addr check
         */
 
-       if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST))
-       {
+       if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {
                if (type != ICMPV6_PKT_TOOBIG &&
-                   !(type == ICMPV6_PARAMETER_PROB && 
+                   !(type == ICMPV6_PARAMPROB && 
                      code == ICMPV6_UNK_OPTION && 
                      (opt_unrec(skb, info))))
-               {
                        return;
-               }
 
                saddr = NULL;
        }
@@ -216,16 +202,13 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
         */
 
        if (addr_type & IPV6_ADDR_LINKLOCAL)
-       {
                src_dev = skb->dev;
-       }
 
        /*
         *      Must not send if we know that source is Anycast also.
         *      for now we don't know that.
         */
-       if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST))
-       {
+       if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
                printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
                return;
        }
@@ -235,9 +218,9 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
         *      getfrag_t callback.
         */
 
-       msg.icmph.type = type;
-       msg.icmph.code = code;
-       msg.icmph.checksum = 0;
+       msg.icmph.icmp6_type = type;
+       msg.icmph.icmp6_code = code;
+       msg.icmph.icmp6_cksum = 0;
        msg.icmph.icmp6_pointer = htonl(info);
 
        msg.data = skb->nh.raw;
@@ -252,31 +235,37 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
        optlen = 0;
 
        len = min(skb->tail - ((unsigned char *) hdr), 
-                 576 - sizeof(struct ipv6hdr) - sizeof(struct icmpv6hdr)
+                 576 - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr)
                  - optlen);
 
-       if (len < 0)
-       {
+       if (len < 0) {
                printk(KERN_DEBUG "icmp: len problem\n");
                return;
        }
 
-       len += sizeof(struct icmpv6hdr);
+       len += sizeof(struct icmp6hdr);
 
        msg.len = len;
 
+       fl.proto = IPPROTO_ICMPV6;
+       fl.nl_u.ip6_u.daddr = &hdr->saddr;
+       fl.nl_u.ip6_u.saddr = saddr;
+       fl.dev = src_dev;
+       fl.uli_u.icmpt.type = type;
+       fl.uli_u.icmpt.code = code;
 
-       ipv6_build_xmit(sk, icmpv6_getfrag, &msg, &hdr->saddr, len,
-                       saddr, src_dev, NULL, IPPROTO_ICMPV6, 0, 1);
+       ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
+                      MSG_DONTWAIT);
 }
 
 static void icmpv6_echo_reply(struct sk_buff *skb)
 {
        struct sock *sk = icmpv6_socket->sk;
        struct ipv6hdr *hdr = skb->nh.ipv6h;
-       struct icmpv6hdr *icmph = (struct icmpv6hdr *) skb->h.raw;
+       struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
        struct in6_addr *saddr;
        struct icmpv6_msg msg;
+       struct flowi fl;
        unsigned char *data;
        int len;
 
@@ -288,11 +277,11 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
                saddr = NULL;
 
        len = skb->tail - data;
-       len += sizeof(struct icmpv6hdr);
+       len += sizeof(struct icmp6hdr);
 
-       msg.icmph.type = ICMPV6_ECHO_REPLY;
-       msg.icmph.code = 0;
-       msg.icmph.checksum = 0;
+       msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
+       msg.icmph.icmp6_code = 0;
+       msg.icmph.icmp6_cksum = 0;
        msg.icmph.icmp6_identifier = icmph->icmp6_identifier;
        msg.icmph.icmp6_sequence = icmph->icmp6_sequence;
 
@@ -300,9 +289,16 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
        msg.csum = 0;
        msg.len = len;
        msg.daddr = &hdr->saddr;
-       
-       ipv6_build_xmit(sk, icmpv6_getfrag, &msg, &hdr->saddr, len, saddr,
-                       skb->dev, NULL, IPPROTO_ICMPV6, 0, 1);
+
+       fl.proto = IPPROTO_ICMPV6;
+       fl.nl_u.ip6_u.daddr = &hdr->saddr;
+       fl.nl_u.ip6_u.saddr = saddr;
+       fl.dev = skb->dev;
+       fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
+       fl.uli_u.icmpt.code = 0;
+
+       ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
+                      MSG_DONTWAIT);
 }
 
 static __inline__ int ipv6_ext_hdr(u8 nexthdr)
@@ -339,19 +335,24 @@ static void icmpv6_notify(int type, int code, unsigned char *buff, int len,
        pbuff = (char *) (hdr + 1);
        len -= sizeof(struct ipv6hdr);
 
-       while (ipv6_ext_hdr(nexthdr)) 
-       {
+       while (ipv6_ext_hdr(nexthdr)) {
                int hdrlen;
 
                if (nexthdr == NEXTHDR_NONE)
                        return;
 
                nexthdr = *pbuff;
+
+               /* Header length is size in 8-octet units, not
+                * including the first 8 octets.
+                */
                hdrlen = *(pbuff+1);
+               hdrlen = (hdrlen + 1) << 3;
 
-               if (((hdrlen + 1) << 3) > len)
+               if (hdrlen > len)
                        return;
                
+               /* Now this is right. */
                pbuff += hdrlen;
                len -= hdrlen;
        }
@@ -360,16 +361,13 @@ static void icmpv6_notify(int type, int code, unsigned char *buff, int len,
 
        for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
             ipprot != NULL; 
-            ipprot=(struct inet6_protocol *)ipprot->next)
-       {
+            ipprot=(struct inet6_protocol *)ipprot->next) {
                if (ipprot->protocol != nexthdr)
                        continue;
 
                if (ipprot->err_handler) 
-               {
                        ipprot->err_handler(type, code, pbuff, info,
                                            saddr, daddr, ipprot);
-               }
                return;
        }
 
@@ -378,16 +376,12 @@ static void icmpv6_notify(int type, int code, unsigned char *buff, int len,
        sk = raw_v6_htable[hash];
 
        if (sk == NULL)
-       {
                return;
-       }
 
        while((sk = raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
                rawv6_err(sk, type, code, pbuff, saddr, daddr);
                sk = sk->next;
        }
-
-       return;
 }
   
 /*
@@ -400,32 +394,29 @@ int icmpv6_rcv(struct sk_buff *skb, struct device *dev,
               int redo, struct inet6_protocol *protocol)
 {
        struct ipv6hdr *orig_hdr;
-       struct icmpv6hdr *hdr = (struct icmpv6hdr *) skb->h.raw;
+       struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
        int ulen;
 
-       /* perform checksum */
-
-
+       /* Perform checksum. */
        switch (skb->ip_summed) {       
        case CHECKSUM_NONE:
                skb->csum = csum_partial((char *)hdr, len, 0);
        case CHECKSUM_HW:
                if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, 
-                                   skb->csum))
-               {
+                                   skb->csum)) {
                        printk(KERN_DEBUG "icmpv6 checksum failed\n");
                        goto discard_it;
                }
        default:
                /* CHECKSUM_UNNECESSARY */
-       }
+       };
 
        /*
         *      length of original packet carried in skb
         */
        ulen = skb->tail - (unsigned char *) (hdr + 1);
        
-       switch (hdr->type) {
+       switch (hdr->icmp6_type) {
 
        case ICMPV6_ECHO_REQUEST:
                icmpv6_echo_reply(skb);
@@ -438,20 +429,19 @@ int icmpv6_rcv(struct sk_buff *skb, struct device *dev,
        case ICMPV6_PKT_TOOBIG:
                orig_hdr = (struct ipv6hdr *) (hdr + 1);
                if (ulen >= sizeof(struct ipv6hdr))
-               {
-                       rt6_handle_pmtu(&orig_hdr->daddr,
-                                       ntohl(hdr->icmp6_mtu));
-               }
+                       rt6_pmtu_discovery(&orig_hdr->daddr, dev,
+                                          ntohl(hdr->icmp6_mtu));
 
                /*
-                * Drop through to notify
+                *      Drop through to notify
                 */
 
        case ICMPV6_DEST_UNREACH:
-       case ICMPV6_TIME_EXCEEDED:
-       case ICMPV6_PARAMETER_PROB:
+       case ICMPV6_TIME_EXCEED:
+       case ICMPV6_PARAMPROB:
 
-               icmpv6_notify(hdr->type, hdr->code, (char *) (hdr + 1), ulen,
+               icmpv6_notify(hdr->icmp6_type, hdr->icmp6_code,
+                             (char *) (hdr + 1), ulen,
                              saddr, daddr, protocol);
                break;
 
@@ -463,32 +453,35 @@ int icmpv6_rcv(struct sk_buff *skb, struct device *dev,
                ndisc_rcv(skb, dev, saddr, daddr, opt, len);            
                break;
 
-       case ICMPV6_MEMBERSHIP_QUERY:
-       case ICMPV6_MEMBERSHIP_REPORT:
-       case ICMPV6_MEMBERSHIP_REDUCTION:
-               /* forward the packet to the igmp module */
+       case ICMPV6_MGM_QUERY:
+               igmp6_event_query(skb, hdr, len);
+               break;
+
+       case ICMPV6_MGM_REPORT:
+               igmp6_event_report(skb, hdr, len);
+               break;
+
+       case ICMPV6_MGM_REDUCTION:
                break;
 
        default:
                printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
                
                /* informational */
-               if (hdr->type & 0x80)
-               {
+               if (hdr->icmp6_type & 0x80)
                        goto discard_it;
-               }
 
                /* 
                 * error of unkown type. 
                 * must pass to upper level 
                 */
 
-               icmpv6_notify(hdr->type, hdr->code, (char *) (hdr + 1), ulen,
+               icmpv6_notify(hdr->icmp6_type, hdr->icmp6_code,
+                             (char *) (hdr + 1), ulen,
                              saddr, daddr, protocol);  
-       }
-
-  discard_it:
+       };
 
+discard_it:
        kfree_skb(skb, FREE_READ);
        return 0;
 }
@@ -509,7 +502,7 @@ void icmpv6_init(struct net_proto_family *ops)
 
        if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0)
                printk(KERN_DEBUG 
-                      "Failed to create the ICMP control socket.\n");
+                      "Failed to create the ICMP6 control socket.\n");
 
        MOD_DEC_USE_COUNT;
 
@@ -518,6 +511,9 @@ void icmpv6_init(struct net_proto_family *ops)
        sk->num = 256;                  /* Don't receive any data */
 
        inet6_add_protocol(&icmpv6_protocol);
+
+       ndisc_init(ops);
+       igmp6_init(ops);
 }
 
 static struct icmp6_err {
@@ -539,8 +535,7 @@ int icmpv6_err_convert(int type, int code, int *err)
 
        switch (type) {
        case ICMPV6_DEST_UNREACH:
-               if (code <= ICMPV6_PORT_UNREACH)
-               {
+               if (code <= ICMPV6_PORT_UNREACH) {
                        *err  = tab_unreach[code].err;
                        fatal = tab_unreach[code].fatal;
                }
@@ -550,7 +545,7 @@ int icmpv6_err_convert(int type, int code, int *err)
                *err = EMSGSIZE;
                break;
                
-       case ICMPV6_PARAMETER_PROB:
+       case ICMPV6_PARAMPROB:
                *err = EPROTO;
                fatal = 1;
                break;
@@ -558,9 +553,3 @@ int icmpv6_err_convert(int type, int code, int *err)
 
        return fatal;
 }
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o icmp.o icmp.c"
- * End:
- */
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
new file mode 100644 (file)
index 0000000..18f7c8b
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ *     Linux INET6 implementation 
+ *     Forwarding Information Database
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *
+ *     $Id: ip6_fib.c,v 1.6 1997/03/18 18:24:33 davem Exp $
+ *
+ *     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/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+
+#ifdef         CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/netlink.h>
+
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+
+#define RT_DEBUG 2
+
+struct rt6_statistics  rt6_stats;
+
+/*
+ *     A routing update causes an increase of the serial number on the
+ *     afected subtree. This allows for cached routes to be asynchronously
+ *     tested when modifications are made to the destination cache as a
+ *     result of redirects, path MTU changes, etc.
+ */
+
+static __u32   rt_sernum       = 0;
+
+static void fib6_run_gc(unsigned long);
+
+static struct timer_list ip6_fib_timer = {
+       NULL, NULL,
+       0,
+       0,
+       fib6_run_gc
+};
+
+/*
+ *     Auxiliary address test functions for the radix tree.
+ *
+ *     These assume a 32bit processor (although it will work on 
+ *     64bit processors)
+ */
+
+/*
+ *     compare "prefix length" bits of an address
+ */
+
+static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
+{
+       __u32 *a1 = token1;
+       __u32 *a2 = token2;
+       int pdw;
+       int pbi;
+
+       pdw = prefixlen >> 0x05;  /* num of whole __u32 in prefix */
+       pbi = prefixlen &  0x1f;  /* num of bits in incomplete u32 in prefix */
+
+       if (pdw)
+               if (memcmp(a1, a2, pdw << 2))
+                       return 0;
+
+       if (pbi) {
+               __u32 w1, w2;
+               __u32 mask;
+
+               w1 = a1[pdw];
+               w2 = a2[pdw];
+
+               mask = htonl((0xffffffff) << (0x20 - pbi));
+
+               if ((w1 ^ w2) & mask)
+                       return 0;
+       }
+
+       return 1;
+}
+
+/*
+ *     test bit
+ */
+
+static __inline__ int addr_bit_set(void *token, int fn_bit)
+{
+       int dw;
+       __u32 b1;
+       __u32 mask;
+       int bit = fn_bit;
+       __u32 *addr = token;
+
+       dw = bit >> 0x05;
+
+       b1 = addr[dw];
+       
+       bit = ~bit;
+       bit &= 0x1f;
+       mask = htonl(1 << bit);
+       return (b1 & mask);
+}
+
+
+
+/*
+ *     find the first different bit between two addresses
+ *     length of address must be a multiple of 32bits
+ */
+
+static __inline__ int addr_diff(void *token1, void *token2, int addrlen)
+{
+       __u32 *a1 = token1;
+       __u32 *a2 = token2;
+       int i;
+
+       addrlen >>= 2;
+
+       for (i = 0; i < addrlen; i++) {
+               __u32 b1, b2;
+               __u32 xb;
+
+               b1 = a1[i];
+               b2 = a2[i];
+
+               xb = b1 ^ b2;
+
+               if (xb) {
+                       int res = 0;
+                       int j=31;
+
+                       xb = ntohl(xb);
+
+                       while (test_bit(j, &xb) == 0) {
+                               res++;
+                               j--;
+                       }
+
+                       return (i * 32 + res);
+               }
+       }
+
+       /*
+        *      we should *never* get to this point since that 
+        *      would mean the addrs are equal
+        */
+
+       return -1;
+}
+
+static __inline__ struct fib6_node * node_alloc(void)
+{
+       struct fib6_node *fn;
+
+       if ((fn = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC))) {
+               memset(fn, 0, sizeof(struct fib6_node));
+               rt6_stats.fib_nodes++;
+       }
+
+       return fn;
+}
+
+static __inline__ void node_free(struct fib6_node * fn)
+{
+       rt6_stats.fib_nodes--;
+       kfree(fn);
+}
+
+/*
+ *     Routing Table
+ *
+ *     return the apropriate node for a routing tree "add" operation
+ *     by either creating and inserting or by returning an existing
+ *     node.
+ */
+
+static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
+                                    int addrlen, int plen,
+                                    unsigned long offset,
+                                    struct rt6_info *rt)
+                                    
+{
+       struct fib6_node *fn;
+       struct fib6_node *pn = NULL;
+       struct fib6_node *in;
+       struct fib6_node *ln;
+       struct rt6key *key;
+       __u32   bit;
+       __u32   dir = 0;
+       __u32   sernum = ++rt_sernum;
+
+       /* insert node in tree */
+
+       fn = root;
+
+       if (plen == 0)
+               return fn;
+
+       for (;;) {
+               if (fn == NULL) {
+                       ln = node_alloc();
+
+                       if (ln == NULL)
+                               return NULL;
+                       ln->fn_bit = plen;
+                       
+                       ln->parent = pn;
+                       ln->fn_sernum = sernum;
+                       rt->rt6i_node = ln;
+
+                       if (dir)
+                               pn->right = ln;
+                       else
+                               pn->left  = ln;
+
+                       return ln;
+               }
+
+               key = (struct rt6key *)((u8 *)fn->leaf + offset);
+
+               if (addr_match(&key->addr, addr, fn->fn_bit)) {
+                       if (plen == fn->fn_bit) {
+                               /* clean up an intermediate node */
+                               if ((fn->fn_flags & RTN_RTINFO) == 0) {
+                                       rt6_release(fn->leaf);
+                                       fn->leaf = NULL;
+                               }
+                       
+                               fn->fn_sernum = sernum;
+                               
+                               return fn;
+                       }
+
+                       if (plen > fn->fn_bit) {
+                               /* Walk down on tree. */
+                               fn->fn_sernum = sernum;
+                               dir = addr_bit_set(addr, fn->fn_bit);
+                               pn = fn;
+                               fn = dir ? fn->right: fn->left;
+
+                               continue;
+                       }
+               }
+
+               /*
+                * split since we don't have a common prefix anymore or 
+                * we have a less significant route.
+                * we've to insert an intermediate node on the list
+                * this new node will point to the one we need to create
+                * and the current
+                */
+
+               pn = fn->parent;
+
+               /* find 1st bit in difference between the 2 addrs */
+               bit = addr_diff(addr, &key->addr, addrlen);
+
+
+               /* 
+                *              (intermediate)  
+                *                /        \
+                *      (new leaf node)    (old node)
+                */
+               if (plen > bit) {
+                       in = node_alloc();
+               
+                       if (in == NULL)
+                               return NULL;
+
+                       /* 
+                        * new intermediate node. 
+                        * RTN_RTINFO will
+                        * be off since that an address that chooses one of
+                        * the branches would not match less specific routes
+                        * int the other branch
+                        */
+
+                       in->fn_bit = bit;
+
+                       in->parent = pn;
+                       in->leaf = rt;
+
+                       in->fn_sernum = sernum;
+                       atomic_inc(&rt->rt6i_ref);
+
+                       /* leaf node */
+                       ln = node_alloc();
+
+                       if (ln == NULL) {
+                               node_free(in);
+                               return NULL;
+                       }
+
+                       /* update parent pointer */
+                       if (dir)
+                               pn->right = in;
+                       else
+                               pn->left  = in;
+
+                       ln->fn_bit = plen;
+
+                       ln->parent = in;
+                       fn->parent = in;
+
+                       ln->fn_sernum = sernum;
+
+                       if (addr_bit_set(addr, bit)) {
+                               in->right = ln;
+                               in->left  = fn;
+                       } else {
+                               in->left  = ln;
+                               in->right = fn;
+                       }
+
+                       return ln;
+               }
+
+               /* 
+                *              (new leaf node)
+                *                /        \
+                *           (old node)    NULL
+                */
+
+               ln = node_alloc();
+
+               if (ln == NULL)
+                       return NULL;
+
+               ln->fn_bit = plen;
+
+               ln->parent = pn;
+
+               ln->fn_sernum = sernum;
+               
+               if (dir)
+                       pn->right = ln;
+               else
+                       pn->left  = ln;
+               
+
+               if (addr_bit_set(&key->addr, plen))
+                       ln->right = fn;
+               else
+                       ln->left  = fn;
+
+               fn->parent = ln;
+
+               return ln;
+       }
+
+       return NULL;
+}
+
+/*
+ *     Insert routing information in a node.
+ */
+
+static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
+{
+       struct rt6_info *iter = NULL;
+       struct rt6_info **ins;
+
+       rt->rt6i_node = fn;
+       ins = &fn->leaf;
+
+       for (iter = fn->leaf; iter; iter=iter->u.next) {
+               /*
+                *      Search for duplicates
+                */
+
+               if (iter->rt6i_metric == rt->rt6i_metric) {
+                       /*
+                        *      Same priority level
+                        */
+
+                       if ((iter->rt6i_dev == rt->rt6i_dev) &&
+                           (iter->rt6i_flowr == rt->rt6i_flowr) &&
+                           (ipv6_addr_cmp(&iter->rt6i_gateway,
+                                          &rt->rt6i_gateway) == 0))
+                               return -EEXIST;
+               }
+
+               if (iter->rt6i_metric > rt->rt6i_metric)
+                       break;
+
+               ins = &iter->u.next;
+       }
+
+       /*
+        *      insert node
+        */
+
+       *ins = rt;
+       rt->u.next = iter;
+       atomic_inc(&rt->rt6i_ref);
+       rt6_stats.fib_rt_entries++;
+
+       if ((fn->fn_flags & RTN_RTINFO) == 0) {
+               rt6_stats.fib_route_nodes++;
+               fn->fn_flags |= RTN_RTINFO;
+       }
+
+       return 0;
+}
+
+static __inline__ void fib6_start_gc(struct rt6_info *rt)
+{
+       if ((ip6_fib_timer.expires == 0) &&
+           (rt->rt6i_flags & (RTF_ADDRCONF | RTF_CACHE))) {
+               ip6_fib_timer.expires = jiffies + ipv6_config.rt_gc_period;
+               add_timer(&ip6_fib_timer);
+       }
+}
+
+/*
+ *     Add routing information to the routing tree.
+ *     <destination addr>/<source addr>
+ *     with source addr info in sub-trees
+ */
+
+int fib6_add(struct fib6_node *root, struct rt6_info *rt)
+{
+       struct fib6_node *fn;
+       int err = -ENOMEM;
+       unsigned long offset;
+       
+       offset = (u8*) &rt->rt6i_dst - (u8*) rt;
+       fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
+                       rt->rt6i_dst.plen, offset, rt);
+
+       if (fn == NULL) {
+#if RT_DEBUG >= 2
+               printk(KERN_DEBUG "fib6_add: fn == NULL\n");
+#endif
+               goto out;
+       }
+
+       if (rt->rt6i_src.plen) {
+               struct fib6_node *sn;
+
+#if RT_DEBUG >= 2
+               printk(KERN_DEBUG "fib6_add: src.len > 0\n");
+#endif
+
+               if (fn->subtree == NULL) {
+                       struct fib6_node *sfn;
+
+                       if (fn->leaf == NULL) {
+                               fn->leaf = rt;
+                               atomic_inc(&rt->rt6i_ref);
+                       }
+
+                       sfn = node_alloc();
+
+                       if (sfn == NULL)
+                               goto out;
+
+                       sfn->parent = fn;
+                       sfn->leaf = &ip6_null_entry;
+                       sfn->fn_flags = RTN_ROOT;
+                       sfn->fn_sernum = ++rt_sernum;
+
+                       fn->subtree = sfn;
+               }
+
+               offset = (u8*) &rt->rt6i_src - (u8*) rt;
+
+               sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
+                               sizeof(struct in6_addr), rt->rt6i_src.plen,
+                               offset, rt);
+
+               if (sn == NULL)
+                       goto out;
+
+               fn = sn;
+       }
+
+       err = fib6_add_rt2node(fn, rt);
+
+       if (err == 0)
+               fib6_start_gc(rt);
+out:
+       return err;
+}
+
+/*
+ *     Routing tree lookup
+ *
+ */
+
+struct lookup_args {
+       unsigned long   offset;         /* key offset on rt6_info       */
+       struct in6_addr *addr;          /* search key                   */
+};
+
+static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
+                                       struct lookup_args *args)
+{
+       struct fib6_node *fn;
+       int dir;
+
+       /*
+        *      Descend on a tree
+        */
+
+       fn = root;
+
+       for (;;) {
+               struct fib6_node *next;
+
+               dir = addr_bit_set(args->addr, fn->fn_bit);
+
+               next = dir ? fn->right : fn->left;
+
+               if (next) {
+                       fn = next;
+                       continue;
+               }
+
+               break;
+       }
+
+       while ((fn->fn_flags & RTN_ROOT) == 0) {
+               if (fn->subtree) {
+                       struct fib6_node *st;
+                       struct lookup_args *narg;
+
+                       narg = args + 1;
+
+                       if (narg->addr) {
+                               st = fib6_lookup_1(fn->subtree, narg);
+
+                               if (!(st->fn_flags & RTN_ROOT))
+                               {
+                                       return st;
+                               }
+                       }
+               }
+
+               if (fn->fn_flags & RTN_RTINFO) {
+                       struct rt6key *key;
+
+                       key = (struct rt6key *) ((u8 *) fn->leaf +
+                                                args->offset);
+
+                       if (addr_match(&key->addr, args->addr, key->plen))
+                               return fn;
+               }
+
+               fn = fn->parent;
+       }
+
+       return NULL;
+}
+
+struct fib6_node * fib6_lookup(struct fib6_node *root, struct in6_addr *daddr,
+                              struct in6_addr *saddr)
+{
+       struct lookup_args args[2];
+       struct rt6_info *rt = NULL;
+       struct fib6_node *fn;
+
+       args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
+       args[0].addr = daddr;
+
+       args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
+       args[1].addr = saddr;
+
+       fn = fib6_lookup_1(root, args);
+
+       if (fn == NULL)
+               fn = root;
+
+       return fn;
+}
+
+/*
+ *     Deletion
+ *
+ */
+
+static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
+{
+       while(fn) {
+               if(fn->left)
+                       return fn->left->leaf;
+
+               if(fn->right)
+                       return fn->right->leaf;
+
+               fn = fn->subtree;
+       }
+       return NULL;
+}
+
+/*
+ *     called to trim the tree of intermediate nodes when possible
+ */
+
+static void fib6_del_2(struct fib6_node *fn)
+{
+       struct rt6_info *rt;
+
+       fn->fn_flags &= ~RTN_RTINFO;
+       rt6_stats.fib_route_nodes--;
+
+       if (fn->fn_flags & RTN_TL_ROOT)
+               return;
+
+       do {
+               struct fib6_node *pn, *child;
+               int children = 0;
+
+               child = NULL;
+
+               if (fn->left) {
+                       children++;
+                       child = fn->left;
+               }
+
+               if (fn->right) {
+                       children++;
+                       child = fn->right;
+               }
+
+               if (children > 1 || (fn->fn_flags & RTN_RTINFO))
+                       break;
+
+               if (fn->subtree)
+                       goto stree_node;
+
+               pn = fn->parent;
+
+               if ((fn->fn_flags & RTN_ROOT) == 0) {
+                       if (pn->left == fn)
+                               pn->left = child;
+                       else
+                               pn->right = child;
+
+                       if (child)
+                               child->parent = pn;
+
+                       if (fn->leaf)
+                               rt6_release(fn->leaf);
+               } else {
+                       if (children)
+                               break;
+
+                       pn->subtree = NULL;
+               }
+
+               node_free(fn);
+               fn = pn;
+
+       } while (!(fn->fn_flags & RTN_TL_ROOT));
+
+       return;
+
+stree_node:
+
+       rt6_release(fn->leaf);
+       rt = fib6_find_prefix(fn);
+
+       if (rt == NULL)
+               panic("fib6_del_2: inconsistent tree\n");
+
+       atomic_inc(&rt->rt6i_ref);
+       fn->leaf = rt;
+}
+
+static struct fib6_node * fib6_del_1(struct rt6_info *rt)
+{
+       struct fib6_node *fn;
+       
+       fn = rt->rt6i_node;
+
+       if (fn) {
+               struct rt6_info **back;
+               struct rt6_info *lf;
+
+               back = &fn->leaf;
+               
+               for(lf = fn->leaf; lf; lf=lf->u.next) {
+                       if (rt == lf) {
+                               /*
+                                *      Delete this entry.
+                                */
+
+                               *back = lf->u.next;
+                               rt6_release(lf);
+                               return fn;
+                       }
+                       back = &lf->u.next;
+               }
+       }
+
+       return NULL;
+}
+
+int fib6_del(struct rt6_info *rt)
+{
+       struct fib6_node *fn;
+
+       fn = fib6_del_1(rt);
+
+       if (fn == NULL)
+               return -ENOENT;
+
+       if (fn->leaf == NULL)
+               fib6_del_2(fn);
+
+       return 0;
+}
+
+/*
+ *     Tree transversal function
+ *
+ */
+
+void fib6_walk_tree(struct fib6_node *root, f_pnode func, void *arg,
+                   int filter)
+{
+       struct fib6_node *fn;
+
+       fn = root;
+       
+       do {
+               if (!(fn->fn_flags & RTN_TAG)) {
+                       fn->fn_flags |= RTN_TAG;
+                       
+                       if (fn->left) {
+                               fn = fn->left;
+                               continue;
+                       }
+               }
+
+               fn->fn_flags &= ~RTN_TAG;
+
+               if (fn->right) {
+                       fn = fn->right;
+                       continue;
+               }
+               
+               do {
+                       struct fib6_node *node;
+                       
+                       if (fn->fn_flags & RTN_ROOT)
+                               break;
+                       node = fn;
+                       fn = fn->parent;
+                       
+                       if (!(node->fn_flags & RTN_TAG)) {
+                               if (node->subtree) {
+                                       fib6_walk_tree(node->subtree, func,
+                                                      arg, filter);
+                               }
+
+                               if (!filter ||
+                                   (node->fn_flags & RTN_RTINFO))
+                                       (*func)(node, arg);
+                       }
+                       
+               } while (!(fn->fn_flags & RTN_TAG));
+
+       } while (!(fn->fn_flags & RTN_ROOT) || (fn->fn_flags & RTN_TAG));
+}
+
+/*
+ *     Garbage collection
+ */
+
+static int fib6_gc_node(struct fib6_node *fn, int timeout)
+{
+       struct rt6_info *rt, **back;
+       int more = 0;
+       unsigned long now = jiffies;
+
+       back = &fn->leaf;
+
+       for (rt = fn->leaf; rt;) {
+               if ((rt->rt6i_flags & RTF_CACHE) && rt->rt6i_use == 0) {
+                       if (now - rt->rt6i_tstamp > timeout) {
+                               struct rt6_info *old;
+
+                               old = rt;
+
+                               rt = rt->u.next;
+
+                               *back = rt;
+
+                               old->rt6i_node = NULL;
+                               rt6_release(old);
+                               rt6_stats.fib_rt_entries--;
+                               continue;
+                       }
+                       more++;
+               }
+
+               /*
+                *      check addrconf expiration here.
+                */
+               back = &rt->u.next;
+               rt = rt->u.next;
+       }
+
+       return more;
+}
+
+struct fib6_gc_args {
+       unsigned long   timeout;
+       int             more;
+};
+
+static void fib6_garbage_collect(struct fib6_node *fn, void *p_arg)
+{
+       struct fib6_gc_args * args = (struct fib6_gc_args *) p_arg;
+
+       if (fn->fn_flags & RTN_RTINFO) {
+               int more;
+
+               more = fib6_gc_node(fn, args->timeout);
+
+               if (fn->leaf) {
+                       args->more += more;
+                       return;
+               }
+
+               rt6_stats.fib_route_nodes--;
+               fn->fn_flags &= ~RTN_RTINFO;
+       }
+
+       /*
+        *      tree nodes (with no routing information)
+        */
+
+       if (!fn->subtree && !(fn->fn_flags & RTN_TL_ROOT)) {
+               int children = 0;
+               struct fib6_node *chld = NULL;
+
+               if (fn->left) {
+                       children++;
+                       chld = fn->left;
+               }
+                       
+               if (fn->right) {
+                       children++;
+                       chld = fn->right;
+               }
+               
+               if ((fn->fn_flags & RTN_ROOT)) {
+                       if (children == 0) {
+                               struct fib6_node *pn;
+
+                               pn = fn->parent;
+                               pn->subtree = NULL;
+
+                               node_free(fn);
+                       }
+                       return;
+               }
+
+               if (children <= 1) {
+                       struct fib6_node *pn = fn->parent;
+                       
+                       if (pn->left == fn)
+                               pn->left = chld;
+                       else
+                               pn->right = chld;
+                       
+                       if (chld)
+                               chld->parent = pn;
+                       
+                       if (fn->leaf)
+                               rt6_release(fn->leaf);
+
+                       node_free(fn);
+
+                       return;
+               }
+       }
+
+       if (fn->leaf == NULL) {
+               struct rt6_info *nrt;
+               
+               nrt = fib6_find_prefix(fn);
+
+               if (nrt == NULL)
+                       panic("fib6: inconsistent tree\n");
+
+               atomic_inc(&nrt->rt6i_ref);
+               fn->leaf = nrt;
+       }
+}
+
+static void fib6_run_gc(unsigned long dummy)
+{
+       struct fib6_gc_args arg = {
+               ipv6_config.rt_cache_timeout,
+               0
+       };
+
+       fib6_walk_tree(&ip6_routing_table, fib6_garbage_collect, &arg, 0);
+
+       if (arg.more) {
+               ip6_fib_timer.expires = jiffies + ipv6_config.rt_gc_period;
+               add_timer(&ip6_fib_timer);
+       } else {
+               ip6_fib_timer.expires = 0;
+       }
+}
diff --git a/net/ipv6/ip6_fw.c b/net/ipv6/ip6_fw.c
new file mode 100644 (file)
index 0000000..f6e7f8d
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ *     IPv6 Firewall
+ *     Linux INET6 implementation
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *
+ *     $Id: ip6_fw.c,v 1.4 1997/03/18 18:24:34 davem Exp $
+ *
+ *     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/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/udp.h>
+
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/ip6_fw.h>
+#include <net/netlink.h>
+
+static unsigned long ip6_fw_rule_cnt;
+static struct ip6_fw_rule ip6_fw_rule_list = {
+       {0},
+       NULL, NULL,
+       {0},
+       IP6_FW_REJECT
+};
+
+static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args);
+
+struct flow_rule_ops ip6_fw_ops = {
+       ip6_fw_accept
+};
+
+
+static struct rt6_info ip6_fw_null_entry = {
+       {{NULL, 0, 0, NULL,
+         0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL,
+         ip6_pkt_discard, ip6_pkt_discard, NULL}},
+       NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL,
+       0, &ip6_fw_rule_list, {{{{0}}}, 128}, {{{{0}}}, 128}
+};
+
+static struct fib6_node ip6_fw_fib = {
+       NULL, NULL, NULL, NULL,
+       &ip6_fw_null_entry,
+       0, RTN_ROOT|RTN_TL_ROOT, 0
+};
+
+static void ip6_rule_add(struct ip6_fw_rule *rl)
+{
+       struct ip6_fw_rule *next;
+
+       start_bh_atomic();
+       ip6_fw_rule_cnt++;
+       next = &ip6_fw_rule_list;
+       rl->next = next;
+       rl->prev = next->prev;
+       rl->prev->next = rl;
+       next->prev = rl;
+       end_bh_atomic();
+}
+
+static void ip6_rule_del(struct ip6_fw_rule *rl)
+{
+       struct ip6_fw_rule *next, *prev;
+
+       start_bh_atomic();
+       ip6_fw_rule_cnt--;
+       next = rl->next;
+       prev = rl->prev;
+       next->prev = prev;
+       prev->next = next;
+       end_bh_atomic();
+}
+
+static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void)
+{
+       struct ip6_fw_rule *rl;
+
+       rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
+
+       memset(rl, 0, sizeof(struct ip6_fw_rule));
+
+       if (rl)
+               rl->flowr.ops = &ip6_fw_ops;
+
+       return rl;
+}
+
+static __inline__ void ip6_fwrule_free(struct ip6_fw_rule * rl)
+{
+       kfree(rl);
+}
+
+static __inline__ int port_match(int rl_port, int fl_port)
+{
+       int res = 0;
+       if (rl_port == 0 || (rl_port == fl_port))
+               res = 1;
+       return res;
+}
+
+static int ip6_fw_accept_trans(struct ip6_fw_rule *rl,
+                              struct fl_acc_args *args)
+{
+       int res = FLOWR_NODECISION;
+       int proto = 0;
+       int sport = 0;
+       int dport = 0;
+
+       switch (args->type) {
+       case FL_ARG_FORWARD:
+       {
+               struct sk_buff *skb = args->fl_u.skb;
+               struct ipv6hdr *hdr = skb->nh.ipv6h;
+               int len;
+
+               len = skb->len - sizeof(struct ipv6hdr);
+
+               proto = hdr->nexthdr;
+
+               switch (proto) {
+               case IPPROTO_TCP:
+               {
+                       struct tcphdr *th;
+
+                       if (len < sizeof(struct tcphdr)) {
+                               res = FLOWR_ERROR;
+                               goto out;
+                       }
+                       th = (struct tcphdr *)(hdr + 1);
+                       sport = th->source;
+                       dport = th->dest;
+                       break;
+               }
+               case IPPROTO_UDP:
+               {
+                       struct udphdr *uh;
+
+                       if (len < sizeof(struct udphdr)) {
+                               res = FLOWR_ERROR;
+                               goto out;
+                       }
+                       uh = (struct udphdr *)(hdr + 1);
+                       sport = uh->source;
+                       dport = uh->dest;
+                       break;
+               }
+               default:
+                       goto out;
+               };
+               break;
+       }
+
+       case FL_ARG_ORIGIN:
+       {
+               proto = args->fl_u.fl_o.flow->proto;
+
+               if (proto == IPPROTO_ICMPV6) {
+                       goto out;
+               } else {
+                       sport = args->fl_u.fl_o.flow->uli_u.ports.sport;
+                       dport = args->fl_u.fl_o.flow->uli_u.ports.dport;
+               }
+               break;
+       }
+
+       if (proto == rl->info.proto &&
+           port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) &&
+           port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) {
+               if (rl->policy & IP6_FW_REJECT)
+                       res = FLOWR_SELECT;
+               else
+                       res = FLOWR_CLEAR;
+       }
+
+       default:
+#if IP6_FW_DEBUG >= 1
+               printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n");
+#endif
+               goto out;
+       };
+
+out:
+       return res;
+}
+
+static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args)
+{
+       struct rt6_info *rt;
+       struct ip6_fw_rule *rl;
+       int proto;
+       int res = FLOWR_NODECISION;
+
+       rt = (struct rt6_info *) dst;
+       rl = (struct ip6_fw_rule *) rt->rt6i_flowr;
+
+       proto = rl->info.proto;
+
+       switch (proto) {
+       case 0:
+               if (rl->policy & IP6_FW_REJECT)
+                       res = FLOWR_SELECT;
+               else
+                       res = FLOWR_CLEAR;
+               break;
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+               res = ip6_fw_accept_trans(rl, args);
+               break;
+       case IPPROTO_ICMPV6:
+       };
+
+       return res;
+}
+
+static struct dst_entry * ip6_fw_dup(struct dst_entry *frule,
+                                    struct dst_entry *rt,
+                                    struct fl_acc_args *args)
+{
+       struct ip6_fw_rule *rl;
+       struct rt6_info *nrt;
+       struct rt6_info *frt;
+
+       frt = (struct rt6_info *) frule;
+
+       rl = (struct ip6_fw_rule *) frt->rt6i_flowr;
+
+       nrt = ip6_rt_copy((struct rt6_info *) rt);
+
+       if (nrt) {
+               nrt->u.dst.input = frule->input;
+               nrt->u.dst.output = frule->output;
+
+               nrt->rt6i_flowr = flow_clone(frt->rt6i_flowr);
+
+               nrt->rt6i_flags |= RTF_CACHE;
+               nrt->rt6i_tstamp = jiffies;
+       }
+
+       return (struct dst_entry *) nrt;
+}
+
+int ip6_fw_reject(struct sk_buff *skb)
+{
+#if IP6_FW_DEBUG >= 1
+       printk(KERN_DEBUG "packet rejected: \n");
+#endif
+
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0,
+                   skb->dev);
+       /*
+        *      send it via netlink, as (rule, skb)
+        */
+
+       kfree_skb(skb, FREE_READ);
+       return 0;
+}
+
+int ip6_fw_discard(struct sk_buff *skb)
+{
+       printk(KERN_DEBUG "ip6_fw: BUG fw_reject called\n");
+       kfree_skb(skb, FREE_READ);
+       return 0;
+}
+
+int ip6_fw_msg_add(struct ip6_fw_msg *msg)
+{
+       struct in6_rtmsg rtmsg;
+       struct ip6_fw_rule *rl;
+       struct rt6_info *rt;
+       int err;
+
+       ipv6_addr_copy(&rtmsg.rtmsg_dst, &msg->dst);
+       ipv6_addr_copy(&rtmsg.rtmsg_src, &msg->src);
+       rtmsg.rtmsg_dst_len = msg->dst_len;
+       rtmsg.rtmsg_src_len = msg->src_len;
+       rtmsg.rtmsg_metric = IP6_RT_PRIO_FW;
+
+       rl = ip6_fwrule_alloc();
+
+       if (rl == NULL)
+               return -ENOMEM;
+
+       rl->policy = msg->policy;
+       rl->info.proto = msg->proto;
+       rl->info.uli_u.data = msg->u.data;
+
+       rtmsg.rtmsg_flags = RTF_NONEXTHOP|RTF_POLICY;
+       rt = ip6_route_add(&rtmsg, &err);
+
+       if (rt == NULL) {
+               ip6_fwrule_free(rl);
+               return -ENOMEM;
+       }
+
+       rt->u.dst.error = -EPERM;
+
+       if (msg->policy == IP6_FW_ACCEPT) {
+               /*
+                *      Accept rules are never selected
+                *      (i.e. packets use normal forwarding)
+                */
+               rt->u.dst.input = ip6_fw_discard;
+               rt->u.dst.output = ip6_fw_discard;
+       } else {
+               rt->u.dst.input = ip6_fw_reject;
+               rt->u.dst.output = ip6_fw_reject;
+       }
+
+       ip6_rule_add(rl);
+
+       rt->rt6i_flowr = flow_clone((struct flow_rule *)rl);
+
+       return 0;
+}
+
+static int ip6_fw_msgrcv(int unit, struct sk_buff *skb)
+{
+       int count = 0;
+
+       while (skb->len) {
+               struct ip6_fw_msg *msg;
+
+               if (skb->len < sizeof(struct ip6_fw_msg)) {
+                       count = -EINVAL;
+                       break;
+               }
+
+               msg = (struct ip6_fw_msg *) skb->data;
+               skb_pull(skb, sizeof(struct ip6_fw_msg));
+               count += sizeof(struct ip6_fw_msg);
+
+               switch (msg->action) {
+               case IP6_FW_MSG_ADD:
+                       ip6_fw_msg_add(msg);
+                       break;
+               case IP6_FW_MSG_DEL:
+                       break;
+               default:
+                       return -EINVAL;
+               };
+       }
+
+       return count;
+}
+
+static void ip6_fw_destroy(struct flow_rule *rl)
+{
+       ip6_fwrule_free((struct ip6_fw_rule *)rl);
+}
+
+#ifdef MODULE
+#define ip6_fw_init module_init
+#endif
+
+void ip6_fw_init(void)
+{
+       netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
+}
+
+#ifdef MODULE
+void module_cleanup(void)
+{
+       netlink_detach(NETLINK_IP6_FW);
+}
+#endif
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
new file mode 100644 (file)
index 0000000..c5e2141
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ *     IPv6 input
+ *     Linux INET6 implementation 
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>
+ *     Ian P. Morris           <I.P.Morris@soton.ac.uk>
+ *
+ *     $Id: ip6_input.c,v 1.4 1997/03/18 18:24:35 davem Exp $
+ *
+ *     Based in linux/net/ipv4/ip_input.c
+ *
+ *     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/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/sched.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/transp_v6.h>
+#include <net/rawv6.h>
+#include <net/ndisc.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev,
+                        __u8 *nhptr, struct ipv6_options *opt);
+
+struct hdrtype_proc {
+       u8      type;
+       int     (*func) (struct sk_buff **, struct device *dev, __u8 *ptr,
+                        struct ipv6_options *opt);
+} hdrproc_lst[] = {
+
+  /*
+       TODO
+
+       {NEXTHDR_HOP,           ipv6_hop_by_hop}
+       {NEXTHDR_ROUTING,       ipv6_routing_header},
+   */
+       {NEXTHDR_FRAGMENT,      ipv6_reassembly},
+  
+       {NEXTHDR_DEST,          ipv6_dest_opt},
+   /*  
+       {NEXTHDR_AUTH,          ipv6_auth_hdr},
+       {NEXTHDR_ESP,           ipv6_esp_hdr},
+    */
+       {NEXTHDR_MAX,           NULL}
+};
+
+/* New header structures */
+
+
+struct ipv6_tlvtype {
+       u8 type;
+       u8 len;
+};
+
+struct ipv6_destopt_hdr {
+       u8 nexthdr;
+       u8 hdrlen;
+};
+
+
+struct tlvtype_proc {
+       u8      type;
+       int     (*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
+                        struct ipv6_options *opt);
+       /*
+        *      these functions do NOT update skb->h.raw
+        */
+
+} tlvprocdestopt_lst[] = {
+       {255,                   NULL}
+};
+
+static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr)
+{
+       struct in6_addr *daddr;
+       int pos;
+
+       /*
+        *      unkown destination option type
+        */
+       
+       pos = (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw;
+       
+       /* I think this is correct please check - IPM */
+
+       switch ((hdr->type & 0xC0) >> 6) {
+       case 0: /* ignore */
+               skb->h.raw += hdr->len+2;
+               return 1;
+               
+       case 1: /* drop packet */
+               break;
+
+       case 2: /* send ICMP PARM PROB regardless and drop packet */
+               icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_UNK_OPTION,
+                           pos, skb->dev);
+               break;
+               
+       case 3: /* Send ICMP if not a multicast address and drop packet */
+               daddr = &skb->nh.ipv6h->daddr;
+               if (!(ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST))
+                       icmpv6_send(skb, ICMPV6_PARAMPROB,
+                                   ICMPV6_UNK_OPTION, pos, skb->dev);
+       };
+       
+       kfree_skb(skb, FREE_READ);
+       return 0;
+}
+
+static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
+                        struct device *dev, __u8 *nhptr,
+                        struct ipv6_options *opt, void *lastopt)
+{
+       struct ipv6_tlvtype *hdr;
+       struct tlvtype_proc *curr;
+
+       while ((hdr=(struct ipv6_tlvtype *)skb->h.raw) != lastopt) {
+               switch (hdr->type & 0x3F) {             
+               case 0: /* TLV encoded Pad1 */
+                       skb->h.raw++;
+                       break;
+
+               case 1: /* TLV encoded PadN */
+                       skb->h.raw += hdr->len+2;
+                       break;
+
+               default: /* Other TLV code so scan list */
+                       for (curr=procs; curr->type != 255; curr++) {
+                               if (curr->type == (hdr->type & 0x3F)) {
+                                       curr->func(skb, dev, nhptr, opt);
+                                       skb->h.raw += hdr->len+2;
+                                       break;
+                               }
+                       }
+                       if (curr->type==255) {
+                               if (ip6_dstopt_unknown(skb, hdr) == 0)
+                                       return 0;
+                       }
+                       break;
+               }
+       }
+       return 1;
+}
+
+static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev,
+                        __u8 *nhptr, struct ipv6_options *opt)
+{
+       struct sk_buff *skb=*skb_ptr;
+       struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
+       int res = 0;
+
+       if (ip6_parse_tlv(tlvprocdestopt_lst, skb, dev, nhptr, opt,
+                         skb->h.raw+hdr->hdrlen))
+               res = hdr->nexthdr;
+
+       return res;
+}
+
+
+int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+       struct ipv6hdr *hdr;
+       int pkt_len;
+
+       if (skb->pkt_type == PACKET_OTHERHOST) {
+               kfree_skb(skb, FREE_READ);
+               return 0;
+       }
+
+       hdr = skb->nh.ipv6h;
+
+       if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6)
+               goto err;
+
+       pkt_len = ntohs(hdr->payload_len);
+
+       if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
+               goto err;
+
+       skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
+
+       ip6_route_input(skb);
+       
+       return 0;
+err:
+       ipv6_statistics.Ip6InHdrErrors++;
+       kfree_skb(skb, FREE_READ);
+       return 0;
+}
+
+/*
+ *     0 - deliver
+ *     1 - block
+ */
+static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
+{
+       struct icmp6hdr *icmph;
+       struct raw6_opt *opt;
+
+       opt = &sk->tp_pinfo.tp_raw;
+       icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1);
+       return test_bit(icmph->icmp6_type, &opt->filter);
+}
+
+/*
+ *     demultiplex raw sockets.
+ *     (should consider queueing the skb in the sock receive_queue
+ *     without calling rawv6.c)
+ */
+static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
+                                     struct ipv6_options *opt,
+                                     int nexthdr, int len)
+{
+       struct in6_addr *saddr;
+       struct in6_addr *daddr;
+       struct sock *sk, *sk2;
+       __u8 hash;
+
+       saddr = &skb->nh.ipv6h->saddr;
+       daddr = saddr + 1;
+
+       hash = nexthdr & (MAX_INET_PROTOS - 1);
+
+       sk = raw_v6_htable[hash];
+
+       /*
+        *      The first socket found will be delivered after
+        *      delivery to transport protocols.
+        */
+
+       if (sk == NULL)
+               return NULL;
+
+       sk = raw_v6_lookup(sk, nexthdr, daddr, saddr);
+
+       if (sk) {
+               sk2 = sk;
+
+               while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {
+                       struct sk_buff *buff;
+
+                       if (nexthdr == IPPROTO_ICMPV6 &&
+                           icmpv6_filter(sk2, skb))
+                               continue;
+
+                       buff = skb_clone(skb, GFP_ATOMIC);
+                       buff->sk = sk2;
+                       rawv6_rcv(buff, skb->dev, saddr, daddr, opt, len);
+               }
+       }
+
+       if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
+               sk = NULL;
+
+       return sk;
+}
+
+/*
+ *     Deliver the packet to the host
+ */
+
+int ip6_input(struct sk_buff *skb)
+{
+       struct ipv6_options *opt = (struct ipv6_options *) skb->cb;
+       struct ipv6hdr *hdr = skb->nh.ipv6h;
+       struct inet6_protocol *ipprot;
+       struct hdrtype_proc *hdrt;
+       struct sock *raw_sk;
+       __u8 *nhptr;
+       int nexthdr;
+       int found = 0;
+       u8 hash;
+       int len;
+       
+       skb->h.raw += sizeof(struct ipv6hdr);
+
+       /*
+        *      Parse extension headers
+        */
+
+       nexthdr = hdr->nexthdr;
+       nhptr = &hdr->nexthdr;
+
+       /*
+        *      check for extension headers
+        */
+
+st_loop:
+
+       for (hdrt=hdrproc_lst; hdrt->type != NEXTHDR_MAX; hdrt++) {
+               if (hdrt->type == nexthdr) {
+                       if ((nexthdr = hdrt->func(&skb, skb->dev, nhptr, opt))) {
+                               nhptr = skb->h.raw;
+                               hdr = skb->nh.ipv6h;
+                               goto st_loop;
+                       }
+                       return 0;
+               }
+       }
+
+       len = skb->tail - skb->h.raw;
+
+       raw_sk = ipv6_raw_deliver(skb, opt, nexthdr, len);
+
+       hash = nexthdr & (MAX_INET_PROTOS - 1);
+       for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
+            ipprot != NULL; 
+            ipprot = (struct inet6_protocol *) ipprot->next) {
+               struct sk_buff *buff = skb;
+               
+               if (ipprot->protocol != nexthdr)
+                       continue;
+               
+               if (ipprot->copy || raw_sk)
+                       buff = skb_clone(skb, GFP_ATOMIC);
+               
+               
+               ipprot->handler(buff, skb->dev, &hdr->saddr, &hdr->daddr,
+                               opt, len, 0, ipprot);
+               found = 1;
+       }
+       
+       if (raw_sk) {
+               skb->sk = raw_sk;
+               rawv6_rcv(skb, skb->dev, &hdr->saddr, &hdr->daddr, opt, len);
+               found = 1;
+       }
+       
+       /*
+        *      not found: send ICMP parameter problem back
+        */
+       
+       if (!found) {
+               unsigned long offset;
+#if IP6_DEBUG >= 2
+               printk(KERN_DEBUG "proto not found %d\n", nexthdr);
+#endif
+               offset = nhptr - (u8*) hdr;
+               icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_UNK_NEXTHDR,
+                           offset, skb->dev);
+               kfree_skb(skb, FREE_READ);
+       }
+
+       return 0;
+}
+
+int ip6_mc_input(struct sk_buff *skb)
+{
+       struct ipv6hdr *hdr;    
+       int deliver = 0;
+       int discard = 1;
+
+       hdr = skb->nh.ipv6h;
+       if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
+               deliver = 1;
+
+#if 0
+       if (ipv6_config.multicast_route) {
+               int addr_type;
+
+               addr_type = ipv6_addr_type(&hdr->daddr);
+
+               if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) {
+                       struct sk_buff *skb2;
+                       struct dst_entry *dst;
+
+                       dst = skb->dst;
+                       
+                       if (deliver) {
+                               skb2 = skb_clone(skb, GFP_ATOMIC);
+                       } else {
+                               discard = 0;
+                               skb2 = skb;
+                       }
+
+                       dst->output(skb2);
+               }
+       }
+#endif
+
+       if (deliver) {
+               discard = 0;
+               ip6_input(skb);
+       }
+
+       if (discard)
+               kfree_skb(skb, FREE_READ);
+
+       return 0;
+}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
new file mode 100644 (file)
index 0000000..6c14747
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ *     IPv6 output functions
+ *     Linux INET6 implementation 
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *
+ *     $Id: ip6_output.c,v 1.3 1997/03/18 18:24:37 davem Exp $
+ *
+ *     Based on linux/net/ipv4/ip_output.c
+ *
+ *     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/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/in6.h>
+#include <linux/route.h>
+
+#include <net/sock.h>
+#include <net/snmp.h>
+
+#include <net/ipv6.h>
+#include <net/ndisc.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+static u32     ipv6_fragmentation_id = 1;
+
+static void ipv6_build_mac_hdr(struct sk_buff *skb, struct dst_entry *dst,
+                              int len)
+{
+       struct device *dev;
+       
+       
+       dev = dst->dev;
+
+       skb->arp = 1;
+       
+       if (dev->hard_header) {
+               int mac;
+               
+#if 0
+               if (dst->hh)
+                       hh_copy_header(dst->hh, skb);
+#endif
+               mac = dev->hard_header(skb, dev, ETH_P_IPV6, NULL, NULL, len);
+
+               if (mac < 0)
+                       skb->arp = 0;
+       }
+       
+       skb->mac.raw = skb->data;
+}
+
+/*
+ *     xmit an sk_buff (used by TCP)
+ *     sk can be NULL (for sending RESETs)
+ */
+
+int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+            struct ipv6_options *opt)
+{
+       struct ipv6_pinfo *np = NULL;
+       struct dst_entry *dst = NULL;
+       struct ipv6hdr *hdr;
+       int seg_len;
+
+       hdr = skb->nh.ipv6h;
+
+       if (sk)
+               np = &sk->net_pinfo.af_inet6;
+
+       if (np && np->dst) {
+               /*
+                *      dst_check returns NULL if route is no longer valid
+                */
+               dst = dst_check(&dst, np->dst_cookie);
+       }
+
+       if (dst == NULL) {
+               dst = ip6_route_output(sk, fl);
+
+               if (dst->error) {
+                       /*
+                        *      NETUNREACH usually
+                        */
+                       return dst->error;
+               }
+       }
+
+       skb->dst = dst_clone(dst);
+       skb->dev = dst->dev;
+       seg_len = skb->tail - ((unsigned char *) hdr);
+       
+       /*
+        *      Link Layer headers
+        */
+
+       skb->protocol = __constant_htons(ETH_P_IPV6);
+       hdr = skb->nh.ipv6h;
+
+       ipv6_build_mac_hdr(skb, dst, seg_len);
+
+       
+       /*
+        *      Fill in the IPv6 header
+        */
+
+       hdr->version = 6;
+       hdr->priority = np ? np->priority : 0;
+
+       if (np)
+               memcpy(hdr->flow_lbl, (void *) &np->flow_lbl, 3);
+       else
+               memset(hdr->flow_lbl, 0, 3);
+
+       hdr->payload_len = htons(seg_len - sizeof(struct ipv6hdr));
+       hdr->nexthdr = fl->proto;
+       hdr->hop_limit = np ? np->hop_limit : ipv6_config.hop_limit;
+       
+       ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
+       ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr);
+
+       ipv6_statistics.Ip6OutRequests++;
+       dst->output(skb);
+
+       if (sk)
+               ip6_dst_store(sk, dst);
+       else
+               dst_release(dst);
+
+       return 0;
+}
+
+/*
+ *     To avoid extra problems ND packets are send through this
+ *     routine. It's code duplication but i really want to avoid
+ *     extra checks since ipv6_build_header is used by TCP (which
+ *     is for us performace critical)
+ */
+
+int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct device *dev,
+              struct in6_addr *saddr, struct in6_addr *daddr,
+              int proto, int len)
+{
+       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+       struct ipv6hdr *hdr;
+       int totlen;
+
+       skb->protocol = __constant_htons(ETH_P_IPV6);
+       skb->dev = dev;
+
+       totlen = len + sizeof(struct ipv6hdr);
+
+       skb->mac.raw = skb->data;
+
+       hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
+       skb->nh.ipv6h = hdr;
+
+       hdr->version  = 6;
+       hdr->priority = np->priority & 0x0f;
+       memset(hdr->flow_lbl, 0, 3);
+
+       hdr->payload_len = htons(len);
+       hdr->nexthdr = proto;
+       hdr->hop_limit = np->hop_limit;
+
+       ipv6_addr_copy(&hdr->saddr, saddr);
+       ipv6_addr_copy(&hdr->daddr, daddr);
+
+       return 0;
+}
+
+static void ip6_bld_1(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
+                     int hlimit, unsigned short pktlength)
+{
+       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+       struct ipv6hdr *hdr;
+       
+       skb->nh.raw = skb_put(skb, sizeof(struct ipv6hdr));
+       hdr = skb->nh.ipv6h;
+       
+       hdr->version = 6;
+       hdr->priority = np->priority;
+       
+       memcpy(hdr->flow_lbl, &np->flow_lbl, 3);
+       
+       hdr->payload_len = htons(pktlength - sizeof(struct ipv6hdr));
+
+       /*
+        *      FIXME: hop limit has default UNI/MCAST and
+        *      msgctl settings
+        */
+       hdr->hop_limit = hlimit;
+
+       ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
+       ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr);      
+}
+
+static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
+                        const void *data, struct dst_entry *dst,
+                        struct flowi *fl, struct ipv6_options *opt,
+                        int hlimit, int flags, unsigned short length)
+{
+       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+       struct ipv6hdr *hdr;
+       struct sk_buff *last_skb;
+       struct frag_hdr *fhdr;
+       int unfrag_len;
+       int payl_len;
+       int frag_len;
+       int last_len;
+       int nfrags;
+       int fhdr_dist;
+       int err;
+
+       /*
+        *      Fragmentation
+        *
+        *      Extension header order:
+        *      Hop-by-hop -> Routing -> Fragment -> rest (...)
+        *      
+        *      We must build the non-fragmented part that
+        *      will be in every packet... this also means
+        *      that other extension headers (Dest, Auth, etc)
+        *      must be considered in the data to be fragmented
+        */
+
+       unfrag_len = sizeof(struct ipv6hdr) + sizeof(struct frag_hdr);
+       payl_len = length;
+
+       if (opt) {
+               unfrag_len += opt->opt_nflen;
+               payl_len += opt->opt_flen;
+       }
+
+       nfrags = payl_len / ((dst->pmtu - unfrag_len) & ~0x7);
+
+       /*
+        *      Length of fragmented part on every packet but 
+        *      the last must be an:
+        *      "integer multiple of 8 octects".
+        */
+
+       frag_len = (dst->pmtu - unfrag_len) & ~0x7;
+
+       /*
+        *      We must send from end to start because of 
+        *      UDP/ICMP checksums. We do a funny trick:
+        *      fill the last skb first with the fixed
+        *      header (and its data) and then use it
+        *      to create the following segments and send it
+        *      in the end. If the peer is checking the M_flag
+        *      to trigger the reassembly code then this 
+        *      might be a good idea.
+        */
+
+       last_len = payl_len - (nfrags * frag_len);
+
+       if (last_len == 0) {
+               last_len = frag_len;
+               nfrags--;
+       }
+               
+       last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len +
+                                      dst->dev->hard_header_len + 15,
+                                      0, flags & MSG_DONTWAIT, &err);
+
+       if (last_skb == NULL)
+               return err;
+
+       last_skb->dst = dst_clone(dst);
+       last_skb->dev = dst->dev;
+       last_skb->protocol = htons(ETH_P_IPV6);
+       last_skb->when = jiffies;
+       last_skb->arp = 0;
+
+       /* 
+        * build the mac header... 
+        */
+       if (dst->dev->hard_header_len) {
+               skb_reserve(last_skb, (dst->dev->hard_header_len + 15) & ~15);
+               ipv6_build_mac_hdr(last_skb, dst, unfrag_len + frag_len);
+       }
+       
+       hdr = (struct ipv6hdr *) skb_put(last_skb, sizeof(struct ipv6hdr));
+       last_skb->nh.ipv6h = hdr;
+
+       hdr->version = 6;
+       hdr->priority = np->priority;
+       
+       memcpy(hdr->flow_lbl, &np->flow_lbl, 3);
+       hdr->payload_len = htons(unfrag_len + frag_len - sizeof(struct ipv6hdr));
+
+       hdr->hop_limit = hlimit;
+
+       hdr->nexthdr = NEXTHDR_FRAGMENT;
+
+       ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
+       ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr);
+
+#if 0
+       if (opt && opt->srcrt) {
+               hdr->nexthdr = ipv6opt_bld_rthdr(last_skb, opt, daddr,
+                                                NEXTHDR_FRAGMENT);
+       }
+#endif
+
+       fhdr = (struct frag_hdr *) skb_put(last_skb, sizeof(struct frag_hdr));
+       memset(fhdr, 0, sizeof(struct frag_hdr));
+
+       fhdr->nexthdr  = fl->proto;             
+       fhdr->frag_off = ntohs(nfrags * frag_len);
+       fhdr->identification = ipv6_fragmentation_id++;
+
+       fhdr_dist = (unsigned char *) fhdr - last_skb->data;
+
+       err = getfrag(data, &hdr->saddr, last_skb->tail, nfrags * frag_len,
+                     last_len);
+
+       if (!err) {
+               while (nfrags--) {
+                       struct sk_buff *skb;
+                       
+                       struct frag_hdr *fhdr2;
+                               
+                       printk(KERN_DEBUG "sending frag %d\n", nfrags);
+                       skb = skb_copy(last_skb, sk->allocation);
+
+                       if (skb == NULL)
+                               return -ENOMEM;
+                       
+                       fhdr2 = (struct frag_hdr *) (skb->data + fhdr_dist);
+
+                       /* more flag on */
+                       fhdr2->frag_off = ntohs(nfrags * frag_len + 1);
+
+                       /*
+                        *      FIXME:
+                        *      if (nfrags == 0)
+                        *      put rest of headers
+                        */
+
+                       err = getfrag(data, &hdr->saddr,skb_put(skb, frag_len),
+                                     nfrags * frag_len, frag_len);
+
+                       if (err) {
+                               kfree_skb(skb, FREE_WRITE);
+                               break;
+                       }
+
+                       ipv6_statistics.Ip6OutRequests++;
+                       dst->output(skb);
+               }
+       }
+
+       if (err) {
+               kfree_skb(last_skb, FREE_WRITE);
+               return -EFAULT;
+       }
+
+       printk(KERN_DEBUG "sending last frag \n");
+
+       hdr->payload_len = htons(unfrag_len + last_len - 
+                                sizeof(struct ipv6hdr));
+
+       /*
+        *      update last_skb to reflect the getfrag we did
+        *      on start.
+        */
+       
+       last_skb->tail += last_len;
+       last_skb->len += last_len;
+
+       /* 
+        *      toss the mac header out and rebuild it.
+        *      needed because of the different frame length.
+        *      ie: not needed for an ethernet.
+        */
+
+       if (dst->dev->type != ARPHRD_ETHER && last_len != frag_len) {
+               skb_pull(last_skb, (unsigned char *)last_skb->nh.ipv6h - 
+                        last_skb->data);
+               ipv6_build_mac_hdr(last_skb, dst, unfrag_len + last_len);
+       }
+
+       ipv6_statistics.Ip6OutRequests++;
+       dst->output(last_skb);
+
+       return 0;
+}
+
+int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
+                  struct flowi *fl, unsigned short length,
+                  struct ipv6_options *opt, int hlimit, int flags)
+{
+       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+       struct in6_addr *final_dst = NULL;
+       struct dst_entry *dst;
+       int pktlength;
+       int err = 0;
+       
+       if (opt && opt->srcrt) {
+               struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+               final_dst = fl->nl_u.ip6_u.daddr;
+               fl->nl_u.ip6_u.daddr = rt0->addr;
+       }
+
+       dst = NULL;
+       
+       if (np->dst)
+               dst = dst_check(&np->dst, np->dst_cookie);
+
+       if (dst == NULL)
+               dst = ip6_route_output(sk, fl);
+
+       if (dst->error) {
+               ipv6_statistics.Ip6OutNoRoutes++;
+               err = -ENETUNREACH;
+               goto out;
+       }
+
+       if (fl->nl_u.ip6_u.saddr == NULL) {
+               struct inet6_ifaddr *ifa;
+               
+               ifa = ipv6_get_saddr(dst, fl->nl_u.ip6_u.daddr);
+               
+               if (ifa == NULL) {
+#if IP6_DEBUG >= 2
+                       printk(KERN_DEBUG "ip6_build_xmit: "
+                              "no availiable source address\n");
+#endif
+                       err = -ENETUNREACH;
+                       goto out;
+               }
+               fl->nl_u.ip6_u.saddr = &ifa->addr;
+       }
+       
+       pktlength = length;
+
+       if (hlimit < 0)
+               hlimit = np->hop_limit;
+
+       if (!sk->ip_hdrincl) {
+               pktlength += sizeof(struct ipv6hdr);
+               if (opt)
+                       pktlength += opt->opt_flen + opt->opt_nflen;
+       }
+
+       if (pktlength <= dst->pmtu) {
+               struct sk_buff *skb;
+               struct ipv6hdr *hdr;
+               struct device *dev;
+
+               skb = sock_alloc_send_skb(sk, pktlength + 15 +
+                                         dst->dev->hard_header_len, 0,
+                                         flags & MSG_DONTWAIT, &err);
+
+               if (skb == NULL) {
+                       ipv6_statistics.Ip6OutDiscards++;
+                       goto out;
+               }
+
+               dev = dst->dev;
+               skb->dst = dst_clone(dst);
+
+               skb->dev = dev;
+               skb->protocol = htons(ETH_P_IPV6);
+               skb->when = jiffies;
+               skb->arp = 0;
+
+               if (dev && dev->hard_header_len) {
+                       skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+                       ipv6_build_mac_hdr(skb, dst, pktlength);
+               }
+
+               hdr = (struct ipv6hdr *) skb->tail;
+               skb->nh.ipv6h = hdr;
+               
+               if (!sk->ip_hdrincl) {
+                       ip6_bld_1(sk, skb, fl, hlimit, pktlength);
+#if 0
+                       if (opt && opt->srcrt) {
+                               hdr->nexthdr = ipv6opt_bld_rthdr(skb, opt,
+                                                                final_dst,
+                                                                fl->proto);
+                       }
+                       else
+#endif
+                               hdr->nexthdr = fl->proto;
+               }
+
+               skb_put(skb, length);
+               err = getfrag(data, &hdr->saddr,
+                             ((char *) hdr) + (pktlength - length),
+                             0, length);
+               
+               if (!err) {
+                       ipv6_statistics.Ip6OutRequests++;
+                       dst->output(skb);
+               } else {
+                       err = -EFAULT;
+                       kfree_skb(skb, FREE_WRITE);
+               }
+       } else {
+               if (sk->ip_hdrincl)
+                       return -EMSGSIZE;
+               
+               err = ip6_frag_xmit(sk, getfrag, data, dst, fl, opt, hlimit,
+                                   flags, pktlength);
+       }
+       
+       /*
+        *      cleanup
+        */
+  out:
+       
+       if (np->dst)
+               ip6_dst_store(sk, dst);
+       else
+               dst_release(dst);
+
+       return err;
+}
+
+int ip6_forward(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb->dst;
+       struct ipv6hdr *hdr = skb->nh.ipv6h;
+       int size;
+       
+       /*
+        *      check hop-by-hop options present
+        */
+#if 0
+       if (hdr->nexthdr == NEXTHDR_HOP)
+       {
+       }
+#endif
+       /*
+        *      check and decrement ttl
+        */
+       if (hdr->hop_limit <= 1) {
+               icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
+                           0, skb->dev);
+
+               kfree_skb(skb, FREE_READ);
+               return -ETIMEDOUT;
+       }
+
+       hdr->hop_limit--;
+
+       if (skb->dev == dst->dev && dst->neighbour) {
+               struct in6_addr *target = NULL;
+               struct rt6_info *rt;
+               struct nd_neigh *ndn = (struct nd_neigh *) dst->neighbour;
+
+               /*
+                *      incoming and outgoing devices are the same
+                *      send a redirect.
+                */
+
+               rt = (struct rt6_info *) dst;
+               if ((rt->rt6i_flags & RTF_GATEWAY))
+                       target = &ndn->ndn_addr;
+               else
+                       target = &hdr->daddr;
+
+               ndisc_send_redirect(skb, dst->neighbour, target);
+       }
+       
+       size = sizeof(struct ipv6hdr) + ntohs(hdr->payload_len);
+
+       if (size > dst->pmtu) {
+               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
+               kfree_skb(skb, FREE_READ);
+               return -EMSGSIZE;
+       }
+
+       skb->dev = dst->dev;
+
+       /*
+        *      Rebuild the mac header
+        */
+       if (skb_headroom(skb) < dst->dev->hard_header_len) {
+               struct sk_buff *buff;
+
+               buff = alloc_skb(dst->dev->hard_header_len + skb->len + 15,
+                                GFP_ATOMIC);
+
+               if (buff == NULL) {
+                       kfree_skb(skb, FREE_WRITE);
+                       return -ENOMEM;
+               }
+               
+               skb_reserve(buff, (dst->dev->hard_header_len + 15) & ~15);
+
+               buff->protocol = __constant_htons(ETH_P_IPV6);
+               buff->h.raw = skb_put(buff, size);
+               buff->dst = dst_clone(dst);
+               buff->dev = dst->dev;
+
+               memcpy(buff->h.raw, hdr, size);
+               buff->nh.ipv6h = (struct ipv6hdr *) buff->h.raw;
+               kfree_skb(skb, FREE_READ);
+               skb = buff;
+       } else {
+               skb_pull(skb, skb->nh.raw - skb->data);
+       }
+
+       ipv6_build_mac_hdr(skb, dst, size);
+
+       if (dst->neighbour)
+               ndisc_event_send(dst->neighbour, skb);
+
+       ipv6_statistics.Ip6ForwDatagrams++;
+       dst->output(skb);
+
+       return 0;
+}
diff --git a/net/ipv6/ipv6_input.c b/net/ipv6/ipv6_input.c
deleted file mode 100644 (file)
index c5e9992..0000000
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- *     IPv6 input
- *     Linux INET6 implementation 
- *
- *     Authors:
- *     Pedro Roque             <roque@di.fc.ul.pt>
- *     Ian P. Morris           <I.P.Morris@soton.ac.uk>
- *
- *     Based in linux/net/ipv4/ip_input.c
- *
- *     $Id: ipv6_input.c,v 1.4 1997/02/28 09:56:33 davem Exp $
- *
- *     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/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/sched.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/in6.h>
-#include <linux/icmpv6.h>
-
-#include <net/sock.h>
-#include <net/snmp.h>
-
-#include <net/ipv6.h>
-#include <net/protocol.h>
-#include <net/transp_v6.h>
-#include <net/rawv6.h>
-#include <net/ndisc.h>
-#include <net/ipv6_route.h>
-#include <net/addrconf.h>
-
-/*
- *     Header processing function list
- *     We process headers in order (as per RFC)
- *     If the processing function returns 0 the packet is considered 
- *     delivered else it returns the value of the nexthdr.
- *     The ptr field of the function points to the previous nexthdr field.
- *     This is allows the processing function to change it if it's sematics
- *     is: return a new packet without this header (like fragmentation).
- *     When a next_header value is not within the list 
- *     the inet protocol list is searched (i.e. to deliver to 
- *     TCP for instance)
- */
-
-static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev, __u8 *nhptr,
-                        struct ipv6_options *opt);
-
-
-struct hdrtype_proc {
-       u8      type;
-       int     (*func) (struct sk_buff **, struct device *dev, __u8 *ptr,
-                        struct ipv6_options *opt);
-} hdrproc_lst[] = {
-  /*
-       TODO
-
-       {NEXTHDR_HOP,           ipv6_hop_by_hop}
-   */
-       {NEXTHDR_ROUTING,       ipv6_routing_header},
-       {NEXTHDR_FRAGMENT,      ipv6_reassembly},
-  
-       {NEXTHDR_DEST,          ipv6_dest_opt},
-   /*  
-       {NEXTHDR_AUTH,          ipv6_auth_hdr},
-       {NEXTHDR_ESP,           ipv6_esp_hdr},
-    */
-       {NEXTHDR_MAX,           NULL}
-};
-
-/* New header structures */
-
-
-struct ipv6_tlvtype {
-       u8 type;
-       u8 len;
-};
-
-struct ipv6_destopt_hdr {
-       u8 nexthdr;
-       u8 hdrlen;
-};
-
-
-struct tlvtype_proc {
-       u8      type;
-       int     (*func) (struct sk_buff *, struct device *dev, __u8 *ptr,
-                        struct ipv6_options *opt); 
-       
-       /* these functions do NOT  update skb->h.raw */
-                        
-} tlvprocdestopt_lst[] = {
-       {255,                   NULL}
-};
-
-
-static int parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb,
-                    struct device *dev, __u8 *nhptr, struct ipv6_options *opt,
-                    void *lastopt)
-{
-       struct ipv6_tlvtype *hdr;
-       struct tlvtype_proc *curr;
-       int pos;
-
-       while ((hdr=(struct ipv6_tlvtype *)skb->h.raw) != lastopt)
-               switch (hdr->type & 0x3F)
-               {
-               case 0: /* TLV encoded Pad1 */
-                       skb->h.raw++;
-                       break;
-
-               case 1: /* TLV encoded PadN */
-                       skb->h.raw += hdr->len+2;
-                       break;
-
-               default: /* Other TLV code so scan list */
-                       for (curr=procs; curr->type != 255; curr++)
-                               if (curr->type == (hdr->type & 0x3F))
-                               {
-                                       curr->func(skb, dev, nhptr, opt);
-                                       skb->h.raw += hdr->len+2;
-                                       break;
-                               }
-               
-                       if (curr->type==255)
-                       { 
-                               /* unkown type */
-                               pos= (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw;
-                               /* I think this is correct please check - IPM */
-
-                               switch ((hdr->type & 0xC0) >> 6) {
-                                       case 0: /* ignore */
-                                               skb->h.raw += hdr->len+2;
-                                               break;
-                                               
-                                       case 1: /* drop packet */
-                                               kfree_skb(skb, FREE_READ);
-                                               return 0;
-
-                                       case 2: /* send ICMP PARM PROB regardless and 
-                                                  drop packet */
-                                               icmpv6_send(skb, ICMPV6_PARAMETER_PROB, 
-                                                           2, pos, dev);
-                                               kfree_skb(skb, FREE_READ);
-                                               return 0;
-
-                                       case 3: /* Send ICMP if not a multicast address 
-                                                  and drop packet */
-                                               if (!(ipv6_addr_type(&(skb->nh.ipv6h->daddr)) & IPV6_ADDR_MULTICAST) )
-                                                       icmpv6_send(skb, ICMPV6_PARAMETER_PROB, 2, pos, dev);
-                                               kfree_skb(skb, FREE_READ);
-                                               return 0;
-                                       }
-                       }
-                       break;
-               }
-       
-       return 1;
-}
-
-
-static int ipv6_dest_opt(struct sk_buff **skb_ptr, struct device *dev, __u8 *nhptr,
-                        struct ipv6_options *opt)
-{
-       struct sk_buff *skb=*skb_ptr;
-       struct ipv6_destopt_hdr *hdr = (struct ipv6_destopt_hdr *) skb->h.raw;
-       
-       if (parse_tlv(tlvprocdestopt_lst, skb, dev, nhptr, opt,skb->h.raw+hdr->hdrlen))
-               return hdr->nexthdr;
-       else
-               return 0;
-}
-
-
-
-/*
- *     0 - deliver
- *     1 - block
- */
-static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
-{
-       struct icmpv6hdr *icmph;
-       struct raw6_opt *opt;
-
-       opt = &sk->tp_pinfo.tp_raw;
-       icmph = (struct icmpv6hdr *) (skb->nh.ipv6h + 1);
-       return test_bit(icmph->type, &opt->filter);
-}
-
-/*
- *     demultiplex raw sockets.
- *     (should consider queueing the skb in the sock receive_queue
- *     without calling rawv6.c)
- */
-static struct sock * ipv6_raw_deliver(struct sk_buff *skb,
-                                     struct device *dev,
-                                     struct ipv6_options *opt,
-                                     __u16 nexthdr,
-                                     __u16 len,
-                                     struct in6_addr *saddr,
-                                     struct in6_addr *daddr)
-{
-       struct sock *sk, *sk2;
-       __u8 hash;
-
-       hash = nexthdr & (MAX_INET_PROTOS - 1);
-
-       sk = raw_v6_htable[hash];
-
-       /*
-        *      The first socket found will be delivered after
-        *      delivery to transport protocols.
-        */
-
-       if (sk == NULL)
-               return NULL;
-       
-       sk = raw_v6_lookup(sk, nexthdr, daddr, saddr);
-
-       if (sk)
-       {
-               sk2 = sk;
-
-               while ((sk2 = raw_v6_lookup(sk2->next, nexthdr, daddr, saddr)))
-               {
-                       struct sk_buff *buff;
-
-                       if (nexthdr == IPPROTO_ICMPV6 &&
-                           icmpv6_filter(sk2, skb))
-                       {
-                               continue;
-                       }
-                       buff = skb_clone(skb, GFP_ATOMIC);
-                       buff->sk = sk2;
-                       rawv6_rcv(buff, dev, saddr, daddr, opt, len);
-               }
-       }
-
-       if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))
-       {
-               sk = NULL;
-       }   
-       
-       return sk;
-}
-
-int ipv6_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
-       struct inet6_ifaddr     *ifp;
-       struct ipv6_options     *opt = (struct ipv6_options *) skb->cb;
-       struct ipv6hdr          *hdr;
-       u8                      hash;
-       u8                      addr_type;
-       struct inet6_protocol   *ipprot;
-       struct sock             *raw_sk;
-       int                     found = 0;
-       int                     nexthdr = 0;
-       __u8                    *nhptr;
-       int                     pkt_len;
-
-       if (skb->pkt_type == PACKET_OTHERHOST) {
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       hdr = skb->nh.ipv6h;
-       skb->h.raw = (__u8*)hdr;
-
-       if (skb->len < sizeof(struct ipv6hdr) || hdr->version != 6)
-       {
-               ipv6_statistics.Ip6InHdrErrors++;
-               printk(KERN_DEBUG "ipv6_rcv: broken header\n");
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       pkt_len = ntohs(hdr->payload_len);
-
-       if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
-       {
-               printk(KERN_DEBUG "ipv6_rcv: invalid payload length\n");
-               kfree_skb(skb, FREE_READ);
-               return 0;
-       }
-
-       skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
-
-       /* check daddr */
-
-       /* Accounting & Firewall check */
-
-       addr_type = ipv6_addr_type(&hdr->daddr);
-
-       if (addr_type & IPV6_ADDR_MULTICAST)
-       {
-               /* 
-                * if mcast address is not for one of our groups
-                * either pass it to mcast router or discard it 
-                */
-
-               if (ipv6_chk_mcast_addr(dev, &hdr->daddr) == 0)
-               {
-                       /* something like:
-                          if (acting_as_router)
-                               ipv6_mcast_route(skb, ...)
-                          else 
-                          */
-                       kfree_skb(skb, FREE_READ);
-                       return 0;
-               }
-       }
-
-       if (addr_type & IPV6_ADDR_MULTICAST ||
-           (ifp = ipv6_chk_addr(&hdr->daddr)))     
-       {
-
-               /* loop in a cicle parsing nexthdrs */
-
-               skb->h.raw   += sizeof(struct ipv6hdr);
-               /* extension header processing must update skb->h.raw */
-
-               nexthdr = hdr->nexthdr;
-               nhptr = &hdr->nexthdr;
-
-
-               while(1)
-               {
-                       struct hdrtype_proc *hdrt;
-
-                       /* check for extension header */
-
-                       for (hdrt=hdrproc_lst; hdrt->type != NEXTHDR_MAX; hdrt++)
-                       {
-                               if (hdrt->type == nexthdr)
-                               {
-                                       if ((nexthdr = hdrt->func(&skb, dev, nhptr, opt)))
-                                       {
-                                               nhptr = skb->h.raw;
-                                               hdr = skb->nh.ipv6h;
-                                               continue;
-                                       }
-                                       return 0;
-                               }
-                       }
-                       break;
-
-               }
-
-               /* 
-                * deliver to raw sockets
-                * should we deliver raw after or before parsing 
-                * extension headers ?
-                * delivering after means we do reassembly of datagrams
-                * in ip.
-                */
-
-               pkt_len = skb->tail - skb->h.raw;
-
-               raw_sk = ipv6_raw_deliver(skb, dev, opt, nexthdr, pkt_len,
-                                         &hdr->saddr, &hdr->daddr);
-
-               /* check inet6_protocol list */
-
-               hash = nexthdr & (MAX_INET_PROTOS -1);
-               for (ipprot = (struct inet6_protocol *) inet6_protos[hash]; 
-                    ipprot != NULL; 
-                    ipprot = (struct inet6_protocol *) ipprot->next)
-               {
-                       struct sk_buff *buff = skb;
-
-                       if (ipprot->protocol != nexthdr)
-                               continue;
-
-                       if (ipprot->copy || raw_sk)
-                               buff = skb_clone(skb, GFP_ATOMIC);
-
-
-                       ipprot->handler(buff, dev, 
-                                       &hdr->saddr, &hdr->daddr,
-                                       opt, pkt_len,
-                                       0, ipprot);
-                       found = 1;
-               }
-
-               if (raw_sk)
-               {
-                       skb->sk = raw_sk;
-                       rawv6_rcv(skb, dev, &hdr->saddr, &hdr->daddr, opt,
-                                 htons(hdr->payload_len));
-                       found = 1;
-               }
-              
-               /* not found: send ICMP parameter problem back */
-
-               if (!found)
-               {
-                       printk(KERN_DEBUG "proto not found %d\n", nexthdr);
-                       kfree_skb(skb, FREE_READ);
-               }
-                       
-       }
-       else
-       {
-               if (skb->pkt_type != PACKET_HOST) {
-                       kfree_skb(skb, FREE_READ);
-                       return 0;
-               }
-
-               if (ipv6_forwarding)
-               {
-                       if (addr_type & IPV6_ADDR_LINKLOCAL)
-                       {
-                               printk(KERN_DEBUG
-                                      "link local pkt to forward\n");
-                               kfree_skb(skb, FREE_READ);
-                               return 0;
-                       }
-                       ipv6_forward(skb, dev, 0);
-               }
-               else
-               {
-                       printk(KERN_WARNING "IPV6: packet to forward -"
-                              "host not configured as router\n");
-                       kfree_skb(skb, FREE_READ);
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Local variables:
- * c-file-style: "Linux"
- * End:
- */
diff --git a/net/ipv6/ipv6_output.c b/net/ipv6/ipv6_output.c
deleted file mode 100644 (file)
index de5e6df..0000000
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
- *     IPv6 output functions
- *     Linux INET6 implementation 
- *
- *     Authors:
- *     Pedro Roque             <roque@di.fc.ul.pt>     
- *
- *     Based on linux/net/ipv4/ip_output.c
- *
- *     $Id: ipv6_output.c,v 1.19 1996/10/16 18:34:16 roque Exp $
- *
- *     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.
- */
-
-/*
- *     Changes:
- *
- *     Andi Kleen              :       exception handling
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/sched.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-
-#include <net/sock.h>
-#include <net/snmp.h>
-
-#include <net/ipv6.h>
-#include <net/ndisc.h>
-#include <net/protocol.h>
-#include <net/transp_v6.h>
-#include <net/ipv6_route.h>
-#include <net/addrconf.h>
-
-static u32     ipv6_fragmentation_id = 1;
-int            ipv6_forwarding = 0;            /* default: host */
-
-static int __inline__ ipv6_build_mac_header(struct sk_buff *skb,
-                                           struct device *dev,
-                                           struct neighbour *neigh, 
-                                           int len)
-{
-       int mac;
-       int hdrlen = 0;
-
-       skb->arp = 1;
-       skb->nexthop = neigh;
-
-       skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-
-       if (dev->hard_header_len)
-       {
-
-               /*
-                *      FIXME: use cached hardware header if availiable
-                */
-               if (dev->hard_header)
-               {
-                       mac = dev->hard_header(skb, dev, ETH_P_IPV6, 
-                                              NULL, NULL, len);
-               
-                       if (mac < 0)
-                       {                               
-                               hdrlen = -mac;
-                               skb->arp = 0;
-                       }
-                       else
-                       {                               
-                               hdrlen = mac;
-                       }
-               }
-               else
-                       hdrlen = dev->hard_header_len;
-       }
-
-       skb->mac.raw = skb->data;
-       return hdrlen;
-}
-
-void ipv6_redo_mac_hdr(struct sk_buff *skb, struct neighbour *neigh, int len)
-{
-       struct device *dev = neigh->dev;
-       int mac;
-       
-       skb->dev = dev;
-       skb->nexthop = neigh;
-       skb->arp = 1;
-
-       skb_pull(skb, (unsigned char *) skb->nh.ipv6h - skb->data);
-
-       /*
-        *      neighbour cache should have the ether address
-        *      cached... use it
-        */ 
-
-       if (dev->hard_header)
-       {
-               /*
-                *      FIXME: use cached hardware header if availiable
-                */
-
-               mac = dev->hard_header(skb, dev, ETH_P_IPV6, 
-                                      NULL, NULL, len);
-               
-               if (mac < 0)
-               {                               
-                       skb->arp = 0;
-               }
-
-       }
-       skb->mac.raw = skb->data;
-}
-
-void default_output_method(struct sk_buff *skb, struct rt6_info *rt)
-{
-       struct sock *sk = skb->sk;
-       struct device *dev = skb->dev;
-
-       if (dev->flags & IFF_UP)
-       {
-               /*
-                *      If we have an owner use its priority setting,
-                *      otherwise use NORMAL
-                */
-
-               dev_queue_xmit(skb);
-       }
-       else
-       {
-               if(sk)
-                       sk->err = ENETDOWN;
-
-               ipv6_statistics.Ip6OutDiscards++;
-               
-               kfree_skb(skb, FREE_WRITE);
-       }
-}
-
-/*
- *     xmit an sk_buff (used by TCP)
- *     sk can be NULL (for sending RESETs)
- */
-int ipv6_xmit(struct sock *sk, struct sk_buff *skb, struct in6_addr *saddr,
-             struct in6_addr *daddr, struct ipv6_options *opt, int proto)
-{
-       struct ipv6hdr *hdr;
-       struct dest_entry *dc;
-       struct ipv6_pinfo *np = NULL;
-       struct device *dev = skb->dev;
-       int seg_len;
-       int addr_type;
-       int rt_flags = 0;
-
-
-       addr_type = ipv6_addr_type(daddr);
-
-       if (addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_SITELOCAL))
-       {
-               /*
-                *      force device match on route lookup
-                */
-               
-               rt_flags |= RTI_DEVRT;
-       }
-
-       if (sk && sk->localroute)
-               rt_flags |= RTI_GATEWAY;
-
-       hdr = skb->nh.ipv6h;
-       
-
-       if (sk)
-       {
-               np = &sk->net_pinfo.af_inet6;
-       }
-       
-       if (np && np->dest)
-       {
-               dc = ipv6_dst_check(np->dest, daddr, np->dc_sernum, rt_flags);
-       }
-       else
-       {
-               dc = ipv6_dst_route(daddr, dev, rt_flags);
-       }
-
-       if (dc == NULL)
-       {
-               ipv6_statistics.Ip6OutNoRoutes++;
-               return(-ENETUNREACH);
-       }
-
-       dev = dc->rt.rt_dev;
-       
-       if (saddr == NULL)
-       {
-               struct inet6_ifaddr *ifa;
-               
-               ifa = ipv6_get_saddr((struct rt6_info *) dc, daddr);
-               
-               if (ifa == NULL)
-               {
-                       printk(KERN_DEBUG 
-                              "ipv6_xmit: get_saddr failed\n");
-                       return -ENETUNREACH;
-               }
-               
-               saddr = &ifa->addr;
-               
-               if (np)
-               {
-                       ipv6_addr_copy(&np->saddr, saddr);
-               }
-       }
-
-       seg_len = skb->tail - ((unsigned char *) hdr);
-
-       /*
-        *      Link Layer headers
-        */
-
-       skb->protocol = __constant_htons(ETH_P_IPV6);
-       skb->dev = dev;
-       
-       ipv6_redo_mac_hdr(skb, dc->dc_nexthop, seg_len);
-       
-       /*
-        *      Fill in the IPv6 header
-        */
-
-       hdr->version = 6;
-       hdr->priority = np ? np->priority : 0;
-
-       if (np)
-               memcpy(hdr->flow_lbl, (void *) &np->flow_lbl, 3);
-       else
-               memset(hdr->flow_lbl, 0, 3);
-
-       hdr->payload_len = htons(seg_len - sizeof(struct ipv6hdr));
-       hdr->nexthdr = proto;
-       hdr->hop_limit = np ? np->hop_limit : ipv6_hop_limit;
-       
-       memcpy(&hdr->saddr, saddr, sizeof(struct in6_addr));
-       memcpy(&hdr->daddr, daddr, sizeof(struct in6_addr));
-
-       
-       /*
-        *      Options
-        */
-
-
-       /*
-        *      Output the packet
-        */
-
-       ipv6_statistics.Ip6OutRequests++;
-
-       if (dc->rt.rt_output_method)
-       {
-               (*dc->rt.rt_output_method)(skb, (struct rt6_info *) dc);
-       }
-       else
-               default_output_method(skb, (struct rt6_info *) dc);
-
-       /*
-        *      Update serial number of cached dest_entry or
-        *      release destination cache entry
-        */
-       
-       if (np)
-       {
-               np->dest = dc;
-               if (dc->rt.fib_node)
-               {
-                       np->dc_sernum = dc->rt.fib_node->fn_sernum;
-               }
-       }
-       else
-       {
-               ipv6_dst_unlock(dc);
-       }
-
-       return 0;
-}
-
-/*
- *     To avoid extra problems ND packets are send through this
- *     routine. It's code duplication but i really want to avoid
- *     extra checks since ipv6_build_header is used by TCP (which
- *     is for us performace critical)
- */
-
-int ipv6_bld_hdr_2(struct sock *sk, struct sk_buff *skb, struct device *dev,
-                  struct neighbour *neigh,
-                  struct in6_addr *saddr, struct in6_addr *daddr,
-                  int proto, int len)
-{
-       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-       struct ipv6hdr *hdr;
-       int hdrlen = 0;
-
-       skb->dev = dev;
-
-       /* build MAC header */
-       hdrlen += ipv6_build_mac_header(skb, dev, neigh, len);
-
-       /* build fixed IPv6 header */
-
-       if (proto == IPPROTO_RAW)
-               return hdrlen;
-
-       
-       hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
-       skb->nh.ipv6h = hdr;
-       
-       hdr->version  = 6;
-       hdr->priority = np->priority & 0x0f;
-
-       memset(hdr->flow_lbl, 0, 3);
-
-       hdr->hop_limit =  np->hop_limit;
-
-       if (saddr == NULL)
-       {
-               printk(KERN_DEBUG "bug: bld_hdr called with no saddr\n");
-               return -ENETUNREACH;
-       }
-
-       memcpy(&hdr->saddr, saddr, sizeof(struct in6_addr));
-       memcpy(&hdr->daddr, daddr, sizeof(struct in6_addr));
-       
-       hdrlen += sizeof(struct ipv6hdr);
-
-       hdr->nexthdr = proto;
-
-       return hdrlen;
-}
-
-void ipv6_queue_xmit(struct sock *sk, struct device *dev, struct sk_buff *skb,
-                    int free)
-{
-       struct ipv6hdr *hdr;
-       u32 seg_len;
-
-       hdr = skb->nh.ipv6h;
-       skb->protocol = __constant_htons(ETH_P_IPV6);
-
-       seg_len = skb->tail - ((unsigned char *) hdr);
-
-       hdr->payload_len = htons(seg_len - sizeof(struct ipv6hdr));
-
-       if (dev == NULL)
-       {
-               printk(KERN_DEBUG "ipv6_queue_xmit: unknown device\n");
-               return;
-       }
-
-       skb->dev = dev;
-       
-       ipv6_statistics.Ip6OutRequests++;
-
-
-       /*
-        *      Multicast loopback
-        */
-
-       if (dev->flags & IFF_UP)
-       {
-               /*
-                *      If we have an owner use its priority setting,
-                *      otherwise use NORMAL
-                */
-
-               dev_queue_xmit(skb);
-       }
-       else
-       {
-               if(sk)
-                       sk->err = ENETDOWN;
-
-               ipv6_statistics.Ip6OutDiscards++;
-
-               kfree_skb(skb, FREE_WRITE);
-       }
-
-}
-
-
-int ipv6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
-                   struct in6_addr *dest, unsigned short int length,
-                   struct in6_addr *saddr, struct device *dev,
-                   struct ipv6_options *opt, int proto, int hlimit,
-                   int noblock)
-{
-       rt6_output_method_t output_method = default_output_method;
-       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-       struct dest_entry *dc = NULL;
-       struct in6_addr *daddr = dest;
-       struct ipv6hdr *hdr;
-       struct neighbour *neigh;        
-       int     addr_type;
-       int     pktlength;
-       int     pmtu = 0;
-       int     rt_flags = 0;
-       int     error; 
-       
-       if (opt && opt->srcrt)
-       {
-               struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-               daddr = rt0->addr;
-       }
-
-       addr_type = ipv6_addr_type(daddr);
-       
-       if (hlimit < 1)
-       {
-               if (addr_type & IPV6_ADDR_MULTICAST)
-               {
-                       hlimit = np->mcast_hops;
-                       if (dev == NULL)
-                       {
-                               dev = np->mc_if;
-                       }
-               }
-               else
-                       hlimit = np->hop_limit;
-       }
-               
-       if (addr_type & (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_SITELOCAL |
-                        IPV6_ADDR_MULTICAST))
-       {
-               /*
-                *      force device match on route lookup
-                */
-               
-               rt_flags |= RTI_DEVRT;
-       }
-
-       if (sk->localroute)
-       {
-               rt_flags |= RTI_GATEWAY;
-       }
-
-       if (np->dest)
-       {
-               np->dest = ipv6_dst_check(np->dest, daddr, np->dc_sernum,
-                                         rt_flags);
-               
-               dc = np->dest;
-
-               if (dc && dc->rt.fib_node)
-               {
-                       np->dc_sernum = dc->rt.fib_node->fn_sernum;
-               }
-               else
-               {
-                       printk(KERN_WARNING "dc entry not in table\n");
-               }
-       }
-       else
-       {
-               dc = ipv6_dst_route(daddr, dev, rt_flags);
-       }
-
-       if (dc == NULL)
-       {
-               if ((addr_type & IPV6_ADDR_MULTICAST) && dev)
-               {
-                       neigh = NULL;
-                       pmtu = dev->mtu;
-               }
-               else
-               {
-                       ipv6_statistics.Ip6OutNoRoutes++;
-                       return(-ENETUNREACH);
-               }
-       }
-       else
-       {
-               neigh = dc->dc_nexthop;
-               dev = neigh->dev;
-
-               if (dc->rt.rt_output_method)
-               {
-                       output_method = dc->rt.rt_output_method;
-               }
-
-               if (dc->dc_flags & DCF_PMTU)
-                       pmtu = dc->dc_pmtu;
-               else
-                       pmtu = dev->mtu;
-       }
-
-
-       if (saddr == NULL)
-       {
-               struct inet6_ifaddr *ifa;
-
-               ifa = ipv6_get_saddr((struct rt6_info *) dc, daddr);
-
-               if (ifa == NULL)
-               {
-                       printk(KERN_DEBUG 
-                              "ipv6_build_xmit: get_saddr failed\n");
-                       return -ENETUNREACH;
-               }
-
-               saddr = &ifa->addr;
-       }
-
-       if (dc && np->dest == NULL)
-       {
-               ipv6_dst_unlock(dc);
-       }
-
-       pktlength = length;
-
-       if (!sk->ip_hdrincl)
-       { 
-               pktlength += sizeof(struct ipv6hdr);
-               if (opt)
-               {
-                       pktlength += opt->opt_flen + opt->opt_nflen;
-               }
-       }
-               
-
-       dev_lock_list();
-
-       /*
-        *      reminder: don't allow fragmentation for IPPROTO_RAW
-        */
-
-
-       if (pktlength <= pmtu) 
-       {
-               struct sk_buff *skb =
-                       sock_alloc_send_skb(sk, pktlength+15+
-                                           dev->hard_header_len,
-                                           0, noblock, &error);
-               
-               if (skb == NULL)
-               {
-                       ipv6_statistics.Ip6OutDiscards++;
-                       dev_unlock_list();
-                       return error;
-
-               }
-
-               skb->dev=dev;
-               skb->protocol = htons(ETH_P_IPV6);
-               skb->when=jiffies;
-               skb->arp=0;
-
-               /* build the mac header... */
-               ipv6_build_mac_header(skb, dev, neigh, pktlength);
-
-               hdr = (struct ipv6hdr *) skb->tail;
-               skb->nh.ipv6h = hdr;
-
-               if (!sk->ip_hdrincl)
-               {
-                       skb_put(skb, sizeof(struct ipv6hdr));
-
-                       hdr->version = 6;
-                       hdr->priority = np->priority;
-
-                       memcpy(hdr->flow_lbl, &np->flow_lbl, 3);
-
-                       hdr->payload_len = htons(pktlength - 
-                                                sizeof(struct ipv6hdr));
-                       
-                       hdr->hop_limit = hlimit;
-
-                       memcpy(&hdr->saddr, saddr, sizeof(struct in6_addr));
-                       memcpy(&hdr->daddr, daddr, sizeof(struct in6_addr));
-
-                       if (opt && opt->srcrt)
-                       {
-                               hdr->nexthdr = ipv6opt_bld_rthdr(skb, opt,
-                                                                dest, proto);
-                                                                
-                       }
-                       else
-                               hdr->nexthdr = proto;
-               }
-                       
-               skb_put(skb, length);
-               error = getfrag(data, &hdr->saddr,
-                               ((char *) hdr) + (pktlength - length),
-                               0, length);
-                       
-               if (!error) 
-               {
-                       ipv6_statistics.Ip6OutRequests++;
-                       (*output_method)(skb, (struct rt6_info *) dc);
-               } else
-               {
-                       error = -EFAULT;
-                       kfree_skb(skb, FREE_WRITE);                     
-               }
-
-               dev_unlock_list();
-               return error;
-       }
-       else
-       {
-               /*
-                *      Fragmentation
-                */
-
-               /*
-                *      Extension header order:
-                *      Hop-by-hop -> Routing -> Fragment -> rest (...)
-                *      
-                *      We must build the non-fragmented part that
-                *      will be in every packet... this also means
-                *      that other extension headers (Dest, Auth, etc)
-                *      must be considered in the data to be fragmented
-                */
-
-               struct sk_buff  *last_skb;
-               struct frag_hdr *fhdr;
-               int unfrag_len;
-               int payl_len;
-               int frag_len;
-               int last_len;
-               int nfrags;
-               int err;
-               int fhdr_dist;
-               __u32 id;
-
-               if (sk->ip_hdrincl)
-               {
-                       return -EMSGSIZE;
-               }
-
-               id = ipv6_fragmentation_id++;
-
-               unfrag_len = sizeof(struct ipv6hdr) + sizeof(struct frag_hdr);
-               payl_len = length;
-
-               if (opt)
-               {
-                       unfrag_len += opt->opt_nflen;
-                       payl_len += opt->opt_flen;
-               }
-
-               nfrags = payl_len / ((pmtu - unfrag_len) & ~0x7);
-
-               /* 
-                * Length of fragmented part on every packet but 
-                * the last must be an:
-                * "integer multiple of 8 octects".
-                */
-
-               frag_len = (pmtu - unfrag_len) & ~0x7;
-
-               /*
-                *      We must send from end to start because of 
-                *      UDP/ICMP checksums. We do a funny trick:
-                *      fill the last skb first with the fixed
-                *      header (and its data) and then use it
-                *      to create the following segments and send it
-                *      in the end. If the peer is checking the M_flag
-                *      to trigger the reassembly code then this 
-                *      might be a good idea.
-                */
-
-               last_len = payl_len - (nfrags * frag_len);
-
-               if (last_len == 0)
-               {
-                       last_len = frag_len;
-                       nfrags--;
-               }
-               
-               last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len +
-                                              dev->hard_header_len + 15,
-                                              0, noblock, &err);
-
-               if (last_skb == NULL)
-               {
-                       dev_unlock_list();
-                       return err;
-               }
-
-               last_skb->dev=dev;
-               last_skb->protocol = htons(ETH_P_IPV6);
-               last_skb->when=jiffies;
-               last_skb->arp=0;
-
-               /* 
-                * build the mac header... 
-                */
-               ipv6_build_mac_header(last_skb, dev, neigh,
-                                     unfrag_len + frag_len);
-
-               hdr = (struct ipv6hdr *) skb_put(last_skb, 
-                                                sizeof(struct ipv6hdr));
-               last_skb->nh.ipv6h = hdr;
-
-               hdr->version = 6;
-               hdr->priority = np->priority;
-
-               memcpy(hdr->flow_lbl, &np->flow_lbl, 3);
-               hdr->payload_len = htons(unfrag_len + frag_len - 
-                                        sizeof(struct ipv6hdr));
-               
-               hdr->hop_limit = hlimit;
-
-               hdr->nexthdr = NEXTHDR_FRAGMENT;
-
-               memcpy(&hdr->saddr, saddr, sizeof(struct in6_addr));
-               memcpy(&hdr->daddr, daddr, sizeof(struct in6_addr));
-               
-               if (opt && opt->srcrt)
-               {
-                       hdr->nexthdr = ipv6opt_bld_rthdr(last_skb, opt, dest,
-                                                        NEXTHDR_FRAGMENT);
-               }
-       
-               fhdr = (struct frag_hdr *)
-                       skb_put(last_skb, sizeof(struct frag_hdr));
-
-               memset(fhdr, 0, sizeof(struct frag_hdr));
-
-               fhdr->nexthdr  = proto;         
-               fhdr->frag_off = ntohs(nfrags * frag_len);
-               fhdr->identification = id;
-
-               fhdr_dist = (unsigned char *) fhdr - last_skb->data;
-
-               error = getfrag(data, &hdr->saddr, last_skb->tail,
-                               nfrags * frag_len, last_len);
-               
-               if (!error)
-               {       
-                       while (nfrags--)
-                       {
-                               struct sk_buff *skb;
-                       
-                               struct frag_hdr *fhdr2;
-                               
-                               printk(KERN_DEBUG "sending frag %d\n", nfrags);
-                               skb = skb_copy(last_skb, sk->allocation);
-                               
-                               fhdr2 = (struct frag_hdr *)
-                                       (skb->data + fhdr_dist);
-                               
-                               /* more flag on */
-                               fhdr2->frag_off = ntohs(nfrags * frag_len + 1);
-                               
-                               /*
-                                *      FIXME:
-                                *      if (nfrags == 0)
-                                *      put rest of headers
-                                */
-                               
-                               error = getfrag(data, &hdr->saddr,
-                                               skb_put(skb, frag_len), 
-                                               nfrags * frag_len, frag_len);
-                       
-                               if (error)
-                               {
-                                       kfree_skb(skb, FREE_WRITE);
-                                       break;
-                               }
-
-                               ipv6_statistics.Ip6OutRequests++;
-                               (*output_method)(skb, (struct rt6_info *) dc);
-                       }
-               }
-
-               if (error)
-               {
-                       kfree_skb(last_skb, FREE_WRITE);
-                       dev_unlock_list();
-                       return -EFAULT;
-               }
-
-               printk(KERN_DEBUG "sending last frag \n");
-
-               hdr->payload_len = htons(unfrag_len + last_len - 
-                                        sizeof(struct ipv6hdr));
-
-               /*
-                *      update last_skb to reflect the getfrag we did
-                *      on start.
-                */
-               last_skb->tail += last_len;
-               last_skb->len += last_len;
-
-               /* 
-                * toss the mac header out and rebuild it.
-                * needed because of the different frame length.
-                * ie: not needed for an ethernet.
-                */
-
-               if (dev->type != ARPHRD_ETHER && last_len != frag_len)
-               {
-                       ipv6_redo_mac_hdr(last_skb, neigh,
-                                         unfrag_len + last_len);
-               }
-
-               ipv6_statistics.Ip6OutRequests++;
-               (*output_method)(last_skb, (struct rt6_info *) dc);
-
-               dev_unlock_list();
-               return 0;
-       }
-       return -1;
-}
-
-static int pri_values[4] =
-{
-       SOPRI_BACKGROUND,
-       SOPRI_NORMAL,
-       SOPRI_NORMAL,
-       SOPRI_INTERACTIVE
-};
-
-void ipv6_forward(struct sk_buff *skb, struct device *dev, int flags)
-{
-       struct neighbour *neigh;
-       struct dest_entry *dest;
-       int priority;
-       int rt_flags;
-       int size;
-       int pmtu;
-
-       if (skb->nh.ipv6h->hop_limit <= 1)
-       {
-               icmpv6_send(skb, ICMPV6_TIME_EXCEEDED, ICMPV6_EXC_HOPLIMIT,
-                           0, dev);
-
-               kfree_skb(skb, FREE_READ);
-               return;
-       }
-
-       skb->nh.ipv6h->hop_limit--;
-
-       if (ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)
-       {
-               printk(KERN_DEBUG "ipv6_forward: link local source addr\n");
-               icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR,
-                           0, dev);            
-               kfree_skb(skb, FREE_READ);
-               return;
-       }
-
-       rt_flags = RTF_MODIFIED;
-
-       if ((flags & IP6_FW_STRICT))
-       {
-               rt_flags |= RTF_GATEWAY;
-       }
-
-       dest = ipv6_dst_route(&skb->nh.ipv6h->daddr, NULL, rt_flags);
-
-       if (dest == NULL)
-       {
-               int code;
-
-               if (flags & IP6_FW_STRICT)
-                       code = ICMPV6_NOT_NEIGHBOUR;
-               else
-                       code = ICMPV6_NOROUTE;
-                       
-               icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, dev);
-                           
-               kfree_skb(skb, FREE_READ);
-               return;
-       }
-
-       neigh = dest->dc_nexthop;
-
-       if (neigh->dev == dev && (dev->flags & IFF_MULTICAST) &&
-           !(flags & IP6_FW_SRCRT))
-       {
-               struct in6_addr *target = NULL;
-               struct nd_neigh *ndn = (struct nd_neigh *) neigh;
-               
-               /* 
-                *      outgoing device equal to incoming device
-                *      send a redirect
-                */
-               
-               if ((dest->dc_flags & RTF_GATEWAY))
-               {
-                       target = &ndn->ndn_addr;
-               }
-               else
-               {
-                       target = &skb->nh.ipv6h->daddr;
-               }
-
-               ndisc_send_redirect(skb, neigh, target);
-       }
-
-       pmtu = neigh->dev->mtu;
-
-       size = sizeof(struct ipv6hdr) + ntohs(skb->nh.ipv6h->payload_len);
-       
-       if (size > pmtu)
-       {
-               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, pmtu, dev);
-               kfree_skb(skb, FREE_READ);
-               return;
-       }
-
-       ipv6_dst_unlock(dest);
-
-       if (skb_headroom(skb) < neigh->dev->hard_header_len)
-       {
-               struct sk_buff *buff;
-
-               buff = alloc_skb(neigh->dev->hard_header_len + skb->len + 15,
-                                GFP_ATOMIC);
-
-               if (buff == NULL)
-               {
-                       return;
-               }
-               
-               skb_reserve(buff, (neigh->dev->hard_header_len + 15) & ~15);
-
-               buff->protocol = __constant_htons(ETH_P_IPV6);
-               buff->h.raw = skb_put(buff, size);
-
-               memcpy(buff->h.raw, skb->nh.ipv6h, size);
-               buff->nh.ipv6h = (struct ipv6hdr *) buff->h.raw;
-               kfree_skb(skb, FREE_READ);
-               skb = buff;
-       }
-
-       ipv6_redo_mac_hdr(skb, neigh, size);
-
-       priority = skb->nh.ipv6h->priority;
-
-       priority = (priority & 0x7) >> 1;
-       priority = pri_values[priority];
-
-       if (dev->flags & IFF_UP)
-       {
-               skb->dev = neigh->dev;
-               dev_queue_xmit(skb);
-       }
-       else
-       {
-               ipv6_statistics.Ip6OutDiscards++;
-               kfree_skb(skb, FREE_READ);
-       }
-}
-
-
-/*
- * Local variables:
- * c-file-style: "Linux"
- * End:
- */
diff --git a/net/ipv6/ipv6_route.c b/net/ipv6/ipv6_route.c
deleted file mode 100644 (file)
index 9c546ec..0000000
+++ /dev/null
@@ -1,2058 +0,0 @@
-/*
- *     IPv6 routing table
- *     Linux INET6 implementation 
- *
- *     Authors:
- *     Pedro Roque             <roque@di.fc.ul.pt>     
- *
- *     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.
- */
-
-/*
- *     Changes:
- *
- *     Masaki Hirabaru                 :       Fix for /proc info > pagesize
- *     <masaki@merit.edu>
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/sched.h>
-#include <linux/net.h>
-#include <linux/route.h>
-#include <linux/netdevice.h>
-#include <linux/in6.h>
-
-#ifdef         CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif
-
-#include <net/tcp.h>
-#include <net/sock.h>
-#include <net/snmp.h>
-
-#include <net/ipv6.h>
-#include <net/ndisc.h>
-#include <net/protocol.h>
-#include <net/ipv6_route.h>
-#include <net/addrconf.h>
-
-#include <net/netlink.h>
-
-#include <asm/uaccess.h>
-
-/*
- *     Routing Table
- *
- *     simplified version of a radix tree
- *
- *     - every node shares it's acestors prefix
- *     - the tree is ordered from less to most specific mask
- *     - default routes are handled apart
- *
- *     this facilitates recursion a lot
- */
-
-static struct rt6_info null_entry = {
-       NULL, NULL, 
-       {{{0}}},
-       0, 1,
-       NULL, NULL,
-       0, 0, RTF_REJECT
-};
-
-struct fib6_node routing_table = {
-       NULL, NULL, NULL, &null_entry, 
-       0, RTN_ROOT, 0
-};
-
-struct rt6_info                *default_rt_list = NULL;
-struct rt6_info                *loopback_rt = NULL;
-
-/*
- *     last_resort_rt - no routers present.
- *     Assume all destinations on link.
- */
-struct rt6_info                *last_resort_rt = NULL;
-
-static struct rt6_req request_queue = {
-       0, NULL, &request_queue, &request_queue
-};
-
-
-/*
- *     A routing update causes an increase of the serial number on the
- *     afected subtree. This allows for cached routes to be asynchronously
- *     tested when modifications are made to the destination cache as a
- *     result of redirects, path MTU changes, etc.
- */
-
-static __u32   rt_sernum       = 0;
-
-static atomic_t rt6_lock       = 0;
-static int     rt6_bh_mask     = 0;
-
-#define RT_BH_REQUEST  1
-#define RT_BH_GC       2
-
-static void __rt6_run_bh(void);
-
-typedef void (*f_pnode)(struct fib6_node *fn, void *);
-
-static void    rt6_walk_tree(f_pnode func, void * arg, int filter);
-static void    rt6_rt_timeout(struct fib6_node *fn, void *arg);
-static int     rt6_msgrcv(int unit, struct sk_buff *skb);
-
-struct rt6_statistics rt6_stats = {
-       1, 0, 1, 1, 0
-};
-
-static atomic_t        rt_clients = 0;
-
-void rt6_timer_handler(unsigned long data);
-
-struct timer_list rt6_gc_timer = {
-       NULL,
-       NULL,
-       0,
-       0,
-       rt6_timer_handler
-};
-
-static __inline__ void rt6_run_bh(void)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-
-       if (rt6_lock == 0 && rt6_bh_mask)
-       {
-               __rt6_run_bh();
-       }
-       restore_flags(flags);
-}
-
-/*
- *     request queue operations
- *     FIFO queue/dequeue
- */
-static __inline__ void rtreq_queue(struct rt6_req * req)
-{
-       unsigned long flags;
-       struct rt6_req *next = &request_queue;
-
-       save_flags(flags);
-       cli();
-
-       req->prev = next->prev;
-       req->prev->next = req;
-       next->prev = req;
-       req->next = next;
-       restore_flags(flags);
-}
-
-static __inline__ struct rt6_req * rtreq_dequeue(void)
-{
-       struct rt6_req *next = &request_queue;
-       struct rt6_req *head;
-
-       head = next->next;
-
-       if (head == next)
-       {
-               return NULL;
-       }
-
-       head->next->prev = head->prev;
-       next->next = head->next;
-
-       head->next = NULL;
-       head->prev = NULL;
-
-       return head;
-}
-
-/*
- *     compare "prefix length" bits of an address
- */
-static __inline__ int addr_match(struct in6_addr *a1, struct in6_addr *a2,
-                                int prefixlen)
-{
-       int pdw;
-       int pbi;
-
-       pdw = prefixlen >> 0x05;  /* num of whole __u32 in prefix */
-       pbi = prefixlen &  0x1f;  /* num of bits in incomplete u32 in prefix */
-
-       if (pdw) 
-       {
-               if (memcmp(a1, a2, pdw << 2))
-                       return 0;
-       }
-
-       if (pbi) 
-       {
-               __u32 w1, w2;
-               __u32 mask;
-
-               w1 = a1->s6_addr32[pdw];
-               w2 = a2->s6_addr32[pdw];
-
-               mask = htonl((0xffffffff) << (0x20 - pbi));
-
-               if ((w1 ^ w2) & mask)
-                       return 0;
-       }
-
-       return 1;
-}
-
-/*
- *     test bit. range [0-127]
- */
-
-static __inline__ int addr_bit_set(struct in6_addr *addr, int fn_bit)
-{
-       int dw;
-       __u32 b1;
-       __u32 mask;
-       int bit = fn_bit;
-
-       dw = bit >> 0x05;
-
-       b1 = addr->s6_addr32[dw];
-       
-       bit = ~bit;
-       bit &= 0x1f;
-       mask = htonl(1 << bit);
-       return (b1 & mask);
-}
-
-static __inline__ int addr_bit_equal(struct in6_addr *a1, struct in6_addr *a2,
-                                    int fn_bit)
-{
-       int dw;
-       __u32 b1, b2;
-       __u32 mask;
-       int bit = fn_bit;
-
-       dw = bit >> 0x05;
-
-       b1 = a1->s6_addr32[dw];
-       b2 = a2->s6_addr32[dw];
-       
-       bit = ~bit;
-       bit &= 0x1f;
-       mask = htonl(1 << bit);
-       return !((b1 ^ b2) & mask);
-}
-
-/*
- *     find the first different bit between two addresses
- */
-static __inline__ int addr_diff(struct in6_addr *a1, struct in6_addr *a2)
-{
-       int i;
-
-       for (i = 0; i<4; i++)
-       {
-               __u32 b1, b2;
-               __u32 xb;
-               
-               b1 = a1->s6_addr32[i];
-               b2 = a2->s6_addr32[i];
-               
-               xb = b1 ^ b2;
-
-               if (xb)
-               {
-                       int res = 0;
-                       int j=31;
-
-                       xb = ntohl(xb);
-
-                       while (test_bit(j, &xb) == 0)
-                       {
-                               res++;
-                               j--;
-                       }
-                       
-                       return (i * 32 + res);
-               }
-       }
-
-       /*
-        *      bit values are in range [0-127]
-        *      128 is an ilegal value as we should *never* get to
-        *      this point since that would mean the addrs are equal
-        */
-       return 128;
-}
-
-/*
- *     add a rt to a node that may already contain routes
- *     sort routes in ascending metric order so that fib lookup
- *     returns the smallest metric by default
- */
-
-static __inline__ void fib6_add_rt2node(struct fib6_node *fn,
-                                       struct rt6_info *rt)
-{
-       struct rt6_info *iter, **back;
-
-       rt->fib_node = fn;
-       back = &fn->leaf;
-       
-       for (iter = fn->leaf; iter; iter=iter->next)
-       {
-               if (iter->rt_metric > rt->rt_metric)
-               {
-                       break;
-               }
-
-               back = &iter->next;
-       }
-
-       rt->next = iter;
-       *back = rt;
-}
-
-/*
- *     Routing Table
- */
-
-static int fib6_add_1(struct rt6_info *rt)
-{
-       struct fib6_node *fn;
-       struct fib6_node *pn = NULL;
-       struct fib6_node *in;
-       struct fib6_node *ln;
-       struct in6_addr *addr;
-       __u32   bit;
-       __u32   dir = 0;
-       __u32   sernum = ++rt_sernum;
-       int pbit = rt->rt_prefixlen - 1;
-
-       addr = &rt->rt_dst;
-
-       /* insert node in tree */
-
-       fn = &routing_table;
-
-       for (;;)
-       {
-               if (fn == NULL)
-               {                       
-                       ln = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC);
-
-                       if (ln == NULL)
-                               return (-ENOMEM);
-
-                       memset(ln, 0, sizeof(struct fib6_node));
-                       ln->fn_bit   = pbit;
-                       ln->fn_flags = RTN_BACKTRACK;
-                       
-                       ln->parent = pn;
-                       ln->leaf = rt;
-                       ln->fn_sernum = sernum;
-                       rt->fib_node = ln;
-
-                       atomic_inc(&rt->rt_ref);
-
-                       if (dir)
-                               pn->right = ln;
-                       else
-                               pn->left  = ln;
-
-                       rt6_stats.fib_nodes++;
-                       rt6_stats.fib_route_nodes++;
-                       rt6_stats.fib_rt_entries++;
-
-                       return(0);
-               }
-
-               if (addr_match(&fn->leaf->rt_dst, addr, fn->fn_bit))
-               {
-                       if (pbit == fn->fn_bit && pbit &&
-                           addr_bit_equal(addr, &fn->leaf->rt_dst,
-                                          rt->rt_prefixlen))
-                       {
-                               /* clean up an intermediate node */
-                               if ((fn->fn_flags & RTN_BACKTRACK) == 0) 
-                               {
-                                       rt_release(fn->leaf);
-                                       fn->leaf = NULL;
-                                       fn->fn_flags |= RTN_BACKTRACK;
-                               }
-                       
-                               fib6_add_rt2node(fn, rt);
-                               fn->fn_sernum = sernum;
-                               atomic_inc(&rt->rt_ref);
-                               
-                               rt6_stats.fib_route_nodes++;
-                               rt6_stats.fib_rt_entries++;
-                               
-                               return 0;
-                       }
-
-                       if (pbit > fn->fn_bit || pbit == 0)
-                       {
-                               /* walk down on tree */
-
-                               fn->fn_sernum = sernum;
-
-                               dir = addr_bit_set(addr, fn->fn_bit); 
-                               pn = fn;
-                               fn = dir ? fn->right: fn->left;
-
-                               continue;
-                       }
-               }
-
-               /*
-                * split since we don't have a common prefix anymore or 
-                * we have a less significant route.
-                * we've to insert an intermediate node on the list
-                * this new node will point to the one we need to create
-                * and the current
-                */
-
-               pn = fn->parent;
-
-               /* find 1st bit in difference between the 2 addrs */
-               bit = addr_diff(addr, &fn->leaf->rt_dst);
-
-
-               /* 
-                *              (intermediate)  
-                *                /        \
-                *      (new leaf node)    (old node)
-                */
-               if (rt->rt_prefixlen > bit)
-               {
-                       in = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC);
-               
-                       if (in == NULL)
-                               return (-ENOMEM);
-
-                       memset(in, 0, sizeof(struct fib6_node));
-
-                       /* 
-                        * new intermediate node. 
-                        * RTN_BACKTRACK will
-                        * be off since that an address that chooses one of
-                        * the branches would not match less specific routes
-                        * int the other branch
-                        */
-
-                       in->fn_bit = bit;
-                       in->parent = pn;
-                       in->leaf = rt;
-                       in->fn_sernum = sernum;
-                       atomic_inc(&rt->rt_ref);
-
-                       /* leaf node */
-                       ln = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC);
-
-                       if (ln == NULL)
-                       {
-                               kfree(in);
-                               return (-ENOMEM);
-                       }
-
-                       /* update parent pointer */
-                       if (dir)
-                               pn->right = in;
-                       else
-                               pn->left  = in;
-
-                       memset(ln, 0, sizeof(struct fib6_node));
-                       ln->fn_bit   = pbit;
-                       ln->fn_flags = RTN_BACKTRACK;
-                       
-                       ln->parent = in;
-                       fn->parent = in;
-
-                       ln->leaf = rt;
-                       ln->fn_sernum = sernum;
-                       atomic_inc(&rt->rt_ref);
-
-                       rt->fib_node = ln;
-
-                       if (addr_bit_set(addr, bit))
-                       {
-                               in->right = ln;
-                               in->left  = fn;
-                       }
-                       else
-                       {
-                               in->left  = ln;
-                               in->right = fn;
-                       }
-
-                       rt6_stats.fib_nodes += 2;
-                       rt6_stats.fib_route_nodes++;
-                       rt6_stats.fib_rt_entries++;
-
-                       return 0;
-               }
-
-               /* 
-                *              (new leaf node)
-                *                /        \
-                *           (old node)    NULL
-                */
-
-               ln = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC);
-
-               if (ln == NULL)
-                       return (-ENOMEM);
-
-               memset(ln, 0, sizeof(struct fib6_node));
-               ln->fn_bit   = pbit;
-               ln->fn_flags = RTN_BACKTRACK;
-                       
-
-               ln->parent = pn;
-               ln->leaf = rt;
-               ln->fn_sernum = sernum;
-               atomic_inc(&rt->rt_ref);
-
-               rt->fib_node = ln;
-
-               if (dir)
-                       pn->right = ln;
-               else
-                       pn->left  = ln;
-               
-
-               if (addr_bit_set(&fn->leaf->rt_dst, pbit))
-                       ln->right = fn;
-               else
-                       ln->left  = fn; 
-
-               fn->parent = ln;
-
-               rt6_stats.fib_nodes++;
-               rt6_stats.fib_route_nodes++;
-               rt6_stats.fib_rt_entries++;
-
-               return(0);
-       }
-
-       return (-1);
-}
-
-static struct rt6_info * fib6_lookup_1(struct in6_addr *addr, int flags)
-{
-       struct fib6_node *fn, *next;
-       int dir;
-
-       fn = &routing_table;
-
-       for (;;)
-       {
-               dir = addr_bit_set(addr, fn->fn_bit);
-
-               next = dir ? fn->right: fn->left;
-
-               if (next)
-               {
-                       fn = next;
-                       continue;
-               }
-
-               break;
-       }
-
-
-       while ((fn->fn_flags & RTN_ROOT) == 0)
-       {
-               if (fn->fn_flags & RTN_BACKTRACK)
-               {
-                       if (addr_match(&fn->leaf->rt_dst, addr, 
-                                      fn->leaf->rt_prefixlen))
-                       {
-                               struct rt6_info *rt;
-                               
-                               for (rt = fn->leaf; rt; rt = rt->next)
-                               {
-                                       if ((rt->rt_flags & flags) == 0)
-                                               return rt;
-                               }
-                       }
-               }
-               
-               fn = fn->parent;
-       }
-
-       return NULL;
-}
-
-
-
-/*
- *     called to trim the tree of intermediate nodes when possible
- */
-
-static void fib6_del_3(struct fib6_node *fn)
-{
-       int children = 0;
-       int dir = 0;
-       int bit;
-
-       /*
-        *      0 or one children:
-        *              delete the node
-        *
-        *      2 children:
-        *              move the bit down
-        */
-
-       if (fn->left)
-       {
-               children++;
-               dir = 0;
-       }
-
-       if (fn->right)
-       {
-               children++;
-               dir = 1;
-       }
-
-       if (children < 2)
-       {
-               struct fib6_node *child;
-               struct fib6_node *pn;
-
-               child = dir ? fn->right : fn->left;
-
-               if (fn->parent->left == fn)
-               {
-                       fn->parent->left = child;
-               }
-               else
-               {
-                       fn->parent->right = child;
-               }
-
-               if (child)
-               {
-                       child->parent = fn->parent;
-               }
-
-               /*
-                *      try to collapse on top
-                */
-               pn = fn->parent;
-               fn->parent = NULL;
-               
-               if ((pn->fn_flags & (RTN_BACKTRACK | RTN_ROOT)) == 0)
-               {
-                       if (pn->leaf)
-                       {
-                               rt_release(pn->leaf);
-                               pn->leaf = NULL;
-                       }
-                       fib6_del_3(pn);
-               }
-
-               if (fn->fn_flags & RTN_BACKTRACK)
-               {
-                       rt6_stats.fib_route_nodes--;
-               }
-               rt6_stats.fib_nodes--;
-               kfree(fn);
-               return;
-       }
-
-       bit = addr_diff(&fn->left->leaf->rt_dst, &fn->right->leaf->rt_dst);
-       
-       fn->fn_bit = bit;
-       fn->fn_flags &= ~RTN_BACKTRACK;
-       
-       fn->leaf = fn->left->leaf;
-       atomic_inc(&fn->leaf->rt_ref);
-
-       rt6_stats.fib_route_nodes--;
-}
-
-static struct fib6_node * fib6_del_2(struct in6_addr *addr, __u32 prefixlen, 
-                                    struct in6_addr *gw, struct device *dev)
-{
-       struct fib6_node *fn;
-
-       for (fn = &routing_table; fn;) 
-       {
-               int dir;
-
-               if ((fn->fn_flags & RTN_BACKTRACK) &&
-                   prefixlen == fn->leaf->rt_prefixlen &&
-                   addr_match(&fn->leaf->rt_dst, addr, fn->leaf->rt_prefixlen)
-                   )
-               {
-                       break;
-               }
-
-               dir = addr_bit_set(addr, fn->fn_bit);
-
-               fn = dir ? fn->right: fn->left;
-       }
-
-       /* 
-        *      if route tree node found
-        *      search among it's entries
-        */
-
-       if (fn)
-       {
-               struct rt6_info *back = NULL;
-               struct rt6_info *lf;
-
-               for(lf = fn->leaf; lf; lf=lf->next)
-               {
-                       if ((gw && (ipv6_addr_cmp(addr, &lf->rt_dst) == 0)) ||
-                           (dev && dev == lf->rt_dev))
-                       {
-                               /* delete this entry */
-                               if (back == NULL)
-                                       fn->leaf = lf->next;
-                               else
-                                       back->next = lf->next;
-
-                               lf->fib_node = NULL;
-                               rt_release(lf);
-                               return fn;              
-                       }
-                       back = lf;
-               }
-       }
-
-       return NULL;
-}
-
-static struct fib6_node * fib6_del_rt_2(struct rt6_info *rt)
-{
-       struct fib6_node *fn;
-       struct in6_addr *addr = &rt->rt_dst;
-       int prefixlen = rt->rt_prefixlen;
-       
-       for (fn = &routing_table; fn;) 
-       {
-               int dir;
-
-               if ((fn->fn_flags & RTN_BACKTRACK) &&
-                   prefixlen == fn->leaf->rt_prefixlen &&
-                   addr_match(&fn->leaf->rt_dst, addr, fn->leaf->rt_prefixlen)
-                   )
-               {
-                       break;
-               }
-
-               dir = addr_bit_set(addr, fn->fn_bit);
-
-               fn = dir ? fn->right: fn->left;
-       }
-
-       /* 
-        *      if route tree node found
-        *      search among its entries
-        */
-
-       if (fn)
-       {
-               struct rt6_info **back;
-               struct rt6_info *lf;
-
-               back = &fn->leaf;
-               
-               for(lf = fn->leaf; lf; lf=lf->next)
-               {
-                       if (rt == lf)
-                       {
-                               /*
-                                *      delete this entry
-                                */
-                               
-                               *back = lf->next;
-                               rt_release(lf);
-                               return fn;
-                       }
-                       back = &lf->next;
-               }
-       }
-
-       return NULL;
-}
-
-int fib6_del_1(struct in6_addr *addr, __u32 prefixlen, struct in6_addr *gw, 
-              struct device *dev)
-{
-       struct fib6_node *fn;
-
-       fn = fib6_del_2(addr, prefixlen, gw, dev);
-
-       if (fn == NULL)
-               return -ENOENT;
-       
-       if (fn->leaf == NULL)
-       {
-               fib6_del_3(fn);
-       }
-
-       return 0;
-}
-
-int fib6_del_rt(struct rt6_info *rt)
-{
-       struct fib6_node *fn;
-
-       fn = fib6_del_rt_2(rt);
-
-       if (fn == NULL)
-               return -ENOENT;
-       
-       if (fn->leaf == NULL)
-       {
-               fib6_del_3(fn);
-       }
-
-       return 0;
-}
-
-static void fib6_flush_1(struct fib6_node *fn, void *p_arg)
-{
-       struct rt6_info *rt;
-
-       for (rt = fn->leaf; rt;)
-       {
-               struct rt6_info *itr;
-
-               itr = rt;
-               rt = rt->next;
-               itr->fib_node = NULL;
-               rt_release(itr);
-       }
-       
-       if (fn->fn_flags & RTN_BACKTRACK)
-       {
-               rt6_stats.fib_route_nodes--;
-       }
-       rt6_stats.fib_nodes--;
-       kfree(fn);
-}
-
-void fib6_flush(void)
-{
-       rt6_walk_tree(fib6_flush_1, NULL, RT6_FILTER_NONE);
-}
-
-int ipv6_route_add(struct in6_rtmsg *rtmsg)
-{
-       struct rt6_info *rt;
-       struct device * dev = NULL;
-       struct inet6_dev *idev;
-       struct rt6_req *request;
-       int flags = rtmsg->rtmsg_flags;
-
-       idev = ipv6_dev_by_index(rtmsg->rtmsg_ifindex);
-       if (idev)
-       {
-               dev = idev->dev; 
-       }
-       
-       rt = (struct rt6_info *) kmalloc(sizeof(struct rt6_info),
-                                        GFP_ATOMIC);
-
-       rt6_stats.fib_rt_alloc++;
-
-       memset(rt, 0, sizeof(struct rt6_info));
-               
-       memcpy(&rt->rt_dst, &rtmsg->rtmsg_dst, sizeof(struct in6_addr));
-       rt->rt_prefixlen = rtmsg->rtmsg_prefixlen;
-
-       if (rt->rt_prefixlen == 0)
-       {
-               printk(KERN_DEBUG "ip6_fib: zero length route not allowed\n");
-               return -EINVAL;
-       }
-       
-       if (flags & (RTF_GATEWAY | RTF_NEXTHOP)) 
-       {
-               /* check to see if its an acceptable gateway */
-               if (flags & RTF_GATEWAY)
-               {
-                       struct rt6_info *gw_rt;
-
-                       gw_rt = fibv6_lookup(&rtmsg->rtmsg_gateway, dev,
-                                            RTI_GATEWAY);
-
-                       if (gw_rt == NULL)
-                       {
-                               return -EHOSTUNREACH;
-                       }
-
-                       dev = gw_rt->rt_dev;
-               }
-
-               rt->rt_nexthop = ndisc_get_neigh(dev, &rtmsg->rtmsg_gateway);
-
-               if (rt->rt_nexthop == NULL)
-               {
-                       printk(KERN_DEBUG "ipv6_route_add: no nexthop\n");
-                       kfree(rt);
-                       return -EINVAL;
-               }
-
-               rt->rt_dev = dev;
-
-               if (loopback_rt == NULL && (dev->flags & IFF_LOOPBACK))
-               {
-                       loopback_rt = rt;
-               }
-
-       }
-       else
-       {
-               if (dev == NULL)
-               {
-                       printk(KERN_DEBUG "ipv6_route_add: NULL dev\n");
-                       kfree(rt);
-                       return -EINVAL;
-               }
-
-               rt->rt_dev = dev;
-               rt->rt_nexthop = NULL;
-       }
-       
-       rt->rt_metric = rtmsg->rtmsg_metric;
-       rt->rt_flags = rtmsg->rtmsg_flags;
-
-       if (rt->rt_flags & RTF_ADDRCONF)
-       {
-               rt->rt_expires = rtmsg->rtmsg_info;
-       }
-
-       request = kmalloc(sizeof(struct rt6_req), GFP_ATOMIC);
-       if (request == NULL)
-       {
-               printk(KERN_WARNING "ipv6_route_add: kmalloc failed\n");
-               return -ENOMEM;
-       }
-
-       request->operation = RT_OPER_ADD;
-       request->ptr = rt;
-       request->next = request->prev = NULL;
-       rtreq_queue(request);
-       rt6_bh_mask |= RT_BH_REQUEST;
-
-       rt6_run_bh();
-
-       return 0;
-}
-
-int ipv6_route_del(struct in6_rtmsg *rtmsg)
-{
-       struct rt6_info * rt;
-       int res = -ENOENT;
-       
-       atomic_inc(&rt6_lock);
-       
-       rt = fib6_lookup_1(&rtmsg->rtmsg_dst, 0);
-       
-       if (rt && (rt->rt_prefixlen == rtmsg->rtmsg_prefixlen))
-       {
-               int test;
-               
-               start_bh_atomic();
-               
-               test = (rt6_lock == 1);
-               
-               if (test)
-               {
-                       res = fib6_del_rt(rt);
-               }
-               end_bh_atomic();
-
-               if (!test)
-               {
-                       struct rt6_req *request;
-                       
-                       request = kmalloc(sizeof(struct rt6_req), GFP_KERNEL);
-                       
-                       if (!request)
-                       {
-                               res = -ENOMEM;
-                               goto out;
-                       }
-                       request->operation = RT_OPER_DEL;
-                       request->ptr = rt;
-                       request->next = request->prev = NULL;
-                       rtreq_queue(request);
-                       rt6_bh_mask |= RT_BH_REQUEST;
-                       res = 0;
-               }
-       }
-  out:
-       atomic_dec(&rt6_lock);
-       rt6_run_bh();
-       return res;
-}
-
-/*
- *     search the routing table
- *     the flags parameter restricts the search to entries where
- *     the flag is *not* set
- */
-struct rt6_info * fibv6_lookup(struct in6_addr *addr, struct device *src_dev,
-                              int flags)
-{
-       struct rt6_info *rt;
-
-       atomic_inc(&rt6_lock);
-       
-       if ((rt = fib6_lookup_1(addr, flags)))
-       {
-               if (src_dev)
-               {
-                       struct rt6_info *sprt;
-
-                       for (sprt=rt; sprt; sprt=sprt->next)
-                       {
-                               if (sprt->rt_dev == src_dev)
-                               {
-                                       rt = sprt;
-                                       goto out;
-                               }
-                       }
-                       
-                       if (flags & RTI_DEVRT)
-                       {
-                               rt = NULL;
-                       }
-               }
-
-               goto out;
-       }
-
-       if (!(flags & RTI_GATEWAY))
-       {
-               if ((rt = dflt_rt_lookup()))
-               {
-                       goto out;
-               }
-
-               rt = last_resort_rt;
-       }
-  out:
-       atomic_dec(&rt6_lock);
-       return rt;
-}
-
-/*
- *     Destination Cache
- */
-
-struct dest_entry * ipv6_dst_route(struct in6_addr * daddr,
-                                  struct device *src_dev,
-                                  int flags)
-{
-       struct dest_entry * dc = NULL;
-       struct rt6_info * rt;
-
-       atomic_inc(&rt6_lock);
-       
-       rt = fibv6_lookup(daddr, src_dev, flags);
-
-       if (rt == NULL)
-       {
-               goto exit;
-       }
-       
-       if (rt->rt_nexthop)
-       {
-               /*
-                *      We can use the generic route
-                *      (warning: the pmtu value maybe invalid)
-                */
-
-               dc = (struct dest_entry *) rt;
-               atomic_inc(&rt->rt_use);
-       }
-       else
-       {
-               struct rt6_req *request;
-
-               if (ipv6_chk_addr(daddr) && !(rt->rt_dev->flags & IFF_LOOPBACK))
-               {
-                       rt = loopback_rt;
-
-                       if (rt == NULL)
-                       {
-                               goto exit;
-                       }
-               }
-
-               /*
-                *      dynamicly allocate a new route
-                */
-               
-               dc = (struct dest_entry *) kmalloc(sizeof(struct dest_entry), 
-                                          GFP_ATOMIC);
-
-               if (dc == NULL)
-               {
-                       printk(KERN_WARNING "dst_route: kmalloc failed\n");
-                       goto exit;
-               }
-
-               rt6_stats.fib_rt_alloc++;
-               rt6_stats.fib_dc_alloc++;
-
-               memset(dc, 0, sizeof(struct dest_entry));
-
-               memcpy(&dc->dc_addr, daddr, sizeof(struct in6_addr));
-               dc->rt.rt_prefixlen = 128;
-               dc->dc_usecnt = 1;
-               dc->rt.rt_metric = rt->rt_metric;
-
-               dc->dc_flags = (rt->rt_flags | RTF_HOST | RTI_DYNAMIC |
-                               RTI_DCACHE | DCF_PMTU);
-
-               dc->dc_pmtu = rt->rt_dev->mtu;
-               dc->rt.rt_dev = rt->rt_dev;
-               dc->rt.rt_output_method = rt->rt_output_method;
-               dc->dc_tstamp = jiffies;
-               /* add it to the request queue */
-               
-               request = kmalloc(sizeof(struct rt6_req), GFP_ATOMIC);
-
-               if (request == NULL)
-               {
-                       printk(KERN_WARNING "dst_route: kmalloc failed\n");
-                       dc = NULL;
-                       goto exit;
-               }
-
-               dc->dc_nexthop = ndisc_get_neigh(rt->rt_dev, daddr);
-
-               rt6_bh_mask |= RT_BH_REQUEST;
-               
-               request->operation = RT_OPER_ADD;
-               request->ptr = (struct rt6_info *) dc;
-               request->next = request->prev = NULL;
-               rtreq_queue(request);
-       }
-
-       atomic_inc(&rt_clients);
-
-  exit:
-       
-       atomic_dec(&rt6_lock);
-       rt6_run_bh();
-
-       return dc;
-}
-
-/*
- *     check cache entry for vality...
- *     this needs to be done as a inline func that calls
- *     ipv6_slow_dst_check if entry is invalid
- */
-
-struct dest_entry * ipv6_dst_check(struct dest_entry *dc,
-                                  struct in6_addr *daddr,
-                                  __u32 sernum, int flags)
-{
-       int uptodate = 0;
-
-       /*
-        *      destination cache becomes invalid when routing
-        *      changes or a more specific dynamic entry is
-        *      created.
-        *      if route is removed from table fib_node will
-        *      become NULL
-        */
-
-       if (dc->rt.fib_node && (dc->rt.fib_node->fn_sernum == sernum))
-               uptodate = 1;
-
-       if (uptodate && ((dc->dc_flags & DCF_INVALID) == 0))
-       {
-               if (dc->dc_nexthop && !(dc->dc_nexthop->flags & NCF_NOARP))
-               {
-                       ndisc_event_send(dc->dc_nexthop, NULL);
-               }
-               return dc;
-       }
-
-       /* route for destination may have changed */
-
-       ipv6_dst_unlock(dc);
-
-       return ipv6_dst_route(daddr, NULL, flags);
-}
-
-void ipv6_dst_unlock(struct dest_entry *dc)
-{
-       /*
-        *      decrement counter and mark entry for deletion
-        *      if counter reaches 0. we delay deletions in hope
-        *      we can reuse cache entries.
-        */
-
-       atomic_dec(&dc->dc_usecnt);
-       
-       if (dc->dc_usecnt == 0)
-       {
-
-               if (dc->dc_flags & RTI_DCACHE)
-               {
-                       /*
-                        *      update last usage tstamp
-                        */
-
-                       dc->dc_tstamp = jiffies;
-                       rt6_bh_mask |= RT_BH_GC;
-               }
-
-               if (dc->rt.rt_ref == 0)
-               {
-                       /*
-                        *      entry out of the routing table
-                        *      pending to be released on last deref
-                        */
-
-                       if (dc->dc_nexthop)
-                       {
-                               neighbour_unlock(dc->dc_nexthop);
-                       }
-                       
-                       if (dc->dc_flags & RTI_DCACHE)
-                       {
-                               rt6_stats.fib_dc_alloc--;
-                       }
-
-                       rt6_stats.fib_rt_alloc--;
-                       kfree(dc);
-               }
-
-       }
-
-       atomic_dec(&rt_clients);
-}
-
-/*
- *     Received a packet too big icmp that lowers the mtu for this
- *     address. If the route for the destination is genric we create
- *     a new route with the apropriate MTU info. The route_add
- *     procedure will update the serial number on the generic routes
- *     belonging to the afected tree forcing clients to request a route
- *     lookup.
- */
-void rt6_handle_pmtu(struct in6_addr *addr, int pmtu)
-{
-       struct rt6_info *rt;
-       struct rt6_req *req;
-       struct dest_entry *dc;
-
-       printk(KERN_DEBUG "rt6_handle_pmtu\n");
-
-       if (pmtu < 0 || pmtu > 65536)
-       {
-               printk(KERN_DEBUG "invalid MTU value\n");
-               return;
-       }
-
-       rt = fibv6_lookup(addr, NULL, 0);
-
-       if (rt == NULL)
-       {
-               printk(KERN_DEBUG "rt6_handle_pmtu: route not found\n");
-               return;
-       }
-
-       if (rt->rt_flags & RTI_DCACHE)
-       {
-               /*
-                *      we do have a destination cache entry for this
-                *      address.
-                */
-               
-               dc = (struct dest_entry *) rt;
-               
-               /*
-                *      fixme: some sanity checks are likely to be needed
-                *       here
-                */
-
-               dc->dc_pmtu = pmtu;
-               dc->dc_flags |= DCF_PMTU;
-               return;
-       }
-
-       req = (struct rt6_req *) kmalloc(sizeof(struct rt6_req), GFP_ATOMIC);
-
-       /* now add the new destination cache entry      */
-       
-       dc = (struct dest_entry *) kmalloc(sizeof(struct dest_entry),
-                                          GFP_ATOMIC);
-       
-       rt6_stats.fib_rt_alloc++;
-       rt6_stats.fib_dc_alloc++;
-
-       memset(dc, 0, sizeof(struct dest_entry));
-       
-       memcpy(&dc->dc_addr, addr, sizeof(struct in6_addr));
-       dc->rt.rt_prefixlen = 128;
-       dc->rt.rt_metric = rt->rt_metric;
-
-       dc->dc_flags = (rt->rt_flags | RTI_DYNAMIC | RTI_DCACHE | DCF_PMTU |
-                       RTF_HOST);
-
-       dc->dc_pmtu = pmtu;
-       dc->dc_tstamp = jiffies;
-       
-       dc->dc_nexthop = rt->rt_nexthop;
-       atomic_inc(&dc->dc_nexthop->refcnt);
-
-       dc->rt.rt_dev = rt->rt_dev;
-       dc->rt.rt_output_method = rt->rt_output_method;
-
-       req->operation = RT_OPER_ADD;
-       req->ptr = (struct rt6_info *) dc;
-       req->next = req->prev = NULL;
-
-       rtreq_queue(req);
-
-       rt6_bh_mask |= RT_BH_REQUEST;
-
-       rt6_run_bh();
-}
-
-/*
- *     Redirect received: target is nexthop for dest
- */
-struct rt6_info * ipv6_rt_redirect(struct device *dev, struct in6_addr *dest,
-                                  struct in6_addr *target, int on_link)
-                                      
-{
-       struct rt6_info *rt;
-       struct rt6_req *req;
-       int metric;
-
-       rt = fibv6_lookup(dest, dev, 0);
-
-       if (rt == NULL)
-       {
-               printk(KERN_WARNING "rt_redirect: unable to locate route\n");
-               return NULL;
-       }
-
-       metric = rt->rt_metric;
-
-       if ((rt->rt_flags & RTF_HOST) == 0)
-       {
-               /* Need to create an host route for this address */
-               
-               rt = (struct rt6_info *) kmalloc(sizeof(struct rt6_info),
-                                                GFP_ATOMIC);
-               memset(rt, 0, sizeof(struct rt6_info));
-               ipv6_addr_copy(&rt->rt_dst, dest);
-               rt->rt_prefixlen = 128;
-               rt->rt_flags = RTF_HOST | RTF_UP;
-               rt->rt_dev = dev;
-
-               /*
-                *      clone rt->rt_output_method ?
-                */
-
-               rt->rt_metric = metric;
-
-               rt6_stats.fib_rt_alloc++;
-
-               req = (struct rt6_req *) kmalloc(sizeof(struct rt6_req),
-                                                GFP_ATOMIC);
-               req->operation = RT_OPER_ADD;
-               req->ptr  = rt;
-               req->next = req->prev = NULL;
-               
-               rtreq_queue(req);
-               rt6_bh_mask |= RT_BH_REQUEST;
-       }
-       else
-       {
-               rt->rt_flags |= RTF_MODIFIED;
-       }
-
-       rt->rt_flags |= RTF_DYNAMIC;
-       if (on_link)
-       {
-               rt->rt_flags &= ~RTF_GATEWAY;
-       }
-       else
-       {
-               rt->rt_flags |= RTF_GATEWAY;
-       }
-
-       if (rt->rt_nexthop)
-       {
-               struct nd_neigh *ndn = (struct nd_neigh *) rt->rt_nexthop;
-               
-               if (ipv6_addr_cmp(&ndn->ndn_addr, target) == 0)
-               {
-                       rt->rt_nexthop = neighbour_clone(rt->rt_nexthop);
-                       goto exit;
-               }
-               else
-               {
-                       neighbour_unlock(rt->rt_nexthop);
-               }
-       }
-       
-       rt->rt_nexthop = ndisc_get_neigh(dev, target);
-
-  exit:
-       rt6_run_bh();
-       return rt;
-}
-
-static int dcache_gc_node(struct fib6_node *fn, int timeout)
-{
-       struct rt6_info *rt, *back;
-       int more = 0;
-       unsigned long now = jiffies;
-
-       back = NULL;
-
-       for (rt = fn->leaf; rt;)
-       {
-               if ((rt->rt_flags & RTI_DCACHE) && rt->rt_use == 0)
-               {
-                       struct dest_entry *dc;
-                       
-                       dc = (struct dest_entry *) rt;
-                       
-                       if (now - dc->dc_tstamp > timeout)
-                       {
-                               struct rt6_info *old;
-
-                               old = rt;
-
-                               rt = rt->next;
-
-                               if (back == NULL)
-                               {
-                                       fn->leaf = rt;
-                               }
-                               else
-                               {
-                                       back->next = rt;
-                               }
-
-                               old->fib_node = NULL;
-                               rt_release(old);
-                               rt6_stats.fib_rt_entries--;
-                               continue;
-                       }
-                       else
-                       {
-                               more++;
-                       }
-               }
-
-               back = rt;
-               rt = rt->next;
-       }
-
-       if (fn->leaf == NULL)
-       {
-               return -1;
-       }
-       return more;
-}
-
-struct dc_gc_args {
-       unsigned long   timeout;
-       int             more;
-};
-
-static void dc_garbage_collect(struct fib6_node *fn, void *p_arg)
-{
-       struct dc_gc_args * args = (struct dc_gc_args *) p_arg;
-       
-       if (fn->fn_flags & RTN_BACKTRACK)
-       {
-               if (fn->fn_bit == 127)
-               {
-                       int more;
-                                               
-                       more = dcache_gc_node(fn, args->timeout);
-
-                       if (more == -1)
-                       {
-                               if (fn->parent->left == fn)
-                                       fn->parent->left = NULL;
-                               else
-                                       fn->parent->right = NULL;
-                               
-                               kfree(fn);
-
-                               rt6_stats.fib_nodes--;
-                               rt6_stats.fib_route_nodes--;
-                               
-                               return;
-                       }
-                       args->more += more;
-               }
-       }
-       else if (!(fn->fn_flags & RTN_ROOT))
-       {
-               int children = 0;
-               struct fib6_node *chld = NULL;
-
-               if (fn->left)
-               {
-                       children++;
-                       chld = fn->left;                        
-               }
-                       
-               if (fn->right)
-               {
-                       children++;
-                       chld = fn->right;
-               }
-               
-               if (children <= 1)
-               {                       
-                       struct fib6_node *pn = fn->parent;
-                       
-                       if (pn->left == fn)
-                       {
-                               pn->left = chld;
-                       }
-                       else
-                       {
-                               pn->right = chld;
-                       }
-                       
-                       if (chld)
-                       {
-                               chld->parent = pn;
-                       }
-                       
-                       rt_release(fn->leaf);
-                       
-                       rt6_stats.fib_nodes--;
-                       kfree(fn);
-               }              
-       }
-}
-
-/*
- *     called with ints off
- */
-
-static void __rt6_run_bh(void)
-{
-       static last_gc_run = 0;
-
-       if (rt6_bh_mask & RT_BH_REQUEST)
-       {
-               struct rt6_req *request;
-
-               while ((request = rtreq_dequeue()))
-               {
-                       struct rt6_info *rt;
-
-                       rt = request->ptr;
-
-                       switch (request->operation) {
-                       case RT_OPER_ADD:
-                               fib6_add_1(rt);
-                               break;
-
-                       case RT_OPER_DEL:
-                               fib6_del_rt(rt);
-                               break;
-
-                       default:
-                               printk(KERN_WARNING
-                                      "rt6_run_bh: bad request in queue\n");
-                       }
-
-                       kfree(request);
-               }
-
-               rt6_bh_mask &= ~RT_BH_REQUEST;
-       }
-
-       if (rt6_bh_mask & RT_BH_GC)
-       {
-               if (jiffies - last_gc_run > DC_TIME_RUN)
-               {
-                       struct dc_gc_args args;
-
-                       if (rt6_stats.fib_dc_alloc >= DC_WATER_MARK)
-                               args.timeout = DC_SHORT_TIMEOUT;
-                       else
-                               args.timeout = DC_LONG_TIMEOUT;
-
-                       args.more = 0;
-                       rt6_walk_tree(dc_garbage_collect, &args, RT6_FILTER_NONE);
-
-                       last_gc_run = jiffies;
-                       
-                       if (!args.more)
-                       {
-                               rt6_bh_mask &= ~RT_BH_GC;
-                       }
-               }
-       }
-}
-
-/*
- *     Timer for expiring routes learned via addrconf and stale DC 
- *     entries when there is no network actuvity
- */
-
-void rt6_timer_handler(unsigned long data)
-{
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-
-       if (rt6_lock == 0)
-       {
-               if (rt_clients == 0 && rt6_bh_mask)
-               {
-                       __rt6_run_bh();
-               }
-
-               /*
-                *      route expiry
-                */
-               
-               rt6_walk_tree(rt6_rt_timeout, NULL, RT6_FILTER_RTNODES);
-       }
-
-       restore_flags(flags);
-
-       rt6_gc_timer.expires = jiffies + 4 * DC_LONG_TIMEOUT;
-       add_timer(&rt6_gc_timer);
-}
-
-/*
- *     Check if routes should be timed out.
- *     Called from rt6_walk_tree for every node.
- */
-
-static void rt6_rt_timeout(struct fib6_node *fn, void *arg)
-{
-       struct rt6_info *rt;
-       unsigned long now = jiffies;
-
-       for (rt = fn->leaf; rt; rt = rt->next)
-       {
-               if ((rt->rt_flags & RTF_ADDRCONF) && now > rt->rt_expires)
-               {
-                       struct rt6_req *req;
-
-                       /*
-                        *      request route deletion. routes will only
-                        *      be deleted after walk_tree completes
-                        */
-
-                       req = (struct rt6_req *) kmalloc(sizeof(struct rt6_req),
-                                                        GFP_ATOMIC);
-                       req->operation = RT_OPER_DEL;
-                       req->ptr  = rt;
-                       req->next = req->prev = NULL;
-               }
-       }
-}
-
-static void rt6_sndrtmsg(struct in6_rtmsg *rtmsg)
-{
-       struct sk_buff *skb;
-       
-       skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
-       if (skb == NULL)
-               return;
-
-       memcpy(skb_put(skb, sizeof(struct in6_rtmsg)), &rtmsg,
-              sizeof(struct in6_rtmsg));
-       
-       if (netlink_post(NETLINK_ROUTE6, skb))
-       {
-               kfree_skb(skb, FREE_WRITE);
-       }
-}
-
-int ipv6_route_ioctl(unsigned int cmd, void *arg)
-{
-       struct in6_rtmsg rtmsg;
-       int err;
-
-       switch(cmd) 
-       {
-               case SIOCADDRT:         /* Add a route */
-               case SIOCDELRT:         /* Delete a route */
-                       if (!suser())
-                               return -EPERM;
-                       err = copy_from_user(&rtmsg, arg,
-                                            sizeof(struct in6_rtmsg));
-                       if (err)
-                               return -EFAULT;
-                       
-                       err = (cmd == SIOCDELRT) ? ipv6_route_del(&rtmsg) :
-                             ipv6_route_add(&rtmsg);
-
-                       if (err == 0)
-                       {
-                               rt6_sndrtmsg(&rtmsg);
-                       }
-                       return err;
-       }
-
-       return -EINVAL;
-}
-
-static void rt6_ifdown_scan(struct fib6_node *fn, void *arg)
-{
-       struct rt6_info *rt;
-       struct device *dev = (struct device *) arg;
-
-       for (rt = fn->leaf; rt; rt=rt->next)
-       {
-               if (((rt->rt_flags & RTI_DCACHE) == 0) && rt->rt_dev == dev)
-               {
-                       struct rt6_req *req;
-
-                       req = kmalloc(sizeof(struct rt6_req), GFP_ATOMIC);
-                       req->operation = RT_OPER_DEL;
-                       req->ptr  = rt;
-                       req->next = req->prev = NULL;
-                       rt6_bh_mask |= RT_BH_REQUEST;
-               }
-       }
-}
-
-void rt6_ifdown(struct device *dev)
-{
-       rt6_walk_tree(rt6_ifdown_scan, (void *) dev, RT6_FILTER_RTNODES);
-}
-
-static void rt6_walk_tree(f_pnode func, void * arg, int filter)
-{
-       struct fib6_node *fn;
-       /*
-        *      adquire lock
-        *      this warranties that the operation will be atomic with
-        *      respect to the garbage collect routine that also does
-        *      a tree transversal and tags nodes with the RTN_TAG flag
-        */
-       atomic_inc(&rt6_lock);
-
-       fn = &routing_table;
-
-       do {
-               if (!(fn->fn_flags & RTN_TAG))
-               {
-                       fn->fn_flags |= RTN_TAG;
-
-                       if (fn->left)
-                       {
-                               fn = fn->left;
-                               continue;
-                       }
-               }
-
-               fn->fn_flags &= ~RTN_TAG;
-
-               if (fn->right)
-               {
-                       fn = fn->right;
-                       continue;
-               }
-                       
-               do {
-                       struct fib6_node *node;
-                       
-                       if (fn->fn_flags & RTN_ROOT)
-                               break;
-                       node = fn;
-                       fn = fn->parent;
-                       
-                       if (!(node->fn_flags & RTN_TAG) && 
-                           (!filter || (node->fn_flags & RTN_BACKTRACK)))
-                       {
-                               (*func)(node, arg);
-                       }
-
-               } while (!(fn->fn_flags & RTN_TAG));
-               
-       } while (!(fn->fn_flags & RTN_ROOT) || (fn->fn_flags & RTN_TAG));
-
-       atomic_dec(&rt6_lock);
-}
-
-#ifdef CONFIG_PROC_FS
-#define RT6_INFO_LEN (32 + 2 + 32 + 2 + 2 + 2 + 4 + 8 + 7 + 1)
-
-struct rt6_proc_arg {
-       char *buffer;
-       int offset;
-       int length;
-       int skip;
-       int len;
-};
-
-static void rt6_info_node(struct fib6_node *fn, void *p_arg)
-{
-       struct rt6_info *rt;
-       struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg;
-
-       for (rt = fn->leaf; rt; rt = rt->next)
-       {
-               int i;
-
-               if (arg->skip < arg->offset / RT6_INFO_LEN)
-               {
-                       arg->skip++;
-                       continue;
-               }
-
-               if (arg->len >= arg->length)
-                       return;
-               
-               for (i=0; i<16; i++)
-               {
-                       sprintf(arg->buffer + arg->len, "%02x",
-                               rt->rt_dst.s6_addr[i]);
-                       arg->len += 2;
-               }
-               arg->len += sprintf(arg->buffer + arg->len, " %02x ",
-                                   rt->rt_prefixlen);
-               if (rt->rt_nexthop)
-               {
-                       for (i=0; i<16; i++)
-                       {
-                               struct nd_neigh *ndn;
-
-                               ndn = (struct nd_neigh *) rt->rt_nexthop;
-                               sprintf(arg->buffer + arg->len, "%02x",
-                                       ndn->ndn_addr.s6_addr[i]);
-                               arg->len += 2;
-                       }
-               }
-               else
-               {
-                       sprintf(arg->buffer + arg->len,
-                               "00000000000000000000000000000000");
-                       arg->len += 32;
-               }
-               arg->len += sprintf(arg->buffer + arg->len,
-                                   " %02x %02x %02x %04x %8s\n",
-                                   rt->rt_metric, rt->rt_use,
-                                   rt->rt_ref, rt->rt_flags, 
-                                   rt->rt_dev ? rt->rt_dev->name : "");
-       }
-}
-
-static int rt6_proc_info(char *buffer, char **start, off_t offset, int length,
-                        int dummy)
-{
-       struct rt6_proc_arg arg;
-       struct fib6_node sfn;
-       arg.buffer = buffer;
-       arg.offset = offset;
-       arg.length = length;
-       arg.skip = 0;
-       arg.len = 0;
-
-       rt6_walk_tree(rt6_info_node, &arg, RT6_FILTER_RTNODES);
-       
-       sfn.leaf = default_rt_list;
-       rt6_info_node(&sfn, &arg);
-
-       sfn.leaf = last_resort_rt;
-       rt6_info_node(&sfn, &arg);
-                            
-       *start = buffer;
-
-       if (offset)
-               *start += offset % RT6_INFO_LEN;
-
-       arg.len -= offset % RT6_INFO_LEN;
-
-       if (arg.len > length)
-               arg.len = length;
-
-       return arg.len;
-}
-
-
-static int rt6_proc_stats(char *buffer, char **start, off_t offset, int length,
-                         int dummy)
-{
-       int len;
-
-       len = sprintf(buffer, "%04x %04x %04x %04x %04x\n",
-                     rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
-                     rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
-                     rt6_stats.fib_dc_alloc);
-
-       len -= offset;
-
-       if (len > length)
-               len = length;
-
-       *start = buffer + offset;
-
-       return len;
-}
-
-#endif                 /* CONFIG_PROC_FS */
-
-/*
- *     init/cleanup code
- *
- */
-
-void ipv6_route_init(void)
-{
-#ifdef         CONFIG_PROC_FS
-       proc_net_register(&(struct proc_dir_entry) {
-               PROC_NET_RT6, 10, "ipv6_route",
-               S_IFREG | S_IRUGO, 1, 0, 0,
-               0, &proc_net_inode_operations,
-               rt6_proc_info
-       });
-       proc_net_register(&(struct proc_dir_entry) {
-               PROC_NET_RT6_STATS, 9, "rt6_stats",
-               S_IFREG | S_IRUGO, 1, 0, 0,
-               0, &proc_net_inode_operations,
-               rt6_proc_stats
-       });
-
-#endif
-       rt6_gc_timer.expires = jiffies + 4 * DC_LONG_TIMEOUT;
-       add_timer(&rt6_gc_timer);
-       netlink_attach(NETLINK_ROUTE6, rt6_msgrcv);
-}
-
-#ifdef MODULE
-void ipv6_route_cleanup(void)
-{
-       proc_net_unregister(PROC_NET_RT6);
-       proc_net_unregister(PROC_NET_RT6_STATS);
-       netlink_detach(NETLINK_ROUTE6);
-       del_timer(&rt6_gc_timer);
-       fib6_flush();
-}
-#endif
-
-/*
- *     NETLINK interface
- *     routing socket moral equivalent
- */
-
-static int rt6_msgrcv(int unit, struct sk_buff *skb)
-{
-       int count = 0;
-       struct in6_rtmsg *rtmsg;
-       
-       while (skb->len)
-       {
-               if (skb->len < sizeof(struct in6_rtmsg))
-               {
-                       count = -EINVAL;
-                       goto out;
-               }
-               
-               rtmsg = (struct in6_rtmsg *) skb->data;
-               skb_pull(skb, sizeof(struct in6_rtmsg));
-               count += sizeof(struct in6_rtmsg);
-
-               switch (rtmsg->rtmsg_type) {
-               case RTMSG_NEWROUTE:
-                       ipv6_route_add(rtmsg);
-                       break;
-               case RTMSG_DELROUTE:
-                       ipv6_route_del(rtmsg);
-                       break;
-               default:
-                       count = -EINVAL;
-                       goto out;
-               }
-       }
-
-  out:
-       kfree_skb(skb, FREE_READ);      
-       return count;
-}
-
-void rt6_sndmsg(__u32 type, struct in6_addr *dst, struct in6_addr *gw,
-               __u16 plen, struct device *dev, __u16 metric, __u16 flags)
-{
-       struct sk_buff *skb;
-       struct in6_rtmsg *msg;
-       int ifindex = 0;
-       
-       skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
-       if (skb == NULL)
-               return;
-
-
-       msg = (struct in6_rtmsg *) skb_put(skb, sizeof(struct in6_rtmsg));
-       
-       msg->rtmsg_type = type;
-
-       if (dst)
-       {
-               ipv6_addr_copy(&msg->rtmsg_dst, dst);
-       }
-       else
-               memset(&msg->rtmsg_dst, 0, sizeof(struct in6_addr));
-
-       if (gw)
-       {
-               ipv6_addr_copy(&msg->rtmsg_gateway, gw);
-       }
-       else
-               memset(&msg->rtmsg_gateway, 0, sizeof(struct in6_addr));
-
-       msg->rtmsg_prefixlen = plen;
-       msg->rtmsg_metric = metric;
-
-       if (dev)
-       {
-               struct inet6_dev *idev;
-
-               idev = ipv6_get_idev(dev);
-               if (idev)
-               {
-                       ifindex = idev->if_index;
-               }
-       }
-       
-       msg->rtmsg_ifindex = ifindex;
-
-       msg->rtmsg_flags = flags;
-
-       if (netlink_post(NETLINK_ROUTE6, skb))
-       {
-               kfree_skb(skb, FREE_WRITE);
-       }
-}
index e5a9753d0679f363baca9d7fcc6353553437e993..b5db01c81a6706181c4dd298e268c50b66406987 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/net/ipv4/ip_sockglue.c
  *
- *     $Id: ipv6_sockglue.c,v 1.12 1996/10/29 22:45:53 roque Exp $
+ *     $Id: ipv6_sockglue.c,v 1.8 1997/03/18 18:24:38 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -40,7 +40,7 @@
 #include <net/ndisc.h>
 #include <net/protocol.h>
 #include <net/transp_v6.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/inet_common.h>
 #include <net/sit.h>
@@ -78,12 +78,9 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
        if(level!=SOL_IPV6)
                goto out;
 
-       if (optval == NULL)
-       {
+       if (optval == NULL) {
                val=0;
-       }
-       else
-       {
+       } else {
                err = get_user(val, (int *) optval);
                if(err)
                        return err;
@@ -93,43 +90,33 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
        switch (optname) {
 
        case IPV6_ADDRFORM:
-               if (val == PF_INET)
-               {
+               if (val == PF_INET) {
                        if (sk->protocol != IPPROTO_UDP &&
                            sk->protocol != IPPROTO_TCP)
-                       {                               
                                goto out;
-                       }
                        
-                       if (sk->state != TCP_ESTABLISHED)
-                       {
+                       if (sk->state != TCP_ESTABLISHED) {
                                retv = ENOTCONN;
                                goto out;
                        }
                        
-                       if (!(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED))
-                       {
+                       if (!(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
                                retv = -EADDRNOTAVAIL;
                                goto out;
                        }
 
-                       if (sk->protocol == IPPROTO_TCP)
-                       {
+                       if (sk->protocol == IPPROTO_TCP) {
                                struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
                                
                                sk->prot = &tcp_prot;
                                tp->af_specific = &ipv4_specific;
                                sk->socket->ops = &inet_stream_ops;
-                       }
-                       else
-                       {
+                       } else {
                                sk->prot = &udp_prot;
                                sk->socket->ops = &inet_dgram_ops;
                        }
                        retv = 0;
-               }
-               else
-               {
+               } else {
                        retv = -EINVAL;
                }
                break;
@@ -146,11 +133,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
 
        case IPV6_UNICAST_HOPS:
                if (val > 255)
-               {
                        retv = -EINVAL;
-               }
-               else
-               {
+               else {
                        np->hop_limit = val;
                        retv = 0;
                }
@@ -158,11 +142,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
 
        case IPV6_MULTICAST_HOPS:
                if (val > 255)
-               {
                        retv = -EINVAL;
-               }
-               else
-               {
+               else {
                        np->mcast_hops = val;
                        retv = 0;
                }
@@ -180,23 +161,19 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
                if(err)
                        return -EFAULT;
                                
-               if (ipv6_addr_any(&addr))
-               {
-                       np->mc_if = NULL;
-               }
-               else
-               {
+               if (ipv6_addr_any(&addr)) {
+                       np->oif = NULL;
+               } else {
                        struct inet6_ifaddr *ifp;
 
                        ifp = ipv6_chk_addr(&addr);
 
-                       if (ifp == NULL)
-                       {
+                       if (ifp == NULL) {
                                retv = -EADDRNOTAVAIL;
                                break;
                        }
 
-                       np->mc_if = ifp->idev->dev;
+                       np->oif = ifp->idev->dev;
                }
                retv = 0;
                break;
@@ -212,8 +189,8 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
                if(err)
                        return -EFAULT;
                
-               if (mreq.ipv6mr_ifindex == 0)
-               {
+               if (mreq.ipv6mr_ifindex == 0) {
+#if 0
                        struct in6_addr mcast;
                        struct dest_entry *dc;
 
@@ -226,34 +203,22 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
                                dev = dc->rt.rt_dev;
                                ipv6_dst_unlock(dc);
                        }
-               }
-               else
-               {
-                       struct inet6_dev *idev;
-                       
-                       if ((idev = ipv6_dev_by_index(mreq.ipv6mr_ifindex)))
-                       {
-                               dev = idev->dev;
-                       }
+#endif
+               } else {
+                       dev = dev_get_by_index(mreq.ipv6mr_ifindex);
                }
 
                if (dev == NULL)
-               {
                        return -ENODEV;
-               }
                
                if (optname == IPV6_ADD_MEMBERSHIP)
-               {
                        retv = ipv6_sock_mc_join(sk, dev, &mreq.ipv6mr_multiaddr);
-               }
                else
-               {
                        retv = ipv6_sock_mc_drop(sk, dev, &mreq.ipv6mr_multiaddr);
-               }
-       }
        }
+       };
 
-  out:
+out:
        return retv;
 }
 
@@ -285,7 +250,7 @@ void ipv6_init(void)
 
        register_netdevice_notifier(&ipv6_dev_notf);
        
-       ipv6_route_init();
+       ip6_route_init();
 }
 
 #ifdef MODULE
@@ -294,14 +259,8 @@ void ipv6_cleanup(void)
        unregister_netdevice_notifier(&ipv6_dev_notf);
        dev_remove_pack(&ipv6_packet_type);
        ipv6_sysctl_unregister();       
-       ipv6_route_cleanup();
+       ip6_route_cleanup();
        ndisc_cleanup();
        addrconf_cleanup();     
 }
 #endif
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O6 -m486 -c ipv6_sockglue.c"
- * End:
- */
index f22adbd7d7ce25ff25e45418cb66b0412b38cc18..6c0d8df80bb088a0954c876ba4295050b457bd95 100644 (file)
@@ -5,6 +5,8 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
+ *     $Id: mcast.c,v 1.7 1997/03/18 18:24:39 davem Exp $
+ *
  *     Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
  *
  *     This program is free software; you can redistribute it and/or
@@ -13,6 +15,8 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#define __NO_VERSION__
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <net/protocol.h>
 #include <net/if_inet6.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
 #include <net/addrconf.h>
 
+#include <net/checksum.h>
+
+/* Set to 3 to get tracing... */
+#define MCAST_DEBUG 2
+
+#if MCAST_DEBUG >= 3
+#define MDBG(x) printk x
+#else
+#define MDBG(x)
+#endif
+
+static struct inode igmp6_inode;
+static struct socket *igmp6_socket=&igmp6_inode.u.socket_i;
+
+static void igmp6_join_group(struct ifmcaddr6 *ma);
+static void igmp6_leave_group(struct ifmcaddr6 *ma);
+void igmp6_timer_handler(unsigned long data);
+
+#define IGMP6_UNSOLICITED_IVAL (10*HZ)
 
 /*
  *     socket join on multicast group
  */
+
 int ipv6_sock_mc_join(struct sock *sk, struct device *dev, 
                      struct in6_addr *addr)
 {
@@ -45,21 +68,25 @@ int ipv6_sock_mc_join(struct sock *sk, struct device *dev,
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
        int err;
 
+       MDBG(("ipv6_sock_mc_join(%s) addr[", dev ? dev->name : "[NULL]"));
+       MDBG(("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+             addr->s6_addr16[0], addr->s6_addr16[1], addr->s6_addr16[2],
+             addr->s6_addr16[3], addr->s6_addr16[4], addr->s6_addr16[5],
+             addr->s6_addr16[6], addr->s6_addr16[7]));
        if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))
                return -EINVAL;
 
        if(!(dev->flags & IFF_MULTICAST))
                return -EADDRNOTAVAIL;
 
-       mc_lst = (struct ipv6_mc_socklist *) 
-               kmalloc(sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
+       mc_lst = kmalloc(sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
 
        if (mc_lst == NULL)
                return -ENOMEM;
 
        mc_lst->next = NULL;
        memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));
-       mc_lst->dev  = dev;
+       mc_lst->dev = dev;
 
        /*
         *      now add/increase the group membership on the device
@@ -67,8 +94,7 @@ int ipv6_sock_mc_join(struct sock *sk, struct device *dev,
 
        err = ipv6_dev_mc_inc(dev, addr);
 
-       if (err)
-       {
+       if (err) {
                kfree(mc_lst);
                return err;
        }
@@ -85,7 +111,30 @@ int ipv6_sock_mc_join(struct sock *sk, struct device *dev,
 int ipv6_sock_mc_drop(struct sock *sk, struct device *dev, 
                      struct in6_addr *addr)
 {
-       return 0;
+       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
+       struct ipv6_mc_socklist *mc_lst, **lnk;
+
+       lnk = &np->ipv6_mc_list;
+
+       MDBG(("ipv6_sock_mc_drop(%s) addr[", dev ? dev->name : "[NULL]"));
+       MDBG(("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+             addr->s6_addr16[0], addr->s6_addr16[1], addr->s6_addr16[2],
+             addr->s6_addr16[3], addr->s6_addr16[4], addr->s6_addr16[5],
+             addr->s6_addr16[6], addr->s6_addr16[7]));
+
+       for (mc_lst = *lnk ; mc_lst; mc_lst = mc_lst->next) {
+               if (mc_lst->dev == dev &&
+                   ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
+                       *lnk = mc_lst->next;
+                       ipv6_dev_mc_dec(mc_lst->dev, &mc_lst->addr);
+                       kfree(mc_lst);
+
+                       return 0;
+               }
+               lnk = &mc_lst->next;
+       }
+
+       return -ENOENT;
 }
 
 void ipv6_sock_mc_close(struct sock *sk)
@@ -93,14 +142,15 @@ void ipv6_sock_mc_close(struct sock *sk)
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
        struct ipv6_mc_socklist *mc_lst;
 
-       for (mc_lst = np->ipv6_mc_list; mc_lst; )
-       {
+       for (mc_lst = np->ipv6_mc_list; mc_lst; ) {
                struct ipv6_mc_socklist *back;
 
                /*
                 *      leave group
                 */
 
+               ipv6_dev_mc_dec(mc_lst->dev, &mc_lst->addr);
+
                back = mc_lst;
                mc_lst = mc_lst->next;
                kfree(back);
@@ -112,53 +162,59 @@ void ipv6_sock_mc_close(struct sock *sk)
  */
 int ipv6_dev_mc_inc(struct device *dev, struct in6_addr *addr)
 {
-       struct ipv6_mc_list *mc;
-       struct inet6_dev    *i6dev;
+       struct ifmcaddr6 *mc;
+       struct inet6_dev    *idev;
        char buf[6];
-       u8 hash;
-       
-       for (i6dev = inet6_dev_lst; i6dev; i6dev=i6dev->next)
-               if (i6dev->dev == dev)
+       int hash;
+
+       MDBG(("ipv6_dev_mc_inc(%s) addr[", dev ? dev->name : "[NULL]"));
+       MDBG(("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+             addr->s6_addr16[0], addr->s6_addr16[1], addr->s6_addr16[2],
+             addr->s6_addr16[3], addr->s6_addr16[4], addr->s6_addr16[5],
+             addr->s6_addr16[6], addr->s6_addr16[7]));
+       hash = ipv6_devindex_hash(dev->ifindex);
+
+       for (idev = inet6_dev_lst[hash]; idev; idev=idev->next)
+               if (idev->dev == dev)
                        break;
-               
-       if (i6dev == NULL)
-       {
+
+       if (idev == NULL) {
                printk(KERN_DEBUG "ipv6_dev_mc_inc: device not found\n");
                return -EINVAL;
        }
 
-       for (mc = i6dev->mc_list; mc; mc = mc->if_next)
-               if (ipv6_addr_cmp(&mc->addr, addr) == 0)
-               {
-                       atomic_inc(&mc->users);
+       hash = ipv6_addr_hash(addr);
+
+       for (mc = inet6_mcast_lst[hash]; mc; mc = mc->next) {
+               if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
+                       atomic_inc(&mc->mca_users);
                        return 0;
                }
+       }
 
        /*
         *      not found: create a new one.
         */
 
-       mc = (struct ipv6_mc_list *) kmalloc(sizeof(struct ipv6_mc_list),
-                                            GFP_ATOMIC);
+       mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
 
        if (mc == NULL)
-       {
                return -ENOMEM;
-       }
 
-       memset(mc, 0, sizeof(struct ipv6_mc_list));
+       MDBG(("create new ipv6 MC entry, "));
+       memset(mc, 0, sizeof(struct ifmcaddr6));
+       mc->mca_timer.function = igmp6_timer_handler;
+       mc->mca_timer.data = (unsigned long) mc;
 
-       memcpy(&mc->addr, addr, sizeof(struct in6_addr));
+       memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
        mc->dev = dev;
-       mc->users = 1;
-
-       hash = ipv6_addr_hash(addr);
+       mc->mca_users = 1;
 
        mc->next = inet6_mcast_lst[hash];
        inet6_mcast_lst[hash] = mc;
-       
-       mc->if_next = i6dev->mc_list;
-       i6dev->mc_list = mc;
+
+       mc->if_next = idev->mc_list;
+       idev->mc_list = mc;
 
        /*
         *      multicast mapping is defined in IPv6-over-foo documents
@@ -167,27 +223,67 @@ int ipv6_dev_mc_inc(struct device *dev, struct in6_addr *addr)
        switch (dev->type) {
        case ARPHRD_ETHER:
                ipv6_mc_map(addr, buf);
+               MDBG(("ARPHRD_ETHER[%02x:%02x:%02x:%02x:%02x:%02x] dev_mc_add()\n",
+                     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]));
                dev_mc_add(dev, buf, ETH_ALEN, 0);
                break;
-               
+
        default:
                printk(KERN_DEBUG "dev_mc_inc: unkown device type\n");
-       }
-       
+       };
 
-       /*
-        *      FIXME: ICMP report handling
-        */
+       igmp6_join_group(mc);
 
        return 0;
 }
 
+static void ipv6_mca_remove(struct device *dev, struct ifmcaddr6 *ma)
+{
+       struct inet6_dev *idev;
+
+       idev = ipv6_get_idev(dev);
+
+       if (idev) {
+               struct ifmcaddr6 *iter, **lnk;
+
+               lnk = &idev->mc_list;
+               
+               for (iter = *lnk; iter; iter = iter->if_next) {
+                       if (iter == ma) {
+                               *lnk = iter->if_next;
+                               break;
+                       }
+                       lnk = &iter->if_next;
+               }
+       }
+}
+
 /*
  *     device multicast group del
  */
 int ipv6_dev_mc_dec(struct device *dev, struct in6_addr *addr)
 {
-       return 0;
+       struct ifmcaddr6 *ma, **lnk;
+       int hash;
+
+       hash = ipv6_addr_hash(addr);
+
+       lnk = &inet6_mcast_lst[hash];
+
+       for (ma = inet6_mcast_lst[hash]; ma; ma = ma->next) {
+               if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
+                       if (atomic_dec_and_test(&ma->mca_users)) {
+                               igmp6_leave_group(ma);
+                               *lnk = ma->next;
+                               ipv6_mca_remove(ma->dev, ma);
+                               kfree(ma);
+                       }
+                       return 0;
+               }
+               lnk = &ma->next;
+       }
+
+       return -ENOENT;
 }
 
 /*
@@ -195,17 +291,15 @@ int ipv6_dev_mc_dec(struct device *dev, struct in6_addr *addr)
  */
 int ipv6_chk_mcast_addr(struct device *dev, struct in6_addr *addr)
 {
-       struct ipv6_mc_list *mc;        
-       u8 hash;
+       struct ifmcaddr6 *mc;
+       int hash;
 
        hash = ipv6_addr_hash(addr);
 
-       for (mc = inet6_mcast_lst[hash]; mc; mc=mc->next)
-               if ((mc->dev == dev) &&
-                   ipv6_addr_cmp(&mc->addr, addr) == 0)
-               {
+       for (mc = inet6_mcast_lst[hash]; mc; mc=mc->next) {
+               if ((mc->dev == dev) && ipv6_addr_cmp(&mc->mca_addr, addr) == 0)
                        return 1;
-               }
+       }
 
        return 0;
 }
@@ -214,8 +308,216 @@ int ipv6_chk_mcast_addr(struct device *dev, struct in6_addr *addr)
  *     IGMP handling (alias multicast ICMPv6 messages)
  */
 
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o mcast.o mcast.c"
- * End:
- */
+static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
+{
+       unsigned long delay;
+
+       ma->mca_flags |= MAF_TIMER_RUNNING;
+
+       delay = ipv6_random() % resptime;
+       ma->mca_timer.expires = jiffies + delay;
+       add_timer(&ma->mca_timer);
+}
+
+int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
+{
+       struct ifmcaddr6 *ma;
+       struct in6_addr *addrp;
+       unsigned long resptime;
+
+       if (len < sizeof(struct icmp6hdr) + sizeof(struct ipv6hdr))
+               return -EINVAL;
+
+       resptime = hdr->icmp6_maxdelay;
+
+       addrp = (struct in6_addr *) (hdr + 1);
+
+       if (ipv6_addr_any(addrp)) {
+               struct inet6_dev *idev;
+
+               idev = ipv6_get_idev(skb->dev);
+
+               if (idev == NULL)
+                       return 0;
+
+               for (ma = idev->mc_list; ma; ma=ma->if_next)
+                       igmp6_group_queried(ma, resptime);
+       } else {
+               int hash = ipv6_addr_hash(addrp);
+
+               for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) {
+                       if (ma->dev == skb->dev &&
+                           ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
+                               igmp6_group_queried(ma, resptime);
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
+{
+       struct ifmcaddr6 *ma;
+       struct in6_addr *addrp;
+       struct device *dev;
+       int hash;
+
+       if (len < sizeof(struct icmp6hdr) + sizeof(struct ipv6hdr))
+               return -EINVAL;
+
+       addrp = (struct in6_addr *) (hdr + 1);
+
+       dev = skb->dev;
+
+       /*
+        *      Cancel the timer for this group
+        */
+
+       hash = ipv6_addr_hash(addrp);
+
+       for (ma = inet6_mcast_lst[hash]; ma; ma=ma->next) {
+               if ((ma->dev == dev) && ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
+                       if (ma->mca_flags & MAF_TIMER_RUNNING) {
+                               del_timer(&ma->mca_timer);
+                               ma->mca_flags &= ~MAF_TIMER_RUNNING;
+                       }
+
+                       ma->mca_flags &= ~MAF_LAST_REPORTER;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+void igmp6_send(struct in6_addr *addr, struct device *dev, int type)
+{
+       struct sock *sk = igmp6_socket->sk;
+        struct sk_buff *skb;
+        struct icmp6hdr *hdr;
+       struct inet6_ifaddr *ifp;
+       struct in6_addr *addrp; 
+       int err, len, plen;
+
+       len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+
+       plen = sizeof(struct ipv6hdr) + len;
+
+       skb = sock_alloc_send_skb(sk, dev->hard_header_len + plen, 0, 0, &err);
+
+       if (skb == NULL)
+               return;
+
+       if (dev->hard_header_len) {
+               skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+               if (dev->hard_header) {
+                       unsigned char ha[MAX_ADDR_LEN];
+                       ipv6_mc_map(addr, ha);
+                       dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, plen);
+                       skb->arp = 1;
+               }
+       }
+
+       ifp = ipv6_get_lladdr(dev);
+
+       if (ifp == NULL) {
+#if MCAST_DEBUG >= 1
+               printk(KERN_DEBUG "igmp6: %s no linklocal address\n",
+                      dev->name);
+#endif
+               return;
+       }
+
+       ip6_nd_hdr(sk, skb, dev, &ifp->addr, addr, IPPROTO_ICMPV6, len);
+
+       /*
+        *      need hop-by-hop router alert option.
+        */
+
+       hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
+       memset(hdr, 0, sizeof(struct icmp6hdr));
+       hdr->icmp6_type = type;
+
+       addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
+       ipv6_addr_copy(addrp, addr);
+
+       hdr->icmp6_cksum = csum_ipv6_magic(&ifp->addr, addr, len,
+                                          IPPROTO_ICMPV6,
+                                          csum_partial((__u8 *) hdr, len, 0));
+
+       dev_queue_xmit(skb);
+}
+
+static void igmp6_join_group(struct ifmcaddr6 *ma)
+{
+       unsigned long delay;
+       int addr_type;
+
+       addr_type = ipv6_addr_type(&ma->mca_addr);
+
+       if ((addr_type & IPV6_ADDR_LINKLOCAL))
+               return;
+
+       igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT);
+
+       delay = ipv6_random() % IGMP6_UNSOLICITED_IVAL;
+       ma->mca_timer.expires = jiffies + delay;
+
+       add_timer(&ma->mca_timer);
+       ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
+}
+
+static void igmp6_leave_group(struct ifmcaddr6 *ma)
+{
+       int addr_type;
+
+       addr_type = ipv6_addr_type(&ma->mca_addr);
+
+       if ((addr_type & IPV6_ADDR_LINKLOCAL))
+               return;
+
+       if (ma->mca_flags & MAF_LAST_REPORTER)
+               igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REDUCTION);
+
+       if (ma->mca_flags & MAF_TIMER_RUNNING)
+               del_timer(&ma->mca_timer);
+}
+
+void igmp6_timer_handler(unsigned long data)
+{
+       struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
+
+       ma->mca_flags |=  MAF_LAST_REPORTER;
+       igmp6_send(&ma->mca_addr, ma->dev, ICMPV6_MGM_REPORT);
+       ma->mca_flags &= ~MAF_TIMER_RUNNING;
+}
+
+void igmp6_init(struct net_proto_family *ops)
+{
+       struct sock *sk;
+       int err;
+
+       igmp6_inode.i_mode = S_IFSOCK;
+       igmp6_inode.i_sock = 1;
+       igmp6_inode.i_uid = 0;
+       igmp6_inode.i_gid = 0;
+
+       igmp6_socket->inode = &igmp6_inode;
+       igmp6_socket->state = SS_UNCONNECTED;
+       igmp6_socket->type = SOCK_RAW;
+
+       if((err=ops->create(igmp6_socket, IPPROTO_ICMPV6))<0)
+               printk(KERN_DEBUG 
+                      "Failed to create the IGMP6 control socket.\n");
+
+       MOD_DEC_USE_COUNT;
+
+       sk = igmp6_socket->sk;
+       sk->allocation = GFP_ATOMIC;
+       sk->num = 256;                  /* Don't receive any data */
+
+       sk->net_pinfo.af_inet6.hop_limit = 1;
+}
index c8bf2fa62edb69a3a11e9a75120bd70dca7fe424..4169b18c50022d7081a51da7dbc69dd075e3b8b8 100644 (file)
@@ -6,7 +6,7 @@
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *     Mike Shaver             <shaver@ingenia.com>
  *
- *     $Id: ndisc.c,v 1.28 1996/10/11 16:03:06 roque Exp $
+ *     $Id: ndisc.c,v 1.13 1997/03/18 18:24:41 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
  *     Janos Farkas                    :       kmalloc failure checks
  */
 
+/* Set to 3 to get tracing... */
 #define ND_DEBUG 2
 
+#if ND_DEBUG >= 3
+#define NDBG(x) printk x
+#else
+#define NDBG(x)
+#endif
+
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/config.h>
@@ -37,7 +44,6 @@
 #include <linux/in6.h>
 #include <linux/route.h>
 
-#include <net/neighbour.h>
 #include <linux/if_arp.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
@@ -48,7 +54,7 @@
 #include <net/ipv6.h>
 #include <net/protocol.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 
 
@@ -68,9 +74,7 @@ struct ndisc_statistics nd_stats;
 static struct neigh_table nd_tbl;
 
 unsigned int   ndisc_hash(void *primary_key);
-int                    ndisc_eth_resolv(unsigned char *h_dest,
-                                        struct device *dev,
-                                        struct sk_buff *skb);
+int            ndisc_eth_resolv(unsigned char *h_dest, struct sk_buff *skb);
 
 static struct neigh_ops nd_neigh_ops = {
        ETH_P_IPV6,
@@ -86,13 +90,8 @@ static struct timer_list ndisc_gc_timer;
  *     Protocol variables
  */
 
-int    nd_max_multicast_solicit        = 3;
-int    nd_max_unicast_solicit          = 3;
-int    nd_retrans_timer                = RETRANS_TIMER;
-int    nd_reachable_time               = RECHABLE_TIME;
-int    nd_base_reachable_time          = RECHABLE_TIME;
-int    nd_delay_first_probe            = 5 * HZ;
-int    nd_gc_interval                  = 5 * HZ;
+unsigned long  nd_reachable_time               = RECHABLE_TIME;
+int            nd_gc_interval                  = 5 * HZ;
 
 /* 
  *     garbage collection timeout must be greater than reachable time
@@ -106,7 +105,7 @@ int nd_gc_staletime                 = 3 * RECHABLE_TIME;
 
 static int  ndisc_event_timer(struct nd_neigh *ndn);
 
-int ipv6_random(void)
+unsigned long ipv6_random(void)
 {
        nd_rand_seed=nd_rand_seed*69069L+1;
         return nd_rand_seed^jiffies;
@@ -116,17 +115,15 @@ static __inline__ unsigned long rand_reach_time(void)
 {
        unsigned long val;
 
-       val = ipv6_random() % (MAX_RANDOM_FACTOR * nd_base_reachable_time);
-       if (val < (MIN_RANDOM_FACTOR * nd_base_reachable_time))
-       {
-               val += (MIN_RANDOM_FACTOR * nd_base_reachable_time);
-       }
+       val = ipv6_random() % (MAX_RANDOM_FACTOR *
+                              ipv6_config.nd_base_reachable_time);
+
+       if (val < (MIN_RANDOM_FACTOR * ipv6_config.nd_base_reachable_time))
+               val+= (MIN_RANDOM_FACTOR * ipv6_config.nd_base_reachable_time);
 
        return val;
 }
 
-void ndisc_verify_reachability(struct neighbour * neigh);
-
 unsigned int ndisc_hash(void *primary_key)
 {
         struct in6_addr *addr = (struct in6_addr *) primary_key;
@@ -152,8 +149,7 @@ static void ndisc_periodic_timer(unsigned long arg)
         *      periodicly compute ReachableTime from random function
         */
        
-       if ((now - last_rand) > REACH_RANDOM_INTERVAL)
-       {
+       if ((now - last_rand) > REACH_RANDOM_INTERVAL) {
                last_rand = now;
                nd_reachable_time = rand_reach_time();
        }
@@ -161,13 +157,10 @@ static void ndisc_periodic_timer(unsigned long arg)
        neigh_table_lock(&nd_tbl);
 
        start_bh_atomic();
-       if (nd_tbl.tbl_lock == 1)
-       {
+       if (nd_tbl.tbl_lock == 1) {
                ntbl_walk_table(&nd_tbl, ndisc_gc_func, 0, 0, NULL);
                ndisc_gc_timer.expires = now + nd_gc_interval;
-       }
-       else
-       {
+       } else {
 #if ND_DEBUG >= 2
                printk(KERN_DEBUG "ndisc_gc delayed: table locked\n");
 #endif
@@ -185,8 +178,7 @@ static int ndisc_gc_func(struct neighbour *neigh, void *arg)
        struct nd_neigh *ndn = (struct nd_neigh *) neigh;
         unsigned long now = jiffies;
 
-       if (ndn->ndn_refcnt == 0)
-       {
+       if (ndn->ndn_refcnt == 0) {
                switch (ndn->ndn_nud_state) {
                
                case NUD_REACHABLE:
@@ -196,7 +188,7 @@ static int ndisc_gc_func(struct neighbour *neigh, void *arg)
                case NUD_FAILED:
                        return 1;
                default:
-               }
+               };
        }
        return 0;
 }
@@ -209,9 +201,7 @@ static __inline__ void ndisc_add_timer(struct nd_neigh *ndn, int timer)
        ndn->ndn_expires = now + timer;
        
        if (del_timer(&ndisc_timer))
-       {
                tval = ndisc_timer.expires;
-       }
 
        tval = min(tval, ndn->ndn_expires);
 
@@ -222,17 +212,15 @@ static __inline__ void ndisc_add_timer(struct nd_neigh *ndn, int timer)
 static void ndisc_del_timer(struct nd_neigh *ndn)
 {
        unsigned long tval = ~0UL;
-
-       if (!(ndn->ndn_nud_state & NUD_IN_TIMER))
-               return;
+       unsigned long neigh_val;
 
        if (del_timer(&ndisc_timer))
-       {
                tval = ndisc_timer.expires;
-       }
-       
-       if (tval == ndn->ndn_expires)
-       {
+
+       neigh_val = ndn->ndn_expires;
+       ndn->ndn_expires = 0;
+
+       if (tval == neigh_val) {
                int i;
                
                tval = ~0UL;
@@ -240,27 +228,24 @@ static void ndisc_del_timer(struct nd_neigh *ndn)
                neigh_table_lock(&nd_tbl);
                
                /* need to search the entire neighbour cache */
-               for (i=0; i < nd_tbl.tbl_size; i++)
-               {
+               for (i=0; i < nd_tbl.tbl_size; i++) {
                        struct neighbour *neigh, *head;
                        head = nd_tbl.hash_buckets[i];
                                
                        if ((neigh = head) == NULL)
                                continue;
-                       
-                       do
-                       {
+
+                       do {
                                struct nd_neigh *n;
 
                                n = (struct nd_neigh *) neigh;
 
-                               if (n->ndn_nud_state & NUD_IN_TIMER)
-                               {
+                               if ((n->ndn_nud_state & NUD_IN_TIMER) &&
+                                    n->ndn_expires)
                                        tval = min(tval, n->ndn_expires);
-                               }
-                               
+
                                neigh = neigh->next;
-                               
+
                        } while (neigh != head);
                }
                neigh_table_unlock(&nd_tbl);
@@ -277,12 +262,9 @@ static int ndisc_forced_gc(struct neighbour *neigh, void *arg)
 {
        struct nd_neigh *ndn = (struct nd_neigh *) neigh;
 
-       if (ndn->ndn_refcnt == 0)
-       {
+       if (ndn->ndn_refcnt == 0) {
                if (ndn->ndn_nud_state & NUD_IN_TIMER)
-               {
                        ndisc_del_timer(ndn);
-               }
                
                return 1;
        }
@@ -294,20 +276,26 @@ static struct nd_neigh * ndisc_new_neigh(struct device *dev,
 {
        struct nd_neigh *ndn;
 
+       NDBG(("ndisc_new_neigh("));
+       if(dev)
+               NDBG(("%s,", dev->name));
+       else
+               NDBG(("[NULL],"));
+       NDBG(("[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]): ",
+             addr->s6_addr16[0], addr->s6_addr16[1], addr->s6_addr16[2],
+             addr->s6_addr16[3], addr->s6_addr16[4], addr->s6_addr16[5],
+             addr->s6_addr16[6], addr->s6_addr16[7]));
+
        ndn = (struct nd_neigh *) neigh_alloc(sizeof(struct nd_neigh),
-                                             GFP_ATOMIC);
-       
-       if (ndn == NULL)
-       {
+                                             &nd_neigh_ops);
+       if (ndn == NULL) {
 
 #if ND_DEBUG >= 2
                printk(KERN_DEBUG "neigh_alloc: out of memory\n");
 #endif
 
                start_bh_atomic();
-               if (nd_tbl.tbl_lock == 1)
-               {
-
+               if (nd_tbl.tbl_lock == 1) {
 #if ND_DEBUG >= 2
                        printk(KERN_DEBUG "ndisc_alloc: forcing gc\n");
 #endif
@@ -329,12 +317,19 @@ static struct nd_neigh * ndisc_new_neigh(struct device *dev,
        ndn->ndn_dev = dev;
        ndn->ndn_tstamp = jiffies;
 
-       if (dev->type == ARPHRD_LOOPBACK || dev->type == ARPHRD_SIT)
-       {
+       if ((ndn->ndn_type & IPV6_ADDR_MULTICAST)) {
+               NDBG(("MULTICAST(NCF_NOARP) "));
+               ndn->ndn_flags |= NCF_NOARP;
+       }
+
+       if (dev->type == ARPHRD_LOOPBACK || dev->type == ARPHRD_SIT) {
+               NDBG(("%s(NCF_NOARP) ",
+                     (dev->type==ARPHRD_LOOPBACK) ? "LOOPBACK" : "SIT"));
                ndn->ndn_flags |= NCF_NOARP;
        }
 
        neigh_insert(&nd_tbl, (struct neighbour *) ndn);
+       NDBG(("returning ndn(%p)\n", ndn));
        return ndn;
 }
 
@@ -353,10 +348,9 @@ struct neighbour * ndisc_get_neigh(struct device *dev, struct in6_addr *addr)
         *      cached information about nexthop and addr resolution
         */
 
-       if (dev == NULL)
-       {
+       if (dev == NULL) {
 #if ND_DEBUG >= 1
-               printk(KERN_DEBUG "ncache_get_neigh: NULL device\n");
+               printk(KERN_DEBUG "ndisc_get_neigh: NULL device\n");
 #endif
                return NULL;
        }
@@ -365,10 +359,7 @@ struct neighbour * ndisc_get_neigh(struct device *dev, struct in6_addr *addr)
 
         neigh = (struct nd_neigh *) neigh_lookup(&nd_tbl, (void *) addr,
                                                 sizeof(struct in6_addr), dev);
-
-       
-       if (neigh == NULL)
-       {
+       if (neigh == NULL) {
                neigh = ndisc_new_neigh(dev, addr);
 
                if (neigh == NULL)
@@ -377,9 +368,7 @@ struct neighbour * ndisc_get_neigh(struct device *dev, struct in6_addr *addr)
 
        neigh_table_unlock(&nd_tbl);
 
-       atomic_inc(&neigh->ndn_refcnt);
-       
-       return (struct neighbour *) neigh;      
+       return neighbour_clone((struct neighbour *) neigh);
 }
 
 /*
@@ -388,45 +377,35 @@ struct neighbour * ndisc_get_neigh(struct device *dev, struct in6_addr *addr)
  *     1 - Address Resolution unfinished / packet queued
  */
 
-int ndisc_eth_resolv(unsigned char *h_dest, struct device *dev,
-                    struct sk_buff *skb)
+int ndisc_eth_resolv(unsigned char *h_dest, struct sk_buff *skb)
 {
-       struct nd_neigh *ndn;
+       struct nd_neigh *ndn = NULL;
 
-       ndn = (struct nd_neigh *) skb->nexthop;
-       
-       if (ndn == NULL)
-       {
-               struct in6_addr *daddr;
-               int addr_type;
-
-               daddr = &skb->nh.ipv6h->daddr;
-               
-               addr_type = ipv6_addr_type(daddr);
-               
-               if (addr_type & IPV6_ADDR_MULTICAST)
-               {
-                       ipv6_mc_map(daddr, h_dest);
-                       return 0;
-               }
+       if (skb->dst)
+               ndn = (struct nd_neigh *) skb->dst->neighbour;
 
+       if (ndn == NULL) {
 #if ND_DEBUG >= 2
                printk(KERN_DEBUG "ndisc_eth_resolv: nexthop is NULL\n");
 #endif
                goto discard;
        }
 
-       if (skb->pkt_type == PACKET_NDISC)
-               goto ndisc_pkt;
-       
+       if ((ndn->ndn_type & IPV6_ADDR_MULTICAST)) {
+               struct in6_addr *daddr;
+
+               daddr = &skb->nh.ipv6h->daddr;
+               ipv6_mc_map(daddr, h_dest);
+               return 0;
+       }
+
        switch (ndn->ndn_nud_state) {   
        case NUD_FAILED:
        case NUD_NONE:
                ndisc_event_send((struct neighbour *)ndn, skb);
 
        case NUD_INCOMPLETE:                    
-               if (skb_queue_len(&ndn->neigh.arp_queue) >= NDISC_QUEUE_LEN)
-               {
+               if (skb_queue_len(&ndn->neigh.arp_queue) >= NDISC_QUEUE_LEN) {
                        struct sk_buff *buff;
                        
                        buff = ndn->neigh.arp_queue.prev;
@@ -437,18 +416,15 @@ int ndisc_eth_resolv(unsigned char *h_dest, struct device *dev,
                return 1;
        default:
                ndisc_event_send((struct neighbour *)ndn, skb);
-       }
+       };
 
-  ndisc_pkt:
-       
-       if ((ndn->ndn_flags & NTF_COMPLETE) == 0)
-       {
+       if ((ndn->ndn_flags & NTF_COMPLETE) == 0) {
 #if ND_DEBUG >=1
                /* This shouldn't happen */
                printk(KERN_DEBUG "ND: using incomplete entry\n");
 #endif
        }
-       memcpy(h_dest, ndn->ndn_ha, dev->addr_len);
+       memcpy(h_dest, ndn->ndn_ha, skb->dev->addr_len);
        return 0;
 
   discard:
@@ -457,14 +433,12 @@ int ndisc_eth_resolv(unsigned char *h_dest, struct device *dev,
        return 1;
 }
 
-
 /*
  *     Send a Neighbour Advertisement
  */
 
 void ndisc_send_na(struct device *dev, struct nd_neigh *ndn,
-                  struct in6_addr *daddr,
-                  struct in6_addr *solicited_addr,
+                  struct in6_addr *daddr, struct in6_addr *solicited_addr,
                   int router, int solicited, int override, int inc_opt) 
 {
         struct sock *sk = ndisc_socket->sk;
@@ -473,38 +447,64 @@ void ndisc_send_na(struct device *dev, struct nd_neigh *ndn,
         struct sk_buff *skb;
        int err;
 
+       NDBG(("ndisc_send_na("));
+       if(dev)
+               NDBG(("%s,", dev->name));
+       else
+               NDBG(("[NULL]"));
+       NDBG(("%p): ", ndn));
+       if(daddr)
+               NDBG(("daddr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     daddr->s6_addr16[0], daddr->s6_addr16[1], daddr->s6_addr16[2],
+                     daddr->s6_addr16[3], daddr->s6_addr16[4], daddr->s6_addr16[5],
+                     daddr->s6_addr16[6], daddr->s6_addr16[7]));
+       if(solicited_addr)
+               NDBG(("solicit_addr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     solicited_addr->s6_addr16[0], solicited_addr->s6_addr16[1],
+                     solicited_addr->s6_addr16[2], solicited_addr->s6_addr16[3],
+                     solicited_addr->s6_addr16[4], solicited_addr->s6_addr16[5],
+                     solicited_addr->s6_addr16[6], solicited_addr->s6_addr16[7]));
+       NDBG(("rtr(%d)sol(%d)ovr(%d)iopt(%d)\n", router, solicited, override, inc_opt));
+
        opt_len = ((dev->addr_len + 1) >> 3) + 1;
-       len = sizeof(struct icmpv6hdr) + sizeof(struct in6_addr);
+       len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 
+#if ND_DEBUG >=1
+       if (dev == NULL) {
+               printk(KERN_DEBUG "send_na: null device\n");
+               return;
+       }
+#endif
        if (inc_opt)
-       {
                len += opt_len << 3;
-       }
 
-       skb = sock_alloc_send_skb(sk, MAX_HEADER + len, 0, 0, &err);
+       skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+                                 0, 0, &err);
 
-       if (skb == NULL)
-       {
+       if (skb == NULL) {
                printk(KERN_DEBUG "send_na: alloc skb failed\n");
                return;
        }
-
-       if (ipv6_bld_hdr_2(sk, skb, dev, (struct neighbour *) ndn, 
-                          solicited_addr, daddr, IPPROTO_ICMPV6, len) < 0)
-        {
-               kfree_skb(skb, FREE_WRITE);
-               printk(KERN_DEBUG 
-                      "ndisc_send_na: ipv6_build_header returned < 0\n");
-               return;
+       /*
+        *      build the MAC header
+        */
+       
+       if (dev->hard_header_len) {
+               skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+               if (dev->hard_header) {
+                       dev->hard_header(skb, dev, ETH_P_IPV6, ndn->ndn_ha,
+                                        NULL, len);
+                       skb->arp = 1;
+               }
        }
 
-       skb->pkt_type = PACKET_NDISC;
-       
+       ip6_nd_hdr(sk, skb, dev, solicited_addr, daddr, IPPROTO_ICMPV6, len);
+
        msg = (struct nd_msg *) skb_put(skb, len);
 
-        msg->icmph.type = NDISC_NEIGHBOUR_ADVERTISEMENT;
-        msg->icmph.code = 0;
-        msg->icmph.checksum = 0;
+        msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+        msg->icmph.icmp6_code = 0;
+        msg->icmph.icmp6_cksum = 0;
 
         msg->icmph.icmp6_unused = 0;
         msg->icmph.icmp6_router    = router;
@@ -514,47 +514,66 @@ void ndisc_send_na(struct device *dev, struct nd_neigh *ndn,
         /* Set the target address. */
        ipv6_addr_copy(&msg->target, solicited_addr);
 
-       if (inc_opt)
-       {
+       if (inc_opt) {
                /* Set the source link-layer address option. */
                msg->opt.opt_type = ND_OPT_TARGET_LL_ADDR;
                msg->opt.opt_len = opt_len;
                memcpy(msg->opt.link_addr, dev->dev_addr, dev->addr_len);
 
-               if ((opt_len << 3) - (2 + dev->addr_len))
-               {
+               if ((opt_len << 3) - (2 + dev->addr_len)) {
                        memset(msg->opt.link_addr + dev->addr_len, 0,
                               (opt_len << 3) - (2 + dev->addr_len));
                }
        }
 
        /* checksum */
-       msg->icmph.checksum = csum_ipv6_magic(solicited_addr, daddr, len, 
-                                             IPPROTO_ICMPV6,
-                                             csum_partial((__u8 *) msg, 
-                                                          len, 0));
+       msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len, 
+                                                IPPROTO_ICMPV6,
+                                                csum_partial((__u8 *) msg, 
+                                                             len, 0));
 
-       ipv6_queue_xmit(sk, skb->dev, skb, 1);
+       dev_queue_xmit(skb);
 }        
 
 void ndisc_send_ns(struct device *dev, struct neighbour *neigh,
                   struct in6_addr *solicit,
                   struct in6_addr *daddr, struct in6_addr *saddr) 
 {
+       unsigned char ha[MAX_ADDR_LEN];
         struct sock *sk = ndisc_socket->sk;
         struct sk_buff *skb;
         struct nd_msg *msg;
-        int len, opt_len;
+        int len, opt_len;      
+       void *h_dest;
        int err;
 
+       NDBG(("ndisc_send_ns(%s,%p): ", (dev ? dev->name : "[NULL]"), neigh));
+       if(daddr)
+               NDBG(("daddr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     daddr->s6_addr16[0], daddr->s6_addr16[1], daddr->s6_addr16[2],
+                     daddr->s6_addr16[3], daddr->s6_addr16[4], daddr->s6_addr16[5],
+                     daddr->s6_addr16[6], daddr->s6_addr16[7]));
+       if(saddr)
+               NDBG(("saddr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     saddr->s6_addr16[0], saddr->s6_addr16[1], saddr->s6_addr16[2],
+                     saddr->s6_addr16[3], saddr->s6_addr16[4], saddr->s6_addr16[5],
+                     saddr->s6_addr16[6], saddr->s6_addr16[7]));
+       if(solicit)
+               NDBG(("solicit[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     solicit->s6_addr16[0], solicit->s6_addr16[1],
+                     solicit->s6_addr16[2], solicit->s6_addr16[3],
+                     solicit->s6_addr16[4], solicit->s6_addr16[5],
+                     solicit->s6_addr16[6], solicit->s6_addr16[7]));
+       NDBG(("\n"));
+
        /* length of addr in 8 octet groups.*/
        opt_len = ((dev->addr_len + 1) >> 3) + 1;
-       len = sizeof(struct icmpv6hdr) + sizeof(struct in6_addr) +
+       len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr) +
                 (opt_len << 3);
 
-       skb = sock_alloc_send_skb(sk, MAX_HEADER + len, 0, 0, &err);
-       if (skb == NULL)
-       {
+       skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+                                 0, 0, &err);
+       if (skb == NULL) {
 #if ND_DEBUG >= 1
                printk(KERN_DEBUG "send_ns: alloc skb failed\n");
 #endif
@@ -563,41 +582,47 @@ void ndisc_send_ns(struct device *dev, struct neighbour *neigh,
 
        skb->pkt_type = PACKET_NDISC;
 
-       if (saddr == NULL)
-       {
+       if (saddr == NULL) {
                struct inet6_ifaddr *ifa;
 
                /* use link local address */
                ifa = ipv6_get_lladdr(dev);
 
                if (ifa)
-               {
                        saddr = &ifa->addr;
-               }
        }
 
-       if(ipv6_addr_type(daddr) == IPV6_ADDR_MULTICAST)
-       {
+       if ((ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST)) {
                nd_stats.snt_probes_mcast++;
-       }
-        else
-       {
+               ipv6_mc_map(daddr, ha);
+               h_dest = ha;
+       } else {
+               if (neigh == NULL) {
+#if ND_DEBUG >= 1
+                       printk(KERN_DEBUG "send_ns: ucast destination "
+                              "with null neighbour\n");
+#endif
+                       return;
+               }
+               h_dest = neigh->ha;
                nd_stats.snt_probes_ucast++;
        }
 
-       if (ipv6_bld_hdr_2(sk, skb, dev, neigh, saddr, daddr, IPPROTO_ICMPV6,
-                          len) < 0 )
-       {
-               kfree_skb(skb, FREE_WRITE);
-               printk(KERN_DEBUG
-                      "ndisc_send_ns: ipv6_build_header returned < 0\n");
-               return;
+       if (dev->hard_header_len) {
+               skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+               if (dev->hard_header) {
+                       dev->hard_header(skb, dev, ETH_P_IPV6, h_dest, NULL,
+                                        len);
+                       skb->arp = 1;
+               }
        }
+
+       ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
        
        msg = (struct nd_msg *)skb_put(skb, len);
-       msg->icmph.type = NDISC_NEIGHBOUR_SOLICITATION;
-       msg->icmph.code = 0;
-       msg->icmph.checksum = 0;
+       msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
+       msg->icmph.icmp6_code = 0;
+       msg->icmph.icmp6_cksum = 0;
        msg->icmph.icmp6_unused = 0;
 
        /* Set the target address. */
@@ -609,20 +634,19 @@ void ndisc_send_ns(struct device *dev, struct neighbour *neigh,
 
        memcpy(msg->opt.link_addr, dev->dev_addr, dev->addr_len);
 
-       if ((opt_len << 3) - (2 + dev->addr_len))
-       {
+       if ((opt_len << 3) - (2 + dev->addr_len)) {
                memset(msg->opt.link_addr + dev->addr_len, 0,
                       (opt_len << 3) - (2 + dev->addr_len));
        }
 
        /* checksum */
-       msg->icmph.checksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
-                                             daddr, len, 
-                                             IPPROTO_ICMPV6,
-                                             csum_partial((__u8 *) msg, 
-                                                          len, 0));
+       msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
+                                                daddr, len, 
+                                                IPPROTO_ICMPV6,
+                                                csum_partial((__u8 *) msg, 
+                                                             len, 0));
        /* send it! */
-       ipv6_queue_xmit(sk, skb->dev, skb, 1);
+       dev_queue_xmit(skb);
 }
 
 void ndisc_send_rs(struct device *dev, struct in6_addr *saddr,
@@ -630,35 +654,52 @@ void ndisc_send_rs(struct device *dev, struct in6_addr *saddr,
 {
        struct sock *sk = ndisc_socket->sk;
         struct sk_buff *skb;
-        struct icmpv6hdr *hdr;
+        struct icmp6hdr *hdr;
        __u8 * opt;
         int len, opt_len;
        int err;
 
+       NDBG(("ndisc_send_rs(%s): ", (dev ? dev->name : "[NULL]")));
+       if(daddr)
+               NDBG(("daddr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     daddr->s6_addr16[0], daddr->s6_addr16[1], daddr->s6_addr16[2],
+                     daddr->s6_addr16[3], daddr->s6_addr16[4], daddr->s6_addr16[5],
+                     daddr->s6_addr16[6], daddr->s6_addr16[7]));
+       if(saddr)
+               NDBG(("saddr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     saddr->s6_addr16[0], saddr->s6_addr16[1], saddr->s6_addr16[2],
+                     saddr->s6_addr16[3], saddr->s6_addr16[4], saddr->s6_addr16[5],
+                     saddr->s6_addr16[6], saddr->s6_addr16[7]));
+       NDBG(("\n"));
+
        /* length of addr in 8 octet groups.*/
        opt_len = ((dev->addr_len + 1) >> 3) + 1;
-       len = sizeof(struct icmpv6hdr) + (opt_len << 3);
+       len = sizeof(struct icmp6hdr) + (opt_len << 3);
 
-        skb = sock_alloc_send_skb(sk, MAX_HEADER + len, 0, 0, &err);
-       if (skb == NULL)
-       {
+        skb = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+                                 0, 0, &err);
+       if (skb == NULL) {
                printk(KERN_DEBUG "send_ns: alloc skb failed\n");
                return;
        }
 
-        if (ipv6_bld_hdr_2(sk, skb, dev, NULL, saddr, daddr, IPPROTO_ICMPV6,
-                          len) < 0 )
-       {
-                kfree_skb(skb, FREE_WRITE);
-                printk(KERN_DEBUG
-                       "ndisc_send_ns: ipv6_build_header returned < 0\n");
-                return;
-        }
+       if (dev->hard_header_len) {
+               skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+               if (dev->hard_header) {
+                       unsigned char ha[MAX_ADDR_LEN];
+
+                       ipv6_mc_map(daddr, ha);
+                       dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, len);
+                       skb->arp = 1;
+               }
+       }
+
+       ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
        
-        hdr = (struct icmpv6hdr *) skb_put(skb, len);
-        hdr->type = NDISC_ROUTER_SOLICITATION;
-        hdr->code = 0;
-        hdr->checksum = 0;
+        hdr = (struct icmp6hdr *) skb_put(skb, len);
+        hdr->icmp6_type = NDISC_ROUTER_SOLICITATION;
+        hdr->icmp6_code = 0;
+        hdr->icmp6_cksum = 0;
         hdr->icmp6_unused = 0;
 
        opt = (u8*) (hdr + 1);
@@ -669,27 +710,25 @@ void ndisc_send_rs(struct device *dev, struct in6_addr *saddr,
 
         memcpy(opt + 2, dev->dev_addr, dev->addr_len);
 
-       if ((opt_len << 3) - (2 + dev->addr_len))
-       {
+       if ((opt_len << 3) - (2 + dev->addr_len)) {
                memset(opt + 2 + dev->addr_len, 0,
                       (opt_len << 3) - (2 + dev->addr_len));
        }
 
        /* checksum */
-       hdr->checksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,
-                                       IPPROTO_ICMPV6,
-                                       csum_partial((__u8 *) hdr, len, 0));
+       hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len,
+                                          IPPROTO_ICMPV6,
+                                          csum_partial((__u8 *) hdr, len, 0));
 
        /* send it! */
-       ipv6_queue_xmit(sk, skb->dev, skb, 1);
+       dev_queue_xmit(skb);
 }
                   
 
 static int ndisc_store_hwaddr(struct nd_neigh *ndn, __u8 *opt, int opt_len,
                              int option)
 {
-       while (*opt != option && opt_len)
-       {
+       while (*opt != option && opt_len) {
                int len;
 
                len = opt[1] << 3;
@@ -704,8 +743,7 @@ static int ndisc_store_hwaddr(struct nd_neigh *ndn, __u8 *opt, int opt_len,
                opt_len -= len;
        }
 
-       if (*opt == option)
-       {
+       if (*opt == option) {
                memcpy(ndn->neigh.ha, opt + 2, ndn->ndn_dev->addr_len); 
                return 0;
        }
@@ -723,40 +761,32 @@ static void ndisc_timer_handler(unsigned long arg)
 
        neigh_table_lock(&nd_tbl);
        
-       for (i=0; i < nd_tbl.tbl_size; i++)
-       {
+       for (i=0; i < nd_tbl.tbl_size; i++) {
                struct nd_neigh *ndn, *head;
 
                head = (struct nd_neigh *) nd_tbl.hash_buckets[i];
 
                if ((ndn = head) == NULL)
                        continue;
-               
-               do
-               {
-                        if (ndn->ndn_nud_state & NUD_IN_TIMER)
-                       {
+
+               do {
+                        if (ndn->ndn_nud_state & NUD_IN_TIMER) {
                                unsigned long time;
 
                                time = ndn->ndn_expires - now;
 
                                if ((long) time <= 0)
-                               {
                                        time = ndisc_event_timer(ndn);
-                               }
                                
                                if (time)
-                               {
                                        ntimer = min(ntimer, time);
-                               }
                        }
                        ndn = (struct nd_neigh *) ndn->neigh.next;
 
                } while (ndn != head);
        }
 
-       if (ntimer != (~0UL))
-       {
+       if (ntimer != (~0UL)) {
                ndisc_timer.expires = now + ntimer;
                add_timer(&ndisc_timer);
        }
@@ -774,23 +804,20 @@ static int ndisc_event_timer(struct nd_neigh *ndn)
        int max_probes;
 
        if (ndn->ndn_nud_state == NUD_DELAY)
-       {
                ndn->ndn_nud_state = NUD_PROBE;
-       }
 
-       max_probes = (ndn->ndn_nud_state == NUD_PROBE ? nd_max_unicast_solicit:
-                     nd_max_multicast_solicit);
+       max_probes = (ndn->ndn_nud_state == NUD_PROBE ?
+                     ipv6_config.nd_max_ucast_solicit:
+                     ipv6_config.nd_max_mcast_solicit);
 
-       if (ndn->ndn_probes == max_probes)
-       {
+       if (ndn->ndn_probes == max_probes) {
                struct sk_buff *skb;
 
                ndn->ndn_nud_state = NUD_FAILED;
                ndn->ndn_flags &= ~NTF_COMPLETE;
                nd_stats.res_failed++;
 
-               while((skb=skb_dequeue(&ndn->neigh.arp_queue)))
-               {
+               while((skb=skb_dequeue(&ndn->neigh.arp_queue))) {
                        /*
                         *      "The sender MUST return an ICMP
                         *       destination unreachable"
@@ -808,20 +835,17 @@ static int ndisc_event_timer(struct nd_neigh *ndn)
        dev = ndn->ndn_dev;
        target = &ndn->ndn_addr;
 
-       if (ndn->ndn_nud_state == NUD_INCOMPLETE)
-       {
+       if (ndn->ndn_nud_state == NUD_INCOMPLETE) {
                addrconf_addr_solict_mult(&ndn->ndn_addr, &mcaddr);
                daddr = &mcaddr;
                ndn = NULL;
-       }
-       else
-       {
+       } else {
                daddr = &ndn->ndn_addr;
        }
 
        ndisc_send_ns(dev, (struct neighbour *) ndn, target, daddr, NULL);
 
-       return nd_retrans_timer;
+       return ipv6_config.nd_retrans_time;
 }
 
 void ndisc_event_send(struct neighbour *neigh, struct sk_buff *skb)
@@ -830,14 +854,15 @@ void ndisc_event_send(struct neighbour *neigh, struct sk_buff *skb)
        struct in6_addr daddr;
        unsigned long now = jiffies;
        struct in6_addr *saddr = NULL;
-       
+
+       if ((ndn->ndn_flags & NCF_NOARP))
+               return;
+
        switch (ndn->ndn_nud_state) {
        case NUD_FAILED:
                ndn->ndn_probes = 0;
        case NUD_NONE:
-
-               if (skb && !skb->stamp.tv_sec)
-               {
+               if (skb && !skb->stamp.tv_sec) {
                        /*
                         *      skb->stamp allows us to know if we are
                         *      originating the skb or forwarding it.
@@ -850,7 +875,7 @@ void ndisc_event_send(struct neighbour *neigh, struct sk_buff *skb)
                addrconf_addr_solict_mult(&ndn->ndn_addr, &daddr);
                ndisc_send_ns(ndn->ndn_dev, NULL, &ndn->ndn_addr, &daddr,
                              saddr);
-               ndisc_add_timer(ndn, nd_retrans_timer);
+               ndisc_add_timer(ndn, ipv6_config.nd_retrans_time);
 
                break;
 
@@ -860,7 +885,7 @@ void ndisc_event_send(struct neighbour *neigh, struct sk_buff *skb)
 
        case NUD_STALE:
                ndn->ndn_nud_state = NUD_DELAY;
-               ndisc_add_timer(ndn, nd_delay_first_probe);
+               ndisc_add_timer(ndn, ipv6_config.nd_delay_probe_time);
        }
 }
 
@@ -872,26 +897,21 @@ void ndisc_event_na(struct nd_neigh *ndn, unsigned char *opt, int opt_len,
 {
        struct sk_buff *skb;
 
+       NDBG(("ndisc_event_na(%p,%p,%d,%d,%d)\n", ndn, opt, opt_len,
+             solicited, override));
+
        if (ndn->ndn_nud_state == NUD_NONE)
-       {
                ndn->ndn_nud_state = NUD_INCOMPLETE;
-       }
 
-       if (ndn->ndn_nud_state == NUD_INCOMPLETE || override)
-       {
-               if (opt_len == 0)
-               {
+       if (ndn->ndn_nud_state == NUD_INCOMPLETE || override) {
+               if (opt_len == 0) {
                        printk(KERN_DEBUG "no opt on NA\n");
-               }
-               else
-               {
-                       /* record hardware address */
-
+               } else {
+                       /* Record hardware address. */
                        ndn->ndn_flags |= NTF_COMPLETE;
 
                        if (ndisc_store_hwaddr(ndn, opt, opt_len,
-                                              ND_OPT_TARGET_LL_ADDR))
-                       {
+                                              ND_OPT_TARGET_LL_ADDR)) {
 #if ND_DEBUG >= 2
                                printk(KERN_DEBUG
                                       "event_na: invalid TARGET_LL_ADDR\n");
@@ -903,42 +923,40 @@ void ndisc_event_na(struct nd_neigh *ndn, unsigned char *opt, int opt_len,
                }
        }
 
-
-       if (solicited || override || ndn->ndn_nud_state == NUD_INCOMPLETE)
-       {
-
+       if (solicited || override || ndn->ndn_nud_state == NUD_INCOMPLETE) {
                ndn->ndn_probes = 0;
                ndn->ndn_tstamp = jiffies;
 
                if (ndn->ndn_nud_state & NUD_IN_TIMER)
-               {
                        ndisc_del_timer(ndn);
-               }
 
                if (solicited)
-               {
                        ndn->ndn_nud_state = NUD_REACHABLE;
-               }
                else
-               {
                        ndn->ndn_nud_state = NUD_STALE;
-               }
        }
                        
        while ((skb=skb_dequeue(&ndn->neigh.arp_queue)))
-       {
                dev_queue_xmit(skb);
-       }
 }
 
-static void ndisc_event_ns(struct in6_addr *saddr, struct sk_buff *skb)
+static struct nd_neigh * ndisc_event_ns(struct in6_addr *saddr,
+                                       struct sk_buff *skb)
 {
        struct nd_neigh *ndn;
        u8 *opt;
        int len;
 
+       NDBG(("ndisc_event_ns: "));
+       if(saddr)
+               NDBG(("saddr[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x] ",
+                     saddr->s6_addr16[0], saddr->s6_addr16[1], saddr->s6_addr16[2],
+                     saddr->s6_addr16[3], saddr->s6_addr16[4], saddr->s6_addr16[5],
+                     saddr->s6_addr16[6], saddr->s6_addr16[7]));
+       NDBG(("\n"));
+
        opt = skb->h.raw;
-       opt += sizeof(struct icmpv6hdr) + sizeof(struct in6_addr);
+       opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 
        len = skb->tail - opt;
 
@@ -949,124 +967,48 @@ static void ndisc_event_ns(struct in6_addr *saddr, struct sk_buff *skb)
                                               skb->dev);
 
        if (ndn == NULL)
-       {
                ndn = ndisc_new_neigh(skb->dev, saddr);
-       }
 
                neigh_table_unlock(&nd_tbl);
 
+       if (ndn == NULL)
+               return NULL;
+
        switch(ndn->ndn_nud_state) {
-               case NUD_REACHABLE:
-               case NUD_STALE:
-               case NUD_DELAY:
-                       if (*opt != ND_OPT_SOURCE_LL_ADDR ||
-                           len != ndn->ndn_dev->addr_len ||
-                           memcmp(ndn->neigh.ha, opt + 2, len))
-                       {
-                               break;
-                       }
+       case NUD_REACHABLE:
+       case NUD_STALE:
+       case NUD_DELAY:
+               if (*opt != ND_OPT_SOURCE_LL_ADDR ||
+                   len != ndn->ndn_dev->addr_len ||
+                   memcmp(ndn->neigh.ha, opt + 2, len))
+                       break;
 
-                       if (ndn->ndn_nud_state & NUD_IN_TIMER)
-                       {
-                               ndisc_del_timer(ndn);
-                       }
-               default:
-                       ndn->ndn_flags |= NTF_COMPLETE;
+               if (ndn->ndn_nud_state & NUD_IN_TIMER)
+                       ndisc_del_timer(ndn);
+
+               /* FALLTHROUGH */
+       default:
+               ndn->ndn_flags |= NTF_COMPLETE;
                        
-                       if (ndisc_store_hwaddr(ndn, opt, len,
-                                              ND_OPT_SOURCE_LL_ADDR))
-                       {
+               if (ndisc_store_hwaddr(ndn, opt, len, ND_OPT_SOURCE_LL_ADDR)) {
 #if ND_DEBUG >= 1
-                               printk(KERN_DEBUG
-                                      "event_ns: invalid SOURCE_LL_ADDR\n");
+                       printk(KERN_DEBUG
+                              "event_ns: invalid SOURCE_LL_ADDR\n");
 #endif
 
-                               ndn->ndn_flags &= ~NTF_COMPLETE;
-                               ndn->ndn_nud_state = NUD_NONE;
-                               return;
-                       }
-
-                       ndn->ndn_nud_state = NUD_STALE;
-                       ndn->ndn_tstamp = jiffies;
-                       ndn->ndn_probes = 0;
-       }
-
-}
-
-static struct rt6_info *ndisc_get_dflt_router(struct device *dev,
-                                             struct in6_addr *addr)
-{      
-       struct rt6_info *iter;
-
-       for (iter = default_rt_list; iter; iter=iter->next)
-       {
-               if (dev == iter->rt_dev &&
-                   ipv6_addr_cmp(&iter->rt_dst, addr) == 0)
-               {
-                       return iter;
+                       ndn->ndn_flags &= ~NTF_COMPLETE;
+                       ndn->ndn_nud_state = NUD_NONE;
+                       return ndn;
                }
-       }
-       return NULL;
-}
-
-static void ndisc_add_dflt_router(struct rt6_info *rt)
-{
-       struct rt6_info *iter;
 
-       rt->rt_ref++;
-       rt->fib_node = &routing_table;
-       rt6_stats.fib_rt_alloc++;
-
-       if (default_rt_list == NULL)
-       {
-               default_rt_list = rt;
-               return;
-       }
-
-       for (iter = default_rt_list; iter->next; iter=iter->next)
-               ;
-
-       iter->next = rt;
-}
-
-static void ndisc_del_dflt_router(struct rt6_info *rt)
-{
-       struct rt6_info *iter, *back;
-
-       if (rt == default_rt_list)
-       {
-               default_rt_list = rt->next;
-       }
-       else
-       {
-               back = NULL;
-               for (iter = default_rt_list; iter; iter=iter->next)
-               {
-                       if (iter == rt)
-                       {
-                               back->next = rt->next;
-                               break;
-                       }
-                       back = iter;
-               }
-       }
+               ndn->ndn_nud_state = NUD_STALE;
+               ndn->ndn_tstamp = jiffies;
+               ndn->ndn_probes = 0;
+       };
 
-       rt->fib_node = NULL;
-       rt_release(rt);
+       return ndn;
 }
 
-static void ndisc_purge_dflt_routers(void)
-{
-       struct rt6_info *iter, *rt;
-
-       for (iter = default_rt_list; iter; )
-       {
-               rt = iter;
-               iter=iter->next;
-               rt_release(rt);
-       }
-       default_rt_list = NULL;
-}
 
 static void ndisc_ll_addr_update(struct nd_neigh *ndn, u8* opt, int len,
                                 int type)
@@ -1077,19 +1019,14 @@ static void ndisc_ll_addr_update(struct nd_neigh *ndn, u8* opt, int len,
        case NUD_DELAY:
                if (len == ndn->ndn_dev->addr_len &&
                    memcmp(ndn->neigh.ha, opt + 2, len) == 0)
-               {
                        break;
-               }
 
                if (ndn->ndn_nud_state & NUD_IN_TIMER)
-               {
                        ndisc_del_timer(ndn);
-               }
        default:
                ndn->ndn_flags |= NTF_COMPLETE;
                
-               if (ndisc_store_hwaddr(ndn, opt, len, type))
-               {
+               if (ndisc_store_hwaddr(ndn, opt, len, type)) {
 #if ND_DEBUG >=1
                        printk(KERN_DEBUG "NDISC: invalid LL_ADDR\n");
 #endif
@@ -1101,45 +1038,7 @@ static void ndisc_ll_addr_update(struct nd_neigh *ndn, u8* opt, int len,
                ndn->ndn_nud_state = NUD_STALE;
                ndn->ndn_tstamp = jiffies;
                ndn->ndn_probes = 0;
-       }
-       
-}
-
-struct rt6_info * dflt_rt_lookup(void)
-{
-       struct rt6_info *match = NULL;
-       struct rt6_info *rt;
-       int score = -1;
-       unsigned long now = jiffies;
-
-       for (rt = default_rt_list; rt; rt=rt->next)
-       {
-               struct neighbour *neigh = rt->rt_nexthop;
-               struct nd_neigh *ndn = (struct nd_neigh *) neigh;
-               
-               if (score < 0)
-               {
-                       score = 0;
-                       match = rt;
-               }
-
-               if (ndn->ndn_nud_state == NUD_REACHABLE)
-               {
-                       if (score < 1)
-                       {
-                               score = 1;
-                               match = rt;
-                       }
-
-                       if (now  - ndn->ndn_tstamp < nd_reachable_time)
-                       {
-                               return rt;
-                       }
-               }
-
-       }
-
-       return match;
+       };
 }
 
 static void ndisc_router_discovery(struct sk_buff *skb)
@@ -1153,10 +1052,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
 
        __u8 * opt = (__u8 *)(ra_msg + 1);
 
+       NDBG(("ndisc_router_discovery(%p)\n", skb));
+
        optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg);
 
-       if (skb->nh.ipv6h->hop_limit != 255)
-       {
+       if (skb->nh.ipv6h->hop_limit != 255) {
                printk(KERN_INFO
                       "NDISC: fake router advertisment received\n");
                return;
@@ -1167,14 +1067,12 @@ static void ndisc_router_discovery(struct sk_buff *skb)
         */
 
        in6_dev = ipv6_get_idev(skb->dev);
-       if (in6_dev == NULL)
-       {
+       if (in6_dev == NULL) {
                printk(KERN_DEBUG "RA: can't find in6 device\n");
                return;
        }
        
-       if (in6_dev->if_flags & IF_RS_SENT)
-       {
+       if (in6_dev->if_flags & IF_RS_SENT) {
                /*
                 *      flag that an RA was received after an RS was sent
                 *      out on this interface.
@@ -1184,94 +1082,57 @@ static void ndisc_router_discovery(struct sk_buff *skb)
 
        lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
 
-       rt = ndisc_get_dflt_router(skb->dev, &skb->nh.ipv6h->saddr);
+       rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
-       if (rt && lifetime == 0)
-       {
-               ndisc_del_dflt_router(rt);
+       if (rt && lifetime == 0) {
+               ip6_del_rt(rt);
                rt = NULL;
        }
 
-       if (rt == NULL && lifetime)
-       {
-               struct in6_addr *saddr;
-               
+       if (rt == NULL && lifetime) {
 #if ND_DEBUG >= 2
-               printk(KERN_DEBUG "ndisc_rdisc: new default router\n");
+               printk(KERN_DEBUG "ndisc_rdisc: adding default router\n");
 #endif
 
-               rt = (struct rt6_info *) kmalloc(sizeof(struct rt6_info),
-                                                GFP_ATOMIC);
+               rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
-               if (rt == NULL)
-               {
-                       /* We are out-of-memory. Ignore it */
+               if (rt == NULL) {
+#if ND_DEBUG >= 1
+                       printk(KERN_DEBUG "route_add failed\n");
+#endif
                        return;
                }
 
-               saddr = &skb->nh.ipv6h->saddr;
-               neigh_table_lock(&nd_tbl);
-               
-               ndn = (struct nd_neigh *) neigh_lookup(&nd_tbl, saddr,
-                                                      sizeof(struct in6_addr),
-                                                      skb->dev);
-
-               if (ndn == NULL)
-               {
-                       ndn = ndisc_new_neigh(skb->dev, saddr);
-                       
-                       if (ndn == NULL)
-                       {
-                               kfree(rt);
-                               neigh_table_unlock(&nd_tbl);
-                               return;
-                       }
+               ndn = (struct nd_neigh *) rt->rt6i_nexthop;
+               if (ndn == NULL) {
+#if ND_DEBUG >= 1
+                       printk(KERN_DEBUG "nd: add default router: null "
+                              "neighbour\n");
+#endif
+                       return;
                }
-               
-               neigh_table_unlock(&nd_tbl);
-
-               atomic_inc(&ndn->ndn_refcnt);
-
                ndn->ndn_flags |= NCF_ROUTER;
-
-               memset(rt, 0, sizeof(struct rt6_info));
-
-               ipv6_addr_copy(&rt->rt_dst, &skb->nh.ipv6h->saddr);
-               rt->rt_metric = 1;
-               rt->rt_flags = RTF_GATEWAY | RTF_DYNAMIC;
-               rt->rt_dev = skb->dev;
-               rt->rt_nexthop = (struct neighbour *) ndn;
-
-               ndisc_add_dflt_router(rt);
        }
 
        if (rt)
-       {
-               rt->rt_expires = jiffies + (HZ * lifetime);
-        }
+               rt->rt6i_expires = jiffies + (HZ * lifetime);
 
        if (ra_msg->icmph.icmp6_hop_limit)
-       {
-               ipv6_hop_limit = ra_msg->icmph.icmp6_hop_limit;
-       }
+               ipv6_config.hop_limit = ra_msg->icmph.icmp6_hop_limit;
 
        /*
         *      Update Reachable Time and Retrans Timer
         */
 
        if (ra_msg->retrans_timer)
-       {
-               nd_retrans_timer = ntohl(ra_msg->retrans_timer);
-       }
+               ipv6_config.nd_retrans_time = ntohl(ra_msg->retrans_timer);
 
-       if (ra_msg->reachable_time)
-       {
+       if (ra_msg->reachable_time) {
                __u32 rtime = ntohl(ra_msg->reachable_time);
 
-               if (rtime != nd_base_reachable_time)
-               {
-                       nd_base_reachable_time = rtime;
-                       nd_gc_staletime = 3 * nd_base_reachable_time;
+               if (rtime != ipv6_config.nd_base_reachable_time) {
+                       ipv6_config.nd_base_reachable_time = rtime;
+                       nd_gc_staletime = 3 * rtime;
                        nd_reachable_time = rand_reach_time();
                }
                
@@ -1286,22 +1147,22 @@ static void ndisc_router_discovery(struct sk_buff *skb)
 
                 len = (opt[1] << 3);
 
-               if (len == 0)
-               {
+               if (len == 0) {
                        printk(KERN_DEBUG "RA: opt has 0 len\n");
                        break;
                }
 
                 switch(*opt) {
                 case ND_OPT_SOURCE_LL_ADDR:
-                       
+
                        if (rt == NULL)
                                break;
                        
-                       ndn = (struct nd_neigh *) rt->rt_nexthop;
+                       ndn = (struct nd_neigh *) rt->rt6i_nexthop;
 
-                       ndisc_ll_addr_update(ndn, opt, len,
-                                            ND_OPT_SOURCE_LL_ADDR);
+                       if (ndn)
+                               ndisc_ll_addr_update(ndn, opt, len,
+                                                    ND_OPT_SOURCE_LL_ADDR);
                        break;
 
                 case ND_OPT_PREFIX_INFO:
@@ -1309,17 +1170,17 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                         break;
 
                 case ND_OPT_MTU:
-
-                       if (rt)
-                       {
+                       if (rt) {
                                int mtu;
                                struct device *dev;
                                
                                mtu = htonl(*(__u32 *)(opt+4));
-                               dev = rt->rt_nexthop->dev;
+                               dev = rt->rt6i_dev;
 
-                               if (mtu < 576)
-                               {
+                               if (dev == NULL)
+                                       break;
+
+                               if (mtu < 576) {
                                        printk(KERN_DEBUG "NDISC: router "
                                               "announcement with mtu = %d\n",
                                               mtu);
@@ -1327,13 +1188,9 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                                }
 
                                if (dev->change_mtu)
-                               {
                                        dev->change_mtu(dev, mtu);
-                               }
                                else
-                               {
                                        dev->mtu = mtu;
-                               }
                        }
                         break;
 
@@ -1343,32 +1200,32 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                        break;
                default:
                        printk(KERN_DEBUG "unkown option in RA\n");
-                }
+                };
                 optlen -= len;
                 opt += len;
         }
-        
 }
 
 void ndisc_forwarding_on(void)
 {
+
        /*
-        *      forwarding was turned on
+        *      Forwarding was turned on.
         */
 
-       ndisc_purge_dflt_routers();
+       rt6_purge_dflt_routers(0);
 }
 
 void ndisc_forwarding_off(void)
 {
        /*
-        *      forwarding was turned off
+        *      Forwarding was turned off.
         */
 }
 
 static void ndisc_redirect_rcv(struct sk_buff *skb)
 {
-       struct icmpv6hdr *icmph;
+       struct icmp6hdr *icmph;
        struct in6_addr *dest;
        struct in6_addr *target;        /* new first hop to destination */
        struct nd_neigh *ndn;
@@ -1377,75 +1234,66 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
        int optlen;
        u8 * opt;
 
-       if (skb->nh.ipv6h->hop_limit != 255)
-       {
+       NDBG(("ndisc_redirect_rcv(%p)\n", skb));
+
+       if (skb->nh.ipv6h->hop_limit != 255) {
                printk(KERN_WARNING
                       "NDISC: fake ICMP redirect received\n");
                return;
        }
 
-       if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL))
-       {
+       if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
                printk(KERN_WARNING
                       "ICMP redirect: source address is not linklocal\n");
                return;
        }
 
        optlen = skb->tail - skb->h.raw;
-       optlen -= sizeof(struct icmpv6hdr) + 2 * sizeof(struct in6_addr);
+       optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
 
-       if (optlen < 0)
-       {
+       if (optlen < 0) {
                printk(KERN_WARNING "ICMP redirect: packet too small\n");
                return;
        }
 
-       icmph = (struct icmpv6hdr *) skb->h.raw;
+       icmph = (struct icmp6hdr *) skb->h.raw;
        target = (struct in6_addr *) (icmph + 1);
        dest = target + 1;
 
-       if (ipv6_addr_type(dest) & IPV6_ADDR_MULTICAST)
-       {
+       if (ipv6_addr_type(dest) & IPV6_ADDR_MULTICAST) {
                printk(KERN_WARNING "ICMP redirect for multicast addr\n");
                return;
        }
 
-       if (ipv6_addr_cmp(dest, target) == 0)
-       {
+       if (ipv6_addr_cmp(dest, target) == 0) {
                on_link = 1;
-       }
-       else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL))
-       {
+       } else if (!(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) {
                printk(KERN_WARNING
                       "ICMP redirect: target address is not linklocal\n");
                return;
        }
 
        /* passed validation tests */
+       rt = rt6_redirect(dest, &skb->nh.ipv6h->saddr, target, skb->dev,
+                         on_link);
 
-       rt = ipv6_rt_redirect(skb->dev, dest, target, on_link);
-
-       if (rt == NULL)
-       {
+       if (rt == NULL) {
                printk(KERN_WARNING "ICMP redirect: no route to host\n");
                return;
        }
 
-       ndn = (struct nd_neigh *) rt->rt_nexthop;
+       ndn = (struct nd_neigh *) rt->rt6i_nexthop;
 
        opt = (u8 *) (dest + 1);
 
-       while (optlen > 0)
-       {
+       while (optlen > 0) {
                int len;
 
                len = (opt[1] << 3);
 
                if (*opt == ND_OPT_TARGET_LL_ADDR)
-               {
                        ndisc_ll_addr_update(ndn, opt, len,
                                             ND_OPT_TARGET_LL_ADDR);
-               }
 
                opt += len;
                optlen -= len;
@@ -1456,12 +1304,13 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                         struct in6_addr *target)
 {
        struct sock *sk = ndisc_socket->sk;
-       int len = sizeof(struct icmpv6hdr) + 2 * sizeof(struct in6_addr);
+       int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
        struct sk_buff *buff;
        struct nd_neigh *ndn = (struct nd_neigh *) neigh;
        struct inet6_ifaddr *ifp;
-       struct icmpv6hdr *icmph;
+       struct icmp6hdr *icmph;
        struct in6_addr *addrp;
+       struct device *dev;
        struct rt6_info *rt;
        int ta_len = 0;
        u8 *opt;
@@ -1469,19 +1318,25 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        int err;
        int hlen;
 
-       rt = fibv6_lookup(&skb->nh.ipv6h->saddr, skb->dev, 0);
-       
-       if (rt->rt_flags & RTF_GATEWAY)
-       {
+       dev = skb->dev;
+       rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev, 0);
+
+       if (rt == NULL || rt->u.dst.error) {
+#if ND_DEBUG >= 1
+               printk(KERN_DEBUG "ndisc_send_redirect: hostunreach\n");
+#endif
+               return;
+       }
+
+       if (rt->rt6i_flags & RTF_GATEWAY) {
 #if ND_DEBUG >= 1
                printk(KERN_DEBUG "ndisc_send_redirect: not a neighbour\n");
 #endif
                return;
        }
 
-       if (ndn->ndn_nud_state == NUD_REACHABLE)
-       {
-               ta_len  = ((neigh->dev->addr_len + 1) >> 3) + 1;
+       if (ndn->ndn_nud_state == NUD_REACHABLE) {
+               ta_len  = ((dev->addr_len + 1) >> 3) + 1;
                len += (ta_len << 3);
        }
 
@@ -1489,20 +1344,18 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        rd_len &= ~0x7;
        len += rd_len;
 
-       ifp = ipv6_get_lladdr(skb->dev);
+       ifp = ipv6_get_lladdr(dev);
 
-       if (ifp == NULL)
-       {
+       if (ifp == NULL) {
 #if ND_DEBUG >= 1
                printk(KERN_DEBUG "redirect: no link_local addr for dev\n");
 #endif
                return;
        }
 
-       buff = sock_alloc_send_skb(sk, MAX_HEADER + len, 0, 0, &err);
-
-       if (buff == NULL)
-       {
+       buff = sock_alloc_send_skb(sk, MAX_HEADER + len + dev->hard_header_len + 15,
+                                  0, 0, &err);
+       if (buff == NULL) {
 #if ND_DEBUG >= 2
                printk(KERN_DEBUG "ndisc_send_redirect: alloc_skb failed\n");
 #endif
@@ -1510,17 +1363,23 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        }
        
        hlen = 0;
-       if (skb->dev->hard_header_len)
-       {
-               hlen = (skb->dev->hard_header_len + 15) & ~15;
-       }
 
-       skb_reserve(buff, hlen + sizeof(struct ipv6hdr));
+       if (dev->hard_header_len) {
+               skb_reserve(buff, (dev->hard_header_len + 15) & ~15);
+               if (dev->hard_header) {
+                       dev->hard_header(buff, dev, ETH_P_IPV6, ndn->ndn_ha,
+                                        NULL, len);
+                       buff->arp = 1;
+               }
+       }
        
-       icmph = (struct icmpv6hdr *) skb_put(buff, len);
+       ip6_nd_hdr(sk, buff, dev, &ifp->addr, &skb->nh.ipv6h->saddr,
+                  IPPROTO_ICMPV6, len);
+
+       icmph = (struct icmp6hdr *) skb_put(buff, len);
 
-       memset(icmph, 0, sizeof(struct icmpv6hdr));
-       icmph->type = NDISC_REDIRECT;
+       memset(icmph, 0, sizeof(struct icmp6hdr));
+       icmph->icmp6_type = NDISC_REDIRECT;
 
        /*
         *      copy target and destination addresses
@@ -1537,8 +1396,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
         *      include target_address option
         */
 
-       if (ta_len)
-       {
+       if (ta_len) {
                int zb;
                
                *(opt++) = ND_OPT_TARGET_LL_ADDR;
@@ -1553,8 +1411,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                 */
 
                zb = (neigh->dev->addr_len + 2) & 0x7; 
-               if (zb)
-               {
+               if (zb) {
                        int comp;
 
                        comp = 8 - zb;
@@ -1574,12 +1431,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 
        memcpy(opt, &skb->nh.ipv6h, rd_len - 8);
        
-       icmph->checksum = csum_ipv6_magic(&ifp->addr, &skb->nh.ipv6h->saddr,
-                                         len, IPPROTO_ICMPV6,
-                                         csum_partial((u8 *) icmph, len, 0));
+       icmph->icmp6_cksum = csum_ipv6_magic(&ifp->addr, &skb->nh.ipv6h->saddr,
+                                            len, IPPROTO_ICMPV6,
+                                            csum_partial((u8 *) icmph, len, 0));
 
-       ipv6_xmit(sk, buff, &ifp->addr, &skb->nh.ipv6h->saddr, NULL,
-                 IPPROTO_ICMPV6);
+       dev_queue_xmit(buff);
 }
 
 /* Called by upper layers to validate neighbour cache entries. */
@@ -1587,14 +1443,15 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 void ndisc_validate(struct neighbour *neigh)
 {
        struct nd_neigh *ndn = (struct nd_neigh *) neigh;
-       
+
+       if (neigh == NULL)
+               return;
+
         if (ndn->ndn_nud_state == NUD_INCOMPLETE)
                 return;
 
         if (ndn->ndn_nud_state == NUD_DELAY) 
-       {
                 ndisc_del_timer(ndn);
-        }
 
         nd_stats.rcv_upper_conf++;
         ndn->ndn_nud_state = NUD_REACHABLE;
@@ -1609,26 +1466,30 @@ int ndisc_rcv(struct sk_buff *skb, struct device *dev,
        struct nd_neigh *ndn;
        struct inet6_ifaddr *ifp;
 
-       switch (msg->icmph.type) {
+       NDBG(("ndisc_rcv(type=%d) ", msg->icmph.icmp6_type));
+       switch (msg->icmph.icmp6_type) {
        case NDISC_NEIGHBOUR_SOLICITATION:
-               if ((ifp = ipv6_chk_addr(&msg->target)))
-               {
+               NDBG(("NS "));
+               if ((ifp = ipv6_chk_addr(&msg->target))) {
                        int addr_type;
 
-                       if (ifp->flags & DAD_INCOMPLETE)
-                       {
+                       if (ifp->flags & DAD_INCOMPLETE) {
                                /*
-                                *      DAD failed 
+                                *      DAD failed
                                 */
 
-                               printk(KERN_DEBUG "duplicate address\n");
+                               /* XXX Check if this came in over same interface
+                                * XXX we just sent an NS from!  That is valid! -DaveM
+                                */
+
+                               printk(KERN_DEBUG "%s: duplicate address\n",
+                                      ifp->idev->dev->name);
                                del_timer(&ifp->timer);
                                return 0;
                        }
 
                        addr_type = ipv6_addr_type(saddr);
-                       if (addr_type & IPV6_ADDR_UNICAST)
-                       {
+                       if (addr_type & IPV6_ADDR_UNICAST) {
                                int inc;
 
                                /* 
@@ -1637,25 +1498,18 @@ int ndisc_rcv(struct sk_buff *skb, struct device *dev,
                                 */
 
                                nd_stats.rcv_probes_ucast++;
-                               ndisc_event_ns(saddr, skb);
-
-                               neigh_table_lock(&nd_tbl);
 
-                               ndn = (struct nd_neigh *)
-                                       neigh_lookup(&nd_tbl, saddr,
-                                                    sizeof(struct in6_addr),
-                                                    dev);
+                               ndn = ndisc_event_ns(saddr, skb);
 
-                               neigh_table_unlock(&nd_tbl);
+                               if (ndn == NULL)
+                                       return 0;
 
                                inc = ipv6_addr_type(daddr);
                                inc &= IPV6_ADDR_MULTICAST;
 
                                ndisc_send_na(dev, ndn, saddr, &ifp->addr, 
                                              ifp->idev->router, 1, inc, inc);
-                       }
-                       else
-                       {
+                       } else {
 #if ND_DEBUG >= 1
                                /* FIXME */
                                printk(KERN_DEBUG "ns: non unicast saddr\n");
@@ -1665,38 +1519,30 @@ int ndisc_rcv(struct sk_buff *skb, struct device *dev,
                break;
 
        case NDISC_NEIGHBOUR_ADVERTISEMENT:
-               
+               NDBG(("NA "));
                neigh_table_lock(&nd_tbl);             
                ndn = (struct nd_neigh *) 
                        neigh_lookup(&nd_tbl, (void *) &msg->target,
                                     sizeof(struct in6_addr), skb->dev);
                neigh_table_unlock(&nd_tbl);
 
-               if (ndn)
-               {
-                       if (ndn->ndn_flags & NCF_ROUTER)
-                       {
-                               if (msg->icmph.icmp6_router == 0)
-                               {
+               if (ndn) {
+                       if (ndn->ndn_flags & NCF_ROUTER) {
+                               if (msg->icmph.icmp6_router == 0) {
                                        /*
                                         *      Change: router to host
                                         */
-                                       
+#if 0                                  
                                        struct rt6_info *rt;
                                        rt = ndisc_get_dflt_router(skb->dev,
                                                                   saddr);
                                        if (rt)
-                                       {
                                                ndisc_del_dflt_router(rt);
-                                       }
+#endif
                                }
-                       }
-                       else
-                       {
+                       } else {
                                if (msg->icmph.icmp6_router)
-                               {
                                        ndn->ndn_flags |= NCF_ROUTER;
-                               }
                        }
                        ndisc_event_na(ndn, (unsigned char *) &msg->opt,
                                       skb->tail - (u8 *)&msg->opt /*opt_len*/,
@@ -1705,24 +1551,28 @@ int ndisc_rcv(struct sk_buff *skb, struct device *dev,
                }
                break;
 
-       }
+       };
 
-       if (ipv6_forwarding == 0)
-       {
-               switch (msg->icmph.type) {
+       if (ipv6_config.forwarding == 0) {
+               switch (msg->icmph.icmp6_type) {
                case NDISC_ROUTER_ADVERTISEMENT:
-                       ndisc_router_discovery(skb);
+                       NDBG(("RA "));
+                       if (ipv6_config.accept_ra)
+                               ndisc_router_discovery(skb);
                        break;
 
                case NDISC_REDIRECT:
-                       ndisc_redirect_rcv(skb);
+                       NDBG(("REDIR "));
+                       if (ipv6_config.accept_redirects)
+                               ndisc_redirect_rcv(skb);
                        break;
-               }
+               };
        }
 
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 int ndisc_get_info(char *buffer, char **start, off_t offset, int length,
                   int dummy)
 {
@@ -1732,8 +1582,7 @@ int ndisc_get_info(char *buffer, char **start, off_t offset, int length,
 
        neigh_table_lock(&nd_tbl);
 
-       for (i = 0; i < nd_tbl.tbl_size; i++)
-       {
+       for (i = 0; i < nd_tbl.tbl_size; i++) {
                struct neighbour *neigh, *head;
                head = nd_tbl.hash_buckets[i];
                
@@ -1744,36 +1593,37 @@ int ndisc_get_info(char *buffer, char **start, off_t offset, int length,
                        struct nd_neigh *ndn = (struct nd_neigh *) neigh;
                        int j;
 
-                       for (j=0; j<16; j++)
-                       {
+                       for (j=0; j<16; j++) {
                                sprintf(buffer + len, "%02x",
                                        ndn->ndn_addr.s6_addr[j]);
                                len += 2;
                        }
 
                        len += sprintf(buffer + len,
-                                      " %02x %02x %08lx %08lx %04x %04lx ", i,
+                                      " %02x %02x %02x %02x %08lx %08lx %08lx %04x %04x %04lx %8s ", i,
+                                      ndn->ndn_plen,
+                                      ndn->ndn_type,
                                       ndn->ndn_nud_state,
-                                      ndn->ndn_expires - now,
+                                      ndn->ndn_expires ? ndn->ndn_expires - now : 0,
                                       now - ndn->ndn_tstamp,
+                                      nd_reachable_time,
+                                      nd_gc_staletime,
                                       ndn->ndn_refcnt,
-                                      ndn->ndn_flags);
+                                      ndn->ndn_flags,
+                                      ndn->ndn_dev ? ndn->ndn_dev->name : "NULLDEV");
 
-                       if ((ndn->ndn_flags & NTF_COMPLETE))
-                       {
-                               for (j=0; j< neigh->dev->addr_len; j++)
-                               {
+                       if ((ndn->ndn_flags & NTF_COMPLETE)) {
+                               for (j=0; j< neigh->dev->addr_len; j++) {
                                        sprintf(buffer + len, "%02x",
                                                neigh->ha[j]);
                                        len += 2;
                                }
-                       }
-                       else
+                       } else {
                                 len += sprintf(buffer + len, "000000000000");
+                       }
                        len += sprintf(buffer + len, "\n");
                        
                        neigh = neigh->next;
-
                } while (neigh != head);
        }
 
@@ -1795,6 +1645,7 @@ struct proc_dir_entry ndisc_proc_entry =
         0, NULL,
         &ndisc_get_info
 };
+#endif /* CONFIG_PROC_FS */
 
 void ndisc_init(struct net_proto_family *ops)
 {
@@ -1845,22 +1696,13 @@ void ndisc_init(struct net_proto_family *ops)
 #ifdef CONFIG_PROC_FS
        proc_net_register(&ndisc_proc_entry);
 #endif
-#ifdef CONFIG_IPV6_MODULE
-       ndisc_eth_hook = ndisc_eth_resolv;
-#endif
 }
 
-#ifdef CONFIG_IPV6_MODULE
+#ifdef MODULE
 void ndisc_cleanup(void)
 {
-       ndisc_eth_hook = NULL;
-
 #ifdef CONFIG_PROC_FS
-#ifdef CONFIG_IPV6_MODULE
-        proc_unregister(&proc_net, ndisc_proc_entry.low_ino);
-#else
-       proc_net_unregister(PROC_NET_NDISC);
-#endif
+        proc_net_unregister(ndisc_proc_entry.low_ino);
 #endif
        del_timer(&ndisc_gc_timer);
        del_timer(&ndisc_timer);
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
new file mode 100644 (file)
index 0000000..8da830c
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             This file implements the various access functions for the
+ *             PROC file system.  This is very similar to the IPv4 version,
+ *             except it reports the sockets in the INET6 address family.
+ *
+ * Version:    $Id: proc.c,v 1.1 1997/03/16 08:47:18 davem Exp $
+ *
+ * Authors:    David S. Miller (davem@caip.rutgers.edu)
+ *
+ *             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/sched.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <net/sock.h>
+#include <net/transp_v6.h>
+
+/* This is the main implementation workhorse of all these routines. */
+static int get__netinfo6(struct proto *pro, char *buffer, int format, char **start,
+                        off_t offset, int length)
+{
+       struct sock *sp;
+       struct tcp_opt *tp;
+       int timer_active, timer_active1, timer_active2;
+       unsigned long timer_expires;
+       struct in6_addr *dest, *src;
+       unsigned short destp, srcp;
+       int len = 0, i = 0;
+       off_t pos = 0;
+       off_t begin;
+       char tmpbuf[150];
+
+       if(offset < 149)
+               len += sprintf(buffer, "%-148s\n",
+                              "  sl  "                                         /* 6 */
+                              "local_address                         "         /* 38 */
+                              "remote_address                        "         /* 38 */
+                              "st tx_queue rx_queue tr tm->when retrnsmt"      /* 41 */
+                              "   uid  timeout inode");                        /* 21 */
+                                                                               /*----*/
+                                                                               /*144 */
+
+       pos = 149;
+       SOCKHASH_LOCK();
+       sp = pro->sklist_next;
+       while(sp != (struct sock *)pro) {
+               pos += 149;
+               if(pos < offset)
+                       goto next;
+               tp = &(sp->tp_pinfo.af_tcp);
+               dest  = &sp->net_pinfo.af_inet6.daddr;
+               src   = &sp->net_pinfo.af_inet6.rcv_saddr;
+               destp = ntohs(sp->dummy_th.dest);
+               srcp  = ntohs(sp->dummy_th.source);
+
+               timer_active1 = del_timer(&sp->retransmit_timer);
+               timer_active2 = del_timer(&sp->timer);
+               if(!timer_active1) sp->retransmit_timer.expires = 0;
+               if(!timer_active2) sp->timer.expires = 0;
+               timer_active = 0;
+               timer_expires = (unsigned) -1;
+               if(timer_active1 && sp->retransmit_timer.expires < timer_expires) {
+                       timer_active = timer_active1;
+                       timer_expires = sp->retransmit_timer.expires;
+               }
+               if(timer_active2 && sp->timer.expires < timer_expires) {
+                       timer_active = timer_active2;
+                       timer_expires = sp->timer.expires;
+               }
+               sprintf(tmpbuf, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+                       "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
+                       i,
+                       src->s6_addr32[0], src->s6_addr32[1],
+                       src->s6_addr32[2], src->s6_addr32[3], srcp,
+                       dest->s6_addr32[0], dest->s6_addr32[1],
+                       dest->s6_addr32[2], dest->s6_addr32[3], destp,
+                       sp->state,
+                       format==0?sp->write_seq-tp->snd_una:sp->wmem_alloc,
+                       format==0?tp->rcv_nxt-sp->copied_seq:sp->rmem_alloc,
+                       timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
+                       sp->socket ? sp->socket->inode->i_uid:0,
+                       timer_active?sp->timeout:0,
+                       sp->socket ? sp->socket->inode->i_ino:0);
+
+               if(timer_active1) add_timer(&sp->retransmit_timer);
+               if(timer_active2) add_timer(&sp->timer);
+               len += sprintf(buffer+len, "%-148s\n", tmpbuf);
+               if(len >= length)
+                       break;
+       next:
+               sp = sp->sklist_next;
+               i++;
+       }
+       SOCKHASH_UNLOCK();
+
+       begin = len - (pos - offset);
+       *start = buffer + begin;
+       len -= begin;
+       if(len > length)
+               len = length;
+       return len;
+}
+
+/* These get exported and registered with procfs in af_inet6.c at init time. */
+int tcp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+       return get__netinfo6(&tcpv6_prot, buffer, 0, start, offset, length);
+}
+
+int udp6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+       return get__netinfo6(&udpv6_prot, buffer, 1, start, offset, length);
+}
+
+int raw6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+       return get__netinfo6(&rawv6_prot, buffer, 1, start, offset, length);
+}
+
+int afinet6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+       int len = 0;
+       len += sprintf(buffer+len, "TCP6: inuse %d highest %d\n",
+                      tcpv6_prot.inuse, tcpv6_prot.highestinuse);
+       len += sprintf(buffer+len, "UDP6: inuse %d highest %d\n",
+                      udpv6_prot.inuse, udpv6_prot.highestinuse);
+       len += sprintf(buffer+len, "RAW6: inuse %d highest %d\n",
+                      rawv6_prot.inuse, rawv6_prot.highestinuse);
+       *start = buffer + offset;
+       len -= offset;
+       if(len > length)
+               len = length;
+       return len;
+}
index 7ba6f5be1f8a9475597b1195a2c5a72713630e78..3ec242adbc2f899a5311fc2022d5478c612ceeaf 100644 (file)
@@ -1,3 +1,20 @@
+/*
+ * INET                An implementation of the TCP/IP protocol suite for the LINUX
+ *             operating system.  INET is implemented using the  BSD Socket
+ *             interface as the means of communication with the user level.
+ *
+ *             AF_INET6 protocol dispatch tables.
+ *
+ * Version:    $Id: protocol.c,v 1.5 1997/03/18 18:24:44 davem Exp $
+ *
+ * Authors:    Pedro Roque     <roque@di.fc.ul.pt>
+ *
+ *             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/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -27,8 +44,7 @@ struct inet6_protocol *inet6_get_protocol(unsigned char prot)
        struct inet6_protocol *p;
 
        hash = prot & (MAX_INET_PROTOS - 1);
-       for (p = inet6_protos[hash] ; p != NULL; p=p->next) 
-       {
+       for (p = inet6_protos[hash] ; p != NULL; p=p->next) {
                if (p->protocol == prot) 
                        return((struct inet6_protocol *) p);
        }
@@ -41,7 +57,7 @@ void inet6_add_protocol(struct inet6_protocol *prot)
        struct inet6_protocol *p2;
 
        hash = prot->protocol & (MAX_INET_PROTOS - 1);
-       prot ->next = inet6_protos[hash];
+       prot->next = inet6_protos[hash];
        inet6_protos[hash] = prot;
        prot->copy = 0;
 
@@ -50,10 +66,8 @@ void inet6_add_protocol(struct inet6_protocol *prot)
         */
         
        p2 = (struct inet6_protocol *) prot->next;
-       while(p2 != NULL) 
-       {
-               if (p2->protocol == prot->protocol) 
-               {
+       while(p2 != NULL) {
+               if (p2->protocol == prot->protocol) {
                        prot->copy = 1;
                        break;
                }
@@ -72,22 +86,19 @@ int inet6_del_protocol(struct inet6_protocol *prot)
        unsigned char hash;
 
        hash = prot->protocol & (MAX_INET_PROTOS - 1);
-       if (prot == inet6_protos[hash]) 
-       {
+       if (prot == inet6_protos[hash]) {
                inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
                return(0);
        }
 
        p = (struct inet6_protocol *) inet6_protos[hash];
-       while(p != NULL) 
-       {
+       while(p != NULL) {
                /*
                 * We have to worry if the protocol being deleted is
                 * the last one on the list, then we may need to reset
                 * someone's copied bit.
                 */
-               if (p->next != NULL && p->next == prot) 
-               {
+               if (p->next != NULL && p->next == prot) {
                        /*
                         * if we are the last one with this protocol and
                         * there is a previous one, reset its copy bit.
@@ -104,9 +115,3 @@ int inet6_del_protocol(struct inet6_protocol *prot)
        }
        return(-1);
 }
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o protocol.o protocol.c"
- * End:
- */
index 006b6cdc6913a1d9ef6e403f2eb51dbc40d47846..dd946515ea5d9f6b7712a774f910c6c189ce29b2 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/raw.c
  *
- *     $Id: raw.c,v 1.8 1997/02/28 09:56:34 davem Exp $
+ *     $Id: raw.c,v 1.11 1997/03/18 18:24:46 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 #include <net/sock.h>
 #include <net/snmp.h>
 
-#include <net/ip.h>
-#include <net/udp.h>
-
 #include <net/ipv6.h>
 #include <net/ndisc.h>
 #include <net/protocol.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/transp_v6.h>
 
@@ -189,15 +186,12 @@ void rawv6_err(struct sock *sk, int type, int code, unsigned char *buff,
 {
        if (sk == NULL) 
                return;
-
 }
 
 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
        /* Charge it to the socket. */
-       
-       if (sock_queue_rcv_skb(sk,skb)<0)
-       {
+       if (sock_queue_rcv_skb(sk,skb)<0) {
                /* ip_statistics.IpInDiscards++; */
                kfree_skb(skb, FREE_READ);
                return 0;
@@ -211,7 +205,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
  *     This is next to useless... 
  *     if we demultiplex in network layer we don't need the extra call
  *     just to queue the skb... 
- *     maybe we could have the network decide uppon an hint if it 
+ *     maybe we could have the network decide uppon a hint if it 
  *     should call raw_rcv for demultiplexing
  */
 int rawv6_rcv(struct sk_buff *skb, struct device *dev,
@@ -222,22 +216,10 @@ int rawv6_rcv(struct sk_buff *skb, struct device *dev,
 
        sk = skb->sk;
 
-#if 1
-/*
- *     It was wrong for IPv4. It breaks NRL too [ANK]
- *     Actually i think this is the option that  does make more 
- *     sense with IPv6 nested headers. [Pedro]
- */
-
        if (sk->ip_hdrincl)
-       {
                skb->h.raw = skb->nh.raw;
-       }
-#else
-        skb->h.raw = skb->nh.raw;
-#endif
 
-       if (sk->users) {
+       if (sk->sock_readers) {
                __skb_queue_tail(&sk->back_log, skb);
                return 0;
        }
@@ -283,8 +265,7 @@ int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
                return err;
 
        /* Copy the address. */
-       if (sin6) 
-       {
+       if (sin6) {
                sin6->sin6_family = AF_INET6;
                memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr, 
                       sizeof(struct in6_addr));
@@ -329,8 +310,7 @@ static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
        hdr->cksum = csum_partial_copy_fromiovecend(buff, hdr->iov, offset, 
                                                    len, hdr->cksum);
        
-       if (offset == 0)
-       {
+       if (offset == 0) {
                struct sock *sk;
                struct raw6_opt *opt;
                struct in6_addr *daddr;
@@ -339,26 +319,19 @@ static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
                opt = &sk->tp_pinfo.tp_raw;
 
                if (hdr->daddr)
-               {
                        daddr = hdr->daddr;
-               }
                else
-               {
                        daddr = addr + 1;
-               }
                
                hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len,
                                             hdr->proto, hdr->cksum);
                
-               if (opt->offset < len)
-               {
+               if (opt->offset < len) {
                        __u16 *csum;
 
                        csum = (__u16 *) (buff + opt->offset);
                        *csum = hdr->cksum;
-               }
-               else
-               {
+               } else {
                        /* 
                         *  FIXME 
                         *  signal an error to user via sk->err
@@ -378,11 +351,12 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
        struct ipv6_options *opt = NULL;
        struct device *dev = NULL;
        struct in6_addr *saddr = NULL;
+       struct flowi fl;
        int addr_len = msg->msg_namelen;
        struct in6_addr *daddr;
        struct raw6_opt *raw_opt;
+       int hlimit = -1;
        u16 proto;
-       int hlimit = 0;
        int err;
        
 
@@ -396,8 +370,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
         *      Get and verify the address. 
         */
 
-       if (sin6) 
-       {
+       if (sin6) {
                if (addr_len < sizeof(struct sockaddr_in6)) 
                        return(-EINVAL);
 
@@ -415,14 +388,11 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
 
                daddr = &sin6->sin6_addr;
                
-               if (np->dest && ipv6_addr_cmp(daddr, &np->daddr))
-               {
-                       ipv6_dst_unlock(np->dest);
-                       np->dest = NULL;
+               if (np->dst && ipv6_addr_cmp(daddr, &np->daddr)) {
+                       dst_release(np->dst);
+                       np->dst = NULL;
                }               
-       }
-       else 
-       {
+       } else {
                if (sk->state != TCP_ESTABLISHED) 
                        return(-EINVAL);
                
@@ -430,8 +400,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
                daddr = &(sk->net_pinfo.af_inet6.daddr);
        }
 
-       if (ipv6_addr_any(daddr))
-       {
+       if (ipv6_addr_any(daddr)) {
                /* 
                 * unspecfied destination address 
                 * treated as error... is this correct ?
@@ -445,14 +414,12 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
        if (len + (sk->ip_hdrincl ? 0 : sizeof(struct ipv6hdr)) > 65535)
                return -EMSGSIZE;
 
-       if (msg->msg_controllen)
-       {
+       if (msg->msg_controllen) {
                opt = &opt_space;
                memset(opt, 0, sizeof(struct ipv6_options));
 
                err = datagram_send_ctl(msg, &dev, &saddr, opt, &hlimit);
-               if (err < 0)
-               {
+               if (err < 0) {
                        printk(KERN_DEBUG "invalid msg_control\n");
                        return err;
                }               
@@ -460,9 +427,14 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
 
        raw_opt = &sk->tp_pinfo.tp_raw;
 
+       fl.proto = proto;
+       fl.nl_u.ip6_u.daddr = daddr;
+       fl.nl_u.ip6_u.saddr = saddr;
+       fl.dev = dev;
+       fl.uli_u.icmpt.type = 0;
+       fl.uli_u.icmpt.code = 0;
        
-       if (raw_opt->checksum)
-       {
+       if (raw_opt->checksum) {
                struct rawv6_fakehdr hdr;
                
                hdr.iov = msg->msg_iov;
@@ -472,23 +444,15 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
                hdr.proto = proto;
 
                if (opt && opt->srcrt)
-               {
                        hdr.daddr = daddr;
-               }
                else
-               {
                        hdr.daddr = NULL;
-               }
 
-               err = ipv6_build_xmit(sk, rawv6_frag_cksum, &hdr, daddr, len,
-                                     saddr, dev, opt, proto, hlimit,
-                                     msg->msg_flags&MSG_DONTWAIT);
-       }
-       else
-       {
-               err = ipv6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, daddr,
-                                     len, saddr, dev, opt, proto, hlimit,
-                                     msg->msg_flags&MSG_DONTWAIT);
+               err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
+                                    opt, hlimit, msg->msg_flags);
+       } else {
+               err = ip6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, &fl, len,
+                                    opt, hlimit, msg->msg_flags);
        }
 
        return err<0?err:len;
@@ -520,8 +484,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
        struct raw6_opt *opt = &sk->tp_pinfo.tp_raw;
        int val, err;
 
-       switch(level)
-       {
+       switch(level) {
                case SOL_RAW:
                        break;
 
@@ -536,7 +499,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
                default:
                        return ipv6_setsockopt(sk, level, optname, optval,
                                               optlen);
-       }
+       };
 
        if (optval == NULL)
                return(-EINVAL);
@@ -545,15 +508,11 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
        if(err)
                return err;
 
-       switch (optname)
-       {
+       switch (optname) {
                case IPV6_CHECKSUM:
-                       if (val < 0)
-                       {
+                       if (val < 0) {
                                opt->checksum = 0;
-                       }
-                       else
-                       {
+                       } else {
                                opt->checksum = 1;
                                opt->offset = val;
                        }
@@ -572,11 +531,10 @@ static void rawv6_close(struct sock *sk, unsigned long timeout)
 
        sk->state = TCP_CLOSE;
 
-       if (np->dest)
-       {
-               ipv6_dst_unlock(np->dest);
-       }
+       if (np->dst)
+               dst_release(np->dst);
 
+       ipv6_sock_mc_close(sk);
        destroy_sock(sk);
 }
 
@@ -616,10 +574,3 @@ struct proto rawv6_prot = {
        0,                              /* inuse */
        0                               /* highestinuse */
 };
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o rawv6.o rawv6.c"
- *  c-file-style: "Linux"
- * End:
- */
index 8c3ba63b5488584de0bc45ad679bd1fad78b5ca2..35aa41b954679c694cb2ee6bf2cfd2b89d320ac4 100644 (file)
@@ -5,6 +5,8 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
+ *     $Id: reassembly.c,v 1.7 1997/03/18 18:24:47 davem Exp $
+ *
  *     Based on: net/ipv4/ip_fragment.c
  *
  *     This program is free software; you can redistribute it and/or
@@ -32,7 +34,6 @@
 #include <net/transp_v6.h>
 #include <net/rawv6.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
 #include <net/addrconf.h>
 
 
@@ -61,9 +62,7 @@ static int reasm_frag(struct frag_queue *fq, struct sk_buff **skb,
        int nh;
 
        if (del_timer(&fq->timer))
-       {
                expires = fq->timer.expires;
-       }
 
        /*
         *      We queue the packet even if it's the last.
@@ -75,14 +74,12 @@ static int reasm_frag(struct frag_queue *fq, struct sk_buff **skb,
         */
        reasm_queue(fq, *skb, fhdr);
 
-       if ((fhdr->frag_off & __constant_htons(0x0001)) == 0)
-       {
+       if ((fhdr->frag_off & __constant_htons(0x0001)) == 0) {
                fq->last_in = 1;
                fq->nhptr = nhptr;
        }
 
-       if (fq->last_in)
-       {
+       if (fq->last_in) {
                if ((nh = reasm_frag_1(fq, skb)))
                        return nh;
        }
@@ -99,17 +96,13 @@ int ipv6_reassembly(struct sk_buff **skb, struct device *dev, __u8 *nhptr,
        struct frag_hdr *fhdr = (struct frag_hdr *) ((*skb)->h.raw);
        struct frag_queue *fq;
        
-       for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next)
-       {
+       for (fq = ipv6_frag_queue.next; fq != &ipv6_frag_queue; fq = fq->next) {
                if (fq->id == fhdr->identification)
-               {                       
                        return reasm_frag(fq, skb, nhptr,fhdr);
-               }
        }
        
        create_frag_entry(*skb, dev, nhptr, fhdr);
 
-
        return 0;
 }
 
@@ -118,8 +111,7 @@ static void fq_free(struct frag_queue *fq)
 {
        struct ipv6_frag *fp, *back;
 
-       for(fp = fq->fragments; fp; )
-       {
+       for(fp = fq->fragments; fp; ) {
                kfree_skb(fp->skb, FREE_READ);          
                back = fp;
                fp=fp->next;
@@ -132,7 +124,6 @@ static void fq_free(struct frag_queue *fq)
        fq->prev = fq->next = NULL;
        
        kfree(fq);
-
 }
 
 static void frag_expire(unsigned long data)
@@ -146,13 +137,12 @@ static void frag_expire(unsigned long data)
 
        frag = fq->fragments;
 
-       if (frag == NULL)
-       {
+       if (frag == NULL) {
                printk(KERN_DEBUG "invalid fragment queue\n");
                return;
        }
 
-       icmpv6_send(frag->skb, ICMPV6_TIME_EXCEEDED, ICMPV6_EXC_FRAGTIME, 0,
+       icmpv6_send(frag->skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
                    frag->skb->dev);
        
        fq_free(fq);
@@ -168,8 +158,7 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev,
        fq = (struct frag_queue *) kmalloc(sizeof(struct frag_queue), 
                                           GFP_ATOMIC);
 
-       if (fq == NULL)
-       {
+       if (fq == NULL) {
                kfree_skb(skb, FREE_READ);
                return;
        }
@@ -188,8 +177,7 @@ static void create_frag_entry(struct sk_buff *skb, struct device *dev,
        fq->nexthdr = fhdr->nexthdr;
 
 
-       if ((fhdr->frag_off & __constant_htons(0x0001)) == 0)
-       {
+       if ((fhdr->frag_off & __constant_htons(0x0001)) == 0) {
                fq->last_in = 1;
                fq->nhptr = nhptr;
        }
@@ -212,13 +200,11 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb,
        nfp = (struct ipv6_frag *) kmalloc(sizeof(struct ipv6_frag), 
                                           GFP_ATOMIC);
 
-       if (nfp == NULL)
-       {
+       if (nfp == NULL) {
                kfree_skb(skb, FREE_READ);
                return;
        }
 
-       
        nfp->offset = ntohs(fhdr->frag_off) & ~0x7;
        nfp->len = (ntohs(skb->nh.ipv6h->payload_len) -
                    ((u8 *) (fhdr + 1) - (u8 *) (skb->nh.ipv6h + 1)));
@@ -231,18 +217,14 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb,
 
        bptr = &fq->fragments;
        
-
-       for (fp = fq->fragments; fp; fp=fp->next)
-       {
+       for (fp = fq->fragments; fp; fp=fp->next) {
                if (nfp->offset <= fp->offset)
                        break;
                bptr = &fp->next;
        }
        
-       if (fp && fp->offset == nfp->offset)
-       {
-               if (fp->len != nfp->len)
-               {
+       if (fp && fp->offset == nfp->offset) {
+               if (fp->len != nfp->len) {
                        /* this cannot happen */
                        printk(KERN_DEBUG "reasm_queue: dup with wrong len\n");
                }
@@ -253,7 +235,6 @@ static void reasm_queue(struct frag_queue *fq, struct sk_buff *skb,
                return;
        }
        
-
        *bptr = nfp;
        nfp->next = fp;
 }
@@ -273,9 +254,7 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in)
        __u16  copy;
        int    nh;
 
-
-       for(fp = fq->fragments; fp; fp=fp->next)
-       {
+       for(fp = fq->fragments; fp; fp=fp->next) {
                if (offset != fp->offset)
                        return 0;
 
@@ -296,8 +275,7 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in)
 
        printk(KERN_DEBUG "reasm: payload len = %d\n", payload_len);
 
-       if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL)
-       {
+       if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) {
                printk(KERN_DEBUG "reasm_frag: no memory for reassembly\n");
                fq_free(fq);
                return 1;
@@ -309,7 +287,6 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in)
 
        skb->dev = fq->dev;
 
-       
        nh = fq->nexthdr;
 
        *(fq->nhptr) = nh;
@@ -325,8 +302,7 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in)
         *      FIXME: If we don't have a checksum we ought to be able
         *      to defragment and checksum in this pass. [AC]
         */
-       for(fp = fq->fragments; fp; )
-       {
+       for(fp = fq->fragments; fp; ) {
                struct ipv6_frag *back;
 
                memcpy(skb_put(skb, fp->len), (__u8*)(fp->fhdr + 1), fp->len);
@@ -345,12 +321,3 @@ static int reasm_frag_1(struct frag_queue *fq, struct sk_buff **skb_in)
 
        return nh;
 }
-
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o reassembly.o reassembly.c"
- * c-file-style: "Linux"
- * End:
- */
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
new file mode 100644 (file)
index 0000000..079576a
--- /dev/null
@@ -0,0 +1,1599 @@
+/*
+ *     Linux INET6 implementation
+ *     FIB front-end.
+ *
+ *     Authors:
+ *     Pedro Roque             <roque@di.fc.ul.pt>     
+ *
+ *     $Id: route.c,v 1.9 1997/03/19 14:56:25 davem Exp $
+ *
+ *     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/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/route.h>
+#include <linux/netdevice.h>
+#include <linux/in6.h>
+
+#ifdef         CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <net/snmp.h>
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/ndisc.h>
+#include <net/addrconf.h>
+#include <net/netlink.h>
+
+#include <asm/uaccess.h>
+
+#undef CONFIG_RT6_POLICY
+
+/* Set to 3 to get tracing. */
+#define RT6_DEBUG 2
+
+#if RT6_DEBUG >= 3
+#define RDBG(x) printk x
+#else
+#define RDBG(x)
+#endif
+
+static struct dst_entry        *ip6_dst_check(struct dst_entry *dst, u32 cookie);
+static struct dst_entry        *ip6_dst_reroute(struct dst_entry *dst,
+                                        struct sk_buff *skb);
+
+static int             ip6_pkt_discard(struct sk_buff *skb);
+
+struct dst_ops ip6_dst_ops = {
+       AF_INET6,
+       ip6_dst_check,
+       ip6_dst_reroute,
+       NULL
+};
+
+struct rt6_info ip6_null_entry = {
+       {{NULL, 0, 0, NULL,
+         0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL,
+         ip6_pkt_discard, ip6_pkt_discard, &ip6_dst_ops}},
+       NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL,
+       0, {NULL}, {{{{0}}}, 128}, {{{{0}}}, 128}
+};
+
+struct fib6_node ip6_routing_table = {
+       NULL, NULL, NULL, NULL,
+       &ip6_null_entry,
+       0, RTN_ROOT|RTN_TL_ROOT, 0
+};
+
+#ifdef CONFIG_RT6_POLICY
+int    ip6_rt_policy = 0;
+
+struct pol_chain *rt6_pol_list = NULL;
+
+
+static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb);
+static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk);
+
+static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
+                                        struct in6_addr *daddr,
+                                        struct in6_addr *saddr,
+                                        struct fl_acc_args *args);
+
+#else
+#define ip6_rt_policy (0)
+#endif
+
+static atomic_t        rt6_tbl_lock    = 0;
+static int     rt6_bh_mask     = 0;
+
+#define RT_BH_REQUEST          1
+#define RT_BH_GC               2
+
+static void __rt6_run_bh(void);
+
+/*
+ *     request queue operations
+ *     FIFO queue/dequeue
+ */
+
+static struct rt6_req request_queue = {
+       0, NULL, &request_queue, &request_queue
+};
+
+static __inline__ void rtreq_queue(struct rt6_req * req)
+{
+       unsigned long flags;
+       struct rt6_req *next = &request_queue;
+
+       save_flags(flags);
+       cli();
+
+       req->prev = next->prev;
+       req->prev->next = req;
+       next->prev = req;
+       req->next = next;
+       restore_flags(flags);
+}
+
+static __inline__ struct rt6_req * rtreq_dequeue(void)
+{
+       struct rt6_req *next = &request_queue;
+       struct rt6_req *head;
+
+       head = next->next;
+
+       if (head == next)
+               return NULL;
+
+       head->next->prev = head->prev;
+       next->next = head->next;
+
+       head->next = NULL;
+       head->prev = NULL;
+
+       return head;
+}
+
+void rtreq_add(struct rt6_info *rt, int operation)
+{
+       struct rt6_req *rtreq;
+
+       rtreq = kmalloc(sizeof(struct rt6_req), GFP_ATOMIC);
+       
+       if (rtreq == NULL)
+               return;
+
+       memset(rtreq, 0, sizeof(struct rt6_req));
+
+       rtreq->operation = operation;
+       rtreq->ptr = rt;
+       rtreq_queue(rtreq);
+
+       rt6_bh_mask |= RT_BH_REQUEST;
+}
+
+static __inline__ void rt6_lock(void)
+{
+       atomic_inc(&rt6_tbl_lock);
+}
+
+static __inline__ void rt6_unlock(void)
+{
+       if (atomic_dec_and_test(&rt6_tbl_lock) && rt6_bh_mask) {
+               start_bh_atomic();
+               __rt6_run_bh();
+               end_bh_atomic();
+       }
+}
+
+/*
+ *     Route lookup
+ */
+
+static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
+                                                   struct device *dev,
+                                                   int strict)
+{
+       struct rt6_info *sprt;
+
+       RDBG(("rt6_device_match: (%p,%p,%d) ", rt, dev, strict));
+       if (dev) {
+               for (sprt = rt; sprt; sprt = sprt->u.next) {
+                       if (sprt->rt6i_dev == dev) {
+                               RDBG(("match --> %p\n", sprt));
+                               return sprt;
+                       }
+               }
+
+               if (strict) {
+                       RDBG(("nomatch & STRICT --> ip6_null_entry\n"));
+                       return &ip6_null_entry;
+               }
+       }
+       RDBG(("!dev or (no match and !strict) --> rt(%p)\n", rt));
+       return rt;
+}
+
+/*
+ *     pointer to the last default router chosen
+ */
+static struct rt6_info *rt6_dflt_pointer = NULL;
+
+static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, struct device *dev)
+{
+       struct rt6_info *match = NULL;
+       struct rt6_info *sprt;
+       int mpri = 0;
+
+       RDBG(("rt6_best_dflt(%p,%p): ", rt, dev));
+       for (sprt = rt; sprt; sprt = sprt->u.next) {
+               struct nd_neigh *ndn;
+
+               RDBG(("sprt(%p): ", sprt));
+               if ((ndn = (struct nd_neigh *) sprt->rt6i_nexthop)) {
+                       int m = -1;
+
+                       RDBG(("nxthop(%p,%d) ", ndn, ndn->ndn_nud_state));
+                       switch (ndn->ndn_nud_state) {
+                       case NUD_REACHABLE:
+                               RDBG(("NUD_REACHABLE "));
+                               if (sprt != rt6_dflt_pointer) {
+                                       rt = sprt;
+                                       RDBG(("sprt!=dflt_ptr -> %p\n",
+                                             sprt));
+                                       goto out;
+                               }
+                               RDBG(("m=2, "));
+                               m = 2;
+                               break;
+
+                       case NUD_DELAY:
+                               RDBG(("NUD_DELAY, m=1, "));
+                               m = 1;
+                               break;
+
+                       case NUD_STALE:
+                               RDBG(("NUD_STALE, m=1, "));
+                               m = 1;
+                               break;
+                       };
+
+                       if (dev && sprt->rt6i_dev == dev) {
+                               RDBG(("dev&&sprt->rt6i_dev==dev(%p), m+=2, ", dev));
+                               m += 2;
+                       }
+
+                       if (m >= mpri) {
+                               RDBG(("m>=mpri setmatch, "));
+                               mpri = m;
+                               match = sprt;
+                       }
+               }
+       }
+
+       if (match) {
+               RDBG(("match, set rt, "));
+               rt = match;
+       } else {
+               /*
+                *      No default routers are known to be reachable.
+                *      SHOULD round robin
+                */
+               RDBG(("!match, trying rt6_dflt_pointer, "));
+               if (rt6_dflt_pointer) {
+                       struct rt6_info *next;
+
+                       if ((next = rt6_dflt_pointer->u.next) &&
+                           next->u.dst.error == 0)
+                               rt = next;
+               }
+       }
+
+out:
+       rt6_dflt_pointer = rt;
+       RDBG(("returning %p, dflt_ptr set\n", rt));
+       return rt;
+}
+
+struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
+                           struct device *dev, int flags)
+{
+       struct fib6_node *fn;
+       struct rt6_info *rt;
+
+       RDBG(("rt6_lookup(%p,%p,%p,%x) from %p\n",
+             daddr, saddr, dev, flags, __builtin_return_address(0)));
+       rt6_lock();
+       fn = fib6_lookup(&ip6_routing_table, daddr, saddr);
+
+       rt = rt6_device_match(fn->leaf, dev, 0);
+       rt6_unlock();
+       return rt;
+}
+
+static struct rt6_info *rt6_cow(struct rt6_info *rt, struct in6_addr *daddr,
+                               struct in6_addr *saddr)
+{
+       /*
+        *      Clone the route.
+        */
+
+       rt = ip6_rt_copy(rt);
+
+       if (rt) {
+               ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
+
+               rt->rt6i_dst.plen = 128;
+               rt->rt6i_flags |= RTF_CACHE;
+
+               if (rt->rt6i_src.plen) {
+                       ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
+                       rt->rt6i_src.plen = 128;
+               }
+
+               rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, daddr);
+
+               rtreq_add(rt, RT_OPER_ADD);
+       } else {
+               rt = &ip6_null_entry;
+       }
+       return rt;
+}
+
+#ifdef CONFIG_RT6_POLICY
+static __inline__ struct rt6_info *rt6_flow_lookup_in(struct rt6_info *rt,
+                                                     struct sk_buff *skb)
+{
+       struct in6_addr *daddr, *saddr;
+       struct fl_acc_args arg;
+
+       arg.type = FL_ARG_FORWARD;
+       arg.fl_u.skb = skb;
+
+       saddr = &skb->nh.ipv6h->saddr;
+       daddr = &skb->nh.ipv6h->daddr;
+
+       return rt6_flow_lookup(rt, daddr, saddr, &arg);
+}
+
+static __inline__ struct rt6_info *rt6_flow_lookup_out(struct rt6_info *rt,
+                                                      struct sock *sk,
+                                                      struct flowi *fl)
+{
+       struct fl_acc_args arg;
+
+       arg.type = FL_ARG_ORIGIN;
+       arg.fl_u.fl_o.sk = sk;
+       arg.fl_u.fl_o.flow = fl;
+
+       return rt6_flow_lookup(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr,
+                              &arg);
+}
+
+#endif
+
+void ip6_route_input(struct sk_buff *skb)
+{
+       struct fib6_node *fn;
+       struct rt6_info *rt;
+       struct dst_entry *dst;
+
+       RDBG(("ip6_route_input(%p) from %p\n", skb, __builtin_return_address(0)));
+       rt6_lock();
+       fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
+                        &skb->nh.ipv6h->saddr);
+
+       rt = fn->leaf;
+
+       if ((rt->rt6i_flags & RTF_CACHE)) {
+               if (ip6_rt_policy == 0) {
+                       rt = rt6_device_match(rt, skb->dev, 0);
+                       goto out;
+               }
+
+#ifdef CONFIG_RT6_POLICY
+               if ((rt->rt6i_flags & RTF_FLOW)) {
+                       struct rt6_info *sprt;
+
+                       for (sprt = rt; sprt; sprt = sprt->u.next) {
+                               if (rt6_flow_match_in(sprt, skb)) {
+                                       rt = sprt;
+                                       goto out;
+                               }
+                       }
+               }
+#endif
+       }
+
+       rt = rt6_device_match(rt, skb->dev, 0);
+
+       if (ip6_rt_policy == 0) {
+               if (!rt->rt6i_nexthop && rt->rt6i_dev &&
+                   ((rt->rt6i_flags & RTF_NONEXTHOP) == 0)) {
+                       rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
+                                    &skb->nh.ipv6h->saddr);
+               }
+       } else {
+#ifdef CONFIG_RT6_POLICY
+               rt = rt6_flow_lookup_in(rt, skb);
+#endif
+       }
+
+out:
+       dst = dst_clone((struct dst_entry *) rt);
+       rt6_unlock();
+
+       skb->dst = dst;
+       dst->input(skb);
+}
+
+struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
+{
+       struct fib6_node *fn;
+       struct rt6_info *rt;
+       struct dst_entry *dst;
+       int strict;
+
+       RDBG(("ip6_route_output(%p,%p) from(%p)", sk, fl,
+             __builtin_return_address(0)));
+       strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & IPV6_ADDR_MULTICAST;
+
+       rt6_lock();
+#if RT6_DEBUG >= 3
+       RDBG(("lkup("));
+       if(fl->nl_u.ip6_u.daddr) {
+               struct in6_addr *addr = fl->nl_u.ip6_u.daddr;
+               int i;
+               RDBG(("daddr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+       }
+       if(fl->nl_u.ip6_u.saddr) {
+               struct in6_addr *addr = fl->nl_u.ip6_u.saddr;
+               int i;
+               RDBG(("saddr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+       }
+#endif
+       fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
+                        fl->nl_u.ip6_u.saddr);
+
+       RDBG(("-->(%p[%s])) ", fn, fn == &ip6_routing_table ? "ROOT" : "!ROOT"));
+
+       rt = fn->leaf;
+
+       if ((rt->rt6i_flags & RTF_CACHE)) {
+               RDBG(("RTF_CACHE "));
+               if (ip6_rt_policy == 0) {
+                       rt = rt6_device_match(rt, fl->dev, strict);
+                       RDBG(("devmatch(%p) ", rt));
+                       goto out;
+               }
+
+#ifdef CONFIG_RT6_POLICY
+               if ((rt->rt6i_flags & RTF_FLOW)) {
+                       struct rt6_info *sprt;
+
+                       for (sprt = rt; sprt; sprt = sprt->u.next) {
+                               if (rt6_flow_match_out(sprt, sk)) {
+                                       rt = sprt;
+                                       goto out;
+                               }
+                       }
+               }
+#endif
+       }
+       RDBG(("!RTF_CACHE "));
+       if (rt->rt6i_flags & RTF_DEFAULT) {
+               RDBG(("RTF_DEFAULT "));
+               if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF) {
+                       rt = rt6_best_dflt(rt, fl->dev);
+                       RDBG(("best_dflt(%p) ", rt));
+               }
+       } else {
+               rt = rt6_device_match(rt, fl->dev, strict);
+               RDBG(("!RTF_DEFAULT devmatch(%p) ", rt));
+       }
+
+       if (ip6_rt_policy == 0) {
+               if (!rt->rt6i_nexthop && rt->rt6i_dev &&
+                   ((rt->rt6i_flags & RTF_NONEXTHOP) == 0)) {
+                       rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
+                                    fl->nl_u.ip6_u.saddr);
+                       RDBG(("(!nhop&&rt6i_dev&&!RTF_NONEXTHOP) cow(%p) ", rt));
+               }
+       } else {
+#ifdef CONFIG_RT6_POLICY
+               rt = rt6_flow_lookup_out(rt, sk, fl);
+#endif
+       }
+
+out:
+       dst = dst_clone((struct dst_entry *) rt);
+       rt6_unlock();
+       RDBG(("dclone/ret(%p)\n", dst));
+       return dst;
+}
+
+
+void rt6_ins(struct rt6_info *rt)
+{
+       start_bh_atomic();
+       if (rt6_tbl_lock == 1)
+               fib6_add(&ip6_routing_table, rt);
+       else
+               rtreq_add(rt, RT_OPER_ADD);
+       end_bh_atomic();
+}
+
+/*
+ *     Destination cache support functions
+ */
+
+struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
+{
+       struct rt6_info *rt;
+
+       RDBG(("ip6dstchk(%p,%08x)[%p]\n", dst, cookie,
+             __builtin_return_address(0)));
+
+       rt = (struct rt6_info *) dst;
+
+       if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) {
+               if (rt->rt6i_nexthop)
+                       ndisc_event_send(rt->rt6i_nexthop, NULL);
+
+               return dst;
+       }
+
+       dst_release(dst);
+       return NULL;
+}
+
+struct dst_entry *ip6_dst_reroute(struct dst_entry *dst, struct sk_buff *skb)
+{
+       /*
+        *      FIXME
+        */
+       RDBG(("ip6_dst_reroute(%p,%p)[%p] (AIEEE)\n", dst, skb,
+             __builtin_return_address(0)));
+       return NULL;
+}
+
+/*
+ *
+ */
+
+struct rt6_info *ip6_route_add(struct in6_rtmsg *rtmsg, int *err)
+{
+       struct rt6_info *rt;
+       struct device *dev = NULL;
+       int addr_type;
+       
+       RDBG(("ip6_route_add(%p)[%p] ", rtmsg, __builtin_return_address(0)));
+       *err = 0;
+       
+       rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops);
+
+       if (rt == NULL) {
+               RDBG(("dalloc fails, "));
+               *err = -ENOMEM;
+               goto out;
+       }
+
+       /*
+        *      default... this should be chosen according to route flags
+        */
+
+#if RT6_DEBUG >= 3
+       {
+               struct in6_addr *addr = &rtmsg->rtmsg_dst;
+               int i;
+
+               RDBG(("daddr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+               addr = &rtmsg->rtmsg_src;
+               RDBG(("saddr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+       }
+#endif
+
+       addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);
+       
+       if (addr_type & IPV6_ADDR_MULTICAST) {
+               RDBG(("MCAST, "));
+               rt->u.dst.input = ip6_mc_input;
+       } else {
+               RDBG(("!MCAST "));
+               rt->u.dst.input = ip6_forward;
+       }
+       
+       rt->u.dst.output = dev_queue_xmit;
+       
+       if (rtmsg->rtmsg_ifindex)
+               dev = dev_get_by_index(rtmsg->rtmsg_ifindex);
+       if(dev)
+               RDBG(("d[%s] ", dev->name));
+
+       ipv6_addr_copy(&rt->rt6i_dst.addr, &rtmsg->rtmsg_dst);
+       rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;
+
+       /* XXX Figure out what really is supposed to be happening here -DaveM */
+       ipv6_addr_copy(&rt->rt6i_src.addr, &rtmsg->rtmsg_src);
+       rt->rt6i_src.plen = rtmsg->rtmsg_src_len;
+       
+       if ((rt->rt6i_src.plen = rtmsg->rtmsg_src_len)) {
+               RDBG(("splen, "));
+               ipv6_addr_copy(&rt->rt6i_src.addr, &rtmsg->rtmsg_src);
+       } else {
+               RDBG(("!splen, "));
+       }
+       /* XXX */
+
+       if (rtmsg->rtmsg_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) {
+               struct rt6_info *grt;
+               struct in6_addr *gw_addr;
+               u32 flags = 0;
+
+               RDBG(("RTF_GATEWAY, "));
+               /*
+                *      1. gateway route lookup
+                *      2. ndisc_get_neigh
+                */
+
+               gw_addr = &rtmsg->rtmsg_gateway;
+
+#if RT6_DEBUG >= 3
+               {
+                       struct in6_addr *addr = gw_addr;
+                       int i;
+
+                       RDBG(("gwaddr["));
+                       for(i = 0; i < 8; i++) {
+                               RDBG(("%04x%c", addr->s6_addr16[i],
+                                     i == 7 ? ']' : ':'));
+                       }
+               }
+#endif
+
+               if ((rtmsg->rtmsg_flags & RTF_GATEWAY) &&
+                   (rtmsg->rtmsg_flags & RTF_ADDRCONF) == 0) {
+                       RDBG(("RTF_GATEWAY && !RTF_ADDRCONF, "));
+                       if (dev)
+                               flags |= RTF_LINKRT;
+
+                       grt = rt6_lookup(gw_addr, NULL, dev, flags);
+
+                       if (grt == NULL)
+                       {
+                               RDBG(("!grt, "));
+                               *err = -EHOSTUNREACH;
+                               goto out;
+                       }
+                       dev = grt->rt6i_dev;
+                       RDBG(("grt(d=%s), ", dev ? dev->name : "NULL"));
+               }
+
+               rt->rt6i_nexthop = ndisc_get_neigh(dev, gw_addr);
+
+               if (rt->rt6i_nexthop == NULL) {
+                       RDBG(("!nxthop, "));
+                       *err = -ENOMEM;
+                       goto out;
+               }
+               RDBG(("nxthop, "));
+       }
+
+       if (dev == NULL) {
+               RDBG(("!dev, "));
+               *err = -ENODEV;
+               goto out;
+       }
+
+       rt->rt6i_metric = rtmsg->rtmsg_metric;
+
+       rt->rt6i_dev = dev;
+       rt->u.dst.pmtu = dev->mtu;
+       rt->rt6i_flags = rtmsg->rtmsg_flags;
+
+       RDBG(("rt6ins(%p) ", rt));
+
+       rt6_lock();
+       rt6_ins(rt);
+       rt6_unlock();
+
+out:
+       if (*err) {
+               RDBG(("dfree(%p) ", rt));
+               dst_free((struct dst_entry *) rt);
+               rt = NULL;
+       }
+       RDBG(("ret(%p)\n", rt));
+       return rt;
+}
+
+int ip6_del_rt(struct rt6_info *rt)
+{
+       rt6_lock();
+
+       start_bh_atomic();
+
+       rt6_dflt_pointer = NULL;
+
+       if (rt6_tbl_lock == 1)
+               fib6_del(rt);
+       else
+               rtreq_add(rt, RT_OPER_DEL);
+       end_bh_atomic();
+       rt6_unlock();
+       return 0;
+}
+
+int ip6_route_del(struct in6_rtmsg *rtmsg)
+{
+       return 0;
+}
+
+
+/*
+ *     bottom handler, runs with atomic_bh protection
+ */
+void __rt6_run_bh(void)
+{
+       struct rt6_req *rtreq;
+
+       while ((rtreq = rtreq_dequeue())) {
+               switch (rtreq->operation) {
+               case RT_OPER_ADD:
+                       fib6_add(&ip6_routing_table, rtreq->ptr);
+                       break;
+               case RT_OPER_DEL:
+                       fib6_del(rtreq->ptr);
+                       break;
+               };
+               kfree(rtreq);
+       }
+       rt6_bh_mask = 0;
+}
+
+/*
+ *     NETLINK interface
+ *     routing socket moral equivalent
+ */
+
+static int rt6_msgrcv(int unit, struct sk_buff *skb)
+{
+       int count = 0;
+       struct in6_rtmsg *rtmsg;
+       int err;
+
+       while (skb->len) {
+               if (skb->len < sizeof(struct in6_rtmsg)) {
+                       count = -EINVAL;
+                       goto out;
+               }
+               
+               rtmsg = (struct in6_rtmsg *) skb->data;
+               skb_pull(skb, sizeof(struct in6_rtmsg));
+               count += sizeof(struct in6_rtmsg);
+
+               switch (rtmsg->rtmsg_type) {
+               case RTMSG_NEWROUTE:
+                       ip6_route_add(rtmsg, &err);
+                       break;
+               case RTMSG_DELROUTE:
+                       ip6_route_del(rtmsg);
+                       break;
+               default:
+                       count = -EINVAL;
+                       goto out;
+               };
+       }
+
+out:
+       kfree_skb(skb, FREE_READ);      
+       return count;
+}
+
+static void rt6_sndrtmsg(struct in6_rtmsg *rtmsg)
+{
+       struct sk_buff *skb;
+       
+       skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
+       if (skb == NULL)
+               return;
+
+       memcpy(skb_put(skb, sizeof(struct in6_rtmsg)), &rtmsg,
+              sizeof(struct in6_rtmsg));
+       
+       if (netlink_post(NETLINK_ROUTE6, skb))
+               kfree_skb(skb, FREE_WRITE);
+}
+
+void rt6_sndmsg(int type, struct in6_addr *dst, struct in6_addr *src,
+               struct in6_addr *gw, struct device *dev, 
+               int dstlen, int srclen, int metric, __u32 flags)
+{
+       struct sk_buff *skb;
+       struct in6_rtmsg *msg;
+       
+       skb = alloc_skb(sizeof(struct in6_rtmsg), GFP_ATOMIC);
+       if (skb == NULL)
+               return;
+
+       msg = (struct in6_rtmsg *) skb_put(skb, sizeof(struct in6_rtmsg));
+
+       memset(msg, 0, sizeof(struct in6_rtmsg));
+       
+       msg->rtmsg_type = type;
+
+       if (dst)
+               ipv6_addr_copy(&msg->rtmsg_dst, dst);
+
+       if (src) {
+               ipv6_addr_copy(&msg->rtmsg_src, src);
+               msg->rtmsg_src_len = srclen;
+       }
+
+       if (gw)
+               ipv6_addr_copy(&msg->rtmsg_gateway, gw);
+
+       msg->rtmsg_dst_len = dstlen;
+       msg->rtmsg_metric = metric;
+
+       if (dev)
+               msg->rtmsg_ifindex = dev->ifindex;
+
+       msg->rtmsg_flags = flags;
+
+       if (netlink_post(NETLINK_ROUTE6, skb))
+               kfree_skb(skb, FREE_WRITE);
+}
+
+/*
+ *     Handle redirects
+ */
+struct rt6_info *rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
+                             struct in6_addr *target, struct device *dev,
+                             int on_link)
+{
+       struct rt6_info *rt, *tgtr, *nrt;
+
+       RDBG(("rt6_redirect(%s)[%p]: ",
+             dev ? dev->name : "NULL",
+             __builtin_return_address(0)));
+       rt = rt6_lookup(dest, NULL, dev, 0);
+
+       if (rt == NULL || rt->u.dst.error) {
+               RDBG(("!rt\n"));
+               printk(KERN_DEBUG "rt6_redirect: no route to destination\n");
+               return NULL;
+       }
+
+       if (rt->rt6i_flags & RTF_GATEWAY) {
+               /*
+                *      This can happen due to misconfiguration
+                *      if we are dealing with an "on link" redirect.
+                */
+               RDBG(("RTF_GATEWAY\n"));
+               printk(KERN_DEBUG "rt6_redirect: destination not directly "
+                      "connected\n");
+               return NULL;
+       }
+       RDBG(("tgt_lkup, "));
+       tgtr = rt6_lookup(target, NULL, dev, 0);
+
+       if (tgtr == NULL || tgtr->u.dst.error) {
+               /*
+                *      duh?! no route to redirect target.
+                *      How where we talking to it in the first place ?
+                */
+               RDBG(("!tgtr||dsterr\n"));
+               printk(KERN_DEBUG "rt6_redirect: no route to target\n");
+               return NULL;
+       }
+
+       if ((tgtr->rt6i_flags & RTF_GATEWAY) &&
+           ipv6_addr_cmp(dest, &tgtr->rt6i_gateway) == 0) {
+               RDBG(("tgt RTF_GATEWAY && dstmatch, dup\n"));
+               /*
+                *      Check if we already have the right route.
+                */
+#if RT6_DEBUG >= 1
+               printk(KERN_DEBUG "rt6_redirect: duplicate\n");
+#endif
+               return NULL;
+       }
+
+       /*
+        *      RFC 1970 specifies that redirects should only be
+        *      accepted if they come from the nexthop to the target.
+        *      Due to the way default routers are chosen, this notion
+        *      is a bit fuzzy and one might need to check all default
+        *      routers.
+        */
+
+       if (ipv6_addr_cmp(saddr, &tgtr->rt6i_gateway)) {
+               RDBG(("saddr/tgt->gway match, "));
+               if (tgtr->rt6i_flags & RTF_DEFAULT) {
+                       tgtr = ip6_routing_table.leaf;
+
+                       for (; tgtr; tgtr = tgtr->u.next) {
+                               if (!ipv6_addr_cmp(saddr, &tgtr->rt6i_gateway)) {
+                                       RDBG(("found srcok, "));
+                                       goto source_ok;
+                               }
+                       }
+               }
+               RDBG(("!dflt||!srcok, "));
+               printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
+                      "for redirect target\n");
+       }
+
+source_ok:
+
+       /*
+        *      We have finally decided to accept it.
+        */
+       RDBG(("srcok: "));
+       if ((tgtr->rt6i_flags & RTF_HOST)) {
+               /*
+                *      Already a host route.
+                *
+                */
+               RDBG(("hralready, "));
+               if (tgtr->rt6i_nexthop) {
+                       RDBG(("nrel(nxthop) "));
+                       neigh_release(tgtr->rt6i_nexthop);
+               }
+               /*
+                *      purge hh_cache
+                */
+               tgtr->rt6i_flags |= RTF_MODIFIED | RTF_CACHE;
+               ipv6_addr_copy(&tgtr->rt6i_gateway, dest);
+               tgtr->rt6i_nexthop = ndisc_get_neigh(tgtr->rt6i_dev, dest);
+               RDBG(("hhpurge, getnewneigh, ret(%p)\n", tgtr));
+               return tgtr;
+       }
+
+       nrt = ip6_rt_copy(tgtr);
+       nrt->rt6i_flags = RTF_GATEWAY|RTF_HOST|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
+
+       ipv6_addr_copy(&nrt->rt6i_dst.addr, target);
+       nrt->rt6i_dst.plen = 128;
+
+       ipv6_addr_copy(&nrt->rt6i_gateway, dest);
+       nrt->rt6i_nexthop = ndisc_get_neigh(nrt->rt6i_dev, dest);
+       nrt->rt6i_dev = dev;
+       nrt->u.dst.pmtu = dev->mtu;
+
+       RDBG(("rt6_ins(%p)\n", nrt));
+
+       rt6_lock();
+       rt6_ins(nrt);
+       rt6_unlock();
+
+       return nrt;
+}
+
+/*
+ *     Handle ICMP "packet too big" messages
+ *     i.e. Path MTU discovery
+ */
+
+void rt6_pmtu_discovery(struct in6_addr *addr, struct device *dev, int pmtu)
+{
+       struct rt6_info *rt;
+
+       if (pmtu < 576 || pmtu > 65536) {
+#if RT6_DEBUG >= 1
+               printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",
+                      pmtu);
+#endif
+               return;
+       }
+
+       rt = rt6_lookup(addr, NULL, dev, 0);
+
+       if (rt == NULL || rt->u.dst.error) {
+#if RT6_DEBUG >= 2
+               printk(KERN_DEBUG "rt6_pmtu_discovery: no route to host\n");
+#endif
+               return;
+       }
+
+       if (rt->rt6i_flags & RTF_HOST) {
+               /*
+                *      host route
+                */
+               rt->u.dst.pmtu = pmtu;
+               rt->rt6i_flags |= RTF_MODIFIED;
+
+               return;
+       }
+
+       rt = ip6_rt_copy(rt);
+       ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+       rt->rt6i_dst.plen = 128;
+
+       rt->rt6i_flags |= (RTF_HOST | RTF_DYNAMIC | RTF_CACHE);
+
+       rt6_lock();
+       rt6_ins(rt);
+       rt6_unlock();
+}
+
+/*
+ *     Misc support functions
+ */
+
+struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
+{
+       struct rt6_info *rt;
+
+       rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops);
+       
+       if (rt) {
+               rt->u.dst.input = ort->u.dst.input;
+               rt->u.dst.output = ort->u.dst.output;
+
+               rt->u.dst.pmtu = ort->u.dst.pmtu;
+               rt->rt6i_dev = ort->rt6i_dev;
+               
+               ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
+               rt->rt6i_keylen = ort->rt6i_keylen;
+               rt->rt6i_flags = ort->rt6i_flags;
+               rt->rt6i_metric = ort->rt6i_metric;
+               
+               memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
+               memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
+       }
+       return rt;
+}
+
+struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct device *dev)
+{      
+       struct rt6_info *rt;
+       struct fib6_node *fn;
+
+       RDBG(("rt6_get_dflt_router(%p,%p)[%p]", addr, dev,
+             __builtin_return_address(0)));
+#if RT6_DEBUG >= 3
+       {
+               int i;
+
+               RDBG(("addr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+       }
+#endif
+       RDBG(("\n"));
+       rt6_lock();
+
+       fn = &ip6_routing_table;
+
+       for (rt = fn->leaf; rt; rt=rt->u.next) {
+               if (dev == rt->rt6i_dev &&
+                   ipv6_addr_cmp(&rt->rt6i_dst.addr, addr) == 0)
+                       break;
+       }
+
+       rt6_unlock();
+       return rt;
+}
+
+struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
+                                    struct device *dev)
+{
+       struct in6_rtmsg rtmsg;
+       struct rt6_info *rt;
+       int err;
+
+       RDBG(("rt6_add_dflt_router(%p,%p)[%p] ", gwaddr, dev,
+             __builtin_return_address(0)));
+#if RT6_DEBUG >= 3
+       {
+               struct in6_addr *addr = gwaddr;
+               int i;
+
+               RDBG(("gwaddr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+       }
+#endif
+       RDBG(("\n"));
+
+       memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
+       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
+       ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
+       rtmsg.rtmsg_metric = 1024;
+       rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP;
+
+       rtmsg.rtmsg_ifindex = dev->ifindex;
+
+       rt = ip6_route_add(&rtmsg, &err);
+
+       if (err) {
+               printk(KERN_DEBUG "rt6_add_dflt: ip6_route_add error %d\n",
+                      err);
+       }
+       return rt;
+}
+
+void rt6_purge_dflt_routers(int last_resort)
+{
+       struct rt6_info *rt;
+       struct fib6_node *fn;
+       u32 flags;
+
+       RDBG(("rt6_purge_dflt_routers(%d)[%p]\n", last_resort,
+             __builtin_return_address(0)));
+       fn = &ip6_routing_table;
+
+       rt6_dflt_pointer = NULL;
+
+       if (last_resort)
+               flags = RTF_ALLONLINK;
+       else
+               flags = RTF_DEFAULT | RTF_ADDRCONF;     
+
+       for (rt = fn->leaf; rt; ) {
+               if ((rt->rt6i_flags & flags)) {
+                       struct rt6_info *drt;
+#if RT6_DEBUG >= 2
+                       printk(KERN_DEBUG "rt6_purge_dflt: deleting entry\n");
+#endif
+                       drt = rt;
+                       rt = rt->u.next;
+                       ip6_del_rt(drt);
+                       continue;
+               }
+               rt = rt->u.next;
+       }
+}
+
+int ipv6_route_ioctl(unsigned int cmd, void *arg)
+{
+       struct in6_rtmsg rtmsg;
+       int err;
+
+       RDBG(("ipv6_route_ioctl(%d,%p)\n", cmd, arg));
+       switch(cmd) {
+       case SIOCADDRT:         /* Add a route */
+       case SIOCDELRT:         /* Delete a route */
+               if (!suser())
+                       return -EPERM;
+               err = copy_from_user(&rtmsg, arg,
+                                    sizeof(struct in6_rtmsg));
+               if (err)
+                       return -EFAULT;
+                       
+               switch (cmd) {
+               case SIOCADDRT:
+                       ip6_route_add(&rtmsg, &err);
+                       break;
+               case SIOCDELRT:
+                       err = ip6_route_del(&rtmsg);
+                       break;
+               default:
+                       err = -EINVAL;
+               };
+
+               if (err == 0)
+                               rt6_sndrtmsg(&rtmsg);
+               return err;
+       };
+
+       return -EINVAL;
+}
+
+/*
+ *     Drop the packet on the floor
+ */
+
+int ip6_pkt_discard(struct sk_buff *skb)
+{      
+       ipv6_statistics.Ip6OutNoRoutes++;
+       kfree_skb(skb, FREE_WRITE);
+       return 0;
+}
+
+/*
+ *     Add address
+ */
+
+int ip6_rt_addr_add(struct in6_addr *addr, struct device *dev)
+{
+       struct rt6_info *rt;
+
+       RDBG(("ip6_rt_addr_add(%p,%p)[%p]\n", addr, dev,
+             __builtin_return_address(0)));
+#if RT6_DEBUG >= 3
+       {
+               int i;
+
+               RDBG(("addr["));
+               for(i = 0; i < 8; i++) {
+                       RDBG(("%04x%c", addr->s6_addr16[i],
+                             i == 7 ? ']' : ':'));
+               }
+       }
+#endif
+       RDBG(("\n"));
+
+       rt = dst_alloc(sizeof(struct rt6_info), &ip6_dst_ops);
+       if (rt == NULL)
+               return -ENOMEM;
+       
+       memset(rt, 0, sizeof(struct rt6_info));
+       
+       rt->u.dst.input = ip6_input;
+       rt->u.dst.output = dev_queue_xmit;
+       rt->rt6i_dev = dev_get("lo");
+       rt->u.dst.pmtu = rt->rt6i_dev->mtu;
+
+       rt->rt6i_flags = RTF_HOST | RTF_LOCAL | RTF_UP | RTF_NONEXTHOP;
+       
+       ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
+       rt->rt6i_dst.plen = 128;
+
+       rt6_lock();
+       rt6_ins(rt);
+       rt6_unlock();
+
+       return 0;
+}
+
+#ifdef CONFIG_RT6_POLICY
+
+static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb)
+{
+       struct flow_filter *frule;
+       struct pkt_filter *filter;
+       int res = 1;
+
+       if ((frule = rt->rt6i_filter) == NULL)
+               goto out;
+
+       if (frule->type != FLR_INPUT) {
+               res = 0;
+               goto out;
+       }
+
+       for (filter = frule->u.filter; filter; filter = filter->next) {
+               __u32 *word;
+
+               word = (__u32 *) skb->h.raw;
+               word += filter->offset;
+
+               if ((*word ^ filter->value) & filter->mask) {
+                       res = 0;
+                       break;
+               }
+       }
+
+out:
+       return res;
+}
+
+static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk)
+{
+       struct flow_filter *frule;
+       int res = 1;
+
+       if ((frule = rt->rt6i_filter) == NULL)
+               goto out;
+
+       if (frule->type != FLR_INPUT) {
+               res = 0;
+               goto out;
+       }
+
+       if (frule->u.sk != sk)
+               res = 0;
+out:
+       return res;
+}
+
+static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
+                                       struct in6_addr *daddr,
+                                       struct in6_addr *saddr,
+                                       struct fl_acc_args *args)
+{
+       struct flow_rule *frule;
+       struct rt6_info *nrt = NULL;
+       struct pol_chain *pol;
+
+       for (pol = rt6_pol_list; pol; pol = pol->next) {
+               struct fib6_node *fn;
+               struct rt6_info *sprt;
+
+               fn = fib6_lookup(pol->rules, daddr, saddr);
+
+               do {
+                       for (sprt = fn->leaf; sprt; sprt=sprt->u.next) {
+                               int res;
+
+                               frule = sprt->rt6i_flowr;
+#if RT6_DEBUG >= 2
+                               if (frule == NULL) {
+                                       printk(KERN_DEBUG "NULL flowr\n");
+                                       goto error;
+                               }
+#endif
+                               res = frule->ops->accept(rt, sprt, args, &nrt);
+
+                               switch (res) {
+                               case FLOWR_SELECT:
+                                       goto found;
+                               case FLOWR_CLEAR:
+                                       goto next_policy;
+                               case FLOWR_NODECISION:
+                                       break;
+                               default:
+                                       goto error;
+                               };
+                       }
+
+                       fn = fn->parent;
+
+               } while ((fn->fn_flags & RTN_TL_ROOT) == 0);
+
+       next_policy:
+       }
+
+error:
+       return &ip6_null_entry;
+
+found:
+
+       if (nrt == NULL)
+               goto error;
+
+       nrt->rt6i_flags |= RTF_CACHE;
+       rt6_ins(nrt);
+
+       return nrt;
+}
+#endif
+
+/*
+ *     /proc
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#define RT6_INFO_LEN (32 + 4 + 32 + 4 + 32 + 40 + 5 + 1)
+
+struct rt6_proc_arg {
+       char *buffer;
+       int offset;
+       int length;
+       int skip;
+       int len;
+};
+
+static void rt6_info_node(struct fib6_node *fn, void *p_arg)
+{
+       struct rt6_info *rt;
+       struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg;
+
+       for (rt = fn->leaf; rt; rt = rt->u.next) {
+               int i;
+
+               if (arg->skip < arg->offset / RT6_INFO_LEN) {
+                       arg->skip++;
+                       continue;
+               }
+
+               if (arg->len >= arg->length)
+                       return;
+               
+               for (i=0; i<16; i++) {
+                       sprintf(arg->buffer + arg->len, "%02x",
+                               rt->rt6i_dst.addr.s6_addr[i]);
+                       arg->len += 2;
+               }
+               arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+                                   rt->rt6i_dst.plen);
+
+               for (i=0; i<16; i++) {
+                       sprintf(arg->buffer + arg->len, "%02x",
+                               rt->rt6i_src.addr.s6_addr[i]);
+                       arg->len += 2;
+               }
+               arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+                                   rt->rt6i_src.plen);
+               
+               if (rt->rt6i_nexthop) {
+                       for (i=0; i<16; i++) {
+                               struct nd_neigh *ndn;
+
+                               ndn = (struct nd_neigh *) rt->rt6i_nexthop;
+                               sprintf(arg->buffer + arg->len, "%02x",
+                                       ndn->ndn_addr.s6_addr[i]);
+                               arg->len += 2;
+                       }
+               } else {
+                       sprintf(arg->buffer + arg->len,
+                               "00000000000000000000000000000000");
+                       arg->len += 32;
+               }
+               arg->len += sprintf(arg->buffer + arg->len,
+                                   " %08lx %08x %08x %08lx %8s\n",
+                                   rt->rt6i_metric, rt->rt6i_use,
+                                   rt->rt6i_ref, rt->rt6i_flags, 
+                                   rt->rt6i_dev ? rt->rt6i_dev->name : "");
+       }
+}
+
+static int rt6_proc_info(char *buffer, char **start, off_t offset, int length,
+                        int dummy)
+{
+       struct rt6_proc_arg arg;
+       arg.buffer = buffer;
+       arg.offset = offset;
+       arg.length = length;
+       arg.skip = 0;
+       arg.len = 0;
+
+       fib6_walk_tree(&ip6_routing_table, rt6_info_node, &arg,
+                      RT6_FILTER_RTNODES);
+
+       rt6_info_node(&ip6_routing_table, &arg);
+
+       *start = buffer;
+       if (offset)
+               *start += offset % RT6_INFO_LEN;
+
+       arg.len -= offset % RT6_INFO_LEN;
+
+       if(arg.len > length)
+               arg.len = length;
+       if(arg.len < 0)
+               arg.len = 0;
+
+       return arg.len;
+}
+
+#define PTR_SZ (sizeof(void *) * 2)
+#define FI_LINE_SZ (2 * (PTR_SZ) + 7 + 32 + 4 + 32 + 4)
+
+static void rt6_tree_node(struct fib6_node *fn, void *p_arg)
+{
+       struct rt6_proc_arg *arg = (struct rt6_proc_arg *) p_arg;
+       struct rt6_info *rt;
+       char f;
+       int i;
+
+       rt = fn->leaf;
+
+       if (arg->skip < arg->offset / FI_LINE_SZ) {
+               arg->skip++;
+               return;
+       }
+
+       if (arg->len + FI_LINE_SZ >= arg->length)
+               return;
+
+       f = (fn->fn_flags & RTN_RTINFO) ? 'r' : 'n';
+       arg->len += sprintf(arg->buffer + arg->len, "%p %p %02x %c ",
+                           fn, fn->parent, fn->fn_bit, f);
+
+       for (i=0; i<16; i++) {
+               sprintf(arg->buffer + arg->len, "%02x",
+                       rt->rt6i_dst.addr.s6_addr[i]);
+               arg->len += 2;
+       }
+       arg->len += sprintf(arg->buffer + arg->len, " %02x ",
+                           rt->rt6i_dst.plen);
+       
+       for (i=0; i<16; i++) {
+               sprintf(arg->buffer + arg->len, "%02x",
+                       rt->rt6i_src.addr.s6_addr[i]);
+               arg->len += 2;
+       }
+       arg->len += sprintf(arg->buffer + arg->len, " %02x\n",
+                           rt->rt6i_src.plen);
+
+}
+
+static int rt6_proc_tree(char *buffer, char **start, off_t offset, int length,
+                        int dummy)
+{
+       struct rt6_proc_arg arg;
+       arg.buffer = buffer;
+       arg.offset = offset;
+       arg.length = length;
+       arg.skip = 0;
+       arg.len = 0;
+
+       fib6_walk_tree(&ip6_routing_table, rt6_tree_node, &arg, 0);
+
+       *start = buffer;
+       if (offset)
+               *start += offset % RT6_INFO_LEN;
+
+       arg.len -= offset % RT6_INFO_LEN;
+
+       if(arg.len > length)
+               arg.len = length;
+       if(arg.len < 0)
+               arg.len = 0;
+
+       return arg.len;
+}
+
+extern struct rt6_statistics rt6_stats;
+
+static int rt6_proc_stats(char *buffer, char **start, off_t offset, int length,
+                         int dummy)
+{
+       int len;
+
+       len = sprintf(buffer, "%04x %04x %04x %04x %04x\n",
+                     rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
+                     rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
+                     rt6_stats.fib_rt_cache);
+
+       len -= offset;
+
+       if (len > length)
+               len = length;
+       if(len < 0)
+               len = 0;
+
+       *start = buffer + offset;
+
+       return len;
+}
+
+static struct proc_dir_entry proc_rt6_info = {
+       PROC_NET_RT6, 10, "ipv6_route",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       rt6_proc_info
+};
+static struct proc_dir_entry proc_rt6_stats = {
+       PROC_NET_RT6_STATS, 9, "rt6_stats",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       rt6_proc_stats
+};
+static struct proc_dir_entry proc_rt6_tree = {
+       PROC_NET_RT6_TREE, 7, "ip6_fib",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_net_inode_operations,
+       rt6_proc_tree
+};
+#endif /* CONFIG_PROC_FS */
+
+void ip6_route_init(void)
+{
+#ifdef         CONFIG_PROC_FS
+       proc_net_register(&proc_rt6_info);
+       proc_net_register(&proc_rt6_stats);
+       proc_net_register(&proc_rt6_tree);
+#endif
+       netlink_attach(NETLINK_ROUTE6, rt6_msgrcv);
+}
+
+#ifdef MODULE
+void ip6_route_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS
+       proc_net_unregister(PROC_NET_RT6);
+       proc_net_unregister(PROC_NET_RT6_TREE);
+       proc_net_unregister(PROC_NET_RT6_STATS);
+#endif
+       netlink_detach(NETLINK_ROUTE6);
+#if 0
+       fib6_flush();
+#endif
+}
+#endif /* MODULE */
index 90267b7f1464e8d109ced0a320d2c0825de3f4d4..4b072889c47795ce57958dd5c6d3581851b7866e 100644 (file)
@@ -5,6 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
+ *     $Id: sit.c,v 1.13 1997/03/18 18:24:50 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -30,7 +31,6 @@
 #include <net/protocol.h>
 #include <net/transp_v6.h>
 #include <net/ndisc.h>
-#include <net/ipv6_route.h>
 #include <net/addrconf.h>
 #include <net/ip.h>
 #include <net/udp.h>
@@ -57,7 +57,7 @@ static void                   sit_err(struct sk_buff *skb, unsigned char *dp);
 static int                     sit_open(struct device *dev);
 static int                     sit_close(struct device *dev);
 
-static struct enet_statistics *        sit_get_stats(struct device *dev);
+static struct net_device_stats *sit_get_stats(struct device *dev);
 
 extern void    udp_err(struct sk_buff *, unsigned char *);
 
@@ -118,10 +118,8 @@ static struct sit_mtu_info * sit_mtu_lookup(__u32 addr)
 
        hash = sit_addr_hash(addr);
 
-       for(iter = sit_mtu_cache[hash]; iter; iter=iter->next)
-       {
-               if (iter->addr == addr)
-               {
+       for(iter = sit_mtu_cache[hash]; iter; iter=iter->next) {
+               if (iter->addr == addr) {
                        iter->tstamp = jiffies;
                        break;
                }
@@ -131,8 +129,7 @@ static struct sit_mtu_info * sit_mtu_lookup(__u32 addr)
         *      run garbage collector
         */
 
-       if (jiffies - sit_gc_last_run > SIT_GC_FREQUENCY)
-       {
+       if (jiffies - sit_gc_last_run > SIT_GC_FREQUENCY) {
                sit_mtu_cache_gc();
                sit_gc_last_run = jiffies;
        }
@@ -146,26 +143,19 @@ static void sit_mtu_cache_gc(void)
        unsigned long now = jiffies;
        int i;
 
-       for (i=0; i < SIT_NUM_BUCKETS; i++)
-       {
+       for (i=0; i < SIT_NUM_BUCKETS; i++) {
                back = NULL;
-               for (iter = sit_mtu_cache[i]; iter;)
-               {
-                       if (now - iter->tstamp > SIT_GC_TIMEOUT)
-                       {
+               for (iter = sit_mtu_cache[i]; iter;) {
+                       if (now - iter->tstamp > SIT_GC_TIMEOUT) {
                                struct sit_mtu_info *old;
 
                                old = iter;
                                iter = iter->next;
 
                                if (back)
-                               {
                                        back->next = iter;
-                               }
                                else
-                               {
                                        sit_mtu_cache[i] = iter;
-                               }
 
                                kfree(old);
                                continue;
@@ -186,12 +176,12 @@ static int sit_init_dev(struct device *dev)
        dev->hard_start_xmit    = sit_xmit;
        dev->get_stats          = sit_get_stats;
 
-       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+       dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
 
        if (dev->priv == NULL)
                return -ENOMEM;
 
-       memset(dev->priv, 0, sizeof(struct enet_statistics));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
 
 
        for (i = 0; i < DEV_NUMBUFFS; i++)
@@ -230,12 +220,12 @@ static int sit_init_vif(struct device *dev)
        int i;
 
        dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
-       dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+       dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
 
        if (dev->priv == NULL)
                return -ENOMEM;
 
-       memset(dev->priv, 0, sizeof(struct enet_statistics));
+       memset(dev->priv, 0, sizeof(struct net_device_stats));
 
        for (i = 0; i < DEV_NUMBUFFS; i++)
                skb_queue_head_init(&dev->buffs[i]);
@@ -253,7 +243,6 @@ static int sit_close(struct device *dev)
        return 0;
 }
 
-
 int sit_init(void)
 {
        int i;
@@ -261,9 +250,7 @@ int sit_init(void)
        /* register device */
 
        if (register_netdev(&sit_device) != 0)
-       {
                return -EIO;
-       }
 
        inet_add_protocol(&sit_protocol);
 
@@ -314,9 +301,8 @@ struct device *sit_add_tunnel(__u32 dstaddr)
 void sit_cleanup(void)
 {
        struct sit_vif *vif;
-       
-       for (vif = vif_list; vif;)
-       {
+
+       for (vif = vif_list; vif;) {
                struct device *dev = vif->dev;
                struct sit_vif *cur;
 
@@ -335,8 +321,6 @@ void sit_cleanup(void)
        
 }
 
-
-
 /*
  *     receive IPv4 ICMP messages
  */
@@ -347,8 +331,7 @@ static void sit_err(struct sk_buff *skb, unsigned char *dp)
        int type = skb->h.icmph->type;
        int code = skb->h.icmph->code;
 
-       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
-       {
+       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
                struct sit_mtu_info *minfo;
                unsigned short info = skb->h.icmph->un.frag.mtu - sizeof(struct iphdr);
 
@@ -356,8 +339,8 @@ static void sit_err(struct sk_buff *skb, unsigned char *dp)
 
                printk(KERN_DEBUG "sit: %08lx pmtu = %ul\n", ntohl(iph->saddr),
                       info);
-               if (minfo == NULL)
-               {
+
+               if (minfo == NULL) {
                        minfo = kmalloc(sizeof(struct sit_mtu_info),
                                        GFP_ATOMIC);
 
@@ -367,9 +350,7 @@ static void sit_err(struct sk_buff *skb, unsigned char *dp)
                        start_bh_atomic();
                        sit_cache_insert(iph->daddr, info);
                        end_bh_atomic();
-               }
-               else
-               {
+               } else {
                        minfo->mtu = info;
                }
        }
@@ -377,7 +358,7 @@ static void sit_err(struct sk_buff *skb, unsigned char *dp)
 
 static int sit_rcv(struct sk_buff *skb, unsigned short len)
 {
-       struct enet_statistics *stats;
+       struct net_device_stats *stats;
        struct device *dev = NULL;
        struct sit_vif *vif;    
        __u32  saddr = skb->nh.iph->saddr;
@@ -386,24 +367,21 @@ static int sit_rcv(struct sk_buff *skb, unsigned short len)
 
        skb->protocol = __constant_htons(ETH_P_IPV6);
 
-       for (vif = vif_list; vif; vif = vif->next)
-       {
-               if (saddr == vif->dev->pa_dstaddr)
-               {
+       for (vif = vif_list; vif; vif = vif->next) {
+               if (saddr == vif->dev->pa_dstaddr) {
                        dev = vif->dev;
                        break;
                }
        }
 
        if (dev == NULL)
-       {
                dev = &sit_device;
-       }
 
        skb->dev = dev;
        skb->ip_summed = CHECKSUM_NONE;
 
-       stats = (struct enet_statistics *)dev->priv;
+       stats = (struct net_device_stats *)dev->priv;
+       stats->rx_bytes += len;
        stats->rx_packets++;
 
        ipv6_rcv(skb, dev, NULL);
@@ -412,7 +390,7 @@ static int sit_rcv(struct sk_buff *skb, unsigned short len)
 
 static int sit_xmit(struct sk_buff *skb, struct device *dev)
 {
-       struct enet_statistics *stats;
+       struct net_device_stats *stats;
        struct sit_mtu_info *minfo;
        struct in6_addr *addr6; 
        struct rtable *rt;
@@ -427,16 +405,16 @@ static int sit_xmit(struct sk_buff *skb, struct device *dev)
         *      Make sure we are not busy (check lock variable) 
         */
 
-       stats = (struct enet_statistics *)dev->priv;
+       stats = (struct net_device_stats *)dev->priv;
 
        daddr = dev->pa_dstaddr;
-       if (daddr == 0)
-       {
-               struct nd_neigh *neigh;
+       if (daddr == 0) {
+               struct nd_neigh *neigh = NULL;
 
-               neigh = (struct nd_neigh *) skb->nexthop;
-               if (neigh == NULL)
-               {
+               if (skb->dst)
+                       neigh = (struct nd_neigh *) skb->dst->neighbour;
+
+               if (neigh == NULL) {
                        printk(KERN_DEBUG "sit: nexthop == NULL\n");
                        goto on_error;
                }
@@ -444,14 +422,12 @@ static int sit_xmit(struct sk_buff *skb, struct device *dev)
                addr6 = &neigh->ndn_addr;
                addr_type = ipv6_addr_type(addr6);
 
-               if (addr_type == IPV6_ADDR_ANY)
-               {
+               if (addr_type == IPV6_ADDR_ANY) {
                        addr6 = &skb->nh.ipv6h->daddr;
                        addr_type = ipv6_addr_type(addr6);
                }
 
-               if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
-               {
+               if ((addr_type & IPV6_ADDR_COMPATv4) == 0) {
                        printk(KERN_DEBUG "sit_xmit: non v4 address\n");
                        goto on_error;
                }
@@ -475,8 +451,7 @@ static int sit_xmit(struct sk_buff *skb, struct device *dev)
 #endif
                mtu = rt->u.dst.pmtu;
 
-       if (mtu > 576 && skb->tail - (skb->data + sizeof(struct ipv6hdr)) > mtu)
-       {
+       if (mtu > 576 && skb->tail - (skb->data + sizeof(struct ipv6hdr)) > mtu) {
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
                ip_rt_put(rt);
                goto on_error;
@@ -522,25 +497,18 @@ static int sit_xmit(struct sk_buff *skb, struct device *dev)
 
        ip_send(skb);
 
+       stats->tx_bytes += skb->len;
        stats->tx_packets++;
 
        return 0;
 
-  on_error:
+on_error:
        dev_kfree_skb(skb, FREE_WRITE);
        stats->tx_errors++;
        return 0;       
 }
 
-static struct enet_statistics *sit_get_stats(struct device *dev)
+static struct net_device_stats *sit_get_stats(struct device *dev)
 {
-       return((struct enet_statistics*) dev->priv);
+       return((struct net_device_stats *) dev->priv);
 }
-
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o sit.o sit.c"
- * c-file-style: "Linux"
- * End:
- */
index ce7bb468196574d33219f784578e7f0b2d2daa83..19ac22c9aa3d1a6f0c37593f2506b37ad8e77345 100644 (file)
 #include <net/ipv6.h>
 #include <net/addrconf.h>
 
-
-int ipv6_hop_limit = IPV6_DEFAULT_HOPLIMIT;
+struct ipv6_config ipv6_config =
+{
+       0,                              /* forwarding           */
+       IPV6_DEFAULT_HOPLIMIT,          /* hop limit            */
+       1,                              /* accept RAs           */
+       1,                              /* accept redirects     */
+
+       3,                              /* nd_max_mcast_solicit */
+       3,                              /* nd_max_ucast_solicit */
+       RETRANS_TIMER,                  /* nd_retrans_time      */
+       RECHABLE_TIME,                  /* nd_base_reach_time   */
+       (5 * HZ),                       /* nd_delay_probe_time  */
+
+       1,                              /* autoconfiguration    */
+       1,                              /* dad transmits        */
+       MAX_RTR_SOLICITATIONS,          /* router solicits      */
+       RTR_SOLICITATION_INTERVAL,      /* rtr solicit interval */
+       MAX_RTR_SOLICITATION_DELAY,     /* rtr solicit delay    */
+
+       60*HZ,                          /* rt cache timeout     */
+       30*HZ,                          /* rt gc period         */
+};
 
 int ipv6_sysctl_forwarding(ctl_table *ctl, int write, struct file * filp,
                           void *buffer, size_t *lenp)
 {
-       int val = ipv6_forwarding;
+       int val = ipv6_config.forwarding;
        int retv;
 
        retv = proc_dointvec(ctl, write, filp, buffer, lenp);
 
-       if (write)
-       {
-               if (ipv6_forwarding && val == 0) {
+       if (write) {
+               if (ipv6_config.forwarding && val == 0) {
                        printk(KERN_DEBUG "sysctl: IPv6 forwarding enabled\n");
                        ndisc_forwarding_on();
                        addrconf_forwarding_on();                      
                }
 
-               if (ipv6_forwarding == 0 && val) {
+               if (ipv6_config.forwarding == 0 && val)
                        ndisc_forwarding_off();
-               }
        }
        return retv;
 }
 
 ctl_table ipv6_table[] = {
-        {NET_IPV6_FORWARDING, "ipv6_forwarding",
-         &ipv6_forwarding, sizeof(int), 0644, NULL,
+        {NET_IPV6_FORWARDING, "forwarding",
+         &ipv6_config.forwarding, sizeof(int), 0644, NULL,
          &ipv6_sysctl_forwarding},
 
-       {NET_IPV6_HOPLIMIT, "ipv6_hop_limit",
-         &ipv6_hop_limit, sizeof(int), 0644, NULL,
+       {NET_IPV6_HOPLIMIT, "hop_limit",
+         &ipv6_config.hop_limit, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ACCEPT_RA, "accept_ra",
+         &ipv6_config.accept_ra, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ACCEPT_REDIRECTS, "accept_redirects",
+         &ipv6_config.accept_redirects, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ND_MAX_MCAST_SOLICIT, "nd_max_mcast_solicit",
+         &ipv6_config.nd_max_mcast_solicit, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ND_MAX_UCAST_SOLICIT, "nd_max_ucast_solicit",
+         &ipv6_config.nd_max_ucast_solicit, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ND_RETRANS_TIME, "nd_retrans_time",
+         &ipv6_config.nd_retrans_time, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ND_REACHABLE_TIME, "nd_base_reachble_time",
+         &ipv6_config.nd_base_reachable_time, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_ND_DELAY_PROBE_TIME, "nd_delay_first_probe_time",
+         &ipv6_config.nd_delay_probe_time, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_AUTOCONF, "autoconf",
+         &ipv6_config.autoconf, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_DAD_TRANSMITS, "dad_transmits",
+         &ipv6_config.dad_transmits, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_RTR_SOLICITS, "router_solicitations",
+         &ipv6_config.rtr_solicits, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_RTR_SOLICIT_INTERVAL, "router_solicitation_interval",
+         &ipv6_config.rtr_solicit_interval, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+
+       {NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay",
+         &ipv6_config.rtr_solicit_delay, sizeof(int), 0644, NULL,
          &proc_dointvec},
 
        {0}
@@ -73,6 +139,4 @@ void ipv6_sysctl_unregister(void)
 {
        unregister_sysctl_table(ipv6_sysctl_header);
 }
-
-#endif
-
+#endif /* MODULE */
index 3d7d85e01a597c544e540a3551ddd4121d847410..d632cbcab6d5ba6292b3fd0d057d000988172c24 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.11 1997/03/03 18:27:31 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.15 1997/03/18 18:24:56 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
 #include <net/ipv6.h>
 #include <net/transp_v6.h>
 #include <net/addrconf.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 
 #include <asm/uaccess.h>
 
-static void tcp_v6_send_reset(struct in6_addr *saddr, struct in6_addr *daddr, 
-                             struct tcphdr *th, struct proto *prot, 
-                             struct ipv6_options *opt,
-                             struct device *dev, int pri, int hop_limit);
+static void    tcp_v6_send_reset(struct in6_addr *saddr,
+                                 struct in6_addr *daddr,
+                                 struct tcphdr *th, struct proto *prot,
+                                 struct ipv6_options *opt,
+                                 struct device *dev, int pri, int hop_limit);
 
-static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, 
-                             struct sk_buff *skb);
+static void    tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len, 
+                                 struct sk_buff *skb);
 
-static int tcp_v6_backlog_rcv(struct sock *sk, struct sk_buff *skb);
-static int tcp_v6_build_header(struct sock *sk, struct sk_buff *skb);
+static int     tcp_v6_backlog_rcv(struct sock *sk, struct sk_buff *skb);
+static int     tcp_v6_build_header(struct sock *sk, struct sk_buff *skb);
+static void    tcp_v6_xmit(struct sk_buff *skb);
 
 static struct tcp_func ipv6_mapped;
 static struct tcp_func ipv6_specific;
@@ -86,14 +88,14 @@ static int tcp_v6_verify_bind(struct sock *sk, unsigned short snum)
 
        SOCKHASH_LOCK();
        sk2 = tcp_bound_hash[tcp_sk_bhashfn(sk)];
-       for(; sk2 != NULL; sk2 = sk2->prev) {
+       for(; sk2 != NULL; sk2 = sk2->bind_next) {
                if((sk2->num == snum) && (sk2 != sk)) {
                        unsigned char state = sk2->state;
                        int sk2_reuse = sk2->reuse;
                        if(addr_type == IPV6_ADDR_ANY || (!sk2->rcv_saddr)) {
                                if((!sk2_reuse)                 ||
                                   (!sk_reuse)                  ||
-                                  (state != TCP_LISTEN)) {
+                                  (state == TCP_LISTEN)) {
                                        retval = 1;
                                        break;
                                }
@@ -120,18 +122,16 @@ static void tcp_v6_hash(struct sock *sk)
        SOCKHASH_LOCK();
        state = sk->state;
        if(state != TCP_CLOSE) {
-               struct sock **htable;
-
-               if(state == TCP_LISTEN) {
-                       sk->hashent = tcp_sk_listen_hashfn(sk);
-                       htable = &tcp_listening_hash[0];
-               } else {
-                       sk->hashent = tcp_v6_sk_hashfn(sk);
-                       htable = &tcp_established_hash[0];
-               }
-               sk->next = htable[sk->hashent];
-               htable[sk->hashent] = sk;
-               sk->hashtable = htable;
+               struct sock **skp;
+
+               if(state == TCP_LISTEN)
+                       skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+               else
+                       skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)];
+               if((sk->next = *skp) != NULL)
+                       (*skp)->pprev = &sk->next;
+               *skp = sk;
+               sk->pprev = skp;
                tcp_sk_bindify(sk);
        }
        SOCKHASH_UNLOCK();
@@ -139,20 +139,12 @@ static void tcp_v6_hash(struct sock *sk)
 
 static void tcp_v6_unhash(struct sock *sk)
 {
-       struct sock **htable;
-
        SOCKHASH_LOCK();
-       htable = sk->hashtable;
-       if(htable) {
-               struct sock **skp = &(htable[sk->hashent]);
-               while(*skp != NULL) {
-                       if(*skp == sk) {
-                               *skp = sk->next;
-                               break;
-                       }
-                       skp = &((*skp)->next);
-               }
-               sk->hashtable = NULL;
+       if(sk->pprev) {
+               if(sk->next)
+                       sk->next->pprev = sk->pprev;
+               *sk->pprev = sk->next;
+               sk->pprev = NULL;
                tcp_sk_unbindify(sk);
        }
        SOCKHASH_UNLOCK();
@@ -160,36 +152,31 @@ static void tcp_v6_unhash(struct sock *sk)
 
 static void tcp_v6_rehash(struct sock *sk)
 {
-       struct sock **htable;
        unsigned char state;
 
        SOCKHASH_LOCK();
-       htable = &(sk->hashtable[sk->hashent]);
        state = sk->state;
-       if(htable) {
-               while(*htable != NULL) {
-                       if(*htable == sk) {
-                               *htable = sk->next;
-                               break;
-                       }
-                       htable = &((*htable)->next);
-               }
+       if(sk->pprev) {
+               if(sk->next)
+                       sk->next->pprev = sk->pprev;
+               *sk->pprev = sk->next;
+               sk->pprev = NULL;
+               tcp_sk_unbindify(sk);
        }
-       htable = NULL;
        if(state != TCP_CLOSE) {
-               if(state == TCP_LISTEN) {
-                       sk->hashent = tcp_sk_listen_hashfn(sk);
-                       htable = &tcp_listening_hash[0];
-               } else {
-                       sk->hashent = tcp_v6_sk_hashfn(sk);
-                       htable = &tcp_established_hash[0];
-               }
-               sk->next = htable[sk->hashent];
-               htable[sk->hashent] = sk;
-       } else {
-               tcp_sk_unbindify(sk);
+               struct sock **skp;
+
+               if(state == TCP_LISTEN)
+                       skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+               else
+                       skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)];
+
+               if((sk->next = *skp) != NULL)
+                       (*skp)->pprev = &sk->next;
+               *skp = sk;
+               sk->pprev = skp;
+               tcp_sk_bindify(sk);
        }
-       sk->hashtable = htable;
        SOCKHASH_UNLOCK();
 }
 
@@ -254,13 +241,10 @@ static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
        __u32 si;
        __u32 di;
 
-       if (skb->protocol == __constant_htons(ETH_P_IPV6))
-       {
+       if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
                si = skb->nh.ipv6h->saddr.s6_addr32[3];
                di = skb->nh.ipv6h->daddr.s6_addr32[3];
-       }
-       else
-       {
+       } else {
                si = skb->nh.iph->saddr;
                di = skb->nh.iph->daddr;
        }
@@ -276,14 +260,15 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
-       struct dest_entry *dc;
        struct inet6_ifaddr *ifa;
+       struct in6_addr *saddr = NULL;
+       struct flowi fl;
+       struct dst_entry *dst;
        struct tcphdr *th;
-       __u8 *ptr;
        struct sk_buff *buff;
        struct sk_buff *skb1;
+       __u8 *ptr;
        int addr_type;
-       int tmp;
 
        if (sk->state != TCP_CLOSE) 
                return(-EISCONN);
@@ -311,9 +296,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        addr_type = ipv6_addr_type(&usin->sin6_addr);
 
        if(addr_type & IPV6_ADDR_MULTICAST)
-       {
                return -ENETUNREACH;
-       }
 
        /*
         *      connect to self not allowed
@@ -321,9 +304,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        if (ipv6_addr_cmp(&usin->sin6_addr, &np->saddr) == 0 &&
            usin->sin6_port == sk->dummy_th.source)
-       {
                return (-EINVAL);
-       }
 
        memcpy(&np->daddr, &usin->sin6_addr, sizeof(struct in6_addr));
 
@@ -331,24 +312,22 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
         *      TCP over IPv4
         */
 
-       if (addr_type == IPV6_ADDR_MAPPED)
-       {
+       if (addr_type == IPV6_ADDR_MAPPED) {
                struct sockaddr_in sin;
                int err;
 
-               printk(KERN_DEBUG "connect: ipv4 mapped\n");
+               SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
 
                sin.sin_family = AF_INET;
                sin.sin_port = usin->sin6_port;
                sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
 
                sk->tp_pinfo.af_tcp.af_specific = &ipv6_mapped;
-               sk->backlog_rcv = tcp_v4_backlog_rcv;
+               sk->backlog_rcv = tcp_v4_do_rcv;
 
                err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
 
-               if (err)
-               {
+               if (err) {
                        sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
                        sk->backlog_rcv = tcp_v6_backlog_rcv;
                }
@@ -356,31 +335,47 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                return err;
        }
 
-       dc = ipv6_dst_route(&np->daddr, NULL, (sk->localroute ? RTI_GATEWAY : 0));
+       if (!ipv6_addr_any(&np->rcv_saddr))
+               saddr = &np->rcv_saddr;
+
+       fl.proto = IPPROTO_TCP;
+       fl.nl_u.ip6_u.daddr = &np->daddr;
+       fl.nl_u.ip6_u.saddr = saddr;
+       fl.dev = NULL;
+       fl.uli_u.ports.dport = usin->sin6_port;
+       fl.uli_u.ports.sport = sk->dummy_th.source;
+
+       dst = ip6_route_output(sk, &fl);
        
-       if (dc == NULL)
-       {
-               return -ENETUNREACH;
+       if (dst->error) {
+               dst_release(dst);
+               return dst->error;
        }
        
-       np->dest = dc;
-       np->dc_sernum = (dc->rt.fib_node ? dc->rt.fib_node->fn_sernum : 0);
+       ip6_dst_store(sk, dst);
 
-       ifa = ipv6_get_saddr((struct rt6_info *)dc, &np->daddr);
+       np->oif = dst->dev;
        
-       if (ifa == NULL)
-       {
-               return -ENETUNREACH;
+       if (saddr == NULL) {
+               ifa = ipv6_get_saddr(dst, &np->daddr);
+       
+               if (ifa == NULL)
+                       return -ENETUNREACH;
+               
+               saddr = &ifa->addr;
+
+               /* set the source address */
+               ipv6_addr_copy(&np->rcv_saddr, saddr);
+               ipv6_addr_copy(&np->saddr, saddr);
        }
 
-       
        /*
         *      Init variables
         */
 
        lock_sock(sk);
 
-       sk->dummy_th.dest = usin->sin6_port;    
+       sk->dummy_th.dest = usin->sin6_port;
        sk->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
                                                   np->daddr.s6_addr32[3],
                                                   sk->dummy_th.source,
@@ -400,17 +395,11 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL);   
 
        if (buff == NULL) 
-       {
                return(-ENOMEM);
-       }
+
        lock_sock(sk);
-       
-       tmp = tcp_v6_build_header(sk, buff);
 
-       /* set the source address */
-                
-       memcpy(&np->saddr, &ifa->addr, sizeof(struct in6_addr));
-       memcpy(&np->rcv_saddr, &ifa->addr, sizeof(struct in6_addr));
+       tcp_v6_build_header(sk, buff);
 
        /* build the tcp header */
        th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
@@ -426,13 +415,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        th->syn = 1;
        th->doff = 6;
 
-       sk->window_clamp=0;
-
-       if ((dc->dc_flags & DCF_PMTU))
-               sk->mtu = dc->dc_pmtu;
-       else
-               sk->mtu = dc->rt.rt_dev->mtu;
+       sk->window_clamp = 0;
 
+       sk->mtu = dst->pmtu;
        sk->mss = sk->mtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
 
        /*
@@ -447,9 +432,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        buff->csum = csum_partial(ptr, 4, 0);
 
        tcp_v6_send_check(sk, th, sizeof(struct tcphdr) + 4, buff);
-       
+
        tcp_set_state(sk, TCP_SYN_SENT);
-       
+
        /* Socket identity change complete, no longer
         * in TCP_CLOSE, so rehash.
         */
@@ -468,17 +453,17 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        skb1 = skb_clone(buff, GFP_KERNEL);
        skb_set_owner_w(skb1, sk);
 
-       tmp = ipv6_xmit(sk, skb1, &np->saddr, &np->daddr, NULL, IPPROTO_TCP);
+       tcp_v6_xmit(skb1);
 
        /* Timer for repeating the SYN until an answer  */
 
        tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
        tcp_statistics.TcpActiveOpens++;
        tcp_statistics.TcpOutSegs++;
-  
+
        release_sock(sk);
-       
-       return(tmp);
+
+       return(0);
 }
 
 static int tcp_v6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
@@ -513,7 +498,7 @@ static int tcp_v6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
 
        lock_sock(sk);
        retval = tcp_do_sendmsg(sk, msg->msg_iovlen, msg->msg_iov, 
-                               len, msg->msg_flags);
+                               msg->msg_flags);
 
        release_sock(sk);
 
@@ -534,45 +519,52 @@ void tcp_v6_err(int type, int code, unsigned char *header, __u32 info,
        sk = tcp_v6_lookup(saddr, th->source, daddr, th->dest);
 
        if (sk == NULL)
-       {
                return;
-       }
 
        np = &sk->net_pinfo.af_inet6;
 
-       if (type == ICMPV6_PKT_TOOBIG)
-       {
+       if (type == ICMPV6_PKT_TOOBIG) {
                /* icmp should have updated the destination cache entry */
 
-               np->dest = ipv6_dst_check(np->dest, &np->daddr, np->dc_sernum,
-                                         0);
+               dst_check(&np->dst, np->dst_cookie);
 
-               np->dc_sernum = (np->dest->rt.fib_node ?
-                                np->dest->rt.fib_node->fn_sernum : 0);
+               if (np->dst == NULL) {
+                       struct flowi fl;
+                       struct dst_entry *dst;
+                       
+                       fl.proto = IPPROTO_TCP;
+                       fl.nl_u.ip6_u.daddr = &np->daddr;
+                       fl.nl_u.ip6_u.saddr = &np->saddr;
+                       fl.dev = np->oif;
+                       fl.uli_u.ports.dport = sk->dummy_th.dest;
+                       fl.uli_u.ports.sport = sk->dummy_th.source;
 
-               if (np->dest->dc_flags & DCF_PMTU)
-                       sk->mtu = np->dest->dc_pmtu;
+                       dst = ip6_route_output(sk, &fl);
 
-               sk->mtu = (sk->mtu - sizeof(struct ipv6hdr) - 
-                          sizeof(struct tcphdr));
+                       ip6_dst_store(sk, dst);
+               }
+
+               if (np->dst->error)
+                       sk->err_soft = np->dst->error;
+               else
+                       sk->mtu = np->dst->pmtu;
 
                return;
        }
 
        opening = (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV);
        
-       if (icmpv6_err_convert(type, code, &err) || opening)
-       {
+       if (icmpv6_err_convert(type, code, &err) || opening) {
                sk->err = err;
-               if (opening)
-               {
+
+               if (opening) {
                        tcp_statistics.TcpAttemptFails++;
                        tcp_set_state(sk,TCP_CLOSE);
                        sk->error_report(sk);
                }
-       }
-       else
+       } else {
                sk->err_soft = err;
+       }
 }
 
 
@@ -583,37 +575,34 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
        struct sk_buff * skb;
        struct tcphdr *th;
        unsigned char *ptr;
-       struct dest_entry *dc;
-       int mss;
+       struct dst_entry *dst;
+       struct flowi fl;
 
        skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
        
        if (skb == NULL)
-       {
                return;
-       }
-
-       skb_reserve(skb, (MAX_HEADER + 15) & ~15);
-       skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
 
-       dc = ipv6_dst_route(&af_req->rmt_addr, af_req->dev, 0);
+       fl.proto = IPPROTO_TCP;
+       fl.nl_u.ip6_u.daddr = &af_req->rmt_addr;
+       fl.nl_u.ip6_u.saddr = &af_req->loc_addr;
+       fl.dev = af_req->dev;
+       fl.uli_u.ports.dport = req->rmt_port;
+       fl.uli_u.ports.sport = sk->dummy_th.source;
 
-       skb->dev = af_req->dev;
-       
-       if (dc)
-       {
-               if (dc->dc_flags & DCF_PMTU)
-                       mss = dc->dc_pmtu;
-               else
-                       mss = dc->dc_nexthop->dev->mtu;
-               mss -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
+       dst = ip6_route_output(sk, &fl);
 
-               ipv6_dst_unlock(dc);
+       if (dst->error) {
+               kfree_skb(skb, FREE_WRITE);
+               dst_release(dst);
+               return;
        }
-       else
-               mss = 516;
 
-       th =(struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
+       skb->dev = dst->dev;
+       skb_reserve(skb, (skb->dev->hard_header_len + 15) & ~15);
+       skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb,sizeof(struct ipv6hdr));
+
+       th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
        skb->h.th = th;
        memset(th, 0, sizeof(struct tcphdr));
        
@@ -635,19 +624,20 @@ static void tcp_v6_send_synack(struct sock *sk, struct open_request *req)
        ptr = skb_put(skb, TCPOLEN_MSS);
        ptr[0] = TCPOPT_MSS;
        ptr[1] = TCPOLEN_MSS;
-       ptr[2] = (mss >> 8) & 0xff;
-       ptr[3] = mss & 0xff;
+       ptr[2] = (dst->pmtu >> 8) & 0xff;
+       ptr[3] = dst->pmtu & 0xff;
        skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
 
-       th->check = tcp_v6_check(th, sizeof(*th) + TCPOLEN_MSS, &af_req->loc_addr, 
-                                &af_req->rmt_addr,
-                                csum_partial((char *)th, sizeof(*th), skb->csum));
+       th->check = tcp_v6_check(th, sizeof(*th) + TCPOLEN_MSS,
+                                &af_req->loc_addr, &af_req->rmt_addr,
+                                csum_partial((char *)th, sizeof(*th),
+                                             skb->csum));
+
+       ip6_dst_store(sk, dst);
+       ip6_xmit(sk, skb, &fl, af_req->opt);
+       dst_release(dst);
 
-       ipv6_xmit(sk, skb, &af_req->loc_addr, &af_req->rmt_addr, af_req->opt,
-                 IPPROTO_TCP);
-                                
        tcp_statistics.TcpOutSegs++;
-                                             
 }
 
 static void tcp_v6_or_free(struct open_request *req)
@@ -666,23 +656,19 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
        struct open_request *req;
        
        /* If the socket is dead, don't accept the connection.  */
-       if (sk->dead)
-       {
-               SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);
+       if (sk->dead) {
+               SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n", sk);
                tcp_statistics.TcpAttemptFails++;
-               return -ENOTCONN;               
+               return -ENOTCONN;
        }
 
        if (skb->protocol == __constant_htons(ETH_P_IP))
-       {
                return tcp_v4_conn_request(sk, skb, ptr, isn);
-       }
 
        /*
         *      There are no SYN attacks on IPv6, yet...
         */
-       if (sk->ack_backlog >= sk->max_ack_backlog)
-       {
+       if (sk->ack_backlog >= sk->max_ack_backlog) {
                printk(KERN_DEBUG "droping syn ack:%d max:%d\n",
                       sk->ack_backlog, sk->max_ack_backlog);
                tcp_statistics.TcpAttemptFails++;
@@ -690,9 +676,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
        }
 
        af_req = kmalloc(sizeof(struct tcp_v6_open_req), GFP_ATOMIC);
-       
-       if (af_req == NULL)
-       {
+
+       if (af_req == NULL) {
                tcp_statistics.TcpAttemptFails++;
                goto exit;              
        }
@@ -709,9 +694,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
        req->mss = tcp_parse_options(skb->h.th);
 
        if (!req->mss)
-       {
                req->mss = 536;
-       }
 
        req->rmt_port = skb->h.th->source;
 
@@ -733,7 +716,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
 
        sk->data_ready(sk, 0);
 
-  exit:
+exit:
        kfree_skb(skb, FREE_READ);
        return 0;
 }
@@ -754,22 +737,21 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 {
        struct tcp_v6_open_req *af_req = (struct tcp_v6_open_req *) req;
        struct ipv6_pinfo *np;
-       struct dest_entry *dc;
+       struct dst_entry *dst;
+       struct flowi fl;
        struct tcp_opt *newtp;
        struct sock *newsk;
-       
 
-       if (skb->protocol == __constant_htons(ETH_P_IP))
-       {
-               /* 
-                *      v6 mapped 
+       if (skb->protocol == __constant_htons(ETH_P_IP)) {
+               /*
+                *      v6 mapped
                 */
-               
+
                newsk = tcp_v4_syn_recv_sock(sk, skb, req);
 
                if (newsk == NULL)
                        return NULL;
-               
+
                np = &newsk->net_pinfo.af_inet6;
 
                ipv6_addr_set(&np->daddr, 0, 0, __constant_htonl(0x0000FFFF),
@@ -781,16 +763,14 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                ipv6_addr_copy(&np->rcv_saddr, &np->saddr);
 
                newsk->tp_pinfo.af_tcp.af_specific = &ipv6_mapped;
-               newsk->backlog_rcv = tcp_v4_backlog_rcv;
+               newsk->backlog_rcv = tcp_v4_do_rcv;
 
                return newsk;
        }
 
        newsk = sk_alloc(GFP_ATOMIC);
        if (newsk == NULL)
-       {
                return NULL;
-       }
 
        memcpy(newsk, sk, sizeof(*newsk));
 
@@ -803,13 +783,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        skb_queue_head_init(&newsk->receive_queue);
        skb_queue_head_init(&newsk->out_of_order_queue);
        skb_queue_head_init(&newsk->error_queue);
-       
+
        /*
         *      Unused
         */
 
        newsk->send_head = NULL;
-       newsk->send_tail = NULL;
 
        newtp = &(newsk->tp_pinfo.af_tcp);
        np = &newsk->net_pinfo.af_inet6;
@@ -826,7 +805,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newsk->cong_count = 0;
        newsk->ssthresh = 0;
        newtp->backoff = 0;
-       newsk->blog = 0;
        newsk->intr = 0;
        newsk->proc = 0;
        newsk->done = 0;
@@ -870,7 +848,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        newsk->dummy_th.source = sk->dummy_th.source;
        newsk->dummy_th.dest = req->rmt_port;
-       newsk->users=0;
+       newsk->sock_readers=0;
 
        newtp->rcv_nxt = req->rcv_isn + 1;
        newtp->rcv_wup = req->rcv_isn + 1;
@@ -881,30 +859,38 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        ipv6_addr_copy(&np->daddr, &af_req->rmt_addr);
        ipv6_addr_copy(&np->saddr, &af_req->loc_addr);
        ipv6_addr_copy(&np->rcv_saddr, &af_req->loc_addr);
-       
+       np->oif = af_req->dev;
+
        /*
-        *      options / mss
+        *      options / mss / route cache
         */
-       
-       dc = ipv6_dst_route(&af_req->rmt_addr, af_req->dev, 0);
-       np->dest = dc;
 
-       if (np->dest && (np->dest->dc_flags & DCF_PMTU))
-               newsk->mtu = np->dest->dc_pmtu;
-       else
+       fl.proto = IPPROTO_TCP;
+       fl.nl_u.ip6_u.daddr = &np->daddr;
+       fl.nl_u.ip6_u.saddr = &np->saddr;
+       fl.dev = np->oif;
+       fl.uli_u.ports.dport = newsk->dummy_th.dest;
+       fl.uli_u.ports.sport = newsk->dummy_th.source;
+
+       dst = ip6_route_output(newsk, &fl);
+
+       ip6_dst_store(newsk, dst);
+
+       if (dst->error)
                newsk->mtu = af_req->dev->mtu;
+       else
+               newsk->mtu = dst->pmtu;
 
-       newsk->mss = min(req->mss, (newsk->mtu - sizeof(struct ipv6hdr) - 
+       newsk->mss = min(req->mss, (newsk->mtu - sizeof(struct ipv6hdr) -
                                    sizeof(struct tcphdr)));
-       
+
        newsk->daddr    = LOOPBACK4_IPV6;
        newsk->saddr    = LOOPBACK4_IPV6;
        newsk->rcv_saddr= LOOPBACK4_IPV6;
-       
-       newsk->prot->hash(newsk);
 
+       newsk->prot->hash(newsk);
+       add_to_prot_sklist(newsk);
        return newsk;
-
 }
 
 static void tcp_v6_reply_reset(struct sk_buff *skb)
@@ -918,6 +904,7 @@ static void tcp_v6_send_reset(struct in6_addr *saddr, struct in6_addr *daddr,
 {
        struct sk_buff *buff;
        struct tcphdr *t1;
+       struct flowi fl;
 
        if(th->rst)
                return;
@@ -947,12 +934,9 @@ static void tcp_v6_send_reset(struct in6_addr *saddr, struct in6_addr *daddr,
        t1->doff = sizeof(*t1)/4;
        t1->rst = 1;
   
-       if(th->ack)
-       {
+       if(th->ack) {
                t1->seq = th->ack_seq;
-       }
-       else
-       {
+       } else {
                t1->ack = 1;
                if(!th->syn)
                        t1->ack_seq = th->seq;
@@ -965,9 +949,14 @@ static void tcp_v6_send_reset(struct in6_addr *saddr, struct in6_addr *daddr,
        t1->check = csum_ipv6_magic(saddr, daddr, sizeof(*t1), IPPROTO_TCP,
                                    buff->csum);
 
-       
-       ipv6_xmit(NULL, buff, saddr, daddr, NULL, IPPROTO_TCP);
-       
+       fl.proto = IPPROTO_TCP;
+       fl.nl_u.ip6_u.daddr = daddr;
+       fl.nl_u.ip6_u.saddr = saddr;
+       fl.dev = dev;
+       fl.uli_u.ports.dport = th->dest;
+       fl.uli_u.ports.sport = th->source;
+
+       ip6_xmit(NULL, buff, &fl, NULL);
        tcp_statistics.TcpOutSegs++;
 }
 
@@ -975,22 +964,18 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        struct open_request *req;
-       
 
        /*
         *      assumption: the socket is not in use.
         *      as we checked the user count on tcp_rcv and we're
         *      running from a soft interrupt.
         */
-               
+
        req = tp->syn_wait_queue;
-       
 
        if (!req)
-       {
                return sk;
-       }
-       
+
        do {
                struct tcp_v6_open_req *af_req;
 
@@ -998,12 +983,10 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
 
                if (!ipv6_addr_cmp(&af_req->rmt_addr, &skb->nh.ipv6h->saddr) &&
                    !ipv6_addr_cmp(&af_req->loc_addr, &skb->nh.ipv6h->daddr) &&
-                   req->rmt_port == skb->h.th->source)
-               {
+                   req->rmt_port == skb->h.th->source) {
                        u32 flg;
-                               
-                       if (req->sk)
-                       {
+
+                       if (req->sk) {
                                printk(KERN_DEBUG "BUG: syn_recv:"
                                       "socket exists\n");
                                break;
@@ -1016,10 +999,9 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
                         */
                        flg = *(((u32 *)skb->h.th) + 3);
                        flg &= __constant_htonl(0x002f0000);
-                               
+
                        if ((flg == __constant_htonl(0x00020000)) &&
-                           (!after(skb->seq, req->rcv_isn)))
-                       {
+                           (!after(skb->seq, req->rcv_isn))) {
                                /*
                                 *      retransmited syn
                                 *      FIXME: must send an ack
@@ -1033,9 +1015,7 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
                        tcp_dec_slow_timer(TCP_SLT_SYNACK);
 
                        if (sk == NULL)
-                       {
                                return NULL;
-                       }
 
                        skb_set_owner_r(skb, sk);
                        req->expires = 0UL;
@@ -1045,10 +1025,8 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
 
                req = req->dl_next;
        } while (req != tp->syn_wait_queue);
-       
 
        return sk;
-
 }
 
 int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
@@ -1070,42 +1048,37 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
 
        sk = skb->sk;
 
-       if (!redo)
-       {
-
+       if (!redo) {
                if (skb->pkt_type != PACKET_HOST)
                        goto discard_it;
 
                /*
                 *      Pull up the IP header.
                 */
-       
+
                skb_pull(skb, skb->h.raw - skb->data);
 
                /*
                 *      Try to use the device checksum if provided.
                 */
-               
-               switch (skb->ip_summed) 
-               {
-                       case CHECKSUM_NONE:
-                               skb->csum = csum_partial((char *)th, len, 0);
-                       case CHECKSUM_HW:
-                               if (tcp_v6_check(th,len,saddr,daddr,skb->csum))
-                               {
-                                       printk(KERN_DEBUG "tcp csum failed\n");
-                                       goto discard_it;
-                               }
-                       default:
-                               /* CHECKSUM_UNNECESSARY */
-               }
+
+               switch (skb->ip_summed) {
+               case CHECKSUM_NONE:
+                       skb->csum = csum_partial((char *)th, len, 0);
+               case CHECKSUM_HW:
+                       if (tcp_v6_check(th,len,saddr,daddr,skb->csum)) {
+                               printk(KERN_DEBUG "tcp csum failed\n");
+                               goto discard_it;
+                       }
+               default:
+                       /* CHECKSUM_UNNECESSARY */
+               };
 
                tcp_statistics.TcpInSegs++;
-               
+
                sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest);
 
-               if (!sk) 
-               {
+               if (!sk) {
                        printk(KERN_DEBUG "socket not found\n");
                        goto no_tcp_socket;
                }
@@ -1117,14 +1090,13 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
 
                skb->acked = 0;
                skb->used = 0;
-       }               
+       }
 
        /*
-        * We may need to add it to the backlog here. 
+        * We may need to add it to the backlog here.
         */
 
-       if (sk->users) 
-       {
+       if (sk->sock_readers) {
                __skb_queue_tail(&sk->back_log, skb);
                return(0);
        }
@@ -1133,46 +1105,38 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
         *      Signal NDISC that the connection is making
         *      "forward progress"
         */
-       if (sk->state != TCP_LISTEN)
-       {
+       if (sk->state != TCP_LISTEN) {
                struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
                struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 
                if (after(skb->seq, tp->rcv_nxt) ||
-                   after(skb->ack_seq, tp->snd_una))
-               {
-                       if (np->dest)
-                               ndisc_validate(np->dest->dc_nexthop);
+                   after(skb->ack_seq, tp->snd_una)) {
+                       if (np->dst)
+                               ndisc_validate(np->dst->neighbour);
                }
        }
 
-       if (!sk->prot) 
-       {
+       if (!sk->prot) {
                printk(KERN_DEBUG "tcp_rcv: sk->prot == NULL\n");
                return(0);
        }
 
        skb_set_owner_r(skb, sk);
 
-       if (sk->state == TCP_ESTABLISHED)
-       {
+       if (sk->state == TCP_ESTABLISHED) {
                if (tcp_rcv_established(sk, skb, th, len))
                        goto no_tcp_socket;
                return 0;
        }
-       
-       if (sk->state == TCP_LISTEN)
-       {
+
+       if (sk->state == TCP_LISTEN) {
                /*
                 *      find possible connection requests
                 */
                sk = tcp_v6_check_req(sk, skb);
 
                if (sk == NULL)
-               {
                        goto discard_it;
-               }
-
        }
 
        if (tcp_rcv_state_process(sk, skb, th, opt, len) == 0)
@@ -1181,11 +1145,11 @@ int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
 no_tcp_socket:
 
        /*
-        *      No such TCB. If th->rst is 0 send a reset 
+        *      No such TCB. If th->rst is 0 send a reset
         *      (checked in tcp_send_reset)
         */
 
-       tcp_v6_send_reset(daddr, saddr, th, &tcpv6_prot, opt, dev, 
+       tcp_v6_send_reset(daddr, saddr, th, &tcpv6_prot, opt, dev,
                          skb->nh.ipv6h->priority, 255);
 
 discard_it:
@@ -1196,37 +1160,38 @@ discard_it:
 
        kfree_skb(skb, FREE_READ);
        return 0;
-
 }
 
 static int tcp_v6_rebuild_header(struct sock *sk, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-       
-       if (np->dest)
-       {
-               np->dest = ipv6_dst_check(np->dest, &np->daddr,
-                                         np->dc_sernum, 0);
-                                         
-       }
-       else
-       {
-               np->dest = ipv6_dst_route(&np->daddr, NULL, 0);
+
+       if (np->dst)
+               dst_check(&np->dst, np->dst_cookie);
+
+       if (np->dst == NULL) {
+               struct flowi fl;
+               struct dst_entry *dst;
+
+               fl.proto = IPPROTO_TCP;
+               fl.nl_u.ip6_u.daddr = &np->daddr;
+               fl.nl_u.ip6_u.saddr = &np->saddr;
+               fl.dev = np->oif;
+               fl.uli_u.ports.dport = sk->dummy_th.dest;
+               fl.uli_u.ports.sport = sk->dummy_th.source;
+
+               dst = ip6_route_output(sk, &fl);
+               ip6_dst_store(sk, dst);
        }
 
-       if (!np->dest)
-       {
+       if (np->dst->error) {
                /*
                 *      lost route to destination
                 */
-               return -1;
+               return -EHOSTUNREACH;
        }
-       
-       np->dc_sernum = (np->dest->rt.fib_node ?
-                        np->dest->rt.fib_node->fn_sernum : 0);
 
-       ipv6_redo_mac_hdr(skb, np->dest->dc_nexthop,
-                         skb->tail - (u8*) skb->nh.ipv6h);
+       skb_pull(skb, skb->nh.raw - skb->data);
        return 0;
 }
 
@@ -1237,7 +1202,7 @@ static int tcp_v6_backlog_rcv(struct sock *sk, struct sk_buff *skb)
        res = tcp_v6_rcv(skb, skb->dev,
                         &skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
                         (struct ipv6_options *) skb->cb,
-                        skb->len, 1, 
+                        skb->len, 1,
                         (struct inet6_protocol *) sk->pair);
        return res;
 }
@@ -1246,20 +1211,16 @@ static struct sock * tcp_v6_get_sock(struct sk_buff *skb, struct tcphdr *th)
 {
        struct in6_addr *saddr;
        struct in6_addr *daddr;
-       struct sock *sk;
 
        saddr = &skb->nh.ipv6h->saddr;
        daddr = &skb->nh.ipv6h->daddr;
-
-       sk = tcp_v6_lookup(saddr, th->source, daddr, th->dest);
-
-       return sk;
+       return tcp_v6_lookup(saddr, th->source, daddr, th->dest);
 }
-       
+
 static int tcp_v6_build_header(struct sock *sk, struct sk_buff *skb)
 {
        skb_reserve(skb, (MAX_HEADER + 15) & ~15);
-       skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
+       skb->nh.raw = skb_put(skb, sizeof(struct ipv6hdr));
 
        /*
         *      FIXME: reserve space for option headers
@@ -1273,28 +1234,33 @@ static void tcp_v6_xmit(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
        struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;
+       struct flowi fl;
        int err;
 
-       err = ipv6_xmit(sk, skb, &np->saddr, &np->daddr, NULL, IPPROTO_TCP);
-       
+       fl.proto = IPPROTO_TCP;
+       fl.nl_u.ip6_u.daddr = &np->daddr;
+       fl.nl_u.ip6_u.saddr = &np->saddr;
+       fl.dev = np->oif;
+       fl.uli_u.ports.sport = sk->dummy_th.source;
+       fl.uli_u.ports.dport = sk->dummy_th.dest;
+
+       err = ip6_xmit(sk, skb, &fl, np->opt);
+
        /*
         *      FIXME: check error handling.
         */
 
        sk->err_soft = err;
 }
-                    
-
 
 static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
 {
        struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
-       
+
        sin6->sin6_family = AF_INET6;
        memcpy(&sin6->sin6_addr, &np->daddr, sizeof(struct in6_addr));
        sin6->sin6_port = sk->dummy_th.dest;
-
 }
 
 static struct tcp_func ipv6_specific = {
@@ -1359,19 +1325,16 @@ static int tcp_v6_init_sock(struct sock *sk)
        /* this is how many unacked bytes we will accept for this socket.  */
        sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
        sk->max_ack_backlog = SOMAXCONN;
-       
+
        sk->mtu = 576;
        sk->mss = 516;
 
        sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
-       
 
        /*
-        *      Speed up by setting some standard state for the dummy_th
-        *      if TCP uses it (maybe move to tcp_init later)
+        *      Speed up by setting some standard state for the dummy_th.
         */
-       
-       sk->dummy_th.ack=1;     
+       sk->dummy_th.ack=1;
        sk->dummy_th.doff=sizeof(struct tcphdr)>>2;
 
        sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
@@ -1385,16 +1348,14 @@ static int tcp_v6_destroy_sock(struct sock *sk)
        struct sk_buff *skb;
 
        tcp_clear_xmit_timers(sk);
-       
+
        if (sk->keepopen)
-       {
                tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
-       }
 
        /*
-        *      Cleanup up the write buffer. 
+        *      Cleanup up the write buffer.
         */
-        
+
        while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
                IS_SKB(skb);
                kfree_skb(skb, FREE_WRITE);
@@ -1413,15 +1374,12 @@ static int tcp_v6_destroy_sock(struct sock *sk)
         *      Release destination entry
         */
 
-       if (np->dest)
-       {
-               ipv6_dst_unlock(np->dest);
-       }
+       if (np->dst)
+               dst_release(np->dst);
 
        return 0;
 }
 
-
 struct proto tcpv6_prot = {
        (struct sock *)&tcpv6_prot,     /* sklist_next */
        (struct sock *)&tcpv6_prot,     /* sklist_prev */
@@ -1454,7 +1412,7 @@ struct proto tcpv6_prot = {
        0                               /* highestinuse */
 };
 
-static struct inet6_protocol tcpv6_protocol = 
+static struct inet6_protocol tcpv6_protocol =
 {
        tcp_v6_rcv,             /* TCP handler          */
        tcp_v6_err,             /* TCP error control    */
@@ -1465,16 +1423,8 @@ static struct inet6_protocol tcpv6_protocol =
        "TCPv6"                 /* name                 */
 };
 
-
 void tcpv6_init(void)
 {
        /* register inet6 protocol */
        inet6_add_protocol(&tcpv6_protocol);
 }
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o tcp_ipv6.o tcp_ipv6.c"
- * c-file-style: "Linux"
- * End:
- */
index 7993e225c0e6ed7bffb45a6b730e72e6cb7279c4..eb86be321e2f26bf0d447711ea5985831deeab11 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/ipv4/udp.c
  *
- *     $Id: udp.c,v 1.9 1997/03/04 10:41:59 davem Exp $
+ *     $Id: udp.c,v 1.12 1997/03/18 18:24:59 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -34,7 +34,7 @@
 #include <net/ndisc.h>
 #include <net/protocol.h>
 #include <net/transp_v6.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/ip.h>
 #include <net/udp.h>
@@ -60,7 +60,7 @@ static int udp_v6_verify_bind(struct sock *sk, unsigned short snum)
                        if(addr_type == IPV6_ADDR_ANY || (!sk2->rcv_saddr)) {
                                if((!sk2_reuse)                 ||
                                   (!sk_reuse)                  ||
-                                  (state != TCP_LISTEN)) {
+                                  (state == TCP_LISTEN)) {
                                        retval = 1;
                                        break;
                                }
@@ -184,9 +184,10 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
        struct in6_addr         *daddr;
-       struct dest_entry       *dest;
+       struct dst_entry        *dst;
        struct ipv6_pinfo       *np;
        struct inet6_ifaddr     *ifa;
+       struct flowi            fl;
        int                     addr_type;
 
        if (addr_len < sizeof(*usin)) 
@@ -198,8 +199,7 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        addr_type = ipv6_addr_type(&usin->sin6_addr);
        np = &sk->net_pinfo.af_inet6;
 
-       if (addr_type == IPV6_ADDR_ANY)
-       {
+       if (addr_type == IPV6_ADDR_ANY) {
                /*
                 *      connect to self
                 */
@@ -208,8 +208,7 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        daddr = &usin->sin6_addr;
 
-       if (addr_type == IPV6_ADDR_MAPPED)
-       {
+       if (addr_type == IPV6_ADDR_MAPPED) {
                struct sockaddr_in sin;
                int err;
 
@@ -219,22 +218,18 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
                
                if (err < 0)
-               {
                        return err;
-               }
                
                ipv6_addr_copy(&np->daddr, daddr);
                
-               if(ipv6_addr_any(&np->saddr))
-               {
+               if(ipv6_addr_any(&np->saddr)) {
                        ipv6_addr_set(&np->saddr, 0, 0, 
                                      __constant_htonl(0x0000ffff),
                                      sk->saddr);
 
                }
 
-               if(ipv6_addr_any(&np->rcv_saddr))
-               {
+               if(ipv6_addr_any(&np->rcv_saddr)) {
                        ipv6_addr_set(&np->rcv_saddr, 0, 0, 
                                      __constant_htonl(0x0000ffff),
                                      sk->rcv_saddr);
@@ -244,35 +239,41 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        ipv6_addr_copy(&np->daddr, daddr);
 
+       sk->dummy_th.dest = usin->sin6_port;
+
        /*
         *      Check for a route to destination an obtain the
         *      destination cache for it.
         */
 
-       dest = ipv6_dst_route(daddr, NULL, sk->localroute ? RTI_GATEWAY : 0);
-
-       np->dest = dest;
+       fl.proto = IPPROTO_UDP;
+       fl.nl_u.ip6_u.daddr = daddr;
+       fl.nl_u.ip6_u.saddr = NULL;
+       fl.dev = NULL;
+       fl.uli_u.ports.dport = sk->dummy_th.dest;
+       fl.uli_u.ports.sport = sk->dummy_th.source;
+
+       dst = ip6_route_output(sk, &fl);
+       
+       if (dst->error) {
+               dst_release(dst);
+               return dst->error;
+       }
 
-       if (dest == NULL)
-               return -ENETUNREACH;
+       ip6_dst_store(sk, dst);
 
        /* get the source adddress used in the apropriate device */
 
-       ifa = ipv6_get_saddr((struct rt6_info *) dest, daddr);
+       ifa = ipv6_get_saddr(dst, daddr);
 
        if(ipv6_addr_any(&np->saddr))
-       {
                ipv6_addr_copy(&np->saddr, &ifa->addr);
-       }
 
-       if(ipv6_addr_any(&np->rcv_saddr))
-       {
+       if(ipv6_addr_any(&np->rcv_saddr)) {
                ipv6_addr_copy(&np->rcv_saddr, &ifa->addr);
                sk->rcv_saddr = 0xffffffff;
        }
 
-       sk->dummy_th.dest = usin->sin6_port;
-
        sk->state = TCP_ESTABLISHED;
 
        return(0);
@@ -285,10 +286,10 @@ static void udpv6_close(struct sock *sk, unsigned long timeout)
        lock_sock(sk);
        sk->state = TCP_CLOSE;
 
-       if (np->dest)
-       {
-               ipv6_dst_unlock(np->dest);
-       }
+       if (np->dst)
+               dst_release(np->dst);
+
+       ipv6_sock_mc_close(sk);
 
        release_sock(sk);
        destroy_sock(sk);
@@ -306,7 +307,6 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        int truesize;
        struct sk_buff *skb;
        int err;
-       
 
        /*
         *      Check any passed addresses
@@ -328,8 +328,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        
        copied=truesize;
 
-       if(copied>len)
-       {
+       if(copied>len) {
                copied=len;
                msg->msg_flags|=MSG_TRUNC;
        }
@@ -346,8 +345,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        sk->stamp=skb->stamp;
 
        /* Copy the address. */
-       if (msg->msg_name) 
-       {
+       if (msg->msg_name) {
                struct sockaddr_in6 *sin6;
          
                sin6 = (struct sockaddr_in6 *) msg->msg_name;
@@ -355,13 +353,10 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
                sin6->sin6_family = AF_INET6;
                sin6->sin6_port = skb->h.uh->source;
 
-               if (skb->protocol == __constant_htons(ETH_P_IP))
-               {
+               if (skb->protocol == __constant_htons(ETH_P_IP)) {
                        ipv6_addr_set(&sin6->sin6_addr, 0, 0,
                                      __constant_htonl(0xffff), skb->nh.iph->saddr);
-               }
-               else
-               {
+               } else {
                        memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
                               sizeof(struct in6_addr));
 
@@ -386,22 +381,20 @@ void udpv6_err(int type, int code, unsigned char *buff, __u32 info,
 
        sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest);
    
-       if (sk == NULL)
-       {
+       if (sk == NULL) {
                printk(KERN_DEBUG "icmp for unkown sock\n");
                return;
        }
 
-       if (icmpv6_err_convert(type, code, &err))
-       {
+       if (icmpv6_err_convert(type, code, &err)) {
                if(sk->bsdism && sk->state!=TCP_ESTABLISHED)
                        return;
                
                sk->err = err;
                sk->error_report(sk);
-       }
-       else
+       } else {
                sk->err_soft = err;
+       }
 }
 
 static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
@@ -507,16 +500,14 @@ int udpv6_rcv(struct sk_buff *skb, struct device *dev,
 
        ulen = ntohs(uh->len);
        
-       if (ulen > len || len < sizeof(*uh))
-       {
+       if (ulen > len || len < sizeof(*uh)) {
                printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len);
                udp_stats_in6.UdpInErrors++;
                kfree_skb(skb, FREE_READ);
                return(0);
        }
 
-       if (uh->check == 0)
-       {
+       if (uh->check == 0) {
                printk(KERN_DEBUG "IPv6: udp checksum is 0\n");
                goto discard;
        }
@@ -525,12 +516,11 @@ int udpv6_rcv(struct sk_buff *skb, struct device *dev,
        case CHECKSUM_NONE:
                skb->csum = csum_partial((char*)uh, len, 0);
        case CHECKSUM_HW:
-               if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, skb->csum))
-               {
+               if (csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, skb->csum)) {
                        printk(KERN_DEBUG "IPv6: udp checksum error\n");
                        goto discard;
                }
-       }
+       };
        
        len = ulen;
 
@@ -551,12 +541,10 @@ int udpv6_rcv(struct sk_buff *skb, struct device *dev,
 
        sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest);
 
-       if (sk == NULL)
-       {
+       if (sk == NULL) {
                udp_stats_in6.UdpNoPorts++;
 
-               icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH,
-                           0, dev);
+               icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
                
                kfree_skb(skb, FREE_READ);
                return(0);
@@ -564,18 +552,14 @@ int udpv6_rcv(struct sk_buff *skb, struct device *dev,
 
        /* deliver */
 
-       if (sk->users)
-       {
+       if (sk->sock_readers)
                __skb_queue_tail(&sk->back_log, skb);
-       }
        else
-       {
                udpv6_queue_rcv_skb(sk, skb);
-       }
        
        return(0);
 
-  discard:
+discard:
        udp_stats_in6.UdpInErrors++;
        kfree_skb(skb, FREE_READ);
        return(0);      
@@ -608,12 +592,9 @@ static int udpv6_getfrag(const void *data, struct in6_addr *addr,
 
        dst = buff;
 
-       if (offset)
-       {
+       if (offset) {
                offset -= sizeof(struct udphdr);
-       }
-       else
-       {
+       } else {
                dst += sizeof(struct udphdr);
                final = 1;
                clen -= sizeof(struct udphdr);
@@ -622,19 +603,15 @@ static int udpv6_getfrag(const void *data, struct in6_addr *addr,
        udh->wcheck = csum_partial_copy_fromiovecend(dst, udh->iov, offset,
                                                     clen, udh->wcheck);
 
-       if (final)
-       {
+       if (final) {
                struct in6_addr *daddr;
                
                udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),
                                           udh->wcheck);
 
-               if (udh->daddr)
-               {
+               if (udh->daddr) {
                        daddr = udh->daddr;
-               }
-               else
-               {
+               } else {
                        /*
                         *      use packet destination address
                         *      this should improve cache locality
@@ -654,27 +631,26 @@ static int udpv6_getfrag(const void *data, struct in6_addr *addr,
 
 static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
 {
-       
        struct ipv6_options opt_space;
        struct udpv6fakehdr udh;
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
        struct ipv6_options *opt = NULL;
        struct device *dev = NULL;
+       struct flowi fl;
        int addr_len = msg->msg_namelen;
        struct in6_addr *daddr;
        struct in6_addr *saddr = NULL;
        int len = ulen + sizeof(struct udphdr);
        int addr_type;
-       int hlimit = 0;
-       int err;
+       int hlimit = -1;
 
+       int err;
        
        if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
                return(-EINVAL);
 
-       if (sin6)
-       {
+       if (sin6) {
                if (addr_len < sizeof(*sin6))
                        return(-EINVAL);
                
@@ -687,14 +663,11 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
                udh.uh.dest = sin6->sin6_port;
                daddr = &sin6->sin6_addr;
 
-               if (np->dest && ipv6_addr_cmp(daddr, &np->daddr))
-               {
-                       ipv6_dst_unlock(np->dest);
-                       np->dest = NULL;
+               if (np->dst && ipv6_addr_cmp(daddr, &np->daddr)) {
+                       dst_release(np->dst);
+                       np->dst = NULL;
                }
-       }
-       else
-       {
+       } else {
                if (sk->state != TCP_ESTABLISHED)
                        return(-EINVAL);
                
@@ -704,8 +677,7 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
 
        addr_type = ipv6_addr_type(daddr);
 
-       if (addr_type == IPV6_ADDR_MAPPED)
-       {
+       if (addr_type == IPV6_ADDR_MAPPED) {
                struct sockaddr_in sin;
                
                sin.sin_family = AF_INET;
@@ -716,22 +688,18 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
 
        udh.daddr = NULL;
        
-       if (msg->msg_controllen)
-       {
+       if (msg->msg_controllen) {
                opt = &opt_space;
                memset(opt, 0, sizeof(struct ipv6_options));
 
                err = datagram_send_ctl(msg, &dev, &saddr, opt, &hlimit);
-               if (err < 0)
-               {
+               if (err < 0) {
                        printk(KERN_DEBUG "invalid msg_control\n");
                        return err;
                }
                
                if (opt->srcrt)
-               {                       
                        udh.daddr = daddr;
-               }
        }
        
        udh.uh.source = sk->dummy_th.source;
@@ -740,11 +708,17 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
        udh.iov = msg->msg_iov;
        udh.wcheck = 0;
        udh.pl_len = len;
-       
-       err = ipv6_build_xmit(sk, udpv6_getfrag, &udh, daddr, len,
-                             saddr, dev, opt, IPPROTO_UDP, hlimit,
-                             msg->msg_flags&MSG_DONTWAIT);
-       
+
+       fl.proto = IPPROTO_UDP;
+       fl.nl_u.ip6_u.daddr = daddr;
+       fl.nl_u.ip6_u.saddr = saddr;
+       fl.dev = dev;
+       fl.uli_u.ports.dport = udh.uh.dest;
+       fl.uli_u.ports.sport = udh.uh.source;
+
+       err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
+                            msg->msg_flags);
+
        if (err < 0)
                return err;
 
index ef51202ce5c399fe3615d0cf35301b357874fe83..ce74c8e2ab7de1e29c1332b1842f4f321bbfc8db 100644 (file)
@@ -714,19 +714,16 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
        struct ipxhdr   *ipx = skb->nh.ipxh;
        ipx_interface   *i;
 
-#ifdef CONFIG_FIREWALL
        /*
         *      We firewall first, ask questions later.
         */
 
-       if (call_in_firewall(PF_IPX, skb->dev, ipx, NULL)!=FW_ACCEPT)
+       if (call_in_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)!=FW_ACCEPT)
        {
                kfree_skb(skb, FREE_READ);
                return 0;
        }
 
-#endif
-
        /* See if we should update our network number */
        if ((intrfc->if_netnum == 0L) &&
                (ipx->ipx_source.net == ipx->ipx_dest.net) &&
@@ -818,16 +815,15 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
                                        printk( "IPX: Forward PPROP onto net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) );
 #endif
                                        skb2 = skb_clone(skb, GFP_ATOMIC);
-#ifdef CONFIG_FIREWALL
+
                                        /*
                                         *      See if we are allowed to firewall forward
                                         */
-                                       if (call_fw_firewall(PF_IPX, skb2->dev, ipx, NULL)!=FW_ACCEPT)
+                                       if (call_fw_firewall(PF_IPX, skb2->dev, ipx, NULL, &skb)!=FW_ACCEPT)
                                        {
                                                kfree_skb(skb, FREE_READ);
                                                return 0;
                                        }
-#endif
                                        ipxrtr_route_skb(skb2);
                                }
 #ifdef DEBUG_IPX_PPROP_ROUTING
@@ -851,16 +847,15 @@ static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
 
        if (intrfc->if_netnum != ipx->ipx_dest.net)
        {
-#ifdef CONFIG_FIREWALL
                /*
                 *      See if we are allowed to firewall forward
                 */
-               if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL)!=FW_ACCEPT)
+               if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)!=FW_ACCEPT)
                {
                        kfree_skb(skb, FREE_READ);
                        return 0;
                }
-#endif
+
                /* We only route point-to-point packets. */
                if (skb->pkt_type == PACKET_HOST)
                {
@@ -1451,13 +1446,11 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, stru
        else
                ipx->ipx_checksum=ipx_set_checksum(ipx, len+sizeof(struct ipxhdr));
 
-#ifdef CONFIG_FIREWALL 
-       if(call_out_firewall(PF_IPX, skb->dev, ipx, NULL)!=FW_ACCEPT)
+       if(call_out_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)!=FW_ACCEPT)
        {
                kfree_skb(skb, FREE_WRITE);
                return -EPERM;
        }
-#endif
        
        return ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? 
                                rt->ir_router_node : ipx->ipx_dest.node);
index 8fda1a0cc3a37ce5681d4838aa618b743f90430b..2679ff514dcfbd49f45d9e3e8e582cd9f222f3c0 100644 (file)
@@ -53,7 +53,7 @@ void lapb_set_timer(lapb_cb *lapb)
 
        lapb->timer.data     = (unsigned long)lapb;
        lapb->timer.function = &lapb_timer;
-       lapb->timer.expires  = jiffies + 10;
+       lapb->timer.expires  = jiffies + (HZ / 10);
 
        add_timer(&lapb->timer);
 }
index 6539201adde0554dde11d53c4e6848264c962372..a4488075c85b0e1bd14fb22baa5313f2f0294297 100644 (file)
@@ -418,19 +418,18 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
        char *optval, int optlen)
 {
        struct sock *sk = sock->sk;
-       int err, opt;
+       int opt;
 
        if (level != SOL_NETROM)
                return -ENOPROTOOPT;
 
-       if(optlen<sizeof(int))
+       if (optlen < sizeof(int))
                return -EINVAL;
-               
-       if(get_user(opt, (int *)optval))
+
+       if (get_user(opt, (int *)optval))
                return -EFAULT;
 
-       switch (optname) 
-       {
+       switch (optname) {
                case NETROM_T1:
                        if (opt < 1)
                                return -EINVAL;
@@ -480,7 +479,7 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
        if (level != SOL_NETROM)
                return -ENOPROTOOPT;
        
-       if(get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
 
        switch (optname) {
@@ -512,11 +511,14 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
                        return -ENOPROTOOPT;
        }
 
-       len=min(len,sizeof(int));
-       if(put_user(len, optlen))
+       len = min(len, sizeof(int));
+
+       if (put_user(len, optlen))
                return -EFAULT;
-       if(copy_to_user(optval,&val,len))
+
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
+
        return 0;
 }
 
index 1bcd7e83b6a770ce2bb63535f5f3c7cc5c7d904a..1387c6c2d07ef270f88ceba0373ce0d8fbd2f155 100644 (file)
@@ -175,7 +175,9 @@ static int nr_open(struct device *dev)
 {
        dev->tbusy = 0;
        dev->start = 1;
+
        MOD_INC_USE_COUNT;
+
        ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
 
        return 0;
@@ -185,8 +187,11 @@ static int nr_close(struct device *dev)
 {
        dev->tbusy = 1;
        dev->start = 0;
+
        ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+
        MOD_DEC_USE_COUNT;
+
        return 0;
 }
 
index 720a6b089de49dd754f0c35b526a8e934bbc0e90..eb8ad7a3512ce634dd68ae49846dfca157a0c84c 100644 (file)
@@ -686,12 +686,10 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        struct device *dev;
        unsigned char *dptr;
 
-#ifdef CONFIG_FIREWALL
-       if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
+       if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
                return 0;
-       if (ax25 == NULL && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
+       if (ax25 == NULL && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
                return 0;
-#endif
 
        nr_src  = (ax25_address *)(skb->data + 0);
        nr_dest = (ax25_address *)(skb->data + 7);
@@ -722,10 +720,8 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        if ((dev = nr_dev_first()) == NULL)
                return 0;
 
-#ifdef CONFIG_FIREWALL
-       if (ax25 != NULL && call_fw_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT)
+       if (ax25 != NULL && call_fw_firewall(PF_NETROM, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
                return 0;
-#endif
 
        dptr  = skb_push(skb, 1);
        *dptr = AX25_P_NETROM;
index 930faa2bfc81ff4e9bf8c7deefdebedb9b4ade57..15b3a8b9faa1a7df328e0c24879afecf743df378 100644 (file)
@@ -55,7 +55,7 @@ void nr_set_timer(struct sock *sk)
 
        sk->timer.data     = (unsigned long)sk;
        sk->timer.function = &nr_timer;
-       sk->timer.expires  = jiffies+10;
+       sk->timer.expires  = jiffies + (HZ / 10);
 
        add_timer(&sk->timer);
 }
index 2933166bbfe577c6c701b56507cca8e789d5b753..70ac39fabc2a08167794490ababb0ece06deb843 100644 (file)
@@ -36,6 +36,7 @@ extern struct net_proto_family inet_family_ops;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
 #include <net/ndisc.h>
+#include <net/dst.h>
 #include <net/transp_v6.h>
 #endif
 
@@ -121,6 +122,11 @@ EXPORT_SYMBOL(neigh_lookup);
 EXPORT_SYMBOL(ntbl_walk_table);
 EXPORT_SYMBOL(neigh_tbl_run_bh);
 
+/*     dst_entry       */
+EXPORT_SYMBOL(dst_alloc);
+EXPORT_SYMBOL(__dst_free);
+EXPORT_SYMBOL(dst_total);
+
 /* Needed by smbfs.o */
 EXPORT_SYMBOL(__scm_destroy);
 EXPORT_SYMBOL(__scm_send);
@@ -137,6 +143,10 @@ EXPORT_SYMBOL(sklist_destroy_socket);
 EXPORT_SYMBOL(sklist_insert_socket);
 #endif
 
+#ifdef CONFIG_SMB_FS_MODULE
+EXPORT_SYMBOL(scm_detach_fds);
+#endif
+
 #ifdef CONFIG_INET
 /* Internet layer registration */
 EXPORT_SYMBOL(inet_add_protocol);
@@ -182,7 +192,6 @@ EXPORT_SYMBOL(destroy_sock);
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(dev_lockct);
-EXPORT_SYMBOL(ndisc_eth_hook);
 EXPORT_SYMBOL(memcpy_fromiovecend);
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
 EXPORT_SYMBOL(__release_sock);
@@ -218,7 +227,7 @@ EXPORT_SYMBOL(tcp_v4_rebuild_header);
 EXPORT_SYMBOL(tcp_v4_send_check);
 EXPORT_SYMBOL(tcp_v4_conn_request);
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
-EXPORT_SYMBOL(tcp_v4_backlog_rcv);
+EXPORT_SYMBOL(tcp_v4_do_rcv);
 EXPORT_SYMBOL(tcp_v4_connect);
 EXPORT_SYMBOL(__ip_chk_addr);
 EXPORT_SYMBOL(net_reset_timer);
@@ -277,6 +286,7 @@ EXPORT_SYMBOL(register_netdev);
 EXPORT_SYMBOL(unregister_netdev);
 EXPORT_SYMBOL(ether_setup);
 EXPORT_SYMBOL(dev_new_index);
+EXPORT_SYMBOL(dev_get_by_index);
 EXPORT_SYMBOL(eth_type_trans);
 EXPORT_SYMBOL(eth_copy_and_sum);
 EXPORT_SYMBOL(alloc_skb);
index 2002505b1d5038a4a0b9ce3916255d1e37fd4129..32fafe1dabb7a74112adbe1fa643bab3159708ae 100644 (file)
@@ -469,13 +469,13 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
        if (level != SOL_ROSE)
                return -ENOPROTOOPT;
 
-       if(optlen<sizeof(int))
+       if (optlen < sizeof(int))
                return -EINVAL;
-       if(get_user(opt, (int *)optval))
+
+       if (get_user(opt, (int *)optval))
                return -EFAULT;
 
-       switch (optname) 
-       {
+       switch (optname) {
                case ROSE_T1:
                        if (opt < 1)
                                return -EINVAL;
@@ -525,7 +525,7 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
        if (level != SOL_ROSE)
                return -ENOPROTOOPT;
                
-       if(get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
        
        switch (optname) {
@@ -557,11 +557,14 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
                        return -ENOPROTOOPT;
        }
 
-       len=min(len,sizeof(int));
-       if(put_user(len,optlen))
+       len = min(len, sizeof(int));
+
+       if (put_user(len, optlen))
                return -EFAULT;
-       if(copy_to_user(optval,&val,len))
+
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
+
        return 0;
 }
 
index a78db85e39964338080dd96b2b7d83d0282fbc53..ebab50e0d90c7c0b26acb739e61fc63e8b168b99 100644 (file)
@@ -145,10 +145,11 @@ static int rose_set_mac_address(struct device *dev, void *addr)
 
 static int rose_open(struct device *dev)
 {
-       MOD_INC_USE_COUNT;
        dev->tbusy = 0;
        dev->start = 1;
 
+       MOD_INC_USE_COUNT;
+
        ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
 
        return 0;
@@ -156,10 +157,11 @@ static int rose_open(struct device *dev)
 
 static int rose_close(struct device *dev)
 {
-       MOD_DEC_USE_COUNT;
        dev->tbusy = 1;
        dev->start = 0;
 
+       MOD_DEC_USE_COUNT;
+
        ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
 
        return 0;
index 5f592803762365253fac04f7ebfb565c7c4d1311..9f1a0c0f5b5ceff3e4a619e5b08792d556296fa2 100644 (file)
@@ -56,7 +56,7 @@ void rose_link_set_timer(struct rose_neigh *neigh)
 
        neigh->timer.data     = (unsigned long)neigh;
        neigh->timer.function = &rose_link_timer;
-       neigh->timer.expires  = jiffies + 10;
+       neigh->timer.expires  = jiffies + (HZ / 10);
 
        add_timer(&neigh->timer);
 }
@@ -278,10 +278,8 @@ void rose_transmit_link(struct sk_buff *skb, struct rose_neigh *neigh)
 {
        unsigned char *dptr;
 
-#ifdef CONFIG_FIREWALL
-       if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT)
+       if (call_fw_firewall(PF_ROSE, skb->dev, skb->data, NULL,&skb) != FW_ACCEPT)
                return;
-#endif
 
        if (!rose_link_up(neigh))
                neigh->restarted = 0;
index 1b6a77d199d832b75175dc19506089da9e68c911..19a53d40df63e322f7fe2f86c0bc0b8daa01dbb4 100644 (file)
@@ -545,10 +545,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
        struct device *dev;
        unsigned long flags;
 
-#ifdef CONFIG_FIREWALL
-       if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL) != FW_ACCEPT)
+       if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
                return 0;
-#endif
 
        frametype = skb->data[2];
        lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
index ffcb1cf9f1942ba7ec3168323a3fed93747d4510..b8eab74a9cb3d7d5308895746a5fb3cfe049a6c9 100644 (file)
@@ -55,7 +55,7 @@ void rose_set_timer(struct sock *sk)
 
        sk->timer.data     = (unsigned long)sk;
        sk->timer.function = &rose_timer;
-       sk->timer.expires  = jiffies + 10;
+       sk->timer.expires  = jiffies + (HZ / 10);
 
        add_timer(&sk->timer);
 }
index d34aa299b028ef6644e41a830562648119779ebe..ea8a2cc1c8cbc682cbde28956145e9c359051343 100644 (file)
@@ -130,7 +130,7 @@ static struct file_operations socket_file_ops = {
  *     The protocol list. Each protocol is registered in here.
  */
 
-static struct net_proto_family *net_families[NPROTO];
+struct net_proto_family *net_families[NPROTO];
 
 /*
  *     Statistics counters of the socket lists
@@ -272,6 +272,7 @@ struct socket *sock_alloc(void)
        inode->i_gid = current->gid;
 
        sock->inode = inode;
+       init_waitqueue(&sock->wait);
        sock->fasync_list = NULL;
        sock->state = SS_UNCONNECTED;
        sock->flags = 0;
index cd1b050de7cf40e0c005580f402d3a822710cc27..6b6a081ca0bddac4fc1ab583ba20713dce7746dc 100644 (file)
@@ -115,17 +115,17 @@ extern __inline__ int unix_may_send(unix_socket *sk, unix_socket *osk)
 
 extern __inline__ void unix_lock(unix_socket *sk)
 {
-       sk->users++;
+       sk->sock_readers++;
 }
 
 extern __inline__ int unix_unlock(unix_socket *sk)
 {
-       return sk->users--;
+       return sk->sock_readers--;
 }
 
 extern __inline__ int unix_locked(unix_socket *sk)
 {
-       return sk->users;
+       return sk->sock_readers;
 }
 
 extern __inline__ void unix_release_addr(struct unix_address *addr)
@@ -348,7 +348,7 @@ static int unix_create(struct socket *sock, int protocol)
        
        sk->protinfo.af_unix.family=AF_UNIX;
        sk->protinfo.af_unix.inode=NULL;
-       sk->users=1;                            /* Us */
+       sk->sock_readers=1;                             /* Us */
        sk->protinfo.af_unix.readsem=MUTEX;     /* single task reading lock */
        sk->mtu=4096;
        sk->protinfo.af_unix.list=&unix_sockets_unbound;
@@ -1303,6 +1303,8 @@ static int unix_shutdown(struct socket *sock, int mode)
 {
        struct sock *sk = sock->sk;
        unix_socket *other=unix_peer(sk);
+       
+       mode++;
 
        if (mode&SEND_SHUTDOWN)
        {
@@ -1382,7 +1384,7 @@ static int unix_read_proc(char *buffer, char **start, off_t offset,
        {
                len+=sprintf(buffer+len,"%p: %08X %08X %08lX %04X %02X %5ld",
                        s,
-                       s->users,
+                       s->sock_readers,
                        0,
                        s->socket ? s->socket->flags : 0,
                        s->type,
index 77a75a2f2effa7255d9c1eb8fed958f12da08c8f..c5a0b0ef37c41c8ec20338527ffe893759db17ee 100644 (file)
@@ -352,21 +352,22 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
        char *optval, int optlen)
 {
        struct sock *sk = sock->sk;
-       int err, opt;
+       int opt;
 
        if (level != SOL_X25)
                return -ENOPROTOOPT;
 
-       if(optlen<sizeof(int))
+       if (optlen < sizeof(int))
                return-EINVAL;
-       if(get_user(opt, (int *)optval))
+
+       if (get_user(opt, (int *)optval))
                return -EFAULT;
 
-       switch (optname) 
-       {
+       switch (optname) {
                case X25_QBITINCL:
                        sk->protinfo.x25->qbitincl = opt ? 1 : 0;
                        return 0;
+
                default:
                        return -ENOPROTOOPT;
        }
@@ -382,11 +383,10 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
        if (level != SOL_X25)
                return -ENOPROTOOPT;
 
-       if(get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
-               
-       switch (optname) 
-       {
+
+       switch (optname) {
                case X25_QBITINCL:
                        val = sk->protinfo.x25->qbitincl;
                        break;
@@ -395,11 +395,14 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
                        return -ENOPROTOOPT;
        }
 
-       len=min(len,sizeof(int));
-       if(put_user(len, optlen))
+       len = min(len, sizeof(int));
+
+       if (put_user(len, optlen))
                return -EFAULT;
-       if(copy_to_user(optval,&val,len))
+
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
+
        return 0;
 }
 
index b6ce9e1274518f0566f0fe8998da10ac1707f52b..6b02a944175fa21e0897fffaecb9f0d9670f8433 100644 (file)
@@ -53,12 +53,10 @@ static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
        unsigned short frametype;
        unsigned int lci;
 
-#ifdef CONFIG_FIREWALL
-       if (call_in_firewall(PF_X25, skb->dev, skb->data, NULL) != FW_ACCEPT) {
+       if (call_in_firewall(PF_X25, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) {
                kfree_skb(skb, FREE_READ);
                return 0;
        }
-#endif
 
        frametype = skb->data[2];
         lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
index 0c884a31f0b4294945fd65fb7d7aa2bbfc0245e5..b3fce46961e229daeb82cf892bb37693fd818e61 100644 (file)
@@ -58,7 +58,7 @@ static void x25_link_set_timer(struct x25_neigh *neigh)
 
        neigh->timer.data     = (unsigned long)neigh;
        neigh->timer.function = &x25_link_timer;
-       neigh->timer.expires  = jiffies + 100;
+       neigh->timer.expires  = jiffies + (HZ / 1);
 
        add_timer(&neigh->timer);
 }
@@ -240,10 +240,8 @@ void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsig
 
 void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
 {
-#ifdef CONFIG_FIREWALL
-       if (call_fw_firewall(PF_X25, skb->dev, skb->data, NULL) != FW_ACCEPT)
+       if (call_fw_firewall(PF_X25, skb->dev, skb->data, NULL,&skb) != FW_ACCEPT)
                return;
-#endif
 
        switch (neigh->state) {
                case X25_LINK_STATE_0:
index fc6bf863f29efb7459f4f274c8a30f7a3c6e6ba9..84f5285e4d340993fef1b42e66e0d4b49e51c745 100644 (file)
@@ -54,7 +54,7 @@ void x25_set_timer(struct sock *sk)
 
        sk->timer.data     = (unsigned long)sk;
        sk->timer.function = &x25_timer;
-       sk->timer.expires  = jiffies + 100;
+       sk->timer.expires  = jiffies + (HZ / 1);
 
        add_timer(&sk->timer);
 }
index 7b005fa7271090b869d1bb801c9fd75ef660afee..787b21bfdadf5432832c13c7feb0e92decb297fe 100644 (file)
@@ -244,7 +244,8 @@ static void do_depend(void)
        struct stat st;
 
        if (fd < 0) {
-               perror("mkdep: open");
+               if (errno != ENOENT)
+                       perror(filename);
                return;
        }
        fstat(fd, &st);