diff -c +recursive +new-files l99.4/linux/Makefile linux/Makefile
*** l99.4/linux/Makefile	Mon Jan 25 21:49:56 1993
--- linux/Makefile	Sat Feb  6 11:20:43 1993
***************
*** 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,151 ****
  
  tools/version.h: $(CONFIGURE) Makefile
  	@./makever.sh
! 	@echo \#define UTS_RELEASE \"0.99.pl4-`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
--- 147,153 ----
  
  tools/version.h: $(CONFIGURE) Makefile
  	@./makever.sh
! 	@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 -c +recursive +new-files l99.4/linux/boot/setup.S linux/boot/setup.S
*** l99.4/linux/boot/setup.S	Mon Jan 25 21:49:56 1993
--- linux/boot/setup.S	Mon Feb  8 16:27:51 1993
***************
*** 436,445 ****
  l1:	inc	si
  	inc	di
  	mov	al,(si)
  	seg es
! 	and	al,(di)
! 	cmp	al,(si)
! 	loope 	l1
  	cmp	cx,#0x00
  	jne	nogen
  	lea	si,dscgenoa
--- 436,446 ----
  l1:	inc	si
  	inc	di
  	mov	al,(si)
+ 	test	al,al
+ 	jz	l2
  	seg es
! 	cmp	al,(di)
! l2:	loope 	l1
  	cmp	cx,#0x00
  	jne	nogen
  	lea	si,dscgenoa
***************
*** 697,703 ****
  		
  idati:		.ascii	"761295520"
  idcandt:	.byte	0xa5
! idgenoa:	.byte	0x77, 0x00, 0x66, 0x99
  idparadise:	.ascii	"VGA="
  idoakvga:	.ascii  "OAK VGA "
  idf1280:	.ascii	"Orchid Technology Fahrenheit 1280"
--- 698,704 ----
  		
  idati:		.ascii	"761295520"
  idcandt:	.byte	0xa5
! idgenoa:	.byte	0x77, 0x00, 0x99, 0x66
  idparadise:	.ascii	"VGA="
  idoakvga:	.ascii  "OAK VGA "
  idf1280:	.ascii	"Orchid Technology Fahrenheit 1280"
diff -c +recursive +new-files l99.4/linux/config.in linux/config.in
*** l99.4/linux/config.in	Mon Jan 25 21:49:26 1993
--- linux/config.in	Sun Jan 31 13:54:56 1993
***************
*** 35,41 ****
  CONFIG_SCSI_AHA1740 y/n y
  Future Domain SCSI support
  CONFIG_SCSI_FUTURE_DOMAIN y/n y
! Seagate ST-02 SCSI support
  CONFIG_SCSI_SEAGATE y/n y
  UltraStor SCSI support
  CONFIG_SCSI_ULTRASTOR y/n y
--- 35,41 ----
  CONFIG_SCSI_AHA1740 y/n y
  Future Domain SCSI support
  CONFIG_SCSI_FUTURE_DOMAIN y/n y
! 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,55 ****
  Extended fs support
  CONFIG_EXT_FS y/n n
  msdos fs support
! CONFIG_MSDOS_FS y/n n
  /proc filesystem support
  CONFIG_PROC_FS y/n y
  NFS filesystem support
--- 49,55 ----
  Extended fs support
  CONFIG_EXT_FS y/n n
  msdos fs support
! CONFIG_MSDOS_FS y/n y
  /proc filesystem support
  CONFIG_PROC_FS y/n y
  NFS filesystem support
diff -c +recursive +new-files l99.4/linux/fs/buffer.c linux/fs/buffer.c
*** l99.4/linux/fs/buffer.c	Mon Jan 25 21:49:14 1993
--- linux/fs/buffer.c	Sat Feb  6 11:03:42 1993
***************
*** 45,50 ****
--- 45,51 ----
  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,310 ****
--- 306,312 ----
  {
  	struct buffer_head * bh, * tmp;
  	int buffers;
+ 	static int grow_size = 0;
  
  repeat:
  	bh = get_hash_table(dev, block, size);
***************
*** 313,322 ****
  			put_last_free(bh);
  		return bh;
  	}
! 
! 	if (nr_free_pages > 30 && buffermem < 6*1024*1024)
  		grow_buffers(size);
! 
  	buffers = nr_buffers;
  	bh = NULL;
  
--- 315,327 ----
  			put_last_free(bh);
  		return bh;
  	}
! 	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,438 ****
  		} else
  			bh[i] = NULL;
  
! 	if(bhnum)
! 	  ll_rw_block(READ, bhnum, bhr);
  
  	for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
  		if (bh[i]) {
--- 436,443 ----
  		} else
  			bh[i] = NULL;
  
! 	if (bhnum)
! 		ll_rw_block(READ, bhnum, bhr);
  
  	for (i=0 ; i<4 ; i++,address += BLOCK_SIZE)
  		if (bh[i]) {
***************
*** 664,669 ****
--- 669,678 ----
  {
  	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 -c +recursive +new-files l99.4/linux/fs/ext/freelists.c linux/fs/ext/freelists.c
*** l99.4/linux/fs/ext/freelists.c	Mon Jan 25 21:49:15 1993
--- linux/fs/ext/freelists.c	Wed Feb  3 10:36:53 1993
***************
*** 48,55 ****
  	struct buffer_head * bh;
  	struct ext_free_block * efb;
  
! 	if (!sb)
! 		panic("trying to free block on nonexistent device");
  	lock_super (sb);
  	if (block < sb->u.ext_sb.s_firstdatazone ||
  	    block >= sb->u.ext_sb.s_nzones) {
--- 48,57 ----
  	struct buffer_head * bh;
  	struct ext_free_block * efb;
  
! 	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,98 ****
  	struct ext_free_block * efb;
  	int j;
  
! 	if (!sb)
! 		panic("trying to get new block from nonexistant device");
  	if (!sb->u.ext_sb.s_firstfreeblock)
  		return 0;
  	lock_super (sb);
--- 93,102 ----
  	struct ext_free_block * efb;
  	int j;
  
! 	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,132 ****
  	}
  	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");
  	}
  	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");
  	clear_block(bh->b_data);
  	bh->b_uptodate = 1;
  	bh->b_dirt = 1;
--- 122,137 ----
  	}
  	if (j < sb->u.ext_sb.s_firstdatazone || j > sb->u.ext_sb.s_nzones) {
  		printk ("ext_new_block: blk = %d\n", j);
! 		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))) {
! 		printk("new_block: cannot get block");
! 		return 0;
! 	}
  	clear_block(bh->b_data);
  	bh->b_uptodate = 1;
  	bh->b_dirt = 1;
***************
*** 194,205 ****
  		return;
  	}
  	if (!inode->i_sb) {
! 		printk("free_inode: inode on nonexistent 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");
  		unlock_super (inode->i_sb);
  		return;
  	}
--- 199,210 ----
  		return;
  	}
  	if (!inode->i_sb) {
! 		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 non-existent inode\n");
  		unlock_super (inode->i_sb);
  		return;
  	}
diff -c +recursive +new-files l99.4/linux/fs/inode.c linux/fs/inode.c
*** l99.4/linux/fs/inode.c	Mon Jan 25 21:49:14 1993
--- linux/fs/inode.c	Fri Jan 29 17:00:50 1993
***************
*** 129,139 ****
   * NFS uses this to get the authentication correct.  -- jrs
   */
  
! int notify_change(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 0;
  }
  
--- 129,139 ----
   * NFS uses this to get the authentication correct.  -- jrs
   */
  
! 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(flags, inode);
  	return 0;
  }
  
diff -c +recursive +new-files l99.4/linux/fs/ioctl.c linux/fs/ioctl.c
*** l99.4/linux/fs/ioctl.c	Mon Jan 25 21:49:15 1993
--- linux/fs/ioctl.c	Sat Jan 30 19:08:31 1993
***************
*** 40,48 ****
  			put_fs_long(filp->f_inode->i_size - filp->f_pos,
  			    (long *) arg);
  			return 0;
- 		default:
- 			return -EINVAL;
  	}
  }
  
  
--- 40,49 ----
  			put_fs_long(filp->f_inode->i_size - filp->f_pos,
  			    (long *) arg);
  			return 0;
  	}
+ 	if (filp->f_op && filp->f_op->ioctl)
+ 		return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg);
+ 	return -EINVAL;
  }
  
  
diff -c +recursive +new-files l99.4/linux/fs/isofs/file.c linux/fs/isofs/file.c
*** l99.4/linux/fs/isofs/file.c	Mon Jan 25 21:49:16 1993
--- linux/fs/isofs/file.c	Sat Jan 30 14:45:15 1993
***************
*** 214,224 ****
  		  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);
  		      break;
  		    }
  		  }
--- 214,220 ----
  		  if (*bhe) {/* test for valid buffer */
  		    wait_on_buffer(*bhe);
  		    if (!(*bhe)->b_uptodate) {
! 		      left = 0;
  		      break;
  		    }
  		  }
diff -c +recursive +new-files l99.4/linux/fs/locks.c linux/fs/locks.c
*** l99.4/linux/fs/locks.c	Mon Jan 25 21:49:56 1993
--- linux/fs/locks.c	Sun Jan 24 23:21:04 1993
***************
*** 191,197 ****
  		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)
  		return 0;
  	switch (l->l_whence) {
  	case 0 /*SEEK_SET*/ : start = 0; break;
--- 191,198 ----
  		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
! 	 && l->l_type != F_SHLCK && l->l_type != F_EXLCK)
  		return 0;
  	switch (l->l_whence) {
  	case 0 /*SEEK_SET*/ : start = 0; break;
diff -c +recursive +new-files l99.4/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
*** l99.4/linux/fs/minix/bitmap.c	Mon Jan 25 21:49:56 1993
--- linux/fs/minix/bitmap.c	Wed Feb  3 10:39:32 1993
***************
*** 102,108 ****
  	int i,j;
  
  	if (!sb) {
! 		printk("trying to get new block from nonexistant device\n");
  		return 0;
  	}
  repeat:
--- 102,108 ----
  	int i,j;
  
  	if (!sb) {
! 		printk("trying to get new block from nonexistent device\n");
  		return 0;
  	}
  repeat:
***************
*** 124,133 ****
  		return 0;
  	if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) {
  		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);
--- 124,129 ----
diff -c +recursive +new-files l99.4/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
*** l99.4/linux/fs/nfs/dir.c	Mon Jan 25 21:49:17 1993
--- linux/fs/nfs/dir.c	Sat Feb  6 11:13:17 1993
***************
*** 577,584 ****
  	error = nfs_proc_rename(NFS_SERVER(old_dir),
  		NFS_FH(old_dir), old_filename,
  		NFS_FH(new_dir), new_filename);
! 	if (!error)
  		nfs_lookup_cache_remove(old_dir, NULL, old_filename);
  	iput(old_dir);
  	iput(new_dir);
  	return error;
--- 577,586 ----
  	error = nfs_proc_rename(NFS_SERVER(old_dir),
  		NFS_FH(old_dir), old_filename,
  		NFS_FH(new_dir), new_filename);
! 	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 -c +recursive +new-files l99.4/linux/fs/nfs/file.c linux/fs/nfs/file.c
*** l99.4/linux/fs/nfs/file.c	Mon Jan 25 21:49:17 1993
--- linux/fs/nfs/file.c	Fri Jan 29 17:00:50 1993
***************
*** 58,63 ****
--- 58,64 ----
  	int n;
  	struct nfs_fattr fattr;
  	char *data;
+ 	off_t pos;
  
  	if (!inode) {
  		printk("nfs_file_read: inode = NULL\n");
***************
*** 68,75 ****
  			inode->i_mode);
  		return -EINVAL;
  	}
  	if (file->f_pos + count > inode->i_size)
! 		count = inode->i_size - file->f_pos;
  	if (count <= 0)
  		return 0;
  	n = NFS_SERVER(inode)->rsize;
--- 69,77 ----
  			inode->i_mode);
  		return -EINVAL;
  	}
+ 	pos = file->f_pos;
  	if (file->f_pos + count > inode->i_size)
! 		count = inode->i_size - pos;
  	if (count <= 0)
  		return 0;
  	n = NFS_SERVER(inode)->rsize;
***************
*** 79,91 ****
  		if (hunk > n)
  			hunk = n;
  		result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
! 			file->f_pos, hunk, data, &fattr);
  		if (result < 0) {
  			kfree_s(data, n);
  			return result;
  		}
  		memcpy_tofs(buf, data, result);
! 		file->f_pos += result;
  		buf += result;
  		if (result < n) {
  			i += result;
--- 81,93 ----
  		if (hunk > n)
  			hunk = n;
  		result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
! 			pos, hunk, data, &fattr);
  		if (result < 0) {
  			kfree_s(data, n);
  			return result;
  		}
  		memcpy_tofs(buf, data, result);
! 		pos += result;
  		buf += result;
  		if (result < n) {
  			i += result;
***************
*** 92,97 ****
--- 94,100 ----
  			break;
  		}
  	}
+ 	file->f_pos = pos;
  	kfree_s(data, n);
  	nfs_refresh_inode(inode, &fattr);
  	return i;
***************
*** 106,111 ****
--- 109,115 ----
  	int n;
  	struct nfs_fattr fattr;
  	char *data;
+ 	int pos;
  
  	if (!inode) {
  		printk("nfs_file_write: inode = NULL\n");
***************
*** 118,125 ****
  	}
  	if (count <= 0)
  		return 0;
  	if (file->f_flags & O_APPEND)
! 		file->f_pos = inode->i_size;
  	n = NFS_SERVER(inode)->wsize;
  	data = (char *) kmalloc(n, GFP_KERNEL);
  	for (i = 0; i < count; i += n) {
--- 122,130 ----
  	}
  	if (count <= 0)
  		return 0;
+ 	pos = file->f_pos;
  	if (file->f_flags & O_APPEND)
! 		pos = inode->i_size;
  	n = NFS_SERVER(inode)->wsize;
  	data = (char *) kmalloc(n, GFP_KERNEL);
  	for (i = 0; i < count; i += n) {
***************
*** 128,139 ****
  			hunk = n;
  		memcpy_fromfs(data, buf, hunk);
  		result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), 
! 			file->f_pos, hunk, data, &fattr);
  		if (result < 0) {
  			kfree_s(data, n);
  			return result;
  		}
! 		file->f_pos += hunk;
  		buf += hunk;
  		if (hunk < n) {
  			i += hunk;
--- 133,144 ----
  			hunk = n;
  		memcpy_fromfs(data, buf, hunk);
  		result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), 
! 			pos, hunk, data, &fattr);
  		if (result < 0) {
  			kfree_s(data, n);
  			return result;
  		}
! 		pos += hunk;
  		buf += hunk;
  		if (hunk < n) {
  			i += hunk;
***************
*** 140,145 ****
--- 145,151 ----
  			break;
  		}
  	}
+ 	file->f_pos = pos;
  	kfree_s(data, n);
  	nfs_refresh_inode(inode, &fattr);
  	return i;
diff -c +recursive +new-files l99.4/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
*** l99.4/linux/fs/nfs/inode.c	Mon Jan 25 21:49:17 1993
--- linux/fs/nfs/inode.c	Fri Jan 29 17:00:50 1993
***************
*** 20,26 ****
  
  extern int close_fp(struct file *filp);
  
! static int nfs_notify_change(struct inode *);
  static void nfs_put_super(struct super_block *);
  static void nfs_statfs(struct super_block *, struct statfs *);
  
--- 20,26 ----
  
  extern int close_fp(struct file *filp);
  
! 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,132 ****
  	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);
  		res.bsize = res.blocks = res.bfree = res.bavail = 0;
  	}
  	put_fs_long(res.bsize, &buf->f_bsize);
--- 125,131 ----
  	error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
  		&res);
  	if (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,200 ****
  	return inode;
  }
  
! int nfs_notify_change(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;
  	error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
  		&sattr, &fattr);
  	if (!error)
--- 180,215 ----
  	return inode;
  }
  
! int nfs_notify_change(int flags, struct inode *inode)
  {
  	struct nfs_sattr sattr;
  	struct nfs_fattr fattr;
  	int error;
  
! 	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 -c +recursive +new-files l99.4/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
*** l99.4/linux/fs/nfs/proc.c	Mon Jan 25 21:49:17 1993
--- linux/fs/nfs/proc.c	Sat Feb  6 11:13:18 1993
***************
*** 26,34 ****
  
  #include <netinet/in.h>
  
- static int proc_debug = 0;
- 
  #ifdef NFS_PROC_DEBUG
  #define PRINTK if (proc_debug) printk
  #else
  #define PRINTK if (0) printk
--- 26,33 ----
  
  #include <netinet/in.h>
  
  #ifdef NFS_PROC_DEBUG
+ static int proc_debug = 0;
  #define PRINTK if (proc_debug) printk
  #else
  #define PRINTK if (0) printk
***************
*** 70,80 ****
  	return p;
  }
  
! static inline int *xdr_decode_string(int *p, char *string)
  {
! 	int len;
  
  	len = ntohl(*p++);
  	memcpy(string, (char *) p, len);
  	string[len] = '\0';
  	p += (len + 3) >> 2;
--- 69,81 ----
  	return p;
  }
  
! static inline int *xdr_decode_string(int *p, char *string, int maxlen)
  {
! 	unsigned int len;
  
  	len = ntohl(*p++);
+ 	if (len > maxlen)
+ 		return NULL;
  	memcpy(string, (char *) p, len);
  	string[len] = '\0';
  	p += (len + 3) >> 2;
***************
*** 93,103 ****
  	return p;
  }
  
! static inline int *xdr_decode_data(int *p, char *data, int *lenp)
  {
! 	int len;
  
  	len = *lenp = ntohl(*p++);
  	memcpy(data, (char *) p, len);
  	data[len] = '\0';
  	p += (len + 3) >> 2;
--- 94,106 ----
  	return p;
  }
  
! static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
  {
! 	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,148 ****
  static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
  {
  	entry->fileid = ntohl(*p++);
! 	p = xdr_decode_string(p, entry->name);
  	entry->cookie = ntohl(*p++);
  	entry->eof = 0;
  	return p;
--- 145,152 ----
  static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
  {
  	entry->fileid = ntohl(*p++);
! 	if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN)))
! 		return NULL;
  	entry->cookie = ntohl(*p++);
  	entry->eof = 0;
  	return p;
***************
*** 178,183 ****
--- 182,189 ----
  		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,208 ****
--- 209,216 ----
  		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,238 ****
--- 241,248 ----
  		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,262 ****
  	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);
  	}
  	free_page((long) p0);
  	return -nfs_stat_to_errno(status);
  }
--- 264,278 ----
  	if (!(p = nfs_rpc_verify(p0)))
  		status = NFSERR_IO;
  	else if ((status = ntohl(*p++)) == NFS_OK) {
! 		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,291 ****
  		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);
  	}
  	free_page((long) p0);
  	return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
  }
--- 299,313 ----
  		status = NFSERR_IO;
  	else if ((status = ntohl(*p++)) == NFS_OK) {
  		p = xdr_decode_fattr(p, fattr);
! 		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,319 ****
--- 336,343 ----
  		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,347 ****
--- 366,373 ----
  		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,370 ****
--- 391,398 ----
  	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,397 ****
--- 420,427 ----
  	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,422 ****
--- 447,454 ----
  	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,448 ****
--- 475,482 ----
  	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,476 ****
--- 505,512 ----
  		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,499 ****
--- 530,537 ----
  	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,533 ****
  	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" : "");
  	}
  	free_page((long) p0);
  	return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
  }
--- 559,583 ----
  	if (!(p = nfs_rpc_verify(p0)))
  		status = NFSERR_IO;
  	else if ((status = ntohl(*p++)) == NFS_OK) {
! 		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,557 ****
--- 602,609 ----
  		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,621 ****
  
  static int *nfs_rpc_verify(int *p)
  {
! 	int n;
  
  	p++;
  	if ((n = ntohl(*p++)) != RPC_REPLY) {
  		printk("nfs_rpc_verify: not an RPC reply: %d\n", n);
! 		return 0;
  	}
  	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
  		printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
! 		return 0;
  	}
! 	if ((n = ntohl(*p++)) != RPC_AUTH_NULL && n != RPC_AUTH_UNIX) {
! 		printk("nfs_rpc_verify: bad RPC authentication type: %d\n",
! 			n);
! 		return 0;
  	}
- 	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 p;
  }
--- 647,678 ----
  
  static int *nfs_rpc_verify(int *p)
  {
! 	unsigned int n;
  
  	p++;
  	if ((n = ntohl(*p++)) != RPC_REPLY) {
  		printk("nfs_rpc_verify: not an RPC reply: %d\n", n);
! 		return NULL;
  	}
  	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
  		printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
! 		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++)) > 400) {
! 		printk("nfs_rpc_verify: giant auth size\n");
! 		return NULL;
  	}
  	p += (n + 3) >> 2;
  	if ((n = ntohl(*p++)) != RPC_SUCCESS) {
  		printk("nfs_rpc_verify: RPC call failed: %d\n", n);
! 		return NULL;
  	}
  	return p;
  }
diff -c +recursive +new-files l99.4/linux/fs/nfs/sock.c linux/fs/nfs/sock.c
*** l99.4/linux/fs/nfs/sock.c	Mon Jan 25 21:49:17 1993
--- linux/fs/nfs/sock.c	Fri Jan 29 17:00:50 1993
***************
*** 90,96 ****
  					goto re_select;
  #endif
  				current->timeout = 0;
! 				result = -EINTR;
  				break;
  			}
  			if (!current->timeout) {
--- 90,96 ----
  					goto re_select;
  #endif
  				current->timeout = 0;
! 				result = -ERESTARTSYS;
  				break;
  			}
  			if (!current->timeout) {
diff -c +recursive +new-files l99.4/linux/fs/open.c linux/fs/open.c
*** l99.4/linux/fs/open.c	Mon Jan 25 21:49:14 1993
--- linux/fs/open.c	Fri Jan 29 17:00:50 1993
***************
*** 89,95 ****
  		inode->i_op->truncate(inode);
  	inode->i_atime = inode->i_mtime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	error = notify_change(inode);
  	iput(inode);
  	return error;
  }
--- 89,95 ----
  		inode->i_op->truncate(inode);
  	inode->i_atime = inode->i_mtime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	error = notify_change(NOTIFY_SIZE, inode);
  	iput(inode);
  	return error;
  }
***************
*** 110,116 ****
  		inode->i_op->truncate(inode);
  	inode->i_atime = inode->i_mtime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	return notify_change(inode);
  }
  
  /* If times==NULL, set access and modification to current time,
--- 110,116 ----
  		inode->i_op->truncate(inode);
  	inode->i_atime = inode->i_mtime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	return notify_change(NOTIFY_SIZE, inode);
  }
  
  /* If times==NULL, set access and modification to current time,
***************
*** 149,155 ****
  	inode->i_mtime = modtime;
  	inode->i_ctime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	error = notify_change(inode);
  	iput(inode);
  	return error;
  }
--- 149,155 ----
  	inode->i_mtime = modtime;
  	inode->i_ctime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	error = notify_change(NOTIFY_TIME, inode);
  	iput(inode);
  	return error;
  }
***************
*** 247,253 ****
  		inode->i_mode &= ~S_ISGID;
  	inode->i_ctime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	return notify_change(inode);
  }
  
  int sys_chmod(const char * filename, mode_t mode)
--- 247,253 ----
  		inode->i_mode &= ~S_ISGID;
  	inode->i_ctime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	return notify_change(NOTIFY_MODE, inode);
  }
  
  int sys_chmod(const char * filename, mode_t mode)
***************
*** 271,277 ****
  		inode->i_mode &= ~S_ISGID;
  	inode->i_ctime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	error = notify_change(inode);
  	iput(inode);
  	return error;
  }
--- 271,277 ----
  		inode->i_mode &= ~S_ISGID;
  	inode->i_ctime = CURRENT_TIME;
  	inode->i_dirt = 1;
! 	error = notify_change(NOTIFY_MODE, inode);
  	iput(inode);
  	return error;
  }
***************
*** 298,304 ****
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
! 		return notify_change(inode);
  	}
  	return -EPERM;
  }
--- 298,304 ----
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
! 		return notify_change(NOTIFY_UIDGID, inode);
  	}
  	return -EPERM;
  }
***************
*** 326,332 ****
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
! 		error = notify_change(inode);
  		iput(inode);
  		return error;
  	}
--- 326,332 ----
  		inode->i_gid = group;
  		inode->i_ctime = CURRENT_TIME;
  		inode->i_dirt = 1;
! 		error = notify_change(NOTIFY_UIDGID, inode);
  		iput(inode);
  		return error;
  	}
***************
*** 380,386 ****
  		inode->i_size = 0;
  		if (inode->i_op && inode->i_op->truncate)
  			inode->i_op->truncate(inode);
! 		if ((i = notify_change(inode))) {
  			iput(inode);
  			current->filp[fd] = NULL;
  			f->f_count--;
--- 380,386 ----
  		inode->i_size = 0;
  		if (inode->i_op && inode->i_op->truncate)
  			inode->i_op->truncate(inode);
! 		if ((i = notify_change(NOTIFY_SIZE, inode))) {
  			iput(inode);
  			current->filp[fd] = NULL;
  			f->f_count--;
diff -c +recursive +new-files l99.4/linux/fs/proc/array.c linux/fs/proc/array.c
*** l99.4/linux/fs/proc/array.c	Mon Jan 25 21:49:56 1993
--- linux/fs/proc/array.c	Fri Jan 29 16:44:24 1993
***************
*** 43,49 ****
  
  static int get_uptime(char * buffer)
  {
! 	return sprintf(buffer,"%d\n",(jiffies+jiffies_offset)/HZ);
  }
  
  static int get_meminfo(char * buffer)
--- 43,58 ----
  
  static int get_uptime(char * buffer)
  {
! 	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,290 ****
  	char * page;
  	int length;
  	int end;
! 	int type, pid;
  
  	if (count < 0)
  		return -EINVAL;
--- 293,299 ----
  	char * page;
  	int length;
  	int end;
! 	unsigned int type, pid;
  
  	if (count < 0)
  		return -EINVAL;
diff -c +recursive +new-files l99.4/linux/fs/proc/base.c linux/fs/proc/base.c
*** l99.4/linux/fs/proc/base.c	Mon Jan 25 21:49:16 1993
--- linux/fs/proc/base.c	Mon Jan 25 11:16:28 1993
***************
*** 89,96 ****
  static int proc_lookupbase(struct inode * dir,const char * name, int len,
  	struct inode ** result)
  {
! 	unsigned int pid;
! 	int i, ino;
  
  	*result = NULL;
  	if (!dir)
--- 89,96 ----
  static int proc_lookupbase(struct inode * dir,const char * name, int len,
  	struct inode ** result)
  {
! 	unsigned int pid, ino;
! 	int i;
  
  	*result = NULL;
  	if (!dir)
diff -c +recursive +new-files l99.4/linux/include/linux/fs.h linux/include/linux/fs.h
*** l99.4/linux/include/linux/fs.h	Mon Jan 25 21:49:57 1993
--- linux/include/linux/fs.h	Fri Jan 29 17:00:50 1993
***************
*** 127,132 ****
--- 127,139 ----
  #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,281 ****
  
  struct super_operations {
  	void (*read_inode) (struct inode *);
! 	int (*notify_change) (struct inode *);
  	void (*write_inode) (struct inode *);
  	void (*put_inode) (struct inode *);
  	void (*put_super) (struct super_block *);
--- 282,288 ----
  
  struct super_operations {
  	void (*read_inode) (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,324 ****
  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 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);
--- 325,331 ----
  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(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 -c +recursive +new-files l99.4/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
*** l99.4/linux/include/linux/interrupt.h	Mon Jan 25 21:49:23 1993
--- linux/include/linux/interrupt.h	Mon Feb  1 20:22:21 1993
***************
*** 17,22 ****
--- 17,23 ----
  	TIMER_BH = 0,
  	CONSOLE_BH,
  	SERIAL_BH,
+ 	TTY_BH,
  	INET_BH,
  	KEYBOARD_BH
  };
diff -c +recursive +new-files l99.4/linux/include/linux/sched.h linux/include/linux/sched.h
*** l99.4/linux/include/linux/sched.h	Mon Jan 25 21:49:57 1993
--- linux/include/linux/sched.h	Mon Jan 25 20:53:07 1993
***************
*** 264,269 ****
--- 264,270 ----
  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 -c +recursive +new-files l99.4/linux/include/linux/serial.h linux/include/linux/serial.h
*** l99.4/linux/include/linux/serial.h	Mon Jan 25 21:49:23 1993
--- linux/include/linux/serial.h	Wed Feb  3 12:21:49 1993
***************
*** 20,27 ****
  	int			baud_base;
  	int			port;
  	int			irq;
! 	int			flags;
! 	int			type;
  	struct tty_struct 	*tty;
  	unsigned long 		timer;
  	int			timeout;
--- 20,27 ----
  	int			baud_base;
  	int			port;
  	int			irq;
! 	int			flags; 		/* defined in tty.h */
! 	int			type; 		/* UART type */
  	struct tty_struct 	*tty;
  	unsigned long 		timer;
  	int			timeout;
***************
*** 30,38 ****
  	int			x_char;	/* xon/xoff characater */
  	int			event;
  	int			line;
  	struct async_struct	*next_port; /* For the linked list */
  	struct async_struct	*prev_port;
- 	
  };
  
  /*
--- 30,40 ----
  	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,49 ****
--- 46,52 ----
  #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 -c +recursive +new-files l99.4/linux/include/linux/sock_ioctl.h linux/include/linux/sock_ioctl.h
*** l99.4/linux/include/linux/sock_ioctl.h	Mon Jan 25 21:49:23 1993
--- linux/include/linux/sock_ioctl.h	Mon Feb  1 22:42:56 1993
***************
*** 16,21 ****
     unsigned long paddr;
     unsigned long router;
     unsigned long net;
!    unsigned long up:1;
  };
  #endif
--- 16,40 ----
     unsigned long paddr;
     unsigned long router;
     unsigned long net;
!    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 -c +recursive +new-files l99.4/linux/include/linux/termios.h linux/include/linux/termios.h
*** l99.4/linux/include/linux/termios.h	Mon Jan 25 21:49:23 1993
--- linux/include/linux/termios.h	Mon Feb  1 20:22:21 1993
***************
*** 38,43 ****
--- 38,45 ----
  #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
***************
*** 224,228 ****
--- 226,235 ----
  #define	TCSANOW		0
  #define	TCSADRAIN	1
  #define	TCSAFLUSH	2
+ 
+ /* line disciplines */
+ #define N_TTY		0
+ #define N_SLIP		1
+ #define N_MOUSE		2
  
  #endif
diff -c +recursive +new-files l99.4/linux/include/linux/tty.h linux/include/linux/tty.h
*** l99.4/linux/include/linux/tty.h	Mon Jan 25 21:49:22 1993
--- linux/include/linux/tty.h	Sat Feb  6 11:06:38 1993
***************
*** 10,15 ****
--- 10,16 ----
  #include <asm/system.h>
  
  #define NR_CONSOLES	8
+ #define NR_LDISCS	16
  
  /*
   * These are set up by the setup-routine at boot-time:
***************
*** 104,110 ****
  #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 IS_A_CONSOLE(min)	(((min) & 0xC0) == 0x00)
  #define IS_A_SERIAL(min)	(((min) & 0xC0) == 0x40)
--- 105,113 ----
  #define ASYNC_FLAGS	0x0036	/* Possible legal async flags */
  
  /* Internal flags used only by kernel/chr_drv/serial.c */
! #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,193 ****
--- 191,197 ----
  	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,208 ****
--- 201,238 ----
  	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,262 ****
--- 286,294 ----
  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,287 ****
--- 314,320 ----
  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,295 ****
--- 323,329 ----
  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,306 ****
  /* serial.c */
  
  extern int  rs_open(struct tty_struct * tty, struct file * filp);
- extern void change_speed(unsigned int line);
  
  /* pty.c */
  
--- 334,339 ----
diff -c +recursive +new-files l99.4/linux/init/main.c linux/init/main.c
*** l99.4/linux/init/main.c	Mon Jan 25 21:49:17 1993
--- linux/init/main.c	Mon Feb  8 22:11:01 1993
***************
*** 249,254 ****
--- 249,271 ----
  	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,293 ****
--- 305,311 ----
  	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 -c +recursive +new-files l99.4/linux/kernel/FPU-emu/README linux/kernel/FPU-emu/README
*** l99.4/linux/kernel/FPU-emu/README	Mon Jan 25 21:49:18 1993
--- linux/kernel/FPU-emu/README	Sun Jan 31 12:50:32 1993
***************
*** 20,29 ****
   +---------------------------------------------------------------------------+
  
  
- ***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
  in turn based upon emu387 which was written by DJ Delorie for djgpp.
--- 20,26 ----
***************
*** 48,53 ****
--- 45,58 ----
  --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,90 ****
  ----------------------- 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
  more important differences are listed below:
  
  Internal computations do not use de-normal numbers (but External
--- 89,95 ----
  ----------------------- Limitations of wm-FPU-emu -----------------------
  
  There are a number of differences between the current wm-FPU-emu
! (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 -c +recursive +new-files l99.4/linux/kernel/FPU-emu/errors.c linux/kernel/FPU-emu/errors.c
*** l99.4/linux/kernel/FPU-emu/errors.c	Mon Jan 25 21:49:18 1993
--- linux/kernel/FPU-emu/errors.c	Sun Jan 31 12:50:32 1993
***************
*** 221,227 ****
  {
    int i, int_type;
  
!   int_type = 0;
    if ( n & EX_INTERNAL )
      {
        int_type = n - EX_INTERNAL;
--- 221,227 ----
  {
    int i, int_type;
  
!   int_type = 0;         /* Needed only to stop compiler warnings */
    if ( n & EX_INTERNAL )
      {
        int_type = n - EX_INTERNAL;
diff -c +recursive +new-files l99.4/linux/kernel/FPU-emu/fpu_entry.c linux/kernel/FPU-emu/fpu_entry.c
*** l99.4/linux/kernel/FPU-emu/fpu_entry.c	Mon Jan 25 21:49:18 1993
--- linux/kernel/FPU-emu/fpu_entry.c	Sun Jan 31 12:50:32 1993
***************
*** 37,42 ****
--- 37,49 ----
  
  #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,63 ****
--- 65,86 ----
    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,70 ****
--- 88,97 ----
  #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_,
***************
*** 75,80 ****
--- 102,122 ----
    _REGI_, _NONE_, _null_, _null_, _REGI_, _null_, _REGI_, _null_,
    _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...
diff -c +recursive +new-files l99.4/linux/kernel/FPU-emu/get_address.c linux/kernel/FPU-emu/get_address.c
*** l99.4/linux/kernel/FPU-emu/get_address.c	Mon Jan 25 21:49:18 1993
--- linux/kernel/FPU-emu/get_address.c	Sun Jan 31 12:50:32 1993
***************
*** 115,121 ****
  {
    unsigned char mod;
    long *cpu_reg_ptr;
!   int offset = 0;
    
    mod = (FPU_modrm >> 6) & 3;
  
--- 115,121 ----
  {
    unsigned char mod;
    long *cpu_reg_ptr;
!   int offset = 0;     /* Initialized just to stop compiler warnings. */
    
    mod = (FPU_modrm >> 6) & 3;
  
diff -c +recursive +new-files l99.4/linux/kernel/FPU-emu/load_store.c linux/kernel/FPU-emu/load_store.c
*** l99.4/linux/kernel/FPU-emu/load_store.c	Mon Jan 25 21:49:18 1993
--- linux/kernel/FPU-emu/load_store.c	Sun Jan 31 12:50:32 1993
***************
*** 48,54 ****
  {
    FPU_REG *pop_ptr;  /* We need a version of FPU_st0_ptr which won't change. */
  
!   pop_ptr = NULL;
    switch ( type_table[(int) (unsigned) type] )
      {
      case _NONE_:
--- 48,54 ----
  {
    FPU_REG *pop_ptr;  /* We need a version of FPU_st0_ptr which won't change. */
  
!   pop_ptr = NULL;    /* Initialized just to stop compiler warnings. */
    switch ( type_table[(int) (unsigned) type] )
      {
      case _NONE_:
diff -c +recursive +new-files l99.4/linux/kernel/FPU-emu/reg_div.S linux/kernel/FPU-emu/reg_div.S
*** l99.4/linux/kernel/FPU-emu/reg_div.S	Mon Jan 25 21:49:19 1993
--- linux/kernel/FPU-emu/reg_div.S	Sun Jan 31 12:50:33 1993
***************
*** 48,54 ****
  
  	movb	SIGN(%esi),%cl
  	cmpb	%cl,SIGN(%ebx)
! 	setneb	(%edi)		// Set the sign, requires neg=1, pos=0
  
  	add	$SIGL_OFFSET,%ebx
  	add	$SIGL_OFFSET,%esi
--- 48,54 ----
  
  	movb	SIGN(%esi),%cl
  	cmpb	%cl,SIGN(%ebx)
! 	setne	(%edi)	      // Set the sign, requires SIGN_NEG=1, SIGN_POS=0
  
  	add	$SIGL_OFFSET,%ebx
  	add	$SIGL_OFFSET,%esi
diff -c +recursive +new-files l99.4/linux/kernel/FPU-emu/version.h linux/kernel/FPU-emu/version.h
*** l99.4/linux/kernel/FPU-emu/version.h	Mon Jan 25 21:49:19 1993
--- linux/kernel/FPU-emu/version.h	Sun Jan 31 12:50:33 1993
***************
*** 8,12 ****
   |                                                                           |
   +---------------------------------------------------------------------------*/
  
! #define FPU_VERSION "wm-FPU-emu version ALPHA 0.8"
  
--- 8,12 ----
   |                                                                           |
   +---------------------------------------------------------------------------*/
  
! #define FPU_VERSION "wm-FPU-emu version BETA 1.0"
  
diff -c +recursive +new-files l99.4/linux/kernel/blk_drv/genhd.c linux/kernel/blk_drv/genhd.c
*** l99.4/linux/kernel/blk_drv/genhd.c	Mon Jan 25 21:49:20 1993
--- linux/kernel/blk_drv/genhd.c	Mon Feb  1 10:00:49 1993
***************
*** 46,55 ****
  	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);
  			return;
- 		}
  	  /*
  	   * This block is from a device that we're about to stomp on.
  	   * So make sure nobody thinks this block is usable.
--- 46,53 ----
  	while (1) {
  		if ((current_minor & mask) >= (4 + hd->max_p))
  			return;
! 		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,76 ****
  			    !(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);
  			current_minor++;
  			p++;
  		/*
--- 64,72 ----
  			    !(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(" %s%c%d", hd->major_name,
! 				'a'+(current_minor >> hd->minor_shift),
! 				mask & current_minor);
  			current_minor++;
  			p++;
  		/*
***************
*** 96,101 ****
--- 92,98 ----
  
  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;
***************
*** 102,114 ****
  	unsigned long first_sector;
  	int mask = (1 << hd->minor_shift) - 1;
  
  	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);
  		return;
  	}
! 	printk("%s%c :\n\r", 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;
--- 99,113 ----
  	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);
  		return;
  	}
! 	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,128 ****
  			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);
  			if ((current_minor & 0x3f) >= 60)
  				continue;
  			if (p->sys_ind == EXTENDED_PARTITION) {
  				extended_partition(hd, (hd->major << 8) | minor);
  			}
  		}
  		/*
--- 115,127 ----
  			if (!(hd->part[minor].nr_sects = p->nr_sects))
  				continue;
  			hd->part[minor].start_sect = first_sector + p->start_sect;
! 			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,153 ****
  					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);
  			}
  		}
  	} else
! 		printk("Bad partition table on dev %04x\n",dev);
  	brelse(bh);
  }
  
--- 137,150 ----
  					continue;
  				hd->part[current_minor].start_sect = p->start_sect;
  				hd->part[current_minor].nr_sects = p->nr_sects;
! 				printk(" %s%c%d", hd->major_name,
! 					'a'+(current_minor >> hd->minor_shift),
! 					current_minor & mask);
  			}
  		}
  	} else
! 		printk(" bad partition table");
! 	printk("\n");
  	brelse(bh);
  }
  
***************
*** 212,220 ****
  		nr += p->nr_real;
  	}
  		
- 	if (nr)
- 		printk("Partition table%s ok.\n\r",(nr>1)?"s":"");
- 
  	if (ramdisk_size)
  		rd_load();
  	mount_root();
--- 209,214 ----
diff -c +recursive +new-files l99.4/linux/kernel/blk_drv/hd.c linux/kernel/blk_drv/hd.c
*** l99.4/linux/kernel/blk_drv/hd.c	Mon Jan 25 21:49:20 1993
--- linux/kernel/blk_drv/hd.c	Sun Feb  7 21:36:29 1993
***************
*** 49,56 ****
  
  #define	HD_DELAY	0
  
! /* Max read/write errors/sector */
! #define MAX_ERRORS	7
  #define MAX_HD		2
  
  static void recal_intr(void);
--- 49,57 ----
  
  #define	HD_DELAY	0
  
! #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,67 ****
--- 63,69 ----
  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,122 ****
  	int i=inb_p(HD_STATUS);
  
  	if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
! 		== (READY_STAT | SEEK_STAT))
  		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);
  	}	
  	return 1;
  }
--- 113,126 ----
  	int i=inb_p(HD_STATUS);
  
  	if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
! 		== (READY_STAT | SEEK_STAT)) {
! 	        hd_error = 0;
  		return 0; /* ok */
+ 	}
  	printk("HD: win_result: status = 0x%02x\n",i);
  	if (i&1) {
! 		hd_error = inb(HD_ERROR);
! 		printk("HD: win_result: error = 0x%02x\n",hd_error);
  	}	
  	return 1;
  }
***************
*** 219,226 ****
  	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);
  }
  
  static void reset_hd(void)
--- 223,230 ----
  	outb(hd_info[0].ctl & 0x0f ,HD_CMD);
  	if (drive_busy())
  		printk("HD-controller still busy\n\r");
! 	if ((hd_error = inb(HD_ERROR)) != 1)
! 		printk("HD-controller reset failed: %02x\n\r",hd_error);
  }
  
  static void reset_hd(void)
***************
*** 259,277 ****
  	SET_TIMER;
  }
  
  static void bad_rw_intr(void)
  {
! 	int i;
  
  	if (!CURRENT)
  		return;
! 	if (++CURRENT->errors >= MAX_ERRORS)
  		end_request(0);
! 	else if (CURRENT->errors > MAX_ERRORS/2)
  		reset = 1;
! 	else
! 		for (i=0; i < NR_HD; i++)
! 			recalibrate[i] = 1;
  }
  
  static inline int wait_DRQ(void)
--- 263,288 ----
  	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 dev;
  
  	if (!CURRENT)
  		return;
! 	dev = MINOR(CURRENT->dev) >> 6;
! 	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
  		end_request(0);
! 		recalibrate[dev] = 1;
! 	} else if (CURRENT->errors % RESET_FREQ == 0)
  		reset = 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,309 ****
  	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);
  	}
  	bad_rw_intr();
  	cli();
--- 313,320 ----
  	sti();
  	printk("HD: read_intr: status = 0x%02x\n",i);
  	if (i & ERR_STAT) {
! 		hd_error = (unsigned) inb(HD_ERROR);
! 		printk("HD: read_intr: error = 0x%02x\n",hd_error);
  	}
  	bad_rw_intr();
  	cli();
***************
*** 351,358 ****
  	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);
  	}
  	bad_rw_intr();
  	cli();
--- 362,369 ----
  	sti();
  	printk("HD: write_intr: status = 0x%02x\n",i);
  	if (i & ERR_STAT) {
! 		hd_error = (unsigned) inb(HD_ERROR);
! 		printk("HD: write_intr: error = 0x%02x\n",hd_error);
  	}
  	bad_rw_intr();
  	cli();
diff -c +recursive +new-files l99.4/linux/kernel/blk_drv/scsi/scsi.c linux/kernel/blk_drv/scsi/scsi.c
*** l99.4/linux/kernel/blk_drv/scsi/scsi.c	Mon Jan 25 21:49:57 1993
--- linux/kernel/blk_drv/scsi/scsi.c	Mon Jan 25 19:52:33 1993
***************
*** 206,213 ****
  		      ((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))
  		      continue;
  		  }
  		  else
--- 206,213 ----
  		      ((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))
  		      continue;
  		  }
  		  else
diff -c +recursive +new-files l99.4/linux/kernel/blk_drv/scsi/wd7000.c linux/kernel/blk_drv/scsi/wd7000.c
*** l99.4/linux/kernel/blk_drv/scsi/wd7000.c	Mon Jan 25 21:49:22 1993
--- linux/kernel/blk_drv/scsi/wd7000.c	Wed Feb  3 12:25:28 1993
***************
*** 506,512 ****
  }
  
  
! static const char *wd_bases[] = {(char *)0xce000};
  typedef struct {
      char * signature;
      unsigned offset;
--- 506,529 ----
  }
  
  
! 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,610 ****
   *   this way, so I think it will work OK.
   */
  {
!   info[0] = 32;
!   info[1] = 64;
    info[2] = (size + 2047) >> 11;
    if (info[2] >= 1024) info[2] = 1024;
    return 0;
--- 620,627 ----
   *   this way, so I think it will work OK.
   */
  {
!   info[0] = 64;
!   info[1] = 32;
    info[2] = (size + 2047) >> 11;
    if (info[2] >= 1024) info[2] = 1024;
    return 0;
diff -c +recursive +new-files l99.4/linux/kernel/chr_drv/busmouse.c linux/kernel/chr_drv/busmouse.c
*** l99.4/linux/kernel/chr_drv/busmouse.c	Mon Jan 25 21:49:20 1993
--- linux/kernel/chr_drv/busmouse.c	Fri Jan 29 17:03:56 1993
***************
*** 48,59 ****
  	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);
  	MSE_INT_ON();
  }
  
--- 48,60 ----
  	buttons = inb(MSE_DATA_PORT);
  	dy |= (buttons & 0xf) << 4;
  	buttons = ((buttons >> 5) & 0x07);
! 	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,81 ****
  	mouse.ready = 0;
  	mouse.dx = 0;
  	mouse.dy = 0;
! 	mouse.buttons = mouse.latch_buttons = 0x80;
  	if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
  		mouse.active = 0;
  		return -EBUSY;
--- 76,82 ----
  	mouse.ready = 0;
  	mouse.dx = 0;
  	mouse.dy = 0;
! 	mouse.buttons = 0x87;
  	if (request_irq(MOUSE_IRQ, mouse_interrupt)) {
  		mouse.active = 0;
  		return -EBUSY;
***************
*** 99,105 ****
  	if (!mouse.ready)
  		return -EAGAIN;
  	MSE_INT_OFF();
! 	put_fs_byte(mouse.latch_buttons | 0x80, buffer);
  	if (mouse.dx < -127)
  		mouse.dx = -127;
  	if (mouse.dx > 127)
--- 100,106 ----
  	if (!mouse.ready)
  		return -EAGAIN;
  	MSE_INT_OFF();
! 	put_fs_byte(mouse.buttons | 0x80, buffer);
  	if (mouse.dx < -127)
  		mouse.dx = -127;
  	if (mouse.dx > 127)
***************
*** 114,120 ****
  		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;
--- 115,120 ----
***************
*** 159,165 ****
  	mouse.present = 1;
  	mouse.active = 0;
  	mouse.ready = 0;
! 	mouse.buttons = mouse.latch_buttons = 0x80;
  	mouse.dx = 0;
  	mouse.dy = 0;
  	mouse.wait = NULL;
--- 159,165 ----
  	mouse.present = 1;
  	mouse.active = 0;
  	mouse.ready = 0;
! 	mouse.buttons = 0x87;
  	mouse.dx = 0;
  	mouse.dy = 0;
  	mouse.wait = NULL;
diff -c +recursive +new-files l99.4/linux/kernel/chr_drv/console.c linux/kernel/chr_drv/console.c
*** l99.4/linux/kernel/chr_drv/console.c	Mon Jan 25 21:49:19 1993
--- linux/kernel/chr_drv/console.c	Wed Feb  3 13:28:55 1993
***************
*** 66,71 ****
--- 66,72 ----
  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,1245 ****
  long con_init(long kmem_start)
  {
  	char *display_desc = "????";
- 	char *display_ptr;
  	int currcons = 0;
  	long base;
  	int orig_x = ORIG_X;
--- 1240,1245 ----
***************
*** 1268,1274 ****
  		{
  			video_type = VIDEO_TYPE_EGAM;
  			video_mem_term = 0xb8000;
! 			display_desc = "EGAm";
  		}
  		else
  		{
--- 1268,1274 ----
  		{
  			video_type = VIDEO_TYPE_EGAM;
  			video_mem_term = 0xb8000;
! 			display_desc = "EGA+";
  		}
  		else
  		{
***************
*** 1287,1293 ****
  		{
  			video_type = VIDEO_TYPE_EGAC;
  			video_mem_term = 0xc0000;
! 			display_desc = "EGAc";
  		}
  		else
  		{
--- 1287,1293 ----
  		{
  			video_type = VIDEO_TYPE_EGAC;
  			video_mem_term = 0xc0000;
! 			display_desc = "EGA+";
  		}
  		else
  		{
***************
*** 1297,1311 ****
  		}
  	}
  	
- 	/* 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;
--- 1297,1302 ----
***************
*** 1337,1342 ****
--- 1328,1339 ----
  	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,1463 ****
  	int currcons = fg_console;
  	char c;
  
! 	if (currcons<0 || currcons>=NR_CONSOLES)
! 		currcons = 0;
  	while ((c = *(b++)) != 0) {
  		if (c == 10 || c == 13 || need_wrap) {
  			if (c != 13)
--- 1453,1460 ----
  	int currcons = fg_console;
  	char c;
  
! 	if (!printable || currcons<0 || currcons>=NR_CONSOLES)
! 		return;
  	while ((c = *(b++)) != 0) {
  		if (c == 10 || c == 13 || need_wrap) {
  			if (c != 13)
diff -c +recursive +new-files l99.4/linux/kernel/chr_drv/pty.c linux/kernel/chr_drv/pty.c
*** l99.4/linux/kernel/chr_drv/pty.c	Mon Jan 25 21:49:20 1993
--- linux/kernel/chr_drv/pty.c	Mon Feb  1 20:22:21 1993
***************
*** 16,28 ****
  #include <linux/sched.h>
  #include <linux/tty.h>
  #include <linux/fcntl.h>
  
  #include <asm/system.h>
! #include <asm/io.h>
  
  static void pty_close(struct tty_struct * tty, struct file * filp)
  {
! 	if (!tty)
  		return;
  	wake_up_interruptible(&tty->read_q.proc_list);
  	if (!tty->link)
--- 16,29 ----
  #include <linux/sched.h>
  #include <linux/tty.h>
  #include <linux/fcntl.h>
+ #include <linux/interrupt.h>
  
  #include <asm/system.h>
! #include <asm/bitops.h>
  
  static void pty_close(struct tty_struct * tty, struct file * filp)
  {
! 	if (!tty || (tty->count > 1))
  		return;
  	wake_up_interruptible(&tty->read_q.proc_list);
  	if (!tty->link)
***************
*** 50,55 ****
--- 51,60 ----
  	}
  	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 -c +recursive +new-files l99.4/linux/kernel/chr_drv/serial.c linux/kernel/chr_drv/serial.c
*** l99.4/linux/kernel/chr_drv/serial.c	Mon Jan 25 21:49:20 1993
--- linux/kernel/chr_drv/serial.c	Wed Feb  3 13:27:35 1993
***************
*** 15,21 ****
   *
   *	long rs_init(long);
   * 	int  rs_open(struct tty_struct * tty, struct file * filp)
-  * 	void change_speed(unsigned int line)
   */
  
  #include <linux/errno.h>
--- 15,20 ----
***************
*** 24,30 ****
--- 23,32 ----
  #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,66 ****
   *		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)
  
  /*
--- 49,56 ----
***************
*** 70,80 ****
   * 				transmitting (and therefore have a
   * 				write timeout pending, in case the
   * 				THRE interrupt gets lost.)
   */
! static volatile unsigned long rs_event = 0;
! static unsigned long rs_write_active = 0;
! 
! static int doing_softint = 0;
  
  static struct async_struct *IRQ_ports[16];
  
--- 60,71 ----
   * 				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 int rs_event[2];
! static int rs_write_active[2];
  
  static struct async_struct *IRQ_ports[16];
  
***************
*** 149,163 ****
   */
  static int baud_table[] = {
  	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
! 	9600, 19200, 38400, 56700, 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 inline unsigned int serial_in(struct async_struct *info, int offset)
  {
--- 140,153 ----
   */
  static int baud_table[] = {
  	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
! 	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);
! 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,206 ****
  				  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
  }
  
  
--- 185,192 ----
  				  int event)
  {
  	info->event |= 1 << event;
! 	set_bit(info->line, rs_event);
! 	mark_bh(SERIAL_BH);
  }
  
  
***************
*** 305,320 ****
  				}
  			}
  			queue->tail = tail;
! 			if (VLEFT > WAKEUP_CHARS)
  				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
  			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
  			timer_active |= 1 << RS_TIMER;
  #ifdef SERIAL_INT_DEBUG
  			printk("THRE...");
--- 291,308 ----
  				}
  			}
  			queue->tail = tail;
! 			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;
! 			set_bit(info->line, rs_write_active);
  			timer_active |= 1 << RS_TIMER;
  #ifdef SERIAL_INT_DEBUG
  			printk("THRE...");
***************
*** 324,331 ****
  		status = serial_in(info, UART_MSR);
  		
  		if (!(CFLAG & CLOCAL) && (status & UART_MSR_DDCD)) {
! 			if (!(status & UART_MSR_DCD))
  				rs_sched_event(info, RS_EVENT_HUP_PGRP);
  		}
  		if (CFLAG & CRTSCTS) {
  			if (info->tty->stopped) {
--- 312,328 ----
  		status = serial_in(info, UART_MSR);
  		
  		if (!(CFLAG & CLOCAL) && (status & UART_MSR_DDCD)) {
! 			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,358 ****
  			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
--- 343,348 ----
***************
*** 371,454 ****
  }
  #endif
  
- #ifdef SOFT_IRQ
  static void do_softint()
  {
! 	unsigned long		mask;
  	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.. */
  				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);
  			}
--- 361,375 ----
  }
  #endif
  
  static void do_softint()
  {
! 	int			i;
  	struct async_struct	*info;
  	
! 	for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
! 		if (!clear_bit(i, rs_event)) {
! 			if (!info->tty)	
  				continue;
  			if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
  				TTY_READ_FLUSH(info->tty);
  			}
***************
*** 461,505 ****
  				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);
  			}
! 			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 ((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
  	}
  }
  
--- 382,414 ----
  				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);
  			}
! 			if (!clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) {
! 				wake_up_interruptible(&info->open_wait);
  			}
  		}
  	}
! }
! 
! /*
!  * 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,640 ****
  	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);
  #endif
  	info->event = 0;
! 	info->tty = 0;
! 	if (info->flags & ASYNC_NO_IRQ)
! 		info->flags &= ~ASYNC_NO_IRQ;
! 	else {
  		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);
  	}
  }
  
  static void startup(struct async_struct * info)
  {
  	unsigned short ICP;
  
  	/*
  	 * First, clear the FIFO buffers and disable them
  	 */
--- 508,558 ----
  	line = DEV_TO_SL(tty->line);
  	if ((line < 0) || (line >= NR_PORTS))
  		return;
  	info = rs_table + line;
! #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->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 (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,696 ****
--- 605,622 ----
  	(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,707 ****
  		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 */
  }
  
! void change_speed(unsigned int line)
  {
  	struct async_struct * info;
  	unsigned short port;
--- 625,637 ----
  		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));
  }
  
! static void change_speed(unsigned int line)
  {
  	struct async_struct * info;
  	unsigned short port;
***************
*** 781,872 ****
  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;
  	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));
  
  	old_info = *info;
! 	info->baud_base = tmp.baud_base;
! 	info->flags = tmp.flags & ASYNC_FLAGS;
! 	info->custom_divisor = tmp.custom_divisor;
! 
! 	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;
  		return -EINVAL;
  	}
! 	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]) {
  			sa.sa_handler = rs_interrupt;
  			sa.sa_flags = (SA_INTERRUPT);
  			sa.sa_mask = 0;
  			sa.sa_restorer = NULL;
! 			retval = irqaction(new_irq,&sa);
  			if (retval) {
  				*info = old_info;
  				return retval;
  			}
  		}
  
  		/*
! 		 * If the new IRQ is OK, now we unlink the async structure from
! 		 * the existing interrupt chain.
  		 */
! 		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);
! 
  		/*
! 		 * Now link in the interrupt to the new interrupt chain.
  		 */
  		info->prev_port = 0;
! 		info->next_port = IRQ_ports[new_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;
  		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))
  		change_speed(info->line);
  	return 0;
  }
  
--- 711,814 ----
  static int set_serial_info(struct async_struct * info,
  			   struct serial_struct * new_info)
  {
! 	struct serial_struct new;
! 	unsigned int		irq,check_irq;
  	int 			retval;
  	struct 			sigaction sa;
  	struct async_struct	old_info;
  
  	if (!new_info)
  		return -EFAULT;
! 	memcpy_fromfs(&new,new_info,sizeof(new));
  
+ 	check_irq = 0;
  	old_info = *info;
! 	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 ((new.irq > 15) || (new.port > 0xffff) ||
! 	    (new.type < PORT_UNKNOWN) || (new.type > PORT_MAX)) {
  		return -EINVAL;
  	}
! 	
! 	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 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);
  			if (retval) {
  				*info = old_info;
  				return retval;
  			}
  		}
+ 	}
  
+ 	if ((new.irq != irq) ||
+ 	    (new.port != info->port)) {
  		/*
! 		 * We need to shutdown the serial port at the old
! 		 * port/irq combination.
  		 */
! 		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)) {
  		/*
! 		 * Link the port into the new interrupt chain.
  		 */
  		info->prev_port = 0;
! 		info->next_port = IRQ_ports[info->irq];
  		if (info->next_port)
  			info->next_port->prev_port = info;
! 		IRQ_ports[info->irq] = info;
  		startup(info);
  		change_speed(info->line);
! 	} 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,962 ****
  		return -EINVAL;
  	}
  	return 0;
! }	
  
  /*
   * This routine is called whenever a serial port is opened.  It
--- 898,922 ----
  		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,1029 ****
  	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;
  #endif
! 	} else
! 		info->flags &= ~ASYNC_NO_IRQ;
  	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;
  	}
  	/*
! 	 * 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);
  	return 0;
! }
  
  static void show_serial_version()
  {
! 	printk("Serial driver version 3.8 with");
  #ifdef CONFIG_AST_FOURPORT
  	printk(" AST_FOURPORT");
  #define SERIAL_OPT
--- 930,1069 ----
  	int 			irq, retval, line;
  	struct sigaction	sa;
  
  	line = DEV_TO_SL(tty->line);
  	if ((line < 0) || (line >= NR_PORTS))
  		return -ENODEV;
  	info = rs_table + line;
! #ifdef SERIAL_DEBUG_OPEN
! 	printk("rs_open ttys%d, count = %d\n", info->line, info->count);
  #endif
! 	info->count++;
  	info->tty = tty;
+ 	
  	tty->write = rs_write;
  	tty->close = rs_close;
  	tty->ioctl = rs_ioctl;
  	tty->throttle = rs_throttle;
! 	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;
  	}
+ 	
+ 	/*
+ 	 * If non-blocking mode is set, then make the check up front
+ 	 * and then exit.
+ 	 */
+ 	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.91 with");
  #ifdef CONFIG_AST_FOURPORT
  	printk(" AST_FOURPORT");
  #define SERIAL_OPT
***************
*** 1044,1063 ****
  #undef SERIAL_OPT
  }
  
- 
- static void init(struct async_struct * info)
- {
  #ifdef CONFIG_AUTO_IRQ
! 	unsigned char status1, status2, scratch, 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);
  	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 */
--- 1084,1102 ----
  #undef SERIAL_OPT
  }
  
  #ifdef CONFIG_AUTO_IRQ
! 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;
! 	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 */
***************
*** 1064,1070 ****
  		ICP = (port & 0xFE0) | 0x01F;
  		save_ICP = inb_p(ICP);
  		outb_p(0x80, ICP);
! 		(void) inb(ICP);
  	} else {
  		serial_outp(info, UART_MCR,
  			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
--- 1103,1109 ----
  		ICP = (port & 0xFE0) | 0x01F;
  		save_ICP = inb_p(ICP);
  		outb_p(0x80, ICP);
! 		(void) inb_p(ICP);
  	} else {
  		serial_outp(info, UART_MCR,
  			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
***************
*** 1086,1106 ****
  	/*
  	 * 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);
  		info->type = PORT_UNKNOWN;
  		return;
  	}
  #else /* CONFIG_AUTO_IRQ */
- 	unsigned char status1, status2, scratch, scratch2;
- 	unsigned short port = info->port;
  
  	/* 
  	 * Check to see if a UART is really there.  
  	 */
--- 1125,1173 ----
  	/*
  	 * Now check to see if we got any business, and clean up.
  	 */
! 	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 */
  
+ 	if (!port)
+ 		return;
+ 			
  	/* 
  	 * Check to see if a UART is really there.  
  	 */
***************
*** 1193,1200 ****
  #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;
--- 1260,1265 ----
***************
*** 1202,1213 ****
  		info->custom_divisor = 0;
  		info->x_char = 0;
  		info->event = 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, 
  		       (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
  		       info->port, info->irq);
  		switch (info->type) {
--- 1267,1281 ----
  		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, 
  		       (info->flags & ASYNC_FOURPORT) ? " FourPort" : "",
  		       info->port, info->irq);
  		switch (info->type) {
***************
*** 1239,1244 ****
--- 1307,1315 ----
  			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 -c +recursive +new-files l99.4/linux/kernel/chr_drv/tty_io.c linux/kernel/chr_drv/tty_io.c
*** l99.4/linux/kernel/chr_drv/tty_io.c	Mon Jan 25 21:49:57 1993
--- linux/kernel/chr_drv/tty_io.c	Sat Feb  6 11:51:55 1993
***************
*** 20,25 ****
--- 20,33 ----
   * 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,49 ****
  
  #include "vt_kern.h"
  
! struct tty_struct *tty_table[256];
! struct termios *tty_termios[256]; /* We need to keep the termios state */
  				  /* around, even when a tty is closed */
  
  /*
   * fg_console is the current virtual console,
--- 49,61 ----
  
  #include "vt_kern.h"
  
! #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,68 ****
--- 75,94 ----
  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,96 ****
--- 117,149 ----
  	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,114 ****
  		return;
  	if (set_bit(TTY_READ_BUSY, &tty->flags))
  		return;
! 	copy_to_cooked(tty);
  	if (clear_bit(TTY_READ_BUSY, &tty->flags))
  		printk("tty_read_flush: bit already cleared\n");
  }
--- 161,167 ----
  		return;
  	if (set_bit(TTY_READ_BUSY, &tty->flags))
  		return;
! 	ldiscs[tty->disc].handler(tty);
  	if (clear_bit(TTY_READ_BUSY, &tty->flags))
  		printk("tty_read_flush: bit already cleared\n");
  }
***************
*** 182,187 ****
--- 235,245 ----
  		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,370 ****
  
  void wait_for_keypress(void)
  {
! 	interruptible_sleep_on(&keypress_wait);
  }
  
  void copy_to_cooked(struct tty_struct * tty)
--- 422,428 ----
  
  void wait_for_keypress(void)
  {
! 	sleep_on(&keypress_wait);
  }
  
  void copy_to_cooked(struct tty_struct * tty)
***************
*** 754,760 ****
  
  	dev = file->f_rdev;
  	if (MAJOR(dev) != 4) {
! 		printk("tty_read: pseudo-major != 4\n");
  		return -EINVAL;
  	}
  	dev = MINOR(dev);
--- 812,818 ----
  
  	dev = file->f_rdev;
  	if (MAJOR(dev) != 4) {
! 		printk("tty_read: bad pseudo-major nr #%d\n", MAJOR(dev));
  		return -EINVAL;
  	}
  	dev = MINOR(dev);
***************
*** 770,776 ****
  			(void) kill_pg(current->pgrp, SIGTTIN, 1);
  			return -ERESTARTSYS;
  		}
! 	i = read_chan(tty,file,buf,count);
  	if (i > 0)
  		inode->i_atime = CURRENT_TIME;
  	return i;
--- 828,837 ----
  			(void) kill_pg(current->pgrp, SIGTTIN, 1);
  			return -ERESTARTSYS;
  		}
! 	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,809 ****
  			return -ERESTARTSYS;
  		}
  	}
! 	i = write_chan(tty,file,buf,count);
  	if (i > 0)
  		inode->i_mtime = CURRENT_TIME;
  	return i;
--- 864,873 ----
  			return -ERESTARTSYS;
  		}
  	}
! 	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,942 ****
  			return;
  		}
  	}
! 	if (tty->count < 2 && tty->close)
  		tty->close(tty, filp);
  	if (IS_A_PTY_MASTER(dev)) {
  		if (--tty->link->count < 0) {
--- 1000,1007 ----
  			return;
  		}
  	}
! 	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,957 ****
--- 1017,1026 ----
  	}
  	if (tty->count)
  		return;
+ 
+ 	if (ldiscs[tty->disc].close != NULL)
+ 		ldiscs[tty->disc].close(tty);
+ 
  	if (o_tty) {
  		if (o_tty->count)
  			return;
***************
*** 981,986 ****
--- 1050,1056 ----
   *
   * 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,1010 ****
  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)
  		return -ENXIO;
! 	if (!dev)
! 		dev = fg_console + 1;
! 	filp->f_rdev = 0x0400 | dev;
! 	retval = init_dev(dev);
  	if (retval)
  		return retval;
! 	tty = tty_table[dev];
  	/* clean up the packet stuff. */
  	tty->status_changed = 0;
  	tty->ctrl_status = 0;
  	tty->packet = 0;
--- 1058,1101 ----
  static int tty_open(struct inode * inode, struct file * filp)
  {
  	struct tty_struct *tty;
! 	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 (IS_A_PTY_MASTER(minor))
! 		noctty = 1;
! 	filp->f_rdev = (major << 8) | minor;
! 	retval = init_dev(minor);
  	if (retval)
  		return retval;
! 	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,1031 ****
  		retval = -ENODEV;
  	}
  	if (retval) {
! 		release_dev(dev, filp);
  		return retval;
  	}
! 	if (!(filp->f_flags & O_NOCTTY) &&
  	    current->leader &&
  	    current->tty<0 &&
  	    tty->session==0) {
! 		current->tty = dev;
  		tty->session = current->session;
  		tty->pgrp = current->pgrp;
  	}
  	return 0;
  }
  
--- 1106,1123 ----
  		retval = -ENODEV;
  	}
  	if (retval) {
! 		release_dev(minor, filp);
  		return retval;
  	}
! 	if (!noctty &&
  	    current->leader &&
  	    current->tty<0 &&
  	    tty->session==0) {
! 		current->tty = minor;
  		tty->session = current->session;
  		tty->pgrp = current->pgrp;
  	}
+ 	filp->f_rdev = 0x0400 | minor; /* Set it to something normal */
  	return 0;
  }
  
***************
*** 1139,1144 ****
--- 1231,1334 ----
  }
  
  /*
+  * 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,1151 ****
--- 1336,1342 ----
  {
  	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,1177 ****
  		tp->c_lflag = ISIG | ICANON | ECHO |
  			ECHOCTL | ECHOKE;
  	} else if (IS_A_SERIAL(line)) {
! 		tp->c_cflag = B2400 | CS8 | CREAD | HUPCL;
  	} else if (IS_A_PTY_MASTER(line)) {
  		tp->c_cflag = B9600 | CS8 | CREAD;
  	} else if (IS_A_PTY_SLAVE(line)) {
--- 1362,1368 ----
  		tp->c_lflag = ISIG | ICANON | ECHO |
  			ECHOCTL | ECHOKE;
  	} else if (IS_A_SERIAL(line)) {
! 		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,1201 ****
  			ECHOCTL | ECHOKE;
  	}
  }
  	
  long tty_init(long kmem_start)
  {
  	int i;
  
  	chrdev_fops[4] = &tty_fops;
  	chrdev_fops[5] = &tty_fops;
! 	for (i=0 ; i<256 ; i++) {
  		tty_table[i] =  0;
  		tty_termios[i] = 0;
  	}
  	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;
  }
--- 1373,1412 ----
  			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< 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);
  	return kmem_start;
  }
diff -c +recursive +new-files l99.4/linux/kernel/chr_drv/tty_ioctl.c linux/kernel/chr_drv/tty_ioctl.c
*** l99.4/linux/kernel/chr_drv/tty_ioctl.c	Mon Jan 25 21:49:19 1993
--- linux/kernel/chr_drv/tty_ioctl.c	Sat Feb  6 11:10:49 1993
***************
*** 2,7 ****
--- 2,11 ----
   *  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,21 ****
--- 20,32 ----
  #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,146 ****
  	return 0;
  }
  
  static int set_termios(struct tty_struct * tty, struct termios * termios,
  			int channel)
  {
  	int i;
! 	unsigned short old_cflag = tty->termios->c_cflag;
  
! 	/* 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;
! 		}
! 	}
  	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
--- 130,163 ----
  	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;
! 	struct termios old_termios = *tty->termios;
  
! 	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);
  
  	/* puting mpty's into echo mode is very bad, and I think under
  	   some situations can cause the kernel to do nothing but
***************
*** 147,152 ****
--- 164,172 ----
  	   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,193 ****
  {
  	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;
! 		}
! 	}
  	for (i=0 ; i< (sizeof (*termio)) ; i++)
  		((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
  
--- 196,206 ----
  {
  	int i;
  	struct termio tmp_termio;
! 	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,220 ****
  	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);
  	return 0;
  }
  
--- 226,235 ----
  	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 (tty->set_termios)
! 		(*tty->set_termios)(tty, &old_termios);
! 
  	return 0;
  }
  
***************
*** 253,258 ****
--- 268,298 ----
  	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,267 ****
--- 302,308 ----
  	int pgrp;
  	int dev;
  	int termios_dev;
+ 	int retval;
  
  	if (MAJOR(file->f_rdev) != 4) {
  		printk("tty_ioctl: tty pseudo-major != 4\n");
***************
*** 434,440 ****
  				tty->session = 0;
  			}
  			return 0;
! 
  	       case TIOCPKT:
  			{
  			   int on;
--- 475,487 ----
  				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,458 ****
  			}
  
  		default:
! 			if (tty->ioctl)
! 				return (tty->ioctl)(tty, file, cmd, arg);
! 			else
! 				return -EINVAL;
  	}
  }
--- 497,512 ----
  			}
  
  		default:
! 			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 -c +recursive +new-files l99.4/linux/kernel/fork.c linux/kernel/fork.c
*** l99.4/linux/kernel/fork.c	Mon Jan 25 21:49:17 1993
--- linux/kernel/fork.c	Mon Feb  8 23:29:07 1993
***************
*** 20,26 ****
  #include <asm/segment.h>
  #include <asm/system.h>
  
! #define MAX_TASKS_PER_USER ((NR_TASKS/4)*3)
  
  long last_pid=0;
  
--- 20,26 ----
  #include <asm/segment.h>
  #include <asm/system.h>
  
! #define MAX_TASKS_PER_USER (NR_TASKS/2)
  
  long last_pid=0;
  
***************
*** 41,51 ****
  static int find_empty_process(void)
  {
  	int i, task_nr;
! 	int this_user_tasks = 0;
  
  repeat:
! 	if ((++last_pid) & 0xffff0000)
  		last_pid=1;
  	for(i=0 ; i < NR_TASKS ; i++) {
  		if (!task[i])
  			continue;
--- 41,52 ----
  static int find_empty_process(void)
  {
  	int i, task_nr;
! 	int this_user_tasks;
  
  repeat:
! 	if ((++last_pid) & 0xffff8000)
  		last_pid=1;
+ 	this_user_tasks = 0;
  	for(i=0 ; i < NR_TASKS ; i++) {
  		if (!task[i])
  			continue;
diff -c +recursive +new-files l99.4/linux/kernel/irq.c linux/kernel/irq.c
*** l99.4/linux/kernel/irq.c	Mon Jan 25 21:49:22 1993
--- linux/kernel/irq.c	Mon Jan 25 21:00:43 1993
***************
*** 239,246 ****
  	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
--- 239,244 ----
***************
*** 251,262 ****
  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.. */
  }
  
  static void no_action(int cpl) { }
--- 249,258 ----
  static void math_error_irq(int cpl)
  {
  	outb(0,0xF0);
! 	if (ignore_irq13)
! 		return;
! 	send_sig(SIGFPE, last_task_used_math, 1);
! 	__asm__("fninit");
  }
  
  static void no_action(int cpl) { }
***************
*** 271,288 ****
  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)
  		printk("Unable to get IRQ13 for math-error handler\n");
  
  	/* intialize the bottom half routines. */
--- 267,278 ----
  void init_IRQ(void)
  {
  	int i;
  
  	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");
! 	if (request_irq(13,math_error_irq))
  		printk("Unable to get IRQ13 for math-error handler\n");
  
  	/* intialize the bottom half routines. */
diff -c +recursive +new-files l99.4/linux/kernel/sched.c linux/kernel/sched.c
*** l99.4/linux/kernel/sched.c	Mon Jan 25 21:49:17 1993
--- linux/kernel/sched.c	Sat Feb  6 13:48:53 1993
***************
*** 30,35 ****
--- 30,36 ----
  
  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,324 ****
--- 317,327 ----
  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,349 ****
  			p->next->jiffies = jiffies;
  			p = p->next;
  		}
  	}
! 	sti();
  }
  
  unsigned long timer_active = 0;
--- 345,354 ----
  			p->next->jiffies = jiffies;
  			p = p->next;
  		}
+ 		if (p->next)
+ 			p->next->jiffies -= p->jiffies;
  	}
! 	restore_flags(flags);
  }
  
  unsigned long timer_active = 0;
diff -c +recursive +new-files l99.4/linux/kernel/sys.c linux/kernel/sys.c
*** l99.4/linux/kernel/sys.c	Mon Jan 25 21:49:18 1993
--- linux/kernel/sys.c	Sun Feb  7 16:50:11 1993
***************
*** 414,420 ****
--- 414,426 ----
  
  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,666 ****
  int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
  {
  	if (tv) {
  		verify_area(tv, sizeof *tv);
! 		put_fs_long(startup_time + CT_TO_SECS(jiffies+jiffies_offset),
  			    (unsigned long *) tv);
! 		put_fs_long(CT_TO_USECS(jiffies+jiffies_offset), 
  			    ((unsigned long *) tv)+1);
  	}
  	if (tz) {
--- 663,673 ----
  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(nowtime),
  			    (unsigned long *) tv);
! 		put_fs_long(CT_TO_USECS(nowtime), 
  			    ((unsigned long *) tv)+1);
  	}
  	if (tz) {
diff -c +recursive +new-files l99.4/linux/kernel/traps.c linux/kernel/traps.c
*** l99.4/linux/kernel/traps.c	Mon Jan 25 21:49:17 1993
--- linux/kernel/traps.c	Mon Jan 25 21:00:43 1993
***************
*** 168,173 ****
--- 168,174 ----
  
  void do_coprocessor_error(long esp, long error_code)
  {
+ 	ignore_irq13 = 1;
  	send_sig(SIGFPE, last_task_used_math, 1);
  	__asm__("fninit");
  }
diff -c +recursive +new-files l99.4/linux/mm/memory.c linux/mm/memory.c
*** l99.4/linux/mm/memory.c	Mon Jan 25 21:49:58 1993
--- linux/mm/memory.c	Mon Feb  8 16:53:14 1993
***************
*** 263,273 ****
  		}
  		for (pc = pcnt; pc--; page_table++) {
  			if ((page = *page_table) != 0) {
- 				--current->rss;
  				*page_table = 0;
! 				if (1 & page)
  					free_page(0xfffff000 & page);
! 				else
  					swap_free(page >> 1);
  			}
  		}
--- 263,273 ----
  		}
  		for (pc = pcnt; pc--; page_table++) {
  			if ((page = *page_table) != 0) {
  				*page_table = 0;
! 				if (1 & page) {
! 					--current->rss;
  					free_page(0xfffff000 & page);
! 				} else
  					swap_free(page >> 1);
  			}
  		}
***************
*** 394,408 ****
  		return 0;
  	}
  	page_table = (unsigned long *) (tsk->tss.cr3 + ((address>>20) & 0xffc));
! 	if ((*page_table)&1)
  		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;
  		return 0;
  	}
  	page_table += (address >> PAGE_SHIFT) & 0x3ff;
--- 394,405 ----
  		return 0;
  	}
  	page_table = (unsigned long *) (tsk->tss.cr3 + ((address>>20) & 0xffc));
! 	if ((*page_table) & PAGE_PRESENT)
  		page_table = (unsigned long *) (0xfffff000 & *page_table);
  	else {
! 		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,776 ****
--- 768,774 ----
  {
  	unsigned long address;
  	unsigned long user_esp = 0;
+ 	unsigned long stack_limit;
  	unsigned int bit;
  	extern void die_if_kernel();
  
***************
*** 789,794 ****
--- 787,802 ----
  			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 -c +recursive +new-files l99.4/linux/net/kern_sock.h linux/net/kern_sock.h
*** l99.4/linux/net/kern_sock.h	Mon Jan 25 21:49:24 1993
--- linux/net/kern_sock.h	Fri Jan 29 16:24:34 1993
***************
*** 37,42 ****
--- 37,46 ----
  	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,75 ****
  	int (*getsockopt)(struct socket *sock, int level, int optname,
  			  char *optval, int *optlen);
  	int (*fcntl) (struct socket *sock, unsigned int cmd,
! 		      unsigned long arg);
  };
  
  extern int sock_awaitconn(struct socket *mysock, struct socket *servsock);
--- 73,79 ----
  	int (*getsockopt)(struct socket *sock, int level, int optname,
  			  char *optval, int *optlen);
  	int (*fcntl) (struct socket *sock, unsigned int cmd,
! 		      unsigned long arg);	
  };
  
  extern int sock_awaitconn(struct socket *mysock, struct socket *servsock);
diff -c +recursive +new-files l99.4/linux/net/socket.c linux/net/socket.c
*** l99.4/linux/net/socket.c	Mon Jan 25 21:49:24 1993
--- linux/net/socket.c	Mon Feb  1 10:06:17 1993
***************
*** 70,79 ****
  	sock_close
  };
  
! #define SOCK_INODE(S) ((struct inode *)(S)->dummy)
! 
! static struct socket sockets[NSOCKETS];
! #define last_socket (sockets + NSOCKETS - 1)
  static struct wait_queue *socket_wait_free = NULL;
  
  /*
--- 70,76 ----
  	sock_close
  };
  
! struct socket sockets[NSOCKETS];
  static struct wait_queue *socket_wait_free = NULL;
  
  /*
***************
*** 177,184 ****
  					return NULL;
  				}
  				SOCK_INODE(sock)->i_mode = S_IFSOCK;
  				sock->wait = &SOCK_INODE(sock)->i_wait;
! 				PRINTK(("sock_alloc: socket 0x%x, inode 0x%x\n",
  				       sock, SOCK_INODE(sock)));
  				return sock;
  			}
--- 174,184 ----
  					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",
  				       sock, SOCK_INODE(sock)));
  				return sock;
  			}
***************
*** 951,961 ****
  	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);
  			proto_table[i].family = -1;
  		}
  		else
--- 951,960 ----
  	for (sock = sockets; sock <= last_socket; ++sock)
  		sock->state = SS_FREE;
  	for (i = ok = 0; i < NPROTO; ++i) {
  		if ((*proto_table[i].ops->init)() < 0) {
! 			printk("sock_init: init failed family %d (%s)\n",
! 			       proto_table[i].family,
! 			       proto_table[i].name);
  			proto_table[i].family = -1;
  		}
  		else
diff -c +recursive +new-files l99.4/linux/net/tcp/Space.c linux/net/tcp/Space.c
*** l99.4/linux/net/tcp/Space.c	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/Space.c	Mon Jan 25 19:26:54 1993
***************
*** 1,8 ****
  /* Space.c */
  
  /* Holds initial configuration information for devices. */
! /* $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ */
  /* $Log: Space.c,v $
   * Revision 0.8.4.5  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 1,14 ----
  /* Space.c */
  
  /* Holds initial configuration information for devices. */
! /* $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 -c +recursive +new-files l99.4/linux/net/tcp/arp.c linux/net/tcp/arp.c
*** l99.4/linux/net/tcp/arp.c	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/arp.c	Mon Jan 25 19:26:54 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: arp.c,v $
   * Revision 0.8.4.5  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,32 ----
      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.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,55 ****
--- 56,64 ----
  
  #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,73 ****
  #define PRINTK(x) /**/
  #endif
  
! static struct arp_table *arp_table[ARP_TABLE_SIZE] ={NULL, };
! struct sk_buff *arp_q=NULL;
  
  /* this will try to retransmit everything on the queue. */
  static void
--- 75,82 ----
  #define PRINTK(x) /**/
  #endif
  
! 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,83 ****
     struct sk_buff *next;
  
     cli();
!    next = arp_q;
     arp_q = NULL;
     sti();
     while ((skb = next) != NULL) {
--- 86,92 ----
     struct sk_buff *next;
  
     cli();
!    next = (struct sk_buff *)arp_q;
     arp_q = NULL;
     sti();
     while ((skb = next) != NULL) {
***************
*** 98,104 ****
         }
  
       /* first remove skb from the queue. */
!      next = skb->next;
       if (next == skb)
         {
  	 next = NULL;
--- 107,113 ----
         }
  
       /* first remove skb from the queue. */
!      next = (struct sk_buff *)skb->next;
       if (next == skb)
         {
  	 next = NULL;
***************
*** 289,295 ****
    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)
      {
        if (apt->ip == paddr)
  	{
--- 298,306 ----
    if (my_ip_addr(paddr)) return (NULL);
    hash = net32(paddr) & (ARP_TABLE_SIZE - 1);
    cli();
!   for (apt = (struct arp_table *)arp_table[hash];
!        apt != NULL;
!        apt = (struct arp_table *)apt->next)
      {
        if (apt->ip == paddr)
  	{
***************
*** 319,325 ****
    /* check the first one. */
    if (arp_table[hash]->ip == paddr)
      {
!       apt = arp_table[hash];
        arp_table[hash] = arp_table[hash]->next;
        arp_free (apt, sizeof (*apt));
        sti();
--- 330,336 ----
    /* check the first one. */
    if (arp_table[hash]->ip == paddr)
      {
!       apt = (struct arp_table *)arp_table[hash];
        arp_table[hash] = arp_table[hash]->next;
        arp_free (apt, sizeof (*apt));
        sti();
***************
*** 327,334 ****
      }
  
    /* 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)
      {
        if (apt->ip == paddr) 
  	{
--- 338,347 ----
      }
  
    /* now deal with it any where else in the chain. */
!   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) 
  	{
***************
*** 557,560 ****
--- 570,636 ----
       }
    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 -c +recursive +new-files l99.4/linux/net/tcp/arp.h linux/net/tcp/arp.h
*** l99.4/linux/net/tcp/arp.h	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/arp.h	Mon Jan 25 19:26:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: arp.h,v $
   * Revision 0.8.4.3  1992/12/03  19:54:12  bir7
   * Added paranoid queue checking.
   *
--- 19,29 ----
      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.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,37 ****
--- 35,43 ----
   *
   * Revision 0.8.3.2  1992/11/10  00:14:47  bir7
   * Changed malloc to kmalloc and added $iId$ 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,71 ****
  
  struct arp_table
  {
!   struct arp_table *next;
!   unsigned long last_used;
    unsigned long ip;
    unsigned char hlen;
    unsigned char hard[MAX_ADDR_LEN];
  };
  
! 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);
--- 64,77 ----
  
  struct arp_table
  {
!   volatile struct arp_table *next;
!   volatile unsigned long last_used;
    unsigned long ip;
    unsigned char hlen;
    unsigned char hard[MAX_ADDR_LEN];
  };
  
! 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);
***************
*** 75,80 ****
--- 81,90 ----
  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
diff -c +recursive +new-files l99.4/linux/net/tcp/dev.c linux/net/tcp/dev.c
*** l99.4/linux/net/tcp/dev.c	Mon Jan 25 21:49:58 1993
--- linux/net/tcp/dev.c	Mon Jan 25 19:26:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: dev.c,v $
   * Revision 0.8.4.10  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,35 ----
      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.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,162 ****
--- 166,174 ----
  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,179 ****
         return;
      }
  
!   if (pri < 0 || pri >= DEV_NUMBUFFS)
      {
         printk ("bad priority in dev_queue_xmit.\n");
         pri = 1;
--- 185,197 ----
         return;
      }
  
!   if (pri < 0)
!     {
!       pri = -pri-1;
!       where = 1;
!     }
! 
!   if ( pri >= DEV_NUMBUFFS)
      {
         printk ("bad priority in dev_queue_xmit.\n");
         pri = 1;
***************
*** 196,206 ****
      }
    else
      {
!       skb2=dev->buffs[pri];
!       skb->next = skb2;
!       skb->prev = skb2->prev;
!       skb->next->prev = skb;
!       skb->prev->next = skb;
      }
    skb->magic = DEV_QUEUE_MAGIC;
    sti();
--- 214,235 ----
      }
    else
      {
!       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,233 ****
  dev_rint(unsigned char *buff, long len, int flags,
  	 struct device * dev)
  {
!    volatile struct sk_buff *skb=NULL;
     unsigned char *to;
     int amount;
  
--- 256,262 ----
  dev_rint(unsigned char *buff, long len, int flags,
  	 struct device * dev)
  {
!    struct sk_buff *skb=NULL;
     unsigned char *to;
     int amount;
  
***************
*** 272,287 ****
     cli();
     if (backlog == NULL)
       {
!        skb->prev = (struct sk_buff *)skb;
!        skb->next = (struct sk_buff *)skb;
         backlog = skb;
       }
     else
       {
!        skb->prev = backlog->prev;
         skb->next = (struct sk_buff *)backlog;
!        skb->next->prev = (struct sk_buff *)skb;
!        skb->prev->next = (struct sk_buff *)skb;
       }
     sti();
     
--- 301,316 ----
     cli();
     if (backlog == NULL)
       {
!        skb->prev = skb;
!        skb->next = skb;
         backlog = skb;
       }
     else
       {
!        skb->prev = (struct sk_buff *)backlog->prev;
         skb->next = (struct sk_buff *)backlog;
!        skb->next->prev = skb;
!        skb->prev->next = skb;
       }
     sti();
     
***************
*** 292,300 ****
  }
  
  void
  inet_bh(void *tmp)
  {
!   volatile struct sk_buff *skb;
    struct packet_type *ptype;
    unsigned short type;
    unsigned char flag =0;
--- 321,343 ----
  }
  
  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)
  {
!   struct sk_buff *skb;
    struct packet_type *ptype;
    unsigned short type;
    unsigned char flag =0;
***************
*** 307,319 ****
        return;
      }
    in_bh=1;
!   
    /* anything left to process? */
    
    while (backlog != NULL)
       {
!        cli();
!        skb= backlog;
         if (skb->next == skb)
  	 {
  	   backlog = NULL;
--- 350,364 ----
        return;
      }
    in_bh=1;
!   sti();
! 
!   dev_transmit();
    /* anything left to process? */
    
+   cli();
    while (backlog != NULL)
       {
!        skb= (struct sk_buff *)backlog;
         if (skb->next == skb)
  	 {
  	   backlog = NULL;
***************
*** 345,351 ****
  		 {
  		   skb2 = kmalloc (skb->mem_len, GFP_ATOMIC);
  		   if (skb2 == NULL) continue;
! 		   memcpy (skb2, skb, skb->mem_len);
  		   skb2->mem_addr = skb2;
  		   skb2->lock = 0;
  		   skb2->h.raw = (void *)((unsigned long)skb2
--- 390,396 ----
  		 {
  		   skb2 = kmalloc (skb->mem_len, GFP_ATOMIC);
  		   if (skb2 == NULL) continue;
! 		   memcpy (skb2, (const void *) skb, skb->mem_len);
  		   skb2->mem_addr = skb2;
  		   skb2->lock = 0;
  		   skb2->h.raw = (void *)((unsigned long)skb2
***************
*** 368,373 ****
--- 413,420 ----
  	   PRINTK (("discarding packet type = %X\n", type));
  	   kfree_skb ((struct sk_buff *)skb, FREE_READ);
  	 }
+        dev_transmit();
+        cli();
       }
    in_bh = 0;
    sti();
***************
*** 379,389 ****
     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)
  {
    int i;
-   int tmp;
    struct sk_buff *skb;
    for (i=0; i < DEV_NUMBUFFS; i++)
      {
--- 426,437 ----
     length of zero is interrpreted to mean the transmit buffers
     are empty, and the transmitter should be shut down. */
  
! /* now the packet is passed on via the other call. */
! 
! void
! dev_tint( struct device *dev)
  {
    int i;
    struct sk_buff *skb;
    for (i=0; i < DEV_NUMBUFFS; i++)
      {
***************
*** 390,396 ****
        while (dev->buffs[i]!=NULL)
  	{
  	  cli();
! 	  skb=dev->buffs[i];
  	  if (skb->magic != DEV_QUEUE_MAGIC)
  	    {
  	      printk ("dev.c skb with bad magic-%X: squashing queue\n",
--- 438,444 ----
        while (dev->buffs[i]!=NULL)
  	{
  	  cli();
! 	  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,479 ****
  	    }
  	  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);
  	}
      }
-   PRINTK (("dev_tint returning 0 \n"));
-   return (0);
  }
--- 478,486 ----
  	    }
  	  skb->next = NULL;
  	  skb->prev = NULL;
  	  sti();
! 	  /* this will send it through the process again. */
! 	  dev->queue_xmit (skb, dev, -i-1);
  	}
      }
  }
diff -c +recursive +new-files l99.4/linux/net/tcp/dev.h linux/net/tcp/dev.h
*** l99.4/linux/net/tcp/dev.h	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/dev.h	Mon Jan 25 19:26:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: dev.h,v $
   * Revision 0.8.4.5  1992/12/08  20:49:15  bir7
   * Edited ctrl-h's out of log messages.
   *
--- 19,32 ----
      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.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,72 ****
    unsigned long mem_start;
    unsigned short base_addr;
    unsigned char irq;
!   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];
    struct sk_buff *backlog; /* no longer used. */
    int  (*open)(struct device *dev);
    int  (*stop)(struct device *dev);
--- 64,78 ----
    unsigned long mem_start;
    unsigned short base_addr;
    unsigned char irq;
!   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;
!   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,85 ****
    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 *private;
  
    unsigned short type;
--- 85,92 ----
    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); /* no longer
! 								   used */
    void *private;
  
    unsigned short type;
***************
*** 110,116 ****
  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_add_pack (struct packet_type *pt);
  void dev_remove_pack (struct packet_type *pt);
  struct device *get_dev (char *name);
--- 117,123 ----
  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);
! 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 -c +recursive +new-files l99.4/linux/net/tcp/eth.c linux/net/tcp/eth.c
*** l99.4/linux/net/tcp/eth.c	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/eth.c	Mon Jan 25 19:26:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: eth.c,v $
   * Revision 0.8.4.3  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,29 ----
      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.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 -c +recursive +new-files l99.4/linux/net/tcp/icmp.c linux/net/tcp/icmp.c
*** l99.4/linux/net/tcp/icmp.c	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/icmp.c	Mon Jan 25 19:26:55 1993
***************
*** 23,30 ****
      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 $ */
  /* $Log: icmp.c,v $
   * Revision 0.8.4.7  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 23,36 ----
      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.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,236 ****
  	   hash = iph->protocol & (MAX_IP_PROTOS -1 );
  
  	   /* this can change while we are doing it. */
! 	   for (ipprot = ip_protos[hash]; ipprot != NULL; )
  	     {
  	       struct ip_protocol *nextip;
! 	       nextip = 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),
--- 233,243 ----
  	   hash = iph->protocol & (MAX_IP_PROTOS -1 );
  
  	   /* this can change while we are doing it. */
! 	   for (ipprot = (struct ip_protocol *)ip_protos[hash];
! 		ipprot != NULL; )
  	     {
  	       struct ip_protocol *nextip;
! 	       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 -c +recursive +new-files l99.4/linux/net/tcp/ip.c linux/net/tcp/ip.c
*** l99.4/linux/net/tcp/ip.c	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/ip.c	Mon Feb  8 16:11:36 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: ip.c,v $
   * Revision 0.8.4.8  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,32 ----
      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.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,83 ****
  
  unsigned long ip_addr[MAX_IP_ADDRES]={0,0,0};
  
  #undef IP_DEBUG
  
  #ifdef IP_DEBUG
! #define PRINTK(X) printk X
  #else
! #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, };
  
  #if 0
  static  struct ip_protocol *
--- 73,106 ----
  
  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
  #else
! #define PRINTK(x) /**/
  #endif
  
  static struct rtable *rt_base=NULL; /* used to base all the routing data. */
  
! 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,114 ****
     ip_protos[hash] = prot;
     prot->copy = 0;
     /* set the copy bit if we need to. */
!    for (p2 = prot->next; p2 != NULL; p2=p2->next)
       {
  	if (p2->protocol == prot->protocol)
  	  {
--- 131,139 ----
     ip_protos[hash] = prot;
     prot->copy = 0;
     /* set the copy bit if we need to. */
!    for (p2 = (struct ip_protocol *)prot->next;
! 	p2 != NULL;
! 	p2= (struct ip_protocol *)p2->next)
       {
  	if (p2->protocol == prot->protocol)
  	  {
***************
*** 130,140 ****
     hash = prot->protocol & (MAX_IP_PROTOS -1);
     if (prot == ip_protos[hash])
       {
!         ip_protos[hash]=ip_protos[hash]->next;
  	return (0);
       }
  
!    for (p = ip_protos[hash]; p != NULL; p = 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
--- 155,167 ----
     hash = prot->protocol & (MAX_IP_PROTOS -1);
     if (prot == ip_protos[hash])
       {
!         ip_protos[hash]=(struct ip_protocol *)ip_protos[hash]->next;
  	return (0);
       }
  
!    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,215 ****
  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));
  }
  
  void
--- 235,246 ----
  void
  print_rt(struct rtable *rt)
  {
! #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,244 ****
--- 270,307 ----
    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)
  {
***************
*** 245,251 ****
    int mask;
    struct rtable *r;
    struct rtable *r1;
!   PRINTK (("add_route (rt=%X):\n",rt));
    print_rt(rt);
  
    if (rt_base == NULL)
--- 308,314 ----
    int mask;
    struct rtable *r;
    struct rtable *r1;
! 
    print_rt(rt);
  
    if (rt_base == NULL)
***************
*** 316,331 ****
    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 (dev == NULL) return (-EINVAL);
  
    /* see if we need to add a broadcast address. */
    if (ipc.net != -1)
--- 379,401 ----
    struct rtable *rt;
    struct device *dev;
    struct ip_config ipc;
  
  
+ 
  /*  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,373 ****
         add_route (rt);
      }
  
  
!   if (!my_ip_addr (ipc.paddr))
      {
!        PRINTK (("new identity: %08X\n", ipc.paddr));
!        ip_addr[ip_ads++] = ipc.paddr;
      }
  
    dev->up = ipc.up;
--- 433,471 ----
         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;
+ 	}
+     }
  
!   /* FIX per FvK 92/11/15 */
!   /* When "downing" an interface, this must be done with paddr = -1L. */
!   if (ipc.paddr != -1L && !ipc.destroy)
      {
!       if (!my_ip_addr (ipc.paddr))
! 	{
! 	  PRINTK (("new identity: %08X\n", ipc.paddr));
! 	  ip_addr[ip_ads++] = ipc.paddr;
! 	}
      }
  
    dev->up = ipc.up;
***************
*** 380,385 ****
--- 478,484 ----
      {
         if (dev->stop)
  	 dev->stop(dev);
+ 	del_devroute(dev);		/* clear routing table for dev	*/
      }
  
    return (0);
***************
*** 732,738 ****
    /* for now we will only deal with packets meant for us. */
    if (!my_ip_addr(iph->daddr))
      {
!        PRINTK (("packet meant for someone else.\n"));
         skb->sk = NULL;
         kfree_skb(skb, 0);
         return (0);
--- 831,841 ----
    /* for now we will only deal with packets meant for us. */
    if (!my_ip_addr(iph->daddr))
      {
! 	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,747 ****
  
    /* deal with fragments.  or don't for now.*/
    if ((iph->frag_off & 32) || (net16(iph->frag_off)&0x1fff))
!     {
!        printk ("packet fragmented. \n");
         skb->sk = NULL;
         kfree_skb(skb, 0);
         return(0);
--- 843,853 ----
  
    /* deal with fragments.  or don't for now.*/
    if ((iph->frag_off & 32) || (net16(iph->frag_off)&0x1fff))
!     {	/* 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,756 ****
    skb->h.raw += iph->ihl*4;
  
    hash = iph->protocol & (MAX_IP_PROTOS -1);
!   for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next)
      {
         struct sk_buff *skb2;
         if (ipprot->protocol != iph->protocol) continue;
--- 856,864 ----
    skb->h.raw += iph->ihl*4;
  
    hash = iph->protocol & (MAX_IP_PROTOS -1);
!   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,897 ****
  	  if (dev->rebuild_header ((struct enet_header *)(skb+1),dev))
  	    {
  	       if (!all) break;
! 	       skb=skb->link3;
  	       continue;
  	    }
         }
--- 999,1005 ----
  	  if (dev->rebuild_header ((struct enet_header *)(skb+1),dev))
  	    {
  	       if (!all) break;
! 	       skb=(struct sk_buff *)skb->link3;
  	       continue;
  	    }
         }
***************
*** 911,917 ****
        /* this should cut it off before we send too
  	 many packets. */
        if (sk->retransmits > sk->cong_window) break;
!       skb=skb->link3;
      }
    /* double the rtt time every time we retransmit. 
       This will cause exponential back off on how
--- 1019,1025 ----
        /* this should cut it off before we send too
  	 many packets. */
        if (sk->retransmits > sk->cong_window) break;
!       skb=(struct sk_buff *)skb->link3;
      }
    /* double the rtt time every time we retransmit. 
       This will cause exponential back off on how
***************
*** 936,994 ****
    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
--- 1044,1046 ----
diff -c +recursive +new-files l99.4/linux/net/tcp/ip.h linux/net/tcp/ip.h
*** l99.4/linux/net/tcp/ip.h	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/ip.h	Mon Feb  1 22:42:54 1993
***************
*** 19,31 ****
      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 $ */
  /* $Log: ip.h,v $
   * 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 $iId$ and $Log: ip.h,v $
   * Revision 0.8.4.1  1992/11/10  00:17:18  bir7
   * version change only.
   *.
--- 19,37 ----
      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.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 $iId$ 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,141 ****
  		   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;
     unsigned char protocol;
     unsigned char copy:1;
     void *data;
--- 141,147 ----
  		   int redo, struct ip_protocol *protocol);
     void (*err_handler) (int err, unsigned char *buff, unsigned long daddr,
  			unsigned long saddr, struct ip_protocol *ipprot);
!    volatile struct ip_protocol *next;
     unsigned char protocol;
     unsigned char copy:1;
     void *data;
***************
*** 142,152 ****
  };
  
  extern struct ip_protocol *ip_protocol_base;
! extern 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];
  int my_ip_addr(unsigned long);
  
  #include "eth.h"
--- 148,159 ----
  };
  
  extern struct ip_protocol *ip_protocol_base;
! extern volatile struct ip_protocol *ip_protos[MAX_IP_PROTOS];
  
  #define MAX_IP_ADDRES 5
  extern unsigned long ip_addr[MAX_IP_ADDRES];
! extern int ip_ads;
! #define MY_IP_ADDR ip_addr[0]
  int my_ip_addr(unsigned long);
  
  #include "eth.h"
diff -c +recursive +new-files l99.4/linux/net/tcp/loopback.c linux/net/tcp/loopback.c
*** l99.4/linux/net/tcp/loopback.c	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/loopback.c	Mon Jan 25 19:26:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: loopback.c,v $
   * Revision 0.8.4.5  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,35 ----
      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.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,131 ****
  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)
      {
         sti();
         return (1);
      }
!   inuse = 1;
    sti();
  
!   done = -1;
!   while (done == -1)
!     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);
! 	      }
! 	    
  	 }
!   inuse = 0;
    return (0);
  }
  
--- 85,113 ----
  static int
  loopback_xmit(struct sk_buff *skb, struct device *dev)
  {
    int done;
    PRINTK (("loopback_xmit (dev = %X)\n", dev));
    cli();
!   if (dev->tbusy != 0)
      {
         sti();
         return (1);
      }
!   dev->tbusy = 1;
    sti();
  
!   done = dev_rint ((unsigned char *)(skb+1), skb->len, 0, dev);
  
    if (skb->free)
      kfree_skb (skb, FREE_WRITE);
  
    while (done != 1)
  	 {
! 	   done = dev_rint (NULL, 0, 0, dev);
  	 }
! 
!   dev->tbusy = 0;
! 
    return (0);
  }
  
***************
*** 135,140 ****
--- 117,123 ----
     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 -c +recursive +new-files l99.4/linux/net/tcp/packet.c linux/net/tcp/packet.c
*** l99.4/linux/net/tcp/packet.c	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/packet.c	Fri Jan 29 16:13:26 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: packet.c,v $
   * Revision 0.8.4.5  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,32 ----
      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.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,164 ****
     else
       return (-EINVAL);
  
!    skb = sk->prot->wmalloc (sk, len+sizeof (*skb) + sk->prot->max_header, 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->sk = sk;
     skb->free = 1;
     saddr.sa_data[13] = 0;
--- 153,169 ----
     else
       return (-EINVAL);
  
!    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");
  	return (-EAGAIN);
       }
     skb->lock = 0;
     skb->mem_addr = skb;
!    skb->mem_len = len + sizeof (*skb);
     skb->sk = sk;
     skb->free = 1;
     saddr.sa_data[13] = 0;
***************
*** 193,198 ****
--- 198,204 ----
     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,261 ****
--- 262,268 ----
  		       return (-ERESTARTSYS);
  		    }
  	       }
+ 	     sk->inuse = 1;
  	     sti();
  	  }
  	skb = sk->rqueue;
***************
*** 268,274 ****
  		    }
  		  else
  		    {
! 			    sk->rqueue = sk->rqueue ->next;
  			    skb->prev->next = skb->next;
  			    skb->next->prev = skb->prev;
  		    }
--- 275,281 ----
  		    }
  		  else
  		    {
! 			    sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
  			    skb->prev->next = skb->next;
  			    skb->next->prev = skb->prev;
  		    }
***************
*** 337,341 ****
    NULL,
    128,
    0,
!   {NULL,}
  };
--- 344,349 ----
    NULL,
    128,
    0,
!   {NULL,},
!   "PACKET"
  };
diff -c +recursive +new-files l99.4/linux/net/tcp/raw.c linux/net/tcp/raw.c
*** l99.4/linux/net/tcp/raw.c	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/raw.c	Fri Jan 29 16:13:26 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: raw.c,v $
   * Revision 0.8.4.9  1992/12/12  19:25:04  bir7
   * Cleaned up Log messages.
   *
--- 19,35 ----
      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.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,270 ****
  	 {
  	   int tmp;
  	   PRINTK (("raw_sendto: write buffer full?\n"));
- 	   print_sk (sk);
  	   if (noblock) return (-EAGAIN);
  	   tmp = sk->wmem_alloc;
  	   release_sock (sk);
--- 273,278 ----
***************
*** 408,414 ****
  		    }
  		  else
  		    {
! 			    sk->rqueue = sk->rqueue ->next;
  			    skb->prev->next = skb->next;
  			    skb->next->prev = skb->prev;
  		    }
--- 416,422 ----
  		    }
  		  else
  		    {
! 			    sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
  			    skb->prev->next = skb->next;
  			    skb->next->prev = skb->prev;
  		    }
***************
*** 476,480 ****
    NULL,
    128,
    0,
!   {NULL,}
  };
--- 484,489 ----
    NULL,
    128,
    0,
!   {NULL,},
!   "RAW"
  };
diff -c +recursive +new-files l99.4/linux/net/tcp/sock.c linux/net/tcp/sock.c
*** l99.4/linux/net/tcp/sock.c	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/sock.c	Mon Feb  1 22:42:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: sock.c,v $
   * Revision 0.8.4.12  1992/12/12  19:25:04  bir7
   * Made memory leak checking more leanent.
   *
--- 19,38 ----
      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.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,75 ****
--- 82,88 ----
  #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,158 ****
  static int ip_proto_fcntl (struct socket *sock, unsigned int cmd,
  			   unsigned long arg);
  
- 
  struct proto_ops inet_proto_ops = 
  {
    ip_proto_init,
--- 165,170 ----
***************
*** 176,182 ****
    ip_proto_shutdown,
    ip_proto_setsockopt,
    ip_proto_getsockopt,
!   ip_proto_fcntl
  };
  
  void
--- 188,194 ----
    ip_proto_shutdown,
    ip_proto_setsockopt,
    ip_proto_getsockopt,
!   ip_proto_fcntl,
  };
  
  void
***************
*** 183,211 ****
  print_sk (volatile struct sock *sk)
  {
    if (!sk) {
!     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));
  }
  
  void
--- 195,224 ----
  print_sk (volatile struct sock *sk)
  {
    if (!sk) {
!     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 ("  urg = %d shutdown=%d\n", sk->urg, sk->shutdown);
  }
  
  void
***************
*** 212,224 ****
  print_skb(struct sk_buff *skb)
  {
    if (!skb) {
!     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));
  }
  
  /* just used to reference some pointers to keep gcc from over optimizing
--- 225,237 ----
  print_skb(struct sk_buff *skb)
  {
    if (!skb) {
!     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);
  }
  
  /* just used to reference some pointers to keep gcc from over optimizing
***************
*** 472,478 ****
    for (skb = sk->wfront; skb != NULL; )
      {
        struct sk_buff *skb2;
!       skb2=skb->next;
        if (skb->magic != TCP_WRITE_QUEUE_MAGIC)
  	{
  	  printk ("sock.c:destroy_sock write queue with bad magic (%X)\n",
--- 485,491 ----
    for (skb = sk->wfront; skb != NULL; )
      {
        struct sk_buff *skb2;
!       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,497 ****
         skb = sk->rqueue;
         do {
  	  struct sk_buff *skb2;
! 	  skb2=skb->next;
  
  	  /* this will take care of closing sockets that were
  	     listening and didn't accept everything. */
--- 504,510 ----
         skb = sk->rqueue;
         do {
  	  struct sk_buff *skb2;
! 	  skb2=(struct sk_buff *)skb->next;
  
  	  /* this will take care of closing sockets that were
  	     listening and didn't accept everything. */
***************
*** 521,527 ****
  
        if (skb->next != NULL)
  	{
! 	  extern struct sk_buff *arp_q;
  	  int i;
  	   if (skb->next != skb)
  	     {
--- 534,540 ----
  
        if (skb->next != NULL)
  	{
! 	  extern volatile struct sk_buff *arp_q;
  	  int i;
  	   if (skb->next != skb)
  	     {
***************
*** 597,603 ****
  	}
        skb->dev = NULL;
        sti();
!       skb2=skb->link3;
        kfree_skb(skb, FREE_WRITE);
        skb=skb2;
      }
--- 610,616 ----
  	}
        skb->dev = NULL;
        sti();
!       skb2=(struct sk_buff *)skb->link3;
        kfree_skb(skb, FREE_WRITE);
        skb=skb2;
      }
***************
*** 611,620 ****
         /* this should never happen. */
         printk ("cleaning back_log. \n");
         cli();
!        skb = sk->back_log;
         do {
  	  struct sk_buff *skb2;
! 	  skb2=skb->next;
  	  kfree_skb(skb, FREE_READ);
  	  skb=skb2;
         } while (skb != sk->back_log);
--- 624,633 ----
         /* this should never happen. */
         printk ("cleaning back_log. \n");
         cli();
!        skb = (struct sk_buff *)sk->back_log;
         do {
  	  struct sk_buff *skb2;
! 	  skb2=(struct sk_buff *)skb->next;
  	  kfree_skb(skb, FREE_READ);
  	  skb=skb2;
         } while (skb != sk->back_log);
***************
*** 642,648 ****
         /* 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;
--- 655,660 ----
***************
*** 650,658 ****
         sk->timeout = TIME_DESTROY;
         reset_timer ((struct timer *)&sk->time_wait);
      }
- 
    PRINTK (("leaving destroy_sock\n"));
-   
  }
  
  
--- 662,668 ----
***************
*** 660,665 ****
--- 670,676 ----
  ip_proto_fcntl (struct socket *sock, unsigned int cmd, unsigned long arg)
  {
     volatile struct sock *sk;
+ 
     sk=sock->data;
     if (sk == NULL)
       {
***************
*** 670,677 ****
     switch (cmd)
       {
         case F_SETOWN:
! 	sk->proc = arg;
! 	return (0);
  
         case F_GETOWN:
  	return (sk->proc);
--- 681,699 ----
     switch (cmd)
       {
         case F_SETOWN:
! 
!        /* 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,875 ****
      {
         struct ip_protocol *tmp;
         /* add all the protocols. */
!        tmp = p->next;
         add_ip_protocol (p);
         p = tmp;
      }
--- 891,897 ----
      {
         struct ip_protocol *tmp;
         /* add all the protocols. */
!        tmp = (struct ip_protocol *) p->next;
         add_ip_protocol (p);
         p = tmp;
      }
***************
*** 997,1002 ****
--- 1019,1025 ----
    sk->urginline = 0;
    sk->intr = 0;
    sk->linger = 0;
+   sk->rtt = 0;
    sk->destroy = 0;
    sk->reuse = 0;
    sk->priority = 1;
***************
*** 1156,1167 ****
  
  /*  verify_area (uaddr, addr_len);*/
    memcpy_fromfs (&addr, uaddr, min (sizeof (addr), addr_len));
    if (addr.sin_family && addr.sin_family != AF_INET)
!     return (-EINVAL); /* this needs to be changed. */
  
    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
--- 1179,1196 ----
  
  /*  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)
!     {
!       /* 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));
    sk = sock->data;
  
    /* we can't just leave the socket bound wherever it is, it might be bound
***************
*** 1182,1188 ****
  
    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)];
--- 1211,1216 ----
***************
*** 1245,1255 ****
    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);
!     }
  
    sock->state = SS_CONNECTING;
    if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
--- 1273,1280 ----
    if (sk->prot->connect == NULL)
      return (-EOPNOTSUPP);
  
!   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,1276 ****
        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;
--- 1288,1299 ----
        if (current->signal & ~current->blocked)
  	{
  	   sti();
  	   return (-ERESTARTSYS);
  	}
      }
    sti();
    sock->state = SS_CONNECTED;
! 
    if (sk->state != TCP_ESTABLISHED && sk->err)
      {
        sock->state = SS_UNCONNECTED;
***************
*** 1298,1303 ****
--- 1321,1327 ----
  
    /* 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,1389 ****
    else
      {
        sin.sin_port = sk->dummy_th.source;
!       sin.sin_addr.s_addr = sk->saddr;
      }
    len = sizeof (sin);
    verify_area (uaddr, len);
--- 1407,1416 ----
    else
      {
        sin.sin_port = sk->dummy_th.source;
!       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,1630 ****
--- 1652,1670 ----
  	 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,1820 ****
      {
        struct sk_buff *skb;
        sk->blog = 1;
!       skb = sk->back_log;
        PRINTK (("release_sock: skb = %X:\n",skb));
-       print_skb(skb);
        if (skb->next != skb)
  	{
  	  sk->back_log = skb->next;
--- 1852,1859 ----
      {
        struct sk_buff *skb;
        sk->blog = 1;
!       skb = (struct sk_buff *)sk->back_log;
        PRINTK (("release_sock: skb = %X:\n",skb));
        if (skb->next != skb)
  	{
  	  sk->back_log = skb->next;
diff -c +recursive +new-files l99.4/linux/net/tcp/sock.h linux/net/tcp/sock.h
*** l99.4/linux/net/tcp/sock.h	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/sock.h	Fri Jan 29 16:13:27 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: sock.h,v $
   * Revision 0.8.4.5  1992/12/12  01:50:49  bir7
   * Fixed support for half duplex connections.
   *
--- 19,32 ----
      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.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,58 ****
  struct sock 
  {
    struct options *opt;
!   unsigned long wmem_alloc;
!   unsigned long rmem_alloc;
    unsigned long send_seq;
    unsigned long acked_seq;
    unsigned long copied_seq;
--- 57,64 ----
  struct sock 
  {
    struct options *opt;
!   volatile unsigned long wmem_alloc;
!   volatile unsigned long rmem_alloc;
    unsigned long send_seq;
    unsigned long acked_seq;
    unsigned long copied_seq;
***************
*** 59,65 ****
    unsigned long rcv_ack_seq;
    unsigned long window_seq;
    unsigned long fin_seq;
!   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;
--- 65,73 ----
    unsigned long rcv_ack_seq;
    unsigned long window_seq;
    unsigned long fin_seq;
!   /* 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,74 ****
    volatile struct sock *pair;
    struct sk_buff *send_tail;
    struct sk_buff *send_head;
!   struct sk_buff *back_log;
    struct sk_buff *send_tmp;
    long retransmits;
    struct sk_buff *wback, *wfront, *rqueue;
--- 76,82 ----
    volatile struct sock *pair;
    struct sk_buff *send_tail;
    struct sk_buff *send_head;
!   volatile struct sk_buff * volatile back_log;
    struct sk_buff *send_tmp;
    long retransmits;
    struct sk_buff *wback, *wfront, *rqueue;
***************
*** 81,100 ****
    unsigned short bytes_rcv;
    unsigned short mtu;
    unsigned short num;
!   unsigned short cong_window;
!   unsigned short packets_out;
!   unsigned short urg;
!   unsigned short shutdown;
    unsigned short mss;
!   short rtt;
!   short err;
    unsigned char protocol;
!   unsigned char state;
!   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;
  };
  
  struct proto 
--- 89,108 ----
    unsigned short bytes_rcv;
    unsigned short mtu;
    unsigned short num;
!   volatile unsigned short cong_window;
!   volatile unsigned short packets_out;
!   volatile unsigned short urg;
!   volatile unsigned short shutdown;
    unsigned short mss;
!   volatile short rtt;
!   volatile short err;
    unsigned char protocol;
!   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. */
!   volatile struct timer time_wait;
  };
  
  struct proto 
***************
*** 139,144 ****
--- 147,153 ----
    unsigned short max_header;
    unsigned long retransmits;
    volatile struct sock *sock_array[SOCK_ARRAY_SIZE];
+   char name[80];
  };
  
  #define TIME_WRITE 1
***************
*** 154,164 ****
  
  struct sk_buff
  {
!   struct sk_buff *next;
!   struct sk_buff *prev;
!   struct sk_buff *link3;
    volatile struct sock *sk;
!   unsigned long when; /* used to compute rtt's. */
    struct device *dev;
    void *mem_addr;
    union
--- 163,173 ----
  
  struct sk_buff
  {
!   volatile struct sk_buff *next;
!   volatile struct sk_buff *prev;
!   volatile struct sk_buff *link3;
    volatile struct sock *sk;
!   volatile unsigned long when; /* used to compute rtt's. */
    struct device *dev;
    void *mem_addr;
    union
***************
*** 176,182 ****
    unsigned long saddr;
    unsigned long daddr;
    int magic;
!   unsigned long acked:1,used:1,free:1,arp:1, urg_used:1, lock:1;
  };
  
  #define PROT_SOCK 1024
--- 185,191 ----
    unsigned long saddr;
    unsigned long daddr;
    int magic;
!   volatile unsigned long acked:1,used:1,free:1,arp:1, urg_used:1, lock:1;
  };
  
  #define PROT_SOCK 1024
diff -c +recursive +new-files l99.4/linux/net/tcp/tcp.c linux/net/tcp/tcp.c
*** l99.4/linux/net/tcp/tcp.c	Mon Jan 25 21:49:58 1993
--- linux/net/tcp/tcp.c	Mon Feb  1 22:42:55 1993
***************
*** 23,30 ****
        Tim MacKenzie (tym@dibbler.cs.moansh.edu.au)
  
   */
! /* $Id: tcp.c,v 0.8.4.12 1992/12/12 19:25:04 bir7 Exp $ */
  /* $Log: tcp.c,v $
   * Revision 0.8.4.12  1992/12/12  19:25:04  bir7
   * Fixed anti-memory Leak in shutdown.
   *
--- 23,42 ----
        Tim MacKenzie (tym@dibbler.cs.moansh.edu.au)
  
   */
! /* $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,140 ****
     struct sk_buff *skb;
     skb = sk->rqueue;
     if (skb == NULL) return (NULL);
!    sk->rqueue = skb->next;
     if (sk->rqueue == skb)
       {
         sk->rqueue = NULL;
--- 146,152 ----
     struct sk_buff *skb;
     skb = sk->rqueue;
     if (skb == NULL) return (NULL);
!    sk->rqueue = (struct sk_buff *)skb->next;
     if (sk->rqueue == skb)
       {
         sk->rqueue = NULL;
***************
*** 221,235 ****
  	return;
       }
  
!    printk ("tcp.c: icmp_err got error\n");
     sk->err = icmp_err_convert[err & 0xff].errno;
     if (icmp_err_convert[err & 0xff].fatal)
       {
! 	if (sk->state != TCP_ESTABLISHED)
  	  {
  	    sk->state = TCP_CLOSE;
  	  }
- 	sk->prot->close(sk, 0);
       }
  
     return;
--- 233,249 ----
  	return;
       }
  
!    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_SYN_SENT)
  	  {
  	    sk->state = TCP_CLOSE;
+ 	    sk->prot->close(sk, 0);
  	  }
       }
  
     return;
***************
*** 245,255 ****
    int count=0;
    int sum;
  
    if (sk == NULL || sk->rqueue == NULL) return (0);
  
!   counted = sk->copied_seq;
    amount = 0;
!   skb = sk->rqueue->next;
  
    /* go until a push or until we are out of data.  */
    do {
--- 259,271 ----
    int count=0;
    int sum;
  
+   PRINTK (("tcp_readable (sk=%X)\n", sk));
+ 
    if (sk == NULL || sk->rqueue == NULL) return (0);
  
!   counted = sk->copied_seq+1;
    amount = 0;
!   skb = (struct sk_buff *)sk->rqueue->next;
  
    /* go until a push or until we are out of data.  */
    do {
***************
*** 256,277 ****
      count ++;
      if (count > 20)
        {
! 	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;
      sum = skb->len - ( counted - skb->h.th->seq);
      if (skb->h.th->syn) sum ++;
      if (sum >= 0)
        {
  	amount += sum;
  	if (skb->h.th->syn) amount --;
  	counted += sum;
- 	if (skb->h.th->psh) break;
        }
!     skb = skb->next;
    } while (skb != sk->rqueue->next);
    return (amount);
  }
  
--- 272,298 ----
      count ++;
      if (count > 20)
        {
! 	PRINTK (("tcp_readable, more than 20 packets without a psh\n"));
! 	PRINTK (("possible read_queue corruption.\n"));
  	return (amount);
        }
!     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 (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,285 ****
--- 301,308 ----
  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,324 ****
  
         if (sk->shutdown & SEND_SHUTDOWN)
  	 {
  	   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)
  	 {
  	   release_sock (sk);
  	   return (1);
  	 }
         release_sock (sk);
         return (0);
  
--- 332,362 ----
  
         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) >= 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,382 ****
  	  sk->inuse = 1;
  	  if (sk->rqueue != NULL)
  	    {
! 	      skb = sk->rqueue->next;
  	      if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
  		answ = 1;
  	    }
--- 414,420 ----
  	  sk->inuse = 1;
  	  if (sk->rqueue != NULL)
  	    {
! 	      skb = (struct sk_buff *)sk->rqueue->next;
  	      if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
  		answ = 1;
  	    }
***************
*** 643,658 ****
    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)
      {
         /* first thing we do is make sure that we are established. */	 
  
        sk->inuse = 1; /* no one else will use this socket. */
        while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
  	{
  	  if (sk->state != TCP_SYN_SENT &&
  	      sk->state != TCP_SYN_RECV)
  	   {
--- 681,721 ----
    PRINTK (("tcp_write (sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
  	  sk, from, len, nonblock, flags));
  
    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,680 ****
  	      return (-EPIPE);
  	    }
  
! 	  if (nonblock)
  	    {
  	      release_sock (sk);
  	      PRINTK (("tcp_write: return 2\n"));
--- 737,743 ----
  	      return (-EPIPE);
  	    }
  
! 	  if (nonblock || copied)
  	    {
  	      release_sock (sk);
  	      PRINTK (("tcp_write: return 2\n"));
***************
*** 774,780 ****
        /* if we didn't get any memory, we need to sleep. */
        if (skb == NULL)
  	{
! 	  if (nonblock)
  	    {
  	      release_sock (sk);
  	      PRINTK (("tcp_write: return 4\n"));
--- 837,843 ----
        /* if we didn't get any memory, we need to sleep. */
        if (skb == NULL)
  	{
! 	  if (nonblock || copied)
  	    {
  	      release_sock (sk);
  	      PRINTK (("tcp_write: return 4\n"));
***************
*** 844,850 ****
        if (flags & MSG_OOB)
  	{
  		((struct tcp_header *)buff)->urg = 1;
! 		((struct tcp_header *)buff)->urg_ptr = copy;
  	}
        skb->len += tmp;
        memcpy_fromfs (buff+tmp, from, copy);
--- 907,913 ----
        if (flags & MSG_OOB)
  	{
  		((struct tcp_header *)buff)->urg = 1;
! 		((struct tcp_header *)buff)->urg_ptr = net16(copy);
  	}
        skb->len += tmp;
        memcpy_fromfs (buff+tmp, from, copy);
***************
*** 986,998 ****
  static  void
  cleanup_rbuf (volatile struct sock *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;
        if (!skb->used) break;
        if (sk->rqueue == skb)
  	{
--- 1049,1061 ----
  static  void
  cleanup_rbuf (volatile struct sock *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=(struct sk_buff *)sk->rqueue->next;
        if (!skb->used) break;
        if (sk->rqueue == skb)
  	{
***************
*** 1009,1038 ****
     /* 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)));
  
     if ((sk->prot->rspace(sk) >
! 	(sk->window - sk->bytes_rcv + TCP_WINDOW_DIFF)))
       {
!        sk->ack_backlog++;
!        if (sk->ack_backlog > sk->max_ack_backlog)
! 	 {
! 	   tcp_read_wakeup (sk);
! 	 }
!        else
  	 {
! 	   /* 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);
! 	     }
  	 }
       }
! 
! }
  
  /* handle reading urgent data. */
  static  int
--- 1072,1107 ----
     /* 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 + sk->mtu)))
       {
!        /* 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))
  	 {
! 	   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,1049 ****
  	     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;
--- 1109,1119 ----
  	     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));
! 
      while (len > 0)
        {
  	 sk->inuse = 1;
***************
*** 1059,1065 ****
  		  return (tmp);
  		}
  
! 	       if (sk->state == TCP_CLOSE)
  		 {
  		   release_sock (sk);
  		   if (copied) return (copied);
--- 1129,1135 ----
  		  return (tmp);
  		}
  
! 	       if (sk->state == TCP_CLOSE || sk->done) 
  		 {
  		   release_sock (sk);
  		   if (copied) return (copied);
***************
*** 1079,1085 ****
  		    return (copied);
  		  }
  
! 	      if (nonblock)
  		{
  		  release_sock (sk);
  		  if (copied) return (copied);
--- 1149,1155 ----
  		    return (copied);
  		  }
  
! 	      if (nonblock || copied)
  		{
  		  release_sock (sk);
  		  if (copied) return (copied);
***************
*** 1103,1132 ****
  	       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;
- 		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))
  		  {
! 		     skb->urg_used = 1;
! 		     sk->urg --;
  		  }
! 		release_sock (sk);
! 		copied += amt;
! 		return (copied);
! 	    }
        }
      return (0);
  }
  
--- 1173,1207 ----
  	       sti();
  	       sk->inuse = 1;
  	    }
  
! 	 skb = (struct sk_buff *)sk->rqueue->next;
! 	 do {
! 		int amt;
! 		if (skb->h.th->urg && !skb->urg_used)
  		  {
! 		    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);
  		  }
! 		skb = (struct sk_buff *)skb->next;
! 	    } while (skb != sk->rqueue->next);
        }
+     sk->urg = 0;
+     release_sock(sk);
      return (0);
  }
  
***************
*** 1156,1162 ****
      /* so no-one else will use this socket. */
      sk->inuse = 1;
      if (sk->rqueue != NULL)
!       skb=sk->rqueue->next;
      else
        skb = NULL;
  
--- 1231,1237 ----
      /* so no-one else will use this socket. */
      sk->inuse = 1;
      if (sk->rqueue != NULL)
!       skb=(struct sk_buff *)sk->rqueue->next;
      else
        skb = NULL;
  
***************
*** 1171,1178 ****
  	    {
  
  	       PRINTK(("skb = %X:\n",skb));
- 	       print_skb(skb);
- 	       print_sk (sk);
  
  	       cleanup_rbuf(sk);
  
--- 1246,1251 ----
***************
*** 1180,1186 ****
  		 {
  		   int tmp;
  		   release_sock (sk);
! 		   if (copied) return (copied);
  		   tmp = -sk->err;
  		   sk->err = 0;
  		   return (tmp);
--- 1253,1263 ----
  		 {
  		   int tmp;
  		   release_sock (sk);
! 		   if (copied) 
! 		     {
! 		       PRINTK (("tcp_read: returing %d\n", copied));
! 		       return (copied);
! 		     }
  		   tmp = -sk->err;
  		   sk->err = 0;
  		   return (tmp);
***************
*** 1189,1195 ****
  	       if (sk->state == TCP_CLOSE)
  		 {
  		   release_sock (sk);
! 		   if (copied) return (copied);
  		   if (!sk->done)
  		     {
  		       sk->done = 1;
--- 1266,1276 ----
  	       if (sk->state == TCP_CLOSE)
  		 {
  		   release_sock (sk);
! 		   if (copied)
! 		     {
! 		       PRINTK (("tcp_read: returing %d\n", copied));
! 		       return (copied);
! 		     }
  		   if (!sk->done)
  		     {
  		       sk->done = 1;
***************
*** 1202,1215 ****
  		   {
  		     release_sock (sk);
  		     if (copied == 0) sk->done = 1;
  		     return (copied);
  		  }
  			
! 	       
! 		if (nonblock)
  		  {
  		    release_sock (sk);
! 		    if (copied) return (copied);
  		    return (-EAGAIN);
  		  }
  
--- 1283,1300 ----
  		   {
  		     release_sock (sk);
  		     if (copied == 0) sk->done = 1;
+ 		     PRINTK (("tcp_read: returing %d\n", copied));
  		     return (copied);
  		  }
  			
! 		if (nonblock || copied)
  		  {
  		    release_sock (sk);
! 		    if (copied) 
! 		      {
! 			PRINTK (("tcp_read: returing %d\n", copied));
! 			return (copied);
! 		      }
  		    return (-EAGAIN);
  		  }
  
***************
*** 1216,1221 ****
--- 1301,1307 ----
  	       if ((flags & MSG_PEEK) && copied != 0)
  		 {
  		   release_sock (sk);
+ 		   PRINTK (("tcp_read: returing %d\n", copied));
  		   return (copied);
  		 }
  		 
***************
*** 1238,1244 ****
  		     if (current->signal & ~current->blocked)
  		       {
  			  sti ();
! 			  if (copied) return (copied);
  			  return (-ERESTARTSYS);
  		       }
  		  }
--- 1324,1335 ----
  		     if (current->signal & ~current->blocked)
  		       {
  			  sti ();
! 			  if (copied)
! 			    {
! 			      PRINTK (("tcp_read: returing %d\n", copied));
! 			      return (copied);
! 			    }
! 			      
  			  return (-ERESTARTSYS);
  		       }
  		  }
***************
*** 1248,1254 ****
  		sk->inuse = 1;
  
  		if (sk->rqueue != NULL)
! 		  skb=sk->rqueue->next;
  		else
  		  skb = NULL;
  
--- 1339,1345 ----
  		sk->inuse = 1;
  
  		if (sk->rqueue != NULL)
! 		  skb=(struct sk_buff *)sk->rqueue->next;
  		else
  		  skb = NULL;
  
***************
*** 1268,1286 ****
  		{
  		   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)
  			  {
  			     skb->used = 1;
! 			     skb=skb->next;
  			     continue;
  			  }
  		     }
  		   else
  		     {
! 			break;
  		     }
  		}
  	      used = min(skb->len - offset, len);
--- 1359,1378 ----
  		{
  		   if (skb->urg_used)
  		     {
! 			sk->copied_seq += net16(skb->h.th->urg_ptr);
! 			offset += net16(skb->h.th->urg_ptr);
! 			if (offset >= skb->len)
  			  {
  			     skb->used = 1;
! 			     skb = (struct sk_buff *)skb->next;
  			     continue;
  			  }
  		     }
  		   else
  		     {
! 		       release_sock (sk);
! 		       if (copied) return (copied);
! 		       return (-EIO);
  		     }
  		}
  	      used = min(skb->len - offset, len);
***************
*** 1315,1326 ****
  	   {
  	      skb->used = 1;
  	   }
! 	 skb=skb->next;
        }
      cleanup_rbuf (sk);
      release_sock (sk);
      if (copied == 0 && nonblock) return (-EAGAIN);
-     PRINTK (("tcp_read returning %d\n", copied));
      return (copied);
  }
  
--- 1407,1418 ----
  	   {
  	      skb->used = 1;
  	   }
! 	 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);
      return (copied);
  }
  
***************
*** 1343,1348 ****
--- 1435,1445 ----
   * 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,1636 ****
  	}
      }
  
-   print_sk (newsk);
    buff=newsk->prot->wmalloc(newsk,MAX_SYN_SIZE,1, GFP_ATOMIC);
    if (buff == NULL)
      {
--- 1727,1732 ----
***************
*** 1732,1738 ****
    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;
--- 1828,1833 ----
***************
*** 1740,1746 ****
    if (!sk->dead)
      wake_up (sk->sleep);
  
- 
    /* we need to flush the recv. buffs. */
    
    if (sk->rqueue != NULL)
--- 1835,1840 ----
***************
*** 1749,1755 ****
         struct sk_buff *skb2;
         skb = sk->rqueue;
         do {
! 	  skb2=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))
--- 1843,1849 ----
         struct sk_buff *skb2;
         skb = sk->rqueue;
         do {
! 	  skb2=(struct sk_buff *)skb->next;
  	  /* if there is some real unread data, send a reset. */
  	  if (skb->len > 0 &&
  	      after (skb->h.th->seq + skb->len + 1, sk->copied_seq))
***************
*** 1901,1907 ****
  	 sk->packets_out < sk->cong_window)
      {
        skb = sk->wfront;
!       sk->wfront = skb->next;
        if (sk->wfront == NULL)
  	sk->wback = NULL;
        skb->next = NULL;
--- 1995,2001 ----
  	 sk->packets_out < sk->cong_window)
      {
        skb = sk->wfront;
!       sk->wfront = (struct sk_buff *)skb->next;
        if (sk->wfront == NULL)
  	sk->wback = NULL;
        skb->next = NULL;
***************
*** 1960,1966 ****
  
        sk->window_seq = ack + net16(th->window);
        cli();
!       for (skb = sk->send_head; skb != NULL; skb=skb->link3)
  	{
  	  if (after( skb->h.seq, sk->window_seq))
  	    {
--- 2054,2060 ----
  
        sk->window_seq = ack + net16(th->window);
        cli();
!       for (skb = sk->send_head; skb != NULL; skb= (struct sk_buff *)skb->link3)
  	{
  	  if (after( skb->h.seq, sk->window_seq))
  	    {
***************
*** 1968,1974 ****
  	      /* remove it from the send queue. */
  	      if (skb2 == NULL)
  		{
! 		  sk->send_head = skb->link3;
  		}
  	      else
  		{
--- 2062,2068 ----
  	      /* remove it from the send queue. */
  	      if (skb2 == NULL)
  		{
! 		  sk->send_head = (struct sk_buff *)skb->link3;
  		}
  	      else
  		{
***************
*** 2062,2068 ****
  	  /* estimate the rtt. */
  	  sk->rtt += ((jiffies - oskb->when) - sk->rtt)/2;
  	  if (sk->rtt < 30) sk->rtt = 30;
! 	  sk->send_head = oskb->link3;
  	  if (sk->send_head == NULL) 
  	    {
  	      sk->send_tail = NULL;
--- 2156,2162 ----
  	  /* estimate the rtt. */
  	  sk->rtt += ((jiffies - oskb->when) - sk->rtt)/2;
  	  if (sk->rtt < 30) sk->rtt = 30;
! 	  sk->send_head = (struct sk_buff *)oskb->link3;
  	  if (sk->send_head == NULL) 
  	    {
  	      sk->send_tail = NULL;
***************
*** 2092,2098 ****
  		   if (oskb == oskb->next)
  		     arp_q = NULL;
  		   else
! 		     arp_q = oskb->next;
  		 }
  	    }
  	  oskb->magic = 0;
--- 2186,2192 ----
  		   if (oskb == oskb->next)
  		     arp_q = NULL;
  		   else
! 		     arp_q = (struct sk_buff *)oskb->next;
  		 }
  	    }
  	  oskb->magic = 0;
***************
*** 2139,2160 ****
  	    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);
  	    sk->timeout = 0;
  	 }
         else
  	 {
  	    if (sk->state == TCP_TIME_WAIT)
  	      {
  		 sk->time_wait.len = TCP_TIMEWAIT_LEN;
  		 sk->timeout = TIME_CLOSE;
  	      }
- 	    sk->timeout = TIME_WRITE;
- 	    sk->time_wait.len = sk->rtt*2;
- 	    reset_timer ((struct timer *)&sk->time_wait);
  	 }
      }
  
--- 2233,2255 ----
  	    if (!sk->dead)
  	      wake_up (sk->sleep);
  
! 	    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;
  	      }
  	 }
      }
  
***************
*** 2189,2195 ****
  	   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;
--- 2284,2289 ----
***************
*** 2218,2224 ****
    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;
  
--- 2312,2317 ----
***************
*** 2240,2246 ****
         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);
--- 2333,2338 ----
***************
*** 2252,2261 ****
       in order, there will be no performance loss, and if they come
       out of order we will be able to fit things in nicely. */
    
    if (sk->rqueue == NULL)
      {
         PRINTK (("tcp_data: skb = %X:\n",skb));
-        print_skb (skb);
  
         sk->rqueue = skb;
         skb->next = skb;
--- 2344,2353 ----
       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));
  
         sk->rqueue = skb;
         skb->next = skb;
***************
*** 2265,2276 ****
    else
      {
        PRINTK (("tcp_data adding to chain sk = %X:\n",sk));
-       print_sk (sk);
  
!       for (skb1=sk->rqueue; ; skb1=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))
  	    {
--- 2357,2366 ----
    else
      {
        PRINTK (("tcp_data adding to chain sk = %X:\n",sk));
  
!       for (skb1=sk->rqueue; ; skb1=(struct sk_buff *)skb1->prev)
  	{
  	  PRINTK (("skb1=%X\n",skb1));
  	  PRINTK (("skb1->h.th->seq = %d\n", skb1->h.th->seq));
  	  if (after ( th->seq+1, skb1->h.th->seq))
  	    {
***************
*** 2294,2302 ****
  	}
  
        PRINTK (("skb = %X:\n",skb));
-       print_skb (skb);
-       PRINTK (("sk now equals:\n"));
-       print_sk (sk);
  
      }
  
--- 2384,2389 ----
***************
*** 2326,2332 ****
  	      sk->shutdown |= RCV_SHUTDOWN;
  	    }
  	  
! 	  for (skb2=skb->next; skb2 != sk->rqueue->next; skb2=skb2->next)
  	    {
  	       if (before(skb2->h.th->seq, sk->acked_seq+1))
  		 {
--- 2413,2421 ----
  	      sk->shutdown |= RCV_SHUTDOWN;
  	    }
  	  
! 	  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,2396 ****
        && 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;
--- 2479,2485 ----
        && sk->rcv_ack_seq == sk->send_seq)
      {
        PRINTK (("tcp_data: entering last_ack state sk = %X\n", sk));
! 
        tcp_send_ack (sk->send_seq, sk->acked_seq, sk, th, saddr);
        sk->shutdown = SHUTDOWN_MASK;
        sk->state = TCP_LAST_ACK;
***************
*** 2416,2437 ****
  	  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)
  	    {
! 		kill_proc (sk->proc, SIGURG, 1);
! 	    }
! 	  else 
! 	    {
! 		kill_pg (-sk->proc, SIGURG, 1);
  	    }
!       }
      return (0);
  }
  
--- 2505,2527 ----
  	  return (0);
        }
  
      if (!sk->urg)
        {
  	  /* so if we get more urgent data, we don't 
  	     signal the user again. */
! 	  if (sk->proc != 0)
  	    {
! 	      if (sk->proc > 0)
! 		{
! 		  kill_proc (sk->proc, SIGURG, 1);
! 		}
! 	      else 
! 		{
! 		  kill_pg (-sk->proc, SIGURG, 1);
! 		}
  	    }
! 	}
!     sk->urg++;
      return (0);
  }
  
***************
*** 2455,2460 ****
--- 2545,2551 ----
      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,2568 ****
    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. */
    
--- 2653,2658 ----
***************
*** 2689,2694 ****
--- 2779,2785 ----
    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,2805 ****
    if (sk)
      {
        PRINTK (("sk = %X:\n",sk));
-       print_sk (sk);
      }
  
    if (!redo)
--- 2890,2895 ----
***************
*** 2947,2952 ****
--- 3037,3043 ----
  	      return (0);
  	    }
  	}
+ #if 0
        if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
  	{
  	   sk->err = ECONNRESET;
***************
*** 2961,2967 ****
  	   release_sock(sk);
  	   return (0);
  	}
! 
        if (th->ack)
  	{
  	   if(!tcp_ack (sk, th, saddr))
--- 3052,3058 ----
  	   release_sock(sk);
  	   return (0);
  	}
! #endif
        if (th->ack)
  	{
  	   if(!tcp_ack (sk, th, saddr))
***************
*** 3079,3088 ****
  	  release_sock(sk);
  	  return (0);
  	}
! /*      if (opt->security != 0 || opt->compartment != 0 )
  	{
  	  sk->err = ECONNRESET;
  	  sk->state = TCP_CLOSE;
  	  tcp_reset (daddr, saddr,  th, sk->prot, opt, dev);
  	  if (!sk->dead)
  	  {
--- 3170,3181 ----
  	  release_sock(sk);
  	  return (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,3098 ****
  	  release_sock(sk);
  	  return (0);
  	} */
! 
        if (!th->ack) 
  	{
  	  if (th->syn)
--- 3185,3191 ----
  	  release_sock(sk);
  	  return (0);
  	} */
! #endif
        if (!th->ack) 
  	{
  	  if (th->syn)
***************
*** 3289,3295 ****
    tcp_shutdown,
    128,
    0,
!   {NULL,}
  };
  
  
--- 3382,3389 ----
    tcp_shutdown,
    128,
    0,
!   {NULL,},
!   "TCP"
  };
  
  
diff -c +recursive +new-files l99.4/linux/net/tcp/tcp.h linux/net/tcp/tcp.h
*** l99.4/linux/net/tcp/tcp.h	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/tcp.h	Mon Feb  1 22:42:55 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: tcp.h,v $
   * Revision 0.8.4.6  1992/12/12  19:25:04  bir7
   * Fixed anti-memory Leak in shutdown.
   *
--- 19,29 ----
      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.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 -c +recursive +new-files l99.4/linux/net/tcp/timer.c linux/net/tcp/timer.c
*** l99.4/linux/net/tcp/timer.c	Mon Jan 25 21:49:25 1993
--- linux/net/tcp/timer.c	Mon Feb  1 22:42:55 1993
***************
*** 20,27 ****
    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 $ */
  /* $Log: timer.c,v $
   * Revision 0.8.4.5  1992/12/12  19:25:04  bir7
   * cleaned up Log messages.
   *
--- 20,36 ----
    C/O Department of Mathematics; Stanford University; Stanford, CA 94305
    */
  
! /* $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,74 ****
  #define PRINTK(x) /**/
  #endif
  
! static struct timer *timer_base=NULL;
  unsigned long seq_offset;
  
  void
--- 77,83 ----
  #define PRINTK(x) /**/
  #endif
  
! static volatile struct timer *timer_base=NULL;
  unsigned long seq_offset;
  
  void
***************
*** 93,99 ****
  	sti();
  	return;
       }
!    for (tm = timer_base;tm->next != NULL ;tm=tm->next)
       {
  	if (tm->next == t)
  	  {
--- 102,110 ----
  	sti();
  	return;
       }
!    for (tm = (struct timer *)timer_base;
! 	tm->next != NULL ;
! 	tm=(struct timer *)tm->next)
       {
  	if (tm->next == t)
  	  {
***************
*** 139,145 ****
  	sti();
  	return;
       }
!    for (tm = timer_base; ; tm=tm->next)
       {
  	if (tm->next == NULL || before (t->when,tm->next->when))
  	  {
--- 150,156 ----
  	sti();
  	return;
       }
!    for (tm = (struct timer *)timer_base; ; tm=(struct timer *)tm->next)
       {
  	if (tm->next == NULL || before (t->when,tm->next->when))
  	  {
***************
*** 179,190 ****
  	  {
  	     sk->time_wait.len = TCP_TIMEOUT_LEN;
  	     sk->timeout = TIME_KEEPOPEN;
! 	     reset_timer (timer_base);
  	  }
  	else
  	  {
  	     sk->timeout = 0;
! 	     delete_timer(timer_base);
  	  }
  	
  	/* always see if we need to send an ack. */
--- 190,201 ----
  	  {
  	     sk->time_wait.len = TCP_TIMEOUT_LEN;
  	     sk->timeout = TIME_KEEPOPEN;
! 	     reset_timer ((struct timer *)timer_base);
  	  }
  	else
  	  {
  	     sk->timeout = 0;
! 	     delete_timer((struct timer *)timer_base);
  	  }
  	
  	/* always see if we need to send an ack. */
***************
*** 213,219 ****
  				  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;
--- 224,229 ----
diff -c +recursive +new-files l99.4/linux/net/tcp/timer.h linux/net/tcp/timer.h
*** l99.4/linux/net/tcp/timer.h	Mon Jan 25 21:49:26 1993
--- linux/net/tcp/timer.h	Mon Jan 25 19:26:57 1993
***************
*** 19,31 ****
      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 $ */
  /* $Log: timer.h,v $
   * 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 $iId$ and $Log: timer.h,v $
   * Revision 0.8.4.1  1992/11/10  00:17:18  bir7
   * version change only.
   *.
--- 19,37 ----
      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.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 $iId$ 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,45 ****
    unsigned long len;
    volatile struct sock *sk;
    unsigned long when;
!   struct timer *next;
  };
  
  
--- 45,51 ----
    unsigned long len;
    volatile struct sock *sk;
    unsigned long when;
!   volatile struct timer *next;
  };
  
  
diff -c +recursive +new-files l99.4/linux/net/tcp/udp.c linux/net/tcp/udp.c
*** l99.4/linux/net/tcp/udp.c	Mon Jan 25 21:49:26 1993
--- linux/net/tcp/udp.c	Fri Jan 29 16:13:28 1993
***************
*** 19,26 ****
      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 $ */
  /* $Log: udp.c,v $
   * Revision 0.8.4.9  1992/12/12  19:25:04  bir7
   * cleaned up Log messages.
   *
--- 19,35 ----
      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.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,380 ****
  
  		  if (skb == NULL)
  		    {
- 		       printk ("udp_sendto: write buffer full?\n");
- 		       print_sk(sk);
  		       tmp = sk->wmem_alloc;
  		       release_sock (sk);
  		       if (copied) return (copied);
--- 382,387 ----
***************
*** 555,560 ****
--- 562,568 ----
  		       return (-ERESTARTSYS);
  		    }
  	       }
+   	     sk->inuse = 1;
  	     sti();
  	  }
  	skb = sk->rqueue;
***************
*** 567,573 ****
  		    }
  		  else
  		    {
! 			    sk->rqueue = sk->rqueue ->next;
  			    skb->prev->next = skb->next;
  			    skb->next->prev = skb->prev;
  		    }
--- 575,581 ----
  		    }
  		  else
  		    {
! 			    sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
  			    skb->prev->next = skb->next;
  			    skb->next->prev = skb->prev;
  		    }
***************
*** 714,720 ****
  
  	/* 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)
--- 722,727 ----
***************
*** 769,774 ****
    NULL,
    128,
    0,
!   {NULL,}
  };
  
--- 776,782 ----
    NULL,
    128,
    0,
!   {NULL,},
!   "UDP"
  };
  
diff -c +recursive +new-files l99.4/linux/net/tcp/we.c linux/net/tcp/we.c
*** l99.4/linux/net/tcp/we.c	Mon Jan 25 21:49:24 1993
--- linux/net/tcp/we.c	Mon Jan 25 19:26:57 1993
***************
*** 44,51 ****
  /* 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 $ */
  /* $Log: we.c,v $
   * Revision 0.8.4.8  1992/12/12  19:25:04  bir7
   * cleaned up Log messages.
   *
--- 44,57 ----
  /* 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.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,94 ****
--- 95,101 ----
  #include <errno.h>
  #include <linux/fcntl.h>
  #include <netinet/in.h>
+ #include <linux/interrupt.h>
  
  #include "dev.h"
  #include "eth.h"
***************
*** 101,122 ****
  #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 */
--- 108,113 ----
***************
*** 145,151 ****
    outb_p(cmd, WD_COMM);
    outb_p(interrupt_mask,WD_IMR);
    sti();
!   status |= START;
  }
  
  int
--- 136,142 ----
    outb_p(cmd, WD_COMM);
    outb_p(interrupt_mask,WD_IMR);
    sti();
!   dev->start = 1;
  }
  
  int
***************
*** 198,204 ****
    cmd|= 4<<CRDMA_SHIFT;
    outb_p(cmd, WD_COMM);
    outb_p(WD_RCONFIG,WD_RCC);
-   status = OPEN;
    wd_start(dev); 
    return (0);
  }
--- 189,194 ----
***************
*** 227,233 ****
    int len;
  
    cli();
!   if (status & TRS_BUSY)
      {
         /* put in a time out. */
         if (jiffies - dev->trans_start < 30)
--- 217,223 ----
    int len;
  
    cli();
!   if (dev->tbusy)
      {
         /* put in a time out. */
         if (jiffies - dev->trans_start < 30)
***************
*** 237,243 ****
  
         printk ("wd8003 transmit timed out. \n");
      }
!   status |= TRS_BUSY;
  
    if (skb == NULL)
      {
--- 227,233 ----
  
         printk ("wd8003 transmit timed out. \n");
      }
!   dev->tbusy = 1;
  
    if (skb == NULL)
      {
***************
*** 264,270 ****
  	      arp_queue (skb);
  	    }
  	   cli (); /* arp_queue turns them back on. */
! 	   status &= ~TRS_BUSY;
  	   sti();
  	   return (0);
  	}
--- 254,260 ----
  	      arp_queue (skb);
  	    }
  	   cli (); /* arp_queue turns them back on. */
!  	  dev->tbusy = 0;
  	   sti();
  	   return (0);
  	}
***************
*** 285,291 ****
    outb_p(cmd, WD_COMM);
  
    interrupt_mask |= TRANS_MASK;
!   if (!(status & IN_INT))
      outb (interrupt_mask, WD_IMR);
  
    outb_p(len&0xff,WD_TB0);
--- 275,281 ----
    outb_p(cmd, WD_COMM);
  
    interrupt_mask |= TRANS_MASK;
!   if (!(dev->interrupt))
      outb (interrupt_mask, WD_IMR);
  
    outb_p(len&0xff,WD_TB0);
***************
*** 400,408 ****
  		  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;
  		  
--- 390,395 ----
***************
*** 478,485 ****
  static  void
  wd_trs( struct device *dev )
  {
! 	unsigned char cmd, errors;
! 	int len;
  
  	if( wd_debug )
  		printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
--- 465,471 ----
  static  void
  wd_trs( struct device *dev )
  {
! 	unsigned char errors;
  
  	if( wd_debug )
  		printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
***************
*** 489,495 ****
--- 475,484 ----
  			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,513 ****
  		}
  		else
  		{
! 			status &= ~TRS_BUSY;
  			interrupt_mask &= ~TRANS_MASK;
  			return;
  		}
! 	}
  	else{ /* TX error occurred! - H/W will reschedule */
  		if( errors & CRS ){
  			stats.tx_carrier_errors++;
--- 492,503 ----
  		}
  		else
  		{
! 			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,561 ****
  	if (wd_debug)
  		printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
  
! 	status |= IN_INT;
  
  	do{ /* find out who called */ 
  	  sti();
--- 545,551 ----
  	if (wd_debug)
  		printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
  
! 	dev->interrupt = 1;
  
  	do{ /* find out who called */ 
  	  sti();
***************
*** 632,638 ****
  		cli();
  	} while( inb_p( ISR ) != 0 );
  
! 	status &= ~IN_INT;
  }
  
  
--- 622,628 ----
  		cli();
  	} while( inb_p( ISR ) != 0 );
  
! 	dev->interrupt = 0;
  }
  
  
***************
*** 659,665 ****
        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");
--- 649,654 ----
***************
*** 709,715 ****
  	  if( (i - dev->mem_start) > 4096 )
  	  	break;
  	  else
! 	  	status = OPEN;
  	}
      }
    /* Calculate how many pages of memory on board */
--- 698,704 ----
  	  if( (i - dev->mem_start) > 4096 )
  	  	break;
  	  else
! 	  	return (1);
  	}
      }
    /* Calculate how many pages of memory on board */
***************
*** 734,740 ****
  	((char *)&stats)[i] = 0;
  
    printk ("\n");
!   status = 0;
  
    if (irqaction (dev->irq, &wd8003_sigaction))
      {
--- 723,730 ----
  	((char *)&stats)[i] = 0;
  
    printk ("\n");
!   dev->tbusy = 0;
!   dev->interrupt = 0;
  
    if (irqaction (dev->irq, &wd8003_sigaction))
      {
diff -c +recursive +new-files l99.4/linux/net/unix.c linux/net/unix.c
*** l99.4/linux/net/unix.c	Mon Jan 25 21:49:24 1993
--- linux/net/unix.c	Fri Jan 29 16:17:52 1993
***************
*** 8,14 ****
  #include <linux/un.h>
  #include <linux/fcntl.h>
  #include <linux/termios.h>
! 
  #include <asm/system.h>
  #include <asm/segment.h>
  
--- 8,15 ----
  #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,108 ****
   	unix_proto_shutdown,
   	unix_proto_setsockopt,
   	unix_proto_getsockopt,
!  	NULL /* unix_proto_fcntl. */
  };
  
  #ifdef SOCK_DEBUG
  void
  sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
--- 101,116 ----
   	unix_proto_shutdown,
   	unix_proto_setsockopt,
   	unix_proto_getsockopt,
!  	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,127 ****
  		       sockaddr_len + UN_PATH_OFFSET);
  	}
  }
! #endif
    
  /* don't have to do anything. */
  static int
--- 129,135 ----
  		       sockaddr_len + UN_PATH_OFFSET);
  	}
  }
! #endif /* SOCK_DEBUG */
    
  /* don't have to do anything. */
  static int
