Commit 2fbc2376 authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.15g

parent 9e11983a
...@@ -158,7 +158,7 @@ function int () { ...@@ -158,7 +158,7 @@ function int () {
eval "$2=$ans" eval "$2=$ans"
} }
CONFIG=.config~ CONFIG=.tmpconfig
CONFIG_H=include/linux/autoconf.h CONFIG_H=include/linux/autoconf.h
trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2 trap "rm -f $CONFIG $CONFIG_H config.new ; exit 1" 1 2
......
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 15 PATCHLEVEL = 15
ALPHA = f ALPHA = g
all: Version zImage all: Version zImage
...@@ -116,10 +116,10 @@ Version: dummy ...@@ -116,10 +116,10 @@ Version: dummy
config: config:
$(CONFIG_SHELL) Configure $(OPTS) < config.in $(CONFIG_SHELL) Configure $(OPTS) < config.in
@if grep -s '^CONFIG_SOUND' .config~ ; then \ @if grep -s '^CONFIG_SOUND' .tmpconfig ; then \
$(MAKE) -C drivers/sound config; \ $(MAKE) -C drivers/sound config; \
else : ; fi else : ; fi
mv .config~ .config mv .tmpconfig .config
linuxsubdirs: dummy linuxsubdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
...@@ -229,7 +229,7 @@ clean: ...@@ -229,7 +229,7 @@ clean:
rm -f zImage zSystem.map tools/zSystem tools/system rm -f zImage zSystem.map tools/zSystem tools/system
rm -f Image System.map boot/bootsect boot/setup rm -f Image System.map boot/bootsect boot/setup
rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback
rm -f drivers/sound/configure rm -f .tmp* drivers/sound/configure
rm -f init/*.o tools/build boot/*.o tools/*.o rm -f init/*.o tools/build boot/*.o tools/*.o
mrproper: clean mrproper: clean
...@@ -246,11 +246,11 @@ backup: mrproper ...@@ -246,11 +246,11 @@ backup: mrproper
depend dep: depend dep:
touch tools/version.h touch tools/version.h
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~ for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .tmpdepend
for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~ for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .tmpdepend
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
rm -f tools/version.h rm -f tools/version.h
mv .depend~ .depend mv .tmpdepend .depend
ifdef CONFIGURATION ifdef CONFIGURATION
..$(CONFIGURATION): ..$(CONFIGURATION):
......
...@@ -84,17 +84,21 @@ void emu_printall() ...@@ -84,17 +84,21 @@ void emu_printall()
RE_ENTRANT_CHECK_OFF; RE_ENTRANT_CHECK_OFF;
/* No need to verify_area(), we have previously fetched these bytes. */ /* No need to verify_area(), we have previously fetched these bytes. */
printk("At %p: ", (void *) address); printk("At %p:", (void *) address);
#define MAX_PRINTED_BYTES 20 #define MAX_PRINTED_BYTES 20
for ( i = 0; i < MAX_PRINTED_BYTES; i++ ) for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
{ {
byte1 = get_fs_byte((unsigned char *) address); byte1 = get_fs_byte((unsigned char *) address);
if ( (byte1 & 0xf8) == 0xd8 ) break; if ( (byte1 & 0xf8) == 0xd8 )
printk("[%02x]", byte1); {
printk(" %02x", byte1);
break;
}
printk(" [%02x]", byte1);
address++; address++;
} }
if ( i == MAX_PRINTED_BYTES ) printk("[more..]"); if ( i == MAX_PRINTED_BYTES ) printk(" [more..]");
printk("%02x ", byte1); printk("\n");
FPU_modrm = get_fs_byte(1 + (unsigned char *) address); FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
partial_status = status_word(); partial_status = status_word();
......
...@@ -144,6 +144,7 @@ static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip, ...@@ -144,6 +144,7 @@ static int valid_prefix(unsigned char *Byte, unsigned char **fpu_eip,
asmlinkage void math_emulate(long arg) asmlinkage void math_emulate(long arg)
{ {
unsigned char FPU_modrm, byte1; unsigned char FPU_modrm, byte1;
unsigned short code;
fpu_addr_modes addr_modes; fpu_addr_modes addr_modes;
int unmasked; int unmasked;
...@@ -250,7 +251,7 @@ asmlinkage void math_emulate(long arg) ...@@ -250,7 +251,7 @@ asmlinkage void math_emulate(long arg)
but a real 80486 uses the following instructions: but a real 80486 uses the following instructions:
fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex. fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
*/ */
unsigned short code = (FPU_modrm << 8) | byte1; code = (FPU_modrm << 8) | byte1;
if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */ if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
(((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv, (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
fnstsw */ fnstsw */
......
...@@ -259,8 +259,10 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) ...@@ -259,8 +259,10 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops)
flush_input(tty); flush_input(tty);
flush_output(tty); flush_output(tty);
wake_up_interruptible(&tty->secondary.proc_list); wake_up_interruptible(&tty->secondary.proc_list);
if (tty->session > 0) if (tty->session > 0) {
kill_sl(tty->session,SIGHUP,1); kill_sl(tty->session,SIGHUP,1);
kill_sl(tty->session,SIGCONT,1);
}
tty->session = 0; tty->session = 0;
tty->pgrp = -1; tty->pgrp = -1;
for_each_task(p) { for_each_task(p) {
...@@ -297,7 +299,7 @@ int tty_hung_up_p(struct file * filp) ...@@ -297,7 +299,7 @@ int tty_hung_up_p(struct file * filp)
* it wants to dissassociate itself from its controlling tty. * it wants to dissassociate itself from its controlling tty.
* *
* It performs the following functions: * It performs the following functions:
* (1) Sends a SIGHUP to the foreground process group * (1) Sends a SIGHUP and SIGCONT to the foreground process group
* (2) Clears the tty from being controlling the session * (2) Clears the tty from being controlling the session
* (3) Clears the controlling tty for all processes in the * (3) Clears the controlling tty for all processes in the
* session group. * session group.
...@@ -310,8 +312,10 @@ void disassociate_ctty(int priv) ...@@ -310,8 +312,10 @@ void disassociate_ctty(int priv)
if (current->tty >= 0) { if (current->tty >= 0) {
tty = tty_table[current->tty]; tty = tty_table[current->tty];
if (tty) { if (tty) {
if (tty->pgrp > 0) if (tty->pgrp > 0) {
kill_pg(tty->pgrp, SIGHUP, priv); kill_pg(tty->pgrp, SIGHUP, priv);
kill_pg(tty->pgrp, SIGCONT, priv);
}
tty->session = 0; tty->session = 0;
tty->pgrp = -1; tty->pgrp = -1;
} else } else
......
...@@ -232,6 +232,13 @@ static void sl_changedmtu(struct slip *sl) ...@@ -232,6 +232,13 @@ static void sl_changedmtu(struct slip *sl)
sl->mtu=dev->mtu; sl->mtu=dev->mtu;
l=(dev->mtu *2); l=(dev->mtu *2);
/*
* allow for arrival of larger UDP packets, even if we say not to
* also fixes a bug in which SunOS sends 512-byte packets even with
* an MSS of 128
*/
if (l < (576 * 2))
l = 576 * 2;
DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n")); DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n"));
...@@ -655,6 +662,14 @@ sl_open(struct device *dev) ...@@ -655,6 +662,14 @@ sl_open(struct device *dev)
* rmem_start Start of RECV frame buffer * rmem_start Start of RECV frame buffer
*/ */
l = (dev->mtu * 2); l = (dev->mtu * 2);
/*
* allow for arrival of larger UDP packets, even if we say not to
* also fixes a bug in which SunOS sends 512-byte packets even with
* an MSS of 128
*/
if (l < (576 * 2))
l = 576 * 2;
p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
if (p == NULL) { if (p == NULL) {
DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP XMIT buffer!\n")); DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP XMIT buffer!\n"));
......
...@@ -277,6 +277,10 @@ static void ext2_setup_super (struct super_block * sb, ...@@ -277,6 +277,10 @@ static void ext2_setup_super (struct super_block * sb,
es->s_mnt_count >= (unsigned short) es->s_max_mnt_count) es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, " printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n"); "running e2fsck is recommended\n");
else if (es->s_checkinterval &&
(es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME))
printk ("EXT2-fs warning: checktime reached, "
"running e2fsck is recommended\n");
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
es->s_state &= ~EXT2_VALID_FS; es->s_state &= ~EXT2_VALID_FS;
if (!es->s_max_mnt_count) if (!es->s_max_mnt_count)
......
...@@ -380,7 +380,7 @@ static int do_remount(const char *dir,int flags,char *data) ...@@ -380,7 +380,7 @@ static int do_remount(const char *dir,int flags,char *data)
return retval; return retval;
} }
static int copy_mount_options (char * data, unsigned long *where) static int copy_mount_options (const void * data, unsigned long *where)
{ {
int i; int i;
unsigned long page; unsigned long page;
......
...@@ -262,6 +262,7 @@ struct ext2_inode { ...@@ -262,6 +262,7 @@ struct ext2_inode {
* Maximal mount counts between two filesystem checks * Maximal mount counts between two filesystem checks
*/ */
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ #define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
/* /*
* Behaviour when detecting errors * Behaviour when detecting errors
...@@ -294,7 +295,9 @@ struct ext2_super_block { ...@@ -294,7 +295,9 @@ struct ext2_super_block {
unsigned short s_state; /* File system state */ unsigned short s_state; /* File system state */
unsigned short s_errors; /* Behaviour when detecting errors */ unsigned short s_errors; /* Behaviour when detecting errors */
unsigned short s_pad; unsigned short s_pad;
unsigned long s_reserved[240]; /* Padding to the end of the block */ unsigned long s_lastcheck; /* time of last check */
unsigned long s_checkinterval; /* max. time between checks */
unsigned long s_reserved[238]; /* Padding to the end of the block */
}; };
/* /*
......
...@@ -969,49 +969,53 @@ dev_ioctl(unsigned int cmd, void *arg) ...@@ -969,49 +969,53 @@ dev_ioctl(unsigned int cmd, void *arg)
int ret; int ret;
switch(cmd) { switch(cmd) {
case IP_SET_DEV: case IP_SET_DEV:
printk("Your network configuration program needs upgrading.\n"); printk("Your network configuration program needs upgrading.\n");
return -EINVAL; return -EINVAL;
case SIOCGIFCONF: case SIOCGIFCONF:
(void) dev_ifconf((char *) arg); (void) dev_ifconf((char *) arg);
ret = 0; return 0;
break;
case SIOCGIFFLAGS: case SIOCGIFFLAGS:
case SIOCSIFFLAGS:
case SIOCGIFADDR: case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR: case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
case SIOCGIFBRDADDR: case SIOCGIFBRDADDR:
case SIOCSIFBRDADDR:
case SIOCGIFNETMASK: case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
case SIOCGIFMETRIC: case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
case SIOCGIFMTU: case SIOCGIFMTU:
case SIOCSIFMTU:
case SIOCGIFMEM: case SIOCGIFMEM:
case SIOCSIFMEM:
case SIOCGIFHWADDR: case SIOCGIFHWADDR:
if (!suser()) return(-EPERM); return dev_ifsioc(arg, cmd);
ret = dev_ifsioc(arg, cmd);
break; case SIOCSIFFLAGS:
case SIOCSIFADDR:
case SIOCSIFDSTADDR:
case SIOCSIFBRDADDR:
case SIOCSIFNETMASK:
case SIOCSIFMETRIC:
case SIOCSIFMTU:
case SIOCSIFMEM:
if (!suser())
return -EPERM;
return dev_ifsioc(arg, cmd);
case SIOCSIFLINK: case SIOCSIFLINK:
if (!suser()) return(-EPERM); if (!suser())
return -EPERM;
memcpy_fromfs(&iflink, arg, sizeof(iflink)); memcpy_fromfs(&iflink, arg, sizeof(iflink));
dev = ddi_map(iflink.id); dev = ddi_map(iflink.id);
if (dev == NULL) return(-EINVAL); if (dev == NULL)
return -EINVAL;
/* Now allocate an interface and connect it. */ /* Now allocate an interface and connect it. */
printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n", printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n",
dev->name, iflink.stream); dev->name, iflink.stream);
ret = 0; return 0;
break;
default: default:
ret = -EINVAL; return -EINVAL;
} }
return(ret);
} }
......
...@@ -497,7 +497,7 @@ static int inet_setsockopt(struct socket *sock, int level, int optname, ...@@ -497,7 +497,7 @@ static int inet_setsockopt(struct socket *sock, int level, int optname,
static int inet_getsockopt(struct socket *sock, int level, int optname, static int inet_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sock *sk = sock->data; struct sock *sk = (struct sock *) sock->data;
if (level == SOL_SOCKET) if (level == SOL_SOCKET)
return sock_getsockopt(sk,level,optname,optval,optlen); return sock_getsockopt(sk,level,optname,optval,optlen);
if(sk->prot->getsockopt==NULL) if(sk->prot->getsockopt==NULL)
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
* Charles Hedrick : TCP fixes * Charles Hedrick : TCP fixes
* Toomas Tamm : TCP window fixes * Toomas Tamm : TCP window fixes
* Alan Cox : Small URG fix to rlogin ^C ack fight * Alan Cox : Small URG fix to rlogin ^C ack fight
* Linus : Rewrote URG handling completely
* *
* *
* To Fix: * To Fix:
...@@ -350,8 +351,8 @@ tcp_readable(struct sock *sk) ...@@ -350,8 +351,8 @@ tcp_readable(struct sock *sk)
if (amount && skb->h.th->psh) break; if (amount && skb->h.th->psh) break;
skb =(struct sk_buff *)skb->next; /* Move along */ skb =(struct sk_buff *)skb->next; /* Move along */
} while(skb != sk->rqueue); } while(skb != sk->rqueue);
if (sk->urg_data && if (amount && !sk->urginline && sk->urg_data &&
(sk->urg_seq - sk->copied_seq) < (counted - sk->copied_seq)) (sk->urg_seq - sk->copied_seq) <= (counted - sk->copied_seq))
amount--; /* don't count urg data */ amount--; /* don't count urg data */
restore_flags(flags); restore_flags(flags);
DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount)); DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount));
...@@ -442,7 +443,7 @@ tcp_select(struct sock *sk, int sel_type, select_table *wait) ...@@ -442,7 +443,7 @@ tcp_select(struct sock *sk, int sel_type, select_table *wait)
return(0); return(0);
case SEL_EX: case SEL_EX:
select_wait(sk->sleep,wait); select_wait(sk->sleep,wait);
if (sk->err) { if (sk->err || sk->urg_data) {
release_sock(sk); release_sock(sk);
return(1); return(1);
} }
...@@ -486,17 +487,11 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -486,17 +487,11 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
} }
case SIOCATMARK: case SIOCATMARK:
{ {
int answ = 0; int answ = sk->urg_data && sk->urg_seq == sk->copied_seq+1;
/* err = verify_area(VERIFY_WRITE,(void *) arg,
* Try to figure out if we need to read
* some urgent data.
*/
if (sk->urg_data && sk->copied_seq+1 == sk->urg_seq)
answ = 1;
err=verify_area(VERIFY_WRITE,(void *) arg,
sizeof(unsigned long)); sizeof(unsigned long));
if(err) if (err)
return err; return err;
put_fs_long(answ,(int *) arg); put_fs_long(answ,(int *) arg);
return(0); return(0);
...@@ -1250,7 +1245,9 @@ tcp_read_urg(struct sock * sk, int nonblock, ...@@ -1250,7 +1245,9 @@ tcp_read_urg(struct sock * sk, int nonblock,
struct wait_queue wait = { current, NULL }; struct wait_queue wait = { current, NULL };
while (len > 0) { while (len > 0) {
if (sk->urg_data && sk->urg_data != URG_READ) { if (sk->urginline || !sk->urg_data || sk->urg_data == URG_READ)
return -EINVAL;
if (sk->urg_data & URG_VALID) {
char c = sk->urg_data; char c = sk->urg_data;
if (!(flags & MSG_PEEK)) if (!(flags & MSG_PEEK))
sk->urg_data = URG_READ; sk->urg_data = URG_READ;
...@@ -1285,8 +1282,8 @@ tcp_read_urg(struct sock * sk, int nonblock, ...@@ -1285,8 +1282,8 @@ tcp_read_urg(struct sock * sk, int nonblock,
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
add_wait_queue(sk->sleep, &wait); add_wait_queue(sk->sleep, &wait);
if ((!sk->urg_data || sk->urg_data == URG_READ) && if ((sk->urg_data & URG_NOTYET) && sk->err == 0 &&
sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) !(sk->shutdown & RCV_SHUTDOWN))
schedule(); schedule();
remove_wait_queue(sk->sleep, &wait); remove_wait_queue(sk->sleep, &wait);
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
...@@ -1302,7 +1299,9 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1302,7 +1299,9 @@ tcp_read(struct sock *sk, unsigned char *to,
{ {
int copied = 0; /* will be used to say how much has been copied. */ int copied = 0; /* will be used to say how much has been copied. */
struct sk_buff *skb; struct sk_buff *skb;
unsigned long peek_seq;
unsigned long offset; unsigned long offset;
unsigned long *seq;
int err; int err;
if (len == 0) if (len == 0)
...@@ -1310,11 +1309,11 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1310,11 +1309,11 @@ tcp_read(struct sock *sk, unsigned char *to,
if (len < 0) if (len < 0)
return -EINVAL; return -EINVAL;
err=verify_area(VERIFY_WRITE,to,len); err=verify_area(VERIFY_WRITE,to,len);
if(err) if (err)
return err; return err;
/* This error should be checked. */ /* This error should be checked. */
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN)
return -ENOTCONN; return -ENOTCONN;
...@@ -1327,6 +1326,11 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1327,6 +1326,11 @@ tcp_read(struct sock *sk, unsigned char *to,
sk->inuse = 1; sk->inuse = 1;
skb=skb_peek(&sk->rqueue); skb=skb_peek(&sk->rqueue);
peek_seq = sk->copied_seq;
seq = &sk->copied_seq;
if (flags & MSG_PEEK)
seq = &peek_seq;
DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n", DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, to, len, nonblock, flags)); sk, to, len, nonblock, flags));
...@@ -1334,7 +1338,7 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1334,7 +1338,7 @@ tcp_read(struct sock *sk, unsigned char *to,
/* skb->used just checks to see if we've gone all the way around. */ /* skb->used just checks to see if we've gone all the way around. */
/* While no data, or first data indicates some is missing, or data is used */ /* While no data, or first data indicates some is missing, or data is used */
while(skb == NULL || skb->used || before(sk->copied_seq+1, skb->h.th->seq)) { while(skb == NULL || skb->used || before(1+*seq, skb->h.th->seq)) {
DPRINTF((DBG_TCP, "skb = %X:\n", skb)); DPRINTF((DBG_TCP, "skb = %X:\n", skb));
cleanup_rbuf(sk); cleanup_rbuf(sk);
if (sk->err) if (sk->err)
...@@ -1413,7 +1417,7 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1413,7 +1417,7 @@ tcp_read(struct sock *sk, unsigned char *to,
} }
skb = skb_peek(&sk->rqueue); skb = skb_peek(&sk->rqueue);
if (skb == NULL || before(sk->copied_seq+1, skb->h.th->seq)) { if (skb == NULL || before(1+*seq, skb->h.th->seq)) {
if(sk->debug) if(sk->debug)
printk("Read wait sleep\n"); printk("Read wait sleep\n");
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
...@@ -1439,30 +1443,18 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1439,30 +1443,18 @@ tcp_read(struct sock *sk, unsigned char *to,
} }
/* /*
* are we at urgent data? * are we at urgent data? Stop if we have read anything.
*/ */
if (sk->urg_data && sk->copied_seq+1 == sk->urg_seq) { if (copied && sk->urg_data && sk->urg_seq == 1+*seq) {
if (sk->urg_data == URG_READ) { release_sock(sk);
if (copied || (flags & MSG_PEEK)) { return copied;
release_sock(sk);
return copied;
}
sk->urg_data = 0;
sk->copied_seq++;
} else {
release_sock(sk);
if (copied)
return copied;
send_sig(SIGURG, current, 0);
return -EINTR;
}
} }
/* /*
* Copy anything from the current block that needs * Copy anything from the current block that needs
* to go into the user buffer. * to go into the user buffer.
*/ */
offset = sk->copied_seq+1 - skb->h.th->seq; offset = *seq - skb->h.th->seq + 1;
if (skb->h.th->syn) offset--; if (skb->h.th->syn) offset--;
...@@ -1473,18 +1465,28 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1473,18 +1465,28 @@ tcp_read(struct sock *sk, unsigned char *to,
if (len < used) if (len < used)
used = len; used = len;
/* do we have urgent data here? */ /* do we have urgent data here? */
if (sk->urg_data && sk->urg_seq - (sk->copied_seq+1) < used) if (sk->urg_data) {
used = sk->urg_seq - (sk->copied_seq+1); unsigned long urg_offset = sk->urg_seq - (1 + *seq);
if (urg_offset < used) {
if (!urg_offset) {
if (!(flags & MSG_PEEK))
sk->urg_data = 0;
if (!sk->urginline) {
++*seq;
offset++;
used--;
}
} else
used = offset;
}
}
/* Copy it */ /* Copy it */
memcpy_tofs(to,((unsigned char *)skb->h.th) + memcpy_tofs(to,((unsigned char *)skb->h.th) +
skb->h.th->doff*4 + offset, used); skb->h.th->doff*4 + offset, used);
copied += used; copied += used;
len -= used; len -= used;
to += used; to += used;
*seq += used;
/* If we were reading the data is 'eaten' */
if (!(flags & MSG_PEEK))
sk->copied_seq += used;
/* /*
* Mark this data used if we are really reading it, and we * Mark this data used if we are really reading it, and we
...@@ -1495,7 +1497,8 @@ tcp_read(struct sock *sk, unsigned char *to, ...@@ -1495,7 +1497,8 @@ tcp_read(struct sock *sk, unsigned char *to,
} }
else else
{ /* already used this data, must be a retransmit */ { /* already used this data, must be a retransmit */
skb->used = 1; if (!(flags & MSG_PEEK))
skb->used = 1;
} }
/* Move along a packet */ /* Move along a packet */
skb =(struct sk_buff *)skb->next; skb =(struct sk_buff *)skb->next;
...@@ -2717,8 +2720,16 @@ tcp_data(struct sk_buff *skb, struct sock *sk, ...@@ -2717,8 +2720,16 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
/* Now figure out if we can ack anything. */ /* Now figure out if we can ack anything. */
if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) { if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) {
if (before(th->seq, sk->acked_seq+1)) { if (before(th->seq, sk->acked_seq+1)) {
if (after(th->ack_seq, sk->acked_seq)) int newwindow;
sk->acked_seq = th->ack_seq;
if (after(th->ack_seq, sk->acked_seq)) {
newwindow = sk->window -
(th->ack_seq - sk->acked_seq);
if (newwindow < 0)
newwindow = 0;
sk->window = newwindow;
sk->acked_seq = th->ack_seq;
}
skb->acked = 1; skb->acked = 1;
/* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */ /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
...@@ -2733,16 +2744,12 @@ tcp_data(struct sk_buff *skb, struct sock *sk, ...@@ -2733,16 +2744,12 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
if (before(skb2->h.th->seq, sk->acked_seq+1)) { if (before(skb2->h.th->seq, sk->acked_seq+1)) {
if (after(skb2->h.th->ack_seq, sk->acked_seq)) if (after(skb2->h.th->ack_seq, sk->acked_seq))
{ {
long old_acked_seq = sk->acked_seq; newwindow = sk->window -
(skb2->h.th->ack_seq - sk->acked_seq);
if (newwindow < 0)
newwindow = 0;
sk->window = newwindow;
sk->acked_seq = skb2->h.th->ack_seq; sk->acked_seq = skb2->h.th->ack_seq;
if((int)(sk->acked_seq - old_acked_seq) >0)
{
int new_window=sk->window-sk->acked_seq+
old_acked_seq;
if(new_window<0)
new_window=0;
sk->window = new_window;
}
} }
skb2->acked = 1; skb2->acked = 1;
...@@ -2845,54 +2852,56 @@ tcp_data(struct sk_buff *skb, struct sock *sk, ...@@ -2845,54 +2852,56 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
} }
static int static void tcp_check_urg(struct sock * sk, struct tcphdr * th)
tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr, unsigned long len)
{ {
unsigned long ptr; unsigned long ptr = ntohs(th->urg_ptr);
extern int kill_pg(int pg, int sig, int priv);
extern int kill_proc(int pid, int sig, int priv);
if (!sk->dead)
sk->data_ready(sk,0);
if (sk->urginline) {
th->urg = 0;
th->psh = 1;
return 0;
}
ptr = ntohs(th->urg_ptr);
if (ptr) if (ptr)
ptr--; ptr--;
ptr += th->seq;
/* is the urgent data in this packet at all? */ /* ignore urgent data that we've already seen and read */
if (th->doff*4 + ptr >= len) if (after(sk->copied_seq+1, ptr))
return 0; return;
/* have we already seen and read this? */
if (after(sk->copied_seq+1, th->seq+ptr))
return 0;
/* is this a duplicate? */ /* do we already have a newer (or duplicate) urgent pointer? */
if (sk->urg_data && sk->urg_seq == th->seq+ptr) if (sk->urg_data && !after(ptr, sk->urg_seq))
return 0; return;
/* /* tell the world about our new urgent pointer */
* We signal the user only for the first urgent data: if urgent if (sk->proc != 0) {
* data already exists, no signal is sent if (sk->proc > 0) {
*/ kill_proc(sk->proc, SIGURG, 1);
if (!sk->urg_data || sk->urg_data == URG_READ) { } else {
if (sk->proc != 0) { kill_pg(-sk->proc, SIGURG, 1);
if (sk->proc > 0) {
kill_proc(sk->proc, SIGURG, 1);
} else {
kill_pg(-sk->proc, SIGURG, 1);
}
} }
} }
sk->urg_data = URG_NOTYET;
sk->urg_seq = ptr;
}
static inline int tcp_urg(struct sock *sk, struct tcphdr *th,
unsigned long saddr, unsigned long len)
{
unsigned long ptr;
/* check if we get a new urgent pointer */
if (th->urg)
tcp_check_urg(sk,th);
sk->urg_data = 0x100 | *(ptr + th->doff*4 + (unsigned char *) th); /* do we wait for any urgent data? */
sk->urg_seq = th->seq + ptr; if (sk->urg_data != URG_NOTYET)
return 0;
/* is the urgent pointer pointing into this packet? */
ptr = sk->urg_seq - th->seq + th->doff*4;
if (ptr >= len)
return 0;
/* ok, got the correct packet, update info */
sk->urg_data = URG_VALID | *(ptr + (unsigned char *) th);
if (!sk->dead)
wake_up_interruptible(sk->sleep);
return 0; return 0;
} }
...@@ -3389,12 +3398,11 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n"); ...@@ -3389,12 +3398,11 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
return(0); return(0);
} }
} }
if (th->urg) {
if (tcp_urg(sk, th, saddr, len)) { if (tcp_urg(sk, th, saddr, len)) {
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
release_sock(sk); release_sock(sk);
return(0); return(0);
}
} }
if (tcp_data(skb, sk, saddr, len)) { if (tcp_data(skb, sk, saddr, len)) {
......
...@@ -30,8 +30,10 @@ ...@@ -30,8 +30,10 @@
#define MIN_WRITE_SPACE 2048 #define MIN_WRITE_SPACE 2048
#define TCP_WINDOW_DIFF 2048 #define TCP_WINDOW_DIFF 2048
/* marks the urg_data as read */ /* urg_data states */
#define URG_READ 0xdeadbeef #define URG_VALID 0x0100
#define URG_NOTYET 0x0200
#define URG_READ 0x0400
#define TCP_RETR1 7 /* #define TCP_RETR1 7 /*
* This is howmany retries it does before it * This is howmany retries it does before it
......
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