diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1994-02-18 14:54:02 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:33 -0400 |
commit | 42f89c5ded09dc700fbabdd6008c7781e99762e2 (patch) | |
tree | 94f70c69ae53701ff5d040f1ed34a1f257b17b13 | |
parent | 2fd717bbd7af8cb1dfd2f00df621b945e55e16fb (diff) | |
download | archive-42f89c5ded09dc700fbabdd6008c7781e99762e2.tar.gz |
ALPHA-pl15f
-rw-r--r-- | Configure | 1 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | drivers/char/psaux.c | 1 | ||||
-rw-r--r-- | drivers/char/serial.c | 6 | ||||
-rw-r--r-- | drivers/char/tty_ioctl.c | 18 | ||||
-rw-r--r-- | drivers/net/3c507.c | 63 | ||||
-rw-r--r-- | drivers/net/8390.c | 252 | ||||
-rw-r--r-- | drivers/net/Space.c | 5 | ||||
-rw-r--r-- | drivers/net/at1700.c | 48 | ||||
-rw-r--r-- | drivers/net/atp.c | 10 | ||||
-rw-r--r-- | drivers/net/eexpress.c | 90 | ||||
-rw-r--r-- | drivers/net/hp.c | 28 | ||||
-rw-r--r-- | drivers/net/lance.c | 31 | ||||
-rw-r--r-- | drivers/net/ne.c | 8 | ||||
-rw-r--r-- | drivers/net/slip.c | 1 | ||||
-rw-r--r-- | drivers/net/smc-ultra.c | 4 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 347 | ||||
-rw-r--r-- | fs/buffer.c | 4 | ||||
-rw-r--r-- | fs/proc/array.c | 2 | ||||
-rw-r--r-- | include/linux/if_ether.h | 35 | ||||
-rw-r--r-- | include/linux/tty.h | 2 | ||||
-rw-r--r-- | ipc/util.c | 27 | ||||
-rw-r--r-- | kernel/ksyms.sh | 2 | ||||
-rw-r--r-- | kernel/traps.c | 9 | ||||
-rw-r--r-- | net/inet/ip.c | 25 | ||||
-rw-r--r-- | net/inet/skbuff.h | 3 | ||||
-rw-r--r-- | net/inet/sock.c | 5 | ||||
-rw-r--r-- | net/inet/sock.h | 3 | ||||
-rw-r--r-- | net/inet/tcp.c | 300 | ||||
-rw-r--r-- | net/inet/tcp.h | 3 | ||||
-rw-r--r-- | zBoot/Makefile | 2 |
31 files changed, 766 insertions, 571 deletions
@@ -160,6 +160,7 @@ function int () { CONFIG=.config~ CONFIG_H=include/linux/autoconf.h +trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2 # # Make sure we start out with a clean slate. @@ -1,6 +1,6 @@ VERSION = 0.99 PATCHLEVEL = 15 -ALPHA = e +ALPHA = f all: Version zImage diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c index da133b3..3944c22 100644 --- a/drivers/char/psaux.c +++ b/drivers/char/psaux.c @@ -442,7 +442,6 @@ unsigned long psaux_init(unsigned long kmem_start) int qp_found = 0; #ifdef CONFIG_82C710_MOUSE - printk("Probing 82C710 mouse port device.\n"); if ((qp_found = probe_qp())) { printk("82C710 type pointing device detected -- driver installed.\n"); /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 88aa55b..136be8f 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -1528,11 +1528,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty->hw_stopped = 0; if (info->flags & ASYNC_INITIALIZED) { rs_start(tty); - /* - * XXX There should be a timeout added to - * wait_until_sent, eventually. TYT 1/19/94 - */ - wait_until_sent(tty); + wait_until_sent(tty, 6000); /* 60 seconds timeout */ } else flush_output(tty); flush_input(tty); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 3895262..1aec5ba 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -82,7 +82,7 @@ void flush_output(struct tty_struct * tty) } } -void wait_until_sent(struct tty_struct * tty) +void wait_until_sent(struct tty_struct * tty, int timeout) { struct wait_queue wait = { current, NULL }; @@ -91,7 +91,11 @@ void wait_until_sent(struct tty_struct * tty) return; add_wait_queue(&tty->write_q.proc_list, &wait); current->counter = 0; /* make us low-priority */ - while (1) { + if (timeout) + current->timeout = timeout + jiffies; + else + current->timeout = (unsigned) -1; + do { current->state = TASK_INTERRUPTIBLE; if (current->signal & ~current->blocked) break; @@ -99,7 +103,7 @@ void wait_until_sent(struct tty_struct * tty) if (EMPTY(&tty->write_q)) break; schedule(); - } + } while (current->timeout); current->state = TASK_RUNNING; remove_wait_queue(&tty->write_q.proc_list, &wait); } @@ -297,7 +301,7 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc) return 0; /* We are already in the desired discipline */ /* Shutdown the current discipline. */ - wait_until_sent(tty); + wait_until_sent(tty, 0); flush_input(tty); if (ldiscs[tty->disc].close) ldiscs[tty->disc].close(tty); @@ -379,7 +383,7 @@ int tty_ioctl(struct inode * inode, struct file * file, if (cmd == TCSETSF || cmd == TCSETSW) { if (cmd == TCSETSF) flush_input(termios_tty); - wait_until_sent(termios_tty); + wait_until_sent(termios_tty, 0); } return set_termios(termios_tty, (struct termios *) arg, termios_dev); @@ -394,7 +398,7 @@ int tty_ioctl(struct inode * inode, struct file * file, if (cmd == TCSETAF || cmd == TCSETAW) { if (cmd == TCSETAF) flush_input(termios_tty); - wait_until_sent(termios_tty); + wait_until_sent(termios_tty, 0); } return set_termio(termios_tty, (struct termio *) arg, termios_dev); @@ -642,7 +646,7 @@ int tty_ioctl(struct inode * inode, struct file * file, retval = check_change(tty, dev); if (retval) return retval; - wait_until_sent(tty); + wait_until_sent(tty, 0); if (!tty->ioctl) return 0; tty->ioctl(tty, file, cmd, arg); diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index ba53e06..8ee16f6 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -11,6 +11,8 @@ Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings) and jrs@world.std.com (Rick Sladkey) for testing and bugfixes. + Mark Salazar <leslie@access.digex.net> made the changes for cards with + only 16K packet buffers. Things remaining to do: Verify that the tx and rx buffers don't have fencepost errors. @@ -19,7 +21,7 @@ */ static char *version = - "3c507.c:v0.03 10/27/93 Donald Becker (becker@super.org)\n"; + "3c507.c:v0.99-15f 2/17/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> @@ -145,6 +147,17 @@ struct net_local { #define iSCB_CBL 0xC /* Command BLock offset. */ #define iSCB_RFA 0xE /* Rx Frame Area offset. */ +/* Since the 3c507 maps the shared memory window so that the last byte is + at 82586 address FFFF, the first byte is at 82586 address 0, 16K, 32K, or + 48K cooresponding to window sizes of 64K, 48K, 32K and 16K respectively. + We can account for this be setting the 'SBC Base' entry in the ISCP table + below for all the 16 bit offset addresses, and also adding the 'SCB Base' + value to all 24 bit physical addresses (in the SCP table and the TX and RX + Buffer Descriptors). + -Mark + */ +#define SCB_BASE ((unsigned)64*1024 - (dev->mem_end - dev->mem_start)) + /* What follows in 'init_words[]' is the "program" that is downloaded to the 82586 memory. It's mostly tables and command blocks, and starts at the @@ -192,7 +205,7 @@ struct net_local { The Tx command chain and buffer list is setup as follows: A Tx command table, with the data buffer pointing to... A Tx data buffer descriptor. The packet is in a single buffer, rather than - chaining together several smaller buffers. + chaining together several smaller buffers. A NoOp command, which initially points to itself, And the packet data. @@ -213,13 +226,17 @@ struct net_local { */ -short init_words[] = { +unsigned short init_words[] = { + /* System Configuration Pointer (SCP). */ 0x0000, /* Set bus size to 16 bits. */ - 0x0000,0x0000, /* Set control mailbox (SCB) addr. */ - 0,0, /* pad to 0x000000. */ + 0,0, /* pad words. */ + 0x0000,0x0000, /* ISCP phys addr, set in init_82586_mem(). */ + + /* Intermediate System Configuration Pointer (ISCP). */ 0x0001, /* Status word that's cleared when init is done. */ 0x0008,0,0, /* SCB offset, (skip, skip) */ + /* System Control Block (SCB). */ 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */ CONFIG_CMD, /* Command list pointer, points to Configure. */ RX_BUF_START, /* Rx block list. */ @@ -270,11 +287,11 @@ void init_82586_mem(struct device *dev); /* Check for a network adaptor of this type, and return '0' iff one exists. - If dev->base_addr == 0, probe all likely locations. - If dev->base_addr == 1, always return failure. - If dev->base_addr == 2, (detachable devices only) alloate space for the - device and return success. - */ + If dev->base_addr == 0, probe all likely locations. + If dev->base_addr == 1, always return failure. + If dev->base_addr == 2, (detachable devices only) alloate space for the + device and return success. + */ int el16_probe(struct device *dev) { @@ -369,9 +386,6 @@ int el16_probe1(struct device *dev, short ioaddr) size = ((mem_config & 3) + 1) << 14; base = 0x0c0000 + ( (mem_config & 0x18) << 12); } - if (size != 0x10000) - printk("%s: Warning, this version probably only works with 64K of" - "shared memory.\n", dev->name); dev->mem_start = base; dev->mem_end = base + size; } @@ -538,9 +552,9 @@ el16_interrupt(int reg_ptr) status = shmem[iSCB_STATUS>>1]; - if (net_debug > 4) { + if (net_debug > 4) { printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); - } + } /* Disable the 82586's input to the interrupt line. */ outb(0x80, ioaddr + MISC_CTRL); @@ -661,6 +675,7 @@ init_rx_bufs(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; unsigned short *write_ptr; + unsigned short SCB_base = SCB_BASE; int cur_rxbuf = lp->rx_head = RX_BUF_START; @@ -683,7 +698,7 @@ init_rx_bufs(struct device *dev) *write_ptr++ = 0x0000; /* Buffer: Actual count */ *write_ptr++ = -1; /* Buffer: Next (none). */ - *write_ptr++ = cur_rxbuf + 0x20; /* Buffer: Address low */ + *write_ptr++ = cur_rxbuf + 0x20 + SCB_base; /* Buffer: Address low */ *write_ptr++ = 0x0000; /* Finally, the number of bytes in the buffer. */ *write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20; @@ -712,12 +727,13 @@ init_82586_mem(struct device *dev) and hold the 586 in reset during the memory initialization. */ outb(0x20, ioaddr + MISC_CTRL); + /* Fix the ISCP address and base. */ + init_words[3] = SCB_BASE; + init_words[7] = SCB_BASE; + /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */ -#ifdef old - memcpy((void*)dev->mem_start+0xfff6, init_words, 10); -#else memcpy((void*)dev->mem_end-10, init_words, 10); -#endif + /* Write the words at 0x0000. */ memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10); @@ -776,7 +792,7 @@ hardware_send_packet(struct device *dev, void *buf, short length) /* Output the data buffer descriptor. */ *write_ptr++ = length | 0x8000; /* Byte count parameter. */ *write_ptr++ = -1; /* No next data buffer. */ - *write_ptr++ = tx_block+22; /* Buffer follows the NoOp command. */ + *write_ptr++ = tx_block+22+SCB_BASE;/* Buffer follows the NoOp command. */ *write_ptr++ = 0x0000; /* Buffer address high bits (always zero). */ /* Output the Loop-back NoOp command. */ @@ -796,10 +812,10 @@ hardware_send_packet(struct device *dev, void *buf, short length) if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) lp->tx_head = TX_BUF_START; - if (net_debug > 4) { + if (net_debug > 4) { printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", dev->name, ioaddr, length, tx_block, lp->tx_head); - } + } if (lp->tx_head != lp->tx_reap) dev->tbusy = 0; @@ -893,6 +909,7 @@ el16_rx(struct device *dev) * version-control: t * kept-new-versions: 5 * tab-width: 4 + * c-indent-level: 4 * End: */ diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 9c896cc..024568e 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -8,22 +8,21 @@ incorporated herein by reference. This is the chip-specific code for many 8390-based ethernet adaptors. + This is not a complete driver, it must be combined with board-specific + code such as ne.c, wd.c, 3c503.c, etc. The Author may be reached as becker@super.org or C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 */ static char *version = - "8390.c:v0.99-13f 10/18/93 Donald Becker (becker@super.org)\n"; + "8390.c:v0.99-15e 2/16/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> /* Braindamage remaining: - - Ethernet devices should use a chr_drv device interface, with ioctl()s to - configure the card, bring the interface up or down, allow access to - statistics, and maybe read() and write() access to raw packets. - This won't be done until after Linux 1.00. + Much of this code should be cleaned up post-1.00, but it has been + extensively beta tested in the current form. Sources: The National Semiconductor LAN Databook, and the 3Com 3c503 databook. @@ -59,11 +58,22 @@ static char *version = #include "8390.h" -#ifndef HAVE_ALLOC_SKB -#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) -#define kfree_skbmem(addr, size) kfree_s(addr,size) -#endif - +/* These are the operational function interfaces to board-specific + routines. + void reset_8390(struct device *dev) + Resets the board associated with DEV, including a hardware reset of + the 8390. This is only called when there is a transmit timeout, and + it is always followed by 8390_init(). + void block_output(struct device *dev, int count, const unsigned char *buf, + int start_page) + Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The + "page" value uses the 8390's 256-byte pages. + int block_input(struct device *dev, int count, char *buf, int ring_offset) + Read COUNT bytes from the packet buffer into BUF. Start reading from + RING_OFFSET, the address as the 8390 sees it. The first read will + always be the 4 byte, page aligned 8390 header. *If* there is a + subsequent read, it will be of the rest of the packet. +*/ #define ei_reset_8390 (ei_local->reset_8390) #define ei_block_output (ei_local->block_output) #define ei_block_input (ei_local->block_input) @@ -75,14 +85,14 @@ int ei_debug = EI_DEBUG; int ei_debug = 1; #endif -/* Max number of packets received at one Intr. */ -/*static int high_water_mark = 0;*/ +/* Max number of packets received at one Intr. + Current this may only be examined by a kernel debugger. */ +static int high_water_mark = 0; /* Index to functions. */ -/* Put in the device structure. */ -int ei_open(struct device *dev); -/* Dispatch from interrupts. */ -void ei_interrupt(int reg_ptr); +int ei_open(struct device *dev); /* Put into the device structure. */ +void ei_interrupt(int reg_ptr); /* Installed as the interrupt handler. */ + static void ei_tx_intr(struct device *dev); static void ei_receive(struct device *dev); static void ei_rx_overrun(struct device *dev); @@ -107,7 +117,7 @@ int ei_open(struct device *dev) if ( ! ei_local) { printk("%s: Opening a non-existent physical device\n", dev->name); - return 1; /* ENXIO would be more accurate. */ + return ENXIO; } irq2dev_map[dev->irq] = dev; @@ -128,31 +138,36 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int length, send_length; - int tmp_tbusy; /* we must lock dev_tint in dev.c with dev->t_busy =1 */ - /* because on a slow pc a quasi endless loop can appear */ + /* We normally shouldn't be called if dev->tbusy is set, but the + existing code does anyway. + If it has been too long (> 100 or 150ms.) since the last Tx we assume + the board has died and kick it. */ + if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */ int txsr = inb(e8390_base+EN0_TSR), isr; int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) { + if (tickssofar < 10 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) { return 1; } isr = inb(e8390_base+EN0_ISR); printk("%s: transmit timed out, TX status %#2x, ISR %#2x.\n", dev->name, txsr, isr); - /* It's possible to check for an IRQ conflict here. - I may have to do that someday. */ + /* Does the 8390 thinks it has posted an interrupt? */ if (isr) - printk("%s: Possible IRQ conflict on IRQ%d?", dev->name, dev->irq); - else + printk("%s: Possible IRQ conflict on IRQ%d?\n", dev->name, dev->irq); + else { + /* The 8390 probably hasn't gotten on the cable yet. */ printk("%s: Possible network cable problem?\n", dev->name); - /* It futile, but try to restart it anyway. */ + ei_local->interface_num ^= 1; /* Try a different xcvr. */ + } + /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); NS8390_init(dev, 1); - printk("\n"); + dev->trans_start = jiffies; } - /* This is new: it means some higher layer thinks we've missed an + /* Sending a NULL skb means some higher layer thinks we've missed an tx-done interrupt. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) { @@ -167,28 +182,22 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) } skb->arp=1; + length = skb->len; if (skb->len <= 0) return 0; - length = skb->len; - send_length = ETH_ZLEN < length ? length : ETH_ZLEN; - /* Turn off interrupts so that we can put the packet out safely. */ - cli(); - if (dev->interrupt || ei_local->irqlock) { - /* We should never get here during an interrupt after 0.99.4. */ - sti(); - if (ei_debug > 2) - printk("%s: Attempt to reenter critical zone%s.\n", - dev->name, ei_local->irqlock ? " during interrupt" : ""); + + /* Block a timer-based transmit from overlapping. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); return 1; - } + } + /* Mask interrupts from the ethercard. */ outb(0x00, e8390_base + EN0_IMR); - - /* Atomically lock out dev.c:dev_tint(). */ - tmp_tbusy = set_bit(0, (void*)&dev->tbusy); - ei_local->irqlock = 1; - sti(); + + send_length = ETH_ZLEN < length ? length : ETH_ZLEN; + if (ei_local->pingpong) { int output_page; if (ei_local->tx1 == 0) { @@ -205,23 +214,19 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing); - } else { - /* We can get to here if we get an rx interrupt and queued - a tx packet just before masking 8390 irqs above. */ - if (ei_debug > 2) + } else { /* We should never get here. */ + if (ei_debug) printk("%s: No packet buffer space for ping-pong use.\n", dev->name); - cli(); ei_local->irqlock = 0; - dev->tbusy = tmp_tbusy; + dev->tbusy = 1; outb_p(ENISR_ALL, e8390_base + EN0_IMR); - sti(); return 1; } - dev->trans_start = jiffies; ei_block_output(dev, length, skb->data, output_page); if (! ei_local->txing) { NS8390_trigger_send(dev, send_length, output_page); + dev->trans_start = jiffies; if (output_page == ei_local->tx_start_page) ei_local->tx1 = -1, ei_local->lasttx = -1; else @@ -229,25 +234,22 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) ei_local->txing = 1; } else ei_local->txqueue++; - if (ei_local->tx1 && ei_local->tx2) - tmp_tbusy = 1; - } else { - dev->trans_start = jiffies; - ei_block_output(dev, length, skb->data, - ei_local->tx_start_page); + + dev->tbusy = (ei_local->tx1 && ei_local->tx2); + } else { /* No pingpong, just a single Tx buffer. */ + ei_block_output(dev, length, skb->data, ei_local->tx_start_page); NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); - tmp_tbusy = 1; - } /* PINGPONG */ + dev->trans_start = jiffies; + dev->tbusy = 1; + } + /* Turn 8390 interrupts back on. */ + ei_local->irqlock = 0; + outb_p(ENISR_ALL, e8390_base + EN0_IMR); + if (skb->free) kfree_skb (skb, FREE_WRITE); - /* Turn 8390 interrupts back on. */ - cli(); - outb_p(ENISR_ALL, e8390_base + EN0_IMR); - ei_local->irqlock = 0; - dev->tbusy=tmp_tbusy; - sti(); return 0; } @@ -289,7 +291,7 @@ void ei_interrupt(int reg_ptr) /* !!Assumption!! -- we stay in page 0. Don't break this. */ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 - && ++boguscount < 20) { + && ++boguscount < 5) { if (interrupts & ENISR_RDC) { /* Ack meaningless DMA complete. */ outb_p(ENISR_RDC, e8390_base + EN0_ISR); @@ -374,24 +376,19 @@ static void ei_tx_intr(struct device *dev) ei_local->txing = 0; dev->tbusy = 0; } - - /* Do the statistics _after_ we start the next TX. */ + + /* Minimize Tx latency: update the statistics after we restart TXing. */ + if (status & ENTSR_COL) ei_local->stat.collisions++; if (status & ENTSR_PTX) ei_local->stat.tx_packets++; - else + else { ei_local->stat.tx_errors++; - if (status & ENTSR_COL) - ei_local->stat.collisions++; - if (status & ENTSR_ABT) - ei_local->stat.tx_aborted_errors++; - if (status & ENTSR_CRS) - ei_local->stat.tx_carrier_errors++; - if (status & ENTSR_FU) - ei_local->stat.tx_fifo_errors++; - if (status & ENTSR_CDH) - ei_local->stat.tx_heartbeat_errors++; - if (status & ENTSR_OWC) - ei_local->stat.tx_window_errors++; + if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++; + if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++; + if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++; + if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++; + if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++; + } mark_bh (INET_BH); } @@ -403,11 +400,11 @@ static void ei_receive(struct device *dev) int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv; int rxing_page, this_frame, next_frame, current_offset; - int boguscount = 0; + int rx_pkt_count = 0; struct e8390_pkt_hdr rx_frame; int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page; - while (++boguscount < 10) { + while (++rx_pkt_count < 10) { int pkt_len; /* Get the rx page (incoming packet pointer). */ @@ -420,8 +417,9 @@ static void ei_receive(struct device *dev) if (this_frame >= ei_local->stop_page) this_frame = ei_local->rx_start_page; - /* Someday we'll omit the previous step, iff we never get this message.*/ - if (ei_debug > 0 && this_frame != ei_local->current_page) + /* Someday we'll omit the previous, iff we never get this message. + (There is at least one clone claimed to have a problem.) */ + if (ei_debug > 0 && this_frame != ei_local->current_page) printk("%s: mismatched read page pointers %2x vs %2x.\n", dev->name, this_frame, ei_local->current_page); @@ -439,46 +437,23 @@ static void ei_receive(struct device *dev) /* Check for bogosity warned by 3c503 book: the status byte is never written. This happened a lot during testing! This code should be cleaned up someday. */ - if ( rx_frame.next != next_frame + if (rx_frame.next != next_frame && rx_frame.next != next_frame + 1 && rx_frame.next != next_frame - num_rx_pages && rx_frame.next != next_frame + 1 - num_rx_pages) { -#ifndef EI_DEBUG ei_local->current_page = rxing_page; outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); + ei_local->stat.rx_errors++; continue; -#else - static int last_rx_bogosity = -1; - printk("%s: bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n", - dev->name, rx_frame.status, rx_frame.next, rx_frame.count, - current_offset); - - if (ei_local->stat.rx_packets != last_rx_bogosity) { - /* Maybe we can avoid resetting the chip... empty the packet ring. */ - ei_local->current_page = rxing_page; - printk("%s: setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n", - dev->name, ei_local->current_page, next_frame, - rx_frame.next, rx_frame.status); - last_rx_bogosity = ei_local->stat.rx_packets; - outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); - continue; - } else { - /* Oh no Mr Bill! Last ditch error recovery. */ - printk("%s: recovery failed, resetting at packet #%d..", - dev->name, ei_local->stat.rx_packets); - sti(); - ei_reset_8390(dev); - NS8390_init(dev, 1); - printk("restarting.\n"); - return; - } -#endif /* EI8390_NOCHECK */ } - - if ((pkt_len < 46 || pkt_len > 1535) && ei_debug) - printk("%s: bogus packet size, status=%#2x nxpg=%#2x size=%#x\n", - dev->name, rx_frame.status, rx_frame.next, rx_frame.count); - if ((rx_frame.status & 0x0F) == ENRSR_RXOK) { + + if (pkt_len < 60 || pkt_len > 1518) { + if (ei_debug) + printk("%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n", + dev->name, rx_frame.count, rx_frame.status, + rx_frame.next); + ei_local->stat.rx_errors++; + } else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) { int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; @@ -495,44 +470,39 @@ static void ei_receive(struct device *dev) skb->len = pkt_len; skb->dev = dev; - /* 'skb->data' points to the start of sk_buff data area. */ ei_block_input(dev, pkt_len, (char *) skb->data, current_offset + sizeof(rx_frame)); -#ifdef HAVE_NETIF_RX netif_rx(skb); -#else - skb->lock = 0; - if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev)) { - kfree_skbmem(skb, sksize); - lp->stats.rx_dropped++; - break; - } -#endif ei_local->stat.rx_packets++; } } else { int errs = rx_frame.status; if (ei_debug) - printk("%s: bogus packet, status=%#2x nxpg=%#2x size=%d\n", - dev->name, rx_frame.status, rx_frame.next, rx_frame.count); + printk("%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n", + dev->name, rx_frame.status, rx_frame.next, + rx_frame.count); if (errs & ENRSR_FO) ei_local->stat.rx_fifo_errors++; } next_frame = rx_frame.next; - /* This should never happen, it's here for debugging. */ + /* This _should_ never happen: it's here for avoiding bad clones. */ if (next_frame >= ei_local->stop_page) { - printk("%s: next frame inconsistency, %#2x..", dev->name, next_frame); + printk("%s: next frame inconsistency, %#2x..", dev->name, + next_frame); next_frame = ei_local->rx_start_page; } - ei_local->current_page += 1 + ((pkt_len+4)>>8); ei_local->current_page = next_frame; outb(next_frame-1, e8390_base+EN0_BOUNDARY); } /* If any worth-while packets have been received, dev_rint() has done a mark_bh(INET_BH) for us and will work on them when we get to the bottom-half routine. */ - + + /* Record the maximum Rx packet queue. */ + if (rx_pkt_count > high_water_mark) + high_water_mark = rx_pkt_count; + /* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */ outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR); return; @@ -553,19 +523,20 @@ static void ei_rx_overrun(struct device *dev) printk("%s: Receiver overrun.\n", dev->name); ei_local->stat.rx_over_errors++; - /* The we.c driver does dummy = inb_p( RBCR[01] ); at this point. + /* The old Biro driver does dummy = inb_p( RBCR[01] ); at this point. It might mean something -- magic to speed up a reset? A 8390 bug?*/ - /* Wait for reset in case the NIC is doing a tx or rx. This could take up to - 1.5msec, but we have no way of timing something in that range. The 'jiffies' - are just a sanity check. */ + /* Wait for the reset to complete. This should happen almost instantly, + but could take up to 1.5msec in certain rare instances. There is no + easy way of timing something in that range, so we use 'jiffies' as + a sanity check. */ while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0) if (jiffies - reset_start_time > 1) { printk("%s: reset did not complete at ei_rx_overrun.\n", dev->name); NS8390_init(dev, 1); return; - }; + } /* Remove packets right away. */ ei_receive(dev); @@ -751,6 +722,7 @@ static void NS8390_trigger_send(struct device *dev, unsigned int length, * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 8390.c" * version-control: t * kept-new-versions: 5 + * c-indent-level: 4 * tab-width: 4 * End: */ diff --git a/drivers/net/Space.c b/drivers/net/Space.c index fc70286..dd53835 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -145,8 +145,9 @@ static struct device atp_dev = { #ifndef ETH0_IRQ # define ETH0_IRQ 0 #endif -/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe". - Enable these with boot-time setup. 0.99pl13+ can optionally autoprobe. */ +/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20), + which means "don't probe". These entries exist to only to provide empty + slots which may be enabled at boot-time. */ static struct device eth3_dev = { "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index cfc5922..288693b 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -12,13 +12,16 @@ */ static char *version = - "at1700.c:v0.03 11/16/93 Donald Becker (becker@super.org)\n"; + "at1700.c:v0.05 2/9/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> /* Sources: The Fujitsu MB86695 datasheet. + + After this driver was written, ATI provided their EEPROM configuration + code header file. Thanks to Gerry Sockins of ATI. */ #include <linux/kernel.h> @@ -30,12 +33,12 @@ static char *version = #include <linux/ioport.h> #include <linux/in.h> #include <linux/malloc.h> +#include <linux/string.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> #include <errno.h> -#include <memory.h> #include "dev.h" #include "eth.h" @@ -142,24 +145,28 @@ at1700_probe(struct device *dev) for (port = &ports[0]; *port; port++) { int ioaddr = *port; -#ifdef HAVE_PORTRESERVE if (check_region(ioaddr, 32)) continue; -#endif - if (inw(ioaddr) != 0x0000) - continue; if (at1700_probe1(dev, ioaddr) == 0) return 0; } - return ENODEV; /* ENODEV would be more accurate. */ + return ENODEV; } +/* The Fujitsu datasheet suggests that the NIC be probed for by checking its + "signature", the default bit pattern after a reset. This *doesn't* work -- + there is no way to reset the bus interface without a complete power-cycle! + + It turns out that ATI came to the same conclusion I did: the only thing + that can be done is checking a few bits and then diving right into an + EEPROM read. */ + int at1700_probe1(struct device *dev, short ioaddr) { - unsigned short signature[4] = {0x0000, 0xffff, 0x41f6, 0xefb6}; - unsigned short signature_invalid[4] = {0x0000, 0xffff, 0x00f0, 0x2f00}; - char irqmap[4] = {3, 4, 5, 9}; + unsigned short signature[4] = {0xffff, 0xffff, 0x7ff7, 0xff5f}; + unsigned short signature_invalid[4] = {0xffff, 0xffff, 0x7ff7, 0xdf0f}; + char irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned short *station_address = (unsigned short *)dev->dev_addr; unsigned int i, irq; @@ -168,18 +175,21 @@ int at1700_probe1(struct device *dev, short ioaddr) */ for (i = 0; i < 4; i++) if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) { - if (net_debug > 1) + if (net_debug > 2) printk("AT1700 signature match failed at %d (%04x vs. %04x)\n", i, inw(ioaddr + 2*i), signature[i]); return -ENODEV; } -#ifdef HAVE_PORTRESERVE + if (read_eeprom(ioaddr, 4) != 0x0000 + || read_eeprom(ioaddr, 5) & 0x00ff != 0x00F4) + return -ENODEV; + /* Grab the region so that we can find another board if the IRQ request fails. */ snarf_region(ioaddr, 32); -#endif - irq = irqmap[ read_eeprom(ioaddr, 0) >> 14 ]; + irq = irqmap[(read_eeprom(ioaddr, 12)&0x04) + | (read_eeprom(ioaddr, 0)>>14)]; /* Snarf the interrupt vector now. */ if (request_irq(irq, &net_interrupt)) { @@ -402,7 +412,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) /* For ethernet, fill in the header. This should really be done by a higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + if (!skb->arp && dev->rebuild_header(skb+1, dev)) { skb->dev = dev; arp_queue (skb); return 0; @@ -415,7 +425,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; + unsigned char *buf = (void *)(skb+1); if (net_debug > 4) printk("%s: Transmitting a packet of length %d.\n", dev->name, @@ -551,14 +561,14 @@ net_rx(struct device *dev) skb->len = pkt_len; skb->dev = dev; - /* 'skb->data' points to the start of sk_buff data area. */ - insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1); + /* 'skb+1' points to the start of sk_buff data area. */ + insw(ioaddr + DATAPORT, (void *)(skb+1), (pkt_len + 1) >> 1); if (net_debug > 5) { int i; printk("%s: Rxed packet of length %d: ", dev->name, pkt_len); for (i = 0; i < 14; i++) - printk(" %02x", skb->data[i]); + printk(" %02x", ((unsigned char*)(skb + 1))[i]); printk(".\n"); } diff --git a/drivers/net/atp.c b/drivers/net/atp.c index d86dc82..e99d024 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -477,7 +477,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) /* For ethernet, fill in the header. This should really be done by a higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + if (!skb->arp && dev->rebuild_header(skb+1, dev)) { skb->dev = dev; arp_queue (skb); return 0; @@ -490,7 +490,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; + unsigned char *buf = (void *)(skb+1); int flags; /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. @@ -686,11 +686,11 @@ static void net_rx(struct device *dev) skb->len = pkt_len; skb->dev = dev; - /* 'skb->data' points to the start of sk_buff data area. */ - read_block(ioaddr, pkt_len, skb->data, dev->if_port); + /* 'skb+1' points to the start of sk_buff data area. */ + read_block(ioaddr, pkt_len, (unsigned char *)(skb + 1), dev->if_port); if (net_debug > 6) { - unsigned char *data = skb->data; + unsigned char *data = (unsigned char *)(skb + 1); printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..", data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index dff4238..d658e50 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -19,7 +19,7 @@ */ static char *version = - "eexpress.c:v0.06 10/27/93 Donald Becker (becker@super.org)\n"; + "eexpress.c:v0.07 1/19/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> @@ -154,7 +154,7 @@ struct net_local { #define ASIC_RESET 0x40 #define _586_RESET 0x80 -/* Offsets into the System Control Block structure. */ +/* Offsets to elements of the System Control Block structure. */ #define SCB_STATUS 0xc008 #define SCB_CMD 0xc00A #define CUC_START 0x0100 @@ -175,8 +175,8 @@ struct net_local { program space than initializing the individual tables, and I feel it's much cleaner. - The databook is particularly useless for the first two structures, I had - to use the Crynwr driver as an example. + The databook is particularly useless for the first two structures; they are + completely undocumented. I had to use the Crynwr driver as an example. The memory setup is as follows: */ @@ -194,17 +194,18 @@ struct net_local { #define TX_BUF_START 0x0100 #define NUM_TX_BUFS 4 -#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */ +#define TX_BUF_SIZE 0x0680 /* packet+header+TBD+extra (1518+14+20+16) */ +#define TX_BUF_END 0x2000 #define RX_BUF_START 0x2000 #define RX_BUF_SIZE (0x640) /* packet+header+RBD+extra */ -#define RX_BUF_END 0x8000 +#define RX_BUF_END 0x4000 /* That's it: only 86 bytes to set up the beast, including every extra command available. The 170 byte buffer at DUMP_DATA is shared between the Dump command (called only by the diagnostic program) and the SetMulticastList - command. + command. To complete the memory setup you only have to write the station address at SA_OFFSET and create the Tx & Rx buffer lists. @@ -326,6 +327,7 @@ express_probe(struct device *dev) #ifdef notdef for (i = 16; i > 0; i--) sum += inb(id_addr); + printk("EtherExpress ID checksum is %04x.\n", sum); #else for (i = 4; i > 0; i--) { short id_val = inb(id_addr); @@ -353,7 +355,7 @@ int eexp_probe1(struct device *dev, short ioaddr) station_addr[1] = read_eeprom(ioaddr, 3); station_addr[2] = read_eeprom(ioaddr, 4); - /* Check the first three octets of the S.A. for the manufactor's code. */ + /* Check the first three octets of the S.A. for the manufactor's code. */ if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) { printk(" rejected (invalid address %04x%04x%04x).\n", station_addr[2], station_addr[1], station_addr[0]); @@ -511,7 +513,7 @@ eexp_send_packet(struct sk_buff *skb, struct device *dev) /* For ethernet, fill in the header. This should really be done by a higher level, rather than duplicated for each ethernet adaptor. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + if (!skb->arp && dev->rebuild_header(skb+1, dev)) { skb->dev = dev; arp_queue (skb); return 0; @@ -523,7 +525,7 @@ eexp_send_packet(struct sk_buff *skb, struct device *dev) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; + unsigned char *buf = (void *)(skb+1); /* Disable the 82586's input to the interrupt line. */ outb(irqrmap[dev->irq], ioaddr + SET_IRQ); @@ -551,8 +553,8 @@ eexp_interrupt(int reg_ptr) struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; int ioaddr, status, boguscount = 0; - short ack_cmd = 0; - + short ack_cmd; + if (dev == NULL) { printk ("net_interrupt(): irq %d for unknown device.\n", irq); return; @@ -595,7 +597,7 @@ eexp_interrupt(int reg_ptr) if (net_debug > 5) printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status); lp->tx_reap += TX_BUF_SIZE; - if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE) + if (lp->tx_reap > TX_BUF_END - TX_BUF_SIZE) lp->tx_reap = TX_BUF_START; if (++boguscount > 4) break; @@ -611,22 +613,43 @@ eexp_interrupt(int reg_ptr) ack_cmd = status & 0xf000; if ((status & 0x0700) != 0x0200 && dev->start) { - if (net_debug) + short saved_write_ptr = inw(ioaddr + WRITE_PTR); + if (net_debug > 1) printk("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); - /* If this ever occurs we should really re-write the idle loop, reset - the Tx list, and do a complete restart of the command unit. - For now we rely on the Tx timeout if the resume doesn't work. */ - ack_cmd |= CUC_RESUME; + /* If this ever occurs we must re-write the idle loop, reset + the Tx list, and do a complete restart of the command unit. */ + outw(IDLELOOP, ioaddr + WRITE_PTR); + outw(0, ioaddr); + outw(CmdNOp, ioaddr); + outw(IDLELOOP, ioaddr); + outw(IDLELOOP, SCB_CBL); + lp->tx_cmd_link = IDLELOOP + 4; + lp->tx_head = lp->tx_reap = TX_BUF_START; + /* Restore the saved write pointer. */ + outw(saved_write_ptr, ioaddr + WRITE_PTR); + ack_cmd |= CUC_START; } if ((status & 0x0070) != 0x0040 && dev->start) { short saved_write_ptr = inw(ioaddr + WRITE_PTR); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ - if (net_debug) - printk("%s: Rx unit stopped, status %04x, restarting.\n", - dev->name, status); + lp->stats.rx_errors++; + if (net_debug > 1) { + int cur_rxbuf = RX_BUF_START; + printk("%s: Rx unit stopped status %04x rx head %04x tail %04x.\n", + dev->name, status, lp->rx_head, lp->rx_tail); + while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE) { + int i; + printk(" Rx buf at %04x:", cur_rxbuf); + outw(cur_rxbuf, ioaddr + READ_PTR); + for (i = 0; i < 0x20; i += 2) + printk(" %04x", inw(ioaddr)); + printk(".\n"); + cur_rxbuf += RX_BUF_SIZE; + } + } init_rx_bufs(dev); outw(RX_BUF_START, SCB_RFA); outw(saved_write_ptr, ioaddr + WRITE_PTR); @@ -813,8 +836,7 @@ init_82586_mem(struct device *dev) } /* Initialize the Rx-block list. */ -static void -init_rx_bufs(struct device *dev) +static void init_rx_bufs(struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; @@ -828,14 +850,14 @@ init_rx_bufs(struct device *dev) outw(0x0000, ioaddr); /* Command */ outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */ outw(cur_rxbuf + 22, ioaddr); /* Buffer offset */ - outw(0x0000, ioaddr); /* Pad for dest addr. */ - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); /* Pad for source addr. */ - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); - outw(0x0000, ioaddr); /* Pad for protocol. */ - + outw(0xFeed, ioaddr); /* Pad for dest addr. */ + outw(0xF00d, ioaddr); + outw(0xF001, ioaddr); + outw(0x0505, ioaddr); /* Pad for source addr. */ + outw(0x2424, ioaddr); + outw(0x6565, ioaddr); + outw(0xdeaf, ioaddr); /* Pad for protocol. */ + outw(0x0000, ioaddr); /* Buffer: Actual count */ outw(-1, ioaddr); /* Buffer: Next (none). */ outw(cur_rxbuf + 0x20, ioaddr); /* Buffer: Address low */ @@ -890,7 +912,7 @@ hardware_send_packet(struct device *dev, void *buf, short length) /* Set the next free tx region. */ lp->tx_head = tx_block + TX_BUF_SIZE; - if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE) + if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE) lp->tx_head = TX_BUF_START; if (net_debug > 4) { @@ -960,7 +982,7 @@ eexp_rx(struct device *dev) outw(data_buffer_addr + 10, ioaddr + READ_PTR); - insw(ioaddr, skb->data, (pkt_len + 1) >> 1); + insw(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1); #ifdef HAVE_NETIF_RX netif_rx(skb); @@ -985,7 +1007,7 @@ eexp_rx(struct device *dev) printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name, rx_head, next_rx_frame, rx_head + RX_BUF_SIZE); next_rx_frame = rx_head + RX_BUF_SIZE; - if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) + if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) next_rx_frame = RX_BUF_START; } #endif diff --git a/drivers/net/hp.c b/drivers/net/hp.c index eda01d1..68e4823 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -13,7 +13,7 @@ */ static char *version = - "hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n"; + "hp.c:v0.99.15c 2/11/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> #include <linux/kernel.h> @@ -56,7 +56,7 @@ static void hp_block_output(struct device *dev, int count, static void hp_init_card(struct device *dev); /* The map from IRQ number to HP_CONFIGURE register setting. */ -/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */ +/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */ static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0}; @@ -86,22 +86,17 @@ int hp_probe(struct device *dev) int hpprobe1(struct device *dev, int ioaddr) { - int status, i, board_id, wordmode; + int i, board_id, wordmode; char *name; unsigned char *station_addr = dev->dev_addr; /* Check for the HP physical address, 08 00 09 xx xx xx. */ + /* This really isn't good enough: we may pick up HP LANCE boards + also! Avoid the lance 0x5757 signature. */ if (inb(ioaddr) != 0x08 || inb(ioaddr+1) != 0x00 - || inb(ioaddr+2) != 0x09) - return ENODEV; - - /* This really isn't good enough, we may pick up HP LANCE boards also! */ - /* Verify that there is a 8390 at the expected location. */ - outb(E8390_NODMA + E8390_STOP, ioaddr); - SLOW_DOWN_IO; - status = inb(ioaddr); - if (status != 0x21 && status != 0x23) + || inb(ioaddr+2) != 0x09 + || inb(ioaddr+14) == 0x57) return ENODEV; /* Set up the parameters based on the board ID. @@ -320,9 +315,10 @@ hp_init_card(struct device *dev) /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * c-indent-level: 4 * End: */ diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 1d610e8..4eac67b 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -205,7 +205,7 @@ struct lance_private { int pad0, pad1; /* Used for alignment */ }; -static unsigned long lance_probe1(short ioaddr, unsigned long mem_start); +unsigned long lance_probe1(short ioaddr, unsigned long mem_start); 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); @@ -236,7 +236,7 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end) return mem_start; } -static unsigned long lance_probe1(short ioaddr, unsigned long mem_start) +unsigned long lance_probe1(short ioaddr, unsigned long mem_start) { struct device *dev; struct lance_private *lp; @@ -512,7 +512,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) } /* Fill in the ethernet header. */ - if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + if (!skb->arp && dev->rebuild_header(skb+1, dev)) { skb->dev = dev; arp_queue (skb); return 0; @@ -553,11 +553,11 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) /* If any part of this buffer is >16M we must copy it to a low-memory buffer. */ - if ((int)(skb->data) + skb->len > 0x01000000) { + if ((int)(skb+1) + skb->len > 0x01000000) { if (lance_debug > 5) printk("%s: bouncing a high-memory packet (%#x).\n", - dev->name, (int)skb->data); - memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); + dev->name, (int)(skb+1)); + memcpy(&lp->tx_bounce_buffs[entry], skb+1, skb->len); lp->tx_ring[entry].base = (int)(lp->tx_bounce_buffs + entry) | 0x83000000; if (skb->free) @@ -567,7 +567,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev) /* Gimme!!! */ if(skb->free==0) skb_kept_by_device(skb); - lp->tx_ring[entry].base = (int)skb->data | 0x83000000; + lp->tx_ring[entry].base = (int)(skb+1) | 0x83000000; } lp->cur_tx++; @@ -638,11 +638,12 @@ lance_interrupt(int reg_ptr) if (err_status & 0x0800) lp->stats.tx_carrier_errors++; if (err_status & 0x1000) lp->stats.tx_window_errors++; if (err_status & 0x4000) lp->stats.tx_fifo_errors++; - /* We should re-init() after the FIFO error. */ - } else if (status & 0x18000000) - lp->stats.collisions++; - else + /* Perhaps we should re-init() after the FIFO error. */ + } else { + if (status & 0x18000000) + lp->stats.collisions++; lp->stats.tx_packets++; + } /* We don't free the skb if it's a data-only copy in the bounce buffer. The address checks here are sorted -- the first test @@ -726,7 +727,7 @@ lance_rx(struct device *dev) skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; - memcpy(skb->data, + memcpy((unsigned char *) (skb + 1), (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), pkt_len); #ifdef HAVE_NETIF_RX @@ -836,6 +837,12 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs) outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */ } #endif + +#ifdef HAVE_DEVLIST +static unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0}; +struct netdev_entry lance_drv = +{"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist}; +#endif /* * Local variables: diff --git a/drivers/net/ne.c b/drivers/net/ne.c index e198d55..a69754a 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -17,7 +17,7 @@ /* Routines for the NatSemi-based designs (NE[12]000). */ static char *version = - "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n"; + "ne.c:v0.99-15b 2/8/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> #include <linux/kernel.h> @@ -155,11 +155,11 @@ static int neprobe1(int ioaddr, struct device *dev, int verbose) } if (wordlength == 2) { - /* We must set the 8390 for word mode, AND RESET IT. */ + /* We must set the 8390 for word mode. */ int tmp; outb_p(0x49, ioaddr + EN0_DCFG); - tmp = inb_p(NE_BASE + NE_RESET); - outb(tmp, NE_BASE + NE_RESET); + /* We used to reset the ethercard here, but it doesn't seem + to be necessary. */ /* Un-double the SA_prom values. */ for (i = 0; i < 16; i++) SA_prom[i] = SA_prom[i+i]; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index dc6cf50..18c506b 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -523,7 +523,6 @@ sl_xmit(struct sk_buff *skb, struct device *dev) { struct tty_struct *tty; struct slip *sl; - int size; /* Find the correct SLIP channel to use. */ diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 5816b83..07dc5ce 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -14,7 +14,7 @@ */ static char *version = - "smc-ultra.c:v0.05 12/21/93 Donald Becker (becker@super.org)\n"; + "smc-ultra.c:v0.06 2/9/94 Donald Becker (becker@super.org)\n"; #include <linux/config.h> #include <linux/kernel.h> @@ -139,7 +139,7 @@ int ultraprobe1(int ioaddr, struct device *dev) dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; { - int addr_tbl[4] = {0x0C0000, 0x0D0000, 0xFC0000, 0xFD0000}; + int addr_tbl[4] = {0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000}; short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff}; dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 23d9abe..7663b41 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -13,6 +13,7 @@ #include <linux/fcntl.h> #include <linux/ptrace.h> #include <linux/malloc.h> +#include <linux/shm.h> #include <asm/segment.h> @@ -21,6 +22,8 @@ asmlinkage int sys_close(unsigned fd); asmlinkage int sys_open(const char *, int, int); asmlinkage int sys_brk(unsigned long); +#define DLINFO_ITEMS 8 + #include <linux/elf.h> /* We need to explicitly zero any fractional pages @@ -43,17 +46,220 @@ static void padzero(int elf_bss){ }; } +unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs) +{ + unsigned long *argv,*envp, *dlinfo; + unsigned long * sp; + struct vm_area_struct *mpnt; + + mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); + if (mpnt) { + mpnt->vm_task = current; + mpnt->vm_start = PAGE_MASK & (unsigned long) p; + mpnt->vm_end = TASK_SIZE; + mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY; + mpnt->vm_share = NULL; + mpnt->vm_inode = NULL; + mpnt->vm_offset = 0; + mpnt->vm_ops = NULL; + insert_vm_struct(current, mpnt); + current->stk_vma = mpnt; + } + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + if(exec) sp -= DLINFO_ITEMS*2; + dlinfo = sp; + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + if (!ibcs) { + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + } + + /* The constant numbers (0-9) that we are writing here are + described in the header file sys/auxv.h on at least + some versions of SVr4 */ + if(exec) { /* Put this here for an ELF program interpreter */ + struct elf_phdr * eppnt; + eppnt = (struct elf_phdr *) exec->e_phoff; + put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++); + put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++); + put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++); + put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++); + put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++); + put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++); + put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++); + put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++); + }; + + put_fs_long((unsigned long)argc,--sp); + current->arg_start = (unsigned long) p; + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + current->arg_end = current->env_start = (unsigned long) p; + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + current->env_end = (unsigned long) p; + return sp; +} + + +/* This is much more generalized than the library routine read function, + so we keep this separate. Techincally the library read function + is only provided so that we can read a.out libraries that have + an ELF header */ + +static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex, + struct inode * interpreter_inode) +{ + struct file * file; + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + unsigned int len; + unsigned int load_addr; + int elf_exec_fileno; + int elf_bss; + int old_fs, retval; + unsigned int last_bss; + int error; + int i, k; + + elf_bss = 0; + last_bss = 0; + error = load_addr = 0; + + /* First of all, some simple consistency checks */ + if((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) || + (!interpreter_inode->i_op || !interpreter_inode->i_op->bmap || + !interpreter_inode->i_op->default_file_ops->mmap)){ + return 0xffffffff; + }; + + /* Now read in all of the header information */ + + if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) + return 0xffffffff; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); + if(!elf_phdata) return 0xffffffff; + + old_fs = get_fs(); + set_fs(get_ds()); + retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + set_fs(old_fs); + + elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); + if (elf_exec_fileno < 0) return 0xffffffff; + file = current->filp[elf_exec_fileno]; + + eppnt = elf_phdata; + for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) + if(eppnt->p_type == PT_LOAD) { + error = do_mmap(file, + eppnt->p_vaddr & 0xfffff000, + eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0), + eppnt->p_offset & 0xfffff000); + + if(!load_addr && interp_elf_ex->e_type == ET_DYN) + load_addr = error; + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if(k > elf_bss) elf_bss = k; + if(error < 0 && error > -1024) break; /* Real error */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if(k > last_bss) last_bss = k; + } + + /* Now use mmap to map the library into memory. */ + + + sys_close(elf_exec_fileno); + if(error < 0 && error > -1024) { + kfree(elf_phdata); + return 0xffffffff; + } + + padzero(elf_bss); + len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > len) + do_mmap(NULL, len, last_bss-len, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + kfree(elf_phdata); + + return ((unsigned int) interp_elf_ex->e_entry) + load_addr; +} + +static unsigned int load_aout_interp(struct exec * interp_ex, + struct inode * interpreter_inode) +{ + int retval; + unsigned int elf_entry; + + current->brk = interp_ex->a_bss + + (current->end_data = interp_ex->a_data + + (current->end_code = interp_ex->a_text)); + elf_entry = interp_ex->a_entry; + + + if (N_MAGIC(*interp_ex) == OMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, 32, (char *) 0, + interp_ex->a_text+interp_ex->a_data); + } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { + do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + retval = read_exec(interpreter_inode, + N_TXTOFF(*interp_ex) , + (char *) N_TXTADDR(*interp_ex), + interp_ex->a_text+interp_ex->a_data); + } else + retval = -1; + + if(retval >= 0) + do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & + 0xfffff000, interp_ex->a_bss, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + if(retval < 0) return 0xffffffff; + return elf_entry; +} + /* * These are the functions used to load ELF style executables and shared * libraries. There is no binary dependent code anywhere else. */ +#define INTERPRETER_NONE 0 +#define INTERPRETER_AOUT 1 +#define INTERPRETER_ELF 2 + int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) { struct elfhdr elf_ex; + struct elfhdr interp_elf_ex; struct file * file; - struct exec ex; + struct exec interp_ex; struct inode *interpreter_inode; + unsigned int load_addr; + unsigned int interpreter_type = INTERPRETER_NONE; int i; int old_fs; int error; @@ -69,6 +275,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) char passed_fileno[6]; status = 0; + load_addr = 0; elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ if (elf_ex.e_ident[0] != 0x7f || @@ -141,11 +348,14 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) retval = read_exec(interpreter_inode,0,bprm->buf,128); if(retval >= 0){ - ex = *((struct exec *) bprm->buf); /* exec-header */ + interp_ex = *((struct exec *) bprm->buf); /* exec-header */ + interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ -#if 0 - printk("Interpreter: %x %x %x\n",N_MAGIC(ex), ex.a_text,ex.a_data); -#endif + }; + if(retval < 0) { + kfree (elf_phdata); + kfree(elf_interpreter); + return retval; }; }; elf_ppnt++; @@ -155,16 +365,28 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) /* Some simple consistency checks for the interpreter */ if(elf_interpreter){ + interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; if(retval < 0) { kfree(elf_interpreter); kfree(elf_phdata); return -ELIBACC; }; - if((N_MAGIC(ex) != OMAGIC) && (N_MAGIC(ex) != ZMAGIC)) { - kfree(elf_interpreter); - kfree(elf_phdata); - return -ELIBBAD; - }; + /* Now figure out which format our binary is */ + if((N_MAGIC(interp_ex) != OMAGIC) && + (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) + interpreter_type = INTERPRETER_ELF; + + if (interp_elf_ex.e_ident[0] != 0x7f || + strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) + interpreter_type &= ~INTERPRETER_ELF; + + if(!interpreter_type) + { + kfree(elf_interpreter); + kfree(elf_phdata); + return -ELIBBAD; + }; } /* OK, we are done with that, now set up the arg stuff, @@ -173,12 +395,14 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (!bprm->sh_bang) { char * passed_p; - sprintf(passed_fileno, "%d", elf_exec_fileno); - passed_p = passed_fileno; + if(interpreter_type == INTERPRETER_AOUT) { + sprintf(passed_fileno, "%d", elf_exec_fileno); + passed_p = passed_fileno; - if(elf_interpreter) { - bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); - bprm->argc++; + if(elf_interpreter) { + bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); + bprm->argc++; + }; }; if (!bprm->p) { if(elf_interpreter) { @@ -217,49 +441,27 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if(elf_ppnt->p_type == PT_INTERP) { /* Set these up so that we are able to load the interpreter */ - current->brk = ex.a_bss + - (current->end_data = ex.a_data + - (current->end_code = ex.a_text)); - elf_entry = ex.a_entry; - - /* Now load the interpreter into user address space */ - set_fs(old_fs); - - if (N_MAGIC(ex) == OMAGIC) { - do_mmap(NULL, 0, ex.a_text+ex.a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, 32, (char *) 0, - ex.a_text+ex.a_data); - iput(interpreter_inode); - } else if (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC) { - do_mmap(NULL, 0, ex.a_text+ex.a_data, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, - N_TXTOFF(ex) , - (char *) N_TXTADDR(ex), - ex.a_text+ex.a_data); - iput(interpreter_inode); - } else - retval = -1; - - old_fs = get_fs(); - set_fs(get_ds()); - - if(retval >= 0) - do_mmap(NULL, (ex.a_text + ex.a_data + 0xfff) & - 0xfffff000, ex.a_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); + /* Now load the interpreter into user address space */ + set_fs(old_fs); - kfree(elf_interpreter); + if(interpreter_type & 1) elf_entry = + load_aout_interp(&interp_ex, interpreter_inode); + + if(interpreter_type & 2) elf_entry = + load_elf_interp(&interp_elf_ex, interpreter_inode); + + old_fs = get_fs(); + set_fs(get_ds()); + + iput(interpreter_inode); + kfree(elf_interpreter); - if(retval < 0) { - kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); - return 0; - }; + if(elf_entry == 0xffffffff) { + printk("Unable to load interpreter\n"); + kfree(elf_phdata); + send_sig(SIGSEGV, current, 0); + return 0; + }; }; @@ -276,6 +478,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) elf_stack = elf_ppnt->p_vaddr & 0xfffff000; #endif + if(!load_addr) + load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; k = elf_ppnt->p_vaddr; if(k > start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; @@ -285,14 +489,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if(end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; if(k > elf_brk) elf_brk = k; - - if(status == 0xffffffff) { - set_fs(old_fs); - kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); - return 0; - }; - }; + }; elf_ppnt++; }; set_fs(old_fs); @@ -307,8 +504,15 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->start_stack = p = elf_stack - 4; #endif bprm->p -= MAX_ARG_PAGES*PAGE_SIZE; - bprm->p = (unsigned long) create_tables((char *)bprm->p,bprm->argc,bprm->envc,0); - if(elf_interpreter) current->arg_start += strlen(passed_fileno) + 1; + bprm->p = (unsigned long) + create_elf_tables((char *)bprm->p, + bprm->argc, + bprm->envc, + (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL), + load_addr, + (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + if(interpreter_type == INTERPRETER_AOUT) + current->arg_start += strlen(passed_fileno) + 1; current->start_brk = current->brk = elf_brk; current->end_code = end_code; current->start_code = start_code; @@ -324,6 +528,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) padzero(elf_bss); + /* Why this, you ask??? Well SVr4 maps page 0 as read-only, + and some applications "depend" upon this behavior. + Since we do not have the power to recompile these, we + emulate the SVr4 behavior. Sigh. */ + error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, 0); + regs->eip = elf_entry; /* eip, magic happens :-) */ regs->esp = bprm->p; /* stack pointer */ if (current->flags & PF_PTRACED) @@ -331,8 +542,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) return 0; } -/* This is really simpleminded and specialized - we are loading an a.out library that is given - an ELF header */ +/* This is really simpleminded and specialized - we are loading an + a.out library that is given an ELF header. */ int load_elf_library(int fd){ struct file * file; diff --git a/fs/buffer.c b/fs/buffer.c index 17fc97c..1f63919 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -954,7 +954,9 @@ int shrink_buffers(unsigned int priority) bh = free_list; i = nr_buffers >> priority; for ( ; i-- > 0 ; bh = bh->b_next_free) { - if (bh->b_count) { + if (bh->b_count || + (priority >= 5 && + mem_map[MAP_NR((unsigned long) bh->b_data)] > 1)) { put_last_free(bh); continue; } diff --git a/fs/proc/array.c b/fs/proc/array.c index a513b9c..fdd92da 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -45,7 +45,7 @@ static int read_core(struct inode * inode, struct file * file,char * buf, int co if (p >= high_memory + PAGE_SIZE) return 0; if (count > high_memory + PAGE_SIZE - p) - count = high_memory - p; + count = high_memory + PAGE_SIZE - p; read = 0; if (p < sizeof(struct user) && count > 0) { diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 68d5330..4b10406 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -5,9 +5,10 @@ * * Global definitions for the Ethernet IEE 802.3 interface. * - * Version: @(#)if_ether.h 1.0.1 03/15/93 + * Version: @(#)if_ether.h 1.0.1a 02/08/94 * * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Donald Becker, <becker@super.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,12 +19,14 @@ #define _LINUX_IF_ETHER_H -/* IEEE 802.3 Ethernet magic constants. */ -#define ETH_ALEN 6 /* #bytes in eth addr */ -#define ETH_HLEN 14 /* #bytes in eth header */ -#define ETH_ZLEN 60 /* min #bytes in frame */ -#define ETH_FLEN 1536 /* max #bytes in frame */ -#define ETH_DLEN (ETH_FLEN - ETH_HLEN) /* max #bytes of data */ +/* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble + and FCS/CRC (frame check sequence). */ +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_HLEN 14 /* Total octets in header. */ +#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ +#define ETH_DATA_LEN 1500 /* Max. octets in payload */ +#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ + /* These are the defined Ethernet Protocol ID's. */ #define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ @@ -38,9 +41,6 @@ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ -/* Define the Ethernet Broadcast Address (48 bits set to "1"). */ -#define ETH_A_BCAST "\377\377\377\377\377\377" - /* This is an Ethernet frame header. */ struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ @@ -48,21 +48,6 @@ struct ethhdr { unsigned short h_proto; /* packet type ID field */ }; -/* This is the complete Ethernet frame. */ -struct ethframe { - struct ethhdr f_hdr; /* frame header */ - char f_data[ETH_DLEN]; /* frame data (variable)*/ -}; - - -/* Receiver modes */ -#define ETH_MODE_MONITOR 1 /* Monitor mode - no receive */ -#define ETH_MODE_PHYS 2 /* Physical address receive only */ -#define ETH_MODE_BCAST 3 /* Broadcast receive + mode 2 */ -#define ETH_MODE_MCAST 4 /* Multicast receive + mode 3 */ -#define ETH_MODE_PROMISC 5 /* Promiscuous mode - receive all */ - - /* Ethernet statistics collection data. */ struct enet_statistics{ int rx_packets; /* total packets received */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 49fdb90..793fef3 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -399,7 +399,7 @@ extern long tty_init(long); extern void flush_input(struct tty_struct * tty); extern void flush_output(struct tty_struct * tty); -extern void wait_until_sent(struct tty_struct * tty); +extern void wait_until_sent(struct tty_struct * tty, int timeout); extern int check_change(struct tty_struct * tty, int channel); extern void stop_tty(struct tty_struct * tty); extern void start_tty(struct tty_struct * tty); @@ -45,24 +45,19 @@ void ipc_init (void) * to ipc resources. return 0 if allowed */ int ipcperms (struct ipc_perm *ipcp, short flag) -{ - int i; mode_t perm; uid_t euid; int egid; - +{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ + int requested_mode, granted_mode; + if (suser()) return 0; - - perm = S_IRWXO; euid = current->euid; - - if (euid == ipcp->cuid || euid == ipcp->uid) - perm = S_IRWXU; - else { - for (i = 0; (egid = current->groups[i]) != NOGROUP; i++) - if ((egid == ipcp->cgid) || (egid == ipcp->gid)) { - perm = S_IRWXG; - break; - } - } - if (!(flag & perm) || flag & perm & ~ipcp->mode) + requested_mode = (flag >> 6) | (flag >> 3) | flag; + granted_mode = ipcp->mode; + if (current->euid == ipcp->cuid || current->euid == ipcp->uid) + granted_mode >>= 6; + else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) + granted_mode >>= 3; + /* is there some bit set in requested_mode but not in granted_mode? */ + if (requested_mode & ~granted_mode & 0007) return -1; return 0; } diff --git a/kernel/ksyms.sh b/kernel/ksyms.sh index d46f091..1a99ed5 100644 --- a/kernel/ksyms.sh +++ b/kernel/ksyms.sh @@ -10,7 +10,7 @@ # # -trap "rm -f ksyms.tmp ksyms.lst" 1 2 +trap "rm -f ksyms.tmp ksyms.lst ; exit 1" 1 2 sed -e '/^#/d' -e '/^[ ]*$/d' ksyms.lst | sort > ksyms.tmp diff --git a/kernel/traps.c b/kernel/traps.c index e0145cc..7321836 100644 --- a/kernel/traps.c +++ b/kernel/traps.c @@ -89,8 +89,8 @@ asmlinkage void alignment_check(void); printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); - printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", - regs->esi, regs->edi, regs->ebp, regs->esp); + printk("esi: %08lx edi: %08lx ebp: %08lx\n", + regs->esi, regs->edi, regs->ebp); printk("ds: %04x es: %04x fs: %04x gs: %04x\n", regs->ds, regs->es, regs->fs, regs->gs); store_TR(i); @@ -98,11 +98,6 @@ asmlinkage void alignment_check(void); for(i=0;i<20;i++) printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip))); printk("\n"); -#if 0 - for(i=0;i<5;i++) - printk("%08lx ", get_seg_long(regs->ss,(i+(unsigned long *)regs->esp))); - printk("\n"); -#endif do_exit(SIGSEGV); } diff --git a/net/inet/ip.c b/net/inet/ip.c index d95e4cd..c8954c4 100644 --- a/net/inet/ip.c +++ b/net/inet/ip.c @@ -34,6 +34,12 @@ * Alan Cox : Save IP header pointer for later * Alan Cox : ip option setting * Alan Cox : Use ip_tos/ip_ttl settings + * Alan Cox : Fragmentation bogosity removed + * (Thanks to Mark.Bush@prg.ox.ac.uk) + * Dmitry Gordchanin : Send of a raw packet crash fix. + * Alan Cox : Silly ip bug when an overlength + * fragment turns up. Now frees the + * queue. * * To Fix: * IP option processing is mostly not needed. ip_forward needs to know about routing rules @@ -785,6 +791,7 @@ static struct sk_buff *ip_glue(struct ipq *qp) if(count+fp->len>skb->len) { printk("Invalid fragment list: Fragment over size.\n"); + ip_free(qp); kfree_skb(skb,FREE_WRITE); return NULL; } @@ -970,7 +977,9 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct /* Point into the IP datagram header. */ raw = skb->data; iph = (struct iphdr *) (raw + dev->hard_header_len); - + + skb->ip_hdr = iph; + /* Setup starting values. */ hlen = (iph->ihl * sizeof(unsigned long)); left = ntohs(iph->tot_len) - hlen; @@ -1008,6 +1017,7 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct while(left > 0) { len = left; +#ifdef OLD if (len+8 > mtu) len = (dev->mtu - hlen - 8); if ((left - len) >= 8) @@ -1015,6 +1025,18 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct len /= 8; len *= 8; } +#else + /* IF: it doesn't fit, use 'mtu' - the data space left */ + if (len > mtu) + len = mtu; + /* IF: we are not sending upto and including the packet end + then align the next start on an eight byte boundary */ + if (len < left) + { + len/=8; + len*=8; + } +#endif DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n", len, len + hlen)); @@ -1368,6 +1390,7 @@ ip_queue_xmit(struct sock *sk, struct device *dev, ptr = skb->data; ptr += dev->hard_header_len; iph = (struct iphdr *)ptr; + skb->ip_hdr = iph; iph->tot_len = ntohs(skb->len-dev->hard_header_len); if(skb->len > dev->mtu) diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h index e976385..d3bcc09 100644 --- a/net/inet/skbuff.h +++ b/net/inet/skbuff.h @@ -72,8 +72,7 @@ struct sk_buff { volatile char acked, used, free, - arp, - urg_used; + arp; unsigned char tries,lock; /* Lock is now unused */ unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ unsigned long padding[0]; diff --git a/net/inet/sock.c b/net/inet/sock.c index c937071..45383b3 100644 --- a/net/inet/sock.c +++ b/net/inet/sock.c @@ -130,7 +130,7 @@ print_sk(struct sock *sk) printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout); printk(" cong_window = %d, packets_out = %d\n", sk->cong_window, sk->packets_out); - printk(" urg = %d shutdown=%d\n", sk->urg, sk->shutdown); + printk(" shutdown=%d\n", sk->shutdown); } @@ -842,6 +842,8 @@ inet_create(struct socket *sock, int protocol) sk->acked_seq = 0; sk->copied_seq = 0; sk->fin_seq = 0; + sk->urg_seq = 0; + sk->urg_data = 0; sk->proc = 0; sk->rtt = TCP_WRITE_TIME << 3; sk->rto = TCP_WRITE_TIME; @@ -859,7 +861,6 @@ inet_create(struct socket *sock, int protocol) sk->priority = 1; sk->shutdown = 0; - sk->urg = 0; sk->keepopen = 0; sk->zapped = 0; sk->done = 0; diff --git a/net/inet/sock.h b/net/inet/sock.h index 3fb08a9..d6dbb6a 100644 --- a/net/inet/sock.h +++ b/net/inet/sock.h @@ -61,6 +61,8 @@ struct sock { unsigned long rcv_ack_seq; unsigned long window_seq; unsigned long fin_seq; + unsigned long urg_seq; + unsigned long urg_data; /* * Not all are volatile, but some are, so we @@ -112,7 +114,6 @@ struct sock { volatile unsigned short cong_count; volatile unsigned short ssthresh; volatile unsigned short packets_out; - volatile unsigned short urg; volatile unsigned short shutdown; volatile unsigned long rtt; volatile unsigned long mdev; diff --git a/net/inet/tcp.c b/net/inet/tcp.c index 221111d..b57e1ed 100644 --- a/net/inet/tcp.c +++ b/net/inet/tcp.c @@ -340,10 +340,8 @@ tcp_readable(struct sock *sk) if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */ break; sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */ - if (skb->h.th->syn) sum++; - if (skb->h.th->urg) { - sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */ - } + if (skb->h.th->syn) + sum++; if (sum >= 0) { /* Add it up, move on */ amount += sum; if (skb->h.th->syn) amount--; @@ -352,6 +350,9 @@ tcp_readable(struct sock *sk) if (amount && skb->h.th->psh) break; skb =(struct sk_buff *)skb->next; /* Move along */ } while(skb != sk->rqueue); + if (sk->urg_data && + (sk->urg_seq - sk->copied_seq) < (counted - sk->copied_seq)) + amount--; /* don't count urg data */ restore_flags(flags); DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount)); if(sk->debug) @@ -485,20 +486,14 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) } case SIOCATMARK: { - struct sk_buff *skb; int answ = 0; /* * Try to figure out if we need to read * some urgent data. */ - sk->inuse = 1; - if ((skb=skb_peek(&sk->rqueue)) != NULL) - { - if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg) - answ = 1; - } - release_sock(sk); + if (sk->urg_data && sk->copied_seq+1 == sk->urg_seq) + answ = 1; err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(unsigned long)); if(err) @@ -1252,98 +1247,51 @@ static int tcp_read_urg(struct sock * sk, int nonblock, unsigned char *to, int len, unsigned flags) { - int copied = 0; - struct sk_buff *skb; + struct wait_queue wait = { current, NULL }; - DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n", - sk, to, len, flags)); + while (len > 0) { + if (sk->urg_data && sk->urg_data != URG_READ) { + char c = sk->urg_data; + if (!(flags & MSG_PEEK)) + sk->urg_data = URG_READ; + put_fs_byte(c, to); + return 1; + } - while(len > 0) - { - sk->inuse = 1; - while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL) { if (sk->err) { - int tmp; - - release_sock(sk); - if (copied) return(copied); - tmp = -sk->err; + int tmp = -sk->err; sk->err = 0; - return(tmp); + return tmp; } if (sk->state == TCP_CLOSE || sk->done) { - release_sock(sk); - if (copied) return(copied); if (!sk->done) { sk->done = 1; - return(0); + return 0; } - return(-ENOTCONN); - } - - if (sk->shutdown & RCV_SHUTDOWN) { - release_sock(sk); - if (copied == 0) - sk->done = 1; - return(copied); + return -ENOTCONN; } - if (nonblock || copied) { - release_sock(sk); - if (copied) return(copied); - return(-EAGAIN); + if (sk->shutdown & RCV_SHUTDOWN) { + sk->done = 1; + return 0; } - /* Now at this point, we may have gotten some data. */ - release_sock(sk); - cli(); - if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) && - sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) { - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) { - sti(); - if (copied) return(copied); - return(-ERESTARTSYS); - } - } - sk->inuse = 1; - sti(); - } + if (nonblock) + return -EAGAIN; - skb = skb_peek(&sk->rqueue); - do { - int amt; - - if (before(sk->copied_seq+1, skb->h.th->seq)) - break; - if (skb->h.th->urg && !skb->urg_used) { - if (skb->h.th->urg_ptr == 0) { - skb->h.th->urg_ptr = ntohs(skb->len); - } - amt = min(ntohs(skb->h.th->urg_ptr),len); - if(amt) - { - memcpy_tofs(to,(unsigned char *)(skb->h.th) + - skb->h.th->doff*4, amt); - } + if (current->signal & ~current->blocked) + return -ERESTARTSYS; - if (!(flags & MSG_PEEK)) { - skb->urg_used = 1; - sk->urg--; - } - cleanup_rbuf(sk); - release_sock(sk); - copied += amt; - return(copied); - } - skb =(struct sk_buff *)skb->next; - } while(skb != sk->rqueue); - } -/*sk->urg = 0;*/ - cleanup_rbuf(sk); - release_sock(sk); - return(0); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(sk->sleep, &wait); + if ((!sk->urg_data || sk->urg_data == URG_READ) && + sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) + schedule(); + remove_wait_queue(sk->sleep, &wait); + current->state = TASK_RUNNING; + } + return 0; } @@ -1352,31 +1300,31 @@ static int tcp_read(struct sock *sk, unsigned char *to, int len, int nonblock, unsigned flags) { - int copied=0; /* will be used to say how much has been copied. */ + int copied = 0; /* will be used to say how much has been copied. */ struct sk_buff *skb; unsigned long offset; - unsigned long used; int err; - if (len == 0) return(0); - if (len < 0) { - return(-EINVAL); - } + if (len == 0) + return 0; + + if (len < 0) + return -EINVAL; err=verify_area(VERIFY_WRITE,to,len); if(err) return err; /* This error should be checked. */ - if (sk->state == TCP_LISTEN) return(-ENOTCONN); + if (sk->state == TCP_LISTEN) + return -ENOTCONN; /* Urgent data needs to be handled specially. */ - if ((flags & MSG_OOB)) - return(tcp_read_urg(sk, nonblock, to, len, flags)); + if (flags & MSG_OOB) + return tcp_read_urg(sk, nonblock, to, len, flags); /* So no-one else will use this socket. */ sk->inuse = 1; - skb=skb_peek(&sk->rqueue); DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n", @@ -1386,8 +1334,7 @@ tcp_read(struct sock *sk, unsigned char *to, /* skb->used just checks to see if we've gone all the way around. */ /* While no data, or first data indicates some is missing, or data is used */ - while(skb == NULL || - before(sk->copied_seq+1, skb->h.th->seq) || skb->used) { + while(skb == NULL || skb->used || before(sk->copied_seq+1, skb->h.th->seq)) { DPRINTF((DBG_TCP, "skb = %X:\n", skb)); cleanup_rbuf(sk); if (sk->err) @@ -1465,8 +1412,8 @@ tcp_read(struct sock *sk, unsigned char *to, continue; } - if (skb_peek(&sk->rqueue) == NULL || - before(sk->copied_seq+1, sk->rqueue->h.th->seq)) { + skb = skb_peek(&sk->rqueue); + if (skb == NULL || before(sk->copied_seq+1, skb->h.th->seq)) { if(sk->debug) printk("Read wait sleep\n"); interruptible_sleep_on(sk->sleep); @@ -1492,42 +1439,42 @@ tcp_read(struct sock *sk, unsigned char *to, } /* + * are we at urgent data? + */ + if (sk->urg_data && sk->copied_seq+1 == sk->urg_seq) { + if (sk->urg_data == URG_READ) { + if (copied || (flags & MSG_PEEK)) { + release_sock(sk); + return copied; + } + sk->urg_data = 0; + sk->copied_seq++; + } else { + release_sock(sk); + if (copied) + return copied; + send_sig(SIGURG, current, 0); + return -EINTR; + } + } + + /* * Copy anything from the current block that needs * to go into the user buffer. */ offset = sk->copied_seq+1 - skb->h.th->seq; if (skb->h.th->syn) offset--; + if (offset < skb->len) /* Some of the packet is useful */ { - /* - * If there is urgent data we must either - * return or skip over it. - */ - if (skb->h.th->urg) - { - if (skb->urg_used) - { - sk->copied_seq += ntohs(skb->h.th->urg_ptr); - offset += ntohs(skb->h.th->urg_ptr); - if (offset >= skb->len) - { - skb->used = 1; - skb =(struct sk_buff *)skb->next; - continue; - } - } - else - { - release_sock(sk); - if (copied) - return(copied); - send_sig(SIGURG, current, 0); - return(-EINTR); - } - } /* Ok so how much can we use ? */ - used = min(skb->len - offset, len); + unsigned long used = skb->len - offset; + if (len < used) + used = len; + /* do we have urgent data here? */ + if (sk->urg_data && sk->urg_seq - (sk->copied_seq+1) < used) + used = sk->urg_seq - (sk->copied_seq+1); /* Copy it */ memcpy_tofs(to,((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used); @@ -1540,23 +1487,11 @@ tcp_read(struct sock *sk, unsigned char *to, sk->copied_seq += used; /* - * Mark this data used if we are really reading it, - * and if it doesn't contain any urgent data. And we + * Mark this data used if we are really reading it, and we * have used all the data. */ - if (!(flags & MSG_PEEK) && - (!skb->h.th->urg || skb->urg_used) && - (used + offset >= skb->len)) + if (!(flags & MSG_PEEK) && (used + offset >= skb->len)) skb->used = 1; - - /* - * See if this is the end of a message or if the - * remaining data is urgent. - */ - if (/*skb->h.th->psh || */skb->h.th->urg) - { - break; - } } else { /* already used this data, must be a retransmit */ @@ -1933,7 +1868,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb, newsk->send_seq = jiffies * SEQ_TICK - seq_offset; newsk->window_seq = newsk->send_seq; newsk->rcv_ack_seq = newsk->send_seq; - newsk->urg =0; + newsk->urg_data = 0; newsk->retransmits = 0; newsk->destroy = 0; newsk->timer.data = (unsigned long)newsk; @@ -2911,32 +2846,54 @@ tcp_data(struct sk_buff *skb, struct sock *sk, static int -tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr) +tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr, unsigned long len) { - extern int kill_pg(int pg, int sig, int priv); - extern int kill_proc(int pid, int sig, int priv); - - if (!sk->dead) - sk->data_ready(sk,0); + unsigned long ptr; + extern int kill_pg(int pg, int sig, int priv); + extern int kill_proc(int pid, int sig, int priv); + + if (!sk->dead) + sk->data_ready(sk,0); - if (sk->urginline) { - th->urg = 0; - th->psh = 1; - return(0); - } + if (sk->urginline) { + th->urg = 0; + th->psh = 1; + return 0; + } - if (!sk->urg) { - /* So if we get more urgent data, we don't signal the user again. */ - if (sk->proc != 0) { - if (sk->proc > 0) { - kill_proc(sk->proc, SIGURG, 1); - } else { - kill_pg(-sk->proc, SIGURG, 1); + ptr = ntohs(th->urg_ptr); + if (ptr) + ptr--; + + /* is the urgent data in this packet at all? */ + if (th->doff*4 + ptr >= len) + return 0; + + /* have we already seen and read this? */ + if (after(sk->copied_seq+1, th->seq+ptr)) + return 0; + + /* is this a duplicate? */ + if (sk->urg_data && sk->urg_seq == th->seq+ptr) + return 0; + + /* + * We signal the user only for the first urgent data: if urgent + * data already exists, no signal is sent + */ + if (!sk->urg_data || sk->urg_data == URG_READ) { + if (sk->proc != 0) { + if (sk->proc > 0) { + kill_proc(sk->proc, SIGURG, 1); + } else { + kill_pg(-sk->proc, SIGURG, 1); + } } } - } - sk->urg++; - return(0); + + sk->urg_data = 0x100 | *(ptr + th->doff*4 + (unsigned char *) th); + sk->urg_seq = th->seq + ptr; + return 0; } @@ -3301,15 +3258,14 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n"); skb->acked = 0; skb->used = 0; skb->free = 0; - skb->urg_used = 0; skb->saddr = daddr; skb->daddr = saddr; th->seq = ntohl(th->seq); - /* We may need to add it to the backlog here. */ - cli(); - if (sk->inuse) { + /* We may need to add it to the backlog here. */ + cli(); + if (sk->inuse) { if (sk->back_log == NULL) { sk->back_log = skb; skb->next = skb; @@ -3434,7 +3390,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n"); } } if (th->urg) { - if (tcp_urg(sk, th, saddr)) { + if (tcp_urg(sk, th, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3622,7 +3578,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n"); * already in the established state. */ if (th->urg) { - if (tcp_urg(sk, th, saddr)) { + if (tcp_urg(sk, th, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); @@ -3637,7 +3593,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n"); } if (th->urg) { - if (tcp_urg(sk, th, saddr)) { + if (tcp_urg(sk, th, saddr, len)) { kfree_skb(skb, FREE_READ); release_sock(sk); return(0); diff --git a/net/inet/tcp.h b/net/inet/tcp.h index e154d5e..5dcdaf5 100644 --- a/net/inet/tcp.h +++ b/net/inet/tcp.h @@ -30,6 +30,9 @@ #define MIN_WRITE_SPACE 2048 #define TCP_WINDOW_DIFF 2048 +/* marks the urg_data as read */ +#define URG_READ 0xdeadbeef + #define TCP_RETR1 7 /* * This is howmany retries it does before it * tries to figure out if the gateway is diff --git a/zBoot/Makefile b/zBoot/Makefile index f4fc25b..ff34719 100644 --- a/zBoot/Makefile +++ b/zBoot/Makefile @@ -6,7 +6,7 @@ SYSTEM = ../tools/zSystem zOBJECTS = $(HEAD) inflate.o unzip.o misc.o -CFLAGS = -O6 -DSTDC_HEADERS $(TEST) +CFLAGS = -O2 -DSTDC_HEADERS $(TEST) .c.s: $(CC) $(CFLAGS) -S -o $*.s $< |