]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.69 1.1.69
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:45 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:45 +0000 (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 203a9b3dbfb945d306f3a405a0136eaafbe196e9..3aeaa1c17f44bed89871e56deda0be43476e0e54 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 68
+SUBLEVEL = 69
 
 ARCH = i386
 
index 2c4bc4ba5c8faa0909180d71a18e25cc07be253c..e88fad8a34983761d23ed06edf0cf0634937993a 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 53d55b17d9bea6c4b38c2dd1d9da4ec1e6a8617d..26a4e8935d4f2f0098eb8aaa8c48d77a81fe2e2b 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 78f1fb332afe323c01aa26a399d7ba3eaa1ad7c9..f6ff04b59ae0b00f7f26126850e6774711138b6d 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 ea65813f12ec3c14687f37a77d3465c67ef6d8b9..dd95f966313909ddab0a3eb6764ab92c2d62c70e 100644 (file)
@@ -13,6 +13,7 @@
 #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 bd983057c3bef31b09aab088b32dd66526fbe65c..46d56c9c09a825a17171e659aeca39e577ac0596 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 66782f42f59d5ae4a3ca436193022d4dc9b5cb6e..2d9007bb8628631fb8be22874dacaab7e2d3581c 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 f8f363c6897cedd77edb3726691af4688d68d432..1c90dd37577210a3ea4ad501906c289dfd79e59a 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 ace82ca4e6761eff66b47405a3e26d50df3af8d4..d02b8ad3e1747836b47a8ddf92c0f18fff5223ce 100644 (file)
@@ -18,7 +18,7 @@
        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 d366d5f1089195412c54dbb069b82b8f986862de..afa99ea93ebf1c29bf9c2c17eef5c24d370ec722 100644 (file)
@@ -15,7 +15,7 @@
           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 a78dbf3f149ebd80003a796e0157bcf88d7cb833..61946fbdfea63e450ffa66a7c9881e397af782f2 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 f54135a47247dd058cfadcc3e8e1e5676834afbc..577f1ed48329cce82450962c131697449e50d802 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 2d5e8e9d33865d776f5b7f8a5f1c01fb94f42ad4..cda10334432c273538315239e0520ed96fbbb7bd 100644 (file)
@@ -1,3 +1,203 @@
+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 3d14837ae97929917b621f0111e89be533fa45a1..dd809c380afb97338d700d190c767c5cc49a6d8c 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 9011814f609bb1250896e0a6aacdedf19a005f98..da3128bfb1bf6c427d897b2ddfdf24c5abcf73a3 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 f3e49c8b9e7aeb9726dfea9047be5cffaec6a8a5..bd19d7eda72aca0b4eb5f76af7000bfa9bf93299 100644 (file)
@@ -24,7 +24,6 @@
  *     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 04ca8b01c03677f8719857765032f01632dd56e3..ff17ee489ad27b8207826f447f4cf30baef4b0c9 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 b6976e1bc7406583ed94ddfc3b16c587f6a8028d..8671f41c4a5bafcc13b04a6ea56da57806caf875 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.
@@ -56,6 +60,7 @@
 #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 27b86f3454af4c870fd46e16333ef0dd4d6ab0f0..694d5feaa21cc27fc1d48ae3db8c48af5d18058f 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 9488c1f1987b2df9e9c55daa69dacf64e581bd88..9e836b915f96f628713c766da3570fdf28e4cbca 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 26b4e1c9fa7d3f7d488f15dfdc680b4ba923d029..fa690d97259d2eb69de72a17e3de8e4bc96174bd 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 96dd21932108813ea5746e3a146e664bd268ecfa..a46a30dd6bc96807202cb9997154bc1a8f112982 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 c0be923c652b884179b3df4a8f9b175852b9fa44..e74e78d2a75158befc6801da63c3c934a938d14f 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 0b377911c572ca7188bf5bc0da052e41aeea8f50..49a7448f72daca78be1ae4d4cd9410bdaef6e1e0 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 abc1c930a0a55b4ca8223705d2668c50ed9847e5..4f6ef3efd7c35ceda763a66f9de2a9024712124a 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 f60d1ffce1e45cbc32c33dbdf1a8f09bde020eeb..c8bf96cfefe18ba1f9d67ae9df09501297008763 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 82dfe55e0fa15c7cf0764618380cc043f5cb43ae..5559a3ef69175d149b5b06f4448b3253b50798cf 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 ea78d19c62253d59fa89dc8ffaaa7402e29eb206..10f260ef040b62b2c76b46ed5903781f6c070861 100644 (file)
@@ -11,7 +11,7 @@
   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 d2b66f9bc1585a41004c412ea60f59057d0df8f0..fcfb3241a24d4fdc0a25786b9ff8640d5746c6f1 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 32cd24ab2c16fe164cf6177d1c6333a1fbbc2135..42feecbac57dfc47f2f987c52cc9402875cd243b 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 92d40121bb30d33290e20293c455a7bde4028689..b36c935811411335694c67604dabf46e1cdcb160 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 78dd720ce94133533adfbc71b012aef2b33c1cb0..c12ca8b0899327ed591ad6d2e921628a1531aee0 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 c2dc5cbca422583f32f5f90d7b9d528741f3d9b5..77a9dc4b6e7868f0661541021fcc7b5ad9e277af 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 6416a1f71632e1350bf7869ccef4741b34c20c80..5e1199c3357992171609b42ec355bcd4363ec846 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 586098cd045b1940df1662acfed170ba5ad8593a..4889b2cc71fb23eb9a275ea9cd5617aa78d755b2 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 bc6faa7edbda496cc05361d4b4ba452b32101671..c9114d1386f6f753fba9fe23083a379be55bbc69 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 69c9e22240b1a8feda1a81b5b5c92d3fe12d0dfc..2075aa49d2e9b7016b0c2ce7f7b4dcb049e53df9 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 633c33e4f043cb033ce3914ed0e355eab7db15c9..68c24455a601fef2f315bfa69b2cb2cbef35550b 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 7278b850e8ba6e7c6f5df2f745b13ff29c52243b..0cb987aaaeea023588d92967039b9964b5d7ef7a 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 a780af479947bcddc4b680c155408e0420351c70..08c91fc7e28d36a89c7e5be08b97125881ffeb0e 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 c1754e337b155b91f709c844341f917dc50dd65d..6666d8acfe0f3295bb4af1c16d28eb8a93a51736 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 d1de73ad02ad379f8d265421aac13c198c4c26b9..7b7a246dce5761dafab05d2dce8412106469d777 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 811176a69e5ffd1f697de733a75a958f165f9512..fad26fd1cc24b10d76b30cae94cb048cc56e453d 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 954540871acbac17a1dd486bd75de95fdf40df45..01b5026a16649f666a3a31e1d1786c9450e55467 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 1b33470cc7438ff5a65fa7576f5ac10f95fef339..dab9c4bdf0c3d3f0c9afe37fe93eba8a6414fd0e 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 63540f15942f0d33014eb37c40eb74869244d08e..1eafdf91161b1c677c4e73db31d4809b05f3dd43 100644 (file)
@@ -70,7 +70,7 @@
 #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 c2bb6e8357dd4f2a39170fda5f52ee00be0999b8..a50133004734f2686b944db11d6a1812bf89e46e 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 63eeab9ed94e5ca523107fe5a173e6391154d90f..cb6b4e05bb1c61853a0bf7879590d71b6458bba6 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 1c268f21676f7f58a5ba37cd025cc1e0f551afcb..e9100c7fe1ee23c7dca63e783a85867cac242bbe 100644 (file)
@@ -23,7 +23,7 @@
 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 a7a841724d683dc0b35994f56a8f1e15479efc8b..3878e0203d11beea336040f72cb3ecffb689cd99 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 e2128f03305961ed559bec8851462548a76a153a..18d836d16d0c85b2f9282262333a1f86e2876245 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 082fd88b736440106a0b4d66097ad499769f9674..12a1e9b0ea582153d9b9174d858ddf21135ad0e7 100644 (file)
@@ -16,4 +16,8 @@
 #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 0c66a3e5efff6be8d49d2f1601c3941a165db59a..f12701e70aebd8bd0deafe053c1714696cb4d91e 100644 (file)
 #define IS_INVBCAST    4               /* Wrong netmask bcast not for us (unused)*/
 #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
@@ -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 fca7ba7cdc78c1bb18e072dfdcd50de26bc8fdca..c282632100a6dca646da75927c5f5b107d545a2b 100644 (file)
@@ -17,7 +17,7 @@
 #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 224880172edd0dd34c01560819225d9d96ee2780..eebfb3f882bf8e1e4f37279def460e91006c98fd 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 f4161494ddeb49cf60a0d165415efc29b599c2a1..514832a4e5cd3f5d1c2178c5dd39f2f6a4bfcd6d 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 c06864acdba58f221e5606f23a852faaf0b90c6e..dedbea6633f41a9908877b55da668ca5e8c0523d 100644 (file)
@@ -43,6 +43,7 @@
 #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 562539a90a356755545f2fc0c3378e349a881ed4..09eecf5a458cdf9f8f1aa2f9deeaa301eaef5544 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 fb0e6970daa60c25a8decf89eb69f59b2ff05fc0..470bdc2ef75c75603c2c5494ee9fc3b126d12c42 100644 (file)
@@ -13,7 +13,7 @@
 #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 b2a8c4fb0bf498f4c8f0fbe130d31c6d4ecb05de..fbac1dd4b2b3b6287644d1bcf20b10c185b1da88 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 63a54e9993e86d0cffb0bb81b2397bb9eb2afd7a..9cc2b4609051e75c6ca4b5614c40a1319e6fdabc 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 62bca052c3707c15e53618d8fa78005ed6d410b0..274e81870f20978ec2d5a1727900f00c034bd493 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 1ce3ee3877af83e3dab0a1bfecc6c8b9d068a08c..95301cf5e8aa98556e89b74451e4f272c08408c6 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 5063d60c27a7906c50ebcec9dcbf2df3c428e616..19495911db11698f9bf648a5d900e5e20b16610d 100644 (file)
@@ -14,7 +14,7 @@
 .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 018f8db8fdbcbbce93f5caaec044c634e9d84f34..8b8f7172ff9f2bbbd6013bdc826105be723beb10 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 3e5a67041c37c379a69ab40fa908e4f34ff6bcdc..d52621330ab11c75c2d00660c3214c6fc5addb3d 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 fbbea985c11b6a678301936a803d0f4da6791cb5..5fc29b2420ed38dac3a22d763e602affa75e4922 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 2d5b16d7c75ed5a3ebdd9508c688cde09d01466f..fe110fca166877bf9ca80cde9d78fef8b4e67845 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -19,6 +19,7 @@
 #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 95af292306d9bf7aed1039f2f43650a8c90bb3dc..2d0c501a97647ddaae850391daab8f37583980dd 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 8e773961184b855c911051eeff2da0e87a0d25b7..ef211f8f48fd24da5c1aa5a2b10047d2b6d274ed 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 67174bb7bf2a352e057851e3787bb922644aa594..0232a6397e9fd77a7a4ed8b95998411086fdd18d 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 97307038889a7f06ef06499e2b8c02b7078af32c..7fd20cc9b9d42edf17149caad7cbe17f06c5ff6f 100644 (file)
@@ -22,6 +22,9 @@
  *                                     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);
 }
 
@@ -304,6 +313,10 @@ int dev_close(struct device *dev)
 #ifdef CONFIG_IPX
                ipxrtr_device_down(dev);
 #endif 
+               /*
+                *      Flush the multicast chain
+                */
+               dev_mc_discard(dev);
                /*
                 *      Blank the IP addresses
                 */
@@ -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 fe48ca8eb7e52eee8ca5dd6c9a53221ddcceda51..dea0dacb08af1ad101f42650a79772055c0a1e2e 100644 (file)
@@ -11,6 +11,7 @@
  *             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
@@ -54,6 +55,9 @@
  *             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
@@ -64,6 +68,7 @@
  *             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>
@@ -86,6 +91,9 @@
 #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.
@@ -1542,6 +1592,14 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                return(0);
        }
 
+       /*
+        *      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 dd2cbc5ca8388570380ce7e5b4d367a5b6326db0..7a4da2b7dad47da97e6054ecf185f9db48017093 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 57e552ea770fbbfc16f953bf64576465652161af..c3947923a0ae94b6800020988ef70537976e9150 100644 (file)
@@ -31,6 +31,7 @@
 #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"
@@ -38,6 +39,7 @@
 #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 b79c1da3c6c21378a9ba188a5a0947a94f1f846f..f3aa44f30589ce7e6c38e75a749f8ebf2209a834 100644 (file)
@@ -26,6 +26,7 @@
  *             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 80cb4b4bf19753eb9b39b1915f388274fa56e366..8f1cf0c223b3f53c269169cd671d4cfdd15a4292 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 d5ae2adef9a42d1e5f6e9f897c62cfc1ba49e312..f0aa485a5f69e95eb8884362a4661d9a042c7cb6 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 fd5f123bd1de4391113aeeda4eef0ba1482c724c..ea92cc340e99f24a04fc720881c6158cbd06469c 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 07b036fd5be6af9506b28f87840b6434c86d809a..f785eb0208b961d55e152b94c260167041941a20 100644 (file)
@@ -43,7 +43,9 @@
 #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 a2bbbe861850c3ef4d271946e2da57d2a6d7be91..02d20dda30873319d17d02f6586f5191839f8f04 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 2dcb22c8283f16b062cc56f82d709b40a09c80c5..b4650d8579c7d35a39b4b825e9d54869d690adbe 100644 (file)
@@ -24,7 +24,7 @@
 #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 6e739e70353c75c088c7067355a15549cc56a4a7..1a8316b173a37866955aae8c1854339d3bb18848 100644 (file)
@@ -78,7 +78,7 @@
 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;