aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-01-13 21:08:25 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:26 -0400
commit5f295b33cf4ea277617047421018a6cd75cc5dff (patch)
tree2851c8b70dda15759fac8f1b310402391fb16ada
parent9ee059ad6f92a777f874ddf472cd36aa9a901c16 (diff)
downloadarchive-5f295b33cf4ea277617047421018a6cd75cc5dff.tar.gz
ALPHA-pl14p
-rw-r--r--Makefile2
-rw-r--r--drivers/FPU-emu/Makefile5
-rw-r--r--drivers/FPU-emu/README7
-rw-r--r--drivers/FPU-emu/errors.c6
-rw-r--r--drivers/FPU-emu/fpu_trig.c26
-rw-r--r--drivers/FPU-emu/reg_norm.S24
-rw-r--r--drivers/FPU-emu/version.h4
-rw-r--r--drivers/block/cdu31a.c394
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/mouse.c4
-rw-r--r--drivers/char/psaux.c2
-rw-r--r--drivers/char/serial.c4
-rw-r--r--drivers/char/tty_io.c8
-rw-r--r--drivers/net/slip.c32
-rw-r--r--fs/binfmt_coff.c17
-rw-r--r--fs/ext2/CHANGES3
-rw-r--r--fs/ext2/dir.c9
-rw-r--r--fs/ext2/file.c13
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/sysv/README11
-rw-r--r--fs/sysv/ialloc.c3
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--include/linux/ext2_fs.h2
-rw-r--r--include/linux/if_ether.h3
-rw-r--r--include/linux/socket.h21
-rw-r--r--include/linux/sockios.h2
-rw-r--r--init/main.c2
-rw-r--r--net/inet/arp.c43
-rw-r--r--net/inet/arp.h1
-rw-r--r--net/inet/datagram.c75
-rw-r--r--net/inet/dev.c69
-rw-r--r--net/inet/eth.c5
-rw-r--r--net/inet/icmp.c7
-rw-r--r--net/inet/ip.c80
-rw-r--r--net/inet/ip.h5
-rw-r--r--net/inet/packet.c3
-rw-r--r--net/inet/raw.c22
-rw-r--r--net/inet/route.c22
-rw-r--r--net/inet/skbuff.c164
-rw-r--r--net/inet/skbuff.h1
-rw-r--r--net/inet/sock.c402
-rw-r--r--net/inet/sock.h19
-rw-r--r--net/inet/tcp.c282
-rw-r--r--net/inet/timer.c8
-rw-r--r--net/inet/udp.c24
-rw-r--r--net/unix/sock.c48
-rw-r--r--net/unix/unix.h2
47 files changed, 1201 insertions, 691 deletions
diff --git a/Makefile b/Makefile
index bca493a..1ebcf6e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = o
+ALPHA = p
all: Version zImage
diff --git a/drivers/FPU-emu/Makefile b/drivers/FPU-emu/Makefile
index 78ebb64..3563c1d 100644
--- a/drivers/FPU-emu/Makefile
+++ b/drivers/FPU-emu/Makefile
@@ -4,14 +4,15 @@
#DEBUG = -DDEBUGGING
DEBUG =
+PARANOID = -DPARANOID
REENTRANT = -DREENTRANT_FPU
-CFLAGS := $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin
+CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
.c.o:
$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
.S.o:
- $(CC) -D__ASSEMBLER__ $(REENTRANT) -c $<
+ $(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
.s.o:
$(CC) -c $<
diff --git a/drivers/FPU-emu/README b/drivers/FPU-emu/README
index 0b1a6f3..8493558 100644
--- a/drivers/FPU-emu/README
+++ b/drivers/FPU-emu/README
@@ -1,7 +1,7 @@
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen
- Sept 1993
+ Jan 1994
----------------------- Internals of wm-FPU-emu -----------------------
@@ -305,7 +305,8 @@ Daniel Carosone, danielce@ee.mu.oz.au
cae@jpmorgan.com
Hamish Coleman, t933093@minyos.xx.rmit.oz.au
Bruce Evans, bde@kralizec.zeta.org.au
-
+Timo Korvola, Timo.Korvola@hut.fi
+
...and numerous others who responded to my request for help with
a real 80486.
diff --git a/drivers/FPU-emu/errors.c b/drivers/FPU-emu/errors.c
index cd3c03a..8506997 100644
--- a/drivers/FPU-emu/errors.c
+++ b/drivers/FPU-emu/errors.c
@@ -3,7 +3,7 @@
| |
| The error handling functions for wm-FPU-emu |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -208,7 +208,7 @@ static struct {
0x125 in fpu_trig.c
0x126 in fpu_entry.c
0x127 in poly_2xm1.c
- 0x2nn in an *.s file:
+ 0x2nn in an *.S file:
0x201 in reg_u_add.S, reg_round.S
0x202 in reg_u_div.S
0x203 in reg_u_div.S
@@ -227,6 +227,8 @@ static struct {
0x216 in reg_round.S
0x217 in reg_round.S
0x218 in reg_round.S
+ 0x220 in reg_norm.S
+ 0x221 in reg_norm.S
*/
void exception(int n)
diff --git a/drivers/FPU-emu/fpu_trig.c b/drivers/FPU-emu/fpu_trig.c
index 76db016..1de4317 100644
--- a/drivers/FPU-emu/fpu_trig.c
+++ b/drivers/FPU-emu/fpu_trig.c
@@ -3,7 +3,7 @@
| |
| Implementation of the FPU "transcendental" functions. |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -88,9 +88,19 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */
significand(&tmp) = q + 1;
tmp.exp = EXP_BIAS + 63;
+ tmp.tag = TW_Valid;
normalize(&tmp);
reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
reg_add(X, &tmp, X, FULL_PRECISION);
+ if ( X->sign == SIGN_NEG )
+ {
+ /* CONST_PI2extra is negative, so the result of the addition
+ can be negative. This means that the argument is actually
+ in a different quadrant. The correction is always < pi/2,
+ so it can't overflow into yet another quadrant. */
+ X->sign = SIGN_POS;
+ q++;
+ }
}
#endif BETTER_THAN_486
}
@@ -107,9 +117,23 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */
significand(&tmp) = q;
tmp.exp = EXP_BIAS + 63;
+ tmp.tag = TW_Valid;
normalize(&tmp);
reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
reg_sub(X, &tmp, X, FULL_PRECISION);
+ if ( (X->exp == CONST_PI2.exp) &&
+ ((X->sigh > CONST_PI2.sigh)
+ || ((X->sigh == CONST_PI2.sigh)
+ && (X->sigl > CONST_PI2.sigl))) )
+ {
+ /* CONST_PI2extra is negative, so the result of the
+ subtraction can be larger than pi/2. This means
+ that the argument is actually in a different quadrant.
+ The correction is always < pi/2, so it can't overflow
+ into yet another quadrant. */
+ reg_sub(&CONST_PI, X, X, FULL_PRECISION);
+ q++;
+ }
}
}
#endif BETTER_THAN_486
diff --git a/drivers/FPU-emu/reg_norm.S b/drivers/FPU-emu/reg_norm.S
index 8ce60a2..9b7a9d7 100644
--- a/drivers/FPU-emu/reg_norm.S
+++ b/drivers/FPU-emu/reg_norm.S
@@ -1,7 +1,7 @@
/*---------------------------------------------------------------------------+
| reg_norm.S |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
@@ -29,6 +29,17 @@ _normalize:
movl PARAM1,%ebx
+#ifdef PARANOID
+ cmpb TW_Valid,TAG(%ebx)
+ je L_ok
+
+ pushl $0x220
+ call _exception
+ addl $4,%esp
+
+L_ok:
+#endif PARANOID
+
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
@@ -98,6 +109,17 @@ _normalize_nuo:
movl PARAM1,%ebx
+#ifdef PARANOID
+ cmpb TW_Valid,TAG(%ebx)
+ je L_ok_nuo
+
+ pushl $0x221
+ call _exception
+ addl $4,%esp
+
+L_ok_nuo:
+#endif PARANOID
+
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
diff --git a/drivers/FPU-emu/version.h b/drivers/FPU-emu/version.h
index 587f364..5ae1f49 100644
--- a/drivers/FPU-emu/version.h
+++ b/drivers/FPU-emu/version.h
@@ -2,12 +2,12 @@
| version.h |
| |
| |
- | Copyright (C) 1992,1993 |
+ | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version BETA 1.6"
+#define FPU_VERSION "wm-FPU-emu version Beta 1.7"
diff --git a/drivers/block/cdu31a.c b/drivers/block/cdu31a.c
index 4a56d16..063da62 100644
--- a/drivers/block/cdu31a.c
+++ b/drivers/block/cdu31a.c
@@ -80,11 +80,13 @@
#define MAJOR_NR CDU31A_CDROM_MAJOR
#include "blk.h"
+#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
static unsigned short cdu31a_addresses[] =
{
0x340, /* Standard configuration Sony Interface */
0x1f88, /* Fusion CD-16 */
+ 0x230, /* SoundBlaster 16 card */
0x360, /* Secondary standard Sony Interface */
0x320, /* Secondary standard Sony Interface */
0x330, /* Secondary standard Sony Interface */
@@ -96,6 +98,13 @@ static int handle_sony_cd_attention(void);
static int read_subcode(void);
static void sony_get_toc(void);
static int scd_open(struct inode *inode, struct file *filp);
+static void do_sony_cd_cmd(unsigned char cmd,
+ unsigned char *params,
+ unsigned int num_params,
+ unsigned char *result_buffer,
+ unsigned int *result_size);
+static void size_to_buf(unsigned int size,
+ unsigned char *buf);
/* The base I/O address of the Sony Interface. This is a variable (not a
@@ -116,7 +125,6 @@ static volatile unsigned short sony_cd_read_reg;
static volatile unsigned short sony_cd_fifost_reg;
-static int initialized = 0; /* Has the drive been initialized? */
static int sony_disc_changed = 1; /* Has the disk been changed
since the last check? */
static int sony_toc_read = 0; /* Has the table of contents been
@@ -306,6 +314,71 @@ write_cmd(unsigned char cmd)
outb(SONY_RES_RDY_INT_EN_BIT, sony_cd_control_reg);
}
+/*
+ * Set the drive parameters so the drive will auto-spin-up when a
+ * disk is inserted.
+ */
+static void
+set_drive_params(void)
+{
+ unsigned char res_reg[2];
+ unsigned int res_size;
+ unsigned char params[3];
+
+
+ params[0] = SONY_SD_MECH_CONTROL;
+ params[1] = 0x03;
+ do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
+ params,
+ 2,
+ res_reg,
+ &res_size);
+ if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
+ {
+ printk(" Unable to set mechanical parameters: 0x%2.2x\n", res_reg[1]);
+ }
+}
+
+/*
+ * This code will reset the drive and attempt to restore sane parameters.
+ */
+static void
+restart_on_error(void)
+{
+ unsigned char res_reg[2];
+ unsigned int res_size;
+ unsigned int retry_count;
+
+
+ printk("cdu31a: Resetting drive on error\n");
+ reset_drive();
+ retry_count = jiffies + SONY_RESET_TIMEOUT;
+ while ((retry_count > jiffies) && (!is_attention()))
+ {
+ sony_sleep();
+ }
+ set_drive_params();
+ do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
+ if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
+ {
+ printk("cdu31a: Unable to spin up drive: 0x%2.2x\n", res_reg[1]);
+ }
+
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 200;
+ schedule();
+
+ do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);
+ if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
+ {
+ printk("cdu31a: Unable to read TOC: 0x%2.2x\n", res_reg[1]);
+ }
+ sony_get_toc();
+ if (!sony_toc_read)
+ {
+ printk("cdu31a: Unable to get TOC data\n");
+ }
+}
/*
* This routine writes data to the parameter register. Since this should
@@ -459,6 +532,39 @@ get_result(unsigned char *result_buffer,
}
}
+/*
+ * Read in a 2048 byte block of data.
+ */
+static void
+read_data_block(unsigned char *data,
+ unsigned char *result_buffer,
+ unsigned int *result_size)
+{
+ int i;
+ unsigned int retry_count;
+
+ for (i=0; i<2048; i++)
+ {
+ retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
+ while ((retry_count > jiffies) && (!is_data_requested()))
+ {
+ while (handle_sony_cd_attention())
+ ;
+
+ sony_sleep();
+ }
+ if (!is_data_requested())
+ {
+ result_buffer[0] = 0x20;
+ result_buffer[1] = SONY_TIMEOUT_OP_ERR;
+ *result_size = 2;
+ return;
+ }
+
+ *data = read_data_register();
+ data++;
+ }
+}
/*
* This routine issues a read data command and gets the data. I don't
@@ -469,35 +575,37 @@ get_result(unsigned char *result_buffer,
* received at any time and should be handled immediately (at least
* between every 2048 byte block) to check for errors, we can't wait
* until all the data is read.
+ *
+ * This routine returns the total number of sectors read. It will
+ * not return an error if it reads at least one sector successfully.
*/
-static void
-get_data(unsigned char *data,
+static unsigned int
+get_data(unsigned char *orig_data,
unsigned char *params, /* 6 bytes with the MSF start address
and number of sectors to read. */
- unsigned int data_size,
+ unsigned int orig_data_size,
unsigned char *result_buffer,
unsigned int *result_size)
{
- int i;
unsigned int cur_offset;
unsigned int retry_count;
int result_read;
int num_retries;
+ unsigned int num_sectors_read = 0;
+ unsigned char *data = orig_data;
+ unsigned int data_size = orig_data_size;
cli();
- if (current != has_cd_task) /* Allow recursive calls to this routine */
+ while (sony_inuse)
{
- while (sony_inuse)
+ interruptible_sleep_on(&sony_wait);
+ if (current->signal & ~current->blocked)
{
- interruptible_sleep_on(&sony_wait);
- if (current->signal & ~current->blocked)
- {
- result_buffer[0] = 0x20;
- result_buffer[1] = SONY_SIGNAL_OP_ERR;
- *result_size = 2;
- return;
- }
+ result_buffer[0] = 0x20;
+ result_buffer[1] = SONY_SIGNAL_OP_ERR;
+ *result_size = 2;
+ return 0;
}
}
sony_inuse = 1;
@@ -506,6 +614,8 @@ get_data(unsigned char *data,
num_retries = 0;
retry_data_operation:
+ result_buffer[0] = 0;
+ result_buffer[1] = 0;
/*
* Clear any outstanding attentions and wait for the drive to
@@ -522,115 +632,120 @@ retry_data_operation:
while (handle_sony_cd_attention())
;
}
+
if (is_busy())
{
result_buffer[0] = 0x20;
result_buffer[1] = SONY_TIMEOUT_OP_ERR;
*result_size = 2;
- goto get_data_end;
}
+ else
+ {
+ /* Issue the command */
+ clear_result_ready();
+ clear_param_reg();
- /* Issue the command */
- clear_result_ready();
- clear_param_reg();
-
- write_params(params, 6);
- write_cmd(SONY_READ_CMD);
+ write_params(params, 6);
+ write_cmd(SONY_READ_CMD);
- /*
- * Read the data from the drive one 2048 byte sector at a time. Handle
- * any results received between sectors, if an error result is returned
- * terminate the operation immediately.
- */
- cur_offset = 0;
- result_read = 0;
- while (data_size > 0)
- {
- /* Wait for the drive to tell us we have something */
- retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
- while ((retry_count > jiffies) && (!(is_result_ready() || is_data_ready())))
- {
- while (handle_sony_cd_attention())
- ;
-
- sony_sleep();
- }
- if (!(is_result_ready() || is_data_ready()))
+ /*
+ * Read the data from the drive one 2048 byte sector at a time. Handle
+ * any results received between sectors, if an error result is returned
+ * terminate the operation immediately.
+ */
+ cur_offset = 0;
+ result_read = 0;
+ while ((data_size > 0) && (result_buffer[0] == 0))
{
- result_buffer[0] = 0x20;
- result_buffer[1] = SONY_TIMEOUT_OP_ERR;
- *result_size = 2;
- goto get_data_end;
- }
+ /* Wait for the drive to tell us we have something */
+ retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
+ while ((retry_count > jiffies) && (!(is_result_ready() || is_data_ready())))
+ {
+ while (handle_sony_cd_attention())
+ ;
+
+ sony_sleep();
+ }
+ if (!(is_result_ready() || is_data_ready()))
+ {
+ result_buffer[0] = 0x20;
+ result_buffer[1] = SONY_TIMEOUT_OP_ERR;
+ *result_size = 2;
+ }
- /* Handle results first */
- if (is_result_ready())
- {
- result_read = 1;
- get_result(result_buffer, result_size);
- if ((*result_size < 2) || (result_buffer[0] != 0))
+ /* Handle results first */
+ else if (is_result_ready())
{
- goto get_data_end;
+ result_read = 1;
+ get_result(result_buffer, result_size);
}
- }
- else /* Handle data next */
- {
- /*
- * The drive has to be polled for status on a byte-by-byte basis
- * to know if the data is ready. Yuck. I really wish I could use DMA.
- */
- clear_data_ready();
- for (i=0; i<2048; i++)
+ else /* Handle data next */
{
- retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
- while ((retry_count > jiffies) && (!is_data_requested()))
- {
- while (handle_sony_cd_attention())
- ;
-
- sony_sleep();
- }
- if (!is_data_requested())
- {
- result_buffer[0] = 0x20;
- result_buffer[1] = SONY_TIMEOUT_OP_ERR;
- *result_size = 2;
- goto get_data_end;
- }
-
- *data = read_data_register();
- data++;
- data_size--;
+ /*
+ * The drive has to be polled for status on a byte-by-byte basis
+ * to know if the data is ready. Yuck. I really wish I could use DMA.
+ */
+ clear_data_ready();
+ read_data_block(data, result_buffer, result_size);
+ data += 2048;
+ data_size -= 2048;
+ cur_offset = cur_offset + 2048;
+ num_sectors_read++;
}
- cur_offset = cur_offset + 2048;
}
- }
- /* Make sure the result has been read */
- if (!result_read)
- {
- get_result(result_buffer, result_size);
+ /* Make sure the result has been read */
+ if (!result_read)
+ {
+ get_result(result_buffer, result_size);
+ }
}
-get_data_end:
if ( ((result_buffer[0] & 0x20) == 0x20)
+ && (result_buffer[1] != SONY_NOT_SPIN_ERR) /* No retry when not spin */
&& (num_retries < MAX_CDU31A_RETRIES))
{
+ /*
+ * If an error occurs, go back and only read one sector at the
+ * given location. Hopefully the error occurred on an unused
+ * sector after the first one. It is hard to say which sector
+ * the error occurred on because the drive returns status before
+ * the data transfer is finished and doesn't say which sector.
+ */
+ data_size = 2048;
+ data = orig_data;
+ num_sectors_read = 0;
+ size_to_buf(1, &params[3]);
+
num_retries++;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 10; /* Wait .1 seconds on retries */
- schedule();
+ /* Issue a reset on an error (the second time), othersize just delay */
+ if (num_retries == 2)
+ {
+ restart_on_error();
+ }
+ else
+ {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 10;
+ schedule();
+ }
+
+ /* Restart the operation. */
goto retry_data_operation;
}
has_cd_task = NULL;
sony_inuse = 0;
wake_up_interruptible(&sony_wait);
+
+ return(num_sectors_read);
}
/*
- * Do a command that does not involve data transfer.
+ * Do a command that does not involve data transfer. This routine must
+ * be re-entrant from the same task to support being called from the
+ * data operation code when an error occurs.
*/
static void
do_sony_cd_cmd(unsigned char cmd,
@@ -641,6 +756,7 @@ do_sony_cd_cmd(unsigned char cmd,
{
unsigned int retry_count;
int num_retries;
+ int recursive_call;
cli();
@@ -657,9 +773,14 @@ do_sony_cd_cmd(unsigned char cmd,
return;
}
}
+ sony_inuse = 1;
+ has_cd_task = current;
+ recursive_call = 0;
+ }
+ else
+ {
+ recursive_call = 1;
}
- sony_inuse = 1;
- has_cd_task = current;
sti();
num_retries = 0;
@@ -681,18 +802,18 @@ retry_cd_operation:
result_buffer[0] = 0x20;
result_buffer[1] = SONY_TIMEOUT_OP_ERR;
*result_size = 2;
- goto do_cmd_end;
}
+ else
+ {
+ clear_result_ready();
+ clear_param_reg();
- clear_result_ready();
- clear_param_reg();
-
- write_params(params, num_params);
- write_cmd(cmd);
+ write_params(params, num_params);
+ write_cmd(cmd);
- get_result(result_buffer, result_size);
+ get_result(result_buffer, result_size);
+ }
-do_cmd_end:
if ( ((result_buffer[0] & 0x20) == 0x20)
&& (num_retries < MAX_CDU31A_RETRIES))
{
@@ -703,26 +824,41 @@ do_cmd_end:
goto retry_cd_operation;
}
- has_cd_task = NULL;
- sony_inuse = 0;
- wake_up_interruptible(&sony_wait);
+ if (!recursive_call)
+ {
+ has_cd_task = NULL;
+ sony_inuse = 0;
+ wake_up_interruptible(&sony_wait);
+ }
}
/*
* Handle an attention from the drive. This will return 1 if it found one
* or 0 if not (if one is found, the caller might want to call again).
+ *
+ * This routine counts the number of consecutive times it is called
+ * (since this is always called from a while loop until it returns
+ * a 0), and returns a 0 if it happens too many times. This will help
+ * prevent a lockup.
*/
static int
handle_sony_cd_attention(void)
{
unsigned char atten_code;
- unsigned char res_reg[2];
- unsigned int res_size;
+ static int num_consecutive_attentions = 0;
if (is_attention())
{
+ if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS)
+ {
+ printk("cdu31a: Too many consecutive attentions: %d\n",
+ num_consecutive_attentions);
+ num_consecutive_attentions = 0;
+ return(0);
+ }
+
clear_attention();
atten_code = read_result_register();
@@ -735,11 +871,6 @@ handle_sony_cd_attention(void)
sony_audio_status = CDROM_AUDIO_NO_STATUS;
sony_first_block = -1;
sony_last_block = -1;
- if (initialized)
- {
- do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
- sony_get_toc();
- }
break;
case SONY_AUDIO_PLAY_DONE_ATTN:
@@ -758,9 +889,12 @@ handle_sony_cd_attention(void)
sony_audio_status = CDROM_AUDIO_ERROR;
break;
}
+
+ num_consecutive_attentions++;
return(1);
}
+ num_consecutive_attentions = 0;
return(0);
}
@@ -862,6 +996,7 @@ do_cdu31a_request(void)
while (1)
{
+cdu31a_request_startover:
/*
* The beginning here is stolen from the hard disk driver. I hope
* its right.
@@ -878,7 +1013,7 @@ do_cdu31a_request(void)
if (dev != 0)
{
end_request(0);
- continue;
+ goto cdu31a_request_startover;
}
switch(CURRENT->cmd)
@@ -891,12 +1026,12 @@ do_cdu31a_request(void)
if ((block / 4) >= sony_toc->lead_out_start_lba)
{
end_request(0);
- return;
+ goto cdu31a_request_startover;
}
if (((block + nsect) / 4) >= sony_toc->lead_out_start_lba)
{
end_request(0);
- return;
+ goto cdu31a_request_startover;
}
while (nsect > 0)
@@ -916,12 +1051,10 @@ do_cdu31a_request(void)
*/
if (((block / 4) + sony_buffer_sectors) >= sony_toc->lead_out_start_lba)
{
- sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1;
read_size = sony_toc->lead_out_start_lba - (block / 4);
}
else
{
- sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1;
read_size = sony_buffer_sectors;
}
size_to_buf(read_size, &params[3]);
@@ -932,7 +1065,12 @@ do_cdu31a_request(void)
*/
spin_up_retry = 0;
try_read_again:
- get_data(sony_buffer, params, (read_size * 2048), res_reg, &res_size);
+ sony_last_block = sony_first_block
+ + (get_data(sony_buffer,
+ params,
+ (read_size * 2048),
+ res_reg,
+ &res_size) * 4) - 1;
if ((res_size < 2) || (res_reg[0] != 0))
{
if ((res_reg[1] == SONY_NOT_SPIN_ERR) && (!spin_up_retry))
@@ -946,7 +1084,7 @@ try_read_again:
sony_first_block = -1;
sony_last_block = -1;
end_request(0);
- return;
+ goto cdu31a_request_startover;
}
}
@@ -1569,7 +1707,7 @@ static char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" };
/* Read-ahead buffer sizes for different drives. These are just arbitrary
values, I don't know what is really optimum. */
-static unsigned int mem_size[] = { 4096, 8192, 16384, 2048 };
+static unsigned int mem_size[] = { 16384, 16384, 16384, 2048 };
void
get_drive_configuration(unsigned short base_io,
@@ -1640,8 +1778,6 @@ unsigned long
cdu31a_init(unsigned long mem_start, unsigned long mem_end)
{
struct s_sony_drive_config drive_config;
- unsigned char params[3];
- unsigned char res_reg[2];
unsigned int res_size;
int i;
int drive_found;
@@ -1695,17 +1831,7 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
}
printk("\n");
- params[0] = SONY_SD_MECH_CONTROL;
- params[1] = 0x03;
- do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
- params,
- 2,
- res_reg,
- &res_size);
- if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))
- {
- printk(" Unable to set mechanical parameters: 0x%2.2x\n", res_reg[1]);
- }
+ set_drive_params();
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
@@ -1716,8 +1842,6 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
mem_start += sizeof(*last_sony_subcode);
sony_buffer = (unsigned char *) mem_start;
mem_start += sony_buffer_size;
-
- initialized = 1;
}
i++;
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b72485c..4148459 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -48,7 +48,7 @@ OBJS := $(OBJS) msbusmouse.o
SRCS := $(SRCS) msbusmouse.c
endif
-ifdef CONFIG_QUICKPORT_MOUSE
+ifdef CONFIG_82C710_MOUSE
CONFIG_PSMOUSE = CONFIG_PSMOUSE
endif
diff --git a/drivers/char/mouse.c b/drivers/char/mouse.c
index debc6ea..107405f 100644
--- a/drivers/char/mouse.c
+++ b/drivers/char/mouse.c
@@ -45,7 +45,7 @@ static int mouse_open(struct inode * inode, struct file * file)
file->f_op = &bus_mouse_fops;
break;
#endif
-#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
+#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
case PSMOUSE_MINOR:
file->f_op = &psaux_fops;
break;
@@ -83,7 +83,7 @@ unsigned long mouse_init(unsigned long kmem_start)
#ifdef CONFIG_BUSMOUSE
kmem_start = bus_mouse_init(kmem_start);
#endif
-#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
+#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
kmem_start = psaux_init(kmem_start);
#endif
#ifdef CONFIG_MS_BUSMOUSE
diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c
index 487b16d..da133b3 100644
--- a/drivers/char/psaux.c
+++ b/drivers/char/psaux.c
@@ -68,7 +68,7 @@
#define AUX_DISABLE_DEV 0xf5 /* disable aux device */
#define AUX_RESET 0xff /* reset aux device */
-#define MAX_RETRIES 30 /* some aux operations take long time*/
+#define MAX_RETRIES 60 /* some aux operations take long time*/
#define AUX_IRQ 12
#define AUX_BUF_SIZE 2048
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index c25c17b..0330087 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -1574,7 +1574,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (info->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&info->close_wait);
- return -EAGAIN;
+ return -ERESTARTSYS;
}
/*
@@ -1632,7 +1632,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
- retval = -EAGAIN;
+ retval = -ERESTARTSYS;
break;
}
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 5422dcc..77fb28a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1315,6 +1315,7 @@ static int tty_open(struct inode * inode, struct file * filp)
int major, minor;
int noctty, retval;
+retry_open:
minor = MINOR(inode->i_rdev);
major = MAJOR(inode->i_rdev);
noctty = filp->f_flags & O_NOCTTY;
@@ -1372,7 +1373,12 @@ static int tty_open(struct inode * inode, struct file * filp)
#endif
release_dev(minor, filp);
- return retval;
+ if (retval != -ERESTARTSYS)
+ return retval;
+ if (current->signal & ~current->blocked)
+ return retval;
+ schedule();
+ goto retry_open;
}
if (!noctty &&
current->leader &&
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index b72dbca..2753824 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -881,6 +881,37 @@ slip_open(struct tty_struct *tty)
return(sl->line);
}
+
+static struct enet_statistics *
+sl_get_stats(struct device *dev)
+{
+ static struct enet_statistics stats;
+ struct slip *sl;
+ struct slcompress *comp;
+
+ /* Find the correct SLIP channel to use. */
+ sl = &sl_ctrl[dev->base_addr];
+ if (! sl)
+ return NULL;
+
+ memset(&stats, 0, sizeof(struct enet_statistics));
+
+ stats.rx_packets = sl->rpacket;
+ stats.rx_over_errors = sl->roverrun;
+ stats.tx_packets = sl->spacket;
+ stats.tx_dropped = sl->sbusy;
+ stats.rx_errors = sl->errors;
+
+ comp = sl->slcomp;
+ if (comp) {
+ stats.rx_fifo_errors = comp->sls_i_compressed;
+ stats.rx_dropped = comp->sls_i_tossed;
+ stats.tx_fifo_errors = comp->sls_o_compressed;
+ stats.collisions = comp->sls_o_misses;
+ }
+
+ return (&stats);
+}
/*
* Close down a SLIP channel.
@@ -1193,6 +1224,7 @@ slip_init(struct device *dev)
dev->hard_header = sl_header;
dev->add_arp = sl_add_arp;
dev->type_trans = sl_type_trans;
+ dev->get_stats = sl_get_stats;
#ifdef HAVE_SET_MAC_ADDR
#ifdef CONFIG_AX25
dev->set_mac_address = sl_set_mac_address;
diff --git a/fs/binfmt_coff.c b/fs/binfmt_coff.c
index 53b5eda..bf57016 100644
--- a/fs/binfmt_coff.c
+++ b/fs/binfmt_coff.c
@@ -38,6 +38,12 @@
* Al Longyear (longyear@sii.com)
* Removed erroneous code which mistakenly folded .data with .bss for
* a shared library.
+ *
+ * 8 Janurary 1994
+ * Al Longyear (longyear@sii.com)
+ * Corrected problem with read of library section returning the byte
+ * count rather than zero. This was a change between the pl12 and
+ * pl14 kernels which slipped by me.
*/
#include <linux/fs.h>
@@ -650,12 +656,21 @@ preload_library (struct linux_binprm *exe_bprm,
buffer, /* Buffer for read */
nbytes); /* Byte count reqd. */
set_fs (old_fs); /* Restore the selector */
+/*
+ * Check the result. The value returned is the byte count actaully read.
+ */
+ if (status >= 0 && status != nbytes) {
+#ifdef COFF_DEBUG
+ printk ("read of lib section was short\n");
+#endif
+ status = -ENOEXEC;
+ }
}
/*
* At this point, go through the list of libraries in the data area.
*/
phdr = (COFF_SLIBHD *) buffer;
- while (status == 0 && nbytes > COFF_SLIBSZ) {
+ while (status >= 0 && nbytes > COFF_SLIBSZ) {
int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
/*
diff --git a/fs/ext2/CHANGES b/fs/ext2/CHANGES
index 258bf23..08b7b64 100644
--- a/fs/ext2/CHANGES
+++ b/fs/ext2/CHANGES
@@ -4,8 +4,7 @@ Changes from version 0.4a to version 0.4b
- Clean up of balloc.c and ialloc.c.
- More consistency checks.
- Block preallocation added by Stephen Tweedie.
- - Direct reads of directories disallowed if CONFIG_EXT2_FS_DIR_READ not
- defined.
+ - Direct reads of directories disallowed.
- Readahead implemented in readdir by Stephen Tweedie.
- Bugs in block and inodes allocation fixed.
- Readahead implemented in ext2_find_entry by Chip Salzenberg.
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 9cfff70..84830b8 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -16,32 +16,23 @@
#include <asm/segment.h>
-#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
-#ifndef CONFIG_EXT2_FS_DIR_READ
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
return -EISDIR;
}
-#else
-int ext2_file_read (struct inode *, struct file *, char *, int);
-#endif
static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */
-#ifdef CONFIG_EXT2_FS_DIR_READ
- ext2_file_read, /* read */
-#else
ext2_dir_read, /* read */
-#endif
NULL, /* write - bad */
ext2_readdir, /* readdir */
NULL, /* select - default */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index e0e9e98..4f7fa7b 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -17,7 +17,6 @@
#include <asm/segment.h>
#include <asm/system.h>
-#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
@@ -34,10 +33,7 @@
#include <linux/fs.h>
#include <linux/ext2_fs.h>
-#ifndef CONFIG_EXT2_FS_DIR_READ
-static
-#endif
-int ext2_file_read (struct inode *, struct file *, char *, int);
+static int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_file_write (struct inode *, struct file *, char *, int);
static void ext2_release_file (struct inode *, struct file *);
@@ -76,10 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
ext2_permission /* permission */
};
-#ifndef CONFIG_EXT2_FS_DIR_READ
-static
-#endif
-int ext2_file_read (struct inode * inode, struct file * filp,
+static int ext2_file_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
int read, left, chars;
@@ -97,7 +90,7 @@ int ext2_file_read (struct inode * inode, struct file * filp,
return -EINVAL;
}
sb = inode->i_sb;
- if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
+ if (!S_ISREG(inode->i_mode)) {
ext2_warning (sb, "ext2_file_read", "mode = %07o",
inode->i_mode);
return -EINVAL;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index d04caea..6c7e7d2 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -274,7 +274,7 @@ static void ext2_setup_super (struct super_block * sb,
printk ("EXT2-fs warning: mounting fs with errors, "
"running e2fsck is recommended\n");
else if (es->s_max_mnt_count >= 0 &&
- es->s_mnt_count >= es->s_max_mnt_count)
+ es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n");
if (!(sb->s_flags & MS_RDONLY)) {
diff --git a/fs/sysv/README b/fs/sysv/README
index f42e57d..6257a0d 100644
--- a/fs/sysv/README
+++ b/fs/sysv/README
@@ -4,16 +4,11 @@ It implements all of
- SystemV/386 FS,
- Coherent FS.
-This is version alpha 5.
+This is version beta 1.
To install:
-* You need Linux 0.99.14.
-* Go to /usr/src/linux, unpack the tar file there, and patch the Linux source:
- patch -p1 < sysvfs.cdif
- To build the Linux kernel with the patches:
- make config
- make depend
- make
+* Answer the 'System V and Coherent filesystem support' question with 'y'
+ when configuring the kernel.
* To mount a disk or a partition, use
mount [-r] -t sysv device mountpoint
The file system type names
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index c8cc98b..cfa5694 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -65,7 +65,8 @@ void sysv_free_inode(struct inode * inode)
return;
}
if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) {
- panic("sysv_free_inode: unable to read inode block"); /* FIXME: too severe? */
+ printk("sysv_free_inode: unable to read inode block on device %d/%d\n",MAJOR(inode->i_dev),MINOR(inode->i_dev));
+ clear_inode(inode);
return;
}
raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 4e2af91..d9eb848 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -316,7 +316,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_dev=0;
unlock_super(sb);
if (!silent)
- printk("VFS: unable to read Xenix/SystemV/Coherent superblock\n");
+ printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device %d/%d\n",MAJOR(dev),MINOR(dev));
return NULL;
ok:
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 3c384b1..7b7bfbb 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -52,7 +52,7 @@
/*
* The second extended file system version
*/
-#define EXT2FS_DATE "94/01/05"
+#define EXT2FS_DATE "94/01/08"
#define EXT2FS_VERSION "0.4b"
/*
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 2d44fb1..2fabe9b 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -31,7 +31,8 @@
#define ETH_P_PUP 0x0400 /* Xerox PUP packet */
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-#define ETH_P_RARP 0x0835 /* Reverse Addr Res packet */
+#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
+#define ETH_P_X25 0x0805 /* CCITT X.25 */
#define ETH_P_IPX 0x8137 /* IPX over DIX */
#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 4e5fdbd..e6a520b 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -30,10 +30,14 @@ struct linger {
#define AF_UNSPEC 0
#define AF_UNIX 1
#define AF_INET 2
+#define AF_AX25 3
+#define AF_IPX 4
/* Protocol families, same as address families. */
#define PF_UNIX AF_UNIX
#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
/* Flags we can use with send/ and recv. */
#define MSG_OOB 1
@@ -41,6 +45,10 @@ struct linger {
/* Setsockoptions(2) level. */
#define SOL_SOCKET 1
+#define SOL_IP 2
+#define SOL_IPX 3
+#define SOL_AX25 4
+#define SOL_TCP 5
/* For setsockoptions(2) */
#define SO_DEBUG 1
@@ -56,6 +64,19 @@ struct linger {
#define SO_NO_CHECK 11
#define SO_PRIORITY 12
#define SO_LINGER 13
+/* IP options */
+#define IP_TOS 1
+#define IPTOS_LOWDELAY 0x10
+#define IPTOS_THROUGHPUT 0x08
+#define IPTOS_RELIABILITY 0x04
+#define IP_TTL 2
+/* IPX options */
+#define IPX_TYPE 1
+/* AX.25 options */
+#define AX25_WINDOW 1
+/* TCP options */
+#define TCP_MSS 1
+#define TCP_NODELAY 2
/* The various priorities. */
#define SOPRI_INTERACTIVE 0
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index 499b219..2090c33 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -28,7 +28,7 @@ struct ip_config {
unsigned long paddr;
unsigned long router;
unsigned long net;
- unsigned int up:1,destroy:1;
+ unsigned long up:1,destroy:1;
};
#endif /* FIXME: */
diff --git a/init/main.c b/init/main.c
index c816f2c..15e3f6b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -235,7 +235,7 @@ static void calibrate_delay(void)
"r" (ticks),
"0" (loops_per_sec)
:"dx");
- printk("ok - %lu.%02lu BogoMips (tm)\n",
+ printk("ok - %lu.%02lu BogoMips\n",
loops_per_sec/500000,
(loops_per_sec/5000) % 100);
return;
diff --git a/net/inet/arp.c b/net/inet/arp.c
index 0b69e1f..d559bcb 100644
--- a/net/inet/arp.c
+++ b/net/inet/arp.c
@@ -36,6 +36,9 @@
* Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet.
* Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet
* one.
+ * Dominik Kubla : Better checking
+ * Tegge : Assorted corrections on cross port stuff
+ * Alan Cox : ATF_PERM was backwards! - might be useful now (sigh)
*
* To Fix:
* : arp response allocates an skbuff to send. However there is a perfectly
@@ -386,7 +389,7 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
/* Delete an ARP mapping entry in the cache. */
void
-arp_destroy(unsigned long paddr)
+arp_destructor(unsigned long paddr, int force)
{
struct arp_table *apt;
struct arp_table **lapt;
@@ -406,6 +409,8 @@ arp_destroy(unsigned long paddr)
lapt = &arp_tables[hash];
while ((apt = *lapt) != NULL) {
if (apt->ip == paddr) {
+ if((apt->flags&ATF_PERM) && !force)
+ return;
*lapt = apt->next;
if(apt->flags&ATF_PUBL)
arp_proxies--;
@@ -418,6 +423,23 @@ arp_destroy(unsigned long paddr)
sti();
}
+/*
+ * Kill an entry - eg for ioctl()
+ */
+
+void arp_destroy(unsigned long paddr)
+{
+ arp_destructor(paddr,1);
+}
+
+/*
+ * Delete a possibly invalid entry (see timer.c)
+ */
+
+void arp_destroy_maybe(unsigned long paddr)
+{
+ arp_destructor(paddr,0);
+}
/* Create an ARP entry. The caller should check for duplicates! */
static struct arp_table *
@@ -536,16 +558,16 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0);
}
- /*
- * A broadcast arp, ignore it
- */
+/*
+ * A broadcast arp, ignore it
+ */
- if((dst&0xFF)==0xFF)
+ if(chk_addr(dst)==IS_BROADCAST)
{
kfree_skb(skb, FREE_READ);
return 0;
}
-
+
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
@@ -654,8 +676,8 @@ arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
* just pretend we did not find it, and then arp_send will
* verify the address for us.
*/
- if ((!(apt->flags & ATF_PERM)) ||
- (!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
+ if ((apt->flags & ATF_PERM) ||
+ (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) {
apt->last_used = jiffies;
memcpy(haddr, apt->ha, dev->addr_len);
return(0);
@@ -814,6 +836,11 @@ arp_req_set(struct arpreq *req)
htype = ARPHRD_ETHER;
hlen = ETH_ALEN;
break;
+ case ARPHRD_AX25:
+ htype = ARPHRD_AX25;
+ hlen = 7;
+ break;
+
default:
return(-EPFNOSUPPORT);
}
diff --git a/net/inet/arp.h b/net/inet/arp.h
index c75c6cf..57f41ac 100644
--- a/net/inet/arp.h
+++ b/net/inet/arp.h
@@ -59,5 +59,6 @@ extern void arp_add_broad(unsigned long addr, struct device *dev);
extern void arp_queue(struct sk_buff *skb);
extern int arp_get_info(char *buffer);
extern int arp_ioctl(unsigned int cmd, void *arg);
+extern void arp_destroy_maybe(unsigned long paddr);
#endif /* _ARP_H */
diff --git a/net/inet/datagram.c b/net/inet/datagram.c
index 931d9f3..7d0687e 100644
--- a/net/inet/datagram.c
+++ b/net/inet/datagram.c
@@ -2,7 +2,7 @@
* SUCS NET2 Debugged.
*
* Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
- * of these would make sense. Not tonight however 8-).
+ * of these would make sense. Not tonight however 8-).
* This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
* identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
*
@@ -13,6 +13,7 @@
* Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
* Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
* AX.25 now works right, and SPX is feasible.
+ * Alan Cox : Fixed write select of non IP protocol crash.
*/
#include <linux/config.h>
@@ -35,7 +36,7 @@
#include "udp.h"
#include "skbuff.h"
#include "sock.h"
-
+
/*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
@@ -46,16 +47,16 @@
*/
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
-{
+{
struct sk_buff *skb;
-
+
/* Socket is inuse - so the timer doesn't attack it */
restart:
sk->inuse = 1;
- while(sk->rqueue == NULL) /* No data */
- {
- /* If we are shutdown then no more data is going to appear. We are done */
- if (sk->shutdown & RCV_SHUTDOWN)
+ while(sk->rqueue == NULL) /* No data */
+ {
+ /* If we are shutdown then no more data is going to appear. We are done */
+ if (sk->shutdown & RCV_SHUTDOWN)
{
release_sock(sk);
*err=0;
@@ -69,7 +70,7 @@ restart:
sk->err=0;
return NULL;
}
-
+
/* Sequenced packets can come disconnected. If so we report the problem */
if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
{
@@ -77,24 +78,24 @@ restart:
*err=-ENOTCONN;
return NULL;
}
-
+
/* User doesn't want to wait */
- if (noblock)
+ if (noblock)
{
release_sock(sk);
*err=-EAGAIN;
return NULL;
}
release_sock(sk);
-
- /* Interrupts off so that no packet arrives before we begin sleeping.
+
+ /* Interrupts off so that no packet arrives before we begin sleeping.
Otherwise we might miss our wake up */
cli();
- if (sk->rqueue == NULL)
+ if (sk->rqueue == NULL)
{
interruptible_sleep_on(sk->sleep);
/* Signals may need a restart of the syscall */
- if (current->signal & ~current->blocked)
+ if (current->signal & ~current->blocked)
{
sti();
*err=-ERESTARTSYS;
@@ -115,26 +116,26 @@ restart:
}
/* Again only user level code calls this function, so nothing interrupt level
will suddenely eat the rqueue */
- if (!(flags & MSG_PEEK))
+ if (!(flags & MSG_PEEK))
{
- skb=skb_dequeue(&sk->rqueue);
- if(skb!=NULL)
- skb->users++;
+ skb=skb_dequeue(&sk->rqueue);
+ if(skb!=NULL)
+ skb->users++;
else
goto restart; /* Avoid race if someone beats us to the data */
}
else
{
- cli();
- skb=skb_peek(&sk->rqueue);
- if(skb!=NULL)
- skb->users++;
- sti();
- if(skb==NULL) /* shouldn't happen but .. */
- *err=-EAGAIN;
+ cli();
+ skb=skb_peek(&sk->rqueue);
+ if(skb!=NULL)
+ skb->users++;
+ sti();
+ if(skb==NULL) /* shouldn't happen but .. */
+ *err=-EAGAIN;
}
return skb;
-}
+}
void skb_free_datagram(struct sk_buff *skb)
{
@@ -156,7 +157,7 @@ void skb_free_datagram(struct sk_buff *skb)
void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
{
- /* We will know all about the fraglist options to allow >4K receives
+ /* We will know all about the fraglist options to allow >4K receives
but not this release */
memcpy_tofs(to,skb->h.raw+offset,size);
}
@@ -165,11 +166,11 @@ void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
* Datagram select: Again totally generic. Moved from udp.c
* Now does seqpacket.
*/
-
+
int datagram_select(struct sock *sk, int sel_type, select_table *wait)
{
select_wait(sk->sleep, wait);
- switch(sel_type)
+ switch(sel_type)
{
case SEL_IN:
if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
@@ -177,7 +178,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
/* Connection closed: Wake up */
return(1);
}
- if (sk->rqueue != NULL || sk->err != 0)
+ if (sk->rqueue != NULL || sk->err != 0)
{ /* This appears to be consistent
with other stacks */
return(1);
@@ -185,16 +186,20 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return(0);
case SEL_OUT:
- if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+ if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+ {
+ return(1);
+ }
+ if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
{
return(1);
}
return(0);
-
+
case SEL_EX:
if (sk->err)
return(1); /* Socket has gone into error state (eg icmp error) */
return(0);
- }
- return(0);
+ }
+ return(0);
}
diff --git a/net/inet/dev.c b/net/inet/dev.c
index e867ae3..0ce0e7b 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -26,6 +26,10 @@
* a) actually works for all A/B nets
* b) doesn't forward off the same interface.
* Alan Cox: Multiple extra protocols
+ * Alan Cox: Fixed ifconfig up of dud device setting the up flag
+ * Alan Cox: Fixed verify_area errors
+ * Alan Cox: Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give
+ * anything away 8)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -709,9 +713,12 @@ dev_ifconf(char *arg)
struct device *dev;
char *pos;
int len;
+ int err;
/* Fetch the caller's info block. */
- verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
+ err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
+ if(err)
+ return err;
memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
len = ifc.ifc_len;
pos = ifc.ifc_buf;
@@ -800,7 +807,9 @@ dev_ifsioc(void *arg, unsigned int getset)
int ret;
/* Fetch the caller's info block. */
- verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
+ int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
+ if(err)
+ return err;
memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));
/* See which interface the caller is talking about. */
@@ -827,8 +836,12 @@ dev_ifsioc(void *arg, unsigned int getset)
if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
ret = dev_close(dev);
} else
+ {
ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
? dev_open(dev) : 0;
+ if(ret<0)
+ dev->flags&=~IFF_UP; /* Didnt open so down the if */
+ }
}
break;
case SIOCGIFADDR:
@@ -946,55 +959,9 @@ dev_ioctl(unsigned int cmd, void *arg)
int ret;
switch(cmd) {
- case IP_SET_DEV:
- { /* Maintain backwards-compatibility, to be deleted for 1.00. */
- struct device *dev;
- /* The old 'struct ip_config'. */
- struct ip_config {
- char name[MAX_IP_NAME];
- unsigned long paddr, router, net,up:1,destroy:1;
- } ipc;
- int retval, loopback;
-
- printk("INET: Warning: old-style ioctl(IP_SET_DEV) called!\n");
- if (!suser())
- return (-EPERM);
-
- verify_area (VERIFY_WRITE, arg, sizeof (ipc));
- memcpy_fromfs(&ipc, arg, sizeof (ipc));
- ipc.name[MAX_IP_NAME-1] = 0;
- loopback = (strcmp(ipc.name, "loopback") == 0);
- dev = dev_get( loopback ? "lo" : ipc.name);
- if (dev == NULL)
- return -EINVAL;
- ipc.destroy = 0;
- dev->pa_addr = ipc.paddr;
- dev->family = AF_INET;
- dev->pa_mask = get_mask(dev->pa_addr);
- dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
- if (ipc.net != 0xffffffff) {
- dev->flags |= IFF_BROADCAST;
- dev->pa_brdaddr = ipc.net;
- }
-
- /* To be proper we should delete the route here. */
- if (ipc.up == 0)
- return (dev->flags & IFF_UP != 0) ? dev_close(dev) : 0;
-
- if ((dev->flags & IFF_UP) == 0
- && (retval = dev_open(dev)) != 0)
- return retval;
- printk("%s: adding HOST route of %8.8lx.\n", dev->name,
- htonl(ipc.paddr));
- rt_add(RTF_HOST, ipc.paddr, 0, 0, dev);
- if (ipc.router != 0 && ipc.router != -1) {
- rt_add(RTF_GATEWAY, ipc.paddr, 0, ipc.router, dev);
- printk("%s: adding GATEWAY route of %8.8lx.\n",
- dev->name, htonl(ipc.paddr));
-
- }
- return 0;
- }
+ case IP_SET_DEV:
+ printk("Your network configuration program needs upgrading.\n");
+ return -EINVAL;
case SIOCGIFCONF:
(void) dev_ifconf((char *) arg);
ret = 0;
diff --git a/net/inet/eth.c b/net/inet/eth.c
index 01e2f51..d6d83eb 100644
--- a/net/inet/eth.c
+++ b/net/inet/eth.c
@@ -17,6 +17,7 @@
* Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and
* minor other things.
+ * Tegge : Arp bug fixes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -124,7 +125,7 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
cli();
memcpy(eth->h_source, &saddr, 4);
/* No. Ask ARP to resolve the Ethernet address. */
- if (arp_find(eth->h_dest, daddr, dev, saddr))
+ if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr))
{
sti();
if(type!=ETH_P_IP)
@@ -155,7 +156,7 @@ eth_rebuild_header(void *buff, struct device *dev)
DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */
- if (arp_find(eth->h_dest, dst, dev, src)) return(1);
+ if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */)) return(1);
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return(0);
}
diff --git a/net/inet/icmp.c b/net/inet/icmp.c
index 7b953d4..8150451 100644
--- a/net/inet/icmp.c
+++ b/net/inet/icmp.c
@@ -14,6 +14,7 @@
* Fixes:
* Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected
+ * Alan Cox : Use tos/ttl settings
*
*
* This program is free software; you can redistribute it and/or
@@ -108,7 +109,7 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
/* Build Layer 2-3 headers for message back to source. */
offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
- &dev, IPPROTO_ICMP, NULL, len);
+ &dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
if (offset < 0) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
@@ -255,7 +256,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
- IPPROTO_ICMP, opt, len);
+ IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
kfree_skb(skb2,FREE_WRITE);
@@ -319,7 +320,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
- IPPROTO_ICMP, opt, len);
+ IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
kfree_skb(skb2,FREE_WRITE);
diff --git a/net/inet/ip.c b/net/inet/ip.c
index 4c9f924..091998c 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -31,6 +31,9 @@
* Gerhard Koerting: IP interface addressing fix.
* Linus Torvalds : More robustness checks
* Alan Cox : Even more checks: Still not as robust as it ought to be
+ * Alan Cox : Save IP header pointer for later
+ * Alan Cox : ip option setting
+ * Alan Cox : Use ip_tos/ip_ttl settings
*
* To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules
@@ -198,7 +201,7 @@ ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
*/
int
ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
- struct device **dev, int type, struct options *opt, int len)
+ struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
{
static struct options optmem;
struct iphdr *iph;
@@ -256,9 +259,9 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
iph = (struct iphdr *)buff;
iph->version = 4;
- iph->tos = 0;
+ iph->tos = tos;
iph->frag_off = 0;
- iph->ttl = 32;
+ iph->ttl = ttl;
iph->daddr = daddr;
iph->saddr = saddr;
iph->protocol = type;
@@ -1267,6 +1270,8 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
}
/* Point into the IP datagram, just past the header. */
+
+ skb->ip_hdr = iph;
skb->h.raw += iph->ihl*4;
hash = iph->protocol & (MAX_INET_PROTOS -1);
for (ipprot = (struct inet_protocol *)inet_protos[hash];
@@ -1504,3 +1509,72 @@ int backoff(int n)
}
}
+/*
+ * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
+ * an IP socket.
+ */
+
+int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+ int val,err;
+
+ if (optval == NULL)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
+ val = get_fs_long((unsigned long *)optval);
+
+ if(level!=SOL_IP)
+ return -EOPNOTSUPP;
+
+ switch(optname)
+ {
+ case IP_TOS:
+ if(val<0||val>255)
+ return -EINVAL;
+ sk->ip_tos=val;
+ return 0;
+ case IP_TTL:
+ if(val<1||val<255)
+ return -EINVAL;
+ sk->ip_ttl=val;
+ return 0;
+ /* IP_OPTIONS and friends go here eventually */
+ default:
+ return(-ENOPROTOOPT);
+ }
+}
+
+int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+ int val,err;
+
+ if(level!=SOL_IP)
+ return -EOPNOTSUPP;
+
+ switch(optname)
+ {
+ case IP_TOS:
+ val=sk->ip_tos;
+ break;
+ case IP_TTL:
+ val=sk->ip_ttl;
+ break;
+ default:
+ return(-ENOPROTOOPT);
+ }
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(val,(unsigned long *)optval);
+
+ return(0);
+}
diff --git a/net/inet/ip.h b/net/inet/ip.h
index 3c01cc8..7f2ecc0 100644
--- a/net/inet/ip.h
+++ b/net/inet/ip.h
@@ -69,7 +69,8 @@ extern int ip_build_header(struct sk_buff *skb,
unsigned long saddr,
unsigned long daddr,
struct device **dev, int type,
- struct options *opt, int len);
+ struct options *opt, int len,
+ int tos,int ttl);
extern unsigned short ip_compute_csum(unsigned char * buff, int len);
extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
@@ -77,5 +78,7 @@ extern void ip_queue_xmit(struct sock *sk,
struct device *dev, struct sk_buff *skb,
int free);
extern void ip_retransmit(struct sock *sk, int all);
+extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
+extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
#endif /* _IP_H */
diff --git a/net/inet/packet.c b/net/inet/packet.c
index c0585a6..ec00afe 100644
--- a/net/inet/packet.c
+++ b/net/inet/packet.c
@@ -18,6 +18,7 @@
* added. Also fixed the peek/read crash
* from all old Linux datagram code.
* Alan Cox : Uses the improved datagram code.
+ * Alan Cox : Added NULL's for socket options.
*
*
* This program is free software; you can redistribute it and/or
@@ -264,6 +265,8 @@ struct proto packet_prot = {
NULL,
packet_init,
NULL,
+ NULL, /* No set/get socket options */
+ NULL,
128,
0,
{NULL,},
diff --git a/net/inet/raw.c b/net/inet/raw.c
index 7533532..249d0b2 100644
--- a/net/inet/raw.c
+++ b/net/inet/raw.c
@@ -19,6 +19,10 @@
* Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too
+ * Alan Cox : Setsocketopt added
+ * Alan Cox : Fixed error return for broadcasts
+ * Alan Cox : Removed wake_up calls
+ * Alan Cox : Use ttl/tos
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -76,7 +80,7 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
}
sk->err = icmp_err_convert[err & 0xff].errno;
- wake_up(sk->sleep);
+ sk->error_report(sk);
return;
}
@@ -123,7 +127,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
}
sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb);
- wake_up(sk->sleep);
+ sk->data_ready(sk,skb->len);
release_sock(sk);
return(0);
}
@@ -169,7 +173,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
if (sin.sin_port == 0) sin.sin_port = sk->protocol;
if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -ENETUNREACH;
+ return -EACCES;
sk->inuse = 1;
skb = NULL;
@@ -214,7 +218,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev,
- sk->protocol, sk->opt, skb->mem_len);
+ sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
kfree_skb(skb,FREE_WRITE);
@@ -330,6 +334,13 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
return err;
put_fs_long(sizeof(*sin), addr_len);
}
+ if(sin)
+ {
+ err=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
+ if(err)
+ return err;
+ }
+
err=verify_area(VERIFY_WRITE,to,len);
if(err)
return err;
@@ -348,7 +359,6 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = skb->daddr;
- verify_area(VERIFY_WRITE, sin, sizeof(*sin));
memcpy_tofs(sin, &addr, sizeof(*sin));
}
@@ -390,6 +400,8 @@ struct proto raw_prot = {
NULL,
raw_init,
NULL,
+ ip_setsockopt,
+ ip_getsockopt,
128,
0,
{NULL,},
diff --git a/net/inet/route.c b/net/inet/route.c
index 269c80d..c6bcdce 100644
--- a/net/inet/route.c
+++ b/net/inet/route.c
@@ -121,21 +121,27 @@ void rt_flush(struct device *dev)
* number of zero 8-bit net numbers, otherwise we use the "default"
* masks judging by the destination address and our device netmask.
*/
+static inline unsigned long default_mask(unsigned long dst)
+{
+ dst = ntohl(dst);
+ if (IN_CLASSA(dst))
+ return htonl(IN_CLASSA_NET);
+ if (IN_CLASSB(dst))
+ return htonl(IN_CLASSB_NET);
+ return htonl(IN_CLASSC_NET);
+}
+
static unsigned long guess_mask(unsigned long dst, struct device * dev)
{
unsigned long mask = 0xffffffff;
+/* this is a rather ugly optimization: works only on little-endian machines */
while (mask & dst)
- mask >>= 8;
+ mask <<= 8;
if (mask)
return ~mask;
- dst = ntohl(dst);
- if (IN_CLASSA(dst))
- mask = htonl(IN_CLASSA_NET);
- else if (IN_CLASSB(dst))
- mask = htonl(IN_CLASSB_NET);
- else
- mask = htonl(IN_CLASSC_NET);
+/* ok, no more hacks.. */
+ mask = default_mask(dst);
if (dev->flags & IFF_POINTOPOINT)
return mask;
if ((dst ^ dev->pa_addr) & mask)
diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c
index 1f3299d..2898729 100644
--- a/net/inet/skbuff.c
+++ b/net/inet/skbuff.c
@@ -13,7 +13,7 @@
* and memory leak hunting.
* Alan Cox : More generic kfree handler
*/
-
+
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -44,14 +44,14 @@
/*
* Resource tracking variables
*/
-
+
volatile unsigned long net_memory=0;
volatile unsigned long net_skbcount=0;
/*
* Debugging paranoia. Can go later when this crud stack works
- */
-
+ */
+
void skb_check(struct sk_buff *skb, int line, char *file)
@@ -81,20 +81,20 @@ void skb_check(struct sk_buff *skb, int line, char *file)
/*
* Insert an sk_buff at the start of a list.
*/
-
+
void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
{
unsigned long flags;
-
- IS_SKB(newsk);
+
+ IS_SKB(newsk);
if(newsk->list)
printk("Suspicious queue head: sk_buff on list!\n");
save_flags(flags);
cli();
newsk->list=list;
-
+
newsk->next=*list;
-
+
if(*list)
newsk->prev=(*list)->prev;
else
@@ -110,14 +110,14 @@ void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
/*
* Insert an sk_buff at the end of a list.
*/
-
+
void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
{
unsigned long flags;
-
+
if(newsk->list)
printk("Suspicious queue tail: sk_buff on list!\n");
-
+
IS_SKB(newsk);
save_flags(flags);
cli();
@@ -137,7 +137,7 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
*list=newsk;
}
IS_SKB(newsk->prev);
- IS_SKB(newsk->next);
+ IS_SKB(newsk->next);
restore_flags(flags);
}
@@ -146,21 +146,21 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
* 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.
*/
-
+
struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
{
long flags;
struct sk_buff *result;
-
+
save_flags(flags);
cli();
-
+
if(*list==NULL)
{
restore_flags(flags);
return(NULL);
}
-
+
result=*list;
if(result->next==result)
*list=NULL;
@@ -173,7 +173,7 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
IS_SKB(result);
restore_flags(flags);
-
+
if(result->list!=list)
printk("Dequeued packet has invalid list pointer\n");
@@ -186,19 +186,19 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
/*
* Insert a packet before another one in a list.
*/
-
+
void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
{
unsigned long flags;
IS_SKB(old);
IS_SKB(newsk);
-
+
if(!old->list)
printk("insert before unlisted item!\n");
if(newsk->list)
printk("inserted item is already on a list.\n");
-
+
save_flags(flags);
cli();
newsk->list=old->list;
@@ -206,18 +206,18 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
newsk->prev=old->prev;
newsk->next->prev=newsk;
newsk->prev->next=newsk;
-
+
restore_flags(flags);
}
/*
* Place a packet after a given packet in a list.
*/
-
+
void skb_append(struct sk_buff *old, struct sk_buff *newsk)
{
unsigned long flags;
-
+
IS_SKB(old);
IS_SKB(newsk);
@@ -225,7 +225,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
printk("append before unlisted item!\n");
if(newsk->list)
printk("append item is already on a list.\n");
-
+
save_flags(flags);
cli();
newsk->list=old->list;
@@ -233,7 +233,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
newsk->next=old->next;
newsk->next->prev=newsk;
newsk->prev->next=newsk;
-
+
restore_flags(flags);
}
@@ -243,7 +243,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
* MUST EXIST when you unlink. Thus a list must have its contents unlinked
* _FIRST_.
*/
-
+
void skb_unlink(struct sk_buff *skb)
{
unsigned long flags;
@@ -251,7 +251,7 @@ void skb_unlink(struct sk_buff *skb)
cli();
IS_SKB(skb);
-
+
if(skb->list)
{
skb->next->prev=skb->prev;
@@ -290,7 +290,7 @@ void skb_new_list_head(struct sk_buff *volatile* list)
while(skb!=*list);
}
}
-
+
/*
* Peek an sk_buff. Unlike most other operations you _MUST_
* be careful with this one. A peek leaves the buffer on the
@@ -310,14 +310,14 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list)
* anyway. Only the memcpy of upto 4K with ints off is not
* as nice as I'd like.
*/
-
+
struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
{
struct sk_buff *orig,*newsk;
unsigned long flags;
unsigned int len;
/* Now for some games to avoid races */
-
+
do
{
save_flags(flags);
@@ -336,7 +336,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
if(newsk==NULL) /* Oh dear... not to worry */
return NULL;
-
+
save_flags(flags);
cli();
if(skb_peek(list)!=orig) /* List changed go around another time */
@@ -349,7 +349,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
kfree_skb(newsk, FREE_WRITE);
continue;
}
-
+
IS_SKB(orig);
IS_SKB(newsk);
memcpy(newsk,orig,len);
@@ -364,11 +364,11 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
newsk->free=1;
}
while(0);
-
+
restore_flags(flags);
return(newsk);
-}
-
+}
+
/*
* Free an sk_buff. This still knows about things it should
* not need to like protocols and sockets.
@@ -376,68 +376,68 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
void kfree_skb(struct sk_buff *skb, int rw)
{
- if (skb == NULL) {
- printk("kfree_skb: skb = NULL\n");
- return;
- }
- IS_SKB(skb);
- if(skb->free == 2)
- printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
- if(skb->list)
- printk("Warning: kfree_skb passed an skb still on a list.\n");
- skb->magic = 0;
- if (skb->sk)
- {
- if(skb->sk->prot!=NULL)
- {
- if (rw)
- skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
- else
- skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
-
+ if (skb == NULL) {
+ printk("kfree_skb: skb = NULL\n");
+ return;
}
- else
+ IS_SKB(skb);
+ if(skb->free == 2)
+ printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
+ if(skb->list)
+ printk("Warning: kfree_skb passed an skb still on a list.\n");
+ skb->magic = 0;
+ if (skb->sk)
+ {
+ if(skb->sk->prot!=NULL)
{
- /* Non INET - default wmalloc/rmalloc handler */
- if (rw)
- skb->sk->rmem_alloc-=skb->mem_len;
+ if (rw)
+ skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
+ else
+ skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
+
+ }
else
- skb->sk->wmem_alloc-=skb->mem_len;
- if(!skb->sk->dead)
+ {
+ /* Non INET - default wmalloc/rmalloc handler */
+ if (rw)
+ skb->sk->rmem_alloc-=skb->mem_len;
+ else
+ skb->sk->wmem_alloc-=skb->mem_len;
+ if(!skb->sk->dead)
wake_up(skb->sk->sleep);
- kfree_skbmem(skb->mem_addr,skb->mem_len);
+ kfree_skbmem(skb->mem_addr,skb->mem_len);
+ }
}
- }
- else
- kfree_skbmem(skb->mem_addr, skb->mem_len);
+ else
+ kfree_skbmem(skb->mem_addr, skb->mem_len);
}
/*
* Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
* fields and also do memory statistics to find all the [BEEP] leaks.
*/
-
+
struct sk_buff *alloc_skb(unsigned int size,int priority)
{
- struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
- if(skb==NULL)
- return NULL;
- skb->free= 2; /* Invalid so we pick up forgetful users */
- skb->list= 0; /* Not on a list */
- skb->truesize=size;
- skb->mem_len=size;
- skb->mem_addr=skb;
- skb->fraglist=NULL;
- net_memory+=size;
- net_skbcount++;
- skb->magic_debug_cookie=SK_GOOD_SKB;
- skb->users=0;
- return skb;
+ struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
+ if(skb==NULL)
+ return NULL;
+ skb->free= 2; /* Invalid so we pick up forgetful users */
+ skb->list= 0; /* Not on a list */
+ skb->truesize=size;
+ skb->mem_len=size;
+ skb->mem_addr=skb;
+ skb->fraglist=NULL;
+ net_memory+=size;
+ net_skbcount++;
+ skb->magic_debug_cookie=SK_GOOD_SKB;
+ skb->users=0;
+ return skb;
}
/*
* Free an skbuff by memory
- */
+ */
void kfree_skbmem(void *mem,unsigned size)
{
@@ -451,4 +451,4 @@ void kfree_skbmem(void *mem,unsigned size)
net_memory-=size;
}
}
-
+
diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h
index 6d5f879..a32f5a9 100644
--- a/net/inet/skbuff.h
+++ b/net/inet/skbuff.h
@@ -60,6 +60,7 @@ struct sk_buff {
ipx_packet *ipx;
#endif
} h;
+ struct iphdr *ip_hdr; /* For IPPROTO_RAW */
unsigned long mem_len;
unsigned long len;
unsigned long fraglen;
diff --git a/net/inet/sock.c b/net/inet/sock.c
index 7ad61c9..1781697 100644
--- a/net/inet/sock.c
+++ b/net/inet/sock.c
@@ -48,6 +48,9 @@
* Alan Cox : SO_LINGER supported
* Alan Cox : Error reporting fixes
* Anonymous : inet_create tidied up (sk->reuse setting)
+ * Alan Cox : inet sockets don't set sk->type!
+ * Alan Cox : Split socket option code
+ * Alan Cox : Callbacks
*
* To Fix:
*
@@ -312,7 +315,7 @@ destroy_sock(struct sock *sk)
/* Incase it's sleeping somewhere. */
if (!sk->dead)
- wake_up(sk->sleep);
+ sk->write_space(sk);
remove_sock(sk);
@@ -471,205 +474,236 @@ inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
}
}
-
-static int
-inet_setsockopt(struct socket *sock, int level, int optname,
+/*
+ * Set socket options on an inet socket.
+ */
+
+static int inet_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
- struct sock *sk;
- int val;
- int err;
- struct linger ling;
-
- /* This should really pass things on to the other levels. */
- if (level != SOL_SOCKET) return(-EOPNOTSUPP);
+ struct sock *sk = (struct sock *) sock->data;
+ if (level == SOL_SOCKET)
+ return sock_setsockopt(sk,level,optname,optval,optlen);
+ if (sk->prot->setsockopt==NULL)
+ return(-EOPNOTSUPP);
+ else
+ return sk->prot->setsockopt(sk,level,optname,optval,optlen);
+}
- sk = (struct sock *) sock->data;
- if (sk == NULL) {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
- if (optval == NULL) return(-EINVAL);
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_fs_long((unsigned long *)optval);
- switch(optname) {
- case SO_TYPE:
- case SO_ERROR:
- return(-ENOPROTOOPT);
-
- case SO_DEBUG:
- sk->debug=val?1:0;
- case SO_DONTROUTE: /* Still to be implemented */
- return(0);
- case SO_BROADCAST:
- sk->broadcast=val?1:0;
- return 0;
- case SO_SNDBUF:
- if(val>32767)
- val=32767;
- if(val<256)
- val=256;
- sk->sndbuf=val;
- return 0;
- case SO_LINGER:
- err=verify_area(VERIFY_READ,optval,sizeof(ling));
- if(err)
- return err;
- memcpy_fromfs(&ling,optval,sizeof(ling));
- if(ling.l_onoff==0)
- sk->linger=0;
- else
- {
- sk->lingertime=ling.l_linger;
- sk->linger=1;
- }
- return 0;
- case SO_RCVBUF:
- if(val>32767)
- val=32767;
- if(val<256)
- val=256;
- sk->rcvbuf=val;
- return(0);
- case SO_REUSEADDR:
- if (val) sk->reuse = 1;
- else sk->reuse = 0;
- return(0);
- case SO_KEEPALIVE:
- if (val) sk->keepopen = 1;
- else sk->keepopen = 0;
- return(0);
+static int inet_getsockopt(struct socket *sock, int level, int optname,
+ char *optval, int *optlen)
+{
+ struct sock *sk = sock->data;
+ if (level == SOL_SOCKET)
+ return sock_getsockopt(sk,level,optname,optval,optlen);
+ if(sk->prot->getsockopt==NULL)
+ return(-EOPNOTSUPP);
+ else
+ return sk->prot->getsockopt(sk,level,optname,optval,optlen);
+}
- case SO_OOBINLINE:
- if (val) sk->urginline = 1;
- else sk->urginline = 0;
- return(0);
+/*
+ * This is meant for all protocols to use and covers goings on
+ * at the socket level. Everything here is generic.
+ */
- case SO_NO_CHECK:
- if (val) sk->no_check = 1;
- else sk->no_check = 0;
- return(0);
+int sock_setsockopt(struct sock *sk, int level, int optname,
+ char *optval, int optlen)
+{
+ int val;
+ int err;
+ struct linger ling;
- case SO_PRIORITY:
- if (val >= 0 && val < DEV_NUMBUFFS) {
- sk->priority = val;
- } else {
- return(-EINVAL);
- }
- return(0);
+ if (optval == NULL)
+ return(-EINVAL);
- default:
- return(-ENOPROTOOPT);
- }
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
+ val = get_fs_long((unsigned long *)optval);
+ switch(optname)
+ {
+ case SO_TYPE:
+ case SO_ERROR:
+ return(-ENOPROTOOPT);
+
+ case SO_DEBUG:
+ sk->debug=val?1:0;
+ case SO_DONTROUTE: /* Still to be implemented */
+ return(0);
+ case SO_BROADCAST:
+ sk->broadcast=val?1:0;
+ return 0;
+ case SO_SNDBUF:
+ if(val>32767)
+ val=32767;
+ if(val<256)
+ val=256;
+ sk->sndbuf=val;
+ return 0;
+ case SO_LINGER:
+ err=verify_area(VERIFY_READ,optval,sizeof(ling));
+ if(err)
+ return err;
+ memcpy_fromfs(&ling,optval,sizeof(ling));
+ if(ling.l_onoff==0)
+ sk->linger=0;
+ else
+ {
+ sk->lingertime=ling.l_linger;
+ sk->linger=1;
+ }
+ return 0;
+ case SO_RCVBUF:
+ if(val>32767)
+ val=32767;
+ if(val<256)
+ val=256;
+ sk->rcvbuf=val;
+ return(0);
+
+ case SO_REUSEADDR:
+ if (val)
+ sk->reuse = 1;
+ else
+ sk->reuse = 0;
+ return(0);
+
+ case SO_KEEPALIVE:
+ if (val)
+ sk->keepopen = 1;
+ else
+ sk->keepopen = 0;
+ return(0);
+
+ case SO_OOBINLINE:
+ if (val)
+ sk->urginline = 1;
+ else
+ sk->urginline = 0;
+ return(0);
+
+ case SO_NO_CHECK:
+ if (val)
+ sk->no_check = 1;
+ else
+ sk->no_check = 0;
+ return(0);
+
+ case SO_PRIORITY:
+ if (val >= 0 && val < DEV_NUMBUFFS)
+ {
+ sk->priority = val;
+ }
+ else
+ {
+ return(-EINVAL);
+ }
+ return(0);
+
+ default:
+ return(-ENOPROTOOPT);
+ }
}
-static int
-inet_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- struct sock *sk;
- int val;
- int err;
- struct linger ling;
-
- /* This should really pass things on to the other levels. */
- if (level != SOL_SOCKET) return(-EOPNOTSUPP);
+int sock_getsockopt(struct sock *sk, int level, int optname,
+ char *optval, int *optlen)
+{
+ int val;
+ int err;
+ struct linger ling;
- sk = (struct sock *) sock->data;
- if (sk == NULL) {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- switch(optname) {
- case SO_DEBUG:
- val = sk->debug;
- break;
-
- case SO_DONTROUTE: /* One last option to implement */
- val = 0;
- break;
+ switch(optname)
+ {
+ case SO_DEBUG:
+ val = sk->debug;
+ break;
- case SO_BROADCAST:
- val= sk->broadcast;
- break;
+ case SO_DONTROUTE: /* One last option to implement */
+ val = 0;
+ break;
- case SO_LINGER:
+ case SO_BROADCAST:
+ val= sk->broadcast;
+ break;
- err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
- if(err)
- return err;
- err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(ling),(unsigned long *)optlen);
- ling.l_onoff=sk->linger;
- ling.l_linger=sk->lingertime;
- memcpy_tofs(optval,&ling,sizeof(ling));
- return 0;
+ case SO_LINGER:
+ err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
+ if(err)
+ return err;
+ err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(ling),(unsigned long *)optlen);
+ ling.l_onoff=sk->linger;
+ ling.l_linger=sk->lingertime;
+ memcpy_tofs(optval,&ling,sizeof(ling));
+ return 0;
- case SO_SNDBUF:
- val=sk->sndbuf;
- break;
+ case SO_SNDBUF:
+ val=sk->sndbuf;
+ break;
- case SO_RCVBUF:
- val =sk->rcvbuf;
- break;
-
- case SO_REUSEADDR:
- val = sk->reuse;
- break;
+ case SO_RCVBUF:
+ val =sk->rcvbuf;
+ break;
- case SO_KEEPALIVE:
- val = sk->keepopen;
- break;
+ case SO_REUSEADDR:
+ val = sk->reuse;
+ break;
- case SO_TYPE:
- if (sk->prot == &tcp_prot) val = SOCK_STREAM;
- else val = SOCK_DGRAM;
- break;
+ case SO_KEEPALIVE:
+ val = sk->keepopen;
+ break;
- case SO_ERROR:
- val = sk->err;
- sk->err = 0;
- break;
+ case SO_TYPE:
+ if (sk->prot == &tcp_prot)
+ val = SOCK_STREAM;
+ else
+ val = SOCK_DGRAM;
+ break;
- case SO_OOBINLINE:
- val = sk->urginline;
- break;
+ case SO_ERROR:
+ val = sk->err;
+ sk->err = 0;
+ break;
- case SO_NO_CHECK:
- val = sk->no_check;
- break;
+ case SO_OOBINLINE:
+ val = sk->urginline;
+ break;
+
+ case SO_NO_CHECK:
+ val = sk->no_check;
+ break;
- case SO_PRIORITY:
- val = sk->priority;
- break;
+ case SO_PRIORITY:
+ val = sk->priority;
+ break;
- default:
- return(-ENOPROTOOPT);
- }
- err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(int),(unsigned long *) optlen);
+ default:
+ return(-ENOPROTOOPT);
+ }
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(int),(unsigned long *) optlen);
- err=verify_area(VERIFY_WRITE, optval, sizeof(int));
- if(err)
- return err;
- put_fs_long(val,(unsigned long *)optval);
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(val,(unsigned long *)optval);
- return(0);
+ return(0);
}
+
+
static int
inet_listen(struct socket *sock, int backlog)
{
@@ -698,6 +732,23 @@ inet_listen(struct socket *sock, int backlog)
return(0);
}
+/*
+ * Default callbacks for user INET sockets. These just wake up
+ * the user owning the socket.
+ */
+
+static void def_callback1(struct sock *sk)
+{
+ if(!sk->dead)
+ wake_up(sk->sleep);
+}
+
+static void def_callback2(struct sock *sk,int len)
+{
+ if(!sk->dead)
+ wake_up(sk->sleep);
+}
+
static int
inet_create(struct socket *sock, int protocol)
@@ -773,6 +824,7 @@ inet_create(struct socket *sock, int protocol)
return(-ESOCKTNOSUPPORT);
}
sk->socket = sock;
+ sk->type = sock->type;
sk->protocol = protocol;
sk->wmem_alloc = 0;
sk->rmem_alloc = 0;
@@ -853,6 +905,14 @@ inet_create(struct socket *sock, int protocol)
sk->dummy_th.urg = 0;
sk->dummy_th.dest = 0;
+ sk->ip_tos=0;
+ sk->ip_ttl=64;
+
+ sk->state_change = def_callback1;
+ sk->data_ready = def_callback2;
+ sk->write_space = def_callback1;
+ sk->error_report = def_callback1;
+
if (sk->num) {
/*
* It assumes that any protocol which allows
@@ -893,7 +953,7 @@ inet_release(struct socket *sock, struct socket *peer)
if (sk == NULL) return(0);
DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer));
- wake_up(sk->sleep);
+ sk->state_change(sk);
/* Start closing the connection. This may take a while. */
/*
@@ -1579,7 +1639,7 @@ sock_wfree(struct sock *sk, void *mem, unsigned long size)
sk->wmem_alloc -= size;
/* In case it might be waiting for more memory. */
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->write_space(sk);
if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) {
DPRINTF((DBG_INET,
"recovered lost memory, sock = %X\n", sk));
diff --git a/net/inet/sock.h b/net/inet/sock.h
index cf6e2f3..cf8397a 100644
--- a/net/inet/sock.h
+++ b/net/inet/sock.h
@@ -136,7 +136,11 @@ struct sock {
char ax25_retxqi;
char ax25_rrtimer;
char ax25_timer;
+ ax25_digi *ax25_digipeat;
#endif
+/* IP 'private area' or will be eventually */
+ int ip_ttl; /* TTL setting */
+ int ip_tos; /* TOS */
struct tcphdr dummy_th;
/* This part is used for the timeout functions (timer.c). */
@@ -145,6 +149,13 @@ struct sock {
/* identd */
struct socket *socket;
+
+ /* Callbacks */
+ void (*state_change)(struct sock *sk);
+ void (*data_ready)(struct sock *sk,int bytes);
+ void (*write_space)(struct sock *sk);
+ void (*error_report)(struct sock *sk);
+
};
struct proto {
@@ -177,7 +188,7 @@ struct proto {
unsigned long saddr,
unsigned long daddr,
struct device **dev, int type,
- struct options *opt, int len);
+ struct options *opt, int len, int tos, int ttl);
int (*connect)(struct sock *sk,
struct sockaddr_in *usin, int addr_len);
struct sock *(*accept) (struct sock *sk, int flags);
@@ -197,6 +208,10 @@ struct proto {
unsigned long arg);
int (*init)(struct sock *sk);
void (*shutdown)(struct sock *sk, int how);
+ int (*setsockopt)(struct sock *sk, int level, int optname,
+ char *optval, int optlen);
+ int (*getsockopt)(struct sock *sk, int level, int optname,
+ char *optval, int *option);
unsigned short max_header;
unsigned long retransmits;
struct sock *sock_array[SOCK_ARRAY_SIZE];
@@ -238,6 +253,8 @@ extern void sock_rfree(struct sock *sk, void *mem,
extern unsigned long sock_rspace(struct sock *sk);
extern unsigned long sock_wspace(struct sock *sk);
+extern int sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen);
+extern int sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen);
/* declarations from timer.c */
extern struct sock *timer_base;
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 83dfb41..9160821 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -47,6 +47,13 @@
* Michael O'Reilly : ack < copied bug fix.
* Johannes Stille : Misc tcp fixes (not all in yet).
* Alan Cox : FIN with no memory -> CRASH
+ * Alan Cox : Added socket option proto entries. Also added awareness of them to accept.
+ * Alan Cox : Added TCP options (SOL_TCP)
+ * Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets.
+ * Alan Cox : Use ip_tos/ip_ttl settings.
+ * Alan Cox : Handle FIN (more) properly (we hope).
+ * Alan Cox : RST frames sent on unsynchronised state ack error/
+ * Alan Cox : Put in missing check for SYN bit.
*
*
* To Fix:
@@ -155,7 +162,7 @@ static void tcp_time_wait(struct sock *sk)
sk->state = TCP_TIME_WAIT;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
- wake_up(sk->sleep);
+ sk->state_change(sk);
reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
}
@@ -213,7 +220,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
if(err<0)
{
sk->err = -err;
- wake_up(sk->sleep);
+ sk->error_report(sk);
return;
}
@@ -237,7 +244,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
if (icmp_err_convert[err & 0xff].fatal) {
if (sk->state == TCP_SYN_SENT) {
sk->state = TCP_CLOSE;
- wake_up(sk->sleep); /* Wake people up to see the error (see connect in sock.c) */
+ sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
}
}
return;
@@ -558,7 +565,20 @@ tcp_send_partial(struct sock *sk)
if (sk == NULL || sk->send_tmp == NULL) return;
skb = sk->send_tmp;
-
+
+ /* If we have queued a header size packet.. */
+ if(skb->len-(unsigned long)skb->h.th + (unsigned long)(skb+1)==sizeof(struct tcphdr))
+ {
+ /* If its got a syn or fin its notionally included in the size..*/
+ if(!skb->h.th->syn && !skb->h.th->fin)
+ {
+ printk("tcp_send_partial: attempt to queue a bogon.\n");
+ kfree_skb(skb,FREE_WRITE);
+ sk->send_tmp=NULL;
+ return;
+ }
+ }
+
/* We need to complete and send the packet. */
tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
skb->len-(unsigned long)skb->h.th +
@@ -622,7 +642,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
/* Put in the IP header and routing stuff. */
tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
buff->free=1;
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
@@ -887,7 +907,7 @@ tcp_write(struct sock *sk, unsigned char *from,
* Perhaps some hints here would be good.
*/
tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, skb->mem_len);
+ IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
if (tmp < 0 ) {
prot->wfree(sk, skb->mem_addr, skb->mem_len);
release_sock(sk);
@@ -1008,7 +1028,7 @@ tcp_read_wakeup(struct sock *sk)
/* Put in the IP header and routing stuff. */
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
buff->free=1;
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
@@ -1484,7 +1504,7 @@ tcp_shutdown(struct sock *sk, int how)
/* Put in the IP header and routing stuff. */
tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr));
+ sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
buff->free=1;
prot->wfree(sk,buff->mem_addr, buff->mem_len);
@@ -1569,7 +1589,7 @@ tcp_recvfrom(struct sock *sk, unsigned char *to,
/* This routine will send an RST to the other tcp. */
static void
tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
- struct proto *prot, struct options *opt, struct device *dev)
+ struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl)
{
struct sk_buff *buff;
struct tcphdr *t1;
@@ -1594,7 +1614,7 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
/* Put in the IP header and routing stuff. */
tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
- sizeof(struct tcphdr));
+ sizeof(struct tcphdr),tos,ttl);
if (tmp < 0) {
buff->free = 1;
prot->wfree(NULL, buff->mem_addr, buff->mem_len);
@@ -1714,10 +1734,10 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* If the socket is dead, don't accept the connection. */
if (!sk->dead) {
- wake_up(sk->sleep);
+ sk->data_ready(sk,0);
} else {
DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+ tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl);
kfree_skb(skb, FREE_READ);
return;
}
@@ -1802,21 +1822,12 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->acked_seq = skb->h.th->seq + 1;
newsk->copied_seq = skb->h.th->seq;
-#ifdef OLDWAY
- if (skb->h.th->doff == 5) {
- newsk->mtu = dev->mtu - HEADER_SIZE;
- } else {
- ptr =(unsigned char *)(skb->h.th + 1);
- if (ptr[0] != 2 || ptr[1] != 4) {
- newsk->mtu = dev->mtu - HEADER_SIZE;
- } else {
- newsk->mtu = min(ptr[2] * 256 + ptr[3] - HEADER_SIZE,
- dev->mtu - HEADER_SIZE);
- }
- }
-#else
+ /* Grab the ttl and tos values and use them */
+ newsk->ip_ttl=sk->ip_ttl;
+ newsk->ip_tos=skb->ip_hdr->tos;
+
tcp_options(newsk,skb->h.th);
-#endif
+
buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
if (buff == NULL) {
sk->err = -ENOMEM;
@@ -1835,7 +1846,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* Put in the IP header and routing stuff. */
tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE);
+ IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
/* Something went wrong. */
if (tmp < 0) {
@@ -1912,25 +1923,13 @@ tcp_close(struct sock *sk, int timeout)
sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead)
+ sk->state_change(sk);
/* We need to flush the recv. buffs. */
if (skb_peek(&sk->rqueue) != NULL)
{
struct sk_buff *skb;
-#ifdef OLD
- struct sk_buff *skb2;
- skb = skb_peek(&sk->rqueue);
- do {
- skb2 =(struct sk_buff *)skb->next;
- /* if there is some real unread data, send a reset. */
- if (skb->len > 0 &&
- after(skb->h.th->seq + skb->len + 1, sk->copied_seq))
- need_reset = 1;
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- } while(skb != sk->rqueue);
-#else
if(sk->debug)
printk("Clean rcv queue\n");
while((skb=skb_dequeue(&sk->rqueue))!=NULL)
@@ -1941,7 +1940,6 @@ tcp_close(struct sock *sk, int timeout)
}
if(sk->debug)
printk("Cleaned.\n");
-#endif
}
sk->rqueue = NULL;
@@ -1999,7 +1997,7 @@ tcp_close(struct sock *sk, int timeout)
/* Put in the IP header and routing stuff. */
tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr));
+ sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
kfree_skb(buff,FREE_WRITE);
DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
@@ -2088,7 +2086,7 @@ tcp_write_xmit(struct sock *sk)
if (before(skb->h.seq, sk->rcv_ack_seq +1)) {
sk->retransmits = 0;
kfree_skb(skb, FREE_WRITE);
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->write_space(sk);
} else {
sk->prot->queue_xmit(sk, skb->dev, skb, skb->free);
}
@@ -2185,30 +2183,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
if (sk->packets_out > 0) sk->packets_out--;
/* We may need to remove this from the dev send list. */
if (skb->next != NULL) {
-#ifdef OLD_WAY
- int i;
-
- if (skb->next != skb) {
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
- }
-
- for(i = 0; i < DEV_NUMBUFFS; i++) {
- if (skb->dev->buffs[i] == skb) {
- if (skb->next == skb)
- skb->dev->buffs[i] = NULL;
- else
- skb->dev->buffs[i] = skb->next;
- break;
- }
- }
- if (arp_q == skb) {
- if (skb->next == skb) arp_q = NULL;
- else arp_q = skb->next;
- }
-#else
skb_unlink(skb);
-#endif
}
/* Now add it to the write_queue. */
skb->magic = TCP_WRITE_QUEUE_MAGIC;
@@ -2272,7 +2247,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
sk->send_head, sk->send_head->h.seq, ack));
/* Wake up the process, it can probably write more. */
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->write_space(sk);
oskb = sk->send_head;
@@ -2310,7 +2285,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
sti();
oskb->magic = 0;
kfree_skb(oskb, FREE_WRITE); /* write. */
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->write_space(sk);
} else {
break;
}
@@ -2330,7 +2305,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
if (sk->send_head == NULL && sk->ack_backlog == 0 &&
sk->state != TCP_TIME_WAIT && !sk->keepopen) {
DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n"));
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->write_space(sk);
if (sk->keepopen)
reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
@@ -2355,7 +2330,8 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
/* See if we are done. */
if (sk->state == TCP_TIME_WAIT) {
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead)
+ sk->state_change(sk);
if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) {
flag |= 1;
sk->state = TCP_CLOSE;
@@ -2364,7 +2340,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
}
if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) {
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->state_change(sk);
if (sk->rcv_ack_seq == sk->send_seq) {
flag |= 1;
if (sk->acked_seq != sk->fin_seq) {
@@ -2421,13 +2397,13 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
if (sk->shutdown & RCV_SHUTDOWN) {
sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
tcp_reset(sk->saddr, sk->daddr, skb->h.th,
- sk->prot, NULL, skb->dev);
+ sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl);
sk->state = TCP_CLOSE;
sk->err = EPIPE;
sk->shutdown = SHUTDOWN_MASK;
DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk));
kfree_skb(skb, FREE_READ);
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->state_change(sk);
return(0);
}
@@ -2523,7 +2499,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
/* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
if (skb->h.th->fin) {
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->state_change(sk);
sk->shutdown |= RCV_SHUTDOWN;
}
@@ -2541,7 +2517,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
*/
if (skb2->h.th->fin) {
sk->shutdown |= RCV_SHUTDOWN;
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->state_change(sk);
}
/* Force an immediate ack. */
@@ -2614,7 +2590,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
if (!sk->dead) {
if(sk->debug)
printk("Data wakeup.\n");
- wake_up(sk->sleep);
+ sk->data_ready(sk,0);
} else {
DPRINTF((DBG_TCP, "data received on dead socket.\n"));
}
@@ -2626,7 +2602,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_LAST_ACK;
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead) sk->state_change(sk);
}
return(0);
@@ -2639,7 +2615,8 @@ tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
extern int kill_pg(int pg, int sig, int priv);
extern int kill_proc(int pid, int sig, int priv);
- if (!sk->dead) wake_up(sk->sleep);
+ if (!sk->dead)
+ sk->data_ready(sk,0);
if (sk->urginline) {
th->urg = 0;
@@ -2662,7 +2639,7 @@ tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
}
-/* This deals with incoming fins. */
+/* This deals with incoming fins. 'Linus at 9 O'clock' 8-) */
static int
tcp_fin(struct sock *sk, struct tcphdr *th,
unsigned long saddr, struct device *dev)
@@ -2671,7 +2648,7 @@ tcp_fin(struct sock *sk, struct tcphdr *th,
sk, th, saddr, dev));
if (!sk->dead) {
- wake_up(sk->sleep);
+ sk->state_change(sk);
}
switch(sk->state) {
@@ -2813,7 +2790,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* Put in the IP header and routing stuff. */
/* We need to build the routing stuff fromt the things saved in skb. */
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE);
+ IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
release_sock(sk);
@@ -2862,7 +2839,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* This functions checks to see if the tcp header is actually acceptible. */
static int
tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
- struct options *opt, unsigned long saddr)
+ struct options *opt, unsigned long saddr, struct device *dev)
{
/*
* This isn't quite right. sk->acked_seq could be more recent
@@ -2883,6 +2860,19 @@ tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
/*
+ * Send a reset if we get something not ours and we are
+ * unsynchronized. Note: We don't do anything to our end. We
+ * are just killing the bogus remote connection then we will
+ * connect again and it will work (with luck).
+ */
+
+ if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV)
+ {
+ tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl);
+ return(1);
+ }
+
+ /*
* If it's too far ahead, send an ack to let the
* other end know what we expect.
*/
@@ -2969,7 +2959,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
{
th->seq = ntohl(th->seq);
/* So reset is always called with th->seq in host order */
- tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
+ tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev,skb->ip_hdr->tos,255);
}
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
@@ -3042,7 +3032,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) {
- wake_up(sk->sleep);
+ sk->state_change(sk);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
@@ -3054,7 +3044,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
case TCP_FIN_WAIT1:
case TCP_FIN_WAIT2:
case TCP_TIME_WAIT:
- if (!tcp_sequence(sk, th, len, opt, saddr)) {
+ if (!tcp_sequence(sk, th, len, opt, saddr,dev)) {
if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
if(!th->rst)
tcp_send_ack(sk->send_seq, sk->acked_seq,
@@ -3077,33 +3067,32 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
* A reset with a fin just means that
* the data was not all read.
*/
-/* The comment above appears completely bogus --clh */
-/* if (!th->fin) { */
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead) {
- wake_up(sk->sleep);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
-/* } */
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead) {
+ sk->state_change(sk);
+ }
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
}
+ if (
#if 0
- if (opt && (opt->security != 0 ||
- opt->compartment != 0 || th->syn)) {
+ if ((opt && (opt->security != 0 ||
+ opt->compartment != 0)) ||
+#endif
+ th->syn) {
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl);
if (!sk->dead) {
- wake_up(sk->sleep);
+ sk->state_change(sk);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
-#endif
if (th->ack) {
if (!tcp_ack(sk, th, saddr, len)) {
kfree_skb(skb, FREE_READ);
@@ -3119,13 +3108,14 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
}
}
- if (th->fin && tcp_fin(sk, th, saddr, dev)) {
+ if (tcp_data(skb, sk, saddr, len)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
- if (tcp_data(skb, sk, saddr, len)) {
+ /* Moved: you must do data then fin bit */
+ if (th->fin && tcp_fin(sk, th, saddr, dev)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
@@ -3145,7 +3135,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
if (!th->rst) {
if (!th->ack)
th->ack_seq = 0;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
@@ -3158,7 +3148,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
return(0);
}
if (th->ack) {
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
@@ -3189,7 +3179,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
return(0);
default:
- if (!tcp_sequence(sk, th, len, opt, saddr)) {
+ if (!tcp_sequence(sk, th, len, opt, saddr,dev)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
@@ -3202,7 +3192,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
sk->shutdown = SHUTDOWN_MASK;
sk->zapped = 1;
if (!sk->dead) {
- wake_up(sk->sleep);
+ sk->state_change(sk);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
@@ -3236,7 +3226,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
case TCP_SYN_SENT:
if (!tcp_ack(sk, th, saddr, len)) {
tcp_reset(daddr, saddr, th,
- sk->prot, opt,dev);
+ sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
@@ -3261,7 +3251,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
case TCP_SYN_RECV:
if (!tcp_ack(sk, th, saddr, len)) {
tcp_reset(daddr, saddr, th,
- sk->prot, opt, dev);
+ sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
@@ -3277,7 +3267,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
sk->dummy_th.dest = th->source;
sk->copied_seq = sk->acked_seq-1;
if (!sk->dead) {
- wake_up(sk->sleep);
+ sk->state_change(sk);
}
/*
@@ -3354,7 +3344,7 @@ tcp_write_wakeup(struct sock *sk)
/* Put in the IP header and routing stuff. */
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
return;
@@ -3389,6 +3379,72 @@ tcp_write_wakeup(struct sock *sk)
sk->prot->queue_xmit(sk, dev, buff, 1);
}
+/*
+ * Socket option code for TCP.
+ */
+
+int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
+{
+ int val,err;
+
+ if(level!=SOL_TCP)
+ return ip_setsockopt(sk,level,optname,optval,optlen);
+
+ if (optval == NULL)
+ return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
+ val = get_fs_long((unsigned long *)optval);
+
+ switch(optname)
+ {
+ case TCP_MSS:
+ if(val<200||val>2048)
+ return -EINVAL;
+ sk->mss=val;
+ return 0;
+ case TCP_NODELAY:
+ /* Ready for Johannes delayed ACK code */
+ return 0;
+ default:
+ return(-ENOPROTOOPT);
+ }
+}
+
+int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
+{
+ int val,err;
+
+ if(level!=SOL_TCP)
+ return ip_getsockopt(sk,level,optname,optval,optlen);
+
+ switch(optname)
+ {
+ case TCP_MSS:
+ val=sk->mss;
+ break;
+ case TCP_NODELAY:
+ val=1; /* Until Johannes stuff is in */
+ break;
+ default:
+ return(-ENOPROTOOPT);
+ }
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(sizeof(int),(unsigned long *) optlen);
+
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
+ put_fs_long(val,(unsigned long *)optval);
+
+ return(0);
+}
+
struct proto tcp_prot = {
sock_wmalloc,
@@ -3414,6 +3470,8 @@ struct proto tcp_prot = {
tcp_ioctl,
NULL,
tcp_shutdown,
+ tcp_setsockopt,
+ tcp_getsockopt,
128,
0,
{NULL,},
diff --git a/net/inet/timer.c b/net/inet/timer.c
index f6540a1..b5d0d13 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -141,7 +141,7 @@ net_timer (unsigned long data)
sk->state = TCP_CLOSE;
delete_timer (sk);
/* Kill the ARP entry in case the hardware has changed. */
- arp_destroy (sk->daddr);
+ arp_destroy_maybe (sk->daddr);
if (!sk->dead)
wake_up (sk->sleep);
sk->shutdown = SHUTDOWN_MASK;
@@ -167,7 +167,7 @@ net_timer (unsigned long data)
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
- arp_destroy (sk->daddr);
+ arp_destroy_maybe (sk->daddr);
ip_route_check (sk->daddr);
}
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
@@ -198,14 +198,14 @@ net_timer (unsigned long data)
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
- arp_destroy (sk->daddr);
+ arp_destroy_maybe (sk->daddr);
ip_route_check (sk->daddr);
release_sock (sk);
break;
}
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
- arp_destroy (sk->daddr);
+ arp_destroy_maybe (sk->daddr);
sk->err = ETIMEDOUT;
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
sk->state = TCP_TIME_WAIT;
diff --git a/net/inet/udp.c b/net/inet/udp.c
index 78066c3..d6e8328 100644
--- a/net/inet/udp.c
+++ b/net/inet/udp.c
@@ -30,10 +30,11 @@
* bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram
+ * Alan Cox : Added get/set sockopt support.
+ * Alan Cox : Broadcasting without option set returns EACCES.
+ * Alan Cox : No wakeup calls. Instead we now use the callbacks.
+ * Alan Cox : Use ip_tos and ip_ttl
*
- * To Do:
- * Verify all the error codes from UDP operations match the
- * BSD behaviour, since thats effectively the formal spec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -114,7 +115,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
if (err < 0) /* As per the calling spec */
{
sk->err = -err;
- wake_up(sk->sleep); /* User process wakes to see error */
+ sk->error_report(sk); /* User process wakes to see error */
return;
}
@@ -130,7 +131,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
sk->err=ECONNREFUSED;
}
- wake_up(sk->sleep);
+ sk->error_report(sk);
}
@@ -249,7 +250,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
- &dev, IPPROTO_UDP, sk->opt, skb->mem_len);
+ &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
skb->sk=sk; /* So memory is freed correctly */
if (tmp < 0 ) {
@@ -335,7 +336,7 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
}
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -ENETUNREACH; /* Must turn broadcast on first */
+ return -EACCES; /* Must turn broadcast on first */
sk->inuse = 1;
/* Send the packet. */
@@ -522,7 +523,7 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return(-EAFNOSUPPORT);
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -ENETUNREACH; /* Must turn broadcast on first */
+ return -EACCES; /* Must turn broadcast on first */
sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port;
@@ -604,8 +605,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->len = len - sizeof(*uh);
- if (!sk->dead) wake_up(sk->sleep);
-
+ if (!sk->dead)
+ sk->data_ready(sk,skb->len);
+
release_sock(sk);
return(0);
}
@@ -635,6 +637,8 @@ struct proto udp_prot = {
udp_ioctl,
NULL,
NULL,
+ ip_setsockopt,
+ ip_getsockopt,
128,
0,
{NULL,},
diff --git a/net/unix/sock.c b/net/unix/sock.c
index f4de8a8..dff2bbe 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -12,11 +12,12 @@
*
* Fixes:
* Alan Cox : Verify Area
+ * NET2E Team : Page fault locks
*
- * BUGS
- * Page faults on read while another process reads could lose data.
- * Page faults on write happen to interleave data (probably not allowed)
- * with any other simultaneous writers on the socket but dont cause harm.
+ * To Do:
+ *
+ * Change to the NET2E3 code for Unix domain sockets in general. The
+ * read/write logic is much better and cleaner.
*
*
* This program is free software; you can redistribute it and/or
@@ -141,6 +142,29 @@ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
}
+/* Support routines doing anti page fault locking
+ * FvK & Matt Dillon (borrowed From NET2E3)
+ */
+
+/*
+ * Locking for unix-domain sockets. We don't use the socket structure's
+ * wait queue because it is allowed to 'go away' outside of our control,
+ * whereas unix_proto_data structures stick around.
+ */
+void unix_lock(struct unix_proto_data *upd)
+{
+ while (upd->lock_flag)
+ sleep_on(&upd->wait);
+ upd->lock_flag = 1;
+}
+
+
+void unix_unlock(struct unix_proto_data *upd)
+{
+ upd->lock_flag = 0;
+ wake_up(&upd->wait);
+}
+
/* don't have to do anything. */
static int
unix_proto_listen(struct socket *sock, int backlog)
@@ -598,6 +622,8 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
* Copy from the read buffer into the user's buffer,
* watching for wraparound. Then we wake up the writer.
*/
+
+ unix_lock(upd);
do {
int part, cando;
@@ -612,7 +638,10 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
avail, todo, cando);
if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
+ {
+ unix_unlock(upd);
return er;
+ }
memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
ubuf += cando;
@@ -620,6 +649,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
avail = UN_BUF_AVAIL(upd);
} while(todo && avail);
+ unix_unlock(upd);
return(size - todo);
}
@@ -666,6 +696,9 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
* Copy from the user's buffer to the write buffer,
* watching for wraparound. Then we wake up the reader.
*/
+
+ unix_lock(pupd);
+
do {
int part, cando;
@@ -681,6 +714,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
*/
if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1);
+ unix_unlock(pupd);
return(-EPIPE);
}
if ((cando = todo) > space) cando = space;
@@ -689,7 +723,10 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
space, todo, cando);
er=verify_area(VERIFY_READ, ubuf, cando);
if(er)
+ {
+ unix_unlock(pupd);
return er;
+ }
memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
ubuf += cando;
@@ -697,6 +734,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
space = UN_BUF_SPACE(pupd);
} while(todo && space);
+ unix_unlock(pupd);
return(size - todo);
}
@@ -842,6 +880,8 @@ unix_ioctl(struct inode *inode, struct file *file,
}
+
+
static struct file_operations unix_fops = {
NULL, /* LSEEK */
NULL, /* READ */
diff --git a/net/unix/unix.h b/net/unix/unix.h
index 5b69801..74b1777 100644
--- a/net/unix/unix.h
+++ b/net/unix/unix.h
@@ -35,6 +35,8 @@ struct unix_proto_data {
int bp_head, bp_tail;
struct inode *inode;
struct unix_proto_data *peerupd;
+ struct wait_queue *wait; /* Lock across page faults (FvK) */
+ int lock_flag;
};
extern struct unix_proto_data unix_datas[NSOCKETS];