Commit 36f4514a authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14p

parent ddd9ed00
VERSION = 0.99
PATCHLEVEL = 14
ALPHA = o
ALPHA = p
all: Version zImage
......
......@@ -4,14 +4,15 @@
#DEBUG = -DDEBUGGING
DEBUG =
PARANOID = -DPARANOID
REENTRANT = -DREENTRANT_FPU
CFLAGS := $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin
CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin
.c.o:
$(CC) $(CFLAGS) $(MATH_EMULATION) -c $<
.S.o:
$(CC) -D__ASSEMBLER__ $(REENTRANT) -c $<
$(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $<
.s.o:
$(CC) -c $<
......
+---------------------------------------------------------------------------+
| wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -47,7 +47,7 @@ Please report bugs, etc to me at:
--Bill Metzenthen
Sept 1993
Jan 1994
----------------------- Internals of wm-FPU-emu -----------------------
......@@ -305,7 +305,8 @@ Daniel Carosone, danielce@ee.mu.oz.au
cae@jpmorgan.com
Hamish Coleman, t933093@minyos.xx.rmit.oz.au
Bruce Evans, bde@kralizec.zeta.org.au
Timo Korvola, Timo.Korvola@hut.fi
...and numerous others who responded to my request for help with
a real 80486.
......@@ -3,7 +3,7 @@
| |
| The error handling functions for wm-FPU-emu |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -208,7 +208,7 @@ static struct {
0x125 in fpu_trig.c
0x126 in fpu_entry.c
0x127 in poly_2xm1.c
0x2nn in an *.s file:
0x2nn in an *.S file:
0x201 in reg_u_add.S, reg_round.S
0x202 in reg_u_div.S
0x203 in reg_u_div.S
......@@ -227,6 +227,8 @@ static struct {
0x216 in reg_round.S
0x217 in reg_round.S
0x218 in reg_round.S
0x220 in reg_norm.S
0x221 in reg_norm.S
*/
void exception(int n)
......
......@@ -3,7 +3,7 @@
| |
| Implementation of the FPU "transcendental" functions. |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -88,9 +88,19 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */
significand(&tmp) = q + 1;
tmp.exp = EXP_BIAS + 63;
tmp.tag = TW_Valid;
normalize(&tmp);
reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
reg_add(X, &tmp, X, FULL_PRECISION);
if ( X->sign == SIGN_NEG )
{
/* CONST_PI2extra is negative, so the result of the addition
can be negative. This means that the argument is actually
in a different quadrant. The correction is always < pi/2,
so it can't overflow into yet another quadrant. */
X->sign = SIGN_POS;
q++;
}
}
#endif BETTER_THAN_486
}
......@@ -107,9 +117,23 @@ static int trig_arg(FPU_REG *X, int even)
128 bits precision. */
significand(&tmp) = q;
tmp.exp = EXP_BIAS + 63;
tmp.tag = TW_Valid;
normalize(&tmp);
reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION);
reg_sub(X, &tmp, X, FULL_PRECISION);
if ( (X->exp == CONST_PI2.exp) &&
((X->sigh > CONST_PI2.sigh)
|| ((X->sigh == CONST_PI2.sigh)
&& (X->sigl > CONST_PI2.sigl))) )
{
/* CONST_PI2extra is negative, so the result of the
subtraction can be larger than pi/2. This means
that the argument is actually in a different quadrant.
The correction is always < pi/2, so it can't overflow
into yet another quadrant. */
reg_sub(&CONST_PI, X, X, FULL_PRECISION);
q++;
}
}
}
#endif BETTER_THAN_486
......
/*---------------------------------------------------------------------------+
| reg_norm.S |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
......@@ -29,6 +29,17 @@ _normalize:
movl PARAM1,%ebx
#ifdef PARANOID
cmpb TW_Valid,TAG(%ebx)
je L_ok
pushl $0x220
call _exception
addl $4,%esp
L_ok:
#endif PARANOID
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
......@@ -98,6 +109,17 @@ _normalize_nuo:
movl PARAM1,%ebx
#ifdef PARANOID
cmpb TW_Valid,TAG(%ebx)
je L_ok_nuo
pushl $0x221
call _exception
addl $4,%esp
L_ok_nuo:
#endif PARANOID
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
......
......@@ -2,12 +2,12 @@
| version.h |
| |
| |
| Copyright (C) 1992,1993 |
| Copyright (C) 1992,1993,1994 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
| Australia. E-mail billm@vaxc.cc.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
#define FPU_VERSION "wm-FPU-emu version BETA 1.6"
#define FPU_VERSION "wm-FPU-emu version Beta 1.7"
This diff is collapsed.
......@@ -48,7 +48,7 @@ OBJS := $(OBJS) msbusmouse.o
SRCS := $(SRCS) msbusmouse.c
endif
ifdef CONFIG_QUICKPORT_MOUSE
ifdef CONFIG_82C710_MOUSE
CONFIG_PSMOUSE = CONFIG_PSMOUSE
endif
......
......@@ -45,7 +45,7 @@ static int mouse_open(struct inode * inode, struct file * file)
file->f_op = &bus_mouse_fops;
break;
#endif
#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
case PSMOUSE_MINOR:
file->f_op = &psaux_fops;
break;
......@@ -83,7 +83,7 @@ unsigned long mouse_init(unsigned long kmem_start)
#ifdef CONFIG_BUSMOUSE
kmem_start = bus_mouse_init(kmem_start);
#endif
#if defined CONFIG_PSMOUSE || defined CONFIG_QUICKPORT_MOUSE
#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE
kmem_start = psaux_init(kmem_start);
#endif
#ifdef CONFIG_MS_BUSMOUSE
......
......@@ -68,7 +68,7 @@
#define AUX_DISABLE_DEV 0xf5 /* disable aux device */
#define AUX_RESET 0xff /* reset aux device */
#define MAX_RETRIES 30 /* some aux operations take long time*/
#define MAX_RETRIES 60 /* some aux operations take long time*/
#define AUX_IRQ 12
#define AUX_BUF_SIZE 2048
......
......@@ -1574,7 +1574,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (info->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&info->close_wait);
return -EAGAIN;
return -ERESTARTSYS;
}
/*
......@@ -1632,7 +1632,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
retval = -EAGAIN;
retval = -ERESTARTSYS;
break;
}
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
......
......@@ -1315,6 +1315,7 @@ static int tty_open(struct inode * inode, struct file * filp)
int major, minor;
int noctty, retval;
retry_open:
minor = MINOR(inode->i_rdev);
major = MAJOR(inode->i_rdev);
noctty = filp->f_flags & O_NOCTTY;
......@@ -1372,7 +1373,12 @@ static int tty_open(struct inode * inode, struct file * filp)
#endif
release_dev(minor, filp);
return retval;
if (retval != -ERESTARTSYS)
return retval;
if (current->signal & ~current->blocked)
return retval;
schedule();
goto retry_open;
}
if (!noctty &&
current->leader &&
......
......@@ -881,6 +881,37 @@ slip_open(struct tty_struct *tty)
return(sl->line);
}
static struct enet_statistics *
sl_get_stats(struct device *dev)
{
static struct enet_statistics stats;
struct slip *sl;
struct slcompress *comp;
/* Find the correct SLIP channel to use. */
sl = &sl_ctrl[dev->base_addr];
if (! sl)
return NULL;
memset(&stats, 0, sizeof(struct enet_statistics));
stats.rx_packets = sl->rpacket;
stats.rx_over_errors = sl->roverrun;
stats.tx_packets = sl->spacket;
stats.tx_dropped = sl->sbusy;
stats.rx_errors = sl->errors;
comp = sl->slcomp;
if (comp) {
stats.rx_fifo_errors = comp->sls_i_compressed;
stats.rx_dropped = comp->sls_i_tossed;
stats.tx_fifo_errors = comp->sls_o_compressed;
stats.collisions = comp->sls_o_misses;
}
return (&stats);
}
/*
* Close down a SLIP channel.
......@@ -1193,6 +1224,7 @@ slip_init(struct device *dev)
dev->hard_header = sl_header;
dev->add_arp = sl_add_arp;
dev->type_trans = sl_type_trans;
dev->get_stats = sl_get_stats;
#ifdef HAVE_SET_MAC_ADDR
#ifdef CONFIG_AX25
dev->set_mac_address = sl_set_mac_address;
......
......@@ -38,6 +38,12 @@
* Al Longyear (longyear@sii.com)
* Removed erroneous code which mistakenly folded .data with .bss for
* a shared library.
*
* 8 Janurary 1994
* Al Longyear (longyear@sii.com)
* Corrected problem with read of library section returning the byte
* count rather than zero. This was a change between the pl12 and
* pl14 kernels which slipped by me.
*/
#include <linux/fs.h>
......@@ -650,12 +656,21 @@ preload_library (struct linux_binprm *exe_bprm,
buffer, /* Buffer for read */
nbytes); /* Byte count reqd. */
set_fs (old_fs); /* Restore the selector */
/*
* Check the result. The value returned is the byte count actaully read.
*/
if (status >= 0 && status != nbytes) {
#ifdef COFF_DEBUG
printk ("read of lib section was short\n");
#endif
status = -ENOEXEC;
}
}
/*
* At this point, go through the list of libraries in the data area.
*/
phdr = (COFF_SLIBHD *) buffer;
while (status == 0 && nbytes > COFF_SLIBSZ) {
while (status >= 0 && nbytes > COFF_SLIBSZ) {
int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
/*
......
......@@ -4,8 +4,7 @@ Changes from version 0.4a to version 0.4b
- Clean up of balloc.c and ialloc.c.
- More consistency checks.
- Block preallocation added by Stephen Tweedie.
- Direct reads of directories disallowed if CONFIG_EXT2_FS_DIR_READ not
defined.
- Direct reads of directories disallowed.
- Readahead implemented in readdir by Stephen Tweedie.
- Bugs in block and inodes allocation fixed.
- Readahead implemented in ext2_find_entry by Chip Salzenberg.
......
......@@ -16,32 +16,23 @@
#include <asm/segment.h>
#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
#ifndef CONFIG_EXT2_FS_DIR_READ
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
return -EISDIR;
}
#else
int ext2_file_read (struct inode *, struct file *, char *, int);
#endif
static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */
#ifdef CONFIG_EXT2_FS_DIR_READ
ext2_file_read, /* read */
#else
ext2_dir_read, /* read */
#endif
NULL, /* write - bad */
ext2_readdir, /* readdir */
NULL, /* select - default */
......
......@@ -17,7 +17,6 @@
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/autoconf.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
......@@ -34,10 +33,7 @@
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#ifndef CONFIG_EXT2_FS_DIR_READ
static
#endif
int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_file_read (struct inode *, struct file *, char *, int);
static int ext2_file_write (struct inode *, struct file *, char *, int);
static void ext2_release_file (struct inode *, struct file *);
......@@ -76,10 +72,7 @@ struct inode_operations ext2_file_inode_operations = {
ext2_permission /* permission */
};
#ifndef CONFIG_EXT2_FS_DIR_READ
static
#endif
int ext2_file_read (struct inode * inode, struct file * filp,
static int ext2_file_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
int read, left, chars;
......@@ -97,7 +90,7 @@ int ext2_file_read (struct inode * inode, struct file * filp,
return -EINVAL;
}
sb = inode->i_sb;
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
if (!S_ISREG(inode->i_mode)) {
ext2_warning (sb, "ext2_file_read", "mode = %07o",
inode->i_mode);
return -EINVAL;
......
......@@ -274,7 +274,7 @@ static void ext2_setup_super (struct super_block * sb,
printk ("EXT2-fs warning: mounting fs with errors, "
"running e2fsck is recommended\n");
else if (es->s_max_mnt_count >= 0 &&
es->s_mnt_count >= es->s_max_mnt_count)
es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
printk ("EXT2-fs warning: maximal mount count reached, "
"running e2fsck is recommended\n");
if (!(sb->s_flags & MS_RDONLY)) {
......
......@@ -4,16 +4,11 @@ It implements all of
- SystemV/386 FS,
- Coherent FS.
This is version alpha 5.
This is version beta 1.
To install:
* You need Linux 0.99.14.
* Go to /usr/src/linux, unpack the tar file there, and patch the Linux source:
patch -p1 < sysvfs.cdif
To build the Linux kernel with the patches:
make config
make depend
make
* Answer the 'System V and Coherent filesystem support' question with 'y'
when configuring the kernel.
* To mount a disk or a partition, use
mount [-r] -t sysv device mountpoint
The file system type names
......
......@@ -65,7 +65,8 @@ void sysv_free_inode(struct inode * inode)
return;
}
if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) {
panic("sysv_free_inode: unable to read inode block"); /* FIXME: too severe? */
printk("sysv_free_inode: unable to read inode block on device %d/%d\n",MAJOR(inode->i_dev),MINOR(inode->i_dev));
clear_inode(inode);
return;
}
raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
......
......@@ -316,7 +316,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_dev=0;
unlock_super(sb);
if (!silent)
printk("VFS: unable to read Xenix/SystemV/Coherent superblock\n");
printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device %d/%d\n",MAJOR(dev),MINOR(dev));
return NULL;
ok:
......
......@@ -52,7 +52,7 @@
/*
* The second extended file system version
*/
#define EXT2FS_DATE "94/01/05"
#define EXT2FS_DATE "94/01/08"
#define EXT2FS_VERSION "0.4b"
/*
......
......@@ -31,7 +31,8 @@
#define ETH_P_PUP 0x0400 /* Xerox PUP packet */
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
#define ETH_P_RARP 0x0835 /* Reverse Addr Res packet */
#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
#define ETH_P_X25 0x0805 /* CCITT X.25 */
#define ETH_P_IPX 0x8137 /* IPX over DIX */
#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
......
......@@ -30,10 +30,14 @@ struct linger {
#define AF_UNSPEC 0
#define AF_UNIX 1
#define AF_INET 2
#define AF_AX25 3
#define AF_IPX 4
/* Protocol families, same as address families. */
#define PF_UNIX AF_UNIX
#define PF_INET AF_INET
#define PF_AX25 AF_AX25
#define PF_IPX AF_IPX
/* Flags we can use with send/ and recv. */
#define MSG_OOB 1
......@@ -41,6 +45,10 @@ struct linger {
/* Setsockoptions(2) level. */
#define SOL_SOCKET 1
#define SOL_IP 2
#define SOL_IPX 3
#define SOL_AX25 4
#define SOL_TCP 5
/* For setsockoptions(2) */
#define SO_DEBUG 1
......@@ -56,6 +64,19 @@ struct linger {
#define SO_NO_CHECK 11
#define SO_PRIORITY 12
#define SO_LINGER 13
/* IP options */
#define IP_TOS 1
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
#define IP_TTL 2
/* IPX options */
#define IPX_TYPE 1
/* AX.25 options */
#define AX25_WINDOW 1
/* TCP options */
#define TCP_MSS 1
#define TCP_NODELAY 2
/* The various priorities. */
#define SOPRI_INTERACTIVE 0
......
......@@ -28,7 +28,7 @@ struct ip_config {
unsigned long paddr;
unsigned long router;
unsigned long net;
unsigned int up:1,destroy:1;
unsigned long up:1,destroy:1;
};
#endif /* FIXME: */
......
......@@ -235,7 +235,7 @@ static void calibrate_delay(void)
"r" (ticks),
"0" (loops_per_sec)
:"dx");
printk("ok - %lu.%02lu BogoMips (tm)\n",
printk("ok - %lu.%02lu BogoMips\n",
loops_per_sec/500000,
(loops_per_sec/5000) % 100);
return;
......
......@@ -36,6 +36,9 @@
* Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet.
* Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet
* one.
* Dominik Kubla : Better checking
* Tegge : Assorted corrections on cross port stuff
* Alan Cox : ATF_PERM was backwards! - might be useful now (sigh)
*
* To Fix:
* : arp response allocates an skbuff to send. However there is a perfectly
......@@ -386,7 +389,7 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
/* Delete an ARP mapping entry in the cache. */
void
arp_destroy(unsigned long paddr)
arp_destructor(unsigned long paddr, int force)
{
struct arp_table *apt;
struct arp_table **lapt;
......@@ -406,6 +409,8 @@ arp_destroy(unsigned long paddr)
lapt = &arp_tables[hash];
while ((apt = *lapt) != NULL) {
if (apt->ip == paddr) {
if((apt->flags&ATF_PERM) && !force)
return;
*lapt = apt->next;
if(apt->flags&ATF_PUBL)
arp_proxies--;
......@@ -418,6 +423,23 @@ arp_destroy(unsigned long paddr)
sti();
}
/*
* Kill an entry - eg for ioctl()
*/
void arp_destroy(unsigned long paddr)
{
arp_destructor(paddr,1);
}
/*
* Delete a possibly invalid entry (see timer.c)
*/
void arp_destroy_maybe(unsigned long paddr)
{
arp_destructor(paddr,0);
}
/* Create an ARP entry. The caller should check for duplicates! */
static struct arp_table *
......@@ -536,16 +558,16 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0);
}
/*
* A broadcast arp, ignore it
*/
/*
* A broadcast arp, ignore it
*/
if((dst&0xFF)==0xFF)
if(chk_addr(dst)==IS_BROADCAST)
{
kfree_skb(skb, FREE_READ);
return 0;
}
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
......@@ -654,8 +676,8 @@ arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
* just pretend we did not find it, and then arp_send will
* verify the address for us.
*/
if ((!(apt->flags & ATF_PERM)) ||
(!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
if ((apt->flags & ATF_PERM) ||
(apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) {
apt->last_used = jiffies;
memcpy(haddr, apt->ha, dev->addr_len);
return(0);
......@@ -814,6 +836,11 @@ arp_req_set(struct arpreq *req)
htype = ARPHRD_ETHER;
hlen = ETH_ALEN;
break;
case ARPHRD_AX25:
htype = ARPHRD_AX25;
hlen = 7;
break;
default:
return(-EPFNOSUPPORT);
}
......
......@@ -59,5 +59,6 @@ extern void arp_add_broad(unsigned long addr, struct device *dev);
extern void arp_queue(struct sk_buff *skb);
extern int arp_get_info(char *buffer);
extern int arp_ioctl(unsigned int cmd, void *arg);
extern void arp_destroy_maybe(unsigned long paddr);
#endif /* _ARP_H */
......@@ -2,7 +2,7 @@
* SUCS NET2 Debugged.
*
* Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
* of these would make sense. Not tonight however 8-).
* of these would make sense. Not tonight however 8-).
* This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
* identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
*
......@@ -13,6 +13,7 @@
* Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
* Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
* AX.25 now works right, and SPX is feasible.
* Alan Cox : Fixed write select of non IP protocol crash.
*/
#include <linux/config.h>
......@@ -35,7 +36,7 @@
#include "udp.h"
#include "skbuff.h"
#include "sock.h"
/*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
......@@ -46,16 +47,16 @@
*/
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
{
{
struct sk_buff *skb;
/* Socket is inuse - so the timer doesn't attack it */
restart:
sk->inuse = 1;
while(sk->rqueue == NULL) /* No data */
{
/* If we are shutdown then no more data is going to appear. We are done */
if (sk->shutdown & RCV_SHUTDOWN)
while(sk->rqueue == NULL) /* No data */
{
/* If we are shutdown then no more data is going to appear. We are done */
if (sk->shutdown & RCV_SHUTDOWN)
{
release_sock(sk);
*err=0;
......@@ -69,7 +70,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
sk->err=0;
return NULL;
}
/* Sequenced packets can come disconnected. If so we report the problem */
if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
{
......@@ -77,24 +78,24 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
*err=-ENOTCONN;
return NULL;
}
/* User doesn't want to wait */
if (noblock)
if (noblock)
{
release_sock(sk);
*err=-EAGAIN;
return NULL;
}
release_sock(sk);
/* Interrupts off so that no packet arrives before we begin sleeping.
/* Interrupts off so that no packet arrives before we begin sleeping.
Otherwise we might miss our wake up */
cli();
if (sk->rqueue == NULL)
if (sk->rqueue == NULL)
{
interruptible_sleep_on(sk->sleep);
/* Signals may need a restart of the syscall */
if (current->signal & ~current->blocked)
if (current->signal & ~current->blocked)
{
sti();
*err=-ERESTARTSYS;
......@@ -115,26 +116,26 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
}
/* Again only user level code calls this function, so nothing interrupt level
will suddenely eat the rqueue */
if (!(flags & MSG_PEEK))
if (!(flags & MSG_PEEK))
{
skb=skb_dequeue(&sk->rqueue);
if(skb!=NULL)
skb->users++;
skb=skb_dequeue(&sk->rqueue);
if(skb!=NULL)
skb->users++;
else
goto restart; /* Avoid race if someone beats us to the data */
}
else
{
cli();
skb=skb_peek(&sk->rqueue);
if(skb!=NULL)
skb->users++;
sti();
if(skb==NULL) /* shouldn't happen but .. */
*err=-EAGAIN;
cli();
skb=skb_peek(&sk->rqueue);
if(skb!=NULL)
skb->users++;
sti();
if(skb==NULL) /* shouldn't happen but .. */
*err=-EAGAIN;
}
return skb;
}
}
void skb_free_datagram(struct sk_buff *skb)
{
......@@ -156,7 +157,7 @@ void skb_free_datagram(struct sk_buff *skb)
void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
{
/* We will know all about the fraglist options to allow >4K receives
/* We will know all about the fraglist options to allow >4K receives
but not this release */
memcpy_tofs(to,skb->h.raw+offset,size);
}
......@@ -165,11 +166,11 @@ void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
* Datagram select: Again totally generic. Moved from udp.c
* Now does seqpacket.
*/
int datagram_select(struct sock *sk, int sel_type, select_table *wait)
{
select_wait(sk->sleep, wait);
switch(sel_type)
switch(sel_type)
{
case SEL_IN:
if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
......@@ -177,7 +178,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
/* Connection closed: Wake up */
return(1);
}
if (sk->rqueue != NULL || sk->err != 0)
if (sk->rqueue != NULL || sk->err != 0)
{ /* This appears to be consistent
with other stacks */
return(1);
......@@ -185,16 +186,20 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return(0);
case SEL_OUT:
if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
return(1);
}
if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
{
return(1);
}
return(0);
case SEL_EX:
if (sk->err)
return(1); /* Socket has gone into error state (eg icmp error) */
return(0);
}
return(0);
}
return(0);
}
......@@ -26,6 +26,10 @@
* a) actually works for all A/B nets
* b) doesn't forward off the same interface.
* Alan Cox: Multiple extra protocols
* Alan Cox: Fixed ifconfig up of dud device setting the up flag
* Alan Cox: Fixed verify_area errors
* Alan Cox: Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give
* anything away 8)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -709,9 +713,12 @@ dev_ifconf(char *arg)
struct device *dev;
char *pos;
int len;
int err;
/* Fetch the caller's info block. */
verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
if(err)
return err;
memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
len = ifc.ifc_len;
pos = ifc.ifc_buf;
......@@ -800,7 +807,9 @@ dev_ifsioc(void *arg, unsigned int getset)
int ret;
/* Fetch the caller's info block. */
verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
if(err)
return err;
memcpy_fromfs(&ifr, arg, sizeof(struct ifreq));
/* See which interface the caller is talking about. */
......@@ -827,8 +836,12 @@ dev_ifsioc(void *arg, unsigned int getset)
if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
ret = dev_close(dev);
} else
{
ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP))
? dev_open(dev) : 0;
if(ret<0)
dev->flags&=~IFF_UP; /* Didnt open so down the if */
}
}
break;
case SIOCGIFADDR:
......@@ -946,55 +959,9 @@ dev_ioctl(unsigned int cmd, void *arg)
int ret;
switch(cmd) {
case IP_SET_DEV:
{ /* Maintain backwards-compatibility, to be deleted for 1.00. */
struct device *dev;
/* The old 'struct ip_config'. */
struct ip_config {
char name[MAX_IP_NAME];
unsigned long paddr, router, net,up:1,destroy:1;
} ipc;
int retval, loopback;
printk("INET: Warning: old-style ioctl(IP_SET_DEV) called!\n");
if (!suser())
return (-EPERM);
verify_area (VERIFY_WRITE, arg, sizeof (ipc));
memcpy_fromfs(&ipc, arg, sizeof (ipc));
ipc.name[MAX_IP_NAME-1] = 0;
loopback = (strcmp(ipc.name, "loopback") == 0);
dev = dev_get( loopback ? "lo" : ipc.name);
if (dev == NULL)
return -EINVAL;
ipc.destroy = 0;
dev->pa_addr = ipc.paddr;
dev->family = AF_INET;
dev->pa_mask = get_mask(dev->pa_addr);
dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
if (ipc.net != 0xffffffff) {
dev->flags |= IFF_BROADCAST;
dev->pa_brdaddr = ipc.net;
}
/* To be proper we should delete the route here. */
if (ipc.up == 0)
return (dev->flags & IFF_UP != 0) ? dev_close(dev) : 0;
if ((dev->flags & IFF_UP) == 0
&& (retval = dev_open(dev)) != 0)
return retval;
printk("%s: adding HOST route of %8.8lx.\n", dev->name,
htonl(ipc.paddr));
rt_add(RTF_HOST, ipc.paddr, 0, 0, dev);
if (ipc.router != 0 && ipc.router != -1) {
rt_add(RTF_GATEWAY, ipc.paddr, 0, ipc.router, dev);
printk("%s: adding GATEWAY route of %8.8lx.\n",
dev->name, htonl(ipc.paddr));
}
return 0;
}
case IP_SET_DEV:
printk("Your network configuration program needs upgrading.\n");
return -EINVAL;
case SIOCGIFCONF:
(void) dev_ifconf((char *) arg);
ret = 0;
......
......@@ -17,6 +17,7 @@
* Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and
* minor other things.
* Tegge : Arp bug fixes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -124,7 +125,7 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
cli();
memcpy(eth->h_source, &saddr, 4);
/* No. Ask ARP to resolve the Ethernet address. */
if (arp_find(eth->h_dest, daddr, dev, saddr))
if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr))
{
sti();
if(type!=ETH_P_IP)
......@@ -155,7 +156,7 @@ eth_rebuild_header(void *buff, struct device *dev)
DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */
if (arp_find(eth->h_dest, dst, dev, src)) return(1);
if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */)) return(1);
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return(0);
}
......
......@@ -14,6 +14,7 @@
* Fixes:
* Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected
* Alan Cox : Use tos/ttl settings
*
*
* This program is free software; you can redistribute it and/or
......@@ -108,7 +109,7 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
/* Build Layer 2-3 headers for message back to source. */
offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
&dev, IPPROTO_ICMP, NULL, len);
&dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255);
if (offset < 0) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
......@@ -255,7 +256,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len);
IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
kfree_skb(skb2,FREE_WRITE);
......@@ -319,7 +320,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len);
IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
kfree_skb(skb2,FREE_WRITE);
......
......@@ -31,6 +31,9 @@
* Gerhard Koerting: IP interface addressing fix.
* Linus Torvalds : More robustness checks
* Alan Cox : Even more checks: Still not as robust as it ought to be
* Alan Cox : Save IP header pointer for later
* Alan Cox : ip option setting
* Alan Cox : Use ip_tos/ip_ttl settings
*
* To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules
......@@ -198,7 +201,7 @@ ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
*/
int
ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
struct device **dev, int type, struct options *opt, int len)
struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
{
static struct options optmem;
struct iphdr *iph;
......@@ -256,9 +259,9 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
iph = (struct iphdr *)buff;
iph->version = 4;
iph->tos = 0;
iph->tos = tos;
iph->frag_off = 0;
iph->ttl = 32;
iph->ttl = ttl;
iph->daddr = daddr;
iph->saddr = saddr;
iph->protocol = type;
......@@ -1267,6 +1270,8 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
}
/* Point into the IP datagram, just past the header. */
skb->ip_hdr = iph;
skb->h.raw += iph->ihl*4;
hash = iph->protocol & (MAX_INET_PROTOS -1);
for (ipprot = (struct inet_protocol *)inet_protos[hash];
......@@ -1504,3 +1509,72 @@ int backoff(int n)
}
}
/*
* Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
* an IP socket.
*/
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
int val,err;
if (optval == NULL)
return(-EINVAL);
err=verify_area(VERIFY_READ, optval, sizeof(int));
if(err)
return err;
val = get_fs_long((unsigned long *)optval);
if(level!=SOL_IP)
return -EOPNOTSUPP;
switch(optname)
{
case IP_TOS:
if(val<0||val>255)
return -EINVAL;
sk->ip_tos=val;
return 0;
case IP_TTL:
if(val<1||val<255)
return -EINVAL;
sk->ip_ttl=val;
return 0;
/* IP_OPTIONS and friends go here eventually */
default:
return(-ENOPROTOOPT);
}
}
int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
{
int val,err;
if(level!=SOL_IP)
return -EOPNOTSUPP;
switch(optname)
{
case IP_TOS:
val=sk->ip_tos;
break;
case IP_TTL:
val=sk->ip_ttl;
break;
default:
return(-ENOPROTOOPT);
}
err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
if(err)
return err;
put_fs_long(sizeof(int),(unsigned long *) optlen);
err=verify_area(VERIFY_WRITE, optval, sizeof(int));
if(err)
return err;
put_fs_long(val,(unsigned long *)optval);
return(0);
}
......@@ -69,7 +69,8 @@ extern int ip_build_header(struct sk_buff *skb,
unsigned long saddr,
unsigned long daddr,
struct device **dev, int type,
struct options *opt, int len);
struct options *opt, int len,
int tos,int ttl);
extern unsigned short ip_compute_csum(unsigned char * buff, int len);
extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
......@@ -77,5 +78,7 @@ extern void ip_queue_xmit(struct sock *sk,
struct device *dev, struct sk_buff *skb,
int free);
extern void ip_retransmit(struct sock *sk, int all);
extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
#endif /* _IP_H */
......@@ -18,6 +18,7 @@
* added. Also fixed the peek/read crash
* from all old Linux datagram code.
* Alan Cox : Uses the improved datagram code.
* Alan Cox : Added NULL's for socket options.
*
*
* This program is free software; you can redistribute it and/or
......@@ -264,6 +265,8 @@ struct proto packet_prot = {
NULL,
packet_init,
NULL,
NULL, /* No set/get socket options */
NULL,
128,
0,
{NULL,},
......
......@@ -19,6 +19,10 @@
* Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too
* Alan Cox : Setsocketopt added
* Alan Cox : Fixed error return for broadcasts
* Alan Cox : Removed wake_up calls
* Alan Cox : Use ttl/tos
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -76,7 +80,7 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
}
sk->err = icmp_err_convert[err & 0xff].errno;
wake_up(sk->sleep);
sk->error_report(sk);
return;
}
......@@ -123,7 +127,7 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
}
sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
sk->data_ready(sk,skb->len);
release_sock(sk);
return(0);
}
......@@ -169,7 +173,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
if (sin.sin_port == 0) sin.sin_port = sk->protocol;
if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -ENETUNREACH;
return -EACCES;
sk->inuse = 1;
skb = NULL;
......@@ -214,7 +218,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev,
sk->protocol, sk->opt, skb->mem_len);
sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
kfree_skb(skb,FREE_WRITE);
......@@ -330,6 +334,13 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
return err;
put_fs_long(sizeof(*sin), addr_len);
}
if(sin)
{
err=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
if(err)
return err;
}
err=verify_area(VERIFY_WRITE,to,len);
if(err)
return err;
......@@ -348,7 +359,6 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = skb->daddr;
verify_area(VERIFY_WRITE, sin, sizeof(*sin));
memcpy_tofs(sin, &addr, sizeof(*sin));
}
......@@ -390,6 +400,8 @@ struct proto raw_prot = {
NULL,
raw_init,
NULL,
ip_setsockopt,
ip_getsockopt,
128,
0,
{NULL,},
......
......@@ -121,21 +121,27 @@ void rt_flush(struct device *dev)
* number of zero 8-bit net numbers, otherwise we use the "default"
* masks judging by the destination address and our device netmask.
*/
static inline unsigned long default_mask(unsigned long dst)
{
dst = ntohl(dst);
if (IN_CLASSA(dst))
return htonl(IN_CLASSA_NET);
if (IN_CLASSB(dst))
return htonl(IN_CLASSB_NET);
return htonl(IN_CLASSC_NET);
}
static unsigned long guess_mask(unsigned long dst, struct device * dev)
{
unsigned long mask = 0xffffffff;
/* this is a rather ugly optimization: works only on little-endian machines */
while (mask & dst)
mask >>= 8;
mask <<= 8;
if (mask)
return ~mask;
dst = ntohl(dst);
if (IN_CLASSA(dst))
mask = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(dst))
mask = htonl(IN_CLASSB_NET);
else
mask = htonl(IN_CLASSC_NET);
/* ok, no more hacks.. */
mask = default_mask(dst);
if (dev->flags & IFF_POINTOPOINT)
return mask;
if ((dst ^ dev->pa_addr) & mask)
......
......@@ -13,7 +13,7 @@
* and memory leak hunting.
* Alan Cox : More generic kfree handler
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
......@@ -44,14 +44,14 @@
/*
* Resource tracking variables
*/
volatile unsigned long net_memory=0;
volatile unsigned long net_skbcount=0;
/*
* Debugging paranoia. Can go later when this crud stack works
*/
*/
void skb_check(struct sk_buff *skb, int line, char *file)
......@@ -81,20 +81,20 @@ void skb_check(struct sk_buff *skb, int line, char *file)
/*
* Insert an sk_buff at the start of a list.
*/
void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
{
unsigned long flags;
IS_SKB(newsk);
IS_SKB(newsk);
if(newsk->list)
printk("Suspicious queue head: sk_buff on list!\n");
save_flags(flags);
cli();
newsk->list=list;
newsk->next=*list;
if(*list)
newsk->prev=(*list)->prev;
else
......@@ -110,14 +110,14 @@ void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *newsk)
/*
* Insert an sk_buff at the end of a list.
*/
void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
{
unsigned long flags;
if(newsk->list)
printk("Suspicious queue tail: sk_buff on list!\n");
IS_SKB(newsk);
save_flags(flags);
cli();
......@@ -137,7 +137,7 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
*list=newsk;
}
IS_SKB(newsk->prev);
IS_SKB(newsk->next);
IS_SKB(newsk->next);
restore_flags(flags);
}
......@@ -146,21 +146,21 @@ void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *newsk)
* Remove an sk_buff from a list. This routine is also interrupt safe
* so you can grab read and free buffers as another process adds them.
*/
struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
{
long flags;
struct sk_buff *result;
save_flags(flags);
cli();
if(*list==NULL)
{
restore_flags(flags);
return(NULL);
}
result=*list;
if(result->next==result)
*list=NULL;
......@@ -173,7 +173,7 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
IS_SKB(result);
restore_flags(flags);
if(result->list!=list)
printk("Dequeued packet has invalid list pointer\n");
......@@ -186,19 +186,19 @@ struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
/*
* Insert a packet before another one in a list.
*/
void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
{
unsigned long flags;
IS_SKB(old);
IS_SKB(newsk);
if(!old->list)
printk("insert before unlisted item!\n");
if(newsk->list)
printk("inserted item is already on a list.\n");
save_flags(flags);
cli();
newsk->list=old->list;
......@@ -206,18 +206,18 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk)
newsk->prev=old->prev;
newsk->next->prev=newsk;
newsk->prev->next=newsk;
restore_flags(flags);
}
/*
* Place a packet after a given packet in a list.
*/
void skb_append(struct sk_buff *old, struct sk_buff *newsk)
{
unsigned long flags;
IS_SKB(old);
IS_SKB(newsk);
......@@ -225,7 +225,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
printk("append before unlisted item!\n");
if(newsk->list)
printk("append item is already on a list.\n");
save_flags(flags);
cli();
newsk->list=old->list;
......@@ -233,7 +233,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
newsk->next=old->next;
newsk->next->prev=newsk;
newsk->prev->next=newsk;
restore_flags(flags);
}
......@@ -243,7 +243,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk)
* MUST EXIST when you unlink. Thus a list must have its contents unlinked
* _FIRST_.
*/
void skb_unlink(struct sk_buff *skb)
{
unsigned long flags;
......@@ -251,7 +251,7 @@ void skb_unlink(struct sk_buff *skb)
cli();
IS_SKB(skb);
if(skb->list)
{
skb->next->prev=skb->prev;
......@@ -290,7 +290,7 @@ void skb_new_list_head(struct sk_buff *volatile* list)
while(skb!=*list);
}
}
/*
* Peek an sk_buff. Unlike most other operations you _MUST_
* be careful with this one. A peek leaves the buffer on the
......@@ -310,14 +310,14 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list)
* anyway. Only the memcpy of upto 4K with ints off is not
* as nice as I'd like.
*/
struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
{
struct sk_buff *orig,*newsk;
unsigned long flags;
unsigned int len;
/* Now for some games to avoid races */
do
{
save_flags(flags);
......@@ -336,7 +336,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
if(newsk==NULL) /* Oh dear... not to worry */
return NULL;
save_flags(flags);
cli();
if(skb_peek(list)!=orig) /* List changed go around another time */
......@@ -349,7 +349,7 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
kfree_skb(newsk, FREE_WRITE);
continue;
}
IS_SKB(orig);
IS_SKB(newsk);
memcpy(newsk,orig,len);
......@@ -364,11 +364,11 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
newsk->free=1;
}
while(0);
restore_flags(flags);
return(newsk);
}
}
/*
* Free an sk_buff. This still knows about things it should
* not need to like protocols and sockets.
......@@ -376,68 +376,68 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
void kfree_skb(struct sk_buff *skb, int rw)
{
if (skb == NULL) {
printk("kfree_skb: skb = NULL\n");
return;
}
IS_SKB(skb);
if(skb->free == 2)
printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
if(skb->list)
printk("Warning: kfree_skb passed an skb still on a list.\n");
skb->magic = 0;
if (skb->sk)
{
if(skb->sk->prot!=NULL)
{
if (rw)
skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
else
skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
if (skb == NULL) {
printk("kfree_skb: skb = NULL\n");
return;
}
else
IS_SKB(skb);
if(skb->free == 2)
printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
if(skb->list)
printk("Warning: kfree_skb passed an skb still on a list.\n");
skb->magic = 0;
if (skb->sk)
{
if(skb->sk->prot!=NULL)
{
/* Non INET - default wmalloc/rmalloc handler */
if (rw)
skb->sk->rmem_alloc-=skb->mem_len;
if (rw)
skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
else
skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
}
else
skb->sk->wmem_alloc-=skb->mem_len;
if(!skb->sk->dead)
{
/* Non INET - default wmalloc/rmalloc handler */
if (rw)
skb->sk->rmem_alloc-=skb->mem_len;
else
skb->sk->wmem_alloc-=skb->mem_len;
if(!skb->sk->dead)
wake_up(skb->sk->sleep);
kfree_skbmem(skb->mem_addr,skb->mem_len);
kfree_skbmem(skb->mem_addr,skb->mem_len);
}
}
}
else
kfree_skbmem(skb->mem_addr, skb->mem_len);
else
kfree_skbmem(skb->mem_addr, skb->mem_len);
}
/*
* Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
* fields and also do memory statistics to find all the [BEEP] leaks.
*/
struct sk_buff *alloc_skb(unsigned int size,int priority)
{
struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
if(skb==NULL)
return NULL;
skb->free= 2; /* Invalid so we pick up forgetful users */
skb->list= 0; /* Not on a list */
skb->truesize=size;
skb->mem_len=size;
skb->mem_addr=skb;
skb->fraglist=NULL;
net_memory+=size;
net_skbcount++;
skb->magic_debug_cookie=SK_GOOD_SKB;
skb->users=0;
return skb;
struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
if(skb==NULL)
return NULL;
skb->free= 2; /* Invalid so we pick up forgetful users */
skb->list= 0; /* Not on a list */
skb->truesize=size;
skb->mem_len=size;
skb->mem_addr=skb;
skb->fraglist=NULL;
net_memory+=size;
net_skbcount++;
skb->magic_debug_cookie=SK_GOOD_SKB;
skb->users=0;
return skb;
}
/*
* Free an skbuff by memory
*/
*/
void kfree_skbmem(void *mem,unsigned size)
{
......@@ -451,4 +451,4 @@ void kfree_skbmem(void *mem,unsigned size)
net_memory-=size;
}
}
......@@ -60,6 +60,7 @@ struct sk_buff {
ipx_packet *ipx;
#endif
} h;
struct iphdr *ip_hdr; /* For IPPROTO_RAW */
unsigned long mem_len;
unsigned long len;
unsigned long fraglen;
......
This diff is collapsed.
......@@ -136,7 +136,11 @@ struct sock {
char ax25_retxqi;
char ax25_rrtimer;
char ax25_timer;
ax25_digi *ax25_digipeat;
#endif
/* IP 'private area' or will be eventually */
int ip_ttl; /* TTL setting */
int ip_tos; /* TOS */
struct tcphdr dummy_th;
/* This part is used for the timeout functions (timer.c). */
......@@ -145,6 +149,13 @@ struct sock {
/* identd */
struct socket *socket;
/* Callbacks */
void (*state_change)(struct sock *sk);
void (*data_ready)(struct sock *sk,int bytes);
void (*write_space)(struct sock *sk);
void (*error_report)(struct sock *sk);
};
struct proto {
......@@ -177,7 +188,7 @@ struct proto {
unsigned long saddr,
unsigned long daddr,
struct device **dev, int type,
struct options *opt, int len);
struct options *opt, int len, int tos, int ttl);
int (*connect)(struct sock *sk,
struct sockaddr_in *usin, int addr_len);
struct sock *(*accept) (struct sock *sk, int flags);
......@@ -197,6 +208,10 @@ struct proto {
unsigned long arg);
int (*init)(struct sock *sk);
void (*shutdown)(struct sock *sk, int how);
int (*setsockopt)(struct sock *sk, int level, int optname,
char *optval, int optlen);
int (*getsockopt)(struct sock *sk, int level, int optname,
char *optval, int *option);
unsigned short max_header;
unsigned long retransmits;
struct sock *sock_array[SOCK_ARRAY_SIZE];
......@@ -238,6 +253,8 @@ extern void sock_rfree(struct sock *sk, void *mem,
extern unsigned long sock_rspace(struct sock *sk);
extern unsigned long sock_wspace(struct sock *sk);
extern int sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen);
extern int sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen);
/* declarations from timer.c */
extern struct sock *timer_base;
......
This diff is collapsed.
......@@ -141,7 +141,7 @@ net_timer (unsigned long data)
sk->state = TCP_CLOSE;
delete_timer (sk);
/* Kill the ARP entry in case the hardware has changed. */
arp_destroy (sk->daddr);
arp_destroy_maybe (sk->daddr);
if (!sk->dead)
wake_up (sk->sleep);
sk->shutdown = SHUTDOWN_MASK;
......@@ -167,7 +167,7 @@ net_timer (unsigned long data)
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
arp_destroy (sk->daddr);
arp_destroy_maybe (sk->daddr);
ip_route_check (sk->daddr);
}
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
......@@ -198,14 +198,14 @@ net_timer (unsigned long data)
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
arp_destroy (sk->daddr);
arp_destroy_maybe (sk->daddr);
ip_route_check (sk->daddr);
release_sock (sk);
break;
}
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
arp_destroy (sk->daddr);
arp_destroy_maybe (sk->daddr);
sk->err = ETIMEDOUT;
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
sk->state = TCP_TIME_WAIT;
......
......@@ -30,10 +30,11 @@
* bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram
* Alan Cox : Added get/set sockopt support.
* Alan Cox : Broadcasting without option set returns EACCES.
* Alan Cox : No wakeup calls. Instead we now use the callbacks.
* Alan Cox : Use ip_tos and ip_ttl
*
* To Do:
* Verify all the error codes from UDP operations match the
* BSD behaviour, since thats effectively the formal spec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -114,7 +115,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
if (err < 0) /* As per the calling spec */
{
sk->err = -err;
wake_up(sk->sleep); /* User process wakes to see error */
sk->error_report(sk); /* User process wakes to see error */
return;
}
......@@ -130,7 +131,7 @@ sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
sk->err=ECONNREFUSED;
}
wake_up(sk->sleep);
sk->error_report(sk);
}
......@@ -249,7 +250,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
&dev, IPPROTO_UDP, sk->opt, skb->mem_len);
&dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
skb->sk=sk; /* So memory is freed correctly */
if (tmp < 0 ) {
......@@ -335,7 +336,7 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
}
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -ENETUNREACH; /* Must turn broadcast on first */
return -EACCES; /* Must turn broadcast on first */
sk->inuse = 1;
/* Send the packet. */
......@@ -522,7 +523,7 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return(-EAFNOSUPPORT);
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -ENETUNREACH; /* Must turn broadcast on first */
return -EACCES; /* Must turn broadcast on first */
sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port;
......@@ -604,8 +605,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->len = len - sizeof(*uh);
if (!sk->dead) wake_up(sk->sleep);
if (!sk->dead)
sk->data_ready(sk,skb->len);
release_sock(sk);
return(0);
}
......@@ -635,6 +637,8 @@ struct proto udp_prot = {
udp_ioctl,
NULL,
NULL,
ip_setsockopt,
ip_getsockopt,
128,
0,
{NULL,},
......
......@@ -12,11 +12,12 @@
*
* Fixes:
* Alan Cox : Verify Area
* NET2E Team : Page fault locks
*
* BUGS
* Page faults on read while another process reads could lose data.
* Page faults on write happen to interleave data (probably not allowed)
* with any other simultaneous writers on the socket but dont cause harm.
* To Do:
*
* Change to the NET2E3 code for Unix domain sockets in general. The
* read/write logic is much better and cleaner.
*
*
* This program is free software; you can redistribute it and/or
......@@ -141,6 +142,29 @@ sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
}
/* Support routines doing anti page fault locking
* FvK & Matt Dillon (borrowed From NET2E3)
*/
/*
* Locking for unix-domain sockets. We don't use the socket structure's
* wait queue because it is allowed to 'go away' outside of our control,
* whereas unix_proto_data structures stick around.
*/
void unix_lock(struct unix_proto_data *upd)
{
while (upd->lock_flag)
sleep_on(&upd->wait);
upd->lock_flag = 1;
}
void unix_unlock(struct unix_proto_data *upd)
{
upd->lock_flag = 0;
wake_up(&upd->wait);
}
/* don't have to do anything. */
static int
unix_proto_listen(struct socket *sock, int backlog)
......@@ -598,6 +622,8 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
* Copy from the read buffer into the user's buffer,
* watching for wraparound. Then we wake up the writer.
*/
unix_lock(upd);
do {
int part, cando;
......@@ -612,7 +638,10 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
avail, todo, cando);
if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
{
unix_unlock(upd);
return er;
}
memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
ubuf += cando;
......@@ -620,6 +649,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
avail = UN_BUF_AVAIL(upd);
} while(todo && avail);
unix_unlock(upd);
return(size - todo);
}
......@@ -666,6 +696,9 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
* Copy from the user's buffer to the write buffer,
* watching for wraparound. Then we wake up the reader.
*/
unix_lock(pupd);
do {
int part, cando;
......@@ -681,6 +714,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
*/
if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1);
unix_unlock(pupd);
return(-EPIPE);
}
if ((cando = todo) > space) cando = space;
......@@ -689,7 +723,10 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
space, todo, cando);
er=verify_area(VERIFY_READ, ubuf, cando);
if(er)
{
unix_unlock(pupd);
return er;
}
memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
ubuf += cando;
......@@ -697,6 +734,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
space = UN_BUF_SPACE(pupd);
} while(todo && space);
unix_unlock(pupd);
return(size - todo);
}
......@@ -842,6 +880,8 @@ unix_ioctl(struct inode *inode, struct file *file,
}
static struct file_operations unix_fops = {
NULL, /* LSEEK */
NULL, /* READ */
......
......@@ -35,6 +35,8 @@ struct unix_proto_data {
int bp_head, bp_tail;
struct inode *inode;
struct unix_proto_data *peerupd;
struct wait_queue *wait; /* Lock across page faults (FvK) */
int lock_flag;
};
extern struct unix_proto_data unix_datas[NSOCKETS];
......
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