@@ -1029,6+1029,13 @@ S: RR #5, 497 Pole Line Road 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
@@ -179,7+179,9 @@ or earlier, you will probably get a weird error on shutdown in which 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
VERSION = 2
PATCHLEVEL = 0
-SUBLEVEL = 1
+SUBLEVEL = 2
ARCH = i386
@@ -123,6+123,15 @@ if [ "$CONFIG_NET" = "y" ]; then 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
@@ -162,6+162,11 @@ CONFIG_DE4X5=y # 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
@@ -2755,8+2755,9 @@ int rs_init(void) 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;
@@ -789,8+789,8 @@ static struct enet_statistics * 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 @@ lance32_get_stats(struct device *dev)
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) {
@@ -114,41+114,34 @@ int unregister_binfmt(struct linux_binfmt * fmt)
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 @@ static void exec_mmap(void) }
/*
- * 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 @@ void flush_old_exec(struct linux_binprm * bprm) 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,¤t->files->close_on_exec))
- sys_close(i);
- FD_ZERO(¤t->files->close_on_exec);
+
+ flush_old_signals(current->sig);
+ flush_old_files(current->files);
}
/*
#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, ¤t->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;
}
#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 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) * 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 @@ int do_open(const char * filename,int flags,int mode) }
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,¤t->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 @@ cleanup_file: 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, ¤t->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 @@ int close_fp(struct file *filp) }
asmlinkage int sys_close(unsigned int fd)
-{
+{
+ int error;
struct file * filp;
-
- if (fd >= NR_OPEN)
- return -EBADF;
- FD_CLR(fd, ¤t->files->close_on_exec);
- if (!(filp = current->files->fd[fd]))
- return -EBADF;
- current->files->fd[fd] = NULL;
- return (close_fp (filp));
+ struct files_struct * files;
+
+ 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;
}
/*
@@ -414,45+414,58 @@ struct inode_operations pipe_inode_operations = { 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;
-
- 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 */
+ goto close_f12;
+
+ error = get_unused_fd();
+ if (error < 0)
+ goto close_f12_inode;
+ i = error;
+
+ 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;
}
@@ -92,11+92,13 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, 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 @@ end_check: 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 @@ repeat: /*
* 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 @@ __set_fd_set(nr, (unsigned int *) (fsp), (unsigned int *) (fdp)) */
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 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct 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;
}
*
* 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 @@ smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, int info_level = 1;
char *p;
+ char *lastname;
int i;
int first, total_count;
struct smb_dirent *current_entry;
@@ -1171,9+1173,15 @@ smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, 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 @@ smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, 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 @@ smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, }
finished:
+ if (mask != NULL)
+ smb_kfree_s(mask, 0);
+
if (resp_data != NULL) {
smb_kfree_s(resp_data, 0);
resp_data = NULL;
#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 */
@@ -74,18+74,18 @@ static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p) #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;
#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 */
@@ -623,6+623,8 @@ extern struct inode * get_empty_inode(void); 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);
@@ -101,7+101,7 @@ struct sockaddr_in { #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
* 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>
@@ -108,20+108,18 @@ extern void trap_init(void);
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, } \
}
@@ -174,22+174,6 @@ extern void tcp_reset_xmit_timer(struct sock *, int, unsigned long); 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);
@@ -393,6+393,26 @@ static inline void forget_original_parent(struct task_struct * father) }
}
+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 @@ static inline void __exit_files(struct task_struct *tsk) 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);
}
}
@@ -160,22+160,33 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) 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, ¤t->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;
}
@@ -926,7+926,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr, * Reuse ?
*/
- if (!sk2->dead)
+ if (!sk2->reuse || sk2->state==TCP_LISTEN)
{
sti();
return(-EADDRINUSE);
* 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
#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 @@ no_listen: 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 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) * 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 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) 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.
*/
@@ -1968,6+1999,15 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) 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));
memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
* 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 @@ static void bad_tcp_sequence(struct sock *sk, struct tcphdr *th, u32 end_seq, * 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 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, struct tcphdr *th;
struct sock *sk;
int syn_ok=0;
+ __u32 seq;
#ifdef CONFIG_IP_TRANSPARENT_PROXY
int r;
#endif
@@ -1859,10+1873,12 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, }
/*
- * 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
@@ -172,36+172,31 @@ int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen) 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, ¤t->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;
}
@@ -710,10+710,9 @@ static int unix_fd_copy(struct sock *sk, struct cmsghdr *cmsg, struct file **fp) 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 @@ static int unix_fd_copy(struct sock *sk, struct cmsghdr *cmsg, struct file **fp) #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 @@ static void unix_fd_free(struct sock *sk, struct file **fp, int num) }
}
-/*
- * 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 @@ static void unix_detach_fds(struct sk_buff *skb, struct cmsghdr *cmsg) /* 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
+ cmfptr = NULL;
+ cmnum = 0;
+ if (cmsg)
{
- cmnum=cmsg->cmsg_len-sizeof(struct cmsghdr);
- cmnum/=sizeof(int);
- cmfptr=(int *)&cmsg->cmsg_data;
+ 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=¤t->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,¤t->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_destruct_fds(struct sk_buff *skb) 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;
}