Commit 36f4514a authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14p

parent ddd9ed00
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 14 PATCHLEVEL = 14
ALPHA = o ALPHA = p
all: Version zImage all: Version zImage
......
...@@ -4,14 +4,15 @@ ...@@ -4,14 +4,15 @@
#DEBUG = -DDEBUGGING #DEBUG = -DDEBUGGING
DEBUG = DEBUG =
PARANOID = -DPARANOID
REENTRANT = -DREENTRANT_FPU REENTRANT = -DREENTRANT_FPU
CFLAGS := $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
.c.o: .c.o:
$(CC) $(CFLAGS) $(MATH_EMULATION) -c $< $(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
.S.o: .S.o:
$(CC) -D__ASSEMBLER__ $(REENTRANT) -c $< $(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
.s.o: .s.o:
$(CC) -c $< $(CC) -c $<
......
+---------------------------------------------------------------------------+ +---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | | 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, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -47,7 +47,7 @@ Please report bugs, etc to me at: ...@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen --Bill Metzenthen
Sept 1993 Jan 1994
----------------------- Internals of wm-FPU-emu ----------------------- ----------------------- Internals of wm-FPU-emu -----------------------
...@@ -305,7 +305,8 @@ Daniel Carosone, danielce@ee.mu.oz.au ...@@ -305,7 +305,8 @@ Daniel Carosone, danielce@ee.mu.oz.au
cae@jpmorgan.com cae@jpmorgan.com
Hamish Coleman, t933093@minyos.xx.rmit.oz.au Hamish Coleman, t933093@minyos.xx.rmit.oz.au
Bruce Evans, bde@kralizec.zeta.org.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 ...and numerous others who responded to my request for help with
a real 80486. a real 80486.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| The error handling functions for wm-FPU-emu | | 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, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -208,7 +208,7 @@ static struct { ...@@ -208,7 +208,7 @@ static struct {
0x125 in fpu_trig.c 0x125 in fpu_trig.c
0x126 in fpu_entry.c 0x126 in fpu_entry.c
0x127 in poly_2xm1.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 0x201 in reg_u_add.S, reg_round.S
0x202 in reg_u_div.S 0x202 in reg_u_div.S
0x203 in reg_u_div.S 0x203 in reg_u_div.S
...@@ -227,6 +227,8 @@ static struct { ...@@ -227,6 +227,8 @@ static struct {
0x216 in reg_round.S 0x216 in reg_round.S
0x217 in reg_round.S 0x217 in reg_round.S
0x218 in reg_round.S 0x218 in reg_round.S
0x220 in reg_norm.S
0x221 in reg_norm.S
*/ */
void exception(int n) void exception(int n)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
| | | |
| Implementation of the FPU "transcendental" functions. | | Implementation of the FPU "transcendental" functions. |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -88,9 +88,19 @@ static int trig_arg(FPU_REG *X, int even) ...@@ -88,9 +88,19 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */ 128 bits precision. */
significand(&tmp) = q + 1; significand(&tmp) = q + 1;
tmp.exp = EXP_BIAS + 63; tmp.exp = EXP_BIAS + 63;
tmp.tag = TW_Valid;
normalize(&tmp); normalize(&tmp);
reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION); reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
reg_add(X, &tmp, X, 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 #endif BETTER_THAN_486
} }
...@@ -107,9 +117,23 @@ static int trig_arg(FPU_REG *X, int even) ...@@ -107,9 +117,23 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */ 128 bits precision. */
significand(&tmp) = q; significand(&tmp) = q;
tmp.exp = EXP_BIAS + 63; tmp.exp = EXP_BIAS + 63;
tmp.tag = TW_Valid;
normalize(&tmp); normalize(&tmp);
reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION); reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
reg_sub(X, &tmp, X, 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 #endif BETTER_THAN_486
......
/*---------------------------------------------------------------------------+ /*---------------------------------------------------------------------------+
| reg_norm.S | | reg_norm.S |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | Australia. E-mail billm@vaxc.cc.monash.edu.au |
| | | |
...@@ -29,6 +29,17 @@ _normalize: ...@@ -29,6 +29,17 @@ _normalize:
movl PARAM1,%ebx 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 SIGH(%ebx),%edx
movl SIGL(%ebx),%eax movl SIGL(%ebx),%eax
...@@ -98,6 +109,17 @@ _normalize_nuo: ...@@ -98,6 +109,17 @@ _normalize_nuo:
movl PARAM1,%ebx 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 SIGH(%ebx),%edx
movl SIGL(%ebx),%eax movl SIGL(%ebx),%eax
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
| version.h | | version.h |
| | | |
| | | |
| Copyright (C) 1992,1993 | | Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au | | 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"
This diff is collapsed.
...@@ -48,7 +48,7 @@ OBJS := $(OBJS) msbusmouse.o ...@@ -48,7 +48,7 @@ OBJS := $(OBJS) msbusmouse.o
SRCS := $(SRCS) msbusmouse.c SRCS := $(SRCS) msbusmouse.c
endif endif
ifdef CONFIG_QUICKPORT_MOUSE ifdef CONFIG_82C710_MOUSE
CONFIG_PSMOUSE = CONFIG_PSMOUSE CONFIG_PSMOUSE = CONFIG_PSMOUSE
endif endif
......
...@@ -45,7 +45,7 @@ static int mouse_open(struct inode * inode, struct file * file) ...@@ -45,7 +45,7 @@ static int mouse_open(struct inode * inode, struct file * file)
file->f_op = &bus_mouse_fops; file->f_op = &bus_mouse_fops;
break; break;
#endif #endif
#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE #if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
case PSMOUSE_MINOR: case PSMOUSE_MINOR:
file->f_op = &psaux_fops; file->f_op = &psaux_fops;
break; break;
...@@ -83,7 +83,7 @@ unsigned long mouse_init(unsigned long kmem_start) ...@@ -83,7 +83,7 @@ unsigned long mouse_init(unsigned long kmem_start)
#ifdef CONFIG_BUSMOUSE #ifdef CONFIG_BUSMOUSE
kmem_start = bus_mouse_init(kmem_start); kmem_start = bus_mouse_init(kmem_start);
#endif #endif
#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE #if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
kmem_start = psaux_init(kmem_start); kmem_start = psaux_init(kmem_start);
#endif #endif
#ifdef CONFIG_MS_BUSMOUSE #ifdef CONFIG_MS_BUSMOUSE
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
#define AUX_DISABLE_DEV 0xf5 /* disable aux device */ #define AUX_DISABLE_DEV 0xf5 /* disable aux device */
#define AUX_RESET 0xff /* reset 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_IRQ 12
#define AUX_BUF_SIZE 2048 #define AUX_BUF_SIZE 2048
......
...@@ -1574,7 +1574,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -1574,7 +1574,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/ */
if (info->flags & ASYNC_CLOSING) { if (info->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&info->close_wait); 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, ...@@ -1632,7 +1632,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) { !(info->flags & ASYNC_INITIALIZED)) {
retval = -EAGAIN; retval = -ERESTARTSYS;
break; break;
} }
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
......
...@@ -1315,6 +1315,7 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1315,6 +1315,7 @@ static int tty_open(struct inode * inode, struct file * filp)
int major, minor; int major, minor;
int noctty, retval; int noctty, retval;
retry_open:
minor = MINOR(inode->i_rdev); minor = MINOR(inode->i_rdev);
major = MAJOR(inode->i_rdev); major = MAJOR(inode->i_rdev);
noctty = filp->f_flags & O_NOCTTY; noctty = filp->f_flags & O_NOCTTY;
...@@ -1372,7 +1373,12 @@ static int tty_open(struct inode * inode, struct file * filp) ...@@ -1372,7 +1373,12 @@ static int tty_open(struct inode * inode, struct file * filp)
#endif #endif
release_dev(minor, filp); release_dev(minor, filp);
return retval; if (retval != -ERESTARTSYS)
return retval;
if (current->signal & ~current->blocked)
return retval;
schedule();
goto retry_open;
} }
if (!noctty && if (!noctty &&
current->leader && current->leader &&
......
...@@ -881,6 +881,37 @@ slip_open(struct tty_struct *tty) ...@@ -881,6 +881,37 @@ slip_open(struct tty_struct *tty)
return(sl->line); 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. * Close down a SLIP channel.
...@@ -1193,6 +1224,7 @@ slip_init(struct device *dev) ...@@ -1193,6 +1224,7 @@ slip_init(struct device *dev)
dev->hard_header = sl_header; dev->hard_header = sl_header;
dev->add_arp = sl_add_arp; dev->add_arp = sl_add_arp;
dev->type_trans = sl_type_trans; dev->type_trans = sl_type_trans;
dev->get_stats = sl_get_stats;
#ifdef HAVE_SET_MAC_ADDR #ifdef HAVE_SET_MAC_ADDR
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
dev->set_mac_address = sl_set_mac_address; dev->set_mac_address = sl_set_mac_address;
......
...@@ -38,6 +38,12 @@ ...@@ -38,6 +38,12 @@
* Al Longyear (longyear@sii.com) * Al Longyear (longyear@sii.com)
* Removed erroneous code which mistakenly folded .data with .bss for * Removed erroneous code which mistakenly folded .data with .bss for
* a shared library. * 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> #include <linux/fs.h>
...@@ -650,12 +656,21 @@ preload_library (struct linux_binprm *exe_bprm, ...@@ -650,12 +656,21 @@ preload_library (struct linux_binprm *exe_bprm,
buffer, /* Buffer for read */ buffer, /* Buffer for read */
nbytes); /* Byte count reqd. */ nbytes); /* Byte count reqd. */
set_fs (old_fs); /* Restore the selector */ 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. * At this point, go through the list of libraries in the data area.
*/ */
phdr = (COFF_SLIBHD *) buffer; 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 entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long); int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
/* /*
......
...@@ -4,8 +4,7 @@ Changes from version 0.4a to version 0.4b ...@@ -4,8 +4,7 @@ Changes from version 0.4a to version 0.4b
- Clean up of balloc.c and ialloc.c. - Clean up of balloc.c and ialloc.c.
- More consistency checks. - More consistency checks.
- Block preallocation added by Stephen Tweedie. - Block preallocation added by Stephen Tweedie.
- Direct reads of directories disallowed if CONFIG_EXT2_FS_DIR_READ not - Direct reads of directories disallowed.
defined.
- Readahead implemented in readdir by Stephen Tweedie. - Readahead implemented in readdir by Stephen Tweedie.
- Bugs in block and inodes allocation fixed. - Bugs in block and inodes allocation fixed.
- Readahead implemented in ext2_find_entry by Chip Salzenberg. - Readahead implemented in ext2_find_entry by Chip Salzenberg.
......
...@@ -16,32 +16,23 @@ ...@@ -16,32 +16,23 @@
#include <asm/segment.h> #include <asm/segment.h>
#include <linux/autoconf.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/stat.h> #include <linux/stat.h>
#ifndef CONFIG_EXT2_FS_DIR_READ
static int ext2_dir_read (struct inode * inode, struct file * filp, static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count) char * buf, int count)
{ {
return -EISDIR; 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 int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext2_dir_operations = { static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */ NULL, /* lseek - default */
#ifdef CONFIG_EXT2_FS_DIR_READ
ext2_file_read, /* read */
#else
ext2_dir_read, /* read */ ext2_dir_read, /* read */
#endif
NULL, /* write - bad */ NULL, /* write - bad */
ext2_readdir, /* readdir */ ext2_readdir, /* readdir */
NULL, /* select - default */ NULL, /* select - default */
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/autoconf.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
...@@ -34,10 +33,7 @@ ...@@ -34,10 +33,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h> #include <linux/ext2_fs.h>
#ifndef CONFIG_EXT2_FS_DIR_READ static int ext2_file_read (struct inode *, struct file *, char *, int);
static
#endif
int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_file_write (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 *); static void ext2_release_file (struct inode *, struct file *);
...@@ -76,10 +72,7 @@ struct inode_operations ext2_file_inode_operations = { ...@@ -76,10 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
ext2_permission /* permission */ ext2_permission /* permission */
}; };
#ifndef CONFIG_EXT2_FS_DIR_READ static int ext2_file_read (struct inode * inode, struct file * filp,
static
#endif
int ext2_file_read (struct inode * inode, struct file * filp,
char * buf, int count) char * buf, int count)
{ {
int read, left, chars; int read, left, chars;
...@@ -97,7 +90,7 @@ int ext2_file_read (struct inode * inode, struct file * filp, ...@@ -97,7 +90,7 @@ int ext2_file_read (struct inode * inode, struct file * filp,
return -EINVAL; return -EINVAL;
} }
sb = inode->i_sb; 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", ext2_warning (sb, "ext2_file_read", "mode = %07o",
inode->i_mode); inode->i_mode);
return -EINVAL; return -EINVAL;
......
...@@ -274,7 +274,7 @@ static void ext2_setup_super (struct super_block * sb, ...@@ -274,7 +274,7 @@ static void ext2_setup_super (struct super_block * sb,
printk ("EXT2-fs warning: mounting fs with errors, " printk ("EXT2-fs warning: mounting fs with errors, "
"running e2fsck is recommended\n"); "running e2fsck is recommended\n");
else if (es->s_max_mnt_count >= 0 && 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, " printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n"); "running e2fsck is recommended\n");
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
......
...@@ -4,16 +4,11 @@ It implements all of ...@@ -4,16 +4,11 @@ It implements all of
- SystemV/386 FS, - SystemV/386 FS,
- Coherent FS. - Coherent FS.
This is version alpha 5. This is version beta 1.
To install: To install:
* You need Linux 0.99.14. * Answer the 'System V and Coherent filesystem support' question with 'y'
* Go to /usr/src/linux, unpack the tar file there, and patch the Linux source: when configuring the kernel.
patch -p1 < sysvfs.cdif
To build the Linux kernel with the patches:
make config
make depend
make
* To mount a disk or a partition, use * To mount a disk or a partition, use
mount [-r] -t sysv device mountpoint mount [-r] -t sysv device mountpoint
The file system type names The file system type names
......
...@@ -65,7 +65,8 @@ void sysv_free_inode(struct inode * inode) ...@@ -65,7 +65,8 @@ void sysv_free_inode(struct inode * inode)
return; return;
} }
if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) { 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; return;
} }
raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1); raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
......
...@@ -316,7 +316,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data, ...@@ -316,7 +316,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_dev=0; sb->s_dev=0;
unlock_super(sb); unlock_super(sb);
if (!silent) 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; return NULL;
ok: ok:
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
/* /*
* The second extended file system version * The second extended file system version
*/ */
#define EXT2FS_DATE "94/01/05" #define EXT2FS_DATE "94/01/08"
#define EXT2FS_VERSION "0.4b" #define EXT2FS_VERSION "0.4b"
/* /*
......
...@@ -31,7 +31,8 @@ ...@@ -31,7 +31,8 @@
#define ETH_P_PUP 0x0400 /* Xerox PUP packet */ #define ETH_P_PUP 0x0400 /* Xerox PUP packet */
#define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_ARP 0x0806 /* Address Resolution 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_IPX 0x8137 /* IPX over DIX */
#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ #define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ #define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
......
...@@ -30,10 +30,14 @@ struct linger { ...@@ -30,10 +30,14 @@ struct linger {
#define AF_UNSPEC 0 #define AF_UNSPEC 0
#define AF_UNIX 1 #define AF_UNIX 1
#define AF_INET 2 #define AF_INET 2
#define AF_AX25 3
#define AF_IPX 4
/* Protocol families, same as address families. */ /* Protocol families, same as address families. */
#define PF_UNIX AF_UNIX #define PF_UNIX AF_UNIX
#define PF_INET AF_INET #define PF_INET AF_INET
#define PF_AX25 AF_AX25
#define PF_IPX AF_IPX
/* Flags we can use with send/ and recv. */ /* Flags we can use with send/ and recv. */
#define MSG_OOB 1 #define MSG_OOB 1
...@@ -41,6 +45,10 @@ struct linger { ...@@ -41,6 +45,10 @@ struct linger {
/* Setsockoptions(2) level. */ /* Setsockoptions(2) level. */
#define SOL_SOCKET 1 #define SOL_SOCKET 1
#define SOL_IP 2
#define SOL_IPX 3
#define SOL_AX25 4
#define SOL_TCP 5
/* For setsockoptions(2) */ /* For setsockoptions(2) */
#define SO_DEBUG 1 #define SO_DEBUG 1
...@@ -56,6 +64,19 @@ struct linger { ...@@ -56,6 +64,19 @@ struct linger {
#define SO_NO_CHECK 11 #define SO_NO_CHECK 11
#define SO_PRIORITY 12 #define SO_PRIORITY 12
#define SO_LINGER 13 #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. */ /* The various priorities. */
#define SOPRI_INTERACTIVE 0 #define SOPRI_INTERACTIVE 0
......
...@@ -28,7 +28,7 @@ struct ip_config { ...@@ -28,7 +28,7 @@ struct ip_config {
unsigned long paddr; unsigned long paddr;
unsigned long router; unsigned long router;
unsigned long net; unsigned long net;
unsigned int up:1,destroy:1; unsigned long up:1,destroy:1;
}; };
#endif /* FIXME: */ #endif /* FIXME: */
......
...@@ -235,7 +235,7 @@ static void calibrate_delay(void) ...@@ -235,7 +235,7 @@ static void calibrate_delay(void)
"r" (ticks), "r" (ticks),
"0" (loops_per_sec) "0" (loops_per_sec)
:"dx"); :"dx");
printk("ok - %lu.%02lu BogoMips (tm)\n", printk("ok - %lu.%02lu BogoMips\n",
loops_per_sec/500000, loops_per_sec/500000,
(loops_per_sec/5000) % 100); (loops_per_sec/5000) % 100);
return; return;
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
* Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet. * 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 * Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet
* one. * 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: * To Fix:
* : arp response allocates an skbuff to send. However there is a perfectly * : 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) ...@@ -386,7 +389,7 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
/* Delete an ARP mapping entry in the cache. */ /* Delete an ARP mapping entry in the cache. */
void void
arp_destroy(unsigned long paddr) arp_destructor(unsigned long paddr, int force)
{ {
struct arp_table *apt; struct arp_table *apt;
struct arp_table **lapt; struct arp_table **lapt;
...@@ -406,6 +409,8 @@ arp_destroy(unsigned long paddr) ...@@ -406,6 +409,8 @@ arp_destroy(unsigned long paddr)
lapt = &arp_tables[hash]; lapt = &arp_tables[hash];
while ((apt = *lapt) != NULL) { while ((apt = *lapt) != NULL) {
if (apt->ip == paddr) { if (apt->ip == paddr) {
if((apt->flags&ATF_PERM) && !force)
return;
*lapt = apt->next; *lapt = apt->next;
if(apt->flags&ATF_PUBL) if(apt->flags&ATF_PUBL)
arp_proxies--; arp_proxies--;
...@@ -418,6 +423,23 @@ arp_destroy(unsigned long paddr) ...@@ -418,6 +423,23 @@ arp_destroy(unsigned long paddr)
sti(); 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! */ /* Create an ARP entry. The caller should check for duplicates! */
static struct arp_table * static struct arp_table *
...@@ -536,16 +558,16 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -536,16 +558,16 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0); 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); kfree_skb(skb, FREE_READ);
return 0; return 0;
} }
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) { if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
DPRINTF((DBG_ARP, "ARP: request was not for me!\n")); 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, ...@@ -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 * just pretend we did not find it, and then arp_send will
* verify the address for us. * verify the address for us.
*/ */
if ((!(apt->flags & ATF_PERM)) || if ((apt->flags & ATF_PERM) ||
(!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) { (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) {
apt->last_used = jiffies; apt->last_used = jiffies;
memcpy(haddr, apt->ha, dev->addr_len); memcpy(haddr, apt->ha, dev->addr_len);
return(0); return(0);
...@@ -814,6 +836,11 @@ arp_req_set(struct arpreq *req) ...@@ -814,6 +836,11 @@ arp_req_set(struct arpreq *req)
htype = ARPHRD_ETHER; htype = ARPHRD_ETHER;
hlen = ETH_ALEN; hlen = ETH_ALEN;
break; break;
case ARPHRD_AX25:
htype = ARPHRD_AX25;
hlen = 7;
break;
default: default:
return(-EPFNOSUPPORT); return(-EPFNOSUPPORT);
} }
......
...@@ -59,5 +59,6 @@ extern void arp_add_broad(unsigned long addr, struct device *dev); ...@@ -59,5 +59,6 @@ extern void arp_add_broad(unsigned long addr, struct device *dev);
extern void arp_queue(struct sk_buff *skb); extern void arp_queue(struct sk_buff *skb);
extern int arp_get_info(char *buffer); extern int arp_get_info(char *buffer);
extern int arp_ioctl(unsigned int cmd, void *arg); extern int arp_ioctl(unsigned int cmd, void *arg);
extern void arp_destroy_maybe(unsigned long paddr);
#endif /* _ARP_H */ #endif /* _ARP_H */
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* SUCS NET2 Debugged. * SUCS NET2 Debugged.
* *
* Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top * 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 * 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. * 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 @@ ...@@ -13,6 +13,7 @@
* Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff. * 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 * 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. * AX.25 now works right, and SPX is feasible.
* Alan Cox : Fixed write select of non IP protocol crash.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -35,7 +36,7 @@ ...@@ -35,7 +36,7 @@
#include "udp.h" #include "udp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sock.h" #include "sock.h"
/* /*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
...@@ -46,16 +47,16 @@ ...@@ -46,16 +47,16 @@
*/ */
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err) struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
{ {
struct sk_buff *skb; struct sk_buff *skb;
/* Socket is inuse - so the timer doesn't attack it */ /* Socket is inuse - so the timer doesn't attack it */
restart: restart:
sk->inuse = 1; sk->inuse = 1;
while(sk->rqueue == NULL) /* No data */ while(sk->rqueue == NULL) /* No data */
{ {
/* If we are shutdown then no more data is going to appear. We are done */ /* If we are shutdown then no more data is going to appear. We are done */
if (sk->shutdown & RCV_SHUTDOWN) if (sk->shutdown & RCV_SHUTDOWN)
{ {
release_sock(sk); release_sock(sk);
*err=0; *err=0;
...@@ -69,7 +70,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, ...@@ -69,7 +70,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
sk->err=0; sk->err=0;
return NULL; return NULL;
} }
/* Sequenced packets can come disconnected. If so we report the problem */ /* Sequenced packets can come disconnected. If so we report the problem */
if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED) if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
{ {
...@@ -77,24 +78,24 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, ...@@ -77,24 +78,24 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
*err=-ENOTCONN; *err=-ENOTCONN;
return NULL; return NULL;
} }
/* User doesn't want to wait */ /* User doesn't want to wait */
if (noblock) if (noblock)
{ {
release_sock(sk); release_sock(sk);
*err=-EAGAIN; *err=-EAGAIN;
return NULL; return NULL;
} }
release_sock(sk); 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 */ Otherwise we might miss our wake up */
cli(); cli();
if (sk->rqueue == NULL) if (sk->rqueue == NULL)
{ {
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
/* Signals may need a restart of the syscall */ /* Signals may need a restart of the syscall */
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked)
{ {
sti(); sti();
*err=-ERESTARTSYS; *err=-ERESTARTSYS;
...@@ -115,26 +116,26 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, ...@@ -115,26 +116,26 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
} }
/* Again only user level code calls this function, so nothing interrupt level /* Again only user level code calls this function, so nothing interrupt level
will suddenely eat the rqueue */ will suddenely eat the rqueue */
if (!(flags & MSG_PEEK)) if (!(flags & MSG_PEEK))
{ {
skb=skb_dequeue(&sk->rqueue); skb=skb_dequeue(&sk->rqueue);
if(skb!=NULL) if(skb!=NULL)
skb->users++; skb->users++;
else else
goto restart; /* Avoid race if someone beats us to the data */ goto restart; /* Avoid race if someone beats us to the data */
} }
else else
{ {
cli(); cli();
skb=skb_peek(&sk->rqueue); skb=skb_peek(&sk->rqueue);
if(skb!=NULL) if(skb!=NULL)
skb->users++; skb->users++;
sti(); sti();
if(skb==NULL) /* shouldn't happen but .. */ if(skb==NULL) /* shouldn't happen but .. */
*err=-EAGAIN; *err=-EAGAIN;
} }
return skb; return skb;
} }
void skb_free_datagram(struct sk_buff *skb) void skb_free_datagram(struct sk_buff *skb)
{ {
...@@ -156,7 +157,7 @@ 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) 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 */ but not this release */
memcpy_tofs(to,skb->h.raw+offset,size); 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) ...@@ -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 * Datagram select: Again totally generic. Moved from udp.c
* Now does seqpacket. * Now does seqpacket.
*/ */
int datagram_select(struct sock *sk, int sel_type, select_table *wait) int datagram_select(struct sock *sk, int sel_type, select_table *wait)
{ {
select_wait(sk->sleep, wait); select_wait(sk->sleep, wait);
switch(sel_type) switch(sel_type)
{ {
case SEL_IN: case SEL_IN:
if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE) 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) ...@@ -177,7 +178,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
/* Connection closed: Wake up */ /* Connection closed: Wake up */
return(1); return(1);
} }
if (sk->rqueue != NULL || sk->err != 0) if (sk->rqueue != NULL || sk->err != 0)
{ /* This appears to be consistent { /* This appears to be consistent
with other stacks */ with other stacks */
return(1); return(1);
...@@ -185,16 +186,20 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait) ...@@ -185,16 +186,20 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return(0); return(0);
case SEL_OUT: 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(1);
} }
return(0); return(0);
case SEL_EX: case SEL_EX:
if (sk->err) if (sk->err)
return(1); /* Socket has gone into error state (eg icmp error) */ return(1); /* Socket has gone into error state (eg icmp error) */
return(0); return(0);
} }
return(0); return(0);
} }
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
* a) actually works for all A/B nets * a) actually works for all A/B nets
* b) doesn't forward off the same interface. * b) doesn't forward off the same interface.
* Alan Cox: Multiple extra protocols * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -709,9 +713,12 @@ dev_ifconf(char *arg) ...@@ -709,9 +713,12 @@ dev_ifconf(char *arg)
struct device *dev; struct device *dev;
char *pos; char *pos;
int len; int len;
int err;
/* Fetch the caller's info block. */ /* 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)); memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
len = ifc.ifc_len; len = ifc.ifc_len;
pos = ifc.ifc_buf; pos = ifc.ifc_buf;
...@@ -800,7 +807,9 @@ dev_ifsioc(void *arg, unsigned int getset) ...@@ -800,7 +807,9 @@ dev_ifsioc(void *arg, unsigned int getset)
int ret; int ret;
/* Fetch the caller's info block. */ /* 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)); memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));
/* See which interface the caller is talking about. */ /* See which interface the caller is talking about. */
...@@ -827,8 +836,12 @@ dev_ifsioc(void *arg, unsigned int getset) ...@@ -827,8 +836,12 @@ dev_ifsioc(void *arg, unsigned int getset)
if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) { if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
ret = dev_close(dev); ret = dev_close(dev);
} else } else
{
ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
? dev_open(dev) : 0; ? dev_open(dev) : 0;
if(ret<0)
dev->flags&=~IFF_UP; /* Didnt open so down the if */
}
} }
break; break;
case SIOCGIFADDR: case SIOCGIFADDR:
...@@ -946,55 +959,9 @@ dev_ioctl(unsigned int cmd, void *arg) ...@@ -946,55 +959,9 @@ dev_ioctl(unsigned int cmd, void *arg)
int ret; int ret;
switch(cmd) { switch(cmd) {
case IP_SET_DEV: case IP_SET_DEV:
{ /* Maintain backwards-compatibility, to be deleted for 1.00. */ printk("Your network configuration program needs upgrading.\n");
struct device *dev; return -EINVAL;
/* 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 SIOCGIFCONF: case SIOCGIFCONF:
(void) dev_ifconf((char *) arg); (void) dev_ifconf((char *) arg);
ret = 0; ret = 0;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* Alan Cox : eth_header ntohs should be htons * Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and * Alan Cox : eth_rebuild_header missing an htons and
* minor other things. * minor other things.
* Tegge : Arp bug fixes.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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, ...@@ -124,7 +125,7 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
cli(); cli();
memcpy(eth->h_source, &saddr, 4); memcpy(eth->h_source, &saddr, 4);
/* No. Ask ARP to resolve the Ethernet address. */ /* 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(); sti();
if(type!=ETH_P_IP) if(type!=ETH_P_IP)
...@@ -155,7 +156,7 @@ eth_rebuild_header(void *buff, struct device *dev) ...@@ -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, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst))); 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(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); memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return(0); return(0);
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* Fixes: * Fixes:
* Alan Cox : Generic queue usage. * Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected * Gerhard Koerting: ICMP addressing corrected
* Alan Cox : Use tos/ttl settings
* *
* *
* This program is free software; you can redistribute it and/or * 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) ...@@ -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. */ /* Build Layer 2-3 headers for message back to source. */
offset = ip_build_header(skb, dev->pa_addr, iph->saddr, 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) { if (offset < 0) {
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
...@@ -255,7 +256,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, ...@@ -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 */ /* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev, offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len); IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
if (offset < 0) { if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ECHO Response\n"); printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
kfree_skb(skb2,FREE_WRITE); kfree_skb(skb2,FREE_WRITE);
...@@ -319,7 +320,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, ...@@ -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 */ /* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev, offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len); IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
if (offset < 0) { if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n"); printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
kfree_skb(skb2,FREE_WRITE); kfree_skb(skb2,FREE_WRITE);
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
* Gerhard Koerting: IP interface addressing fix. * Gerhard Koerting: IP interface addressing fix.
* Linus Torvalds : More robustness checks * Linus Torvalds : More robustness checks
* Alan Cox : Even more checks: Still not as robust as it ought to be * 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: * To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules * 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, ...@@ -198,7 +201,7 @@ ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
*/ */
int int
ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, 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; static struct options optmem;
struct iphdr *iph; struct iphdr *iph;
...@@ -256,9 +259,9 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, ...@@ -256,9 +259,9 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
iph = (struct iphdr *)buff; iph = (struct iphdr *)buff;
iph->version = 4; iph->version = 4;
iph->tos = 0; iph->tos = tos;
iph->frag_off = 0; iph->frag_off = 0;
iph->ttl = 32; iph->ttl = ttl;
iph->daddr = daddr; iph->daddr = daddr;
iph->saddr = saddr; iph->saddr = saddr;
iph->protocol = type; iph->protocol = type;
...@@ -1267,6 +1270,8 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -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. */ /* Point into the IP datagram, just past the header. */
skb->ip_hdr = iph;
skb->h.raw += iph->ihl*4; skb->h.raw += iph->ihl*4;
hash = iph->protocol & (MAX_INET_PROTOS -1); hash = iph->protocol & (MAX_INET_PROTOS -1);
for (ipprot = (struct inet_protocol *)inet_protos[hash]; for (ipprot = (struct inet_protocol *)inet_protos[hash];
...@@ -1504,3 +1509,72 @@ int backoff(int n) ...@@ -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);
}
...@@ -69,7 +69,8 @@ extern int ip_build_header(struct sk_buff *skb, ...@@ -69,7 +69,8 @@ extern int ip_build_header(struct sk_buff *skb,
unsigned long saddr, unsigned long saddr,
unsigned long daddr, unsigned long daddr,
struct device **dev, int type, 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 unsigned short ip_compute_csum(unsigned char * buff, int len);
extern int ip_rcv(struct sk_buff *skb, struct device *dev, extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt); struct packet_type *pt);
...@@ -77,5 +78,7 @@ extern void ip_queue_xmit(struct sock *sk, ...@@ -77,5 +78,7 @@ extern void ip_queue_xmit(struct sock *sk,
struct device *dev, struct sk_buff *skb, struct device *dev, struct sk_buff *skb,
int free); int free);
extern void ip_retransmit(struct sock *sk, int all); 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 */ #endif /* _IP_H */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* added. Also fixed the peek/read crash * added. Also fixed the peek/read crash
* from all old Linux datagram code. * from all old Linux datagram code.
* Alan Cox : Uses the improved 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 * This program is free software; you can redistribute it and/or
...@@ -264,6 +265,8 @@ struct proto packet_prot = { ...@@ -264,6 +265,8 @@ struct proto packet_prot = {
NULL, NULL,
packet_init, packet_init,
NULL, NULL,
NULL, /* No set/get socket options */
NULL,
128, 128,
0, 0,
{NULL,}, {NULL,},
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
* Alan Cox : Checks sk->broadcast. * Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram * Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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, ...@@ -76,7 +80,7 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
} }
sk->err = icmp_err_convert[err & 0xff].errno; sk->err = icmp_err_convert[err & 0xff].errno;
wake_up(sk->sleep); sk->error_report(sk);
return; return;
} }
...@@ -123,7 +127,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -123,7 +127,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
} }
sk->rmem_alloc += skb->mem_len; sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb); skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep); sk->data_ready(sk,skb->len);
release_sock(sk); release_sock(sk);
return(0); return(0);
} }
...@@ -169,7 +173,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -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 (sin.sin_port == 0) sin.sin_port = sk->protocol;
if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -ENETUNREACH; return -EACCES;
sk->inuse = 1; sk->inuse = 1;
skb = NULL; skb = NULL;
...@@ -214,7 +218,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -214,7 +218,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp = sk->prot->build_header(skb, sk->saddr, tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev, 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) { if (tmp < 0) {
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
kfree_skb(skb,FREE_WRITE); kfree_skb(skb,FREE_WRITE);
...@@ -330,6 +334,13 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -330,6 +334,13 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
return err; return err;
put_fs_long(sizeof(*sin), addr_len); 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); err=verify_area(VERIFY_WRITE,to,len);
if(err) if(err)
return err; return err;
...@@ -348,7 +359,6 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -348,7 +359,6 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = skb->daddr; addr.sin_addr.s_addr = skb->daddr;
verify_area(VERIFY_WRITE, sin, sizeof(*sin));
memcpy_tofs(sin, &addr, sizeof(*sin)); memcpy_tofs(sin, &addr, sizeof(*sin));
} }
...@@ -390,6 +400,8 @@ struct proto raw_prot = { ...@@ -390,6 +400,8 @@ struct proto raw_prot = {
NULL, NULL,
raw_init, raw_init,
NULL, NULL,
ip_setsockopt,
ip_getsockopt,
128, 128,
0, 0,
{NULL,}, {NULL,},
......
...@@ -121,21 +121,27 @@ void rt_flush(struct device *dev) ...@@ -121,21 +121,27 @@ void rt_flush(struct device *dev)
* number of zero 8-bit net numbers, otherwise we use the "default" * number of zero 8-bit net numbers, otherwise we use the "default"
* masks judging by the destination address and our device netmask. * 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) static unsigned long guess_mask(unsigned long dst, struct device * dev)
{ {
unsigned long mask = 0xffffffff; unsigned long mask = 0xffffffff;
/* this is a rather ugly optimization: works only on little-endian machines */
while (mask & dst) while (mask & dst)
mask >>= 8; mask <<= 8;
if (mask) if (mask)
return ~mask; return ~mask;
dst = ntohl(dst); /* ok, no more hacks.. */
if (IN_CLASSA(dst)) mask = default_mask(dst);
mask = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(dst))
mask = htonl(IN_CLASSB_NET);
else
mask = htonl(IN_CLASSC_NET);
if (dev->flags & IFF_POINTOPOINT) if (dev->flags & IFF_POINTOPOINT)
return mask; return mask;
if ((dst ^ dev->pa_addr) & mask) if ((dst ^ dev->pa_addr) & mask)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* and memory leak hunting. * and memory leak hunting.
* Alan Cox : More generic kfree handler * Alan Cox : More generic kfree handler
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -44,14 +44,14 @@ ...@@ -44,14 +44,14 @@
/* /*
* Resource tracking variables * Resource tracking variables
*/ */
volatile unsigned long net_memory=0; volatile unsigned long net_memory=0;
volatile unsigned long net_skbcount=0; volatile unsigned long net_skbcount=0;
/* /*
* Debugging paranoia. Can go later when this crud stack works * Debugging paranoia. Can go later when this crud stack works
*/ */
void skb_check(struct sk_buff *skb, int line, char *file) 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) ...@@ -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. * Insert an sk_buff at the start of a list.
*/ */
void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk) void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
{ {
unsigned long flags; unsigned long flags;
IS_SKB(newsk); IS_SKB(newsk);
if(newsk->list) if(newsk->list)
printk("Suspicious queue head: sk_buff on list!\n"); printk("Suspicious queue head: sk_buff on list!\n");
save_flags(flags); save_flags(flags);
cli(); cli();
newsk->list=list; newsk->list=list;
newsk->next=*list; newsk->next=*list;
if(*list) if(*list)
newsk->prev=(*list)->prev; newsk->prev=(*list)->prev;
else else
...@@ -110,14 +110,14 @@ void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk) ...@@ -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. * Insert an sk_buff at the end of a list.
*/ */
void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk) void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
{ {
unsigned long flags; unsigned long flags;
if(newsk->list) if(newsk->list)
printk("Suspicious queue tail: sk_buff on list!\n"); printk("Suspicious queue tail: sk_buff on list!\n");
IS_SKB(newsk); IS_SKB(newsk);
save_flags(flags); save_flags(flags);
cli(); cli();
...@@ -137,7 +137,7 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk) ...@@ -137,7 +137,7 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
*list=newsk; *list=newsk;
} }
IS_SKB(newsk->prev); IS_SKB(newsk->prev);
IS_SKB(newsk->next); IS_SKB(newsk->next);
restore_flags(flags); restore_flags(flags);
} }
...@@ -146,21 +146,21 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk) ...@@ -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 * 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. * so you can grab read and free buffers as another process adds them.
*/ */
struct sk_buff *skb_dequeue(struct sk_buff *volatile* list) struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
{ {
long flags; long flags;
struct sk_buff *result; struct sk_buff *result;
save_flags(flags); save_flags(flags);
cli(); cli();
if(*list==NULL) if(*list==NULL)
{ {
restore_flags(flags); restore_flags(flags);
return(NULL); return(NULL);
} }
result=*list; result=*list;
if(result->next==result) if(result->next==result)
*list=NULL; *list=NULL;
...@@ -173,7 +173,7 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list) ...@@ -173,7 +173,7 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
IS_SKB(result); IS_SKB(result);
restore_flags(flags); restore_flags(flags);
if(result->list!=list) if(result->list!=list)
printk("Dequeued packet has invalid list pointer\n"); printk("Dequeued packet has invalid list pointer\n");
...@@ -186,19 +186,19 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list) ...@@ -186,19 +186,19 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
/* /*
* Insert a packet before another one in a list. * Insert a packet before another one in a list.
*/ */
void skb_insert(struct sk_buff *old, struct sk_buff *newsk) void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
{ {
unsigned long flags; unsigned long flags;
IS_SKB(old); IS_SKB(old);
IS_SKB(newsk); IS_SKB(newsk);
if(!old->list) if(!old->list)
printk("insert before unlisted item!\n"); printk("insert before unlisted item!\n");
if(newsk->list) if(newsk->list)
printk("inserted item is already on a list.\n"); printk("inserted item is already on a list.\n");
save_flags(flags); save_flags(flags);
cli(); cli();
newsk->list=old->list; newsk->list=old->list;
...@@ -206,18 +206,18 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk) ...@@ -206,18 +206,18 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
newsk->prev=old->prev; newsk->prev=old->prev;
newsk->next->prev=newsk; newsk->next->prev=newsk;
newsk->prev->next=newsk; newsk->prev->next=newsk;
restore_flags(flags); restore_flags(flags);
} }
/* /*
* Place a packet after a given packet in a list. * Place a packet after a given packet in a list.
*/ */
void skb_append(struct sk_buff *old, struct sk_buff *newsk) void skb_append(struct sk_buff *old, struct sk_buff *newsk)
{ {
unsigned long flags; unsigned long flags;
IS_SKB(old); IS_SKB(old);
IS_SKB(newsk); IS_SKB(newsk);
...@@ -225,7 +225,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk) ...@@ -225,7 +225,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
printk("append before unlisted item!\n"); printk("append before unlisted item!\n");
if(newsk->list) if(newsk->list)
printk("append item is already on a list.\n"); printk("append item is already on a list.\n");
save_flags(flags); save_flags(flags);
cli(); cli();
newsk->list=old->list; newsk->list=old->list;
...@@ -233,7 +233,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk) ...@@ -233,7 +233,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
newsk->next=old->next; newsk->next=old->next;
newsk->next->prev=newsk; newsk->next->prev=newsk;
newsk->prev->next=newsk; newsk->prev->next=newsk;
restore_flags(flags); restore_flags(flags);
} }
...@@ -243,7 +243,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk) ...@@ -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 * MUST EXIST when you unlink. Thus a list must have its contents unlinked
* _FIRST_. * _FIRST_.
*/ */
void skb_unlink(struct sk_buff *skb) void skb_unlink(struct sk_buff *skb)
{ {
unsigned long flags; unsigned long flags;
...@@ -251,7 +251,7 @@ void skb_unlink(struct sk_buff *skb) ...@@ -251,7 +251,7 @@ void skb_unlink(struct sk_buff *skb)
cli(); cli();
IS_SKB(skb); IS_SKB(skb);
if(skb->list) if(skb->list)
{ {
skb->next->prev=skb->prev; skb->next->prev=skb->prev;
...@@ -290,7 +290,7 @@ void skb_new_list_head(struct sk_buff *volatile* list) ...@@ -290,7 +290,7 @@ void skb_new_list_head(struct sk_buff *volatile* list)
while(skb!=*list); while(skb!=*list);
} }
} }
/* /*
* Peek an sk_buff. Unlike most other operations you _MUST_ * Peek an sk_buff. Unlike most other operations you _MUST_
* be careful with this one. A peek leaves the buffer on the * 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) ...@@ -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 * anyway. Only the memcpy of upto 4K with ints off is not
* as nice as I'd like. * as nice as I'd like.
*/ */
struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list) struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
{ {
struct sk_buff *orig,*newsk; struct sk_buff *orig,*newsk;
unsigned long flags; unsigned long flags;
unsigned int len; unsigned int len;
/* Now for some games to avoid races */ /* Now for some games to avoid races */
do do
{ {
save_flags(flags); save_flags(flags);
...@@ -336,7 +336,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list) ...@@ -336,7 +336,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
if(newsk==NULL) /* Oh dear... not to worry */ if(newsk==NULL) /* Oh dear... not to worry */
return NULL; return NULL;
save_flags(flags); save_flags(flags);
cli(); cli();
if(skb_peek(list)!=orig) /* List changed go around another time */ 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) ...@@ -349,7 +349,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
kfree_skb(newsk, FREE_WRITE); kfree_skb(newsk, FREE_WRITE);
continue; continue;
} }
IS_SKB(orig); IS_SKB(orig);
IS_SKB(newsk); IS_SKB(newsk);
memcpy(newsk,orig,len); memcpy(newsk,orig,len);
...@@ -364,11 +364,11 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list) ...@@ -364,11 +364,11 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
newsk->free=1; newsk->free=1;
} }
while(0); while(0);
restore_flags(flags); restore_flags(flags);
return(newsk); return(newsk);
} }
/* /*
* Free an sk_buff. This still knows about things it should * Free an sk_buff. This still knows about things it should
* not need to like protocols and sockets. * not need to like protocols and sockets.
...@@ -376,68 +376,68 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list) ...@@ -376,68 +376,68 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
void kfree_skb(struct sk_buff *skb, int rw) void kfree_skb(struct sk_buff *skb, int rw)
{ {
if (skb == NULL) { if (skb == NULL) {
printk("kfree_skb: skb = NULL\n"); printk("kfree_skb: skb = NULL\n");
return; 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);
} }
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)
if (rw) skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
skb->sk->rmem_alloc-=skb->mem_len; else
skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
}
else 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); wake_up(skb->sk->sleep);
kfree_skbmem(skb->mem_addr,skb->mem_len); kfree_skbmem(skb->mem_addr,skb->mem_len);
}
} }
} else
else kfree_skbmem(skb->mem_addr, skb->mem_len);
kfree_skbmem(skb->mem_addr, skb->mem_len);
} }
/* /*
* Allocate a new skbuff. We do this ourselves so we can fill in a few 'private' * 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. * 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 *alloc_skb(unsigned int size,int priority)
{ {
struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority); struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
if(skb==NULL) if(skb==NULL)
return NULL; return NULL;
skb->free= 2; /* Invalid so we pick up forgetful users */ skb->free= 2; /* Invalid so we pick up forgetful users */
skb->list= 0; /* Not on a list */ skb->list= 0; /* Not on a list */
skb->truesize=size; skb->truesize=size;
skb->mem_len=size; skb->mem_len=size;
skb->mem_addr=skb; skb->mem_addr=skb;
skb->fraglist=NULL; skb->fraglist=NULL;
net_memory+=size; net_memory+=size;
net_skbcount++; net_skbcount++;
skb->magic_debug_cookie=SK_GOOD_SKB; skb->magic_debug_cookie=SK_GOOD_SKB;
skb->users=0; skb->users=0;
return skb; return skb;
} }
/* /*
* Free an skbuff by memory * Free an skbuff by memory
*/ */
void kfree_skbmem(void *mem,unsigned size) void kfree_skbmem(void *mem,unsigned size)
{ {
...@@ -451,4 +451,4 @@ void kfree_skbmem(void *mem,unsigned size) ...@@ -451,4 +451,4 @@ void kfree_skbmem(void *mem,unsigned size)
net_memory-=size; net_memory-=size;
} }
} }
...@@ -60,6 +60,7 @@ struct sk_buff { ...@@ -60,6 +60,7 @@ struct sk_buff {
ipx_packet *ipx; ipx_packet *ipx;
#endif #endif
} h; } h;
struct iphdr *ip_hdr; /* For IPPROTO_RAW */
unsigned long mem_len; unsigned long mem_len;
unsigned long len; unsigned long len;
unsigned long fraglen; unsigned long fraglen;
......
This diff is collapsed.
...@@ -136,7 +136,11 @@ struct sock { ...@@ -136,7 +136,11 @@ struct sock {
char ax25_retxqi; char ax25_retxqi;
char ax25_rrtimer; char ax25_rrtimer;
char ax25_timer; char ax25_timer;
ax25_digi *ax25_digipeat;
#endif #endif
/* IP 'private area' or will be eventually */
int ip_ttl; /* TTL setting */
int ip_tos; /* TOS */
struct tcphdr dummy_th; struct tcphdr dummy_th;
/* This part is used for the timeout functions (timer.c). */ /* This part is used for the timeout functions (timer.c). */
...@@ -145,6 +149,13 @@ struct sock { ...@@ -145,6 +149,13 @@ struct sock {
/* identd */ /* identd */
struct socket *socket; 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 { struct proto {
...@@ -177,7 +188,7 @@ struct proto { ...@@ -177,7 +188,7 @@ struct proto {
unsigned long saddr, unsigned long saddr,
unsigned long daddr, unsigned long daddr,
struct device **dev, int type, struct device **dev, int type,
struct options *opt, int len); struct options *opt, int len, int tos, int ttl);
int (*connect)(struct sock *sk, int (*connect)(struct sock *sk,
struct sockaddr_in *usin, int addr_len); struct sockaddr_in *usin, int addr_len);
struct sock *(*accept) (struct sock *sk, int flags); struct sock *(*accept) (struct sock *sk, int flags);
...@@ -197,6 +208,10 @@ struct proto { ...@@ -197,6 +208,10 @@ struct proto {
unsigned long arg); unsigned long arg);
int (*init)(struct sock *sk); int (*init)(struct sock *sk);
void (*shutdown)(struct sock *sk, int how); 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 short max_header;
unsigned long retransmits; unsigned long retransmits;
struct sock *sock_array[SOCK_ARRAY_SIZE]; struct sock *sock_array[SOCK_ARRAY_SIZE];
...@@ -238,6 +253,8 @@ extern void sock_rfree(struct sock *sk, void *mem, ...@@ -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_rspace(struct sock *sk);
extern unsigned long sock_wspace(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 */ /* declarations from timer.c */
extern struct sock *timer_base; extern struct sock *timer_base;
......
This diff is collapsed.
...@@ -141,7 +141,7 @@ net_timer (unsigned long data) ...@@ -141,7 +141,7 @@ net_timer (unsigned long data)
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
delete_timer (sk); delete_timer (sk);
/* Kill the ARP entry in case the hardware has changed. */ /* Kill the ARP entry in case the hardware has changed. */
arp_destroy (sk->daddr); arp_destroy_maybe (sk->daddr);
if (!sk->dead) if (!sk->dead)
wake_up (sk->sleep); wake_up (sk->sleep);
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
...@@ -167,7 +167,7 @@ net_timer (unsigned long data) ...@@ -167,7 +167,7 @@ net_timer (unsigned long data)
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); 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); ip_route_check (sk->daddr);
} }
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
...@@ -198,14 +198,14 @@ net_timer (unsigned long data) ...@@ -198,14 +198,14 @@ net_timer (unsigned long data)
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); 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); ip_route_check (sk->daddr);
release_sock (sk); release_sock (sk);
break; break;
} }
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
arp_destroy (sk->daddr); arp_destroy_maybe (sk->daddr);
sk->err = ETIMEDOUT; sk->err = ETIMEDOUT;
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) { if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
sk->state = TCP_TIME_WAIT; sk->state = TCP_TIME_WAIT;
......
...@@ -30,10 +30,11 @@ ...@@ -30,10 +30,11 @@
* bug no longer crashes it. * bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast. * Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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 ...@@ -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 */ if (err < 0) /* As per the calling spec */
{ {
sk->err = -err; sk->err = -err;
wake_up(sk->sleep); /* User process wakes to see error */ sk->error_report(sk); /* User process wakes to see error */
return; return;
} }
...@@ -130,7 +131,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th ...@@ -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) { if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
sk->err=ECONNREFUSED; sk->err=ECONNREFUSED;
} }
wake_up(sk->sleep); sk->error_report(sk);
} }
...@@ -249,7 +250,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin, ...@@ -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", 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)); saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr, 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 */ skb->sk=sk; /* So memory is freed correctly */
if (tmp < 0 ) { if (tmp < 0 ) {
...@@ -335,7 +336,7 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock, ...@@ -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) 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; sk->inuse = 1;
/* Send the packet. */ /* Send the packet. */
...@@ -522,7 +523,7 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) ...@@ -522,7 +523,7 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return(-EAFNOSUPPORT); return(-EAFNOSUPPORT);
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) 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->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port; sk->dummy_th.dest = sin.sin_port;
...@@ -604,8 +605,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -604,8 +605,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->len = len - sizeof(*uh); skb->len = len - sizeof(*uh);
if (!sk->dead) wake_up(sk->sleep); if (!sk->dead)
sk->data_ready(sk,skb->len);
release_sock(sk); release_sock(sk);
return(0); return(0);
} }
...@@ -635,6 +637,8 @@ struct proto udp_prot = { ...@@ -635,6 +637,8 @@ struct proto udp_prot = {
udp_ioctl, udp_ioctl,
NULL, NULL,
NULL, NULL,
ip_setsockopt,
ip_getsockopt,
128, 128,
0, 0,
{NULL,}, {NULL,},
......
...@@ -12,11 +12,12 @@ ...@@ -12,11 +12,12 @@
* *
* Fixes: * Fixes:
* Alan Cox : Verify Area * Alan Cox : Verify Area
* NET2E Team : Page fault locks
* *
* BUGS * To Do:
* Page faults on read while another process reads could lose data. *
* Page faults on write happen to interleave data (probably not allowed) * Change to the NET2E3 code for Unix domain sockets in general. The
* with any other simultaneous writers on the socket but dont cause harm. * read/write logic is much better and cleaner.
* *
* *
* This program is free software; you can redistribute it and/or * 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) ...@@ -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. */ /* don't have to do anything. */
static int static int
unix_proto_listen(struct socket *sock, int backlog) unix_proto_listen(struct socket *sock, int backlog)
...@@ -598,6 +622,8 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -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, * Copy from the read buffer into the user's buffer,
* watching for wraparound. Then we wake up the writer. * watching for wraparound. Then we wake up the writer.
*/ */
unix_lock(upd);
do { do {
int part, cando; int part, cando;
...@@ -612,7 +638,10 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -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", dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
avail, todo, cando); avail, todo, cando);
if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0) if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
{
unix_unlock(upd);
return er; return er;
}
memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando); memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1); upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
ubuf += cando; ubuf += cando;
...@@ -620,6 +649,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -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); if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
avail = UN_BUF_AVAIL(upd); avail = UN_BUF_AVAIL(upd);
} while(todo && avail); } while(todo && avail);
unix_unlock(upd);
return(size - todo); return(size - todo);
} }
...@@ -666,6 +696,9 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -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, * Copy from the user's buffer to the write buffer,
* watching for wraparound. Then we wake up the reader. * watching for wraparound. Then we wake up the reader.
*/ */
unix_lock(pupd);
do { do {
int part, cando; int part, cando;
...@@ -681,6 +714,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -681,6 +714,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
*/ */
if (sock->state == SS_DISCONNECTING) { if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1); send_sig(SIGPIPE, current, 1);
unix_unlock(pupd);
return(-EPIPE); return(-EPIPE);
} }
if ((cando = todo) > space) cando = space; if ((cando = todo) > space) cando = space;
...@@ -689,7 +723,10 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -689,7 +723,10 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
space, todo, cando); space, todo, cando);
er=verify_area(VERIFY_READ, ubuf, cando); er=verify_area(VERIFY_READ, ubuf, cando);
if(er) if(er)
{
unix_unlock(pupd);
return er; return er;
}
memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1); pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
ubuf += cando; ubuf += cando;
...@@ -697,6 +734,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) ...@@ -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); if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
space = UN_BUF_SPACE(pupd); space = UN_BUF_SPACE(pupd);
} while(todo && space); } while(todo && space);
unix_unlock(pupd);
return(size - todo); return(size - todo);
} }
...@@ -842,6 +880,8 @@ unix_ioctl(struct inode *inode, struct file *file, ...@@ -842,6 +880,8 @@ unix_ioctl(struct inode *inode, struct file *file,
} }
static struct file_operations unix_fops = { static struct file_operations unix_fops = {
NULL, /* LSEEK */ NULL, /* LSEEK */
NULL, /* READ */ NULL, /* READ */
......
...@@ -35,6 +35,8 @@ struct unix_proto_data { ...@@ -35,6 +35,8 @@ struct unix_proto_data {
int bp_head, bp_tail; int bp_head, bp_tail;
struct inode *inode; struct inode *inode;
struct unix_proto_data *peerupd; 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]; extern struct unix_proto_data unix_datas[NSOCKETS];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment