VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 68
+SUBLEVEL = 69
ARCH = i386
@@ -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
@@ -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)
+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
#include <linux/sched.h>
#include <linux/lp.h>
#include <linux/malloc.h>
+#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/segment.h>
@@ -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
@@ -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,
@@ -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) {
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
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 */
}
@@ -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;
@@ -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)
{
+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
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
@@ -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.. */
* 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;
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 \
/*
* eata.c - Low-level SCSI driver for EISA EATA SCSI controllers.
*
+ * 30 Nov 1994 rev. 1.09 for linux 1.1.68
+ * Redo i/o on target status CONDITION_GOOD for TYPE_DISK only.
+ * Added optional support for using a single board at a time.
+ *
* 18 Nov 1994 rev. 1.08 for linux 1.1.64
- * Forces sg_tablesize = 64 and can_queue = 64 if these
- * values are not correctly detected (DPT PM2012).
+ * Forces sg_tablesize = 64 and can_queue = 64 if these
+ * values are not correctly detected (DPT PM2012).
*
* 14 Nov 1994 rev. 1.07 for linux 1.1.63 Final BETA release.
* 04 Aug 1994 rev. 1.00 for linux 1.1.39 First BETA release.
#define NO_DEBUG_DETECT
#define NO_DEBUG_INTERRUPT
#define NO_DEBUG_STATISTICS
+#define NO_SINGLE_HOST_OPERATIONS
#define MAX_TARGET 8
#define MAX_IRQ 16
@@ -303,7+308,7 @@ static inline int port_detect (ushort *port_base, unsigned int j, sh[j]->sg_tablesize = (ushort) ntohs(info.scatt_size);
sh[j]->this_id = (ushort) ntohl(info.host_addr);
sh[j]->can_queue = (ushort) ntohs(info.queue_size);
- sh[j]->hostt->cmd_per_lun = MAX_CMD_PER_LUN;
+ sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
sh[j]->unchecked_isa_dma = FALSE;
memset(HD(j), 0, sizeof(struct hostdata));
HD(j)->board_number = j;
@@ -313,7+318,7 @@ static inline int port_detect (ushort *port_base, unsigned int j, printk("%s: SCSI ID %d, PORT 0x%03x, IRQ %u, SG %d, "\
"Mbox %d, CmdLun %d.\n", BN(j), sh[j]->this_id,
sh[j]->io_port, sh[j]->irq, sh[j]->sg_tablesize,
- sh[j]->can_queue, sh[j]->hostt->cmd_per_lun);
+ sh[j]->can_queue, sh[j]->cmd_per_lun);
/* DPT PM2012 does not allow to detect sg_tablesize correctly */
if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
@@ -363,6+368,16 @@ int eata_detect (Scsi_Host_Template * tpnt) { port_base++;
}
+#if defined (SINGLE_HOST_OPERATIONS)
+ /* Create a circular linked list among the detected boards. */
+ if (j > 1) {
+
+ for (k = 0; k < (j - 1); k++) sh[k]->block = sh[k + 1];
+
+ sh[j - 1]->block = sh[0];
+ }
+#endif
+
restore_flags(flags);
return j;
}
@@ -764,7+779,7 @@ static void eata_interrupt_handler(int irq) {
/* If there was a bus reset, redo operation on each target */
else if (spp->target_status == CONDITION_GOOD
- && SCpnt->device->type != TYPE_TAPE
+ && SCpnt->device->type == TYPE_DISK
&& HD(j)->target_reset[SCpnt->target])
status = DID_BUS_BUSY << 16;
else
#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, \
@@ -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)
@@ -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;
/*
@@ -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++;
};
};
@@ -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;
@@ -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;
}
@@ -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
@@ -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;
@@ -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");
}
}
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 = 0 ;
+ 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));
@@ -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
/*
* 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
@@ -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, \
@@ -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
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:
@@ -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;
@@ -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;
}
@@ -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);
@@ -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);
}
@@ -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);
@@ -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)
@@ -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;
}
#
# 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:
#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
+
@@ -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;
}
@@ -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 */
};
@@ -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);
@@ -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;
#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 */
@@ -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)
#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;
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) |
--- /dev/null
+/*
+ * 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 */
@@ -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 */
@@ -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);
#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 */
#define IS_MULTICAST 5 /* Multicast IP address */
/*
+ * We tag these structures with multicasts.
+ */
+
+struct dev_mc_list
+{
+ struct dev_mc_list *next;
+ char dmi_addr[MAX_ADDR_LEN];
+ unsigned short dmi_addrlen;
+ unsigned short dmi_users;
+};
+
+/*
* The DEVICE structure.
* Actually, this whole structure is a big mistake. It mixes I/O
* data with strictly "high-level" data, and it has to know about
@@ -107,7+119,12 @@ struct device unsigned long pa_dstaddr; /* protocol P-P other side addr */
unsigned long pa_mask; /* protocol netmask */
unsigned short pa_alen; /* protocol address length */
+
+ struct dev_mc_list *mc_list; /* Multicast mac addresses */
+ int mc_count; /* Number of installed mcasts */
+ struct ip_mc_list *ip_mc_list; /* IP multicast filter chain */
+
/* For load balancing driver pair support */
unsigned long pkt_queue; /* Packets queued */
@@ -202,6+219,13 @@ extern int ether_config(struct device *dev, struct ifmap *map); extern int register_netdev(struct device *dev);
extern void unregister_netdev(struct device *dev);
+/* Functions used for multicast support */
+
+extern void dev_mc_upload(struct device *dev);
+extern void dev_mc_delete(struct device *dev, void *addr, int alen, int all);
+extern void dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
+extern void dev_mc_discard(struct device *dev);
+
#endif /* __KERNEL__ */
#endif /* _LINUX_DEV_H */
#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);
@@ -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
#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 */
#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
@@ -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);
#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;
}
@@ -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);
@@ -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;
@@ -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),
@@ -32,7+32,7 @@ extern void adjust_clock(void);
asmlinkage int sys_ni_syscall(void)
{
- return -EINVAL;
+ return -ENOSYS;
}
asmlinkage int sys_idle(void)
.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)
--- /dev/null
+/*
+ * 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;
+}
@@ -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
@@ -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 */
-};
@@ -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));
#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;
$(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
@@ -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...
@@ -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;
* keep the queue safe.
* Alan Cox : Fixed double lock.
* Alan Cox : Fixed promisc NULL pointer trap
+ * ???????? : Support the full private ioctl range
+ * Alan Cox : Moved ioctl permission check into drivers
+ * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI
*
* Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have
* the rest as well commented in the end.
@@ -266,6+269,12 @@ int dev_open(struct device *dev) if (ret == 0)
dev->flags |= (IFF_UP | IFF_RUNNING);
+ /*
+ * Initialise multicasting status
+ */
+
+ dev_mc_upload(dev);
+
return(ret);
}
@@ -305,6+314,10 @@ int dev_close(struct device *dev) ipxrtr_device_down(dev);
#endif
/*
+ * Flush the multicast chain
+ */
+ dev_mc_discard(dev);
+ /*
* Blank the IP addresses
*/
dev->pa_addr = 0;
@@ -360,9+373,9 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) dev=dev->slave;
restore_flags(flags);
#endif
-
+#ifdef CONFIG_SKB_CHECK
IS_SKB(skb);
-
+#endif
skb->dev = dev;
/*
@@ -495,8+508,9 @@ void netif_rx(struct sk_buff *skb) /*
* Add it to the "backlog" queue.
*/
-
+#ifdef CONFIG_SKB_CHECK
IS_SKB(skb);
+#endif
skb_queue_tail(&backlog,skb);
backlog_size++;
@@ -1070,15+1084,21 @@ static int dev_ifsioc(void *arg, unsigned int getset) dev->flags = ifr.ifr_flags & (
IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
- IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER);
+ IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER
+ | IFF_MULTICAST);
#ifdef CONFIG_SLAVE_BALANCING
if(!(dev->flags&IFF_MASTER) && dev->slave)
{
dev->slave->flags&=~IFF_SLAVE;
dev->slave=NULL;
}
-#endif
+#endif
+ /*
+ * Load in the correct multicast list now the flags have changed.
+ */
+ dev_mc_upload(dev);
+#if 0
if( dev->set_multicast_list!=NULL)
{
@@ -1096,7+1116,7 @@ static int dev_ifsioc(void *arg, unsigned int getset) if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
dev->set_multicast_list(dev,-1,NULL);
}
-
+#endif
/*
* Have we downed the interface
*/
@@ -1340,6+1360,22 @@ static int dev_ifsioc(void *arg, unsigned int getset) }
break;
#endif
+
+ case SIOCADDMULTI:
+ if(dev->set_multicast_list==NULL)
+ return -EINVAL;
+ if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC)
+ return -EINVAL;
+ dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1);
+ return 0;
+
+ case SIOCDELMULTI:
+ if(dev->set_multicast_list==NULL)
+ return -EINVAL;
+ if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC)
+ return -EINVAL;
+ dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1);
+ return 0;
/*
* Unknown or private ioctl
*/
@@ -1420,8+1456,6 @@ int dev_ioctl(unsigned int cmd, void *arg) default:
if((cmd >= SIOCDEVPRIVATE) &&
(cmd <= (SIOCDEVPRIVATE + 15))) {
- if (!suser())
- return -EPERM;
return dev_ifsioc(arg, cmd);
}
return -EINVAL;
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
+ * Richard Underwood
*
* Fixes:
* Alan Cox : Commented a couple of minor bits of surplus code
* Alan Cox : IP options adjust sk->priority.
* Pedro Roque : Fix mtu/length error in ip_forward.
* Alan Cox : Avoid ip_chk_addr when possible.
+ * Richard Underwood : IP multicasting.
+ * Alan Cox : Cleaned up multicast handlers.
+ * Alan Cox : RAW sockets demultiplex in the BSD style.
*
* To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
#include "sock.h"
#include "arp.h"
#include "icmp.h"
+#include "raw.h"
+#include "igmp.h"
+#include <linux/ip_fw.h>
#define CONFIG_IP_DEFRAG
@@ -99,7+107,17 @@ extern void sort_send(struct sock *sk); * SNMP management statistics
*/
+#ifdef CONFIG_IP_FORWARDING
struct ip_mib ip_statistics={1,64,}; /* Forwarding=Yes, Default TTL=64 */
+#else
+struct ip_mib ip_statistics={1,64,}; /* Forwarding=No, Default TTL=64 */
+#endif
+
+#ifdef CONFIG_IP_MULTICAST
+
+struct ip_mc_list *ip_mc_head=NULL;
+
+#endif
/*
* Handle the issuing of an ioctl() request
@@ -1259,6+1277,16 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) unsigned char *ptr; /* Data pointer */
unsigned long raddr; /* Router IP address */
+ /*
+ * See if we are allowed to forward this.
+ */
+
+#ifdef CONFIG_IP_FIREWALL
+ if(!ip_fw_chk(skb->h.iph, ip_fw_fwd_chain))
+ {
+ return;
+ }
+#endif
/*
* According to the RFC, we must first decrease the TTL field. If
* that reaches zero, we must reply an ICMP control message telling
@@ -1403,6+1431,14 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) }
else
{
+#ifdef CONFIG_IP_ACCT
+ /*
+ * Count mapping we shortcut
+ */
+
+ ip_acct_cnt(iph,ip_acct_chain,1);
+#endif
+
/*
* Map service types to priority. We lie about
* throughput being low priority, but its a good
@@ -1428,6+1464,7 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct iphdr *iph = skb->h.iph;
+ struct sock *raw_sk=NULL;
unsigned char hash;
unsigned char flag = 0;
unsigned char opts_p = 0; /* Set iff the packet has options. */
@@ -1437,7+1474,6 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) int brd=IS_MYADDR;
int is_frag=0;
-
ip_statistics.IpInReceives++;
/*
@@ -1461,7+1497,21 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) kfree_skb(skb, FREE_WRITE);
return(0);
}
+
+ /*
+ * See if the firewall wants to dispose of the packet.
+ */
+
+#ifdef CONFIG_IP_FIREWALL
+
+ if(!LOOPBACK(iph->daddr) && !ip_fw_chk(iph,ip_fw_blk_chain))
+ {
+ kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
+#endif
+
/*
* Our transport medium may have padded the buffer out. Now we know it
* is IP we can trim to the true length of the frame.
@@ -1543,6+1593,14 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) }
/*
+ * Account for the packet
+ */
+
+#ifdef CONFIG_IP_ACCT
+ ip_acct_cnt(iph,ip_acct_chain,1);
+#endif
+
+ /*
* Reassemble IP fragments.
*/
@@ -1554,6+1612,8 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) return 0;
iph=skb->h.iph;
}
+
+
/*
* Point into the IP datagram, just past the header.
@@ -1561,7+1621,39 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
skb->ip_hdr = iph;
skb->h.raw += iph->ihl*4;
-
+
+ /*
+ * Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies.
+ */
+
+ hash = iph->protocol & (SOCK_ARRAY_SIZE-1);
+
+ /* If there maybe a raw socket we must check - if not we don't care less */
+ if((raw_sk=raw_prot.sock_array[hash])!=NULL)
+ {
+ struct sock *sknext=NULL;
+ struct sk_buff *skb1;
+ raw_sk=get_sock_raw(raw_sk, hash, iph->saddr, iph->daddr);
+ if(raw_sk) /* Any raw sockets */
+ {
+ do
+ {
+ /* Find the next */
+ sknext=get_sock_raw(raw_sk->next, hash, iph->saddr, iph->daddr);
+ if(sknext)
+ skb1=skb_clone(skb, GFP_ATOMIC);
+ else
+ break; /* One pending raw socket left */
+ if(skb1)
+ raw_rcv(raw_sk, skb1, dev, iph->saddr,iph->daddr);
+ raw_sk=sknext;
+ }
+ while(raw_sk!=NULL);
+ /* Here either raw_sk is the last raw socket, or NULL if none */
+ /* We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy */
+ }
+ }
+
/*
* skb->h.raw now points at the protocol beyond the IP header.
*/
@@ -1576,14+1668,10 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) /*
* See if we need to make a copy of it. This will
* only be set if more than one protocol wants it.
- * and then not for the last one.
- *
- * This is an artifact of poor upper protocol design.
- * Because the upper protocols damage the actual packet
- * we must do copying. In actual fact it's even worse
- * than this as TCP may hold on to the buffer.
+ * and then not for the last one. If there is a pending
+ * raw delivery wait for that
*/
- if (ipprot->copy)
+ if (ipprot->copy || raw_sk)
{
skb2 = skb_clone(skb, GFP_ATOMIC);
if(skb2==NULL)
@@ -1613,7+1701,9 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) * ICMP reply messages get queued up for transmission...)
*/
- if (!flag)
+ if(raw_sk!=NULL) /* Shift to last raw user */
+ raw_rcv(raw_sk, skb, dev, iph->saddr, iph->daddr);
+ else if (!flag) /* Free and report errors */
{
if (brd != IS_BROADCAST && brd!=IS_MULTICAST)
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
@@ -1768,6+1858,9 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, * If the indicated interface is up and running, send the packet.
*/
ip_statistics.IpOutRequests++;
+#ifdef CONFIG_IP_ACCT
+ ip_acct_cnt(iph,ip_acct_chain,1);
+#endif
if (dev->flags & IFF_UP)
{
@@ -1916,6+2009,50 @@ void ip_retransmit(struct sock *sk, int all) reset_timer(sk, TIME_WRITE, sk->rto);
}
+#ifdef CONFIG_IP_MULTICAST
+
+/*
+ * Write an multicast group list table for the IGMP daemon to
+ * read.
+ */
+
+int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
+{
+ off_t pos=0, begin=0;
+ struct ip_mc_list *im;
+ unsigned long flags;
+ int len=0;
+
+
+ len=sprintf(buffer,"Device : Multicast\n");
+ save_flags(flags);
+ cli();
+
+ im=ip_mc_head;
+
+ while(im!=NULL)
+ {
+ len+=sprintf(buffer+len,"%-10s: %08lX\n", im->interface->name, im->multiaddr);
+ pos=begin+len;
+ if(pos<offset)
+ {
+ len=0;
+ begin=pos;
+ }
+ if(pos>offset+length)
+ break;
+ im=im->next;
+ }
+ restore_flags(flags);
+ *start=buffer+(offset-begin);
+ len-=(offset-begin);
+ if(len>length)
+ len=length;
+ return len;
+}
+
+
+#endif
/*
* Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
* an IP socket.
@@ -1928,7+2065,9 @@ void ip_retransmit(struct sock *sk, int all) int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
int val,err;
-
+#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
+ struct ip_fw tmp_fw;
+#endif
if (optval == NULL)
return(-EINVAL);
@@ -1957,6+2096,227 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt return -EINVAL;
sk->ip_ttl=val;
return 0;
+#ifdef CONFIG_IP_MULTICAST
+ case IP_MULTICAST_TTL:
+ {
+ unsigned char ucval;
+
+ ucval=get_fs_byte((unsigned char *)optval);
+ printk("MC TTL %d\n", ucval);
+ if(ucval<1||ucval>255)
+ return -EINVAL;
+ sk->ip_mc_ttl=(int)ucval;
+ return 0;
+ }
+
+ case IP_MULTICAST_IF:
+ {
+ /* Not fully tested */
+ struct in_addr addr;
+ struct device *dev=NULL;
+
+ /*
+ * Check the arguments are allowable
+ */
+
+ err=verify_area(VERIFY_READ, optval, sizeof(addr));
+ if(err)
+ return err;
+
+ memcpy_fromfs(&addr,optval,sizeof(addr));
+
+ printk("MC bind %s\n", in_ntoa(addr.s_addr));
+
+ /*
+ * What address has been requested
+ */
+
+ if(addr.s_addr==INADDR_ANY) /* Default */
+ {
+ sk->ip_mc_name[0]=0;
+ return 0;
+ }
+
+ /*
+ * Find the device
+ */
+
+ for(dev = dev_base; dev; dev = dev->next)
+ {
+ if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
+ (dev->pa_addr==addr.s_addr))
+ break;
+ }
+
+ /*
+ * Did we find one
+ */
+
+ if(dev)
+ {
+ strcpy(sk->ip_mc_name,dev->name);
+ return 0;
+ }
+ return -EADDRNOTAVAIL;
+ }
+
+ case IP_ADD_MEMBERSHIP:
+ {
+
+/*
+ * FIXME: Add/Del membership should have a semaphore protecting them from re-entry
+ */
+ struct ip_mreq mreq;
+ static struct options optmem;
+ unsigned long route_src;
+ struct rtable *rt;
+ struct ip_mc_list *l=NULL;
+ struct device *dev=NULL;
+ int ct=0;
+
+ /*
+ * Check the arguments.
+ */
+
+ err=verify_area(VERIFY_READ, optval, sizeof(mreq));
+ if(err)
+ return err;
+
+ memcpy_fromfs(&mreq,optval,sizeof(mreq));
+
+ /*
+ * Get device for use later
+ */
+
+ if(mreq.imr_interface.s_addr==INADDR_ANY)
+ {
+ /*
+ * Not set so scan.
+ */
+ if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL)
+ {
+ dev=rt->rt_dev;
+ rt->rt_use--;
+ }
+ }
+ else
+ {
+ /*
+ * Find a suitable device.
+ */
+ for(dev = dev_base; dev; dev = dev->next)
+ {
+ if((dev->flags&IFF_UP)&&(dev->flags&IFF_MULTICAST)&&
+ (dev->pa_addr==mreq.imr_interface.s_addr))
+ break;
+ }
+ }
+
+ /*
+ * No device, no cookies.
+ */
+
+ if(!dev)
+ return -ENODEV;
+
+ /*
+ * Join group.
+ */
+
+ return ip_mc_join_group(sk,dev,mreq.imr_multiaddr.s_addr);
+ }
+
+ case IP_DROP_MEMBERSHIP:
+ {
+ struct ip_mreq mreq;
+ struct rtable *rt;
+ static struct options optmem;
+ unsigned long route_src;
+ struct device *dev=NULL;
+
+ /*
+ * Check the arguments
+ */
+
+ err=verify_area(VERIFY_READ, optval, sizeof(mreq));
+ if(err)
+ return err;
+
+ memcpy_fromfs(&mreq,optval,sizeof(mreq));
+
+ /*
+ * Get device for use later
+ */
+
+ if(mreq.imr_interface.s_addr==INADDR_ANY)
+ {
+ if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,&optmem, &route_src))!=NULL)
+ {
+ dev=rt->rt_dev;
+ rt->rt_use--;
+ }
+ }
+ else
+ {
+ for(dev = dev_base; dev; dev = dev->next)
+ {
+ if((dev->flags&IFF_UP)&& (dev->flags&IFF_MULTICAST)&&
+ (dev->pa_addr==mreq.imr_interface.s_addr))
+ break;
+ }
+ }
+
+ /*
+ * Did we find a suitable device.
+ */
+
+ if(!dev)
+ return -ENODEV;
+
+ /*
+ * Leave group
+ */
+
+ return ip_mc_leave_group(sk,dev,mreq.imr_multiaddr.s_addr);
+ }
+#endif
+#ifdef CONFIG_IP_FIREWALL
+ case IP_FW_ADD_BLK:
+ case IP_FW_DEL_BLK:
+ case IP_FW_ADD_FWD:
+ case IP_FW_DEL_FWD:
+ case IP_FW_CHK_BLK:
+ case IP_FW_CHK_FWD:
+ case IP_FW_FLUSH:
+ case IP_FW_POLICY:
+ if(!suser())
+ return -EPERM;
+ if(optlen>sizeof(tmp_fw) || optlen<1)
+ return -EINVAL;
+ err=verify_area(VERIFY_READ,optval,optlen);
+ if(err)
+ return err;
+ memcpy_fromfs(&tmp_fw,optval,optlen);
+ err=ip_fw_ctl(optname, &tmp_fw,optlen);
+ return -err; /* -0 is 0 after all */
+
+#endif
+#ifdef CONFIG_IP_ACCT
+ case IP_ACCT_DEL:
+ case IP_ACCT_ADD:
+ case IP_ACCT_FLUSH:
+ case IP_ACCT_ZERO:
+ if(!suser())
+ return -EPERM;
+ if(optlen>sizeof(tmp_fw) || optlen<1)
+ return -EINVAL;
+ err=verify_area(VERIFY_READ,optval,optlen);
+ if(err)
+ return err;
+ memcpy_fromfs(&tmp_fw, optval,optlen);
+ err=ip_acct_ctl(optname, &tmp_fw,optlen);
+ return -err; /* -0 is 0 after all */
+#endif
/* IP_OPTIONS and friends go here eventually */
default:
return(-ENOPROTOOPT);
@@ -1971,7+2331,10 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
{
int val,err;
-
+#ifdef CONFIG_IP_MULTICAST
+ int len;
+#endif
+
if(level!=SOL_IP)
return -EOPNOTSUPP;
@@ -1983,6+2346,22 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op case IP_TTL:
val=sk->ip_ttl;
break;
+#ifdef CONFIG_IP_MULTICAST
+ case IP_MULTICAST_TTL:
+ val=sk->ip_mc_ttl;
+ break;
+ case IP_MULTICAST_IF:
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ len=strlen(sk->ip_mc_name);
+ err=verify_area(VERIFY_WRITE, optval, len);
+ if(err)
+ return err;
+ put_fs_long(len,(unsigned long *) optlen);
+ memcpy_tofs((void *)optval,sk->ip_mc_name, len);
+ return 0;
+#endif
default:
return(-ENOPROTOOPT);
}
#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 {
--- /dev/null
+/*
+ * 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 */
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
+#include <linux/timer.h>
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "sock.h"
#include "icmp.h"
#include "udp.h"
+#include "igmp.h"
static struct inet_protocol tcp_protocol = {
@@ -75,8+77,23 @@ static struct inet_protocol icmp_protocol = { "ICMP" /* name */
};
-
+#ifndef CONFIG_IP_MULTICAST
struct inet_protocol *inet_protocol_base = &icmp_protocol;
+#else
+static struct inet_protocol igmp_protocol = {
+ igmp_rcv, /* IGMP handler */
+ NULL, /* IGMP never fragments anyway */
+ NULL, /* IGMP error control */
+ &icmp_protocol, /* next */
+ IPPROTO_IGMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "IGMP" /* name */
+};
+
+struct inet_protocol *inet_protocol_base = &igmp_protocol;
+#endif
+
struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
NULL
};
* 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,
@@ -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 */
@@ -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
}
/*
@@ -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)
{
#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);
@@ -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);
#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 ||
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;