Import 1.1.691.1.69
authorLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:45 +0000 (23 15:09 -0500)
committerLinus Torvalds<torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:45 +0000 (23 15:09 -0500)
89 files changed:
Makefile
arch/i386/config.in
drivers/block/blk.h
drivers/char/ChangeLog
drivers/char/lp.c
drivers/char/serial.c
drivers/char/tty_io.c
drivers/net/3c509.c
drivers/net/eexpress.c
drivers/net/lance.c
drivers/net/net_init.c
drivers/net/plip.c
drivers/scsi/ChangeLog
drivers/scsi/README.st
drivers/scsi/aha1542.c
drivers/scsi/buslogic.c
drivers/scsi/buslogic.h
drivers/scsi/eata.c
drivers/scsi/eata.h
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/scsi.c
drivers/scsi/scsi_ioctl.c
drivers/scsi/seagate.c
drivers/scsi/seagate.h
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/scsi/st.c
drivers/scsi/st.h
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.h
fs/Makefile
fs/binfmt_elf.c
fs/buffer.c
fs/exec.c
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/inode.c
fs/isofs/Makefile
fs/isofs/inode.c
fs/locks.c
fs/nfs/mmap.c
fs/proc/fd.c
ibcs/binfmt_elf.c
include/asm-i386/dma.h
include/linux/fs.h
include/linux/if.h
include/linux/in.h
include/linux/ip_fw.h[new file with mode: 0644]
include/linux/ipc.h
include/linux/mm.h
include/linux/mman.h
include/linux/netdevice.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/sockios.h
include/linux/termios.h
ipc/shm.c
ipc/util.c
kernel/exit.c
kernel/fork.c
kernel/ksyms.c
kernel/sys.c
mm/Makefile
mm/filemap.c[new file with mode: 0644]
mm/kmalloc.c
mm/memory.c
mm/mmap.c
mm/swap.c
net/inet/Makefile
net/inet/af_inet.c
net/inet/arp.c
net/inet/dev.c
net/inet/dev_mcast.c[new file with mode: 0644]
net/inet/igmp.c[new file with mode: 0644]
net/inet/igmp.h[new file with mode: 0644]
net/inet/ip.c
net/inet/ip.h
net/inet/ip_fw.c[new file with mode: 0644]
net/inet/protocol.c
net/inet/raw.c
net/inet/raw.h
net/inet/skbuff.c
net/inet/sock.c
net/inet/sock.h
net/inet/tcp.c
net/inet/tcp.h
net/inet/udp.c

index 203a9b3..3aeaa1c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6+1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 68
+SUBLEVEL = 69
 
 ARCH = i386
 
index 2c4bc4b..e88fad8 100644 (file)
@@ -20,6+20,9 @@ comment 'Networking options'
 bool 'TCP/IP networking' CONFIG_INET y
 if [ "$CONFIG_INET" "=" "y" ]; then
 bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n
+#bool 'IP multicasting (ALPHA)' CONFIG_IP_MULTICAST n
+#bool 'IP firewalling' CONFIG_IP_FIREWALL n
+#bool 'IP accounting' CONFIG_IP_ACCT n
 comment '(it is safe to leave these untouched)'
 bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
 bool 'Reverse ARP' CONFIG_INET_RARP n
@@ -95,6+98,10 @@ if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
        bool 'WD80*3 support' CONFIG_WD80x3 n
        bool 'SMC Ultra support' CONFIG_ULTRA n
 fi
+bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
+if [ "$CONFIG_LANCE" = "y" ]; then
+       bool '   with PCnet/PCI support' CONFIG_PCI y
+fi
 bool '3COM cards' CONFIG_NET_VENDOR_3COM y
 if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
        bool '3c501 support' CONFIG_EL1 n
@@ -107,32+114,41 @@ if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
 fi
 bool 'Other ISA cards' CONFIG_NET_ISA n
 if [ "$CONFIG_NET_ISA" = "y" ]; then
-       bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n
-       bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
+       bool 'Cabletron E21xx support' CONFIG_E2100 n
        bool 'DEPCA support' CONFIG_DEPCA n
        bool 'EtherWorks 3 support' CONFIG_EWRK3 n
        if [ "$CONFIG_NET_ALPHA" = "y" ]; then
-               bool 'EtherExpress support' CONFIG_EEXPRESS n
+#              bool 'Arcnet support' CONFIG_ARCNET n
                bool 'AT1700 support' CONFIG_AT1700 n
+#              bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
+               bool 'EtherExpress support' CONFIG_EEXPRESS n
                bool 'NI5210 support' CONFIG_NI52 n
                bool 'NI6510 support' CONFIG_NI65 n
        fi
-       bool 'HP PCLAN support' CONFIG_HPLAN n
-       bool 'HP PCLAN PLUS support' CONFIG_HPLAN_PLUS n
+       bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
+       bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
        bool 'NE2000/NE1000 support' CONFIG_NE2000 y
        bool 'SK_G16 support' CONFIG_SK_G16 n
 fi
-bool 'EISA and on board controllers' CONFIG_NET_EISA n
+bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
+if [ "$CONFIG_NET_EISA" = "y" ]; then
        if [ "$CONFIG_NET_ALPHA" = "y" ]; then
                bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
        fi
        bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
+#      bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
+#      bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
+#      bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
+       bool 'Zenith Z-Note support' CONFIG_ZNET y
+fi
 bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
 if [ "$CONFIG_NET_POCKET" = "y" ]; then
+       bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
        bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
        bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
-       bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
-       bool 'Zenith Z-Note support' CONFIG_ZNET n
+#      bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
+#      bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
+#      bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
 fi
 fi
 fi
index 53d55b1..26a4e89 100644 (file)
@@ -117,7+117,7 @@ static void floppy_off(unsigned int nr);
 
 #define DEVICE_NAME "scsitape"
 #define DEVICE_INTR do_st  
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (MINOR(device) & 0x7f)
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
index 78f1fb3..f6ff04b 100644 (file)
@@ -1,3+1,32 @@
+Tue Nov 29 10:21:09 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+       * tty_io.c (tty_unregister_driver): Fix bug in
+               tty_unregister_driver where the pointer to the refcount is
+               tested, instead of the refcount itself.  This caused
+               tty_unregister_driver to always return EBUSY.
+
+Sat Nov 26 11:59:24 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+       * tty_io.c (tty_ioctl): Add support for the new ioctl
+               TIOCTTYGSTRUCT, which allow a kernel debugging program
+               direct read access to the tty and tty_driver structures.
+
+Fri Nov 25 17:26:22 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+       * serial.c (rs_set_termios): Don't wake up processes blocked in
+               open when the CLOCAL flag changes, since a blocking
+               open only samples the CLOCAL flag once when it blocks,
+               and doesn't check it again.  (n.b.  FreeBSD has a
+               different behavior for blocking opens; it's not clear
+               whether Linux or FreeBSD's interpretation is correct.
+               POSIX doesn't give clear guidance on this issue, so
+               this may change in the future....)
+
+       * serial.c (block_til_ready): Use the correct termios structure to
+               check the CLOCAL flag.  If the cuaXX device is active,
+               then check the saved termios for the ttySXX device.
+               Otherwise, use the currently active termios structure.
+
 Sun Nov  6 21:05:44 1994  Theodore Y. Ts'o  (tytso@rt-11)
 
        * serial.c (change_speed): Add support for direct access of
index ea65813..dd95f96 100644 (file)
 #include <linux/sched.h>
 #include <linux/lp.h>
 #include <linux/malloc.h>
+#include <linux/ioport.h>
 
 #include <asm/io.h>
 #include <asm/segment.h>
index bd98305..46d56c9 100644 (file)
@@ -1773,9+1773,17 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
                rs_start(tty);
        }
 
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
        if (!(old_termios->c_cflag & CLOCAL) &&
            (tty->termios->c_cflag & CLOCAL))
                wake_up_interruptible(&info->open_wait);
+#endif
 }
 
 /*
@@ -1967,9+1975,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                return 0;
        }
 
-       if (info->normal_termios.c_cflag & CLOCAL)
-               do_clocal = 1;
-
+       if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+               if (info->normal_termios.c_cflag & CLOCAL)
+                       do_clocal = 1;
+       } else {
+               if (tty->termios->c_cflag & CLOCAL)
+                       do_clocal = 1;
+       }
+       
        /*
         * Block waiting for the carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
index 66782f4..2d9007b 100644 (file)
@@ -1438,6+1438,14 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                                default: 
                                        return -EINVAL;
                        }
+               case TIOCTTYGSTRUCT:
+                       retval = verify_area(VERIFY_WRITE, (void *) arg,
+                                               sizeof(struct tty_struct));
+                       if (retval)
+                               return retval;
+                       memcpy_tofs((struct tty_struct *) arg,
+                                   tty, sizeof(struct tty_struct));
+                       return 0;
                default:
                        if (tty->driver.ioctl) {
                                retval = (tty->driver.ioctl)(tty, file,
index f8f363c..1c90dd3 100644 (file)
@@ -633,8+633,13 @@ static void
 set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 {
        short ioaddr = dev->base_addr;
-       if (el3_debug > 1)
-               printk("%s: Setting Rx mode to %d addresses.\n", dev->name, num_addrs);
+       if (el3_debug > 1) {
+               static int old = 0;
+               if (old != num_addrs) {
+                       old = num_addrs;
+                       printk("%s: Setting Rx mode to %d addresses.\n", dev->name, num_addrs);
+               }
+       }
        if (num_addrs > 0) {
                outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
        } else if (num_addrs < 0) {
index ace82ca..d02b8ad 100644 (file)
        Rework the board error reset
        The statistics need to be updated correctly.
 
-        Modularized my Pauline Middelink <middelin@polyware.iaf.nl>
+        Modularized by Pauline Middelink <middelin@polyware.iaf.nl>
 */
 
 static char *version =
@@ -654,6+654,9 @@ eexp_close(struct device *dev)
 
        irq2dev_map[dev->irq] = 0;
 
+       /* release the ioport-region */
+       release_region(ioaddr, 16);
+
        /* Update the statistics here. */
 
 #ifdef MODULE
index d366d5f..afa99ea 100644 (file)
           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 */
 
-static char *version = "lance.c:v1.05 9/23/94 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "lance.c:v1.06 11/29/94 becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -26,6+26,8 @@ static char *version = "lance.c:v1.05 9/23/94 becker@cesdis.gsfc.nasa.gov\n";
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -37,7+39,7 @@ static char *version = "lance.c:v1.05 9/23/94 becker@cesdis.gsfc.nasa.gov\n";
 struct device *init_etherdev(struct device *dev, int sizeof_private,
                                                         unsigned long *mem_startp);
 static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};
-unsigned long lance_probe1(short ioaddr, unsigned long mem_start);
+unsigned long lance_probe1(int ioaddr, unsigned long mem_start);
 
 #ifdef HAVE_DEVLIST
 struct netdev_entry lance_drv =
@@ -72,7+74,7 @@ have on-board buffer memory needed to support the slower shared memory mode.)
 Most ISA boards have jumpered settings for the I/O base, IRQ line, and DMA
 channel.  This driver probes the likely base addresses:
 {0x300, 0x320, 0x340, 0x360}.
-After the board is found it generates an DMA-timeout interrupt and uses
+After the board is found it generates a DMA-timeout interrupt and uses
 autoIRQ to find the IRQ line.  The DMA channel can be set with the low bits
 of the otherwise-unused dev->mem_start value (aka PARAM1).  If unset it is
 probed for by enabling each free DMA channel in turn and checking if
@@ -102,7+104,7 @@ statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to
 avoid the administrative overhead. For the Rx side this avoids dynamically
 allocating full-sized buffers "just in case", at the expense of a
 memory-to-memory data copy for each packet received.  For most systems this
-is an good tradeoff: the Rx buffer will always be in low memory, the copy
+is a good tradeoff: the Rx buffer will always be in low memory, the copy
 is inexpensive, and it primes the cache for later packet processing.  For Tx
 the buffers are only used when needed as low-memory bounce buffers.
 
@@ -218,12+220,17 @@ static struct lance_chip_type {
        {0x0003, "PCnet/ISA 79C960", 0},        /* 79C960 PCnet/ISA.  */
        {0x2260, "PCnet/ISA+ 79C961", 0},       /* 79C961 PCnet/ISA+, Plug-n-Play.  */
        {0x2420, "PCnet/PCI 79C970", 0},        /* 79C970 or 79C974 PCnet-SCSI, PCI. */
-       {0x2430, "PCnet/VLB 79C965", 0},        /* 79C965 PCnet for VL bus. */
+       /* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
+               it the PCnet32. */
+       {0x2430, "PCnet32", 0},                         /* 79C965 PCnet for VL bus. */
        {0x0,    "PCnet (unknown)", 0},
 };
 
 enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, LANCE_UNKNOWN=5};
 
+/* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
+static unsigned char pci_irq_line = 0;
+
 static int lance_open(struct device *dev);
 static void lance_init_ring(struct device *dev);
 static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -239,12+246,41 @@ static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 
 /* This lance probe is unlike the other board probes in 1.0.*.  The LANCE may
    have to allocate a contiguous low-memory region for bounce buffers.
-   This requirement is satisfied by having the lance initialization occur before the
-   memory management system is started, and thus well before the other probes. */
+   This requirement is satisfied by having the lance initialization occur
+   before the memory management system is started, and thus well before the
+   other probes. */
+
 unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
 {
        int *port;
 
+#if defined(CONFIG_PCI)
+#define AMD_VENDOR_ID 0x1022
+#define AMD_DEVICE_ID 0x2000
+    if (pcibios_present()) {
+           int pci_index;
+               printk("lance.c: PCI bios is present, checking for devices...\n");
+               for (pci_index = 0; pci_index < 8; pci_index++) {
+                       unsigned char pci_bus, pci_device_fn;
+                       unsigned long pci_ioaddr;
+               
+                       if (pcibios_find_device (AMD_VENDOR_ID, AMD_DEVICE_ID, pci_index,
+                                                                        &pci_bus, &pci_device_fn) != 0)
+                               break;
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                                                        PCI_INTERRUPT_LINE, &pci_irq_line);
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
+                       /* Remove I/O space marker in bit 0. */
+                       pci_ioaddr &= ~3;
+                       printk("Found PCnet/PCI at %#lx, irq %d (mem_start is %#lx).\n",
+                                  pci_ioaddr, pci_irq_line, mem_start);
+                       mem_start = lance_probe1(pci_ioaddr, mem_start);
+                       pci_irq_line = 0;
+               }
+       }
+#endif  /* defined(CONFIG_PCI) */
+
        for (port = lance_portlist; *port; port++) {
                int ioaddr = *port;
 
@@ -258,7+294,7 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
        return mem_start;
 }
 
-unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
+unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
 {
        struct device *dev;
        struct lance_private *lp;
@@ -365,7+401,10 @@ unsigned long lance_probe1(short ioaddr, unsigned long mem_start)
        outw(0x0000, ioaddr+LANCE_ADDR);
        inw(ioaddr+LANCE_ADDR);
 
-       if (hp_builtin) {
+       if (pci_irq_line) {
+               dev->dma = 4;                   /* Native bus-master, no DMA channel needed. */
+               dev->irq = pci_irq_line;
+       } else if (hp_builtin) {
                char dma_tbl[4] = {3, 5, 6, 0};
                char irq_tbl[8] = {3, 4, 5, 9};
                unsigned char port_val = inb(hp_builtin);
@@ -494,7+533,8 @@ lance_open(struct device *dev)
        int ioaddr = dev->base_addr;
        int i;
 
-       if (request_irq(dev->irq, &lance_interrupt, 0, "lance")) {
+       if (dev->irq == 0 ||
+               request_irq(dev->irq, &lance_interrupt, 0, "lance")) {
                return -EAGAIN;
        }
 
@@ -840,7+880,7 @@ lance_rx(struct device *dev)
                int status = lp->rx_ring[entry].base >> 24;
 
                if (status != 0x03) {                   /* There was an error. */
-                       /* There is an tricky error noted by John Murphy,
+                       /* There is a tricky error noted by John Murphy,
                           <murf@perftech.com> to Russ Nelson: Even with full-sized
                           buffers it's possible for a jabber packet to use two
                           buffers, with only the last correctly noting the error. */
@@ -971,6+1011,8 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
                }
                outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
        } else {
+               /* Log any net taps. */
+               printk("%s: Promiscuous mode enabled.\n", dev->name);
                outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
        }
 
index a78dbf3..61946fb 100644 (file)
@@ -165,7+165,7 @@ void ether_setup(struct device *dev)
        }
 
        /* New-style flags. */
-       dev->flags              = IFF_BROADCAST;
+       dev->flags              = IFF_BROADCAST|IFF_MULTICAST;
        dev->family             = AF_INET;
        dev->pa_addr    = 0;
        dev->pa_brdaddr = 0;
index f54135a..577f1ed 100644 (file)
@@ -545,7+545,7 @@ plip_device_clear(struct device *dev)
     enable_irq(dev->irq);
 }
 
-/* PLIP_ERROR --- wait til other end settled */
+/* PLIP_ERROR --- wait till other end settled */
 static int
 plip_error(struct device *dev)
 {
index 2d5e8e9..cda1033 100644 (file)
+Tue Nov 29 15:43:50 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.68 released.
+
+       Add support for 12 byte vendor specific commands in scsi-generics,
+       more (i.e. the last manditory) low-level changes to support
+       loadable modules, plus a few other changes people have requested
+       lately.  Changes by me (ERY) unless otherwise noted.  Spelling
+       changes appear from some unknown corner of the universe.
+
+       * Throughout: Change COMMAND_SIZE() to use SCpnt->cmd_len.
+
+       * Throughout: Change info() low level function to take a Scsi_Host
+       pointer.  This way the info function can return specific
+       information about the host in question, if desired.
+
+       * All low-level drivers: Add NULL in initializer for the
+       usage_count field added to Scsi_Host_Template.
+
+       * aha152x.[c,h]: Remove redundant info() function.
+
+       * aha1542.[c,h]: Likewise.
+
+       * aha1740.[c,h]: Likewise.
+
+       * aha274x.[c,h]: Likewise.
+
+       * eata.[c,h]: Likewise.
+
+       * pas16.[c,h]: Likewise.
+
+       * scsi_debug.[c,h]: Likewise.
+
+       * t128.[c,h]: Likewise.
+
+       * u14-34f.[c,h]: Likewise.
+
+       * ultrastor.[c,h]: Likewise.
+
+       * wd7000.[c,h]: Likewise.
+
+       * aha1542.c: Add support for command line options with lilo to set
+       DMA parameters, I/O port.  From Matt Aarnio.
+
+       * buslogic.[c,h]: New version (1.13) from Dave Gentzel.
+
+       * hosts.h: Add new field to Scsi_Hosts "block" to allow blocking
+       all I/O to certain other cards.  Helps prevent problems with some
+       ISA motherboards.
+
+       * hosts.h: Add usage_count to Scsi_Host_Template.
+
+       * hosts.h: Add n_io_port to Scsi_Host (used when releasing module).
+
+       * hosts.c: Initialize block field.
+       
+       * in2000.c: Remove "static" declarations from exported functions.
+
+       * in2000.h: Likewise.
+
+       * scsi.c: Correctly set cmd_len field as required.  Save and
+       change setting when doing a request_sense, restore when done.
+       Move abort timeout message.  Fix panic in request_queueable to
+       print correct function name.
+
+       * scsi.c: When incrementing usage count, walk block linked list
+       for host, and or in SCSI_HOST_BLOCK bit.  When decrementing usage
+       count to 0, clear this bit to allow usage to continue, wake up
+       processes waiting.
+
+
+       * scsi_ioctl.c: If we have an info() function, call it, otherwise
+       if we have a "name" field, use it, else do nothing.
+
+       * sd.c, sr.c: Clear cmd_len field prior to each command we
+       generate.
+
+       * sd.h: Add "has_part_table" bit to rscsi_disks.
+
+       * sg.[c,h]: Add support for vendor specific 12 byte commands (i.e.
+       override command length in COMMAND_SIZE).
+
+       * sr.c: Bugfix from Gerd in photocd code.
+
+       * sr.c: Bugfix in get_sectorsize - always use scsi_malloc buffer -
+       we cannot guarantee that the stack is < 16Mb.
+
+Tue Nov 22 15:40:46 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.67 released.
+
+       * sr.c: Change spelling of manufactor to manufacturer.
+
+       * scsi.h: Likewise.
+
+       * scsi.c: Likewise.
+
+       * qlogic.c: Spelling corrections.
+
+       * in2000.h: Spelling corrections.
+
+       * in2000.c: Update from Bill Earnest, change from
+       jshiffle@netcom.com.  Support new bios versions.
+
+       * README.qlogic: Spelling correction.
+
+Tue Nov 22 15:40:46 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.66 released.
+
+       * u14-34f.c: Spelling corrections.
+
+       * sr.[h,c]: Add support for multi-session CDs from Gerd Knorr.
+
+       * scsi.h: Add manufactor field for keeping track of device
+       manufacturer.
+
+       * scsi.c: More spelling corrections.
+
+       * qlogic.h, qlogic.c, README.qlogic: New driver from Tom Zerucha.
+
+       * in2000.c, in2000.h: New driver from Brad McLean/Bill Earnest.
+
+       * fdomain.c: Spelling correction.
+
+       * eata.c: Spelling correction.
+
+Fri Nov 18 15:22:44 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.65 released.
+
+       * eata.h: Update version string to 1.08.00.
+
+       * eata.c: Set sg_tablesize correctly for DPT PM2012 boards.
+
+       * aha274x.seq: Spell checking.
+
+       * README.st: Likewise.
+
+       * README.aha274x: Likewise.
+
+       * ChangeLog: Likewise.
+
+Tue Nov 15 15:35:08 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.64 released.
+
+       * u14-34f.h: Update version number to 1.10.01.
+
+       * u14-34f.c: Use Scsi_Host can_queue variable instead of one from template.
+
+       * eata.[c,h]: New driver for DPT boards from Dario Ballabio.
+
+       * buslogic.c: Use can_queue field.
+
+Wed Nov 30 12:09:09 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.63 released.
+
+       * sd.c: Give I/O error if we attempt 512 byte I/O to a disk with
+       1024 byte sectors.
+
+       * scsicam.c: Make sure we do read from whole disk (mask off
+       partition).
+
+       * scsi.c: Use can_queue in Scsi_Host structure.
+       Fix panic message about invalid host.
+
+       * hosts.c: Initialize can_queue from template.
+
+       * hosts.h: Add can_queue to Scsi_Host structure.
+
+       * aha1740.c: Print out warning about NULL ecbptr.
+
+Fri Nov  4 12:40:30 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.62 released.
+
+       * fdomain.c: Update to version 5.20. (From Rik Faith).  Support
+       BIOS version 3.5.
+
+       * st.h: Add ST_EOD symbol.
+
+       * st.c: Patches from Kai Makisara - support additional densities,
+       add support for MTFSS, MTBSS, MTWSM commands.
+
+       * README.st: Update to document new commands.
+
+       * scsi.c: Add Mediavision CDR-H93MV to blacklist.
+
+Sat Oct 29 20:57:36 1994  Eric Youngdale  (eric@andante.aib.com)
+
+       * Linux 1.1.60 released.
+
+       * u14-34f.[c,h]: New driver from Dario Ballabio.
+
+       * aic7770.c, aha274x_seq.h, aha274x.seq, aha274x.h, aha274x.c,
+       README.aha274x: New files, new driver from John Aycock.
+
+
 Tue Oct 11 08:47:39 1994  Eric Youngdale  (eric@andante)
 
        * Linux 1.1.54 released.
@@ -6,6+206,13 @@ Tue Oct 11 08:47:39 1994  Eric Youngdale  (eric@andante)
 
        * buslogic.c: Set BUSLOGIC_CMDLUN back to 1 [Eric].
 
+       * ultrastor.c: Fix asm directives for new GCC.
+
+       * sr.c, sd.c: Use new end_scsi_request function.
+
+       * scsi.h(end_scsi_request): Return pointer to block if still
+       active, else return NULL if inactive.  Fixes race condition.
+
 Sun Oct  9 20:23:14 1994  Eric Youngdale  (eric@andante)
 
        * Linux 1.1.53 released.
@@ -141,6+348,140 @@ Thu Aug  4 08:47:27 1994  Eric Youngdale  (eric@andante)
 
        * st.c: Print correct number for device.
 
+Tue Aug  2 11:29:14 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.38 released.
+
+       Lots of changes in 1.1.38.  All from Drew unless otherwise noted.
+
+       * 53c7,8xx.c: New file from Drew.  PCI driver.
+
+       * 53c7,8xx.h: Likewise.
+
+       * 53c7,8xx.scr: Likewise.
+
+       * 53c8xx_d.h, 53c8xx_u.h, script_asm.pl: Likewise.
+
+       * scsicam.c: New file from Drew.  Read block 0 on the disk and
+       read the partition table.  Attempt to deduce the geometry from
+       the partition table if possible.  Only used by 53c[7,8]xx right
+       now, but could be used by any device for which we have no way
+       of identifying the geometry.
+
+       * sd.c: Use device letters instead of sd%d in a lot of messages.
+
+       * seagate.c: Fix bug that resulted in lockups with some devices.
+
+       * sr.c (sr_open): Return -EROFS, not -EACCES if we attempt to open
+       device for write.
+
+       * hosts.c, Makefile: Update for new driver.
+
+       * NCR5380.c, NCR5380.h, g_NCR5380.h: Update from Drew to support
+       53C400 chip.
+
+       * constants.c: Define CONST_CMND and CONST_MSG.  Other minor
+       cleanups along the way.  Improve handling of CONST_MSG.
+
+       * fdomain.c, fdomain.h: New version from Rik Faith.  Update to
+       5.18.  Should now support TMC-3260 PCI card with 18C30 chip.
+
+       * pas16.c: Update with new irq initialization.
+
+       * t128.c: Update with minor cleanups.
+
+       * scsi.c (scsi_pid): New variable - gives each command a unique
+       id. Add Quantum LPS5235S to blacklist.  Change in_scan to
+       in_scan_scsis and make global.
+
+       * scsi.h: Add some defines for extended message handling,
+       INITIATE/RELEASE_RECOVERY.  Add a few new fields to support sync
+       transfers.
+
+       * scsi_ioctl.h: Add ioctl to request synchronous transfers.
+
+
+Tue Jul 26 21:36:58 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.37 released.
+
+       * aha1542.c: Always call aha1542_mbenable, use new udelay
+       mechanism so we do not wait a long time if the board does not
+       implement this command.
+
+       * g_NCR5380.c: Remove #include <linux/config.h> and #if
+       defined(CONFIG_SCSI_*).
+
+       * seagate.c: Likewise.
+
+       Next round of changes to support loadable modules.  Getting closer
+       now, still not possible to do anything remotely usable.
+
+       hosts.c: Create a linked list of detected high level devices.
+       (scsi_register_device): New function to insert into this list.
+       (scsi_init): Call scsi_register_device for each of the known high
+       level drivers.
+
+       hosts.h: Add prototype for linked list header.  Add structure
+       definition for device template structure which defines the linked
+       list.
+
+       scsi.c: (scan_scsis): Use linked list instead of knowledge about
+       existing high level device drivers.
+       (scsi_dev_init): Use init functions for drivers on linked list
+       instead of explicit list to initialize and attach devices to high
+       level drivers.
+
+       scsi.h: Add new field "attached" to scsi_device - count of number
+       of high level devices attached.
+
+       sd.c, sr.c, sg.c, st.c: Adjust init/attach functions to use new
+       scheme.
+
+Sat Jul 23 13:03:17 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.35 released.
+
+       * ultrastor.c: Change constraint on asm() operand so that it works
+       with gcc 2.6.0.
+
+Thu Jul 21 10:37:39 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.33 released.
+
+       * sr.c(sr_open): Do not allow opens with write access.
+
+Mon Jul 18 09:51:22 1994 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.31 released.
+
+       * sd.c: Increase SD_TIMEOUT from 300 to 600.
+
+       * sr.c: Remove stray task_struct* variable that was no longer
+       used.
+
+       * sr_ioctl.c: Fix typo in up() call.
+
+Sun Jul 17 16:25:29 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.30 released.
+
+       * scsi.c (scan_scsis): Fix detection of some Toshiba CDROM drives
+       that report themselves as disk drives.
+
+       * (Throughout): Use request.sem instead of request.waiting.
+       Should fix swap problem with fdomain.
+
+Thu Jul 14 10:51:42 1994  Eric Youngdale  (eric@esp22)
+
+       * Linux 1.1.29 released.
+
+       * scsi.c (scan_scsis): Add new devices to end of linked list, not
+       to the beginning.
+
+       * scsi.h (SCSI_SLEEP): Remove brain dead hack to try and save
+       the task state before sleeping.
+
 Sat Jul  9 15:01:03 1994  Eric Youngdale  (eric@esp22)
 
        More changes to eventually support loadable modules.  Mainly
index 3d14837..dd809c3 100644 (file)
@@ -1,5+1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Sun Oct 16 19:20:03 1994 by root@kai.home
+Last modified: Wed Nov 30 20:34:03 1994 by root@kai.home
 
 BASICS
 
@@ -128,8+128,8 @@ MTIOCGET Returns some status information.
         The current block size and the density code are stored in the field
         mt_dsreg (shifts for the subfields are MT_ST_BLKSIZE_SHIFT and
         MT_ST_DENSITY_SHIFT).
-       The WR_PROT, BOT, EOF, EOT, EOD, and D_[800,1600,6250]_BPI
-       status bits reflect the tape status. The other bits are not used.
+       The GMT_xxx status bits reflect the drive status. GMT_DR_OPEN
+       is set if there is no tape in the drive.
 
 
 MISCELLANEOUS COMPILE OPTIONS
index 9011814..da3128b 100644 (file)
@@ -45,7+45,7 @@ static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha
 /* The adaptec can be configured for quite a number of addresses, but
 I generally do not want the card poking around at random.  We allow
 two addresses - this allows people to use the Adaptec with a Midi
-card, which also used 0x330 -- can be overriden with LILO! */
+card, which also used 0x330 -- can be overridden with LILO! */
 
 #define MAXBOARDS 2    /* Increase this and the sizes of the
                           arrays below, if you need more.. */
index f3e49c8..bd19d7e 100644 (file)
  *     5. Allow multiple boards to share an IRQ if the bus allows (EISA, MCA,
  *        and PCI).
  *     6. Avoid using the 445S workaround for board revs >= D.
- *     7. Get cmd_per_lun put in the Scsi_Host structure.
  */
 
 /*
    bump up this number. */
 #define BUSLOGIC_MAILBOXES 16
 
-#define BUSLOGIC_NONISA_CMDLUN 4       /* ??? Arbitrary (> 1) */
+#define BUSLOGIC_CMDLUN 4              /* ??? Arbitrary */
 
 /* BusLogic boards can be configured for quite a number of port addresses (six
    to be exact), but I generally do not want the driver poking around at
@@ -390,9+389,10 @@ static unsigned int makecode(unsigned int haerr, unsigned int scsierr)
     return (hosterr << 16) | scsierr;
 }
 
-const char *buslogic_info(void)
+/* ??? this should really be "const struct Scsi_Host *" */
+const char *buslogic_info(struct Scsi_Host *shpnt)
 {
-    return "BusLogic SCSI driver version " BUSLOGIC_VERSION;
+    return "BusLogic SCSI driver " BUSLOGIC_VERSION;
 }
 
 /* A "high" level interrupt handler. */
@@ -613,7+613,7 @@ int buslogic_queuecommand(Scsi_Cmnd *scpnt, void (*done)(Scsi_Cmnd *))
                        target, *cmd, i, bufflen);
        buslogic_stat(scpnt->host->io_port);
        buslogic_printk("buslogic_queuecommand: dumping scsi cmd:");
-       for (i = 0; i < (COMMAND_SIZE(*cmd)); i++)
+       for (i = 0; i < scpnt->cmd_len; i++)
            printk(" %02X", cmd[i]);
        printk("\n");
        if (*cmd == WRITE_10 || *cmd == WRITE_6)
@@ -665,7+665,7 @@ int buslogic_queuecommand(Scsi_Cmnd *scpnt, void (*done)(Scsi_Cmnd *))
 
     memset(&ccb[mbo], 0, sizeof (struct ccb));
 
-    ccb[mbo].cdblen = COMMAND_SIZE(*cmd);      /* SCSI Command Descriptor
+    ccb[mbo].cdblen = scpnt->cmd_len;          /* SCSI Command Descriptor
                                                   Block Length */
 
     direction = 0;
@@ -1229,13+1229,8 @@ int buslogic_detect(Scsi_Host_Template *tpnt)
 #endif
            /* Have to keep cmd_per_lun at 1 for ISA machines otherwise lots
               of memory gets sucked up for bounce buffers.  */
-           /* ??? Unfortunately, cmd_per_lun is only in the
-              Scsi_Host_Template structure, not the Scsi_Host structure.
-              Therefore, this could cause high memory consumption if a system
-              has multiple BusLogic adapters which are a mix of ISA and
-              non-ISA. */
-           if (!shpnt->unchecked_isa_dma)
-               shpnt->hostt->cmd_per_lun = BUSLOGIC_NONISA_CMDLUN;
+           shpnt->cmd_per_lun
+               = (shpnt->unchecked_isa_dma ? 1 : BUSLOGIC_CMDLUN);
            shpnt->sg_tablesize = max_sg;
            if (shpnt->sg_tablesize > BUSLOGIC_MAX_SG)
                shpnt->sg_tablesize = BUSLOGIC_MAX_SG;
index 04ca8b0..ff17ee4 100644 (file)
 int buslogic_detect(Scsi_Host_Template *);
 int buslogic_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int buslogic_abort(Scsi_Cmnd *);
-const char *buslogic_info(void);
+const char *buslogic_info(struct Scsi_Host *);
 int buslogic_reset(Scsi_Cmnd *);
 int buslogic_biosparam(Disk *, int, int *);
 
-#define BUSLOGIC_CMDLUN 1      /* Do not set this too high.  It sucks
-                                  up lots of memory on ISA machines
-                                  with > 16MB because of the huge number of
-                                  bounce buffers that need to be allocated.
-                                  For boards that use non-ISA bus, we can
-                                  bump this in the board detect routine.  
-                                                       10/8/94 ERY */
-
-#define BUSLOGIC { NULL,                       \
+#define BUSLOGIC { NULL, NULL,                 \
                   "BusLogic",                  \
                   buslogic_detect,             \
-                  NULL,                        \
+                  0,   /* no release func */   \
                   buslogic_info,               \
                   0,   /* no command func */   \
                   buslogic_queuecommand,       \
@@ -41,7+33,7 @@ int buslogic_biosparam(Disk *, int, int *);
                   0,   /* set by driver */     \
                   0,   /* set by driver */     \
                   0,   /* set by driver */     \
-                  BUSLOGIC_CMDLUN,             \
+                  0,   /* set by driver */     \
                   0,                           \
                   0,   /* set by driver */     \
                   ENABLE_CLUSTERING            \
index b6976e1..8671f41 100644 (file)
@@ -1,9+1,13 @@
 /*
  *      eata.c - Low-level SCSI driver for EISA EATA SCSI controllers.
  *
+ *      30 Nov 1994 rev. 1.09 for linux 1.1.68
+ *          Redo i/o on target status CONDITION_GOOD for TYPE_DISK only.
+ *          Added optional support for using a single board at a time.
+ *
  *      18 Nov 1994 rev. 1.08 for linux 1.1.64
- *                  Forces sg_tablesize = 64 and can_queue = 64 if these
- *                  values are not correctly detected (DPT PM2012).
+ *          Forces sg_tablesize = 64 and can_queue = 64 if these
+ *          values are not correctly detected (DPT PM2012).
  *
  *      14 Nov 1994 rev. 1.07 for linux 1.1.63  Final BETA release.
  *      04 Aug 1994 rev. 1.00 for linux 1.1.39  First BETA release.
 #define NO_DEBUG_DETECT
 #define NO_DEBUG_INTERRUPT
 #define NO_DEBUG_STATISTICS
+#define NO_SINGLE_HOST_OPERATIONS
 
 #define MAX_TARGET 8
 #define MAX_IRQ 16
@@ -303,7+308,7 @@ static inline int port_detect (ushort *port_base, unsigned int j,
    sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size);
    sh[j]->this_id = (ushort) ntohl(info.host_addr);
    sh[j]->can_queue = (ushort) ntohs(info.queue_size);
-   sh[j]->hostt->cmd_per_lun = MAX_CMD_PER_LUN;
+   sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
    sh[j]->unchecked_isa_dma = FALSE;
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->board_number = j;
@@ -313,7+318,7 @@ static inline int port_detect (ushort *port_base, unsigned int j,
    printk("%s: SCSI ID %d, PORT 0x%03x, IRQ %u, SG %d, "\
           "Mbox %d, CmdLun %d.\n", BN(j), sh[j]->this_id, 
            sh[j]->io_port, sh[j]->irq, sh[j]->sg_tablesize, 
-           sh[j]->can_queue, sh[j]->hostt->cmd_per_lun);
+           sh[j]->can_queue, sh[j]->cmd_per_lun);
 
    /* DPT PM2012 does not allow to detect sg_tablesize correctly */
    if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
@@ -363,6+368,16 @@ int eata_detect (Scsi_Host_Template * tpnt) {
       port_base++;
       }
 
+#if defined (SINGLE_HOST_OPERATIONS)
+   /* Create a circular linked list among the detected boards. */
+   if (j > 1) {
+
+      for (k = 0; k < (j - 1); k++) sh[k]->block = sh[k + 1];
+
+      sh[j - 1]->block = sh[0];
+      }
+#endif
+
    restore_flags(flags);
    return j;
 }
@@ -764,7+779,7 @@ static void eata_interrupt_handler(int irq) {
    
                   /* If there was a bus reset, redo operation on each target */
                   else if (spp->target_status == CONDITION_GOOD
-                                        && SCpnt->device->type != TYPE_TAPE
+                                        && SCpnt->device->type == TYPE_DISK
                                         && HD(j)->target_reset[SCpnt->target])
                      status = DID_BUS_BUSY << 16;
                   else
index 27b86f3..694d5fe 100644 (file)
@@ -5,7+5,7 @@
 #ifndef _EISA_EATA_H
 #define _EISA_EATA_H
 
-#define EATA_VERSION "1.08.00"
+#define EATA_VERSION "1.09.01"
 
 int eata_detect(Scsi_Host_Template *);
 int eata_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
@@ -14,7+14,7 @@ int eata_reset(Scsi_Cmnd *);
 int eata_bios_param(Disk *, int, int*);
 
 #define EATA {  NULL, /* Ptr for modules */                    \
-                 NULL, /* usage count for modules */          \
+                NULL, /* usage count for modules */           \
                 "EISA EATA 2.0A rev. " EATA_VERSION " by "     \
                 "Dario_Ballabio@milano.europe.dg.com.",        \
                 eata_detect,                                  \
index 9488c1f..9e836b9 100644 (file)
@@ -247,6+247,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
        retval->this_id = tpnt->this_id;
        retval->can_queue = tpnt->can_queue;
        retval->sg_tablesize = tpnt->sg_tablesize;
+       retval->cmd_per_lun = tpnt->cmd_per_lun;
        retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
 
        if(!scsi_hostlist)
index 26b4e1c..fa690d9 100644 (file)
@@ -228,7+228,7 @@ typedef struct  SHT
        be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
 */
 
-#define SCSI_HOST_BLOCK 0x800
+#define SCSI_HOST_BLOCK 0x80
 
 struct Scsi_Host
        {
@@ -259,6+259,7 @@ struct Scsi_Host
                
                int this_id;
                int can_queue;
+               short cmd_per_lun;
                short unsigned int sg_tablesize;
                unsigned unchecked_isa_dma:1;
                /*
index 96dd219..a46a30d 100644 (file)
@@ -150,6+150,7 @@ static struct blist blacklist[] =
                                     * controller, which causes SCSI code to reset bus.*/
    {"SEAGATE", "ST296","921"},   /* Responds to all lun */
    {"SONY","CD-ROM CDU-541","4.3d"},
+   {"SONY","CD-ROM CDU-55S","1.0i"},
    {"TANDBERG","TDC 3600","U07"},  /* Locks up if polled for lun != 0 */
    {"TEAC","CD-ROM","1.06"},   /* causes failed REQUEST SENSE on lun 1 for seagate
                                 * controller, which causes SCSI code to reset bus.*/
@@ -898,7+899,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
              if (host->block) {
                struct Scsi_Host * block;
                for(block = host->block; block != host; block = block->block)
-                 block->host_busy |= ~SCSI_HOST_BLOCK;
+                 block->host_busy |= SCSI_HOST_BLOCK;
              }
              sti();
              break;
@@ -1810,7+1811,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
          for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
            if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
          if(SDpnt->type != -1){
-           for(j=0;j<SDpnt->host->hostt->cmd_per_lun;j++){
+           for(j=0;j<SDpnt->host->cmd_per_lun;j++){
              SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd));
              SCpnt->host = SDpnt->host;
              SCpnt->device = SDpnt;
@@ -1843,13+1844,13 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
          if(SDpnt->type != TYPE_TAPE)
            dma_sectors += ((host->sg_tablesize * 
                             sizeof(struct scatterlist) + 511) >> 9) * 
-                              host->hostt->cmd_per_lun;
+                              host->cmd_per_lun;
          
          if(host->unchecked_isa_dma &&
             memory_end - 1 > ISA_DMA_THRESHOLD &&
             SDpnt->type != TYPE_TAPE) {
            dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-             host->hostt->cmd_per_lun;
+             host->cmd_per_lun;
            need_isa_buffer++;
          };
        };
index c0be923..e74e78d 100644 (file)
@@ -168,6+168,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
          if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
          buf = (char *) scsi_malloc(buf_needed);
          if (!buf) return -ENOMEM;
+         memset(buf, 0, buf_needed);
        } else
          buf = NULL;
 
index 0b37791..49a7448 100644 (file)
@@ -328,13+328,14 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt)
        } /* (! controller_type) */
  
        tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;
+       tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
 
        if (base_address)
                {
                st0x_cr_sr =(void *) (((unsigned char *) base_address) + (controller_type == SEAGATE ? 0x1a00 : 0x1c00)); 
                st0x_dr = (void *) (((unsigned char *) base_address ) + (controller_type == SEAGATE ? 0x1c00 : 0x1e00));
 #ifdef DEBUG
-               printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr);
+               printk("%s detected. Base address = %x, cr = %x, dr = %x\n", tpnt->name, base_address, st0x_cr_sr, st0x_dr);
 #endif
 /*
  *     At all times, we will use IRQ 5.  Should also check for IRQ3 if we 
@@ -382,8+383,8 @@ const char *seagate_st0x_info(struct Scsi_Host * shpnt) {
 #ifdef LINKED
 " LINKED"
 #endif
-              "\n", hostno, (controller_type == SEAGATE) ? "seagate" : 
-              "FD TMC-8xx", irq, base_address);
+              "\n", hostno, (controller_type == SEAGATE) ? ST0X_ID_STR : 
+              FD_ID_STR, irq, base_address);
         return buffer;
 }
 
index abc1c93..4f6ef3e 100644 (file)
@@ -129,6+129,8 @@ extern volatile int seagate_st0x_timeout;
 #define SEAGATE 1      /* these determine the type of the controller */
 #define FD     2
 
+#define ST0X_ID_STR    "Seagate ST-01/ST-02"
+#define FD_ID_STR      "TMC-8XX/TMC-950"
 
 #endif
 
index f60d1ff..c8bf96c 100644 (file)
@@ -274,7+274,7 @@ static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
   /* now issue command */
   SCpnt->request.dev=dev;
   SCpnt->sense_buffer[0]=0;
-  size=COMMAND_SIZE(get_fs_byte(buf));
+  opcode = get_fs_byte(buf);
   size=COMMAND_SIZE(opcode);
   if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
   SCpnt->cmd_len = size;
index 82dfe55..5559a3e 100644 (file)
@@ -326,7+326,6 @@ static void sr_photocd(struct inode *inode)
       frame = (unsigned long)buffer[17]/16*10 + (unsigned long)buffer[17]%16;
       sector = min*60*75 + sec*75 + frame;
       if (sector) {
-       sector -= CD_BLOCK_OFFSET;
        printk("sr_photocd: multisession PhotoCD detected\n");
       }
     }
index ea78d19..10f260e 100644 (file)
   Copyright 1992, 1993, 1994 Kai Makisara
                 email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
 
-  Last modified: Tue Oct 25 19:37:33 1994 by root@kai.home
+  Last modified: Wed Nov 30 21:09:53 1994 by root@kai.home
 */
 
 #include <linux/fs.h>
@@ -348,6+348,9 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
   STp = &(scsi_tapes[dev]);
   STbuffer = STp->buffer;
 
+  if (STp->ready != ST_READY)
+    return 0;
+
   if (STp->rw == ST_WRITING)  /* Writing */
     return flush_write_buffer(dev);
 
@@ -415,6+418,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
 
     STp->dirty = 0;
     STp->rw = ST_IDLE;
+    STp->ready = ST_READY;
     if (STp->eof != ST_EOD)  /* Save EOD across opens */
       STp->eof = ST_NOEOF;
     STp->eof_hit = 0;
@@ -459,14+463,21 @@ scsi_tape_open(struct inode * inode, struct file * filp)
          (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) {
         (STp->mt_status)->mt_fileno = STp->drv_block = 0 ;
        printk("st%d: No tape.\n", dev);
+       STp->ready = ST_NO_TAPE;
       } else {
        printk("st%d: Error %x.\n", dev, SCpnt->result);
         (STp->mt_status)->mt_fileno = STp->drv_block = (-1);
+       STp->ready = ST_NOT_READY;
       }
-      (STp->buffer)->in_use = 0;
-      STp->in_use = 0;
       SCpnt->request.dev = -1;  /* Mark as not busy */
-      return (-EIO);
+      (STp->buffer)->in_use = 0;
+      STp->buffer = NULL;
+      STp->density = 0;   /* Clear the errorneus "residue" */
+      STp->write_prot = 0;
+      STp->block_size = 0;
+      STp->eof = ST_NOEOF;
+      (STp->mt_status)->mt_fileno = STp->drv_block = 0;
+      return 0;
     }
 
     SCpnt->sense_buffer[0]=0;
@@ -533,10+544,10 @@ scsi_tape_open(struct inode * inode, struct file * filp)
        (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
 #ifdef DEBUG
       if (debugging)
-       printk("st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d\n",
+       printk("st%d: Density %x, tape length: %x, drv buffer: %d\n",
               dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
               (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
-              STp->block_size, STp->drv_buffer);
+              STp->drv_buffer);
 #endif
       if (STp->block_size > st_buffer_size) {
        printk("st%d: Blocksize %d too large for buffer.\n", dev,
@@ -651,7+662,8 @@ scsi_tape_close(struct inode * inode, struct file * filp)
     if (rewind)
       st_int_ioctl(inode, filp, MTREW, 1);
 
-    (STp->buffer)->in_use = 0;
+    if (STp->buffer != NULL)
+      (STp->buffer)->in_use = 0;
     STp->in_use = 0;
 
     return;
@@ -672,6+684,8 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
 
     dev = MINOR(inode->i_rdev) & 127;
     STp = &(scsi_tapes[dev]);
+    if (STp->ready != ST_READY)
+      return (-EIO);
 #ifdef DEBUG
     if (!STp->in_use) {
       printk("st%d: Incorrect device.\n", dev);
@@ -884,6+898,7 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
     else
       SCpnt->request.dev = -1;  /* Mark as not busy */
 
+    STp->at_sm &= (total != 0);
     return( total);
 }   
 
@@ -901,6+916,8 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
 
     dev = MINOR(inode->i_rdev) & 127;
     STp = &(scsi_tapes[dev]);
+    if (STp->ready != ST_READY)
+      return (-EIO);
 #ifdef DEBUG
     if (!STp->in_use) {
       printk("st%d: Incorrect device.\n", dev);
@@ -930,8+947,8 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
             (STp->buffer)->buffer_bytes);
 #endif
     if (((STp->buffer)->buffer_bytes == 0) &&
-       STp->eof == ST_EOM_OK)  /* EOM or Blank Check */
-      return (-EIO);
+       (STp->eof == ST_EOM_OK || STp->eof == ST_EOD))
+      return (-EIO);  /* EOM or Blank Check */
 
     STp->rw = ST_READING;
 
@@ -975,6+992,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
 
        (STp->buffer)->read_pointer = 0;
        STp->eof_hit = 0;
+       STp->at_sm = 0;
 
        if ((STp->buffer)->last_result_fatal) {
 #ifdef DEBUG
@@ -1180,12+1198,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
    unsigned char cmd[10];
    Scsi_Cmnd * SCpnt;
    Scsi_Tape * STp;
-   int fileno, blkno, undone, datalen;
+   int fileno, blkno, at_sm, undone, datalen;
 
    dev = dev & 127;
    STp = &(scsi_tapes[dev]);
+   if (STp->ready != ST_READY)
+     return (-EIO);
    fileno = (STp->mt_status)->mt_fileno ;
    blkno = STp->drv_block;
+   at_sm = STp->at_sm;
 
    memset(cmd, 0, 10);
    datalen = 0;
@@ -1204,6+1225,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        fileno += arg;
        blkno = 0;
+       at_sm &= (arg != 0);
        break; 
      case MTBSF:
      case MTBSFM:
@@ -1223,6+1245,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        fileno -= arg;
        blkno = (-1);  /* We can't know the block number */
+       at_sm &= (arg != 0);
        break; 
       case MTFSR:
        cmd[0] = SPACE;
@@ -1237,6+1260,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        if (blkno >= 0)
         blkno += arg;
+       at_sm &= (arg != 0);
        break; 
      case MTBSR:
        cmd[0] = SPACE;
@@ -1255,6+1279,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        if (blkno >= 0)
         blkno -= arg;
+       at_sm &= (arg != 0);
        break; 
       case MTFSS:
        cmd[0] = SPACE;
@@ -1267,8+1292,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
         printk("st%d: Spacing tape forward %d setmarks.\n", dev,
                cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
 #endif
-       if (arg != 0)
+       if (arg != 0) {
         blkno = fileno = (-1);
+        at_sm = 1;
+       }
        break; 
      case MTBSS:
        cmd[0] = SPACE;
@@ -1285,8+1312,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
         printk("st%d: Spacing tape backward %ld setmarks.\n", dev, (-ltmp));
        }
 #endif
-       if (arg != 0)
+       if (arg != 0) {
         blkno = fileno = (-1);
+        at_sm = 1;
+       }
        break; 
      case MTWEOF:
      case MTWSM:
@@ -1311,6+1340,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
 #endif
        fileno += arg;
        blkno = 0;
+       at_sm = (cmd_in == MTWSM);
        break; 
      case MTREW:
        cmd[0] = REZERO_UNIT;
@@ -1322,7+1352,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
        if (debugging)
         printk("st%d: Rewinding tape.\n", dev);
 #endif
-       fileno = blkno = 0 ;
+       fileno = blkno = at_sm = 0 ;
        break; 
      case MTOFFL:
        cmd[0] = START_STOP;
@@ -1334,7+1364,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
        if (debugging)
         printk("st%d: Unloading tape.\n", dev);
 #endif
-       fileno = blkno = 0 ;
+       fileno = blkno = at_sm = 0 ;
        break; 
      case MTNOP:
 #ifdef DEBUG
@@ -1354,7+1384,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
        if (debugging)
         printk("st%d: Retensioning tape.\n", dev);
 #endif
-       fileno = blkno = ;
+       fileno = blkno = at_sm = 0;
        break; 
      case MTEOM:
        /* space to the end of tape */
@@ -1371,6+1401,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
         printk("st%d: Spacing to end of recorded medium.\n", dev);
 #endif
        blkno = (-1);
+       at_sm = 0;
        break; 
      case MTERASE:
        if (STp->write_prot)
@@ -1381,7+1412,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
        if (debugging)
         printk("st%d: Erasing tape.\n", dev);
 #endif
-       fileno = blkno = 0 ;
+       fileno = blkno = at_sm = 0 ;
        break;
      case MTSEEK:
        if ((STp->device)->scsi_level < SCSI_2) {
@@ -1408,6+1439,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
         printk("st%d: Seeking tape to block %ld.\n", dev, arg);
 #endif
        fileno = blkno = (-1);
+       at_sm = 0;
        break;
      case MTSETBLK:  /* Set block length */
      case MTSETDENSITY: /* Set tape density */
@@ -1481,9+1513,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
      if (cmd_in != MTSEEK) {
        STp->drv_block = blkno;
        (STp->mt_status)->mt_fileno = fileno;
+       STp->at_sm = at_sm;
      }
-     else
+     else {
        STp->drv_block = (STp->mt_status)->mt_fileno = (-1);
+       STp->at_sm = 0;
+     }
      if (cmd_in == MTFSF)
        STp->moves_after_eof = 0;
      else
@@ -1642,6+1677,12 @@ st_ioctl(struct inode * inode,struct file * file,
        (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff);
      else if (STp->density == 3)
        (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff);
+     if (STp->ready == ST_READY)
+       (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff);
+     if (STp->ready == ST_NO_TAPE)
+       (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
+     if (STp->at_sm)
+       (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
 
      memcpy_tofs((char *)arg, (char *)(STp->mt_status),
                 sizeof(struct mtget));
@@ -1650,6+1691,8 @@ st_ioctl(struct inode * inode,struct file * file,
      return 0;
    }
    else if (cmd == (MTIOCPOS & IOCCMD_MASK)) {
+     if (STp->ready != ST_READY)
+       return (-EIO);
 #ifdef DEBUG
      if (debugging)
        printk("st%d: get tape position.\n", dev);
@@ -1712,8+1755,10 @@ st_ioctl(struct inode * inode,struct file * file,
      memcpy_tofs((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
      return result;
    }
-   else
+   else if (STp->ready == ST_READY)
      return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+   else
+     return (-EIO);
 }
 
 \f
@@ -1829,6+1874,7 @@ static void st_init()
     STp->write_threshold = st_write_threshold;
     STp->drv_block = 0;
     STp->moves_after_eof = 1;
+    STp->at_sm = 0;
     STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget));
     /* Initialize status */
     memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
index d2b66f9..fcfb324 100644 (file)
@@ -27,6+27,7 @@ typedef struct {
   Scsi_Device* device;
   unsigned char dirty;
   unsigned char rw;
+  unsigned char ready;
   unsigned char eof;
   unsigned char write_prot;
   unsigned char drv_write_prot;
@@ -46,6+47,7 @@ typedef struct {
   int recover_count;
   int drv_block;       /* The block where the drive head is */
   unsigned char moves_after_eof;
+  unsigned char at_sm;
   struct mtget * mt_status;
   Scsi_Cmnd SCpnt;
 } Scsi_Tape;
@@ -62,6+64,11 @@ typedef struct {
 #define        ST_READING      1
 #define        ST_WRITING      2
 
+/* Values of ready state */
+#define ST_READY       0
+#define ST_NOT_READY   1
+#define ST_NO_TAPE     2
+
 /* Positioning SCSI-commands for Tandberg, etc. drives */
 #define        QFA_REQUEST_BLOCK       0x02
 #define        QFA_SEEK_BLOCK          0x0c
index 32cd24a..42feecb 100644 (file)
@@ -1,6+1,10 @@
 /*
  *      u14-34f.c - Low-level SCSI driver for UltraStor 14F/34F
  *
+ *      30 Nov 1994 rev. 1.09 for linux 1.1.68
+ *          Redo i/o on target status CONDITION_GOOD for TYPE_DISK only.
+ *          Added optional support for using a single board at a time.
+ *
  *      14 Nov 1994 rev. 1.10 for linux 1.1.63
  *
  *      28 Oct 1994 rev. 1.09 for linux 1.1.58  Final BETA release.
 #define NO_DEBUG_DETECT
 #define NO_DEBUG_INTERRUPT
 #define NO_DEBUG_STATISTICS
+#define SINGLE_HOST_OPERATIONS
 
 #define MAX_TARGET 8
 #define MAX_IRQ 16
@@ -327,7+332,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
    sh[j]->irq = irq;
    sh[j]->this_id = config_2.ha_scsi_id;
    sh[j]->can_queue = MAX_MAILBOXES;
-   sh[j]->hostt->cmd_per_lun = MAX_CMD_PER_LUN;
+   sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
    sys_mask = inb(sh[j]->io_port + REG_SYS_MASK);
    lcl_mask = inb(sh[j]->io_port + REG_LCL_MASK);
 
@@ -381,7+386,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
           "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port, 
           (int)sh[j]->base, sh[j]->irq, 
           sh[j]->dma_channel, sh[j]->sg_tablesize, 
-          sh[j]->can_queue, sh[j]->hostt->cmd_per_lun,
+          sh[j]->can_queue, sh[j]->cmd_per_lun,
           sh[j]->hostt->use_clustering);
    return TRUE;
 }
@@ -412,6+417,16 @@ int u14_34f_detect (Scsi_Host_Template * tpnt) {
       port_base++;
       }
 
+#if defined (SINGLE_HOST_OPERATIONS)
+   /* Create a circular linked list among the detected boards. */
+   if (j > 1) {
+
+      for (k = 0; k < (j - 1); k++) sh[k]->block = sh[k + 1];
+
+      sh[j - 1]->block = sh[0];
+      }
+#endif
+
    restore_flags(flags);
    return j;
 }
@@ -784,7+799,7 @@ static void u14_34f_interrupt_handler(int irq) {
 
                /* If there was a bus reset, redo operation on each target */
                else if (spp->target_status == CONDITION_GOOD
-                                     && SCpnt->device->type != TYPE_TAPE
+                                     && SCpnt->device->type == TYPE_DISK
                                      && HD(j)->target_reset[SCpnt->target])
                   status = DID_BUS_BUSY << 16;
                else
index 92d4012..b36c935 100644 (file)
@@ -10,13+10,13 @@ int u14_34f_abort(Scsi_Cmnd *);
 int u14_34f_reset(Scsi_Cmnd *);
 int u14_34f_biosparam(Disk *, int, int *);
 
-#define U14_34F_VERSION "1.10.01"
+#define U14_34F_VERSION "1.11.01"
 
 #define ULTRASTOR_14_34F {                                            \
                 NULL,                                                 \
                 NULL,                                                 \
                 "UltraStor 14F/34F rev. " U14_34F_VERSION " by "      \
-                "Dario_Ballabio@milano.europe.dg.com.",\
+                "Dario_Ballabio@milano.europe.dg.com.",               \
                 u14_34f_detect,                                       \
                 NULL,                                                 \
                 NULL,                                                \
index 78dd720..c12ca8b 100644 (file)
@@ -28,6+28,8 @@ FS_SUBDIRS := $(FS_SUBDIRS) proc
 endif
 ifdef CONFIG_ISO9660_FS
 FS_SUBDIRS := $(FS_SUBDIRS) isofs
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) isofs
 endif
 ifdef CONFIG_NFS_FS
 FS_SUBDIRS := $(FS_SUBDIRS) nfs
@@ -50,7+52,7 @@ endif
 ifdef CONFIG_BINFMT_ELF
 BINFMTS := $(BINFMTS) binfmt_elf.o
 else
-MODULES := $(MODULES) binfmt_elf.o
+MODULE_OBJS := $(MODULE_OBJS) binfmt_elf.o
 endif
 
 .c.s:
index c2dc5cb..77a9dc4 100644 (file)
@@ -93,7+93,6 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
                mpnt->vm_flags = VM_GROWSDOWN;
 #  endif
 #endif
-               mpnt->vm_share = NULL;
                mpnt->vm_inode = NULL;
                mpnt->vm_offset = 0;
                mpnt->vm_ops = NULL;
index 6416a1f..5e1199c 100644 (file)
@@ -979,6+979,22 @@ static void read_buffers(struct buffer_head * bh[], int nrbuf)
        }
 }
 
+/*
+ * This actually gets enough info to try to align the stuff,
+ * but we don't bother yet.. We'll have to check that nobody
+ * else uses the buffers etc.
+ *
+ * "address" points to the new page we can use to move things
+ * around..
+ */
+static unsigned long try_to_align(struct buffer_head ** bh, int nrbuf,
+       unsigned long address)
+{
+       while (nrbuf-- > 0)
+               brelse(bh[nrbuf]);
+       return 0;
+}
+
 static unsigned long check_aligned(struct buffer_head * first, unsigned long address,
        dev_t dev, int *b, int size)
 {
@@ -987,15+1003,13 @@ static unsigned long check_aligned(struct buffer_head * first, unsigned long add
        unsigned long offset;
        int block;
        int nrbuf;
+       int aligned = 1;
 
-       page = (unsigned long) first->b_data;
-       if (page & ~PAGE_MASK) {
-               brelse(first);
-               return 0;
-       }
-       mem_map[MAP_NR(page)]++;
        bh[0] = first;
        nrbuf = 1;
+       page = (unsigned long) first->b_data;
+       if (page & ~PAGE_MASK)
+               aligned = 0;
        for (offset = size ; offset < PAGE_SIZE ; offset += size) {
                block = *++b;
                if (!block)
@@ -1005,8+1019,11 @@ static unsigned long check_aligned(struct buffer_head * first, unsigned long add
                        goto no_go;
                bh[nrbuf++] = first;
                if (page+offset != (unsigned long) first->b_data)
-                       goto no_go;
+                       aligned = 0;
        }
+       if (!aligned)
+               return try_to_align(bh, nrbuf, address);
+       mem_map[MAP_NR(page)]++;
        read_buffers(bh,nrbuf);         /* make sure they are actually read correctly */
        while (nrbuf-- > 0)
                brelse(bh[nrbuf]);
@@ -1016,7+1033,6 @@ static unsigned long check_aligned(struct buffer_head * first, unsigned long add
 no_go:
        while (nrbuf-- > 0)
                brelse(bh[nrbuf]);
-       free_page(page);
        return 0;
 }
 
index 586098c..4889b2c 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -326,7+326,6 @@ unsigned long * create_tables(char * p,int argc,int envc,int ibcs)
                mpnt->vm_end = TASK_SIZE;
                mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
                mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_share = NULL;
                mpnt->vm_ops = NULL;
                mpnt->vm_offset = 0;
                mpnt->vm_inode = NULL;
@@ -545,6+544,7 @@ void flush_old_exec(struct linux_binprm * bprm)
                mpnt1 = mpnt->vm_next;
                if (mpnt->vm_ops && mpnt->vm_ops->close)
                        mpnt->vm_ops->close(mpnt);
+               remove_shared_vm_struct(mpnt);
                if (mpnt->vm_inode)
                        iput(mpnt->vm_inode);
                kfree(mpnt);
index bc6faa7..c9114d1 100644 (file)
@@ -232,7+232,7 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
        mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 
        mark_buffer_dirty(bh, 1);
-       if (sb->s_flags & MS_SYNC) {
+       if (sb->s_flags & MS_SYNCHRONOUS) {
                ll_rw_block (WRITE, 1, &bh);
                wait_on_buffer (bh);
        }
@@ -441,7+441,7 @@ got_block:
        j = tmp;
 
        mark_buffer_dirty(bh, 1);
-       if (sb->s_flags & MS_SYNC) {
+       if (sb->s_flags & MS_SYNCHRONOUS) {
                ll_rw_block (WRITE, 1, &bh);
                wait_on_buffer (bh);
        }
index 69c9e22..2075aa4 100644 (file)
@@ -247,7+247,7 @@ void ext2_free_inode (struct inode * inode)
                set_inode_dtime (inode, gdp);
        }
        mark_buffer_dirty(bh, 1);
-       if (sb->s_flags & MS_SYNC) {
+       if (sb->s_flags & MS_SYNCHRONOUS) {
                ll_rw_block (WRITE, 1, &bh);
                wait_on_buffer (bh);
        }
@@ -414,7+414,7 @@ repeat:
                        goto repeat;
                }
                mark_buffer_dirty(bh, 1);
-               if (sb->s_flags & MS_SYNC) {
+               if (sb->s_flags & MS_SYNCHRONOUS) {
                        ll_rw_block (WRITE, 1, &bh);
                        wait_on_buffer (bh);
                }
@@ -476,7+476,7 @@ repeat:
        inode->u.ext2_i.i_block_group = i;
        inode->i_op = NULL;
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
-               inode->i_flags |= MS_SYNC;
+               inode->i_flags |= MS_SYNCHRONOUS;
        insert_inode_hash(inode);
        inc_inode_version (inode, gdp, mode);
 
index 633c33e..68c2445 100644 (file)
@@ -567,7+567,7 @@ void ext2_read_inode (struct inode * inode)
        else if (S_ISFIFO(inode->i_mode))
                init_fifo(inode);
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
-               inode->i_flags |= MS_SYNC;
+               inode->i_flags |= MS_SYNCHRONOUS;
        if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL)
                inode->i_flags |= S_APPEND;
        if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)
index 7278b85..0cb987a 100644 (file)
@@ -406,6+406,11 @@ repeat:
                goto repeat;
        }
        inode->i_count--;
+       if (inode->i_mmap) {
+               printk("iput: inode %lu on device %d/%d still has mappings.\n",
+                       inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+               inode->i_mmap = NULL;
+       }
        nr_free_inodes++;
        return;
 }
index a780af4..08c91fc 100644 (file)
@@ -7,6+7,10 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+ifndef CONFIG_ISO9660_FS
+CFLAGS := $(CFLAGS) -DMODULE
+endif
+
 .c.s:
        $(CC) $(CFLAGS) -S $<
 .c.o:
index c1754e3..6666d8a 100644 (file)
 #include <asm/system.h>
 #include <asm/segment.h>
 
+#ifdef MODULE
+#include <linux/module.h>
+#include "../../tools/version.h"
+#endif
+
 #ifdef LEAK_CHECK
 static int check_malloc = 0;
 static int check_bread = 0;
@@ -35,6+40,9 @@ void isofs_put_super(struct super_block *sb)
 #endif
        sb->s_dev = 0;
        unlock_super(sb);
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
        return;
 }
 
@@ -301,7+309,12 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
                return NULL;
        }
 
-       if(!check_disk_change(s->s_dev)) return s;
+       if(!check_disk_change(s->s_dev)) {
+#ifdef MODULE
+         MOD_INC_USE_COUNT;
+#endif
+         return s;
+       }
  out: /* Kick out for various error conditions */
        brelse(bh);
        s->s_dev = 0;
@@ -705,3+718,30 @@ void leak_check_brelse(struct buffer_head * bh){
 }
 
 #endif
+
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type iso9660_fs_type = {
+       isofs_read_super, "iso9660", 1, NULL
+};
+
+int init_module(void)
+{
+       register_filesystem(&iso9660_fs_type);
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       if (MOD_IN_USE)
+               printk("ne: device busy, remove delayed\n");
+       else
+       {
+               unregister_filesystem(&iso9660_fs_type);
+       }
+}
+
+#endif
+
index d1de73a..7b7a246 100644 (file)
@@ -186,7+186,7 @@ int locks_deadlocked(int my_pid,int blocked_pid)
                                if (ret_val) return -EDEADLOCK;
                        }
                        dlock_wait = dlock_wait->next;
-               } while (dlock_wait != NULL);
+               } while (dlock_wait != fl->fl_wait);
        }
        return 0;
 }
@@ -473,14+473,18 @@ static struct file_lock *alloc_lock(struct file_lock **pos,
        if (tmp->fl_owner != NULL)
                panic("alloc_lock: broken free list\n");
 
-       *tmp = *fl;
-
        tmp->fl_next = *pos;    /* insert into file's list */
        *pos = tmp;
 
        tmp->fl_owner = current;        /* FIXME: needed? */
        tmp->fl_fd = fd;                /* FIXME: needed? */
        tmp->fl_wait = NULL;
+
+       tmp->fl_type = fl->fl_type;
+       tmp->fl_whence = fl->fl_whence;
+       tmp->fl_start = fl->fl_start;
+       tmp->fl_end = fl->fl_end;
+
        return tmp;
 }
 
index 811176a..fad26fd 100644 (file)
@@ -74,13+74,18 @@ static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
        }
        return page;
 }
+
 struct vm_operations_struct nfs_file_mmap = {
        NULL,                   /* open */
        NULL,                   /* close */
+       NULL,                   /* unmap */
+       NULL,                   /* protect */
+       NULL,                   /* sync */
+       NULL,                   /* advise */
        nfs_file_mmap_nopage,   /* nopage */
        NULL,                   /* wppage */
-       NULL,                   /* share */
-       NULL,                   /* unmap */
+       NULL,                   /* swapout */
+       NULL,                   /* swapin */
 };
 
 
index 9545408..01b5026 100644 (file)
@@ -62,11+62,10 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
        ino = dir->i_ino;
        pid = ino >> 16;
        ino &= 0x0000ffff;
-       ino -= 7;
        if (!dir)
                return -ENOENT;
        sb = dir->i_sb;
-       if (!pid || ino || !S_ISDIR(dir->i_mode)) {
+       if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode)) {
                iput(dir);
                return -ENOENT;
        }
@@ -76,7+75,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
                        *result = dir;
                        return 0;
                }
-               if (!(*result = iget(sb,(pid << 16)+2))) {
+               if (!(*result = iget(sb,(pid << 16)+PROC_PID_INO))) {
                        iput(dir);
                        return -ENOENT;
                }
@@ -108,7+107,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
        if (fd >= NR_OPEN || !p->files->fd[fd] || !p->files->fd[fd]->f_inode)
          return -ENOENT;
 
-       ino = (pid << 16) + 0x100 + fd;
+       ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
        if (!(*result = iget(sb,ino)))
                return -ENOENT;
@@ -127,8+126,7 @@ static int proc_readfd(struct inode * inode, struct file * filp,
        ino = inode->i_ino;
        pid = ino >> 16;
        ino &= 0x0000ffff;
-       ino -= 7;
-       if (ino)
+       if (ino != PROC_PID_FD)
                return 0;
        while (1) {
                fd = filp->f_pos;
@@ -138,7+136,7 @@ static int proc_readfd(struct inode * inode, struct file * filp,
                        if (!fd)
                                fd = inode->i_ino;
                        else
-                               fd = (inode->i_ino & 0xffff0000) | 2;
+                               fd = (inode->i_ino & 0xffff0000) | PROC_PID_INO;
                        put_fs_long(fd, &dirent->d_ino);
                        put_fs_word(i, &dirent->d_reclen);
                        put_fs_byte(0, i+dirent->d_name);
@@ -165,7+163,7 @@ static int proc_readfd(struct inode * inode, struct file * filp,
                        i++;
                }
                j = i;
-               ino = (pid << 16) + 0x100 + fd;
+               ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
 
                put_fs_long(ino, &dirent->d_ino);
                put_fs_word(i, &dirent->d_reclen);
index 1b33470..dab9c4b 100644 (file)
@@ -67,7+67,6 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
                mpnt->vm_end = TASK_SIZE;
                mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
                mpnt->vm_flags = VM_STACK_FLAGS;
-               mpnt->vm_share = NULL;
                mpnt->vm_ops = NULL;
                mpnt->vm_inode = NULL;
                mpnt->vm_offset = 0;
index 63540f1..1eafdf9 100644 (file)
 #define MAX_DMA_CHANNELS       8
 
 /* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS      0xffffff
+#define MAX_DMA_ADDRESS      0x1000000
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
index c2bb6e8..a501330 100644 (file)
@@ -63,12+63,12 @@ extern unsigned long name_cache_init(unsigned long start, unsigned long end);
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
  */
-#define MS_RDONLY    1 /* mount read-only */
-#define MS_NOSUID    2 /* ignore suid and sgid bits */
-#define MS_NODEV     4 /* disallow access to device special files */
-#define MS_NOEXEC    8 /* disallow program execution */
-#define MS_SYNC     16 /* writes are synced at once */
-#define        MS_REMOUNT  32 /* alter flags of a mounted FS */
+#define MS_RDONLY       1 /* mount read-only */
+#define MS_NOSUID       2 /* ignore suid and sgid bits */
+#define MS_NODEV        4 /* disallow access to device special files */
+#define MS_NOEXEC       8 /* disallow program execution */
+#define MS_SYNCHRONOUS 16 /* writes are synced at once */
+#define MS_REMOUNT     32 /* alter flags of a mounted FS */
 
 #define S_APPEND    256 /* append-only file */
 #define S_IMMUTABLE 512 /* immutable file */
@@ -96,7+96,7 @@ extern unsigned long name_cache_init(unsigned long start, unsigned long end);
 #define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID)
 #define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV)
 #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
-#define IS_SYNC(inode) ((inode)->i_flags & MS_SYNC)
+#define IS_SYNC(inode) ((inode)->i_flags & MS_SYNCHRONOUS)
 
 #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
index 63eeab9..cb6b4e0 100644 (file)
 #define        IFF_NOTRAILERS  0x20            /* avoid use of trailers        */
 #define        IFF_RUNNING     0x40            /* resources allocated          */
 #define        IFF_NOARP       0x80            /* no ARP protocol              */
-#define        IFF_PROMISC     0x100           /* recve all packets            */
-/* These are not yet used: */
-#define        IFF_ALLMULTI    0x200           /* recve all multicast packets  */
+#define        IFF_PROMISC     0x100           /* receive all packets          */
+/* Not supported */
+#define        IFF_ALLMULTI    0x200           /* receive all multicast packets*/
 
 #define IFF_MASTER     0x400           /* master of a load balancer    */
 #define IFF_SLAVE      0x800           /* slave of a load balancer     */
 
+#define IFF_MULTICAST  0x1000          /* Supports multicast           */
+
 /*
  * The ifaddr structure contains information about one address
  * of an interface.  They are maintained by the different address
  * and are linked together so all addresses for an interface can
  * be located.
  */
-struct ifaddr {
-  struct sockaddr      ifa_addr;       /* address of interface         */
-  union {
-       struct sockaddr ifu_broadaddr;
-       struct sockaddr ifu_dstaddr;
-  } ifa_ifu;
-  struct iface         *ifa_ifp;       /* back-pointer to interface    */
-  struct ifaddr                *ifa_next;      /* next address for interface   */
+struct ifaddr 
+{
+       struct sockaddr ifa_addr;       /* address of interface         */
+       union {
+               struct sockaddr ifu_broadaddr;
+               struct sockaddr ifu_dstaddr;
+       } ifa_ifu;
+       struct iface            *ifa_ifp;       /* back-pointer to interface    */
+       struct ifaddr           *ifa_next;      /* next address for interface   */
 };
+
 #define        ifa_broadaddr   ifa_ifu.ifu_broadaddr   /* broadcast address    */
 #define        ifa_dstaddr     ifa_ifu.ifu_dstaddr     /* other end of link    */
 
@@ -67,7+72,8 @@ struct ifaddr {
  *     being very small might be worth keeping for clean configuration.
  */
 
-struct ifmap {
+struct ifmap 
+{
        unsigned long mem_start;
        unsigned long mem_end;
        unsigned short base_addr; 
@@ -83,7+89,9 @@ struct ifmap {
  * definitions which begin with ifr_name.  The
  * remainder may be interface specific.
  */
-struct ifreq {
+
+struct ifreq 
+{
 #define IFHWADDRLEN    6
 #define        IFNAMSIZ        16
        union
@@ -127,9+135,12 @@ struct ifreq {
  * for machine (useful for programs which
  * must know all networks accessible).
  */
-struct ifconf {
+
+struct ifconf 
+{
        int     ifc_len;                        /* size of buffer       */
-       union {
+       union 
+       {
                caddr_t ifcu_buf;
                struct  ifreq *ifcu_req;
        } ifc_ifcu;
index 1c268f2..e9100c7 100644 (file)
 enum {
   IPPROTO_IP = 0,              /* Dummy protocol for TCP               */
   IPPROTO_ICMP = 1,            /* Internet Control Message Protocol    */
-  IPPROTO_GGP = 2,             /* Gateway Protocol (deprecated)        */
+  IPPROTO_IGMP = 2,            /* Internet Gateway Management Protocol */
   IPPROTO_TCP = 6,             /* Transmission Control Protocol        */
   IPPROTO_EGP = 8,             /* Exterior Gateway Protocol            */
   IPPROTO_PUP = 12,            /* PUP protocol                         */
@@ -40,6+40,14 @@ struct in_addr {
        unsigned long int       s_addr;
 };
 
+/* Request struct for multicast socket ops */
+
+struct ip_mreq 
+{
+       struct in_addr imr_multiaddr;   /* IP multicast address of group */
+       struct in_addr imr_interface;   /* local IP address of interface */
+};
+
 
 /* Structure describing an Internet (IP) socket address. */
 #define __SOCK_SIZE__  16              /* sizeof(struct sockaddr)      */
@@ -121,7+129,7 @@ extern unsigned short int   ntohs(unsigned short int);
 extern unsigned long int       htonl(unsigned long int);
 extern unsigned short int      htons(unsigned short int);
 
-static __inline__ unsigned long int
+extern __inline__ unsigned long int
 __ntohl(unsigned long int x)
 {
        __asm__("xchgb %b0,%h0\n\t"     /* swap lower bytes     */
@@ -132,7+140,7 @@ __ntohl(unsigned long int x)
        return x;
 }
 
-static __inline__ unsigned long int
+extern __inline__ unsigned long int
 __constant_ntohl(unsigned long int x)
 {
        return (((x & 0x000000ffU) << 24) |
@@ -141,7+149,7 @@ __constant_ntohl(unsigned long int x)
                ((x & 0xff000000U) >> 24));
 }
 
-static __inline__ unsigned short int
+extern __inline__ unsigned short int
 __ntohs(unsigned short int x)
 {
        __asm__("xchgb %b0,%h0"         /* swap bytes           */
@@ -150,7+158,7 @@ __ntohs(unsigned short int x)
        return x;
 }
 
-static __inline__ unsigned short int
+extern __inline__ unsigned short int
 __constant_ntohs(unsigned short int x)
 {
        return (((x & 0x00ff) << 8) |
diff --git a/include/linux/ip_fw.h b/include/linux/ip_fw.h
new file mode 100644 (file)
index 0000000..6c15ec8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *     IP firewalling code. This is taken from 4.4BSD. Please note the 
+ *     copyright message below. As per the GPL it must be maintained
+ *     and the licenses thus do not conflict. While this port is subject
+ *     to the GPL I also place my modifications under the original 
+ *     license in recognition of the original copyright. 
+ *
+ *     Ported from BSD to Linux,
+ *             Alan Cox 22/Nov/1994.
+ *
+ *     All the real work was done by .....
+ */
+
+/*
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ */
+
+/*
+ *     Format of an IP firewall descriptor
+ *
+ *     src, dst, src_mask, dst_mask are always stored in network byte order.
+ *     flags and num_*_ports are stored in host byte order (of course).
+ *     Port numbers are stored in HOST byte order.
+ */
+#ifndef _IP_FW_H
+#define _IP_FW_H
+
+struct ip_fw 
+{
+       struct ip_fw *next;                     /* Next firewall on chain */
+       struct in_addr src, dst;                /* Source and destination IP addr */
+       struct in_addr src_mask, dst_mask;      /* Mask for src and dest IP addr */
+       unsigned short flags;                   /* Flags word */
+       unsigned short n_src_p, n_dst_p;        /* # of src ports and # of dst ports */
+                                               /* in ports array (dst ports follow */
+                                               /* src ports; max of 10 ports in all; */
+                                               /* count of 0 means match all ports) */
+#define IP_FW_MAX_PORTS        10                      /* A reasonable maximum */
+       unsigned short ports[IP_FW_MAX_PORTS];  /* Array of port numbers to match */
+       unsigned long p_cnt,b_cnt;              /* Packet and byte counters */
+};
+
+/*
+ *     Values for "flags" field .
+ */
+
+#define IP_FW_F_ALL    0x00    /* This is a universal packet firewall*/
+#define IP_FW_F_TCP    0x01    /* This is a TCP packet firewall      */
+#define IP_FW_F_UDP    0x02    /* This is a UDP packet firewall      */
+#define IP_FW_F_ICMP   0x03    /* This is a ICMP packet firewall     */
+#define IP_FW_F_KIND   0x03    /* Mask to isolate firewall kind      */
+#define IP_FW_F_ACCEPT 0x04    /* This is an accept firewall (as     *
+                                *         opposed to a deny firewall)*
+                                *                                    */
+#define IP_FW_F_SRNG   0x08    /* The first two src ports are a min  *
+                                * and max range (stored in host byte *
+                                * order).                            *
+                                *                                    */
+#define IP_FW_F_DRNG   0x10    /* The first two dst ports are a min  *
+                                * and max range (stored in host byte *
+                                * order).                            *
+                                * (ports[0] <= port <= ports[1])     *
+                                *                                    */
+#define IP_FW_F_PRN    0x20    /* In verbose mode print this firewall*/
+#define IP_FW_F_BIDIR  0x40    /* For accounting-count two way       */
+#define IP_FW_F_MASK   0x7F    /* All possible flag bits mask        */
+
+/*    
+ *     New IP firewall options for [gs]etsockopt at the RAW IP level.
+ *     Unlike BSD Linux inherits IP options so you don't have to use
+ *     a raw socket for this. Instead we check rights in the calls.
+ */     
+
+#define IP_FW_BASE_CTL 64
+
+#define IP_FW_ADD_BLK (IP_FW_BASE_CTL)
+#define IP_FW_ADD_FWD (IP_FW_BASE_CTL+1)   
+#define IP_FW_CHK_BLK (IP_FW_BASE_CTL+2)
+#define IP_FW_CHK_FWD (IP_FW_BASE_CTL+3)
+#define IP_FW_DEL_BLK (IP_FW_BASE_CTL+4)
+#define IP_FW_DEL_FWD (IP_FW_BASE_CTL+5)
+#define IP_FW_FLUSH   (IP_FW_BASE_CTL+6)
+#define IP_FW_POLICY  (IP_FW_BASE_CTL+7) 
+
+#define IP_ACCT_ADD   (IP_FW_BASE_CTL+10)
+#define IP_ACCT_DEL   (IP_FW_BASE_CTL+11)
+#define IP_ACCT_FLUSH (IP_FW_BASE_CTL+12)
+#define IP_ACCT_ZERO  (IP_FW_BASE_CTL+13)
+
+
+/*
+ *     Main firewall chains definitions and global var's definitions.
+ */
+
+#ifdef __KERNEL__
+#ifdef CONFIG_IP_FIREWALL
+extern struct ip_fw *ip_fw_blk_chain;
+extern struct ip_fw *ip_fw_fwd_chain;
+extern int ip_fw_policy;
+extern int ip_fw_chk(struct iphdr *, struct ip_fw *);
+extern int ip_fw_ctl(int, void *, int);
+#endif
+#ifdef CONFIG_IP_ACCT
+extern struct ip_fw *ip_acct_chain;
+extern void ip_acct_cnt(struct iphdr *, struct ip_fw *, int);
+extern int ip_acct_ctl(int, void *, int);
+#endif
+#endif /* KERNEL */
+
+#endif /* _IP_FW_H */
index a7a8417..3878e02 100644 (file)
@@ -58,6+58,8 @@ struct ipc_kludge {
 #define SHMGET                 23
 #define SHMCTL                 24
 
+#define IPCCALL(version,op)    ((version)<<16 | (op))
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_IPC_H */
index e2128f0..18d836d 100644 (file)
@@ -33,8+33,14 @@ struct vm_area_struct {
        unsigned long vm_end;
        unsigned short vm_page_prot;
        unsigned short vm_flags;
-       struct vm_area_struct * vm_next;        /* linked list */
-       struct vm_area_struct * vm_share;       /* linked list */
+/* linked list of VM areas per task, sorted by address */
+       struct vm_area_struct * vm_next;
+/* for areas with inode, the circular list inode->i_mmap */
+/* for shm areas, the linked list of attaches */
+/* otherwise unused */
+       struct vm_area_struct * vm_next_share;
+       struct vm_area_struct * vm_prev_share;
+/* more */
        struct vm_operations_struct * vm_ops;
        unsigned long vm_offset;
        struct inode * vm_inode;
@@ -64,21+70,22 @@ struct vm_area_struct {
 #define VM_STACK_FLAGS 0x0177
 
 /*
- * These are the virtual MM functions - opening of an area, closing it (needed to
- * keep files on disk up-to-date etc), pointer to the functions called when a
- * no-page or a wp-page exception occurs, and the function which decides on sharing
- * of pages between different processes.
+ * These are the virtual MM functions - opening of an area, closing and
+ * unmapping it (needed to keep files on disk up-to-date etc), pointer
+ * to the functions called when a no-page or a wp-page exception occurs. 
  */
 struct vm_operations_struct {
        void (*open)(struct vm_area_struct * area);
        void (*close)(struct vm_area_struct * area);
+       void (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
+       void (*protect)(struct vm_area_struct *area, unsigned long, size_t, unsigned int newprot);
+       void (*sync)(struct vm_area_struct *area, unsigned long, size_t, unsigned int flags);
+       void (*advise)(struct vm_area_struct *area, unsigned long, size_t, unsigned int advise);
        unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address,
                unsigned long page, int error_code);
        unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
                unsigned long page);
-       int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
-       int (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
-       void (*swapout)(struct vm_area_struct *,  unsigned long *);
+       void (*swapout)(struct vm_area_struct *,  unsigned long, unsigned long *);
        unsigned long (*swapin)(struct vm_area_struct *,  unsigned long);
 };
 
@@ -136,6+143,7 @@ extern unsigned char * free_area_map[NR_MEM_LISTS];
  */
 #define __get_free_page(priority) __get_free_pages((priority),0)
 extern unsigned long __get_free_pages(int priority, unsigned long gfporder);
+extern unsigned long __get_dma_pages(int priority, unsigned long gfporder);
 extern inline unsigned long get_free_page(int priority)
 {
        unsigned long page;
@@ -197,6+205,7 @@ extern int do_mmap(struct file * file, unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long off);
 extern void merge_segments(struct vm_area_struct *);
 extern void insert_vm_struct(struct task_struct *, struct vm_area_struct *);
+extern void remove_shared_vm_struct(struct vm_area_struct *);
 extern int do_munmap(unsigned long, size_t);
 extern unsigned long get_unmapped_area(unsigned long);
 
index 082fd88..12a1e9b 100644 (file)
 #define MAP_DENYWRITE  0x0800          /* ETXTBSY */
 #define MAP_EXECUTABLE 0x1000          /* mark it as a executable */
 
+#define MS_ASYNC       1       /* sync memory asynchronously */
+#define MS_INVALIDATE  2       /* invalidate the caches */
+#define MS_SYNC                4       /* synchronous memory sync */
+
 #endif /* _LINUX_MMAN_H */
index 0c66a3e..f12701e 100644 (file)
 #define IS_MULTICAST   5               /* Multicast IP address */
 
 /*
+ *     We tag these structures with multicasts.
+ */
+struct dev_mc_list
+{      
+       struct dev_mc_list *next;
+       char dmi_addr[MAX_ADDR_LEN];
+       unsigned short dmi_addrlen;
+       unsigned short dmi_users;
+};
+
+/*
  * The DEVICE structure.
  * Actually, this whole structure is a big mistake.  It mixes I/O
  * data with strictly "high-level" data, and it has to know about
@@ -107,7+119,12 @@ struct device
   unsigned long                  pa_dstaddr;   /* protocol P-P other side addr */
   unsigned long                  pa_mask;      /* protocol netmask             */
   unsigned short         pa_alen;      /* protocol address length      */
+
+  struct dev_mc_list    *mc_list;      /* Multicast mac addresses      */
+  int                   mc_count;      /* Number of installed mcasts   */
   
+  struct ip_mc_list     *ip_mc_list;   /* IP multicast filter chain    */
+    
   /* For load balancing driver pair support */
   
   unsigned long                   pkt_queue;   /* Packets queued */
@@ -202,6+219,13 @@ extern int         ether_config(struct device *dev, struct ifmap *map);
 extern int             register_netdev(struct device *dev);
 extern void            unregister_netdev(struct device *dev);
 
+/* Functions used for multicast support */
+
+extern void            dev_mc_upload(struct device *dev);
+extern void            dev_mc_delete(struct device *dev, void *addr, int alen, int all);
+extern void            dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
+extern void            dev_mc_discard(struct device *dev);
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_DEV_H */
index fca7ba7..c282632 100644 (file)
 #include <linux/wait.h>
 #include <linux/time.h>
 
-#define CONFIG_SKB_CHECK       1
+#undef CONFIG_SKB_CHECK
 
 #define HAVE_ALLOC_SKB         /* For the drivers to know */
 
@@ -94,7+94,9 @@ struct sk_buff {
 /*
  *     Handling routines are only of interest to the kernel
  */
+
+#include <asm/system.h>
+
 #if 0
 extern void                    print_skb(struct sk_buff *);
 #endif
@@ -131,8+133,146 @@ extern int                        skb_check(struct sk_buff *skb,int,int, char *);
 #define IS_SKB(skb)            skb_check((skb), 0, __LINE__,__FILE__)
 #define IS_SKB_HEAD(skb)       skb_check((skb), 1, __LINE__,__FILE__)
 #else
-#define IS_SKB(skb)            0
-#define IS_SKB_HEAD(skb)       0
+#define IS_SKB(skb)            
+#define IS_SKB_HEAD(skb)       
+
+extern __inline__ void skb_queue_head_init(struct sk_buff_head *list)
+{
+       list->prev = (struct sk_buff *)list;
+       list->next = (struct sk_buff *)list;
+}
+
+/*
+ *     Insert an sk_buff at the start of a list.
+ */
+
+extern __inline__ void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk)
+{
+       unsigned long flags;
+       struct sk_buff *list = (struct sk_buff *)list_;
+
+       save_flags(flags);
+       cli();
+       newsk->next = list->next;
+       newsk->prev = list;
+       newsk->next->prev = newsk;
+       newsk->prev->next = newsk;
+       restore_flags(flags);
+}
+
+/*
+ *     Insert an sk_buff at the end of a list.
+ */
+
+extern __inline__ void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
+{
+       unsigned long flags;
+       struct sk_buff *list = (struct sk_buff *)list_;
+
+       save_flags(flags);
+       cli();
+
+       newsk->next = list;
+       newsk->prev = list->prev;
+
+       newsk->next->prev = newsk;
+       newsk->prev->next = newsk;
+
+       restore_flags(flags);
+}
+
+/*
+ *     Remove an sk_buff from a list. This routine is also interrupt safe
+ *     so you can grab read and free buffers as another process adds them.
+ */
+
+extern __inline__ struct sk_buff *skb_dequeue(struct sk_buff_head *list_)
+{
+       long flags;
+       struct sk_buff *result;
+       struct sk_buff *list = (struct sk_buff *)list_;
+
+       save_flags(flags);
+       cli();
+
+       result = list->next;
+       if (result == list) {
+               restore_flags(flags);
+               return NULL;
+       }
+
+       result->next->prev = list;
+       list->next = result->next;
+
+       result->next = NULL;
+       result->prev = NULL;
+
+       restore_flags(flags);
+
+       return result;
+}
+
+/*
+ *     Insert a packet before another one in a list.
+ */
+
+extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       newsk->next = old;
+       newsk->prev = old->prev;
+       old->prev = newsk;
+       newsk->prev->next = newsk;
+
+       restore_flags(flags);
+}
+
+/*
+ *     Place a packet after a given packet in a list.
+ */
+
+extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+
+       newsk->prev = old;
+       newsk->next = old->next;
+       newsk->next->prev = newsk;
+       old->next = newsk;
+
+       restore_flags(flags);
+}
+
+/*
+ *     Remove an sk_buff from its list. Works even without knowing the list it
+ *     is sitting on, which can be handy at times. It also means that THE LIST
+ *     MUST EXIST when you unlink. Thus a list must have its contents unlinked
+ *     _FIRST_.
+ */
+
+extern __inline__ void skb_unlink(struct sk_buff *skb)
+{
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+
+       if(skb->prev && skb->next)
+       {
+               skb->next->prev = skb->prev;
+               skb->prev->next = skb->next;
+               skb->next = NULL;
+               skb->prev = NULL;
+       }
+       restore_flags(flags);
+}
+
 #endif
 
 extern struct sk_buff *                skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
index 2248801..eebfb3f 100644 (file)
@@ -32,6+32,7 @@ struct linger {
 #define AF_INET                2
 #define AF_AX25                3
 #define AF_IPX         4
+#define AF_APPLETALK   5
 
 #define AF_MAX         8       /* For now.. */
 
@@ -41,8+42,10 @@ struct linger {
 #define PF_INET                AF_INET
 #define PF_AX25                AF_AX25
 #define PF_IPX         AF_IPX
+#define PF_APPLETALK   AF_APPLETALK
 
 #define PF_MAX         AF_MAX
+
 /* Flags we can use with send/ and recv. */
 #define MSG_OOB                1
 #define MSG_PEEK       2
@@ -70,6+73,7 @@ struct linger {
 #define SO_NO_CHECK    11
 #define SO_PRIORITY    12
 #define SO_LINGER      13
+/* To add :#define SO_REUSEPORT 14 */
 
 /* IP options */
 #define IP_TOS         1
@@ -77,7+81,21 @@ struct linger {
 #define        IPTOS_THROUGHPUT        0x08
 #define        IPTOS_RELIABILITY       0x04
 #define IP_TTL         2
+#define IP_HRDINCL     3
+#define IP_OPTIONS     4
+
+#define IP_MULTICAST_IF                        32
+#define IP_MULTICAST_TTL               33
+#define IP_MULTICAST_LOOP              34
+#define IP_ADD_MEMBERSHIP              35
+#define IP_DROP_MEMBERSHIP             36
+
 
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL        1
+#define IP_DEFAULT_MULTICAST_LOOP       1
+#define IP_MAX_MEMBERSHIPS              20
 /* IPX options */
 #define IPX_TYPE       1
 
index f416149..514832a 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 */
 
 /* Routing table calls (oldrtent - don't use) */
 #define SIOCADDRTOLD   0x8940          /* add routing table entry      */
index c06864a..dedbea6 100644 (file)
 #define TIOCSETD       0x5423
 #define TIOCGETD       0x5424
 #define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT 0x5426  /* For debugging only */
 #define FIONCLEX       0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX                0x5451
 #define FIOASYNC       0x5452
index 562539a..09eecf5 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -351,7+351,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
  * shmd->vm_start      virt addr of attach, multiple of SHMLBA
  * shmd->vm_end                multiple of SHMLBA
  * shmd->vm_next       next attach for task
- * shmd->vm_share      next attach for segment
+ * shmd->vm_next_share next attach for segment
  * shmd->vm_offset     offset into segment
  * shmd->vm_pte                signature for this attach
  */
@@ -359,10+359,12 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 static struct vm_operations_struct shm_vm_ops = {
        shm_open,               /* open */
        shm_close,              /* close */
+       NULL,                   /* unmap */
+       NULL,                   /* protect */
+       NULL,                   /* sync */
+       NULL,                   /* advise */
        NULL,                   /* nopage (done with swapin) */
        NULL,                   /* wppage */
-       NULL,                   /* share */
-       NULL,                   /* unmap */
        NULL,                   /* swapout (hardcoded right now) */
        shm_swap_in             /* swapin */
 };
@@ -438,7+440,6 @@ static int shm_map (struct vm_area_struct *shmd, int remap)
 
 /*
  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
- * raddr is needed to return addresses above 2Gig.
  */
 int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
@@ -453,12+454,6 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                return -EINVAL;
        }
 
-       if (raddr) {
-               err = verify_area(VERIFY_WRITE, raddr, sizeof(ulong));
-               if (err)
-                       return err;
-       }
-
        shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
        if (shp == IPC_UNUSED || shp == IPC_NOID) {
                /* printk("shmat() -> EINVAL because shmid = %d is invalid\n",shmid); */
@@ -510,7+505,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
        shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
                         | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
                         | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
-       shmd->vm_share = NULL;
+       shmd->vm_next_share = NULL;
        shmd->vm_inode = NULL;
        shmd->vm_offset = 0;
        shmd->vm_ops = &shm_vm_ops;
@@ -523,14+518,12 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
                return err;
        }
 
-       shmd->vm_share = shp->attaches;
+       shmd->vm_next_share = shp->attaches;
        shp->attaches = shmd;
        shp->shm_lpid = current->pid;
        shp->shm_atime = CURRENT_TIME;
 
-       if (!raddr)
-               return addr;
-       put_fs_long (addr, raddr);
+       *raddr = addr;
        return 0;
 }
 
@@ -546,7+539,7 @@ static void shm_open (struct vm_area_struct *shmd)
                printk("shm_open: unused id=%d PANIC\n", id);
                return;
        }
-       shmd->vm_share = shp->attaches;
+       shmd->vm_next_share = shp->attaches;
        shp->attaches = shmd;
        shp->shm_nattch++;
        shp->shm_atime = CURRENT_TIME;
@@ -570,9+563,9 @@ static void shm_close (struct vm_area_struct *shmd)
        /* remove from the list of attaches of the shm segment */
        id = (shmd->vm_pte >> SHM_ID_SHIFT) & SHM_ID_MASK;
        shp = shm_segs[id];
-       for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->vm_share)
+       for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->vm_next_share)
                if (*shmdp == shmd) {
-                       *shmdp = shmd->vm_share;
+                       *shmdp = shmd->vm_next_share;
                        goto found;
                }
        printk("shm_close: shm segment (id=%d) attach list inconsistent\n",id);
@@ -714,7+707,7 @@ int shm_swap (int prio)
                swap_free (swap_nr);
                return 0;
        }
-       for (shmd = shp->attaches; shmd; shmd = shmd->vm_share) {
+       for (shmd = shp->attaches; shmd; shmd = shmd->vm_next_share) {
                unsigned long tmp, *pte;
                if ((shmd->vm_pte >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {
                        printk ("shm_swap: id=%ld does not match shmd->vm_pte.id=%ld\n", id, shmd->vm_pte >> SHM_ID_SHIFT & SHM_ID_MASK);
index fb0e697..470bdc2 100644 (file)
 #include <linux/stat.h>
 
 void ipc_init (void);
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr);
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth);
 
 #ifdef CONFIG_SYSVIPC
 
@@ -62,9+62,13 @@ int ipcperms (struct ipc_perm *ipcp, short flag)
        return 0;
 }
 
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
-       
+       int version;
+
+       version = call >> 16; /* hack for backward compatibility */
+       call &= 0xffff;
+
        if (call <= SEMCTL)
                switch (call) {
                case SEMOP:
@@ -89,17+93,21 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
                case MSGSND:
                        return sys_msgsnd (first, (struct msgbuf *) ptr, 
                                           second, third);
-               case MSGRCV: {
-                       struct ipc_kludge tmp;
-                       int err;
-                       if (!ptr)
-                               return -EINVAL;
-                       if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
-                               return err;
-                       memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
-                                      sizeof (tmp));
-                       return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
-                                               third);
+               case MSGRCV:
+                       switch (version) {
+                       case 0: {
+                               struct ipc_kludge tmp;
+                               int err;
+                               if (!ptr)
+                                       return -EINVAL;
+                               if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+                                       return err;
+                               memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
+                                              sizeof (tmp));
+                               return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+                               }
+                       case 1: default:
+                               return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
                        }
                case MSGGET:
                        return sys_msgget ((key_t) first, second);
@@ -111,8+119,21 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
        if (call <= SHMCTL) 
                switch (call) {
                case SHMAT:
-                       return sys_shmat (first, (char *) ptr, second, 
-                                                       (ulong *) third);
+                       switch (version) {
+                       case 0: default: {
+                               ulong raddr;
+                               int err;
+                               if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+                                       return err;
+                               err = sys_shmat (first, (char *) ptr, second, &raddr);
+                               if (err)
+                                       return err;
+                               put_fs_long (raddr, (ulong *) third);
+                               return 0;
+                               }
+                       case 1:
+                               return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+                       }
                case SHMDT: 
                        return sys_shmdt ((char *)ptr);
                case SHMGET:
@@ -127,7+148,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
 
 #else /* not CONFIG_SYSVIPC */
 
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) 
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth
 {
     return -ENOSYS;
 }
index b2a8c4f..fbac1dd 100644 (file)
@@ -364,6+364,7 @@ static void exit_mm(void)
                struct vm_area_struct * next = mpnt->vm_next;
                if (mpnt->vm_ops && mpnt->vm_ops->close)
                        mpnt->vm_ops->close(mpnt);
+               remove_shared_vm_struct(mpnt);
                if (mpnt->vm_inode)
                        iput(mpnt->vm_inode);
                kfree(mpnt);
index 63a54e9..9cc2b46 100644 (file)
@@ -100,8+100,13 @@ static int dup_mmap(struct task_struct * tsk)
                *tmp = *mpnt;
                tmp->vm_task = tsk;
                tmp->vm_next = NULL;
-               if (tmp->vm_inode)
+               if (tmp->vm_inode) {
                        tmp->vm_inode->i_count++;
+                       /* insert tmp into the share list, just after mpnt */
+                       tmp->vm_next_share->vm_prev_share = tmp;
+                       mpnt->vm_next_share = tmp;
+                       tmp->vm_prev_share = mpnt;
+               }
                if (tmp->vm_ops && tmp->vm_ops->open)
                        tmp->vm_ops->open(tmp);
                *p = tmp;
index 62bca05..274e818 100644 (file)
@@ -105,9+105,12 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
        X(set_blocksize),
        X(getblk),
        X(bread),
+       X(breada),
        X(brelse),
        X(ll_rw_block),
        X(__wait_on_buffer),
+       X(dcache_lookup),
+       X(dcache_add),
 
        /* device registration */
        X(register_chrdev),
index 1ce3ee3..95301cf 100644 (file)
@@ -32,7+32,7 @@ extern void adjust_clock(void);
 
 asmlinkage int sys_ni_syscall(void)
 {
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 asmlinkage int sys_idle(void)
index 5063d60..1949591 100644 (file)
 .c.s:
        $(CC) $(CFLAGS) -S $<
 
-OBJS   = memory.o swap.o mmap.o mprotect.o kmalloc.o vmalloc.o
+OBJS   = memory.o swap.o mmap.o filemap.o mprotect.o kmalloc.o vmalloc.o
 
 mm.o: $(OBJS)
        $(LD) -r -o mm.o $(OBJS)
diff --git a/mm/filemap.c b/mm/filemap.c
new file mode 100644 (file)
index 0000000..c829d2b
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *     linux/mm/filemmap.c
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+/*
+ * This file handles the generic file mmap semantics used by
+ * most "normal" filesystems (but you don't /have/ to use this:
+ * the NFS filesystem does this differently, for example)
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+/*
+ * Shared mappings implemented 30.11.1994. It's not fully working yet,
+ * though.
+ */
+
+static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
+       unsigned long page, int no_share)
+{
+       struct inode * inode = area->vm_inode;
+       unsigned int block;
+       int nr[8];
+       int i, *p;
+
+       address &= PAGE_MASK;
+       block = address - area->vm_start + area->vm_offset;
+       block >>= inode->i_sb->s_blocksize_bits;
+       i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
+       p = nr;
+       do {
+               *p = bmap(inode,block);
+               i--;
+               block++;
+               p++;
+       } while (i > 0);
+       return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, no_share);
+}
+
+/*
+ * NOTE! mmap sync doesn't really work yet. This is mainly a stub for it,
+ * which only works if the buffers and the page were already sharing the
+ * same physical page (that's actually pretty common, especially if the
+ * file has been mmap'ed before being read the normal way).
+ *
+ * Todo:
+ * - non-shared pages also need to be synced with the buffers.
+ * - the "swapout()" function needs to swap out the page to
+ *   the shared file instead of using the swap device.
+ */
+static inline void file_mmap_sync_page(struct vm_area_struct * vma,
+       unsigned long offset,
+       unsigned long page)
+{
+       struct buffer_head * bh;
+
+       bh = buffer_pages[MAP_NR(page)];
+       if (bh) {
+               /* whee.. just mark the buffer heads dirty */
+               struct buffer_head * tmp = bh;
+               do {
+                       mark_buffer_dirty(tmp, 0);
+                       tmp = tmp->b_this_page;
+               } while (tmp != bh);
+               return;
+       }
+       /* we'll need to go fetch the buffer heads etc.. RSN */
+       printk("msync: %ld: [%08lx]\n", offset, page);
+       printk("Can't handle non-shared page yet\n");
+       return;
+}
+
+static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start,
+       size_t size, unsigned int flags)
+{
+       unsigned long page_dir;
+       unsigned long *page_table, *dir;
+       unsigned long poff, pcnt, pc;
+
+       size = size >> PAGE_SHIFT;
+       dir = PAGE_DIR_OFFSET(current->tss.cr3,start);
+       poff = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
+       start -= vma->vm_start;
+       if ((pcnt = PTRS_PER_PAGE - poff) > size)
+               pcnt = size;
+
+       for ( ; size > 0; ++dir, size -= pcnt,
+            pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
+               if (!(PAGE_PRESENT & (page_dir = *dir))) {
+                       if (page_dir)
+                               printk("file_mmap_sync: bad page directory.\n");
+                       poff = 0;
+                       start += pcnt*PAGE_SIZE;
+                       continue;
+               }
+               page_table = (unsigned long *)(PAGE_MASK & page_dir);
+               if (poff) {
+                       page_table += poff;
+                       poff = 0;
+               }
+               for (pc = pcnt; pc--; page_table++, start += PAGE_SIZE) {
+                       unsigned long page = *page_table;
+                       if (!(page & PAGE_PRESENT))
+                               continue;
+                       if (!(page & PAGE_DIRTY))
+                               continue;
+                       mem_map[MAP_NR(page)]++;
+                       if (flags & MS_INVALIDATE) {
+                               *page_table = 0;
+                               free_page(page);
+                       } else
+                               *page_table = page & ~PAGE_DIRTY;
+                       file_mmap_sync_page(vma, start, page);
+                       free_page(page);
+               }
+       }
+       invalidate();
+       return;
+}
+
+/*
+ * This handles area unmaps..
+ */
+static void file_mmap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len)
+{
+       if (vma->vm_page_prot & PAGE_RW)
+               file_mmap_sync(vma, start, len, MS_ASYNC);
+}
+
+/*
+ * This handles complete area closes..
+ */
+static void file_mmap_close(struct vm_area_struct * vma)
+{
+       if (vma->vm_page_prot & PAGE_RW)
+               file_mmap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC);
+}
+
+/*
+ * This isn't implemented yet: you'll get a warning and incorrect behaviour.
+ *
+ * Note that the page is free'd by the higher-level after return,
+ * so we have to either write it out or just forget it. We currently
+ * forget it..
+ */
+void file_mmap_swapout(struct vm_area_struct * vma,
+       unsigned long offset,
+       unsigned long *pte)
+{
+       printk("swapout not implemented on shared files..\n");
+       *pte = 0;
+}
+
+/*
+ * Shared mappings need to be able to do the right thing at
+ * close/unmap/sync. They will also use the private file as
+ * backing-store for swapping..
+ */
+static struct vm_operations_struct file_shared_mmap = {
+       NULL,                   /* open */
+       file_mmap_close,        /* close */
+       file_mmap_unmap,        /* unmap */
+       NULL,                   /* protect */
+       file_mmap_sync,         /* sync */
+       NULL,                   /* advise */
+       file_mmap_nopage,       /* nopage */
+       NULL,                   /* wppage */
+       file_mmap_swapout,      /* swapout */
+       NULL,                   /* swapin */
+};
+
+/*
+ * Private mappings just need to be able to load in the map
+ *
+ * (this is actually used for shared mappings as well, if we
+ * know they can't ever get write permissions..)
+ */
+static struct vm_operations_struct file_private_mmap = {
+       NULL,                   /* open */
+       NULL,                   /* close */
+       NULL,                   /* unmap */
+       NULL,                   /* protect */
+       NULL,                   /* sync */
+       NULL,                   /* advise */
+       file_mmap_nopage,       /* nopage */
+       NULL,                   /* wppage */
+       NULL,                   /* swapout */
+       NULL,                   /* swapin */
+};
+
+/* This is used for a general mmap of a disk file */
+int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+{
+       struct vm_operations_struct * ops;
+
+       if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
+               return -EINVAL;
+       if (!inode->i_sb || !S_ISREG(inode->i_mode))
+               return -EACCES;
+       if (!inode->i_op || !inode->i_op->bmap)
+               return -ENOEXEC;
+       ops = &file_private_mmap;
+       if (vma->vm_flags & VM_SHARED) {
+               if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+                       ops = &file_shared_mmap;
+       }
+       if (!IS_RDONLY(inode)) {
+               inode->i_atime = CURRENT_TIME;
+               inode->i_dirt = 1;
+       }
+       vma->vm_inode = inode;
+       inode->i_count++;
+       vma->vm_ops = ops;
+       return 0;
+}
index 018f8db..8b8f717 100644 (file)
@@ -84,6+84,7 @@ struct page_descriptor {
  */
 struct size_descriptor {
        struct page_descriptor *firstfree;
+       struct page_descriptor *dmafree; /* DMA-able memory */
        int size;
        int nblocks;
 
@@ -100,20+101,20 @@ struct size_descriptor {
  */
 
 struct size_descriptor sizes[] = { 
-       { NULL,  32,127, 0,0,0,0, 0},
-       { NULL,  64, 63, 0,0,0,0, 0 },
-       { NULL, 128, 31, 0,0,0,0, 0 },
-       { NULL, 252, 16, 0,0,0,0, 0 },
-       { NULL, 508,  8, 0,0,0,0, 0 },
-       { NULL,1020,  4, 0,0,0,0, 0 },
-       { NULL,2040,  2, 0,0,0,0, 0 },
-       { NULL,4096-16,  1, 0,0,0,0, 0 },
-       { NULL,8192-16,  1, 0,0,0,0, 1 },
-       { NULL,16384-16,  1, 0,0,0,0, 2 },
-       { NULL,32768-16,  1, 0,0,0,0, 3 },
-       { NULL,65536-16,  1, 0,0,0,0, 4 },
-       { NULL,131072-16,  1, 0,0,0,0, 5 },
-       { NULL,   0,  0, 0,0,0,0, 0 }
+       { NULL, NULL,  32,127, 0,0,0,0, 0},
+       { NULL, NULL,  64, 63, 0,0,0,0, 0 },
+       { NULL, NULL, 128, 31, 0,0,0,0, 0 },
+       { NULL, NULL, 252, 16, 0,0,0,0, 0 },
+       { NULL, NULL, 508,  8, 0,0,0,0, 0 },
+       { NULL, NULL,1020,  4, 0,0,0,0, 0 },
+       { NULL, NULL,2040,  2, 0,0,0,0, 0 },
+       { NULL, NULL,4096-16,  1, 0,0,0,0, 0 },
+       { NULL, NULL,8192-16,  1, 0,0,0,0, 1 },
+       { NULL, NULL,16384-16,  1, 0,0,0,0, 2 },
+       { NULL, NULL,32768-16,  1, 0,0,0,0, 3 },
+       { NULL, NULL,65536-16,  1, 0,0,0,0, 4 },
+       { NULL, NULL,131072-16,  1, 0,0,0,0, 5 },
+       { NULL, NULL,   0,  0, 0,0,0,0, 0 }
 };
 
 
@@ -164,9+165,13 @@ void * kmalloc (size_t size, int priority)
 {
        unsigned long flags;
        int order,tries,i,sz;
+       int dma_flag;
        struct block_header *p;
        struct page_descriptor *page;
 
+       dma_flag = (priority & GFP_DMA);
+       priority &= GFP_LEVEL_MASK;
+         
 /* Sanity check... */
        if (intr_count && priority != GFP_ATOMIC) {
                static int count = 0;
@@ -193,7+198,7 @@ while (tries --)
     {
     /* Try to allocate a "recently" freed memory block */
     cli ();
-    if ((page = sizes[order].firstfree) &&
+    if ((page = (dma_flag ? sizes[order].dmafree : sizes[order].firstfree)) &&
         (p    =  page->firstfree))
         {
         if (p->bh_flags == MF_FREE)
@@ -224,7+229,11 @@ while (tries --)
     sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */
 
     /* This can be done with ints on: This is private to this invocation */
-    page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
+    if (dma_flag)
+      page = (struct page_descriptor *) __get_dma_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
+    else
+      page = (struct page_descriptor *) __get_free_pages (priority & GFP_LEVEL_MASK, sizes[order].gfporder);
+
     if (!page) {
         static unsigned long last = 0;
         if (last + 10*HZ < jiffies) {
@@ -262,7+271,10 @@ while (tries --)
      * here, but you never know.... 
      */
     page->next = sizes[order].firstfree;
-    sizes[order].firstfree = page;
+    if (dma_flag)
+      sizes[order].dmafree = page;
+    else
+      sizes[order].firstfree = page;
     restore_flags(flags);
     }
 
@@ -280,7+292,6 @@ printk ("Hey. This is very funny. I tried %d times to allocate a whole\n"
 return NULL;
 }
 
-
 void kfree_s (void *ptr,int size)
 {
 unsigned long flags;
@@ -315,7+326,8 @@ page->firstfree = p;
 page->nfree ++;
 
 if (page->nfree == 1)
-   { /* Page went from full to one free block: put it on the freelist */
+   { /* Page went from full to one free block: put it on the freelist.  Do not bother
+      trying to put it on the DMA list. */
    if (page->next)
         {
         printk ("Page %p already on freelist dazed and confused....\n", page);
@@ -337,12+349,21 @@ if (page->nfree == NBLOCKS (page->order))
         {
         sizes[order].firstfree = page->next;
         }
+    else if (sizes[order].dmafree == page)
+        {
+        sizes[order].dmafree = page->next;
+        }
     else
         {
         for (pg2=sizes[order].firstfree;
                 (pg2 != NULL) && (pg2->next != page);
                         pg2=pg2->next)
             /* Nothing */;
+       if (!pg2)
+         for (pg2=sizes[order].dmafree;
+              (pg2 != NULL) && (pg2->next != page);
+              pg2=pg2->next)
+            /* Nothing */;
         if (pg2 != NULL)
             pg2->next = page->next;
         else
index 3e5a670..d526213 100644 (file)
@@ -84,7+84,7 @@ unsigned short * mem_map = NULL;
  */
 void oom(struct task_struct * task)
 {
-       printk("\nOut of memory.\n");
+       printk("\nOut of memory for %s.\n", current->comm);
        task->sigaction[SIGKILL-1].sa_handler = NULL;
        task->blocked &= ~(1<<(SIGKILL-1));
        send_sig(SIGKILL,task,1);
@@ -804,10+804,10 @@ static int share_page(struct vm_area_struct * area, unsigned long address,
        unsigned long error_code, unsigned long newpage)
 {
        struct inode * inode;
-       struct task_struct ** p;
        unsigned long offset;
        unsigned long from_address;
        unsigned long give_page;
+       struct vm_area_struct * mpnt;
 
        if (!area || !(inode = area->vm_inode) || inode->i_count < 2)
                return 0;
@@ -819,34+819,29 @@ static int share_page(struct vm_area_struct * area, unsigned long address,
                give_page = newpage;
        }
        offset = address - area->vm_start + area->vm_offset;
-       for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
-               struct vm_area_struct * mpnt;
-               if (!*p)
+       /* See if there is something in the VM we can share pages with. */
+       /* Traverse the entire circular i_mmap list, except `area' itself. */
+       for (mpnt = area->vm_next_share; mpnt != area; mpnt = mpnt->vm_next_share) {
+               /* must be same inode */
+               if (mpnt->vm_inode != inode) {
+                       printk("Aiee! Corrupt vm_area_struct i_mmap ring\n");
+                       break;  
+               }
+               /* offsets must be mutually page-aligned */
+               if ((mpnt->vm_offset ^ area->vm_offset) & ~PAGE_MASK)
                        continue;
-               if (area->vm_task == *p)
+               /* the other area must actually cover the wanted page.. */
+               from_address = offset + mpnt->vm_start - mpnt->vm_offset;
+               if (from_address < mpnt->vm_start || from_address >= mpnt->vm_end)
                        continue;
-               /* Now see if there is something in the VMM that
-                  we can share pages with */
-               for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
-                       /* must be same inode */
-                       if (mpnt->vm_inode != inode)
-                               continue;
-                       /* offsets must be mutually page-aligned */
-                       if ((mpnt->vm_offset ^ area->vm_offset) & ~PAGE_MASK)
-                               continue;
-                       /* the other area must actually cover the wanted page.. */
-                       from_address = offset + mpnt->vm_start - mpnt->vm_offset;
-                       if (from_address < mpnt->vm_start || from_address >= mpnt->vm_end)
-                               continue;
-                       /* .. NOW we can actually try to use the same physical page */
-                       if (!try_to_share(address, area, from_address, mpnt, give_page))
-                               continue;
-                       /* free newpage if we never used it.. */
-                       if (give_page || !newpage)
-                               return 1;
-                       free_page(newpage);
+               /* .. NOW we can actually try to use the same physical page */
+               if (!try_to_share(address, area, from_address, mpnt, give_page))
+                       continue;
+               /* free newpage if we never used it.. */
+               if (give_page || !newpage)
                        return 1;
-               }
+               free_page(newpage);
+               return 1;
        }
        return 0;
 }
@@ -1283,38+1278,3 @@ void si_meminfo(struct sysinfo *val)
        val->sharedram <<= PAGE_SHIFT;
        return;
 }
-
-
-/*
- * This handles a generic mmap of a disk file.
- */
-static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address,
-       unsigned long page, int no_share)
-{
-       struct inode * inode = area->vm_inode;
-       unsigned int block;
-       int nr[8];
-       int i, *p;
-
-       address &= PAGE_MASK;
-       block = address - area->vm_start + area->vm_offset;
-       block >>= inode->i_sb->s_blocksize_bits;
-       i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
-       p = nr;
-       do {
-               *p = bmap(inode,block);
-               i--;
-               block++;
-               p++;
-       } while (i > 0);
-       return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, no_share);
-}
-
-struct vm_operations_struct file_mmap = {
-       NULL,                   /* open */
-       NULL,                   /* close */
-       file_mmap_nopage,       /* nopage */
-       NULL,                   /* wppage */
-       NULL,                   /* share */
-       NULL,                   /* unmap */
-};
index fbbea98..5fc29b2 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -341,15+341,16 @@ int do_munmap(unsigned long addr, size_t len)
                mpnt = free;
                free = free->vm_next;
 
+               remove_shared_vm_struct(mpnt);
+
                st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
                end = addr+len;
                end = end > mpnt->vm_end ? mpnt->vm_end : end;
 
                if (mpnt->vm_ops && mpnt->vm_ops->unmap)
                        mpnt->vm_ops->unmap(mpnt, st, end-st);
-               else
-                       unmap_fixup(mpnt, st, end-st);
 
+               unmap_fixup(mpnt, st, end-st);
                kfree(mpnt);
        }
 
@@ -357,35+358,14 @@ int do_munmap(unsigned long addr, size_t len)
        return 0;
 }
 
-/* This is used for a general mmap of a disk file */
-int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
-{
-       extern struct vm_operations_struct file_mmap;
-
-       if (vma->vm_page_prot & PAGE_RW)        /* only PAGE_COW or read-only supported right now */
-               return -EINVAL;
-       if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
-               return -EINVAL;
-       if (!inode->i_sb || !S_ISREG(inode->i_mode))
-               return -EACCES;
-       if (!inode->i_op || !inode->i_op->bmap)
-               return -ENOEXEC;
-       if (!IS_RDONLY(inode)) {
-               inode->i_atime = CURRENT_TIME;
-               inode->i_dirt = 1;
-       }
-       vma->vm_inode = inode;
-       inode->i_count++;
-       vma->vm_ops = &file_mmap;
-       return 0;
-}
-
 /*
- * Insert vm structure into process list sorted by address.
+ * Insert vm structure into process list sorted by address
+ * and into the inode's i_mmap ring.
  */
 void insert_vm_struct(struct task_struct *t, struct vm_area_struct *vmp)
 {
-       struct vm_area_struct **p, *mpnt;
+       struct vm_area_struct **p, *mpnt, *share;
+       struct inode * inode;
 
        p = &t->mm->mmap;
        while ((mpnt = *p) != NULL) {
@@ -397,6+377,43 @@ void insert_vm_struct(struct task_struct *t, struct vm_area_struct *vmp)
        }
        vmp->vm_next = mpnt;
        *p = vmp;
+
+       inode = vmp->vm_inode;
+       if (!inode)
+               return;
+
+       /* insert vmp into inode's circular share list */
+       if ((share = inode->i_mmap)) {
+               vmp->vm_next_share = share->vm_next_share;
+               vmp->vm_next_share->vm_prev_share = vmp;
+               share->vm_next_share = vmp;
+               vmp->vm_prev_share = share;
+       } else
+               inode->i_mmap = vmp->vm_next_share = vmp->vm_prev_share = vmp;
+}
+
+/*
+ * Remove one vm structure from the inode's i_mmap ring.
+ */
+void remove_shared_vm_struct(struct vm_area_struct *mpnt)
+{
+       struct inode * inode = mpnt->vm_inode;
+
+       if (!inode)
+               return;
+
+       if (mpnt->vm_next_share == mpnt) {
+               if (inode->i_mmap != mpnt)
+                       printk("Inode i_mmap ring corrupted\n");
+               inode->i_mmap = NULL;
+               return;
+       }
+
+       if (inode->i_mmap == mpnt)
+               inode->i_mmap = mpnt->vm_next_share;
+
+       mpnt->vm_prev_share->vm_next_share = mpnt->vm_next_share;
+       mpnt->vm_next_share->vm_prev_share = mpnt->vm_prev_share;
 }
 
 /*
@@ -451,6+468,7 @@ void merge_segments(struct vm_area_struct *mpnt)
                        mpnt->vm_start = mpnt->vm_end;
                        mpnt->vm_ops->close(mpnt);
                }
+               remove_shared_vm_struct(mpnt);
                if (mpnt->vm_inode)
                        mpnt->vm_inode->i_count--;
                kfree_s(mpnt, sizeof(*mpnt));
index 2d5b16d..fe110fc 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
 #include <linux/stat.h>
 #include <linux/fs.h>
 
+#include <asm/dma.h>
 #include <asm/system.h> /* for cli()/sti() */
 #include <asm/bitops.h>
 
@@ -287,7+288,7 @@ unsigned long swap_in(unsigned long entry)
        return page | PAGE_DIRTY | PAGE_PRESENT;
 }
 
-static inline int try_to_swap_out(unsigned long * table_ptr)
+static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, unsigned long * table_ptr)
 {
        unsigned long page, entry;
 
@@ -311,13+312,18 @@ static inline int try_to_swap_out(unsigned long * table_ptr)
                page &= PAGE_MASK;
                if (mem_map[MAP_NR(page)] != 1)
                        return 0;
-               if (!(entry = get_swap_page()))
-                       return 0;
-               *table_ptr = entry;
-               invalidate();
-               write_swap_page(entry, (char *) page);
+               if (vma->vm_ops && vma->vm_ops->swapout)
+                       vma->vm_ops->swapout(vma, offset, table_ptr);
+               else
+               {
+                       if (!(entry = get_swap_page()))
+                               return 0;
+                       *table_ptr = entry;
+                       invalidate();
+                       write_swap_page(entry, (char *) page);
+               }
                free_page(page);
-               return 1;
+               return 1 + mem_map[MAP_NR(page)];
        }
         if ((entry = find_in_swap_cache(page)))  {
                if (mem_map[MAP_NR(page)] != 1) {
@@ -370,11+376,28 @@ static int swap_out_process(struct task_struct * p)
        unsigned long offset;
        unsigned long *pgdir;
        unsigned long pg_table;
+       struct vm_area_struct* vma;
 
        /*
         * Go through process' page directory.
         */
        address = p->mm->swap_address;
+       p->mm->swap_address = 0;
+
+       /*
+        * Find the proper vm-area
+        */
+       vma = p->mm->mmap;
+       for (;;) {
+               if (!vma)
+                       return 0;
+               if (address <= vma->vm_end)
+                       break;
+               vma = vma->vm_next;
+       }
+       if (address < vma->vm_start)
+               address = vma->vm_start;
+
        pgdir = (address >> PGDIR_SHIFT) + (unsigned long *) p->tss.cr3;
        offset = address & ~PGDIR_MASK;
        address &= PGDIR_MASK;
@@ -397,7+420,18 @@ static int swap_out_process(struct task_struct * p)
                 * Go through this page table.
                 */
                for( ; offset < ~PGDIR_MASK ; offset += PAGE_SIZE) {
-                       switch(try_to_swap_out((unsigned long *) (pg_table + (offset >> 10)))) {
+                       /*
+                        * Update vma again..
+                        */
+                       for (;;) {
+                               if (address+offset < vma->vm_end)
+                                       break;
+                               vma = vma->vm_next;
+                               if (!vma)
+                                       return 0;
+                       }
+
+                       switch(try_to_swap_out(vma, offset+address-vma->vm_start, (unsigned long *) (pg_table + (offset >> 10)))) {
                                case 0:
                                        break;
 
@@ -415,9+449,8 @@ static int swap_out_process(struct task_struct * p)
        }
        /*
         * Finish work with this process, if we reached the end of the page
-        * directory.  Mark restart from the beginning the next time.
+        * directory.
         */
-       p->mm->swap_address = 0;
        return 0;
 }
 
@@ -647,10+680,10 @@ repeat:
  */
 unsigned long __get_dma_pages(int priority, unsigned long order)
 {
-       unsigned long list = 0; 
+       unsigned long list = 0;
        unsigned long result;
-       unsigned long limit = 16*1024*1024;
-       
+       unsigned long limit = MAX_DMA_ADDRESS;
+
        /* if (EISA_bus) limit = ~0UL; */
        if (priority != GFP_ATOMIC)
                priority = GFP_BUFFER;
index 95af292..2d0c501 100644 (file)
        $(CC) $(CFLAGS) -S $<
 
 
-OBJS   := sock.o eth.o dev.o skbuff.o datagram.o
+OBJS   := sock.o eth.o dev.o dev_mcast.o skbuff.o datagram.o
 
 ifdef CONFIG_INET
 
 OBJS   := $(OBJS) utils.o route.o proc.o timer.o protocol.o packet.o \
-                  arp.o ip.o raw.o icmp.o tcp.o udp.o devinet.o af_inet.o
-
-endif
+                  arp.o ip.o raw.o icmp.o tcp.o udp.o devinet.o af_inet.o \
+                  igmp.o ip_fw.o 
 
 ifdef CONFIG_INET_RARP
 
 OBJS   := $(OBJS) rarp.o
 
 endif
+endif
 
 ifdef CONFIG_AX25
 
index 8e77396..ef211f8 100644 (file)
@@ -652,6+652,11 @@ static int inet_create(struct socket *sock, int protocol)
        sk->dummy_th.dest = 0;
        sk->ip_tos=0;
        sk->ip_ttl=64;
+#ifdef CONFIG_IP_MULTICAST
+       sk->ip_mc_loop=0;
+       sk->ip_mc_ttl=1;
+       *sk->ip_mc_name=0;
+#endif
        
        sk->state_change = def_callback1;
        sk->data_ready = def_callback2;
@@ -1227,6+1232,12 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCSIFFLAGS:
                case SIOCGIFADDR:
                case SIOCSIFADDR:
+
+/* begin multicast support change */
+               case SIOCADDMULTI:
+               case SIOCDELMULTI:
+/* end multicast support change */
+               
                case SIOCGIFDSTADDR:
                case SIOCSIFDSTADDR:
                case SIOCGIFBRDADDR:
@@ -1331,6+1342,79 @@ struct sock *get_sock(struct proto *prot, unsigned short num,
        return result;
 }
 
+/*
+ *     Deliver a datagram to raw sockets.
+ */
+struct sock *get_sock_raw(struct sock *sk, 
+                               unsigned short num,
+                               unsigned long raddr,
+                               unsigned long laddr)
+{
+       struct sock *s;
+
+       s=sk;
+
+       for(; s != NULL; s = s->next) 
+       {
+               if (s->num != num) 
+                       continue;
+               if(s->dead && (s->state == TCP_CLOSE))
+                       continue;
+               if(s->daddr && s->daddr!=raddr)
+                       continue;
+               if(s->saddr  && s->saddr!=laddr)
+                       continue;
+               return(s);
+       }
+       return(NULL);
+}
+
+#ifdef CONFIG_IP_MULTICAST
+/*
+ *     Deliver a datagram to broadcast/multicast sockets.
+ */
+struct sock *get_sock_mcast(struct sock *sk, 
+                               unsigned short num,
+                               unsigned long raddr,
+                               unsigned short rnum, unsigned long laddr)
+{
+       struct sock *s;
+       unsigned short hnum;
+
+       hnum = ntohs(num);
+
+       /*
+        * SOCK_ARRAY_SIZE must be a power of two.  This will work better
+        * than a prime unless 3 or more sockets end up using the same
+        * array entry.  This should not be a problem because most
+        * well known sockets don't overlap that much, and for
+        * the other ones, we can just be careful about picking our
+        * socket number when we choose an arbitrary one.
+        */
+       
+       s=sk;
+
+       for(; s != NULL; s = s->next) 
+       {
+               if (s->num != hnum) 
+                       continue;
+               if(s->dead && (s->state == TCP_CLOSE))
+                       continue;
+               if(s->daddr && s->daddr!=raddr)
+                       continue;
+               if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) 
+                       continue;
+               if(s->saddr  && s->saddr!=laddr)
+                       continue;
+               return(s);
+       }
+       return(NULL);
+}
+
+#endif
+
 static struct proto_ops inet_proto_ops = {
        AF_INET,
 
@@ -1369,7+1453,7 @@ void inet_proto_init(struct net_proto *pro)
        int i;
 
 
-       printk("Swansea University Computer Society TCP/IP for NET3.017\n");
+       printk("Swansea University Computer Society TCP/IP for NET3.018\n");
 
        /*
         *      Tell SOCKET that we are alive... 
index 67174bb..0232a63 100644 (file)
@@ -787,6+787,10 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
 {
        struct arp_table *entry;
        unsigned long hash;
+#ifdef CONFIG_IP_MULTICAST
+       unsigned long taddr;
+#endif 
+
        switch (ip_chk_addr(paddr))
        {
                case IS_MYADDR:
@@ -794,6+798,26 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
                        memcpy(haddr, dev->dev_addr, dev->addr_len);
                        skb->arp = 1;
                        return 0;
+#ifdef CONFIG_IP_MULTICAST
+               case IS_MULTICAST:
+                       if(dev->type==ARPHRD_ETHER || dev->type==ARPHRD_IEEE802)
+                       {
+                               haddr[0]=0x01;
+                               haddr[1]=0x00;
+                               haddr[2]=0x5e;
+                               taddr=ntohl(paddr);
+                               haddr[5]=taddr&0xff;
+                               taddr=taddr>>8;
+                               haddr[4]=taddr&0xff;
+                               taddr=taddr>>8;
+                               haddr[3]=taddr&0x7f;
+                               return 0;
+                       }
+               /*
+                *      If a device does not support multicast broadcast the stuff (eg AX.25 for now)
+                */
+#endif
+               
                case IS_BROADCAST:
                        memcpy(haddr, dev->broadcast, dev->addr_len);
                        skb->arp = 1;
index 9730703..7fd20cc 100644 (file)
  *                                     keep the queue safe.
  *             Alan Cox        :       Fixed double lock.
  *             Alan Cox        :       Fixed promisc NULL pointer trap
+ *             ????????        :       Support the full private ioctl range
+ *             Alan Cox        :       Moved ioctl permission check into drivers
+ *             Tim Kordas      :       SIOCADDMULTI/SIOCDELMULTI
  *
  *     Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have
  *     the rest as well commented in the end.
@@ -266,6+269,12 @@ int dev_open(struct device *dev)
        if (ret == 0) 
                dev->flags |= (IFF_UP | IFF_RUNNING);
        
+       /*
+        *      Initialise multicasting status 
+        */
+        
+       dev_mc_upload(dev);
+
        return(ret);
 }
 
@@ -305,6+314,10 @@ int dev_close(struct device *dev)
                ipxrtr_device_down(dev);
 #endif 
                /*
+                *      Flush the multicast chain
+                */
+               dev_mc_discard(dev);
+               /*
                 *      Blank the IP addresses
                 */
                dev->pa_addr = 0;
@@ -360,9+373,9 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
                dev=dev->slave;
        restore_flags(flags);
 #endif         
+#ifdef CONFIG_SKB_CHECK 
        IS_SKB(skb);
-    
+#endif    
        skb->dev = dev;
 
        /*
@@ -495,8+508,9 @@ void netif_rx(struct sk_buff *skb)
        /*
         *      Add it to the "backlog" queue. 
         */
-
+#ifdef CONFIG_SKB_CHECK
        IS_SKB(skb);
+#endif 
        skb_queue_tail(&backlog,skb);
        backlog_size++;
   
@@ -1070,15+1084,21 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                                dev->flags = ifr.ifr_flags & (
                                        IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
                                        IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
-                                       IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER);
+                                       IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER
+                                       | IFF_MULTICAST);
 #ifdef CONFIG_SLAVE_BALANCING                          
                                if(!(dev->flags&IFF_MASTER) && dev->slave)
                                {
                                        dev->slave->flags&=~IFF_SLAVE;
                                        dev->slave=NULL;
                                }
-#endif                         
+#endif
+                               /*
+                                *      Load in the correct multicast list now the flags have changed.
+                                */                             
 
+                               dev_mc_upload(dev);
+#if 0
                                if( dev->set_multicast_list!=NULL)
                                {
                                
@@ -1096,7+1116,7 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                                        if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
                                                dev->set_multicast_list(dev,-1,NULL);
                                }
-                                       
+#endif                                 
                                /*
                                 *      Have we downed the interface
                                 */
@@ -1340,6+1360,22 @@ static int dev_ifsioc(void *arg, unsigned int getset)
                }
                break;
 #endif                 
+
+               case SIOCADDMULTI:
+                       if(dev->set_multicast_list==NULL)
+                               return -EINVAL;
+                       if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC)
+                               return -EINVAL;
+                       dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1);
+                       return 0;
+
+               case SIOCDELMULTI:
+                       if(dev->set_multicast_list==NULL)
+                               return -EINVAL;
+                       if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC)
+                               return -EINVAL;
+                       dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1);
+                       return 0;
                /*
                 *      Unknown or private ioctl
                 */
@@ -1420,8+1456,6 @@ int dev_ioctl(unsigned int cmd, void *arg)
                default:
                        if((cmd >= SIOCDEVPRIVATE) &&
                           (cmd <= (SIOCDEVPRIVATE + 15))) {
-                               if (!suser())
-                                       return -EPERM;
                                return dev_ifsioc(arg, cmd);
                        }
                        return -EINVAL;
diff --git a/net/inet/dev_mcast.c b/net/inet/dev_mcast.c
new file mode 100644 (file)
index 0000000..94375d2
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ *     Linux NET3:     Multicast List maintenance. 
+ *
+ *     Authors:
+ *             Tim Kordas <tjk@nostromo.eeap.cwru.edu> 
+ *             Richard Underwood <richard@wuzz.demon.co.uk>
+ *
+ *     Stir fried together from the IP multicast and CAP patches above
+ *             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.
+ */
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include "ip.h"
+#include "route.h"
+#include <linux/skbuff.h>
+#include "sock.h"
+#include "arp.h"
+
+
+/*
+ *     Device multicast list maintenance. This knows about such little matters as promiscuous mode and
+ *     converting from the list to the array the drivers use. At least until I fix the drivers up.
+ *
+ *     This is used both by IP and by the user level maintenance functions. Unlike BSD we maintain a usage count
+ *     on a given multicast address so that a casual user application can add/delete multicasts used by protocols
+ *     without doing damage to the protocols when it deletes the entries. It also helps IP as it tracks overlapping
+ *     maps.
+ */
+
+/*
+ *     Update the multicast list into the physical NIC controller.
+ */
+void dev_mc_upload(struct device *dev)
+{
+       struct dev_mc_list *dmi;
+       char *data;
+       
+       /* Promiscuous is promiscuous - so no filter needed */
+       
+       if(dev->flags&IFF_PROMISC)
+               return;
+               
+       /* Devices with no set multicast don't get set */
+       if(dev->set_multicast_list==NULL)
+               return;
+       if(dev->mc_count==0)
+       {
+               dev->set_multicast_list(dev,0,NULL);
+               return;
+       }
+       
+       data=kmalloc(dev->mc_count*dev->addr_len, GFP_KERNEL);
+       if(data==NULL)
+       {
+               printk("Unable to get memory to set multicast list on %s\n",dev->name);
+               return;
+       }
+       for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
+       {
+               memcpy(data,dmi->dmi_addr, dmi->dmi_addrlen);
+               data+=dev->addr_len;
+       }
+       dev->set_multicast_list(dev,dev->mc_count,data);
+       kfree_s(data,dev->mc_count*dev->addr_len);
+}
+  
+/*
+ *     Delete a device level multicast
+ */
+void dev_mc_delete(struct device *dev, void *addr, int alen, int all)
+{
+       struct dev_mc_list **dmi;
+       for(dmi=&dev->mc_list;*dmi!=NULL;dmi=&(*dmi)->next)
+       {
+               if(memcmp((*dmi)->dmi_addr,addr,(*dmi)->dmi_addrlen)==0 && alen==(*dmi)->dmi_addrlen)
+               {
+                       struct dev_mc_list *tmp= *dmi;
+                       if((*dmi)->dmi_users-- && !all)
+                               return;
+                       *dmi=(*dmi)->next;
+                       dev->mc_count--;
+                       kfree_s(tmp,sizeof(*tmp));
+                       return;
+               }
+       }
+       dev_mc_upload(dev);
+}
+
+/*
+ *     Add a device level multicast
+ */
+void dev_mc_add(struct device *dev, void *addr, int alen, int newonly)
+{
+       struct dev_mc_list *dmi;
+       for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next)
+       {
+               if(memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen)
+               {
+                       if(!newonly)
+                               dmi->dmi_users++;
+                       return;
+               }
+       }
+       dmi=(struct dev_mc_list *)kmalloc(sizeof(*dmi),GFP_KERNEL);
+       if(dmi==NULL)
+               return; /* GFP_KERNEL so can't happen anyway */
+       memcpy(dmi->dmi_addr, addr, alen);
+       dmi->dmi_addrlen=alen;
+       dmi->next=dev->mc_list;
+       dmi->dmi_users=1;
+       dev->mc_list=dmi;
+       dev->mc_count++;
+       dev_mc_upload(dev);
+}
+
+/*
+ *     Discard multicast list when a device is downed
+ */
+
+void dev_mc_discard(struct device *dev)
+{
+       while(dev->mc_list!=NULL)
+       {
+               struct dev_mc_list *tmp=dev->mc_list;
+               dev->mc_list=dev->mc_list->next;
+               kfree_s(tmp,sizeof(*tmp));
+       }
+       dev->mc_count=0;
+}
+
diff --git a/net/inet/igmp.c b/net/inet/igmp.c
new file mode 100644 (file)
index 0000000..0825813
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ *     Linux NET3:     Internet Gateway Management Protocol  [IGMP]
+ *
+ *     Authors:
+ *             Alan Cox <Alan.Cox@linux.org>   
+ *
+ *     WARNING:
+ *             This is a 'prelimary' implementation... on your own head
+ *     be it.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include "ip.h"
+#include "protocol.h"
+#include "route.h"
+#include <linux/skbuff.h>
+#include "sock.h"
+#include "igmp.h"
+
+#ifdef CONFIG_IP_MULTICAST
+
+
+/*
+ *     Timer management
+ */
+static void igmp_stop_timer(struct ip_mc_list *im)
+{
+       del_timer(&im->timer);
+       im->tm_running=0;
+}
+
+static int random(void)
+{
+       static unsigned long seed=152L;
+       seed=seed*69069L+1;
+       return seed^jiffies;
+}
+
+
+static void igmp_start_timer(struct ip_mc_list *im)
+{
+       int tv;
+       if(im->tm_running)
+               return;
+       tv=random()%(10*HZ);            /* Pick a number any number 8) */
+       im->timer.expires=tv;
+       add_timer(&im->timer);
+}
+/*
+ *     Send an IGMP report.
+ */
+
+#define MAX_IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+64)
+
+static void igmp_send_report(struct device *dev, unsigned long address, int type)
+{
+       struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC);
+       int tmp;
+       struct igmphdr *igh;
+       
+       if(skb==NULL)
+               return;
+       tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL,
+                               skb->mem_len, 0, 1);
+       if(tmp<0)
+       {
+               kfree_skb(skb, FREE_WRITE);
+               return;
+       }
+       igh=(struct igmphdr *)(skb->data+tmp);
+       skb->len=tmp+sizeof(*igh);
+       igh->csum=0;
+       igh->unused=0;
+       igh->type=type;
+       igh->group=address;
+       igh->csum=ip_compute_csum((void *)igh,sizeof(*igh));
+       ip_queue_xmit(NULL,dev,skb,1);
+}
+
+
+static void igmp_timer_expire(unsigned long data)
+{
+       struct ip_mc_list *im=(struct ip_mc_list *)data;
+       igmp_stop_timer(im);
+       igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+}
+
+static void igmp_init_timer(struct ip_mc_list *im)
+{
+       im->tm_running=0;
+       init_timer(&im->timer);
+       im->timer.data=(unsigned long)im;
+       im->timer.function=&igmp_timer_expire;
+}
+       
+
+static void igmp_heard_report(struct device *dev, unsigned long address)
+{
+       struct ip_mc_list *im;
+       for(im=dev->ip_mc_list;im!=NULL;im=im->next)
+               if(im->multiaddr==address)
+                       igmp_stop_timer(im);
+}
+
+static void igmp_heard_query(struct device *dev)
+{
+       struct ip_mc_list *im;
+       for(im=dev->ip_mc_list;im!=NULL;im=im->next)
+               if(!im->tm_running && im->multiaddr!=IGMP_ALL_HOSTS)
+                       igmp_start_timer(im);
+}
+
+/*
+ *     Map a multicast IP onto multicast MAC for type ethernet.
+ */
+static void ip_mc_map(unsigned long addr, char *buf)
+{
+       addr=ntohl(addr);
+       buf[0]=0x01;
+       buf[1]=0x00;
+       buf[2]=0x5e;
+       buf[5]=addr&0xFF;
+       addr>>=8;
+       buf[4]=addr&0xFF;
+       addr>>=8;
+       buf[3]=addr&0x7F;
+}
+
+/*
+ *     Add a filter to a device
+ */
+void ip_mc_filter_add(struct device *dev, unsigned long addr)
+{
+       char buf[6];
+       if(dev->type!=ARPHRD_ETHER)
+               return; /* Only do ethernet now */
+       ip_mc_map(addr,buf);    
+       dev_mc_add(dev,buf,ETH_ALEN,0);
+}
+
+/*
+ *     Remove a filter from a device
+ */
+void ip_mc_filter_del(struct device *dev, unsigned long addr)
+{
+       char buf[6];
+       if(dev->type!=ARPHRD_ETHER)
+               return; /* Only do ethernet now */
+       ip_mc_map(addr,buf);    
+       dev_mc_delete(dev,buf,ETH_ALEN,0);
+}
+
+static void igmp_group_dropped(struct ip_mc_list *im)
+{
+       del_timer(&im->timer);
+       igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
+       ip_mc_filter_del(im->interface, im->multiaddr);
+}
+
+static void igmp_group_added(struct ip_mc_list *im)
+{
+       igmp_init_timer(im);
+       igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
+       ip_mc_filter_add(im->interface, im->multiaddr);
+}
+
+int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+       unsigned long daddr, unsigned short len, unsigned long saddr, int redo,
+       struct inet_protocol *protocol)
+{
+       /* This basically follows the spec line by line -- see RFC1112 */
+       struct igmphdr *igh=(struct igmphdr *)skb->h.raw;
+       
+       if(skb->ip_hdr->ttl!=1 || ip_compute_csum((void *)igh,sizeof(*igh)))
+       {
+               kfree_skb(skb, FREE_READ);
+               return 0;
+       }
+       
+       if(igh->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
+               igmp_heard_query(dev);
+       if(igh->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==igh->group)
+               igmp_heard_report(dev,igh->group);
+       kfree_skb(skb, FREE_READ);
+       return 0;
+}
+
+/*
+ *     Multicast list managers
+ */
+/*
+ *     A socket has joined a multicast group on device dev.
+ */
+  
+static void ip_mc_inc_group(struct device *dev, unsigned long addr)
+{
+       struct ip_mc_list *i;
+       for(i=dev->ip_mc_list;i!=NULL;i=i->next)
+       {
+               if(i->multiaddr==addr)
+               {
+                       i->users++;
+                       return;
+               }
+       }
+       i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
+       if(!i)
+               return;
+       i->users=1;
+       i->interface=dev;
+       i->next=dev->ip_mc_list;
+       igmp_group_added(i);
+       dev->ip_mc_list=i;
+}
+
+/*
+ *     A socket has left a multicast group on device dev
+ */
+       
+static void ip_mc_dec_group(struct device *dev, unsigned long addr)
+{
+       struct ip_mc_list **i;
+       for(i=&dev->ip_mc_list;i!=NULL;i=&(*i)->next)
+       {
+               if((*i)->multiaddr==addr)
+               {
+                       if(--(*i)->users)
+                               return;
+                       else
+                       {
+                               struct ip_mc_list *tmp= *i;
+                               igmp_group_dropped(tmp);
+                               *i=(*i)->next;
+                               kfree_s(tmp,sizeof(*tmp));
+                       }
+               }
+       }
+}
+
+/*
+ *     Device going down: Clean up.
+ */
+void ip_mc_drop_device(struct device *dev)
+{
+       struct ip_mc_list *i;
+       struct ip_mc_list *j;
+       for(i=dev->ip_mc_list;i!=NULL;i=j)
+       {
+               j=i->next;
+               kfree_s(i,sizeof(*i));
+       }
+       dev->ip_mc_list=NULL;
+}
+
+/*
+ *     Join a socket to a group
+ */
+int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr)
+{
+       int unused= -1;
+       int i;
+       if(!MULTICAST(addr))
+               return -EINVAL;
+       if(!(dev->flags&IFF_MULTICAST))
+               return -EADDRNOTAVAIL;
+       if(sk->ip_mc_list==NULL)
+       {
+               if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL)
+                       return -ENOMEM;
+               memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list));
+       }
+       for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
+       {
+               if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
+                       return -EADDRINUSE;
+               if(sk->ip_mc_list->multidev[i]==NULL)
+                       unused=i;
+       }
+       
+       if(unused==-1)
+               return -ENOBUFS;
+       sk->ip_mc_list->multiaddr[unused]=addr;
+       sk->ip_mc_list->multidev[unused]=dev;
+       ip_mc_inc_group(dev,addr);
+       return 0;
+}
+
+/*
+ *     Ask a socket to leave a group.
+ */
+int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr)
+{
+       int i;
+       if(!MULTICAST(addr))
+               return -EINVAL;
+       if(!(dev->flags&IFF_MULTICAST))
+               return -EADDRNOTAVAIL;
+       if(sk->ip_mc_list==NULL)
+               return -EADDRNOTAVAIL;
+               
+       for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
+       {
+               if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
+               {
+                       sk->ip_mc_list->multidev[i]=NULL;
+                       ip_mc_dec_group(dev,addr);
+                       return 0;
+               }
+       }
+       return -EADDRNOTAVAIL;
+}
+
+/*
+ *     A socket is closing.
+ */
+void ip_mc_drop_socket(struct sock *sk)
+{
+       int i;
+       
+       if(sk->ip_mc_list==NULL)
+               return;
+               
+       for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
+       {
+               if(sk->ip_mc_list->multidev[i])
+               {
+                       ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]);
+                       sk->ip_mc_list->multidev[i]=NULL;
+               }
+       }
+       kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list));
+       sk->ip_mc_list=NULL;
+}
+
+#endif
diff --git a/net/inet/igmp.h b/net/inet/igmp.h
new file mode 100644 (file)
index 0000000..8c9aca3
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *     Linux NET3:     Internet Gateway Management Protocol  [IGMP]
+ *
+ *     Authors:
+ *             Alan Cox <Alan.Cox@linux.org>   
+ *
+ *     WARNING:
+ *             This is a 'prelimary' implementation... on your own head
+ *     be it.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _IGMP_H
+#define _IGMP_H
+
+/*
+ *     IGMP protocol structures
+ */
+
+struct igmphdr
+{
+       unsigned char type;
+       unsigned char unused;
+       unsigned short csum;
+       unsigned long group;
+};
+
+#define IGMP_HOST_MEMBERSHIP_QUERY     0x11    /* From RFC1112 */
+#define IGMP_HOST_MEMBERSHIP_REPORT    0x12    /* Ditto */
+#define IGMP_HOST_LEAVE_MESSAGE                0x17    /* An extra BSD seems to send */
+
+                               /* 224.0.0.1 */
+#define IGMP_ALL_HOSTS         htonl(0xE0000001L)
+
+/*
+ * struct for keeping the multicast list in
+ */
+
+struct ip_mc_socklist
+{
+       unsigned long multiaddr[IP_MAX_MEMBERSHIPS];    /* This is a speed trade off */
+       struct device *multidev[IP_MAX_MEMBERSHIPS];
+};
+
+struct ip_mc_list 
+{
+       struct device *interface;
+       unsigned long multiaddr;
+       struct ip_mc_list *next;
+       struct timer_list timer;
+       int tm_running;
+       int users;
+};
+extern struct ip_mc_list *ip_mc_head;
+
+
+#ifdef __KERNEL__
+extern int igmp_rcv(struct sk_buff *, struct device *, struct options *, unsigned long, unsigned short,
+       unsigned long, int , struct inet_protocol *);
+extern void ip_mc_drop_device(struct device *dev); 
+extern int ip_mc_join_group(struct sock *sk, struct device *dev, unsigned long addr);
+extern int ip_mc_leave_group(struct sock *sk, struct device *dev,unsigned long addr);
+extern void ip_mc_drop_socket(struct sock *sk);
+#endif
+#endif
index fe48ca8..dea0dac 100644 (file)
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Donald Becker, <becker@super.org>
  *             Alan Cox, <gw4pts@gw4pts.ampr.org>
+ *             Richard Underwood
  *
  * Fixes:
  *             Alan Cox        :       Commented a couple of minor bits of surplus code
  *             Alan Cox        :       IP options adjust sk->priority.
  *             Pedro Roque     :       Fix mtu/length error in ip_forward.
  *             Alan Cox        :       Avoid ip_chk_addr when possible.
+ *     Richard Underwood       :       IP multicasting.
+ *             Alan Cox        :       Cleaned up multicast handlers.
+ *             Alan Cox        :       RAW sockets demultiplex in the BSD style.
  *
  * To Fix:
  *             IP option processing is mostly not needed. ip_forward needs to know about routing rules
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  */
+
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <linux/types.h>
 #include "sock.h"
 #include "arp.h"
 #include "icmp.h"
+#include "raw.h"
+#include "igmp.h"
+#include <linux/ip_fw.h>
 
 #define CONFIG_IP_DEFRAG
 
@@ -99,7+107,17 @@ extern void sort_send(struct sock *sk);
  *     SNMP management statistics
  */
 
+#ifdef CONFIG_IP_FORWARDING
 struct ip_mib ip_statistics={1,64,};   /* Forwarding=Yes, Default TTL=64 */
+#else
+struct ip_mib ip_statistics={1,64,};   /* Forwarding=No, Default TTL=64 */
+#endif
+
+#ifdef CONFIG_IP_MULTICAST
+
+struct ip_mc_list *ip_mc_head=NULL;
+
+#endif
 
 /*
  *     Handle the issuing of an ioctl() request
@@ -1259,6+1277,16 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
        unsigned char *ptr;     /* Data pointer */
        unsigned long raddr;    /* Router IP address */
 
+       /* 
+        *      See if we are allowed to forward this.
+        */
+
+#ifdef CONFIG_IP_FIREWALL
+       if(!ip_fw_chk(skb->h.iph, ip_fw_fwd_chain))
+       {
+               return;
+       }
+#endif
        /*
         *      According to the RFC, we must first decrease the TTL field. If
         *      that reaches zero, we must reply an ICMP control message telling
@@ -1403,6+1431,14 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
                }
                else
                {
+#ifdef CONFIG_IP_ACCT          
+                       /*
+                        *      Count mapping we shortcut
+                        */
+                        
+                       ip_acct_cnt(iph,ip_acct_chain,1);
+#endif                 
+                       
                        /*
                         *      Map service types to priority. We lie about
                         *      throughput being low priority, but its a good
@@ -1428,6+1464,7 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
 int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 {
        struct iphdr *iph = skb->h.iph;
+       struct sock *raw_sk=NULL;
        unsigned char hash;
        unsigned char flag = 0;
        unsigned char opts_p = 0;       /* Set iff the packet has options. */
@@ -1437,7+1474,6 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        int brd=IS_MYADDR;
        int is_frag=0;
 
-
        ip_statistics.IpInReceives++;
 
        /*
@@ -1461,7+1497,21 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                kfree_skb(skb, FREE_WRITE);
                return(0);
        }
+       
+       /*
+        *      See if the firewall wants to dispose of the packet. 
+        */
+
+#ifdef CONFIG_IP_FIREWALL
+       
+       if(!LOOPBACK(iph->daddr) && !ip_fw_chk(iph,ip_fw_blk_chain))
+       {
+               kfree_skb(skb, FREE_WRITE);
+               return 0;       
+       }
 
+#endif
+       
        /*
         *      Our transport medium may have padded the buffer out. Now we know it
         *      is IP we can trim to the true length of the frame.
@@ -1543,6+1593,14 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        }
 
        /*
+        *      Account for the packet
+        */
+        
+#ifdef CONFIG_IP_ACCT
+       ip_acct_cnt(iph,ip_acct_chain,1);
+#endif 
+
+       /*
         * Reassemble IP fragments.
         */
 
@@ -1554,6+1612,8 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                        return 0;
                iph=skb->h.iph;
        }
+       
+                
 
        /*
         *      Point into the IP datagram, just past the header.
@@ -1561,7+1621,39 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 
        skb->ip_hdr = iph;
        skb->h.raw += iph->ihl*4;
-
+       
+       /*
+        *      Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies.
+        */
+        
+       hash = iph->protocol & (SOCK_ARRAY_SIZE-1);
+       
+       /* If there maybe a raw socket we must check - if not we don't care less */
+       if((raw_sk=raw_prot.sock_array[hash])!=NULL)
+       {
+               struct sock *sknext=NULL;
+               struct sk_buff *skb1;
+               raw_sk=get_sock_raw(raw_sk, hash,  iph->saddr, iph->daddr);
+               if(raw_sk)      /* Any raw sockets */
+               {
+                       do
+                       {
+                               /* Find the next */
+                               sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr);
+                               if(sknext)
+                                       skb1=skb_clone(skb, GFP_ATOMIC);
+                               else
+                                       break;  /* One pending raw socket left */
+                               if(skb1)
+                                       raw_rcv(raw_sk, skb1, dev, iph->saddr,iph->daddr);
+                               raw_sk=sknext;
+                       }
+                       while(raw_sk!=NULL);
+                       /* Here either raw_sk is the last raw socket, or NULL if none */
+                       /* We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy */
+               }
+       }
+       
        /*
         *      skb->h.raw now points at the protocol beyond the IP header.
         */
@@ -1576,14+1668,10 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
        /*
        *       See if we need to make a copy of it.  This will
        *       only be set if more than one protocol wants it.
-       *       and then not for the last one.
-       *
-       *       This is an artifact of poor upper protocol design.
-       *       Because the upper protocols damage the actual packet
-       *       we must do copying. In actual fact it's even worse
-       *       than this as TCP may hold on to the buffer.
+       *       and then not for the last one. If there is a pending
+       *       raw delivery wait for that
        */
-               if (ipprot->copy)
+               if (ipprot->copy || raw_sk)
                {
                        skb2 = skb_clone(skb, GFP_ATOMIC);
                        if(skb2==NULL)
@@ -1613,7+1701,9 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
         * ICMP reply messages get queued up for transmission...)
         */
 
-       if (!flag)
+       if(raw_sk!=NULL)        /* Shift to last raw user */
+               raw_rcv(raw_sk, skb, dev, iph->saddr, iph->daddr);
+       else if (!flag)         /* Free and report errors */
        {
                if (brd != IS_BROADCAST && brd!=IS_MULTICAST)
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
@@ -1768,6+1858,9 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
         *      If the indicated interface is up and running, send the packet.
         */
        ip_statistics.IpOutRequests++;
+#ifdef CONFIG_IP_ACCT
+       ip_acct_cnt(iph,ip_acct_chain,1);
+#endif 
 
        if (dev->flags & IFF_UP)
        {
@@ -1916,6+2009,50 @@ void ip_retransmit(struct sock *sk, int all)
        reset_timer(sk, TIME_WRITE, sk->rto);
 }
 
+#ifdef CONFIG_IP_MULTICAST
+
+/*
+ *     Write an multicast group list table for the IGMP daemon to
+ *     read.
+ */
+int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+       off_t pos=0, begin=0;
+       struct ip_mc_list *im;
+       unsigned long flags;
+       int len=0;
+       
+       
+       len=sprintf(buffer,"Device    : Multicast\n");  
+       save_flags(flags);
+       cli();
+       
+       im=ip_mc_head;
+       
+       while(im!=NULL)
+       {
+               len+=sprintf(buffer+len,"%-10s: %08lX\n", im->interface->name, im->multiaddr);
+               pos=begin+len;
+               if(pos<offset)
+               {
+                       len=0;
+                       begin=pos;
+               }
+               if(pos>offset+length)
+                       break;
+               im=im->next;
+       }
+       restore_flags(flags);
+       *start=buffer+(offset-begin);
+       len-=(offset-begin);
+       if(len>length)
+               len=length;     
+       return len;
+}
+
+
+#endif 
 /*
  *     Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
  *     an IP socket.
@@ -1928,7+2065,9 @@ void ip_retransmit(struct sock *sk, int all)
 int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
 {
        int val,err;
-
+#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
+       struct ip_fw tmp_fw;
+#endif 
        if (optval == NULL)
                return(-EINVAL);
 
@@ -1957,6+2096,227 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                                return -EINVAL;
                        sk->ip_ttl=val;
                        return 0;
+#ifdef CONFIG_IP_MULTICAST
+               case IP_MULTICAST_TTL: 
+               {
+                       unsigned char ucval;
+
+                       ucval=get_fs_byte((unsigned char *)optval);
+                       printk("MC TTL %d\n", ucval);
+                       if(ucval<1||ucval>255)
+                                return -EINVAL;
+                       sk->ip_mc_ttl=(int)ucval;
+                       return 0;
+               }
+
+               case IP_MULTICAST_IF: 
+               {
+                       /* Not fully tested */
+                       struct in_addr addr;
+                       struct device *dev=NULL;
+                       
+                       /*
+                        *      Check the arguments are allowable
+                        */
+
+                       err=verify_area(VERIFY_READ, optval, sizeof(addr));
+                       if(err)
+                               return err;
+                               
+                       memcpy_fromfs(&addr,optval,sizeof(addr));
+                       
+                       printk("MC bind %s\n", in_ntoa(addr.s_addr));
+                       
+                       /*
+                        *      What address has been requested
+                        */
+                       
+                       if(addr.s_addr==INADDR_ANY)     /* Default */
+                       {
+                               sk->ip_mc_name[0]=0;
+                               return 0;
+                       }
+                       
+                       /*
+                        *      Find the device
+                        */
+                        
+                       for(dev = dev_base; dev; dev = dev->next)
+                       {
+                               if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
+                                       (dev->pa_addr==addr.s_addr))
+                                       break;
+                       }
+                       
+                       /*
+                        *      Did we find one
+                        */
+                        
+                       if(dev) 
+                       {
+                               strcpy(sk->ip_mc_name,dev->name);
+                               return 0;
+                       }
+                       return -EADDRNOTAVAIL;
+               }
+               
+               case IP_ADD_MEMBERSHIP: 
+               {
+               
+/*
+ *     FIXME: Add/Del membership should have a semaphore protecting them from re-entry
+ */
+                       struct ip_mreq mreq;
+                       static struct options optmem;
+                       unsigned long route_src;
+                       struct rtable *rt;
+                       struct ip_mc_list *l=NULL;
+                       struct device *dev=NULL;
+                       int ct=0;
+                       
+                       /*
+                        *      Check the arguments.
+                        */
+
+                       err=verify_area(VERIFY_READ, optval, sizeof(mreq));
+                       if(err)
+                               return err;
+
+                       memcpy_fromfs(&mreq,optval,sizeof(mreq));
+
+                       /* 
+                        *      Get device for use later
+                        */
+
+                       if(mreq.imr_interface.s_addr==INADDR_ANY) 
+                       {
+                               /*
+                                *      Not set so scan.
+                                */
+                               if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL)
+                               {
+                                       dev=rt->rt_dev;
+                                       rt->rt_use--;
+                               }
+                       }
+                       else
+                       {
+                               /*
+                                *      Find a suitable device.
+                                */
+                               for(dev = dev_base; dev; dev = dev->next)
+                               {
+                                       if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
+                                               (dev->pa_addr==mreq.imr_interface.s_addr))
+                                               break;
+                               }
+                       }
+                       
+                       /*
+                        *      No device, no cookies.
+                        */
+                        
+                       if(!dev)
+                               return -ENODEV;
+                               
+                       /*
+                        *      Join group.
+                        */
+                        
+                       return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr);
+               }
+               
+               case IP_DROP_MEMBERSHIP: 
+               {
+                       struct ip_mreq mreq;
+                       struct rtable *rt;
+                       static struct options optmem;
+                        unsigned long route_src;
+                       struct device *dev=NULL;
+
+                       /*
+                        *      Check the arguments
+                        */
+                        
+                       err=verify_area(VERIFY_READ, optval, sizeof(mreq));
+                       if(err)
+                               return err;
+
+                       memcpy_fromfs(&mreq,optval,sizeof(mreq));
+
+                       /*
+                        *      Get device for use later 
+                        */
+                       if(mreq.imr_interface.s_addr==INADDR_ANY) 
+                       {
+                               if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL)
+                               {
+                                       dev=rt->rt_dev;
+                                       rt->rt_use--;
+                               }
+                       }
+                       else 
+                       {
+                               for(dev = dev_base; dev; dev = dev->next)
+                               {
+                                       if((dev->flags&IFF_UP)&& (dev->flags&IFF_MULTICAST)&&
+                                                       (dev->pa_addr==mreq.imr_interface.s_addr))
+                                               break;
+                               }
+                       }
+                       
+                       /*
+                        *      Did we find a suitable device.
+                        */
+                        
+                       if(!dev)
+                               return -ENODEV;
+                               
+                       /*
+                        *      Leave group
+                        */
+                        
+                       return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr);
+               }
+#endif                 
+#ifdef CONFIG_IP_FIREWALL
+               case IP_FW_ADD_BLK:
+               case IP_FW_DEL_BLK:
+               case IP_FW_ADD_FWD:
+               case IP_FW_DEL_FWD:
+               case IP_FW_CHK_BLK:
+               case IP_FW_CHK_FWD:
+               case IP_FW_FLUSH:
+               case IP_FW_POLICY:
+                       if(!suser())
+                               return -EPERM;
+                       if(optlen>sizeof(tmp_fw) || optlen<1)
+                               return -EINVAL;
+                       err=verify_area(VERIFY_READ,optval,optlen);
+                       if(err)
+                               return err;
+                       memcpy_fromfs(&tmp_fw,optval,optlen);
+                       err=ip_fw_ctl(optname, &tmp_fw,optlen);
+                       return -err;    /* -0 is 0 after all */
+                       
+#endif
+#ifdef CONFIG_IP_ACCT
+               case IP_ACCT_DEL:
+               case IP_ACCT_ADD:
+               case IP_ACCT_FLUSH:
+               case IP_ACCT_ZERO:
+                       if(!suser())
+                               return -EPERM;
+                       if(optlen>sizeof(tmp_fw) || optlen<1)
+                               return -EINVAL;
+                       err=verify_area(VERIFY_READ,optval,optlen);
+                       if(err)
+                               return err;
+                       memcpy_fromfs(&tmp_fw, optval,optlen);
+                       err=ip_acct_ctl(optname, &tmp_fw,optlen);
+                       return -err;    /* -0 is 0 after all */
+#endif
                /* IP_OPTIONS and friends go here eventually */
                default:
                        return(-ENOPROTOOPT);
@@ -1971,7+2331,10 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
 {
        int val,err;
-
+#ifdef CONFIG_IP_MULTICAST
+       int len;
+#endif
+       
        if(level!=SOL_IP)
                return -EOPNOTSUPP;
 
@@ -1983,6+2346,22 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
                case IP_TTL:
                        val=sk->ip_ttl;
                        break;
+#ifdef CONFIG_IP_MULTICAST                     
+               case IP_MULTICAST_TTL:
+                       val=sk->ip_mc_ttl;
+                       break;
+               case IP_MULTICAST_IF:
+                       err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+                       if(err)
+                               return err;
+                       len=strlen(sk->ip_mc_name);
+                       err=verify_area(VERIFY_WRITE, optval, len);
+                       if(err)
+                               return err;
+                       put_fs_long(len,(unsigned long *) optlen);
+                       memcpy_tofs((void *)optval,sk->ip_mc_name, len);
+                       return 0;
+#endif
                default:
                        return(-ENOPROTOOPT);
        }
index dd2cbc5..7a4da2b 100644 (file)
 
 #define IP_FRAG_TIME   (30 * HZ)               /* fragment lifetime    */
 
+#ifdef CONFIG_IP_MULTICAST
+extern void            ip_mc_dropsocket(struct sock *);
+extern void            ip_mc_dropdevice(struct device *dev);
+extern int             ip_mc_procinfo(char *, char **, off_t, int);
+#define MULTICAST(x)   (IN_MULTICAST(htonl(x)))
+#endif
 
 /* Describe an IP fragment. */
 struct ipfrag {
diff --git a/net/inet/ip_fw.c b/net/inet/ip_fw.c
new file mode 100644 (file)
index 0000000..adad2e6
--- /dev/null
@@ -0,0 +1,907 @@
+/*
+ *     IP firewalling code. This is taken from 4.4BSD. Please note the 
+ *     copyright message below. As per the GPL it must be maintained
+ *     and the licenses thus do not conflict. While this port is subject
+ *     to the GPL I also place my modifications under the original 
+ *     license in recognition of the original copyright. 
+ *
+ *     Ported from BSD to Linux,
+ *             Alan Cox 22/Nov/1994.
+ *
+ *     All the real work was done by .....
+ */
+
+/*
+ * Copyright (c) 1993 Daniel Boulet
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include "ip.h"
+#include "protocol.h"
+#include "route.h"
+#include "tcp.h"
+#include <linux/skbuff.h>
+#include "sock.h"
+#include "icmp.h"
+#include <linux/ip_fw.h>
+
+/*
+ *     Implement IP packet firewall
+ */
+
+#ifdef CONFIG_IP_FIREWALL
+struct ip_fw *ip_fw_fwd_chain;
+struct ip_fw *ip_fw_blk_chain;
+static int ip_fw_policy=1;
+#endif
+#ifdef CONFIG_IP_ACCT
+struct ip_fw *ip_acct_chain;
+#endif
+
+
+extern inline void print_ip(unsigned long xaddr)
+{
+       unsigned long addr = ntohl(xaddr);
+       printk("%ld.%ld.%ld.%ld",(addr>>24) & 0xff,
+                         (addr>>16)&0xff,
+                         (addr>>8)&0xff,
+                         addr&0xFF);
+}                  
+
+
+/*
+ *     Returns 1 if the port is matched by the vector, 0 otherwise
+ */
+
+extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag)
+{
+       if (!nports)
+               return 1;
+       if ( range_flag ) 
+       {
+               if ( portptr[0] <= port && port <= portptr[1] ) 
+               {
+                       return( 1 );
+               }
+               nports -= 2;
+               portptr += 2;
+       }
+       while ( nports-- > 0 ) 
+       {
+               if ( *portptr++ == port ) 
+               {
+                       return( 1 );
+               }
+       }
+       return(0);
+}
+
+
+/*
+ *     Returns 0 if packet should be dropped, 1 or more if it should be accepted
+ */
+
+#ifdef CONFIG_IP_FIREWALL
+
+int ip_fw_chk(struct iphdr *ip, struct ip_fw *chain)
+{
+       unsigned long src, dst;
+       char got_proto=0;
+       int frwl_proto, proto=0;
+       struct ip_fw *f;
+       unsigned short src_port=0, dst_port=0;
+       unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]);
+
+       if (!chain) 
+               return(1);     /* If no chain , always say Ok to packet */
+
+       src = ip->saddr;
+       dst = ip->daddr;
+
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+       {
+               printk("packet ");
+               switch(ip->protocol) 
+               {
+                       case IPPROTO_TCP:
+                               printf("TCP ");
+                               break;
+                       case IPPROTO_UDP:
+                               printf("UDP ");
+                               break;
+                       case IPPROTO_ICMP:
+                               printf("ICMP:%d ",((char *)portptr)[0]&0xff);
+                               break;
+                       default:
+                               printf("p=%d ",ip->protocol);
+                               break;
+               }
+               print_ip(ip->saddr);
+               if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
+               {
+                       printf(":%d ",ntohs(portptr[0]));
+               }
+               print_ip(ip->daddr);
+               if ( ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
+               {
+                       printf(":%d ",ntohs(portptr[1]));
+               }
+               printf("\n");
+       }
+#endif
+
+       for (f=chain;f;f=f->next) 
+       {
+               if ((src&f->src_mask.s_addr)==f->src.s_addr
+                       &&  (dst&f->dst_mask.s_addr)==f->dst.s_addr) 
+               {
+                       frwl_proto=f->flags&IP_FW_F_KIND;
+                       if (frwl_proto==IP_FW_F_ALL) 
+                       {
+                               /* Universal frwl - we've got a match! */
+
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                               printf("universal frwl match\n");
+#endif
+#ifdef CONFIG_IP_FIREWALL_VERBOSE
+                               if (!(f->flags & IP_FW_F_ACCEPT))
+                                       goto bad_packet;
+                               return 1;
+#else
+                               return( f->flags & IP_FW_F_ACCEPT );
+#endif
+                       }
+                       else
+                       {
+                               /*
+                                *      Specific firewall - packet's protocol must match firewall's
+                                */
+                               if (!got_proto) 
+                               {
+                                       /*
+                                        * We still had not determined the protocol
+                                        * of this packet,now the time to do so.
+                                        */
+                                       switch(ip->protocol) 
+                                       {
+                                               case IPPROTO_TCP:
+                                                       /*
+                                                        *      First two shorts in TCP are src/dst ports
+                                                        */
+                                                       proto=IP_FW_F_TCP;
+                                                       src_port=ntohs(portptr[0]);
+                                                       dst_port=ntohs(portptr[1]);
+                                                       break;
+                                               case IPPROTO_UDP:
+                                                       /*
+                                                        *      First two shorts in UDP are src/dst ports
+                                                        */
+                                                       proto = IP_FW_F_UDP;
+                                                       src_port = ntohs(portptr[0]);
+                                                       dst_port = ntohs(portptr[1]);
+                                                       break;
+                                               case IPPROTO_ICMP:
+                                                       proto=IP_FW_F_ICMP;
+                                                       break;
+                                               default:
+                                                       proto=IP_FW_F_ALL;
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                                                       printf("non TCP/UDP packet\n");
+#endif
+                                       }
+                                       got_proto=1;
+                               } 
+                               /*
+                                * At this moment we surely know the protocol of this
+                                * packet and we'll check if it matches,then proceed futher..
+                                */
+                               if (proto==frwl_proto) 
+                               {
+       
+                                       if (proto==IP_FW_F_ICMP || (port_match(&f->ports[0],f->n_src_p,src_port,
+                                               f->flags&IP_FW_F_SRNG) &&
+                                               port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port,
+                                               f->flags&IP_FW_F_DRNG))) 
+                                       {
+#ifdef CONFIG_IP_FIREWALL_VERBOSE
+                                               if (!(f->flags & IP_FW_F_ACCEPT))
+                                                       goto bad_packet;
+                                               return 1;
+#else
+                                               return( f->flags & IP_FW_F_ACCEPT);
+#endif
+                                       } /* Ports match */
+                               } /* Proto matches */
+                       }  /* ALL/Specific */
+               } /* IP addr/mask matches */
+       } /* Loop */
+       
+       /*
+        * If we get here then none of the firewalls matched.
+        * So now we relay on policy defined by user-unmatched packet can
+        * be ever accepted or rejected...
+        */
+
+#ifdef CONFIG_IP_FIREWALL_VERBOSE
+       if (!(ip_fw_policy))
+               goto bad_packet;
+       return 1;
+#else
+       return(ip_fw_policy);
+#endif
+
+#ifdef CONFIG_IP_FIREWALL_VERBOSE
+bad_packet:
+       /*
+        * VERY ugly piece of code which actually
+        * makes kernel printf for denied packets...
+        */
+       if (f->flags&IP_FW_F_PRN) 
+       {
+               printf("ip_fw_chk says no to ");
+               switch(ip->protocol) 
+               {
+                       case IPPROTO_TCP:
+                               printf("TCP ");
+                               break;
+                       case IPPROTO_UDP:
+                               printf("UDP ");
+                               break;
+                       case IPPROTO_ICMP:
+                               printf("ICMP:%d ",((char *)portptr)[0]&0xff);
+                               break;
+                       default:
+                               printf("p=%d ",ip->protocol);
+                               break;
+               }
+               print_ip(ip->saddr);
+               if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) 
+               {
+                       printf(":%d ",ntohs(portptr[0]));
+               }
+               else
+               {
+                       printf("\n");
+               }
+               print_ip(ip->daddr);
+               if ( ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ) 
+               {
+                       printf(":%d ",ntohs(portptr[1]));
+               }
+               printf("\n");
+       }
+       return(0);
+#endif
+}
+#endif /* CONFIG_IP_FIREWALL */
+
+
+
+
+#ifdef CONFIG_IP_ACCT
+void ip_acct_cnt(struct iphdr *ip,struct ip_fw *chain,int nh_conv)
+{
+       unsigned long src, dst;
+       char got_proto=0,rev=0;
+       int frwl_proto, proto=0;
+       struct ip_fw *f;
+       unsigned short src_port=0, dst_port=0;
+       unsigned short *portptr=(unsigned short *)&(((u_int *)ip)[ip->ihl]);
+
+       if (!chain) 
+               return;     
+
+       src = ip->saddr;
+       dst = ip->daddr;
+
+       for (f=chain;f;f=f->next) 
+       {
+               if ((src&f->src_mask.s_addr)==f->src.s_addr
+                       &&  (dst&f->dst_mask.s_addr)==f->dst.s_addr) 
+               {
+                       rev=0;
+                       goto addr_match;
+               }
+               if  ((f->flags&IP_FW_F_BIDIR) &&
+                   ((src&f->src_mask.s_addr)==f->dst.s_addr
+               &&  (dst&f->dst_mask.s_addr)==f->src.s_addr)) 
+               { 
+                       rev=1;
+                       goto addr_match;
+               }
+               continue;
+addr_match:
+               frwl_proto=f->flags&IP_FW_F_KIND;
+               if (frwl_proto==IP_FW_F_ALL) 
+               {
+                       /*      Universal frwl - we've got a match! */
+                       f->p_cnt++;     /*      Rise packet count */
+
+                       /*
+                        *      Rise byte count, if need to convert from host to network byte order,do it.
+                        */
+                        
+                       if (nh_conv)                
+                               f->b_cnt+=ntohs(ip->tot_len);
+                       else
+                               f->b_cnt+=ip->tot_len;
+               }
+               else
+               {
+                       /*
+                        *      Specific firewall - packet's protocol must match firewall's
+                        */
+                        
+                       if (!got_proto) 
+                       {
+                               /*
+                                *      We still had not determined the protocol
+                                *      of this packet,now the time to do so.
+                                */
+                               switch(ip->protocol) 
+                               {
+                                       case IPPROTO_TCP:
+                                               /*
+                                                *      First two shorts in TCP are src/dst ports
+                                                */
+                                               proto=IP_FW_F_TCP;
+                                               src_port=ntohs(portptr[0]);
+                                               dst_port=ntohs(portptr[1]);
+                                               break;
+                                       case IPPROTO_UDP:
+                                               /*
+                                                * First two shorts in UDP are src/dst ports
+                                                */
+                                               proto = IP_FW_F_UDP;
+                                               src_port = ntohs(portptr[0]);
+                                               dst_port = ntohs(portptr[1]);
+                                               break;
+                                       case IPPROTO_ICMP:
+                                               proto=IP_FW_F_ICMP;
+                                               break;
+                                       default:
+                                               proto=IP_FW_F_ALL;
+                               }
+                               got_proto=1;
+                       } 
+                       /*
+                        * At this moment we surely know the protocol of this
+                        * packet and we'll check if it matches,then proceed futher..
+                        */
+                       if (proto==frwl_proto) 
+                       {
+
+                               if ((proto==IP_FW_F_ICMP ||
+                                       (port_match(&f->ports[0],f->n_src_p,src_port,
+                                       f->flags&IP_FW_F_SRNG) &&
+                                       port_match(&f->ports[f->n_src_p],f->n_dst_p,dst_port,
+                                       f->flags&IP_FW_F_DRNG)))
+                                       || ((rev)   
+                                               && (port_match(&f->ports[0],f->n_src_p,dst_port,
+                                               f->flags&IP_FW_F_SRNG)
+                                               && port_match(&f->ports[f->n_src_p],f->n_dst_p,src_port,
+                                               f->flags&IP_FW_F_DRNG))))
+                               {
+                                       f->p_cnt++;                   /* Rise packet count */
+                                       /*
+                                        * Rise byte count, if need to convert from host to network byte order,do it.
+                                        */
+                                       if (nh_conv)                
+                                               f->b_cnt+=ntohs(ip->tot_len);
+                                       else
+                                               f->b_cnt+=ip->tot_len;
+                               } /* Ports match */
+                       } /* Proto matches */
+               }  /* ALL/Specific */
+       } /* IP addr/mask matches */
+} /* End of whole function */
+#endif /* CONFIG_IP_ACCT */
+
+#ifdef CONFIG_IP_ACCT
+
+static void zero_fw_chain(struct ip_fw *chainptr)
+{
+       struct ip_fw *ctmp=chainptr;
+       while(ctmp) 
+       {
+               ctmp->p_cnt=0l;
+               ctmp->b_cnt=0l;
+               ctmp=ctmp->next;
+       }
+}
+
+#endif
+
+#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
+
+static void free_fw_chain(struct ip_fw **chainptr)
+{
+       unsigned long flags;
+       save_flags(flags);
+       cli();
+       while ( *chainptr != NULL ) 
+       {
+               struct ip_fw *ftmp;
+               ftmp = *chainptr;
+               *chainptr = ftmp->next;
+               kfree_s(ftmp,sizeof(*ftmp));
+       }
+       restore_flags(flags);
+}
+
+#endif  /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
+
+#ifdef CONFIG_IP_FIREWALL
+
+static int add_to_chain(struct ip_fw **chainptr, struct ip_fw *frwl)
+{
+       struct ip_fw *ftmp;
+       struct ip_fw *chtmp=NULL;
+       struct ip_fw *chtmp_prev=NULL;
+       unsigned long flags;
+       unsigned long m_src_mask,m_dst_mask;
+       unsigned long n_sa,n_da,o_sa,o_da,o_sm,o_dm,n_sm,n_dm;
+       unsigned short n_sr,n_dr,o_sr,o_dr; 
+       unsigned short oldkind,newkind;
+       int addb4=0;
+       int n_o,n_n;
+       
+       save_flags(flags);
+       
+       ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC );
+       if ( ftmp == NULL ) 
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl:  malloc said no\n");
+#endif
+               return( ENOSPC );
+       }
+
+       memcpy(ftmp, frwl, sizeof( struct ip_fw ) );
+       ftmp->p_cnt=0L;
+       ftmp->b_cnt=0L;
+
+       ftmp->next = NULL;
+
+       cli();
+       
+       if (*chainptr==NULL)
+       {
+               *chainptr=ftmp;
+       }
+       else
+       {
+               chtmp_prev=NULL;
+               for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->next) 
+               {
+                       addb4=0;
+                       newkind=ftmp->flags & IP_FW_F_KIND;
+                       oldkind=chtmp->flags & IP_FW_F_KIND;
+       
+                       if (newkind!=IP_FW_F_ALL 
+                               &&  oldkind!=IP_FW_F_ALL
+                               &&  oldkind!=newkind) 
+                       {
+                               chtmp_prev=chtmp;
+                               continue;
+                       }
+
+                       /*
+                        *      Very very *UGLY* code...
+                        *      Sorry,but i had to do this....
+                        */
+
+                       n_sa=ntohl(ftmp->src.s_addr);
+                       n_da=ntohl(ftmp->dst.s_addr);
+                       n_sm=ntohl(ftmp->src_mask.s_addr);
+                       n_dm=ntohl(ftmp->dst_mask.s_addr);
+
+                       o_sa=ntohl(chtmp->src.s_addr);
+                       o_da=ntohl(chtmp->dst.s_addr);
+                       o_sm=ntohl(chtmp->src_mask.s_addr);
+                       o_dm=ntohl(chtmp->dst_mask.s_addr);
+
+                       m_src_mask = o_sm & n_sm;
+                       m_dst_mask = o_dm & n_dm;
+
+                       if ((o_sa & m_src_mask) == (n_sa & m_src_mask)) 
+                       {
+                               if (n_sm > o_sm) 
+                                       addb4++;
+                               if (n_sm < o_sm) 
+                                       addb4--;
+                       }
+               
+                       if ((o_da & m_dst_mask) == (n_da & m_dst_mask)) 
+                       {
+                               if (n_dm > o_dm)
+                                       addb4++;
+                               if (n_dm < o_dm)
+                                       addb4--;
+                       }
+
+                       if (((o_da & o_dm) == (n_da & n_dm))
+                                       &&((o_sa & o_sm) == (n_sa & n_sm)))
+                       {
+                               if (newkind!=IP_FW_F_ALL &&
+                                       oldkind==IP_FW_F_ALL)
+                                       addb4++;
+                               if (newkind==oldkind && (oldkind==IP_FW_F_TCP
+                                       ||  oldkind==IP_FW_F_UDP)) 
+                               {
+       
+                                       /*
+                                        *      Here the main idea is to check the size
+                                        *      of port range which the frwl covers
+                                        *      We actually don't check their values but
+                                        *      just the wideness of range they have
+                                        *      so that less wide ranges or single ports
+                                        *      go first and wide ranges go later. No ports
+                                        *      at all treated as a range of maximum number
+                                        *      of ports.
+                                        */
+
+                                       if (ftmp->flags & IP_FW_F_SRNG) 
+                                               n_sr=ftmp->ports[1]-ftmp->ports[0];
+                                       else 
+                                               n_sr=(ftmp->n_src_p)?ftmp->n_src_p : 0xFFFF;
+                                               
+                                       if (chtmp->flags & IP_FW_F_SRNG) 
+                                               o_sr=chtmp->ports[1]-chtmp->ports[0];
+                                       else 
+                                               o_sr=(chtmp->n_src_p)?chtmp->n_src_p : 0xFFFF;
+
+                                       if (n_sr<o_sr)
+                                               addb4++;
+                                       if (n_sr>o_sr)
+                                               addb4--;
+                                       
+                                       n_n=ftmp->n_src_p;
+                                       n_o=chtmp->n_src_p;
+       
+                                       /*
+                                        * Actually this cannot happen as the frwl control
+                                        * procedure checks for number of ports in source and
+                                        * destination range but we will try to be more safe.
+                                        */
+                                        
+                                       if ((n_n>(IP_FW_MAX_PORTS-2)) ||
+                                               (n_o>(IP_FW_MAX_PORTS-2)))
+                                               goto skip_check;
+
+                                       if (ftmp->flags & IP_FW_F_DRNG) 
+                                              n_dr=ftmp->ports[n_n+1]-ftmp->ports[n_n];
+                                       else 
+                                              n_dr=(ftmp->n_dst_p)? ftmp->n_dst_p : 0xFFFF;
+
+                                       if (chtmp->flags & IP_FW_F_DRNG) 
+                                               o_dr=chtmp->ports[n_o+1]-chtmp->ports[n_o];
+                                       else 
+                                               o_dr=(chtmp->n_dst_p)? chtmp->n_dst_p : 0xFFFF;
+                                       if (n_dr<o_dr)
+                                               addb4++;
+                                       if (n_dr>o_dr)
+                                               addb4--;
+skip_check:
+                               }
+                       }
+                       if (addb4>0) 
+                       {
+                               if (chtmp_prev) 
+                               {
+                                       chtmp_prev->next=ftmp; 
+                                       ftmp->next=chtmp;
+                               } 
+                               else 
+                               {
+                                       *chainptr=ftmp;
+                                       ftmp->next=chtmp;
+                               }
+                               restore_flags(flags);
+                               return 0;
+                       }
+                       chtmp_prev=chtmp;
+               }
+       }
+       
+       if (chtmp_prev)
+               chtmp_prev->next=ftmp;
+       else
+       {
+               *chainptr=ftmp;
+               printk("ip_fw: add_to_chain: Can't happen");
+       }
+       restore_flags(flags);
+       return(0);
+}
+
+static int del_from_chain(struct ip_fw **chainptr, struct ip_fw *frwl)
+{
+       struct ip_fw    *ftmp,*ltmp;
+       unsigned short  tport1,tport2,tmpnum;
+       char            matches,was_found;
+       unsigned long   flags;
+
+       save_flags(flags);
+       cli();
+       
+       ftmp=*chainptr;
+
+       if ( ftmp == NULL ) 
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl:  chain is empty\n");
+#endif
+               restore_flags(flags);
+               return( EINVAL );
+       }
+
+       ltmp=NULL;
+       was_found=0;
+
+       while( ftmp != NULL )
+       {
+               matches=1;
+               if ((memcmp(&ftmp->src,&frwl->src,sizeof(struct in_addr))) 
+                       || (memcmp(&ftmp->src_mask,&frwl->src_mask,sizeof(struct in_addr)))
+                       || (memcmp(&ftmp->dst,&frwl->dst,sizeof(struct in_addr)))
+                       || (memcmp(&ftmp->dst_mask,&frwl->dst_mask,sizeof(struct in_addr)))
+                       || (ftmp->flags!=frwl->flags))
+                       matches=0;
+
+               tport1=ftmp->n_src_p+ftmp->n_dst_p;
+               tport2=frwl->n_src_p+frwl->n_dst_p;
+               if (tport1!=tport2)
+                       matches=0;
+               else if (tport1!=0)
+               {
+                       for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++)
+                       if (ftmp->ports[tmpnum]!=frwl->ports[tmpnum])
+                               matches=0;
+               }
+               if(matches)
+               {
+                       was_found=1;
+                       if (ltmp)
+                       {
+                               ltmp->next=ftmp->next;
+                               kfree_s(ftmp,sizeof(*ftmp));
+                               ftmp=ltmp->next;
+                       }
+                       else
+                       {
+                               *chainptr=ftmp->next; 
+                               kfree_s(ftmp,sizeof(*ftmp));
+                               ftmp=*chainptr;
+                       }       
+               }
+               else
+               {
+                       ltmp = ftmp;
+                       ftmp = ftmp->next;
+                }
+       }
+       restore_flags(flags);
+       if (was_found)
+               return 0;
+       else
+               return(EINVAL);
+}
+
+#endif /* CONFIG_IP_FIREWALL */
+
+struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
+{
+
+       if ( len != sizeof(struct ip_fw) )
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl: len=%d, want %d\n",m->m_len,
+                                       sizeof(struct ip_fw));
+#endif
+               return(NULL);
+       }
+
+       if ( (frwl->flags & ~IP_FW_F_MASK) != 0 )
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl: undefined flag bits set (flags=%x)\n",
+                       frwl->flags);
+#endif
+               return(NULL);
+       }
+
+       if ( (frwl->flags & IP_FW_F_SRNG) && frwl->n_src_p < 2 ) 
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl: src range set but n_src_p=%d\n",
+                       frwl->n_src_p);
+#endif
+               return(NULL);
+       }
+
+       if ( (frwl->flags & IP_FW_F_DRNG) && frwl->n_dst_p < 2 ) 
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl: dst range set but n_dst_p=%d\n",
+                       frwl->n_dst_p);
+#endif
+               return(NULL);
+       }
+
+       if ( frwl->n_src_p + frwl->n_dst_p > IP_FW_MAX_PORTS ) 
+       {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+               printf("ip_fw_ctl: too many ports (%d+%d)\n",
+                       frwl->n_src_p,frwl->n_dst_p);
+#endif
+               return(NULL);
+       }
+
+       return frwl;
+}
+
+
+
+
+#ifdef CONFIG_IP_ACCT
+int ip_acct_ctl(int stage, void *m, int len)
+{
+       if ( stage == IP_ACCT_FLUSH )
+       {
+               free_fw_chain(&ip_acct_chain);
+               return(0);
+       }  
+       if ( stage == IP_ACCT_ZERO )
+       {
+               zero_fw_chain(ip_acct_chain);
+               return(0);
+       }
+       if ( stage == IP_ACCT_ADD
+         || stage == IP_ACCT_DEL
+          )
+       {
+               struct ip_fw *frwl;
+
+               if (!(frwl=check_ipfw_struct(m,len)))
+                       return (EINVAL);
+
+               switch (stage) 
+               {
+                       case IP_ACCT_ADD:
+                               return( add_to_chain(&ip_acct_chain,frwl));
+                       case IP_ACCT_DEL:
+                               return( del_from_chain(&ip_acct_chain,frwl));
+                       default:
+                               /*
+                                *      Should be panic but... (Why ??? - AC)
+                                */
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                               printf("ip_acct_ctl:  unknown request %d\n",stage);
+#endif
+                               return(EINVAL);
+               }
+       }
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+       printf("ip_acct_ctl:  unknown request %d\n",stage);
+#endif
+       return(EINVAL);
+}
+#endif
+
+#ifdef CONFIG_IP_FIREWALL
+int ip_fw_ctl(int stage, void *m, int len)
+{
+       if ( stage == IP_FW_FLUSH )
+       {
+               free_fw_chain(&ip_fw_blk_chain);
+               free_fw_chain(&ip_fw_fwd_chain);
+               return(0);
+       }  
+
+       if ( stage == IP_FW_POLICY )
+       {
+               int *tmp_policy_ptr;
+               tmp_policy_ptr=(int *)m;
+               if ((*tmp_policy_ptr)!=1 && (*tmp_policy_ptr)!=0)
+                       return (EINVAL);
+               ip_fw_policy=*tmp_policy_ptr;
+               return 0;
+       }
+
+       if ( stage == IP_FW_CHK_BLK 
+               || stage == IP_FW_CHK_FWD )
+       {
+               struct iphdr *ip;
+
+               if ( len < sizeof(struct iphdr) + 2 * sizeof(unsigned short) )
+               {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                       printf("ip_fw_ctl: len=%d, want at least %d\n",
+                               len,sizeof(struct ip) + 2 * sizeof(unsigned short));
+#endif
+                       return( EINVAL );
+               }
+
+               ip = (struct iphdr *)m;
+
+               if ( ip->ihl != sizeof(struct iphdr) / sizeof(int))
+               {
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                       printf("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
+                                       sizeof(struct ip)/sizeof(int));
+#endif
+                       return(EINVAL);
+               }
+
+               if ( ip_fw_chk(ip,
+                       stage == IP_FW_CHK_BLK ?
+                       ip_fw_blk_chain : ip_fw_fwd_chain )
+                      ) 
+                       return(0);
+               else    
+                       return(EACCES);
+       }
+
+/*
+ *     Here we really working hard-adding new elements
+ *     to blocking/forwarding chains or deleting'em
+ */
+
+       if ( stage == IP_FW_ADD_BLK || stage == IP_FW_ADD_FWD
+               || stage == IP_FW_DEL_BLK || stage == IP_FW_DEL_FWD
+               )
+       {
+               struct ip_fw *frwl;
+               frwl=check_ipfw_struct(m,len);
+               if (frwl==NULL)
+                       return (EINVAL);
+               
+               switch (stage) 
+               {
+                       case IP_FW_ADD_BLK:
+                               return(add_to_chain(&ip_fw_blk_chain,frwl));
+                       case IP_FW_ADD_FWD:
+                               return(add_to_chain(&ip_fw_fwd_chain,frwl));
+                       case IP_FW_DEL_BLK:
+                               return(del_from_chain(&ip_fw_blk_chain,frwl));
+                       case IP_FW_DEL_FWD: 
+                               return(del_from_chain(&ip_fw_fwd_chain,frwl));
+                       default:
+                       /*
+                        *      Should be panic but... (Why are BSD people panic obsessed ??)
+                        */
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+                               printf("ip_fw_ctl:  unknown request %d\n",stage);
+#endif
+                               return(EINVAL);
+               }
+       } 
+
+#ifdef DEBUG_CONFIG_IP_FIREWALL
+       printf("ip_fw_ctl:  unknown request %d\n",stage);
+#endif
+       return(EINVAL);
+}
+#endif /* CONFIG_IP_FIREWALL */
index 57e552e..c394792 100644 (file)
 #include <linux/in.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
+#include <linux/timer.h>
 #include "ip.h"
 #include "protocol.h"
 #include "tcp.h"
 #include "sock.h"
 #include "icmp.h"
 #include "udp.h"
+#include "igmp.h"
 
 
 static struct inet_protocol tcp_protocol = {
@@ -75,8+77,23 @@ static struct inet_protocol icmp_protocol = {
   "ICMP"               /* name                 */
 };
 
-
+#ifndef CONFIG_IP_MULTICAST
 struct inet_protocol *inet_protocol_base = &icmp_protocol;
+#else
+static struct inet_protocol igmp_protocol = {
+  igmp_rcv,            /* IGMP handler         */
+  NULL,                        /* IGMP never fragments anyway */
+  NULL,                        /* IGMP error control   */
+  &icmp_protocol,      /* next                 */
+  IPPROTO_IGMP,                /* protocol ID          */
+  0,                   /* copy                 */
+  NULL,                        /* data                 */
+  "IGMP"               /* name                 */
+};
+
+struct inet_protocol *inet_protocol_base = &igmp_protocol;
+#endif
+
 struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
   NULL
 };
index b79c1da..f3aa44f 100644 (file)
  *             Alan Cox        :       Cleaned up old debugging
  *             Alan Cox        :       Use new kernel side addresses
  *     Arnt Gulbrandsen        :       Fixed MSG_DONTROUTE in raw sockets.
+ *             Alan Cox        :       BSD style RAW socket demultiplexing.
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
@@ -89,35+90,15 @@ void raw_err (int err, unsigned char *header, unsigned long daddr,
 
 /*
  *     This should be the easiest of all, all we do is
- *     copy it into a buffer.
+ *     copy it into a buffer. All demultiplexing is done
+ *     in ip.c
  */
 
-int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
-       unsigned long daddr, unsigned short len, unsigned long saddr,
-       int redo, struct inet_protocol *protocol)
+int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, long saddr, long daddr)
 {
-       struct sock *sk;
-
-       if (skb == NULL)
-               return(0);
-       
-       if (protocol == NULL) 
-       {
-               kfree_skb(skb, FREE_READ);
-               return(0);
-       }
-  
-       sk = (struct sock *) protocol->data;
-       if (sk == NULL) 
-       {
-               kfree_skb(skb, FREE_READ);
-               return(0);
-       }
-
        /* Now we need to copy this into memory. */
-
        skb->sk = sk;
-       skb->len = len + skb->ip_hdr->ihl*sizeof(long);
+       skb->len = ntohs(skb->ip_hdr->tot_len);
        skb->h.raw = (unsigned char *) skb->ip_hdr;
        skb->dev = dev;
        skb->saddr = daddr;
@@ -154,7+135,10 @@ static int raw_sendto(struct sock *sk, unsigned char *from,
        /*
         *      Check the flags. Only MSG_DONTROUTE is permitted.
         */
-        
+
+       if (flags & MSG_OOB)            /* Mirror BSD error message compatibility */
+               return -EOPNOTSUPP;
+                        
        if (flags & ~MSG_DONTROUTE)
                return(-EINVAL);
        /*
@@ -240,35+224,12 @@ static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
 
 static void raw_close(struct sock *sk, int timeout)
 {
-       sk->inuse = 1;
        sk->state = TCP_CLOSE;
-
-       inet_del_protocol((struct inet_protocol *)sk->pair);
-       kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
-       sk->pair = NULL;
-       release_sock(sk);
 }
 
 
 static int raw_init(struct sock *sk)
 {
-       struct inet_protocol *p;
-
-       p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
-       if (p == NULL)
-               return(-ENOMEM);
-
-       p->handler = raw_rcv;
-       p->protocol = sk->protocol;
-       p->data = (void *)sk;
-       p->err_handler = raw_err;
-       p->name="USER";
-       p->frag_handler = NULL; /* For now */
-       inet_add_protocol(p);
-   
-       /* We need to remember this somewhere. */
-       sk->pair = (struct sock *)p;
-
        return(0);
 }
 
@@ -287,6+248,9 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
        int err;
        int truesize;
 
+       if (flags & MSG_OOB)
+               return -EOPNOTSUPP;
+               
        if (sk->shutdown & RCV_SHUTDOWN) 
                return(0);
 
@@ -340,7+304,7 @@ struct proto raw_prot = {
        ip_retransmit,
        NULL,
        NULL,
-       raw_rcv,
+       NULL,
        datagram_select,
        NULL,
        raw_init,
index 80cb4b4..8f1cf0c 100644 (file)
@@ -23,14+23,12 @@ extern struct proto raw_prot;
 
 extern void    raw_err(int err, unsigned char *header, unsigned long daddr,
                        unsigned long saddr, struct inet_protocol *protocol);
-extern int     raw_rcv(struct sk_buff *skb, struct device *dev,
-                       struct options *opt, unsigned long daddr,
-                       unsigned short len, unsigned long saddr,
-                       int redo, struct inet_protocol *protocol);
 extern int     raw_recvfrom(struct sock *sk, unsigned char *to,
-                            int len, int noblock, unsigned flags,
-                            struct sockaddr_in *sin, int *addr_len);
+                       int len, int noblock, unsigned flags,
+                       struct sockaddr_in *sin, int *addr_len);
 extern int     raw_read(struct sock *sk, unsigned char *buff,
-                        int len, int noblock, unsigned flags);
+                       int len, int noblock, unsigned flags);
+extern int     raw_rcv(struct sock *, struct sk_buff *, struct device *, 
+                       long, long);
 
 #endif /* _RAW_H */
index d5ae2ad..f0aa485 100644 (file)
@@ -149,13+149,12 @@ int skb_check(struct sk_buff *skb, int head, int line, char *file)
 #endif
 
 
+#ifdef CONFIG_SKB_CHECK
 void skb_queue_head_init(struct sk_buff_head *list)
 {
        list->prev = (struct sk_buff *)list;
        list->next = (struct sk_buff *)list;
-#if CONFIG_SKB_CHECK
        list->magic_debug_cookie = SK_HEAD_SKB;
-#endif
 }
 
 
@@ -170,12+169,10 @@ void skb_queue_head(struct sk_buff_head *list_,struct sk_buff *newsk)
        save_flags(flags);
        cli();
 
-#if CONFIG_SKB_CHECK
        IS_SKB(newsk);
        IS_SKB_HEAD(list);
        if (newsk->next || newsk->prev)
                printk("Suspicious queue head: sk_buff on list!\n");
-#endif
 
        newsk->next = list->next;
        newsk->prev = list;
@@ -197,12+194,10 @@ void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk)
        save_flags(flags);
        cli();
 
-#if CONFIG_SKB_CHECK
        if (newsk->next || newsk->prev)
                printk("Suspicious queue tail: sk_buff on list!\n");
        IS_SKB(newsk);
        IS_SKB_HEAD(list);
-#endif
 
        newsk->next = list;
        newsk->prev = list->prev;
@@ -254,7+249,6 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
 
-#if CONFIG_SKB_CHECK
        IS_SKB(old);
        IS_SKB(newsk);
 
@@ -262,7+256,6 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
                printk("insert before unlisted item!\n");
        if(newsk->next || newsk->prev)
                printk("inserted item is already on a list.\n");
-#endif
 
        save_flags(flags);
        cli();
@@ -281,7+274,6 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
 {
        unsigned long flags;
 
-#if CONFIG_SKB_CHECK
        IS_SKB(old);
        IS_SKB(newsk);
 
@@ -289,7+281,6 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
                printk("append before unlisted item!\n");
        if(newsk->next || newsk->prev)
                printk("append item is already on a list.\n");
-#endif
 
        save_flags(flags);
        cli();
@@ -331,6+322,8 @@ void skb_unlink(struct sk_buff *skb)
        restore_flags(flags);
 }
 
+#endif
+
 /*
  *     Free an sk_buff. This still knows about things it should
  *     not need to like protocols and sockets.
@@ -344,7+337,9 @@ void kfree_skb(struct sk_buff *skb, int rw)
                        __builtin_return_address(0));
                return;
        }
+#ifdef CONFIG_SKB_CHECK
        IS_SKB(skb);
+#endif
        if (skb->lock)
        {
                skb->free = 3;    /* Free when unlocked */
@@ -456,6+451,7 @@ void kfree_skbmem(struct sk_buff *skb,unsigned size)
                skb->dev->pkt_queue--;
        restore_flags(flags);
 #endif
+#ifdef CONFIG_SKB_CHECK
        IS_SKB(skb);
        if(size!=skb->truesize)
                printk("kfree_skbmem: size mismatch.\n");
@@ -473,6+469,14 @@ void kfree_skbmem(struct sk_buff *skb,unsigned size)
        }
        else
                printk("kfree_skbmem: bad magic cookie\n");
+#else
+       save_flags(flags);
+       cli();
+       kfree_s((void *)skb,size);
+       net_skbcount--;
+       net_memory -= size;
+       restore_flags(flags);
+#endif
 }
 
 /*
index fd5f123..ea92cc3 100644 (file)
@@ -383,7+383,9 @@ unsigned long sock_wspace(struct sock *sk)
 
 void sock_wfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
 {
+#ifdef CONFIG_SKB_CHECK
        IS_SKB(skb);
+#endif
        kfree_skbmem(skb, size);
        if (sk) 
        {
@@ -398,7+400,9 @@ void sock_wfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
 
 void sock_rfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
 {
+#ifdef CONFIG_SKB_CHECK
        IS_SKB(skb);
+#endif 
        kfree_skbmem(skb, size);
        if (sk) 
        {
index 07b036f..f785eb0 100644 (file)
 #include "ipx.h"
 #endif
 
-#define SOCK_ARRAY_SIZE        64
+#include "igmp.h"
+
+#define SOCK_ARRAY_SIZE        256             /* Think big (also on some systems a byte is faster */
 
 
 /*
@@ -157,6+159,12 @@ struct sock {
   int                          ip_ttl;         /* TTL setting */
   int                          ip_tos;         /* TOS */
   struct tcphdr                        dummy_th;
+#ifdef CONFIG_IP_MULTICAST  
+  int                          ip_mc_ttl;                      /* Multicasting TTL */
+  int                          ip_mc_loop;                     /* Loopback (not implemented yet) */
+  char                         ip_mc_name[MAX_ADDR_LEN];       /* Multicast device name */
+  struct ip_mc_socklist                *ip_mc_list;                    /* Group array */
+#endif  
 
   /* This part is used for the timeout functions (timer.c). */
   int                          timeout;        /* What are we waiting for? */
@@ -256,7+264,12 @@ extern void                        release_sock(struct sock *sk);
 extern struct sock             *get_sock(struct proto *, unsigned short,
                                          unsigned long, unsigned short,
                                          unsigned long);
-extern void                    print_sk(struct sock *);
+extern struct sock             *get_sock_mcast(struct sock *, unsigned short,
+                                         unsigned long, unsigned short,
+                                         unsigned long);
+extern struct sock             *get_sock_raw(struct sock *, unsigned short,
+                                         unsigned long, unsigned long);
+
 extern struct sk_buff          *sock_wmalloc(struct sock *sk,
                                              unsigned long size, int force,
                                              int priority);
index a2bbbe8..02d20dd 100644 (file)
@@ -925,7+925,7 @@ static void tcp_send_ack(unsigned long sequence, unsigned long ack,
  *     This routine builds a generic TCP header. 
  */
  
-static int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
+extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
 {
 
        /* FIXME: want to get rid of this. */
@@ -3041,8+3041,13 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int
               (((flag&2) && sk->retransmits) ||
               (sk->send_head->when + sk->rto < jiffies))) 
        {
-               ip_do_retransmit(sk, 1);
-               reset_timer(sk, TIME_WRITE, sk->rto);
+               if(sk->send_head->when + sk->rto < jiffies)
+                       tcp_retransmit(sk,0);   
+               else
+               {
+                       ip_do_retransmit(sk, 1);
+                       reset_timer(sk, TIME_WRITE, sk->rto);
+               }
        }
 
        return(1);
@@ -3352,7+3357,6 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk,
        }
        else
        {
-               /* We missed a packet.  Send an ack to try to resync things. */
                tcp_send_ack(sk->sent_seq, sk->acked_seq, sk, th, saddr);
        }
 
@@ -3508,7+3512,7 @@ static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th,
                        reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
                        return(0);
        }
-       sk->ack_backlog++;
+/*     sk->ack_backlog++;     tcp_data has already dealt with ACK's */
 
        return(0);
 }
@@ -3866,7+3870,6 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                }
 
                skb->len = len;
-               skb->sk = sk;
                skb->acked = 0;
                skb->used = 0;
                skb->free = 0;
@@ -3905,12+3908,12 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
         
        if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) 
        {
-               skb->sk = NULL;
                kfree_skb(skb, FREE_READ);
                release_sock(sk);
                return(0);
        }
 
+       skb->sk=sk;
        sk->rmem_alloc += skb->mem_len;
 
 #ifdef TCP_FASTPATH
@@ -4042,24+4045,22 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
 
                        if (th->rst) 
                        {
-                               tcp_statistics.TcpEstabResets++;
-                               sk->zapped=1;
-                               /* This means the thing should really be closed. */
-                               sk->err = ECONNRESET;
-                               if (sk->state == TCP_CLOSE_WAIT) 
+                               if(sk->state!=TCP_TIME_WAIT)    /* RFC 1337 recommendation re RST in time wait */
                                {
-                                       sk->err = EPIPE;
-                               }
-       
-                               /*
-                                * A reset with a fin just means that
-                                * the data was not all read.
-                                */
-                               tcp_set_state(sk,TCP_CLOSE);
-                               sk->shutdown = SHUTDOWN_MASK;
-                               if (!sk->dead) 
-                               {
-                                       sk->state_change(sk);
+                                       tcp_statistics.TcpEstabResets++;
+                                       sk->zapped=1;
+                                       /* This means the thing should really be closed. */
+                                       sk->err = ECONNRESET;
+                                       if (sk->state == TCP_CLOSE_WAIT) 
+                                       {
+                                               sk->err = EPIPE;
+                                       }
+                                       tcp_set_state(sk,TCP_CLOSE);
+                                       sk->shutdown = SHUTDOWN_MASK;
+                                       if (!sk->dead) 
+                                       {
+                                               sk->state_change(sk);
+                                       }
                                }
                                kfree_skb(skb, FREE_READ);
                                release_sock(sk);
index 2dcb22c..b4650d8 100644 (file)
 #define MAX_FIN_SIZE   40 + MAX_HEADER
 #define MAX_ACK_SIZE   40 + MAX_HEADER
 #define MAX_RESET_SIZE 40 + MAX_HEADER
-#define MAX_WINDOW     8192
+#define MAX_WINDOW     16384
 #define MIN_WINDOW     2048
 #define MAX_ACK_BACKLOG        2
 #define MIN_WRITE_SPACE        2048
  * The next routines deal with comparing 32 bit unsigned ints
  * and worry about wraparound (automatic with unsigned arithmetic).
  */
-static inline int before(unsigned long seq1, unsigned long seq2)
+
+extern __inline int before(unsigned long seq1, unsigned long seq2)
 {
         return (long)(seq1-seq2) < 0;
 }
 
-static inline int after(unsigned long seq1, unsigned long seq2)
+extern __inline int after(unsigned long seq1, unsigned long seq2)
 {
        return (long)(seq1-seq2) > 0;
 }
 
 
 /* is s2<=s1<=s3 ? */
-static inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
+extern __inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
 {
        return (after(seq1+1, seq2) && before(seq1, seq3+1));
 }
@@ -101,7+102,7 @@ static inline int between(unsigned long seq1, unsigned long seq2, unsigned long
  * convinced that this is the solution for the 'getpeername(2)'
  * problem. Thanks to Stephen A. Wood <saw@cebaf.gov>  -FvK
  */
-static inline const int
+extern __inline const int
 tcp_connected(const int state)
 {
   return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
index 6e739e7..1a8316b 100644 (file)
 struct udp_mib         udp_statistics;
 
 
-
+static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len);
 
 #define min(a,b)       ((a)<(b)?(a):(b))
 
@@ -255,6+255,7 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
        unsigned char *buff;
        unsigned long saddr;
        int size, tmp;
+       int ttl;
   
        /* 
         *      Allocate an sk_buff copy of the packet.
@@ -278,8+279,14 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
        buff = skb->data;
        saddr = sk->saddr;
        dev = NULL;
+       ttl = sk->ip_ttl;
+#ifdef CONFIG_IP_MULTICAST
+       if (MULTICAST(sin->sin_addr.s_addr))
+               ttl = sk->ip_mc_ttl;
+#endif
        tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
-                       &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
+                       &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);
+
        skb->sk=sk;     /* So memory is freed correctly */
        
        /*
@@ -556,6+563,10 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        struct sock *sk;
        struct udphdr *uh;
        unsigned short ulen;
+       int addr_type=IS_MYADDR;
+       
+       if(skb->dev->pa_addr!=daddr)
+               addr_type=ip_chk_addr(daddr);
                
        /*
         *      Get the header.
@@ -577,13+588,54 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                kfree_skb(skb, FREE_WRITE);
                return(0);
        }
+
+       if (uh->check && udp_check(uh, len, saddr, daddr)) 
+       {
+               printk("UDP: bad checksum.\n");
+               udp_statistics.UdpInErrors++;
+               kfree_skb(skb, FREE_WRITE);
+               return(0);
+       }
+
+
        len=ulen;
 
+#ifdef CONFIG_IP_MULTICAST
+       if (addr_type!=IS_MYADDR)
+       {
+               /*
+                *      Multicasts and broadcasts go to each listener.
+                */
+               struct sock *sknext=NULL;
+               sk=get_sock_mcast(udp_prot.sock_array[ntohs(uh->dest)&(SOCK_ARRAY_SIZE-1)], uh->dest,
+                               saddr, uh->source, daddr);
+               if(sk)
+               {               
+                       do
+                       {
+                               struct sk_buff *skb1;
+
+                               sknext=get_sock_mcast(sk->next, uh->dest, saddr, uh->source, daddr);
+                               if(sknext)
+                                       skb1=skb_clone(skb,GFP_ATOMIC);
+                               else
+                                       skb1=skb;
+                               if(skb1)
+                                       udp_deliver(sk, uh, skb1,skb->dev,saddr,daddr,len);
+                               sk=sknext;
+                       }
+                       while(sknext!=NULL);
+               }
+               else
+                       kfree_skb(skb, FREE_READ);
+               return 0;
+       }       
+#endif
        sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
        if (sk == NULL) 
        {
                udp_statistics.UdpNoPorts++;
-               if (ip_chk_addr(daddr) == IS_MYADDR) 
+               if (addr_type == IS_MYADDR) 
                {
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
                }
@@ -596,14+648,11 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
                return(0);
        }
 
-       if (uh->check && udp_check(uh, len, saddr, daddr)) 
-       {
-               printk("UDP: bad checksum.\n");
-               udp_statistics.UdpInErrors++;
-               kfree_skb(skb, FREE_WRITE);
-               return(0);
-       }
+       return udp_deliver(sk,uh,skb,skb->dev, saddr, daddr, len);
+}
 
+static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len)
+{
        skb->sk = sk;
        skb->dev = dev;
        skb->len = len;
close