aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1993-02-09 22:03:01 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:12 -0400
commit1680d965ceb874b34ebbc3788fdb1b0dd594f043 (patch)
tree4ec1dc6b7651f2e57cff25c70c4b10663d74c345
parentb75fb8468bb5353db99f69805408db991ac0ed39 (diff)
downloadarchive-1680d965ceb874b34ebbc3788fdb1b0dd594f043.tar.gz
ANNOUNCE: linux 0.99 patchelevel 5 availablev0.99-pl5
"He's done it yet again - doesn't he ever rest?" - anonymous linux kernel hacker Only complete newbies don't know what this is all about, but I'd better tell you anyway: patchlevel 5 of the 0.99 kernel is now available on nic.funet.fi (pub/OS/Linux/PEOPLE/Linus) as both context diffs against pl4 and complete source code. I'm not even going to speculate on 1.0 right now. The pl5 diffs are about 90kB compressed: the major changes are to the tcp/ip code and the serial driver, while there are various minor fixes strewn around the system: - serial lines/tty changes (tytso & Fred v Kempen) - NFS bugfixes (Rick Sladkey) - tcp/ip (Ross Biro) - coprocessor handling changes (me) - harddisk driver error handling (Mika Liljeberg) - various minor patches (me and others) Serial lines now implement non-blocking opens correctly and support dial-out lines (same minor, major==5). I changed the default startup mode to be CLOCAL so that people won't get confused by the modem line code when not using dial-in. Another interesting change is the 387 error-coupling tests at bootup: the code to check if the intel-recommended exception 16 error reporting is present is "non-obvious". If you have had problems with coprocessor error handling, or have a non-intel coprocessor, I'd suggest you test this out: I'd like to hear about problems/successes. Linus PS. If you tested out the latest ALPHA-diffs (the ones that already changed the kernel version to pl5), the changes to the final pl5 were only cosmetic.
-rw-r--r--Makefile4
-rw-r--r--boot/setup.S9
-rw-r--r--config.in4
-rw-r--r--fs/buffer.c19
-rw-r--r--fs/ext/freelists.c27
-rw-r--r--fs/inode.c4
-rw-r--r--fs/ioctl.c5
-rw-r--r--fs/isofs/file.c6
-rw-r--r--fs/locks.c3
-rw-r--r--fs/minix/bitmap.c6
-rw-r--r--fs/nfs/dir.c4
-rw-r--r--fs/nfs/file.c18
-rw-r--r--fs/nfs/inode.c39
-rw-r--r--fs/nfs/proc.c115
-rw-r--r--fs/nfs/sock.c2
-rw-r--r--fs/open.c16
-rw-r--r--fs/proc/array.c13
-rw-r--r--fs/proc/base.c4
-rw-r--r--include/linux/fs.h11
-rw-r--r--include/linux/interrupt.h1
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/serial.h9
-rw-r--r--include/linux/sock_ioctl.h21
-rw-r--r--include/linux/termios.h7
-rw-r--r--include/linux/tty.h37
-rw-r--r--init/main.c18
-rw-r--r--kernel/FPU-emu/README13
-rw-r--r--kernel/FPU-emu/errors.c2
-rw-r--r--kernel/FPU-emu/fpu_entry.c42
-rw-r--r--kernel/FPU-emu/get_address.c2
-rw-r--r--kernel/FPU-emu/load_store.c2
-rw-r--r--kernel/FPU-emu/reg_div.S2
-rw-r--r--kernel/FPU-emu/version.h2
-rw-r--r--kernel/blk_drv/genhd.c42
-rw-r--r--kernel/blk_drv/hd.c45
-rw-r--r--kernel/blk_drv/scsi/scsi.c4
-rw-r--r--kernel/blk_drv/scsi/wd7000.c23
-rw-r--r--kernel/chr_drv/busmouse.c20
-rw-r--r--kernel/chr_drv/console.c25
-rw-r--r--kernel/chr_drv/pty.c9
-rw-r--r--kernel/chr_drv/serial.c633
-rw-r--r--kernel/chr_drv/tty_io.c265
-rw-r--r--kernel/chr_drv/tty_ioctl.c122
-rw-r--r--kernel/fork.c7
-rw-r--r--kernel/irq.c20
-rw-r--r--kernel/sched.c7
-rw-r--r--kernel/sys.c11
-rw-r--r--kernel/traps.c1
-rw-r--r--mm/memory.c28
-rw-r--r--net/kern_sock.h6
-rw-r--r--net/socket.c17
-rw-r--r--net/tcp/Space.c8
-rw-r--r--net/tcp/arp.c94
-rw-r--r--net/tcp/arp.h18
-rw-r--r--net/tcp/dev.c137
-rw-r--r--net/tcp/dev.h25
-rw-r--r--net/tcp/eth.c5
-rw-r--r--net/tcp/icmp.c13
-rw-r--r--net/tcp/ip.c206
-rw-r--r--net/tcp/ip.h15
-rw-r--r--net/tcp/loopback.c53
-rw-r--r--net/tcp/packet.c22
-rw-r--r--net/tcp/raw.c17
-rw-r--r--net/tcp/sock.c149
-rw-r--r--net/tcp/sock.h47
-rw-r--r--net/tcp/tcp.c338
-rw-r--r--net/tcp/tcp.h5
-rw-r--r--net/tcp/timer.c24
-rw-r--r--net/tcp/timer.h10
-rw-r--r--net/tcp/udp.c20
-rw-r--r--net/tcp/we.c60
-rw-r--r--net/unix.c14
72 files changed, 1993 insertions, 1040 deletions
diff --git a/Makefile b/Makefile
index f377e4a..0ef7fab 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,8 @@
all: Version Image
+.EXPORT_ALL_VARIABLES:
+
#
# Make "config" the default target if there is no configuration file or
# "depend" the target if there is no top-level dependency information.
@@ -145,7 +147,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile
@./makever.sh
- @echo \#define UTS_RELEASE \"0.99.pl4-`cat .version`\" > tools/version.h
+ @echo \#define UTS_RELEASE \"0.99.pl5-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
diff --git a/boot/setup.S b/boot/setup.S
index 1bebecd..b8db58f 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -436,10 +436,11 @@ noevrx: lea si,idgenoa ! Check Genoa 'clues'
l1: inc si
inc di
mov al,(si)
+ test al,al
+ jz l2
seg es
- and al,(di)
- cmp al,(si)
- loope l1
+ cmp al,(di)
+l2: loope l1
cmp cx,#0x00
jne nogen
lea si,dscgenoa
@@ -697,7 +698,7 @@ msg3: .ascii "Choose mode by pressing the corresponding number."
idati: .ascii "761295520"
idcandt: .byte 0xa5
-idgenoa: .byte 0x77, 0x00, 0x66, 0x99
+idgenoa: .byte 0x77, 0x00, 0x99, 0x66
idparadise: .ascii "VGA="
idoakvga: .ascii "OAK VGA "
idf1280: .ascii "Orchid Technology Fahrenheit 1280"
diff --git a/config.in b/config.in
index 09ae809..d48ff79 100644
--- a/config.in
+++ b/config.in
@@ -35,7 +35,7 @@ Adaptec AHA1740 support
CONFIG_SCSI_AHA1740 y/n y
Future Domain SCSI support
CONFIG_SCSI_FUTURE_DOMAIN y/n y
-Seagate ST-02 SCSI support
+Seagate ST-02 and Future Domain TMC-8xx SCSI support
CONFIG_SCSI_SEAGATE y/n y
UltraStor SCSI support
CONFIG_SCSI_ULTRASTOR y/n y
@@ -49,7 +49,7 @@ CONFIG_MINIX_FS y/n y
Extended fs support
CONFIG_EXT_FS y/n n
msdos fs support
-CONFIG_MSDOS_FS y/n n
+CONFIG_MSDOS_FS y/n y
/proc filesystem support
CONFIG_PROC_FS y/n y
NFS filesystem support
diff --git a/fs/buffer.c b/fs/buffer.c
index 6561bb0..d8bfb60 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -45,6 +45,7 @@ static struct wait_queue * buffer_wait = NULL;
int nr_buffers = 0;
int buffermem = 0;
int nr_buffer_heads = 0;
+static int min_free_pages = 20; /* nr free pages needed before buffer grows */
/*
* Rewrote the wait-routines to use the "new" wait-queue functionality,
@@ -305,6 +306,7 @@ struct buffer_head * getblk(dev_t dev, int block, int size)
{
struct buffer_head * bh, * tmp;
int buffers;
+ static int grow_size = 0;
repeat:
bh = get_hash_table(dev, block, size);
@@ -313,10 +315,13 @@ repeat:
put_last_free(bh);
return bh;
}
-
- if (nr_free_pages > 30 && buffermem < 6*1024*1024)
+ grow_size -= size;
+ if (nr_free_pages > min_free_pages &&
+ buffermem < 6*1024*1024 &&
+ grow_size <= 0) {
grow_buffers(size);
-
+ grow_size = 4096;
+ }
buffers = nr_buffers;
bh = NULL;
@@ -431,8 +436,8 @@ void bread_page(unsigned long address, dev_t dev, int b[4])
} else
bh[i] = NULL;
- if(bhnum)
- ll_rw_block(READ, bhnum, bhr);
+ if (bhnum)
+ ll_rw_block(READ, bhnum, bhr);
for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
if (bh[i]) {
@@ -664,6 +669,10 @@ void buffer_init(void)
{
int i;
+ if (high_memory >= 4*1024*1024)
+ min_free_pages = 200;
+ else
+ min_free_pages = 20;
for (i = 0 ; i < NR_HASH ; i++)
hash_table[i] = NULL;
free_list = 0;
diff --git a/fs/ext/freelists.c b/fs/ext/freelists.c
index 6b092ea..53d6ab4 100644
--- a/fs/ext/freelists.c
+++ b/fs/ext/freelists.c
@@ -48,8 +48,10 @@ void ext_free_block(struct super_block * sb, int block)
struct buffer_head * bh;
struct ext_free_block * efb;
- if (!sb)
- panic("trying to free block on nonexistent device");
+ if (!sb) {
+ printk("trying to free block on non-existent device\n");
+ return;
+ }
lock_super (sb);
if (block < sb->u.ext_sb.s_firstdatazone ||
block >= sb->u.ext_sb.s_nzones) {
@@ -91,8 +93,10 @@ int ext_new_block(struct super_block * sb)
struct ext_free_block * efb;
int j;
- if (!sb)
- panic("trying to get new block from nonexistant device");
+ if (!sb) {
+ printk("trying to get new block from non-existent device\n");
+ return 0;
+ }
if (!sb->u.ext_sb.s_firstfreeblock)
return 0;
lock_super (sb);
@@ -118,15 +122,16 @@ printk("ext_new_block: block empty, skipping to %d\n", efb->next);
}
if (j < sb->u.ext_sb.s_firstdatazone || j > sb->u.ext_sb.s_nzones) {
printk ("ext_new_block: blk = %d\n", j);
- panic ("allocating block not in data zone\n");
+ printk("allocating block not in data zone\n");
+ return 0;
}
sb->u.ext_sb.s_freeblockscount --;
sb->s_dirt = 1;
- if (!(bh=getblk(sb->s_dev, j, sb->s_blocksize)))
- panic("new_block: cannot get block");
- if (bh->b_count != 1)
- panic("new block: count is != 1");
+ if (!(bh=getblk(sb->s_dev, j, sb->s_blocksize))) {
+ printk("new_block: cannot get block");
+ return 0;
+ }
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
@@ -194,12 +199,12 @@ void ext_free_inode(struct inode * inode)
return;
}
if (!inode->i_sb) {
- printk("free_inode: inode on nonexistent device\n");
+ printk("free_inode: inode on non-existent device\n");
return;
}
lock_super (inode->i_sb);
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.ext_sb.s_ninodes) {
- printk("free_inode: inode 0 or nonexistent inode\n");
+ printk("free_inode: inode 0 or non-existent inode\n");
unlock_super (inode->i_sb);
return;
}
diff --git a/fs/inode.c b/fs/inode.c
index 92ed94f..276513a 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -129,11 +129,11 @@ static void read_inode(struct inode * inode)
* NFS uses this to get the authentication correct. -- jrs
*/
-int notify_change(struct inode * inode)
+int notify_change(int flags, struct inode * inode)
{
if (inode->i_sb && inode->i_sb->s_op &&
inode->i_sb->s_op->notify_change)
- return inode->i_sb->s_op->notify_change(inode);
+ return inode->i_sb->s_op->notify_change(flags, inode);
return 0;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 86f829d..7e14598 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -40,9 +40,10 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
put_fs_long(filp->f_inode->i_size - filp->f_pos,
(long *) arg);
return 0;
- default:
- return -EINVAL;
}
+ if (filp->f_op && filp->f_op->ioctl)
+ return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
+ return -EINVAL;
}
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index 67051ff..effca2d 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -214,11 +214,7 @@ static int isofs_file_read(struct inode * inode, struct file * filp, char * buf,
if (*bhe) {/* test for valid buffer */
wait_on_buffer(*bhe);
if (!(*bhe)->b_uptodate) {
- do {
- brelse(*bhe);
- if (++bhe == &buflist[NBUF])
- bhe = buflist;
- } while (bhe != bhb);
+ left = 0;
break;
}
}
diff --git a/fs/locks.c b/fs/locks.c
index 2179318..efd9641 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -191,7 +191,8 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l)
return 0;
if (!S_ISREG(filp->f_inode->i_mode))
return 0;
- if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK)
+ if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK
+ && l->l_type != F_SHLCK && l->l_type != F_EXLCK)
return 0;
switch (l->l_whence) {
case 0 /*SEEK_SET*/ : start = 0; break;
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 93466b2..66e1aed 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -102,7 +102,7 @@ int minix_new_block(struct super_block * sb)
int i,j;
if (!sb) {
- printk("trying to get new block from nonexistant device\n");
+ printk("trying to get new block from nonexistent device\n");
return 0;
}
repeat:
@@ -126,10 +126,6 @@ repeat:
printk("new_block: cannot get block");
return 0;
}
- if (bh->b_count != 1) {
- printk("new block: count is != 1");
- return 0;
- }
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 473d0d2..f1a3304 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -577,8 +577,10 @@ static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
error = nfs_proc_rename(NFS_SERVER(old_dir),
NFS_FH(old_dir), old_filename,
NFS_FH(new_dir), new_filename);
- if (!error)
+ if (!error) {
nfs_lookup_cache_remove(old_dir, NULL, old_filename);
+ nfs_lookup_cache_remove(new_dir, NULL, new_filename);
+ }
iput(old_dir);
iput(new_dir);
return error;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index c8af995..d3d4c67 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -58,6 +58,7 @@ static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
int n;
struct nfs_fattr fattr;
char *data;
+ off_t pos;
if (!inode) {
printk("nfs_file_read: inode = NULL\n");
@@ -68,8 +69,9 @@ static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
inode->i_mode);
return -EINVAL;
}
+ pos = file->f_pos;
if (file->f_pos + count > inode->i_size)
- count = inode->i_size - file->f_pos;
+ count = inode->i_size - pos;
if (count <= 0)
return 0;
n = NFS_SERVER(inode)->rsize;
@@ -79,19 +81,20 @@ static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
if (hunk > n)
hunk = n;
result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
- file->f_pos, hunk, data, &fattr);
+ pos, hunk, data, &fattr);
if (result < 0) {
kfree_s(data, n);
return result;
}
memcpy_tofs(buf, data, result);
- file->f_pos += result;
+ pos += result;
buf += result;
if (result < n) {
i += result;
break;
}
}
+ file->f_pos = pos;
kfree_s(data, n);
nfs_refresh_inode(inode, &fattr);
return i;
@@ -106,6 +109,7 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
int n;
struct nfs_fattr fattr;
char *data;
+ int pos;
if (!inode) {
printk("nfs_file_write: inode = NULL\n");
@@ -118,8 +122,9 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
}
if (count <= 0)
return 0;
+ pos = file->f_pos;
if (file->f_flags & O_APPEND)
- file->f_pos = inode->i_size;
+ pos = inode->i_size;
n = NFS_SERVER(inode)->wsize;
data = (char *) kmalloc(n, GFP_KERNEL);
for (i = 0; i < count; i += n) {
@@ -128,18 +133,19 @@ static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
hunk = n;
memcpy_fromfs(data, buf, hunk);
result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode),
- file->f_pos, hunk, data, &fattr);
+ pos, hunk, data, &fattr);
if (result < 0) {
kfree_s(data, n);
return result;
}
- file->f_pos += hunk;
+ pos += hunk;
buf += hunk;
if (hunk < n) {
i += hunk;
break;
}
}
+ file->f_pos = pos;
kfree_s(data, n);
nfs_refresh_inode(inode, &fattr);
return i;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4c6ebe4..7fa86d0 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -20,7 +20,7 @@
extern int close_fp(struct file *filp);
-static int nfs_notify_change(struct inode *);
+static int nfs_notify_change(int, struct inode *);
static void nfs_put_super(struct super_block *);
static void nfs_statfs(struct super_block *, struct statfs *);
@@ -125,8 +125,7 @@ void nfs_statfs(struct super_block *sb, struct statfs *buf)
error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
&res);
if (error) {
- if (error != -EINTR)
- printk("nfs_statfs: statfs error = %d\n", -error);
+ printk("nfs_statfs: statfs error = %d\n", -error);
res.bsize = res.blocks = res.bfree = res.bavail = 0;
}
put_fs_long(res.bsize, &buf->f_bsize);
@@ -181,20 +180,36 @@ struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
return inode;
}
-int nfs_notify_change(struct inode *inode)
+int nfs_notify_change(int flags, struct inode *inode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
int error;
- sattr.mode = inode->i_mode;
- sattr.uid = inode->i_uid;
- sattr.gid = inode->i_gid;
- sattr.size = S_ISREG(inode->i_mode) ? inode->i_size : -1;
- sattr.mtime.seconds = inode->i_mtime;
- sattr.mtime.useconds = 0;
- sattr.atime.seconds = inode->i_atime;
- sattr.atime.useconds = 0;
+ if (flags & NOTIFY_MODE)
+ sattr.mode = inode->i_mode;
+ else
+ sattr.mode = -1;
+ if (flags & NOTIFY_UIDGID) {
+ sattr.uid = inode->i_uid;
+ sattr.gid = inode->i_gid;
+ }
+ else
+ sattr.uid = sattr.gid = -1;
+ if (flags & NOTIFY_SIZE)
+ sattr.size = S_ISREG(inode->i_mode) ? inode->i_size : -1;
+ else
+ sattr.size = -1;
+ if (flags & NOTIFY_TIME) {
+ sattr.mtime.seconds = inode->i_mtime;
+ sattr.mtime.useconds = 0;
+ sattr.atime.seconds = inode->i_atime;
+ sattr.atime.useconds = 0;
+ }
+ else {
+ sattr.mtime.seconds = sattr.mtime.useconds = -1;
+ sattr.atime.seconds = sattr.atime.useconds = -1;
+ }
error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
&sattr, &fattr);
if (!error)
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 0867f2a..522b8aa 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -26,9 +26,8 @@
#include <netinet/in.h>
-static int proc_debug = 0;
-
#ifdef NFS_PROC_DEBUG
+static int proc_debug = 0;
#define PRINTK if (proc_debug) printk
#else
#define PRINTK if (0) printk
@@ -70,11 +69,13 @@ static inline int *xdr_encode_string(int *p, char *string)
return p;
}
-static inline int *xdr_decode_string(int *p, char *string)
+static inline int *xdr_decode_string(int *p, char *string, int maxlen)
{
- int len;
+ unsigned int len;
len = ntohl(*p++);
+ if (len > maxlen)
+ return NULL;
memcpy(string, (char *) p, len);
string[len] = '\0';
p += (len + 3) >> 2;
@@ -93,11 +94,13 @@ static inline int *xdr_encode_data(int *p, char *data, int len)
return p;
}
-static inline int *xdr_decode_data(int *p, char *data, int *lenp)
+static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
{
- int len;
+ unsigned int len;
len = *lenp = ntohl(*p++);
+ if (len > maxlen)
+ return NULL;
memcpy(data, (char *) p, len);
data[len] = '\0';
p += (len + 3) >> 2;
@@ -142,7 +145,8 @@ static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr)
static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
{
entry->fileid = ntohl(*p++);
- p = xdr_decode_string(p, entry->name);
+ if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN)))
+ return NULL;
entry->cookie = ntohl(*p++);
entry->eof = 0;
return p;
@@ -178,6 +182,8 @@ int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply getattr\n");
}
+ else
+ PRINTK("NFS reply getattr failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -203,6 +209,8 @@ int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply setattr\n");
}
+ else
+ PRINTK("NFS reply setattr failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -233,6 +241,8 @@ int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, char *name,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply lookup\n");
}
+ else
+ PRINTK("NFS reply lookup failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -254,9 +264,15 @@ int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
- p = xdr_decode_string(p, res);
- PRINTK("NFS reply readlink %s\n", res);
- }
+ if (!(p = xdr_decode_string(p, res, NFS_MAXPATHLEN))) {
+ printk("nfs_proc_readlink: giant pathname\n");
+ status = NFSERR_IO;
+ }
+ else
+ PRINTK("NFS reply readlink %s\n", res);
+ }
+ else
+ PRINTK("NFS reply readlink failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -283,9 +299,15 @@ int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
status = NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
p = xdr_decode_fattr(p, fattr);
- p = xdr_decode_data(p, data, &len);
- PRINTK("NFS reply read %d\n", len);
- }
+ if (!(p = xdr_decode_data(p, data, &len, count))) {
+ printk("nfs_proc_read: giant data size\n");
+ status = NFSERR_IO;
+ }
+ else
+ PRINTK("NFS reply read %d\n", len);
+ }
+ else
+ PRINTK("NFS reply read failed = %d\n", status);
free_page((long) p0);
return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
}
@@ -314,6 +336,8 @@ int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply write\n");
}
+ else
+ PRINTK("NFS reply write failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -342,6 +366,8 @@ int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply create\n");
}
+ else
+ PRINTK("NFS reply create failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -365,6 +391,8 @@ int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, char *name)
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply remove\n");
}
+ else
+ PRINTK("NFS reply remove failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -392,6 +420,8 @@ int nfs_proc_rename(struct nfs_server *server,
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply rename\n");
}
+ else
+ PRINTK("NFS reply rename failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -417,6 +447,8 @@ int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply link\n");
}
+ else
+ PRINTK("NFS reply link failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -443,6 +475,8 @@ int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply symlink\n");
}
+ else
+ PRINTK("NFS reply symlink failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -471,6 +505,8 @@ int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
p = xdr_decode_fattr(p, fattr);
PRINTK("NFS reply mkdir\n");
}
+ else
+ PRINTK("NFS reply mkdir failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -494,6 +530,8 @@ int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, char *name)
else if ((status = ntohl(*p++)) == NFS_OK) {
PRINTK("NFS reply rmdir\n");
}
+ else
+ PRINTK("NFS reply rmdir failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -521,13 +559,25 @@ int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
if (!(p = nfs_rpc_verify(p0)))
status = NFSERR_IO;
else if ((status = ntohl(*p++)) == NFS_OK) {
- for (i = 0; i < count && *p++; i++)
- p = xdr_decode_entry(p, entry++);
- eof = (i == count && !*p++ && *p++) || (i < count && *p++);
- if (eof && i)
- entry[-1].eof = 1;
- PRINTK("NFS reply readdir %d %s\n", i, eof ? "eof" : "");
- }
+ for (i = 0; i < count && *p++; i++) {
+ if (!(p = xdr_decode_entry(p, entry++)))
+ break;
+ }
+ if (!p) {
+ printk("nfs_proc_readdir: giant filename\n");
+ status = NFSERR_IO;
+ }
+ else {
+ eof = (i == count && !*p++ && *p++)
+ || (i < count && *p++);
+ if (eof && i)
+ entry[-1].eof = 1;
+ PRINTK("NFS reply readdir %d %s\n", i,
+ eof ? "eof" : "");
+ }
+ }
+ else
+ PRINTK("NFS reply readdir failed = %d\n", status);
free_page((long) p0);
return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
}
@@ -552,6 +602,8 @@ int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
p = xdr_decode_fsinfo(p, res);
PRINTK("NFS reply statfs\n");
}
+ else
+ PRINTK("NFS reply statfs failed = %d\n", status);
free_page((long) p0);
return -nfs_stat_to_errno(status);
}
@@ -595,27 +647,32 @@ static int *nfs_rpc_header(int *p, int procedure)
static int *nfs_rpc_verify(int *p)
{
- int n;
+ unsigned int n;
p++;
if ((n = ntohl(*p++)) != RPC_REPLY) {
printk("nfs_rpc_verify: not an RPC reply: %d\n", n);
- return 0;
+ return NULL;
}
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
- return 0;
+ return NULL;
+ }
+ switch (n = ntohl(*p++)) {
+ case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT:
+ break;
+ default:
+ printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n);
+ return NULL;
}
- if ((n = ntohl(*p++)) != RPC_AUTH_NULL && n != RPC_AUTH_UNIX) {
- printk("nfs_rpc_verify: bad RPC authentication type: %d\n",
- n);
- return 0;
+ if ((n = ntohl(*p++)) > 400) {
+ printk("nfs_rpc_verify: giant auth size\n");
+ return NULL;
}
- n = ntohl(*p++);
p += (n + 3) >> 2;
if ((n = ntohl(*p++)) != RPC_SUCCESS) {
printk("nfs_rpc_verify: RPC call failed: %d\n", n);
- return 0;
+ return NULL;
}
return p;
}
diff --git a/fs/nfs/sock.c b/fs/nfs/sock.c
index 3f3ba59..7c8f51e 100644
--- a/fs/nfs/sock.c
+++ b/fs/nfs/sock.c
@@ -90,7 +90,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
goto re_select;
#endif
current->timeout = 0;
- result = -EINTR;
+ result = -ERESTARTSYS;
break;
}
if (!current->timeout) {
diff --git a/fs/open.c b/fs/open.c
index 6d1a950..9aa632f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -89,7 +89,7 @@ int sys_truncate(const char * path, unsigned int length)
inode->i_op->truncate(inode);
inode->i_atime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
- error = notify_change(inode);
+ error = notify_change(NOTIFY_SIZE, inode);
iput(inode);
return error;
}
@@ -110,7 +110,7 @@ int sys_ftruncate(unsigned int fd, unsigned int length)
inode->i_op->truncate(inode);
inode->i_atime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
- return notify_change(inode);
+ return notify_change(NOTIFY_SIZE, inode);
}
/* If times==NULL, set access and modification to current time,
@@ -149,7 +149,7 @@ int sys_utime(char * filename, struct utimbuf * times)
inode->i_mtime = modtime;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
- error = notify_change(inode);
+ error = notify_change(NOTIFY_TIME, inode);
iput(inode);
return error;
}
@@ -247,7 +247,7 @@ int sys_fchmod(unsigned int fd, mode_t mode)
inode->i_mode &= ~S_ISGID;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
- return notify_change(inode);
+ return notify_change(NOTIFY_MODE, inode);
}
int sys_chmod(const char * filename, mode_t mode)
@@ -271,7 +271,7 @@ int sys_chmod(const char * filename, mode_t mode)
inode->i_mode &= ~S_ISGID;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
- error = notify_change(inode);
+ error = notify_change(NOTIFY_MODE, inode);
iput(inode);
return error;
}
@@ -298,7 +298,7 @@ int sys_fchown(unsigned int fd, uid_t user, gid_t group)
inode->i_gid = group;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
- return notify_change(inode);
+ return notify_change(NOTIFY_UIDGID, inode);
}
return -EPERM;
}
@@ -326,7 +326,7 @@ int sys_chown(const char * filename, uid_t user, gid_t group)
inode->i_gid = group;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
- error = notify_change(inode);
+ error = notify_change(NOTIFY_UIDGID, inode);
iput(inode);
return error;
}
@@ -380,7 +380,7 @@ int sys_open(const char * filename,int flag,int mode)
inode->i_size = 0;
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
- if ((i = notify_change(inode))) {
+ if ((i = notify_change(NOTIFY_SIZE, inode))) {
iput(inode);
current->filp[fd] = NULL;
f->f_count--;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index c552584..b3ed0b9 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -43,7 +43,16 @@ static int get_loadavg(char * buffer)
static int get_uptime(char * buffer)
{
- return sprintf(buffer,"%d\n",(jiffies+jiffies_offset)/HZ);
+ unsigned long uptime;
+ unsigned long idle;
+
+ uptime = jiffies + jiffies_offset;
+ idle = task[0]->utime + task[0]->stime;
+ return sprintf(buffer,"%d.%02d %d.%02d\n",
+ uptime / HZ,
+ uptime % HZ,
+ idle / HZ,
+ idle % HZ);
}
static int get_meminfo(char * buffer)
@@ -284,7 +293,7 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
char * page;
int length;
int end;
- int type, pid;
+ unsigned int type, pid;
if (count < 0)
return -EINVAL;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 7b39d66..487b925 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -89,8 +89,8 @@ int proc_match(int len,const char * name,struct proc_dir_entry * de)
static int proc_lookupbase(struct inode * dir,const char * name, int len,
struct inode ** result)
{
- unsigned int pid;
- int i, ino;
+ unsigned int pid, ino;
+ int i;
*result = NULL;
if (!dir)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2c4536e..ebcdae4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -127,6 +127,13 @@ extern unsigned long inode_init(unsigned long start, unsigned long end);
#define FIBMAP 1 /* bmap access */
#define FIGETBSZ 2 /* get the block size used for bmap */
+/* these flags tell notify_change what is being changed */
+
+#define NOTIFY_SIZE 1
+#define NOTIFY_MODE 2
+#define NOTIFY_TIME 4
+#define NOTIFY_UIDGID 8
+
typedef char buffer_block[BLOCK_SIZE];
struct buffer_head {
@@ -275,7 +282,7 @@ struct inode_operations {
struct super_operations {
void (*read_inode) (struct inode *);
- int (*notify_change) (struct inode *);
+ int (*notify_change) (int flags, struct inode *);
void (*write_inode) (struct inode *);
void (*put_inode) (struct inode *);
void (*put_super) (struct super_block *);
@@ -318,7 +325,7 @@ extern void sync_inodes(dev_t dev);
extern void sync_dev(dev_t dev);
extern void sync_supers(dev_t dev);
extern int bmap(struct inode * inode,int block);
-extern int notify_change(struct inode * inode);
+extern int notify_change(int flags, struct inode * inode);
extern int namei(const char * pathname, struct inode ** res_inode);
extern int lnamei(const char * pathname, struct inode ** res_inode);
extern int permission(struct inode * inode,int mask);
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 0494bba..85de5ca 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -17,6 +17,7 @@ enum {
TIMER_BH = 0,
CONSOLE_BH,
SERIAL_BH,
+ TTY_BH,
INET_BH,
KEYBOARD_BH
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
index dcdb86f..e3a0835 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -264,6 +264,7 @@ extern unsigned long startup_time;
extern int jiffies_offset;
extern int need_resched;
extern int hard_math;
+extern int ignore_irq13;
#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ)
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 3701554..21804a5 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -20,8 +20,8 @@ struct async_struct {
int baud_base;
int port;
int irq;
- int flags;
- int type;
+ int flags; /* defined in tty.h */
+ int type; /* UART type */
struct tty_struct *tty;
unsigned long timer;
int timeout;
@@ -30,9 +30,11 @@ struct async_struct {
int x_char; /* xon/xoff characater */
int event;
int line;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ struct wait_queue *open_wait;
struct async_struct *next_port; /* For the linked list */
struct async_struct *prev_port;
-
};
/*
@@ -44,6 +46,7 @@ struct async_struct {
#define RS_EVENT_HUP_PGRP 2
#define RS_EVENT_BREAK_INT 3
#define RS_EVENT_DO_SAK 4
+#define RS_EVENT_OPEN_WAKEUP 5
/*
* These are the UART port assignments, expressed as offsets from the base
diff --git a/include/linux/sock_ioctl.h b/include/linux/sock_ioctl.h
index 91fbb63..d7384f1 100644
--- a/include/linux/sock_ioctl.h
+++ b/include/linux/sock_ioctl.h
@@ -16,6 +16,25 @@ struct ip_config
unsigned long paddr;
unsigned long router;
unsigned long net;
- unsigned long up:1;
+ unsigned long up:1,destroy:1;
};
+
+#define SIOCSARP 0x2501
+#define SIOCGARP 0x2502
+#define SIOCDARP 0x2503
+
+/*
+ * ARP ioctl request
+ */
+struct arpreq {
+ struct sockaddr arp_pa; /* protocol address */
+ struct sockaddr arp_ha; /* hardware address */
+ int arp_flags; /* flags */
+};
+
+#define ATF_COM 0x02
+#define ATF_PERM 0x04
+#define ATF_PUBL 0x08
+#define ATF_USETRAILERS 0x10
+
#endif
diff --git a/include/linux/termios.h b/include/linux/termios.h
index 2afeb5c..b6d284d 100644
--- a/include/linux/termios.h
+++ b/include/linux/termios.h
@@ -38,6 +38,8 @@
#define TIOCPKT 0x5420
#define FIONBIO 0x5421
#define TIOCNOTTY 0x5422
+#define TIOCSETD 0x5423
+#define TIOCGETD 0x5424
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define FIOCLEX 0x5451
#define FIOASYNC 0x5452
@@ -225,4 +227,9 @@ struct termios {
#define TCSADRAIN 1
#define TCSAFLUSH 2
+/* line disciplines */
+#define N_TTY 0
+#define N_SLIP 1
+#define N_MOUSE 2
+
#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 71c8ddd..55066a4 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -10,6 +10,7 @@
#include <asm/system.h>
#define NR_CONSOLES 8
+#define NR_LDISCS 16
/*
* These are set up by the setup-routine at boot-time:
@@ -104,7 +105,9 @@ struct serial_struct {
#define ASYNC_FLAGS 0x0036 /* Possible legal async flags */
/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ASYNC_NO_IRQ 0x80000000 /* No IRQ was initialized */
+#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00)
#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40)
@@ -188,6 +191,7 @@ struct tty_struct {
unsigned char stopped:1, status_changed:1, packet:1;
unsigned char ctrl_status;
short line;
+ int disc;
int flags;
int count;
struct winsize winsize;
@@ -197,12 +201,38 @@ struct tty_struct {
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned int arg);
void (*throttle)(struct tty_struct * tty, int status);
+ void (*set_termios)(struct tty_struct *tty, struct termios * old);
struct tty_struct *link;
+ unsigned char *write_data_ptr;
+ int write_data_cnt;
+ void (*write_data_callback)(void * data);
+ void * write_data_arg;
struct tty_queue read_q;
struct tty_queue write_q;
struct tty_queue secondary;
};
+struct tty_ldisc {
+ int flags;
+ /*
+ * The following routines are called from above.
+ */
+ int (*open)(struct tty_struct *);
+ void (*close)(struct tty_struct *);
+ int (*read)(struct tty_struct * tty, struct file * file,
+ char * buf, int nr);
+ int (*write)(struct tty_struct * tty, struct file * file,
+ char * buf, int nr);
+ int (*ioctl)(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned int arg);
+ /*
+ * The following routines are called from below.
+ */
+ void (*handler)(struct tty_struct *);
+};
+
+#define LDISC_FLAG_DEFINED 0x00000001
+
/*
* These are the different types of thottle status which can be sent
* to the low-level tty driver. The tty_io.c layer is responsible for
@@ -256,7 +286,9 @@ extern void tty_write_flush(struct tty_struct *);
extern void tty_read_flush(struct tty_struct *);
extern struct tty_struct *tty_table[];
+extern int tty_check_write[];
extern struct tty_struct * redirect;
+extern struct tty_ldisc ldiscs[];
extern int fg_console;
extern unsigned long video_num_columns;
extern unsigned long video_num_lines;
@@ -282,6 +314,7 @@ extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty);
extern void wait_until_sent(struct tty_struct * tty);
extern void copy_to_cooked(struct tty_struct * tty);
+extern int tty_register_ldisc(int disc, struct tty_ldisc *new);
extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int);
extern int is_orphaned_pgrp(int pgrp);
@@ -290,6 +323,7 @@ extern int tty_signal(int sig, struct tty_struct *tty);
extern int kill_pg(int pgrp, int sig, int priv);
extern int kill_sl(int sess, int sig, int priv);
extern void tty_hangup(struct tty_struct * tty);
+extern void tty_unhangup(struct file *filp);
extern void do_SAK(struct tty_struct *tty);
/* tty write functions */
@@ -300,7 +334,6 @@ extern void con_write(struct tty_struct * tty);
/* serial.c */
extern int rs_open(struct tty_struct * tty, struct file * filp);
-extern void change_speed(unsigned int line);
/* pty.c */
diff --git a/init/main.c b/init/main.c
index 9f8b16f..803ab09 100644
--- a/init/main.c
+++ b/init/main.c
@@ -249,6 +249,23 @@ void start_kernel(void)
floppy_init();
sock_init();
sti();
+ /*
+ * check if exception 16 works correctly.. This is truly evil
+ * code: it disables the high 8 interrupts to make sure that
+ * the irq13 doesn't happen. But as this will lead to a lockup
+ * if no exception16 arrives, it depends on the fact that the
+ * high 8 interrupts will be re-enabled by the next timer tick.
+ * So the irq13 will happen eventually, but the exception 16
+ * should get there first..
+ */
+ if (hard_math) {
+ unsigned short control_word;
+ __asm__("fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
+ control_word &= 0xffc0;
+ __asm__("fldcw %0 ; fwait"::"m" (*&control_word));
+ outb_p(inb_p(0x21) | (1 << 2), 0x21);
+ __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
+ }
move_to_user_mode();
if (!fork()) /* we count on this going ok */
init();
@@ -288,6 +305,7 @@ void init(void)
printf(linux_banner);
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
+ execve("/sbin/init",argv_init,envp_init);
/* if this fails, fall through to original stuff */
if (!(pid=fork())) {
diff --git a/kernel/FPU-emu/README b/kernel/FPU-emu/README
index 53cbea2..062bb3b 100644
--- a/kernel/FPU-emu/README
+++ b/kernel/FPU-emu/README
@@ -20,9 +20,6 @@
+---------------------------------------------------------------------------+
-***NOTE*** THIS SHOULD BE REGARDED AS AN ALPHA TEST VERSION
- (although the beta version may be identical)
-
wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was
@@ -48,6 +45,14 @@ Please report bugs, etc to me at:
--Bill Metzenthen
Oct 1992
+
+[ note: I have advanced the version number from alpha numbers
+ to beta numbers. This is not meant to indicate any major
+ changes but rather the fact that the emulator has been a
+ standard part of the Linux distribution for some months
+ and is currently reasonably stable. WM Jan 1993 ]
+
+
----------------------- Internals of wm-FPU-emu -----------------------
Numeric algorithms:
@@ -84,7 +89,7 @@ is confined to five files:
----------------------- Limitations of wm-FPU-emu -----------------------
There are a number of differences between the current wm-FPU-emu
-(version ALPHA 0.7) and the 80486 FPU (apart from bugs). Some of the
+(version beta 1.0) and the 80486 FPU (apart from bugs). Some of the
more important differences are listed below:
Internal computations do not use de-normal numbers (but External
diff --git a/kernel/FPU-emu/errors.c b/kernel/FPU-emu/errors.c
index 1cf6503..e789740 100644
--- a/kernel/FPU-emu/errors.c
+++ b/kernel/FPU-emu/errors.c
@@ -221,7 +221,7 @@ void exception(int n)
{
int i, int_type;
- int_type = 0;
+ int_type = 0; /* Needed only to stop compiler warnings */
if ( n & EX_INTERNAL )
{
int_type = n - EX_INTERNAL;
diff --git a/kernel/FPU-emu/fpu_entry.c b/kernel/FPU-emu/fpu_entry.c
index dc54407..222a190 100644
--- a/kernel/FPU-emu/fpu_entry.c
+++ b/kernel/FPU-emu/fpu_entry.c
@@ -37,6 +37,13 @@
#define __BAD__ Un_impl /* Not implemented */
+#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
+
+/* WARNING: These codes are not documented by Intel in their 80486 manual
+ and may not work on FPU clones or later Intel FPUs. */
+
+/* Changes to support the un-doc codes provided by Linus Torvalds. */
+
#define _d9_d8_ fstp_i /* unofficial code (19) */
#define _dc_d0_ fcom_st /* unofficial code (14) */
#define _dc_d8_ fcompst /* unofficial code (1c) */
@@ -58,6 +65,22 @@ static FUNC st_instr_table[64] = {
fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
};
+#else /* Support only documented FPU op-codes */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
+ fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
+ fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+
+#endif NO_UNDOC_CODE
+
+
#define _NONE_ 0 /* Take no special action */
#define _REG0_ 1 /* Need to check for not empty st(0) */
#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
@@ -65,6 +88,10 @@ static FUNC st_instr_table[64] = {
#define _PUSH_ 3 /* Need to check for space to push onto stack */
#define _null_ 4 /* Function illegal or not implemented */
+#ifndef NO_UNDOC_CODE
+
+/* Un-documented FPU op-codes supported by default. (see above) */
+
static unsigned char type_table[64] = {
_REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _REGi_,
_REGI_, _REGI_, _null_, _null_, _REGI_, _REGI_, _REGI_, _REGI_,
@@ -76,6 +103,21 @@ static unsigned char type_table[64] = {
_REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
};
+#else /* Support only documented FPU op-codes */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGI_, _REGi_, _REGI_, _null_,
+ _REGI_, _REGI_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
+ _REGI_, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
+ _REGI_, _null_, _null_, _null_, _null_, _REG0_, _REGI_, _null_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGI_, _REGI_, _REGI_, _NONE_,
+ _REGI_, _NONE_, _REGI_, _null_, _REGI_, _REGI_, _REGI_, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_
+};
+
+#endif NO_UNDOC_CODE
+
/* Be careful when using any of these global variables...
they might change if swapping is triggered */
diff --git a/kernel/FPU-emu/get_address.c b/kernel/FPU-emu/get_address.c
index 3d5e97f..5f0ee62 100644
--- a/kernel/FPU-emu/get_address.c
+++ b/kernel/FPU-emu/get_address.c
@@ -115,7 +115,7 @@ void get_address(unsigned char FPU_modrm)
{
unsigned char mod;
long *cpu_reg_ptr;
- int offset = 0;
+ int offset = 0; /* Initialized just to stop compiler warnings. */
mod = (FPU_modrm >> 6) & 3;
diff --git a/kernel/FPU-emu/load_store.c b/kernel/FPU-emu/load_store.c
index 72e11b3..51ea3ef 100644
--- a/kernel/FPU-emu/load_store.c
+++ b/kernel/FPU-emu/load_store.c
@@ -48,7 +48,7 @@ void load_store_instr(char type)
{
FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't change. */
- pop_ptr = NULL;
+ pop_ptr = NULL; /* Initialized just to stop compiler warnings. */
switch ( type_table[(int) (unsigned) type] )
{
case _NONE_:
diff --git a/kernel/FPU-emu/reg_div.S b/kernel/FPU-emu/reg_div.S
index 46979b5..5c24cb7 100644
--- a/kernel/FPU-emu/reg_div.S
+++ b/kernel/FPU-emu/reg_div.S
@@ -48,7 +48,7 @@ _reg_div:
movb SIGN(%esi),%cl
cmpb %cl,SIGN(%ebx)
- setneb (%edi) // Set the sign, requires neg=1, pos=0
+ setne (%edi) // Set the sign, requires SIGN_NEG=1, SIGN_POS=0
add $SIGL_OFFSET,%ebx
add $SIGL_OFFSET,%esi
diff --git a/kernel/FPU-emu/version.h b/kernel/FPU-emu/version.h
index 4472e47..cccf328 100644
--- a/kernel/FPU-emu/version.h
+++ b/kernel/FPU-emu/version.h
@@ -8,5 +8,5 @@
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version ALPHA 0.8"
+#define FPU_VERSION "wm-FPU-emu version BETA 1.0"
diff --git a/kernel/blk_drv/genhd.c b/kernel/blk_drv/genhd.c
index 291ca30..c5b9293 100644
--- a/kernel/blk_drv/genhd.c
+++ b/kernel/blk_drv/genhd.c
@@ -46,10 +46,8 @@ static void extended_partition(struct gendisk *hd, int dev)
while (1) {
if ((current_minor & mask) >= (4 + hd->max_p))
return;
- if (!(bh = bread(dev,0,1024))) {
- printk("Unable to read partition table of device %04x\n",dev);
+ if (!(bh = bread(dev,0,1024)))
return;
- }
/*
* This block is from a device that we're about to stomp on.
* So make sure nobody thinks this block is usable.
@@ -66,11 +64,9 @@ static void extended_partition(struct gendisk *hd, int dev)
!(hd->part[current_minor].nr_sects = p->nr_sects))
goto done; /* shouldn't happen */
hd->part[current_minor].start_sect = this_sector + p->start_sect;
- printk(" Logical part %d start %d size %d end %d\n\r",
- mask & current_minor, hd->part[current_minor].start_sect,
- hd->part[current_minor].nr_sects,
- hd->part[current_minor].start_sect +
- hd->part[current_minor].nr_sects - 1);
+ printk(" %s%c%d", hd->major_name,
+ 'a'+(current_minor >> hd->minor_shift),
+ mask & current_minor);
current_minor++;
p++;
/*
@@ -96,19 +92,22 @@ done:
static void check_partition(struct gendisk *hd, unsigned int dev)
{
+ static int first_time = 1;
int i, minor = current_minor;
struct buffer_head *bh;
struct partition *p;
unsigned long first_sector;
int mask = (1 << hd->minor_shift) - 1;
+ if (first_time)
+ printk("Partition check:\n");
+ first_time = 0;
first_sector = hd->part[MINOR(dev)].start_sect;
-
if (!(bh = bread(dev,0,1024))) {
- printk("Unable to read partition table of device %04x\n",dev);
+ printk(" unable to read partition table of device %04x\n",dev);
return;
}
- printk("%s%c :\n\r", hd->major_name, 'a'+(minor >> hd->minor_shift));
+ printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
current_minor += 4; /* first "extra" minor */
if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
p = 0x1BE + (void *)bh->b_data;
@@ -116,13 +115,13 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
if (!(hd->part[minor].nr_sects = p->nr_sects))
continue;
hd->part[minor].start_sect = first_sector + p->start_sect;
- printk(" part %d start %d size %d end %d \n\r", i,
- hd->part[minor].start_sect, hd->part[minor].nr_sects,
- hd->part[minor].start_sect + hd->part[minor].nr_sects - 1);
+ printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), i);
if ((current_minor & 0x3f) >= 60)
continue;
if (p->sys_ind == EXTENDED_PARTITION) {
+ printk(" <");
extended_partition(hd, (hd->major << 8) | minor);
+ printk(" >");
}
}
/*
@@ -138,16 +137,14 @@ static void check_partition(struct gendisk *hd, unsigned int dev)
continue;
hd->part[current_minor].start_sect = p->start_sect;
hd->part[current_minor].nr_sects = p->nr_sects;
- printk(" DM part %d start %d size %d end %d\n\r",
- current_minor & mask,
- hd->part[current_minor].start_sect,
- hd->part[current_minor].nr_sects,
- hd->part[current_minor].start_sect +
- hd->part[current_minor].nr_sects - 1);
+ printk(" %s%c%d", hd->major_name,
+ 'a'+(current_minor >> hd->minor_shift),
+ current_minor & mask);
}
}
} else
- printk("Bad partition table on dev %04x\n",dev);
+ printk(" bad partition table");
+ printk("\n");
brelse(bh);
}
@@ -212,9 +209,6 @@ int sys_setup(void * BIOS)
nr += p->nr_real;
}
- if (nr)
- printk("Partition table%s ok.\n\r",(nr>1)?"s":"");
-
if (ramdisk_size)
rd_load();
mount_root();
diff --git a/kernel/blk_drv/hd.c b/kernel/blk_drv/hd.c
index 1e74ca9..fa0cac7 100644
--- a/kernel/blk_drv/hd.c
+++ b/kernel/blk_drv/hd.c
@@ -49,8 +49,9 @@ static inline unsigned char CMOS_READ(unsigned char addr)
#define HD_DELAY 0
-/* Max read/write errors/sector */
-#define MAX_ERRORS 7
+#define MAX_ERRORS 16 /* Max read/write errors/sector */
+#define RESET_FREQ 8 /* Reset controller every 8th retry */
+#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
#define MAX_HD 2
static void recal_intr(void);
@@ -62,6 +63,7 @@ static char busy[MAX_HD] = {0, };
static struct wait_queue * busy_wait = NULL;
static int reset = 0;
+static int hd_error = 0;
#if (HD_DELAY > 0)
unsigned long last_req, read_timer();
@@ -111,12 +113,14 @@ static int win_result(void)
int i=inb_p(HD_STATUS);
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
- == (READY_STAT | SEEK_STAT))
+ == (READY_STAT | SEEK_STAT)) {
+ hd_error = 0;
return 0; /* ok */
+ }
printk("HD: win_result: status = 0x%02x\n",i);
if (i&1) {
- i=inb(HD_ERROR);
- printk("HD: win_result: error = 0x%02x\n",i);
+ hd_error = inb(HD_ERROR);
+ printk("HD: win_result: error = 0x%02x\n",hd_error);
}
return 1;
}
@@ -219,8 +223,8 @@ static void reset_controller(void)
outb(hd_info[0].ctl & 0x0f ,HD_CMD);
if (drive_busy())
printk("HD-controller still busy\n\r");
- if ((i = inb(HD_ERROR)) != 1)
- printk("HD-controller reset failed: %02x\n\r",i);
+ if ((hd_error = inb(HD_ERROR)) != 1)
+ printk("HD-controller reset failed: %02x\n\r",hd_error);
}
static void reset_hd(void)
@@ -259,19 +263,26 @@ void unexpected_hd_interrupt(void)
SET_TIMER;
}
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ */
static void bad_rw_intr(void)
{
- int i;
+ int dev;
if (!CURRENT)
return;
- if (++CURRENT->errors >= MAX_ERRORS)
+ dev = MINOR(CURRENT->dev) >> 6;
+ if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(0);
- else if (CURRENT->errors > MAX_ERRORS/2)
+ recalibrate[dev] = 1;
+ } else if (CURRENT->errors % RESET_FREQ == 0)
reset = 1;
- else
- for (i=0; i < NR_HD; i++)
- recalibrate[i] = 1;
+ else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
+ recalibrate[dev] = 1;
+ /* Otherwise just retry */
}
static inline int wait_DRQ(void)
@@ -302,8 +313,8 @@ static void read_intr(void)
sti();
printk("HD: read_intr: status = 0x%02x\n",i);
if (i & ERR_STAT) {
- i = (unsigned) inb(HD_ERROR);
- printk("HD: read_intr: error = 0x%02x\n",i);
+ hd_error = (unsigned) inb(HD_ERROR);
+ printk("HD: read_intr: error = 0x%02x\n",hd_error);
}
bad_rw_intr();
cli();
@@ -351,8 +362,8 @@ static void write_intr(void)
sti();
printk("HD: write_intr: status = 0x%02x\n",i);
if (i & ERR_STAT) {
- i = (unsigned) inb(HD_ERROR);
- printk("HD: write_intr: error = 0x%02x\n",i);
+ hd_error = (unsigned) inb(HD_ERROR);
+ printk("HD: write_intr: error = 0x%02x\n",hd_error);
}
bad_rw_intr();
cli();
diff --git a/kernel/blk_drv/scsi/scsi.c b/kernel/blk_drv/scsi/scsi.c
index 3ef91be..b4cf946 100644
--- a/kernel/blk_drv/scsi/scsi.c
+++ b/kernel/blk_drv/scsi/scsi.c
@@ -206,8 +206,8 @@ static void scan_scsis (void)
((SCmd.sense_buffer[0] & 0x70) >> 4) == 7) {
if (SCmd.sense_buffer[2] &0xe0)
continue; /* No devices here... */
- if((SCmd.sense_buffer[2] & 0xf != NOT_READY) &&
- (SCmd.sense_buffer[2] & 0xf != UNIT_ATTENTION))
+ if(((SCmd.sense_buffer[2] & 0xf) != NOT_READY) &&
+ ((SCmd.sense_buffer[2] & 0xf) != UNIT_ATTENTION))
continue;
}
else
diff --git a/kernel/blk_drv/scsi/wd7000.c b/kernel/blk_drv/scsi/wd7000.c
index cbd55b4..704fc82 100644
--- a/kernel/blk_drv/scsi/wd7000.c
+++ b/kernel/blk_drv/scsi/wd7000.c
@@ -506,7 +506,24 @@ void wd7000_revision(void)
}
-static const char *wd_bases[] = {(char *)0xce000};
+static const char *wd_bases[] = {
+ (char *)0xde000,
+ (char *)0xdc000,
+ (char *)0xda000,
+ (char *)0xd8000,
+ (char *)0xd6000,
+ (char *)0xd4000,
+ (char *)0xd2000,
+ (char *)0xd0000,
+ (char *)0xce000,
+ (char *)0xcc000,
+ (char *)0xca000,
+ (char *)0xc8000,
+ (char *)0xc6000,
+ (char *)0xc4000,
+ (char *)0xc2000,
+ (char *)0xc0000
+ };
typedef struct {
char * signature;
unsigned offset;
@@ -603,8 +620,8 @@ int wd7000_biosparam(int size, int dev, int* info)
* this way, so I think it will work OK.
*/
{
- info[0] = 32;
- info[1] = 64;
+ info[0] = 64;
+ info[1] = 32;
info[2] = (size + 2047) >> 11;
if (info[2] >= 1024) info[2] = 1024;
return 0;
diff --git a/kernel/chr_drv/busmouse.c b/kernel/chr_drv/busmouse.c
index 4a27672..a3ad17b 100644
--- a/kernel/chr_drv/busmouse.c
+++ b/kernel/chr_drv/busmouse.c
@@ -48,12 +48,13 @@ static void mouse_interrupt(int unused)
buttons = inb(MSE_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ((buttons >> 5) & 0x07);
- mouse.buttons = buttons;
- mouse.latch_buttons |= buttons;
- mouse.dx += dx;
- mouse.dy += dy;
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
+ if (dx != 0 || dy != 0 || buttons != mouse.buttons) {
+ mouse.buttons = buttons;
+ mouse.dx += dx;
+ mouse.dy += dy;
+ mouse.ready = 1;
+ wake_up_interruptible(&mouse.wait);
+ }
MSE_INT_ON();
}
@@ -75,7 +76,7 @@ static int open_mouse(struct inode * inode, struct file * file)
mouse.ready = 0;
mouse.dx = 0;
mouse.dy = 0;
- mouse.buttons = mouse.latch_buttons = 0x80;
+ mouse.buttons = 0x87;
if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
mouse.active = 0;
return -EBUSY;
@@ -99,7 +100,7 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
if (!mouse.ready)
return -EAGAIN;
MSE_INT_OFF();
- put_fs_byte(mouse.latch_buttons | 0x80, buffer);
+ put_fs_byte(mouse.buttons | 0x80, buffer);
if (mouse.dx < -127)
mouse.dx = -127;
if (mouse.dx > 127)
@@ -114,7 +115,6 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
put_fs_byte(0x00, buffer + i);
mouse.dx = 0;
mouse.dy = 0;
- mouse.latch_buttons = mouse.buttons;
mouse.ready = 0;
MSE_INT_ON();
return i;
@@ -159,7 +159,7 @@ unsigned long bus_mouse_init(unsigned long kmem_start)
mouse.present = 1;
mouse.active = 0;
mouse.ready = 0;
- mouse.buttons = mouse.latch_buttons = 0x80;
+ mouse.buttons = 0x87;
mouse.dx = 0;
mouse.dy = 0;
mouse.wait = NULL;
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index aaab09b..cfd4a51 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -66,6 +66,7 @@ static unsigned char video_page; /* Initial video page */
static unsigned short video_port_reg; /* Video register select port */
static unsigned short video_port_val; /* Video register value port */
static int can_do_color = 0;
+static int printable = 0;
static struct {
unsigned short vc_video_erase_char; /* Background erase character */
@@ -1239,7 +1240,6 @@ return s;
long con_init(long kmem_start)
{
char *display_desc = "????";
- char *display_ptr;
int currcons = 0;
long base;
int orig_x = ORIG_X;
@@ -1268,7 +1268,7 @@ long con_init(long kmem_start)
{
video_type = VIDEO_TYPE_EGAM;
video_mem_term = 0xb8000;
- display_desc = "EGAm";
+ display_desc = "EGA+";
}
else
{
@@ -1287,7 +1287,7 @@ long con_init(long kmem_start)
{
video_type = VIDEO_TYPE_EGAC;
video_mem_term = 0xc0000;
- display_desc = "EGAc";
+ display_desc = "EGA+";
}
else
{
@@ -1297,15 +1297,6 @@ long con_init(long kmem_start)
}
}
- /* Let the user know what kind of display driver we are using */
-
- display_ptr = ((char *)video_mem_base) + video_size_row - 8;
- while (*display_desc)
- {
- *display_ptr++ = *display_desc++;
- display_ptr++;
- }
-
/* Initialize the variables used for scrolling (mostly EGA/VGA) */
base = (long)vc_scrmembuf;
@@ -1337,6 +1328,12 @@ long con_init(long kmem_start)
save_cur(currcons);
gotoxy(currcons,orig_x,orig_y);
update_screen(fg_console);
+ printable = 1;
+ printk("Console: %s %s %dx%d, %d virtual consoles\n",
+ can_do_color?"colour":"mono",
+ display_desc,
+ video_num_columns,video_num_lines,
+ NR_CONSOLES);
return kmem_start;
}
@@ -1456,8 +1453,8 @@ void console_print(const char * b)
int currcons = fg_console;
char c;
- if (currcons<0 || currcons>=NR_CONSOLES)
- currcons = 0;
+ if (!printable || currcons<0 || currcons>=NR_CONSOLES)
+ return;
while ((c = *(b++)) != 0) {
if (c == 10 || c == 13 || need_wrap) {
if (c != 13)
diff --git a/kernel/chr_drv/pty.c b/kernel/chr_drv/pty.c
index 6b08ab0..dc071ab 100644
--- a/kernel/chr_drv/pty.c
+++ b/kernel/chr_drv/pty.c
@@ -16,13 +16,14 @@
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
+#include <linux/interrupt.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <asm/bitops.h>
static void pty_close(struct tty_struct * tty, struct file * filp)
{
- if (!tty)
+ if (!tty || (tty->count > 1))
return;
wake_up_interruptible(&tty->read_q.proc_list);
if (!tty->link)
@@ -50,6 +51,10 @@ static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
}
TTY_READ_FLUSH(to);
wake_up_interruptible(&from->write_q.proc_list);
+ if (from->write_data_cnt) {
+ set_bit(from->line, &tty_check_write);
+ mark_bh(TTY_BH);
+ }
}
/*
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index d6f4123..7da8ca6 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -15,7 +15,6 @@
*
* long rs_init(long);
* int rs_open(struct tty_struct * tty, struct file * filp)
- * void change_speed(unsigned int line)
*/
#include <linux/errno.h>
@@ -24,7 +23,10 @@
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/serial.h>
+#include <linux/interrupt.h>
#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -47,20 +49,8 @@
* Enables support for the Accent Async 4 port serial
* port.
*
- * SOFT_IRQ
- * Not yet ready; requires changes in the rest of the
- * Linux kernel
- *
*/
-#define NEW_INTERRUPT_ROUTINE
-#undef SOFT_IRQ
-#undef FAKE_SOFT_IRQ
-
-#ifdef FAKE_SOFT_IRQ
-#define SOFT_IRQ
-#endif
-
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
/*
@@ -70,11 +60,12 @@
* transmitting (and therefore have a
* write timeout pending, in case the
* THRE interrupt gets lost.)
+ *
+ * We assume here that int's are 32 bits, so an array of two gives us
+ * 64 lines, which is the maximum we can support.
*/
-static volatile unsigned long rs_event = 0;
-static unsigned long rs_write_active = 0;
-
-static int doing_softint = 0;
+static int rs_event[2];
+static int rs_write_active[2];
static struct async_struct *IRQ_ports[16];
@@ -149,15 +140,14 @@ struct async_struct rs_table[] = {
*/
static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 56700, 115200, 0 };
+ 9600, 19200, 38400, 57600, 115200, 0 };
static void startup(struct async_struct * info);
static void shutdown(struct async_struct * info);
static void rs_throttle(struct tty_struct * tty, int status);
static void restart_port(struct async_struct *info);
-#ifdef FAKE_SOFT_IRQ
-static void do_softint();
-#endif
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct async_struct *info);
static inline unsigned int serial_in(struct async_struct *info, int offset)
{
@@ -195,12 +185,8 @@ static inline void rs_sched_event(struct async_struct *info,
int event)
{
info->event |= 1 << event;
- rs_event |= 1 << info->line;
-
-#ifndef SOFT_IRQ
- timer_table[RS_TIMER].expires = 0;
- timer_active |= 1 << RS_TIMER;
-#endif
+ set_bit(info->line, rs_event);
+ mark_bh(SERIAL_BH);
}
@@ -305,16 +291,18 @@ static void rs_interrupt(int irq)
}
}
queue->tail = tail;
- if (VLEFT > WAKEUP_CHARS)
+ if (VLEFT > WAKEUP_CHARS) {
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+ if (info->tty->write_data_cnt) {
+ set_bit(info->tty->line,
+ &tty_check_write);
+ mark_bh(TTY_BH);
+ }
+ }
info->timer = jiffies + info->timeout;
if (info->timer < timer_table[RS_TIMER].expires)
timer_table[RS_TIMER].expires = info->timer;
-#ifdef i386
- rs_write_active |= 1 << info->line;
-#else
- set_bit(info->line, &rs_write_active);
-#endif
+ set_bit(info->line, rs_write_active);
timer_active |= 1 << RS_TIMER;
#ifdef SERIAL_INT_DEBUG
printk("THRE...");
@@ -324,8 +312,17 @@ static void rs_interrupt(int irq)
status = serial_in(info, UART_MSR);
if (!(CFLAG & CLOCAL) && (status & UART_MSR_DDCD)) {
- if (!(status & UART_MSR_DCD))
+ if (status & UART_MSR_DCD) {
+#ifdef SERIAL_INT_DEBUG
+ printk("DCD on...");
+#endif
+ rs_sched_event(info, RS_EVENT_OPEN_WAKEUP);
+ } else {
+#ifdef SERIAL_INT_DEBUG
+ printk("DCD off...");
+#endif
rs_sched_event(info, RS_EVENT_HUP_PGRP);
+ }
}
if (CFLAG & CRTSCTS) {
if (info->tty->stopped) {
@@ -346,13 +343,6 @@ static void rs_interrupt(int irq)
done = 1;
}
}
-#ifdef FAKE_SOFT_IRQ
- if (rs_event && !doing_softint) {
- doing_softint = 1;
- sti(); /* Turn on interrupts! */
- do_softint();
- }
-#endif
}
#ifdef CONFIG_AUTO_IRQ
@@ -371,84 +361,15 @@ static void rs_probe(int irq)
}
#endif
-#ifdef SOFT_IRQ
static void do_softint()
{
- unsigned long mask;
+ int i;
struct async_struct *info;
- while (rs_event) {
- info = rs_table;
- for (mask = 1 ; mask ; info++, mask <<= 1) {
- if (mask > rs_event)
- break;
- if (!info->tty) /* check that we haven't closed it.. */
+ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+ if (!clear_bit(i, rs_event)) {
+ if (!info->tty)
continue;
- if (mask & rs_event) {
- rs_event &= ~mask;
- if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
- TTY_READ_FLUSH(info->tty);
- }
- if (!clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->tty->write_q.proc_list);
- }
- if (!clear_bit(RS_EVENT_HUP_PGRP, &info->event))
- tty_hangup(info->tty);
- if (!clear_bit(RS_EVENT_BREAK_INT, &info->event)) {
- flush_input(info->tty);
- flush_output(info->tty);
- if (info->tty->pgrp > 0)
- kill_pg(info->tty->pgrp,SIGINT,1);
- }
- if (!clear_bit(RS_EVENT_DO_SAK, &info->event)) {
- do_SAK(info->tty);
- }
- }
- }
- }
-#ifdef FAKE_SOFT_IRQ
- doing_softint = 0;
-#endif
-}
-#endif
-
-/*
- * This subroutine handles all of the timer functionality required for
- * the serial ports.
- */
-
-#define END_OF_TIME 0xffffffff
-static void rs_timer(void)
-{
- unsigned long mask;
- struct async_struct *info;
- unsigned long next_timeout;
-
-#ifdef FAKE_SOFT_IRQ
- cli();
- if (rs_event && !doing_softint) {
- doing_softint = 1;
- sti(); /* Turn on interrupts! */
- do_softint();
- }
- sti();
-#endif
- info = rs_table;
- next_timeout = END_OF_TIME;
- for (mask = 1 ; mask ; info++, mask <<= 1) {
- if (
-#ifndef SOFT_IRQ
- (mask > rs_event) &&
-#endif
- (mask > rs_write_active))
- break;
- if (!info->tty) { /* check that we haven't closed it.. */
- rs_event &= ~mask;
- rs_write_active &= ~mask;
- continue;
- }
-#ifndef SOFT_IRQ
- if (mask & rs_event) {
if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
TTY_READ_FLUSH(info->tty);
}
@@ -461,45 +382,33 @@ static void rs_timer(void)
flush_input(info->tty);
flush_output(info->tty);
if (info->tty->pgrp > 0)
- kill_pg(info->tty->pgrp,SIGINT,1);
+ kill_pg(info->tty->pgrp, SIGINT,1);
}
if (!clear_bit(RS_EVENT_DO_SAK, &info->event)) {
do_SAK(info->tty);
}
- cli();
- if (info->event)
- next_timeout = 0;
- else
- rs_event &= ~mask;
- sti();
- }
-#endif
- if (mask & rs_write_active) {
- if (info->timer <= jiffies) {
-#ifdef i386
- rs_write_active &= ~mask;
-#else
- clear_bit(info->line, &rs_write_active);
-#endif
- rs_write(info->tty);
+ if (!clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->open_wait);
}
- if ((mask & rs_write_active) &&
- (info->timer < next_timeout))
- next_timeout = info->timer;
}
}
- if (next_timeout != END_OF_TIME) {
- timer_table[RS_TIMER].expires = next_timeout;
-#ifdef i386
- /*
- * This must compile to a single, atomic instruction.
- * It does using 386 with GCC; if you're not sure, use
- * the set_bit function, which is supposed to be atomic.
- */
- timer_active |= 1 << RS_TIMER;
-#else
- set_bit(RS_TIMER, &timer_active);
-#endif
+}
+
+/*
+ * This subroutine handles all of the timer functionality required for
+ * the serial ports.
+ */
+
+static void rs_timer(void)
+{
+ int i;
+ struct async_struct *info;
+
+ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+ if (test_bit(i, rs_write_active) && (info->timer <= jiffies)) {
+ clear_bit(i, rs_write_active);
+ rs_write(info->tty);
+ }
}
}
@@ -599,41 +508,50 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
line = DEV_TO_SL(tty->line);
if ((line < 0) || (line >= NR_PORTS))
return;
- tty->stopped = 0; /* Force flush to succeed */
- wait_until_sent(tty);
info = rs_table + line;
- if (!info->port)
- return;
- shutdown(info);
-#ifdef i386
- rs_write_active &= ~(1 << line);
- rs_event &= ~(1 << line);
-#else
- clear_bit(line, &rs_write_active);
- clear_bit(line, &rs_event);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_close ttys%d, count = %d\n", info->line, info->count);
#endif
+ if (--info->count > 0)
+ return;
+ tty->stopped = 0; /* Force flush to succeed */
+ wait_until_sent(tty);
+ clear_bit(line, rs_write_active);
+ clear_bit(line, rs_event);
info->event = 0;
- info->tty = 0;
- if (info->flags & ASYNC_NO_IRQ)
- info->flags &= ~ASYNC_NO_IRQ;
- else {
+ info->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ if (info->blocked_open) {
+ shutdown(info);
+ startup(info);
+ wake_up_interruptible(&info->open_wait);
+ return;
+ }
+ if (info->flags & ASYNC_INITIALIZED) {
+ shutdown(info);
irq = info->irq;
if (irq == 2)
irq = 9;
- if (info->next_port)
- info->next_port->prev_port = info->prev_port;
- if (info->prev_port)
- info->prev_port->next_port = info->next_port;
- else
- IRQ_ports[irq] = info->next_port;
- if (!IRQ_ports[irq])
- free_irq(irq);
+ if (irq) {
+ if (info->next_port)
+ info->next_port->prev_port = info->prev_port;
+ if (info->prev_port)
+ info->prev_port->next_port = info->next_port;
+ else
+ IRQ_ports[irq] = info->next_port;
+ if (!IRQ_ports[irq])
+ free_irq(irq);
+ }
}
+ info->tty = 0;
}
static void startup(struct async_struct * info)
{
unsigned short ICP;
+ unsigned long flags;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
/*
* First, clear the FIFO buffers and disable them
@@ -687,10 +605,18 @@ static void startup(struct async_struct * info)
(void)serial_inp(info, UART_RX);
(void)serial_inp(info, UART_IIR);
(void)serial_inp(info, UART_MSR);
+
+ info->flags |= ASYNC_INITIALIZED;
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
static void shutdown(struct async_struct * info)
{
+ unsigned long flags;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
serial_outp(info, UART_IER, 0x00); /* disable all intrs */
if (info->tty && !(info->tty->termios->c_cflag & HUPCL))
serial_outp(info, UART_MCR, UART_MCR_DTR);
@@ -699,9 +625,13 @@ static void shutdown(struct async_struct * info)
serial_outp(info, UART_MCR, 0x00);
serial_outp(info, UART_FCR, UART_FCR_CLEAR_CMD); /* disable FIFO's */
(void)serial_in(info, UART_RX); /* read data port to reset things */
+ info->flags &= ~ASYNC_INITIALIZED;
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
-void change_speed(unsigned int line)
+static void change_speed(unsigned int line)
{
struct async_struct * info;
unsigned short port;
@@ -781,92 +711,104 @@ static int get_serial_info(struct async_struct * info,
static int set_serial_info(struct async_struct * info,
struct serial_struct * new_info)
{
- struct serial_struct tmp;
- unsigned int new_port;
- unsigned int irq,new_irq;
+ struct serial_struct new;
+ unsigned int irq,check_irq;
int retval;
struct sigaction sa;
struct async_struct old_info;
- if (!suser())
- return -EPERM;
if (!new_info)
return -EFAULT;
- memcpy_fromfs(&tmp,new_info,sizeof(tmp));
+ memcpy_fromfs(&new,new_info,sizeof(new));
+ check_irq = 0;
old_info = *info;
- info->baud_base = tmp.baud_base;
- info->flags = tmp.flags & ASYNC_FLAGS;
- info->custom_divisor = tmp.custom_divisor;
+ if (!suser()) {
+ info->flags = ((info->flags & ~ASYNC_SPD_MASK) |
+ (new.flags & ASYNC_SPD_MASK));
+ info->custom_divisor = new.custom_divisor;
+ new.port = 0; /* Prevent initialization below */
+ goto check_and_exit;
+ }
- if ((tmp.type >= PORT_UNKNOWN) && (tmp.type <= PORT_MAX))
- info->type = tmp.type;
-
- new_port = tmp.port;
- new_irq = tmp.irq;
- if (new_irq > 15 || new_port > 0xffff) {
- *info = old_info;
+ if ((new.irq > 15) || (new.port > 0xffff) ||
+ (new.type < PORT_UNKNOWN) || (new.type > PORT_MAX)) {
return -EINVAL;
}
- if (new_irq == 2)
- new_irq = 9;
+
+ info->baud_base = new.baud_base;
+ info->flags = new.flags & ASYNC_FLAGS;
+ info->custom_divisor = new.custom_divisor;
+ info->type = new.type;
+
+ if (new.irq == 2)
+ new.irq = 9;
irq = info->irq;
if (irq == 2)
irq = 9;
- if (irq != new_irq) {
- /*
- * We need to change the IRQ for this board. OK, if
- * necessary, first we try to grab the new IRQ for
- * serial interrupts.
- */
- if (!IRQ_ports[new_irq]) {
+
+ /*
+ * If necessary, first we try to grab the new IRQ for serial
+ * interrupts. (We have to do this early, since we may get an
+ * error trying to do this.)
+ */
+ if (new.port && new.irq && info->type &&
+ ((irq != new.irq) || !(info->flags & ASYNC_INITIALIZED))) {
+ if (!IRQ_ports[new.irq]) {
sa.sa_handler = rs_interrupt;
sa.sa_flags = (SA_INTERRUPT);
sa.sa_mask = 0;
sa.sa_restorer = NULL;
- retval = irqaction(new_irq,&sa);
+ retval = irqaction(new.irq,&sa);
if (retval) {
*info = old_info;
return retval;
}
}
+ }
+ if ((new.irq != irq) ||
+ (new.port != info->port)) {
/*
- * If the new IRQ is OK, now we unlink the async structure from
- * the existing interrupt chain.
+ * We need to shutdown the serial port at the old
+ * port/irq combination.
*/
- if (info->next_port)
- info->next_port->prev_port = info->prev_port;
- if (info->prev_port)
- info->prev_port->next_port = info->next_port;
- else
- IRQ_ports[irq] = info->next_port;
- if (!IRQ_ports[irq])
- free_irq(irq);
-
+ if (info->flags & ASYNC_INITIALIZED) {
+ shutdown(info);
+ if (info->next_port)
+ info->next_port->prev_port = info->prev_port;
+ if (info->prev_port)
+ info->prev_port->next_port = info->next_port;
+ else
+ IRQ_ports[irq] = info->next_port;
+ check_irq = irq; /* Check later if we need to */
+ /* free the IRQ */
+ }
+ info->irq = new.irq;
+ info->port = new.port;
+ }
+
+check_and_exit:
+ if (new.port && new.irq && info->type &&
+ !(info->flags & ASYNC_INITIALIZED)) {
/*
- * Now link in the interrupt to the new interrupt chain.
+ * Link the port into the new interrupt chain.
*/
info->prev_port = 0;
- info->next_port = IRQ_ports[new_irq];
+ info->next_port = IRQ_ports[info->irq];
if (info->next_port)
info->next_port->prev_port = info;
- IRQ_ports[new_irq] = info;
- info->irq = new_irq;
- }
- cli();
- if (new_port != info->port) {
- shutdown(info);
- info->port = new_port;
+ IRQ_ports[info->irq] = info;
startup(info);
change_speed(info->line);
- old_info = *info; /* To avoid second change_speed */
- }
- sti();
-
- if (((old_info.flags & ASYNC_SPD_MASK) != (info->flags & ASYNC_SPD_MASK)) ||
- (old_info.custom_divisor != info->custom_divisor))
+ } else if (((old_info.flags & ASYNC_SPD_MASK) !=
+ (info->flags & ASYNC_SPD_MASK)) ||
+ (old_info.custom_divisor != info->custom_divisor))
change_speed(info->line);
+
+ if (check_irq && !IRQ_ports[check_irq])
+ free_irq(check_irq);
+
return 0;
}
@@ -956,7 +898,25 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return -EINVAL;
}
return 0;
-}
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+
+ change_speed(DEV_TO_SL(tty->line));
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->stopped = 0;
+ rs_write(tty);
+ }
+
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&rs_table[DEV_TO_SL(tty->line)].open_wait);
+}
/*
* This routine is called whenever a serial port is opened. It
@@ -970,60 +930,140 @@ int rs_open(struct tty_struct *tty, struct file * filp)
int irq, retval, line;
struct sigaction sa;
- if (!tty)
- return -ENODEV;
- if (tty->count > 1)
- return 0; /* We've already been initialized */
line = DEV_TO_SL(tty->line);
if ((line < 0) || (line >= NR_PORTS))
return -ENODEV;
info = rs_table + line;
- if (!info->port || !info->irq || !info->type) {
-#ifdef TTY_IO_ERROR
- set_bit(TTY_IO_ERROR, &tty->flags);
- info->flags |= ASYNC_NO_IRQ;
- info->tty = tty;
- tty->close = rs_close;
- tty->ioctl = rs_ioctl;
- return 0;
-#else
- return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttys%d, count = %d\n", info->line, info->count);
#endif
- } else
- info->flags &= ~ASYNC_NO_IRQ;
+ info->count++;
info->tty = tty;
+
tty->write = rs_write;
tty->close = rs_close;
tty->ioctl = rs_ioctl;
tty->throttle = rs_throttle;
- irq = info->irq;
- if (irq == 2)
- irq = 9;
- if (!IRQ_ports[irq]) {
- sa.sa_handler = rs_interrupt;
- sa.sa_flags = (SA_INTERRUPT);
- sa.sa_mask = 0;
- sa.sa_restorer = NULL;
- retval = irqaction(irq,&sa);
- if (retval)
- return retval;
+ tty->set_termios = rs_set_termios;
+
+ if (!(info->flags & ASYNC_INITIALIZED)) {
+ if (!info->port || !info->irq || !info->type) {
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ return 0;
+ }
+ irq = info->irq;
+ if (irq == 2)
+ irq = 9;
+ if (!IRQ_ports[irq]) {
+ sa.sa_handler = rs_interrupt;
+ sa.sa_flags = (SA_INTERRUPT);
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+ retval = irqaction(irq,&sa);
+ if (retval)
+ return retval;
+ }
+ /*
+ * Link in port to IRQ chain
+ */
+ info->prev_port = 0;
+ info->next_port = IRQ_ports[irq];
+ if (info->next_port)
+ info->next_port->prev_port = info;
+ IRQ_ports[irq] = info;
+
+ startup(info);
+ change_speed(info->line);
+ }
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval)
+ return retval;
+
+ return 0;
+
+}
+
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct async_struct *info)
+{
+ struct wait_queue wait = { current, NULL };
+ int retval;
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (MAJOR(filp->f_rdev) == 5) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
}
+
/*
- * Link in port to IRQ chain
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
*/
- info->prev_port = 0;
- info->next_port = IRQ_ports[irq];
- if (info->next_port)
- info->next_port->prev_port = info;
- IRQ_ports[irq] = info;
- startup(info);
- change_speed(info->line);
+ if (filp->f_flags & O_NONBLOCK) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ info->count--;
+ info->blocked_open++;
+ while (1) {
+ serial_out(info, UART_MCR,
+ serial_inp(info, UART_MCR) | UART_MCR_DTR);
+ current->state = TASK_INTERRUPTIBLE;
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ ((tty->termios->c_cflag & CLOCAL) ||
+ (serial_in(info, UART_MSR) & UART_MSR_DCD)))
+ break;
+ if (current->signal & ~current->blocked) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ info->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ info->line, info->count);
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ tty_unhangup(filp); /* To make sure fops is OK */
return 0;
-}
+}
+
static void show_serial_version()
{
- printk("Serial driver version 3.8 with");
+ printk("Serial driver version 3.91 with");
#ifdef CONFIG_AST_FOURPORT
printk(" AST_FOURPORT");
#define SERIAL_OPT
@@ -1044,27 +1084,26 @@ static void show_serial_version()
#undef SERIAL_OPT
}
-
-static void init(struct async_struct * info)
-{
#ifdef CONFIG_AUTO_IRQ
- unsigned char status1, status2, scratch, save_ICP=0;
+static int get_auto_irq(struct async_struct *info)
+{
+ unsigned char save_MCR, save_IER, save_ICP=0;
unsigned short ICP=0, port = info->port;
unsigned long timeout;
-
+
/*
* Enable interrupts and see who answers
*/
rs_irq_triggered = 0;
- scratch = serial_inp(info, UART_IER);
- status1 = serial_inp(info, UART_MCR);
+ save_IER = serial_inp(info, UART_IER);
+ save_MCR = serial_inp(info, UART_MCR);
if (info->flags & ASYNC_FOURPORT) {
serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
serial_outp(info, UART_IER, 0x0f); /* enable all intrs */
ICP = (port & 0xFE0) | 0x01F;
save_ICP = inb_p(ICP);
outb_p(0x80, ICP);
- (void) inb(ICP);
+ (void) inb_p(ICP);
} else {
serial_outp(info, UART_MCR,
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
@@ -1086,21 +1125,49 @@ static void init(struct async_struct * info)
/*
* Now check to see if we got any business, and clean up.
*/
- if (rs_irq_triggered) {
- serial_outp(info, UART_IER, 0);
- info->irq = rs_irq_triggered;
- } else {
- serial_outp(info, UART_IER, scratch);
- serial_outp(info, UART_MCR, status1);
- if (info->flags & ASYNC_FOURPORT)
- outb_p(save_ICP, ICP);
+ serial_outp(info, UART_IER, save_IER);
+ serial_outp(info, UART_MCR, save_MCR);
+ if (info->flags & ASYNC_FOURPORT)
+ outb_p(save_ICP, ICP);
+ return(rs_irq_triggered);
+}
+#endif
+
+
+static void init(struct async_struct * info)
+{
+ unsigned char status1, status2, scratch, scratch2;
+ unsigned port = info->port;
+#ifdef CONFIG_AUTO_IRQ
+ int retries;
+
+ if (!port)
+ return;
+
+ scratch2 = 0;
+ for (retries = 0; retries < 5; retries++) {
+ if (!scratch)
+ scratch = get_auto_irq(info);
+ if (!scratch2)
+ scratch2 = get_auto_irq(info);
+ if (scratch && scratch2) {
+ if (scratch == scratch2)
+ break;
+ scratch = scratch2 = 0;
+ }
+ }
+ if (scratch && (scratch == scratch2))
+ info->irq = scratch;
+ else {
info->type = PORT_UNKNOWN;
return;
}
+
#else /* CONFIG_AUTO_IRQ */
- unsigned char status1, status2, scratch, scratch2;
- unsigned short port = info->port;
+ if (!port)
+ return;
+
/*
* Check to see if a UART is really there.
*/
@@ -1193,8 +1260,6 @@ long rs_init(long kmem_start)
#endif
show_serial_version();
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
- if (!info->port)
- continue;
info->line = i;
info->tty = 0;
info->type = PORT_UNKNOWN;
@@ -1202,12 +1267,15 @@ long rs_init(long kmem_start)
info->custom_divisor = 0;
info->x_char = 0;
info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->open_wait = 0;
info->next_port = 0;
info->prev_port = 0;
init(info);
if (info->type == PORT_UNKNOWN)
continue;
- printk("ttys%d%s at 0x%04x (irq = %d)", info->line,
+ printk("ttyS%d%s at 0x%04x (irq = %d)", info->line,
(info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
info->port, info->irq);
switch (info->type) {
@@ -1239,6 +1307,9 @@ long rs_init(long kmem_start)
free_irq(i);
}
#endif
+ bh_base[SERIAL_BH].routine = do_softint;
+ memset(&rs_event, 0, sizeof(rs_event));
+ memset(&rs_write_active, 0, sizeof(rs_write_active));
return kmem_start;
}
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 455c2bb..4a91925 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -20,6 +20,14 @@
* between the high-level tty routines (tty_io.c and tty_ioctl.c) and
* the low-level tty routines (serial.c, pty.c, console.c). This
* makes for cleaner and more compact code. -TYT, 9/17/92
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ *
+ * NOTE: pay no attention to the line discpline code (yet); its
+ * interface is still subject to change in this version...
+ * -- TYT, 1/31/92
*/
#include <linux/types.h>
@@ -41,9 +49,13 @@
#include "vt_kern.h"
-struct tty_struct *tty_table[256];
-struct termios *tty_termios[256]; /* We need to keep the termios state */
+#define MAX_TTYS 256
+
+struct tty_struct *tty_table[MAX_TTYS];
+struct termios *tty_termios[MAX_TTYS]; /* We need to keep the termios state */
/* around, even when a tty is closed */
+struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
+int tty_check_write[MAX_TTYS/32]; /* bitfield for the bh handler */
/*
* fg_console is the current virtual console,
@@ -63,6 +75,20 @@ static int tty_select(struct inode *, struct file *, int, select_table *);
static int tty_open(struct inode *, struct file *);
static void tty_release(struct inode *, struct file *);
+int tty_register_ldisc(int disc, struct tty_ldisc *new)
+{
+ if (disc < N_TTY || disc >= NR_LDISCS)
+ return -EINVAL;
+
+ if (new) {
+ ldiscs[disc] = *new;
+ ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
+ } else
+ memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
+
+ return 0;
+}
+
void put_tty_queue(char c, struct tty_queue * queue)
{
int head;
@@ -91,6 +117,33 @@ int get_tty_queue(struct tty_queue * queue)
return result;
}
+/*
+ * This routine copies out a maximum of buflen characters from the
+ * read_q; it is a convenience for line disciplins so they can grab a
+ * large block of data without calling get_tty_char directly. It
+ * returns the number of characters actually read.
+ */
+int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen)
+{
+ int result = 0;
+ unsigned char *p = bufp;
+ unsigned long flags;
+ int head, tail;
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ tail = tty->read_q.tail;
+ head = tty->read_q.head;
+ while ((result < buflen) && (tail!=head)) {
+ *p++ = tty->read_q.buf[tail++];
+ tail &= TTY_BUF_SIZE-1;
+ result++;
+ }
+ tty->read_q.tail = tail;
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ return result;
+}
+
+
void tty_write_flush(struct tty_struct * tty)
{
if (!tty->write || EMPTY(&tty->write_q))
@@ -108,7 +161,7 @@ void tty_read_flush(struct tty_struct * tty)
return;
if (set_bit(TTY_READ_BUSY, &tty->flags))
return;
- copy_to_cooked(tty);
+ ldiscs[tty->disc].handler(tty);
if (clear_bit(TTY_READ_BUSY, &tty->flags))
printk("tty_read_flush: bit already cleared\n");
}
@@ -182,6 +235,11 @@ void tty_hangup(struct tty_struct * tty)
kill_sl(tty->session,SIGHUP,1);
}
+void tty_unhangup(struct file *filp)
+{
+ filp->f_op = &tty_fops;
+}
+
static inline int hung_up(struct file * filp)
{
return filp->f_op == &hung_up_tty_fops;
@@ -364,7 +422,7 @@ void change_console(unsigned int new_console)
void wait_for_keypress(void)
{
- interruptible_sleep_on(&keypress_wait);
+ sleep_on(&keypress_wait);
}
void copy_to_cooked(struct tty_struct * tty)
@@ -754,7 +812,7 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
dev = file->f_rdev;
if (MAJOR(dev) != 4) {
- printk("tty_read: pseudo-major != 4\n");
+ printk("tty_read: bad pseudo-major nr #%d\n", MAJOR(dev));
return -EINVAL;
}
dev = MINOR(dev);
@@ -770,7 +828,10 @@ static int tty_read(struct inode * inode, struct file * file, char * buf, int co
(void) kill_pg(current->pgrp, SIGTTIN, 1);
return -ERESTARTSYS;
}
- i = read_chan(tty,file,buf,count);
+ if (ldiscs[tty->disc].read)
+ i = (ldiscs[tty->disc].read)(tty,file,buf,count);
+ else
+ i = -EIO;
if (i > 0)
inode->i_atime = CURRENT_TIME;
return i;
@@ -803,7 +864,10 @@ static int tty_write(struct inode * inode, struct file * file, char * buf, int c
return -ERESTARTSYS;
}
}
- i = write_chan(tty,file,buf,count);
+ if (ldiscs[tty->disc].write)
+ i = (ldiscs[tty->disc].write)(tty,file,buf,count);
+ else
+ i = -EIO;
if (i > 0)
inode->i_mtime = CURRENT_TIME;
return i;
@@ -936,7 +1000,8 @@ static void release_dev(int dev, struct file * filp)
return;
}
}
- if (tty->count < 2 && tty->close)
+ tty->write_data_cnt = 0; /* Clear out pending trash */
+ if (tty->close)
tty->close(tty, filp);
if (IS_A_PTY_MASTER(dev)) {
if (--tty->link->count < 0) {
@@ -952,6 +1017,10 @@ static void release_dev(int dev, struct file * filp)
}
if (tty->count)
return;
+
+ if (ldiscs[tty->disc].close != NULL)
+ ldiscs[tty->disc].close(tty);
+
if (o_tty) {
if (o_tty->count)
return;
@@ -981,6 +1050,7 @@ static void release_dev(int dev, struct file * filp)
*
* Open-counting is needed for pty masters, as well as for keeping
* track of serial lines: DTR is dropped when the last close happens.
+ * (This is not done solely through tty->count, now. - Ted 1/27/92)
*
* The termios state of a pty is reset on first open so that
* settings don't persist across reuse.
@@ -988,23 +1058,44 @@ static void release_dev(int dev, struct file * filp)
static int tty_open(struct inode * inode, struct file * filp)
{
struct tty_struct *tty;
- int dev, retval;
-
- dev = inode->i_rdev;
- if (MAJOR(dev) == 5)
- dev = current->tty;
- else
- dev = MINOR(dev);
- if (dev < 0)
+ int major, minor;
+ int noctty, retval;
+
+ minor = MINOR(inode->i_rdev);
+ major = MAJOR(inode->i_rdev);
+ noctty = filp->f_flags & O_NOCTTY;
+ if (major == 5) {
+ if (!minor) {
+ major = 4;
+ minor = current->tty;
+ }
+ noctty = 1;
+ } else if (major == 4) {
+ if (!minor) {
+ minor = fg_console + 1;
+ noctty = 1;
+ }
+ } else {
+ printk("Bad major #%d in tty_open\n", MAJOR(inode->i_rdev));
+ return -ENODEV;
+ }
+ if (minor <= 0)
return -ENXIO;
- if (!dev)
- dev = fg_console + 1;
- filp->f_rdev = 0x0400 | dev;
- retval = init_dev(dev);
+ if (IS_A_PTY_MASTER(minor))
+ noctty = 1;
+ filp->f_rdev = (major << 8) | minor;
+ retval = init_dev(minor);
if (retval)
return retval;
- tty = tty_table[dev];
+ tty = tty_table[minor];
+
/* clean up the packet stuff. */
+ /*
+ * Why is this not done in init_dev? Right here, if another
+ * process opens up a tty in packet mode, all the packet
+ * variables get cleared. Come to think of it, is anything
+ * using the packet mode at all??? - Ted, 1/27/93
+ */
tty->status_changed = 0;
tty->ctrl_status = 0;
tty->packet = 0;
@@ -1015,17 +1106,18 @@ static int tty_open(struct inode * inode, struct file * filp)
retval = -ENODEV;
}
if (retval) {
- release_dev(dev, filp);
+ release_dev(minor, filp);
return retval;
}
- if (!(filp->f_flags & O_NOCTTY) &&
+ if (!noctty &&
current->leader &&
current->tty<0 &&
tty->session==0) {
- current->tty = dev;
+ current->tty = minor;
tty->session = current->session;
tty->pgrp = current->pgrp;
}
+ filp->f_rdev = 0x0400 | minor; /* Set it to something normal */
return 0;
}
@@ -1139,6 +1231,104 @@ void do_SAK( struct tty_struct *tty)
}
/*
+ * This routine allows a kernel routine to send a large chunk of data
+ * to a particular tty; if all of the data can be queued up for ouput
+ * immediately, tty_write_data() will return 0. If, however, not all
+ * of the data can be immediately queued for delivery, the number of
+ * bytes left to be queued up will be returned, and the rest of the
+ * data will be queued up when there is room. The callback function
+ * will be called (with the argument callarg) when the last of the
+ * data is finally in the queue.
+ *
+ * Note that the callback routine will _not_ be called if all of the
+ * data could be queued immediately. This is to avoid a problem with
+ * the kernel stack getting too deep, which might happen if the
+ * callback routine calls tty_write_data with itself as an argument.
+ */
+int tty_write_data(struct tty_struct *tty, char *bufp, int buflen,
+ void (*callback)(void * data), void * callarg)
+{
+ int head, tail, count;
+ unsigned long flags;
+ char *p;
+
+#define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1))
+
+ __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
+ if (tty->write_data_cnt) {
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ return -EBUSY;
+ }
+
+ head = tty->write_q.head;
+ tail = tty->write_q.tail;
+ count = buflen;
+ p = bufp;
+
+ while (count && VLEFT > 0) {
+ tty->write_q.buf[head++] = *p++;
+ head &= TTY_BUF_SIZE-1;
+ }
+ tty->write_q.head = head;
+ if (count) {
+ tty->write_data_cnt = count;
+ tty->write_data_ptr = p;
+ tty->write_data_callback = callback;
+ tty->write_data_arg = callarg;
+ }
+ __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
+ return count;
+}
+
+/*
+ * This routine routine is called after an interrupt has drained a
+ * tty's write queue, so that there is more space for data waiting to
+ * be sent in tty->write_data_ptr.
+ *
+ * tty_check_write[8] is a bitstring which indicates which ttys
+ * needs to be processed.
+ */
+void tty_bh_routine()
+{
+ int i, j, line, mask;
+ int head, tail, count;
+ unsigned char * p;
+ struct tty_struct * tty;
+
+ for (i = 0, line = 0; i < MAX_TTYS / 32; i++) {
+ if (!tty_check_write[i]) {
+ line += 32;
+ continue;
+ }
+ for (j=0, mask=0; j < 32; j++, line++, mask <<= 1) {
+ if (!clear_bit(j, &tty_check_write[i])) {
+ tty = tty_table[line];
+ if (!tty || !tty->write_data_cnt)
+ continue;
+ cli();
+ head = tty->write_q.head;
+ tail = tty->write_q.tail;
+ count = tty->write_data_cnt;
+ p = tty->write_data_ptr;
+
+ while (count && VLEFT > 0) {
+ tty->write_q.buf[head++] = *p++;
+ head &= TTY_BUF_SIZE-1;
+ }
+ tty->write_q.head = head;
+ tty->write_data_ptr = p;
+ tty->write_data_cnt = count;
+ sti();
+ if (!count)
+ (tty->write_data_callback)
+ (tty->write_data_arg);
+ }
+ }
+ }
+
+}
+
+/*
* This subroutine initializes a tty structure. We have to set up
* things correctly for each different type of tty.
*/
@@ -1146,6 +1336,7 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
{
memset(tty, 0, sizeof(struct tty_struct));
tty->line = line;
+ tty->disc = N_TTY;
tty->pgrp = -1;
tty->winsize.ws_row = 24;
tty->winsize.ws_col = 80;
@@ -1171,7 +1362,7 @@ static void initialize_termios(int line, struct termios * tp)
tp->c_lflag = ISIG | ICANON | ECHO |
ECHOCTL | ECHOKE;
} else if (IS_A_SERIAL(line)) {
- tp->c_cflag = B2400 | CS8 | CREAD | HUPCL;
+ tp->c_cflag = B2400 | CS8 | CREAD | HUPCL | CLOCAL;
} else if (IS_A_PTY_MASTER(line)) {
tp->c_cflag = B9600 | CS8 | CREAD;
} else if (IS_A_PTY_SLAVE(line)) {
@@ -1182,20 +1373,40 @@ static void initialize_termios(int line, struct termios * tp)
ECHOCTL | ECHOKE;
}
}
+
+static struct tty_ldisc tty_ldisc_N_TTY = {
+ 0, /* flags */
+ NULL, /* open */
+ NULL, /* close */
+ read_chan, /* read */
+ write_chan, /* write */
+ NULL, /* ioctl */
+ copy_to_cooked /* handler */
+};
+
long tty_init(long kmem_start)
{
int i;
+ if (sizeof(struct tty_struct) > 4096)
+ panic("size of tty structure > 4096!");
+
chrdev_fops[4] = &tty_fops;
chrdev_fops[5] = &tty_fops;
- for (i=0 ; i<256 ; i++) {
+ for (i=0 ; i< MAX_TTYS ; i++) {
tty_table[i] = 0;
tty_termios[i] = 0;
}
+ memset(tty_check_write, 0, sizeof(tty_check_write));
+ bh_base[TTY_BH].routine = tty_bh_routine;
+
+ /* Setup the default TTY line discipline. */
+ memset(ldiscs, 0, sizeof(ldiscs));
+ (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+
kmem_start = kbd_init(kmem_start);
kmem_start = con_init(kmem_start);
kmem_start = rs_init(kmem_start);
- printk("%d virtual consoles\n\r",NR_CONSOLES);
return kmem_start;
}
diff --git a/kernel/chr_drv/tty_ioctl.c b/kernel/chr_drv/tty_ioctl.c
index 7eb6e4e..c34b91a 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/kernel/chr_drv/tty_ioctl.c
@@ -2,6 +2,10 @@
* linux/kernel/chr_drv/tty_ioctl.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
*/
#include <linux/types.h>
@@ -16,6 +20,13 @@
#include <asm/segment.h>
#include <asm/system.h>
+#undef DEBUG
+#ifdef DEBUG
+# define PRINTK(x) printk (x)
+#else
+# define PRINTK(x) /**/
+#endif
+
extern int session_of_pgrp(int pgrp);
extern int do_screendump(int arg);
extern int kill_pg(int pgrp, int sig, int priv);
@@ -119,34 +130,43 @@ static int get_termios(struct tty_struct * tty, struct termios * termios)
return 0;
}
+static int check_change(struct tty_struct * tty, int channel)
+{
+ /* If we try to set the state of terminal and we're not in the
+ foreground, send a SIGTTOU. If the signal is blocked or
+ ignored, go ahead and perform the operation. POSIX 7.2) */
+ if (current->tty != channel)
+ return 0;
+ if (tty->pgrp <= 0 || tty->pgrp == current->pgrp)
+ return 0;
+ if (is_orphaned_pgrp(current->pgrp))
+ return -EIO;
+ if (is_ignored(SIGTTOU))
+ return 0;
+ (void) kill_pg(current->pgrp,SIGTTOU,1);
+ return -ERESTARTSYS;
+}
+
static int set_termios(struct tty_struct * tty, struct termios * termios,
int channel)
{
int i;
- unsigned short old_cflag = tty->termios->c_cflag;
+ struct termios old_termios = *tty->termios;
- /* If we try to set the state of terminal and we're not in the
- foreground, send a SIGTTOU. If the signal is blocked or
- ignored, go ahead and perform the operation. POSIX 7.2) */
- if ((current->tty == channel) &&
- (tty->pgrp != current->pgrp)) {
- if (is_orphaned_pgrp(current->pgrp))
- return -EIO;
- if (!is_ignored(SIGTTOU)) {
- (void) kill_pg(current->pgrp,SIGTTOU,1);
- return -ERESTARTSYS;
- }
- }
+ i = check_change(tty, channel);
+ if (i)
+ return i;
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
- if (IS_A_SERIAL(channel) && tty->termios->c_cflag != old_cflag)
- change_speed(channel-64);
/* puting mpty's into echo mode is very bad, and I think under
some situations can cause the kernel to do nothing but
copy characters back and forth. -RAB */
if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
+ if (tty->set_termios)
+ (*tty->set_termios)(tty, &old_termios);
+
return 0;
}
@@ -176,18 +196,11 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
{
int i;
struct termio tmp_termio;
- unsigned short old_cflag = tty->termios->c_cflag;
-
- if ((current->tty == channel) &&
- (tty->pgrp > 0) &&
- (tty->pgrp != current->pgrp)) {
- if (is_orphaned_pgrp(current->pgrp))
- return -EIO;
- if (!is_ignored(SIGTTOU)) {
- (void) kill_pg(current->pgrp,SIGTTOU,1);
- return -ERESTARTSYS;
- }
- }
+ struct termios old_termios = *tty->termios;
+
+ i = check_change(tty, channel);
+ if (i)
+ return i;
for (i=0 ; i< (sizeof (*termio)) ; i++)
((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
@@ -213,8 +226,10 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
tty->termios->c_line = tmp_termio.c_line;
for(i=0 ; i < NCC ; i++)
tty->termios->c_cc[i] = tmp_termio.c_cc[i];
- if (IS_A_SERIAL(channel) && tty->termios->c_cflag != old_cflag)
- change_speed(channel-64);
+
+ if (tty->set_termios)
+ (*tty->set_termios)(tty, &old_termios);
+
return 0;
}
@@ -253,6 +268,31 @@ static int get_window_size(struct tty_struct * tty, struct winsize * ws)
return 0;
}
+/* Set the discipline of a tty line. */
+static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+{
+ if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
+ !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
+ return -EINVAL;
+
+ if (tty->disc == ldisc)
+ return 0; /* We are already in the desired discipline */
+
+ /* Shutdown the current discipline. */
+ wait_until_sent(tty);
+ flush_input(tty);
+ if (ldiscs[tty->disc].close)
+ ldiscs[tty->disc].close(tty);
+
+ /* Now set up the new line discipline. */
+ tty->disc = ldisc;
+ if (ldiscs[tty->disc].open)
+ return(ldiscs[tty->disc].open(tty));
+ else
+ return 0;
+}
+
+
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned int arg)
{
@@ -262,6 +302,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
int pgrp;
int dev;
int termios_dev;
+ int retval;
if (MAJOR(file->f_rdev) != 4) {
printk("tty_ioctl: tty pseudo-major != 4\n");
@@ -434,7 +475,13 @@ int tty_ioctl(struct inode * inode, struct file * file,
tty->session = 0;
}
return 0;
-
+ case TIOCGETD:
+ verify_area((void *) arg,4);
+ put_fs_long(tty->disc, (unsigned long *) arg);
+ return 0;
+ case TIOCSETD:
+ arg = get_fs_long((unsigned long *) arg);
+ return tty_set_ldisc(tty, arg);
case TIOCPKT:
{
int on;
@@ -450,9 +497,16 @@ int tty_ioctl(struct inode * inode, struct file * file,
}
default:
- if (tty->ioctl)
- return (tty->ioctl)(tty, file, cmd, arg);
- else
- return -EINVAL;
+ if (tty->ioctl) {
+ retval = (tty->ioctl)(tty, file, cmd, arg);
+ if (retval != -EINVAL)
+ return retval;
+ }
+ if (ldiscs[tty->disc].ioctl) {
+ retval = (ldiscs[tty->disc].ioctl)
+ (tty, file, cmd, arg);
+ return retval;
+ }
+ return -EINVAL;
}
}
diff --git a/kernel/fork.c b/kernel/fork.c
index b5b8f21..856d864 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -20,7 +20,7 @@
#include <asm/segment.h>
#include <asm/system.h>
-#define MAX_TASKS_PER_USER ((NR_TASKS/4)*3)
+#define MAX_TASKS_PER_USER (NR_TASKS/2)
long last_pid=0;
@@ -41,11 +41,12 @@ void verify_area(void * addr,int size)
static int find_empty_process(void)
{
int i, task_nr;
- int this_user_tasks = 0;
+ int this_user_tasks;
repeat:
- if ((++last_pid) & 0xffff0000)
+ if ((++last_pid) & 0xffff8000)
last_pid=1;
+ this_user_tasks = 0;
for(i=0 ; i < NR_TASKS ; i++) {
if (!task[i])
continue;
diff --git a/kernel/irq.c b/kernel/irq.c
index 8a6cefe..0c03383 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -239,8 +239,6 @@ void free_irq(unsigned int irq)
restore_flags(flags);
}
-extern void do_coprocessor_error(long,long);
-
/*
* Note that on a 486, we don't want to do a SIGFPE on a irq13
* as the irq is unreliable, and exception 16 works correctly
@@ -251,12 +249,10 @@ extern void do_coprocessor_error(long,long);
static void math_error_irq(int cpl)
{
outb(0,0xF0);
- do_coprocessor_error(0,0);
-}
-
-static void math_error_irq_486(int cpl)
-{
- outb(0,0xF0); /* even this is probably not needed.. */
+ if (ignore_irq13)
+ return;
+ send_sig(SIGFPE, last_task_used_math, 1);
+ __asm__("fninit");
}
static void no_action(int cpl) { }
@@ -271,18 +267,12 @@ static struct sigaction ignore_IRQ = {
void init_IRQ(void)
{
int i;
- unsigned long cr0;
for (i = 0; i < 16 ; i++)
set_intr_gate(0x20+i,bad_interrupt[i]);
if (irqaction(2,&ignore_IRQ))
printk("Unable to get IRQ2 for cascade\n");
- __asm__("movl %%cr0,%%eax":"=a" (cr0));
- if (cr0 & CR0_NE)
- i = request_irq(13,math_error_irq_486);
- else
- i = request_irq(13,math_error_irq);
- if (i)
+ if (request_irq(13,math_error_irq))
printk("Unable to get IRQ13 for math-error handler\n");
/* intialize the bottom half routines. */
diff --git a/kernel/sched.c b/kernel/sched.c
index 3276ac2..77e323b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -30,6 +30,7 @@
int need_resched = 0;
int hard_math = 0; /* set by boot/head.S */
+int ignore_irq13 = 0; /* set if exception 16 works */
unsigned long * prof_buffer = NULL;
unsigned long prof_len = 0;
@@ -316,9 +317,11 @@ static struct timer_list * next_timer = NULL;
void add_timer(long jiffies, void (*fn)(void))
{
struct timer_list * p;
+ unsigned long flags;
if (!fn)
return;
+ save_flags(flags);
cli();
if (jiffies <= 0)
(fn)();
@@ -342,8 +345,10 @@ void add_timer(long jiffies, void (*fn)(void))
p->next->jiffies = jiffies;
p = p->next;
}
+ if (p->next)
+ p->next->jiffies -= p->jiffies;
}
- sti();
+ restore_flags(flags);
}
unsigned long timer_active = 0;
diff --git a/kernel/sys.c b/kernel/sys.c
index 26e2671..22d22cb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -414,7 +414,13 @@ int sys_times(struct tms * tbuf)
int sys_brk(unsigned long end_data_seg)
{
+ unsigned long rlim;
+
+ rlim = current->rlim[RLIMIT_DATA].rlim_cur;
+ if (rlim >= RLIM_INFINITY)
+ rlim = 0xffffffff;
if (end_data_seg >= current->end_code &&
+ end_data_seg-current->end_code <= rlim &&
end_data_seg < current->start_stack - 16384)
current->brk = end_data_seg;
return current->brk;
@@ -657,10 +663,11 @@ int sys_getrusage(int who, struct rusage *ru)
int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
{
if (tv) {
+ unsigned long nowtime = jiffies+jiffies_offset;
verify_area(tv, sizeof *tv);
- put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset),
+ put_fs_long(startup_time + CT_TO_SECS(nowtime),
(unsigned long *) tv);
- put_fs_long(CT_TO_USECS(jiffies+jiffies_offset),
+ put_fs_long(CT_TO_USECS(nowtime),
((unsigned long *) tv)+1);
}
if (tz) {
diff --git a/kernel/traps.c b/kernel/traps.c
index 97cf82f..f4076c3 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -168,6 +168,7 @@ void do_stack_segment(long esp,long error_code)
void do_coprocessor_error(long esp, long error_code)
{
+ ignore_irq13 = 1;
send_sig(SIGFPE, last_task_used_math, 1);
__asm__("fninit");
}
diff --git a/mm/memory.c b/mm/memory.c
index 19a961e..bde475b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -263,11 +263,11 @@ int unmap_page_range(unsigned long from, unsigned long size)
}
for (pc = pcnt; pc--; page_table++) {
if ((page = *page_table) != 0) {
- --current->rss;
*page_table = 0;
- if (1 & page)
+ if (1 & page) {
+ --current->rss;
free_page(0xfffff000 & page);
- else
+ } else
swap_free(page >> 1);
}
}
@@ -394,15 +394,12 @@ static unsigned long put_page(struct task_struct * tsk,unsigned long page,unsign
return 0;
}
page_table = (unsigned long *) (tsk->tss.cr3 + ((address>>20) & 0xffc));
- if ((*page_table)&1)
+ if ((*page_table) & PAGE_PRESENT)
page_table = (unsigned long *) (0xfffff000 & *page_table);
else {
- tmp = get_free_page(GFP_KERNEL);
- if (!tmp) {
- oom(tsk);
- tmp = BAD_PAGETABLE;
- }
- *page_table = tmp | PAGE_ACCESSED | 7;
+ printk("put_page: bad page directory entry\n");
+ oom(tsk);
+ *page_table = BAD_PAGETABLE | PAGE_ACCESSED | 7;
return 0;
}
page_table += (address >> PAGE_SHIFT) & 0x3ff;
@@ -771,6 +768,7 @@ void do_page_fault(unsigned long *esp, unsigned long error_code)
{
unsigned long address;
unsigned long user_esp = 0;
+ unsigned long stack_limit;
unsigned int bit;
extern void die_if_kernel();
@@ -789,6 +787,16 @@ void do_page_fault(unsigned long *esp, unsigned long error_code)
do_wp_page(error_code, address, current, user_esp);
else
do_no_page(error_code, address, current, user_esp);
+ if (!user_esp)
+ return;
+ stack_limit = current->rlim[RLIMIT_STACK].rlim_cur;
+ if (stack_limit >= RLIM_INFINITY)
+ return;
+ if (stack_limit >= current->start_stack)
+ return;
+ stack_limit = current->start_stack - stack_limit;
+ if (user_esp < stack_limit)
+ send_sig(SIGSEGV, current, 1);
return;
}
printk("Unable to handle kernel paging request at address %08x\n",address);
diff --git a/net/kern_sock.h b/net/kern_sock.h
index 0b8a5ee..c9c853c 100644
--- a/net/kern_sock.h
+++ b/net/kern_sock.h
@@ -37,6 +37,10 @@ struct socket {
void *dummy;
};
+#define SOCK_INODE(S) ((struct inode *)(S)->dummy)
+extern struct socket sockets[NSOCKETS];
+#define last_socket (sockets + NSOCKETS - 1)
+
struct proto_ops {
int (*init)(void);
int (*create)(struct socket *sock, int protocol);
@@ -69,7 +73,7 @@ struct proto_ops {
int (*getsockopt)(struct socket *sock, int level, int optname,
char *optval, int *optlen);
int (*fcntl) (struct socket *sock, unsigned int cmd,
- unsigned long arg);
+ unsigned long arg);
};
extern int sock_awaitconn(struct socket *mysock, struct socket *servsock);
diff --git a/net/socket.c b/net/socket.c
index ff67b47..d34db75 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -70,10 +70,7 @@ static struct file_operations socket_file_ops = {
sock_close
};
-#define SOCK_INODE(S) ((struct inode *)(S)->dummy)
-
-static struct socket sockets[NSOCKETS];
-#define last_socket (sockets + NSOCKETS - 1)
+struct socket sockets[NSOCKETS];
static struct wait_queue *socket_wait_free = NULL;
/*
@@ -177,8 +174,11 @@ sock_alloc(int wait)
return NULL;
}
SOCK_INODE(sock)->i_mode = S_IFSOCK;
+ SOCK_INODE(sock)->i_uid = current->euid;
+ SOCK_INODE(sock)->i_gid = current->egid;
+
sock->wait = &SOCK_INODE(sock)->i_wait;
- PRINTK(("sock_alloc: socket 0x%x, inode 0x%x\n",
+ PRINTK(("sock_alloc: socket 0x%x,inode 0x%x\n",
sock, SOCK_INODE(sock)));
return sock;
}
@@ -951,11 +951,10 @@ sock_init(void)
for (sock = sockets; sock <= last_socket; ++sock)
sock->state = SS_FREE;
for (i = ok = 0; i < NPROTO; ++i) {
- printk("sock_init: initializing family %d (%s)\n",
- proto_table[i].family, proto_table[i].name);
if ((*proto_table[i].ops->init)() < 0) {
- printk("sock_init: init failed.\n",
- proto_table[i].family);
+ printk("sock_init: init failed family %d (%s)\n",
+ proto_table[i].family,
+ proto_table[i].name);
proto_table[i].family = -1;
}
else
diff --git a/net/tcp/Space.c b/net/tcp/Space.c
index f859ef6..8bcfce9 100644
--- a/net/tcp/Space.c
+++ b/net/tcp/Space.c
@@ -1,8 +1,14 @@
/* Space.c */
/* Holds initial configuration information for devices. */
-/* $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: Space.c,v 0.8.4.7 1993/01/22 23:21:38 bir7 Exp $ */
/* $Log: Space.c,v $
+ * Revision 0.8.4.7 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
+ * Revision 0.8.4.6 1993/01/22 22:58:08 bir7
+ * *** empty log message ***
+ *
* Revision 0.8.4.5 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
diff --git a/net/tcp/arp.c b/net/tcp/arp.c
index b6b08ab..451d316 100644
--- a/net/tcp/arp.c
+++ b/net/tcp/arp.c
@@ -19,8 +19,14 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: arp.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: arp.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: arp.c,v $
+ * Revision 0.8.4.8 1993/01/23 18:00:11 bir7
+ * Added ioctls as supplied by R.P. Bellis <rpb@psy.ox.ac.uk>
+ *
+ * Revision 0.8.4.7 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
* Revision 0.8.4.5 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -50,6 +56,9 @@
#include <linux/socket.h>
#include <netinet/in.h>
+#include <linux/sock_ioctl.h>
+#include <linux/errno.h>
+#include <asm/segment.h>
#include <asm/system.h>
#include "timer.h"
@@ -66,8 +75,8 @@
#define PRINTK(x) /**/
#endif
-static struct arp_table *arp_table[ARP_TABLE_SIZE] ={NULL, };
-struct sk_buff *arp_q=NULL;
+static volatile struct arp_table *arp_table[ARP_TABLE_SIZE] ={NULL, };
+volatile struct sk_buff *arp_q=NULL;
/* this will try to retransmit everything on the queue. */
static void
@@ -77,7 +86,7 @@ send_arp_q(void)
struct sk_buff *next;
cli();
- next = arp_q;
+ next = (struct sk_buff *)arp_q;
arp_q = NULL;
sti();
while ((skb = next) != NULL) {
@@ -98,7 +107,7 @@ send_arp_q(void)
}
/* first remove skb from the queue. */
- next = skb->next;
+ next = (struct sk_buff *)skb->next;
if (next == skb)
{
next = NULL;
@@ -289,7 +298,9 @@ arp_lookup (unsigned long paddr)
if (my_ip_addr(paddr)) return (NULL);
hash = net32(paddr) & (ARP_TABLE_SIZE - 1);
cli();
- for (apt = arp_table[hash]; apt != NULL; apt = apt->next)
+ for (apt = (struct arp_table *)arp_table[hash];
+ apt != NULL;
+ apt = (struct arp_table *)apt->next)
{
if (apt->ip == paddr)
{
@@ -319,7 +330,7 @@ arp_destroy(unsigned long paddr)
/* check the first one. */
if (arp_table[hash]->ip == paddr)
{
- apt = arp_table[hash];
+ apt = (struct arp_table *)arp_table[hash];
arp_table[hash] = arp_table[hash]->next;
arp_free (apt, sizeof (*apt));
sti();
@@ -327,8 +338,10 @@ arp_destroy(unsigned long paddr)
}
/* now deal with it any where else in the chain. */
- lapt = arp_table[hash];
- for (apt = arp_table[hash]->next; apt != NULL; apt = apt->next)
+ lapt = (struct arp_table *)arp_table[hash];
+ for (apt = (struct arp_table *)arp_table[hash]->next;
+ apt != NULL;
+ apt = (struct arp_table *)apt->next)
{
if (apt->ip == paddr)
{
@@ -558,3 +571,66 @@ arp_queue(struct sk_buff *skb)
skb->magic = ARP_QUEUE_MAGIC;
sti();
}
+
+static int arpreq_check(struct arpreq *req)
+{
+ /* Check protocol familys */
+ if (req->arp_pa.sa_family != AF_INET) return -1;
+
+ if (req->arp_ha.sa_family != AF_UNSPEC) return -1;
+
+ return 0;
+}
+
+int arp_ioctl_set(struct arpreq *req)
+{
+ struct arpreq r;
+ struct arp_table *apt;
+
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (arpreq_check(&r) != 0) return -EPFNOSUPPORT;
+
+ apt = arp_lookup(*(unsigned long *)r.arp_pa.sa_data);
+ if (apt) {
+ apt->last_used = timer_seq;
+ memcpy(apt->hard, r.arp_ha.sa_data , 6);
+ } else {
+ if (!create_arp(*(unsigned long *)r.arp_pa.sa_data,
+ r.arp_ha.sa_data, 6)) {
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+int arp_ioctl_get(struct arpreq *req)
+{
+ struct arpreq r;
+ struct arp_table *apt;
+
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (arpreq_check(&r) != 0) return -EPFNOSUPPORT;
+ apt = arp_lookup(*(unsigned long *)r.arp_pa.sa_data);
+ if (apt) {
+ memcpy(r.arp_ha.sa_data, apt->hard, apt->hlen);
+ } else {
+ return -ENXIO;
+ }
+
+ /* Copy the information back */
+ memcpy_tofs(req, &r, sizeof(r));
+ return 0;
+}
+
+int arp_ioctl_del(struct arpreq *req)
+{
+ struct arpreq r;
+
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (arpreq_check(&r) != 0) return -EPFNOSUPPORT;
+
+ arp_destroy(*(unsigned long *)r.arp_pa.sa_data);
+
+ return 0;
+}
diff --git a/net/tcp/arp.h b/net/tcp/arp.h
index 844d23f..7d36f5a 100644
--- a/net/tcp/arp.h
+++ b/net/tcp/arp.h
@@ -19,8 +19,11 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: arp.h,v 0.8.4.3 1992/12/03 19:54:12 bir7 Exp $ */
+/* $Id: arp.h,v 0.8.4.4 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: arp.h,v $
+ * Revision 0.8.4.4 1993/01/23 18:00:11 bir7
+ * Added ioctls as supplied by R.P. Bellis <rpb@psy.ox.ac.uk>
+ *
* Revision 0.8.4.3 1992/12/03 19:54:12 bir7
* Added paranoid queue checking.
*
@@ -32,6 +35,9 @@
*
* Revision 0.8.3.2 1992/11/10 00:14:47 bir7
* Changed malloc to kmalloc and added $iId$ and $Log: arp.h,v $
+ * Revision 0.8.4.4 1993/01/23 18:00:11 bir7
+ * Added ioctls as supplied by R.P. Bellis <rpb@psy.ox.ac.uk>
+ *
* Revision 0.8.4.3 1992/12/03 19:54:12 bir7
* Added paranoid queue checking.
*
@@ -58,14 +64,14 @@ struct arp
struct arp_table
{
- struct arp_table *next;
- unsigned long last_used;
+ volatile struct arp_table *next;
+ volatile unsigned long last_used;
unsigned long ip;
unsigned char hlen;
unsigned char hard[MAX_ADDR_LEN];
};
-struct sk_buff *arp_q;
+volatile struct sk_buff *arp_q;
int arp_rcv(struct sk_buff *, struct device *, struct packet_type *);
void arp_snd (unsigned long, struct device *, unsigned long);
@@ -76,6 +82,10 @@ void arp_destroy (unsigned long);
void arp_add (unsigned long addr, unsigned char *haddr, struct device *dev);
void arp_queue (struct sk_buff *skb);
+int arp_ioctl_set(struct arpreq *req);
+int arp_ioctl_get(struct arpreq *req);
+int arp_ioctl_del(struct arpreq *req);
+
#define ARP_TABLE_SIZE 16
#define ARP_IP_PROT ETHERTYPE_IP
#define ARP_REQUEST 1
diff --git a/net/tcp/dev.c b/net/tcp/dev.c
index ee3388f..438cfd6 100644
--- a/net/tcp/dev.c
+++ b/net/tcp/dev.c
@@ -19,8 +19,17 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: dev.c,v 0.8.4.10 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: dev.c,v 0.8.4.13 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: dev.c,v $
+ * Revision 0.8.4.13 1993/01/23 18:00:11 bir7
+ * Fixed problems from merging.
+ *
+ * Revision 0.8.4.12 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
+ * Revision 0.8.4.11 1993/01/22 22:58:08 bir7
+ * Changed so transmitting takes place in bottom half of interrupt routine.
+ *
* Revision 0.8.4.10 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -157,6 +166,9 @@ void
dev_queue_xmit (struct sk_buff *skb, struct device *dev, int pri)
{
struct sk_buff *skb2;
+ int where=0; /* used to say if the packet should go at the
+ front or the back of the queue. */
+
PRINTK (("dev_queue_xmit (skb=%X, dev=%X, pri = %d)\n", skb, dev, pri));
if (dev == NULL)
@@ -173,7 +185,13 @@ dev_queue_xmit (struct sk_buff *skb, struct device *dev, int pri)
return;
}
- if (pri < 0 || pri >= DEV_NUMBUFFS)
+ if (pri < 0)
+ {
+ pri = -pri-1;
+ where = 1;
+ }
+
+ if ( pri >= DEV_NUMBUFFS)
{
printk ("bad priority in dev_queue_xmit.\n");
pri = 1;
@@ -196,11 +214,22 @@ dev_queue_xmit (struct sk_buff *skb, struct device *dev, int pri)
}
else
{
- skb2=dev->buffs[pri];
- skb->next = skb2;
- skb->prev = skb2->prev;
- skb->next->prev = skb;
- skb->prev->next = skb;
+ if (where)
+ {
+ skb->next = (struct sk_buff *)dev->buffs[pri];
+ skb->prev = (struct sk_buff *)dev->buffs[pri]->prev;
+ skb->prev->next = skb;
+ skb->next->prev = skb;
+ dev->buffs[pri] = skb;
+ }
+ else
+ {
+ skb2= (struct sk_buff *)dev->buffs[pri];
+ skb->next = skb2;
+ skb->prev = skb2->prev;
+ skb->next->prev = skb;
+ skb->prev->next = skb;
+ }
}
skb->magic = DEV_QUEUE_MAGIC;
sti();
@@ -227,7 +256,7 @@ int
dev_rint(unsigned char *buff, long len, int flags,
struct device * dev)
{
- volatile struct sk_buff *skb=NULL;
+ struct sk_buff *skb=NULL;
unsigned char *to;
int amount;
@@ -272,16 +301,16 @@ dev_rint(unsigned char *buff, long len, int flags,
cli();
if (backlog == NULL)
{
- skb->prev = (struct sk_buff *)skb;
- skb->next = (struct sk_buff *)skb;
+ skb->prev = skb;
+ skb->next = skb;
backlog = skb;
}
else
{
- skb->prev = backlog->prev;
+ skb->prev = (struct sk_buff *)backlog->prev;
skb->next = (struct sk_buff *)backlog;
- skb->next->prev = (struct sk_buff *)skb;
- skb->prev->next = (struct sk_buff *)skb;
+ skb->next->prev = skb;
+ skb->prev->next = skb;
}
sti();
@@ -292,9 +321,23 @@ dev_rint(unsigned char *buff, long len, int flags,
}
void
+dev_transmit(void)
+{
+ struct device *dev;
+
+ for (dev = dev_base; dev != NULL; dev=dev->next)
+ {
+ if (!dev->tbusy)
+ {
+ dev_tint (dev);
+ }
+ }
+}
+
+void
inet_bh(void *tmp)
{
- volatile struct sk_buff *skb;
+ struct sk_buff *skb;
struct packet_type *ptype;
unsigned short type;
unsigned char flag =0;
@@ -307,13 +350,15 @@ inet_bh(void *tmp)
return;
}
in_bh=1;
-
+ sti();
+
+ dev_transmit();
/* anything left to process? */
+ cli();
while (backlog != NULL)
{
- cli();
- skb= backlog;
+ skb= (struct sk_buff *)backlog;
if (skb->next == skb)
{
backlog = NULL;
@@ -345,7 +390,7 @@ inet_bh(void *tmp)
{
skb2 = kmalloc (skb->mem_len, GFP_ATOMIC);
if (skb2 == NULL) continue;
- memcpy (skb2, skb, skb->mem_len);
+ memcpy (skb2, (const void *) skb, skb->mem_len);
skb2->mem_addr = skb2;
skb2->lock = 0;
skb2->h.raw = (void *)((unsigned long)skb2
@@ -368,6 +413,8 @@ inet_bh(void *tmp)
PRINTK (("discarding packet type = %X\n", type));
kfree_skb ((struct sk_buff *)skb, FREE_READ);
}
+ dev_transmit();
+ cli();
}
in_bh = 0;
sti();
@@ -379,18 +426,19 @@ inet_bh(void *tmp)
length of zero is interrpreted to mean the transmit buffers
are empty, and the transmitter should be shut down. */
-unsigned long
-dev_tint(unsigned char *buff, struct device *dev)
+/* now the packet is passed on via the other call. */
+
+void
+dev_tint( struct device *dev)
{
int i;
- int tmp;
struct sk_buff *skb;
for (i=0; i < DEV_NUMBUFFS; i++)
{
while (dev->buffs[i]!=NULL)
{
cli();
- skb=dev->buffs[i];
+ skb=(struct sk_buff *)dev->buffs[i];
if (skb->magic != DEV_QUEUE_MAGIC)
{
printk ("dev.c skb with bad magic-%X: squashing queue\n",
@@ -430,50 +478,9 @@ dev_tint(unsigned char *buff, struct device *dev)
}
skb->next = NULL;
skb->prev = NULL;
-
- if (!skb->arp)
- {
- if (dev->rebuild_header (skb+1, dev))
- {
- skb->dev = dev;
- sti();
- arp_queue (skb);
- continue;
- }
- }
-
- tmp = skb->len;
- if (tmp <= dev->mtu)
- {
- if (dev->send_packet != NULL)
- {
- dev->send_packet(skb, dev);
- }
- if (buff != NULL)
- memcpy (buff, skb + 1, tmp);
-
- PRINTK ((">>\n"));
- print_eth ((struct enet_header *)(skb+1));
- }
- else
- {
- printk ("dev.c:**** bug len bigger than mtu, "
- "squashing queue. \n");
- cli();
- dev->buffs[i] = NULL;
- continue;
-
- }
sti();
- if (skb->free)
- {
- kfree_skb(skb, FREE_WRITE);
- }
-
- if (tmp != 0)
- return (tmp);
+ /* this will send it through the process again. */
+ dev->queue_xmit (skb, dev, -i-1);
}
}
- PRINTK (("dev_tint returning 0 \n"));
- return (0);
}
diff --git a/net/tcp/dev.h b/net/tcp/dev.h
index 2e9d188..f590fc9 100644
--- a/net/tcp/dev.h
+++ b/net/tcp/dev.h
@@ -19,8 +19,14 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: dev.h,v 0.8.4.5 1992/12/08 20:49:15 bir7 Exp $ */
+/* $Id: dev.h,v 0.8.4.7 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: dev.h,v $
+ * Revision 0.8.4.7 1993/01/23 18:00:11 bir7
+ * Fixed problems from merging.
+ *
+ * Revision 0.8.4.6 1993/01/22 22:58:08 bir7
+ * Changed so transmitting takes place in bottom half of interrupt routine.
+ *
* Revision 0.8.4.5 1992/12/08 20:49:15 bir7
* Edited ctrl-h's out of log messages.
*
@@ -58,15 +64,15 @@ struct device
unsigned long mem_start;
unsigned short base_addr;
unsigned char irq;
- unsigned char start:1,
- tbusy:1,
- loopback:1,
- interrupt:1,
- up:1;
+ volatile unsigned char start:1,
+ tbusy:1,
+ loopback:1,
+ interrupt:1,
+ up:1;
struct device *next;
int (*init)(struct device *dev);
unsigned long trans_start;
- struct sk_buff *buffs[DEV_NUMBUFFS];
+ volatile struct sk_buff * volatile buffs[DEV_NUMBUFFS];
struct sk_buff *backlog; /* no longer used. */
int (*open)(struct device *dev);
int (*stop)(struct device *dev);
@@ -79,7 +85,8 @@ struct device
void (*queue_xmit)(struct sk_buff *skb, struct device *dev, int pri);
int (*rebuild_header)(void *eth, struct device *dev);
unsigned short (*type_trans) (struct sk_buff *skb, struct device *dev);
- void (*send_packet)(struct sk_buff *skb, struct device *dev);
+ void (*send_packet)(struct sk_buff *skb, struct device *dev); /* no longer
+ used */
void *private;
unsigned short type;
@@ -110,7 +117,7 @@ struct packet_type
extern struct packet_type *ptype_base;
void dev_queue_xmit (struct sk_buff *skb, struct device *dev, int pri);
int dev_rint (unsigned char *buff, long len, int flags, struct device *dev);
-unsigned long dev_tint (unsigned char *buff, struct device *dev);
+void dev_tint ( struct device *dev);
void dev_add_pack (struct packet_type *pt);
void dev_remove_pack (struct packet_type *pt);
struct device *get_dev (char *name);
diff --git a/net/tcp/eth.c b/net/tcp/eth.c
index 5f8eb30..a277d5d 100644
--- a/net/tcp/eth.c
+++ b/net/tcp/eth.c
@@ -19,8 +19,11 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: eth.c,v 0.8.4.3 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: eth.c,v 0.8.4.4 1993/01/22 23:21:38 bir7 Exp $ */
/* $Log: eth.c,v $
+ * Revision 0.8.4.4 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
* Revision 0.8.4.3 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
diff --git a/net/tcp/icmp.c b/net/tcp/icmp.c
index 077635e..0b3c515 100644
--- a/net/tcp/icmp.c
+++ b/net/tcp/icmp.c
@@ -23,8 +23,14 @@
The author of this file may be reached at rth@sparta.com or Sparta, Inc.
7926 Jones Branch Dr. Suite 900, McLean Va 22102.
*/
-/* $Id: icmp.c,v 0.8.4.7 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: icmp.c,v $
+ * Revision 0.8.4.9 1993/01/23 18:00:11 bir7
+ * added volatile keyword to many variables.
+ *
+ * Revision 0.8.4.8 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
* Revision 0.8.4.7 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -227,10 +233,11 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
hash = iph->protocol & (MAX_IP_PROTOS -1 );
/* this can change while we are doing it. */
- for (ipprot = ip_protos[hash]; ipprot != NULL; )
+ for (ipprot = (struct ip_protocol *)ip_protos[hash];
+ ipprot != NULL; )
{
struct ip_protocol *nextip;
- nextip = ipprot->next;
+ nextip = (struct ip_protocol *)ipprot->next;
/* pass it off to everyone who wants it. */
if (iph->protocol == ipprot->protocol && ipprot->err_handler)
ipprot->err_handler (err, (unsigned char *)(icmph+1),
diff --git a/net/tcp/ip.c b/net/tcp/ip.c
index 496d392..e83b865 100644
--- a/net/tcp/ip.c
+++ b/net/tcp/ip.c
@@ -19,8 +19,14 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: ip.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: ip.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: ip.c,v $
+ * Revision 0.8.4.10 1993/01/23 18:00:11 bir7
+ * added volatile keyword to many variables.
+ *
+ * Revision 0.8.4.9 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
* Revision 0.8.4.8 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -67,17 +73,34 @@
unsigned long ip_addr[MAX_IP_ADDRES]={0,0,0};
+#ifdef PRINTK
+#undef PRINTK
+#endif
+
#undef IP_DEBUG
#ifdef IP_DEBUG
-#define PRINTK(X) printk X
+#define PRINTK(x) printk x
#else
-#define PRINTK(X) /**/
+#define PRINTK(x) /**/
#endif
static struct rtable *rt_base=NULL; /* used to base all the routing data. */
-struct ip_protocol *ip_protos[MAX_IP_PROTOS] = { NULL, };
+volatile struct ip_protocol *ip_protos[MAX_IP_PROTOS] = { NULL, };
+int ip_ads = 0;
+
+static char *in_ntoa(unsigned long addr)
+{
+ static char buf[100];
+
+ sprintf(buf,"%d.%d.%d.%d",
+ (addr & 0xff),
+ ((addr >> 8) & 0xff),
+ ((addr >> 16) & 0xff),
+ ((addr >> 24) & 0xff));
+ return buf;
+}
#if 0
static struct ip_protocol *
@@ -108,7 +131,9 @@ add_ip_protocol (struct ip_protocol *prot)
ip_protos[hash] = prot;
prot->copy = 0;
/* set the copy bit if we need to. */
- for (p2 = prot->next; p2 != NULL; p2=p2->next)
+ for (p2 = (struct ip_protocol *)prot->next;
+ p2 != NULL;
+ p2= (struct ip_protocol *)p2->next)
{
if (p2->protocol == prot->protocol)
{
@@ -130,11 +155,13 @@ delete_ip_protocol (struct ip_protocol *prot)
hash = prot->protocol & (MAX_IP_PROTOS -1);
if (prot == ip_protos[hash])
{
- ip_protos[hash]=ip_protos[hash]->next;
+ ip_protos[hash]=(struct ip_protocol *)ip_protos[hash]->next;
return (0);
}
- for (p = ip_protos[hash]; p != NULL; p = p->next)
+ for (p = (struct ip_protocol *)ip_protos[hash];
+ p != NULL;
+ p = (struct ip_protocol *) p->next)
{
/* we have to worry if the protocol being deleted is the
last one on the list, then we may need to reset someones
@@ -208,8 +235,12 @@ loose_route(struct ip_header *iph, struct options *opt)
void
print_rt(struct rtable *rt)
{
- PRINTK (("net = %08X router = %08X\n",rt->net, rt->router));
- PRINTK (("dev = %X, next = %X\n",rt->dev, rt->next));
+#ifdef IP_DEBUG
+ printk("RT: %06lx NXT=%06lx DEV=%06lx(%s) NET=%s ",
+ (long) rt, (long) rt->next, (long) rt->dev,
+ rt->dev->name, in_ntoa(rt->net));
+ printk("ROUTER=%s\n", in_ntoa(rt->router));
+#endif
}
void
@@ -239,13 +270,45 @@ ip_route(struct options *opt, unsigned long daddr, unsigned long *raddr)
return (NULL);
};
+/* Remove all routing table entries for a device. */
+void
+del_devroute (struct device *dev)
+{
+ struct rtable *r, *x, *p;
+
+ if ((r = rt_base) == NULL) return; /* nothing to remove! */
+ PRINTK (("IFACE DOWN: clearing routing table for dev 0x%08lx (%s)\n",
+ (long) dev, dev->name));
+ p = NULL;
+ while(r != NULL)
+ {
+ PRINTK ((">> R=%06lx N=%06lx P=%06lx DEV=%06lx(%s) A=%s\n",
+ (long) r, (long) r->next, (long) p, (long) r->dev,
+ r->dev->name, in_ntoa(r->net)));
+ if (r->dev == dev)
+ {
+ PRINTK ((">>> MATCH: removing rt=%08lx\n", (long) r));
+ if (p == NULL) rt_base = r->next;
+ else p->next = r->next;
+ x = r->next;
+ kfree_s(r, sizeof(*r));
+ r = x;
+ }
+ else
+ {
+ p = r;
+ r = r->next;
+ }
+ }
+}
+
void
add_route (struct rtable *rt)
{
int mask;
struct rtable *r;
struct rtable *r1;
- PRINTK (("add_route (rt=%X):\n",rt));
+
print_rt(rt);
if (rt_base == NULL)
@@ -316,16 +379,23 @@ ip_set_dev (struct ip_config *u_ipc)
struct rtable *rt;
struct device *dev;
struct ip_config ipc;
- static int ip_ads = 0;
- if (ip_ads >= MAX_IP_ADDRES) return (-EINVAL);
+
/* verify_area (u_ipc, sizeof (ipc));*/
memcpy_fromfs(&ipc, u_ipc, sizeof (ipc));
ipc.name[MAX_IP_NAME-1] = 0;
dev = get_dev (ipc.name);
+#if 1 /* making this a 0 will let you remove an ip address from
+ the list, which is useful under SLIP. But it may not
+ be compatible with older configs. */
+ ipc.destroy = 0;
+#endif
+
if (dev == NULL) return (-EINVAL);
+ if (ip_ads >= MAX_IP_ADDRES && !ipc.destroy && ipc.paddr != -1)
+ return (-EINVAL);
/* see if we need to add a broadcast address. */
if (ipc.net != -1)
@@ -363,11 +433,39 @@ ip_set_dev (struct ip_config *u_ipc)
add_route (rt);
}
+ if (ipc.destroy)
+ {
+ int i;
+ for (i = 0; i <MAX_IP_ADDRES; i++)
+ {
+ if (ip_addr[i] == ipc.paddr)
+ {
+ break;
+ }
+ }
+ if (i != MAX_IP_ADDRES)
+ {
+ PRINTK (("ip.c: Destroying Identity %8X, entry %d\n", ipc.paddr, i));
+ i++;
+ ip_ads--;
+ while (i < MAX_IP_ADDRES)
+ {
+ ip_addr[i-1] = ip_addr[i];
+ i++;
+ }
+ ip_addr[MAX_IP_ADDRES-1] = 0;
+ }
+ }
- if (!my_ip_addr (ipc.paddr))
+ /* FIX per FvK 92/11/15 */
+ /* When "downing" an interface, this must be done with paddr = -1L. */
+ if (ipc.paddr != -1L && !ipc.destroy)
{
- PRINTK (("new identity: %08X\n", ipc.paddr));
- ip_addr[ip_ads++] = ipc.paddr;
+ if (!my_ip_addr (ipc.paddr))
+ {
+ PRINTK (("new identity: %08X\n", ipc.paddr));
+ ip_addr[ip_ads++] = ipc.paddr;
+ }
}
dev->up = ipc.up;
@@ -380,6 +478,7 @@ ip_set_dev (struct ip_config *u_ipc)
{
if (dev->stop)
dev->stop(dev);
+ del_devroute(dev); /* clear routing table for dev */
}
return (0);
@@ -732,7 +831,11 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/* for now we will only deal with packets meant for us. */
if (!my_ip_addr(iph->daddr))
{
- PRINTK (("packet meant for someone else.\n"));
+ PRINTK(("\nIP: *** datagram routing not yet implemented ***\n"));
+ PRINTK((" SRC = %s ", in_ntoa(iph->saddr)));
+ PRINTK((" DST = %s (ignored)\n", in_ntoa(iph->daddr)));
+ icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
+
skb->sk = NULL;
kfree_skb(skb, 0);
return (0);
@@ -740,8 +843,11 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/* deal with fragments. or don't for now.*/
if ((iph->frag_off & 32) || (net16(iph->frag_off)&0x1fff))
- {
- printk ("packet fragmented. \n");
+ { /* FIXME: this ^^^ used to be 64, as per bugfix */
+ printk("\nIP: *** datagram fragmentation not yet implemented ***\n");
+ printk(" SRC = %s ", in_ntoa(iph->saddr));
+ printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr));
+ icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
skb->sk = NULL;
kfree_skb(skb, 0);
return(0);
@@ -750,7 +856,9 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
skb->h.raw += iph->ihl*4;
hash = iph->protocol & (MAX_IP_PROTOS -1);
- for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next)
+ for (ipprot = (struct ip_protocol *)ip_protos[hash];
+ ipprot != NULL;
+ ipprot=(struct ip_protocol *)ipprot->next)
{
struct sk_buff *skb2;
if (ipprot->protocol != iph->protocol) continue;
@@ -891,7 +999,7 @@ ip_retransmit (volatile struct sock *sk, int all)
if (dev->rebuild_header ((struct enet_header *)(skb+1),dev))
{
if (!all) break;
- skb=skb->link3;
+ skb=(struct sk_buff *)skb->link3;
continue;
}
}
@@ -911,7 +1019,7 @@ ip_retransmit (volatile struct sock *sk, int all)
/* this should cut it off before we send too
many packets. */
if (sk->retransmits > sk->cong_window) break;
- skb=skb->link3;
+ skb=(struct sk_buff *)skb->link3;
}
/* double the rtt time every time we retransmit.
This will cause exponential back off on how
@@ -936,59 +1044,3 @@ print_iph (struct ip_header *ip)
PRINTK ((" frag_off=%d\n", ip->frag_off));
PRINTK ((" saddr = %X, daddr = %X\n",ip->saddr, ip->daddr));
}
-
-#if 0
-int
-ip_handoff (volatile struct sock *sk)
-{
- struct ip_protocol *p;
- struct sk_buff *skb;
- p = get_protocol (sk->protocol);
-
- if (p == NULL)
- {
- /* this can never happen. */
- printk ("sock_ioctl: protocol not found. \n");
- /* what else can I do, I suppose I could send a sigkill. */
- return (-EIO);
- }
-
- while (p->handler != sk->prot->rcv)
- {
- p=p->next;
- if (p == NULL)
- {
- /* this can never happen. */
- printk ("sock_ioctl: protocol not found. \n");
- /* what else can I do, I suppose I could send a sigkill. */
- return (-EIO);
- }
- }
- p = p-> next;
- sk->inuse = 1;
-
- /* now we have to remove the top sock buff. If there are none, then
- we return. */
- if (sk->rqueue == NULL) return (0);
- skb = sk->rqueue;
- if (skb->next == skb)
- {
- sk->rqueue = NULL;
- }
- else
- {
- sk->rqueue = skb->next;
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
- }
- if (p != NULL)
- {
- p->handler ((unsigned char *)(skb+1), skb->dev, NULL, skb->saddr,
- skb->len, skb->daddr, p->protocol, 0);
- }
- kfree_skb (skb, FREE_READ);
- release_sock (sk);
- return (0);
-}
-
-#endif
diff --git a/net/tcp/ip.h b/net/tcp/ip.h
index 3776a19..4d543f9 100644
--- a/net/tcp/ip.h
+++ b/net/tcp/ip.h
@@ -19,13 +19,19 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: ip.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ */
+/* $Id: ip.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: ip.h,v $
+ * Revision 0.8.4.2 1993/01/23 18:00:11 bir7
+ * added volatile keyword to many variables.
+ *
* Revision 0.8.4.1 1992/11/10 00:17:18 bir7
* version change only.
*
* Revision 0.8.3.2 1992/11/10 00:14:47 bir7
* Changed malloc to kmalloc and added $iId$ and $Log: ip.h,v $
+ * Revision 0.8.4.2 1993/01/23 18:00:11 bir7
+ * added volatile keyword to many variables.
+ *
* Revision 0.8.4.1 1992/11/10 00:17:18 bir7
* version change only.
*.
@@ -135,18 +141,19 @@ struct ip_protocol
int redo, struct ip_protocol *protocol);
void (*err_handler) (int err, unsigned char *buff, unsigned long daddr,
unsigned long saddr, struct ip_protocol *ipprot);
- struct ip_protocol *next;
+ volatile struct ip_protocol *next;
unsigned char protocol;
unsigned char copy:1;
void *data;
};
extern struct ip_protocol *ip_protocol_base;
-extern struct ip_protocol *ip_protos[MAX_IP_PROTOS];
+extern volatile struct ip_protocol *ip_protos[MAX_IP_PROTOS];
#define MAX_IP_ADDRES 5
extern unsigned long ip_addr[MAX_IP_ADDRES];
-#define MY_IP_ADDR ip_addr[0];
+extern int ip_ads;
+#define MY_IP_ADDR ip_addr[0]
int my_ip_addr(unsigned long);
#include "eth.h"
diff --git a/net/tcp/loopback.c b/net/tcp/loopback.c
index 4a355e2..afe8889 100644
--- a/net/tcp/loopback.c
+++ b/net/tcp/loopback.c
@@ -19,8 +19,17 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: loopback.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: loopback.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: loopback.c,v $
+ * Revision 0.8.4.8 1993/01/23 18:00:11 bir7
+ * Fixed problems introduced by merge.
+ *
+ * Revision 0.8.4.7 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
+ * Revision 0.8.4.6 1993/01/22 22:58:08 bir7
+ * Changed so transmitting takes place in bottom half of interrupt routine.
+ *
* Revision 0.8.4.5 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -76,56 +85,29 @@
static int
loopback_xmit(struct sk_buff *skb, struct device *dev)
{
- static int inuse=0;
- struct enet_header *eth;
- int i;
int done;
- static unsigned char buff[2048];
- unsigned char *tmp;
-
PRINTK (("loopback_xmit (dev = %X)\n", dev));
cli();
- if (inuse)
+ if (dev->tbusy != 0)
{
sti();
return (1);
}
- inuse = 1;
+ dev->tbusy = 1;
sti();
- done = -1;
- while (done == -1)
- done = dev_rint ((unsigned char *)(skb+1), skb->len, 0, dev);
+ done = dev_rint ((unsigned char *)(skb+1), skb->len, 0, dev);
if (skb->free)
kfree_skb (skb, FREE_WRITE);
- tmp = NULL;
- i = 0;
while (done != 1)
{
- if (done != -1 && (i = dev_tint (buff,dev)) != 0)
- {
- /* print out the buffer. */
- PRINTK (("loopback xmit: \n"));
- eth = (struct enet_header *)buff;
- print_eth (eth);
- tmp = buff;
- done = dev_rint (buff, i, 0, dev);
- if (done != -1)
- {
- tmp = NULL;
- i = 0;
- }
- }
- else
- {
- if (i == 0) tmp = NULL;
- done = dev_rint (tmp, i, 0, dev);
- }
-
+ done = dev_rint (NULL, 0, 0, dev);
}
- inuse = 0;
+
+ dev->tbusy = 0;
+
return (0);
}
@@ -135,6 +117,7 @@ loopback_init(struct device *dev)
printk ("Loopback device init\n");
/* initialize the rest of the device structure. */
dev->mtu = 2000; /* mtu */
+ dev->tbusy = 0;
dev->hard_start_xmit = loopback_xmit;
dev->open = NULL;
dev->hard_header = eth_hard_header;
diff --git a/net/tcp/packet.c b/net/tcp/packet.c
index 3513390..6004480 100644
--- a/net/tcp/packet.c
+++ b/net/tcp/packet.c
@@ -19,8 +19,14 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: packet.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: packet.c,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ */
/* $Log: packet.c,v $
+ * Revision 0.8.4.7 1993/01/26 22:04:00 bir7
+ * Added support for proc fs.
+ *
+ * Revision 0.8.4.6 1993/01/23 18:00:11 bir7
+ * Added volatile keyword
+ *
* Revision 0.8.4.5 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -147,18 +153,17 @@ packet_sendto (volatile struct sock *sk, unsigned char *from, int len,
else
return (-EINVAL);
- skb = sk->prot->wmalloc (sk, len+sizeof (*skb) + sk->prot->max_header, 0,
- GFP_KERNEL);
+ skb = sk->prot->wmalloc (sk, len+sizeof (*skb), 0, GFP_KERNEL);
+
/* this shouldn't happen, but it could. */
if (skb == NULL)
{
PRINTK ("packet_sendto: write buffer full?\n");
- print_sk (sk);
return (-EAGAIN);
}
skb->lock = 0;
skb->mem_addr = skb;
- skb->mem_len = len + sizeof (*skb) +sk->prot->max_header;
+ skb->mem_len = len + sizeof (*skb);
skb->sk = sk;
skb->free = 1;
saddr.sa_data[13] = 0;
@@ -193,6 +198,7 @@ packet_close (volatile struct sock *sk, int timeout)
sk->state = TCP_CLOSE;
dev_remove_pack ((struct packet_type *)sk->pair);
kfree_s ((void *)sk->pair, sizeof (struct packet_type));
+ sk->pair = NULL;
release_sock (sk);
}
@@ -256,6 +262,7 @@ packet_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
return (-ERESTARTSYS);
}
}
+ sk->inuse = 1;
sti();
}
skb = sk->rqueue;
@@ -268,7 +275,7 @@ packet_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
}
else
{
- sk->rqueue = sk->rqueue ->next;
+ sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
}
@@ -337,5 +344,6 @@ struct proto packet_prot =
NULL,
128,
0,
- {NULL,}
+ {NULL,},
+ "PACKET"
};
diff --git a/net/tcp/raw.c b/net/tcp/raw.c
index b312f89..56257b5 100644
--- a/net/tcp/raw.c
+++ b/net/tcp/raw.c
@@ -19,8 +19,17 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: raw.c,v 0.8.4.9 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: raw.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ */
/* $Log: raw.c,v $
+ * Revision 0.8.4.12 1993/01/26 22:04:00 bir7
+ * Added support for proc fs.
+ *
+ * Revision 0.8.4.11 1993/01/23 18:00:11 bir7
+ * Added volatile keyword
+ *
+ * Revision 0.8.4.10 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
* Revision 0.8.4.9 1992/12/12 19:25:04 bir7
* Cleaned up Log messages.
*
@@ -264,7 +273,6 @@ raw_sendto (volatile struct sock *sk, unsigned char *from, int len,
{
int tmp;
PRINTK (("raw_sendto: write buffer full?\n"));
- print_sk (sk);
if (noblock) return (-EAGAIN);
tmp = sk->wmem_alloc;
release_sock (sk);
@@ -408,7 +416,7 @@ raw_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
}
else
{
- sk->rqueue = sk->rqueue ->next;
+ sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
}
@@ -476,5 +484,6 @@ struct proto raw_prot =
NULL,
128,
0,
- {NULL,}
+ {NULL,},
+ "RAW"
};
diff --git a/net/tcp/sock.c b/net/tcp/sock.c
index 8a19eee..fd0f329 100644
--- a/net/tcp/sock.c
+++ b/net/tcp/sock.c
@@ -19,8 +19,20 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: sock.c,v 0.8.4.12 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: sock.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $ */
/* $Log: sock.c,v $
+ * Revision 0.8.4.16 1993/01/26 22:04:00 bir7
+ * Added support for proc fs.
+ *
+ * Revision 0.8.4.15 1993/01/23 18:00:11 bir7
+ * Added volatile keyword
+ *
+ * Revision 0.8.4.14 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
+ * Revision 0.8.4.13 1993/01/22 22:58:08 bir7
+ * *** empty log message ***
+ *
* Revision 0.8.4.12 1992/12/12 19:25:04 bir7
* Made memory leak checking more leanent.
*
@@ -70,6 +82,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
+#include <linux/config.h>
#include <linux/sock_ioctl.h>
#include "../kern_sock.h"
#include "timer.h"
@@ -152,7 +165,6 @@ static int ip_proto_getsockopt (struct socket *sock, int level, int optname,
static int ip_proto_fcntl (struct socket *sock, unsigned int cmd,
unsigned long arg);
-
struct proto_ops inet_proto_ops =
{
ip_proto_init,
@@ -176,49 +188,50 @@ struct proto_ops inet_proto_ops =
ip_proto_shutdown,
ip_proto_setsockopt,
ip_proto_getsockopt,
- ip_proto_fcntl
+ ip_proto_fcntl,
};
void
print_sk (volatile struct sock *sk)
{
if (!sk) {
- PRINTK ((" print_sk(NULL)\n"));
+ printk (" print_sk(NULL)\n");
return;
}
- PRINTK ((" wmem_alloc = %d\n", sk->wmem_alloc));
- PRINTK ((" rmem_alloc = %d\n", sk->rmem_alloc));
- PRINTK ((" send_head = %X\n", sk->send_head));
- PRINTK ((" state = %d\n",sk->state));
- PRINTK ((" wback = %X, rqueue = %X\n", sk->wback, sk->rqueue));
- PRINTK ((" wfront = %X\n", sk->wfront));
- PRINTK ((" daddr = %X, saddr = %X\n", sk->daddr,sk->saddr));
- PRINTK ((" num = %d", sk->num));
- PRINTK ((" next = %X\n", sk->next));
- PRINTK ((" send_seq = %d, acked_seq = %d, copied_seq = %d\n",
- sk->send_seq, sk->acked_seq, sk->copied_seq));
- PRINTK ((" rcv_ack_seq = %d, window_seq = %d, fin_seq = %d\n",
- sk->rcv_ack_seq, sk->window_seq, sk->fin_seq));
- PRINTK ((" prot = %X\n", sk->prot));
- PRINTK ((" pair = %X, back_log = %X\n", sk->pair,sk->back_log));
- PRINTK ((" inuse = %d , blog = %d\n", sk->inuse, sk->blog));
- PRINTK ((" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks));
- PRINTK ((" retransmits = %d, timeout = %d\n", sk->retransmits, sk->timeout));
- PRINTK ((" cong_window = %d, packets_out = %d\n", sk->cong_window,
- sk->packets_out));
+ printk (" wmem_alloc = %d\n", sk->wmem_alloc);
+ printk (" rmem_alloc = %d\n", sk->rmem_alloc);
+ printk (" send_head = %X\n", sk->send_head);
+ printk (" state = %d\n",sk->state);
+ printk (" wback = %X, rqueue = %X\n", sk->wback, sk->rqueue);
+ printk (" wfront = %X\n", sk->wfront);
+ printk (" daddr = %X, saddr = %X\n", sk->daddr,sk->saddr);
+ printk (" num = %d", sk->num);
+ printk (" next = %X\n", sk->next);
+ printk (" send_seq = %d, acked_seq = %d, copied_seq = %d\n",
+ sk->send_seq, sk->acked_seq, sk->copied_seq);
+ printk (" rcv_ack_seq = %d, window_seq = %d, fin_seq = %d\n",
+ sk->rcv_ack_seq, sk->window_seq, sk->fin_seq);
+ printk (" prot = %X\n", sk->prot);
+ printk (" pair = %X, back_log = %X\n", sk->pair,sk->back_log);
+ printk (" inuse = %d , blog = %d\n", sk->inuse, sk->blog);
+ printk (" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks);
+ printk (" retransmits = %d, timeout = %d\n", sk->retransmits, sk->timeout);
+ printk (" cong_window = %d, packets_out = %d\n", sk->cong_window,
+ sk->packets_out);
+ printk (" urg = %d shutdown=%d\n", sk->urg, sk->shutdown);
}
void
print_skb(struct sk_buff *skb)
{
if (!skb) {
- PRINTK ((" print_skb(NULL)\n"));
+ printk (" print_skb(NULL)\n");
return;
}
- PRINTK ((" prev = %X, next = %X\n", skb->prev, skb->next));
- PRINTK ((" sk = %X link3 = %X\n", skb->sk, skb->link3));
- PRINTK ((" mem_addr = %X, mem_len = %d\n", skb->mem_addr, skb->mem_len));
- PRINTK ((" used = %d free = %d\n", skb->used,skb->free));
+ printk (" prev = %X, next = %X\n", skb->prev, skb->next);
+ printk (" sk = %X link3 = %X\n", skb->sk, skb->link3);
+ printk (" mem_addr = %X, mem_len = %d\n", skb->mem_addr, skb->mem_len);
+ printk (" used = %d free = %d\n", skb->used,skb->free);
}
/* just used to reference some pointers to keep gcc from over optimizing
@@ -472,7 +485,7 @@ destroy_sock(volatile struct sock *sk)
for (skb = sk->wfront; skb != NULL; )
{
struct sk_buff *skb2;
- skb2=skb->next;
+ skb2=(struct sk_buff *)skb->next;
if (skb->magic != TCP_WRITE_QUEUE_MAGIC)
{
printk ("sock.c:destroy_sock write queue with bad magic (%X)\n",
@@ -491,7 +504,7 @@ destroy_sock(volatile struct sock *sk)
skb = sk->rqueue;
do {
struct sk_buff *skb2;
- skb2=skb->next;
+ skb2=(struct sk_buff *)skb->next;
/* this will take care of closing sockets that were
listening and didn't accept everything. */
@@ -521,7 +534,7 @@ destroy_sock(volatile struct sock *sk)
if (skb->next != NULL)
{
- extern struct sk_buff *arp_q;
+ extern volatile struct sk_buff *arp_q;
int i;
if (skb->next != skb)
{
@@ -597,7 +610,7 @@ destroy_sock(volatile struct sock *sk)
}
skb->dev = NULL;
sti();
- skb2=skb->link3;
+ skb2=(struct sk_buff *)skb->link3;
kfree_skb(skb, FREE_WRITE);
skb=skb2;
}
@@ -611,10 +624,10 @@ destroy_sock(volatile struct sock *sk)
/* this should never happen. */
printk ("cleaning back_log. \n");
cli();
- skb = sk->back_log;
+ skb = (struct sk_buff *)sk->back_log;
do {
struct sk_buff *skb2;
- skb2=skb->next;
+ skb2=(struct sk_buff *)skb->next;
kfree_skb(skb, FREE_READ);
skb=skb2;
} while (skb != sk->back_log);
@@ -642,7 +655,6 @@ destroy_sock(volatile struct sock *sk)
/* this should never happen. */
/* actually it can if an ack has just been sent. */
PRINTK (("possible memory leak in socket = %X\n", sk));
- print_sk (sk);
sk->destroy = 1;
sk->ack_backlog = 0;
sk->inuse = 0;
@@ -650,9 +662,7 @@ destroy_sock(volatile struct sock *sk)
sk->timeout = TIME_DESTROY;
reset_timer ((struct timer *)&sk->time_wait);
}
-
PRINTK (("leaving destroy_sock\n"));
-
}
@@ -660,6 +670,7 @@ static int
ip_proto_fcntl (struct socket *sock, unsigned int cmd, unsigned long arg)
{
volatile struct sock *sk;
+
sk=sock->data;
if (sk == NULL)
{
@@ -670,8 +681,19 @@ ip_proto_fcntl (struct socket *sock, unsigned int cmd, unsigned long arg)
switch (cmd)
{
case F_SETOWN:
- sk->proc = arg;
- return (0);
+
+ /* this is a little restrictive, but it's the only way to make
+ sure that you can't send a sigurg to another process. */
+ if (!suser() && current->pgrp != -arg && current->pid != arg)
+ return (-EPERM);
+
+ sk->proc = arg;
+ return (0);
+
+
+
+ sk->proc = arg;
+ return (0);
case F_GETOWN:
return (sk->proc);
@@ -869,7 +891,7 @@ static int ip_proto_init(void)
{
struct ip_protocol *tmp;
/* add all the protocols. */
- tmp = p->next;
+ tmp = (struct ip_protocol *) p->next;
add_ip_protocol (p);
p = tmp;
}
@@ -997,6 +1019,7 @@ ip_proto_create (struct socket *sock, int protocol)
sk->urginline = 0;
sk->intr = 0;
sk->linger = 0;
+ sk->rtt = 0;
sk->destroy = 0;
sk->reuse = 0;
sk->priority = 1;
@@ -1156,12 +1179,18 @@ ip_proto_bind (struct socket *sock, struct sockaddr *uaddr,
/* verify_area (uaddr, addr_len);*/
memcpy_fromfs (&addr, uaddr, min (sizeof (addr), addr_len));
+
+#if 0
if (addr.sin_family && addr.sin_family != AF_INET)
- return (-EINVAL); /* this needs to be changed. */
+ {
+ /* this is really a bug in BSD which we need to emulate because
+ ftp expects it. */
+ return (-EINVAL);
+ }
+#endif
snum = net16(addr.sin_port);
PRINTK (("bind sk =%X to port = %d\n", sk, snum));
- print_sk (sk);
sk = sock->data;
/* we can't just leave the socket bound wherever it is, it might be bound
@@ -1182,7 +1211,6 @@ ip_proto_bind (struct socket *sock, struct sockaddr *uaddr,
PRINTK (("sock_array[%d] = %X:\n", snum & (SOCK_ARRAY_SIZE -1),
sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]));
- print_sk (sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]);
/* make sure we are allowed to bind here. */
for (sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];
@@ -1245,11 +1273,8 @@ ip_proto_connect (struct socket *sock, struct sockaddr * uaddr,
if (sk->prot->connect == NULL)
return (-EOPNOTSUPP);
- if (sk->intr == 0)
- {
- err = sk->prot->connect (sk, (struct sockaddr_in *)uaddr, addr_len);
- if (err < 0) return (err);
- }
+ err = sk->prot->connect (sk, (struct sockaddr_in *)uaddr, addr_len);
+ if (err < 0) return (err);
sock->state = SS_CONNECTING;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
@@ -1263,14 +1288,12 @@ ip_proto_connect (struct socket *sock, struct sockaddr * uaddr,
if (current->signal & ~current->blocked)
{
sti();
- sk->intr = 1;
- sock->state = SS_UNCONNECTED;
return (-ERESTARTSYS);
}
}
sti();
sock->state = SS_CONNECTED;
- sk->intr = 0;
+
if (sk->state != TCP_ESTABLISHED && sk->err)
{
sock->state = SS_UNCONNECTED;
@@ -1298,6 +1321,7 @@ ip_proto_accept (struct socket *sock, struct socket *newsock, int flags)
/* we've been passed an extra socket. We need to free it up because
the tcp module creates it's own when it accepts one. */
+
if (newsock->data)
kfree_s (newsock->data, sizeof (struct sock));
@@ -1383,7 +1407,10 @@ ip_proto_getname(struct socket *sock, struct sockaddr *uaddr,
else
{
sin.sin_port = sk->dummy_th.source;
- sin.sin_addr.s_addr = sk->saddr;
+ if (sk->saddr == 0)
+ sin.sin_addr.s_addr = MY_IP_ADDR;
+ else
+ sin.sin_addr.s_addr = sk->saddr;
}
len = sizeof (sin);
verify_area (uaddr, len);
@@ -1625,6 +1652,19 @@ ip_proto_ioctl (struct socket *sock, unsigned int cmd,
return (-EPERM);
return (ip_set_dev((struct ip_config *)arg));
+ case SIOCSARP:
+ if (!suser())
+ return (-EPERM);
+ return (arp_ioctl_set((struct arpreq *)arg));
+
+ case SIOCGARP:
+ return (arp_ioctl_get((struct arpreq *)arg));
+
+ case SIOCDARP:
+ if (!suser())
+ return (-EPERM);
+ return (arp_ioctl_del((struct arpreq *)arg));
+
case FIOSETOWN:
case SIOCSPGRP:
{
@@ -1812,9 +1852,8 @@ void release_sock (volatile struct sock *sk)
{
struct sk_buff *skb;
sk->blog = 1;
- skb = sk->back_log;
+ skb = (struct sk_buff *)sk->back_log;
PRINTK (("release_sock: skb = %X:\n",skb));
- print_skb(skb);
if (skb->next != skb)
{
sk->back_log = skb->next;
diff --git a/net/tcp/sock.h b/net/tcp/sock.h
index 3d8716d..b077cef 100644
--- a/net/tcp/sock.h
+++ b/net/tcp/sock.h
@@ -19,8 +19,14 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: sock.h,v 0.8.4.5 1992/12/12 01:50:49 bir7 Exp $ */
+/* $Id: sock.h,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ */
/* $Log: sock.h,v $
+ * Revision 0.8.4.7 1993/01/26 22:04:00 bir7
+ * Added support for proc fs.
+ *
+ * Revision 0.8.4.6 1993/01/23 18:00:11 bir7
+ * Added volatile keyword
+ *
* Revision 0.8.4.5 1992/12/12 01:50:49 bir7
* Fixed support for half duplex connections.
*
@@ -51,15 +57,17 @@
struct sock
{
struct options *opt;
- unsigned long wmem_alloc;
- unsigned long rmem_alloc;
+ volatile unsigned long wmem_alloc;
+ volatile unsigned long rmem_alloc;
unsigned long send_seq;
unsigned long acked_seq;
unsigned long copied_seq;
unsigned long rcv_ack_seq;
unsigned long window_seq;
unsigned long fin_seq;
- unsigned long inuse:1, dead:1, urginline:1,
+ /* not all are volatile, but some are, so we might as
+ well say they all are. */
+ volatile unsigned long inuse:1, dead:1, urginline:1,
intr:1, blog:1, done:1, reuse:1, keepopen:1, linger:1,
delay_acks:1, timeout:3, destroy:1, ack_timed:1, no_check:1,
exp_growth:1;
@@ -68,7 +76,7 @@ struct sock
volatile struct sock *pair;
struct sk_buff *send_tail;
struct sk_buff *send_head;
- struct sk_buff *back_log;
+ volatile struct sk_buff * volatile back_log;
struct sk_buff *send_tmp;
long retransmits;
struct sk_buff *wback, *wfront, *rqueue;
@@ -81,20 +89,20 @@ struct sock
unsigned short bytes_rcv;
unsigned short mtu;
unsigned short num;
- unsigned short cong_window;
- unsigned short packets_out;
- unsigned short urg;
- unsigned short shutdown;
+ volatile unsigned short cong_window;
+ volatile unsigned short packets_out;
+ volatile unsigned short urg;
+ volatile unsigned short shutdown;
unsigned short mss;
- short rtt;
- short err;
+ volatile short rtt;
+ volatile short err;
unsigned char protocol;
- unsigned char state;
- unsigned char ack_backlog;
+ volatile unsigned char state;
+ volatile unsigned char ack_backlog;
unsigned char max_ack_backlog;
unsigned char priority;
struct tcp_header dummy_th; /* I may be able to get rid of this. */
- struct timer time_wait;
+ volatile struct timer time_wait;
};
struct proto
@@ -139,6 +147,7 @@ struct proto
unsigned short max_header;
unsigned long retransmits;
volatile struct sock *sock_array[SOCK_ARRAY_SIZE];
+ char name[80];
};
#define TIME_WRITE 1
@@ -154,11 +163,11 @@ struct proto
struct sk_buff
{
- struct sk_buff *next;
- struct sk_buff *prev;
- struct sk_buff *link3;
+ volatile struct sk_buff *next;
+ volatile struct sk_buff *prev;
+ volatile struct sk_buff *link3;
volatile struct sock *sk;
- unsigned long when; /* used to compute rtt's. */
+ volatile unsigned long when; /* used to compute rtt's. */
struct device *dev;
void *mem_addr;
union
@@ -176,7 +185,7 @@ struct sk_buff
unsigned long saddr;
unsigned long daddr;
int magic;
- unsigned long acked:1,used:1,free:1,arp:1, urg_used:1, lock:1;
+ volatile unsigned long acked:1,used:1,free:1,arp:1, urg_used:1, lock:1;
};
#define PROT_SOCK 1024
diff --git a/net/tcp/tcp.c b/net/tcp/tcp.c
index eb9c797..7307778 100644
--- a/net/tcp/tcp.c
+++ b/net/tcp/tcp.c
@@ -23,8 +23,20 @@
Tim MacKenzie (tym@dibbler.cs.moansh.edu.au)
*/
-/* $Id: tcp.c,v 0.8.4.12 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: tcp.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $ */
/* $Log: tcp.c,v $
+ * Revision 0.8.4.16 1993/01/26 22:04:00 bir7
+ * Added support for proc fs.
+ *
+ * Revision 0.8.4.15 1993/01/23 18:00:11 bir7
+ * added volatile keyword and fixed infinite loop in tcp_write.
+ *
+ * Revision 0.8.4.14 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
+ * Revision 0.8.4.13 1993/01/22 22:58:08 bir7
+ * Check in for merge with previous .99 pl 4.
+ *
* Revision 0.8.4.12 1992/12/12 19:25:04 bir7
* Fixed anti-memory Leak in shutdown.
*
@@ -134,7 +146,7 @@ get_firstr(volatile struct sock *sk)
struct sk_buff *skb;
skb = sk->rqueue;
if (skb == NULL) return (NULL);
- sk->rqueue = skb->next;
+ sk->rqueue = (struct sk_buff *)skb->next;
if (sk->rqueue == skb)
{
sk->rqueue = NULL;
@@ -221,15 +233,17 @@ tcp_err (int err, unsigned char *header, unsigned long daddr,
return;
}
- printk ("tcp.c: icmp_err got error\n");
+ PRINTK (("tcp.c: icmp_err got error\n"));
sk->err = icmp_err_convert[err & 0xff].errno;
+ /* if we've already connected we will keep trying
+ until we time out, or the user gives up. */
if (icmp_err_convert[err & 0xff].fatal)
{
- if (sk->state != TCP_ESTABLISHED)
+ if (sk->state == TCP_SYN_SENT)
{
sk->state = TCP_CLOSE;
+ sk->prot->close(sk, 0);
}
- sk->prot->close(sk, 0);
}
return;
@@ -245,33 +259,40 @@ tcp_readable (volatile struct sock *sk)
int count=0;
int sum;
+ PRINTK (("tcp_readable (sk=%X)\n", sk));
+
if (sk == NULL || sk->rqueue == NULL) return (0);
- counted = sk->copied_seq;
+ counted = sk->copied_seq+1;
amount = 0;
- skb = sk->rqueue->next;
+ skb = (struct sk_buff *)sk->rqueue->next;
/* go until a push or until we are out of data. */
do {
count ++;
if (count > 20)
{
- printk ("tcp_readable, more than 20 packets without a psh\n");
- printk ("possible read_queue corruption.\n");
+ PRINTK (("tcp_readable, more than 20 packets without a psh\n"));
+ PRINTK (("possible read_queue corruption.\n"));
return (amount);
}
- if (before (counted+1, skb->h.th->seq)) break;
+ if (before (counted, skb->h.th->seq)) break;
sum = skb->len - ( counted - skb->h.th->seq);
if (skb->h.th->syn) sum ++;
+ if (skb->h.th->urg)
+ {
+ sum -= net16(skb->h.th->urg_ptr);
+ }
if (sum >= 0)
{
amount += sum;
if (skb->h.th->syn) amount --;
counted += sum;
- if (skb->h.th->psh) break;
}
- skb = skb->next;
+ if (amount && skb->h.th->psh) break;
+ skb = (struct sk_buff *)skb->next;
} while (skb != sk->rqueue->next);
+ PRINTK (("tcp readable returning %d bytes\n", amount));
return (amount);
}
@@ -280,6 +301,8 @@ static int
tcp_select (volatile struct sock *sk, int sel_type, select_table *wait)
{
sk->inuse = 1;
+ PRINTK (("tcp_select (sk=%X, sel_type = %d, wait = %X)\n",
+ sk, sel_type, wait));
switch (sel_type)
{
case SEL_IN:
@@ -309,16 +332,31 @@ tcp_select (volatile struct sock *sk, int sel_type, select_table *wait)
if (sk->shutdown & SEND_SHUTDOWN)
{
+ PRINTK (("write select on shutdown socket.\n"));
+ /* should this return an error? */
release_sock (sk);
return (0);
}
+
/* hack so it will probably be able to write something
if it says it's ok to write. */
- if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+ if (sk->prot->wspace(sk) >= sk->mtu)
{
release_sock (sk);
+ /* This should cause connect to work ok. */
+ if (sk->state == TCP_SYN_RECV || sk->state == TCP_SYN_SENT)
+ return (0);
return (1);
}
+
+ PRINTK (("tcp_select: sleeping on write sk->wmem_alloc = %d, "
+ "sk->packets_out = %d\n"
+ "sk->wback = %X, sk->wfront = %X\n"
+ "sk->send_seq = %u, sk->window_seq=%u\n",
+ sk->wmem_alloc, sk->packets_out,
+ sk->wback, sk->wfront,
+ sk->send_seq, sk->window_seq));
+
release_sock (sk);
return (0);
@@ -376,7 +414,7 @@ tcp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
sk->inuse = 1;
if (sk->rqueue != NULL)
{
- skb = sk->rqueue->next;
+ skb = (struct sk_buff *)sk->rqueue->next;
if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
answ = 1;
}
@@ -643,16 +681,41 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
PRINTK (("tcp_write (sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, from, len, nonblock, flags));
- print_sk (sk);
-
prot = sk->prot;
while (len > 0)
{
+
+ if (sk->err)
+ {
+ if (copied) return (copied);
+ tmp = -sk->err;
+ sk->err = 0;
+ return (tmp);
+ }
+
/* first thing we do is make sure that we are established. */
sk->inuse = 1; /* no one else will use this socket. */
+ if (sk->shutdown & SEND_SHUTDOWN)
+ {
+ release_sock (sk);
+ sk->err = EPIPE;
+ if (copied) return (copied);
+ sk->err = 0;
+ return (-EPIPE);
+ }
+
while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
{
+
+ if (sk->err)
+ {
+ if (copied) return (copied);
+ tmp = -sk->err;
+ sk->err = 0;
+ return (tmp);
+ }
+
if (sk->state != TCP_SYN_SENT &&
sk->state != TCP_SYN_RECV)
{
@@ -674,7 +737,7 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
return (-EPIPE);
}
- if (nonblock)
+ if (nonblock || copied)
{
release_sock (sk);
PRINTK (("tcp_write: return 2\n"));
@@ -774,7 +837,7 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
/* if we didn't get any memory, we need to sleep. */
if (skb == NULL)
{
- if (nonblock)
+ if (nonblock || copied)
{
release_sock (sk);
PRINTK (("tcp_write: return 4\n"));
@@ -844,7 +907,7 @@ tcp_write (volatile struct sock *sk, unsigned char *from,
if (flags & MSG_OOB)
{
((struct tcp_header *)buff)->urg = 1;
- ((struct tcp_header *)buff)->urg_ptr = copy;
+ ((struct tcp_header *)buff)->urg_ptr = net16(copy);
}
skb->len += tmp;
memcpy_fromfs (buff+tmp, from, copy);
@@ -986,13 +1049,13 @@ tcp_read_wakeup(volatile struct sock *sk)
static void
cleanup_rbuf (volatile struct sock *sk)
{
-/* PRINTK (("cleaning rbuf for sk=%X\n",sk));*/
+ PRINTK (("cleaning rbuf for sk=%X\n",sk));
/* we have to loop through all the buffer headers, and
try to free up all the space we can. */
while (sk->rqueue != NULL )
{
struct sk_buff *skb;
- skb=sk->rqueue->next;
+ skb=(struct sk_buff *)sk->rqueue->next;
if (!skb->used) break;
if (sk->rqueue == skb)
{
@@ -1009,30 +1072,36 @@ cleanup_rbuf (volatile struct sock *sk)
/* at this point we should send an ack if the difference in
the window, and the amount of space is bigger than
TCP_WINDOW_DIFF */
+
PRINTK (("sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk)));
+ /* this area has caused the most trouble. The current strategy
+ is to simply do nothing if the other end has room to send atleast
+ 3 full packets, because the ack from those will automatically
+ update the window. If the other end doesn't think we have much
+ space left, but we have room for atleast 1 more complete packet
+ than it thinks we do, we will send an ack immediatedly. Otherwise
+ we will wait up to .5 seconds in case the user reads some more. */
+
+ sk->ack_backlog ++;
if ((sk->prot->rspace(sk) >
- (sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF)))
+ (sk->window - sk->bytes_rcv + sk->mtu)))
{
- sk->ack_backlog++;
- if (sk->ack_backlog > sk->max_ack_backlog)
- {
- tcp_read_wakeup (sk);
- }
- else
+ /* send an ack right now. */
+ tcp_read_wakeup (sk);
+ }
+ else
+ {
+ /* force it to send an ack soon. */
+ if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when))
{
- /* force it to send an ack soon. */
- if ( before (jiffies + TCP_ACK_TIME, sk->time_wait.when))
- {
- sk->time_wait.len = TCP_ACK_TIME;
- sk->timeout = TIME_WRITE;
- reset_timer ((struct timer *)&sk->time_wait);
- }
+ sk->time_wait.len = TCP_ACK_TIME;
+ sk->timeout = TIME_WRITE;
+ reset_timer ((struct timer *)&sk->time_wait);
}
}
-
-}
+}
/* handle reading urgent data. */
static int
@@ -1040,10 +1109,11 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
unsigned char *to, int len, unsigned flags)
{
int copied = 0;
+
struct sk_buff *skb;
PRINTK (("tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n",
sk, to, len, flags));
- print_sk(sk);
+
while (len > 0)
{
sk->inuse = 1;
@@ -1059,7 +1129,7 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
return (tmp);
}
- if (sk->state == TCP_CLOSE)
+ if (sk->state == TCP_CLOSE || sk->done)
{
release_sock (sk);
if (copied) return (copied);
@@ -1079,7 +1149,7 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
return (copied);
}
- if (nonblock)
+ if (nonblock || copied)
{
release_sock (sk);
if (copied) return (copied);
@@ -1103,30 +1173,35 @@ tcp_read_urg(volatile struct sock * sk, int nonblock,
sti();
sk->inuse = 1;
}
- /* now we have some urgent data, we must find it.*/
- for (skb = sk->rqueue->next; skb->next != sk->rqueue;
- skb = skb->next)
- {
- int offset;
+
+ skb = (struct sk_buff *)sk->rqueue->next;
+ do {
int amt;
- if (!skb->h.th->urg) continue;
- offset = 0;
- amt = min(skb->h.th->urg_ptr,len);
- verify_area (to, amt);
- memcpy_tofs (to, (unsigned char *)(skb->h.th) +
- skb->h.th->doff*4
- + offset, amt);
-
- if (!(flags & MSG_PEEK))
+ if (skb->h.th->urg && !skb->urg_used)
{
- skb->urg_used = 1;
- sk->urg --;
+ if (skb->h.th->urg_ptr == 0)
+ {
+ skb->h.th->urg_ptr = net16(skb->len);
+ }
+ amt = min(net16(skb->h.th->urg_ptr),len);
+ verify_area (to, amt);
+ memcpy_tofs (to, (unsigned char *)(skb->h.th) +
+ skb->h.th->doff*4, amt);
+
+ if (!(flags & MSG_PEEK))
+ {
+ skb->urg_used = 1;
+ sk->urg --;
+ }
+ release_sock (sk);
+ copied += amt;
+ return (copied);
}
- release_sock (sk);
- copied += amt;
- return (copied);
- }
+ skb = (struct sk_buff *)skb->next;
+ } while (skb != sk->rqueue->next);
}
+ sk->urg = 0;
+ release_sock(sk);
return (0);
}
@@ -1156,7 +1231,7 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
/* so no-one else will use this socket. */
sk->inuse = 1;
if (sk->rqueue != NULL)
- skb=sk->rqueue->next;
+ skb=(struct sk_buff *)sk->rqueue->next;
else
skb = NULL;
@@ -1171,8 +1246,6 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
{
PRINTK(("skb = %X:\n",skb));
- print_skb(skb);
- print_sk (sk);
cleanup_rbuf(sk);
@@ -1180,7 +1253,11 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
{
int tmp;
release_sock (sk);
- if (copied) return (copied);
+ if (copied)
+ {
+ PRINTK (("tcp_read: returing %d\n", copied));
+ return (copied);
+ }
tmp = -sk->err;
sk->err = 0;
return (tmp);
@@ -1189,7 +1266,11 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
if (sk->state == TCP_CLOSE)
{
release_sock (sk);
- if (copied) return (copied);
+ if (copied)
+ {
+ PRINTK (("tcp_read: returing %d\n", copied));
+ return (copied);
+ }
if (!sk->done)
{
sk->done = 1;
@@ -1202,20 +1283,25 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
{
release_sock (sk);
if (copied == 0) sk->done = 1;
+ PRINTK (("tcp_read: returing %d\n", copied));
return (copied);
}
-
- if (nonblock)
+ if (nonblock || copied)
{
release_sock (sk);
- if (copied) return (copied);
+ if (copied)
+ {
+ PRINTK (("tcp_read: returing %d\n", copied));
+ return (copied);
+ }
return (-EAGAIN);
}
if ((flags & MSG_PEEK) && copied != 0)
{
release_sock (sk);
+ PRINTK (("tcp_read: returing %d\n", copied));
return (copied);
}
@@ -1238,7 +1324,12 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
if (current->signal & ~current->blocked)
{
sti ();
- if (copied) return (copied);
+ if (copied)
+ {
+ PRINTK (("tcp_read: returing %d\n", copied));
+ return (copied);
+ }
+
return (-ERESTARTSYS);
}
}
@@ -1248,7 +1339,7 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
sk->inuse = 1;
if (sk->rqueue != NULL)
- skb=sk->rqueue->next;
+ skb=(struct sk_buff *)sk->rqueue->next;
else
skb = NULL;
@@ -1268,19 +1359,20 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
{
if (skb->urg_used)
{
- if (flags & MSG_PEEK) break;
- sk->copied_seq += skb->h.th->urg_ptr;
- offset += skb->h.th->urg_ptr;
- if (offset > skb->len)
+ sk->copied_seq += net16(skb->h.th->urg_ptr);
+ offset += net16(skb->h.th->urg_ptr);
+ if (offset >= skb->len)
{
skb->used = 1;
- skb=skb->next;
+ skb = (struct sk_buff *)skb->next;
continue;
}
}
else
{
- break;
+ release_sock (sk);
+ if (copied) return (copied);
+ return (-EIO);
}
}
used = min(skb->len - offset, len);
@@ -1315,12 +1407,12 @@ tcp_read (volatile struct sock *sk, unsigned char *to,
{
skb->used = 1;
}
- skb=skb->next;
+ skb=(struct sk_buff *)skb->next;
}
cleanup_rbuf (sk);
release_sock (sk);
+ PRINTK (("tcp_read: returing %d\n", copied));
if (copied == 0 && nonblock) return (-EAGAIN);
- PRINTK (("tcp_read returning %d\n", copied));
return (copied);
}
@@ -1343,6 +1435,11 @@ tcp_shutdown (volatile struct sock *sk, int how)
* Most of this is guesswork, so maybe it will work...
*/
+ /* if we've already sent a fin, return. */
+ if (sk->state == TCP_FIN_WAIT1 ||
+ sk->state == TCP_FIN_WAIT2)
+ return;
+
if (!(how & SEND_SHUTDOWN)) return;
sk->inuse = 1;
@@ -1630,7 +1727,6 @@ tcp_conn_request(volatile struct sock *sk, struct sk_buff *skb,
}
}
- print_sk (newsk);
buff=newsk->prot->wmalloc(newsk,MAX_SYN_SIZE,1, GFP_ATOMIC);
if (buff == NULL)
{
@@ -1732,7 +1828,6 @@ tcp_close (volatile struct sock *sk, int timeout)
struct device *dev=NULL;
int tmp;
PRINTK (("tcp_close ((struct sock *)%X, %d)\n",sk, timeout));
- print_sk (sk);
sk->inuse = 1;
sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK;
@@ -1740,7 +1835,6 @@ tcp_close (volatile struct sock *sk, int timeout)
if (!sk->dead)
wake_up (sk->sleep);
-
/* we need to flush the recv. buffs. */
if (sk->rqueue != NULL)
@@ -1749,7 +1843,7 @@ tcp_close (volatile struct sock *sk, int timeout)
struct sk_buff *skb2;
skb = sk->rqueue;
do {
- skb2=skb->next;
+ 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))
@@ -1901,7 +1995,7 @@ tcp_write_xmit (volatile struct sock *sk)
sk->packets_out < sk->cong_window)
{
skb = sk->wfront;
- sk->wfront = skb->next;
+ sk->wfront = (struct sk_buff *)skb->next;
if (sk->wfront == NULL)
sk->wback = NULL;
skb->next = NULL;
@@ -1960,7 +2054,7 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
sk->window_seq = ack + net16(th->window);
cli();
- for (skb = sk->send_head; skb != NULL; skb=skb->link3)
+ for (skb = sk->send_head; skb != NULL; skb= (struct sk_buff *)skb->link3)
{
if (after( skb->h.seq, sk->window_seq))
{
@@ -1968,7 +2062,7 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
/* remove it from the send queue. */
if (skb2 == NULL)
{
- sk->send_head = skb->link3;
+ sk->send_head = (struct sk_buff *)skb->link3;
}
else
{
@@ -2062,7 +2156,7 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
/* estimate the rtt. */
sk->rtt += ((jiffies - oskb->when) - sk->rtt)/2;
if (sk->rtt < 30) sk->rtt = 30;
- sk->send_head = oskb->link3;
+ sk->send_head = (struct sk_buff *)oskb->link3;
if (sk->send_head == NULL)
{
sk->send_tail = NULL;
@@ -2092,7 +2186,7 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
if (oskb == oskb->next)
arp_q = NULL;
else
- arp_q = oskb->next;
+ arp_q = (struct sk_buff *)oskb->next;
}
}
oskb->magic = 0;
@@ -2139,22 +2233,23 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
if (!sk->dead)
wake_up (sk->sleep);
- /* Lets send a probe once in a while. */
- sk->time_wait.len = TCP_PROBEWAIT_LEN;
- sk->timeout = TIME_KEEPOPEN;
- reset_timer((struct timer *)&sk->time_wait);
+ delete_timer((struct timer *)&sk->time_wait);
sk->timeout = 0;
}
else
{
+ if (sk->state != sk->keepopen)
+ {
+ sk->timeout = TIME_WRITE;
+ sk->time_wait.len = sk->rtt*2;
+ reset_timer ((struct timer *)&sk->time_wait);
+ }
if (sk->state == TCP_TIME_WAIT)
{
sk->time_wait.len = TCP_TIMEWAIT_LEN;
+ reset_timer ((struct timer *)&sk->time_wait);
sk->timeout = TIME_CLOSE;
}
- sk->timeout = TIME_WRITE;
- sk->time_wait.len = sk->rtt*2;
- reset_timer ((struct timer *)&sk->time_wait);
}
}
@@ -2189,7 +2284,6 @@ tcp_ack (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
else
{
PRINTK (("tcp_ack closing socket - %X\n", sk));
- print_sk (sk);
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, sk->daddr);
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_CLOSE;
@@ -2218,7 +2312,6 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
skb->len = len - (th->doff*4);
PRINTK(("tcp_data len = %d sk = %X:\n",skb->len, sk));
- print_sk(sk);
sk->bytes_rcv += skb->len;
@@ -2240,7 +2333,6 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
sk->err = EPIPE;
sk->shutdown = SHUTDOWN_MASK;
PRINTK (("tcp_data: closing socket - %X\n", sk));
- print_sk (sk);
kfree_skb (skb, FREE_READ);
if (!sk->dead) wake_up (sk->sleep);
return (0);
@@ -2252,10 +2344,10 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
in order, there will be no performance loss, and if they come
out of order we will be able to fit things in nicely. */
+ /* this should start at the last one, and then go around forwards. */
if (sk->rqueue == NULL)
{
PRINTK (("tcp_data: skb = %X:\n",skb));
- print_skb (skb);
sk->rqueue = skb;
skb->next = skb;
@@ -2265,12 +2357,10 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
else
{
PRINTK (("tcp_data adding to chain sk = %X:\n",sk));
- print_sk (sk);
- for (skb1=sk->rqueue; ; skb1=skb1->prev)
+ for (skb1=sk->rqueue; ; skb1=(struct sk_buff *)skb1->prev)
{
PRINTK (("skb1=%X\n",skb1));
- print_skb(skb1);
PRINTK (("skb1->h.th->seq = %d\n", skb1->h.th->seq));
if (after ( th->seq+1, skb1->h.th->seq))
{
@@ -2294,9 +2384,6 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
}
PRINTK (("skb = %X:\n",skb));
- print_skb (skb);
- PRINTK (("sk now equals:\n"));
- print_sk (sk);
}
@@ -2326,7 +2413,9 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
sk->shutdown |= RCV_SHUTDOWN;
}
- for (skb2=skb->next; skb2 != sk->rqueue->next; skb2=skb2->next)
+ for (skb2=(struct sk_buff *)skb->next;
+ skb2 !=(struct sk_buff *) sk->rqueue->next;
+ skb2=(struct sk_buff *)skb2->next)
{
if (before(skb2->h.th->seq, sk->acked_seq+1))
{
@@ -2390,7 +2479,7 @@ tcp_data (struct sk_buff *skb, volatile struct sock *sk,
&& sk->rcv_ack_seq == sk->send_seq)
{
PRINTK (("tcp_data: entering last_ack state sk = %X\n", sk));
- print_sk (sk);
+
tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, saddr);
sk->shutdown = SHUTDOWN_MASK;
sk->state = TCP_LAST_ACK;
@@ -2416,22 +2505,23 @@ tcp_urg (volatile struct sock *sk, struct tcp_header *th, unsigned long saddr)
return (0);
}
- sk->urg++;
-
if (!sk->urg)
{
/* so if we get more urgent data, we don't
signal the user again. */
- if (sk->proc == 0) return (0);
- if (sk->proc > 0)
+ if (sk->proc != 0)
{
- kill_proc (sk->proc, SIGURG, 1);
- }
- else
- {
- kill_pg (-sk->proc, SIGURG, 1);
+ if (sk->proc > 0)
+ {
+ kill_proc (sk->proc, SIGURG, 1);
+ }
+ else
+ {
+ kill_pg (-sk->proc, SIGURG, 1);
+ }
}
- }
+ }
+ sk->urg++;
return (0);
}
@@ -2455,6 +2545,7 @@ tcp_fin (volatile struct sock *sk, struct tcp_header *th,
case TCP_ESTABLISHED:
sk->fin_seq = th->seq+1; /* Contains the one that needs to be acked */
sk->state = TCP_CLOSE_WAIT;
+ if (th->rst) sk->shutdown = SHUTDOWN_MASK;
break;
case TCP_CLOSE_WAIT:
@@ -2562,7 +2653,6 @@ tcp_accept (volatile struct sock *sk, int flags)
struct sk_buff *skb;
PRINTK (("tcp_accept(sk=%X, flags=%X)\n", sk, flags));
- print_sk(sk);
/* we need to make sure that this socket is listening, and that
it has something pending. */
@@ -2689,6 +2779,7 @@ tcp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
sk->prot->queue_xmit(sk, dev, buff, 0);
sk->time_wait.len = TCP_CONNECT_TIME;
+ sk->rtt = TCP_CONNECT_TIME;
reset_timer ((struct timer *)&sk->time_wait);
sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
release_sock (sk);
@@ -2799,7 +2890,6 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
if (sk)
{
PRINTK (("sk = %X:\n",sk));
- print_sk (sk);
}
if (!redo)
@@ -2947,6 +3037,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return (0);
}
}
+#if 0
if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
{
sk->err = ECONNRESET;
@@ -2961,7 +3052,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
release_sock(sk);
return (0);
}
-
+#endif
if (th->ack)
{
if(!tcp_ack (sk, th, saddr))
@@ -3079,10 +3170,12 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
release_sock(sk);
return (0);
}
-/* if (opt->security != 0 || opt->compartment != 0 )
+#if 0
+ if (opt->security != 0 || opt->compartment != 0 )
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
tcp_reset (daddr, saddr, th, sk->prot, opt, dev);
if (!sk->dead)
{
@@ -3092,7 +3185,7 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
release_sock(sk);
return (0);
} */
-
+#endif
if (!th->ack)
{
if (th->syn)
@@ -3289,7 +3382,8 @@ struct proto tcp_prot =
tcp_shutdown,
128,
0,
- {NULL,}
+ {NULL,},
+ "TCP"
};
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index f428073..123cdba 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -19,8 +19,11 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: tcp.h,v 0.8.4.6 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: tcp.h,v 0.8.4.7 1993/01/22 22:58:08 bir7 Exp $ */
/* $Log: tcp.h,v $
+ * Revision 0.8.4.7 1993/01/22 22:58:08 bir7
+ * Check in for merge with previous .99 pl 4.
+ *
* Revision 0.8.4.6 1992/12/12 19:25:04 bir7
* Fixed anti-memory Leak in shutdown.
*
diff --git a/net/tcp/timer.c b/net/tcp/timer.c
index c6e3182..a2c4d08 100644
--- a/net/tcp/timer.c
+++ b/net/tcp/timer.c
@@ -20,8 +20,17 @@
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: timer.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: timer.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: timer.c,v $
+ * Revision 0.8.4.8 1993/01/23 18:00:11 bir7
+ * added volatile keyword.
+ *
+ * Revision 0.8.4.7 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
+ * Revision 0.8.4.6 1993/01/22 22:58:08 bir7
+ * Check in for merge with previous .99 pl 4.
+ *
* Revision 0.8.4.5 1992/12/12 19:25:04 bir7
* cleaned up Log messages.
*
@@ -68,7 +77,7 @@
#define PRINTK(x) /**/
#endif
-static struct timer *timer_base=NULL;
+static volatile struct timer *timer_base=NULL;
unsigned long seq_offset;
void
@@ -93,7 +102,9 @@ delete_timer (struct timer *t)
sti();
return;
}
- for (tm = timer_base;tm->next != NULL ;tm=tm->next)
+ for (tm = (struct timer *)timer_base;
+ tm->next != NULL ;
+ tm=(struct timer *)tm->next)
{
if (tm->next == t)
{
@@ -139,7 +150,7 @@ reset_timer (struct timer *t)
sti();
return;
}
- for (tm = timer_base; ; tm=tm->next)
+ for (tm = (struct timer *)timer_base; ; tm=(struct timer *)tm->next)
{
if (tm->next == NULL || before (t->when,tm->next->when))
{
@@ -179,12 +190,12 @@ net_timer (void)
{
sk->time_wait.len = TCP_TIMEOUT_LEN;
sk->timeout = TIME_KEEPOPEN;
- reset_timer (timer_base);
+ reset_timer ((struct timer *)timer_base);
}
else
{
sk->timeout = 0;
- delete_timer(timer_base);
+ delete_timer((struct timer *)timer_base);
}
/* always see if we need to send an ack. */
@@ -213,7 +224,6 @@ net_timer (void)
socket to be freed. We need to
print an error message. */
PRINTK (("possible memory leak. sk = %X\n", sk));
- print_sk (sk);
reset_timer ((struct timer *)&sk->time_wait);
sk->inuse = 0;
break;
diff --git a/net/tcp/timer.h b/net/tcp/timer.h
index 934005b..29df38d 100644
--- a/net/tcp/timer.h
+++ b/net/tcp/timer.h
@@ -19,13 +19,19 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: timer.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ */
+/* $Id: timer.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: timer.h,v $
+ * Revision 0.8.4.2 1993/01/23 18:00:11 bir7
+ * added volatile keyword.
+ *
* Revision 0.8.4.1 1992/11/10 00:17:18 bir7
* version change only.
*
* Revision 0.8.3.2 1992/11/10 00:14:47 bir7
* Changed malloc to kmalloc and added $iId$ and $Log: timer.h,v $
+ * Revision 0.8.4.2 1993/01/23 18:00:11 bir7
+ * added volatile keyword.
+ *
* Revision 0.8.4.1 1992/11/10 00:17:18 bir7
* version change only.
*.
@@ -39,7 +45,7 @@ struct timer
unsigned long len;
volatile struct sock *sk;
unsigned long when;
- struct timer *next;
+ volatile struct timer *next;
};
diff --git a/net/tcp/udp.c b/net/tcp/udp.c
index b4b4c5d..b4c60b9 100644
--- a/net/tcp/udp.c
+++ b/net/tcp/udp.c
@@ -19,8 +19,17 @@
The Author may be reached as bir7@leland.stanford.edu or
C/O Department of Mathematics; Stanford University; Stanford, CA 94305
*/
-/* $Id: udp.c,v 0.8.4.9 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: udp.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ */
/* $Log: udp.c,v $
+ * Revision 0.8.4.12 1993/01/26 22:04:00 bir7
+ * Added support for proc fs.
+ *
+ * Revision 0.8.4.11 1993/01/23 18:00:11 bir7
+ * added volatile keyword.
+ *
+ * Revision 0.8.4.10 1993/01/22 23:21:38 bir7
+ * Merged with 99 pl4
+ *
* Revision 0.8.4.9 1992/12/12 19:25:04 bir7
* cleaned up Log messages.
*
@@ -373,8 +382,6 @@ udp_sendto (volatile struct sock *sk, unsigned char *from, int len,
if (skb == NULL)
{
- printk ("udp_sendto: write buffer full?\n");
- print_sk(sk);
tmp = sk->wmem_alloc;
release_sock (sk);
if (copied) return (copied);
@@ -555,6 +562,7 @@ udp_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
return (-ERESTARTSYS);
}
}
+ sk->inuse = 1;
sti();
}
skb = sk->rqueue;
@@ -567,7 +575,7 @@ udp_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
}
else
{
- sk->rqueue = sk->rqueue ->next;
+ sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
}
@@ -714,7 +722,6 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
/* At this point we should print the thing out. */
PRINTK (("<< \n"));
- print_sk (sk);
/* now add it to the data chain and wake things up. */
if (sk->rqueue == NULL)
@@ -769,6 +776,7 @@ struct proto udp_prot =
NULL,
128,
0,
- {NULL,}
+ {NULL,},
+ "UDP"
};
diff --git a/net/tcp/we.c b/net/tcp/we.c
index 28b30ef..5cd6079 100644
--- a/net/tcp/we.c
+++ b/net/tcp/we.c
@@ -44,8 +44,14 @@
/* Note: My driver was full of bugs. Basically if it works, credit
Bob Harris. If it's broken blame me. -RAB */
-/* $Id: we.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $ */
+/* $Id: we.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $ */
/* $Log: we.c,v $
+ * Revision 0.8.4.10 1993/01/23 18:00:11 bir7
+ * Added volatile keyword and converted entry points.
+ *
+ * Revision 0.8.4.9 1993/01/22 22:58:08 bir7
+ * Check in for merge with previous .99 pl 4.
+ *
* Revision 0.8.4.8 1992/12/12 19:25:04 bir7
* cleaned up Log messages.
*
@@ -89,6 +95,7 @@
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
+#include <linux/interrupt.h>
#include "dev.h"
#include "eth.h"
@@ -101,22 +108,6 @@
#include "wereg.h"
static unsigned char interrupt_mask;
-/* format of status byte.
- bit
- 0 start
- 1 open
- 2 transmitter in use */
-
-#define START 1
-#define OPEN 2
-#define TRS_BUSY 0x400
-#define IN_INT 8
-
-/* We need to get rid of all these statics and move them into the
- device structure that way we can have more than one wd8003 board
- in the system at once. */
-
-static volatile unsigned int status;
static struct enet_statistics stats; /* Statistics collection */
static unsigned char max_pages; /* Board memory/256 */
@@ -145,7 +136,7 @@ wd_start(struct device *dev)
outb_p(cmd, WD_COMM);
outb_p(interrupt_mask,WD_IMR);
sti();
- status |= START;
+ dev->start = 1;
}
int
@@ -198,7 +189,6 @@ wd8003_open(struct device *dev)
cmd|= 4<<CRDMA_SHIFT;
outb_p(cmd, WD_COMM);
outb_p(WD_RCONFIG,WD_RCC);
- status = OPEN;
wd_start(dev);
return (0);
}
@@ -227,7 +217,7 @@ wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
int len;
cli();
- if (status & TRS_BUSY)
+ if (dev->tbusy)
{
/* put in a time out. */
if (jiffies - dev->trans_start < 30)
@@ -237,7 +227,7 @@ wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
printk ("wd8003 transmit timed out. \n");
}
- status |= TRS_BUSY;
+ dev->tbusy = 1;
if (skb == NULL)
{
@@ -264,7 +254,7 @@ wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
arp_queue (skb);
}
cli (); /* arp_queue turns them back on. */
- status &= ~TRS_BUSY;
+ dev->tbusy = 0;
sti();
return (0);
}
@@ -285,7 +275,7 @@ wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
outb_p(cmd, WD_COMM);
interrupt_mask |= TRANS_MASK;
- if (!(status & IN_INT))
+ if (!(dev->interrupt))
outb (interrupt_mask, WD_IMR);
outb_p(len&0xff,WD_TB0);
@@ -400,9 +390,6 @@ wd_rcv( struct device *dev )
stats.rx_packets++; /* count all receives */
done = wdget( ring, dev ); /* get the packet */
- /* see if we need to process this packet again. */
- if (done == -1) continue;
-
/* Calculate next packet location */
pkt = ring->next;
@@ -478,8 +465,7 @@ wd_rx_over( struct device *dev )
static void
wd_trs( struct device *dev )
{
- unsigned char cmd, errors;
- int len;
+ unsigned char errors;
if( wd_debug )
printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
@@ -489,7 +475,10 @@ wd_trs( struct device *dev )
stats.tx_packets++;
tx_aborted = 0;
}
+ dev->tbusy = 0;
+ mark_bh (INET_BH);
+#if 0
/* attempt to start a new transmission. */
len = dev_tint( (unsigned char *)dev->mem_start, dev );
if( len != 0 ){
@@ -503,11 +492,12 @@ wd_trs( struct device *dev )
}
else
{
- status &= ~TRS_BUSY;
+ dev->tbusy = 0
interrupt_mask &= ~TRANS_MASK;
return;
}
- }
+#endif
+ }
else{ /* TX error occurred! - H/W will reschedule */
if( errors & CRS ){
stats.tx_carrier_errors++;
@@ -555,7 +545,7 @@ wd8003_interrupt(int reg_ptr)
if (wd_debug)
printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
- status |= IN_INT;
+ dev->interrupt = 1;
do{ /* find out who called */
sti();
@@ -632,7 +622,7 @@ wd8003_interrupt(int reg_ptr)
cli();
} while( inb_p( ISR ) != 0 );
- status &= ~IN_INT;
+ dev->interrupt = 0;
}
@@ -659,7 +649,6 @@ wd8003_init(struct device *dev)
printk ("Warning WD8013 board not found at i/o = %X.\n",dev->base_addr);
/* make sure no one can attempt to open the device. */
- status = OPEN;
return (1);
}
printk("wd8013");
@@ -709,7 +698,7 @@ wd8003_init(struct device *dev)
if( (i - dev->mem_start) > 4096 )
break;
else
- status = OPEN;
+ return (1);
}
}
/* Calculate how many pages of memory on board */
@@ -734,7 +723,8 @@ wd8003_init(struct device *dev)
((char *)&stats)[i] = 0;
printk ("\n");
- status = 0;
+ dev->tbusy = 0;
+ dev->interrupt = 0;
if (irqaction (dev->irq, &wd8003_sigaction))
{
diff --git a/net/unix.c b/net/unix.c
index bef3697..9ace268 100644
--- a/net/unix.c
+++ b/net/unix.c
@@ -8,7 +8,8 @@
#include <linux/un.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
-
+#include <linux/mm.h>
+#include <linux/config.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -100,9 +101,16 @@ struct proto_ops unix_proto_ops = {
unix_proto_shutdown,
unix_proto_setsockopt,
unix_proto_getsockopt,
- NULL /* unix_proto_fcntl. */
+ NULL, /* unix_proto_fcntl. */
};
+static inline int
+min (int a, int b)
+{
+ if (a < b) return (a);
+ return (b);
+}
+
#ifdef SOCK_DEBUG
void
sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
@@ -121,7 +129,7 @@ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
sockaddr_len + UN_PATH_OFFSET);
}
}
-#endif
+#endif /* SOCK_DEBUG */
/* don't have to do anything. */
static int