]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.86 1.3.86
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:47 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:47 +0000 (15:10 -0500)
83 files changed:
Documentation/Configure.help
Documentation/mandatory.txt
Documentation/svga.txt
Makefile
arch/i386/boot/video.S
arch/i386/defconfig
arch/i386/mm/init.c
drivers/block/ide.c
drivers/block/triton.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/dlci.c
drivers/net/eepro.c
drivers/net/wic.c [new file with mode: 0644]
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/NCR5380.c
drivers/scsi/NCR5380.h
drivers/scsi/README.dtc3x80 [new file with mode: 0644]
drivers/scsi/dtc.c [new file with mode: 0644]
drivers/scsi/dtc.h [new file with mode: 0644]
drivers/scsi/g_NCR5380.h
drivers/scsi/hosts.c
drivers/scsi/pas16.c
drivers/scsi/pas16.h
drivers/scsi/sd.c
drivers/scsi/t128.c
drivers/scsi/t128.h
drivers/sound/Readme.cards
fs/locks.c
fs/namei.c
fs/nfs/nfsroot.c
fs/open.c
fs/read_write.c
fs/super.c
include/asm-i386/segment.h
include/asm-i386/string.h
include/linux/fs.h
include/linux/if_frad.h
include/linux/if_wic.h [new file with mode: 0644]
include/linux/ip.h
include/linux/ip_fw.h
include/linux/sdla.h
include/linux/skbuff.h
include/linux/sockios.h
include/net/br.h [new file with mode: 0644]
include/net/ip_masq.h
include/net/tcp.h
mm/filemap.c
mm/mmap.c
net/802/Makefile
net/Config.in
net/Makefile
net/appletalk/ddp.c
net/ax25/af_ax25.c
net/ax25/ax25_subr.c
net/bridge/Makefile [new file with mode: 0644]
net/bridge/br.c [new file with mode: 0644]
net/bridge/br_tree.c [new file with mode: 0644]
net/core/Makefile
net/core/dev.c
net/core/firewall.c
net/core/skbuff.c
net/ipv4/af_inet.c
net/ipv4/icmp.c
net/ipv4/ip_fw.c
net/ipv4/ip_input.c
net/ipv4/ip_masq.c
net/ipv4/ip_masq_app.c
net/ipv4/ip_masq_ftp.c
net/ipv4/ip_masq_irc.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipx/af_ipx.c
net/netrom/af_netrom.c
net/netsyms.c
net/unix/af_unix.c
scripts/ksymoops.cc
scripts/tkparse.c

index ac5e331c27c399a78080b67c9978797de48d1e0d..d7abd8f8380f240096d186e6ccc9acf465bc01b7 100644 (file)
@@ -422,6 +422,12 @@ CONFIG_ALPHA_AVANTI
 ### Add info about Platform2000, EB164
 ###
 
+Is it really a true XL
+CONFIG_ALPHA_XL
+  If your Avanti Machine is of type XL (a.k.a. "Windows NT Dream
+  Machine") (as opposed to Mustang (AS200), M3 (AS250) or Avanti
+  (AS400)), say Y, otherwise N.
+
 Limit memory to low 16MB
 CONFIG_MAX_16M
   This is for some buggy motherboards which cannot properly deal with
@@ -710,13 +716,18 @@ CONFIG_IP_FORWARD
   traffic from one of the local computers and destined for an outside
   host is changed by your box so that it appears to come from you),
   you'll have to say Y here and also to IP firewalling and IP
-  masquerading below. You should say Y here also if you want to
+  masquerading below. You should also say Y here if you want to
   configure your box as a SLIP (the protocol for sending internet
   traffic over telephone lines) or PPP (a better SLIP) server for
   other people to dial into and your box is connected to a local
   network at the same time. You would then most likely use proxy-ARP
   (Address Resolution Protocol), explained in the Proxy-Arp mini howto
-  on sunsite in /pub/Linux/docs/HOWTO/mini. If unsure, say N.
+  on sunsite in /pub/Linux/docs/HOWTO/mini. You also need to say Y
+  here if you want to run mrouted in order to do multicast routing as
+  used on the MBONE (a high bandwidth network on top of the internet
+  which carries audio and video broadcasts) for example. In this case,
+  say Y to "IP: multicasting" and "IP: multicast routing" as well. If
+  unsure, say N.
 
 IP: multicasting
 CONFIG_IP_MULTICAST
@@ -842,9 +853,12 @@ CONFIG_IP_ALIAS
 IP: multicast routing(in progress)
 CONFIG_IP_MROUTE
   This is used if you want your machine to act as a router for IP
-  packets that have several destination addresses. Information about
-  the multicast capabilities of the various network cards is contained
-  in drivers/net/README.multicast. If you haven't heard about it, you
+  packets that have several destination addresses. It is needed on the
+  MBONE, a high bandwidth network on top of the internet which carries
+  audio and video broadcasts. In order to do that, you would most
+  likely run the program mrouted. Information about the multicast
+  capabilities of the various network cards is contained in
+  drivers/net/README.multicast. If you haven't heard about it, you
   don't need it.
 
 PC/TCP compatibility mode
@@ -1032,6 +1046,13 @@ CONFIG_BPQETHER
   useful if some other computer on your local network has a direct
   amateur radio connection.
 
+Bridging (test)
+CONFIG_BRIDGE
+  Enables bridge mode support in the box. This allows you to use a Linux
+  box (suitably configured) as an ethernet bridge including 802.1 spanning
+  tree support. This is in test. There are a small batch of changes before
+  final release but it should work nicely.
+
 Kernel/User network link driver(ALPHA)
 CONFIG_NETLINK
   This driver allows for two-way communication between certain parts
@@ -1132,6 +1153,9 @@ CONFIG_SCSI_AUTO_BIOSP
   determine the mapping used under the other operating systems (e.g.
   DOS), and set these parameters to the determined values, or if the
   disk has no valid partition table, to an optimal value.
+###
+### What are the advantages/disadvantages? What is a safe value?
+###
 
 AdvanSys SCSI support
 CONFIG_SCSI_ADVANSYS
@@ -1197,6 +1221,11 @@ CONFIG_SCSI_BUSLOGIC
   You might also want to read the SCSI-HOWTO, available via anonymous
   ftp from sunsite.unc.edu:/pub/Linux/docs/HOWTO.
  
+DTC3180/3280 SCSI support
+CONFIG_SCSI_DTC3280
+  This is support for DTC 3180/3280 SCSI Host Adaptors.  It does not
+  use IRQ's.  It does not support parity on the SCSI bus.
+
 EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support
 CONFIG_SCSI_EATA_DMA
   This is support for a SCSI host adaptor. Please read the
@@ -1284,6 +1313,18 @@ CONFIG_SCSI_NCR53C7xx
   = code which can be inserted in and removed from the running kernel
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
+
+always negotiate synchronous transfers
+CONFIG_SCSI_NCR53C7xx_sync
+  In general, this is good; however, it is a bit dangerous since there
+  are some broken SCSI devices out there. Take your chances. Safe bet
+  is N.
+
+allow FAST-SCSI [10MHz]
+CONFIG_SCSI_NCR53C7xx_FAST
+  This will enable 10MHz FAST-SCSI transfers with your host
+  adaptor. Some systems have problems with that speed, so it's safest
+  to say N here.
  
 Always IN2000 SCSI support (test release)
 CONFIG_SCSI_IN2000
@@ -1606,10 +1647,10 @@ CONFIG_DLCI
   that has one of the programs lynx, netscape or Mosaic.) To use frame
   relay, you need supporting hardware (FRAD) and certain programs from
   the net-tools package as explained in
-  Documentation/framerelay.txt. This driver is also available as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  Documentation/networking/framerelay.txt. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
 
 Max open DLCI
 CONFIG_DLCI_COUNT 
@@ -2579,20 +2620,17 @@ CONFIG_NFS_FS
   about 27 kB. This filesystem is also available as a module ( = code
   which can be inserted in and removed from the running kernel
   whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt. If you don't know what all
-  this is about, say N.
+  here and read Documentation/modules.txt. If you configure a diskless
+  machine which will mount its root filesystem over nfs, you cannot
+  compile this driver as a module. If you don't know what all this is
+  about, say N.
 
 Root file system on NFS
 CONFIG_ROOT_NFS
   If you want your Linux box to mount its whole root filesystem from
   some other computer over the net via NFS (presumably because your
-  box doesn't have a harddisk), say Y here. You will then have to
-  specify the directory that should be remotely mounted with the
-  "root" kernel command line option at boot time. See the
-  documentation of your boot loader (lilo or loadlin) about how to
-  pass options to the kernel. The lilo procedure is also explained in
-  the SCSI-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.) Most people say N here.
+  box doesn't have a harddisk), say Y. Read Documentation/nfsroot.txt
+  for details. Most people say N here.
 
 BOOTP support
 CONFIG_RNFS_BOOTP
@@ -2604,7 +2642,8 @@ CONFIG_RNFS_BOOTP
   booting Linux and does BOOTP itself, providing all necessary
   information on the kernel command line, you can say N here.
   If unsure, say Y. Note that in case you want to use BOOTP, a BOOTP
-  server must be operating on your network.
+  server must be operating on your network. Read
+  Documentation/nfsroot.txt for details.
 
 RARP support
 CONFIG_RNFS_RARP
@@ -2613,7 +2652,8 @@ CONFIG_RNFS_RARP
   of your computer to be discovered automatically using the RARP
   protocol (an older protocol which is being obsoleted by BOOTP), say
   Y here. Note that in case you want to use RARP, a RARP server must be
-  operating on your network.
+  operating on your network. Read Documentation/nfsroot.txt for
+  details. 
 
 ISO9660 cdrom filesystem support
 CONFIG_ISO9660_FS
@@ -2713,6 +2753,14 @@ CONFIG_SERIAL
   serial mice, modems and similar devices connecting to the standard
   serial ports.
 
+Digiboard PC/X Support
+CONFIG_DIGI
+  This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards
+  that give you many serial ports. You would need something like this
+  to connect more than two modems to your linux box, for instance in
+  order to become a BBS. If you have a card like that, say Y here and
+  read the file Documentation/digiboard.txt.
+
 Cyclades async mux support
 CONFIG_CYCLADES
   This is a driver for a card that gives you many serial ports. You
@@ -2898,7 +2946,7 @@ CONFIG_APM_IGNORE_USER_SUSPEND
   compliant APM BIOS, you want to say N.  However, on the NEC Versa M
   series notebooks, it is necessary to say Y because of a BIOS bug.
 
-Enable APM features
+Enable APM at boot time
 CONFIG_APM_DO_ENABLE
   Enable APM features at boot time.  From page 36 of the APM BIOS
   specification: "When disabled, the APM BIOS does not automatically
@@ -3139,4 +3187,6 @@ CONFIG_ISDN_DRV_TELES
 # LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
 # LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
 # LocalWords:  FC DC dc PPA IOMEGA's ppa RNFS FMV Fujitsu ARPD arpd loran layes
-# LocalWords:  FRAD indiana framerelay DLCI DCLIs Sangoma SDLA
+# LocalWords:  FRAD indiana framerelay DLCI DCLIs Sangoma SDLA mrouted sync sec
+# LocalWords:  Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard
+# LocalWords:  DIGI Xe Xeve digiboard UMISC touchscreens
index 7068ac07d1234735ab9232b61c194d516a56e4cb..4121eb52369b90af0d1b4f9cac3c82236bd274b3 100644 (file)
@@ -60,25 +60,39 @@ to run mandatory lock candidates with setgid privileges.
 Available implementations
 -------------------------
 
-I originally intended to base my implementation on SunOS, only to find out that
-the implementation in SunOS 4.1.1 (the latest version that will work on my Sun
-3/80 at home) is completely hopeless.
+I have considered the implementations of mandatory locking available with
+SunOS 4.1.x, Solaris 2.x and HP-UX 9.x.
 
-For one thing, calls to open() for a file fail with EAGAIN if another process
-holds a mandatory lock on the file. However, processes already holding open
-file descriptors can carry on using them. Wierd!
+Generally I have tried to make the most sense out of the behaviour exhibited
+by these three reference systems. There are many anomalies.
 
-In addition, SunOS doesn't seem to honour the O_NONBLOCK (O_NDELAY) flag for
-mandatory locks, so reads and writes to locked files always block when they
-should probably return EAGAIN.
+Originally I wrote (about SunOS):
+ "For one thing, calls to open() for a file fail with EAGAIN if another
+  process holds a mandatory lock on the file. However, processes already
+  holding open file descriptors can carry on using them. Wierd!"
+
+Well, all my reference systems do it, so I decided to go with the flow.
+My gut feeling is that only calls to open() and creat() with O_TRUNC should be
+rejected, as these are the only ones that try to modify the file contents as
+part of the open() call.
+
+HP-UX even disallows open() with O_TRUNC for a file with advisory locks, not
+just mandatory locks. That to me contravenes POSIX.1.
+
+mmap() is another interesting case. All the operating systems mentioned
+prevent mandatory locks from being applied to an mmap()'ed file, but  HP-UX
+also disallows advisory locks for such a file.
+
+My opinion is that only MAP_SHARED mappings should be immune from locking, and
+then only from mandatory locks - that is what is currently implemented.
 
-I found some test code online, which I think comes from one of Stevens' UNIX
-programming books, that confirmed what I considered to be be the "obvious"
-semantics, described below. I shall attempt to run my test programs on other
-platforms to verify my implementation.
+SunOS is so hopeless that it doesn't even honour the O_NONBLOCK flag for
+mandatory locks, so reads and writes to locked files always block when they
+should return EAGAIN.
 
-Personally I feel that this is such an esoteric area that these semantics are
-just as valid as any others, so long as the main points seem to agree.
+I'm afraid that this is such an esoteric area that the semantics described
+below are just as valid as any others, so long as the main points seem to
+agree. 
 
 Semantics
 ---------
@@ -99,13 +113,24 @@ Semantics
    unless a process has opened the file with the O_NONBLOCK flag in which case
    the system call will return immediately with the error status EAGAIN.
 
+4. Calls to open() or creat() on a file that has any mandatory locks owned
+   by other processes will be rejected with the error status EAGAIN.
+
+5. Attempts to apply a mandatory lock to a file that is memory mapped and
+   shared (via mmap() with MAP_SHARED) will be rejected with the error status
+   EAGAIN.
+
+6. Attempts to create a shared memory map of a file (via mmap() with MAP_SHARED)
+   that has any mandatory locks in effect will be rejected with the error status
+   EAGAIN.
+
 Which system calls are affected?
 --------------------------------
 
 Those which modify a file's contents, not just the inode. That gives read(),
-write(), readv(), writev(), truncate() and ftruncate(). truncate() and
-ftruncate() are considered to be "write" actions for the purposes of mandatory
-locking.
+write(), readv(), writev(), open(), creat(), mmap(), truncate() and
+ftruncate(). truncate() and ftruncate() are considered to be "write" actions
+for the purposes of mandatory locking.
 
 The affected region is usually defined as stretching from the current position
 for the total number of bytes read or written. For the truncate calls it is
@@ -124,3 +149,4 @@ Not even root can override a mandatory lock, so runaway process can wreak
 havoc if they lock crucial files. The way around it is to change the file
 permissions (remove the setgid bit) before trying to read or wite to it.
 Of course, that might be a bit tricky if the system is hung :-(
+
index 56b3d73bcf65b3cc9bdfa78a0ab36a00f596d4d9..16bff284ef87407ce8b9840161b2247f09df43d4 100644 (file)
@@ -1,4 +1,4 @@
-                       Video Mode Selection Support 2.6
+                       Video Mode Selection Support 2.7
              (c) 1995, 1996 Martin Mares, <mj@k332.feld.cvut.cz>
 --------------------------------------------------------------------------------
 
@@ -103,8 +103,10 @@ can be divided to three regions:
        (as presented to INT 10, function 00) increased by 0x0100. You can
        use any mode numbers even if not shown on the menu.
 
-   0x0200 to 0x04ff - VESA BIOS modes. The ID is a VESA mode ID increased by
-       0x0200. All VESA modes should be autodetected and shown on the menu.
+   0x0200 to 0x08ff - VESA BIOS modes. The ID is a VESA mode ID increased by
+       0x0100. All VESA modes should be autodetected and shown on the menu.
+
+   0x0900 to 0x09ff - Video7 special modes. Set by calling INT 0x10, AX=0x6f05.
 
    0x0f00 to 0x0fff - special modes (they are set by various tricks -- usually
        by modifying one of the standard modes). Currently available:
@@ -113,6 +115,9 @@ can be divided to three regions:
        0x0f02  VGA 80x43 (VGA switched to 350 scanlines with a 8-point font)
        0x0f03  VGA 80x28 (standard VGA scans, but 14-point font)
        0x0f04  leave current video mode
+       0x0f05  VGA 80x30 (480 scans, 16-point font)
+       0x0f06  VGA 80x34 (480 scans, 14-point font)
+       0x0f07  VGA 80x60 (480 scans, 8-point font)
 
    0x1000 to 0x7fff - modes specified by resolution. The code has a "0xRRCC"
        form where RR is a number of rows and CC is a number of columns.
@@ -148,7 +153,7 @@ it's possible that the first variant doesn't work, while some of the others do
 -- in this case turn this switch off to see the rest.
 
    CONFIG_VIDEO_RETAIN - enables retaining of screen contents when switching
-video modes. Works only with some boot loaders leaving enough room for the
+video modes. Works only with some boot loaders which leave enough room for the
 buffer.
 
    CONFIG_VIDEO_LOCAL - enables inclusion of "local modes" in the list. The
@@ -225,3 +230,14 @@ this must be done manually -- no autodetection mechanisms are available.
 2.5 (19-Mar-96)        Fixed a VESA mode scanning bug introduced in 2.4.
 2.6 (25-Mar-96)        Some VESA BIOS errors not reported -- it fixes error reports on
                several cards with broken VESA code (e.g., ATI VGA).
+2.7 (09-Apr-96)        - Accepted all VESA modes in range 0x100 to 0x7ff, because some
+                 cards use very strange mode numbers.
+               - Added Realtek VGA modes (thanks to Gonzalo Tornaria).
+               - Hardware testing order slightly changed, tests based on ROM
+                 contents done as first.
+               - Added support for special Video7 mode switching functions
+                 (thanks to Tom Vander Aa).
+               - Added 480-scanline modes (especially useful for notebooks,
+                 original version written by hhanemaa@cs.ruu.nl, patched by
+                 Jeff Chua, rewritten by me).
+               - Screen store/restore fixed.
index 4baec8373d147b2f2b17252e654d64e082453826..6dab3bddf4716cf199469c5db4cde928d6315332 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 85
+SUBLEVEL = 86
 
 ARCH = i386
 
index 07c3f9fc09c08274fa4ce43957e66486dedd8156..748e235b5fa38b51bd76848cfed066e7b98f65dd 100644 (file)
@@ -1,5 +1,5 @@
 !
-!      Display adapter & video mode setup, version 2.6 (25-Mar-96)
+!      Display adapter & video mode setup, version 2.7 (09-Apr-96)
 !
 !      Copyright (C) 1995, 1996 Martin Mares <mj@k332.feld.cvut.cz>
 !      Based on the original setup.S code (C) Linus Torvalds
@@ -32,6 +32,8 @@
 #define VIDEO_FIRST_BIOS 0x0100
 ! VESA BIOS video modes (VESA number + 0x0200)
 #define VIDEO_FIRST_VESA 0x0200
+! Video7 special modes (BIOS number + 0x0900)
+#define VIDEO_FIRST_V7 0x0900
 ! Special video modes
 #define VIDEO_FIRST_SPECIAL 0x0f00
 #define VIDEO_80x25 0x0f00
 #define VIDEO_80x43 0x0f02
 #define VIDEO_80x28 0x0f03
 #define VIDEO_CURRENT_MODE 0x0f04
-#define VIDEO_LAST_SPECIAL 0x0f05
+#define VIDEO_80x30 0x0f05
+#define VIDEO_80x34 0x0f06
+#define VIDEO_80x60 0x0f07
+#define VIDEO_LAST_SPECIAL 0x0f08
 ! Video modes given by resolution
 #define VIDEO_FIRST_RESOLUTION 0x1000
 
@@ -152,20 +157,22 @@ mopar0:   seg     gs                      ! Font size
        seg     fs
        mov     [PARAM_FONT_POINTS],ax  ! (valid only on EGA/VGA)
 
-       cmpb    [def_mode],#0   ! Default mode -- force sane values
+       mov     ax,[force_size] ! Forced size?
+       or      ax,ax
        jz      mopar1
        seg     fs
-       movb    [PARAM_VIDEO_COLS],#80
-mopar2:        seg     fs
-       movb    [PARAM_VIDEO_LINES],#25
+       mov     [PARAM_VIDEO_COLS],ah
+       seg     fs
+       mov     [PARAM_VIDEO_LINES],al
        ret
 
-mopar1:        cmpb    [adapter],#0    ! If we are on CGA/MDA/HGA, the screen must
+mopar1:        mov     al,#25
+       cmpb    [adapter],#0    ! If we are on CGA/MDA/HGA, the screen must
        jz      mopar2          ! have 25 lines.
        seg     gs              ! On EGA/VGA, use the EGA+ BIOS variable
        mov     al,[0x484]      ! containing maximal line number.
        inc     al
-       seg     fs
+mopar2:        seg     fs
        movb    [PARAM_VIDEO_LINES],al
        ret
 
@@ -316,6 +323,18 @@ lmscan:    cmpb    [adapter],#0    ! Scanning supported only on EGA/VGA
 
 lmdef: ret
 
+!
+! Additional parts of mode_set... (relative jumps, you know)
+!
+
+setv7:                         ! Video7 extended modes
+       DO_STORE
+       sub     bh,#VIDEO_FIRST_V7>>8
+       mov     ax,#0x6f05
+       int     0x10
+       stc
+       ret
+
 !
 ! Aliases for backward compatibility.
 !
@@ -344,6 +363,8 @@ mode_set:
        jnc     setres
        cmp     ah,#VIDEO_FIRST_SPECIAL>>8
        jz      setspc
+       cmp     ah,#VIDEO_FIRST_V7>>8
+       jz      setv7
        cmp     ah,#VIDEO_FIRST_VESA>>8
        jnc     setvesa
        or      ah,ah
@@ -453,13 +474,16 @@ spec_inits:
        .word   set_80x43
        .word   set_80x28
        .word   set_current
+       .word   set_80x30
+       .word   set_80x34
+       .word   set_80x60
 
 !
 ! Set the 80x25 mode. If already set, do nothing.
 !
 
 set_80x25:
-       incb    [def_mode]      ! Signal "we use default mode"
+       mov     [force_size],#0x5019    ! Override possibly broken BIOS vars
 use_80x25:
        mov     ah,#0x0f        ! Get current mode ID
        int     0x10
@@ -513,7 +537,7 @@ set_current:
 set_80x28:
        DO_STORE
        call    use_80x25       ! The base is 80x25
-       mov     ax,#0x1111      ! Use 9x14 font
+set14: mov     ax,#0x1111      ! Use 9x14 font
        xor     bl,bl
        int     0x10
        mov     ah,#0x01        ! Define cursor (scan lines 11 to 12)
@@ -536,6 +560,69 @@ set_80x43:
        int     0x10
        jmp     set_8pt         ! Use 8-pixel font
 
+!
+! Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
+!
+
+set_80x30:
+       call    use_80x25       ! Start with real 80x25
+       DO_STORE
+       mov     dx,#0x3cc       ! Get CRTC port
+       in      al,dx
+       mov     dl,#0xd4
+       ror     al,#1           ! Mono or color?
+       jc      set48a
+       mov     dl,#0xb4
+set48a:        mov     ax,#0x0c11      ! Vertical sync end (also unlocks CR0-7)
+       call    outidx
+       mov     ax,#0x0b06      ! Vertical total
+       call    outidx
+       mov     ax,#0x3e07      ! (Vertical) overflow
+       call    outidx
+       mov     ax,#0xea10      ! Vertical sync start
+       call    outidx
+       mov     ax,#0xdf12      ! Vertical display end
+       call    outidx
+       mov     ax,#0xe715      ! Vertical blank start
+       call    outidx
+       mov     ax,#0x0416      ! Vertical blank end
+       call    outidx
+       push    dx
+       mov     dl,#0xcc        ! Misc output register (read)
+       in      al,dx
+       mov     dl,#0xc2        ! (write)
+       and     al,#0x0d        ! Preserve clock select bits and color bit
+       or      al,#0xe2        ! Set correct sync polarity
+       out     dx,al
+       pop     dx
+       mov     [force_size],#0x501e
+       stc                     ! That's all.
+       ret
+
+!
+! Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
+!
+
+set_80x34:
+       call    set_80x30       ! Set 480 scans
+       call    set14           ! And 14-pt font
+       mov     ax,#0xdb12      ! VGA vertical display end
+       mov     [force_size],#0x5022
+setvde:        call    outidx
+       stc
+       ret
+
+!
+! Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
+!
+
+set_80x60:
+       call    set_80x30       ! Set 480 scans
+       call    set_8pt         ! And 8-pt font
+       mov     ax,#0xdf12      ! VGA vertial display end
+       mov     [force_size],#0x503c
+       jmp     setvde
+
 #ifdef CONFIG_VIDEO_RETAIN
 
 !
@@ -549,12 +636,10 @@ store_screen:
        jz      stsr
        push    ax
        push    bx
-       mov     al,[def_mode]           ! "Default mode" flag overriden
-       push    ax
-       movb    [def_mode],#0
+       push    [force_size]            ! Don't force specific size
+       mov     [force_size],#0
        call    mode_params             ! Obtain params of current mode
-       pop     ax
-       mov     [def_mode],al
+       pop     [force_size]
 
        seg     fs
        mov     ah,[PARAM_VIDEO_LINES]
@@ -564,7 +649,7 @@ store_screen:
        mul     ah
        mov     cx,ax                   ! CX=number of characters to store
        add     ax,ax                   ! Calculate image size
-       add     ax,modelist+1024+4
+       add     ax,#modelist+1024+4
        cmp     ax,[heap_end_ptr]
        jnc     sts1                    ! Unfortunately, out of memory
 
@@ -681,12 +766,10 @@ mode_table:
        jmp     mtabe
 mtab1x:        jmp     mtab1
 
-mtabv: mov     eax,#VIDEO_8POINT + 0x50320000  ! The 80x50 mode (VGA only)
-       stosd
-       mov     eax,#VIDEO_80x43 + 0x502b0000   ! The 80x43 mode (VGA only)
-       stosd
-       mov     eax,#VIDEO_80x28 + 0x501c0000   ! The 80x28 mode (VGA only)
-       stosd
+mtabv: lea     si,vga_modes                    ! All modes for std VGA
+       mov     cx,#12
+       rep
+       movsw
 
        cmpb    [scanning],#0                   ! Mode scan requested?
        jz      mscan1
@@ -737,6 +820,22 @@ cmt2:
 mtab1: lea     si,modelist     ! Returning: SI=mode list, DI=list end
 ret0:  ret
 
+! Modes usable on all standard VGAs
+
+vga_modes:
+       .word   VIDEO_8POINT
+       .word   0x5032          ! 80x50
+       .word   VIDEO_80x43
+       .word   0x502b          ! 80x43
+       .word   VIDEO_80x28
+       .word   0x501c          ! 80x28
+       .word   VIDEO_80x30
+       .word   0x501e          ! 80x30
+       .word   VIDEO_80x34
+       .word   0x5022          ! 80x34
+       .word   VIDEO_80x60
+       .word   0x503c          ! 80x60
+
 !
 ! Detect VESA modes.
 !
@@ -768,8 +867,8 @@ vesa1:      seg     gs              ! Get next mode in the list
        cmp     ax,#0x0080      ! Check validity of mode ID
        jc      vesa2
        or      ah,ah           ! Valid ID's are 0x0000-0x007f
-       jz      vesae           ! and 0x0100-0x02ff.
-       cmp     ax,#0x0300
+       jz      vesae           ! and 0x0100-0x07ff.
+       cmp     ax,#0x0800
        jnc     vesae
 vesa2: push    cx
        mov     cx,ax           ! Get mode information structure
@@ -901,7 +1000,7 @@ dosvga:    lodsw
        or      bp,bp
        jz      dosvga
        mov     si,bp           ! Found, copy the modes
-       mov     ah,#0x01
+       mov     ah,[svga_prefix]
 cpsvga:        lodsb
        or      al,al
        jz      didsv
@@ -920,20 +1019,21 @@ didsv1:  ret
 !
 
 svga_table:
-       .word   s3_md, s3_test
        .word   ati_md, ati_test
+       .word   oak_md, oak_test
+       .word   paradise_md, paradise_test
+       .word   realtek_md, realtek_test
+       .word   s3_md, s3_test
        .word   chips_md, chips_test
+       .word   video7_md, video7_test
        .word   cirrus5_md, cirrus5_test
        .word   cirrus6_md, cirrus6_test
        .word   cirrus1_md, cirrus1_test
        .word   ahead_md, ahead_test
        .word   everex_md, everex_test
        .word   genoa_md, genoa_test
-       .word   oak_md, oak_test
-       .word   paradise_md, paradise_test
        .word   trident_md, trident_test
        .word   tseng_md, tseng_test
-       .word   video7_md, video7_test
        .word   0
 
 !
@@ -1426,7 +1526,7 @@ tseng_test:
        out     dx,al
        cmp     ah,#0x55
        je      istsen
-       xor     bp,bp
+isnot: xor     bp,bp
 istsen:        ret
 
 tseng_md:
@@ -1472,9 +1572,9 @@ even7:    mov     al,#0x0c
        mov     al,#0x55
        xor     al,#0xea
        cmp     al,bh
-       je      isvid7
-       xor     bp,bp
-isvid7:        ret
+       jne     isnot
+       movb    [svga_prefix],#VIDEO_FIRST_V7>>8        ! Use special mode switching
+       ret
 
 video7_md:
        .byte   0x40, 0x2b, 0x50
@@ -1487,6 +1587,30 @@ video7_md:
        .ascii  "Video 7"
        .byte   0
 
+! Realtek VGA
+
+realtek_test:
+       lea     si,idrtvga
+       mov     di,#0x45
+       mov     cx,#0x0b
+       repe
+       cmpsb
+       je      isrt
+       xor     bp,bp
+isrt:  ret
+
+idrtvga:       .ascii  "REALTEK VGA"
+
+realtek_md:
+       .byte   0x1a, 0x3c, 0x50
+       .byte   0x1b, 0x19, 0x84
+       .byte   0x1c, 0x1e, 0x84
+       .byte   0x1d, 0x2b, 0x84
+       .byte   0x1e, 0x3c, 0x84
+       .byte   0
+       .ascii  "REALTEK"
+       .byte   0
+
 #endif /* CONFIG_VIDEO_SVGA */
 
 !
@@ -1606,13 +1730,14 @@ skip10: mov     al,ah
 ! Variables:
 
 adapter:       .byte   0       ! Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
-def_mode:      .byte   0       ! "Default mode selected" flag
 mt_end:                .word   0       ! End of video mode table if built
 edit_buf:      .space  6       ! Line editor buffer
 card_name:     .word   0       ! Pointer to adapter name
 scanning:      .byte   0       ! Performing mode scan
 do_restore:    .byte   0       ! Screen contents altered during mode change
+svga_prefix:   .byte   VIDEO_FIRST_BIOS>>8     ! Default prefix for BIOS modes
 video_segment: .word   0xb800  ! Video memory segment
+force_size:    .word   0       ! Use this size instead of the one in BIOS vars
 
 ! Messages:
 
index df8179569ba6f8afdf3110fd0063bc961c23cb3f..6f96917bf0ceb11e7081afc765d8633c24f51005 100644 (file)
@@ -74,6 +74,7 @@ CONFIG_SKB_LARGE=y
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_AX25 is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_NETLINK is not set
 
 #
@@ -89,6 +90,7 @@ CONFIG_DUMMY=m
 # CONFIG_SLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_STRIP is not set
+# CONFIG_WIC is not set
 # CONFIG_SCC is not set
 # CONFIG_PLIP is not set
 # CONFIG_EQUALIZER is not set
index 91f07f104fed4e33c187aa2f78762871d3a6f23e..d156da35bc0dc9b9056f7cb6922b7446a06c8db1 100644 (file)
@@ -153,8 +153,13 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        pg_dir = swapper_pg_dir;
        while (address < end_mem) {
 #ifdef USE_PENTIUM_MM
-               if (address + 4*1024*1024 <= end_mem &&
-                   (x86_capability & 8)) {
+               /*
+                * This will create page tables that
+                * span up to the next 4MB virtual
+                * memory boundary, but that's ok,
+                * we won't use that memory anyway.
+                */
+               if (x86_capability & 8) {
 #ifdef GAS_KNOWS_CR4
                        __asm__("movl %%cr4,%%eax\n\t"
                                "orl $16,%%eax\n\t"
index effc889491cc91ecb56fe3530a5e14da8e4ddd11..3bd6c2ca3ac9a9ba1d4efbd15af859e3ccacf690 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 5.36  Mar 30, 1996
+ *  linux/drivers/block/ide.c  Version 5.37  Apr 6, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
  * Version 5.35                cosmetic changes
  *                     fix cli() problem in try_to_identify()
  * Version 5.36                fixes to optional PCMCIA support
+ * Version 5.37                don't use DMA when "noautotune" is specified
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -2207,9 +2208,10 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                                        drive->media = ide_tape;
                                        drive->present = 1;
                                        drive->removeable = 1;
-                                       if (HWIF(drive)->dmaproc != NULL &&
-                                           !HWIF(drive)->dmaproc(ide_dma_check, drive))
-                                               printk(", DMA");
+                                       if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
+                                               if (!HWIF(drive)->dmaproc(ide_dma_check, drive))
+                                                       printk(", DMA");
+                                       }
                                        printk("\n");
                                }
                                else {
@@ -2309,7 +2311,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
                if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
                        drive->special.b.set_multmode = 1;
        }
-       if (HWIF(drive)->dmaproc != NULL) {     /* hwif supports DMA? */
+       if (drive->autotune != 2 && HWIF(drive)->dmaproc != NULL) {
                if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
                        printk(", DMA");
        }
index b57ff567dd31fee4d7c6d007df219ce99e990ec2..8df33f2ec6b730c652ed7d06144fff0dd5866c70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/triton.c       Version 1.09  Mar 31, 1996
+ *  linux/drivers/block/triton.c       Version 1.10  Apr 3, 1996
  *
  *  Copyright (c) 1995-1996  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -86,7 +86,8 @@
  *       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, giving 3-4MB/sec performance, about the same as 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.
  * known to work fine with this interface under Linux.
  */
 const char *good_dma_drives[] = {"Micropolis 2112A",
-                                /* "Maxtor 71260 AT", known-bad! */
                                 "CONNER CTMA 4000"};
 
 /*
@@ -379,8 +379,8 @@ void ide_init_triton (byte bus, byte fn)
 {
        int rc = 0, h;
        int dma_enabled = 0;
-       unsigned short bmiba, pcicmd;
-       unsigned int timings;
+       unsigned short pcicmd;
+       unsigned int bmiba, timings;
 
        printk("ide: 430FX (Triton) on PCI bus %d function %d\n", bus, fn);
        /*
@@ -400,20 +400,24 @@ void ide_init_triton (byte bus, byte fn)
                 */
                int try_again = 1;
                do {
-                       if ((rc = pcibios_read_config_word(bus, fn, 0x20, &bmiba)))
+                       if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba)))
                                goto quit;
                        bmiba &= 0xfff0;        /* extract port base address */
                        if (bmiba) {
                                dma_enabled = 1;
+                               break;
                        } else {
-                               printk("ide: BM-DMA base register is invalid (BIOS problem)\n");
-                               if (inb(DEFAULT_BMIBA) == 0xff) {
-                                       printk("ide: setting BM-DMA base register to 0x%04x\n", DEFAULT_BMIBA);
-                                       if ((rc = pcibios_write_config_word(bus, fn, 0x20, DEFAULT_BMIBA)))
-                                               goto quit;
-                               }
+                               printk("ide: BM-DMA base register is invalid (0x%04x, PnP BIOS problem)\n", bmiba);
+                               if (inb(DEFAULT_BMIBA) != 0xff || !try_again)
+                                       break;
+                               printk("ide: setting BM-DMA base register to 0x%04x\n", DEFAULT_BMIBA);
+                               if ((rc = pcibios_write_config_word(bus, fn, 0x04, pcicmd&~1)))
+                                       goto quit;
+                               rc = pcibios_write_config_dword(bus, fn, 0x20, DEFAULT_BMIBA|1);
+                               if (pcibios_write_config_word(bus, fn, 0x04, pcicmd|5) || rc)
+                                       goto quit;
                        }
-               } while (!dma_enabled && try_again--);
+               } while (try_again--);
        }
 
        /*
index 112302e6cdd854a804da8c92f59beab56e16ba31..af97ddd324e5d53257a3cb6f871b03b5bba1e7da 100644 (file)
@@ -12,6 +12,7 @@ if [ ! "$CONFIG_PPP" = "n" ]; then
   comment 'CCP compressors for PPP are only built as modules.'
 fi
 tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
+tristate 'WIC (Radio IP bridge)' CONFIG_WIC
 tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
 tristate 'PLIP (parallel port) support' CONFIG_PLIP
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
index 644eacd0f6afd97e8fa6e85bf18384c489915cac..e2b84d236b71da2ce15b4e7e1628a881ffb42cc6 100644 (file)
@@ -63,6 +63,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_WIC),y)
+L_OBJS += wic.o
+else
+  ifeq ($(CONFIG_WIC),m)
+  M_OBJS += wic.o
+  endif
+endif
+
 ifeq ($(CONFIG_SMC9194),y)
 L_OBJS += smc9194.o
 else
index 94213bdf9eaaae4e5f06595f137c5c8ac07f96c7..3dfe2f3ac1d5c4e5c9baaabf0bbef76011178a7d 100644 (file)
@@ -5,7 +5,7 @@
  *             interfaces.  Requires 'dlcicfg' program to create usable 
  *             interfaces, the initial one, 'dlci' is for IOCTL use only.
  *
- * Version:    @(#)dlci.c      0.10    23 Mar 1996
+ * Version:    @(#)dlci.c      0.15    31 Mar 1996
  *
  * Author:     Mike McLagan <mike.mclagan@linux.org>
  *
@@ -41,7 +41,7 @@
 #include <net/sock.h>
 
 static const char *devname = "dlci";
-static const char *version = "DLCI driver v0.10, 23 Mar 1996, mike.mclagan@linux.org";
+static const char *version = "DLCI driver v0.15, 31 Mar 1996, mike.mclagan@linux.org";
 
 static struct device *open_dev[CONFIG_DLCI_COUNT];
 
@@ -68,9 +68,13 @@ int register_frad(const char *name)
    }
 
    if (i == sizeof(basename) / sizeof(char *))
+      return(-EMLINK);
+
+   basename[i] = kmalloc(strlen(name) + 1, GFP_KERNEL);
+   if (!basename[i])
       return(-ENOMEM);
 
-   basename[i] = (char *) name;
+   strcpy(basename[i], name);
 
    return(0);
 }
@@ -89,22 +93,23 @@ int unregister_frad(const char *name)
    if (i == sizeof(basename) / sizeof(char *))
       return(-EINVAL);
 
+   kfree(basename[i]);
    basename[i] = NULL;
 
    return(0);
 }
 
 /* 
  these encapsulate the RFC 1490 requirements as well as 
  deal with packet transmission and reception, working with
  the upper network layers 
* these encapsulate the RFC 1490 requirements as well as 
* deal with packet transmission and reception, working with
* the upper network layers 
  */
 
 static int dlci_header(struct sk_buff *skb, struct device *dev, 
                            unsigned short type, void *daddr, void *saddr, 
                            unsigned len)
 {
-   struct fradhdr    hdr;
+   struct frhdr      hdr;
    struct dlci_local *dlp;
    unsigned          hlen;
    char              *dest;
@@ -115,8 +120,8 @@ static int dlci_header(struct sk_buff *skb, struct device *dev,
    switch(type)
    {
       case ETH_P_IP:
-         hdr.pad = FRAD_P_IP;
-         hlen = sizeof(hdr.control) + sizeof(hdr.pad);
+         hdr.IP_NLPID = FRAD_P_IP;
+         hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
          break;
 
       /* feel free to add other types, if necessary */
@@ -142,11 +147,11 @@ static int dlci_header(struct sk_buff *skb, struct device *dev,
 static void dlci_receive(struct sk_buff *skb, struct device *dev)
 {
    struct dlci_local *dlp;
-   struct fradhdr    *hdr;
+   struct frhdr      *hdr;
    int               process, header;
 
    dlp = dev->priv;
-   hdr = (struct fradhdr *) skb->data;
+   hdr = (struct frhdr *) skb->data;
    process = 0;
    header = 0;
    skb->dev = dev;
@@ -157,7 +162,7 @@ static void dlci_receive(struct sk_buff *skb, struct device *dev)
       dlp->stats.rx_errors++;
    }
    else
-      switch(hdr->pad)
+      switch(hdr->IP_NLPID)
       {
          case FRAD_P_PADDING:
             if (hdr->NLPID != FRAD_P_SNAP)
@@ -175,13 +180,13 @@ static void dlci_receive(struct sk_buff *skb, struct device *dev)
             }
 
             /* at this point, it's an EtherType frame */
-            header = sizeof(struct fradhdr);
+            header = sizeof(struct frhdr);
             skb->protocol = htons(hdr->PID);
             process = 1;
             break;
 
          case FRAD_P_IP:
-            header = sizeof(hdr->control) + sizeof(hdr->pad);
+            header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
             skb->protocol = htons(ETH_P_IP);
             process = 1;
             break;
@@ -230,14 +235,25 @@ static int dlci_transmit(struct sk_buff *skb, struct device *dev)
       printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
    else
    {
-      ret = dlp->slave->hard_start_xmit(skb, dlp->slave); 
-      if (ret)
-         dlp->stats.tx_errors++;
-      else 
-         dlp->stats.tx_packets++;
+      ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
+      switch (ret)
+      {
+         case DLCI_RET_OK:
+            dlp->stats.tx_packets++;
+            break;
 
-      /* per Alan Cox, always return 0, let the slave free the packet */
+         case DLCI_RET_ERR:
+            dlp->stats.tx_errors++;
+            break;
+
+         case DLCI_RET_DROP:
+            dlp->stats.tx_dropped++;
+            break;
+      }
+
+      /* Alan Cox recommends always returning 0, and always freeing the packet */
       ret = 0;
+      dev_kfree_skb(skb, FREE_WRITE);
       dev->tbusy = 0;
    }
 
@@ -257,6 +273,10 @@ int dlci_add(struct dlci_add *new)
    if (err)
       return(err);
 
+   err = verify_area(VERIFY_WRITE, new, sizeof(*new));
+   if (err)
+      return(err);
+
    memcpy_fromfs(&dlci, new, sizeof(dlci));
 
    /* validate slave device */
@@ -293,7 +313,7 @@ int dlci_add(struct dlci_add *new)
       return(-ENOMEM);
 
    memset(master, 0, sizeof(*master));
-   master->name = kmalloc(strlen(buf), GFP_KERNEL);
+   master->name = kmalloc(strlen(buf) + 1, GFP_KERNEL);
 
    if (!master->name)
    {
@@ -502,6 +522,7 @@ static int dlci_close(struct device *dev)
    err = (*flp->deactivate)(dlp->slave, dev);
 
    dev->start = 0;
+   dev->tbusy = 1;
 
    return 0;
 }
@@ -540,14 +561,25 @@ int dlci_init(struct device *dev)
 
    dev->type            = ARPHRD_DLCI;
    dev->family          = AF_INET;
-   dev->hard_header_len = sizeof(struct fradhdr);
+   dev->hard_header_len = sizeof(struct frhdr);
    dev->pa_alen         = sizeof(unsigned long);
-
+   dev->addr_len        = sizeof(short);
    memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
 
+   dev->pa_addr         = 0;
+   dev->pa_dstaddr      = 0;
+   dev->pa_brdaddr      = 0;
+   dev->pa_mask         = 0;
+
    for (i = 0; i < DEV_NUMBUFFS; i++) 
       skb_queue_head_init(&dev->buffs[i]);
 
+   if (strcmp(dev->name, devname) == 0)
+   {
+      dev->type = 0xFFFF;
+      dev->family = AF_UNSPEC;
+   }
+
    return(0);
 }
 
@@ -567,7 +599,7 @@ int dlci_setup(void)
 }
 
 #ifdef MODULE
-static struct device dlci = {"dlci", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, dlci_init, };
+static struct device dlci = {devname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, dlci_init, };
 
 int init_module(void)
 {
@@ -577,32 +609,7 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-   struct dlci_local   *dlp;
-   struct frad_local   *flp;
-   int                 i;
-
    unregister_netdev(&dlci);
-
-   for(i=0;i<CONFIG_DLCI_COUNT;i++)
-      if (open_dev[i])
-      {
-         dlp = open_dev[i]->priv;
-         flp = open_dev[i]->slave->priv;
-
-         if (open_dev[i]->start)
-         {
-            if (flp->deactivate)
-               (*flp->deactivate)(open_dev[i]->slave, open_dev[i]);
-            open_dev[i]->start = 0;
-         }
-
-         (*flp->deassoc)(open_dev[i]->slave, open_dev[i]);
-         kfree(open_dev[i]->priv);
-         kfree(open_dev[i]->name);
-         kfree(open_dev[i]);
-         open_dev[i] = NULL;
-      }
-
    if (dlci.priv)
       kfree(dlci.priv);
 }
index 4e9b7173a39c4e082301b248879774d0c424ed86..0d6a01df11584bed33c2720d366b70630b2e4cc7 100644 (file)
@@ -1,8 +1,8 @@
 /* eepro.c: Intel EtherExpress Pro/10 device driver for Linux. */
 /*
-       Written 1994, 1995 by Bao C. Ha.
+       Written 1994, 1995,1996 by Bao C. Ha.
 
-       Copyright (C) 1994, 1995 by Bao C. Ha.
+       Copyright (C) 1994, 1995,1996 by Bao C. Ha.
 
        This software may be used and distributed
        according to the terms of the GNU Public License,
        If you have a problem of not detecting the 82595 during a
        reboot (warm reset), disable the FLASH memory should fix it.
        This is a compatibility hardware problem.
-       
+
        Versions:
 
+       0.08    Implement 32-bit I/O for the 82595TX and 82595FX
+               based lan cards.  Disable full-duplex mode if TPE
+               is not used.  (BCH, 4/8/96)
+
        0.07a   Fix a stat report which counts every packet as a
                heart-beat failure. (BCH, 6/3/95)
 
@@ -52,7 +56,7 @@
 */
 
 static const char *version =
-       "eepro.c: v0.07a 6/5/95 Bao C. Ha (bao@saigon.async.com)\n";
+       "eepro.c: v0.08 4/8/96 Bao C. Ha (bao.ha@srs.gov)\n";
 
 #include <linux/module.h>
 
@@ -69,8 +73,9 @@ static const char *version =
        provided by Donald Becker.  I also borrowed the EEPROM routine from
        Donald Becker's 82586 driver.
 
-       Datasheet for the Intel 82595. It provides just enough info that 
-       the casual reader might think that it documents the i82595.
+       Datasheet for the Intel 82595 (including the TX and FX version). It 
+       provides just enough info that the casual reader might think that it 
+       documents the i82595.
 
        The User Manual for the 82595.  It provides a lot of the missing
        information.
@@ -112,6 +117,11 @@ static unsigned int net_debug = NET_DEBUG;
 /* The number of low I/O ports used by the ethercard. */
 #define EEPRO_IO_EXTENT        16
 
+/* Different 82595 chips */
+#define        LAN595          0
+#define        LAN595TX        1
+#define        LAN595FX        2
+
 /* Information that need to be kept for each board. */
 struct eepro_local {
        struct enet_statistics stats;
@@ -121,6 +131,9 @@ struct eepro_local {
        unsigned tx_end;   /* end of the transmit chain (plus 1) */
        int eepro;      /* a flag, TRUE=1 for the EtherExpress Pro/10,
                           FALSE = 0 for other 82595-based lan cards. */
+       int version;    /* a flag to indicate if this is a TX or FX
+                                  version of the 82595 chip. */
+       int stepping;
 };
 
 /* The station (ethernet) address prefix, used for IDing the board. */
@@ -219,11 +232,13 @@ allowing up to 8K worth of packets to be queued.
 #define        TX_MASK         0x04
 #define        EXEC_MASK       0x08
 #define        ALL_MASK        0x0f
+#define        IO_32_BIT       0x10
 #define        RCV_BAR         0x04    /* The following are word (16-bit) registers */
 #define        RCV_STOP        0x06
 #define        XMT_BAR         0x0a
 #define        HOST_ADDRESS_REG        0x0c
 #define        IO_PORT         0x0e
+#define        IO_PORT_32_BIT  0x0c
 
 /* Bank 1 registers */
 #define        REG1    0x01
@@ -245,6 +260,9 @@ allowing up to 8K worth of packets to be queued.
 #define        REG3            0x03
 #define        TPE_BIT         0x04
 #define        BNC_BIT         0x20
+#define        REG13           0x0d
+#define        FDX             0x00
+#define        A_N_ENABLE      0x02
        
 #define        I_ADD_REG0      0x04
 #define        I_ADD_REG1      0x05
@@ -497,7 +515,7 @@ static int  eepro_grab_irq(struct device *dev)
 static int
 eepro_open(struct device *dev)
 {
-       unsigned short temp_reg;
+       unsigned short temp_reg, old8, old9;
        int i, ioaddr = dev->base_addr;
        struct eepro_local *lp = (struct eepro_local *)dev->priv;
 
@@ -524,6 +542,12 @@ eepro_open(struct device *dev)
 
        outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
        temp_reg = inb(ioaddr + EEPROM_REG);
+
+       lp->stepping = temp_reg >> 5;   /* Get the stepping number of the 595 */
+       
+       if (net_debug > 3)
+               printk("The stepping of the 82595 is %d\n", lp->stepping);
+
        if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
                outb(temp_reg & 0xef, ioaddr + EEPROM_REG);
        for (i=0; i < 6; i++) 
@@ -569,6 +593,40 @@ eepro_open(struct device *dev)
 
        /* Initialize XMT */
        outw(XMT_LOWER_LIMIT << 8, ioaddr + XMT_BAR); 
+
+       /* Check for the i82595TX and i82595FX */
+       old8 = inb(ioaddr + 8);
+       outb(~old8, ioaddr + 8);
+       if ((temp_reg = inb(ioaddr + 8)) == old8) {
+               if (net_debug > 3)
+                       printk("i82595 detected!\n");
+               lp->version = LAN595;
+       }
+       else {
+               lp->version = LAN595TX;
+               outb(old8, ioaddr + 8);
+               old9 = inb(ioaddr + 9);
+               outb(~old9, ioaddr + 9);
+               if ((temp_reg = inb(ioaddr + 9)) == ~old9) {
+                       enum iftype { AUI=0, BNC=1, TPE=2 };
+                       if (net_debug > 3)
+                               printk("i82595FX detected!\n");
+                       lp->version = LAN595FX;
+                       outb(old9, ioaddr + 9);
+                       if (dev->if_port != TPE) {      /* Hopefully, this will fix the
+                                                       problem of using Pentiums and
+                                                       pro/10 w/ BNC. */
+                               outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+                               temp_reg = inb(ioaddr + REG13);
+                               /* disable the full duplex mode since it is not
+                               applicable with the 10Base2 cable. */
+                               outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
+                               outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
+                       }
+               }
+               else if (net_debug > 3)
+                       printk("i82595TX detected!\n");
+       }
        
        outb(SEL_RESET_CMD, ioaddr);
        /* We are supposed to wait for 2 us after a SEL_RESET */
@@ -954,19 +1012,19 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                   service routines. */
                outb(ALL_MASK, ioaddr + INT_MASK_REG);
 
-               if (((((length + 1) >> 1) << 1) + 2*XMT_HEADER) 
+               if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) 
                        >= tx_available)   /* No space available ??? */
                        continue;
 
                last = lp->tx_end;
-               end = last + (((length + 1) >> 1) << 1) + XMT_HEADER;
+               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
 
                if (end >= RAM_SIZE) { /* the transmit buffer is wrapped around */
                        if ((RAM_SIZE - last) <= XMT_HEADER) {  
                        /* Arrrr!!!, must keep the xmt header together,
                          several days were lost to chase this one down. */
                                last = RCV_RAM;
-                               end = last + (((length + 1) >> 1) << 1) + XMT_HEADER;
+                               end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
                        }       
                        else end = RCV_RAM + (end - RAM_SIZE);
                }
@@ -976,7 +1034,15 @@ hardware_send_packet(struct device *dev, void *buf, short length)
                outw(0, ioaddr + IO_PORT);
                outw(end, ioaddr + IO_PORT);
                outw(length, ioaddr + IO_PORT);
-               outsw(ioaddr + IO_PORT, buf, (length + 1) >> 1);
+
+               if (lp->version == LAN595)
+                       outsw(ioaddr + IO_PORT, buf, (length + 3) >> 1);
+               else {  /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+                       unsigned short temp = inb(ioaddr + INT_MASK_REG);
+                       outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+                       outsl(ioaddr + IO_PORT_32_BIT, buf, (length + 3) >> 2);
+                       outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+               }
 
                if (lp->tx_start != lp->tx_end) { 
                        /* update the next address and the chain bit in the 
@@ -1046,7 +1112,7 @@ eepro_rx(struct device *dev)
                        struct sk_buff *skb;
 
                        rcv_size &= 0x3fff;
-                       skb = dev_alloc_skb(rcv_size+2);
+                       skb = dev_alloc_skb(rcv_size+5);
                        if (skb == NULL) {
                                printk("%s: Memory squeeze, dropping packet.\n", dev->name);
                                lp->stats.rx_dropped++;
@@ -1055,7 +1121,15 @@ eepro_rx(struct device *dev)
                        skb->dev = dev;
                        skb_reserve(skb,2);
 
-                       insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 1) >> 1);
+                       if (lp->version == LAN595)
+                               insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 3) >> 1);
+                       else {  /* LAN595TX or LAN595FX, capable of 32-bit I/O processing */
+                               unsigned short temp = inb(ioaddr + INT_MASK_REG);
+                               outb(temp | IO_32_BIT, ioaddr + INT_MASK_REG);
+                               insl(ioaddr+IO_PORT_32_BIT, skb_put(skb,rcv_size), (rcv_size + 3) >> 2);
+                               outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG);
+                       }
+
        
                        skb->protocol = eth_type_trans(skb,dev);        
                        netif_rx(skb);
diff --git a/drivers/net/wic.c b/drivers/net/wic.c
new file mode 100644 (file)
index 0000000..82a050e
--- /dev/null
@@ -0,0 +1,1454 @@
+/* $Id: wic.c,v 1.0 1995/02/11 10:26:05 hayes Exp $ */
+/* WIC: A parallel port "network" driver for Linux. */
+/* based on the plip network driver */
+
+char *version = "NET3 WIC version 0.9 hayes@netplumbing.com";
+
+/*
+  Sources:
+       Ideas and protocols came from Russ Nelson's <nelson@crynwr.com>
+       "parallel.asm" parallel port packet driver and from the plip.c
+       parallel networking linux driver from the 1.2.13 Linux
+       distribution.
+
+  The packet is encapsulated as if it were ethernet.
+
+*/
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/if_ether.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/lp.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_wic.h>
+
+#include <linux/tqueue.h>
+#include <linux/ioport.h>
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <string.h>
+
+#define NET_DEBUG 1
+/* Use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 1
+#endif
+unsigned int net_debug = NET_DEBUG;
+
+/* Connection time out = WIC_TRIGGER_WAIT * WIC_DELAY_UNIT usec */
+#define WIC_TRIGGER_WAIT        500
+
+/* Nibble time out = WIC_NIBBLE_WAIT * WIC_DELAY_UNIT usec */
+#define WIC_NIBBLE_WAIT        3000
+
+#define PAR_DATA(dev)          ((dev)->base_addr+0)
+#define PAR_STATUS(dev)                ((dev)->base_addr+1)
+#define PAR_CONTROL(dev)       ((dev)->base_addr+2)
+
+/* Bottom halfs */
+void wic_kick_bh(struct device *dev);
+void wic_bh(struct device *dev);
+
+/* Interrupt handler */
+void wic_interrupt(int irq, void *dev_ptr, struct pt_regs *regs);
+
+/* Functions for DEV methods */
+int wic_rebuild_header(void *buff, struct device *dev,
+                              unsigned long raddr, struct sk_buff *skb);
+int wic_tx_packet(struct sk_buff *skb, struct device *dev);
+int wic_open(struct device *dev);
+int wic_close(struct device *dev);
+struct enet_statistics *wic_get_stats(struct device *dev);
+int wic_config(struct device *dev, struct ifmap *map);
+int wic_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+int send_cmd(struct device *dev, unsigned char *cmd, char len);
+int recv_cmd_resp(struct device *dev, unsigned char *cmd);
+int send_byte(struct device *dev, unsigned char c);
+int get_byte(struct device *dev, unsigned char *c);
+int ack_resp(struct device *dev);
+int check_bfr(struct device *dev);
+void wic_reset(struct device *dev);
+void wic_set_multicast_list(struct device *dev, int num_addrs, 
+               void *addrs);
+
+#define LOOPCNT 30000  
+unsigned char tog = 3;
+unsigned char save = 0;
+
+enum wic_connection_state {
+       WIC_CN_NONE=0,
+       WIC_CN_RECEIVE,
+       WIC_CN_SEND,
+       WIC_CN_CLOSING,
+       WIC_CN_ERROR
+};
+
+enum wic_packet_state {
+       WIC_PK_DONE=0,
+       WIC_PK_TRIGGER,
+       WIC_PK_LENGTH_LSB,
+       WIC_PK_LENGTH_MSB,
+       WIC_PK_DATA,
+       WIC_PK_CHECKSUM
+};
+
+enum wic_nibble_state {
+       WIC_NB_BEGIN,
+       WIC_NB_1,
+       WIC_NB_2,
+};
+
+struct wic_local {
+       enum wic_packet_state state;
+       enum wic_nibble_state nibble;
+       union {
+               struct {
+#if defined(LITTLE_ENDIAN)
+                       unsigned char lsb;
+                       unsigned char msb;
+#elif defined(BIG_ENDIAN)
+                       unsigned char msb;
+                       unsigned char lsb;
+#else
+#error "Please fix the endianness defines in <asm/byteorder.h>"
+#endif                                         
+               } b;
+               unsigned short h;
+       } length;
+       unsigned short byte;
+       unsigned char  checksum;
+       unsigned char  data;
+       struct sk_buff *skb;
+};
+
+struct net_local {
+       struct enet_statistics enet_stats;
+       struct tq_struct immediate;
+       struct tq_struct deferred;
+       struct wic_local snd_data;
+       struct wic_local rcv_data;
+       unsigned long  trigger;
+       unsigned long  nibble;
+       enum wic_connection_state connection;
+       unsigned short timeout_count;
+       char is_deferred;
+       int (*orig_rebuild_header)(void *eth, struct device *dev,
+                                  unsigned long raddr, struct sk_buff *skb);
+};
+
+/* Entry point of WIC driver.
+   Probe the hardware, and register/initialize the driver. */
+int
+wic_init(struct device *dev)
+{
+       struct net_local *nl;
+       struct wicconf wc;
+       int i;
+
+       /* Check region before the probe */
+       if (check_region(PAR_DATA(dev), 3) < 0)
+               return -ENODEV;
+       
+       /* Check that there is something at base_addr. */
+       outb(0, PAR_DATA(dev));
+       udelay(1000);
+       if (inb(PAR_DATA(dev)) != 0)
+               return -ENODEV;
+
+       printk("%s\n",version);
+       printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
+       if (dev->irq) {
+               printk("using assigned IRQ %d.\n", dev->irq);
+       } else {
+               int irq = 0;
+#ifdef MODULE
+               /* dev->irq==0 means autoprobe, but we don't try to do so
+                  with module.  We can change it by ifconfig */
+#else
+               unsigned int irqs = probe_irq_on();
+
+               outb(0x00, PAR_CONTROL(dev));
+               udelay(1000);
+               udelay(1000);
+               irq = probe_irq_off(irqs);
+#endif
+               if (irq > 0) {
+                       dev->irq = irq;
+                       printk("using probed IRQ %d.\n", dev->irq);
+               } else
+                       printk("failed to detect IRQ(%d) --"
+                              " Please set IRQ by ifconfig.\n", irq);
+       }
+
+       request_region(PAR_DATA(dev), 3, dev->name);
+
+       /* Fill in the generic fields of the device structure. */
+       ether_setup(dev);
+
+       /* Then, override parts of it */
+       dev->hard_start_xmit    = wic_tx_packet;
+       dev->open               = wic_open;
+       dev->stop               = wic_close;
+       dev->get_stats          = wic_get_stats;
+       dev->set_config         = wic_config;
+       dev->do_ioctl           = wic_ioctl;
+       dev->mtu                = 1514;
+       dev->set_multicast_list = wic_set_multicast_list;
+       dev->flags              = IFF_BROADCAST | IFF_RUNNING | IFF_NOTRAILERS;
+
+       /* get the MAC address from the controller */
+       wc.len = 1;
+       wc.pcmd = WIC_GETNET;
+       check_bfr(dev);
+       send_cmd(dev, (unsigned char *)&wc, 1);
+       wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
+       while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
+               wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
+       
+       printk("%s:MAC address: ",dev->name);   
+       for (i=0; i < ETH_ALEN ; i++) {
+               dev->dev_addr[i] = wc.data[i];
+               printk("%2x ",dev->dev_addr[i]);
+       }
+       printk("\n");
+
+       /* Set the private structure */
+       dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
+       if (dev->priv == NULL)
+               return EAGAIN;
+       memset(dev->priv, 0, sizeof(struct net_local));
+       nl = (struct net_local *) dev->priv;
+
+       nl->orig_rebuild_header = dev->rebuild_header;
+       dev->rebuild_header     = wic_rebuild_header;
+
+       /* Initialize constants */
+       nl->trigger     = WIC_TRIGGER_WAIT;
+       nl->nibble      = WIC_NIBBLE_WAIT;
+
+       /* Initialize task queue structures */
+       nl->immediate.next = &tq_last;
+       nl->immediate.sync = 0;
+       nl->immediate.routine = (void *)(void *)wic_bh;
+       nl->immediate.data = dev;
+
+       nl->deferred.next = &tq_last;
+       nl->deferred.sync = 0;
+       nl->deferred.routine = (void *)(void *)wic_kick_bh;
+       nl->deferred.data = dev;
+
+       return 0;
+}
+
+/* Bottom half handler for the delayed request.
+   This routine is kicked by do_timer().
+   Request `wic_bh' to be invoked. */
+void
+wic_kick_bh(struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+
+       if (nl->is_deferred) {
+               queue_task(&nl->immediate, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }
+}
+
+/* Forward declarations of internal routines */
+int wic_none(struct device *, struct net_local *,
+                    struct wic_local *, struct wic_local *);
+int wic_receive_packet(struct device *, struct net_local *,
+                              struct wic_local *, struct wic_local *);
+int wic_send_packet(struct device *, struct net_local *,
+                           struct wic_local *, struct wic_local *);
+int wic_connection_close(struct device *, struct net_local *,
+                                struct wic_local *, struct wic_local *);
+int wic_error(struct device *, struct net_local *,
+                     struct wic_local *, struct wic_local *);
+int wic_bh_timeout_error(struct device *dev, struct net_local *nl,
+                                struct wic_local *snd,
+                                struct wic_local *rcv,
+                                int error);
+
+#define OK        0
+#define TIMEOUT   1
+#define ERROR     2
+
+typedef int (*wic_func)(struct device *dev, struct net_local *nl,
+                        struct wic_local *snd, struct wic_local *rcv);
+
+wic_func connection_state_table[] =
+{
+       wic_none,
+       wic_receive_packet,
+       wic_send_packet,
+       wic_connection_close,
+       wic_error
+};
+
+void 
+wic_set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+       struct wicconf wc;
+       struct wic_net *wn;
+       
+       disable_irq(dev->irq);
+       save &= 0xef; /* disable */
+       outb(save, PAR_CONTROL(dev));
+       
+       wc.len = 1;
+       wc.pcmd = WIC_GETNET;
+       check_bfr(dev);
+       tog = 3;
+       send_cmd(dev, (unsigned char *)&wc, 1);
+       wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
+       while ((wc.len == 1) && (wc.data[0] == 0x7)) /* controller int */
+               wc.len = recv_cmd_resp(dev, (unsigned char *)&wc.data);
+       wn = (struct wic_net *)&wc.data;
+       switch (num_addrs) {
+               case -1:        /* promiscuous mode */
+                       wn->mode |= (NET_MODE_ME | NET_MODE_BCAST | 
+                               NET_MODE_MCAST | NET_MODE_PROM);
+       printk("%s: Setting promiscuous mode\n", dev->name);
+                       break;
+               default:        /* my address and bcast addresses */
+                       wn->mode &= ~(NET_MODE_PROM | NET_MODE_MCAST);
+                       wn->mode |= (NET_MODE_ME | NET_MODE_BCAST);
+                       /* break; */
+       }
+       wc.len = 23;
+       wc.pcmd = WIC_SETNET;
+       check_bfr(dev);
+       tog = 3;
+       send_cmd(dev, (unsigned char *)&wc, wc.len);
+
+       save |= 0x10; /* enable */
+       outb(save, PAR_CONTROL(dev));
+       enable_irq(dev->irq);
+       return;
+}
+
+/* Bottom half handler of WIC. */
+void
+wic_bh(struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct wic_local *snd = &nl->snd_data;
+       struct wic_local *rcv = &nl->rcv_data;
+       wic_func f;
+       int r;
+
+       nl->is_deferred = 0;
+       f = connection_state_table[nl->connection];
+       if ((r = (*f)(dev, nl, snd, rcv)) != OK
+           && (r = wic_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
+               nl->is_deferred = 1;
+               queue_task(&nl->deferred, &tq_timer);
+       }
+}
+
+int
+wic_bh_timeout_error(struct device *dev, struct net_local *nl,
+                     struct wic_local *snd, struct wic_local *rcv,
+                     int error)
+{
+       unsigned char c0;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (nl->connection == WIC_CN_SEND) {
+
+               if (error != ERROR) { /* Timeout */
+                       nl->timeout_count++;
+                       if ((snd->state == WIC_PK_TRIGGER
+                            && nl->timeout_count <= 10)
+                           || nl->timeout_count <= 3) {
+                               restore_flags(flags);
+                               /* Try again later */
+                               return TIMEOUT;
+                       }
+                       c0 = inb(PAR_STATUS(dev));
+                       printk("%s: transmit timeout(%d,%02x)\n",
+                              dev->name, snd->state, c0);
+               }
+               nl->enet_stats.tx_errors++;
+               nl->enet_stats.tx_aborted_errors++;
+       } else if (nl->connection == WIC_CN_RECEIVE) {
+               if (rcv->state == WIC_PK_TRIGGER) {
+                       /* Transmission was interrupted. */
+                       restore_flags(flags);
+                       return OK;
+               }
+               if (error != ERROR) { /* Timeout */
+                       if (++nl->timeout_count <= 3) {
+                               restore_flags(flags);
+                               /* Try again later */
+                               return TIMEOUT;
+                       }
+                       c0 = inb(PAR_STATUS(dev));
+                       printk("%s: receive timeout(%d,%02x)\n",
+                              dev->name, rcv->state, c0);
+               }
+               nl->enet_stats.rx_dropped++;
+       }
+       rcv->state = WIC_PK_DONE;
+       if (rcv->skb) {
+               rcv->skb->free = 1;
+               kfree_skb(rcv->skb, FREE_READ);
+               rcv->skb = NULL;
+       }
+       snd->state = WIC_PK_DONE;
+       if (snd->skb) {
+               snd->skb->free = 1;
+               dev_kfree_skb(snd->skb, FREE_WRITE);
+               snd->skb = NULL;
+       }
+#if (0)
+       disable_irq(dev->irq);
+       save &= 0xef; /* disable */
+       outb(save, PAR_CONTROL(dev));
+       dev->tbusy = 1;
+       outb(0x00, PAR_DATA(dev));
+#endif /* (0) */
+       nl->connection = WIC_CN_ERROR;
+       restore_flags(flags);
+
+       return TIMEOUT;
+}
+
+int
+wic_none(struct device *dev, struct net_local *nl,
+         struct wic_local *snd, struct wic_local *rcv)
+{
+       return OK;
+}
+
+/* WIC_RECEIVE --- receive a byte(two nibbles)
+   Returns OK on success, TIMEOUT on timeout */
+inline int
+wic_receive(unsigned short nibble_timeout, unsigned short status_addr,
+            enum wic_nibble_state *ns_p, unsigned char *data_p)
+{
+unsigned int cx;
+
+       cx = LOOPCNT;
+       while ((inb(status_addr) & 0x08) != ((tog<<3) & 0x08)) {
+               if (--cx == 0) {
+                       return TIMEOUT;
+               }
+       }
+       *data_p = inb(status_addr-1);
+       tog ^= 0x01;
+       outb(tog| save, status_addr+1);
+       return OK;
+}
+
+/* WIC_RECEIVE_PACKET --- receive a packet */
+int
+wic_receive_packet(struct device *dev, struct net_local *nl,
+                   struct wic_local *snd, struct wic_local *rcv)
+{
+       unsigned short status_addr = PAR_STATUS(dev);
+       unsigned short nibble_timeout = nl->nibble;
+       unsigned char *lbuf;
+       unsigned char junk;
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       switch (rcv->state) {
+       case WIC_PK_TRIGGER:
+               disable_irq(dev->irq);
+               save &= 0xef; /* disable */
+               outb(save, PAR_CONTROL(dev));
+               
+               dev->interrupt = 0;
+
+               tog &= 0xfe;
+               ack_resp(dev);
+               if (net_debug > 2)
+                       printk("%s: receive start\n", dev->name);
+               rcv->state = WIC_PK_LENGTH_LSB;
+               rcv->nibble = WIC_NB_BEGIN;
+
+       case WIC_PK_LENGTH_LSB:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_LENGTH_LSB\n", dev->name);
+               if (snd->state != WIC_PK_DONE) {
+                       if (wic_receive(nl->trigger, status_addr,
+                                        &rcv->nibble, &rcv->length.b.lsb)) {
+                               /* collision, here dev->tbusy == 1 */
+                               rcv->state = WIC_PK_DONE;
+                               nl->is_deferred = 1;
+                               nl->connection = WIC_CN_SEND;
+                               restore_flags(flags);
+                               queue_task(&nl->deferred, &tq_timer);
+                               save |= 0x10; /* enable */
+                               outb(save, PAR_CONTROL(dev));
+                               enable_irq(dev->irq);
+                               return OK;
+                       }
+               } else {
+                       if (wic_receive(nibble_timeout, status_addr,
+                                        &rcv->nibble, &rcv->length.b.lsb)) {
+                               restore_flags(flags);
+                               return TIMEOUT;
+                       }
+               }
+               rcv->state = WIC_PK_LENGTH_MSB;
+
+       case WIC_PK_LENGTH_MSB:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
+               if (wic_receive(nibble_timeout, status_addr,
+                                &rcv->nibble, &rcv->length.b.msb)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+               if (rcv->length.h > dev->mtu || rcv->length.h < 8) {
+                       printk("%s: bad packet size %d.\n", dev->name, rcv->length.h);
+                       restore_flags(flags);
+                       return ERROR;
+               }
+               /* Malloc up new buffer. */
+               rcv->skb = dev_alloc_skb(rcv->length.h);
+               if (rcv->skb == NULL) {
+                       printk("%s: Memory squeeze.\n", dev->name);
+                       restore_flags(flags);
+                       return ERROR;
+               }
+               skb_put(rcv->skb,rcv->length.h);
+               rcv->skb->dev = dev;
+               
+               rcv->state = WIC_PK_DATA;
+               rcv->byte = 0;
+               rcv->checksum = 0;
+               
+               /* sequence numbers */
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_SEQ\n", dev->name);
+               if (wic_receive(nibble_timeout, status_addr,
+                                &rcv->nibble, &junk)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+               if (wic_receive(nibble_timeout, status_addr,
+                                &rcv->nibble, &junk)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+
+       case WIC_PK_DATA:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_DATA: length %i\n", dev->name, 
+                               rcv->length.h);
+               lbuf = rcv->skb->data;
+               do {
+                       if (wic_receive(nibble_timeout, status_addr, 
+                                        &rcv->nibble, &lbuf[rcv->byte])) {
+                               restore_flags(flags);
+                               return TIMEOUT;
+                       }
+               } while (++rcv->byte < (rcv->length.h - 4));
+
+               /* receive pad byte */
+               if (rcv->length.h & 0x01)
+                       wic_receive(nibble_timeout, status_addr, 
+                                        &rcv->nibble, &lbuf[rcv->byte]);
+               
+               do {
+                       rcv->checksum += lbuf[--rcv->byte];
+               } while (rcv->byte);
+
+               rcv->state = WIC_PK_CHECKSUM;
+
+       case WIC_PK_CHECKSUM:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_CHECKSUM\n", dev->name);
+               if (wic_receive(nibble_timeout, status_addr,
+                                &rcv->nibble, &junk)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+               outb(0, PAR_DATA(dev));
+               rcv->state = WIC_PK_DONE;
+
+       case WIC_PK_DONE:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_DONE\n", dev->name);
+               /* Inform the upper layer for the arrival of a packet. */
+               netif_rx(rcv->skb);
+               nl->enet_stats.rx_packets++;
+               rcv->skb = NULL;
+               if (net_debug > 2)
+                       printk("%s: receive end\n", dev->name);
+
+               /* Close the connection. */
+               if (snd->state != WIC_PK_DONE) {
+                       nl->connection = WIC_CN_SEND;
+                       restore_flags(flags);
+                       queue_task(&nl->immediate, &tq_immediate);
+                       save |= 0x10; /* enable */
+                       outb(save, PAR_CONTROL(dev));
+                       enable_irq(dev->irq);
+                       return OK;
+               } else {
+                       nl->connection = WIC_CN_NONE;
+                       restore_flags(flags);
+                       save |= 0x10; /* enable */
+                       outb(save, PAR_CONTROL(dev));
+                       enable_irq(dev->irq);
+                       return OK;
+               }
+       }
+       restore_flags(flags);
+       return OK;
+}
+
+/* WIC_SEND --- send a byte (two nibbles) 
+   Returns OK on success, TIMEOUT when timeout    */
+inline int
+wic_send(unsigned short nibble_timeout, unsigned short data_addr,
+         enum wic_nibble_state *ns_p, unsigned char data)
+{
+unsigned int cx;
+
+       cx = LOOPCNT;
+       while ((inb(data_addr+1) & 0x80) == ((tog<<7) & 0x80)) {
+               if (--cx == 0) {
+                       return -TIMEOUT;
+               }
+       }
+       outb(data, data_addr);
+       outb(tog | save, data_addr+2);
+       tog ^= 0x01;
+       return OK;
+}
+
+/* WIC_SEND_PACKET --- send a packet */
+int
+wic_send_packet(struct device *dev, struct net_local *nl,
+                struct wic_local *snd, struct wic_local *rcv)
+{
+       unsigned short data_addr = PAR_DATA(dev);
+       unsigned short nibble_timeout = nl->nibble;
+       unsigned char *lbuf;
+       unsigned int cx;
+       unsigned int pad = 2;
+       unsigned long flags;
+
+       if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
+               printk("%s: send skb lost\n", dev->name);
+               snd->state = WIC_PK_DONE;
+               snd->skb = NULL;
+               save |= 0x10; /* enable */
+               outb(save, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+               return ERROR;
+       }
+
+       save_flags(flags);      
+       cli();
+       switch (snd->state) {
+       case WIC_PK_TRIGGER:
+       
+               if (nl->connection == WIC_CN_RECEIVE) {
+                       /* interrupted */
+                       nl->enet_stats.collisions++;
+                       restore_flags(flags);
+                       if (net_debug > 1)
+                               printk("%s: collision.\n", dev->name);
+                       save |= 0x10; /* enable */
+                       outb(save, PAR_CONTROL(dev));
+                       enable_irq(dev->irq);
+                       return OK;
+               }
+               
+               disable_irq(dev->irq);
+               save &= 0xef; /* disable */
+               outb(save, PAR_CONTROL(dev));
+               
+               /* interrupt controller */
+               tog = 3;
+               outb(0x06 | save, PAR_CONTROL(dev));
+                       
+               cx = LOOPCNT;
+               while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
+                       if (--cx == 0) {
+                               restore_flags(flags);
+                               return TIMEOUT;
+                       }
+                       if (cx == 10)
+                               outb(0x02, PAR_CONTROL(dev));
+               }
+               
+               if (net_debug > 2)
+                       printk("%s: send start\n", dev->name);
+               snd->state = WIC_PK_LENGTH_LSB;
+               snd->nibble = WIC_NB_BEGIN;
+               nl->timeout_count = 0;
+
+       case WIC_PK_LENGTH_LSB:
+               if (snd->length.h & 0x01)
+                       pad = 3;
+               else
+                       pad = 2;
+               snd->length.h += (4 + pad); /* len + seq + data + pad */
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_LENGTH_LSB: length = %i\n", 
+                               dev->name, snd->length.h);
+
+               if (wic_send(nibble_timeout, data_addr,
+                             &snd->nibble, snd->length.b.lsb)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+               snd->state = WIC_PK_LENGTH_MSB;
+
+       case WIC_PK_LENGTH_MSB:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_LENGTH_MSB\n", dev->name);
+               if (wic_send(nibble_timeout, data_addr,
+                             &snd->nibble, snd->length.b.msb)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+               snd->state = WIC_PK_DATA;
+               snd->byte = 0;
+               snd->checksum = 0;
+
+       case WIC_PK_DATA:
+               /* adjust length back to data only */
+               snd->length.h -= (4 + pad); /* len + seq + data + pad */
+               /* send 2 byte sequence number */
+               if (net_debug > 2)
+                       printk("%s: WIC_SEQ\n", dev->name);
+               if (wic_send(nibble_timeout, data_addr,
+                             &snd->nibble, 0)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }
+               if (wic_send(nibble_timeout, data_addr,
+                             &snd->nibble, 0)) {
+                       restore_flags(flags);
+                       return TIMEOUT;
+               }       
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_DATA\n", dev->name);
+
+               do {
+                       if (wic_send(nibble_timeout, data_addr,
+                                     &snd->nibble, lbuf[snd->byte])) {
+                               restore_flags(flags);
+                               return TIMEOUT;
+                       }
+               }
+               while (++snd->byte < snd->length.h);
+               
+               do
+                       snd->checksum += lbuf[--snd->byte];
+               while (snd->byte);
+
+               snd->state = WIC_PK_CHECKSUM;
+
+       case WIC_PK_CHECKSUM:
+               /* send pad bytes */
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_PAD: %i bytes\n", 
+                               dev->name, pad);
+               while(pad--)
+                       if (wic_send(nibble_timeout, data_addr,
+                               &snd->nibble, 0)) {
+                               restore_flags(flags);
+                               return TIMEOUT;
+                       }
+               dev_kfree_skb(snd->skb, FREE_WRITE);
+               nl->enet_stats.tx_packets++;
+               snd->state = WIC_PK_DONE;
+
+       case WIC_PK_DONE:
+               if (net_debug > 2)
+                       printk("%s: WIC_PK_DONE\n", dev->name);
+               /* Close the connection */
+               outb (0x00, PAR_DATA(dev));
+               outb(save, PAR_CONTROL(dev));
+               
+               snd->skb = NULL;
+               if (net_debug > 2)
+                       printk("%s: send end\n", dev->name);
+               nl->connection = WIC_CN_CLOSING;
+               nl->is_deferred = 1;
+               restore_flags(flags);
+               queue_task(&nl->deferred, &tq_timer);
+               save |= 0x10; /* enable */
+               outb(save, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+               return OK;
+       }
+       restore_flags(flags);
+       return OK;
+}
+
+int
+wic_connection_close(struct device *dev, struct net_local *nl,
+                     struct wic_local *snd, struct wic_local *rcv)
+{
+unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       if (nl->connection == WIC_CN_CLOSING) {
+               nl->connection = WIC_CN_NONE;
+               dev->tbusy = 0;
+               mark_bh(NET_BH);
+       }
+       restore_flags(flags);
+       return OK;
+}
+
+/* WIC_ERROR --- wait till other end settled */
+int
+wic_error(struct device *dev, struct net_local *nl,
+          struct wic_local *snd, struct wic_local *rcv)
+{
+       unsigned char status;
+
+       status = inb(PAR_STATUS(dev));
+       if ((status & 0xf8) == 0x80) {
+               if (net_debug > 2)
+                       printk("%s: reset interface.\n", dev->name);
+               nl->connection = WIC_CN_NONE;
+               dev->tbusy = 0;
+               dev->interrupt = 0;
+               save |= 0x10; /* enable */
+               outb(save, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+               mark_bh(NET_BH);
+       } else {
+               nl->is_deferred = 1;
+               queue_task(&nl->deferred, &tq_timer);
+       }
+
+       return OK;
+}
+
+/* Handle the parallel port interrupts. */
+void
+wic_interrupt(int irq, void *dev_ptr, struct pt_regs * regs)
+{
+       struct device *dev = (struct device *) irq2dev_map[irq];
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct wic_local *rcv = &nl->rcv_data;
+       unsigned long flags;
+
+       if (dev == NULL) {
+               printk ("wic_interrupt: irq %d for unknown device.\n", irq);
+               return;
+       }
+
+       if (dev->interrupt) {
+               return;
+       }
+
+       if (check_bfr(dev) < 0) {
+               return;
+       }
+       
+       dev->interrupt = 1;
+       if (net_debug > 3)
+               printk("%s: interrupt.\n", dev->name);
+
+       save_flags(flags);
+       cli();
+       switch (nl->connection) {
+       case WIC_CN_CLOSING:
+               dev->tbusy = 0;
+       case WIC_CN_NONE:
+       case WIC_CN_SEND:
+               dev->last_rx = jiffies;
+               rcv->state = WIC_PK_TRIGGER;
+               nl->connection = WIC_CN_RECEIVE;
+               nl->timeout_count = 0;
+               restore_flags(flags);
+               queue_task(&nl->immediate, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+               break;
+
+       case WIC_CN_RECEIVE:
+               printk("%s: receive interrupt when receiving packet\n", dev->name);
+               restore_flags(flags);
+               break;
+
+       case WIC_CN_ERROR:
+               printk("%s: receive interrupt in error state\n", dev->name);
+               restore_flags(flags);
+               break;
+       }
+}
+
+int
+wic_rebuild_header(void *buff, struct device *dev, unsigned long dst,
+                   struct sk_buff *skb)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct ethhdr *eth = (struct ethhdr *)buff;
+       int i;
+
+       if ((dev->flags & IFF_NOARP)==0)
+               return nl->orig_rebuild_header(buff, dev, dst, skb);
+
+       if (eth->h_proto != htons(ETH_P_IP)) {
+               printk("wic_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
+               memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+               return 0;
+       }
+
+       for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+               eth->h_dest[i] = 0xfc;
+       memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
+       return 0;
+}
+
+int
+wic_tx_packet(struct sk_buff *skb, struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct wic_local *snd = &nl->snd_data;
+       unsigned long flags;
+
+       if (dev->tbusy)
+               return 1;
+
+       /* If some higher layer thinks we've missed an tx-done interrupt
+          we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+          itself. */
+       if (skb == NULL) {
+               dev_tint(dev);
+               return 0;
+       }
+
+       if (set_bit(0, (void*)&dev->tbusy) != 0) {
+               printk("%s: Transmitter access conflict.\n", dev->name);
+               return 1;
+       }
+
+       if (skb->len > dev->mtu) {
+               printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
+               dev->tbusy = 0;
+               return 0;
+       }
+
+       if (net_debug > 2)
+               printk("%s: send request\n", dev->name);
+
+       save_flags(flags);
+       cli();
+       dev->trans_start = jiffies;
+       snd->skb = skb;
+       snd->length.h = skb->len;
+       snd->state = WIC_PK_TRIGGER;
+       if (nl->connection == WIC_CN_NONE) {
+               nl->connection = WIC_CN_SEND;
+               nl->timeout_count = 0;
+       }
+       restore_flags(flags);
+       queue_task(&nl->immediate, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+
+       return 0;
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine gets exclusive access to the parallel port by allocating
+   its IRQ line.
+ */
+int
+wic_open(struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       unsigned long flags;
+
+       if (dev->irq == 0) {
+               printk("%s: IRQ is not set.  Please set it by ifconfig.\n", dev->name);
+               return -EAGAIN;
+       }
+       save_flags(flags);
+       cli();
+       check_bfr(dev);
+       if (request_irq(dev->irq , wic_interrupt, 0, dev->name, NULL) != 0) {
+               sti();
+               printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
+               return -EAGAIN;
+       }
+       irq2dev_map[dev->irq] = dev;
+       restore_flags(flags);
+
+       save |= 0x10; /* enable */
+       outb(save, PAR_CONTROL(dev));
+       /* Initialize the state machine. */
+       nl->rcv_data.state = nl->snd_data.state = WIC_PK_DONE;
+       nl->rcv_data.skb = nl->snd_data.skb = NULL;
+       nl->connection = WIC_CN_NONE;
+       nl->is_deferred = 0;
+
+       dev->interrupt = 0;
+       dev->start = 1;
+       dev->tbusy = 0;
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+/* The inverse routine to wic_open (). */
+int
+wic_close(struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct wic_local *snd = &nl->snd_data;
+       struct wic_local *rcv = &nl->rcv_data;
+
+       dev->tbusy = 1;
+       dev->start = 0;
+       cli();
+       free_irq(dev->irq, NULL);
+       irq2dev_map[dev->irq] = NULL;
+       nl->is_deferred = 0;
+       nl->connection = WIC_CN_NONE;
+       sti();
+       outb(0x00, PAR_DATA(dev));
+
+       snd->state = WIC_PK_DONE;
+       if (snd->skb) {
+               snd->skb->free = 1;
+               dev_kfree_skb(snd->skb, FREE_WRITE);
+               snd->skb = NULL;
+       }
+       rcv->state = WIC_PK_DONE;
+       if (rcv->skb) {
+               rcv->skb->free = 1;
+               kfree_skb(rcv->skb, FREE_READ);
+               rcv->skb = NULL;
+       }
+
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+struct enet_statistics *
+wic_get_stats(struct device *dev)
+{
+       struct net_local *nl = (struct net_local *)dev->priv;
+       struct enet_statistics *r = &nl->enet_stats;
+
+       return r;
+}
+
+int
+wic_config(struct device *dev, struct ifmap *map)
+{
+       if (dev->flags & IFF_UP)
+               return -EBUSY;
+
+       if (map->base_addr != (unsigned long)-1
+           && map->base_addr != dev->base_addr)
+               printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
+
+       if (map->irq != (unsigned char)-1)
+               dev->irq = map->irq;
+       return 0;
+}
+
+int
+wic_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+       struct wicconf wc;
+       int err;
+       char len = 0;
+       unsigned long flags;
+
+       err=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(struct wicconf));
+       if (err)
+               return err;
+       memcpy_fromfs(&wc, rq->ifr_data, sizeof(struct wicconf));
+       switch(wc.pcmd) {
+               case WIC_AYT:
+                       strcpy(wc.data, version);
+                       wc.len = strlen(wc.data);
+                       memcpy_tofs(rq->ifr_data, &wc, sizeof(struct wicconf));
+                       /* return 0; */
+                       break;
+               case WIC_RESET:
+                       wic_reset(dev);
+                       return(0);
+                       /* break; */
+               case WIC_SETSN:
+                       len = 17;
+                       break;
+               case WIC_SETPS:
+                       len = 3;
+                       break;
+               case WIC_SETAF:
+               case WIC_SETGPF:
+                       len = 2;
+                       break;
+               case WIC_SETNET:
+                       len = 23;
+                       break;
+               case WIC_SETSYS:
+                       len = 15;
+                       break;
+               case WIC_GETVERH:
+               case WIC_GETNL:
+               case WIC_GETSN:
+               case WIC_CLRSTATS:
+               case WIC_GETSTATS:
+               case WIC_GETVERM:
+               case WIC_GETNET:
+               case WIC_GETSYS:
+                       len = 1;
+                       break;  
+               default:
+                       return -EOPNOTSUPP;
+       }
+
+       /* Wait for lock to free */
+       while (set_bit(0, (void *)&dev->tbusy) != 0); 
+       save_flags(flags);
+       cli();
+
+       disable_irq(dev->irq);
+       save &= 0xef; /* disable */
+       outb(save, PAR_CONTROL(dev));
+       err = check_bfr(dev);
+       tog = 3;
+       err = send_cmd(dev, (unsigned char *)&wc, len);
+
+       if (wc.pcmd & 0x40) {   /* response */
+               len = (char)recv_cmd_resp(dev, wc.data);
+               while ((len == 1) && (wc.data[0] == 0x7)) { /* controller int */
+                       len = (char)recv_cmd_resp(dev, wc.data);
+               }
+               save |= 0x10; /* enable */
+               outb(save, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+               wc.len = (len <0) ? 0 : len;
+               memcpy_tofs(rq->ifr_data, &wc, sizeof(struct wicconf));
+       } else {
+               save |= 0x10; /* enable */
+               outb(save, PAR_CONTROL(dev));
+               enable_irq(dev->irq);
+       }
+       restore_flags(flags);
+
+       outb(0, PAR_DATA(dev));
+       dev->tbusy = 0;
+       return 0;
+}
+
+int
+get_byte(struct device *dev, unsigned char *c)
+{
+unsigned int cx;
+
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0x08) != ((tog << 3)&0x08)) {
+               if (--cx == 0) {
+                       return(-TIMEOUT);
+               }
+       }
+       /* receive a byte of data */
+       *c = inb(PAR_DATA(dev));
+       tog ^= 0x01;
+       /* ack reception of data */
+       outb(tog| save, PAR_CONTROL(dev));
+       return OK;
+}
+
+int
+ack_resp(struct device *dev)
+{
+unsigned int cx;
+       
+       outb(save | 0x27, PAR_CONTROL(dev));
+
+       /* wait for controller to remove interrupt [Ack(low), Busy(low)] */
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0xc0) != 0x80) {
+               if (--cx == 0) {
+                       return -TIMEOUT;
+               }
+       }
+       
+       outb(save | 0x22, PAR_CONTROL(dev));
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0x08) == 0x08) {
+               if (--cx == 0) {
+                       return TIMEOUT;
+               }
+       }
+       tog |= 0x20;
+       tog &= 0xfe;
+       return OK;
+}
+
+void
+wic_reset(struct device *dev)
+{
+unsigned char stat;
+
+       stat = inb(PAR_CONTROL(dev));
+       outb(0, PAR_DATA(dev));
+       outb(stat | 0x08, PAR_CONTROL(dev));
+       outb(stat & 0xf7, PAR_CONTROL(dev));
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       tog = 3;
+       save = 0;
+       return;
+}
+
+int
+check_bfr(struct device *dev)
+{
+unsigned char c0, l;
+
+       if ((inb(PAR_STATUS(dev)) & 0xc8) == 0x48) {
+               save |= 0x80;
+               outb(0x23| save, PAR_CONTROL(dev));
+               ack_resp(dev);
+               get_byte(dev, &l);      /* len */
+               while (l--) {
+                       get_byte(dev, &c0);
+               }
+               get_byte(dev, &c0);
+               save &=0x7f;
+               outb(0, PAR_DATA(dev));
+               return -l;
+       } else
+       return (0);
+}
+
+
+int
+recv_cmd_resp(struct device *dev, unsigned char *buf)
+{
+unsigned char cksum = 0;
+int err;
+unsigned char c0 = 0;
+int len;
+int savelen;
+unsigned int cx;
+int i;
+
+       tog &= 0xfe;
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0xc8) != 0x48) {
+               if (--cx == 0) {
+                       /* clear Busy */
+                       outb(0, PAR_DATA(dev));
+                       printk("rcv_cmd_resp: timeout\n");
+                       return -TIMEOUT;
+               }
+       }
+       
+       /* acknowledge the interrupt */
+       i = ack_resp(dev);
+
+       /* get length */
+       err = get_byte(dev, &c0);
+       if (err < 0) {
+               printk("get_byte1: failed\n");
+               return(err);
+       }
+       len = c0;
+       savelen = len;
+
+       /* get data */
+       while(len--) {
+               err = get_byte(dev, &c0);
+               if (err < 0) {
+                       printk("get_byte2: failed\n");
+                       return(err);
+               }
+               outb(0, PAR_DATA(dev)); 
+               *buf = c0;
+               cksum += c0;
+               buf++;
+       }       
+       /* get cksum */
+       err = get_byte(dev, &c0);
+       if (err < 0) {
+               printk("get_byte3: failed\n");
+               return(err);
+       }
+       if (cksum != c0) {
+               printk("cksum failed\n");
+               return(-3);
+       }
+       /* get trailing byte, if any... */
+       get_byte(dev, &c0);
+       return(savelen);
+}      
+
+int
+send_byte(struct device *dev, unsigned char c)
+{
+unsigned int cx;
+
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog<<7) & 0x80)) {
+               if (--cx == 0) {
+                       return(-TIMEOUT);
+               }
+       }
+       outb(c, PAR_DATA(dev));
+       outb(save |tog, PAR_CONTROL(dev));
+       tog ^= 0x01;
+       return OK;
+}
+
+
+int
+send_cmd(struct device *dev, unsigned char *cmd, char len)
+{
+unsigned char cksum = 0;
+int err = 0;
+unsigned int cx;
+
+       /* interrupt controller */
+       outb(save | 0x04, PAR_CONTROL(dev));
+       /* wait for ACK */
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0xe8) != 0xc0) {
+               if (--cx == 0) 
+                       return -TIMEOUT;
+               if (cx == 10)
+                       outb(0x02, PAR_CONTROL(dev));
+       }
+       /* cmd coming... */
+       outb(save | 0x02, PAR_CONTROL(dev));
+       /* send length byte */
+       err = send_byte(dev, (unsigned char)len);
+       
+       /* send data */
+       while (len--) {
+               err = send_byte(dev, *cmd);     
+               if (err < 0) {
+                       return err;
+               }
+               cksum += *cmd;
+               cmd++;
+       }
+       
+       /* send cksum byte */
+       err = send_byte(dev, cksum);    
+       if (err < 0)
+               return err;
+
+       cx = LOOPCNT;
+       while ((inb(PAR_STATUS(dev)) & 0x80) == ((tog <<7)&0x80)) {
+               if (--cx == 0) 
+                       return -TIMEOUT;
+       }
+       save |= 0x80;
+       outb(save | 0x23, PAR_CONTROL(dev));
+       outb(0, PAR_DATA(dev));
+       return OK;      
+}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+struct device dev_wic0 = 
+{
+       "wic0" /*"wic"*/,
+       0, 0, 0, 0,             /* memory */
+       0x3BC, 5,               /* base, irq */
+       0, 0, 0, NULL, wic_init 
+};
+
+struct device dev_wic1 = 
+{
+       "wic1" /*"wic"*/,
+       0, 0, 0, 0,             /* memory */
+       0x378, 7,               /* base, irq */
+       0, 0, 0, NULL, wic_init 
+};
+
+struct device dev_wic2 = 
+{
+       "wic2" /*"wic"*/,
+       0, 0, 0, 0,             /* memory */
+       0x278, 2,               /* base, irq */
+       0, 0, 0, NULL, wic_init 
+};
+
+int
+init_module(void)
+{
+       int devices=0;
+
+       if (register_netdev(&dev_wic0) != 0)
+               devices++;
+       if (register_netdev(&dev_wic1) != 0)
+               devices++;
+       if (register_netdev(&dev_wic2) != 0)
+               devices++;
+       if (devices == 0)
+               return -EIO;
+       return 0;
+}
+
+void
+cleanup_module(void)
+{
+       if (dev_wic0.priv) {
+               unregister_netdev(&dev_wic0);
+               release_region(PAR_DATA(&dev_wic0), 3);
+               kfree_s(dev_wic0.priv, sizeof(struct net_local));
+               dev_wic0.priv = NULL;
+       }
+       if (dev_wic1.priv) {
+               unregister_netdev(&dev_wic1);
+               release_region(PAR_DATA(&dev_wic1), 3);
+               kfree_s(dev_wic1.priv, sizeof(struct net_local));
+               dev_wic1.priv = NULL;
+       }
+       if (dev_wic2.priv) {
+               unregister_netdev(&dev_wic2);
+               release_region(PAR_DATA(&dev_wic2), 3);
+               kfree_s(dev_wic2.priv, sizeof(struct net_local));
+               dev_wic2.priv = NULL;
+       }
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c wic.c"
+ * End:
+ */
index ba3261b168ef7286160dbc264dafc3e8d4067fdd..69299994db5277b973e90553ad3d068ac31d3e76 100644 (file)
@@ -22,6 +22,7 @@ dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
+dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
 dep_tristate 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
 dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
index c7af6042fd11df078bc51bdde6793f236c215864..d91ceb2b430f79a06f0c19f767fcdc556ea7e698 100644 (file)
@@ -251,6 +251,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_DTC3280),y)
+L_OBJS += dtc.o
+else
+  ifeq ($(CONFIG_SCSI_DTC3280),m)
+  M_OBJS += dtc.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_ULTRASTOR),y)
 L_OBJS += ultrastor.o
 else
index 945606028599edbfaab0cdccce23e0bb6f81b200..3b988c463d4aa5b4f7245693c6901a60fe290cf5 100644 (file)
 
 /*
  * $Log: NCR5380.c,v $
+ * Revision 1.7  1996/3/2      Ray Van Tassle (rayvt@comm.mot.com)
+ * added proc_info
+ * added support needed for DTC 3180/3280
+ * fixed a couple of bugs
+ *
+
  * Revision 1.5  1994/01/19  09:14:57  drew
  * Fixed udelay() hack that was being used on DATAOUT phases
  * instead of a proper wait for the final handshake.
  * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
  *     transceivers. 
  *
+ * DONT_USE_INTR - if defined, never use interrupts, even if we probe or
+ *     override-configure an IRQ.
+ *
  * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
  *     bytes at a time.  Since interrupts are disabled by default during
  *     these transfers, we might need this to give reasonable interrupt
  * USLEEP_POLL - amount of time, in jiffies, to poll
  *
  * These macros MUST be defined :
- * NCR5380_local_declare() - declare any local variables needed for your transfer
- *     routines.
+ * NCR5380_local_declare() - declare any local variables needed for your
+ *     transfer routines.
  *
  * NCR5380_setup(instance) - initialize any local variables needed from a given
  *     instance of the host adapter for NCR5380_{read,write,pread,pwrite}
  * NCR5380_queue_command
  * NCR5380_reset
  * NCR5380_abort
+ * NCR5380_proc_info
  *
  * to be the global entry points into the specific driver, ie 
  * #define NCR5380_queue_command t128_queue_command.
@@ -724,10 +734,9 @@ static void NCR5380_print_options (struct Scsi_Host *instance) {
  */
 
 static void NCR5380_print_status (struct Scsi_Host *instance) {
-    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 
-       instance->hostdata;
-    Scsi_Cmnd *ptr;
-
+   char pr_bfr[256];
+   char *start;
+   int len;
 
     printk("NCR5380 : coroutine is%s running.\n",
        main_running ? "" : "n't");
@@ -737,27 +746,144 @@ static void NCR5380_print_status (struct Scsi_Host *instance) {
     NCR5380_print_phase (instance);
 #endif
 
-    cli();
-    if (!hostdata->connected) {
-       printk ("scsi%d: no currently connected command\n",
-           instance->host_no);
-    } else {
-       print_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected);
-    }
+   len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr),
+                       instance->host_no, 0);
+   pr_bfr[len] = 0;
+   printk("\n%s\n", pr_bfr);
+  }
 
-    printk ("scsi%d: issue_queue\n", instance->host_no);
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
 
-    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; 
-       ptr = (Scsi_Cmnd *) ptr->host_scribble) 
-       print_Scsi_Cmnd (ptr);
+#undef SPRINTF
+#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+static
+char *lprint_command (unsigned char *cmd, char *pos, char *buffer, int len);
+static
+char *lprint_opcode(int opcode, char *pos, char *buffer, int length);
 
-    printk ("scsi%d: disconnected_queue\n", instance->host_no);
+#ifndef NCR5380_proc_info
+static
+#endif
+int NCR5380_proc_info (
+     char *buffer, char **start,off_t offset,
+     int length,int hostno,int inout)
+{
+   char *pos = buffer;
+   struct Scsi_Host *instance;
+   struct NCR5380_hostdata *hostdata;
+   Scsi_Cmnd *ptr;
+
+   for (instance = first_instance; instance &&
+        instance->host_no != hostno; instance=instance->next)
+        ;
+   if (!instance)
+      return(-ESRCH);
+   hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+   if (inout) { /* Has data been written to the file ? */
+#ifdef DTC_PUBLIC_RELEASE
+        dtc_wmaxi = dtc_maxi = 0;
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+        pas_wmaxi = pas_maxi = 0;
+#endif
+      return(-ENOSYS);  /* Currently this is a no-op */
+   }
+   SPRINTF("NCR5380 core release=%d.   ", NCR5380_PUBLIC_RELEASE);
+   if (((struct NCR5380_hostdata *)instance->hostdata)->flags & FLAG_NCR53C400)
+        SPRINTF("ncr53c400 release=%d.  ", NCR53C400_PUBLIC_RELEASE);
+#ifdef DTC_PUBLIC_RELEASE
+   SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE);
+#endif
+#ifdef T128_PUBLIC_RELEASE
+   SPRINTF("T128 release %d", T128_PUBLIC_RELEASE);
+#endif
+#ifdef GENERIC_NCR5380_PUBLIC_RELEASE
+   SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE);
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
+#endif
+
+   SPRINTF("\nBase Addr: 0x%05X    ", (int)instance->base);
+   SPRINTF("io_port: %04x      ", (int)instance->io_port);
+   if (instance->irq == IRQ_NONE)
+      SPRINTF("IRQ: None.\n");
+   else
+      SPRINTF("IRQ: %d.\n", instance->irq);
+
+#ifdef DTC_PUBLIC_RELEASE
+   SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n",
+        dtc_wmaxi, dtc_maxi);
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+   SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n",
+        pas_wmaxi, pas_maxi);
+#endif
+    cli();
+    SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't");
+    if (!hostdata->connected)
+      SPRINTF("scsi%d: no currently connected command\n", instance->host_no);
+   else
+      pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+        pos, buffer, length);
+   SPRINTF("scsi%d: issue_queue\n", instance->host_no);
+   for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr;
+        ptr = (Scsi_Cmnd *) ptr->host_scribble)
+        pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+
+   SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);
+   for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+        ptr = (Scsi_Cmnd *) ptr->host_scribble)
+        pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+
+   sti();
+   *start=buffer;
+  if (pos - buffer < offset)
+    return 0;
+  else if (pos - buffer - offset < length)
+    return pos - buffer - offset;
+  return length;
+}
 
-    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; 
-       ptr = (Scsi_Cmnd *) ptr->host_scribble) 
-       print_Scsi_Cmnd (ptr);
-    
-    sti();
+static 
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) {
+   SPRINTF("scsi%d : destination target %d, lun %d\n",
+        cmd->host->host_no, cmd->target, cmd->lun);
+   SPRINTF("        command = ");
+   pos = lprint_command (cmd->cmnd, pos, buffer, length);
+   return (pos);
+}
+
+static 
+char *lprint_command (unsigned char *command,
+     char *pos, char *buffer, int length) {
+   int i, s;
+   pos = lprint_opcode(command[0], pos, buffer, length);
+   for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+      SPRINTF("%02x ", command[i]);
+   SPRINTF("\n");
+   return(pos);
+}
+
+static 
+char *lprint_opcode(int opcode, char *pos, char *buffer, int length) {
+   SPRINTF("%2d (0x%02x)", opcode, opcode);
+   return(pos);
 }
 
 
@@ -926,7 +1052,6 @@ int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) {
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
     switch (cmd->cmnd[0]) {
-    case WRITE:
     case WRITE_6:
     case WRITE_10:
        printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
@@ -1152,6 +1277,7 @@ static void NCR5380_main (void) {
     main_running = 0;
 }
 
+#ifndef DONT_USE_INTR
 /*
  * Function : void NCR5380_intr (int irq)
  * 
@@ -1263,6 +1389,7 @@ static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) {
            } /* if (instance->irq == irq) */
     } while (!done);
 }
+#endif
 
 #ifdef NCR5380_STATS
 static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
@@ -2071,6 +2198,9 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
     return 0;
 #else /* defined(REAL_DMA_POLL) */
     if (p & SR_IO) {
+#ifdef DMA_WORKS_RIGHT
+        foo = NCR5380_pread(instance, d, c);
+#else
        int diff = 1;
        if (hostdata->flags & FLAG_NCR53C400) {
            diff=0;
@@ -2106,8 +2236,12 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
                d[c - 1] = NCR5380_read(INPUT_DATA_REG);
            }
        }
+#endif
     } else {
-       int timeout;
+#ifdef DMA_WORKS_RIGHT
+        foo = NCR5380_pwrite(instance, d, c);
+#else
+        int timeout;
 #if (NDEBUG & NDEBUG_C400_PWRITE)
        printk("About to pwrite %d bytes\n", c);
 #endif
@@ -2164,6 +2298,7 @@ static int NCR5380_transfer_dma (struct Scsi_Host *instance,
            udelay (5);
 #endif
        }
+#endif
     }
 
     NCR5380_write(MODE_REG, MR_BASE);
@@ -2316,6 +2451,10 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) {
                    !(hostdata->flags & FLAG_NO_PSEUDO_DMA) &&
                    cmd->SCp.this_residual && !(cmd->SCp.this_residual % 
                    transfersize)) {
+                    /* Limit transfers to 32K, for xx400 & xx406
+                     * pseudoDMA that transfers in 128 bytes blocks. */
+                    if (transfersize > 32*1024)
+                         transfersize = 32*1024;
 #endif
                    len = transfersize;
                    if (NCR5380_transfer_dma(instance, &phase,
index 9408e599d748cb4b129ededcf6bc9af712b74c53..fd87d23ef02386eb425c77d1fed08f9d0f33fd60 100644 (file)
@@ -7,7 +7,7 @@
  *     drew@colorado.edu
  *      +1 (303) 666-5836
  *
- * DISTRIBUTION RELEASE 6
+ * DISTRIBUTION RELEASE 7
  *
  * For more information, please consult 
  *
@@ -28,7 +28,7 @@
 #ifndef NCR5380_H
 #define NCR5380_H
 
-#define NCR5380_PUBLIC_RELEASE 6
+#define NCR5380_PUBLIC_RELEASE 7
 #define NCR53C400_PUBLIC_RELEASE 2
 
 #define NDEBUG_ARBITRATION     0x1
@@ -284,7 +284,9 @@ static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible);
 #endif
 static void NCR5380_init (struct Scsi_Host *instance, int flags);
 static void NCR5380_information_transfer (struct Scsi_Host *instance);
+#ifndef DONT_USE_INTR
 static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs);
+#endif
 static void NCR5380_main (void);
 static void NCR5380_print_options (struct Scsi_Host *instance);
 static void NCR5380_print_phase (struct Scsi_Host *instance);
diff --git a/drivers/scsi/README.dtc3x80 b/drivers/scsi/README.dtc3x80
new file mode 100644 (file)
index 0000000..6c12b4e
--- /dev/null
@@ -0,0 +1,44 @@
+REAME file for the Linux DTC3180/3280 scsi driver.
+by Ray Van Tassle (rayvt@comm.mot.com)  March 1996
+Based on the generic & core NCR5380 code by Drew Eckhard
+
+SCSI device driver for the DTC 3180/3280.
+Data Technology Corp---a division of Qume.
+
+The 3280 has a standard floppy interface.
+The 3180 does not.  Otherwise, they are identical.
+The DTC3x80 does not support DMA but it does have Pseudo-DMA which is
+supported by the driver.
+It's DTC406 scsi chip is supposedly compatible with the NCR 53C400.
+It is memory mapped, uses an IRQ, but no dma or io-port.  There is 
+internal DMA, between SCSI bus and an on-chip 128-byte buffer.  Double
+buffering is done automagically by the chip.
+Data is transferred between the on-chip buffer and CPU/RAM via
+memory moves.
+
+The driver detects the possible memory addresses (jumper selectable):
+       CC00, DC00, C800, and D800
+The possible IRQ's (jumper selectable) are:
+       IRQ 10, 11, 12, 15
+Parity is supported by the chip, but not by this driver.
+Information can be obtained from /proc/scsi/dtc3c80/N.
+
+Note on interrupts:
+The documentation says that it can be set to interrupt whenever the
+on-chip buffer needs CPU attention.  I couldn't get this to work.
+So the driver polls for data-ready in the pseudo-DMA transfer routine.
+The interrupt support routines in the NCR3280.c core modules handle
+scsi disconnect/reconnect, and this (mostly) works.
+However.....
+I have tested it with 4 totally different hard drives (both SCSI-1 
+and SCSI-2), and one CDROM drive.
+Interrupts works great for all but one specific hard drive.  For this one,
+the driver will eventually hang in the transfer state.
+I have tested with: "dd bs=4k count=2k of=/dev/null if=/dev/sdb".  It
+reads ok for a while, then hangs.  After beating my head against this for a
+couple of weeks, getting nowhere, I give up.
+So.....This driver does NOT use interrupts, even if you have the card 
+jumpered to an IRQ.  Probably nobody will ever care.
+Nor will I when the $380 2.5GB IDE drives hit the market in early 1996!
+
+
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
new file mode 100644 (file)
index 0000000..8e2ef88
--- /dev/null
@@ -0,0 +1,400 @@
+
+#define AUTOSENSE
+#define PSEUDO_DMA
+#define DONT_USE_INTR
+#define UNSAFE         /* Leave interrupts enabled during pseudo-dma I/O */
+#define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\
+                NDEBUG_SELECTION+NDEBUG_ARBITRATION)
+#define DMA_WORKS_RIGHT
+
+
+/*
+ * DTC 3180/3280 driver, by
+ *     Ray Van Tassle  rayvt@comm.mot.com
+ *
+ *     taken from ...
+ *     Trantor T128/T128F/T228 driver by...
+ *
+ *     Drew Eckhardt
+ *     Visionary Computing
+ *     (Unix and Linux consulting and custom programming)
+ *     drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 1.
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+*/
+
+/*
+ * Options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *      for commands that return with a CHECK CONDITION status. 
+ *
+ * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
+ * increase compared to polled I/O.
+ *
+ * PARITY - enable parity checking.  Not supported.
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. 
+ *             You probably want this.
+ *
+ * The card is detected and initialized in one of several ways : 
+ * 1.  Autoprobe (default) - since the board is memory mapped, 
+ *     a BIOS signature is scanned for to locate the registers.
+ *     An interrupt is triggered to autoprobe for the interrupt
+ *     line.
+ *
+ * 2.  With command line overrides - dtc=address,irq may be 
+ *     used on the LILO command line to override the defaults.
+ * 
+*/
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+ where something crashed or gets stuck at */
+/* 1 = blue
+ 2 = green
+ 3 = cyan
+ 4 = red
+ 5 = magenta
+ 6 = yellow
+ 7 = white
+*/
+#if 0
+#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+
+
+#include <asm/system.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/blk.h>
+#include <asm/io.h>
+#include "scsi.h"
+#include "hosts.h"
+#include "dtc.h"
+#define AUTOPROBE_IRQ
+#include "NCR5380.h"
+#include "constants.h"
+#include "sd.h"
+#include<linux/stat.h>
+#include<linux/string.h>
+
+struct proc_dir_entry proc_scsi_dtc = {
+   PROC_SCSI_T128, 7, "dtc3x80",
+       S_IFDIR | S_IRUGO | S_IXUGO, 2
+     };
+
+
+static struct override {
+   unsigned char *address;
+   int irq;
+} overrides
+#ifdef OVERRIDE
+[] = OVERRIDE;
+#else
+[4] = {{NULL, IRQ_AUTO}, {NULL, IRQ_AUTO}, {NULL, IRQ_AUTO},
+     {NULL, IRQ_AUTO}};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+static struct base {
+   unsigned char *address;
+   int noauto;
+} bases[] = {{(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0},
+{(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}};
+
+#define NO_BASES (sizeof (bases) / sizeof (struct base))
+
+static const struct signature {
+   const char *string;
+   int offset;
+} signatures[] = { {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, };
+
+#define NO_SIGNATURES (sizeof (signatures) /  sizeof (struct signature))
+
+/*
+ * Function : dtc_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ * 
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *     equal to the number of ints.
+ *
+*/
+
+void dtc_setup(char *str, int *ints) {
+   static int commandline_current = 0;
+   int i;
+   if (ints[0] != 2)
+      printk("dtc_setup: usage dtc=address,irq\n");
+   else
+      if (commandline_current < NO_OVERRIDES) {
+      overrides[commandline_current].address = (unsigned char *) ints[1];
+      overrides[commandline_current].irq = ints[2];
+      for (i = 0; i < NO_BASES; ++i)
+        if (bases[i].address == (unsigned char *) ints[1]) {
+        bases[i].noauto = 1;
+        break;
+      }
+      ++commandline_current;
+   }
+}
+
+/* 
+ * Function : int dtc_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : detects and initializes DTC 3180/3280 controllers
+ *     that were autoprobed, overridden on the LILO command line, 
+ *     or specified at compile time.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ * 
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+*/
+
+
+int dtc_detect(Scsi_Host_Template * tpnt) {
+   static int current_override = 0, current_base = 0;
+   struct Scsi_Host *instance;
+   unsigned char *base;
+   int sig, count;
+
+   tpnt->proc_dir = &proc_scsi_dtc;
+   tpnt->proc_info = &dtc_proc_info;
+
+   for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+      base = NULL;
+
+      if (overrides[current_override].address)
+        base = overrides[current_override].address;
+      else
+        for (; !base && (current_base < NO_BASES); ++current_base) {
+#if (DTCDEBUG & DTCDEBUG_INIT)
+        printk("scsi : probing address %08x\n", (unsigned int) bases[current_base].address);
+#endif
+        for (sig = 0; sig < NO_SIGNATURES; ++sig)
+           if (!bases[current_base].noauto && !memcmp
+             (bases[current_base].address + signatures[sig].offset,
+             signatures[sig].string, strlen(signatures[sig].string))) {
+           base = bases[current_base].address;
+#if (DTCDEBUG & DTCDEBUG_INIT)
+           printk("scsi-dtc : detected board.\n");
+#endif
+           break;
+        }
+      }
+
+#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
+      printk("scsi-dtc : base = %08x\n", (unsigned int) base);
+#endif
+
+      if (!base)
+        break;
+
+      instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+      instance->base = base;
+
+      NCR5380_init(instance, 0);
+
+      NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */
+      if (overrides[current_override].irq != IRQ_AUTO)
+        instance->irq = overrides[current_override].irq;
+      else
+        instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
+
+#ifndef DONT_USE_INTR
+/* With interrupts enabled, it will sometimes hang when doing heavy
+ * reads. So better not enable them until I finger it out. */
+      if (instance->irq != IRQ_NONE)
+        if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc")) {
+        printk("scsi%d : IRQ%d not free, interrupts disabled\n",
+             instance->host_no, instance->irq);
+        instance->irq = IRQ_NONE;
+      }
+
+      if (instance->irq == IRQ_NONE) {
+        printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+        printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+      }
+#else
+      if (instance->irq != IRQ_NONE)
+        printk("scsi%d : interrupts not used. Might as well not jumper it.\n",
+               instance->host_no);
+      instance->irq = IRQ_NONE;
+#endif
+#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
+      printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
+#endif
+
+      printk("scsi%d : at 0x%05X", instance->host_no, (int)instance->base);
+      if (instance->irq == IRQ_NONE)
+        printk (" interrupts disabled");
+      else
+        printk (" irq %d", instance->irq);
+      printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
+          CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
+      NCR5380_print_options(instance);
+      printk("\n");
+
+      ++current_override;
+      ++count;
+   }
+   return count;
+}
+
+/*
+ * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ *     the specified device / size.
+ * 
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ *     major / minor, ip[] = {heads, sectors, cylinders}  
+ *
+ * Returns : always 0 (success), initializes ip
+ *     
+*/
+
+/* 
+ * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+*/
+
+int dtc_biosparam(Disk * disk, kdev_t dev, int * ip)
+{
+   int size = disk->capacity;
+
+   ip[0] = 64;
+   ip[1] = 32;
+   ip[2] = size >> 11;
+   return 0;
+}
+
+/****************************************************************
+ * Function : int NCR5380_pread (struct Scsi_Host *instance, 
+ *     unsigned char *dst, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to 
+ *     dst
+ * 
+ * Inputs : dst = destination, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ *     timeout.
+*/
+
+static int dtc_maxi = 0;
+static int dtc_wmaxi = 0;
+
+static inline int NCR5380_pread (struct Scsi_Host *instance,
+     unsigned char *dst, int len)
+     {
+   unsigned char *d = dst;
+   int i;      /* For counting time spent in the poll-loop */
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   i = 0;
+   NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+   NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
+   if (instance->irq == IRQ_NONE)
+      NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
+   else
+      NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
+   NCR5380_write(DTC_BLK_CNT, len >> 7);        /* Block count */
+   rtrc(1);
+   while (len > 0) {
+      rtrc(2);
+      while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
+        ++i;
+      rtrc(3);
+      memcpy(d, (char *)(base + DTC_DATA_BUF), 128);
+      d += 128;
+      len -= 128;
+      rtrc(7); /*** with int's on, it sometimes hangs after here.
+                * Looks like something makes HBNR go away. */
+   }
+   rtrc(4);
+   while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
+      ++i;
+   NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
+   rtrc(0);
+   NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+   if (i > dtc_maxi)
+      dtc_maxi = i;
+   return(0);
+}
+
+/****************************************************************
+ * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
+ *     unsigned char *src, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
+ *     src
+ * 
+ * Inputs : src = source, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ *     timeout.
+*/
+
+static inline int NCR5380_pwrite (struct Scsi_Host *instance,
+     unsigned char *src, int len) {
+   int i;
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+   NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
+   /* set direction (write) */
+   if (instance->irq == IRQ_NONE)
+      NCR5380_write(DTC_CONTROL_REG, 0);
+   else
+      NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
+   NCR5380_write(DTC_BLK_CNT, len >> 7);        /* Block count */
+   for (i = 0; len > 0; ++i) {
+      rtrc(5);
+      /* Poll until the host buffer can accept data. */
+      while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
+        ++i;
+      rtrc(3);
+      memcpy((char *)(base + DTC_DATA_BUF), src, 128);
+      src += 128;
+      len -= 128;
+   }
+   rtrc(4);
+   while ( !(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
+      ++i;
+   rtrc(6);
+   /* Wait until the last byte has been sent to the disk */
+   while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+      ++i;
+   rtrc(7);
+   /* Check for parity error here. fixme. */
+   NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
+   rtrc(0);
+   if (i > dtc_wmaxi)
+      dtc_wmaxi = i;
+   return (0);
+}
+
+#include "NCR5380.c"
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = DTC3x80;
+
+#include "scsi_module.c"
+#endif
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
new file mode 100644 (file)
index 0000000..e2c8462
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * DTC controller, taken from T128 driver by...
+ * Copyright 1993, Drew Eckhardt
+ *     Visionary Computing
+ *     (Unix and Linux consulting and custom programming)
+ *     drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 1. 
+ *
+ * For more information, please consult 
+ *
+ * 
+ * 
+ * and 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+#ifndef DTC3280_H
+#define DTC3280_H
+
+#define DTC_PUBLIC_RELEASE 1
+
+/*#define DTCDEBUG 0x1*/
+#define DTCDEBUG_INIT  0x1
+#define DTCDEBUG_TRANSFER 0x2
+
+/*
+ * The DTC3180 & 3280 boards are memory mapped.
+ * 
+ */
+
+/*
+ */ 
+/* Offset from DTC_5380_OFFSET */
+#define DTC_CONTROL_REG                0x100   /* rw */
+#define D_CR_ACCESS            0x80    /* ro set=can access 3280 registers */
+#define CSR_DIR_READ           0x40    /* rw direction, 1 = read 0 = write */
+
+#define CSR_RESET              0x80    /* wo  Resets 53c400 */
+#define CSR_5380_REG           0x80    /* ro  5380 registers can be accessed */
+#define CSR_TRANS_DIR          0x40    /* rw  Data transfer direction */
+#define CSR_SCSI_BUFF_INTR     0x20    /* rw  Enable int on transfer ready */
+#define CSR_5380_INTR          0x10    /* rw  Enable 5380 interrupts */
+#define CSR_SHARED_INTR        0x08    /* rw  Interrupt sharing */
+#define CSR_HOST_BUF_NOT_RDY   0x04    /* ro  Host buffer not ready */
+#define CSR_SCSI_BUF_RDY       0x02    /* ro  SCSI buffer ready */
+#define CSR_GATED_5380_IRQ     0x01    /* ro  Last block xferred */
+#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR)
+
+
+#define DTC_BLK_CNT            0x101   /* rw 
+                                        * # of 128-byte blocks to transfer */
+
+
+#define D_CR_ACCESS             0x80    /* ro set=can access 3280 registers */
+
+#define DTC_SWITCH_REG         0x3982  /* ro - DIP switches */
+#define DTC_RESUME_XFER                0x3982  /* wo - resume data xfer 
+                                          * after disconnect/reconnect*/
+
+#define DTC_5380_OFFSET                0x3880  /* 8 registers here, see NCR5380.h */
+
+/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */
+#define DTC_DATA_BUF           0x3900  /* rw 128 bytes long */
+
+
+#ifndef ASM
+int dtc_abort(Scsi_Cmnd *);
+int dtc_biosparam(Disk *, kdev_t, int*);
+int dtc_detect(Scsi_Host_Template *);
+int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int dtc_reset(Scsi_Cmnd *);
+int dtc_proc_info (char *buffer, char **start, off_t offset,
+                  int length, int hostno, int inout);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 32 
+#endif
+
+/* 
+ * I hadn't thought of this with the earlier drivers - but to prevent
+ * macro definition conflicts, we shouldn't define all of the internal
+ * macros when this is being used solely for the host stub.
+ */
+
+#if defined(HOSTS_C) || defined(MODULE)
+
+#define DTC3x80 {NULL, NULL, NULL, NULL, \
+       "DTC 3180/3280 ", dtc_detect, NULL,  \
+       NULL,                                                   \
+       NULL, dtc_queue_command, dtc_abort, dtc_reset, NULL,    \
+       dtc_biosparam,                                          \
+       /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL,                  \
+       /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+
+#endif
+
+#ifndef HOSTS_C
+
+#define NCR5380_implementation_fields \
+    volatile unsigned char *base
+
+#define NCR5380_local_declare() \
+    volatile unsigned char *base
+
+#define NCR5380_setup(instance) \
+    base = (volatile unsigned char *) (instance)->base
+
+#define DTC_address(reg) (base + DTC_5380_OFFSET + reg)
+
+#define dbNCR5380_read(reg)                                              \
+    (rval=*(DTC_address(reg)), \
+     (((unsigned char) printk("DTC : read register %d at addr %08x is: %02x\n"\
+    , (reg), (int)DTC_address(reg), rval)), rval ) )
+
+#define dbNCR5380_write(reg, value) do {                                  \
+    printk("DTC : write %02x to register %d at address %08x\n",         \
+            (value), (reg), (int)DTC_address(reg));     \
+    *(DTC_address(reg)) = (value);} while(0)
+
+
+#if !(DTCDEBUG & DTCDEBUG_TRANSFER) 
+#define NCR5380_read(reg) (*(DTC_address(reg)))
+#define NCR5380_write(reg, value) (*(DTC_address(reg)) = (value))
+#else
+#define NCR5380_read(reg) (*(DTC_address(reg)))
+#define xNCR5380_read(reg)                                             \
+    (((unsigned char) printk("DTC : read register %d at address %08x\n"\
+    , (reg), DTC_address(reg))), *(DTC_address(reg)))
+
+#define NCR5380_write(reg, value) do {                                 \
+    printk("DTC : write %02x to register %d at address %08x\n",        \
+           (value), (reg), (int)DTC_address(reg));     \
+    *(DTC_address(reg)) = (value);             } while(0)
+#endif
+
+#define NCR5380_intr dtc_intr
+#define NCR5380_queue_command dtc_queue_command
+#define NCR5380_abort dtc_abort
+#define NCR5380_reset dtc_reset
+#define NCR5380_proc_info dtc_proc_info 
+
+/* 15 12 11 10
+   1001 1100 0000 0000 */
+
+#define DTC_IRQS 0x9c00
+
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* DTC3280_H */
index b823f33a6dcf2abbd07131e4833a10f7659d94e3..9e02128f9f4b6caf43006cbb74cae2f70711401f 100644 (file)
@@ -47,6 +47,8 @@ int generic_NCR5380_detect(Scsi_Host_Template *);
 int generic_NCR5380_release_resources(struct Scsi_Host *);
 int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int generic_NCR5380_reset(Scsi_Cmnd *);
+int notyet_generic_proc_info (char *buffer ,char **start, off_t offset,
+                     int length, int hostno, int inout);
 const char* generic_NCR5380_info(struct Scsi_Host *);
 #ifdef BIOSPARAM
 int generic_NCR5380_biosparam(Disk *, kdev_t, int *);
@@ -72,7 +74,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
        generic_NCR5380_proc_info,                                      \
        "Generic NCR5380/NCR53C400 Scsi Driver",                        \
        generic_NCR5380_detect, generic_NCR5380_release_resources,      \
-       generic_NCR5380_info, NULL,                                     \
+       (void *)generic_NCR5380_info, NULL,                             \
        generic_NCR5380_queue_command, generic_NCR5380_abort,           \
        generic_NCR5380_reset, NULL,                                    \
        NCR5380_BIOSPARAM,                                              \
@@ -151,6 +153,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
 #define NCR5380_reset generic_NCR5380_reset
 #define NCR5380_pread generic_NCR5380_pread
 #define NCR5380_pwrite generic_NCR5380_pwrite
+#define NCR5380_proc_info notyet_generic_proc_info
 
 #define BOARD_NCR5380  0
 #define BOARD_NCR53C400        1
index bbf340101e2c99a3a589c537ed044ebcea5f4adc..69a404415f6712e2b0297f2be3d9ea7f61079193 100644 (file)
 #include "t128.h"
 #endif
 
+#ifdef CONFIG_SCSI_DTC3280
+#include "dtc.h"
+#endif
+
 #ifdef CONFIG_SCSI_NCR53C7xx
 #include "53c7,8xx.h"
 #endif
 #include "scsi_debug.h"
 #endif
 
+
 /*
 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.3 1993/09/24 12:21:00 drew Exp drew $";
 */
@@ -219,6 +224,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_T128
     TRANTOR_T128,
 #endif
+#ifdef CONFIG_SCSI_DTC3280
+        DTC3x80,
+#endif
 #ifdef CONFIG_SCSI_NCR53C7xx
     NCR53c7xx,
 #endif
index aa443e220a51a40cdbbb40daeedf0923a51b0d7e..2f6f226988b1e358c8c99d2233a89f27d2321d8f 100644 (file)
@@ -126,6 +126,9 @@ struct proc_dir_entry proc_scsi_pas16 = {
     PROC_SCSI_PAS16, 5, "pas16",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
+static int pas_maxi = 0;
+static int pas_wmaxi = 0;
 
 int scsi_irq_translate[] =
        { 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
@@ -180,7 +183,22 @@ unsigned short  pas16_offset[ 8 ] =
                    * START_DMA_INITIATOR_RECEIVE_REG wo
                    */
     };
-
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+ where something crashed or gets stuck at */
+/* 1 = blue
+ 2 = green
+ 3 = cyan
+ 4 = red
+ 5 = magenta
+ 6 = yellow
+ 7 = white
+*/
+#if 1
+#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
 
 
 /*
@@ -357,6 +375,7 @@ int pas16_detect(Scsi_Host_Template * tpnt) {
     int  count;
 
     tpnt->proc_dir = &proc_scsi_pas16;
+    tpnt->proc_info = &pas16_proc_info;
 
     for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
        io_port = 0;
@@ -400,6 +419,7 @@ int pas16_detect(Scsi_Host_Template * tpnt) {
        else 
            instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
 
+                instance->irq = IRQ_NONE;  /*****temp****/
        if (instance->irq != IRQ_NONE) 
            if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", NULL)) {
                printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
@@ -492,8 +512,10 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
     register unsigned short reg = (unsigned short) (instance->io_port + 
        P_DATA_REG_OFFSET);
     register i = len;
+    int ii = 0;
 
-    while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) );
+    while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
+        ++ii;
 
     insb( reg, d, i );
 
@@ -502,8 +524,10 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
        printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
            instance->host_no);
        return -1;
-    } else
-       return 0;
+    }
+   if (ii > pas_maxi)
+      pas_maxi = ii;
+    return 0;
 }
 
 /*
@@ -524,8 +548,10 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
     register unsigned char *s = src;
     register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
     register i = len;
+    int ii = 0;
 
-    while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) );
+    while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
+        ++ii;
  
     outsb( reg, s, i );
 
@@ -534,8 +560,10 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
        printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
            instance->host_no);
        return -1;
-    } else 
-       return 0;
+    }
+    if (ii > pas_maxi)
+        pas_wmaxi = ii;
+    return 0;
 }
 
 #include "NCR5380.c"
index 9733792b249cdf6ac1ee6f7b0a7a09a28b4b8080..afe8bca9998fccbb6090c55d29e9c2e6374de21a 100644 (file)
@@ -119,6 +119,8 @@ int pas16_biosparam(Disk *, kdev_t, int*);
 int pas16_detect(Scsi_Host_Template *);
 int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int pas16_reset(Scsi_Cmnd *);
+int pas16_proc_info (char *buffer ,char **start, off_t offset,
+                    int length, int hostno, int inout);
 
 #ifndef NULL
 #define NULL 0
@@ -182,6 +184,7 @@ int pas16_reset(Scsi_Cmnd *);
 #define NCR5380_queue_command pas16_queue_command
 #define NCR5380_abort pas16_abort
 #define NCR5380_reset pas16_reset
+#define NCR5380_proc_info pas16_proc_info
 
 /* 15 14 12 10 7 5 3 
    1101 0100 1010 1000 */
index b527d5b4f0a747e5dc132aada51768d547f6c936..6ee0352ac2fa97942c2bf43128c6141242df3a7c 100644 (file)
@@ -1157,18 +1157,26 @@ static int sd_init_onedisk(int i)
        }
     {
        /*
-        * The msdos fs need to know the hardware sector size
+        * The msdos fs needs to know the hardware sector size
         * So I have created this table. See ll_rw_blk.c
         * Jacques Gelinas (Jacques@solucorp.qc.ca)
         */
-       int m;
+       int m, mb;
+        int sz_quot, sz_rem;
        int hard_sector = rscsi_disks[i].sector_size;
-       /* There is 16 minor allocated for each devices */
+       /* There are 16 minors allocated for each major device */
        for (m=i<<4; m<((i+1)<<4); m++){
            sd_hardsizes[m] = hard_sector;
        }
-       printk ("SCSI Hardware sector size is %d bytes on device sd%c\n",
-               hard_sector,i+'a');
+        mb = (hard_sector * rscsi_disks[i].capacity) / (1024*1024);
+        /* sz = div(m/100, 10);  this seems to not be in the libr */
+        m = (mb + 50) / 100;
+        sz_quot = m / 10;
+        sz_rem = m - (10 * sz_quot);
+       printk ("SCSI device sd%c: hdwr sector= %d bytes."
+               " Sectors= %d [%d MB] [%d.%1d GB]\n",
+               i+'a', hard_sector, rscsi_disks[i].capacity, 
+                mb, sz_quot, sz_rem);
     }
        if(rscsi_disks[i].sector_size == 1024)
            rscsi_disks[i].capacity <<= 1;  /* Change into 512 byte sectors */
index 91901ddf7e2256d5ea6307dd1fcb0440f6f780ec..fe5fa79bec9d144e6a2ce4dac472a66702fdf0a9 100644 (file)
@@ -204,6 +204,7 @@ int t128_detect(Scsi_Host_Template * tpnt) {
     int sig, count;
 
     tpnt->proc_dir = &proc_scsi_t128;
+    tpnt->proc_info = &t128_proc_info;
 
     for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
        base = NULL;
index 009161374ba97c5c033271ef266f59ccc470d5c9..af7175edfc8debf2ffc106e8b6e7bda09b23080a 100644 (file)
@@ -96,6 +96,8 @@ int t128_biosparam(Disk *, kdev_t, int*);
 int t128_detect(Scsi_Host_Template *);
 int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int t128_reset(Scsi_Cmnd *);
+int t128_proc_info (char *buffer, char **start, off_t offset,
+                  int length, int hostno, int inout);
 
 #ifndef NULL
 #define NULL 0
@@ -127,7 +129,7 @@ int t128_reset(Scsi_Cmnd *);
 
 #endif
 
-#ifndef(HOSTS_C)
+#ifndef HOSTS_C
 
 #define NCR5380_implementation_fields \
     volatile unsigned char *base
@@ -159,6 +161,7 @@ int t128_reset(Scsi_Cmnd *);
 #define NCR5380_queue_command t128_queue_command
 #define NCR5380_abort t128_abort
 #define NCR5380_reset t128_reset
+#define NCR5380_proc_info t128_proc_info
 
 /* 15 14 12 10 7 5 3 
    1101 0100 1010 1000 */
index 29dd1efece243b16ed21e5c8c376016b95beb183..720a6f43d6ba011966a7957f6473828987f16eb8 100644 (file)
@@ -219,7 +219,8 @@ MAD16 and Mozart based cards
 Audio Excell DSP16 
        Support for this card was written by Riccardo Faccetti
        (riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
-       (This driver is not functional in version 3.5 of this driver).
+       (This driver is not functional in version 3.5 of this driver. A
+       patch should be made available during April 96 (sunsite.unc.edu)).
        
 Crystal CS4232 based cards such as AcerMagic S23, TB Tropez _Plus_ and 
        many PC motherboards (Compaq, HP, Intel, ...)
@@ -835,6 +836,7 @@ them so read the card's manual carefully.
 ESS ES1688 and ES688 'AudioDrive' based cards
 ---------------------------------------------
 
+Support for these two ESS chips is embedded in the SB Pro driver.
 Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port'
 if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
 so you don't need to enable it (the driver uses normal SB MIDI automaticly
@@ -888,6 +890,12 @@ willing to maintain a database of supported cards (just like in XF86)?).
 Cards not supported yet
 =======================
 
+Please check which version of sound driver you are using before 
+complaining that your card is not supported. It's possible that you are 
+using a driver version which was released months before your card was
+introduced. Driver's release date is listed after it's version number
+in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h.
+
 First of all. There is an easy way to make most soundcards to work
 with Linux. Just use the DOS based driver to initialize the card
 to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured
index b4debc033b7059c5970caf956636a8474c01a885..1f2f5ed7e92ec1f778b391df49a1f6e4077a5b1d 100644 (file)
  *  once we've checked for blocking and deadlocking.
  *  Andy Walker (andy@lysaker.kvaerner.no), April 03, 1996.
  *
- *  NOTE:
- *  Starting to look at mandatory locks - using SunOS as a model.
- *  Probably a configuration option because mandatory locking can cause
- *  all sorts  of chaos with runaway processes.
- *
  *  Initial implementation of mandatory locks. SunOS turned out to be
  *  a rotten model, so I implemented the "obvious" semantics.
  *  See 'linux/Documentation/mandatory.txt' for details.
  *  Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996.
+ *
+ *  Don't allow mandatory locks on mmap()'ed files. Added simple functions to
+ *  check if a file has mandatory locks, used by mmap(), open() and creat() to
+ *  see if system call should be rejected. Ref. HP-UX/SunOS/Solaris Reference
+ *  Manual, Section 2.
+ *  Andy Walker (andy@lysaker.kvaerner.no), April 09, 1996.
  */
 
 #include <linux/malloc.h>
@@ -195,7 +196,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
            (flock.l_type == F_SHLCK))
                return (-EINVAL);
 
-       if (!posix_make_lock(filp, &file_lock, &flock))
+       if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
                return (-EINVAL);
 
        for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
@@ -227,6 +228,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
        struct file *filp;
        struct file_lock file_lock;
        struct flock flock;
+       struct inode *inode;
 
        /*
         * Get arguments and validate them ...
@@ -239,6 +241,21 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
        if (error)
                return (error);
        
+       if (!(inode = filp->f_inode))
+               return (-EINVAL);
+       
+       /* Don't allow mandatory locks on files that may be memory mapped
+        * and shared.
+        */
+       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && inode->i_mmap) {
+               struct vm_area_struct *vma = inode->i_mmap;
+               do {
+                       if (vma->vm_flags & VM_MAYSHARE)
+                               return (-EAGAIN);
+                       vma = vma->vm_next_share;
+               } while (vma != inode->i_mmap);
+       }
+
        memcpy_fromfs(&flock, l, sizeof(flock));
        if (!posix_make_lock(filp, &file_lock, &flock))
                return (-EINVAL);
@@ -246,16 +263,16 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
        switch (flock.l_type) {
        case F_RDLCK :
                if (!(filp->f_mode & 1))
-                       return -EBADF;
+                       return (-EBADF);
                break;
        case F_WRLCK :
                if (!(filp->f_mode & 2))
-                       return -EBADF;
+                       return (-EBADF);
                break;
        case F_SHLCK :
        case F_EXLCK :
                if (!(filp->f_mode & 3))
-                       return -EBADF;
+                       return (-EBADF);
                break;
        case F_UNLCK :
                break;
@@ -288,21 +305,44 @@ void locks_remove_locks(struct task_struct *task, struct file *filp)
        return;
 }
 
-int locks_verify(int read_write, struct inode *inode, struct file *filp,
-                unsigned int offset, unsigned int count)
+int locks_verify_locked(struct inode *inode)
 {
        /* Candidates for mandatory locking have the setgid bit set
         * but no group execute bit -  an otherwise meaningless combination.
         */
        if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-               return (locks_locked_mandatory(read_write, inode, filp,
-                                              offset, count));
+               return (locks_mandatory_locked(inode));
+       return (0);
+}
+
+int locks_mandatory_locked(struct inode *inode)
+{
+       struct file_lock *fl;
+
+       /* Search the lock list for this inode for any POSIX locks.
+        */
+       for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+               if (fl->fl_flags == F_POSIX && fl->fl_owner != current)
+                       return (-EAGAIN);
+       }
+       return (0);
+}
+
+int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
+                     unsigned int offset, unsigned int count)
+{
+       /* Candidates for mandatory locking have the setgid bit set
+        * but no group execute bit -  an otherwise meaningless combination.
+        */
+       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+               return (locks_mandatory_area(read_write, inode, filp, offset,
+                                            count));
        return (0);
 }
        
-int locks_locked_mandatory(int read_write, struct inode *inode,
-                          struct file *filp, unsigned int offset,
-                          unsigned int count)
+int locks_mandatory_area(int read_write, struct inode *inode,
+                        struct file *filp, unsigned int offset,
+                        unsigned int count)
 {
        struct file_lock *fl;
 
@@ -353,9 +393,6 @@ static int posix_make_lock(struct file *filp, struct file_lock *fl,
 {
        off_t start;
 
-       if (!filp->f_inode)     /* just in case */
-               return (0);
-
        switch (l->l_type) {
        case F_RDLCK :
        case F_WRLCK :
index 21b935ce20968a8dbce019250bc1e3ad02f1bba8..3865b8c9ee4af58543e87e423023286b0fbc9890 100644 (file)
@@ -385,6 +385,13 @@ int open_namei(const char * pathname, int flag, int mode,
                iput(dir);
                return error;
        }
+       /* SunOS, Solaris 2.x and HPUX all deny open() on
+        * an existing file with mandatory locks.
+        */
+       if ((error = locks_verify_locked(inode)) != 0) {
+               iput(inode);
+               return error;
+       }
        error = follow_link(dir,inode,flag,mode,&inode);
        if (error)
                return error;
@@ -430,6 +437,17 @@ int open_namei(const char * pathname, int flag, int mode,
                        iput(inode);
                        return error;
                }
+#if 0
+               /*
+                * In my opinion the mandatory lock check should really be
+                * here. Only O_TRUNC calls can modify the file contents -
+                * but none of the commercial OS'es seem to do it this way.
+                */
+               if ((error = locks_verify_locked(inode)) != 0) {
+                       iput(inode);
+                       return error;
+               }
+#endif
                if (inode->i_sb && inode->i_sb->dq_op)
                        inode->i_sb->dq_op->initialize(inode, -1);
                        
index 8711d5e2fa51354318d8338fab46021b4ac07005..2e2125c6b76bb3bba3b30d9f0c4e9f65386ddf00 100644 (file)
@@ -834,7 +834,8 @@ static void root_bootp_recv(void)
 
        /* Extract basic fields */
        myaddr.sin_addr.s_addr = recv_bootp->your_ip;
-       server.sin_addr.s_addr = recv_bootp->server_ip;
+       if (server.sin_addr.s_addr==INADDR_NONE)
+               server.sin_addr.s_addr = recv_bootp->server_ip;
 
        /* Parse extensions */
        if (recv_bootp->vendor_area[0] == 99 && /* Check magic cookie */
index 2f6d38af277b0eb2d37276ae76914c4b90f850a2..3532c99122f9588586ecb5c9e70b19f2c8ce255c 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -107,9 +107,9 @@ asmlinkage int sys_truncate(const char * path, unsigned long length)
                iput(inode);
                return error;
        }
-       error = locks_verify(FLOCK_VERIFY_WRITE, inode, NULL,
-                            length < inode->i_size ? length : inode->i_size,
-                            abs(inode->i_size - length));
+       error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, NULL,
+                                 length < inode->i_size ? length : inode->i_size,
+                                 abs(inode->i_size - length));
        if (error)
                return error;
        error = do_truncate(inode, length);
@@ -132,9 +132,9 @@ asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
                return -EACCES;
        if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                return -EPERM;
-       error = locks_verify(FLOCK_VERIFY_WRITE, inode, file,
-                            length < inode->i_size ? length : inode->i_size,
-                            abs(inode->i_size - length));
+       error = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+                                 length < inode->i_size ? length : inode->i_size,
+                                 abs(inode->i_size - length));
        if (error)
                return error;
        return do_truncate(inode, length);
index 6fe80809d58a30206a780457d1d8b5538dd3e7c0..2318b9fe240c244791c90eb31ef87ab2dda7b933 100644 (file)
@@ -114,7 +114,7 @@ asmlinkage int sys_read(unsigned int fd,char * buf,unsigned int count)
                return -EINVAL;
        if (!count)
                return 0;
-       error = locks_verify(FLOCK_VERIFY_READ,inode,file,file->f_pos,count);
+       error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count);
        if (error)
                return error;
        error = verify_area(VERIFY_WRITE,buf,count);
@@ -138,7 +138,7 @@ asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count)
                return -EINVAL;
        if (!count)
                return 0;
-       error = locks_verify(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count);
+       error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count);
        if (error)
                return error;
        error = verify_area(VERIFY_READ,buf,count);
@@ -227,8 +227,8 @@ static int do_readv_writev(int type, struct inode * inode, struct file * file,
                        return retval;
        }
 
-       retval = locks_verify(type == VERIFY_READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
-                             inode, file, file->f_pos, tot_len);
+       retval = locks_verify_area(type == VERIFY_READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
+                                  inode, file, file->f_pos, tot_len);
        if (retval)
                return retval;
 
index 47f7967de9cb0a4cd86ea9f44e24f22609b20c11..798ecbe64d477dd2cb51ac03d6716d7c9f094360 100644 (file)
@@ -582,10 +582,14 @@ asmlinkage int sys_umount(char * name)
                iput(inode);
                return -ENXIO;
        }
-       if (!(retval = do_umount(dev,0)) && dev != ROOT_DEV) {
-               blkdev_release (inode);
-               if (MAJOR(dev) == UNNAMED_MAJOR)
-                       put_unnamed_dev(dev);
+       retval = do_umount(dev,0);
+       if (!retval) {
+               fsync_dev(dev);
+               if (dev != ROOT_DEV) {
+                       blkdev_release (inode);
+                       if (MAJOR(dev) == UNNAMED_MAJOR)
+                               put_unnamed_dev(dev);
+               }
        }
        if (inode != &dummy_inode)
                iput(inode);
index 186f41484f9788c0955b993f15eccfead7074d62..6052ad459f558697b8f9cb88e9ba282cb910ab78 100644 (file)
@@ -85,9 +85,9 @@ static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned
     __asm__ volatile
        ("      cld
                push %%es
-               movw %%fs,%%cx
-               movw %%cx,%%es
+               push %%fs
                cmpl $3,%0
+               pop %%es
                jbe 1f
                movl %%edi,%%ecx
                negl %%ecx
index 1d067077e3b6b6b8a43efe9c5934ea1ee295c3f4..a7611c735ebb780ee68243a7d88f79367ebc9c42 100644 (file)
@@ -406,6 +406,24 @@ extern inline void * __constant_memcpy(void * to, const void * from, size_t n)
                        *(unsigned long *)to = *(const unsigned long *)from;
                        *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
                        return to;
+               case 12:
+                       *(unsigned long *)to = *(const unsigned long *)from;
+                       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+                       *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
+                       return to;
+               case 16:
+                       *(unsigned long *)to = *(const unsigned long *)from;
+                       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+                       *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
+                       *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
+                       return to;
+               case 20:
+                       *(unsigned long *)to = *(const unsigned long *)from;
+                       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
+                       *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
+                       *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
+                       *(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
+                       return to;
        }
 #define COMMON(x) \
 __asm__("cld\n\t" \
index 87700fe0a02c0348f18b43442cca8c25fbce9016..175ef2887d2d50c3f084d9a6c1ae0084930a092c 100644 (file)
@@ -354,19 +354,29 @@ extern void locks_remove_locks(struct task_struct *task, struct file *filp);
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
 
-extern int locks_locked_mandatory(int read_write, struct inode *inode,
-                                 struct file *filp, unsigned int offset,
-                                 unsigned int count);
-extern inline int locks_verify(int read_write, struct inode *inode,
-                              struct file *filp, unsigned int offset,
-                              unsigned int count)
+extern int locks_mandatory_locked(struct inode *inode);
+extern inline int locks_verify_locked(struct inode *inode)
 {
        /* Candidates for mandatory locking have the setgid bit set
         * but no group execute bit -  an otherwise meaningless combination.
         */
        if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-               return (locks_locked_mandatory(read_write, inode, filp,
-                                              offset, count));
+               return (locks_mandatory_locked(inode));
+       return (0);
+}
+extern int locks_mandatory_area(int read_write, struct inode *inode,
+                               struct file *filp, unsigned int offset,
+                               unsigned int count);
+extern inline int locks_verify_area(int read_write, struct inode *inode,
+                                   struct file *filp, unsigned int offset,
+                                   unsigned int count)
+{
+       /* Candidates for mandatory locking have the setgid bit set
+        * but no group execute bit -  an otherwise meaningless combination.
+        */
+       if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+               return (locks_mandatory_area(read_write, inode, filp, offset,
+                                            count));
        return (0);
 }
 
index 25e9abe107af4fdba7daa0aaded1c4714a21005c..d5d8d5608f5051aa7acf0c6162cded3debbcd544 100644 (file)
@@ -6,7 +6,7 @@
  *             code, including it's RFC1490 encapsulation along side the current
  *             implementation for the Sangoma cards.
  *
- * Version:    @(#)if_ifrad.h  0.10    23 Mar 96
+ * Version:    @(#)if_ifrad.h  0.15    31 Mar 96
  *
  * Author:     Mike McLagan <mike.mclagan@linux.org>
  *
@@ -33,7 +33,11 @@ struct dlci_add
 #define DLCI_GET_CONF  (SIOCDEVPRIVATE + 2)
 #define DLCI_SET_CONF  (SIOCDEVPRIVATE + 3)
 
-/* These are related to the Sangoma FRAD */
+/* 
+ * These are related to the Sangoma SDLA and should remain in order. 
+ * Code within the SDLA module is based on the specifics of this 
+ * structure.  Change at your own peril.
+ */
 struct dlci_conf {
    short flags;
    short CIR_fwd;
@@ -48,6 +52,8 @@ struct dlci_conf {
    short Tc_bwd;
    short Tf_max;
    short Tb_max;
+
+/* add any new fields here above is a mirror of sdla_dlci_conf */
 };
 
 #define DLCI_GET_SLAVE (SIOCDEVPRIVATE + 4)
@@ -59,6 +65,10 @@ struct dlci_conf {
 
 #define DLCI_VALID_FLAGS       0x000B
 
+/* FRAD driver uses these to indicate what it did with packet */
+#define DLCI_RET_OK            0x00
+#define DLCI_RET_ERR           0x01
+#define DLCI_RET_DROP          0x02
 
 /* defines for the actual Frame Relay hardware */
 #define FRAD_GET_CONF  (SIOCDEVPRIVATE)
@@ -66,6 +76,11 @@ struct dlci_conf {
 
 #define FRAD_LAST_IOCTL        FRAD_SET_CONF
 
+/*
+ * Based on the setup for the Sangoma SDLA.  If changes are 
+ * necessary to this structure, a routine will need to be 
+ * added to that module to copy fields.
+ */
 struct frad_conf 
 {
    short station;
@@ -85,7 +100,7 @@ struct frad_conf
    short Bc_bwd;
    short Be_bwd;
 
-/* Add new fields here, above is a mirror of the sangoma_conf */
+/* Add new fields here, above is a mirror of the sdla_conf */
 
 };
 
@@ -106,14 +121,19 @@ struct frad_conf
 
 #ifdef __KERNEL__
 
-struct fradhdr
+/* these are the fields of an RFC 1490 header */
+struct frhdr
 {
-   /* these are the fields of an RFC 1490 header               */
-   unsigned char  control;
-   unsigned char  pad;         /* for IP packets, this can be the NLPID */
-   unsigned char  NLPID;
-   unsigned char  OUI[3];
-   unsigned short PID;
+   unsigned char  control      __attribute__((packed));
+
+   /* for IP packets, this can be the NLPID */
+   unsigned char  pad          __attribute__((packed)); 
+
+   unsigned char  NLPID                __attribute__((packed));
+   unsigned char  OUI[3]       __attribute__((packed));
+   unsigned short PID          __attribute__((packed));
+
+#define IP_NLPID pad 
 };
 
 /* see RFC 1490 for the definition of the following */
@@ -139,12 +159,15 @@ struct dlci_local
 struct frad_local
 {
    struct enet_statistics stats;
-   struct timer_list timer;
 
    /* devices which this FRAD is slaved to */
    struct device     *master[CONFIG_DLCI_MAX];
    short             dlci[CONFIG_DLCI_MAX];
 
+   struct frad_conf  config;
+   int               configured;       /* has this device been configured */
+   int               initialized;      /* mem_start, port, irq set ? */
+
    /* callback functions */
    int               (*activate)(struct device *, struct device *);
    int               (*deactivate)(struct device *, struct device *);
@@ -152,12 +175,11 @@ struct frad_local
    int               (*deassoc)(struct device *, struct device *);
    int               (*dlci_conf)(struct device *, struct device *, int get);
 
-   int               initialized;      /* mem_start, port, irq set ? */
-   int               configured;       /* has this device been configured */
+   /* fields that are used by the Sangoma SDLA cards */
+   struct timer_list timer;
    int               type;             /* adapter type */
    int               state;            /* state of the S502/8 control latch */
    int               buffer;           /* current buffer for S508 firmware */
-   struct frad_conf  config;
 };
 
 int register_frad(const char *name);
diff --git a/include/linux/if_wic.h b/include/linux/if_wic.h
new file mode 100644 (file)
index 0000000..bb70de3
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _LINUX_IF_WIC_H
+#define _LINUX_IF_WIC_H
+
+#include <linux/sockios.h>
+
+#define        SIOCDEVWIC      SIOCDEVPRIVATE
+
+struct wicconf
+{
+       unsigned char   pcmd;
+       unsigned char   data[120];
+       unsigned char   len;
+};
+
+/* WIC host to controller commands */
+
+#define WIC_AYT                0x10    /* test dki */
+#define WIC_RESET      0x11    /* reset controller */
+#define WIC_SETSN      0x21    /* set station name */
+#define WIC_SETPS      0x22    /* set power saving mode */
+#define WIC_SETAF      0x23    /* set announce filter */
+#define WIC_SETGPF     0x24    /* set GPSP filter */
+#define WIC_GETVERH    0x61    /* get interface controller version */
+#define WIC_GETNL      0x62    /* get neighbor list */
+#define WIC_GETSN      0x65    /* get station name */
+#define WIC_CLRSTATS   0x83    /* clear controller statistics */
+#define WIC_SETNET     0x84    /* set network configuration */
+#define WIC_SETSYS     0x85    /* set system configuration */
+#define WIC_GETSTATS   0xc1    /* get statistics */
+#define WIC_GETVERM    0xc3    /* get MAC version */
+#define WIC_GETNET     0xc4    /* get network configuration */
+#define WIC_GETSYS     0xc5    /* get system configuration */
+
+/*
+ * structure used for the GETNET/SETNET command
+ */
+
+struct wic_net {
+       unsigned char ula[6];           /* ula of interface */
+       unsigned char mode;             /* operating mode */
+#define NET_MODE_ME            0x01    /* receive my ula */
+#define NET_MODE_BCAST         0x02    /* receive bcasts */
+#define NET_MODE_MCAST         0x04    /* receive mcasts */
+#define NET_MODE_PROM          0x08    /* promiscuous */
+#define NET_MODE_HC            0x10    /* is a hop coordinator */
+#define NET_MODE_HC_VALID      0x20    /* hc addres is valid */
+#define NET_MODE_HCAP          0x40    /* hc is also ap */
+#define NET_MODE_HC_KNOWN      0x80    /* hc is known */
+       unsigned char rts_lo;           /* rts threshhold */
+       unsigned char rts_hi;           /* rts threshhold */
+       unsigned char retry;            /* retry limit */
+       unsigned char hc_ula[6];        /* ula of hc */
+       unsigned char key[4];           /* network key */
+       unsigned char dsl;              /* direct send limit */
+       unsigned char res1;             /* reserved */
+};
+
+/*
+ * structure used for the GETSYS/SETSYS command 
+ */
+
+struct wic_sys {
+       unsigned char mode;             /* set operating mode */
+#define SYS_MODE_ANT_DIV       0x00    /* use antenna diversity */
+#define SYS_MODE_ANT_1         0x01    /* use ant 1 for tx */
+#define SYS_MODE_ANT_2         0x02    /* use ant 2 for tx */
+#define SYS_MODE_HC_LOCK       0x04    /* lock onto current hc */
+#define SYS_MODE_DEBUG         0x08    /* upload failed frames */
+#define SYS_MODE_IAM_AP                0x10    /* I am AP */
+#define SYS_MODE_IAM_HC                0x20    /* I am HC */
+#define SYS_MODE_USE_SKIP      0x40    /* use skipping mechanism */
+#define SYS_MODE_AUTO          0x80    /* station is in auto mode */
+       unsigned char switches;         /* radio/controller switches */
+#define SYS_SWITCH_STDBY       0x01    /* switch radio to standby */
+#define SYS_SWITCH_TXRX                0x02    /* 1 = tx, manual mode only */
+#define SYS_SWITCH_PA          0x04    /* 1 = enable PA on radio */
+#define SYS_SWITCH_PWR         0x10    /* 1 = hi, 0 = lo power output */
+#define SYS_SWITCH_RES1                0x20    /* reserved, must be 0 */
+#define SYS_SWITCH_LIGHTS      0x40    /* light for tx & rx */
+#define SYS_SWITCH_LIGHTS_HC   0x80    /* light for rx while coordinated */
+       unsigned char hop_min;          /* hop range */
+       unsigned char hop_max;          /* hop range */
+       unsigned char pre_len;          /* preamble length (bytes) */
+       unsigned char pre_match;        /* valid preamble match (bytes) */
+       unsigned char mod;              /* data mod: 1 = 8:1, 0 = none */
+       unsigned char cca_mode;         /* cca flags */
+#define CCA_PKT_DET_BSY                0x01    /* busy if packet is detected */
+#define CCA_VIRT_CARR          0x02    /* use virtual carrier */
+#define CCA_RSSI_BSY           0x04    /* busy if rssi > thresshold */
+#define CCA_DATA_BSY           0x08    /* busy if valid data > XXX usec */
+       unsigned char dwell_hi;         /* dwell time */
+       unsigned char dwell_lo;         /* dwell time */
+       unsigned char hc_timeout;       /* HC timeout */
+       unsigned char rssi;             /* rssi threshhold */
+       unsigned char hc_rssi;          /* rssi of last hc frame */
+       unsigned char hc_rssi_chan;     /* channel of hc rssi value */
+};
+
+
+#endif /* _LINUX_IF_WIC_H */
+
+
index 4d5d70c1ab00059611aa61adc791517485fb252f..74d0fa81a6bf5c815ba021dbaa6213d1e4687bdf 100644 (file)
@@ -109,5 +109,4 @@ struct iphdr {
        /*The options start here. */
 };
 
-
 #endif /* _LINUX_IP_H */
index 85f04e84243641906fc2d39c0173de0b5ee6c142..461979d0bd5f95163816dd93dc1e45be41696ecc 100644 (file)
@@ -124,6 +124,7 @@ struct ip_fw
 #define IP_FW_ZERO             (IP_FW_BASE_CTL+4)
 #define IP_FW_POLICY           (IP_FW_BASE_CTL+5)
 #define IP_FW_CHECK            (IP_FW_BASE_CTL+6)
+#define IP_FW_MASQ_TIMEOUTS    (IP_FW_BASE_CTL+7)
 
 #define IP_FW_INSERT_FWD       (IP_FW_INSERT | (IP_FW_FWD << IP_FW_SHIFT))
 #define IP_FW_APPEND_FWD       (IP_FW_APPEND | (IP_FW_FWD << IP_FW_SHIFT))
@@ -167,6 +168,12 @@ struct ip_fwpkt
        char           fwp_vianame[IFNAMSIZ];   /* interface name */
 };
 
+/*
+ * timeouts for ip masquerading
+ */
+
+struct ip_fw_masq;
+
 /*
  *     Main firewall chains definitions and global var's definitions.
  */
index 26fcd8c3cb6fa3c483f409f550599a807567d4aa..4469b325756947e3c69cce3e74788a3dba3d7e8c 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Global definitions for the Frame relay interface.
  *
- * Version:    @(#)if_ifrad.h  0.10    23 Mar 96
+ * Version:    @(#)if_ifrad.h  0.15    31 Mar 96
  *
  * Author:     Mike McLagan <mike.mclagan@linux.org>
  *
@@ -64,12 +64,15 @@ struct sdla_mem {
 #define SDLA_CONF_ADDR                 0x0010
 #define SDLA_S502A_NMIADDR             0x0066
 #define SDLA_CODE_BASEADDR             0x0100
+#define SDLA_WINDOW_SIZE               0x2000
+#define SDLA_ADDR_MASK                 0x1FFF
 
 /* largest handlable block of data */
 #define SDLA_MAX_DATA                  4080
 #define SDLA_MAX_MTU                   4072    /* MAX_DATA - sizeof(fradhdr) */
 #define SDLA_MAX_DLCI                  24
 
+/* this should be the same as frad_conf */
 struct sdla_conf {
    short station;
    short config;
@@ -89,7 +92,8 @@ struct sdla_conf {
    short Be_bwd;
 };
 
-struct sdla_dlci {
+/* this should be the same as dlci_conf */
+struct sdla_dlci_conf {
    short config;
    short CIR_fwd;
    short Bc_fwd;
@@ -97,8 +101,6 @@ struct sdla_dlci {
    short CIR_bwd;
    short Bc_bwd;
    short Be_bwd; 
-
-/* these are part of the status READ */
    short Tc_fwd;
    short Tc_bwd;
    short Tf_max;
@@ -203,7 +205,7 @@ void sdla(void *cfg_info, char *dev, struct frad_conf *conf, int quiet);
 #define SDLA_RET_NO_DATA               0x05
 #define SDLA_RET_BUF_OVERSIZE          0x06
 #define SDLA_RET_CIR_OVERFLOW          0x07
-#define SDLA_RET_NO_BUFF               0x08
+#define SDLA_RET_NO_BUFS               0x08
 #define SDLA_RET_TIMEOUT               0x0A
 #define SDLA_RET_MODEM                 0x10
 #define SDLA_RET_CHANNEL_OFF           0x11
index 63cc599560e13e1eaa32cdf8179259a5c5d86fd7..cd3bdc4da6d9745ea1a48536ededcbd425eaf9f0 100644 (file)
@@ -94,6 +94,7 @@ struct sk_buff
                        lock,                   /* Are we locked ?                              */
                        localroute,             /* Local routing asserted for this frame        */
                        pkt_type,               /* Packet class                                 */
+                       pkt_bridged,            /* Tracker for bridging                         */
                        ip_summed;              /* Driver fed us an IP checksum                 */
 #define PACKET_HOST            0               /* To us                                        */
 #define PACKET_BROADCAST       1               /* To all                                       */
index b03c12bc5ed7354799b23b34a387f4a09cf25669..c268b6e06131e1a086ca0eee93c33151ecdef775 100644 (file)
 #define SIOCGIFHWADDR  0x8927          /* Get hardware address         */
 #define SIOCGIFSLAVE   0x8929          /* Driver slaving support       */
 #define SIOCSIFSLAVE   0x8930
-/* begin multicast support change */
-#define SIOCADDMULTI  0x8931
-#define SIOCDELMULTI  0x8932
-/* end multicast support change */
+#define SIOCADDMULTI   0x8931          /* Multicast address lists      */
+#define SIOCDELMULTI   0x8932
+
+#define SIOCGIFBR      0x8940          /* Bridging support             */
+#define SIOCSIFBR      0x8941          /* Set bridging options         */
 
 /* ARP cache control calls. */
 #define OLD_SIOCDARP   0x8950          /* old delete ARP table entry   */
diff --git a/include/net/br.h b/include/net/br.h
new file mode 100644 (file)
index 0000000..b6c023c
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Constants and structure definitions for the bridging code
+ */
+
+#if !defined(One)
+#define Zero    0
+#define One    1
+#endif  /* !defined(One) */
+
+#if !defined(TRUE)
+#define FALSE   0
+#define TRUE   1
+#endif /* !defined(TRUE) */
+
+/** port states. **/
+#define Disabled       0                         /* (4.4 5)     */
+#define Listening      1                         /* (4.4.2)     */
+#define Learning       2                         /* (4.4.3)     */
+#define Forwarding     3                         /* (4 4 4)     */
+#define Blocking       4                         /* (4.4.1)     */
+
+#define No_of_ports 8
+/* arbitrary choice, to allow the code below to compile */
+
+#define All_ports (No_of_ports + 1)
+
+/*
+ * We time out our entries in the FDB after this many seconds.
+ */
+#define FDB_TIMEOUT    300
+
+/*
+ * the following defines are the initial values used when the 
+ * bridge is booted.  These may be overridden when this bridge is
+ * not the root bridge.  These are the reccomended default values 
+ * from the 802.1d specification.
+ */
+#define BRIDGE_MAX_AGE         20
+#define BRIDGE_HELLO_TIME      2
+#define BRIDGE_FORWARD_DELAY   15
+#define HOLD_TIME              1
+
+#define Default_path_cost 10
+
+/*
+ * minimum increment possible to avoid underestimating age, allows for BPDU
+ * transmission time
+ */
+#define Message_age_increment 1
+
+#define No_port 0
+/*
+ * reserved value for Bridge's root port parameter indicating no root port,
+ * used when Bridge is the root - also used to indicate the source when
+ * a frame is being generated by a higher layer protocol on this host
+ */
+
+/** Configuration BPDU Parameters (4.5.1) **/
+
+typedef struct {
+       union {
+               struct {
+                       unsigned short priority;
+                       unsigned char ula[6];
+               } p_u;
+               unsigned int id[2];
+       } bi;
+} bridge_id_t;
+
+#define BRIDGE_PRIORITY        bi.p_u.priority
+#define BRIDGE_ID_ULA  bi.p_u.ula
+#define BRIDGE_ID      bi.id
+
+typedef struct {
+       unsigned short  protocol_id;    
+       unsigned char   protocol_version_id;
+       unsigned char   type;
+       unsigned char   flags;
+#define TOPOLOGY_CHANGE                0x01
+#define TOPOLOGY_CHANGE_ACK    0x80
+       bridge_id_t      root_id;                 /* (4.5.1.1)   */
+       unsigned int     root_path_cost;          /* (4.5.1.2)   */
+       bridge_id_t      bridge_id;               /* (4.5.1.3)   */
+       unsigned short   port_id;                 /* (4.5.1.4)   */
+       unsigned short   message_age;             /* (4.5.1.5)   */
+       unsigned short   max_age;                 /* (4.5.1.6)   */
+       unsigned short   hello_time;              /* (4.5.1.7)   */
+       unsigned short   forward_delay;           /* (4.5.1.8)   */
+} Config_bpdu;
+
+
+/** Topology Change Notification BPDU Parameters (4.5.2) **/
+
+typedef struct {
+       unsigned short  protocol_id;    
+       unsigned char   protocol_version_id;
+       unsigned char   type;
+} Tcn_bpdu;
+
+#define BPDU_TYPE_CONFIG       0
+#define BPDU_TYPE_TOPO_CHANGE  128
+
+/** Bridge Parameters (4.5.3) **/
+typedef struct {
+       bridge_id_t      designated_root;         /* (4.5.3.1)   */
+       unsigned int     root_path_cost;          /* (4.5.3.2)   */
+       unsigned int     root_port;               /* (4.5.3.3)   */
+       unsigned short   max_age;                 /* (4.5.3.4)   */
+       unsigned short   hello_time;              /* (4.5.3.5)   */
+       unsigned short   forward_delay;           /* (4.5.3.6)   */
+       bridge_id_t      bridge_id;               /* (4.5.3.7)   */
+       unsigned short   bridge_max_age;          /* (4.5.3.8)   */
+       unsigned short   bridge_hello_time;       /* (4.5.3.9)   */
+       unsigned short   bridge_forward_delay;    /* (4.5.3.10)  */
+       unsigned int     topology_change_detected; /* (4.5.3.11) */
+       unsigned int     topology_change;         /* (4.5.3.12)  */
+       unsigned short   topology_change_time;    /* (4.5.3.13)  */
+       unsigned short   hold_time;               /* (4.5.3.14)  */
+       unsigned int     top_change;
+       unsigned int     top_change_detected;
+} Bridge_data;
+
+/** Port Parameters (4.5.5) **/
+typedef struct {
+       unsigned short   port_id;                 /* (4.5.5.1)   */
+       unsigned int     state;                   /* (4.5.5.2)   */
+       unsigned int     path_cost;               /* (4.5.5.3)   */
+       bridge_id_t      designated_root;         /* (4.5.5.4)   */
+       unsigned int     designated_cost;         /* (4.5.5.5)   */
+       bridge_id_t      designated_bridge;       /* (4.5.5.6)   */
+       unsigned short   designated_port;         /* (4.5.5.7)   */
+       unsigned int     top_change_ack;          /* (4.5.5.8)   */
+       unsigned int     config_pending;          /* (4.5.5.9)   */
+       struct device *dev;     
+       struct fdb *fdb;        /* head of per port fdb chain */
+} Port_data;
+
+
+
+/** types to support timers for this pseudo-implementation. **/
+typedef struct {
+       unsigned int     active;                          /* timer in use. */
+       unsigned int     value;                   /* current value of timer,
+                                                  * counting up. */
+} Timer;
+
+struct fdb {
+       unsigned char ula[6];
+       unsigned char pad[2];
+       unsigned short port;
+       unsigned int timer;
+       unsigned int flags;
+#define FDB_ENT_VALID  0x01
+/* AVL tree of all addresses, sorted by address */
+       short fdb_avl_height;
+       struct fdb *fdb_avl_left;
+       struct fdb *fdb_avl_right;
+/* linked list of addresses for each port */
+       struct fdb *fdb_next;
+};
+
+#define IS_BRIDGED     0x2e
+
+struct br_stat {
+       unsigned int flags;
+       Bridge_data bridge_data;
+       Port_data port_data[No_of_ports];
+};
+
+/* defined flags for br_stat.flags */
+#define BR_UP          0x0001  /* bridging enabled */
+#define BR_DEBUG       0x0002  /* debugging enabled */
+
+struct br_cf {
+       unsigned int cmd;
+       unsigned int arg1;
+       unsigned int arg2;
+};
+
+/* defined cmds */
+#define        BRCMD_BRIDGE_ENABLE     1
+#define        BRCMD_BRIDGE_DISABLE    2
+#define        BRCMD_PORT_ENABLE       3       /* arg1 = port */
+#define        BRCMD_PORT_DISABLE      4       /* arg1 = port */
+#define        BRCMD_SET_BRIDGE_PRIORITY       5       /* arg1 = priority */
+#define        BRCMD_SET_PORT_PRIORITY 6       /* arg1 = port, arg2 = priority */
+#define        BRCMD_SET_PATH_COST     7       /* arg1 = port, arg2 = cost */
+#define        BRCMD_DISPLAY_FDB       8       /* arg1 = port */
+#define        BRCMD_ENABLE_DEBUG      9
+#define        BRCMD_DISABLE_DEBUG     10
+
+/* 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 */
+
+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);
+
+void free_fdb(struct fdb *);
+struct fdb *get_fdb(void);
+
+/* externs */
+
+extern struct br_stat br_stats;
+
index e4a3b527b5578416a40542c36f84d129a6254066..4f2f06e4c75d3e3bf9f62e0f23e6f38bb5d8aad1 100644 (file)
@@ -55,6 +55,18 @@ struct ip_masq {
        unsigned  flags;                /* status flags */
 };
 
+/*
+ *     timeout values
+ */
+
+struct ip_fw_masq {
+        int tcp_timeout;
+        int tcp_fin_timeout;
+        int udp_timeout;
+};
+
+extern struct ip_fw_masq *ip_masq_expire;
+
 /*
  *     [0]: UDP free_ports
  *     [1]: TCP free_ports
index 98f88f4a0b032d4a437e1f1e643e3df16c6b6580..2f71c23a90e5afb8078fb7c43d24c1cdd497d81a 100644 (file)
@@ -149,7 +149,7 @@ extern void tcp_write_wakeup(struct sock *);
 extern void tcp_send_fin(struct sock *sk);
 extern void tcp_send_synack(struct sock *, struct sock *, struct sk_buff *);
 extern void tcp_send_skb(struct sock *, struct sk_buff *);
-extern void tcp_send_ack(u32, u32, struct sock *sk, struct tcphdr *th, u32);
+extern void tcp_send_ack(struct sock *sk);
 extern void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
          struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl);
 
index 1e75eedee1f68c3fa1a227c310ef506b96ecd749..69d4a68635536c18b0645b0f8d38feef2718e928 100644 (file)
@@ -425,6 +425,7 @@ read_page:
        if (read) {
                error = read;
 
+#ifdef WE_SHOULD_DO_SOME_EXTRA_CHECKS
                /*
                 * Start some extra read-ahead if we haven't already
                 * read ahead enough..
@@ -434,6 +435,7 @@ read_page:
                        ra_pos += PAGE_SIZE;
                }
                run_task_queue(&tq_disk);
+#endif
 
                filp->f_pos = pos;
                filp->f_reada = ra_pos;
index e350aa3dea339c924b81200acc41a35d0e9557ff..b6da1035ec26af42cd01da9da3438bd9ca48e20a 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -73,6 +73,11 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
                case MAP_SHARED:
                        if ((prot & PROT_WRITE) && !(file->f_mode & 2))
                                return -EACCES;
+                       /*
+                        * make sure there are no mandatory locks on the file.
+                        */
+                       if (locks_verify_locked(file->f_inode))
+                               return -EAGAIN;
                        /* fall through */
                case MAP_PRIVATE:
                        if (!(file->f_mode & 1))
index 2f061f580d94ffba37171222722edce4a13d4b42..12b299e8d523427187f056f9fb13cb6b0498fc63 100644 (file)
@@ -15,12 +15,12 @@ O_OBJS += tr.o
 endif
 
 ifdef CONFIG_IPX
-O_OBJS += p8022.o psnap.o p8022tr.o
+OX_OBJS += p8022.o psnap.o p8022tr.o
 endif
 
 ifdef CONFIG_ATALK
 ifndef CONFIG_IPX
-O_OBJS += p8022.o psnap.o p8022tr.o
+OX_OBJS += p8022.o psnap.o p8022tr.o
 endif
 endif
 
index ae21864c095a9d85bce5dab25acdec4e723967d0..fceccde8eb304a46f8bf91c52a812c5eb67559e5 100644 (file)
@@ -11,7 +11,7 @@ if [ "$CONFIG_INET" = "y" ]; then
 fi
 comment ' '
 tristate 'The IPX protocol' CONFIG_IPX
-if [ ! "$CONFIG_IPX" = "n" ]; then
+if [ "$CONFIG_IPX" != "n" ]; then
   bool 'Full internal IPX network' CONFIG_IPX_INTERN
 fi
 tristate 'Appletalk DDP' CONFIG_ATALK
@@ -20,6 +20,7 @@ if [ "$CONFIG_AX25" = "y" ]; then
   bool 'AX.25 over Ethernet' CONFIG_BPQETHER
   bool 'Amateur Radio NET/ROM' CONFIG_NETROM
 fi
+bool 'Bridging (test)' CONFIG_BRIDGE
 bool 'Kernel/User network link driver(ALPHA)' CONFIG_NETLINK
 if [ "$CONFIG_NETLINK" = "y" ]; then
   bool 'Routing messages' CONFIG_RTNETLINK
index 111c18958744942d89f6bf6d6597b09e4c8e04b2..cb64dbdba8c27fc2c3f613d52b5144635ece79c7 100644 (file)
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 MOD_SUB_DIRS := ipv4
-ALL_SUB_DIRS := 802 ax25 core ethernet ipv4 ipx unix appletalk netrom
+ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipx unix appletalk netrom 
 SUB_DIRS     := 802 core ethernet unix
 MOD_LIST_NAME := NET_MISC_MODULES
 
@@ -16,6 +16,10 @@ ifeq ($(CONFIG_INET),y)
 SUB_DIRS += ipv4
 endif
 
+ifeq ($(CONFIG_BRIDGE),y)
+SUB_DIRS += bridge
+endif
+
 ifeq ($(CONFIG_IPX),y)
 SUB_DIRS += ipx
 else
index 8e12efae5e3a7b52ebb5956c4954d031de1112f1..7da3991acac2d4673587e3d344ff65d0a9c37ae9 100644 (file)
@@ -1143,40 +1143,19 @@ static int atalk_create(struct socket *sock, int protocol)
 
        MOD_INC_USE_COUNT;
 
-       sk->dead=0;
-       sk->next=NULL;
-       sk->broadcast=0;
        sk->no_check=0;         /* Checksums on by default */
        sk->allocation=GFP_KERNEL;
        sk->rcvbuf=SK_RMEM_MAX;
        sk->sndbuf=SK_WMEM_MAX;
        sk->pair=NULL;
-       sk->wmem_alloc=0;
-       sk->rmem_alloc=0;
-       sk->users=0;
-       sk->proc=0;
        sk->priority=1;
-       sk->shutdown=0;
-       sk->prot=NULL;  /* So we use default free mechanisms */
-       sk->broadcast=0;
-       sk->err=0;
        skb_queue_head_init(&sk->receive_queue);
        skb_queue_head_init(&sk->write_queue);
-       sk->send_head=NULL;
        skb_queue_head_init(&sk->back_log);
        sk->state=TCP_CLOSE;
        sk->socket=sock;
        sk->type=sock->type;
-       sk->debug=0;
        
-       sk->protinfo.af_at.src_net=0;
-       sk->protinfo.af_at.src_node=0;
-       sk->protinfo.af_at.src_port=0;
-       
-       sk->protinfo.af_at.dest_net=0;
-       sk->protinfo.af_at.dest_node=0;
-       sk->protinfo.af_at.dest_port=0;
-
        sk->mtu=DDP_MAXSZ;
        
        if(sock!=NULL)
index cf0570eddc5ec5bb7855dbd0fbd6a6378331be3f..53043aac0cd0f2c042eb80e99abf455c6c530f79 100644 (file)
@@ -447,7 +447,7 @@ void ax25_destroy_socket(ax25_cb *ax25)     /* Not static as its used by the timer *
                                ax25->digipeat = NULL;
                        }
                
-                       kfree_s(ax25->sk, sizeof(*ax25->sk));
+                       sk_free(ax25->sk);
                        kfree_s(ax25, sizeof(*ax25));
                }
        } else {
@@ -1105,25 +1105,12 @@ static int ax25_create(struct socket *sock, int protocol)
        sk->socket        = sock;
        sk->type          = sock->type;
        sk->protocol      = protocol;
-       sk->dead          = 0;
        sk->next          = NULL;
-       sk->broadcast     = 0;
        sk->allocation    = GFP_KERNEL;
        sk->rcvbuf        = SK_RMEM_MAX;
        sk->sndbuf        = SK_WMEM_MAX;
-       sk->wmem_alloc    = 0;
-       sk->rmem_alloc    = 0;
-       sk->users         = 0;
-       sk->debug         = 0;
-       sk->destroy       = 0;
-       sk->prot          = NULL;       /* So we use default free mechanisms */
-       sk->err           = 0;
-       sk->localroute    = 0;
-       sk->send_head     = NULL;
        sk->state         = TCP_CLOSE;
-       sk->shutdown      = 0;
        sk->priority      = SOPRI_NORMAL;
-       sk->ack_backlog   = 0;
        sk->mtu           = AX25_MTU;   /* 256 */
        sk->zapped        = 1;
 
@@ -1176,26 +1163,14 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev)
        skb_queue_head_init(&sk->write_queue);
        skb_queue_head_init(&sk->back_log);
 
-       sk->dead        = 0;
        sk->next        = NULL;
        sk->priority    = osk->priority;
-       sk->broadcast   = 0;
        sk->protocol    = osk->protocol;
        sk->rcvbuf      = osk->rcvbuf;
        sk->sndbuf      = osk->sndbuf;
-       sk->wmem_alloc  = 0;
-       sk->rmem_alloc  = 0;
-       sk->users       = 0;
-       sk->ack_backlog = 0;
-       sk->destroy     = 0;
-       sk->prot        = NULL; /* So we use default free mechanisms */
-       sk->err         = 0;
-       sk->localroute  = 0;
-       sk->send_head   = NULL;
        sk->debug       = osk->debug;
        sk->state       = TCP_ESTABLISHED;
        sk->window      = osk->window;
-       sk->shutdown    = 0;
        sk->mtu         = osk->mtu;
        sk->sleep       = osk->sleep;
        sk->zapped      = osk->zapped;
index 0e30c50d7606c0046394c9e701a7eae8e12ed1e5..617f645d6ffd4cb6374c0c3eaf34043569c4509a 100644 (file)
@@ -496,7 +496,7 @@ static int ax25_list_length(struct sk_buff_head *list, struct sk_buff *skb)
 
        skbq = (struct sk_buff *) list->next;
 
-       while (skbq != list) {
+       while (skbq != (struct sk_buff *)list) {
                if (skb->sk == skbq->sk)
                        count++;
                skbq = skbq->next;
diff --git a/net/bridge/Makefile b/net/bridge/Makefile
new file mode 100644 (file)
index 0000000..48c0794
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for the Linux TCP/IP (INET) layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := bridge.o
+O_OBJS  := br.o br_tree.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+tar:
+               tar -cvf /dev/f1 .
diff --git a/net/bridge/br.c b/net/bridge/br.c
new file mode 100644 (file)
index 0000000..af6adf7
--- /dev/null
@@ -0,0 +1,1561 @@
+/*
+ *     Linux NET3 Bridge Support
+ *
+ *     Originally by John Hayes (Network Plumbing).
+ *     Minor hacks to get it to run with 1.3.x by Alan Cox <Alan.Cox@linux.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.
+ *
+ *     Fixes:
+ *
+ *     Todo:
+ *             Don't bring up devices automatically. Start ports disabled
+ *     and use a netlink notifier so a daemon can maintain the bridge
+ *     port group (could we also do multiple groups ????).
+ *             A nice /proc file interface.
+ *             Put the path costs in the port info and devices
+ *             Put the bridge port number in the device structure for speed.
+ *     
+ */
+#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/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <net/br.h>
+
+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)     */
+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)   */
+
+/* entries timeout after this many seconds */
+unsigned int fdb_aging_time = FDB_TIMEOUT; 
+
+struct br_stat br_stats;
+
+static struct timer_list tl; /* for 1 second timer... */
+
+/*
+ * the following structure is required so that we receive
+ * event notifications when network deviced are enabled and
+ * disabled (ifconfig up and down).
+ */
+static struct notifier_block br_dev_notifier={
+       br_device_event,
+       NULL,
+       0
+};
+
+/** Elements of Procedure (4.6) **/
+
+/*
+ * this section of code was gratiously borrowed from the IEEE 802.1d
+ * specification section 4.9.1 starting on pg 69.  It has been
+ * modified somewhat to fit within out framework and structure.  It
+ * implements the spanning tree algorithm that is the heart of the
+ * 802.1d bridging protocol.
+ */
+
+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)   */
+       } else {                                  /* (4.6.1.3.2)         */
+               config_bpdu[port_no].type = BPDU_TYPE_CONFIG;
+               config_bpdu[port_no].root_id = bridge_info.designated_root;
+               /* (4.6.1.3.2(1)) */
+               config_bpdu[port_no].root_path_cost = bridge_info.root_path_cost;
+               /* (4.6.1.3.2(2)) */
+               config_bpdu[port_no].bridge_id = bridge_info.bridge_id;
+               /* (4.6.1.3.2(3)) */
+               config_bpdu[port_no].port_id = port_info[port_no].port_id;
+               /*
+                * (4.6.1.3.2(4))
+                */
+               if (root_bridge()) {
+                       config_bpdu[port_no].message_age = Zero;        /* (4.6.1.3.2(5)) */
+               } else {
+                       config_bpdu[port_no].message_age
+                               = message_age_timer[bridge_info.root_port].value
+                               + Message_age_increment;        /* (4.6.1.3.2(6)) */
+               }
+
+               config_bpdu[port_no].max_age = bridge_info.max_age;     /* (4.6.1.3.2(7)) */
+               config_bpdu[port_no].hello_time = bridge_info.hello_time;
+               config_bpdu[port_no].forward_delay = bridge_info.forward_delay;
+               config_bpdu[port_no].flags = 0;
+               config_bpdu[port_no].flags |=
+                       port_info[port_no].top_change_ack ? TOPOLOGY_CHANGE_ACK : 0;
+               /* (4.6.1.3.2(8)) */
+               port_info[port_no].top_change_ack = 0;
+               /* (4.6.1.3.2(8)) */
+               config_bpdu[port_no].flags |=
+                       bridge_info.top_change ? TOPOLOGY_CHANGE : 0;
+               /* (4.6.1.3.2(9)) */
+
+               send_config_bpdu(port_no, &config_bpdu[port_no]);
+               port_info[port_no].config_pending = FALSE;      /* (4.6.1.3.2(10)) */
+               start_hold_timer(port_no);        /* (4.6.1.3.2(11)) */
+       }
+}
+
+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)   */
+{
+       return (
+               (br_cmp(config->root_id.BRIDGE_ID,
+                port_info[port_no].designated_root.BRIDGE_ID) < 0)     /* (4.6.2.2.1)   */ 
+               ||
+               ((br_cmp(config->root_id.BRIDGE_ID,
+                 port_info[port_no].designated_root.BRIDGE_ID) == 0
+                 )
+                &&
+                ((config->root_path_cost
+                  < port_info[port_no].designated_cost /* (4.6.2.2.2)   */
+                  )
+                 ||
+                 ((config->root_path_cost
+                   == port_info[port_no].designated_cost
+                   )
+                  &&
+                  ((br_cmp(config->bridge_id.BRIDGE_ID,
+                    port_info[port_no].designated_bridge.BRIDGE_ID) < 0        /* (4.6.2.2.3)    */
+                    )
+                   ||
+                   ((br_cmp(config->bridge_id.BRIDGE_ID,
+                     port_info[port_no].designated_bridge.BRIDGE_ID) == 0
+                     )                           /* (4.6.2.2.4)         */
+                    &&
+                    ((br_cmp(config->bridge_id.BRIDGE_ID,
+                       bridge_info.bridge_id.BRIDGE_ID) != 0
+                      )                          /* (4.6.2.2.4(1)) */
+                     ||
+                     (config->port_id <=
+                      port_info[port_no].designated_port
+                      )                          /* (4.6.2.2.4(2)) */
+                     ))))))
+               );
+}
+
+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;
+       port_info[port_no].designated_bridge = config->bridge_id;
+       port_info[port_no].designated_port = config->port_id;
+       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)     */
+{
+       bridge_info.max_age = config->max_age;    /* (4.6.3.3)   */
+       bridge_info.hello_time = config->hello_time;
+       bridge_info.forward_delay = config->forward_delay;
+       if (config->flags & TOPOLOGY_CHANGE)
+               bridge_info.top_change = 1;
+}
+
+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) */
+               if (designated_port(port_no)      /* (4.6.4.3)   */
+                               &&
+                               (port_info[port_no].state != Disabled)
+                       ) {
+                       transmit_config(port_no); /* (4.6.4.3)   */
+               }                                 /* (4.6.1.2)   */
+       }
+}
+
+int
+designated_port(int port_no)
+{
+       return ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
+                bridge_info.bridge_id.BRIDGE_ID) == 0
+                )
+               &&
+               (port_info[port_no].designated_port
+                == port_info[port_no].port_id
+                )
+               );
+}
+
+void
+reply(int port_no)                                       /* (4.6.5)     */
+{
+       transmit_config(port_no);                 /* (4.6.5.3)   */
+}
+
+void
+transmit_tcn(void)
+{                                                /* (4.6.6)     */
+       int             port_no;
+
+       port_no = bridge_info.root_port;
+       tcn_bpdu[port_no].type = BPDU_TYPE_TOPO_CHANGE;
+       send_tcn_bpdu(port_no, &tcn_bpdu[bridge_info.root_port]);       /* (4.6.6.3)     */
+}
+
+void
+configuration_update(void)     /* (4.6.7) */
+{
+       root_selection();                         /* (4.6.7.3.1)         */
+       /* (4.6.8.2)     */
+       designated_port_selection();              /* (4.6.7.3.2)         */
+       /* (4.6.9.2)     */
+}
+
+void
+root_selection(void)
+{                                                /* (4.6.8) */
+       int             root_port;
+       int             port_no;
+       root_port = No_port;
+       for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.8.3.1) */
+               if (((!designated_port(port_no))
+                    &&
+                    (port_info[port_no].state != Disabled)
+                    &&
+               (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
+                       bridge_info.bridge_id.BRIDGE_ID) < 0)
+                       )
+                               &&
+                               ((root_port == No_port)
+                                ||
+                                (br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
+                                 port_info[root_port].designated_root.BRIDGE_ID) < 0
+                                 )
+                                ||
+                                ((br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
+                                  port_info[root_port].designated_root.BRIDGE_ID) == 0
+                                  )
+                                 &&
+                                 (((port_info[port_no].designated_cost
+                                    + port_info[port_no].path_cost
+                                    )
+                                   ==
+                                   (port_info[root_port].designated_cost
+                                    + port_info[root_port].path_cost
+                                    )            /* (4.6.8.3.1(2)) */
+                                   )
+                                  ||
+                                  (((port_info[port_no].designated_cost
+                                     + port_info[port_no].path_cost
+                                     )
+                                    ==
+                                    (port_info[root_port].designated_cost
+                                     + port_info[root_port].path_cost
+                                     )
+                                    )
+                                   &&
+                                   ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
+                                   port_info[root_port].designated_bridge.BRIDGE_ID) < 0
+                                     )           /* (4.6.8.3.1(3)) */
+                                    ||
+                                    ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
+                                  port_info[root_port].designated_bridge.BRIDGE_ID) == 0
+                                      )
+                                     &&
+                                     ((port_info[port_no].designated_port
+                                     < port_info[root_port].designated_port
+                                       )         /* (4.6.8.3.1(4)) */
+                                      ||
+                                      ((port_info[port_no].designated_port
+                                     = port_info[root_port].designated_port
+                                        )
+                                       &&
+                                       (port_info[port_no].port_id
+                                        < port_info[root_port].port_id
+                                        )        /* (4.6.8.3.1(5)) */
+                                       ))))))))) {
+                       root_port = port_no;
+               }
+       }
+       bridge_info.root_port = root_port;        /* (4.6.8.3.1)         */
+
+       if (root_port == No_port) {               /* (4.6.8.3.2)         */
+               bridge_info.designated_root = bridge_info.bridge_id;
+               /* (4.6.8.3.2(1)) */
+               bridge_info.root_path_cost = Zero;/* (4.6.8.3.2(2)) */
+       } else {                                  /* (4.6.8.3.3)         */
+               bridge_info.designated_root = port_info[root_port].designated_root;
+               /* (4.6.8.3.3(1)) */
+               bridge_info.root_path_cost = (port_info[root_port].designated_cost
+                                           + port_info[root_port].path_cost
+                       );                        /* (4.6.8.3.3(2)) */
+       }
+}
+
+void
+designated_port_selection(void)
+{                                                /* (4.6.9)     */
+       int             port_no;
+
+       for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.6.9.3)     */
+               if (designated_port(port_no)      /* (4.6.9.3.1)         */
+                               ||
+                               (
+                                br_cmp(port_info[port_no].designated_root.BRIDGE_ID,
+                                bridge_info.designated_root.BRIDGE_ID) != 0
+                                )
+                               ||
+                               (bridge_info.root_path_cost
+                                < port_info[port_no].designated_cost
+                                )                /* (4.6.9.3.3)         */
+                               ||
+                               ((bridge_info.root_path_cost
+                                 == port_info[port_no].designated_cost
+                                 )
+                                &&
+                                ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
+                                  port_info[port_no].designated_bridge.BRIDGE_ID) < 0
+                                  )              /* (4.6.9.3.4)         */
+                                 ||
+                                 ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
+                                   port_info[port_no].designated_bridge.BRIDGE_ID) == 0
+                                   )
+                                  &&
+                                  (port_info[port_no].port_id
+                                   <= port_info[port_no].designated_port
+                                   )             /* (4.6.9.3.5)         */
+                                  )))) {
+                       become_designated_port(port_no);        /* (4.6.10.3.2.2) */
+               }
+       }
+}
+
+void
+become_designated_port(int port_no)
+{                                                /* (4.6.10)    */
+
+       /* (4.6.10.3.1) */
+       port_info[port_no].designated_root = bridge_info.designated_root;
+       /* (4.6.10.3.2) */
+       port_info[port_no].designated_cost = bridge_info.root_path_cost;
+       /* (4.6.10.3.3) */
+       port_info[port_no].designated_bridge = bridge_info.bridge_id;
+       /* (4.6.10.3.4) */
+       port_info[port_no].designated_port = port_info[port_no].port_id;
+}
+
+void
+port_state_selection(void)
+{                                                /* (4.6.11) */
+       int             port_no;
+       for (port_no = One; port_no <= No_of_ports; port_no++) {
+               if (port_no == bridge_info.root_port) { /* (4.6.11.3.1) */
+                       port_info[port_no].config_pending = FALSE;      /* (4.6.11.3~1(1)) */
+                       port_info[port_no].top_change_ack = 0;
+                       make_forwarding(port_no); /* (4.6.11.3.1(2)) */
+               } else if (designated_port(port_no)) {  /* (4.6.11.3.2) */
+                       stop_message_age_timer(port_no);        /* (4.6.11.3.2(1)) */
+                       make_forwarding(port_no); /* (4.6.11.3.2(2)) */
+               } else {                          /* (4.6.11.3.3) */
+                       port_info[port_no].config_pending = FALSE;      /* (4.6.11.3.3(1)) */
+                       port_info[port_no].top_change_ack = 0;
+                       make_blocking(port_no);   /* (4.6.11.3.3(2)) */
+               }
+       }
+
+}
+
+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) */
+               start_forward_delay_timer(port_no);     /* (4.6.12.3.2) */
+       }
+}
+
+void 
+topology_change_detection(void)
+{                                                /* (4.6.14)       */
+       if (root_bridge()) {                      /* (4.6.14.3.1)   */
+               bridge_info.top_change = 1;
+               start_topology_change_timer();    /* (4.6.14.3.1(2)) */
+       } else if (!(bridge_info.top_change_detected)) {
+               transmit_tcn();                   /* (4.6.14.3.2(1)) */
+               start_tcn_timer();                /* (4.6.14.3.2(2)) */
+       }
+       bridge_info.top_change = 1;
+}
+
+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)
+{                                                /* (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)    */
+{
+
+       if ((port_info[port_no].state != Disabled)
+                       &&
+                       (port_info[port_no].state != Blocking)
+       /* (4.6.13.3)    */
+               ) {
+               if ((port_info[port_no].state == Forwarding)
+                               ||
+                               (port_info[port_no].state == Learning)
+                       ) {
+                       topology_change_detection();    /* (4.6.13.3.1) */
+                       /* (4.6.14.2.3)  */
+               }
+               set_port_state(port_no, Blocking);/* (4.6.13.3.2) */
+               stop_forward_delay_timer(port_no);/* (4.6.13.3.3) */
+       }
+}
+
+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)     */
+{
+       int         root;
+
+       root = root_bridge();
+       if (port_info[port_no].state != Disabled) {
+               if (supersedes_port_info(port_no, config)) {    /* (4.7.1.1)     *//* (4.
+                                                                * 6.2.2)        */
+                       record_config_information(port_no, config);     /* (4.7.1.1.1)   */
+                       /* (4.6.2.2)     */
+                       configuration_update();   /* (4.7.1.1.2)         */
+                       /* (4.6.7.2.1)   */
+                       port_state_selection();   /* (4.7.1.1.3)         */
+                       /* (4.6.11.2.1)  */
+                       if ((!root_bridge()) && root) { /* (4.7.1.1.4)   */
+                               stop_hello_timer();
+                               if (bridge_info.top_change_detected) {  /* (4.7.1.1.5~ */
+                                       stop_topology_change_timer();
+                                       transmit_tcn(); /* (4.6.6.1)     */
+                                       start_tcn_timer();
+                               }
+                       }
+                       if (port_no == bridge_info.root_port) {
+                               record_config_timeout_values(config);   /* (4.7.1.1.6)   */
+                               /* (4.6.3.2)     */
+                               config_bpdu_generation();       /* (4.6.4.2.1)   */
+                               if (config->flags & TOPOLOGY_CHANGE_ACK) {      /* (4.7.1.1.7)    */
+                                       topology_change_acknowledged(); /* (4.6.15.2)    */
+                               }
+                       }
+               } else if (designated_port(port_no)) {  /* (4.7.1.2)     */
+                       reply(port_no);           /* (4.7.1.2.1)         */
+                       /* (4.6.5.2)     */
+               }
+       }
+}
+
+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)) {
+                       topology_change_detection();    /* (4.7.2.1)     */
+                       /* (4.6.14.2.1)  */
+                       acknowledge_topology_change(port_no);   /* (4.7.2.2)     */
+               }                                 /* (4.6.16.2)  */
+       }
+}
+
+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)     */
+{
+       int         root;
+       root = root_bridge();
+
+       become_designated_port(port_no);          /* (4.7.4.1)   */
+       /* (4.6.10.2.1)  */
+       configuration_update();                   /* (4.7.4.2)   */
+       /* (4.6.7.2.2)   */
+       port_state_selection();                   /* (4.7.4.3)   */
+       /* (4.6.11.2.2)  */
+       if ((root_bridge()) && (!root)) {         /* (4.7.4.4)   */
+
+               bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.7.4.4.1)    */
+               bridge_info.hello_time = bridge_info.bridge_hello_time;
+               bridge_info.forward_delay = bridge_info.bridge_forward_delay;
+               topology_change_detection();      /* (4.7.4.4.2)         */
+               /* (4.6.14.2.4)  */
+               stop_tcn_timer();                 /* (4.7.4.4.3)         */
+               config_bpdu_generation();         /* (4.7.4.4.4)         */
+               /* (4.6.4.4.3)   */
+               start_hello_timer();
+       }
+}
+
+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)   */
+               start_forward_delay_timer(port_no);     /* (4.7.5.1.2)   */
+       } else if (port_info[port_no].state == Learning) {      /* (4.7.5.2) */
+               set_port_state(port_no, Forwarding);    /* (4.7.5.2.1) */
+               if (designated_for_some_port()) { /* (4.7.5.2.2) */
+                       topology_change_detection();    /* (4.6.14.2.2) */
+
+               }
+       }
+}
+
+int
+designated_for_some_port(void)
+{
+       int             port_no;
+
+
+       for (port_no = One; port_no <= No_of_ports; port_no++) {
+               if ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID,
+                               bridge_info.bridge_id.BRIDGE_ID) == 0)
+                       ) {
+                       return (TRUE);
+               }
+       }
+       return (FALSE);
+}
+
+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)
+{                                                /* (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)     */
+{
+       if (port_info[port_no].config_pending) {
+               transmit_config(port_no);         /* (4.7.8.1)   */
+       }                                         /* (4.6.1.2.3)         */
+}
+
+void
+br_init(void)
+{                                                /* (4.8.1)     */
+       int             port_no;
+
+       bridge_info.designated_root = bridge_info.bridge_id;    /* (4.8.1.1)     */
+       bridge_info.root_path_cost = Zero;
+       bridge_info.root_port = No_port;
+
+       bridge_info.bridge_max_age = BRIDGE_MAX_AGE;
+       bridge_info.bridge_hello_time = BRIDGE_HELLO_TIME;
+       bridge_info.bridge_forward_delay = BRIDGE_FORWARD_DELAY;
+       bridge_info.hold_time = HOLD_TIME;
+
+       bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.1.2)     */
+       bridge_info.hello_time = bridge_info.bridge_hello_time;
+       bridge_info.forward_delay = bridge_info.bridge_forward_delay;
+
+       bridge_info.top_change_detected = 0;
+       bridge_info.top_change = 0;
+       stop_tcn_timer();
+       stop_topology_change_timer();
+       for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.1.4) */
+               br_init_port(port_no);
+               disable_port(port_no);
+       }
+       port_state_selection();                   /* (4.8.1.5)   */
+       config_bpdu_generation();                 /* (4.8.1.6)   */
+       
+       /* initialize system timer */
+       tl.expires = HZ;        /* 1 second */
+       tl.function = br_tick;
+       add_timer(&tl);
+
+       register_netdevice_notifier(&br_dev_notifier);
+       br_stats.flags = BR_UP | BR_DEBUG;      /* enable bridge */
+       start_hello_timer();
+}
+
+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)    */
+       port_info[port_no].top_change_ack = 0;
+       port_info[port_no].config_pending = FALSE;/* (4.8.1.4.4)         */
+       stop_message_age_timer(port_no);          /* (4.8.1.4.5)         */
+       stop_forward_delay_timer(port_no);        /* (4.8.1.4.6)         */
+       stop_hold_timer(port_no);                 /* (4.8.1.4.7)         */
+}
+
+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)     */
+{
+       int         root;
+
+       root = root_bridge();
+       become_designated_port(port_no);          /* (4.8.3.1)   */
+       set_port_state(port_no, Disabled);        /* (4.8.3.2)   */
+       port_info[port_no].top_change_ack = 0;
+       port_info[port_no].config_pending = FALSE;/* (4.8.3.4)   */
+       stop_message_age_timer(port_no);          /* (4.8.3.5)   */
+       stop_forward_delay_timer(port_no);        /* (4.8.3.6)   */
+       configuration_update();
+       port_state_selection();                   /* (4.8.3.7)   */
+       if ((root_bridge()) && (!root)) {         /* (4.8.3.8)   */
+               bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.3.8.1)    */
+               bridge_info.hello_time = bridge_info.bridge_hello_time;
+               bridge_info.forward_delay = bridge_info.bridge_forward_delay;
+               topology_change_detection();      /* (4.8.3.8.2)    */
+               stop_tcn_timer();                 /* (4.8.3.8.3)    */
+               config_bpdu_generation();         /* (4.8.3.8.4)    */
+               start_hello_timer();
+       }
+}
+
+
+void
+set_bridge_priority(bridge_id_t *new_bridge_id)                  /* (4.8.4)     */
+{
+
+       int         root;
+       int             port_no;
+       root = root_bridge();
+       for (port_no = One; port_no <= No_of_ports; port_no++) {        /* (4.8.4.2) */
+               if (designated_port(port_no)) {
+                       port_info[port_no].designated_bridge = *new_bridge_id;
+               }
+       }
+
+       bridge_info.bridge_id = *new_bridge_id;   /* (4.8.4.3)   */
+       configuration_update();                   /* (4.8.4.4)   */
+       port_state_selection();                   /* (4.8.4.5)   */
+       if ((root_bridge()) && (!root)) {         /* (4.8.4.6)   */
+               bridge_info.max_age = bridge_info.bridge_max_age;       /* (4.8.4.6.1)    */
+               bridge_info.hello_time = bridge_info.bridge_hello_time;
+               bridge_info.forward_delay = bridge_info.bridge_forward_delay;
+               topology_change_detection();      /* (4.8.4.6.2)    */
+               stop_tcn_timer();                 /* (4.8.4.6.3)    */
+               config_bpdu_generation(),         /* (4.8.4.6.4)    */
+               start_hello_timer();
+       }
+}
+
+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;
+       }
+       port_info[port_no].port_id = new_port_id; /* (4.8.5.3)   */
+       if ((br_cmp(bridge_info.bridge_id.BRIDGE_ID,
+            port_info[port_no].designated_bridge.BRIDGE_ID) == 0
+            )
+                       &&
+                       (port_info[port_no].port_id
+                        < port_info[port_no].designated_port
+
+                        )
+               ) {
+               become_designated_port(port_no);  /* (4.8.5.4.1) */
+               port_state_selection();           /* (4.8.5.4.2) */
+       }
+}
+
+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)   */
+       port_state_selection();                   /* (4.8.6.3)   */
+}
+
+static void
+br_tick(unsigned long arg)
+{
+       int             port_no;
+
+       if (hello_timer_expired()) {
+               hello_timer_expiry();
+       }
+       if (tcn_timer_expired()) {
+               tcn_timer_expiry();
+       }
+       if (topology_change_timer_expired()) {
+               topology_change_timer_expiry();
+       }
+       for (port_no = One; port_no <= No_of_ports; port_no++) {
+               if (forward_delay_timer_expired(port_no)) {
+                       forward_delay_timer_expiry(port_no);
+               }
+               if (message_age_timer_expired(port_no)) {
+                       message_age_timer_expiry(port_no);
+               }
+               if (hold_timer_expired(port_no)) {
+                       hold_timer_expiry(port_no);
+               }
+       }
+       /* call me again sometime... */
+       tl.expires = HZ;        /* 1 second */
+       tl.function = br_tick;
+       add_timer(&tl);
+}
+
+void
+start_hello_timer(void)
+{
+       hello_timer.value = 0;
+       hello_timer.active = TRUE;
+}
+
+void
+stop_hello_timer(void)
+{
+       hello_timer.active = FALSE;
+}
+
+int
+hello_timer_expired(void)
+{
+       if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) {
+               hello_timer.active = FALSE;
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+void
+start_tcn_timer(void)
+{
+       tcn_timer.value = 0;
+       tcn_timer.active = TRUE;
+}
+
+void
+stop_tcn_timer(void)
+{
+       tcn_timer.active = FALSE;
+}
+
+int
+tcn_timer_expired(void)
+{
+       if (tcn_timer.active && (++tcn_timer.value >=
+                                bridge_info.bridge_hello_time)) {
+               tcn_timer.active = FALSE;
+               return (TRUE);
+       }
+       return (FALSE);
+
+}
+
+void
+start_topology_change_timer(void)
+{
+       topology_change_timer.value = 0;
+       topology_change_timer.active = TRUE;
+}
+
+void
+stop_topology_change_timer(void)
+{
+       topology_change_timer.active = FALSE;
+}
+
+int
+topology_change_timer_expired(void)
+{
+       if (topology_change_timer.active
+                       && (++topology_change_timer.value
+                           >= bridge_info.topology_change_time
+                           )) {
+               topology_change_timer.active = FALSE;
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+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)
+{
+       message_age_timer[port_no].active = FALSE;
+}
+
+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)) {
+               message_age_timer[port_no].active = FALSE;
+               return (TRUE);
+       }
+       return (FALSE);
+}
+
+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)
+{
+       forward_delay_timer[port_no].active = FALSE;
+}
+
+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)) {
+                       forward_delay_timer[port_no].active = FALSE;
+                       return (TRUE);
+               }
+               return (FALSE);
+}
+
+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)
+{
+       hold_timer[port_no].active = FALSE;
+}
+
+
+int
+hold_timer_expired(int port_no)
+{
+       if (hold_timer[port_no].active &&
+                  (++hold_timer[port_no].value >= bridge_info.hold_time)) {
+               hold_timer[port_no].active = FALSE;
+               return (TRUE);
+       }
+       return (FALSE);
+
+}
+
+int
+send_config_bpdu(int port_no, Config_bpdu *config_bpdu)
+{
+struct sk_buff *skb;
+struct device *dev = port_info[port_no].dev;
+int size;
+unsigned long flags;
+       
+       if (port_info[port_no].state == Disabled) {
+               printk("send_config_bpdu: port %i not valid\n",port_no);
+               return(-1);
+               }
+       if (br_stats.flags & BR_DEBUG)
+               printk("send_config_bpdu: ");
+       /*
+        * create and send the message
+        */
+       size = sizeof(Config_bpdu) + dev->hard_header_len;
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (skb == NULL) {
+               printk("send_config_bpdu: no skb available\n");
+               return(-1);
+               }
+       skb->dev = dev;
+       skb->free = 1;
+       skb->h.eth = (struct ethhdr *)skb_put(skb, size);
+       memcpy(skb->h.eth->h_dest, bridge_ula, ETH_ALEN);
+       memcpy(skb->h.eth->h_source, dev->dev_addr, ETH_ALEN);
+       if (br_stats.flags & BR_DEBUG)
+               printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
+                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                       port_no,
+                       skb->h.eth->h_source[0],
+                       skb->h.eth->h_source[1],
+                       skb->h.eth->h_source[2],
+                       skb->h.eth->h_source[3],
+                       skb->h.eth->h_source[4],
+                       skb->h.eth->h_source[5],
+                       skb->h.eth->h_dest[0],
+                       skb->h.eth->h_dest[1],
+                       skb->h.eth->h_dest[2],
+                       skb->h.eth->h_dest[3],
+                       skb->h.eth->h_dest[4],
+                       skb->h.eth->h_dest[5]);
+       skb->h.eth->h_proto = htonl(0x8038);    /* XXX verify */
+
+       skb->h.raw += skb->dev->hard_header_len;
+       memcpy(skb->h.raw, config_bpdu, sizeof(Config_bpdu));
+
+       /* won't get bridged again... */
+       skb->pkt_bridged = IS_BRIDGED;
+       skb->arp = 1;   /* do not resolve... */
+       skb->h.raw = skb->data + ETH_HLEN;
+       save_flags(flags);
+       cli();
+       skb_queue_tail(dev->buffs, skb);
+       restore_flags(flags);
+       return(0);
+}
+
+int
+send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu)
+{
+struct sk_buff *skb;
+struct device *dev = port_info[port_no].dev;
+int size;
+unsigned long flags;
+       
+       if (port_info[port_no].state == Disabled) {
+               printk("send_tcn_bpdu: port %i not valid\n",port_no);
+               return(-1);
+               }
+       if (br_stats.flags & BR_DEBUG)
+               printk("send_tcn_bpdu: ");
+       size = sizeof(Tcn_bpdu) + dev->hard_header_len;
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (skb == NULL) {
+               printk("send_tcn_bpdu: no skb available\n");
+               return(-1);
+               }
+       skb->dev = dev;
+       skb->free = 1;
+       skb->h.eth = (struct ethhdr *)skb_put(skb,size);
+       memcpy(skb->h.eth->h_dest, bridge_ula, ETH_ALEN);
+       memcpy(skb->h.eth->h_source, dev->dev_addr, ETH_ALEN);
+       if (br_stats.flags & BR_DEBUG)
+               printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
+                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                       port_no,
+                       skb->h.eth->h_source[0],
+                       skb->h.eth->h_source[1],
+                       skb->h.eth->h_source[2],
+                       skb->h.eth->h_source[3],
+                       skb->h.eth->h_source[4],
+                       skb->h.eth->h_source[5],
+                       skb->h.eth->h_dest[0],
+                       skb->h.eth->h_dest[1],
+                       skb->h.eth->h_dest[2],
+                       skb->h.eth->h_dest[3],
+                       skb->h.eth->h_dest[4],
+                       skb->h.eth->h_dest[5]);
+       skb->h.eth->h_proto = 0x8038;   /* XXX verify */
+
+       skb->h.raw += skb->dev->hard_header_len;
+       memcpy(skb->h.raw, bpdu, sizeof(Tcn_bpdu));
+
+       /* mark that's we've been here... */
+       skb->pkt_bridged = IS_BRIDGED;
+       skb->arp = 1;   /* do not resolve... */
+       skb->h.raw = skb->data + ETH_HLEN;
+       save_flags(flags);
+       cli();
+       skb_queue_tail(dev->buffs, skb);
+       restore_flags(flags);
+       return(0);
+}
+
+static int 
+br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
+{
+       struct device *dev = ptr;
+       int i;
+
+       /* check for loopback devices */
+       if (dev->flags & IFF_LOOPBACK)
+               return(NOTIFY_DONE);
+
+       switch (event) {
+       case NETDEV_DOWN:
+               if (br_stats.flags & BR_DEBUG)
+                       printk("br_device_event: NETDEV_DOWN...\n");
+               /* find our device and mark it down */
+               for (i = One; i <= No_of_ports; i++) {
+                       if (port_info[i].dev == dev) {
+                               disable_port(i);
+                               return NOTIFY_DONE;
+                               break;
+                       }
+               }
+               break;
+       case NETDEV_UP:
+               if (br_stats.flags & BR_DEBUG)
+                       printk("br_device_event: NETDEV_UP...\n");
+               /* Only handle ethernet ports */
+               if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK)
+                       return NOTIFY_DONE;
+               /* look up an unused device and enable it */
+               for (i = One; i <= No_of_ports; i++) {
+                       if ((port_info[i].dev == (struct device *)0) ||
+                               (port_info[i].dev == dev)) {
+                               port_info[i].dev = dev;
+                               enable_port(i);
+                               set_path_cost(i, br_port_cost(dev));
+                               set_port_priority(i, 128); 
+                               port_info[i].port_id = i;
+                               /* set bridge addr from 1st device addr */
+                               if ((bridge_info.bridge_id.BRIDGE_ID[0] == 0) &&
+                                               (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) {
+                                       memcpy(bridge_info.bridge_id.BRIDGE_ID_ULA, dev->dev_addr, 6);
+                                       bridge_info.bridge_id.BRIDGE_PRIORITY = port_info[i].port_id;
+                                       set_bridge_priority(&bridge_info.bridge_id);
+                               }       
+                               make_forwarding(i);
+                               return NOTIFY_DONE;
+                               break;
+                       }
+               }
+               break;
+       default:
+               printk("br_device_event: unknown event [%x]\n",
+                       (unsigned int)event);
+       }
+       return NOTIFY_DONE;
+}
+
+/*
+ * following routine is called when a frame is received
+ * from an interface, it returns 1 when it consumes the
+ * frame, 0 when it does not
+ */
+
+int
+br_receive_frame(struct sk_buff *skb)  /* 3.5 */
+{
+       int port;
+       
+       if (br_stats.flags & BR_DEBUG)
+               printk("br_receive_frame: ");
+       /* sanity */
+       if (!skb) {
+               printk("no skb!\n");
+               return(1);
+       }
+       /* check for loopback */
+       if (skb->dev->flags & IFF_LOOPBACK)
+               return(0);
+
+       port = find_port(skb->dev);
+       skb->h.raw = skb->data;
+       if (br_stats.flags & BR_DEBUG)
+               printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\
+                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                       port,
+                       skb->h.eth->h_source[0],
+                       skb->h.eth->h_source[1],
+                       skb->h.eth->h_source[2],
+                       skb->h.eth->h_source[3],
+                       skb->h.eth->h_source[4],
+                       skb->h.eth->h_source[5],
+                       skb->h.eth->h_dest[0],
+                       skb->h.eth->h_dest[1],
+                       skb->h.eth->h_dest[2],
+                       skb->h.eth->h_dest[3],
+                       skb->h.eth->h_dest[4],
+                       skb->h.eth->h_dest[5]);
+
+       if (!port) {
+               printk("\nbr_receive_frame: no port!\n");
+               return(0);
+       }
+
+       switch (port_info[port].state) {
+               case Learning:
+                       (void) br_learn(skb, port);     /* 3.8 */
+                       /* fall through */
+               case Listening:
+                       /* process BPDUs */
+                       if (memcmp(skb->h.eth->h_dest, bridge_ula, 6) == 0) {
+                               br_bpdu(skb);
+                               return(1); /* br_bpdu consumes skb */
+                       }
+                       /* fall through */
+               case Blocking:
+                       /* fall through */
+               case Disabled:
+                       /* should drop frames, but for now, we let
+                        * them get passed up to the next higher layer
+                       return(br_drop(skb));   
+                        */
+                       return(0);      /* pass frame up stack */
+                       break;
+               case Forwarding:
+                       (void) br_learn(skb, port);     /* 3.8 */
+                       /* process BPDUs */
+                       if (memcmp(skb->h.eth->h_dest, bridge_ula, 
+                                       ETH_ALEN) == 0) {
+                               printk("frame bpdu processor for me!!!\n");
+                               br_bpdu(skb);
+                               return(1); /* br_bpdu consumes skb */
+                       }
+                       /* is frame for me? */  
+                       if (memcmp(skb->h.eth->h_dest, 
+                                       port_info[port].dev->dev_addr, 
+                                       ETH_ALEN) == 0) {
+                               return(0);      /* pass frame up our stack (this will */
+                                               /* happen in net_bh() in dev.c) */
+                       }
+                       /* ok, forward this frame... */
+                       return(br_forward(skb, port));
+               default:
+                       printk("br_receive_frame: port [%i] unknown state [%i]\n",
+                               port, port_info[port].state);
+                       return(0);      /* pass frame up stack? */
+       }
+}
+
+/*
+ * the following routine is called to transmit frames from the host
+ * stack.  it returns 1 when it consumes the frame and
+ * 0 when it does not.
+ */
+
+int
+br_tx_frame(struct sk_buff *skb)       /* 3.5 */
+{
+       int port;
+       
+       /* sanity */
+       if (!skb) {
+               printk("br_tx_frame: no skb!\n");
+               return(0);
+       }
+       /* check for loopback */
+       if (skb->dev->flags & IFF_LOOPBACK)
+               return(0);
+
+       skb->h.raw = skb->data;
+       port = 0;       /* an impossible port */        
+       if (br_stats.flags & BR_DEBUG)
+               printk("br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x\
+                       dest %02x:%02x:%02x:%02x:%02x:%02x\n", 
+                       port,
+                       skb->h.eth->h_source[0],
+                       skb->h.eth->h_source[1],
+                       skb->h.eth->h_source[2],
+                       skb->h.eth->h_source[3],
+                       skb->h.eth->h_source[4],
+                       skb->h.eth->h_source[5],
+                       skb->h.eth->h_dest[0],
+                       skb->h.eth->h_dest[1],
+                       skb->h.eth->h_dest[2],
+                       skb->h.eth->h_dest[3],
+                       skb->h.eth->h_dest[4],
+                       skb->h.eth->h_dest[5]);
+       return(br_forward(skb, port));
+}
+
+/*
+ * this routine returns 0 when it learns (or updates) from the
+ * frame, and -1 if the frame is simply discarded due to port
+ * state or lack of resources...
+ */
+
+int
+br_learn(struct sk_buff *skb, int port)        /* 3.8 */
+{
+       struct fdb *f;
+
+       switch (port_info[port].state) {
+               case Listening:
+               case Blocking:
+               case Disabled:
+               default:
+                       return(-1);
+                       /* break; */
+               case Learning:
+               case Forwarding:
+                       /* don't keep group addresses in the tree */
+                       if (skb->h.eth->h_source[0] & 0x01)
+                               return(-1);
+                       
+                       f = (struct fdb *)kmalloc(sizeof(struct fdb), 
+                               GFP_ATOMIC);
+
+                       if (!f) {
+                               printk("br_learn: unable to malloc fdb\n");
+                               return(-1);
+                       }
+                       f->port = port; /* source port */
+                       memcpy(f->ula, skb->h.eth->h_source, 6);
+                       f->timer = CURRENT_TIME;
+                       f->flags = FDB_ENT_VALID;
+                       /*
+                        * add entity to AVL tree.  If entity already
+                        * exists in the tree, update the fields with
+                        * what we have here.
+                        */
+                       if (br_avl_insert(f) == 0) { /* update */
+                               kfree(f);
+                               return(0);
+                       }
+                       /* add to head of port chain */
+                       f->fdb_next = port_info[port].fdb;
+                       port_info[port].fdb = f;
+                       return(0);
+                       /* break */
+       }
+}
+
+/*
+ * this routine always consumes the frame
+ */
+
+int
+br_drop(struct sk_buff *skb)
+{
+       kfree_skb(skb, 0);
+       return(1);
+}
+
+/*
+ * this routine returns 1 if it consumes the frame, 0
+ * if not...
+ */
+
+int
+br_forward(struct sk_buff *skb, int port)      /* 3.7 */
+{
+struct fdb *f;
+unsigned long flags;
+       
+       /*
+        * flood all ports with frames destined for a group
+        * address.  If frame came from above, drop it,
+        * otherwise it will be handled in br_receive_frame()
+        * Multicast frames will also need to be seen
+        * by our upper layers.
+        */     
+       if (skb->h.eth->h_dest[0] & 0x01) {     /* group address */
+               br_flood(skb, port);
+               if (port == 0)                  /* locally generated */
+                       return(br_drop(skb));
+               return(0);
+       } else {
+               /* locate port to forward to */
+               f = br_avl_find_addr(skb->h.eth->h_dest);
+               if (!f | !(f->flags & FDB_ENT_VALID)) {
+                       /* not found; flood all ports */
+                       br_flood(skb, port);
+                       return(br_drop(skb));
+               }
+               if (port_info[f->port].state == Forwarding) {
+                       /* has entry expired? */
+                       if (f->timer + fdb_aging_time < CURRENT_TIME) {
+                               /* timer expired, invalidate entry */
+                               f->flags &= ~FDB_ENT_VALID;
+                               if (br_stats.flags & BR_DEBUG)
+                                       printk("fdb entry expired...\n");
+                               br_flood(skb, port);
+                               return(br_drop(skb));
+                       }
+                       /* mark that's we've been here... */
+                       skb->pkt_bridged = IS_BRIDGED;
+                       
+                       /*
+                        * if the frame is originating in this host,
+                        * we may need to resolve the outgoing address
+                       if (port != 0)
+                               skb->arp = 1;
+                        */
+               
+                       /* reset the skb->ip pointer */ 
+                       skb->h.raw = skb->data + ETH_HLEN;
+
+                       /* we must unlock the skb before requeueing it... */
+                       if (skb_device_locked(skb))
+                               skb_device_unlock(skb);
+
+                       save_flags(flags);      /* enter critical section */
+                       cli();
+                       skb_queue_head(port_info[f->port].dev->buffs, skb);
+                       restore_flags(flags);   /* exit critical section */
+                       return(1);      /* skb has been consumed */
+               } else {
+                       return(br_drop(skb));
+               }
+       }
+}
+
+/*
+ * this routine sends a copy of the frame to all forwarding ports
+ * with the exception of the port given.  This routine never
+ * consumes the original frame.
+ */
+       
+int
+br_flood(struct sk_buff *skb, int port)
+{
+int i;
+struct sk_buff *nskb;
+unsigned long flags;
+
+       for (i = One; i <= No_of_ports; i++) {
+               if (i == port)
+                       continue;
+               if (port_info[i].state == Forwarding) {
+                       nskb = skb_clone(skb, GFP_ATOMIC);
+                       /* mark that's we've been here... */
+                       nskb->pkt_bridged = IS_BRIDGED;
+                       /*
+                        * if the frame is originating in this host,
+                        * we may need to resolve the outgoing address
+                       if (port != 0)
+                               nskb->arp = 1;
+                        */
+                       nskb->h.raw = nskb->data + ETH_HLEN;
+                       save_flags(flags);
+                       cli();
+                       skb_queue_tail(port_info[i].dev->buffs, nskb);
+                       restore_flags(flags);
+               }
+       }
+       return(0);
+}
+
+int
+find_port(struct device *dev)
+{
+int i;
+
+       for (i = One; i <= No_of_ports; i++)
+               if ((port_info[i].dev == dev) && 
+                       (port_info[i].state != Disabled))
+                       return(i);
+       return(0);
+}
+
+int
+br_port_cost(struct device *dev)       /* 4.10.2 */
+{
+       if (strncmp(dev->name, "eth", 3) == 0)  /* ethernet */
+               return(100);
+       if (strncmp(dev->name, "wic", 3) == 0)  /* wic */
+               return(1600);
+       if (strncmp(dev->name, "plip",4) == 0) /* plip */
+               return (1600);
+       return(100);    /* default */
+}
+
+/*
+ * this routine always consumes the skb 
+ */
+
+void
+br_bpdu(struct sk_buff *skb) /* consumes skb */
+{
+Tcn_bpdu *bpdu;
+int port;
+
+       port = find_port(skb->dev);
+       if (port == 0) {        /* unknown port */
+               br_drop(skb);
+               return;
+       }
+               
+       bpdu = (Tcn_bpdu *)skb->data + ETH_HLEN;
+       switch (bpdu->type) {
+               case BPDU_TYPE_CONFIG:
+                       received_config_bpdu(port, (Config_bpdu *)bpdu);
+                       break;
+               case BPDU_TYPE_TOPO_CHANGE:
+                       received_tcn_bpdu(port, bpdu);
+                       break;
+               default:
+                       printk("br_bpdu: received unknown bpdu, type = %i\n",
+                               bpdu->type);
+                       /* break; */
+       }
+       br_drop(skb);
+}
+
+int
+br_ioctl(unsigned int cmd, void *arg)
+{
+       int err;
+       struct br_cf bcf;
+       int i;
+
+       switch(cmd)
+       {
+               case SIOCGIFBR: /* get bridging control blocks */
+                       err = verify_area(VERIFY_WRITE, arg, 
+                               sizeof(struct br_stat));
+                       if(err)
+                               return err;
+                       memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
+                       memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
+                       memcpy_tofs(arg, &br_stats, sizeof(struct br_stat));
+                       return(0);
+               case SIOCSIFBR:
+                       if (!suser())
+                               return -EPERM;
+                       err = verify_area(VERIFY_READ, arg, 
+                               sizeof(struct br_cf));
+                       if(err)
+                               return err;
+                       memcpy_fromfs(&bcf, arg, sizeof(struct br_cf));
+                       switch (bcf.cmd) {
+                               case BRCMD_BRIDGE_ENABLE:
+                                       if (br_stats.flags & BR_UP)
+                                               return(-EALREADY);      
+                                       printk("br: enabling bridging function\n");
+                                       register_netdevice_notifier(&br_dev_notifier);
+                                       br_stats.flags |= BR_UP;        /* enable bridge */
+                                       start_hello_timer();
+                                       break;
+                               case BRCMD_BRIDGE_DISABLE:
+                                       if (!(br_stats.flags & BR_UP))
+                                               return(-EALREADY);      
+                                       printk("br: disabling bridging function\n");
+                                       unregister_netdevice_notifier(&br_dev_notifier);
+                                       br_stats.flags &= ~BR_UP;       /* disable bridge */
+                                       stop_hello_timer();
+                                       for (i = One; i <= No_of_ports; i++)
+                                               if (port_info[i].state != Disabled)
+                                                       disable_port(i);
+                                       break;
+                               case BRCMD_PORT_ENABLE:
+                                       if (port_info[bcf.arg1].dev == 0)
+                                               return(-EINVAL);
+                                       if (port_info[bcf.arg1].state != Disabled)
+                                               return(-EALREADY);
+                                       printk("br: enabling port %i\n",bcf.arg1);
+                                       enable_port(bcf.arg1);
+                                       break;
+                               case BRCMD_PORT_DISABLE:
+                                       if (port_info[bcf.arg1].dev == 0)
+                                               return(-EINVAL);
+                                       if (port_info[bcf.arg1].state == Disabled)
+                                               return(-EALREADY);
+                                       printk("br: disabling port %i\n",bcf.arg1);
+                                       disable_port(bcf.arg1);
+                                       break;
+                               case BRCMD_SET_BRIDGE_PRIORITY:
+                                       set_bridge_priority((bridge_id_t *)&bcf.arg1);
+                                       break;
+                               case BRCMD_SET_PORT_PRIORITY:
+                                       if (port_info[bcf.arg1].dev == 0)
+                                               return(-EINVAL);
+                                       set_port_priority(bcf.arg1, bcf.arg2);
+                                       break;
+                               case BRCMD_SET_PATH_COST:
+                                       if (port_info[bcf.arg1].dev == 0)
+                                               return(-EINVAL);
+                                       set_path_cost(bcf.arg1, bcf.arg2);
+                                       break;
+                               case BRCMD_ENABLE_DEBUG:
+                                       br_stats.flags |= BR_DEBUG;
+                                       break;
+                               case BRCMD_DISABLE_DEBUG:
+                                       br_stats.flags &= ~BR_DEBUG;
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+                       return(0);
+               default:
+                       return -EINVAL;
+       }
+       /*NOTREACHED*/
+       return 0;
+}
+
+int br_cmp(unsigned int *a, unsigned int *b)
+{
+       int i;  
+       for (i=0; i<2; i++) {
+               if (a[i] == b[i])
+                       continue;
+               if (a[i] < b[i])
+                       return(1);
+               if (a[i] > b[i])
+                       return(-1);
+       }
+       return(0);
+}
+               
diff --git a/net/bridge/br_tree.c b/net/bridge/br_tree.c
new file mode 100644 (file)
index 0000000..70c34ad
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * this code is derived from the avl functions in mmap.c
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/skbuff.h>
+
+#include <net/br.h>
+#define _DEBUG_AVL
+
+/*
+ * Use an AVL (Adelson-Velskii and Landis) tree to speed up this search
+ * from O(n) to O(log n), where n is the number of ULAs.
+ * Written by Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>.
+ * Taken from mmap.c, extensively modified by John Hayes 
+ * <hayes@netplumbing.com>
+ */
+
+struct fdb fdb_head;
+struct fdb *fhp = &fdb_head;
+struct fdb **fhpp = &fhp;
+static int fdb_inited = 0;
+
+int addr_cmp(unsigned char *a1, unsigned char *a2);
+static void printk_avl (struct fdb * tree);
+
+/*
+ * fdb_head is the AVL tree corresponding to fdb
+ * or, more exactly, its root.
+ * A fdb has the following fields:
+ *   fdb_avl_left     left son of a tree node
+ *   fdb_avl_right    right son of a tree node
+ *   fdb_avl_height   1+max(heightof(left),heightof(right))
+ * The empty tree is represented as NULL.
+ */
+#ifndef avl_br_empty
+#define avl_br_empty   (struct fdb *) NULL
+#endif
+
+/* Since the trees are balanced, their height will never be large. */
+#define avl_maxheight  127
+#define heightof(tree) ((tree) == avl_br_empty ? 0 : (tree)->fdb_avl_height)
+/*
+ * Consistency and balancing rules:
+ * 1. tree->fdb_avl_height == 1+max(heightof(tree->fdb_avl_left),heightof(tree->fdb_avl_right))
+ * 2. abs( heightof(tree->fdb_avl_left) - heightof(tree->fdb_avl_right) ) <= 1
+ * 3. foreach node in tree->fdb_avl_left: node->fdb_avl_key <= tree->fdb_avl_key,
+ *    foreach node in tree->fdb_avl_right: node->fdb_avl_key >= tree->fdb_avl_key.
+ */
+
+int
+fdb_init(void)
+{
+       fdb_head.fdb_avl_height = 0;
+       fdb_head.fdb_avl_left = (struct fdb *)0;
+       fdb_head.fdb_avl_right = (struct fdb *)0;
+       fdb_inited = 1;
+       return(0);
+}
+
+struct fdb *
+br_avl_find_addr(unsigned char addr[6])
+{
+       struct fdb * result = NULL;
+       struct fdb * tree;
+
+       if (!fdb_inited)
+               fdb_init();
+#if (DEBUG_AVL)
+       printk("searching for ula %02x:%02x:%02x:%02x:%02x:%02x\n",
+               addr[0],
+               addr[1],
+               addr[2],
+               addr[3],
+               addr[4],
+               addr[5]);
+#endif /* DEBUG_AVL */
+       for (tree = &fdb_head ; ; ) {
+               if (tree == avl_br_empty) {
+#if (DEBUG_AVL)
+                       printk("search failed, returning node 0x%x\n", (unsigned int)result);
+#endif /* DEBUG_AVL */
+                       return result;
+               }
+
+#if (DEBUG_AVL)
+               printk("node 0x%x: checking ula %02x:%02x:%02x:%02x:%02x:%02x\n",
+                       (unsigned int)tree,
+                       tree->ula[0],
+                       tree->ula[1],
+                       tree->ula[2],
+                       tree->ula[3],
+                       tree->ula[4],
+                       tree->ula[5]);
+#endif /* DEBUG_AVL */
+               if (addr_cmp(addr, tree->ula) == 0) {
+#if (DEBUG_AVL)
+                       printk("found node 0x%x\n", (unsigned int)tree);
+#endif /* DEBUG_AVL */
+                       return tree;
+               }
+               if (addr_cmp(addr, tree->ula) < 0) {
+                       tree = tree->fdb_avl_left;
+               } else {
+                       tree = tree->fdb_avl_right;
+               }
+       }
+}
+
+/*
+ * 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)
+{
+       if (!fdb_inited)
+               fdb_init();
+       for ( ; count > 0 ; count--) {
+               struct fdb ** nodeplace = *--nodeplaces_ptr;
+               struct fdb * node = *nodeplace;
+               struct fdb * nodeleft = node->fdb_avl_left;
+               struct fdb * noderight = node->fdb_avl_right;
+               int heightleft = heightof(nodeleft);
+               int heightright = heightof(noderight);
+               if (heightright + 1 < heightleft) {
+                       /*                                                      */
+                       /*                            *                         */
+                       /*                          /   \                       */
+                       /*                       n+2      n                     */
+                       /*                                                      */
+                       struct fdb * nodeleftleft = nodeleft->fdb_avl_left;
+                       struct fdb * nodeleftright = nodeleft->fdb_avl_right;
+                       int heightleftright = heightof(nodeleftright);
+                       if (heightof(nodeleftleft) >= heightleftright) {
+                               /*                                                        */
+                               /*                *                    n+2|n+3            */
+                               /*              /   \                  /    \             */
+                               /*           n+2      n      -->      /   n+1|n+2         */
+                               /*           / \                      |    /    \         */
+                               /*         n+1 n|n+1                 n+1  n|n+1  n        */
+                               /*                                                        */
+                               node->fdb_avl_left = nodeleftright; 
+                               nodeleft->fdb_avl_right = node;
+                               nodeleft->fdb_avl_height = 1 + (node->fdb_avl_height = 1 + heightleftright);
+                               *nodeplace = nodeleft;
+                       } else {
+                               /*                                                        */
+                               /*                *                     n+2               */
+                               /*              /   \                 /     \             */
+                               /*           n+2      n      -->    n+1     n+1           */
+                               /*           / \                    / \     / \           */
+                               /*          n  n+1                 n   L   R   n          */
+                               /*             / \                                        */
+                               /*            L   R                                       */
+                               /*                                                        */
+                               nodeleft->fdb_avl_right = nodeleftright->fdb_avl_left;
+                               node->fdb_avl_left = nodeleftright->fdb_avl_right;
+                               nodeleftright->fdb_avl_left = nodeleft;
+                               nodeleftright->fdb_avl_right = node;
+                               nodeleft->fdb_avl_height = node->fdb_avl_height = heightleftright;
+                               nodeleftright->fdb_avl_height = heightleft;
+                               *nodeplace = nodeleftright;
+                       }
+               } else if (heightleft + 1 < heightright) {
+                       /* similar to the above, just interchange 'left' <--> 'right' */
+                       struct fdb * noderightright = noderight->fdb_avl_right;
+                       struct fdb * noderightleft = noderight->fdb_avl_left;
+                       int heightrightleft = heightof(noderightleft);
+                       if (heightof(noderightright) >= heightrightleft) {
+                               node->fdb_avl_right = noderightleft; 
+                               noderight->fdb_avl_left = node;
+                               noderight->fdb_avl_height = 1 + (node->fdb_avl_height = 1 + heightrightleft);
+                               *nodeplace = noderight;
+                       } else {
+                               noderight->fdb_avl_left = noderightleft->fdb_avl_right;
+                               node->fdb_avl_right = noderightleft->fdb_avl_left;
+                               noderightleft->fdb_avl_right = noderight;
+                               noderightleft->fdb_avl_left = node;
+                               noderight->fdb_avl_height = node->fdb_avl_height = heightrightleft;
+                               noderightleft->fdb_avl_height = heightright;
+                               *nodeplace = noderightleft;
+                       }
+               } else {
+                       int height = (heightleft<heightright ? heightright : heightleft) + 1;
+                       if (height == node->fdb_avl_height)
+                               break;
+                       node->fdb_avl_height = height;
+               }
+       }
+#ifdef DEBUG_AVL
+       printk_avl(&fdb_head);
+#endif /* DEBUG_AVL */
+}
+
+/* Insert a node into a tree. */
+int 
+br_avl_insert (struct fdb * new_node)
+{
+       struct fdb ** nodeplace = fhpp;
+       struct fdb ** stack[avl_maxheight];
+       int stack_count = 0;
+       struct fdb *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
+       if (!fdb_inited)
+               fdb_init();
+       for (;;) {
+               struct fdb *node;
+               
+               node = *nodeplace;
+               if (node == avl_br_empty)
+                       break;
+               *stack_ptr++ = nodeplace; stack_count++;
+               if (addr_cmp(new_node->ula, node->ula) == 0) { /* update */
+                       node->flags = new_node->flags;
+                       node->timer = new_node->timer;  
+                       return(0);
+               }
+               if (addr_cmp(new_node->ula, node->ula) < 0) {
+                       nodeplace = &node->fdb_avl_left;
+               } else {
+                       nodeplace = &node->fdb_avl_right;
+               }
+       }
+#if (DEBUG_AVL)
+       printk("node 0x%x: adding ula %02x:%02x:%02x:%02x:%02x:%02x\n",
+               (unsigned int)new_node,
+               new_node->ula[0],
+               new_node->ula[1],
+               new_node->ula[2],
+               new_node->ula[3],
+               new_node->ula[4],
+               new_node->ula[5]);
+#endif /* (DEBUG_AVL) */
+       new_node->fdb_avl_left = avl_br_empty;
+       new_node->fdb_avl_right = avl_br_empty;
+       new_node->fdb_avl_height = 1;
+       *nodeplace = new_node;
+#if (0)        
+       br_avl_rebalance(stack_ptr,stack_count);
+#endif /* (0) */
+#ifdef DEBUG_AVL
+       printk_avl(&fdb_head);
+#endif /* DEBUG_AVL */
+       return(1);
+}
+
+/* Removes a node out of a tree. */
+int
+br_avl_remove (struct fdb * node_to_delete)
+{
+       struct fdb ** nodeplace = fhpp;
+       struct fdb ** stack[avl_maxheight];
+       int stack_count = 0;
+       struct fdb *** stack_ptr = &stack[0]; /* = &stack[stackcount] */
+       struct fdb ** nodeplace_to_delete;
+       if (!fdb_inited)
+               fdb_init();
+       for (;;) {
+               struct fdb * node = *nodeplace;
+               if (node == avl_br_empty) {
+                       /* what? node_to_delete not found in tree? */
+                       printk("avl_remove: node to delete not found in tree\n");
+                       return(-1);
+               }
+               *stack_ptr++ = nodeplace; stack_count++;
+               if (addr_cmp(node_to_delete->ula, node->ula) == 0)
+                               break;
+               if (addr_cmp(node_to_delete->ula, node->ula) < 0)
+                       nodeplace = &node->fdb_avl_left;
+               else
+                       nodeplace = &node->fdb_avl_right;
+       }
+       nodeplace_to_delete = nodeplace;
+       /* Have to remove node_to_delete = *nodeplace_to_delete. */
+       if (node_to_delete->fdb_avl_left == avl_br_empty) {
+               *nodeplace_to_delete = node_to_delete->fdb_avl_right;
+               stack_ptr--; stack_count--;
+       } else {
+               struct fdb *** stack_ptr_to_delete = stack_ptr;
+               struct fdb ** nodeplace = &node_to_delete->fdb_avl_left;
+               struct fdb * node;
+               for (;;) {
+                       node = *nodeplace;
+                       if (node->fdb_avl_right == avl_br_empty)
+                               break;
+                       *stack_ptr++ = nodeplace; stack_count++;
+                       nodeplace = &node->fdb_avl_right;
+               }
+               *nodeplace = node->fdb_avl_left;
+               /* node replaces node_to_delete */
+               node->fdb_avl_left = node_to_delete->fdb_avl_left;
+               node->fdb_avl_right = node_to_delete->fdb_avl_right;
+               node->fdb_avl_height = node_to_delete->fdb_avl_height;
+               *nodeplace_to_delete = node; /* replace node_to_delete */
+               *stack_ptr_to_delete = &node->fdb_avl_left; /* replace &node_to_delete->fdb_avl_left */
+       }
+       br_avl_rebalance(stack_ptr,stack_count);
+       return(0);
+}
+
+#ifdef DEBUG_AVL
+
+/* print a tree */
+static void printk_avl (struct fdb * tree)
+{
+       if (tree != avl_br_empty) {
+               printk("(");
+               printk("%02x:%02x:%02x:%02x:%02x:%02x",
+                       tree->ula[0],
+                       tree->ula[1],
+                       tree->ula[2],
+                       tree->ula[3],
+                       tree->ula[4],
+                       tree->ula[5]);
+               if (tree->fdb_avl_left != avl_br_empty) {
+                       printk_avl(tree->fdb_avl_left);
+                       printk("<");
+               }
+               if (tree->fdb_avl_right != avl_br_empty) {
+                       printk(">");
+                       printk_avl(tree->fdb_avl_right);
+               }
+               printk(")\n");
+       }
+}
+
+#if (0)
+static char *avl_check_point = "somewhere";
+
+/* check a tree's consistency and balancing */
+static void avl_checkheights (struct fdb * tree)
+{
+       int h, hl, hr;
+
+       if (tree == avl_br_empty)
+               return;
+       avl_checkheights(tree->fdb_avl_left);
+       avl_checkheights(tree->fdb_avl_right);
+       h = tree->fdb_avl_height;
+       hl = heightof(tree->fdb_avl_left);
+       hr = heightof(tree->fdb_avl_right);
+       if ((h == hl+1) && (hr <= hl) && (hl <= hr+1))
+               return;
+       if ((h == hr+1) && (hl <= hr) && (hr <= hl+1))
+               return;
+       printk("%s: avl_checkheights: heights inconsistent\n",avl_check_point);
+}
+
+/* check that all values stored in a tree are < key */
+static void avl_checkleft (struct fdb * tree, fdb_avl_key_t key)
+{
+       if (tree == avl_br_empty)
+               return;
+       avl_checkleft(tree->fdb_avl_left,key);
+       avl_checkleft(tree->fdb_avl_right,key);
+       if (tree->fdb_avl_key < key)
+               return;
+       printk("%s: avl_checkleft: left key %lu >= top key %lu\n",avl_check_point,tree->fdb_avl_key,key);
+}
+
+/* check that all values stored in a tree are > key */
+static void avl_checkright (struct fdb * tree, fdb_avl_key_t key)
+{
+       if (tree == avl_br_empty)
+               return;
+       avl_checkright(tree->fdb_avl_left,key);
+       avl_checkright(tree->fdb_avl_right,key);
+       if (tree->fdb_avl_key > key)
+               return;
+       printk("%s: avl_checkright: right key %lu <= top key %lu\n",avl_check_point,tree->fdb_avl_key,key);
+}
+
+/* check that all values are properly increasing */
+static void avl_checkorder (struct fdb * tree)
+{
+       if (tree == avl_br_empty)
+               return;
+       avl_checkorder(tree->fdb_avl_left);
+       avl_checkorder(tree->fdb_avl_right);
+       avl_checkleft(tree->fdb_avl_left,tree->fdb_avl_key);
+       avl_checkright(tree->fdb_avl_right,tree->fdb_avl_key);
+}
+
+#endif /* (0) */
+#endif /* DEBUG_AVL */
+
+int
+addr_cmp(unsigned char a1[], unsigned char a2[])
+{
+       int i;
+
+       for (i=0; i<6; i++) {
+               if (a1[i] > a2[i]) return(1);
+               if (a1[i] < a2[i]) return(-1);
+       }
+       return(0);
+}
+
index e2acb2484a70fc49c0a948faedcaa2a102366401..c4216d0e9edecd60bf86e2d63f90a39ec5c79996 100644 (file)
@@ -16,7 +16,7 @@ ifdef CONFIG_NET
 O_OBJS += dev.o dev_mcast.o
 
 ifdef CONFIG_FIREWALL
-O_OBJS += firewall.o
+OX_OBJS += firewall.o
 endif
 
 ifdef CONFIG_NET_ALIAS
index 05eeb884a89b376b4d0ab67641db17bae6daad3e..166a3cc2165f7c40b46a05337f6af4ac96f0138b 100644 (file)
@@ -75,6 +75,7 @@
 #include <net/slhc.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <net/br.h>
 #ifdef CONFIG_NET_ALIAS
 #include <linux/net_alias.h>
 #endif
@@ -216,15 +217,15 @@ struct device *dev_get(const char *name)
 
 extern __inline__ void dev_load(const char *name)
 {
-        if(!dev_get(name)) {
+       if(!dev_get(name)) {
 #ifdef CONFIG_NET_ALIAS
-               const char *sptr;
+               const char *sptr;
  
-                for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break;
-                if (!(*sptr && *(sptr+1)))
+               for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break;
+               if (!(*sptr && *(sptr+1)))
 #endif
-                        request_module(name);
-        }
+               request_module(name);
+       }
 }
 
 #endif
@@ -391,6 +392,20 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
        if (net_alias_is(dev))
                skb->dev = dev = net_alias_main_dev(dev);
 #endif
+
+       /*
+        *      If we are bridging and this is directly generated output
+        *      pass the frame via the bridge.
+        */
+
+#ifdef CONFIG_BRIDGE
+       if(skb->pkt_bridged!=IS_BRIDGED && br_stats.flags & BR_UP)
+       {
+               if(br_tx_frame(skb))
+                       return;
+       }
+#endif
+
        list = dev->buffs + pri;
 
        save_flags(flags);
@@ -502,11 +517,7 @@ void netif_rx(struct sk_buff *skb)
         *      hardware interrupt returns.
         */
 
-#ifdef CONFIG_NET_RUNONIRQ     /* Dont enable yet, needs some driver mods */
-       net_bh();
-#else
        mark_bh(NET_BH);
-#endif
        return;
 }
 
@@ -584,12 +595,29 @@ void net_bh(void)
                backlog_size--;
                sti();
                
-              /*
-               *       Bump the pointer to the next structure.
-               *
-               *       On entry to the protocol layer. skb->data and
-               *       skb->h.raw point to the MAC and encapsulated data
-               */
+
+#ifdef CONFIG_BRIDGE
+
+               /*
+                *      If we are bridging then pass the frame up to the
+                *      bridging code. If it is bridged then move on
+                */
+                
+               if (br_stats.flags & BR_UP)
+               {
+                       cli();
+                       if(br_receive_frame(skb))
+                               continue;
+                       sti();
+               }
+#endif
+               
+               /*
+                *      Bump the pointer to the next structure.
+                * 
+                *      On entry to the protocol layer. skb->data and
+                *      skb->h.raw point to the MAC and encapsulated data
+                */
 
                skb->h.raw = skb->data;
 
@@ -604,6 +632,7 @@ void net_bh(void)
                 *      list. There are two lists. The ptype_all list of taps (normally empty)
                 *      and the main protocol list which is hashed perfectly for normal protocols.
                 */
+               
                pt_prev = NULL;
                for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next)
                {
@@ -775,8 +804,8 @@ static int dev_ifconf(char *arg)
 
        for (dev = dev_base; dev != NULL; dev = dev->next) 
        {
-               if(!(dev->flags & IFF_UP))      /* Downed devices don't count */
-                       continue;
+               if(!(dev->flags & IFF_UP))      /* Downed devices don't count */
+                       continue;
                /*
                 *      Have we run out of space here ?
                 */
@@ -1005,7 +1034,7 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                                 */                             
 
                                dev_mc_upload(dev);
-                       }
+                       }
                        break;
                
                case SIOCGIFADDR:       /* Get interface address (and family) */
@@ -1142,10 +1171,10 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                        if(ifr.ifr_mtu<68)
                                return -EINVAL;
 
-                        if (dev->change_mtu)
+                       if (dev->change_mtu)
                                ret = (*dev->change_mtu)(dev, ifr.ifr_mtu);
-                        else
-                        {
+                       else
+                       {
                                dev->mtu = ifr.ifr_mtu;
                                ret = 0;
                        }
@@ -1319,15 +1348,23 @@ int net_dev_init(void)
        skb_queue_head_init(&backlog);
        
        /*
-        * This is VeryUgly(tm).
+        *      The bridge has to be up before the devices
+        */
+
+#ifdef CONFIG_BRIDGE    
+       br_init();
+#endif 
+       
+       /*
+        * This is Very Ugly(tm).
         *
-        * Some devices want to be initialized eary..
+        * Some devices want to be initialized early..
         */
 #if defined(CONFIG_LANCE)
        lance_init();
 #endif
 #if defined(CONFIG_NI65)
-        ni65_init();
+       ni65_init();
 #endif
 #if defined(CONFIG_PI)
        pi_init();
@@ -1336,10 +1373,10 @@ int net_dev_init(void)
        pt_init();
 #endif
 #if defined(CONFIG_DLCI)
-        dlci_setup();
+       dlci_setup();
 #endif
 #if defined(CONFIG_SDLA)
-        sdla_setup();
+       sdla_setup();
 #endif
        /*
         *      SLHC if present needs attaching so other people see it
index 2f4f87c2fac99900c946bfafec9c19eedf164f5c..ee660673a3861cd3705b8b5ddf363465b0653c04 100644 (file)
@@ -5,7 +5,8 @@
  *     Authors:        Dave Bonn (for IP)
  *     much hacked by: Alan Cox
  */
+
+#include <linux/module.h> 
 #include <linux/skbuff.h>
 #include <linux/firewall.h>
 
@@ -145,9 +146,20 @@ int call_out_firewall(int pf, struct device *dev, void *phdr)
        return firewall_policy[pf];
 }
 
+static struct symbol_table firewall_syms = {
+#include <linux/symtab_begin.h>
+       X(register_firewall),
+       X(unregister_firewall),
+       X(call_in_firewall),
+       X(call_out_firewall),
+       X(call_fw_firewall),
+#include <linux/symtab_end.h>
+};
+
 void fwchain_init(void)
 {
        int i;
        for(i=0;i<NPROTO;i++)
                firewall_policy[i]=FW_ACCEPT;
+       register_symtab(&firewall_syms);
 }
index 02ae3a136c7949e9481624b5e93811649d7ab3e6..96d054de246374f5675cbcf2c4866bff55637400 100644 (file)
@@ -679,6 +679,7 @@ struct sk_buff *alloc_skb(unsigned int size,int priority)
        skb->free = 2;  /* Invalid so we pick up forgetful users */
        skb->lock = 0;
        skb->pkt_type = PACKET_HOST;    /* Default type */
+       skb->pkt_bridged = 0;           /* Not bridged */
        skb->prev = skb->next = skb->link3 = NULL;
        skb->list = NULL;
        skb->sk = NULL;
index 6eaa4ca8c0d06c3d78ca4c2034a2947660fa10ff..58731ea091f7a6a2f884989f598ebf6d78512c0d 100644 (file)
@@ -96,6 +96,9 @@
 #ifdef CONFIG_IP_ALIAS
 #include <net/ip_alias.h>
 #endif
+#ifdef CONFIG_BRIDGE
+#include <net/br.h>
+#endif
 #ifdef CONFIG_KERNELD
 #include <linux/kerneld.h>
 #endif
@@ -1276,6 +1279,14 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCGIFSLAVE:
                        return(dev_ioctl(cmd,(void *) arg));
 
+               case SIOCGIFBR:
+               case SIOCSIFBR:
+#ifdef CONFIG_BRIDGE           
+                       return(br_ioctl(cmd,(void *) arg));
+#else
+                       return -ENOPKG;
+#endif                                         
+                       
                default:
                        if ((cmd >= SIOCDEVPRIVATE) &&
                           (cmd <= (SIOCDEVPRIVATE + 15)))
index 31f1eea8f0d22fcf63f41ccc51092220e157eb2b..d7d4d0a7b74a1935a310041206d1aa4f22dac2ae 100644 (file)
@@ -495,7 +495,9 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
        /*
         *      We are a router. Routers should not respond to ICMP_REDIRECT messages.
         */
-       printk(KERN_INFO "icmp: ICMP redirect from %s on %s ignored.\n", in_ntoa(source), dev->name);
+       printk(KERN_INFO "icmp: ICMP redirect ignored. dest = %s, "
+              "orig gw = %s, \"new\" gw = %s, device = %s.\n", in_ntoa(ip),
+               in_ntoa(source), in_ntoa(icmph->un.gateway), dev->name);
 #else  
        switch(icmph->code & 7) 
        {
index 5e6dcf68f6f8865ec41b12215340009609cb8d80..1bdf6849cc2069e98abce189e53bd4ded21b8efc 100644 (file)
@@ -899,6 +899,44 @@ int ip_fw_ctl(int stage, void *m, int len)
                        return(ETIMEDOUT);
        }
 
+       if ( cmd == IP_FW_MASQ_TIMEOUTS )
+       {
+#ifdef CONFIG_IP_MASQUERADE
+               struct ip_fw_masq *masq;
+
+               if ( len != sizeof(struct ip_fw_masq) )
+               {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                       printk("ip_fw_ctl (masq): length %d, expected %d\n",
+                               len, sizeof(struct ip_fw_masq));
+
+#endif
+                       return( EINVAL );
+               }
+
+               masq = (struct ip_fw_masq *) m;
+
+               if (masq->tcp_timeout)
+               {
+                       ip_masq_expire->tcp_timeout = masq->tcp_timeout;
+               }
+
+               if (masq->tcp_fin_timeout)
+               {
+                       ip_masq_expire->tcp_fin_timeout = masq->tcp_fin_timeout;
+               }
+
+               if (masq->udp_timeout)
+               {
+                       ip_masq_expire->udp_timeout = masq->udp_timeout;
+               }
+
+               return 0;
+#else
+               return( EINVAL );
+#endif
+       }
+
 /*
  *     Here we really working hard-adding new elements
  *     to blocking/forwarding chains or deleting 'em
index 2cf9f2903d8218ee7d64affd086c343db159a734..04be37d63b279d0faf21db2f1f71d146847a7be9 100644 (file)
@@ -447,6 +447,15 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                                return 0;
                        skb->dev = dev;
                        iph=skb->h.iph;
+#ifdef CONFIG_IP_MASQUERADE
+                       if (ip_fw_demasquerade(&skb,dev))
+                       {
+                               struct iphdr *iph=skb->h.iph;
+                               if (ip_forward(skb, dev, IPFWD_MASQUERADED, iph->daddr))
+                                       kfree_skb(skb, FREE_WRITE);
+                               return 0;
+                       }
+#endif
                }
 
                /*
index 60f32848857384814be4def68e642d7a176fb0ac..bcb76f0cb4928c4fc4103bf1eb1f367e08370b2b 100644 (file)
@@ -72,6 +72,7 @@ static struct symbol_table ip_masq_syms = {
        X(ip_masq_new),
         X(ip_masq_set_expire),
         X(ip_masq_free_ports),
+       X(ip_masq_expire),
 #include <linux/symtab_end.h>
 };
 
@@ -82,6 +83,18 @@ static struct symbol_table ip_masq_syms = {
 struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE];
 struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE];
 
+/*
+ * timeouts
+ */
+
+static struct ip_fw_masq ip_masq_dummy = {
+       MASQUERADE_EXPIRE_TCP,
+       MASQUERADE_EXPIRE_TCP_FIN,
+       MASQUERADE_EXPIRE_UDP
+};
+
+struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
+
 /*
  *     Returns hash value
  */
@@ -409,7 +422,7 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
 
        if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
                return;
+
        /*
         *      Now hunt the list to see if we have an old entry
         */
@@ -472,7 +485,7 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
         
        if (iph->protocol==IPPROTO_UDP) 
        {
-                timeout = MASQUERADE_EXPIRE_UDP;
+                timeout = ip_masq_expire->udp_timeout;
                recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
        }
        else 
@@ -485,10 +498,10 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
                 */
                if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
                 {
-                        timeout = MASQUERADE_EXPIRE_TCP_FIN;
+                        timeout = ip_masq_expire->tcp_fin_timeout;
                        ms->flags |= IP_MASQ_F_SAW_FIN;
                }
-               else timeout = MASQUERADE_EXPIRE_TCP;
+               else timeout = ip_masq_expire->tcp_timeout;
  
                skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
                tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
@@ -516,10 +529,22 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev)
        struct iphdr    *iph = skb->h.iph;
        __u16   *portptr;
        struct ip_masq  *ms;
+       unsigned short  frag;
  
        if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
                return 0;
  
+       /*
+        * Toss fragments, since we handle them in ip_rcv()
+        */
+
+       frag = ntohs(iph->frag_off);
+
+       if ((frag & IP_MF) != 0 || (frag & IP_OFFSET) != 0)
+       {
+               return 0;
+       }
+
        portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
            ntohs(portptr[1]) > PORT_MASQ_END)
index 25598822c3821e6f1c7a882061cb0b2958f969ea..2fc8a4d4ec18d01093755216f660cf9d1356aa6b 100644 (file)
@@ -487,14 +487,26 @@ int ip_masq_app_init(void)
 
 static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
 {
-        int diff, o_offset;
+        int maxsize, diff, o_offset;
         struct sk_buff *n_skb;
 
+       maxsize = skb->truesize - sizeof(struct sk_buff);
+
         diff = n_len - o_len;
         o_offset = o_buf - (char*) skb->data;
 
-        if (diff != 0)  {
-                
+       if (maxsize <= n_len) {
+           if (diff != 0) {
+               memcpy(skb->data + o_offset + n_len,o_buf + o_len,
+                      skb->len - (o_offset + o_len));
+           }
+
+           memcpy(skb->data + o_offset, n_buf, n_len);
+
+           n_skb    = skb;
+           skb->len = n_len;
+           skb->end = skb->head+n_len;
+       } else {
                 /*
                  *     Sizes differ, make a copy
                  */
@@ -526,14 +538,6 @@ static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, i
                  */
                 
                 kfree_skb(skb, FREE_WRITE);
-                
-        } else {
-                
-                /*
-                 *     Same len, just copy
-                 */
-                n_skb = skb;
-                memcpy(n_skb->data + o_offset, n_buf, n_len);
         }
         return n_skb;
 }
index 1b7820eec12f0696e8f24e0175bfe5f7c70be5e4..941b5e3be211f51c698ff8de7c0ee2e6fe8e67f8 100644 (file)
@@ -112,7 +112,7 @@ masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
                if (n_ms==NULL)
                        return 0;
 
-                ip_masq_set_expire(n_ms, MASQUERADE_EXPIRE_TCP_FIN);
+                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout);
                 
                /*
                 * Replace the old PORT with the new one
index 33b3b4b96da496ab6e98304f3866a0c52614ab00..3cfa797c74a5475cbc9b66e5377ef0cd1d176b46 100644 (file)
@@ -173,7 +173,7 @@ masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb
                if (n_ms==NULL)
                        return 0;
 
-                ip_masq_set_expire(n_ms, MASQUERADE_EXPIRE_TCP_FIN);
+                ip_masq_set_expire(n_ms, ip_masq_expire->tcp_fin_timeout);
                 
                /*
                 * Replace the old "address port" with the new one
index 00cc7c71688b3f98c7493e3a51c60590aec3170f..8c066db62e49aa94e32fb612cd1deeaba0e555a4 100644 (file)
@@ -210,7 +210,7 @@ void ip_options_fragment(struct sk_buff * skb)
                        continue;
                }
                optlen = optptr[1];
-               if (l<2 || optlen>l)
+               if (optlen<2 || optlen>l)
                  return;
                if (!(*optptr & 0x80))
                        memset(optptr, IPOPT_NOOP, optlen);
@@ -274,7 +274,7 @@ int ip_options_compile(struct options * opt, struct sk_buff * skb)
                        continue;
                }
                optlen = optptr[1];
-               if (l<2 || optlen>l || !optlen)
+               if (optlen<2 || optlen>l)
                {
                        pp_ptr = optptr;
                        break;
index 5b02692abe5bee37cecbd69cb0219446aa71ea1c..0fdba9d5bed3aa5d6310b1ecaf9419470b2c8835 100644 (file)
@@ -21,6 +21,8 @@
  *     Fixes:
  *             Alan Cox        :       Missing nonblock feature in ip_build_xmit.
  *             Mike Kilburn    :       htons() missing in ip_build_xmit.
+ *             Bradford Johnson:       Fix faulty handling of some frames when 
+ *                                     no route is found.
  */
 
 #include <asm/segment.h>
@@ -168,7 +170,7 @@ static int ip_send_room(struct rtable * rt, struct sk_buff *skb, __u32 daddr, in
 #endif
                        skb->arp = 0;
                        skb->raddr = daddr;
-                       return -dev->hard_header_len;
+                       return dev->hard_header_len;
                }
                mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len);
                if (mac < 0)
@@ -265,7 +267,7 @@ int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr,
 
        skb->dev = *dev;
        skb->saddr = saddr;
-
+       
        /*
         *      Now build the IP header.
         */
index 4c1c552435c9a596362a6566aa2b85fde5ecb2fa..cec17ede68274d5adda22e372ee76f07ab52d9b3 100644 (file)
@@ -387,6 +387,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                case IP_FW_POLICY_IN:
                case IP_FW_POLICY_OUT:
                case IP_FW_POLICY_FWD:
+               case IP_FW_MASQ_TIMEOUTS:
                        if(!suser())
                                return -EPERM;
                        if(optlen>sizeof(tmp_fw) || optlen<1)
index 023149e1f4a49d4ebd6ef8d11c925390cc3256ff..68ce23ee0591b84032c218be0d55eb7b0aa6e03e 100644 (file)
@@ -1205,18 +1205,13 @@ out:
        
 
 /*
- *     Send an ack if one is backlogged at this point. Ought to merge
- *     this with tcp_send_ack().
+ *     Send an ack if one is backlogged at this point. 
+ *
  *      This is called for delayed acks also.
  */
  
 void tcp_read_wakeup(struct sock *sk)
 {
-       int tmp;
-       struct device *dev = NULL;
-       struct tcphdr *t1;
-       struct sk_buff *buff;
-
        if (!sk->ack_backlog) 
                return;
 
@@ -1227,57 +1222,7 @@ void tcp_read_wakeup(struct sock *sk)
        if ((sk->state == TCP_CLOSE) || (sk->state == TCP_TIME_WAIT))
                return; 
 
-       /*
-        * FIXME: we need to put code here to prevent this routine from
-        * being called.  Being called once in a while is ok, so only check
-        * if this is the second time in a row.
-        */
-
-       /*
-        * We need to grab some memory, and put together an ack,
-        * and then put it into the queue to be sent.
-        */
-
-       buff = sock_wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
-       if (buff == NULL) 
-       {
-               /* Try again real soon. */
-               tcp_reset_xmit_timer(sk, TIME_WRITE, HZ);
-               return;
-       }
-
-       buff->sk = sk;
-       buff->localroute = sk->localroute;
-       buff->csum = 0;
-       
-       /*
-        *      Put in the IP header and routing stuff. 
-        */
-
-       tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
-                              IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache);
-       if (tmp < 0) 
-       {
-               buff->free = 1;
-               sock_wfree(sk, buff);
-               return;
-       }
-
-       t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr));
-
-       memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
-       t1->seq = htonl(sk->sent_seq);
-
-       sk->ack_backlog = 0;
-       sk->bytes_rcv = 0;
-
-       sk->window = tcp_select_window(sk);
-       t1->window = htons(sk->window);
-       t1->ack_seq = htonl(sk->acked_seq);
-       t1->doff = sizeof(*t1)/4;
-       tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), buff);
-       sk->prot->queue_xmit(sk, dev, buff, 1);
-       tcp_statistics.TcpOutSegs++;
+       tcp_send_ack(sk);
 }
 
 
index 36b5101838affccab840d15aa9213cb3581f7fea..704afa7ca9891220b2a526b6791e77b2da49d9f1 100644 (file)
@@ -184,7 +184,7 @@ static void bad_tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
         *
         *      We also should be spotting triple bad sequences.
         */
-       tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
+       tcp_send_ack(sk);
        return;
 }
 
@@ -733,7 +733,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                 *      Was it a usable window open ?
                 */
                 
-               if (skb_peek(&sk->write_queue) != NULL &&   /* should always be non-null */
+               if (!skb_queue_empty(&sk->write_queue) &&   /* should always be true */
                    ! before (sk->window_seq, sk->write_queue.next->end_seq)) 
                {
                        sk->backoff = 0;
@@ -1204,8 +1204,7 @@ static inline u32 tcp_queue_ack(struct sk_buff * skb, struct sock * sk)
        return skb->end_seq;
 }      
 
-static void tcp_queue(struct sk_buff * skb, struct sock * sk,
-       struct tcphdr *th, unsigned long saddr)
+static void tcp_queue(struct sk_buff * skb, struct sock * sk, struct tcphdr *th)
 {
        u32 ack_seq;
 
@@ -1249,7 +1248,7 @@ static void tcp_queue(struct sk_buff * skb, struct sock * sk,
                 * side, so we only have to worry about the first two.
                 */
                if (!sk->delay_acks || th->fin) {
-                       tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
+                       tcp_send_ack(sk);
                }
                else
                {
@@ -1299,7 +1298,7 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk,
                 *      (someone sent us dataless, boring frame)
                 */
                if (!th->ack)
-                       tcp_send_ack(sk->sent_seq, sk->acked_seq,sk, th, saddr);
+                       tcp_send_ack(sk);
                kfree_skb(skb, FREE_READ);
                return(0);
        }
@@ -1361,7 +1360,7 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk,
 
 #endif
 
-       tcp_queue(skb, sk, th, saddr);
+       tcp_queue(skb, sk, th);
 
        /*
         *      If we've missed a packet, send an ack.
@@ -1370,7 +1369,7 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk,
         
        if (!skb->acked) 
        {
-               tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
+               tcp_send_ack(sk);
                sk->ack_backlog++;
                tcp_reset_xmit_timer(sk, TIME_WRITE, min(sk->ato, HZ/2));
        }
@@ -1715,7 +1714,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                                sk->acked_seq = skb->seq+1;
                                sk->lastwin_seq = skb->seq+1;
                                sk->fin_seq = skb->seq;
-                               tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr);
+                               tcp_send_ack(sk);
                                tcp_set_state(sk, TCP_ESTABLISHED);
                                tcp_options(sk,th);
                                sk->dummy_th.dest=th->source;
index 67d522b7b0324324ec26b4084ed83ec4cc3653a4..b195cc0834790fd75ac0e6018a94cb8271014196 100644 (file)
@@ -750,9 +750,7 @@ void tcp_send_synack(struct sock * newsk, struct sock * sk, struct sk_buff * skb
  *     This routine sends an ack and also updates the window. 
  */
  
-void tcp_send_ack(u32 sequence, u32 ack,
-            struct sock *sk,
-            struct tcphdr *th, u32 daddr)
+void tcp_send_ack(struct sock *sk)
 {
        struct sk_buff *buff;
        struct tcphdr *t1;
@@ -762,6 +760,26 @@ void tcp_send_ack(u32 sequence, u32 ack,
        if(sk->zapped)
                return;         /* We have been reset, we may not send again */
                
+       /*
+        *      If we have nothing queued for transmit and the transmit timer
+        *      is on we are just doing an ACK timeout and need to switch
+        *      to a keepalive.
+        */
+        
+       sk->ack_backlog = 0;
+       sk->bytes_rcv = 0;
+       sk->ack_timed = 0;
+
+       if (sk->send_head == NULL
+           && skb_queue_empty(&sk->write_queue)
+           && sk->ip_xmit_timeout == TIME_WRITE)
+       {
+               if(sk->keepopen)
+                       tcp_reset_xmit_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
+               else
+                       delete_timer(sk);
+       }
+
        /*
         * We need to grab some memory, and put together an ack,
         * and then put it into the queue to be sent.
@@ -797,7 +815,7 @@ void tcp_send_ack(u32 sequence, u32 ack,
         *      Put in the IP header and routing stuff. 
         */
         
-       tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
+       tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
                                IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache);
        if (tmp < 0) 
        {
@@ -807,45 +825,20 @@ void tcp_send_ack(u32 sequence, u32 ack,
        }
        t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr));
 
-       memcpy(t1, &sk->dummy_th, sizeof(*t1));
-
-       /*
-        *      Swap the send and the receive. 
-        */
-        
-       t1->dest = th->source;
-       t1->source = th->dest;
-       t1->seq = ntohl(sequence);
-       sk->window = tcp_select_window(sk);
-       t1->window = ntohs(sk->window);
-       
-       /*
-        *      If we have nothing queued for transmit and the transmit timer
-        *      is on we are just doing an ACK timeout and need to switch
-        *      to a keepalive.
-        */
-        
-       if (ack == sk->acked_seq) {               
-               sk->ack_backlog = 0;
-               sk->bytes_rcv = 0;
-               sk->ack_timed = 0;
-
-               if (sk->send_head == NULL && skb_peek(&sk->write_queue) == NULL
-                   && sk->ip_xmit_timeout == TIME_WRITE)       
-                 if(sk->keepopen) 
-                   tcp_reset_xmit_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN);
-                 else 
-                   delete_timer(sk);                           
-       }
-
        /*
         *      Fill in the packet and send it
         */
         
-       t1->ack_seq = htonl(ack);
-       tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), buff);
+       sk->window = tcp_select_window(sk);
+
+       memcpy(t1, &sk->dummy_th, sizeof(*t1));
+       t1->seq     = htonl(sk->sent_seq);
+       t1->ack_seq = htonl(sk->acked_seq);
+       t1->window  = htons(sk->window);
+
+       tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), buff);
        if (sk->debug)
-                printk("\rtcp_ack: seq %x ack %x\n", sequence, ack);
+                printk("\rtcp_ack: seq %x ack %x\n", sk->sent_seq, sk->acked_seq);
        sk->prot->queue_xmit(sk, dev, buff, 1);
        tcp_statistics.TcpOutSegs++;
 }
index 578ae2838308bff2bcf2665a6771bbf181690e10..b96fe375191e3ba1b0e0f2caaa2457947782a5a3 100644 (file)
@@ -2201,11 +2201,11 @@ static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
                                return -EPERM;
                        return(ipxrtr_ioctl(cmd,(void *)arg));
                case SIOCSIFADDR:
-               case SIOCGIFADDR:
                case SIOCAIPXITFCRT:
                case SIOCAIPXPRISLT:
                        if(!suser())
                                return -EPERM;
+               case SIOCGIFADDR:
                        return(ipxitf_ioctl(cmd,(void *)arg));
                case SIOCIPXCFGDATA: 
                {
@@ -2379,6 +2379,9 @@ ipx_proto_finito(void)
        unregister_snap_client(ipx_snap_id);
        pSNAP_datalink = NULL;
 
+       unregister_8022tr_client(ipx_8022_type);
+       p8022tr_datalink = NULL;
+
        unregister_8022_client(ipx_8022_type);
        p8022_datalink = NULL;
 
index fa2e8f949d164f2692460f886ed2639ae19a834d..4e586fda1cc45113fb227a105a7fc2d50a10b87f 100644 (file)
@@ -432,25 +432,11 @@ static int nr_create(struct socket *sock, int protocol)
        sk->socket        = sock;
        sk->type          = sock->type;
        sk->protocol      = protocol;
-       sk->dead          = 0;
-       sk->next          = NULL;
-       sk->broadcast     = 0;
        sk->allocation    = GFP_KERNEL;
        sk->rcvbuf        = SK_RMEM_MAX;
        sk->sndbuf        = SK_WMEM_MAX;
-       sk->wmem_alloc    = 0;
-       sk->rmem_alloc    = 0;
-       sk->users         = 0;
-       sk->debug         = 0;
-       sk->destroy       = 0;
-       sk->prot          = NULL;       /* So we use default free mechanisms */
-       sk->err           = 0;
-       sk->localroute    = 0;
-       sk->send_head     = NULL;
        sk->state         = TCP_CLOSE;
-       sk->shutdown      = 0;
        sk->priority      = SOPRI_NORMAL;
-       sk->ack_backlog   = 0;
        sk->mtu           = NETROM_MTU; /* 236 */
        sk->zapped        = 1;
        sk->window        = nr_default.window;
@@ -532,26 +518,13 @@ static struct sock *nr_make_new(struct sock *osk)
 
        sk->type        = osk->type;
        sk->socket      = osk->socket;
-       sk->dead        = 0;
-       sk->next        = NULL;
        sk->priority    = osk->priority;
-       sk->broadcast   = 0;
        sk->protocol    = osk->protocol;
        sk->rcvbuf      = osk->rcvbuf;
        sk->sndbuf      = osk->sndbuf;
-       sk->wmem_alloc  = 0;
-       sk->rmem_alloc  = 0;
-       sk->users       = 0;
-       sk->ack_backlog = 0;
-       sk->destroy     = 0;
-       sk->prot        = NULL; /* So we use default free mechanisms */
-       sk->err         = 0;
-       sk->localroute  = 0;
-       sk->send_head   = NULL;
        sk->debug       = osk->debug;
        sk->state       = TCP_ESTABLISHED;
        sk->window      = osk->window;
-       sk->shutdown    = 0;
        sk->mtu         = osk->mtu;
        sk->sleep       = osk->sleep;
        sk->zapped      = osk->zapped;
index eaa7c09c9d265238ede60e8cf9da8aef9d693430..605542b52852252b6c3350a826f54db18e202fff 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
-#include <linux/firewall.h>
 #include <linux/trdevice.h>
 #include <linux/ioport.h>
 
@@ -81,12 +80,6 @@ static struct symbol_table net_syms = {
        X(destroy_EII_client),
 #endif
 
-#ifdef CONFIG_FIREWALL
-       /* Firewall registration */
-       X(register_firewall),
-       X(unregister_firewall),
-#endif
-
 #ifdef CONFIG_INET
        /* Internet layer registration */
        X(inet_add_protocol),
@@ -148,6 +141,7 @@ static struct symbol_table net_syms = {
        X(ether_setup),
        X(eth_type_trans),
        X(eth_copy_and_sum),
+       X(arp_query),
        X(alloc_skb),
        X(kfree_skb),
        X(skb_clone),
@@ -169,11 +163,6 @@ static struct symbol_table net_syms = {
        X(tty_register_ldisc),
        X(kill_fasync),
        X(arp_query),
-#ifdef CONFIG_FIREWALL
-       X(call_in_firewall),
-       X(call_out_firewall),
-       X(call_fw_firewall),
-#endif
 #endif  /* CONFIG_INET */
 
 #include <linux/symtab_end.h>
index bf519d02079ea7ce29803daef368fdff70f55bcd..1ea23ad26b56d8a2e695c42f0c859f159a77088b 100644 (file)
@@ -309,28 +309,11 @@ static int unix_create(struct socket *sock, int protocol)
        sk->protinfo.af_unix.inode=NULL;
        sk->protinfo.af_unix.locks=1;           /* Us */
        sk->protinfo.af_unix.readsem=MUTEX;     /* single task reading lock */
-       sk->protinfo.af_unix.name=NULL;
-       sk->protinfo.af_unix.other=NULL;
-       sk->protocol=0;
-       sk->rmem_alloc=0;
-       sk->wmem_alloc=0;
-       sk->dead=0;
-       sk->next=NULL;
-       sk->broadcast=0;
        sk->rcvbuf=SK_RMEM_MAX;
        sk->sndbuf=SK_WMEM_MAX;
        sk->allocation=GFP_KERNEL;
-       sk->users=0;
-       sk->bsdism=0;
-       sk->debug=0;
-       sk->prot=NULL;
-       sk->err=0;
-       sk->localroute=0;
-       sk->send_head=NULL;
        sk->state=TCP_CLOSE;
        sk->priority=SOPRI_NORMAL;
-       sk->ack_backlog=0;
-       sk->shutdown=0;
        sk->state_change=def_callback1;
        sk->data_ready=def_callback2;
        sk->write_space=def_callback3;
@@ -339,7 +322,6 @@ static int unix_create(struct socket *sock, int protocol)
        sk->socket=sock;
        sock->data=(void *)sk;
        sk->sleep=sock->wait;
-       sk->zapped=0;
        unix_insert_socket(sk);
        return 0;
 }
index 41da88aadd305adcda9c00f06b8982525cf3ce17..8ee8995daa502bfb1fa53066baf743247683689d 100644 (file)
@@ -95,7 +95,7 @@ class NameList
   private:
     // Caution: Fixed Allocation!
     // This should suffice for awhile since 1.1.86 has only 2482 symbols.
-    KSym ksyms_0_[4096];
+    KSym ksyms_0_[8000];
     int cardinality_;
 
   public:
index 68df48a7ca666d0bf4d2b0b1bbf503f7d89b3a5a..94181a12d611082cab4df43dffb874a833e49203 100644 (file)
@@ -135,7 +135,7 @@ static struct condition * parse_if(char * pnt)
        pnt++;
        while(*pnt && *pnt != '`') *pnt1++ = *pnt++;
        *pnt1++ = '\0';
-       cpnt->variable = strdup(varname);
+       cpnt->variable.str = strdup(varname);
        if( *pnt == '`' ) pnt++;
        if( *pnt == '"' ) pnt++;
        continue;
@@ -147,7 +147,7 @@ static struct condition * parse_if(char * pnt)
        pnt++;
        while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
        *pnt1++ = '\0';
-       cpnt->variable = strdup(varname);
+       cpnt->variable.str = strdup(varname);
        if( *pnt == '"' ) pnt++;
        continue;
       }
@@ -156,7 +156,7 @@ static struct condition * parse_if(char * pnt)
     pnt1 = varname;
     while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
     *pnt1++ = '\0';
-    cpnt->variable = strdup(varname);
+    cpnt->variable.str = strdup(varname);
     if( *pnt == '"' ) pnt++;
     continue;
   }