Commit b6a823e7 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.0.2

parent a96e1f22
......@@ -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
......
......@@ -122,6 +122,15 @@ if [ "$CONFIG_NET" = "y" ]; then
endmenu
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)'
......
......@@ -161,6 +161,11 @@ CONFIG_DE4X5=y
# CONFIG_TR is not set
# CONFIG_ARCNET is not set
#
# ISDN subsystem
#
# CONFIG_ISDN is not set
#
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
#
......
......@@ -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,&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);
}
/*
......
......@@ -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;
}
......
......@@ -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 @@ 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,&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 @@ int do_open(const char * filename,int flags,int mode)
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 @@ 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, &current->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 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
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 @@ static int do_select(int n, fd_set *in, fd_set *out, fd_set *ex,
/*
* 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;
}
......@@ -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 @@ 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;
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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
......
......@@ -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>
......
......@@ -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, &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;
}
......
......@@ -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);
......
......@@ -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 @@ static struct sock *tcp_accept(struct sock *sk, int flags)
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));
......
......@@ -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 @@ 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, &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;
}
......
......@@ -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=&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_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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment