diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1993-02-09 22:03:01 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:12 -0400 |
commit | 1680d965ceb874b34ebbc3788fdb1b0dd594f043 (patch) | |
tree | 4ec1dc6b7651f2e57cff25c70c4b10663d74c345 | |
parent | b75fb8468bb5353db99f69805408db991ac0ed39 (diff) | |
download | archive-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.
72 files changed, 1993 insertions, 1040 deletions
@@ -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" @@ -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; } @@ -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; } @@ -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; } } @@ -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) { @@ -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)) { @@ -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 |