diff -u --recursive --new-file v2.0.1/linux/CREDITS linux/CREDITS
--- v2.0.1/linux/CREDITS	Sun Jun  9 13:28:40 1996
+++ linux/CREDITS	Fri Jul  5 11:43:39 1996
@@ -1029,6 +1029,13 @@
 S: Thunder Bay, Ontario
 S: CANADA P7C 5M9
 
+N: Yuri Per
+E: yuri@pts.mipt.ru
+D: Some smbfs fixes
+S: Demonstratsii 8-382
+S: Tula 300000
+S: Russia
+
 N: Kai Petzke
 E: wpp@marie.physik.tu-berlin.de
 W: http://physik.tu-berlin.de/~wpp
diff -u --recursive --new-file v2.0.1/linux/Documentation/Changes linux/Documentation/Changes
--- v2.0.1/linux/Documentation/Changes	Wed Jul  3 22:05:06 1996
+++ linux/Documentation/Changes	Fri Jul  5 18:58:56 1996
@@ -179,7 +179,9 @@
 your computer shuts down fine but "INIT: error reading initrequest" or
 words to that effect scroll across your screen hundreds of times.  To
 fix, upgrade to
-ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.62.tar.gz.
+
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz or
+ftp://tsx-11.mit.edu /pub/linux/sources/sbin/sysvinit-2.64.tar.gz
 
    If you're trying to run NCSA httpd, you have to set pre-spawning of
 daemons to zero, as it incorrectly assumes SunOS behavior.  I recommend
diff -u --recursive --new-file v2.0.1/linux/Makefile linux/Makefile
--- v2.0.1/linux/Makefile	Wed Jul  3 22:05:06 1996
+++ linux/Makefile	Wed Jul  3 22:06:38 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 0
-SUBLEVEL = 1
+SUBLEVEL = 2
 
 ARCH = i386
 
diff -u --recursive --new-file v2.0.1/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.0.1/linux/arch/alpha/config.in	Wed Jun  5 10:41:27 1996
+++ linux/arch/alpha/config.in	Thu Jul  4 08:51:42 1996
@@ -123,6 +123,15 @@
 fi
 
 mainmenu_option next_comment
+comment 'ISDN subsystem'
+
+tristate 'ISDN support' CONFIG_ISDN
+if [ "$CONFIG_ISDN" != "n" ]; then
+  source drivers/isdn/Config.in
+fi
+endmenu
+
+mainmenu_option next_comment
 comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
 
 bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
diff -u --recursive --new-file v2.0.1/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.0.1/linux/arch/alpha/defconfig	Wed Jul  3 22:05:07 1996
+++ linux/arch/alpha/defconfig	Fri Jul  5 13:48:38 1996
@@ -162,6 +162,11 @@
 # CONFIG_ARCNET is not set
 
 #
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
 # CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
 #
 # CONFIG_CD_NO_IDESCSI is not set
diff -u --recursive --new-file v2.0.1/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.0.1/linux/drivers/char/serial.c	Wed Jul  3 22:05:08 1996
+++ linux/drivers/char/serial.c	Thu Jul  4 00:00:22 1996
@@ -2755,8 +2755,9 @@
 	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	serial_driver.subtype = SERIAL_TYPE_NORMAL;
 	serial_driver.init_termios = tty_std_termios;
-	serial_driver.init_termios.c_lflag &=~ (ISIG | ICANON | ECHO);
-	serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
 	serial_driver.refcount = &serial_refcount;
 	serial_driver.table = serial_table;
 	serial_driver.termios = serial_termios;
diff -u --recursive --new-file v2.0.1/linux/drivers/net/lance32.c linux/drivers/net/lance32.c
--- v2.0.1/linux/drivers/net/lance32.c	Tue May  7 16:22:29 1996
+++ linux/drivers/net/lance32.c	Thu Jul  4 08:52:04 1996
@@ -789,8 +789,8 @@
 lance32_get_stats(struct device *dev)
 {
 	struct lance32_private *lp = (struct lance32_private *)dev->priv;
-	short ioaddr = dev->base_addr;
-	short saved_addr;
+	int ioaddr = dev->base_addr;
+	unsigned short saved_addr;
 	unsigned long flags;
 
 	save_flags(flags);
@@ -809,7 +809,7 @@
 
 static void lance32_set_multicast_list(struct device *dev)
 {
-	short ioaddr = dev->base_addr;
+	int ioaddr = dev->base_addr;
 	struct lance32_private *lp = (struct lance32_private *)dev->priv;    
 
 	if (dev->flags&IFF_PROMISC) {
diff -u --recursive --new-file v2.0.1/linux/fs/exec.c linux/fs/exec.c
--- v2.0.1/linux/fs/exec.c	Wed Jul  3 22:05:18 1996
+++ linux/fs/exec.c	Fri Jul  5 15:06:38 1996
@@ -114,41 +114,34 @@
 
 int open_inode(struct inode * inode, int mode)
 {
-	int error, fd;
-	struct file *f, **fpp;
+	int fd;
 
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		return -EINVAL;
-	f = get_empty_filp();
-	if (!f)
-		return -ENFILE;
-	fd = 0;
-	fpp = current->files->fd;
-	for (;;) {
-		if (!*fpp)
-			break;
-		if (++fd >= NR_OPEN) {
-			f->f_count--;
-			return -EMFILE;
+	fd = get_unused_fd();
+	if (fd >= 0) {
+		struct file * f = get_empty_filp();
+		if (!f) {
+			put_unused_fd(fd);
+			return -ENFILE;
 		}
-		fpp++;
-	}
-	*fpp = f;
-	f->f_flags = mode;
-	f->f_mode = (mode+1) & O_ACCMODE;
-	f->f_inode = inode;
-	f->f_pos = 0;
-	f->f_reada = 0;
-	f->f_op = inode->i_op->default_file_ops;
-	if (f->f_op->open) {
-		error = f->f_op->open(inode,f);
-		if (error) {
-			*fpp = NULL;
-			f->f_count--;
-			return error;
+		f->f_flags = mode;
+		f->f_mode = (mode+1) & O_ACCMODE;
+		f->f_inode = inode;
+		f->f_pos = 0;
+		f->f_reada = 0;
+		f->f_op = inode->i_op->default_file_ops;
+		if (f->f_op->open) {
+			int error = f->f_op->open(inode,f);
+			if (error) {
+				f->f_count--;
+				put_unused_fd(fd);
+				return error;
+			}
 		}
+		current->files->fd[fd] = f;
+		inode->i_count++;
 	}
-	inode->i_count++;
 	return fd;
 }
 
@@ -399,10 +392,45 @@
 }
 
 /*
- * This function flushes out all traces of the currently running executable so
- * that a new one can be started
+ * These functions flushes out all traces of the currently running executable
+ * so that a new one can be started
  */
 
+static inline void flush_old_signals(struct signal_struct *sig)
+{
+	int i;
+	struct sigaction * sa = sig->action;
+
+	for (i=32 ; i != 0 ; i--) {
+		sa->sa_mask = 0;
+		sa->sa_flags = 0;
+		if (sa->sa_handler != SIG_IGN)
+			sa->sa_handler = NULL;
+		sa++;
+	}
+}
+
+static inline void flush_old_files(struct files_struct * files)
+{
+	unsigned long j;
+
+	j = 0;
+	for (;;) {
+		unsigned long set, i;
+
+		i = j * __NFDBITS;
+		if (i >= NR_OPEN)
+			break;
+		set = files->close_on_exec.fds_bits[j];
+		files->close_on_exec.fds_bits[j] = 0;
+		j++;
+		for ( ; set ; i++,set >>= 1) {
+			if (set & 1)
+				sys_close(i);
+		}
+	}
+}
+
 void flush_old_exec(struct linux_binprm * bprm)
 {
 	int i;
@@ -429,16 +457,9 @@
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
 	    permission(bprm->inode,MAY_READ))
 		current->dumpable = 0;
-	for (i=0 ; i<32 ; i++) {
-		current->sig->action[i].sa_mask = 0;
-		current->sig->action[i].sa_flags = 0;
-		if (current->sig->action[i].sa_handler != SIG_IGN)
-			current->sig->action[i].sa_handler = NULL;
-	}
-	for (i=0 ; i<NR_OPEN ; i++)
-		if (FD_ISSET(i,&current->files->close_on_exec))
-			sys_close(i);
-	FD_ZERO(&current->files->close_on_exec);
+
+	flush_old_signals(current->sig);
+	flush_old_files(current->files);
 }
 
 /* 
diff -u --recursive --new-file v2.0.1/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.0.1/linux/fs/fcntl.c	Sun May  5 08:52:03 1996
+++ linux/fs/fcntl.c	Thu Jul  4 21:23:45 1996
@@ -13,23 +13,24 @@
 #include <linux/fcntl.h>
 #include <linux/string.h>
 
+#include <asm/bitops.h>
+
 extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
 
 static inline int dupfd(unsigned int fd, unsigned int arg)
 {
-	if (fd >= NR_OPEN || !current->files->fd[fd])
+	struct files_struct * files = current->files;
+
+	if (fd >= NR_OPEN || !files->fd[fd])
 		return -EBADF;
 	if (arg >= NR_OPEN)
 		return -EINVAL;
-	while (arg < NR_OPEN)
-		if (current->files->fd[arg])
-			arg++;
-		else
-			break;
-	if (arg >= NR_OPEN)
+	arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
+	if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
 		return -EMFILE;
-	FD_CLR(arg, &current->files->close_on_exec);
-	(current->files->fd[arg] = current->files->fd[fd])->f_count++;
+	FD_SET(arg, &files->open_fds);
+	FD_CLR(arg, &files->close_on_exec);
+	(files->fd[arg] = files->fd[fd])->f_count++;
 	return arg;
 }
 
diff -u --recursive --new-file v2.0.1/linux/fs/open.c linux/fs/open.c
--- v2.0.1/linux/fs/open.c	Wed Jul  3 22:05:19 1996
+++ linux/fs/open.c	Fri Jul  5 09:27:10 1996
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 
 #include <asm/segment.h>
+#include <asm/bitops.h>
 
 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 {
@@ -496,11 +497,11 @@
  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
  * used by symlinks.
  */
-int do_open(const char * filename,int flags,int mode)
+static int do_open(const char * filename,int flags,int mode, int fd)
 {
 	struct inode * inode;
 	struct file * f;
-	int flag,error,fd;
+	int flag,error;
 
 	f = get_empty_filp();
 	if (!f)
@@ -533,21 +534,9 @@
 	}
 	f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 
-	/*
-	 * We have to do this last, because we mustn't export
-	 * an incomplete fd to other processes which may share
-	 * the same file table with us.
-	 */
-	for(fd = 0; fd < NR_OPEN && fd < current->rlim[RLIMIT_NOFILE].rlim_cur; fd++) {
-		if (!current->files->fd[fd]) {
-			current->files->fd[fd] = f;
-			FD_CLR(fd,&current->files->close_on_exec);
-			return fd;
-		}
-	}
-	error = -EMFILE;
-	if (f->f_op && f->f_op->release)
-		f->f_op->release(inode,f);
+	current->files->fd[fd] = f;
+	return 0;
+
 cleanup_all:
 	if (f->f_mode & FMODE_WRITE)
 		put_write_access(inode);
@@ -558,16 +547,44 @@
 	return error;
 }
 
+/*
+ * Find a empty file descriptor entry, and mark it busy
+ */
+int get_unused_fd(void)
+{
+	int fd;
+	struct files_struct * files = current->files;
+
+	fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
+	if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) {
+		FD_SET(fd, &files->open_fds);
+		FD_CLR(fd, &files->close_on_exec);
+		return fd;
+	}
+	return -EMFILE;
+}
+
+inline void put_unused_fd(int fd)
+{
+	FD_CLR(fd, &current->files->open_fds);
+}
+
 asmlinkage int sys_open(const char * filename,int flags,int mode)
 {
 	char * tmp;
-	int error;
+	int fd, error;
 
+	fd = get_unused_fd();
+	if (fd < 0)
+		return fd;
 	error = getname(filename, &tmp);
-	if (error)
-		return error;
-	error = do_open(tmp,flags,mode);
-	putname(tmp);
+	if (!error) {
+		error = do_open(tmp,flags,mode, fd);
+		putname(tmp);
+		if (!error)
+			return fd;
+	}
+	put_unused_fd(fd);
 	return error;
 }
 
@@ -610,16 +627,20 @@
 }
 
 asmlinkage int sys_close(unsigned int fd)
-{	
+{
+	int error;
 	struct file * filp;
+	struct files_struct * files;
 
-	if (fd >= NR_OPEN)
-		return -EBADF;
-	FD_CLR(fd, &current->files->close_on_exec);
-	if (!(filp = current->files->fd[fd]))
-		return -EBADF;
-	current->files->fd[fd] = NULL;
-	return (close_fp (filp));
+	files = current->files;
+	error = -EBADF;
+	if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) {
+		put_unused_fd(fd);
+		FD_CLR(fd, &files->close_on_exec);
+		files->fd[fd] = NULL;
+		error = close_fp(filp);
+	}
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.0.1/linux/fs/pipe.c linux/fs/pipe.c
--- v2.0.1/linux/fs/pipe.c	Wed Jul  3 22:05:19 1996
+++ linux/fs/pipe.c	Thu Jul  4 21:17:24 1996
@@ -414,45 +414,58 @@
 int do_pipe(int *fd)
 {
 	struct inode * inode;
-	struct file *f[2];
+	struct file *f1, *f2;
+	int error;
 	int i,j;
 
+	error = ENFILE;
+	f1 = get_empty_filp();
+	if (!f1)
+		goto no_files;
+
+	f2 = get_empty_filp();
+	if (!f2)
+		goto close_f1;
+
 	inode = get_pipe_inode();
 	if (!inode)
-		return -ENFILE;
+		goto close_f12;
+
+	error = get_unused_fd();
+	if (error < 0)
+		goto close_f12_inode;
+	i = error;
 
-	for(j=0 ; j<2 ; j++)
-		if (!(f[j] = get_empty_filp()))
-			break;
-	if (j < 2) {
-		iput(inode);
-		iput(inode);
-		if (j)
-			f[0]->f_count--;
-		return -ENFILE;
-	}
-	j=0;
-	for(i=0;j<2 && i<NR_OPEN && i<current->rlim[RLIMIT_NOFILE].rlim_cur;i++)
-		if (!current->files->fd[i]) {
-			current->files->fd[ fd[j]=i ] = f[j];
-			j++;
-		}
-	if (j<2) {
-		iput(inode);
-		iput(inode);
-		f[0]->f_count--;
-		f[1]->f_count--;
-		if (j)
-			current->files->fd[fd[0]] = NULL;
-		return -EMFILE;
-	}
-	f[0]->f_inode = f[1]->f_inode = inode;
-	f[0]->f_pos = f[1]->f_pos = 0;
-	f[0]->f_flags = O_RDONLY;
-	f[0]->f_op = &read_pipe_fops;
-	f[0]->f_mode = 1;		/* read */
-	f[1]->f_flags = O_WRONLY;
-	f[1]->f_op = &write_pipe_fops;
-	f[1]->f_mode = 2;		/* write */
+	error = get_unused_fd();
+	if (error < 0)
+		goto close_f12_inode_i;
+	j = error;
+
+	f1->f_inode = f2->f_inode = inode;
+	/* read file */
+	f1->f_pos = f2->f_pos = 0;
+	f1->f_flags = O_RDONLY;
+	f1->f_op = &read_pipe_fops;
+	f1->f_mode = 1;
+	/* write file */
+	f2->f_flags = O_WRONLY;
+	f2->f_op = &write_pipe_fops;
+	f2->f_mode = 2;
+	current->files->fd[i] = f1;
+	current->files->fd[j] = f2;
+	fd[0] = i;
+	fd[1] = j;
 	return 0;
+
+close_f12_inode_i:
+	put_unused_fd(i);
+close_f12_inode:
+	inode->i_count--;
+	iput(inode);
+close_f12:
+	f2->f_count--;
+close_f1:
+	f1->f_count--;
+no_files:
+	return error;	
 }
diff -u --recursive --new-file v2.0.1/linux/fs/select.c linux/fs/select.c
--- v2.0.1/linux/fs/select.c	Wed Sep 27 09:57:19 1995
+++ linux/fs/select.c	Fri Jul  5 13:48:39 1996
@@ -92,11 +92,13 @@
 	int i,j;
 	int max = -1;
 
-	for (j = 0 ; j < __FDSET_INTS ; j++) {
+	j = 0;
+	for (;;) {
 		i = j * __NFDBITS;
 		if (i >= n)
 			break;
 		set = in->fds_bits[j] | out->fds_bits[j] | ex->fds_bits[j];
+		j++;
 		for ( ; set ; i++,set >>= 1) {
 			if (i >= n)
 				goto end_check;
@@ -113,9 +115,6 @@
 	n = max + 1;
 	if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
-	FD_ZERO(res_in);
-	FD_ZERO(res_out);
-	FD_ZERO(res_ex);
 	count = 0;
 	wait_table.nr = 0;
 	wait_table.entry = entry;
@@ -153,51 +152,79 @@
 /*
  * We do a VERIFY_WRITE here even though we are only reading this time:
  * we'll write to it eventually..
+ *
+ * Use "int" accesses to let user-mode fd_set's be int-aligned.
  */
-static int __get_fd_set(int nr, unsigned int * fs_pointer, fd_set * fdset)
+static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset)
 {
-	int error, i;
-	unsigned int * tmp;
-
-	FD_ZERO(fdset);
-	if (!fs_pointer)
-		return 0;
-	error = verify_area(VERIFY_WRITE,fs_pointer,sizeof(fd_set));
-	if (error)
+	/* round up nr to nearest "int" */
+	nr = (nr + 8*sizeof(int)-1) / (8*sizeof(int));
+	if (fs_pointer) {
+		int error = verify_area(VERIFY_WRITE,fs_pointer,nr*sizeof(int));
+		if (!error) {
+			while (nr) {
+				*fdset = get_user(fs_pointer);
+				nr--;
+				fs_pointer++;
+				fdset++;
+			}
+		}
 		return error;
-	tmp = fdset->fds_bits;
-	for (i = __FDSET_INTS; i > 0; i--) {
-		if (nr <= 0)
-			break;
-		*tmp = get_user(fs_pointer);
-		tmp++;
-		fs_pointer++;
-		nr -= 8 * sizeof(unsigned int);
+	}
+	while (nr) {
+		*fdset = 0;
+		nr--;
+		fdset++;
 	}
 	return 0;
 }
 
-static void __set_fd_set(int nr, unsigned int * fs_pointer, unsigned int * fdset)
+static void __set_fd_set(long nr, int * fs_pointer, int * fdset)
 {
-	int i;
-
 	if (!fs_pointer)
 		return;
-	for (i = __FDSET_INTS; i > 0; i--) {
-		if (nr <= 0)
-			break;
+	while (nr >= 0) {
 		put_user(*fdset, fs_pointer);
+		nr -= 8 * sizeof(int);
 		fdset++;
 		fs_pointer++;
-		nr -= 8 * sizeof(unsigned int);
 	}
 }
 
+/* We can do long accesses here, kernel fdsets are always long-aligned */
+static inline void __zero_fd_set(long nr, unsigned long * fdset)
+{
+	while (nr >= 0) {
+		*fdset = 0;
+		nr -= 8 * sizeof(unsigned long);
+		fdset++;
+	}
+}		
+
+/*
+ * Due to kernel stack usage, we use a _limited_ fd_set type here, and once
+ * we really start supporting >256 file descriptors we'll probably have to
+ * allocate the kernel fd_set copies dynamically.. (The kernel select routines
+ * are careful to touch only the defined low bits of any fd_set pointer, this
+ * is important for performance too).
+ *
+ * Note a few subtleties: we use "long" for the dummy, not int, and we do a
+ * subtract by 1 on the nr of file descriptors. The former is better for
+ * machines with long > int, and the latter allows us to test the bit count
+ * against "zero or positive", which can mostly be just a sign bit test..
+ */
+typedef struct {
+	unsigned long dummy[NR_OPEN/(8*(sizeof(unsigned long)))];
+} limited_fd_set;
+
 #define get_fd_set(nr,fsp,fdp) \
-__get_fd_set(nr, (unsigned int *) (fsp), fdp)
+__get_fd_set(nr, (int *) (fsp), (int *) (fdp))
 
 #define set_fd_set(nr,fsp,fdp) \
-__set_fd_set(nr, (unsigned int *) (fsp), (unsigned int *) (fdp))
+__set_fd_set((nr)-1, (int *) (fsp), (int *) (fdp))
+
+#define zero_fd_set(nr,fdp) \
+__zero_fd_set((nr)-1, (unsigned long *) (fdp))
 
 /*
  * We can actually return ERESTARTSYS instead of EINTR, but I'd
@@ -209,31 +236,41 @@
  */
 asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
-	int i;
-	fd_set res_in, in;
-	fd_set res_out, out;
-	fd_set res_ex, ex;
+	int error;
+	limited_fd_set res_in, in;
+	limited_fd_set res_out, out;
+	limited_fd_set res_ex, ex;
 	unsigned long timeout;
 
+	error = -EINVAL;
 	if (n < 0)
-		return -EINVAL;
+		goto out;
 	if (n > NR_OPEN)
 		n = NR_OPEN;
-	if ((i = get_fd_set(n, inp, &in)) ||
-	    (i = get_fd_set(n, outp, &out)) ||
-	    (i = get_fd_set(n, exp, &ex))) return i;
+	if ((error = get_fd_set(n, inp, &in)) ||
+	    (error = get_fd_set(n, outp, &out)) ||
+	    (error = get_fd_set(n, exp, &ex))) goto out;
 	timeout = ~0UL;
 	if (tvp) {
-		i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
-		if (i)
-			return i;
+		error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
+		if (error)
+			goto out;
 		timeout = ROUND_UP(get_user(&tvp->tv_usec),(1000000/HZ));
 		timeout += get_user(&tvp->tv_sec) * (unsigned long) HZ;
 		if (timeout)
 			timeout += jiffies + 1;
 	}
+	zero_fd_set(n, &res_in);
+	zero_fd_set(n, &res_out);
+	zero_fd_set(n, &res_ex);
 	current->timeout = timeout;
-	i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex);
+	error = do_select(n,
+		(fd_set *) &in,
+		(fd_set *) &out,
+		(fd_set *) &ex,
+		(fd_set *) &res_in,
+		(fd_set *) &res_out,
+		(fd_set *) &res_ex);
 	timeout = current->timeout - jiffies - 1;
 	current->timeout = 0;
 	if ((long) timeout < 0)
@@ -244,12 +281,17 @@
 		timeout *= (1000000/HZ);
 		put_user(timeout, &tvp->tv_usec);
 	}
-	if (i < 0)
-		return i;
-	if (!i && (current->signal & ~current->blocked))
-		return -ERESTARTNOHAND;
+	if (error < 0)
+		goto out;
+	if (!error) {
+		error = -ERESTARTNOHAND;
+		if (current->signal & ~current->blocked)
+			goto out;
+		error = 0;
+	}
 	set_fd_set(n, inp, &res_in);
 	set_fd_set(n, outp, &res_out);
 	set_fd_set(n, exp, &res_ex);
-	return i;
+out:
+	return error;
 }
diff -u --recursive --new-file v2.0.1/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.0.1/linux/fs/smbfs/proc.c	Wed Jul  3 22:05:19 1996
+++ linux/fs/smbfs/proc.c	Fri Jul  5 11:43:38 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
  *
+ *  28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
  */
 
 #include <linux/config.h>
@@ -1152,6 +1153,7 @@
         int info_level = 1;
 
 	char *p;
+	char *lastname;
 	int i;
 	int first, total_count;
         struct smb_dirent *current_entry;
@@ -1171,9 +1173,15 @@
         int ff_dir_handle=0;
         int loop_count = 0;
 
-	int dirlen = strlen(SMB_FINFO(dir)->path);
-	char mask[dirlen + 5];
+	int dirlen = strlen(SMB_FINFO(dir)->path) + 3;
+	char *mask;
 
+	mask = smb_kmalloc(dirlen, GFP_KERNEL);
+	if (mask == NULL)
+	{
+		printk("smb_proc_readdir_long: Memory allocation failed\n");
+		return -ENOMEM;
+	}
 	strcpy(mask, SMB_FINFO(dir)->path);
 	strcat(mask, "\\*");
 
@@ -1297,22 +1305,37 @@
                 p = resp_data;
 
                 /* we might need the lastname for continuations */
+		lastname = "";
                 if (ff_lastname > 0)
                 {
                         switch(info_level)
                         {
                         case 260:
-                                ff_resume_key =0;
-                                strcpy(mask,p+ff_lastname+94);
+				lastname = p + ff_lastname + 94;
+				ff_resume_key = 0;
                                 break;
                         case 1:
-                                strcpy(mask,p + ff_lastname + 1);
+				lastname = p + ff_lastname + 1;
                                 ff_resume_key = 0;
                                 break;
                         }
                 }
-                else
-                        strcpy(mask,"");
+  
+		/* Increase size of mask, if it is too small */
+		i = strlen(lastname) + 1;
+		if (i > dirlen)
+		{
+			smb_kfree_s(mask,  0);
+			dirlen = i;
+			mask = smb_kmalloc(dirlen, GFP_KERNEL);
+			if (mask == NULL)
+			{
+				printk("smb_proc_readdir_long: Memory allocation failed\n");
+				result = -ENOMEM;
+				break;
+			}
+			strcpy(mask, lastname);
+		}
   
 		/* Now we are ready to parse smb directory entries. */
 		
@@ -1355,6 +1378,9 @@
         }
 
  finished:
+ 	if (mask != NULL)
+		smb_kfree_s(mask,  0);
+
         if (resp_data != NULL) {
                 smb_kfree_s(resp_data,  0);
                 resp_data = NULL;
diff -u --recursive --new-file v2.0.1/linux/include/asm-alpha/errno.h linux/include/asm-alpha/errno.h
--- v2.0.1/linux/include/asm-alpha/errno.h	Wed Jul  3 22:05:19 1996
+++ linux/include/asm-alpha/errno.h	Thu Jul  4 07:28:57 1996
@@ -106,9 +106,9 @@
 #define	ENOANO		100	/* No anode */
 #define	EBADRQC		101	/* Invalid request code */
 #define	EBADSLT		102	/* Invalid slot */
-#if 0
-#define	EDEADLOCK	103	/* File locking deadlock error */
-#endif
+
+#define	EDEADLOCK	EDEADLK
+
 #define	EBFONT		104	/* Bad font file format */
 #define	ENONET		105	/* Machine is not on the network */
 #define	ENOLINK		106	/* Link has been severed */
diff -u --recursive --new-file v2.0.1/linux/include/asm-alpha/posix_types.h linux/include/asm-alpha/posix_types.h
--- v2.0.1/linux/include/asm-alpha/posix_types.h	Fri Apr  5 13:35:28 1996
+++ linux/include/asm-alpha/posix_types.h	Fri Jul  5 13:48:39 1996
@@ -74,18 +74,18 @@
 #undef __FD_ZERO
 static __inline__ void __FD_ZERO(__kernel_fd_set *p)
 {
-	unsigned int *tmp = p->fds_bits;
+	unsigned long *tmp = p->fds_bits;
 	int i;
 
-	if (__builtin_constant_p(__FDSET_INTS)) {
-		switch (__FDSET_INTS) {
+	if (__builtin_constant_p(__FDSET_LONGS)) {
+		switch (__FDSET_LONGS) {
 			case 8:
 				tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0;
 				tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0;
 				return;
 		}
 	}
-	i = __FDSET_INTS;
+	i = __FDSET_LONGS;
 	while (i) {
 		i--;
 		*tmp = 0;
diff -u --recursive --new-file v2.0.1/linux/include/asm-i386/errno.h linux/include/asm-i386/errno.h
--- v2.0.1/linux/include/asm-i386/errno.h	Wed Jul  3 22:05:19 1996
+++ linux/include/asm-i386/errno.h	Thu Jul  4 07:28:57 1996
@@ -58,9 +58,9 @@
 #define	ENOANO		55	/* No anode */
 #define	EBADRQC		56	/* Invalid request code */
 #define	EBADSLT		57	/* Invalid slot */
-#if 0
-#define	EDEADLOCK	58	/* File locking deadlock error */
-#endif
+
+#define	EDEADLOCK	EDEADLK
+
 #define	EBFONT		59	/* Bad font file format */
 #define	ENOSTR		60	/* Device not a stream */
 #define	ENODATA		61	/* No data available */
diff -u --recursive --new-file v2.0.1/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.0.1/linux/include/linux/fs.h	Wed Jul  3 22:05:20 1996
+++ linux/include/linux/fs.h	Fri Jul  5 18:24:23 1996
@@ -623,6 +623,8 @@
 extern void insert_inode_hash(struct inode *);
 extern void clear_inode(struct inode *);
 extern struct inode * get_pipe_inode(void);
+extern int get_unused_fd(void);
+extern void put_unused_fd(int);
 extern struct file * get_empty_filp(void);
 extern int close_fp(struct file *filp);
 extern struct buffer_head * get_hash_table(kdev_t dev, int block, int size);
diff -u --recursive --new-file v2.0.1/linux/include/linux/in.h linux/include/linux/in.h
--- v2.0.1/linux/include/linux/in.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/in.h	Fri Jul  5 15:10:58 1996
@@ -101,7 +101,7 @@
 #define	INADDR_BROADCAST	((unsigned long int) 0xffffffff)
 
 /* Address indicating an error return. */
-#define	INADDR_NONE		0xffffffff
+#define	INADDR_NONE		((unsigned long int) 0xffffffff)
 
 /* Network number for local host loopback. */
 #define	IN_LOOPBACKNET		127
diff -u --recursive --new-file v2.0.1/linux/include/linux/posix_types.h linux/include/linux/posix_types.h
--- v2.0.1/linux/include/linux/posix_types.h	Wed Jul  3 22:05:20 1996
+++ linux/include/linux/posix_types.h	Fri Jul  5 13:48:39 1996
@@ -27,22 +27,22 @@
  * use the ones here. 
  */
 #undef __NFDBITS
-#define __NFDBITS	(8 * sizeof(unsigned int))
+#define __NFDBITS	(8 * sizeof(unsigned long))
 
 #undef __FD_SETSIZE
 #define __FD_SETSIZE	1024
 
-#undef __FDSET_INTS
-#define __FDSET_INTS	(__FD_SETSIZE/__NFDBITS)
+#undef __FDSET_LONGS
+#define __FDSET_LONGS	(__FD_SETSIZE/__NFDBITS)
 
 #undef __FDELT
 #define	__FDELT(d)	((d) / __NFDBITS)
 
 #undef __FDMASK
-#define	__FDMASK(d)	(1 << ((d) % __NFDBITS))
+#define	__FDMASK(d)	(1UL << ((d) % __NFDBITS))
 
 typedef struct {
-	unsigned int fds_bits [__FDSET_INTS];
+	unsigned long fds_bits [__FDSET_LONGS];
 } __kernel_fd_set;
 
 #include <asm/posix_types.h>
diff -u --recursive --new-file v2.0.1/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.0.1/linux/include/linux/sched.h	Mon Jun  3 16:46:58 1996
+++ linux/include/linux/sched.h	Fri Jul  5 18:24:23 1996
@@ -108,19 +108,17 @@
 
 asmlinkage void schedule(void);
 
-/* ??? */
+/* Open file table structure */
 struct files_struct {
-	/* ??? */
 	int count;
-	/* bit mask to close fds on exec */
 	fd_set close_on_exec;
-	/* do we have at most NR_OPEN available fds? I assume fd i maps into
- 	 * each open file */	
+	fd_set open_fds;
 	struct file * fd[NR_OPEN];
 };
 
 #define INIT_FILES { \
 	1, \
+	{ { 0, } }, \
 	{ { 0, } }, \
 	{ NULL, } \
 }
diff -u --recursive --new-file v2.0.1/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.0.1/linux/include/net/tcp.h	Tue May 21 19:52:38 1996
+++ linux/include/net/tcp.h	Fri Jul  5 18:29:39 1996
@@ -174,22 +174,6 @@
 extern void tcp_delack_timer(unsigned long);
 extern void tcp_retransmit_timer(unsigned long);
 
-/*
- *	Default sequence number picking algorithm.
- *	As close as possible to RFC 793, which
- *	suggests using a 250kHz clock.
- *	Further reading shows this assumes 2MB/s networks.
- *	For 10MB/s ethernet, a 1MHz clock is appropriate.
- *	That's funny, Linux has one built in!  Use it!
- */
-
-static inline u32 tcp_init_seq(void)
-{
-	struct timeval tv;
-	do_gettimeofday(&tv);
-	return tv.tv_usec+tv.tv_sec*1000000;
-}
-
 static __inline__ int tcp_old_window(struct sock * sk)
 {
 	return sk->window - (sk->acked_seq - sk->lastwin_seq);
diff -u --recursive --new-file v2.0.1/linux/kernel/exit.c linux/kernel/exit.c
--- v2.0.1/linux/kernel/exit.c	Wed Jul  3 22:05:20 1996
+++ linux/kernel/exit.c	Fri Jul  5 13:48:39 1996
@@ -393,6 +393,26 @@
 	}
 }
 
+static inline void close_files(struct files_struct * files)
+{
+	int i, j;
+
+	j = 0;
+	for (;;) {
+		unsigned long set = files->open_fds.fds_bits[j];
+		i = j * __NFDBITS;
+		j++;
+		if (i >= NR_OPEN)
+			break;
+		while (set) {
+			if (set & 1)
+				close_fp(files->fd[i]);
+			i++;
+			set >>= 1;
+		}
+	}
+}
+
 static inline void __exit_files(struct task_struct *tsk)
 {
 	struct files_struct * files = tsk->files;
@@ -400,14 +420,7 @@
 	if (files) {
 		tsk->files = NULL;
 		if (!--files->count) {
-			int i;
-			for (i=0 ; i<NR_OPEN ; i++) {
-				struct file * filp = files->fd[i];
-				if (!filp)
-					continue;
-				files->fd[i] = NULL;
-				close_fp(filp);
-			}
+			close_files(files);
 			kfree(files);
 		}
 	}
diff -u --recursive --new-file v2.0.1/linux/kernel/fork.c linux/kernel/fork.c
--- v2.0.1/linux/kernel/fork.c	Wed Jul  3 22:05:20 1996
+++ linux/kernel/fork.c	Thu Jul  4 20:09:41 1996
@@ -160,22 +160,33 @@
 static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk)
 {
 	int i;
+	struct files_struct *oldf, *newf;
+	struct file **old_fds, **new_fds;
 
+	oldf = current->files;
 	if (clone_flags & CLONE_FILES) {
-		current->files->count++;
+		oldf->count++;
 		return 0;
 	}
-	tsk->files = kmalloc(sizeof(*tsk->files), GFP_KERNEL);
-	if (!tsk->files)
+
+	newf = kmalloc(sizeof(*newf), GFP_KERNEL);
+	tsk->files = newf;
+	if (!newf)
 		return -1;
-	tsk->files->count = 1;
-	memcpy(&tsk->files->close_on_exec, &current->files->close_on_exec,
-		sizeof(tsk->files->close_on_exec));
-	for (i = 0; i < NR_OPEN; i++) {
-		struct file * f = current->files->fd[i];
+			
+	newf->count = 1;
+	newf->close_on_exec = oldf->close_on_exec;
+	newf->open_fds = oldf->open_fds;
+
+	old_fds = oldf->fd;
+	new_fds = newf->fd;
+	for (i = NR_OPEN; i != 0; i--) {
+		struct file * f = *old_fds;
+		old_fds++;
+		*new_fds = f;
+		new_fds++;
 		if (f)
 			f->f_count++;
-		tsk->files->fd[i] = f;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.0.1/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.0.1/linux/net/ipv4/af_inet.c	Wed Jul  3 22:05:23 1996
+++ linux/net/ipv4/af_inet.c	Fri Jul  5 18:17:12 1996
@@ -926,7 +926,7 @@
 			 *	Reuse ?
 			 */
 			 
-			if (!sk2->dead)
+			if (!sk2->reuse || sk2->state==TCP_LISTEN)
 			{
 				sti();
 				return(-EADDRINUSE);
diff -u --recursive --new-file v2.0.1/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.0.1/linux/net/ipv4/tcp.c	Wed Jul  3 22:05:23 1996
+++ linux/net/ipv4/tcp.c	Fri Jul  5 18:17:12 1996
@@ -202,6 +202,7 @@
  *					improvement.
  *	Stefan Magdalinski	:	adjusted tcp_readable() to fix FIONREAD
  *	Willy Konynenberg	:	Transparent proxying support.
+ *		Theodore Ts'o	:	Do secure TCP sequence numbers.
  *					
  * To Fix:
  *		Fast path the code. Two things here - fix the window calculation
@@ -427,6 +428,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
+#include <linux/random.h>
 
 #include <net/icmp.h>
 #include <net/tcp.h>
@@ -1886,6 +1888,36 @@
 	goto out;
 }
 
+/*
+ * Check that a TCP address is unique, don't allow multiple
+ * connects to/from the same address
+ */
+static int tcp_unique_address(u32 saddr, u16 snum, u32 daddr, u16 dnum)
+{
+	int retval = 1;
+	struct sock * sk;
+
+	/* Make sure we are allowed to connect here. */
+	cli();
+	for (sk = tcp_prot.sock_array[snum & (SOCK_ARRAY_SIZE -1)];
+			sk != NULL; sk = sk->next)
+	{
+		/* hash collision? */
+		if (sk->num != snum)
+			continue;
+		if (sk->saddr != saddr)
+			continue;
+		if (sk->daddr != daddr)
+			continue;
+		if (sk->dummy_th.dest != dnum)
+			continue;
+		retval = 0;
+		break;
+	}
+	sti();
+	return retval;
+}
+
 
 /*
  *	This will initiate an outgoing connection.
@@ -1921,7 +1953,7 @@
   	 *	connect() to INADDR_ANY means loopback (BSD'ism).
   	 */
 
-  	if(usin->sin_addr.s_addr==INADDR_ANY)
+  	if (usin->sin_addr.s_addr==INADDR_ANY)
 		usin->sin_addr.s_addr=ip_my_addr();
 
 	/*
@@ -1931,27 +1963,26 @@
 	if ((atype=ip_chk_addr(usin->sin_addr.s_addr)) == IS_BROADCAST || atype==IS_MULTICAST)
 		return -ENETUNREACH;
 
+	if (!tcp_unique_address(sk->saddr, sk->num, usin->sin_addr.s_addr, usin->sin_port))
+		return -EADDRNOTAVAIL;
+
 	lock_sock(sk);
 	sk->daddr = usin->sin_addr.s_addr;
-	sk->write_seq = tcp_init_seq();
-	sk->window_seq = sk->write_seq;
-	sk->rcv_ack_seq = sk->write_seq -1;
+
 	sk->rcv_ack_cnt = 1;
 	sk->err = 0;
 	sk->dummy_th.dest = usin->sin_port;
-	release_sock(sk);
 
 	buff = sock_wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
 	if (buff == NULL)
 	{
+		release_sock(sk);
 		return(-ENOMEM);
 	}
-	lock_sock(sk);
 	buff->sk = sk;
 	buff->free = 0;
 	buff->localroute = sk->localroute;
 
-
 	/*
 	 *	Put in the IP header and routing stuff.
 	 */
@@ -1967,6 +1998,15 @@
 	if ((rt = sk->ip_route_cache) != NULL && !sk->saddr)
 		sk->saddr = rt->rt_src;
 	sk->rcv_saddr = sk->saddr;
+
+	/*
+	 * Set up our outgoing TCP sequence number
+	 */
+	sk->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
+						   sk->dummy_th.source,
+						   usin->sin_port);
+	sk->window_seq = sk->write_seq;
+	sk->rcv_ack_seq = sk->write_seq -1;
 
 	t1 = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
 
diff -u --recursive --new-file v2.0.1/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.0.1/linux/net/ipv4/tcp_input.c	Wed Jul  3 22:05:23 1996
+++ linux/net/ipv4/tcp_input.c	Thu Jul  4 12:54:01 1996
@@ -28,9 +28,12 @@
  *		Eric Schenk	: 	Skip fast retransmit on small windows.
  *		Eric schenk	:	Fixes to retransmission code to
  *				:	avoid extra retransmission.
+ *		Theodore Ts'o	:	Do secure TCP sequence numbers.
  */
 
 #include <linux/config.h>
+#include <linux/types.h>
+#include <linux/random.h>
 #include <net/tcp.h>
 
 /*
@@ -208,7 +211,17 @@
 	 * 	from the far end, but sometimes it means the far end lost
 	 *	an ACK we sent, so we better send an ACK.
 	 */
-	tcp_send_ack(sk);
+	/*
+	 *	BEWARE! Unconditional answering by ack to out-of-window ack
+	 *	can result in infinite exchange of empty acks.
+	 *	This check cures bug, found by Michiel Boland, but
+	 *	not another possible cases.
+	 *	If we are in TCP_TIME_WAIT, we have already received
+	 *	FIN, so that our peer need not window update. If our
+	 *	ACK were lost, peer would retransmit his FIN anyway. --ANK
+	 */
+	if (sk->state != TCP_TIME_WAIT || ntohl(th->seq) != end_seq)
+		tcp_send_ack(sk);
 }
 
 /*
@@ -1722,6 +1735,7 @@
 	struct tcphdr *th;
 	struct sock *sk;
 	int syn_ok=0;
+	__u32 seq;
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	int r;
 #endif
@@ -1859,10 +1873,12 @@
 			}
 		
 			/*	
-			 *	Guess we need to make a new socket up 
+			 *	Guess we need to make a new socket up
 			 */
-		
-			tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq());
+			seq = secure_tcp_sequence_number(saddr, daddr,
+							 skb->h.th->dest,
+							 skb->h.th->source);
+			tcp_conn_request(sk, skb, daddr, saddr, opt, dev, seq);
 		
 			/*
 			 *	Now we have several options: In theory there is nothing else
diff -u --recursive --new-file v2.0.1/linux/net/socket.c linux/net/socket.c
--- v2.0.1/linux/net/socket.c	Wed Jul  3 22:05:23 1996
+++ linux/net/socket.c	Thu Jul  4 21:26:25 1996
@@ -172,36 +172,31 @@
 static int get_fd(struct inode *inode)
 {
 	int fd;
-	struct file *file;
 
 	/*
 	 *	Find a file descriptor suitable for return to the user. 
 	 */
 
-	file = get_empty_filp();
-	if (!file) 
-		return(-1);
+	fd = get_unused_fd();
+	if (fd >= 0) {
+		struct file *file = get_empty_filp();
 
-	for (fd = 0; fd < NR_OPEN; ++fd)
-		if (!current->files->fd[fd]) 
-			break;
-	if (fd == NR_OPEN) 
-	{
-		file->f_count = 0;
-		return(-1);
-	}
+		if (!file) {
+			put_unused_fd(fd);
+			return -ENFILE;
+		}
 
-	FD_CLR(fd, &current->files->close_on_exec);
 		current->files->fd[fd] = file;
-	file->f_op = &socket_file_ops;
-	file->f_mode = 3;
-	file->f_flags = O_RDWR;
-	file->f_count = 1;
-	file->f_inode = inode;
-	if (inode) 
-		inode->i_count++;
-	file->f_pos = 0;
-	return(fd);
+		file->f_op = &socket_file_ops;
+		file->f_mode = 3;
+		file->f_flags = O_RDWR;
+		file->f_count = 1;
+		file->f_inode = inode;
+		if (inode) 
+			inode->i_count++;
+		file->f_pos = 0;
+	}
+	return fd;
 }
 
 
diff -u --recursive --new-file v2.0.1/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.0.1/linux/net/unix/af_unix.c	Fri May 17 15:32:21 1996
+++ linux/net/unix/af_unix.c	Fri Jul  5 16:57:33 1996
@@ -710,10 +710,9 @@
 	int num=cmsg->cmsg_len-sizeof(struct cmsghdr);
 	int i;
 	int *fdp=(int *)cmsg->cmsg_data;
-	num/=4;	/* Odd bytes are forgotten in BSD not errored */
-	
 
-	if(num>=UNIX_MAX_FD)
+	num /= sizeof(int);	/* Odd bytes are forgotten in BSD not errored */
+	if (num >= UNIX_MAX_FD)
 		return -EINVAL;
 	
 	/*
@@ -728,9 +727,9 @@
 #if 0
 		printk("testing  fd %d\n", fd);
 #endif
-		if(fd < 0|| fd >=NR_OPEN)
+		if (fd < 0 || fd >= NR_OPEN)
 			return -EBADF;
-		if(current->files->fd[fd]==NULL)
+		if (current->files->fd[fd]==NULL)
 			return -EBADF;
 	}
 	
@@ -759,30 +758,6 @@
 	}
 }
 
-/*
- *	Count the free descriptors available to a process. 
- *	Interpretation issue: Is the limit the highest descriptor (buggy
- *	allowing passed fd's higher up to cause a limit to be exceeded) -
- *	but how the old code did it - or like this...
- */
-
-static int unix_files_free(void)
-{
-	int i;
-	int n=0;
-	for (i=0;i<NR_OPEN;i++)
-	{
-		if(current->files->fd[i])
-			n++;
-	}
-	
-	i=NR_OPEN;
-	if(i>current->rlim[RLIMIT_NOFILE].rlim_cur)
-		i=current->rlim[RLIMIT_NOFILE].rlim_cur;
-	if(n>=i)
-		return 0;
-	return i-n;
-}
 
 /*
  *	Perform the AF_UNIX file descriptor pass out functionality. This
@@ -795,50 +770,39 @@
 	/* count of space in parent for fds */
 	int cmnum;
 	struct file **fp;
-	struct file **ufp;
-	int *cmfptr=NULL;	/* =NULL To keep gcc happy */
-	/* number of fds actually passed */
+	int *cmfptr;
 	int fdnum;
-	int ffree;
-	int ufn=0;
 
-	if(cmsg==NULL)
-		cmnum=0;
-	else
-	{
-		cmnum=cmsg->cmsg_len-sizeof(struct cmsghdr);
-		cmnum/=sizeof(int);
-		cmfptr=(int *)&cmsg->cmsg_data;
+	cmfptr = NULL;
+	cmnum = 0;
+	if (cmsg)
+	{
+		cmnum = (cmsg->cmsg_len-sizeof(struct cmsghdr)) / sizeof(int);
+		cmfptr = (int *)&cmsg->cmsg_data;
 	}
 	
-	memcpy(&fdnum,skb->h.filp,sizeof(int));
-	fp=(struct file **)(skb->h.filp+sizeof(int));
-	if(cmnum>fdnum)
-		cmnum=fdnum;
-	ffree=unix_files_free();
-	if(cmnum>ffree)
-		cmnum=ffree;
-	ufp=&current->files->fd[0];
-	
+	fdnum = *(int *)skb->h.filp;
+	fp = (struct file **)(skb->h.filp+sizeof(long));
+
+	if (cmnum > fdnum)
+		cmnum = fdnum;
+
 	/*
 	 *	Copy those that fit
 	 */
-	for(i=0;i<cmnum;i++)
+	for (i = 0 ; i < cmnum ; i++)
 	{
-		/*
-		 *	Insert the fd
-		 */
-		while(ufp[ufn]!=NULL)
-			ufn++;
-		ufp[ufn]=fp[i];
-		*cmfptr++=ufn;
-		FD_CLR(ufn,&current->files->close_on_exec);
+		int new_fd = get_unused_fd();
+		if (new_fd < 0)
+			break;
+		current->files->fd[new_fd]=fp[i];
+		*cmfptr++ = new_fd;
 		unix_notinflight(fp[i]);
 	}
 	/*
 	 *	Dump those that don't
 	 */
-	for(;i<fdnum;i++)
+	for( ; i < fdnum ; i++)
 	{
 		close_fp(fp[i]);
 		unix_notinflight(fp[i]);
@@ -861,12 +825,12 @@
 static void unix_attach_fds(int fpnum,struct file **fp,struct sk_buff *skb)
 {
 
-	skb->h.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *), 
+	skb->h.filp = kmalloc(sizeof(long)+fpnum*sizeof(struct file *), 
 							GFP_KERNEL);
 	/* number of descriptors starts block */
-	memcpy(skb->h.filp,&fpnum,sizeof(int));
+	*(int *)skb->h.filp = fpnum;
 	/* actual  descriptors */
-	memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *));
+	memcpy(skb->h.filp+sizeof(long),fp,fpnum*sizeof(struct file *));
 	skb->destructor = unix_destruct_fds;
 }
 
