aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-01-08 13:13:10 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:26 -0400
commit9ee059ad6f92a777f874ddf472cd36aa9a901c16 (patch)
treeb89bcf7ec57269238ee371f67b6a3e1344c89dba
parenta9cc257a8016df80d8bbfdc3ffc6dd2193280c0a (diff)
downloadarchive-9ee059ad6f92a777f874ddf472cd36aa9a901c16.tar.gz
ALPHA-pl14o
-rw-r--r--Makefile4
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/slip.c4
-rw-r--r--fs/isofs/rock.c25
-rw-r--r--include/linux/ip.h2
-rw-r--r--include/linux/socket.h21
-rw-r--r--include/linux/sockios.h10
-rw-r--r--net/Makefile13
-rw-r--r--net/Space.c44
-rw-r--r--net/ddi.c73
-rw-r--r--net/inet/Makefile9
-rw-r--r--net/inet/README23
-rw-r--r--net/inet/arp.c1321
-rw-r--r--net/inet/arp.h36
-rw-r--r--net/inet/datagram.c200
-rw-r--r--net/inet/dev.c1
-rw-r--r--net/inet/devinet.c266
-rw-r--r--net/inet/devinet.h22
-rw-r--r--net/inet/eth.c228
-rw-r--r--net/inet/icmp.c666
-rw-r--r--net/inet/ip.c2412
-rw-r--r--net/inet/ip.h8
-rw-r--r--net/inet/loopback.c130
-rw-r--r--net/inet/packet.c379
-rw-r--r--net/inet/proc.c119
-rw-r--r--net/inet/protocol.c210
-rw-r--r--net/inet/raw.c585
-rw-r--r--net/inet/route.c101
-rw-r--r--net/inet/route.h18
-rw-r--r--net/inet/skbuff.c454
-rw-r--r--net/inet/skbuff.h107
-rw-r--r--net/inet/sockinet.c1636
-rw-r--r--net/inet/sockinet.h118
-rw-r--r--net/inet/tcp.c6004
-rw-r--r--net/inet/tcp.h64
-rw-r--r--net/inet/timer.c340
-rw-r--r--net/inet/udp.c855
-rw-r--r--net/inet/utils.c188
-rw-r--r--net/socket/Makefile37
-rw-r--r--net/socket/datagram.c213
-rw-r--r--net/socket/dev.c980
-rw-r--r--net/socket/dev.h187
-rw-r--r--net/socket/skbuff.c461
-rw-r--r--net/socket/skbuff.h111
-rw-r--r--net/socket/sock.c418
-rw-r--r--net/socket/sock.h191
-rw-r--r--net/unix/proc.c84
-rw-r--r--net/unix/sock.c1373
48 files changed, 7875 insertions, 12880 deletions
diff --git a/Makefile b/Makefile
index 3b14313..bca493a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = n
+ALPHA = o
all: Version zImage
@@ -50,7 +50,7 @@ SVGA_MODE= -DSVGA_MODE=NORMAL_VGA
# standard CFLAGS
#
-CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -pipe
+CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe
ifdef CONFIG_CPP
CFLAGS := $(CFLAGS) -x c++
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e6d1140..51c1c8d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -8,8 +8,8 @@
include CONFIG
NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o)
-CFLAGS := $(CFLAGS) -I../../net/inet -I../../net/socket -I../../net
-CPP := $(CPP) -I../../net/inet -I../../net/socket -I../../net
+CFLAGS := $(CFLAGS) -I../../net/inet
+CPP := $(CPP) -I../../net/inet
# The point of the makefile...
all: net.a
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index a3f2e1c..b72dbca 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -40,9 +40,9 @@
#include <linux/tty.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#ifdef CONFIG_AX25
-#include "ax25/ax25.h"
+#include "ax25.h"
#endif
#include "eth.h"
#include "ip.h"
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 25b4214..ebbb449 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -53,19 +53,27 @@
#define MAYBE_CONTINUE(LABEL,DEV) \
{if (buffer) kfree(buffer); \
if (cont_extent){ \
- int block, offset; \
+ int block, offset, offset1; \
struct buffer_head * bh; \
buffer = kmalloc(cont_size,GFP_KERNEL); \
block = cont_extent; \
offset = cont_offset; \
+ offset1 = 0; \
if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \
block <<= 1; \
if (offset >= 1024) block++; \
offset &= 1023; \
+ if(offset + cont_size >= 1024) { \
+ bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \
+ memcpy(buffer, bh->b_data + offset, 1024 - offset); \
+ brelse(bh); \
+ offset1 = 1024 - offset; \
+ offset = 0; \
+ } \
}; \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \
- memcpy(buffer, bh->b_data, cont_size); \
+ memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
brelse(bh); \
chr = (unsigned char *) buffer; \
len = cont_size; \
@@ -291,10 +299,17 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
};
break;
case SIG('T','F'):
+ /* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
+ Try and handle this correctly for either case. */
cnt = 0; /* Rock ridge never appears on a High Sierra disk */
- if(rr->u.TF.flags & TF_CREATE) inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
- if(rr->u.TF.flags & TF_MODIFY) inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
- if(rr->u.TF.flags & TF_ACCESS) inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0);
+ if(rr->u.TF.flags & TF_CREATE)
+ inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
+ if(rr->u.TF.flags & TF_MODIFY)
+ inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
+ if(rr->u.TF.flags & TF_ACCESS)
+ inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0);
+ if(rr->u.TF.flags & TF_ATTRIBUTES)
+ inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
break;
case SIG('S','L'):
{int slen;
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 887b2cb..26d4a59 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -59,8 +59,6 @@ struct options {
unsigned short handling;
unsigned short stream;
unsigned tcc;
- int option_length;
- void *option_data;
};
diff --git a/include/linux/socket.h b/include/linux/socket.h
index e6a520b..4e5fdbd 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -30,14 +30,10 @@ 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
@@ -45,10 +41,6 @@ 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
@@ -64,19 +56,6 @@ 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
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index 4484b14..499b219 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -24,11 +24,11 @@
#define IP_SET_DEV 0x2401
struct ip_config {
- char name[MAX_IP_NAME];
- unsigned long paddr;
- unsigned long router;
- unsigned long net;
- unsigned int up:1,destroy:1;
+ char name[MAX_IP_NAME];
+ unsigned long paddr;
+ unsigned long router;
+ unsigned long net;
+ unsigned int up:1,destroy:1;
};
#endif /* FIXME: */
diff --git a/net/Makefile b/net/Makefile
index 8299a0e..6478d1e 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -7,17 +7,10 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-SUBDIRS := unix socket
+# only these two lines should need to be changed to remove inet sockets.
+# (and the inet/tcpip.o in net.o)
-ifdef CONFIG_INET
-SUBDIRS := $(SUBDIRS) inet
-endif
-ifdef CONFIG_IPX
-SUBDIRS := $(SUBDIRS) ipx
-endif
-ifdef CONFIG_AX25
-SUBDIRS := $(SUBDIRS) ax25
-endif
+SUBDIRS := unix inet
SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o)
diff --git a/net/Space.c b/net/Space.c
index 5c90082..b2cc011 100644
--- a/net/Space.c
+++ b/net/Space.c
@@ -30,10 +30,10 @@
# include "inet/inet.h"
#endif
#ifdef CONFIG_IPX
-#include "ipx/ipxcall.h"
+#include "inet/ipxcall.h"
#endif
#ifdef CONFIG_AX25
-#include "ax25/ax25call.h"
+#include "inet/ax25call.h"
#endif
struct ddi_proto protocols[] = {
@@ -53,3 +53,43 @@ struct ddi_proto protocols[] = {
};
+/*
+ * Section B: Device Driver Modules.
+ * This section defines which network device drivers
+ * get linked into the Linux kernel. It is currently
+ * only used by the INET protocol. Any takers for the
+ * other protocols like XNS or Novell?
+ *
+ * WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!!
+ */
+/*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */
+/*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */
+/*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */
+
+
+struct ddi_device devices[] = {
+#if CONF_WE8003
+ { "WD80x3[EBT]",
+ "", 0, 1, we8003_init, NULL,
+ 19, 0, DDI_FCHRDEV,
+ { 0x280, 0, 15, 0, 32768, 0xD0000 } },
+#endif
+#if CONF_DP8390
+ { "DP8390/WD80x3",
+ "", 0, 1, dpwd8003_init, NULL,
+ 20, 0, DDI_FCHRDEV,
+ { 0, 0, 0, 0, 0, 0, } },
+ { "DP8390/NE-x000",
+ "", 0, 1, dpne2000_init, NULL,
+ 20, 8, DDI_FCHRDEV,
+ { 0, 0, 0, 0, 0, 0, } },
+ { "DP8390/3C50x",
+ "", 0, 1, dpec503_init, NULL,
+ 20, 16, DDI_FCHRDEV,
+ { 0, 0, 0, 0, 0, 0, } },
+#endif
+ { NULL,
+ "", 0, 0, NULL, NULL,
+ 0, 0, 0,
+ { 0, 0, 0, 0, 0, 0 } }
+};
diff --git a/net/ddi.c b/net/ddi.c
index 79bcb00..7ebd3bf 100644
--- a/net/ddi.c
+++ b/net/ddi.c
@@ -4,11 +4,9 @@
* but it eventually might move to an upper directory of
* the system.
*
- * Version: @(#)ddi.c 1.28 27/12/93
+ * Version: @(#)ddi.c 1.0.5 04/22/93
*
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
- * Unused pieces nobbled.
*/
#include <asm/segment.h>
#include <asm/system.h>
@@ -20,9 +18,6 @@
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/ddi.h>
-#include <linux/interrupt.h>
-
-#include "socket/dev.h"
#undef DDI_DEBUG
@@ -33,32 +28,64 @@
#endif
+extern struct ddi_device devices[]; /* device driver map */
extern struct ddi_proto protocols[]; /* network protocols */
/*
+ * This function gets called with an ASCII string representing the
+ * ID of some DDI driver. We loop through the DDI Devices table
+ * and return the address of the control block that has a matching
+ * "name" field. It is used by upper-level layers that want to
+ * dynamically bind some UNIX-domain "/dev/XXXX" file name to a
+ * DDI device driver. The "iflink(8)" program is an example of
+ * this behaviour.
+ */
+struct ddi_device *
+ddi_map(const char *id)
+{
+ register struct ddi_device *dev;
+
+ PRINTK (("DDI: MAP: looking for \"%s\": ", id));
+ dev = devices;
+ while (dev->title != NULL) {
+ if (strncmp(dev->name, id, DDI_MAXNAME) == 0) {
+ PRINTK (("OK at 0x%X\n", dev));
+ return(dev);
+ }
+ dev++;
+ }
+ PRINTK (("NOT FOUND\n"));
+ return(NULL);
+}
+
+
+/*
* This is the function that is called by a kernel routine during
* system startup. Its purpose is to walk trough the "devices"
* table (defined above), and to call all moduled defined in it.
*/
-
-void ddi_init(void)
+void
+ddi_init(void)
{
- struct ddi_proto *pro;
+ struct ddi_proto *pro;
+ struct ddi_device *dev;
- PRINTK (("DDI: Starting up!\n"));
+ PRINTK (("DDI: Starting up!\n"));
- /* First off, kick all configured protocols. */
- pro = protocols;
- while (pro->name != NULL)
- {
- (*pro->init)(pro);
- pro++;
- }
+ /* First off, kick all configured protocols. */
+ pro = protocols;
+ while (pro->name != NULL) {
+ (*pro->init)(pro);
+ pro++;
+ }
- dev_init();
- /* Initialize the "Buffer Head" pointers. */
- bh_base[INET_BH].routine = inet_bh;
-
- /* We're all done... */
-}
+ /* Done. Now kick all configured device drivers. */
+ dev = devices;
+ while (dev->title != NULL) {
+ (*dev->init)(dev);
+ dev++;
+ }
+
+ /* We're all done... */
+}
diff --git a/net/inet/Makefile b/net/inet/Makefile
index 4c1aa76..a10caa3 100644
--- a/net/inet/Makefile
+++ b/net/inet/Makefile
@@ -7,9 +7,6 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-CFLAGS := $(CFLAGS) -I../socket -I..
-CPP := $(CPP) -I../socket -I..
-
.c.o:
$(CC) $(CFLAGS) -c -o $*.o $<
.s.o:
@@ -18,8 +15,10 @@ CPP := $(CPP) -I../socket -I..
$(CC) $(CFLAGS) -S -o $*.s $<
-OBJS = sockinet.o utils.o route.o proc.o timer.o protocol.o loopback.o \
- eth.o packet.o arp.o devinet.o ip.o raw.o icmp.o tcp.o udp.o
+OBJS = sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \
+ eth.o packet.o arp.o dev.o ip.o raw.o icmp.o tcp.o udp.o \
+ datagram.o skbuff.o
+# ipx.o ax25.o ax25_in.o ax25_out.o ax25_subr.o ax25_timer.o
ifdef CONFIG_INET
diff --git a/net/inet/README b/net/inet/README
index f216f16..79f957f 100644
--- a/net/inet/README
+++ b/net/inet/README
@@ -1,8 +1,27 @@
-NET2Debugged 1.28 README
+NET2Debugged 1.24 README
------------------------
-
+Major Changes
+
+o PLIP driver sort of works
+o UDP and RAW have been partially rewritten for speed
+o Internals heavily cleaned up, and memory monitoring of network
+ memory is now done. (On shift-scroll-lock)
+o ARP should now not generate garbage
+o Using MSG_PEEK can't cause race conditions and crashes
+o Support for bootp clients.
+o Supports RFC931 TAP authd
+o NFS problems with certain types of network configuration are
+ fixed.
+o Doesn't forward packets for other subnet (can cause packet storms)
+o TCP won't ack rst frames causing packet storms (especially with
+ Lan workplace for DOS).
+o Numerous fixes for solidity
+o Verify_area used properly.
+o MSG_PEEK is faster again
+o Minor TCP fixes. Hopefully no more TCP lockups (ha!)
+o Donald's promiscuous mode. Go forth and write protocol analysers...
-------------------------------------------------------------------------
NOTE:
Drivers for this stack set must be using alloc_skb() not just
diff --git a/net/inet/arp.c b/net/inet/arp.c
index c272817..0b69e1f 100644
--- a/net/inet/arp.c
+++ b/net/inet/arp.c
@@ -13,7 +13,7 @@
* resolver, like it should be. It will be put in a separate
* directory under 'net', being a protocol of its own. -FvK
*
- * Version: @(#)arp.c 1.28 20/12/93
+ * Version: @(#)arp.c 1.0.15 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -36,11 +36,6 @@
* 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 : Heavily reformatted & recommented ready for the big day
- * 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
@@ -69,27 +64,52 @@
#include <asm/segment.h>
#include <stdarg.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "arp.h"
-/*
- * We will try an ARP the recommended three times before we abandon it. If we
- * do abandon it all is not lost as the next frame will also try.
- */
#define ARP_MAX_TRIES 3
-/*
- * The ARP table itself
- */
-
+
+static char *unk_print(unsigned char *, int);
+static char *eth_aprint(unsigned char *, int);
+
+
+static char *arp_cmds[] = {
+ "0x%04X",
+ "REQUEST",
+ "REPLY",
+ "REVERSE REQUEST",
+ "REVERSE REPLY",
+ NULL
+};
+#define ARP_MAX_CMDS (sizeof(arp_cmds) / sizeof(arp_cmds[0]))
+
+static struct {
+ char *name;
+ char *(*print)(unsigned char *ptr, int len);
+} arp_types[] = {
+ { "0x%04X", unk_print },
+ { "10 Mbps Ethernet", eth_aprint },
+ { "3 Mbps Ethernet", eth_aprint },
+ { "AX.25", unk_print },
+ { "Pronet", unk_print },
+ { "Chaos", unk_print },
+ { "IEEE 802.2 Ethernet (?)", eth_aprint },
+ { "Arcnet", unk_print },
+ { "AppleTalk", unk_print },
+ { NULL, NULL }
+};
+#define ARP_MAX_TYPE (sizeof(arp_types) / sizeof(arp_types[0]))
+
+
struct arp_table *arp_tables[ARP_TABLE_SIZE] = {
NULL,
};
@@ -98,43 +118,103 @@ static int arp_proxies=0; /* So we can avoid the proxy arp
overhead with the usual case of
no proxy arps */
-/*
- * Every packet awaiting an ARP resolution is stuffed on this
- * queue until resolved or deleted. Note items in this queue
- * may be on other (tcp retransmit) queues and we must not
- * be the one to delete them.
- */
-
struct sk_buff * volatile arp_q = NULL;
static struct arp_table *arp_lookup(unsigned long addr);
static struct arp_table *arp_lookup_proxy(unsigned long addr);
-/*
- * We grab the arp queue, empty it and walk down it adding anything we can't
- * resolve back onto the queue. We MUST do things this way as other entries
- * may (will) get added as we walk the old list.
- */
+/* Dump the ADDRESS bytes of an unknown hardware type. */
+static char *
+unk_print(unsigned char *ptr, int len)
+{
+ static char buff[32];
+ char *bufp = buff;
+ int i;
+
+ for (i = 0; i < len; i++)
+ bufp += sprintf(bufp, "%02X ", (*ptr++ & 0377));
+ return(buff);
+}
+
-static void arp_send_q(void)
+/* Dump the ADDRESS bytes of an Ethernet hardware type. */
+static char *
+eth_aprint(unsigned char *ptr, int len)
{
- struct sk_buff *skb;
- struct sk_buff *volatile work_q;
- cli();
- work_q = arp_q;
- skb_new_list_head(&work_q);
- arp_q = NULL;
- sti();
- while((skb=skb_dequeue(&work_q))!=NULL)
- {
- IS_SKB(skb);
- skb->magic = 0; /* So everyone knows this is _NOT_ on the arp queue */
+ if (len != ETH_ALEN) return("");
+ return(eth_print(ptr));
+}
- /* Decrement the 'tries' counter. */
- cli();
- skb->tries--;
- if (skb->tries == 0)
- {
+
+/* Dump an ARP packet. Not complete yet for non-Ethernet packets. */
+static void
+arp_print(struct arphdr *arp)
+{
+ int len, idx;
+ unsigned char *ptr;
+
+ if (inet_debug != DBG_ARP) return;
+
+ printk("ARP: ");
+ if (arp == NULL) {
+ printk("(null)\n");
+ return;
+ }
+
+ /* Print the opcode name. */
+ len = htons(arp->ar_op);
+ if (len < ARP_MAX_CMDS) idx = len;
+ else idx = 0;
+ printk("op ");
+ printk(arp_cmds[idx], len);
+
+ /* Print the ARP header. */
+ len = htons(arp->ar_hrd);
+ if (len < ARP_MAX_TYPE) idx = len;
+ else idx = 0;
+ printk(" hrd = "); printk(arp_types[idx].name, len);
+ printk(" pro = 0x%04X\n", htons(arp->ar_pro));
+ printk(" hlen = %d plen = %d\n", arp->ar_hln, arp->ar_pln);
+
+ /*
+ * Print the variable data.
+ * When ARP gets redone (after the formal introduction of NET-2),
+ * this part will be redone. ARP will then be a multi-family address
+ * resolver, and the code below will be made more general. -FvK
+ */
+ ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
+ printk(" sender HA = %s ", arp_types[idx].print(ptr, arp->ar_hln));
+ ptr += arp->ar_hln;
+ printk(" PA = %s\n", in_ntoa(*(unsigned long *) ptr));
+ ptr += arp->ar_pln;
+ printk(" target HA = %s ", arp_types[idx].print(ptr, arp->ar_hln));
+ ptr += arp->ar_hln;
+ printk(" PA = %s\n", in_ntoa(*(unsigned long *) ptr));
+}
+
+
+/* This will try to retransmit everything on the queue. */
+static void
+arp_send_q(void)
+{
+ struct sk_buff *skb;
+ struct sk_buff *volatile work_q;
+ cli();
+ work_q = arp_q;
+ skb_new_list_head(&work_q);
+ arp_q = NULL;
+ sti();
+ while((skb=skb_dequeue(&work_q))!=NULL)
+ {
+ IS_SKB(skb);
+ skb->magic = 0;
+ skb->next = NULL;
+ skb->prev = NULL;
+
+ /* Decrement the 'tries' counter. */
+ cli();
+ skb->tries--;
+ if (skb->tries == 0) {
/*
* Grmpf.
* We have tried ARP_MAX_TRIES to resolve the IP address
@@ -144,270 +224,231 @@ static void arp_send_q(void)
* In any case, trying further is useless. So, we kill
* this packet from the queue. (grinnik) -FvK
*/
- skb->sk = NULL;
- if(skb->free)
- kfree_skb(skb, FREE_WRITE);
+ skb->sk = NULL;
+ if(skb->free)
+ kfree_skb(skb, FREE_WRITE);
/* If free was 0, magic is now 0, next is 0 and
the write queue will notice and kill */
- sti();
- continue;
- }
-
- /* Can we now complete this packet? */
sti();
- if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev))
- {
- skb->arp = 1;
- skb->dev->queue_xmit(skb, skb->dev, 0);
- }
- else
- {
- /* Alas. Re-queue it... */
- skb->magic = ARP_QUEUE_MAGIC;
- skb_queue_head(&arp_q,skb);
- }
- }
+ continue;
+ }
+
+ /* Can we now complete this packet? */
+ sti();
+ if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev)) {
+ skb->arp = 1;
+ skb->dev->queue_xmit(skb, skb->dev, 0);
+ } else {
+ /* Alas. Re-queue it... */
+ skb->magic = ARP_QUEUE_MAGIC;
+ skb_queue_head(&arp_q,skb);
+ }
+ }
}
-/*
- * Create and send our response to an ARP request.
- */
-
-static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
+/* Create and send our response to an ARP request. */
+static int
+arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
{
- struct arphdr *arp2;
- struct sk_buff *skb;
- unsigned long src, dst;
- unsigned char *ptr1, *ptr2;
- int hlen;
- struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */
-
- /* Decode the source (REQUEST) message. */
- ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short);
- src = *((unsigned long *) (ptr1 + arp1->ar_hln));
- dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln));
+ struct arphdr *arp2;
+ struct sk_buff *skb;
+ unsigned long src, dst;
+ unsigned char *ptr1, *ptr2;
+ int hlen;
+ struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */
+
+ /* Decode the source (REQUEST) message. */
+ ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short);
+ src = *((unsigned long *) (ptr1 + arp1->ar_hln));
+ dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln));
- if(addrtype!=IS_MYADDR)
- {
- apt=arp_lookup_proxy(dst);
- if(apt==NULL)
- return(1);
- }
-
- /* Get some mem and initialize it for the return trip. */
- skb = alloc_skb(sizeof(struct sk_buff) +
+ if(addrtype!=IS_MYADDR)
+ {
+ apt=arp_lookup_proxy(dst);
+ if(apt==NULL)
+ return(1);
+ }
+
+ /* Get some mem and initialize it for the return trip. */
+ skb = alloc_skb(sizeof(struct sk_buff) +
sizeof(struct arphdr) +
(2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
dev->hard_header_len, GFP_ATOMIC);
-
- if (skb == NULL)
- {
- printk("ARP: no memory available for ARP REPLY!\n");
- return(1);
- }
-
- skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
- (2 * arp1->ar_pln) + dev->hard_header_len;
- hlen = dev->hard_header((unsigned char *)(skb+1), dev,
+ if (skb == NULL) {
+ printk("ARP: no memory available for ARP REPLY!\n");
+ return(1);
+ }
+
+ skb->mem_addr = skb;
+ skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
+ (2 * arp1->ar_pln) + dev->hard_header_len;
+ skb->mem_len = sizeof(struct sk_buff) + skb->len;
+ hlen = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, src, dst, skb->len);
- if (hlen < 0)
- {
- printk("ARP: cannot create HW frame header for REPLY !\n");
- kfree_skb(skb, FREE_WRITE);
- return(1);
- }
+ if (hlen < 0) {
+ printk("ARP: cannot create HW frame header for REPLY !\n");
+ kfree_skb(skb, FREE_WRITE);
+ return(1);
+ }
/*
* Fill in the ARP REPLY packet.
* This looks ugly, but we have to deal with the variable-length
* ARP packets and such. It is not as bad as it looks- FvK
*/
- arp2 = (struct arphdr *) ((unsigned char *) (skb+1) + hlen);
- ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short);
- arp2->ar_hrd = arp1->ar_hrd;
- arp2->ar_pro = arp1->ar_pro;
- arp2->ar_hln = arp1->ar_hln;
- arp2->ar_pln = arp1->ar_pln;
- arp2->ar_op = htons(ARPOP_REPLY);
-
- if(addrtype==IS_MYADDR)
- memcpy(ptr2, dev->dev_addr, arp2->ar_hln);
- else /* Proxy arp, so pull from the table */
- memcpy(ptr2, apt->ha, arp2->ar_hln);
-
- ptr2 += arp2->ar_hln;
- memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);
- ptr2 += arp2->ar_pln;
- memcpy(ptr2, ptr1, arp2->ar_hln);
- ptr2 += arp2->ar_hln;
- memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln);
-
- skb->free = 1;
- skb->arp = 1;
- skb->sk = NULL;
- skb->next = NULL;
-
- /* Queue the packet for transmission. */
- dev->queue_xmit(skb, dev, 0);
- return(0);
+ arp2 = (struct arphdr *) ((unsigned char *) (skb+1) + hlen);
+ ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short);
+ arp2->ar_hrd = arp1->ar_hrd;
+ arp2->ar_pro = arp1->ar_pro;
+ arp2->ar_hln = arp1->ar_hln;
+ arp2->ar_pln = arp1->ar_pln;
+ arp2->ar_op = htons(ARPOP_REPLY);
+ if(addrtype==IS_MYADDR)
+ memcpy(ptr2, dev->dev_addr, arp2->ar_hln);
+ else /* Proxy arp, so pull from the table */
+ memcpy(ptr2, apt->ha, arp2->ar_hln);
+ ptr2 += arp2->ar_hln;
+ memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);
+ ptr2 += arp2->ar_pln;
+ memcpy(ptr2, ptr1, arp2->ar_hln);
+ ptr2 += arp2->ar_hln;
+ memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln);
+
+ skb->free = 1;
+ skb->arp = 1;
+ skb->sk = NULL;
+ skb->next = NULL;
+
+ DPRINTF((DBG_ARP, ">>"));
+ arp_print(arp2);
+
+ /* Queue the packet for transmission. */
+ dev->queue_xmit(skb, dev, 0);
+ return(0);
}
-/*
- * This will find an entry in the ARP table by looking at the IP address.
- */
-
-static struct arp_table *arp_lookup(unsigned long paddr)
+/* This will find an entry in the ARP table by looking at the IP address. */
+static struct arp_table *
+arp_lookup(unsigned long paddr)
{
- struct arp_table *apt;
- unsigned long hash;
-
- DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));
-
- /* We don't want to ARP ourselves. */
- if (chk_addr(paddr) == IS_MYADDR)
- {
- printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr));
- return(NULL);
- }
-
- /* Loop through the table for the desired address. */
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
- cli();
- apt = arp_tables[hash];
- while(apt != NULL)
- {
- if (apt->ip == paddr)
- {
- sti();
- return(apt);
- }
- apt = apt->next;
- }
- sti();
- return(NULL);
+ struct arp_table *apt;
+ unsigned long hash;
+
+ DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));
+
+ /* We don't want to ARP ourselves. */
+ if (chk_addr(paddr) == IS_MYADDR) {
+ printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr));
+ return(NULL);
+ }
+
+ /* Loop through the table for the desired address. */
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+ cli();
+ apt = arp_tables[hash];
+ while(apt != NULL) {
+ if (apt->ip == paddr) {
+ sti();
+ return(apt);
+ }
+ apt = apt->next;
+ }
+ sti();
+ return(NULL);
}
-/*
- * This will find a proxy in the ARP table by looking at the IP address.
- */
-
+/* This will find a proxy in the ARP table by looking at the IP address. */
static struct arp_table *arp_lookup_proxy(unsigned long paddr)
{
- struct arp_table *apt;
- unsigned long hash;
+ struct arp_table *apt;
+ unsigned long hash;
- DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr)));
- /* Loop through the table for the desired address. */
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
- cli();
- apt = arp_tables[hash];
- while(apt != NULL)
- {
- if (apt->ip == paddr && (apt->flags & ATF_PUBL) )
- {
- sti();
- return(apt);
- }
- apt = apt->next;
- }
- sti();
- return(NULL);
+ /* Loop through the table for the desired address. */
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+ cli();
+ apt = arp_tables[hash];
+ while(apt != NULL) {
+ if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) {
+ sti();
+ return(apt);
+ }
+ apt = apt->next;
+ }
+ sti();
+ return(NULL);
}
-/*
- * Delete an ARP mapping entry in the cache.
- */
-
-static void arp_destructor(unsigned long paddr, int force)
+/* Delete an ARP mapping entry in the cache. */
+void
+arp_destroy(unsigned long paddr)
{
- struct arp_table *apt;
- struct arp_table **lapt;
- unsigned long hash;
+ struct arp_table *apt;
+ struct arp_table **lapt;
+ unsigned long hash;
- DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr)));
- /* We cannot destroy our own ARP entry. */
- if (chk_addr(paddr) == IS_MYADDR)
- {
- DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n",
+ /* We cannot destroy our own ARP entry. */
+ if (chk_addr(paddr) == IS_MYADDR) {
+ DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n",
in_ntoa(paddr)));
+ return;
+ }
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+
+ cli();
+ lapt = &arp_tables[hash];
+ while ((apt = *lapt) != NULL) {
+ if (apt->ip == paddr) {
+ *lapt = apt->next;
+ if(apt->flags&ATF_PUBL)
+ arp_proxies--;
+ kfree_s(apt, sizeof(struct arp_table));
+ sti();
return;
}
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
-
- cli();
- 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--;
- kfree_s(apt, sizeof(struct arp_table));
- sti();
- return;
- }
- lapt = &apt->next;
- }
- sti();
+ lapt = &apt->next;
+ }
+ 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)
+/* Create an ARP entry. The caller should check for duplicates! */
+static struct arp_table *
+arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
{
- arp_destructor(paddr,0);
-}
-
-/*
- * Create an ARP entry. The caller should check for duplicates!
- */
-
-static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
-{
- struct arp_table *apt;
- unsigned long hash;
-
-
- apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
- if (apt == NULL)
- {
- printk("ARP: no memory available for new ARP entry!\n");
- return(NULL);
- }
-
- /* Fill in the allocated ARP cache entry. */
- hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
- apt->ip = paddr;
- apt->hlen = hlen;
- apt->htype = htype;
- apt->flags = (ATF_INUSE | ATF_COM); /* USED and COMPLETED entry */
- memcpy(apt->ha, addr, hlen);
- apt->last_used = jiffies;
- cli();
- apt->next = arp_tables[hash];
- arp_tables[hash] = apt;
- sti();
- return(apt);
+ struct arp_table *apt;
+ unsigned long hash;
+
+ DPRINTF((DBG_ARP, "ARP: create(%s, ", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "%s, ", eth_print(addr)));
+ DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype));
+
+ apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
+ if (apt == NULL) {
+ printk("ARP: no memory available for new ARP entry!\n");
+ return(NULL);
+ }
+
+ /* Fill in the allocated ARP cache entry. */
+ hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
+ apt->ip = paddr;
+ apt->hlen = hlen;
+ apt->htype = htype;
+ apt->flags = (ATF_INUSE | ATF_COM); /* USED and COMPLETED entry */
+ memcpy(apt->ha, addr, hlen);
+ apt->last_used = jiffies;
+ cli();
+ apt->next = arp_tables[hash];
+ arp_tables[hash] = apt;
+ sti();
+ return(apt);
}
@@ -420,295 +461,281 @@ static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, in
* one of our own IP addresses), we set up and send out an ARP REPLY
* packet to the sender.
*/
-int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+int
+arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- struct arphdr *arp;
- struct arp_table *tbl;
- unsigned long src, dst;
- unsigned char *ptr;
- int ret;
- int addr_hint;
-
- arp = skb->h.arp;
-
- /* If this test doesn't pass, its not IP. Might be DECNET or friends */
- if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
- {
- DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name));
- kfree_skb(skb, FREE_READ);
- return(0);
- }
+ struct arphdr *arp;
+ struct arp_table *tbl;
+ unsigned long src, dst;
+ unsigned char *ptr;
+ int ret;
+ int addr_hint;
+
+ DPRINTF((DBG_ARP, "<<\n"));
+ arp = skb->h.arp;
+ arp_print(arp);
+
+ /* If this test doesn't pass, its not IP. Might be DECNET or friends */
+ if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
+ {
+ DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name));
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ /* For now we will only deal with IP addresses. */
+ if (((arp->ar_pro != NET16(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4)
+ {
+ if (arp->ar_op != NET16(ARPOP_REQUEST))
+ DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name));
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
- /* For now we will only deal with IP addresses. */
- if (((arp->ar_pro != NET16(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4)
- {
- if (arp->ar_op != NET16(ARPOP_REQUEST))
- DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name));
+ /*
+ * As said before, we try to be smart by using the
+ * info already present in the packet: the sender's
+ * IP and hardware address.
+ */
+ ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
+ memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);
+ tbl = arp_lookup(src);
+ if (tbl != NULL) {
+ DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));
+ memcpy(tbl->ha, ptr, arp->ar_hln);
+ tbl->hlen = arp->ar_hln;
+ tbl->flags |= ATF_COM;
+ tbl->last_used = jiffies;
+ } else {
+ memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
+ if (chk_addr(dst) != IS_MYADDR) {
kfree_skb(skb, FREE_READ);
return(0);
- }
-
- /*
- * As said before, we try to be smart by using the
- * info already present in the packet: the sender's
- * IP and hardware address.
- */
- ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
- memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);
- tbl = arp_lookup(src);
- if (tbl != NULL)
- {
- DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));
- memcpy(tbl->ha, ptr, arp->ar_hln);
- tbl->hlen = arp->ar_hln;
- tbl->flags |= ATF_COM;
- tbl->last_used = jiffies;
- }
- else
- {
- memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
- if (chk_addr(dst) != IS_MYADDR)
- {
+ } else {
+ tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);
+ if (tbl == NULL) {
kfree_skb(skb, FREE_READ);
return(0);
- }
- else
- {
- tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);
- if (tbl == NULL)
- {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
}
- }
+ }
+ }
/*
* Since we updated the ARP cache, we might have enough
* information to send out some previously queued IP
* datagrams....
*/
- arp_send_q();
+ arp_send_q();
/*
* OK, we used that part of the info. Now check if the
* request was an ARP REQUEST for one of our own addresses..
*/
- if (arp->ar_op != NET16(ARPOP_REQUEST))
- {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
+ if (arp->ar_op != NET16(ARPOP_REQUEST)) {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
/*
* A broadcast arp, ignore it
*/
- if(chk_addr(dst)==IS_BROADCAST)
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
+ if((dst&0xFF)==0xFF)
+ {
+ 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"));
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- /*
- * Yes, it is for us.
- * Allocate, fill in and send an ARP REPLY packet.
- */
- ret = arp_response(arp, dev, addr_hint);
- kfree_skb(skb, FREE_READ);
- return(ret);
+ 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"));
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ /*
+ * Yes, it is for us.
+ * Allocate, fill in and send an ARP REPLY packet.
+ */
+ ret = arp_response(arp, dev, addr_hint);
+ kfree_skb(skb, FREE_READ);
+ return(ret);
}
-/*
- * Create and send an ARP REQUEST packet.
- */
-
-void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
+/* Create and send an ARP REQUEST packet. */
+void
+arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
{
- struct sk_buff *skb;
- struct arphdr *arp;
- unsigned char *ptr;
- int tmp;
+ struct sk_buff *skb;
+ struct arphdr *arp;
+ unsigned char *ptr;
+ int tmp;
- DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr)));
- DPRINTF((DBG_ARP, "dev=%s, ", dev->name));
- DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));
+ DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "dev=%s, ", dev->name));
+ DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));
- skb = alloc_skb(sizeof(struct sk_buff) +
+ skb = alloc_skb(sizeof(struct sk_buff) +
sizeof(struct arphdr) + (2 * dev->addr_len) +
dev->hard_header_len +
(2 * 4 /* arp->plen */), GFP_ATOMIC);
- if (skb == NULL)
- {
- printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
- return;
- }
+ if (skb == NULL) {
+ printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
+ return;
+ }
- /* Fill in the request. */
- skb->sk = NULL;
- skb->len = sizeof(struct arphdr) +
+ /* Fill in the request. */
+ skb->sk = NULL;
+ skb->mem_addr = skb;
+ skb->len = sizeof(struct arphdr) +
dev->hard_header_len + (2 * dev->addr_len) + 8;
- skb->arp = 1;
- skb->dev = dev;
- skb->next = NULL;
- skb->free = 1;
- tmp = dev->hard_header((unsigned char *)(skb+1), dev,
+ skb->mem_len = sizeof(struct sk_buff) + skb->len;
+ skb->arp = 1;
+ skb->dev = dev;
+ skb->next = NULL;
+ skb->free = 1;
+ tmp = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, 0, saddr, skb->len);
- if (tmp < 0)
- {
- kfree_skb(skb,FREE_WRITE);
- return;
- }
- arp = (struct arphdr *) ((unsigned char *) (skb+1) + tmp);
- arp->ar_hrd = htons(dev->type);
- if(dev->type!=3) /* AX.25 */
- arp->ar_pro = htons(ETH_P_IP);
- else
- arp->ar_pro = htons(0xCC);
- arp->ar_hln = dev->addr_len;
- arp->ar_pln = 4;
- arp->ar_op = htons(ARPOP_REQUEST);
-
- ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
- memcpy(ptr, dev->dev_addr, arp->ar_hln);
- ptr += arp->ar_hln;
- memcpy(ptr, &saddr, arp->ar_pln);
- ptr += arp->ar_pln;
- /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/
- memset(ptr,0,arp->ar_hln);
- ptr += arp->ar_hln;
- memcpy(ptr, &paddr, arp->ar_pln);
-
- dev->queue_xmit(skb, dev, 0);
+ if (tmp < 0) {
+ kfree_skb(skb,FREE_WRITE);
+ return;
+ }
+ arp = (struct arphdr *) ((unsigned char *) (skb+1) + tmp);
+ arp->ar_hrd = htons(dev->type);
+ if(dev->type!=3) /* AX.25 */
+ arp->ar_pro = htons(ETH_P_IP);
+ else
+ arp->ar_pro = htons(0xCC);
+ arp->ar_hln = dev->addr_len;
+ arp->ar_pln = 4;
+ arp->ar_op = htons(ARPOP_REQUEST);
+
+ ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
+ memcpy(ptr, dev->dev_addr, arp->ar_hln);
+ ptr += arp->ar_hln;
+ memcpy(ptr, &saddr, arp->ar_pln);
+ ptr += arp->ar_pln;
+ /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/
+ memset(ptr,0,arp->ar_hln);
+ ptr += arp->ar_hln;
+ memcpy(ptr, &paddr, arp->ar_pln);
+
+ DPRINTF((DBG_ARP, ">>\n"));
+ arp_print(arp);
+ dev->queue_xmit(skb, dev, 0);
}
-/*
- * Find an ARP mapping in the cache. If not found, post a REQUEST.
- */
-
-int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
- unsigned long saddr)
+/* Find an ARP mapping in the cache. If not found, post a REQUEST. */
+int
+arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
+ unsigned long saddr)
{
- struct arp_table *apt;
+ struct arp_table *apt;
- switch(chk_addr(paddr))
- {
- case IS_MYADDR:
- memcpy(haddr, dev->dev_addr, dev->addr_len);
- return(0);
- case IS_BROADCAST:
- memcpy(haddr, dev->broadcast, dev->addr_len);
- return(0);
- }
+ DPRINTF((DBG_ARP, "ARP: find(haddr=%s, ", eth_print(haddr)));
+ DPRINTF((DBG_ARP, "paddr=%s, ", in_ntoa(paddr)));
+ DPRINTF((DBG_ARP, "dev=%s, saddr=%s)\n", dev->name, in_ntoa(saddr)));
+
+ switch(chk_addr(paddr)) {
+ case IS_MYADDR:
+ memcpy(haddr, dev->dev_addr, dev->addr_len);
+ return(0);
+ case IS_BROADCAST:
+ memcpy(haddr, dev->broadcast, dev->addr_len);
+ return(0);
+ }
- apt = arp_lookup(paddr);
- if (apt != NULL)
- {
+ apt = arp_lookup(paddr);
+ if (apt != NULL) {
/*
* Make sure it's not too old. If it is too old, we will
* just pretend we did not find it, and then arp_send will
* verify the address for us.
*/
- 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);
- }
- else
- {
- DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",
- in_ntoa(apt->ip)));
- }
- }
+ if ((!(apt->flags & ATF_PERM)) ||
+ (!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
+ apt->last_used = jiffies;
+ memcpy(haddr, apt->ha, dev->addr_len);
+ return(0);
+ } else {
+ DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",
+ in_ntoa(apt->ip)));
+ }
+ }
/*
* This assume haddr are at least 4 bytes.
* If this isn't true we can use a lookup table, one for every dev.
+ * NOTE: this bit of code still looks fishy to me- FvK
*/
-
- *(unsigned long *)haddr = paddr;
+ *(unsigned long *)haddr = paddr;
- /* If we didn't find an entry, we will try to send an ARP packet. */
- arp_send(paddr, dev, saddr);
+ /* If we didn't find an entry, we will try to send an ARP packet. */
+ arp_send(paddr, dev, saddr);
- return(1);
+ return(1);
}
-/*
- * Add an entry to the ARP cache. Check for dupes!
- */
-
-void arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
+/* Add an entry to the ARP cache. Check for dupes! */
+void
+arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
{
- struct arp_table *apt;
-
- /* This is probably a good check... */
- if (addr == 0)
- {
- printk("ARP: add: will not add entry for 0.0.0.0 !\n");
- return;
- }
-
- /* First see if the address is already in the table. */
- apt = arp_lookup(addr);
- if (apt != NULL)
- {
- DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));
- apt->last_used = jiffies;
- memcpy(apt->ha, haddr , dev->addr_len);
- return;
- }
- arp_create(addr, haddr, dev->addr_len, dev->type);
+ struct arp_table *apt;
+
+ DPRINTF((DBG_ARP, "ARP: add(%s, ", in_ntoa(addr)));
+ DPRINTF((DBG_ARP, "%s, ", eth_print(haddr)));
+ DPRINTF((DBG_ARP, "%d, %d)\n", dev->hard_header_len, dev->type));
+
+ /* This is probably a good check... */
+ if (addr == 0) {
+ printk("ARP: add: will not add entry for 0.0.0.0 !\n");
+ return;
+ }
+
+ /* First see if the address is already in the table. */
+ apt = arp_lookup(addr);
+ if (apt != NULL) {
+ DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));
+ apt->last_used = jiffies;
+ memcpy(apt->ha, haddr , dev->addr_len);
+ return;
+ }
+ arp_create(addr, haddr, dev->addr_len, dev->type);
}
-/*
- * Create an ARP entry for a device's broadcast address.
- */
-
-void arp_add_broad(unsigned long addr, struct device *dev)
+/* Create an ARP entry for a device's broadcast address. */
+void
+arp_add_broad(unsigned long addr, struct device *dev)
{
- struct arp_table *apt;
-
- arp_add(addr, dev->broadcast, dev);
- apt = arp_lookup(addr);
- if (apt != NULL)
- {
- apt->flags |= ATF_PERM;
- }
+ struct arp_table *apt;
+
+ arp_add(addr, dev->broadcast, dev);
+ apt = arp_lookup(addr);
+ if (apt != NULL) {
+ apt->flags |= ATF_PERM;
+ }
}
/* Queue an IP packet, while waiting for the ARP reply packet. */
-void arp_queue(struct sk_buff *skb)
+void
+arp_queue(struct sk_buff *skb)
{
- unsigned long flags;
- save_flags(flags);
- cli();
- skb->tries = ARP_MAX_TRIES;
+ cli();
+ skb->tries = ARP_MAX_TRIES;
- if (skb->next != NULL)
- {
- sti();
- printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
- return;
- }
- skb_queue_tail(&arp_q,skb);
- skb->magic = ARP_QUEUE_MAGIC;
- restore_flags(flags);
+ if (skb->next != NULL) {
+ sti();
+ printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
+ return;
+ }
+ skb_queue_tail(&arp_q,skb);
+ skb->magic = ARP_QUEUE_MAGIC;
+ sti();
}
@@ -727,196 +754,172 @@ void arp_queue(struct sk_buff *skb)
*
* Perhaps we should redo PROCfs to handle larger buffers? Michael?
*/
-
-int arp_get_info(char *buffer)
+int
+arp_get_info(char *buffer)
{
- struct arpreq *req;
- struct arp_table *apt;
- int i;
- char *pos;
-
- /* Loop over the ARP table and copy structures to the buffer. */
- pos = buffer;
- i = 0;
- for (i = 0; i < ARP_TABLE_SIZE; i++)
- {
- cli();
- apt = arp_tables[i];
- sti();
- while (apt != NULL)
- {
- if (pos < (buffer + 4000))
- {
- req = (struct arpreq *) pos;
- memset((char *) req, 0, sizeof(struct arpreq));
- req->arp_pa.sa_family = AF_INET;
- memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4);
+ struct arpreq *req;
+ struct arp_table *apt;
+ int i;
+ char *pos;
+
+ /* Loop over the ARP table and copy structures to the buffer. */
+ pos = buffer;
+ i = 0;
+ for (i = 0; i < ARP_TABLE_SIZE; i++) {
+ cli();
+ apt = arp_tables[i];
+ sti();
+ while (apt != NULL) {
+ if (pos < (buffer + 4000)) {
+ req = (struct arpreq *) pos;
+ memset((char *) req, 0, sizeof(struct arpreq));
+ req->arp_pa.sa_family = AF_INET;
+ memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4);
req->arp_ha.sa_family = apt->htype;
- memcpy((char *) req->arp_ha.sa_data,
- (char *) &apt->ha, apt->hlen);
- }
- pos += sizeof(struct arpreq);
- cli();
- apt = apt->next;
- sti();
+ memcpy((char *) req->arp_ha.sa_data,
+ (char *) &apt->ha, apt->hlen);
}
- }
- return(pos - buffer);
+ pos += sizeof(struct arpreq);
+ cli();
+ apt = apt->next;
+ sti();
+ }
+ }
+ return(pos - buffer);
}
-/*
- * Set (create) an ARP cache entry.
- */
-
-static int arp_req_set(struct arpreq *req)
+/* Set (create) an ARP cache entry. */
+static int
+arp_req_set(struct arpreq *req)
{
- struct arpreq r;
- struct arp_table *apt;
- struct sockaddr_in *si;
- int htype, hlen;
-
- /* We only understand about IP addresses... */
- memcpy_fromfs(&r, req, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET)
- return(-EPFNOSUPPORT);
-
- /*
- * Find out about the hardware type.
- * We have to be compatible with BSD UNIX, so we have to
- * assume that a "not set" value (i.e. 0) means Ethernet.
- */
- si = (struct sockaddr_in *) &r.arp_pa;
- switch(r.arp_ha.sa_family)
- {
- case 0:
- case ARPHRD_ETHER:
- htype = ARPHRD_ETHER;
- hlen = ETH_ALEN;
- break;
- case ARPHRD_AX25:
- htype = ARPHRD_AX25;
- hlen = 7;
- break;
-
- default:
- return(-EPFNOSUPPORT);
- }
-
- /* Is there an existing entry for this address? */
- if (si->sin_addr.s_addr == 0)
- {
- printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
- return(-EINVAL);
- }
- apt = arp_lookup(si->sin_addr.s_addr);
- if (apt == NULL)
- {
- apt = arp_create(si->sin_addr.s_addr,
- (unsigned char *) r.arp_ha.sa_data, hlen, htype);
- if (apt == NULL)
- return(-ENOMEM);
- }
-
- /* We now have a pointer to an ARP entry. Update it! */
- memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen);
- apt->last_used = jiffies;
- apt->flags = r.arp_flags;
- if(apt->flags&ATF_PUBL)
- arp_proxies++; /* Count proxy arps so we know if to use it */
-
- return(0);
-}
+ struct arpreq r;
+ struct arp_table *apt;
+ struct sockaddr_in *si;
+ int htype, hlen;
+ /* We only understand about IP addresses... */
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
+
+ /*
+ * Find out about the hardware type.
+ * We have to be compatible with BSD UNIX, so we have to
+ * assume that a "not set" value (i.e. 0) means Ethernet.
+ */
+ si = (struct sockaddr_in *) &r.arp_pa;
+ switch(r.arp_ha.sa_family) {
+ case 0:
+ case ARPHRD_ETHER:
+ htype = ARPHRD_ETHER;
+ hlen = ETH_ALEN;
+ break;
+ default:
+ return(-EPFNOSUPPORT);
+ }
+
+ /* Is there an existing entry for this address? */
+ if (si->sin_addr.s_addr == 0) {
+ printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
+ return(-EINVAL);
+ }
+ apt = arp_lookup(si->sin_addr.s_addr);
+ if (apt == NULL) {
+ apt = arp_create(si->sin_addr.s_addr,
+ (unsigned char *) r.arp_ha.sa_data, hlen, htype);
+ if (apt == NULL) return(-ENOMEM);
+ }
+
+ /* We now have a pointer to an ARP entry. Update it! */
+ memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen);
+ apt->last_used = jiffies;
+ apt->flags = r.arp_flags;
+ if(apt->flags&ATF_PUBL)
+ arp_proxies++; /* Count proxy arps so we know if to use it */
+
+ return(0);
+}
-/*
- * Get an ARP cache entry.
- */
-static int arp_req_get(struct arpreq *req)
+/* Get an ARP cache entry. */
+static int
+arp_req_get(struct arpreq *req)
{
- struct arpreq r;
- struct arp_table *apt;
- struct sockaddr_in *si;
-
- /* We only understand about IP addresses... */
- memcpy_fromfs(&r, req, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET)
- return(-EPFNOSUPPORT);
-
- /* Is there an existing entry for this address? */
- si = (struct sockaddr_in *) &r.arp_pa;
- apt = arp_lookup(si->sin_addr.s_addr);
- if (apt == NULL)
- return(-ENXIO);
-
- /* We found it; copy into structure. */
- memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);
- r.arp_ha.sa_family = apt->htype;
-
- /* Copy the information back */
- memcpy_tofs(req, &r, sizeof(r));
- return(0);
+ struct arpreq r;
+ struct arp_table *apt;
+ struct sockaddr_in *si;
+
+ /* We only understand about IP addresses... */
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
+
+ /* Is there an existing entry for this address? */
+ si = (struct sockaddr_in *) &r.arp_pa;
+ apt = arp_lookup(si->sin_addr.s_addr);
+ if (apt == NULL) return(-ENXIO);
+
+ /* We found it; copy into structure. */
+ memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);
+ r.arp_ha.sa_family = apt->htype;
+
+ /* Copy the information back */
+ memcpy_tofs(req, &r, sizeof(r));
+ return(0);
}
-/*
- * Delete an ARP cache entry.
- */
-
-static int arp_req_del(struct arpreq *req)
+/* Delete an ARP cache entry. */
+static int
+arp_req_del(struct arpreq *req)
{
- struct arpreq r;
- struct sockaddr_in *si;
-
- /* We only understand about IP addresses... */
- memcpy_fromfs(&r, req, sizeof(r));
- if (r.arp_pa.sa_family != AF_INET)
- return(-EPFNOSUPPORT);
- si = (struct sockaddr_in *) &r.arp_pa;
+ struct arpreq r;
+ struct sockaddr_in *si;
+
+ /* We only understand about IP addresses... */
+ memcpy_fromfs(&r, req, sizeof(r));
+ if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
+
+ si = (struct sockaddr_in *) &r.arp_pa;
- /* The system cope with this but splats up a nasty kernel message
- We trap it beforehand and tell the user off */
- if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR)
- return -EINVAL;
+ /* The system cope with this but splats up a nasty kernel message
+ We trap it beforehand and tell the user off */
+ if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR)
+ return -EINVAL;
- arp_destroy(si->sin_addr.s_addr);
-
- return(0);
+ arp_destroy(si->sin_addr.s_addr);
+
+ return(0);
}
-/*
- * Handle an ARP layer I/O control request.
- */
-
-int arp_ioctl(unsigned int cmd, void *arg)
+/* Handle an ARP layer I/O control request. */
+int
+arp_ioctl(unsigned int cmd, void *arg)
{
- int err;
- switch(cmd)
- {
- case DDIOCSDBG:
- return(dbg_ioctl(arg, DBG_ARP));
- case SIOCDARP:
- if (!suser()) return(-EPERM);
- err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
- if(err)
- return err;
- return(arp_req_del((struct arpreq *)arg));
- case SIOCGARP:
- err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq));
- if(err)
- return err;
- return(arp_req_get((struct arpreq *)arg));
- case SIOCSARP:
- if (!suser()) return(-EPERM);
- err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
- if(err)
- return err;
- return(arp_req_set((struct arpreq *)arg));
- default:
- return(-EINVAL);
- }
- /*NOTREACHED*/
- return(0);
+ int err;
+ switch(cmd) {
+ case DDIOCSDBG:
+ return(dbg_ioctl(arg, DBG_ARP));
+ case SIOCDARP:
+ if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
+ return(arp_req_del((struct arpreq *)arg));
+ case SIOCGARP:
+ err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
+ return(arp_req_get((struct arpreq *)arg));
+ case SIOCSARP:
+ if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
+ return(arp_req_set((struct arpreq *)arg));
+ default:
+ return(-EINVAL);
+ }
+ /*NOTREACHED*/
+ return(0);
}
diff --git a/net/inet/arp.h b/net/inet/arp.h
index b18e0ae..c75c6cf 100644
--- a/net/inet/arp.h
+++ b/net/inet/arp.h
@@ -5,7 +5,7 @@
*
* Definitions for the ARP protocol module.
*
- * Version: @(#)arp.h 1.28 24/12/93
+ * Version: @(#)arp.h 1.0.6 05/21/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -26,31 +26,29 @@
#define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */
-/*
- * This structure defines the ARP mapping cache.
- */
-
-struct arp_table
-{
- struct arp_table *next;
- volatile unsigned long last_used;
- unsigned int flags;
- unsigned long ip;
- unsigned char ha[MAX_ADDR_LEN];
- unsigned char hlen;
- unsigned char htype;
+/* This structure defines the ARP mapping cache. */
+struct arp_table {
+ struct arp_table *next;
+ volatile unsigned long last_used;
+ unsigned int flags;
+#if 1
+ unsigned long ip;
+#else
+ unsigned char pa[MAX_ADDR_LEN];
+ unsigned char plen;
+ unsigned char ptype;
+#endif
+ unsigned char ha[MAX_ADDR_LEN];
+ unsigned char hlen;
+ unsigned char htype;
};
-/*
- * This is also used in "sock.c" and "tcp.c" - YUCK! - FvK
- */
-
+/* This is also used in "sock.c" and "tcp.c" - YUCK! - FvK */
extern struct sk_buff *arp_q;
extern void arp_destroy(unsigned long paddr);
-extern void arp_destroy_maybe(unsigned long paddr);
extern int arp_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
extern int arp_find(unsigned char *haddr, unsigned long paddr,
diff --git a/net/inet/datagram.c b/net/inet/datagram.c
index e69de29..931d9f3 100644
--- a/net/inet/datagram.c
+++ b/net/inet/datagram.c
@@ -0,0 +1,200 @@
+/*
+ * 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-).
+ * 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.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
+ *
+ * Fixes:
+ * Alan Cox : NULL return from skb_peek_copy() understood
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+
+
+/*
+ * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
+ * races. This replaces identical code in packet,raw and udp, as well as the yet to
+ * be released IPX support. It also finally fixes the long standing peek and read
+ * race for datagram sockets. If you alter this routine remember it must be
+ * re-entrant.
+ */
+
+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)
+ {
+ release_sock(sk);
+ *err=0;
+ return NULL;
+ }
+
+ if(sk->err)
+ {
+ release_sock(sk);
+ *err=-sk->err;
+ 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)
+ {
+ release_sock(sk);
+ *err=-ENOTCONN;
+ return NULL;
+ }
+
+ /* User doesn't want to wait */
+ if (noblock)
+ {
+ release_sock(sk);
+ *err=-EAGAIN;
+ return NULL;
+ }
+ release_sock(sk);
+
+ /* Interrupts off so that no packet arrives before we begin sleeping.
+ Otherwise we might miss our wake up */
+ cli();
+ if (sk->rqueue == NULL)
+ {
+ interruptible_sleep_on(sk->sleep);
+ /* Signals may need a restart of the syscall */
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ *err=-ERESTARTSYS;
+ return(NULL);
+ }
+ if(sk->err != 0) /* Error while waiting for packet
+ eg an icmp sent earlier by the
+ peer has finaly turned up now */
+ {
+ *err = -sk->err;
+ sti();
+ sk->err=0;
+ return NULL;
+ }
+ }
+ sk->inuse = 1;
+ sti();
+ }
+ /* Again only user level code calls this function, so nothing interrupt level
+ will suddenely eat the rqueue */
+ if (!(flags & MSG_PEEK))
+ {
+ 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;
+ }
+ return skb;
+}
+
+void skb_free_datagram(struct sk_buff *skb)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ skb->users--;
+ if(skb->users>0)
+ {
+ restore_flags(flags);
+ return;
+ }
+ /* See if it needs destroying */
+ if(skb->list == NULL) /* Been dequeued by someone - ie its read */
+ kfree_skb(skb,FREE_READ);
+ restore_flags(flags);
+}
+
+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
+ but not this release */
+ memcpy_tofs(to,skb->h.raw+offset,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)
+ {
+ case SEL_IN:
+ if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
+ {
+ /* Connection closed: Wake up */
+ return(1);
+ }
+ if (sk->rqueue != NULL || sk->err != 0)
+ { /* This appears to be consistent
+ with other stacks */
+ return(1);
+ }
+ return(0);
+
+ case SEL_OUT:
+ if (sk->prot->wspace(sk) >= 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);
+}
diff --git a/net/inet/dev.c b/net/inet/dev.c
index 05c2db4..e867ae3 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -790,6 +790,7 @@ static inline int bad_mask(unsigned long mask, unsigned long addr)
return 0;
}
+
/* Perform the SIOCxIFxxx calls. */
static int
dev_ifsioc(void *arg, unsigned int getset)
diff --git a/net/inet/devinet.c b/net/inet/devinet.c
index 6b83134..e69de29 100644
--- a/net/inet/devinet.c
+++ b/net/inet/devinet.c
@@ -1,266 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Interface (streams) handling functions.
- *
- * Version: @(#)dev.c 1.28 20/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- *
- * Fixes:
- * Alan Cox: check_addr returns a value for a wrong subnet
- * ie not us but don't forward this!
- * Alan Cox: block timer if the inet_bh handler is running
- * Alan Cox: generic queue code added. A lot neater now
- * C.E.Hawkins: SIOCGIFCONF only reports 'upped' interfaces
- * C.E.Hawkins: IFF_PROMISC support
- * Alan Cox: Supports Donald Beckers new hardware
- * multicast layer, but not yet multicast lists.
- * Alan Cox: ip_addr_match problems with class A/B nets.
- * C.E.Hawkins IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT]
- * Alan Cox: Removed bogus subnet check now the subnet code
- * a) actually works for all A/B nets
- * b) doesn't forward off the same interface.
- * Alan Cox: Multiple extra protocols
- * Alan Cox: A Couple more escaped verify_area calls die
- * Alan Cox: IP_SET_DEV is gone (forever) as per Fred's comment.
- * Alan Cox: Grand tidy up ready for the big day.
- * Alan Cox: Handles dev_open errors correctly.
- * Alan Cox: IP and generic parts split
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include "inet.h"
-#include "devinet.h"
-#include "eth.h"
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
-#include "skbuff.h"
-
-
-/*
- * Determine a default network mask, based on the IP address.
- */
-
-unsigned long ip_get_mask(unsigned long addr)
-{
- unsigned long dst;
-
- if (addr == 0L)
- return(0L); /* special case */
-
- dst = ntohl(addr);
- if (IN_CLASSA(dst))
- return(htonl(IN_CLASSA_NET));
- if (IN_CLASSB(dst))
- return(htonl(IN_CLASSB_NET));
- if (IN_CLASSC(dst))
- return(htonl(IN_CLASSC_NET));
-
- /* Something else, probably a subnet. */
- return(0);
-}
-
-/*
- * See if a pair of addresses match.
- */
-
-int ip_addr_match(unsigned long me, unsigned long him)
-{
- int i;
- unsigned long mask=0xFFFFFFFF;
- DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me)));
- DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him)));
-
- /* Fast path for 99.9% of cases */
- if (me == him)
- return(1);
-
- for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8)
- {
- if ((me & 0xFF) != (him & 0xFF))
- {
- /*
- * The only way this could be a match is for
- * the rest of addr1 to be 0 or 255.
- */
- if (me != 0 && me != mask)
- return(0);
- return(1);
- }
- }
- return(1);
-}
-
-
-/*
- * Check the address for our address, broadcasts, etc.
- *
- * This routine is used a lot, and in many time critical
- * places. It's already _TOO_ slow so be careful how you
- * alter it.
- */
-
-int chk_addr(unsigned long addr)
-{
- struct device *dev;
- unsigned long dst;
-
- DPRINTF((DBG_DEV, "chk_addr(%s) --> ", in_ntoa(addr)));
- dst = ntohl(addr);
-
- /*
- * Accept both `all ones' and `all zeros' as BROADCAST.
- * All 0's is the old BSD broadcast.
- */
-
- if (dst == INADDR_ANY || dst == INADDR_BROADCAST)
- {
- DPRINTF((DBG_DEV, "BROADCAST\n"));
- return(IS_BROADCAST);
- }
-
- /* Accept all of the `loopback' class A net. */
- if ((dst & IN_CLASSA_NET) == 0x7F000000L)
- {
- DPRINTF((DBG_DEV, "LOOPBACK\n"));
-
- /*
- * We force `loopback' to be equal to MY_ADDR.
- */
- return(IS_MYADDR);
- /* return(IS_LOOPBACK); */
- }
-
- /* OK, now check the interface addresses. */
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (!(dev->flags&IFF_UP))
- continue;
- if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
- return(IS_MYADDR);
- /* Is it the exact IP address? */
- if (addr == dev->pa_addr)
- {
- DPRINTF((DBG_DEV, "MYADDR\n"));
- return(IS_MYADDR);
- }
-
- /* Nope. Check for a subnetwork broadcast. */
- if ((addr & dev->pa_mask) == (dev->pa_addr & dev->pa_mask))
- {
- if ((addr & ~dev->pa_mask) == 0)
- {
- DPRINTF((DBG_DEV, "SUBBROADCAST-0\n"));
- return(IS_BROADCAST);
- }
- if (((addr & ~dev->pa_mask) | dev->pa_mask)
- == INADDR_BROADCAST)
- {
- DPRINTF((DBG_DEV, "SUBBROADCAST-1\n"));
- return(IS_BROADCAST);
- }
- }
-
- /* Nope. Check for Network broadcast. */
- if(IN_CLASSA(dst))
- {
- if( addr == (dev->pa_addr | 0xffffff00))
- {
- DPRINTF((DBG_DEV, "CLASS A BROADCAST-1\n"));
- return(IS_BROADCAST);
- }
- }
- else if(IN_CLASSB(dst))
- {
- if( addr == (dev->pa_addr | 0xffff0000))
- {
- DPRINTF((DBG_DEV, "CLASS B BROADCAST-1\n"));
- return(IS_BROADCAST);
- }
- }
- else
- { /* IN_CLASSC */
- if( addr == (dev->pa_addr | 0xff000000))
- {
- DPRINTF((DBG_DEV, "CLASS C BROADCAST-1\n"));
- return(IS_BROADCAST);
- }
- }
- }
-
- DPRINTF((DBG_DEV, "NONE\n"));
-
- return(0); /* no match at all */
-}
-
-
-/*
- * Retrieve our own address.
- * Because the loopback address (127.0.0.1) is already recognized
- * automatically, we can use the loopback interface's address as
- * our "primary" interface. This is the addressed used by IP et
- * al when it doesn't know which address to use (i.e. it does not
- * yet know from or to which interface to go...).
- */
-
-unsigned long my_addr(void)
-{
- struct device *dev;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (dev->flags & IFF_LOOPBACK)
- return(dev->pa_addr);
- }
- return(0);
-}
-
-
-
-/*
- * Find an interface that can handle addresses for a certain address.
- */
-
-struct device *dev_check(unsigned long addr)
-{
- struct device *dev;
-
- for (dev = dev_base; dev; dev = dev->next)
- if ((dev->flags & IFF_UP) && (dev->flags & IFF_POINTOPOINT) &&
- (addr == dev->pa_dstaddr))
- return dev;
- for (dev = dev_base; dev; dev = dev->next)
- if ((dev->flags & IFF_UP) && !(dev->flags & IFF_POINTOPOINT) &&
- (dev->flags & IFF_LOOPBACK ? (addr == dev->pa_addr) :
- (dev->pa_mask & addr) == (dev->pa_addr & dev->pa_mask)))
- break;
- /* no need to check broadcast addresses */
- return dev;
-}
-
diff --git a/net/inet/devinet.h b/net/inet/devinet.h
index c9fc5cc..e69de29 100644
--- a/net/inet/devinet.h
+++ b/net/inet/devinet.h
@@ -1,22 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the INET bits of the interfaces handler.
- *
- */
-
-#ifndef _DEVINET_H
-#define _DEVINET_H
-
-#ifndef _DEV_H
-#include "dev.h"
-#endif
-
-extern int ip_addr_match(unsigned long addr1, unsigned long addr2);
-extern int chk_addr(unsigned long addr);
-extern struct device *dev_check(unsigned long daddr);
-extern unsigned long my_addr(void);
-
-#endif /* _DEVINET_H */
diff --git a/net/inet/eth.c b/net/inet/eth.c
index 7bf2657..01e2f51 100644
--- a/net/inet/eth.c
+++ b/net/inet/eth.c
@@ -5,27 +5,24 @@
*
* Ethernet-type device handling.
*
- * Version: @(#)eth.c 1.28 20/12/93
+ * Version: @(#)eth.c 1.0.7 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
*
* Fixes:
- * Mr Linux : Arp problems.
- * Alan Cox : Generic queue tidyup (very tiny here).
- * Alan Cox : eth_header ntohs should be htons.
+ * Mr Linux : Arp problems
+ * Alan Cox : Generic queue tidyup (very tiny here)
+ * Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and
* minor other things.
- * Tegge : Arp bug fixes.
- * Alan Cox : Tidy up ready for the big day.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
@@ -36,19 +33,18 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include <linux/errno.h>
#include "arp.h"
-#ifdef ETH_DEBUG
/* Display an Ethernet address in readable format. */
char *eth_print(unsigned char *ptr)
{
@@ -61,16 +57,32 @@ char *eth_print(unsigned char *ptr)
);
return(buff);
}
-#endif
-
-
-#ifdef ETH_DEBUG
-/*
- * Display the contents of the Ethernet MAC header.
- */
+void eth_setup(char *str, int *ints)
+{
+ struct device *d = dev_base;
+
+ if (!str || !*str)
+ return;
+ while (d) {
+ if (!strcmp(str,d->name)) {
+ if (ints[0] > 0)
+ d->irq=ints[1];
+ if (ints[0] > 1)
+ d->base_addr=ints[2];
+ if (ints[0] > 2)
+ d->mem_start=ints[3];
+ if (ints[0] > 3)
+ d->mem_end=ints[4];
+ break;
+ }
+ d=d->next;
+ }
+}
-void eth_dump(struct ethhdr *eth)
+/* Display the contents of the Ethernet MAC header. */
+void
+eth_dump(struct ethhdr *eth)
{
if (inet_debug != DBG_ETH) return;
@@ -79,128 +91,96 @@ void eth_dump(struct ethhdr *eth)
printk("TYPE = %04X\n", ntohs(eth->h_proto));
}
-#endif
-
-/*
- * Create the Ethernet MAC header.
- *
- * ARP might prevent this from working all in one go. See also
- * the rebuild header function.
- */
-
-int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
+/* Create the Ethernet MAC header. */
+int
+eth_header(unsigned char *buff, struct device *dev, unsigned short type,
unsigned long daddr, unsigned long saddr, unsigned len)
{
- struct ethhdr *eth;
-
- DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr)));
- DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type));
-
- /* Fill in the basic Ethernet MAC header. */
- eth = (struct ethhdr *) buff;
- eth->h_proto = htons(type);
-
- /* We don't ARP for the LOOPBACK device... */
- if (dev->flags & IFF_LOOPBACK)
- {
- DPRINTF((DBG_DEV, "ETH: No header for loopback\n"));
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- memset(eth->h_dest, 0, dev->addr_len);
- return(dev->hard_header_len);
- }
-
- /* Check if we can use the MAC BROADCAST address. */
- if (chk_addr(daddr) == IS_BROADCAST)
- {
- DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
- return(dev->hard_header_len);
- }
- /*
- * We disable interrupts here to avoid a race if the ARP
- * reply is too quick.
- */
- cli();
- memcpy(eth->h_source, &saddr, 4);
- /* No. Ask ARP to resolve the Ethernet address. */
- if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr/* saddr */))
- {
- sti();
- if(type!=ETH_P_IP)
- printk("Erk: protocol %X got into an arp request state!\n",type);
- return(-dev->hard_header_len);
- }
- else
- {
- memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the
- header built correctly! */
- sti();
- return(dev->hard_header_len);
- }
+ struct ethhdr *eth;
+
+ DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr)));
+ DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type));
+
+ /* Fill in the basic Ethernet MAC header. */
+ eth = (struct ethhdr *) buff;
+ eth->h_proto = htons(type);
+
+ /* We don't ARP for the LOOPBACK device... */
+ if (dev->flags & IFF_LOOPBACK) {
+ DPRINTF((DBG_DEV, "ETH: No header for loopback\n"));
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ memset(eth->h_dest, 0, dev->addr_len);
+ return(dev->hard_header_len);
+ }
+
+ /* Check if we can use the MAC BROADCAST address. */
+ if (chk_addr(daddr) == IS_BROADCAST) {
+ DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
+ return(dev->hard_header_len);
+ }
+ cli();
+ memcpy(eth->h_source, &saddr, 4);
+ /* No. Ask ARP to resolve the Ethernet address. */
+ if (arp_find(eth->h_dest, daddr, dev, saddr))
+ {
+ sti();
+ if(type!=ETH_P_IP)
+ printk("Erk: protocol %X got into an arp request state!\n",type);
+ return(-dev->hard_header_len);
+ }
+ else
+ {
+ memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the
+ header built correctly! */
+ sti();
+ return(dev->hard_header_len);
+ }
}
-/*
- * Rebuild the Ethernet MAC header.
- *
- * We've got a 'stuck' packet that failed to go out before. See if
- * the arp is resolved and we can finally shift it.
- */
-
-int eth_rebuild_header(void *buff, struct device *dev)
+/* Rebuild the Ethernet MAC header. */
+int
+eth_rebuild_header(void *buff, struct device *dev)
{
- struct ethhdr *eth;
- unsigned long src, dst;
-
- DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
- eth = (struct ethhdr *) buff;
- src = *(unsigned long *) eth->h_source;
- dst = *(unsigned long *) eth->h_dest;
- 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, dev->pa_addr /* src */))
- /* Still not known */
- return(1);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return(0);
+ struct ethhdr *eth;
+ unsigned long src, dst;
+
+ DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
+ eth = (struct ethhdr *) buff;
+ src = *(unsigned long *) eth->h_source;
+ dst = *(unsigned long *) eth->h_dest;
+ 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);
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ return(0);
}
-/*
- * Add an ARP entry for a host on this interface.
- */
-
-void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
+/* Add an ARP entry for a host on this interface. */
+void
+eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
{
- struct ethhdr *eth;
+ struct ethhdr *eth;
- eth = (struct ethhdr *) (skb + 1);
- arp_add(addr, eth->h_source, dev);
+ eth = (struct ethhdr *) (skb + 1);
+ arp_add(addr, eth->h_source, dev);
}
-/*
- * Determine the packet's protocol ID.
- *
- * Ethernet comes in two 'species' DIX (Digitial Intel Xerox) and IEE802.3
- * needless to say they are different. Fortunately there is a way of telling
- * them apart. All 'normal' modern DIX service ID's are >1536.
- * All IEE802.3 frames have a length at this position and that cannot be
- * >=1536. Note IEE802.3 frames have a second 802.2 header normally. We don't
- * deal with this bit in the current kernel, but a user using SOCK_PACKET
- * for 802.3 frames can do so.
- */
-
-unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
+/* Determine the packet's protocol ID. */
+unsigned short
+eth_type_trans(struct sk_buff *skb, struct device *dev)
{
- struct ethhdr *eth;
+ struct ethhdr *eth;
- eth = (struct ethhdr *) (skb + 1);
+ eth = (struct ethhdr *) (skb + 1);
- if(ntohs(eth->h_proto)<1536)
- return(htons(ETH_P_802_3));
- return(eth->h_proto);
+ if(ntohs(eth->h_proto)<1536)
+ return(htons(ETH_P_802_3));
+ return(eth->h_proto);
}
diff --git a/net/inet/icmp.c b/net/inet/icmp.c
index 467a119..7b953d4 100644
--- a/net/inet/icmp.c
+++ b/net/inet/icmp.c
@@ -5,7 +5,7 @@
*
* Internet Control Message Protocol (ICMP)
*
- * Version: @(#)icmp.c 1.28 20/12/93
+ * Version: @(#)icmp.c 1.0.11 06/02/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -14,7 +14,6 @@
* Fixes:
* Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected
- * Tegge : Subnet problems
*
*
* This program is free software; you can redistribute it and/or
@@ -22,7 +21,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -30,14 +28,14 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
@@ -65,413 +63,379 @@ struct icmp_err icmp_err_convert[] = {
};
-#ifdef ICMP_DEBUG
-
/* Display the contents of an ICMP header. */
static void
print_icmp(struct icmphdr *icmph)
{
- if (inet_debug != DBG_ICMP)
- return;
+ if (inet_debug != DBG_ICMP) return;
- printk("ICMP: type = %d, code = %d, checksum = %X\n",
+ printk("ICMP: type = %d, code = %d, checksum = %X\n",
icmph->type, icmph->code, icmph->checksum);
- printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
+ printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
}
-#endif
-
-/*
- * Send an ICMP message.
- *
- * ICMP is the control message protocol for error reporting in IP.
- * A good document to start with for this stuff is RFC 791.
- */
-void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
+/* Send an ICMP message. */
+void
+icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
{
- struct sk_buff *skb;
- struct iphdr *iph;
- int offset;
- struct icmphdr *icmph;
- int len;
+ struct sk_buff *skb;
+ struct iphdr *iph;
+ int offset;
+ struct icmphdr *icmph;
+ int len;
- DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
+ DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n",
skb_in, type, code, dev));
- /* Get some memory for the reply. */
- len = sizeof(struct sk_buff) + dev->hard_header_len +
- sizeof(struct iphdr) + sizeof(struct icmphdr) +
- sizeof(struct iphdr) + 8; /* amount of header to return */
+ /* Get some memory for the reply. */
+ len = sizeof(struct sk_buff) + dev->hard_header_len +
+ sizeof(struct iphdr) + sizeof(struct icmphdr) +
+ sizeof(struct iphdr) + 8; /* amount of header to return */
- skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
- /* We just forget about failed ICMP messages. ICMP is unreliable anyway and
- things will sort out in time */
-
- if (skb == NULL)
- return;
-
- skb->sk = NULL;
- len -= sizeof(struct sk_buff);
-
- /* Find the IP header. */
- iph = (struct iphdr *) (skb_in + 1);
- iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
-
- /* 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, 25, IPTOS_RELIABILITY);
- if (offset < 0)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /* Re-adjust length according to actual IP header size. */
- skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
- icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
- icmph->type = type;
- icmph->code = code;
- icmph->checksum = 0;
- icmph->un.gateway = 0;
- memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
-
- icmph->checksum = ip_compute_csum((unsigned char *)icmph,
- sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
-
-#ifdef ICMP_DEBUG
- DPRINTF((DBG_ICMP, ">>\n"));
- print_icmp(icmph);
-#endif
- /* Send it and free it. */
- ip_queue_xmit(NULL, dev, skb, 1);
+ skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ skb->sk = NULL;
+ skb->mem_addr = skb;
+ skb->mem_len = len;
+ len -= sizeof(struct sk_buff);
+
+ /* Find the IP header. */
+ iph = (struct iphdr *) (skb_in + 1);
+ iph = (struct iphdr *) ((unsigned char *) iph + dev->hard_header_len);
+
+ /* 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);
+ if (offset < 0) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8;
+ icmph = (struct icmphdr *) ((unsigned char *) (skb + 1) + offset);
+ icmph->type = type;
+ icmph->code = code;
+ icmph->checksum = 0;
+ icmph->un.gateway = 0;
+ memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8);
+
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph,
+ sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
+
+ DPRINTF((DBG_ICMP, ">>\n"));
+ print_icmp(icmph);
+
+ /* Send it and free it. */
+ ip_queue_xmit(NULL, dev, skb, 1);
}
-/*
- * Handle ICMP_UNREACH and ICMP_QUENCH.
- */
-
-static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
+/* Handle ICMP_UNREACH and ICMP_QUENCH. */
+static void
+icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
{
- struct inet_protocol *ipprot;
- struct iphdr *iph;
- unsigned char hash;
- int err;
-
- err = (icmph->type << 8) | icmph->code;
- iph = (struct iphdr *) (icmph + 1);
- switch(icmph->code & 7)
- {
- case ICMP_NET_UNREACH:
- DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
- in_ntoa(iph->daddr)));
- break;
- case ICMP_HOST_UNREACH:
- DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
+ struct inet_protocol *ipprot;
+ struct iphdr *iph;
+ unsigned char hash;
+ int err;
+
+ err = (icmph->type << 8) | icmph->code;
+ iph = (struct iphdr *) (icmph + 1);
+ switch(icmph->code & 7) {
+ case ICMP_NET_UNREACH:
+ DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
in_ntoa(iph->daddr)));
- break;
- case ICMP_PROT_UNREACH:
- printk("ICMP: %s:%d: protocol unreachable.\n",
- in_ntoa(iph->daddr), ntohs(iph->protocol));
- break;
- case ICMP_PORT_UNREACH:
- DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
- in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
- break;
- case ICMP_FRAG_NEEDED:
- printk("ICMP: %s: fragmentation needed and DF set.\n",
- in_ntoa(iph->daddr));
- break;
- case ICMP_SR_FAILED:
- printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
- break;
- default:
- DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
- (icmph->code & 7), in_ntoa(iph->daddr)));
- break;
- }
-
- /* Get the protocol(s). */
- hash = iph->protocol & (MAX_INET_PROTOS -1);
-
- /* This can change while we are doing it. */
- ipprot = (struct inet_protocol *) inet_protos[hash];
- while(ipprot != NULL)
- {
- struct inet_protocol *nextip;
-
- nextip = (struct inet_protocol *) ipprot->next;
-
- /* Pass it off to everyone who wants it. */
- if (iph->protocol == ipprot->protocol && ipprot->err_handler)
- {
- ipprot->err_handler(err, (unsigned char *)(icmph + 1),
+ break;
+ case ICMP_HOST_UNREACH:
+ DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n",
+ in_ntoa(iph->daddr)));
+ break;
+ case ICMP_PROT_UNREACH:
+ printk("ICMP: %s:%d: protocol unreachable.\n",
+ in_ntoa(iph->daddr), ntohs(iph->protocol));
+ break;
+ case ICMP_PORT_UNREACH:
+ DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n",
+ in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */));
+ break;
+ case ICMP_FRAG_NEEDED:
+ printk("ICMP: %s: fragmentation needed and DF set.\n",
+ in_ntoa(iph->daddr));
+ break;
+ case ICMP_SR_FAILED:
+ printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr));
+ break;
+ default:
+ DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n",
+ (icmph->code & 7), in_ntoa(iph->daddr)));
+ break;
+ }
+
+ /* Get the protocol(s). */
+ hash = iph->protocol & (MAX_INET_PROTOS -1);
+
+ /* This can change while we are doing it. */
+ ipprot = (struct inet_protocol *) inet_protos[hash];
+ while(ipprot != NULL) {
+ struct inet_protocol *nextip;
+
+ nextip = (struct inet_protocol *) ipprot->next;
+
+ /* Pass it off to everyone who wants it. */
+ if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
+ ipprot->err_handler(err, (unsigned char *)(icmph + 1),
iph->daddr, iph->saddr, ipprot);
- }
+ }
- ipprot = nextip;
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ ipprot = nextip;
+ }
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/*
- * Handle ICMP_REDIRECT.
- */
-
-static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
+/* Handle ICMP_REDIRECT. */
+static void
+icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
{
- struct iphdr *iph;
- unsigned long ip;
-
- iph = (struct iphdr *) (icmph + 1);
- ip = iph->daddr;
- switch(icmph->code & 7)
- {
- case ICMP_REDIR_NET:
- rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev);
- break;
- case ICMP_REDIR_HOST:
- rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
- ip, 0, icmph->un.gateway, dev);
- break;
- case ICMP_REDIR_NETTOS:
- case ICMP_REDIR_HOSTTOS:
- printk("ICMP: cannot handle TOS redirects yet!\n");
- break;
- default:
- DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
- (icmph->code & 7)));
+ struct iphdr *iph;
+ unsigned long ip;
+
+ iph = (struct iphdr *) (icmph + 1);
+ ip = iph->daddr;
+ switch(icmph->code & 7) {
+ case ICMP_REDIR_NET:
+ rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
+ ip, 0, icmph->un.gateway, dev);
break;
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ case ICMP_REDIR_HOST:
+ rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
+ ip, 0, icmph->un.gateway, dev);
+ break;
+ case ICMP_REDIR_NETTOS:
+ case ICMP_REDIR_HOSTTOS:
+ printk("ICMP: cannot handle TOS redirects yet!\n");
+ break;
+ default:
+ DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n",
+ (icmph->code & 7)));
+ break;
+ }
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
/* Handle ICMP_ECHO ("ping") requests. */
-static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+static void
+icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
-
- size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
- if (skb2 == NULL)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->sk = NULL;
- skb2->free = 1;
-
- /* Build Layer 2-3 headers for message back to source */
- offset = ip_build_header(skb2, daddr, saddr, &dev,
- IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
- if (offset < 0)
- {
- printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
- kfree_skb(skb2,FREE_WRITE);
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /* Re-adjust length according to actual IP header size. */
- skb2->len = offset + len;
-
- /* Build ICMP_ECHO Response message. */
- icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
- memcpy((char *) icmphr, (char *) icmph, len);
- icmphr->type = ICMP_ECHOREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /* Ship it out - free it when done */
- ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ struct icmphdr *icmphr;
+ struct sk_buff *skb2;
+ int size, offset;
+
+ size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
+ skb2 = alloc_skb(size, GFP_ATOMIC);
+ if (skb2 == NULL) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ skb2->sk = NULL;
+ skb2->mem_addr = skb2;
+ skb2->mem_len = size;
+ skb2->free = 1;
+
+ /* Build Layer 2-3 headers for message back to source */
+ offset = ip_build_header(skb2, daddr, saddr, &dev,
+ IPPROTO_ICMP, opt, len);
+ if (offset < 0) {
+ printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
+ kfree_skb(skb2,FREE_WRITE);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb2->len = offset + len;
+
+ /* Build ICMP_ECHO Response message. */
+ icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
+ memcpy((char *) icmphr, (char *) icmph, len);
+ icmphr->type = ICMP_ECHOREPLY;
+ icmphr->code = 0;
+ icmphr->checksum = 0;
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
+
+ /* Ship it out - free it when done */
+ ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
+
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/*
- * Handle the ICMP INFORMATION REQUEST.
- */
-
-static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+/* Handle the ICMP INFORMATION REQUEST. */
+static void
+icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
- /* NOT YET */
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ /* NOT YET */
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/*
- * Handle ICMP_ADRESS_MASK requests.
- */
-
-static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+/* Handle ICMP_ADRESS_MASK requests. */
+static void
+icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
- struct icmphdr *icmphr;
- struct sk_buff *skb2;
- int size, offset;
-
- size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = alloc_skb(size, GFP_ATOMIC);
- if (skb2 == NULL)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
- skb2->sk = NULL;
- skb2->free = 1;
-
- /* Build Layer 2-3 headers for message back to source */
- offset = ip_build_header(skb2, daddr, saddr, &dev,
- IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
- if (offset < 0)
- {
- printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
- kfree_skb(skb2,FREE_WRITE);
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /* Re-adjust length according to actual IP header size. */
- skb2->len = offset + len;
-
- /* Build ICMP ADDRESS MASK Response message. */
- icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
- icmphr->type = ICMP_ADDRESSREPLY;
- icmphr->code = 0;
- icmphr->checksum = 0;
- icmphr->un.echo.id = icmph->un.echo.id;
- icmphr->un.echo.sequence = icmph->un.echo.sequence;
- memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
-
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
-
- /* Ship it out - free it when done */
- ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
-
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
+ struct icmphdr *icmphr;
+ struct sk_buff *skb2;
+ int size, offset;
+
+ size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
+ skb2 = alloc_skb(size, GFP_ATOMIC);
+ if (skb2 == NULL) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ skb2->sk = NULL;
+ skb2->mem_addr = skb2;
+ skb2->mem_len = size;
+ skb2->free = 1;
+
+ /* Build Layer 2-3 headers for message back to source */
+ offset = ip_build_header(skb2, daddr, saddr, &dev,
+ IPPROTO_ICMP, opt, len);
+ if (offset < 0) {
+ printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
+ kfree_skb(skb2,FREE_WRITE);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb2->len = offset + len;
+
+ /* Build ICMP ADDRESS MASK Response message. */
+ icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
+ icmphr->type = ICMP_ADDRESSREPLY;
+ icmphr->code = 0;
+ icmphr->checksum = 0;
+ icmphr->un.echo.id = icmph->un.echo.id;
+ icmphr->un.echo.sequence = icmph->un.echo.sequence;
+ memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
+
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
+
+ /* Ship it out - free it when done */
+ ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
+
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
}
-/*
- * Deal with incoming ICMP packets.
- */
-
-int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
+/* Deal with incoming ICMP packets. */
+int
+icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
- struct icmphdr *icmph;
- unsigned char *buff;
+ struct icmphdr *icmph;
+ unsigned char *buff;
- /* Drop broadcast packets. */
- if (chk_addr(daddr) == IS_BROADCAST)
- {
- DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
+ /* Drop broadcast packets. */
+ if (chk_addr(daddr) == IS_BROADCAST) {
+ DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
in_ntoa(saddr)));
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ }
+
+ buff = skb1->h.raw;
+ icmph = (struct icmphdr *) buff;
+
+ /* Validate the packet first */
+ if (ip_compute_csum((unsigned char *) icmph, len)) {
+ /* Failed checksum! */
+ printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ }
+ print_icmp(icmph);
+
+ /* Parse the ICMP message */
+ switch(icmph->type) {
+ case ICMP_TIME_EXCEEDED:
+ case ICMP_DEST_UNREACH:
+ case ICMP_SOURCE_QUENCH:
+ icmp_unreach(icmph, skb1);
+ return(0);
+ case ICMP_REDIRECT:
+ icmp_redirect(icmph, skb1, dev);
+ return(0);
+ case ICMP_ECHO:
+ icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_ECHOREPLY:
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
- }
-
- buff = skb1->h.raw;
- icmph = (struct icmphdr *) buff;
-
- /* Validate the packet first */
- if (ip_compute_csum((unsigned char *) icmph, len))
- {
- /* Failed checksum! */
- printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
+ case ICMP_INFO_REQUEST:
+ icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_INFO_REPLY:
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
- }
-#ifdef ICMP_DEBUG
- print_icmp(icmph);
-#endif
- /* Parse the ICMP message */
- switch(icmph->type)
- {
- case ICMP_TIME_EXCEEDED:
- case ICMP_DEST_UNREACH:
- case ICMP_SOURCE_QUENCH:
- icmp_unreach(icmph, skb1);
- return(0);
- case ICMP_REDIRECT:
- icmp_redirect(icmph, skb1, dev);
- return(0);
- case ICMP_ECHO:
- icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ECHOREPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_INFO_REQUEST:
- icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_INFO_REPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- case ICMP_ADDRESS:
- icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
- return 0;
- case ICMP_ADDRESSREPLY:
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- default:
- DPRINTF((DBG_ICMP,
- "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
- in_ntoa(saddr), icmph->type));
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
- /*NOTREACHED*/
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(-1);
+ case ICMP_ADDRESS:
+ icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_ADDRESSREPLY:
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ default:
+ DPRINTF((DBG_ICMP,
+ "ICMP: Unsupported ICMP from %s, type = 0x%X\n",
+ in_ntoa(saddr), icmph->type));
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ }
+ /*NOTREACHED*/
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(-1);
}
-/*
- * Perform any ICMP-related I/O control requests.
- *
- * In the case of ICMP all the user can do is play with the debygging
- */
-
-int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+/* Perform any ICMP-related I/O control requests. */
+int
+icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- switch(cmd)
- {
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_ICMP));
- default:
- return(-EINVAL);
- }
- return(0);
+ switch(cmd) {
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_ICMP));
+ default:
+ return(-EINVAL);
+ }
+ return(0);
}
diff --git a/net/inet/ip.c b/net/inet/ip.c
index a3cc4ec..4c9f924 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) module.
*
- * Version: @(#)ip.c 1.28 20/12/93
+ * Version: @(#)ip.c 1.0.16b 9/1/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -31,14 +31,10 @@
* 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 : Reformatted for neatness and final release.
- * Alan Cox : Tags ip header for RAW sockets, and for accept(). Old
- * method wasn't suitable for AX.25
- * Alan Cox : Most of the ip_options processing logic added.
*
* To Fix:
- * RFC791 states that options are a 'required' feature of an
- * IP implementation. We don't do options at all.
+ * IP option processing is mostly not needed. ip_forward needs to know about routing rules
+ * and time stamp but that's about all.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -56,176 +52,141 @@
#include <linux/sockios.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "route.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "arp.h"
#include "icmp.h"
-/*
- * These two can normally be left. In olden times the numerous bugs used to
- * make forwarding go crazy on some nets and fragmentation fragment your
- * computer 8-)
- */
-
-#define CONFIG_IP_FORWARD /* Forwarding ? */
-#define CONFIG_IP_DEFRAG /* Fragmentation ? */
-
+#define CONFIG_IP_FORWARD
+#define CONFIG_IP_DEFRAG
extern int last_retran;
extern void sort_send(struct sock *sk);
-#ifdef IP_DEBUG
-
-void ip_print(struct iphdr *ip)
+void
+ip_print(struct iphdr *ip)
{
- unsigned char buff[32];
- unsigned char *ptr;
- int addr, len, i;
-
- if (inet_debug != DBG_IP)
- return;
-
- /* Dump the IP header. */
- printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
- ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len));
- printk(" id=%X, ttl=%d, prot=%d, check=%X\n",
- ip->id, ip->ttl, ip->protocol, ip->check);
- printk(" frag_off=%d\n", ip->frag_off);
- printk(" soucre=%s ", in_ntoa(ip->saddr));
- printk("dest=%s\n", in_ntoa(ip->daddr));
- printk(" ----\n");
-
- /* Dump the data. */
- ptr = (unsigned char *)(ip + 1);
- addr = 0;
- len = ntohs(ip->tot_len) - (4 * ip->ihl);
- while (len > 0)
- {
- printk(" %04X: ", addr);
- for(i = 0; i < 16; i++)
- {
- if (len > 0)
- {
- printk("%02X ", (*ptr & 0xFF));
- buff[i] = *ptr++;
- if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
- }
- else
- {
- printk(" ");
- buff[i] = ' ';
- }
- addr++;
- len--;
- };
- buff[i] = '\0';
- printk(" \"%s\"\n", buff);
- }
- printk(" ----\n\n");
+ unsigned char buff[32];
+ unsigned char *ptr;
+ int addr, len, i;
+
+ if (inet_debug != DBG_IP) return;
+
+ /* Dump the IP header. */
+ printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
+ ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len));
+ printk(" id=%X, ttl=%d, prot=%d, check=%X\n",
+ ip->id, ip->ttl, ip->protocol, ip->check);
+ printk(" frag_off=%d\n", ip->frag_off);
+ printk(" soucre=%s ", in_ntoa(ip->saddr));
+ printk("dest=%s\n", in_ntoa(ip->daddr));
+ printk(" ----\n");
+
+ /* Dump the data. */
+ ptr = (unsigned char *)(ip + 1);
+ addr = 0;
+ len = ntohs(ip->tot_len) - (4 * ip->ihl);
+ while (len > 0) {
+ printk(" %04X: ", addr);
+ for(i = 0; i < 16; i++) {
+ if (len > 0) {
+ printk("%02X ", (*ptr & 0xFF));
+ buff[i] = *ptr++;
+ if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
+ } else {
+ printk(" ");
+ buff[i] = ' ';
+ }
+ addr++;
+ len--;
+ };
+ buff[i] = '\0';
+ printk(" \"%s\"\n", buff);
+ }
+ printk(" ----\n\n");
}
-#endif
-/*
- * Low level user requests to the IP device. NOT that same as IP layer
- * socket requests (which also do nothing useful at the moment)
- */
-
-int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
+int
+ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- switch(cmd)
- {
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_IP));
- default:
- return(-EINVAL);
- }
+ switch(cmd) {
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_IP));
+ default:
+ return(-EINVAL);
+ }
}
-/*
- * These two routines will do routing when we have ip options support
- * (RFC 791 page 18,19)
- */
-
-static void strict_route(struct iphdr *iph, struct options *opt)
+/* these two routines will do routining. */
+static void
+strict_route(struct iphdr *iph, struct options *opt)
{
}
-static void loose_route(struct iphdr *iph, struct options *opt)
+static void
+loose_route(struct iphdr *iph, struct options *opt)
{
}
-static void print_ipprot(struct inet_protocol *ipprot)
+static void
+print_ipprot(struct inet_protocol *ipprot)
{
- DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
- ipprot->handler, ipprot->protocol, ipprot->copy));
+ DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
+ ipprot->handler, ipprot->protocol, ipprot->copy));
}
-/*
- * This routine will check to see if we have lost a gateway.
- */
-
-void ip_route_check(unsigned long daddr)
+/* This routine will check to see if we have lost a gateway. */
+void
+ip_route_check(unsigned long daddr)
{
}
-/*
- * This routine puts the options at the end of an ip header.
- */
-
-static int build_options(struct iphdr *iph, struct options *opt)
+#if 0
+/* this routine puts the options at the end of an ip header. */
+static int
+build_options(struct iphdr *iph, struct options *opt)
{
- unsigned char *ptr;
- ptr = (unsigned char *)(iph+1);
- /* currently we don't support any options. */
- if(opt==NULL)
- {
- *ptr = 0;
- return (1);
- }
- else
- {
- memcpy(ptr,opt->option_data,opt->option_length);
- return((opt->option_length+3)/4);
- }
+ unsigned char *ptr;
+ /* currently we don't support any options. */
+ ptr = (unsigned char *)(iph+1);
+ *ptr = 0;
+ return (4);
}
+#endif
-/*
- * Take an skb, and fill in the MAC header.
- */
-
-static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
+/* Take an skb, and fill in the MAC header. */
+static int
+ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
unsigned long saddr)
{
- unsigned char *ptr;
- int mac;
-
- ptr = (unsigned char *)(skb + 1);
- mac = 0;
- skb->arp = 1;
- if (dev->hard_header)
- {
- mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
- }
- if (mac < 0)
- {
- mac = -mac;
- skb->arp = 0;
- }
- skb->dev = dev;
- return(mac);
+ unsigned char *ptr;
+ int mac;
+
+ ptr = (unsigned char *)(skb + 1);
+ mac = 0;
+ skb->arp = 1;
+ if (dev->hard_header) {
+ mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
+ }
+ if (mac < 0) {
+ mac = -mac;
+ skb->arp = 0;
+ }
+ skb->dev = dev;
+ return(mac);
}
@@ -235,419 +196,333 @@ static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct dev
* protocol knows what it's doing, otherwise it uses the
* routing/ARP tables to select a device struct.
*/
-int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
- struct device **dev, int type, struct options *opt, int len, int ttl,int tos)
+int
+ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
+ struct device **dev, int type, struct options *opt, int len)
{
- static struct options optmem;
- struct iphdr *iph;
- struct rtable *rt;
- unsigned char *buff;
- unsigned long raddr;
- static int count = 0;
- int tmp;
- int optlen;
-
- if (saddr == 0)
- saddr = my_addr();
-
- DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n"
- " type=%d, opt=%X, len = %d)\n",
- skb, saddr, daddr, *dev, type, opt, len));
+ static struct options optmem;
+ struct iphdr *iph;
+ struct rtable *rt;
+ unsigned char *buff;
+ unsigned long raddr;
+ static int count = 0;
+ int tmp;
+
+ if (saddr == 0)
+ saddr = my_addr();
+
+ DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n"
+ " type=%d, opt=%X, len = %d)\n",
+ skb, saddr, daddr, *dev, type, opt, len));
- buff = (unsigned char *)(skb + 1);
+ buff = (unsigned char *)(skb + 1);
- /* See if we need to look up the device. */
- if (*dev == NULL)
- {
- rt = rt_route(daddr, &optmem);
- if (rt == NULL)
- return(-ENETUNREACH);
-
- *dev = rt->rt_dev;
- if (saddr == 0x0100007FL && daddr != 0x0100007FL)
- saddr = rt->rt_dev->pa_addr;
- raddr = rt->rt_gateway;
-
- DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
- opt = &optmem;
- }
- else
- {
- /* We still need the address of the first hop. */
- rt = rt_route(daddr, &optmem);
- raddr = (rt == NULL) ? 0 : rt->rt_gateway;
- }
- if (raddr == 0)
- raddr = daddr;
+ /* See if we need to look up the device. */
+ if (*dev == NULL) {
+ rt = rt_route(daddr, &optmem);
+ if (rt == NULL)
+ return(-ENETUNREACH);
- /* Now build the MAC header. */
- tmp = ip_send(skb, raddr, len, *dev, saddr);
- buff += tmp;
- len -= tmp;
-
- skb->dev = *dev;
- skb->saddr = saddr;
- if (skb->sk)
- skb->sk->saddr = saddr;
-
- /* Now build the IP header. */
-
- /* If we are using IPPROTO_RAW, then we don't need an IP header, since
- one is being supplied to us by the user */
-
- if(type == IPPROTO_RAW)
- return (tmp);
-
- iph = (struct iphdr *)buff;
- iph->version = 4;
- iph->tos = tos;
- iph->frag_off = 0;
- iph->ttl = ttl;
- iph->daddr = daddr;
- iph->saddr = saddr;
- iph->protocol = type;
- iph->ihl = 5;
- iph->id = htons(count++);
-
- /* Setup the IP options. Length is in longs.*/
+ *dev = rt->rt_dev;
+ if (saddr == 0x0100007FL && daddr != 0x0100007FL)
+ saddr = rt->rt_dev->pa_addr;
+ raddr = rt->rt_gateway;
- optlen=build_options(iph, opt);
- iph->ihl+=optlen;
+ DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
+ opt = &optmem;
+ } else {
+ /* We still need the address of the first hop. */
+ rt = rt_route(daddr, &optmem);
+ raddr = (rt == NULL) ? 0 : rt->rt_gateway;
+ }
+ if (raddr == 0)
+ raddr = daddr;
+
+ /* Now build the MAC header. */
+ tmp = ip_send(skb, raddr, len, *dev, saddr);
+ buff += tmp;
+ len -= tmp;
+
+ skb->dev = *dev;
+ skb->saddr = saddr;
+ if (skb->sk) skb->sk->saddr = saddr;
+
+ /* Now build the IP header. */
+
+ /* If we are using IPPROTO_RAW, then we don't need an IP header, since
+ one is being supplied to us by the user */
+
+ if(type == IPPROTO_RAW) return (tmp);
+
+ iph = (struct iphdr *)buff;
+ iph->version = 4;
+ iph->tos = 0;
+ iph->frag_off = 0;
+ iph->ttl = 32;
+ iph->daddr = daddr;
+ iph->saddr = saddr;
+ iph->protocol = type;
+ iph->ihl = 5;
+ iph->id = htons(count++);
+
+ /* Setup the IP options. */
+#ifdef Not_Yet_Avail
+ build_options(iph, opt);
+#endif
- return(20 + tmp + 4*optlen); /* IP header plus MAC header size */
+ return(20 + tmp); /* IP header plus MAC header size */
}
-/*
- * Interpret the incoming options
- */
-
-static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device *dev)
+static int
+do_options(struct iphdr *iph, struct options *opt)
{
- unsigned char *buff;
- int done = 0;
- int i, len = sizeof(struct iphdr);
- unsigned char *outbuf;
- struct options *opt;
- int ol;
- int optsiz;
-
- if(iph->ihl==5)
- {
- *opt_ptr=NULL;
- return(0);
- }
-
- /* Allocate a buffer to stuff the options (decoded) and the raw option data into */
-
- ol=(iph->ihl*4)-sizeof(struct iphdr);
-
- opt=(struct options *)kmalloc(ol+sizeof(*opt),GFP_ATOMIC);
- *opt_ptr=opt;
-
- if(opt==NULL)
- return(1);
-
- opt->option_length=ol;
- outbuf=(unsigned char *)(opt+1);
- opt->option_data=outbuf;
-
- /* Zero out the options. */
- opt->record_route.route_size = 0;
- opt->loose_route.route_size = 0;
- opt->strict_route.route_size = 0;
- opt->tstamp.ptr = 0;
- opt->security = 0;
- opt->compartment = 0;
- opt->handling = 0;
- opt->stream = 0;
- opt->tcc = 0;
-
-
- /* Advance the pointer to start at the options. */
- buff = (unsigned char *)(iph + 1);
- /* Copy the data */
- memcpy(outbuf,buff,opt->option_length);
- buff = outbuf;
-
- /* Now start the processing. */
- while (!done && len < iph->ihl*4) switch(*buff)
- {
- case IPOPT_END:
- done = 1;
- break;
- case IPOPT_NOOP:
- buff++;
- len++;
- break;
- case IPOPT_SEC:
- buff++;
- if (*buff != 11)
- return(1);
- buff++;
- opt->security = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->compartment = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->handling = ntohs(*(unsigned short *)buff);
- buff += 2;
- opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1));
- buff += 3;
- len += 11;
- break;
- case IPOPT_LSRR:
- buff++;
- if ((*buff - 3)% 4 != 0)
- return(1);
- if(*buff<2)
- return(1);
- len += (optsiz= *buff);
- opt->loose_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0)
- return(1);
- opt->loose_route.pointer = *buff/4 - 1;
- if(*buff<=optsiz)
- *buff+=4; /* Move on a route */
- buff++;
- buff++;
- for (i = 0; i < opt->loose_route.route_size; i++)
- {
- if(i>=MAX_ROUTE)
- return(1);
- if(i==opt->strict_route.pointer)
- *(unsigned long *)buff=dev->pa_addr;
- opt->loose_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_SSRR:
- buff++;
- if ((*buff - 3)% 4 != 0)
+ unsigned char *buff;
+ int done = 0;
+ int i, len = sizeof(struct iphdr);
+
+ /* Zero out the options. */
+ opt->record_route.route_size = 0;
+ opt->loose_route.route_size = 0;
+ opt->strict_route.route_size = 0;
+ opt->tstamp.ptr = 0;
+ opt->security = 0;
+ opt->compartment = 0;
+ opt->handling = 0;
+ opt->stream = 0;
+ opt->tcc = 0;
+ return(0);
+
+ /* Advance the pointer to start at the options. */
+ buff = (unsigned char *)(iph + 1);
+
+ /* Now start the processing. */
+ while (!done && len < iph->ihl*4) switch(*buff) {
+ case IPOPT_END:
+ done = 1;
+ break;
+ case IPOPT_NOOP:
+ buff++;
+ len++;
+ break;
+ case IPOPT_SEC:
+ buff++;
+ if (*buff != 11) return(1);
+ buff++;
+ opt->security = ntohs(*(unsigned short *)buff);
+ buff += 2;
+ opt->compartment = ntohs(*(unsigned short *)buff);
+ buff += 2;
+ opt->handling = ntohs(*(unsigned short *)buff);
+ buff += 2;
+ opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1));
+ buff += 3;
+ len += 11;
+ break;
+ case IPOPT_LSRR:
+ buff++;
+ if ((*buff - 3)% 4 != 0) return(1);
+ len += *buff;
+ opt->loose_route.route_size = (*buff -3)/4;
+ buff++;
+ if (*buff % 4 != 0) return(1);
+ opt->loose_route.pointer = *buff/4 - 1;
+ buff++;
+ buff++;
+ for (i = 0; i < opt->loose_route.route_size; i++) {
+ if(i>=MAX_ROUTE)
return(1);
- if(*buff<2)
- return(1);
- len += (optsiz= *buff);
- opt->strict_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0)
- return(1);
- opt->strict_route.pointer = *buff/4 - 1;
- if(*buff<=optsiz)
- *buff+=4;
- buff++;
- buff++;
- for (i = 0; i < opt->strict_route.route_size; i++)
- {
- if(i>=MAX_ROUTE)
- return(1);
- if(i==opt->strict_route.pointer)
- *(unsigned long *)buff=dev->pa_addr;
- opt->strict_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_RR:
- buff++;
- if ((*buff - 3)% 4 != 0)
- return(1);
- if(*buff<2)
- return(1);
- len += (optsiz= *buff);
- opt->record_route.route_size = (*buff -3)/4;
- buff++;
- if (*buff % 4 != 0)
+ opt->loose_route.route[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ case IPOPT_SSRR:
+ buff++;
+ if ((*buff - 3)% 4 != 0) return(1);
+ len += *buff;
+ opt->strict_route.route_size = (*buff -3)/4;
+ buff++;
+ if (*buff % 4 != 0) return(1);
+ opt->strict_route.pointer = *buff/4 - 1;
+ buff++;
+ buff++;
+ for (i = 0; i < opt->strict_route.route_size; i++) {
+ if(i>=MAX_ROUTE)
return(1);
- opt->record_route.pointer = *buff/4 - 1;
- if(*buff+4<=optsiz)
- *buff+=4;
- buff++;
- buff++;
- for (i = 0; i < opt->record_route.route_size; i++)
- {
- if(i>=MAX_ROUTE)
- return 1;
- if(i==opt->record_route.pointer)
- *(unsigned long *)buff=dev->pa_addr;
- opt->record_route.route[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- case IPOPT_SID:
- len += 4;
- buff +=2;
- opt->stream = *(unsigned short *)buff;
- buff += 2;
- break;
- case IPOPT_TIMESTAMP:
- /* FIXME: This one isn't altered correctly yet */
- buff++;
- if(*buff<2)
+ opt->strict_route.route[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ case IPOPT_RR:
+ buff++;
+ if ((*buff - 3)% 4 != 0) return(1);
+ len += *buff;
+ opt->record_route.route_size = (*buff -3)/4;
+ buff++;
+ if (*buff % 4 != 0) return(1);
+ opt->record_route.pointer = *buff/4 - 1;
+ buff++;
+ buff++;
+ for (i = 0; i < opt->record_route.route_size; i++) {
+ if(i>=MAX_ROUTE)
return 1;
- len += *buff;
- if (*buff % 4 != 0)
- return(1);
- opt->tstamp.len = *buff / 4 - 1;
- buff++;
- if ((*buff - 1) % 4 != 0)
- return(1);
- opt->tstamp.ptr = (*buff-1)/4;
- buff++;
- opt->tstamp.x.full_char = *buff;
- buff++;
- for (i = 0; i < opt->tstamp.len; i++)
- {
- opt->tstamp.data[i] = *(unsigned long *)buff;
- buff += 4;
- }
- break;
- default:
- return(1);
- }
+ opt->record_route.route[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ case IPOPT_SID:
+ len += 4;
+ buff +=2;
+ opt->stream = *(unsigned short *)buff;
+ buff += 2;
+ break;
+ case IPOPT_TIMESTAMP:
+ buff++;
+ len += *buff;
+ if (*buff % 4 != 0) return(1);
+ opt->tstamp.len = *buff / 4 - 1;
+ buff++;
+ if ((*buff - 1) % 4 != 0) return(1);
+ opt->tstamp.ptr = (*buff-1)/4;
+ buff++;
+ opt->tstamp.x.full_char = *buff;
+ buff++;
+ for (i = 0; i < opt->tstamp.len; i++) {
+ opt->tstamp.data[i] = *(unsigned long *)buff;
+ buff += 4;
+ }
+ break;
+ default:
+ return(1);
+ }
- if (opt->record_route.route_size == 0)
- {
- if (opt->strict_route.route_size != 0)
- {
- memcpy(&(opt->record_route), &(opt->strict_route),
+ if (opt->record_route.route_size == 0) {
+ if (opt->strict_route.route_size != 0) {
+ memcpy(&(opt->record_route), &(opt->strict_route),
sizeof(opt->record_route));
- }
- else if (opt->loose_route.route_size != 0)
- {
- memcpy(&(opt->record_route), &(opt->loose_route),
+ } else if (opt->loose_route.route_size != 0) {
+ memcpy(&(opt->record_route), &(opt->loose_route),
sizeof(opt->record_route));
- }
}
+ }
- if (opt->strict_route.route_size != 0 &&
- opt->strict_route.route_size != opt->strict_route.pointer)
- {
- strict_route(iph, opt);
- return(0);
- }
-
- if (opt->loose_route.route_size != 0 &&
- opt->loose_route.route_size != opt->loose_route.pointer)
- {
- loose_route(iph, opt);
- return(0);
- }
+ if (opt->strict_route.route_size != 0 &&
+ opt->strict_route.route_size != opt->strict_route.pointer) {
+ strict_route(iph, opt);
+ return(0);
+ }
+ if (opt->loose_route.route_size != 0 &&
+ opt->loose_route.route_size != opt->loose_route.pointer) {
+ loose_route(iph, opt);
return(0);
+ }
+
+ return(0);
}
-/*
- * This is a version of ip_compute_csum() optimized for IP headers, which
- * always checksum on 4 octet boundaries.
- */
-
-static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
+/* This is a version of ip_compute_csum() optimized for IP headers, which
+ always checksum on 4 octet boundaries. */
+static inline unsigned short
+ip_fast_csum(unsigned char * buff, int wlen)
{
- unsigned long sum = 0;
-
- if (wlen) {
- unsigned long bogus;
- __asm__("clc\n"
- "1:\t"
- "lodsl\n\t"
- "adcl %3, %0\n\t"
- "decl %2\n\t"
- "jne 1b\n\t"
- "adcl $0, %0\n\t"
- "movl %0, %3\n\t"
- "shrl $16, %3\n\t"
- "addw %w3, %w0\n\t"
- "adcw $0, %w0"
- : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
- : "0" (sum), "1" (buff), "2" (wlen));
- }
- return (~sum) & 0xffff;
+ unsigned long sum = 0;
+
+ if (wlen) {
+ unsigned long bogus;
+ __asm__("clc\n"
+ "1:\t"
+ "lodsl\n\t"
+ "adcl %3, %0\n\t"
+ "decl %2\n\t"
+ "jne 1b\n\t"
+ "adcl $0, %0\n\t"
+ "movl %0, %3\n\t"
+ "shrl $16, %3\n\t"
+ "addw %w3, %w0\n\t"
+ "adcw $0, %w0"
+ : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
+ : "0" (sum), "1" (buff), "2" (wlen));
+ }
+ return (~sum) & 0xffff;
}
/*
* This routine does all the checksum computations that don't
* require anything special (like copying or special headers).
*/
-
-unsigned short ip_compute_csum(unsigned char * buff, int len)
+unsigned short
+ip_compute_csum(unsigned char * buff, int len)
{
- unsigned long sum = 0;
-
- /* Do the first multiple of 4 bytes and convert to 16 bits. */
- if (len > 3) {
- __asm__("clc\n"
- "1:\t"
- "lodsl\n\t"
- "adcl %%eax, %%ebx\n\t"
- "loop 1b\n\t"
- "adcl $0, %%ebx\n\t"
- "movl %%ebx, %%eax\n\t"
- "shrl $16, %%eax\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum) , "=S" (buff)
- : "0" (sum), "c" (len >> 2) ,"1" (buff)
- : "ax", "cx", "si", "bx" );
- }
- if (len & 2) {
- __asm__("lodsw\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum), "=S" (buff)
- : "0" (sum), "1" (buff)
- : "bx", "ax", "si");
- }
- if (len & 1) {
- __asm__("lodsb\n\t"
- "movb $0, %%ah\n\t"
- "addw %%ax, %%bx\n\t"
- "adcw $0, %%bx"
- : "=b" (sum), "=S" (buff)
- : "0" (sum), "1" (buff)
- : "bx", "ax", "si");
- }
- sum =~sum;
- return(sum & 0xffff);
+ unsigned long sum = 0;
+
+ /* Do the first multiple of 4 bytes and convert to 16 bits. */
+ if (len > 3) {
+ __asm__("clc\n"
+ "1:\t"
+ "lodsl\n\t"
+ "adcl %%eax, %%ebx\n\t"
+ "loop 1b\n\t"
+ "adcl $0, %%ebx\n\t"
+ "movl %%ebx, %%eax\n\t"
+ "shrl $16, %%eax\n\t"
+ "addw %%ax, %%bx\n\t"
+ "adcw $0, %%bx"
+ : "=b" (sum) , "=S" (buff)
+ : "0" (sum), "c" (len >> 2) ,"1" (buff)
+ : "ax", "cx", "si", "bx" );
+ }
+ if (len & 2) {
+ __asm__("lodsw\n\t"
+ "addw %%ax, %%bx\n\t"
+ "adcw $0, %%bx"
+ : "=b" (sum), "=S" (buff)
+ : "0" (sum), "1" (buff)
+ : "bx", "ax", "si");
+ }
+ if (len & 1) {
+ __asm__("lodsb\n\t"
+ "movb $0, %%ah\n\t"
+ "addw %%ax, %%bx\n\t"
+ "adcw $0, %%bx"
+ : "=b" (sum), "=S" (buff)
+ : "0" (sum), "1" (buff)
+ : "bx", "ax", "si");
+ }
+ sum =~sum;
+ return(sum & 0xffff);
}
-/*
- * Check the header of an incoming IP datagram. This version is still used in slhc.c.
- */
-
-int ip_csum(struct iphdr *iph)
+/* Check the header of an incoming IP datagram. This version is still used in slhc.c. */
+int
+ip_csum(struct iphdr *iph)
{
- return ip_fast_csum((unsigned char *)iph, iph->ihl);
+ return ip_fast_csum((unsigned char *)iph, iph->ihl);
}
-/*
- * Generate a checksym for an outgoing IP datagram. (RFC791, Page 14)
- */
-
-static void ip_send_check(struct iphdr *iph)
+/* Generate a checksym for an outgoing IP datagram. */
+static void
+ip_send_check(struct iphdr *iph)
{
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/
static struct ipq *ipqueue = NULL; /* IP fragment queue */
-
-/*
- * Create a new fragment entry.
- */
-
+ /* Create a new fragment entry. */
static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
{
- struct ipfrag *fp;
+ struct ipfrag *fp;
- fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
- if (fp == NULL)
- {
+ fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC);
+ if (fp == NULL)
+ {
printk("IP: frag_create: no memory left !\n");
return(NULL);
- }
- memset(fp, 0, sizeof(struct ipfrag));
+ }
+ memset(fp, 0, sizeof(struct ipfrag));
/* Fill in the structure. */
fp->offset = offset;
@@ -664,7 +539,6 @@ static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, u
* Find the correct entry in the "incomplete datagrams" queue for
* this IP datagram, and return the queue entry address if found.
*/
-
static struct ipq *ip_find(struct iphdr *iph)
{
struct ipq *qp;
@@ -674,14 +548,14 @@ static struct ipq *ip_find(struct iphdr *iph)
qplast = NULL;
for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next)
{
- if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr &&
+ if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr &&
iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol)
{
del_timer(&qp->timer); /* So it doesnt vanish on us. The timer will be reset anyway */
- sti();
- return(qp);
- }
- }
+ sti();
+ return(qp);
+ }
+ }
sti();
return(NULL);
}
@@ -709,62 +583,60 @@ static void ip_free(struct ipq *qp)
ipqueue = qp->next;
if (ipqueue != NULL)
ipqueue->prev = NULL;
- }
- else
- {
- qp->prev->next = qp->next;
- if (qp->next != NULL)
- qp->next->prev = qp->prev;
- }
-
- /* Release all fragment data. */
+ }
+ else
+ {
+ qp->prev->next = qp->next;
+ if (qp->next != NULL)
+ qp->next->prev = qp->prev;
+ }
+
+ /* Release all fragment data. */
/* printk("ip_free: kill frag data\n");*/
- fp = qp->fragments;
- while (fp != NULL)
- {
- xp = fp->next;
- IS_SKB(fp->skb);
- kfree_skb(fp->skb,FREE_READ);
- kfree_s(fp, sizeof(struct ipfrag));
- fp = xp;
- }
-
+ fp = qp->fragments;
+ while (fp != NULL)
+ {
+ xp = fp->next;
+ IS_SKB(fp->skb);
+ kfree_skb(fp->skb,FREE_READ);
+ kfree_s(fp, sizeof(struct ipfrag));
+ fp = xp;
+ }
+
/* printk("ip_free: cleanup\n");*/
- /* Release the MAC header. */
- kfree_s(qp->mac, qp->maclen);
+ /* Release the MAC header. */
+ kfree_s(qp->mac, qp->maclen);
- /* Release the IP header. */
- kfree_s(qp->iph, qp->ihlen + 8);
+ /* Release the IP header. */
+ kfree_s(qp->iph, qp->ihlen + 8);
- /* Finally, release the queue descriptor itself. */
- kfree_s(qp, sizeof(struct ipq));
+ /* Finally, release the queue descriptor itself. */
+ kfree_s(qp, sizeof(struct ipq));
/* printk("ip_free:done\n");*/
- sti();
+ sti();
}
-/*
- * Oops- a fragment queue timed out. Kill it and send an ICMP reply.
- */
+ /* Oops- a fragment queue timed out. Kill it and send an ICMP reply. */
static void ip_expire(unsigned long arg)
{
- struct ipq *qp;
+ struct ipq *qp;
- qp = (struct ipq *)arg;
- DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp));
+ qp = (struct ipq *)arg;
+ DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp));
- /* Send an ICMP "Fragment Reassembly Timeout" message. */
+ /* Send an ICMP "Fragment Reassembly Timeout" message. */
#if 0
- icmp_send(qp->iph->ip_src.s_addr, ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, qp->iph);
+ icmp_send(qp->iph->ip_src.s_addr, ICMP_TIME_EXCEEDED,
+ ICMP_EXC_FRAGTIME, qp->iph);
#endif
- if(qp->fragments!=NULL)
- icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
- ICMP_EXC_FRAGTIME, qp->dev);
+ if(qp->fragments!=NULL)
+ icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED,
+ ICMP_EXC_FRAGTIME, qp->dev);
- /* Nuke the fragment queue. */
+ /* Nuke the fragment queue. */
ip_free(qp);
}
@@ -778,168 +650,158 @@ static void ip_expire(unsigned long arg)
static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev)
{
- struct ipq *qp;
- int maclen;
- int ihlen;
+ struct ipq *qp;
+ int maclen;
+ int ihlen;
- qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC);
- if (qp == NULL)
- {
+ qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC);
+ if (qp == NULL)
+ {
printk("IP: create: no memory left !\n");
return(NULL);
- }
- memset(qp, 0, sizeof(struct ipq));
-
- /* Allocate memory for the MAC header. */
- maclen = ((unsigned long) iph) - ((unsigned long) (skb + 1));
- qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC);
- if (qp->mac == NULL)
- {
+ }
+ memset(qp, 0, sizeof(struct ipq));
+
+ /* Allocate memory for the MAC header. */
+ maclen = ((unsigned long) iph) - ((unsigned long) (skb + 1));
+ qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC);
+ if (qp->mac == NULL)
+ {
printk("IP: create: no memory left !\n");
kfree_s(qp, sizeof(struct ipq));
return(NULL);
- }
+ }
- /* Allocate memory for the IP header (plus 8 octects for ICMP). */
- ihlen = (iph->ihl * sizeof(unsigned long));
- qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC);
- if (qp->iph == NULL)
- {
+ /* Allocate memory for the IP header (plus 8 octects for ICMP). */
+ ihlen = (iph->ihl * sizeof(unsigned long));
+ qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC);
+ if (qp->iph == NULL)
+ {
printk("IP: create: no memory left !\n");
kfree_s(qp->mac, maclen);
kfree_s(qp, sizeof(struct ipq));
return(NULL);
- }
-
- /* Fill in the structure. */
- memcpy(qp->mac, (skb + 1), maclen);
- memcpy(qp->iph, iph, ihlen + 8);
- qp->len = 0;
- qp->ihlen = ihlen;
- qp->maclen = maclen;
- qp->fragments = NULL;
- qp->dev = dev;
+ }
+
+ /* Fill in the structure. */
+ memcpy(qp->mac, (skb + 1), maclen);
+ memcpy(qp->iph, iph, ihlen + 8);
+ qp->len = 0;
+ qp->ihlen = ihlen;
+ qp->maclen = maclen;
+ qp->fragments = NULL;
+ qp->dev = dev;
/* printk("Protocol = %d\n",qp->iph->protocol);*/
- /* Start a timer for this entry. */
- qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
-
- /* Add this entry to the queue. */
- qp->prev = NULL;
- cli();
- qp->next = ipqueue;
- if (qp->next != NULL)
- qp->next->prev = qp;
- ipqueue = qp;
- sti();
- return(qp);
+ /* Start a timer for this entry. */
+ qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
+ qp->timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->timer.function = ip_expire; /* expire function */
+ add_timer(&qp->timer);
+
+ /* Add this entry to the queue. */
+ qp->prev = NULL;
+ cli();
+ qp->next = ipqueue;
+ if (qp->next != NULL)
+ qp->next->prev = qp;
+ ipqueue = qp;
+ sti();
+ return(qp);
}
-/*
- * See if a fragment queue is complete.
- */
-
+ /* See if a fragment queue is complete. */
static int ip_done(struct ipq *qp)
{
struct ipfrag *fp;
int offset;
- /* Only possible if we received the final fragment. */
- if (qp->len == 0)
- return(0);
-
- /* Check all fragment offsets to see if they connect. */
- fp = qp->fragments;
- offset = 0;
- while (fp != NULL)
- {
- if (fp->offset > offset)
- return(0); /* fragment(s) missing */
- offset = fp->end;
- fp = fp->next;
- }
-
- /* All fragments are present. */
- return(1);
+ /* Only possible if we received the final fragment. */
+ if (qp->len == 0)
+ return(0);
+
+ /* Check all fragment offsets to see if they connect. */
+ fp = qp->fragments;
+ offset = 0;
+ while (fp != NULL)
+ {
+ if (fp->offset > offset)
+ return(0); /* fragment(s) missing */
+ offset = fp->end;
+ fp = fp->next;
+ }
+
+ /* All fragments are present. */
+ return(1);
}
-/*
- * Build a new IP datagram from all its fragments.
- */
-
+/* Build a new IP datagram from all its fragments. */
static struct sk_buff *ip_glue(struct ipq *qp)
{
struct sk_buff *skb;
- struct iphdr *iph;
- struct ipfrag *fp;
- unsigned char *ptr;
- int count, len;
-
- /* Allocate a new buffer for the datagram. */
- len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len;
- if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL)
- {
- printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp);
- ip_free(qp);
- return(NULL);
- }
-
- /* Fill in the basic details. */
- skb->len = (len - qp->maclen);
- skb->h.raw = (unsigned char *) (skb + 1);
- skb->free = 1;
- skb->lock = 1;
-
- /* Copy the original MAC and IP headers into the new buffer. */
- ptr = (unsigned char *) skb->h.raw;
- memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen);
+ struct iphdr *iph;
+ struct ipfrag *fp;
+ unsigned char *ptr;
+ int count, len;
+
+ /* Allocate a new buffer for the datagram. */
+ len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len;
+ if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL)
+ {
+ printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp);
+ ip_free(qp);
+ return(NULL);
+ }
+
+ /* Fill in the basic details. */
+ skb->len = (len - qp->maclen);
+ skb->h.raw = (unsigned char *) (skb + 1);
+ skb->free = 1;
+ skb->lock = 1;
+
+ /* Copy the original MAC and IP headers into the new buffer. */
+ ptr = (unsigned char *) skb->h.raw;
+ memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen);
/* printk("Copied %d bytes of mac header.\n",qp->maclen);*/
- ptr += qp->maclen;
- memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
+ ptr += qp->maclen;
+ memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen);
/* printk("Copied %d byte of ip header.\n",qp->ihlen);*/
- ptr += qp->ihlen;
- skb->h.raw += qp->maclen;
-
+ ptr += qp->ihlen;
+ skb->h.raw += qp->maclen;
+
/* printk("Protocol = %d\n",skb->h.iph->protocol);*/
- count = 0;
-
- /* Copy the data portions of all fragments into the new buffer. */
- fp = qp->fragments;
- while(fp != NULL)
- {
- if(count+fp->len>skb->len)
- {
- /* In case some fool sends us a silly fragment. */
- printk("Invalid fragment list: Fragment over size.\n");
- kfree_skb(skb,FREE_WRITE);
- return NULL;
- }
+ count = 0;
+
+ /* Copy the data portions of all fragments into the new buffer. */
+ fp = qp->fragments;
+ while(fp != NULL)
+ {
+ if(count+fp->len>skb->len)
+ {
+ printk("Invalid fragment list: Fragment over size.\n");
+ kfree_skb(skb,FREE_WRITE);
+ return NULL;
+ }
/* printk("Fragment %d size %d\n",fp->offset,fp->len);*/
- memcpy((ptr + fp->offset), fp->ptr, fp->len);
- count += fp->len;
- fp = fp->next;
- }
-
- /* We glued together all fragments, so remove the queue entry. */
- ip_free(qp);
-
- /* Done with all fragments. Fixup the new IP header. */
- iph = skb->h.iph;
- iph->frag_off = 0;
- iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count);
- return(skb);
+ memcpy((ptr + fp->offset), fp->ptr, fp->len);
+ count += fp->len;
+ fp = fp->next;
+ }
+
+ /* We glued together all fragments, so remove the queue entry. */
+ ip_free(qp);
+
+ /* Done with all fragments. Fixup the new IP header. */
+ iph = skb->h.iph;
+ iph->frag_off = 0;
+ iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count);
+ return(skb);
}
-/*
- * Process an incoming IP datagram fragment.
- */
-
+/* Process an incoming IP datagram fragment. */
static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev)
{
struct ipfrag *prev, *next;
@@ -951,135 +813,135 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
int i, ihl, end;
/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
- qp = ip_find(iph);
-
- /* Is this a non-fragmented datagram? */
- offset = ntohs(iph->frag_off);
- flags = offset & ~IP_OFFSET;
- offset &= IP_OFFSET;
- if (((flags & IP_MF) == 0) && (offset == 0))
- {
- if (qp != NULL)
- ip_free(qp); /* Huh? How could this exist?? */
- return(skb);
- }
- offset <<= 3; /* offset is in 8-byte chunks */
-
- /*
- * If the queue already existed, keep restarting its timer as long
- * as we still are receiving fragments. Otherwise, create a fresh
- * queue entry.
- */
- if (qp != NULL)
- {
- del_timer(&qp->timer);
- qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
- qp->timer.data = (unsigned long) qp; /* pointer to queue */
- qp->timer.function = ip_expire; /* expire function */
- add_timer(&qp->timer);
- }
- else
- {
- if ((qp = ip_create(skb, iph, dev)) == NULL)
- return(NULL);
- }
-
- /* Determine the position of this fragment. */
- ihl = (iph->ihl * sizeof(unsigned long));
- end = offset + ntohs(iph->tot_len) - ihl;
-
- /* Point into the IP datagram 'data' part. */
- ptr = ((unsigned char *) (skb + 1)) + dev->hard_header_len + ihl;
-
- /* Is this the final fragment? */
- if ((flags & IP_MF) == 0)
- qp->len = end;
-
- /*
- * Find out which fragments are in front and at the back of us
- * in the chain of fragments so far. We must know where to put
- * this fragment, right?
- */
- prev = NULL;
- for(next = qp->fragments; next != NULL; next = next->next)
- {
- if (next->offset > offset)
- break; /* bingo! */
- prev = next;
- }
-
- /*
- * We found where to put this one.
- * Check for overlap with preceeding fragment, and, if needed,
- * align things so that any overlaps are eliminated.
- */
- if (prev != NULL && offset < prev->end)
- {
- i = prev->end - offset;
- offset += i; /* ptr into datagram */
- ptr += i; /* ptr into fragment data */
- DPRINTF((DBG_IP, "IP: defrag: fixed low overlap %d bytes\n", i));
- }
-
- /*
- * Look for overlap with succeeding segments.
- * If we can merge fragments, do it.
+ qp = ip_find(iph);
+
+ /* Is this a non-fragmented datagram? */
+ offset = ntohs(iph->frag_off);
+ flags = offset & ~IP_OFFSET;
+ offset &= IP_OFFSET;
+ if (((flags & IP_MF) == 0) && (offset == 0))
+ {
+ if (qp != NULL)
+ ip_free(qp); /* Huh? How could this exist?? */
+ return(skb);
+ }
+ offset <<= 3; /* offset is in 8-byte chunks */
+
+ /*
+ * If the queue already existed, keep restarting its timer as long
+ * as we still are receiving fragments. Otherwise, create a fresh
+ * queue entry.
+ */
+ if (qp != NULL)
+ {
+ del_timer(&qp->timer);
+ qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
+ qp->timer.data = (unsigned long) qp; /* pointer to queue */
+ qp->timer.function = ip_expire; /* expire function */
+ add_timer(&qp->timer);
+ }
+ else
+ {
+ if ((qp = ip_create(skb, iph, dev)) == NULL)
+ return(NULL);
+ }
+
+ /* Determine the position of this fragment. */
+ ihl = (iph->ihl * sizeof(unsigned long));
+ end = offset + ntohs(iph->tot_len) - ihl;
+
+ /* Point into the IP datagram 'data' part. */
+ ptr = ((unsigned char *) (skb + 1)) + dev->hard_header_len + ihl;
+
+ /* Is this the final fragment? */
+ if ((flags & IP_MF) == 0)
+ qp->len = end;
+
+ /*
+ * Find out which fragments are in front and at the back of us
+ * in the chain of fragments so far. We must know where to put
+ * this fragment, right?
+ */
+ prev = NULL;
+ for(next = qp->fragments; next != NULL; next = next->next)
+ {
+ if (next->offset > offset)
+ break; /* bingo! */
+ prev = next;
+ }
+
+ /*
+ * We found where to put this one.
+ * Check for overlap with preceeding fragment, and, if needed,
+ * align things so that any overlaps are eliminated.
+ */
+ if (prev != NULL && offset < prev->end)
+ {
+ i = prev->end - offset;
+ offset += i; /* ptr into datagram */
+ ptr += i; /* ptr into fragment data */
+ DPRINTF((DBG_IP, "IP: defrag: fixed low overlap %d bytes\n", i));
+ }
+
+ /*
+ * Look for overlap with succeeding segments.
+ * If we can merge fragments, do it.
*/
- for(; next != NULL; next = tfp)
- {
- tfp = next->next;
- if (next->offset >= end)
- break; /* no overlaps at all */
-
- i = end - next->offset; /* overlap is 'i' bytes */
- next->len -= i; /* so reduce size of */
- next->offset += i; /* next fragment */
- next->ptr += i;
-
- /* If we get a frag size of <= 0, remove it. */
- if (next->len <= 0)
- {
- DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n",
- next, next->len));
- if (next->prev != NULL)
- next->prev->next = next->next;
- else
- qp->fragments = next->next;
-
- if (tfp->next != NULL)
- next->next->prev = next->prev;
-
- kfree_s(next, sizeof(struct ipfrag));
- }
- DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i));
- }
-
- /* Insert this fragment in the chain of fragments. */
- tfp = NULL;
- tfp = ip_frag_create(offset, end, skb, ptr);
- tfp->prev = prev;
- tfp->next = next;
- if (prev != NULL)
- prev->next = tfp;
+ for(; next != NULL; next = tfp)
+ {
+ tfp = next->next;
+ if (next->offset >= end)
+ break; /* no overlaps at all */
+
+ i = end - next->offset; /* overlap is 'i' bytes */
+ next->len -= i; /* so reduce size of */
+ next->offset += i; /* next fragment */
+ next->ptr += i;
+
+ /* If we get a frag size of <= 0, remove it. */
+ if (next->len <= 0)
+ {
+ DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n",
+ next, next->len));
+ if (next->prev != NULL)
+ next->prev->next = next->next;
+ else
+ qp->fragments = next->next;
+
+ if (tfp->next != NULL)
+ next->next->prev = next->prev;
+
+ kfree_s(next, sizeof(struct ipfrag));
+ }
+ DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i));
+ }
+
+ /* Insert this fragment in the chain of fragments. */
+ tfp = NULL;
+ tfp = ip_frag_create(offset, end, skb, ptr);
+ tfp->prev = prev;
+ tfp->next = next;
+ if (prev != NULL)
+ prev->next = tfp;
else
qp->fragments = tfp;
- if (next != NULL)
- next->prev = tfp;
-
- /*
- * OK, so we inserted this new fragment into the chain.
- * Check if we now have a full IP datagram which we can
- * bump up to the IP layer...
- */
+ if (next != NULL)
+ next->prev = tfp;
+
+ /*
+ * OK, so we inserted this new fragment into the chain.
+ * Check if we now have a full IP datagram which we can
+ * bump up to the IP layer...
+ */
- if (ip_done(qp))
- {
- skb2 = ip_glue(qp); /* glue together the fragments */
- return(skb2);
- }
- return(NULL);
+ if (ip_done(qp))
+ {
+ skb2 = ip_glue(qp); /* glue together the fragments */
+ return(skb2);
+ }
+ return(NULL);
}
@@ -1091,398 +953,363 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
* ip_queue_xmit(). Note that this is recursion, and bad things will happen
* if this function causes a loop...
*/
-
void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag)
{
- struct iphdr *iph;
- unsigned char *raw;
- unsigned char *ptr;
- struct sk_buff *skb2;
- int left, mtu, hlen, len;
- int offset;
-
- /* Point into the IP datagram header. */
- raw = (unsigned char *) (skb + 1);
- iph = (struct iphdr *) (raw + dev->hard_header_len);
-
- /* Setup starting values. */
- hlen = (iph->ihl * sizeof(unsigned long));
- left = ntohs(iph->tot_len) - hlen;
- hlen += dev->hard_header_len;
- mtu = (dev->mtu - hlen);
- ptr = (raw + hlen);
-
- DPRINTF((DBG_IP, "IP: Fragmentation Desired\n"));
- DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
- dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
-
- /* Check for any "DF" flag. */
- if (ntohs(iph->frag_off) & IP_DF)
- {
- DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n"));
- DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
- dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
-
- /*
- * FIXME:
- * We should send an ICMP warning message here!
- */
-
- icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev);
- return;
- }
-
- /*
- * If it won't fit then error it.
- * NOTE: We don't send a ICMP here. Suppose the ICMP didn't fit....
- */
-
- if(mtu<8)
- {
- return;
- }
-
- /* Fragment the datagram. */
+ struct iphdr *iph;
+ unsigned char *raw;
+ unsigned char *ptr;
+ struct sk_buff *skb2;
+ int left, mtu, hlen, len;
+ int offset;
+
+ /* Point into the IP datagram header. */
+ raw = (unsigned char *) (skb + 1);
+ iph = (struct iphdr *) (raw + dev->hard_header_len);
+
+ /* Setup starting values. */
+ hlen = (iph->ihl * sizeof(unsigned long));
+ left = ntohs(iph->tot_len) - hlen;
+ hlen += dev->hard_header_len;
+ mtu = (dev->mtu - hlen);
+ ptr = (raw + hlen);
+
+ DPRINTF((DBG_IP, "IP: Fragmentation Desired\n"));
+ DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
+ dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
+
+ /* Check for any "DF" flag. */
+ if (ntohs(iph->frag_off) & IP_DF)
+ {
+ DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n"));
+ DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s",
+ dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
+
+ /*
+ * FIXME:
+ * We should send an ICMP warning message here!
+ */
+
+ icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev);
+ return;
+ }
+
+ /* Fragment the datagram. */
if (is_frag & 2)
offset = (ntohs(iph->frag_off) & 0x1fff) << 3;
else
- offset = 0;
- while(left > 0)
- {
- len = left;
- if (len+8 > mtu)
- len = (dev->mtu - hlen - 8);
- if ((left - len) >= 8)
- {
- len /= 8;
- len *= 8;
- }
- DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
- len, len + hlen));
-
- /* Allocate buffer. */
- if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL)
- {
- printk("IP: frag: no memory for new fragment!\n");
- return;
- }
- skb2->arp = skb->arp;
- skb2->free = skb->free;
- skb2->len = len + hlen;
- skb2->h.raw=(char *)(skb2+1);
-
- if (sk)
- sk->wmem_alloc += skb2->mem_len;
-
- /* Copy the packet header into the new buffer. */
- memcpy(skb2->h.raw, raw, hlen);
-
- /* Copy a block of the IP datagram. */
- memcpy(skb2->h.raw + hlen, ptr, len);
- left -= len;
+ offset = 0;
+ while(left > 0)
+ {
+ len = left;
+ if (len+8 > mtu)
+ len = (dev->mtu - hlen - 8);
+ if ((left - len) >= 8)
+ {
+ len /= 8;
+ len *= 8;
+ }
+ DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
+ len, len + hlen));
+
+ /* Allocate buffer. */
+ if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL)
+ {
+ printk("IP: frag: no memory for new fragment!\n");
+ return;
+ }
+ skb2->arp = skb->arp;
+ skb2->free = skb->free;
+ skb2->len = len + hlen;
+ skb2->h.raw=(char *)(skb2+1);
+
+ if (sk)
+ sk->wmem_alloc += skb2->mem_len;
+
+ /* Copy the packet header into the new buffer. */
+ memcpy(skb2->h.raw, raw, hlen);
+
+ /* Copy a block of the IP datagram. */
+ memcpy(skb2->h.raw + hlen, ptr, len);
+ left -= len;
skb2->h.raw+=dev->hard_header_len;
- /* Fill in the new header fields. */
- iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/);
- iph->frag_off = htons((offset >> 3));
- /* Added AC : If we are fragmenting a fragment thats not the
- last fragment then keep MF on each bit */
- if (left > 0 || (is_frag & 1))
- iph->frag_off |= htons(IP_MF);
- ptr += len;
- offset += len;
+ /* Fill in the new header fields. */
+ iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/);
+ iph->frag_off = htons((offset >> 3));
+ /* Added AC : If we are fragmenting a fragment thats not the
+ last fragment then keep MF on each bit */
+ if (left > 0 || (is_frag & 1))
+ iph->frag_off |= htons(IP_MF);
+ ptr += len;
+ offset += len;
/* printk("Queue frag\n");*/
- /* Put this fragment into the sending queue. */
- ip_queue_xmit(sk, dev, skb2, 1);
+ /* Put this fragment into the sending queue. */
+ ip_queue_xmit(sk, dev, skb2, 1);
/* printk("Queued\n");*/
- }
+ }
}
#ifdef CONFIG_IP_FORWARD
-/*
- * Forward an IP datagram to its next destination.
- */
-
-static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
+/* Forward an IP datagram to its next destination. */
+static void
+ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
{
- struct device *dev2;
- struct iphdr *iph;
- struct sk_buff *skb2;
- struct rtable *rt;
- unsigned char *ptr;
- unsigned long raddr;
+ struct device *dev2;
+ struct iphdr *iph;
+ struct sk_buff *skb2;
+ struct rtable *rt;
+ unsigned char *ptr;
+ unsigned long raddr;
- /*
- * Only forward packets that were fired at us when we are in promiscuous
- * mode. In standard mode we rely on the driver to filter for us.
- */
+ /*
+ * Only forward packets that were fired at us when we are in promiscuous
+ * mode. In standard mode we rely on the driver to filter for us.
+ */
- if(dev->flags&IFF_PROMISC)
- {
- if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len))
- return;
- }
+ if(dev->flags&IFF_PROMISC)
+ {
+ if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len))
+ return;
+ }
- /*
- * According to the RFC, we must first decrease the TTL field. If
- * that reaches zero, we must reply an ICMP control message telling
- * that the packet's lifetime expired. RFC791 page 30.
- */
- iph = skb->h.iph;
- iph->ttl--;
- if (iph->ttl <= 0)
- {
- DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));
- DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
-
- /* Tell the sender its packet died... */
- icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev);
- return;
- }
+ /*
+ * According to the RFC, we must first decrease the TTL field. If
+ * that reaches zero, we must reply an ICMP control message telling
+ * that the packet's lifetime expired.
+ */
+ iph = skb->h.iph;
+ iph->ttl--;
+ if (iph->ttl <= 0) {
+ DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));
+ DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
- /* Re-compute the IP header checksum. */
- ip_send_check(iph);
+ /* Tell the sender its packet died... */
+ icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev);
+ return;
+ }
- /*
- * OK, the packet is still valid. Fetch its destination address,
- * and give it to the IP sender for further processing.
- */
- rt = rt_route(iph->daddr, NULL);
- if (rt == NULL)
- {
- DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));
+ /* Re-compute the IP header checksum. */
+ ip_send_check(iph);
- /* Tell the sender its packet cannot be delivered... */
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev);
- return;
- }
+ /*
+ * OK, the packet is still valid. Fetch its destination address,
+ * and give it to the IP sender for further processing.
+ */
+ rt = rt_route(iph->daddr, NULL);
+ if (rt == NULL) {
+ DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));
+ /* Tell the sender its packet cannot be delivered... */
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev);
+ return;
+ }
- /*
- * Gosh. Not only is the packet valid; we even know how to
- * forward it onto its final destination. Can we say this
- * is being plain lucky?
- * If the router told us that there is no GW, use the dest.
- * IP address itself- we seem to be connected directly...
- */
- raddr = rt->rt_gateway;
- if (raddr != 0)
- {
- rt = rt_route(raddr, NULL);
- if (rt == NULL)
- {
- DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));
- /* Tell the sender its packet cannot be delivered... */
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);
- return;
- }
- if (rt->rt_gateway != 0)
- raddr = rt->rt_gateway;
- }
- else
- raddr = iph->daddr;
- dev2 = rt->rt_dev;
+ /*
+ * Gosh. Not only is the packet valid; we even know how to
+ * forward it onto its final destination. Can we say this
+ * is being plain lucky?
+ * If the router told us that there is no GW, use the dest.
+ * IP address itself- we seem to be connected directly...
+ */
+ raddr = rt->rt_gateway;
+ if (raddr != 0) {
+ rt = rt_route(raddr, NULL);
+ if (rt == NULL) {
+ DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));
- /*
- * Never forward out on the same interface, its not allowed, its often not pretty either (except for on
- * source routing)
- */
- if (dev == dev2)
+ /* Tell the sender its packet cannot be delivered... */
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);
return;
- /*
- * We now allocate a new buffer, and copy the datagram into it.
- * If the indicated interface is up and running, kick it.
- */
- DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n",
+ }
+ if (rt->rt_gateway != 0) raddr = rt->rt_gateway;
+ } else raddr = iph->daddr;
+ dev2 = rt->rt_dev;
+
+
+ if (dev == dev2)
+ return;
+ /*
+ * We now allocate a new buffer, and copy the datagram into it.
+ * If the indicated interface is up and running, kick it.
+ */
+ DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n",
in_ntoa(raddr), dev2->name, skb->len));
- if (dev2->flags & IFF_UP)
- {
- skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +
+ if (dev2->flags & IFF_UP) {
+ skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +
dev2->hard_header_len + skb->len, GFP_ATOMIC);
- if (skb2 == NULL)
- {
- printk("\nIP: No memory available for IP forward\n");
- return;
- }
- ptr = (unsigned char *)(skb2 + 1);
- skb2->sk = NULL;
- skb2->free = 1;
- skb2->len = skb->len + dev2->hard_header_len;
- skb2->next = NULL;
- skb2->h.raw = ptr;
-
- /* Copy the packet data into the new buffer. */
- memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len);
+ if (skb2 == NULL) {
+ printk("\nIP: No memory available for IP forward\n");
+ return;
+ }
+ ptr = (unsigned char *)(skb2 + 1);
+ skb2->sk = NULL;
+ skb2->free = 1;
+ skb2->len = skb->len + dev2->hard_header_len;
+ skb2->mem_addr = skb2;
+ skb2->mem_len = sizeof(struct sk_buff) + skb2->len;
+ skb2->next = NULL;
+ skb2->h.raw = ptr;
+
+ /* Copy the packet data into the new buffer. */
+ memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len);
- /* Now build the MAC header. */
- (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);
+ /* Now build the MAC header. */
+ (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);
- if(skb2->len > dev2->mtu)
- {
- ip_fragment(NULL,skb2,dev2, is_frag);
- kfree_skb(skb2,FREE_WRITE);
- }
- else
- dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL);
+ if(skb2->len > dev2->mtu)
+ {
+ ip_fragment(NULL,skb2,dev2, is_frag);
+ kfree_skb(skb2,FREE_WRITE);
}
+ else
+ dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL);
+ }
}
#endif
-
-/*
- * This function receives all incoming IP datagrams.
- */
-
-int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+/* This function receives all incoming IP datagrams. */
+int
+ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- struct iphdr *iph = skb->h.iph;
- unsigned char hash;
- unsigned char flag = 0;
- unsigned char opts_p = 0; /* Set iff the packet has options. */
- struct inet_protocol *ipprot;
- struct options *opt=NULL;
-
- int brd;
- int is_frag=0;
-
- DPRINTF((DBG_IP, "<<\n"));
-
- /* Is the datagram acceptable? */
- if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)
- {
- DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
- DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
- DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- if (iph->ihl != 5)
- { /* Fast path for the typical optionless IP packet. */
-#ifdef IP_DEBUG
- ip_print(iph); /* Bogus, only for debugging. */
-#endif
- if (do_options(iph, &opt,dev) != 0)
- {
- if(opt)
- kfree(opt);
- return 0;
- }
-/* skb->ip_options=opt_ptr;*/
- kfree(opt);
- opt = NULL;
- opts_p = 0/*1*/;
- }
-
- if (iph->frag_off & 0x0020)
- is_frag|=1;
- if (ntohs(iph->frag_off) & 0x1fff)
- is_frag|=2;
-
- /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */
- if ((brd = chk_addr(iph->daddr)) == 0)
- {
+ struct iphdr *iph = skb->h.iph;
+ unsigned char hash;
+ unsigned char flag = 0;
+ unsigned char opts_p = 0; /* Set iff the packet has options. */
+ struct inet_protocol *ipprot;
+ static struct options opt; /* since we don't use these yet, and they
+ take up stack space. */
+ int brd;
+ int is_frag=0;
+
+ DPRINTF((DBG_IP, "<<\n"));
+
+ /* Is the datagram acceptable? */
+ if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) {
+ DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
+ DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
+ DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+
+ if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */
+ ip_print(iph); /* Bogus, only for debugging. */
+ memset((char *) &opt, 0, sizeof(opt));
+ if (do_options(iph, &opt) != 0)
+ return 0;
+ opts_p = 1;
+ }
+
+ if (iph->frag_off & 0x0020)
+ is_frag|=1;
+ if (ntohs(iph->frag_off) & 0x1fff)
+ is_frag|=2;
+
+ /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */
+ if ((brd = chk_addr(iph->daddr)) == 0) {
#ifdef CONFIG_IP_FORWARD
- ip_forward(skb, dev, is_frag);
+ ip_forward(skb, dev, is_frag);
#else
- printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n",
+ printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n",
iph->saddr,iph->daddr);
#endif
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
/*
* Reassemble IP fragments.
*/
- if(is_frag)
- {
+ if(is_frag)
+ {
#ifdef CONFIG_IP_DEFRAG
- skb=ip_defrag(iph,skb,dev);
- if(skb==NULL)
- {
- return 0;
- }
- iph=skb->h.iph;
+ skb=ip_defrag(iph,skb,dev);
+ if(skb==NULL)
+ {
+ return 0;
+ }
+ iph=skb->h.iph;
#else
- printk("\nIP: *** datagram fragmentation not yet implemented ***\n");
- printk(" SRC = %s ", in_ntoa(iph->saddr));
- printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr));
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
+ printk("\nIP: *** datagram fragmentation not yet implemented ***\n");
+ printk(" SRC = %s ", in_ntoa(iph->saddr));
+ printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr));
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
#endif
- }
+ }
- /* 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);
-
- /* Find someone to deliver it too */
-
- for (ipprot = (struct inet_protocol *)inet_protos[hash];
- ipprot != NULL;
- ipprot=(struct inet_protocol *)ipprot->next)
- {
- struct sk_buff *skb2;
- if (ipprot->protocol != iph->protocol)
- continue;
- DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot));
- print_ipprot(ipprot);
+ if(brd==IS_INVBCAST)
+ {
+/* printk("Invalid broadcast address from %x [target %x] (Probably they have a wrong netmask)\n",
+ iph->saddr,iph->daddr);*/
+ skb->sk=NULL;
+ kfree_skb(skb,FREE_WRITE);
+ return(0);
+ }
+
+ /* Point into the IP datagram, just past the header. */
+ skb->h.raw += iph->ihl*4;
+ hash = iph->protocol & (MAX_INET_PROTOS -1);
+ for (ipprot = (struct inet_protocol *)inet_protos[hash];
+ ipprot != NULL;
+ ipprot=(struct inet_protocol *)ipprot->next)
+ {
+ struct sk_buff *skb2;
+
+ if (ipprot->protocol != iph->protocol) continue;
+ DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot));
+ print_ipprot(ipprot);
/*
* See if we need to make a copy of it. This will
* only be set if more than one protocol wants it.
* and then not for the last one.
*/
- if (ipprot->copy)
- {
- skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
- if (skb2 == NULL)
- continue;
- memcpy(skb2, skb, skb->mem_len);
- skb2->mem_addr = skb2;
- skb2->h.raw = (unsigned char *)(
+ if (ipprot->copy) {
+ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
+ if (skb2 == NULL)
+ continue;
+ memcpy(skb2, skb, skb->mem_len);
+ skb2->mem_addr = skb2;
+ skb2->h.raw = (unsigned char *)(
(unsigned long)skb2 +
(unsigned long) skb->h.raw -
(unsigned long)skb);
- skb2->free=1;
- }
- else
- {
- skb2 = skb;
- }
- flag = 1;
+ skb2->free=1;
+ } else {
+ skb2 = skb;
+ }
+ flag = 1;
- /*
- * Pass on the datagram to each protocol that wants it,
- * based on the datagram protocol. We should really
- * check the protocol handler's return values here...
- */
- ipprot->handler(skb2, dev, opts_p ? opt : 0, iph->daddr,
+ /*
+ * Pass on the datagram to each protocol that wants it,
+ * based on the datagram protocol. We should really
+ * check the protocol handler's return values here...
+ */
+ ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,
(ntohs(iph->tot_len) - (iph->ihl * 4)),
iph->saddr, 0, ipprot);
- }
+ }
/*
* All protocols checked.
@@ -1490,15 +1317,14 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* causes (proven, grin) ARP storms and a leakage of memory (i.e. all
* ICMP reply messages get queued up for transmission...)
*/
- if (!flag)
- {
- if (brd != IS_BROADCAST)
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- }
+ if (!flag) {
+ if (brd != IS_BROADCAST)
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ }
- return(0);
+ return(0);
}
@@ -1509,174 +1335,148 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* This routine also needs to put in the total length, and
* compute the checksum.
*/
-void ip_queue_xmit(struct sock *sk, struct device *dev,
+void
+ip_queue_xmit(struct sock *sk, struct device *dev,
struct sk_buff *skb, int free)
{
- struct iphdr *iph;
- unsigned char *ptr;
-
- if (sk == NULL)
- free = 1;
- if (dev == NULL)
- {
- printk("IP: ip_queue_xmit dev = NULL\n");
- return;
- }
- IS_SKB(skb);
- skb->free = free;
- skb->dev = dev;
- skb->when = jiffies;
+ struct iphdr *iph;
+ unsigned char *ptr;
+
+ if (sk == NULL) free = 1;
+ if (dev == NULL) {
+ printk("IP: ip_queue_xmit dev = NULL\n");
+ return;
+ }
+ IS_SKB(skb);
+ skb->free = free;
+ skb->dev = dev;
+ skb->when = jiffies;
- DPRINTF((DBG_IP, ">>\n"));
- ptr = (unsigned char *)(skb + 1);
- ptr += dev->hard_header_len;
- iph = (struct iphdr *)ptr;
- iph->tot_len = ntohs(skb->len-dev->hard_header_len);
-
- if(skb->len > dev->mtu)
- {
-/* printk("Fragment!\n");*/
- ip_fragment(sk,skb,dev,0);
- IS_SKB(skb);
- kfree_skb(skb,FREE_WRITE);
- return;
- }
+ DPRINTF((DBG_IP, ">>\n"));
+ ptr = (unsigned char *)(skb + 1);
+ ptr += dev->hard_header_len;
+ iph = (struct iphdr *)ptr;
+ iph->tot_len = ntohs(skb->len-dev->hard_header_len);
+
+ if(skb->len > dev->mtu)
+ {
+/* printk("Fragment!\n");*/
+ ip_fragment(sk,skb,dev,0);
+ IS_SKB(skb);
+ kfree_skb(skb,FREE_WRITE);
+ return;
+ }
- ip_send_check(iph);
-#ifdef IP_DEBUG
- ip_print(iph);
-#endif
- skb->next = NULL;
-
- /* See if this is the one trashing our queue. Ross? */
- skb->magic = 1;
- if (!free)
- {
- skb->link3 = NULL;
- sk->packets_out++;
- cli();
- if (sk->send_head == NULL)
- {
+ ip_send_check(iph);
+ ip_print(iph);
+ skb->next = NULL;
+
+ /* See if this is the one trashing our queue. Ross? */
+ skb->magic = 1;
+ if (!free) {
+ skb->link3 = NULL;
+ sk->packets_out++;
+ cli();
+ if (sk->send_head == NULL) {
+ sk->send_tail = skb;
+ sk->send_head = skb;
+ } else {
+ /* See if we've got a problem. */
+ if (sk->send_tail == NULL) {
+ printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");
+ sort_send(sk);
+ } else {
+ sk->send_tail->link3 = skb;
sk->send_tail = skb;
- sk->send_head = skb;
- }
- else
- {
- /* See if we've got a problem. */
- if (sk->send_tail == NULL)
- {
- printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");
- sort_send(sk);
- }
- else
- {
- sk->send_tail->link3 = skb;
- sk->send_tail = skb;
- }
}
- sti();
- reset_timer(sk, TIME_WRITE,
- backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
- }
- else
- {
- skb->sk = sk;
}
-
- /* If the indicated interface is up and running, kick it. */
- if (dev->flags & IFF_UP)
- {
- if (sk != NULL)
- {
- dev->queue_xmit(skb, dev, sk->priority);
- }
- else
- {
- dev->queue_xmit(skb, dev, SOPRI_NORMAL);
- }
+ sti();
+ reset_timer(sk, TIME_WRITE,
+ backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ } else {
+ skb->sk = sk;
+ }
+
+ /* If the indicated interface is up and running, kick it. */
+ if (dev->flags & IFF_UP) {
+ if (sk != NULL) {
+ dev->queue_xmit(skb, dev, sk->priority);
}
- else
- {
- if (free) kfree_skb(skb, FREE_WRITE);
+ else {
+ dev->queue_xmit(skb, dev, SOPRI_NORMAL);
}
+ } else {
+ if (free) kfree_skb(skb, FREE_WRITE);
+ }
}
-void ip_retransmit(struct sock *sk, int all)
+void
+ip_retransmit(struct sock *sk, int all)
{
- struct sk_buff * skb;
- struct proto *prot;
- struct device *dev;
-
- prot = sk->prot;
- skb = sk->send_head;
- while (skb != NULL)
+ struct sk_buff * skb;
+ struct proto *prot;
+ struct device *dev;
+
+ prot = sk->prot;
+ skb = sk->send_head;
+ while (skb != NULL) {
+ dev = skb->dev;
+ /* I know this can't happen but as it does.. */
+ if(dev==NULL)
{
- dev = skb->dev;
- /* I know this can't happen but as it does.. */
- if(dev==NULL)
- {
- printk("ip_retransmit: NULL device bug!\n");
- goto oops;
- }
-
- IS_SKB(skb);
-
- /*
- * The rebuild_header function sees if the ARP is done.
- * If not it sends a new ARP request, and if so it builds
- * the header.
- */
- cli(); /* We might get interrupted by an arp reply here and fill
- the frame in twice. Because of the technique used this
- would be a little sad */
- if (!skb->arp)
- {
- if (dev->rebuild_header(skb+1, dev))
- {
- sti(); /* Failed to rebuild - next */
- if (!all)
- break;
- skb = (struct sk_buff *)skb->link3;
- continue;
- }
- }
- skb->arp = 1;
- sti();
- skb->when = jiffies;
+ printk("ip_retransmit: NULL device bug!\n");
+ goto oops;
+ }
+
+ IS_SKB(skb);
- /* If the interface is (still) up and running, kick it. */
- if (dev->flags & IFF_UP)
- {
- if (sk)
- dev->queue_xmit(skb, dev, sk->priority);
+ /*
+ * The rebuild_header function sees if the ARP is done.
+ * If not it sends a new ARP request, and if so it builds
+ * the header.
+ */
+ cli(); /* We might get interrupted by an arp reply here and fill
+ the frame in twice. Because of the technique used this
+ would be a little sad */
+ if (!skb->arp) {
+ if (dev->rebuild_header(skb+1, dev)) {
+ sti(); /* Failed to rebuild - next */
+ if (!all) break;
+ skb = (struct sk_buff *)skb->link3;
+ continue;
}
+ }
+ skb->arp = 1;
+ sti();
+ skb->when = jiffies;
-oops: sk->retransmits++;
- sk->prot->retransmits ++;
- if (!all)
- break;
-
- /* This should cut it off before we send too many packets. */
- if (sk->retransmits > sk->cong_window)
- break;
- skb = (struct sk_buff *)skb->link3;
+ /* If the interface is (still) up and running, kick it. */
+ if (dev->flags & IFF_UP) {
+ if (sk) dev->queue_xmit(skb, dev, sk->priority);
+ /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
+oops: sk->retransmits++;
+ sk->prot->retransmits ++;
+ if (!all) break;
+
+ /* This should cut it off before we send too many packets. */
+ if (sk->retransmits > sk->cong_window) break;
+ skb = (struct sk_buff *)skb->link3;
+ }
+
/*
* Increase the RTT time every time we retransmit.
* This will cause exponential back off on how hard we try to
* get through again. Once we get through, the rtt will settle
* back down reasonably quickly.
*/
- sk->backoff++;
- reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
-}
-
-/*
- * Backoff function - the subject of much research
- */
+ sk->backoff++;
+ reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+}
+/* Backoff function - the subject of much research */
int backoff(int n)
{
/* Use binary exponential up to retry #4, and quadratic after that
@@ -1704,73 +1504,3 @@ 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);
-}
diff --git a/net/inet/ip.h b/net/inet/ip.h
index 95daf2c..3c01cc8 100644
--- a/net/inet/ip.h
+++ b/net/inet/ip.h
@@ -21,8 +21,8 @@
#include <linux/ip.h>
-#include "sockinet.h"
+#include "sock.h" /* struct sock */
/* IP flags. */
#define IP_CE 0x8000 /* Flag: "Congestion" */
@@ -69,8 +69,7 @@ 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,
- int tos,int ttl);
+ struct options *opt, int len);
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);
@@ -78,6 +77,5 @@ 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 */
diff --git a/net/inet/loopback.c b/net/inet/loopback.c
index 949e41a..66203eb 100644
--- a/net/inet/loopback.c
+++ b/net/inet/loopback.c
@@ -5,77 +5,71 @@
*
* Pseudo-driver for the loopback interface.
*
- * Version: @(#)loopback.c 1.28 20/12/93
+ * Version: @(#)loopback.c 1.0.4b 08/16/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
*
- * This file should be in drivers/net, but our glorious leader
- * has put it here, and who are we to argue with the Linus 8-)
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
-#include <linux/tty.h>
#include <linux/types.h>
-#include <linux/ptrace.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/if_ether.h> /* For the statistics structure. */
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "arp.h"
-static int loopback_xmit(struct sk_buff *skb, struct device *dev)
+static int
+loopback_xmit(struct sk_buff *skb, struct device *dev)
{
- struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
- int done;
+ struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
+ int done;
- DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
- if (skb == NULL || dev == NULL)
- return(0);
+ DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
+ if (skb == NULL || dev == NULL) return(0);
- cli();
- if (dev->tbusy != 0)
- {
- sti();
- stats->tx_errors++;
- return(1);
- }
- dev->tbusy = 1;
- sti();
+ cli();
+ if (dev->tbusy != 0) {
+ sti();
+ stats->tx_errors++;
+ return(1);
+ }
+ dev->tbusy = 1;
+ sti();
- done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev);
- if (skb->free)
- kfree_skb(skb, FREE_WRITE);
+ done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev);
+ if (skb->free) kfree_skb(skb, FREE_WRITE);
- while (done != 1)
- {
- done = dev_rint(NULL, 0, 0, dev);
- }
- stats->tx_packets++;
+ while (done != 1) {
+ done = dev_rint(NULL, 0, 0, dev);
+ }
+ stats->tx_packets++;
- dev->tbusy = 0;
+ dev->tbusy = 0;
#if 1
__asm__("cmpl $0,_intr_count\n\t"
@@ -92,50 +86,52 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
: "ax", "dx", "cx");
#endif
- return(0);
+ return(0);
}
-static struct enet_statistics *get_stats(struct device *dev)
+static struct enet_statistics *
+get_stats(struct device *dev)
{
return (struct enet_statistics *)dev->priv;
}
/* Initialize the rest of the LOOPBACK device. */
-int loopback_init(struct device *dev)
+int
+loopback_init(struct device *dev)
{
- dev->mtu = 2000; /* MTU */
- dev->tbusy = 0;
- dev->hard_start_xmit = loopback_xmit;
- dev->open = NULL;
+ dev->mtu = 2000; /* MTU */
+ dev->tbusy = 0;
+ dev->hard_start_xmit = loopback_xmit;
+ dev->open = NULL;
#if 1
- dev->hard_header = eth_header;
- dev->add_arp = NULL;
- dev->hard_header_len = ETH_HLEN; /* 14 */
- dev->addr_len = ETH_ALEN; /* 6 */
- dev->type = ARPHRD_ETHER; /* 0x0001 */
- dev->type_trans = eth_type_trans;
- dev->rebuild_header = eth_rebuild_header;
+ dev->hard_header = eth_header;
+ dev->add_arp = NULL;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->type = ARPHRD_ETHER; /* 0x0001 */
+ dev->type_trans = eth_type_trans;
+ dev->rebuild_header = eth_rebuild_header;
#else
- dev->hard_header_length = 0;
- dev->add_arp = NULL;
- dev->addr_len = 0;
- dev->type = 0; /* loopback_type (0) */
- dev->hard_header = NULL;
- dev->type_trans = NULL;
- dev->rebuild_header = NULL;
+ dev->hard_header_length = 0;
+ dev->add_arp = NULL;
+ dev->addr_len = 0;
+ dev->type = 0; /* loopback_type (0) */
+ dev->hard_header = NULL;
+ dev->type_trans = NULL;
+ dev->rebuild_header = NULL;
#endif
- dev->queue_xmit = dev_queue_xmit;
+ dev->queue_xmit = dev_queue_xmit;
/* New-style flags. */
- dev->flags = IFF_LOOPBACK;
- dev->family = AF_INET;
- dev->pa_addr = in_aton("127.0.0.1");
- dev->pa_brdaddr = in_aton("127.255.255.255");
- dev->pa_mask = in_aton("255.0.0.0");
- dev->pa_alen = sizeof(unsigned long);
- dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct enet_statistics));
- dev->get_stats = get_stats;
+ dev->flags = IFF_LOOPBACK;
+ dev->family = AF_INET;
+ dev->pa_addr = in_aton("127.0.0.1");
+ dev->pa_brdaddr = in_aton("127.255.255.255");
+ dev->pa_mask = in_aton("255.0.0.0");
+ dev->pa_alen = sizeof(unsigned long);
+ dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct enet_statistics));
+ dev->get_stats = get_stats;
- return(0);
+ return(0);
};
diff --git a/net/inet/packet.c b/net/inet/packet.c
index 48b2184..c0585a6 100644
--- a/net/inet/packet.c
+++ b/net/inet/packet.c
@@ -5,7 +5,7 @@
*
* PACKET - implements raw packet sockets.
*
- * Version: @(#)packet.c 1.28 20/12/93
+ * Version: @(#)packet.c 1.0.6 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -18,7 +18,6 @@
* added. Also fixed the peek/read crash
* from all old Linux datagram code.
* Alan Cox : Uses the improved datagram code.
- * Alan Cox : Clean up for final release.
*
*
* This program is free software; you can redistribute it and/or
@@ -32,12 +31,12 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
@@ -45,152 +44,138 @@
#include "udp.h"
#include "raw.h"
-/*
- * I'm sure there should be one of these, not one every file.
- */
-static unsigned long min(unsigned long a, unsigned long b)
+static unsigned long
+min(unsigned long a, unsigned long b)
{
- if (a < b)
- return(a);
- return(b);
+ if (a < b) return(a);
+ return(b);
}
-/*
- * This should be the easiest of all, all we do is copy it into a buffer.
- */
-
-int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+/* This should be the easiest of all, all we do is copy it into a buffer. */
+int
+packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- struct sock *sk;
-
- sk = (struct sock *) pt->data;
- skb->dev = dev;
- skb->len += dev->hard_header_len;
-
- skb->sk = sk;
-
- /* Charge it too the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk->rmem_alloc += skb->mem_len;
- skb_queue_tail(&sk->rqueue,skb);
- release_sock(sk);
- sk->data_ready(sk,skb->len);
- return(0);
+ struct sock *sk;
+
+ sk = (struct sock *) pt->data;
+ skb->dev = dev;
+ skb->len += dev->hard_header_len;
+
+ skb->sk = sk;
+
+ /* Charge it too the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
+ skb_queue_tail(&sk->rqueue,skb);
+ wake_up(sk->sleep);
+ release_sock(sk);
+ return(0);
}
-/*
- * This will do terrible things if len + ipheader + devheader > dev->mtu
- * Since only root can use these thats okish...
- */
-
-static int packet_sendto(struct sock *sk, unsigned char *from, int len,
+/* This will do terrible things if len + ipheader + devheader > dev->mtu */
+static int
+packet_sendto(struct sock *sk, unsigned char *from, int len,
int noblock, unsigned flags, struct sockaddr_in *usin,
int addr_len)
{
- struct sk_buff *skb;
- struct device *dev;
- struct sockaddr saddr;
- int err;
-
- /* Check the flags. */
- if (flags)
- return(-EINVAL);
- if (len < 0)
- return(-EINVAL);
-
- /* Get and verify the address. */
- if (usin)
- {
- if (addr_len < sizeof(saddr))
- return(-EINVAL);
- err=verify_area(VERIFY_READ, usin, sizeof(saddr));
- if(err)
- return err;
- memcpy_fromfs(&saddr, usin, sizeof(saddr));
- }
- else
- return(-EINVAL);
+ struct sk_buff *skb;
+ struct device *dev;
+ struct sockaddr saddr;
+ int err;
+
+ /* Check the flags. */
+ if (flags) return(-EINVAL);
+ if (len < 0) return(-EINVAL);
+
+ /* Get and verify the address. */
+ if (usin) {
+ if (addr_len < sizeof(saddr)) return(-EINVAL);
+ err=verify_area(VERIFY_READ, usin, sizeof(saddr));
+ if(err)
+ return err;
+ memcpy_fromfs(&saddr, usin, sizeof(saddr));
+ } else
+ return(-EINVAL);
- err=verify_area(VERIFY_READ,from,len);
- if(err)
- return(err);
- /* Find the device first to size check it */
-
- saddr.sa_data[13] = 0;
- dev = dev_get(saddr.sa_data);
- if (dev == NULL)
- {
- return(-ENXIO);
- }
- if(len>dev->mtu)
- return -EMSGSIZE;
-
- /* Now allocate the buffer, knowing 4K pagelimits wont break this line */
- skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
-
- /* This shouldn't happen, but it could. */
- if (skb == NULL)
- {
- DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
- return(-ENOMEM);
- }
- /* Fill it in */
- skb->sk = sk;
- skb->free = 1;
- memcpy_fromfs (skb+1, from, len);
- skb->len = len;
- skb->next = NULL;
- if (dev->flags & IFF_UP)
- dev->queue_xmit(skb, dev, sk->priority);
- else
- kfree_skb(skb, FREE_WRITE);
- return(len);
+ err=verify_area(VERIFY_READ,from,len);
+ if(err)
+ return(err);
+/* Find the device first to size check it */
+
+ saddr.sa_data[13] = 0;
+ dev = dev_get(saddr.sa_data);
+ if (dev == NULL) {
+ return(-ENXIO);
+ }
+ if(len>dev->mtu)
+ return -EMSGSIZE;
+
+/* Now allocate the buffer, knowing 4K pagelimits wont break this line */
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
+
+ /* This shouldn't happen, but it could. */
+ if (skb == NULL) {
+ DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
+ return(-ENOMEM);
+ }
+ /* Fill it in */
+ skb->mem_addr = skb;
+ skb->mem_len = len + sizeof(*skb);
+ skb->sk = sk;
+ skb->free = 1;
+ memcpy_fromfs (skb+1, from, len);
+ skb->len = len;
+ skb->next = NULL;
+ if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority);
+ else kfree_skb(skb, FREE_WRITE);
+ return(len);
}
-static int packet_write(struct sock *sk, unsigned char *buff,
+static int
+packet_write(struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
- return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
+ return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
-static void packet_close(struct sock *sk, int timeout)
+static void
+packet_close(struct sock *sk, int timeout)
{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
- dev_remove_pack((struct packet_type *)sk->pair);
- kfree_s((void *)sk->pair, sizeof(struct packet_type));
- sk->pair = NULL;
- release_sock(sk);
+ sk->inuse = 1;
+ sk->state = TCP_CLOSE;
+ dev_remove_pack((struct packet_type *)sk->pair);
+ kfree_s((void *)sk->pair, sizeof(struct packet_type));
+ sk->pair = NULL;
+ release_sock(sk);
}
-static int packet_init(struct sock *sk)
+static int
+packet_init(struct sock *sk)
{
- struct packet_type *p;
+ struct packet_type *p;
- p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL)
- return(-ENOMEM);
+ p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p == NULL) return(-ENOMEM);
- p->func = packet_rcv;
- p->type = sk->num;
- p->data = (void *)sk;
- dev_add_pack(p);
-
- /* We need to remember this somewhere. */
- sk->pair = (struct sock *)p;
+ p->func = packet_rcv;
+ p->type = sk->num;
+ p->data = (void *)sk;
+ dev_add_pack(p);
+
+ /* We need to remember this somewhere. */
+ sk->pair = (struct sock *)p;
- return(0);
+ return(0);
}
@@ -198,95 +183,89 @@ static int packet_init(struct sock *sk)
* This should be easy, if there is something there
* we return it, otherwise we block.
*/
-int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
+int
+packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
- int copied=0;
- struct sk_buff *skb;
- struct sockaddr *saddr;
- int err;
-
- saddr = (struct sockaddr *)sin;
- if (len == 0)
- return(0);
- if (len < 0)
- return(-EINVAL);
-
- if (sk->shutdown & RCV_SHUTDOWN)
- return(0);
- if (addr_len)
- {
- err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
- if(err)
- return err;
- put_fs_long(sizeof(*saddr), addr_len);
- }
+ int copied=0;
+ struct sk_buff *skb;
+ struct sockaddr *saddr;
+ int err;
+
+ saddr = (struct sockaddr *)sin;
+ if (len == 0) return(0);
+ if (len < 0) return(-EINVAL);
+
+ if (sk->shutdown & RCV_SHUTDOWN) return(0);
+ if (addr_len) {
+ err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(err)
+ return err;
+ put_fs_long(sizeof(*saddr), addr_len);
+ }
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
- skb=skb_recv_datagram(sk,flags,noblock,&err);
- if(skb==NULL)
- return err;
- copied = min(len, skb->len);
-
- memcpy_tofs(to, skb+1, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */
-
- /* Copy the address. */
- if (saddr)
- {
- struct sockaddr addr;
-
- addr.sa_family = skb->dev->type;
- memcpy(addr.sa_data,skb->dev->name, 14);
- verify_area(VERIFY_WRITE, saddr, sizeof(*saddr));
- memcpy_tofs(saddr, &addr, sizeof(*saddr));
- }
-
- skb_free_datagram(skb); /* Its either been used up, or its a peek_copy anyway */
-
- release_sock(sk);
- return(copied);
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
+ copied = min(len, skb->len);
+
+ memcpy_tofs(to, skb+1, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */
+
+ /* Copy the address. */
+ if (saddr) {
+ struct sockaddr addr;
+
+ addr.sa_family = skb->dev->type;
+ memcpy(addr.sa_data,skb->dev->name, 14);
+ verify_area(VERIFY_WRITE, saddr, sizeof(*saddr));
+ memcpy_tofs(saddr, &addr, sizeof(*saddr));
+ }
+
+ skb_free_datagram(skb); /* Its either been used up, or its a peek_copy anyway */
+
+ release_sock(sk);
+ return(copied);
}
-int packet_read(struct sock *sk, unsigned char *buff,
+int
+packet_read(struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
- return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
+ return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
-struct proto packet_prot =
-{
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- packet_close,
- packet_read,
- packet_write,
- packet_sendto,
- packet_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- ip_retransmit,
- NULL,
- NULL,
- NULL,
- datagram_select,
- NULL,
- packet_init,
- NULL,
- NULL, /* No set/get socket options */
- NULL,
- 128,
- 0,
- {NULL,},
- "PACKET"
+struct proto packet_prot = {
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ packet_close,
+ packet_read,
+ packet_write,
+ packet_sendto,
+ packet_recvfrom,
+ ip_build_header,
+ udp_connect,
+ NULL,
+ ip_queue_xmit,
+ ip_retransmit,
+ NULL,
+ NULL,
+ NULL,
+ datagram_select,
+ NULL,
+ packet_init,
+ NULL,
+ 128,
+ 0,
+ {NULL,},
+ "PACKET"
};
diff --git a/net/inet/proc.c b/net/inet/proc.c
index 04ed9e8..d5bc16e 100644
--- a/net/inet/proc.c
+++ b/net/inet/proc.c
@@ -7,7 +7,7 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: @(#)proc.c 1.28 20/12/93
+ * Version: @(#)proc.c 1.0.5 05/27/93
*
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -18,7 +18,10 @@
* using hint flag for the netinfo.
* Pauline Middelink : Pidentd support
* Alan Cox : Make /proc safer.
- * Alan Cox : Final clean up.
+ *
+ * To Do:
+ * Put the creating userid in the proc/net/... files. This will
+ * allow us to write an RFC931 daemon for Linux
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -34,13 +37,13 @@
#include <linux/in.h>
#include <linux/param.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "udp.h"
-#include "socket/skbuff.h"
-#include "sockinet.h"
+#include "skbuff.h"
+#include "sock.h"
#include "raw.h"
/*
@@ -50,83 +53,81 @@
* As in get_unix_netinfo, the buffer might be too small. If this
* happens, get__netinfo returns only part of the available infos.
*/
-static int get__netinfo(struct proto *pro, char *buffer, int format)
+static int
+get__netinfo(struct proto *pro, char *buffer, int format)
{
- struct sock **s_array;
- struct sock *sp;
- char *pos=buffer;
- int i;
- int timer_active;
- unsigned long dest, src;
- unsigned short destp, srcp;
-
- s_array = pro->sock_array;
- pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n");
+ struct sock **s_array;
+ struct sock *sp;
+ char *pos=buffer;
+ int i;
+ int timer_active;
+ unsigned long dest, src;
+ unsigned short destp, srcp;
+
+ s_array = pro->sock_array;
+ pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n");
/*
* This was very pretty but didn't work when a socket is destroyed at the wrong moment
* (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing
* with timers we just concede defeat and cli().
*/
- for(i = 0; i < SOCK_ARRAY_SIZE; i++)
- {
- cli();
- sp = s_array[i];
- while(sp != NULL)
- {
- dest = sp->daddr;
- src = sp->saddr;
- destp = sp->dummy_th.dest;
- srcp = sp->dummy_th.source;
+ for(i = 0; i < SOCK_ARRAY_SIZE; i++) {
+ cli();
+ sp = s_array[i];
+ while(sp != NULL) {
+ dest = sp->daddr;
+ src = sp->saddr;
+ destp = sp->dummy_th.dest;
+ srcp = sp->dummy_th.source;
- /* Since we are Little Endian we need to swap the bytes :-( */
- destp = ntohs(destp);
- srcp = ntohs(srcp);
- timer_active = del_timer(&sp->timer);
- if (!timer_active)
- sp->timer.expires = 0;
- pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n",
- i, src, srcp, dest, destp, sp->state,
- format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc,
- format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
- timer_active, sp->timer.expires, (unsigned) sp->retransmits,
- SOCK_INODE(sp->socket)->i_uid);
- if (timer_active)
- add_timer(&sp->timer);
- /* Is place in buffer too rare? then abort. */
- if (pos > buffer+PAGE_SIZE-80)
- {
- printk("oops, too many %s sockets for netinfo.\n",
+ /* Since we are Little Endian we need to swap the bytes :-( */
+ destp = ntohs(destp);
+ srcp = ntohs(srcp);
+ timer_active = del_timer(&sp->timer);
+ if (!timer_active)
+ sp->timer.expires = 0;
+ pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n",
+ i, src, srcp, dest, destp, sp->state,
+ format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc,
+ format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
+ timer_active, sp->timer.expires, (unsigned) sp->retransmits,
+ SOCK_INODE(sp->socket)->i_uid);
+ if (timer_active)
+ add_timer(&sp->timer);
+ /* Is place in buffer too rare? then abort. */
+ if (pos > buffer+PAGE_SIZE-80) {
+ printk("oops, too many %s sockets for netinfo.\n",
pro->name);
- return(strlen(buffer));
- }
-
- /*
- * All sockets with (port mod SOCK_ARRAY_SIZE) = i
- * are kept in sock_array[i], so we must follow the
- * 'next' link to get them all.
- */
- sp = sp->next;
+ return(strlen(buffer));
}
- sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up
+
+ /*
+ * All sockets with (port mod SOCK_ARRAY_SIZE) = i
+ * are kept in sock_array[i], so we must follow the
+ * 'next' link to get them all.
+ */
+ sp = sp->next;
+ }
+ sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up
before this will clear before we jump back and cli, so its not as bad as it looks */
- }
- return(strlen(buffer));
+ }
+ return(strlen(buffer));
}
int tcp_get_info(char *buffer)
{
- return get__netinfo(&tcp_prot, buffer,0);
+ return get__netinfo(&tcp_prot, buffer,0);
}
int udp_get_info(char *buffer)
{
- return get__netinfo(&udp_prot, buffer,1);
+ return get__netinfo(&udp_prot, buffer,1);
}
int raw_get_info(char *buffer)
{
- return get__netinfo(&raw_prot, buffer,1);
+ return get__netinfo(&raw_prot, buffer,1);
}
diff --git a/net/inet/protocol.c b/net/inet/protocol.c
index b6390db..5690267 100644
--- a/net/inet/protocol.c
+++ b/net/inet/protocol.c
@@ -5,7 +5,7 @@
*
* INET protocol dispatch tables.
*
- * Version: @(#)protocol.c 1.28 20/12/93
+ * Version: @(#)protocol.c 1.0.5 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -14,8 +14,7 @@
* Alan Cox : Ahah! udp icmp errors don't work because
* udp_err is never called!
* Alan Cox : Added new fields for init and ready for
- * proper fragmentation (_NO_ 4K limits!).
- * Alan Cox : Final clean up.
+ * proper fragmentation (_NO_ 4K limits!)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -31,143 +30,132 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
-#include "socket/skbuff.h"
-#include "sockinet.h"
+#include "skbuff.h"
+#include "sock.h"
#include "icmp.h"
#include "udp.h"
-static struct inet_protocol tcp_protocol =
-{
- tcp_rcv, /* TCP handler */
- NULL, /* No fragment handler (and won't be for a long time) */
- tcp_err, /* TCP error control */
- NULL, /* next */
- IPPROTO_TCP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "TCP" /* name */
+static struct inet_protocol tcp_protocol = {
+ tcp_rcv, /* TCP handler */
+ NULL, /* No fragment handler (and won't be for a long time) */
+ tcp_err, /* TCP error control */
+ NULL, /* next */
+ IPPROTO_TCP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "TCP" /* name */
};
-static struct inet_protocol udp_protocol =
-{
- udp_rcv, /* UDP handler */
- NULL, /* Will be UDP fraglist handler */
- udp_err, /* UDP error control */
- &tcp_protocol, /* next */
- IPPROTO_UDP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "UDP" /* name */
+static struct inet_protocol udp_protocol = {
+ udp_rcv, /* UDP handler */
+ NULL, /* Will be UDP fraglist handler */
+ udp_err, /* UDP error control */
+ &tcp_protocol, /* next */
+ IPPROTO_UDP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "UDP" /* name */
};
-static struct inet_protocol icmp_protocol =
-{
- icmp_rcv, /* ICMP handler */
- NULL, /* ICMP never fragments anyway */
- NULL, /* ICMP error control */
- &udp_protocol, /* next */
- IPPROTO_ICMP, /* protocol ID */
- 0, /* copy */
- NULL, /* data */
- "ICMP" /* name */
+static struct inet_protocol icmp_protocol = {
+ icmp_rcv, /* ICMP handler */
+ NULL, /* ICMP never fragments anyway */
+ NULL, /* ICMP error control */
+ &udp_protocol, /* next */
+ IPPROTO_ICMP, /* protocol ID */
+ 0, /* copy */
+ NULL, /* data */
+ "ICMP" /* name */
};
struct inet_protocol *inet_protocol_base = &icmp_protocol;
-
-struct inet_protocol *inet_protos[MAX_INET_PROTOS] =
-{
- NULL
+struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
+ NULL
};
-struct inet_protocol *inet_get_protocol(unsigned char prot)
+struct inet_protocol *
+inet_get_protocol(unsigned char prot)
{
- unsigned char hash;
- struct inet_protocol *p;
-
- DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
- hash = prot & (MAX_INET_PROTOS - 1);
- for (p = inet_protos[hash] ; p != NULL; p=p->next)
- {
- DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
- if (p->protocol == prot)
- return((struct inet_protocol *) p);
- }
- return(NULL);
+ unsigned char hash;
+ struct inet_protocol *p;
+
+ DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
+ hash = prot & (MAX_INET_PROTOS - 1);
+ for (p = inet_protos[hash] ; p != NULL; p=p->next) {
+ DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
+ if (p->protocol == prot) return((struct inet_protocol *) p);
+ }
+ return(NULL);
}
-void inet_add_protocol(struct inet_protocol *prot)
+void
+inet_add_protocol(struct inet_protocol *prot)
{
- unsigned char hash;
- struct inet_protocol *p2;
-
- hash = prot->protocol & (MAX_INET_PROTOS - 1);
- prot ->next = inet_protos[hash];
- inet_protos[hash] = prot;
- prot->copy = 0;
-
- /* Set the copy bit if we need to. */
- p2 = (struct inet_protocol *) prot->next;
- while(p2 != NULL)
- {
- if (p2->protocol == prot->protocol)
- {
- prot->copy = 1;
- break;
- }
- p2 = (struct inet_protocol *) prot->next;
- }
+ unsigned char hash;
+ struct inet_protocol *p2;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ prot ->next = inet_protos[hash];
+ inet_protos[hash] = prot;
+ prot->copy = 0;
+
+ /* Set the copy bit if we need to. */
+ p2 = (struct inet_protocol *) prot->next;
+ while(p2 != NULL) {
+ if (p2->protocol == prot->protocol) {
+ prot->copy = 1;
+ break;
+ }
+ p2 = (struct inet_protocol *) prot->next;
+ }
}
-int inet_del_protocol(struct inet_protocol *prot)
+int
+inet_del_protocol(struct inet_protocol *prot)
{
- struct inet_protocol *p;
- struct inet_protocol *lp = NULL;
- unsigned char hash;
-
- hash = prot->protocol & (MAX_INET_PROTOS - 1);
- if (prot == inet_protos[hash])
- {
- inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
- return(0);
- }
-
- p = (struct inet_protocol *) inet_protos[hash];
- while(p != NULL)
- {
+ struct inet_protocol *p;
+ struct inet_protocol *lp = NULL;
+ unsigned char hash;
+
+ hash = prot->protocol & (MAX_INET_PROTOS - 1);
+ if (prot == inet_protos[hash]) {
+ inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
+ return(0);
+ }
+
+ p = (struct inet_protocol *) inet_protos[hash];
+ while(p != NULL) {
+ /*
+ * We have to worry if the protocol being deleted is
+ * the last one on the list, then we may need to reset
+ * someones copied bit.
+ */
+ if (p->next != NULL && p->next == prot) {
/*
- * We have to worry if the protocol being deleted is
- * the last one on the list, then we may need to reset
- * someones copied bit.
+ * if we are the last one with this protocol and
+ * there is a previous one, reset its copy bit.
*/
- if (p->next != NULL && p->next == prot)
- {
- /*
- * if we are the last one with this protocol and
- * there is a previous one, reset its copy bit.
- */
- if (p->copy == 0 && lp != NULL)
- lp->copy = 0;
- p->next = prot->next;
- return(0);
- }
-
- if (p->next != NULL && p->next->protocol == prot->protocol)
- {
- lp = p;
- }
-
- p = (struct inet_protocol *) p->next;
- }
- return(-1);
+ if (p->copy == 0 && lp != NULL) lp->copy = 0;
+ p->next = prot->next;
+ return(0);
+ }
+
+ if (p->next != NULL && p->next->protocol == prot->protocol) {
+ lp = p;
+ }
+
+ p = (struct inet_protocol *) p->next;
+ }
+ return(-1);
}
diff --git a/net/inet/raw.c b/net/inet/raw.c
index aa56a3c..7533532 100644
--- a/net/inet/raw.c
+++ b/net/inet/raw.c
@@ -5,7 +5,7 @@
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: @(#)raw.c 1.28 20/12/93
+ * Version: @(#)raw.c 1.0.4 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -19,16 +19,12 @@
* Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too
- * Alan Cox : Cleaned up and reformatted for final release
- * Alan Cox : Added socket option call to proto
- * Alan Cox : Corrected broadcast check error to EACCES
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/types.h>
@@ -41,301 +37,269 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "icmp.h"
#include "udp.h"
-static unsigned long min(unsigned long a, unsigned long b)
+static unsigned long
+min(unsigned long a, unsigned long b)
{
- if (a < b)
- return(a);
- return(b);
+ if (a < b) return(a);
+ return(b);
}
-/*
- * raw_err gets called by the icmp module.
- */
-
-void raw_err (int err, unsigned char *header, unsigned long daddr,
+/* raw_err gets called by the icmp module. */
+void
+raw_err (int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
- struct sock *sk;
+ struct sock *sk;
- DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n",
+ DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n",
err, header, daddr, saddr, protocol));
- if (protocol == NULL)
- return;
-
- sk = (struct sock *) protocol->data;
- if (sk == NULL)
- return;
+ if (protocol == NULL) return;
+ sk = (struct sock *) protocol->data;
+ if (sk == NULL) return;
- /* This is meaningless in raw sockets. */
+ /* This is meaningless in raw sockets. */
+ if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) {
+ if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
+ return;
+ }
- if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8))
- {
- if (sk->cong_window > 1)
- sk->cong_window = sk->cong_window/2;
- return;
- }
-
- sk->err = icmp_err_convert[err & 0xff].errno;
- sk->error_report(sk);
- return;
+ sk->err = icmp_err_convert[err & 0xff].errno;
+ wake_up(sk->sleep);
+
+ return;
}
/*
- * This should be the easiest of all, all we do is\
- * copy it into a buffer. We do have to diddle the pointer
- * to get the ip header too.
+ * This should be the easiest of all, all we do is\
+ * copy it into a buffer.
*/
-
-int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+int
+raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long saddr,
int redo, struct inet_protocol *protocol)
{
- struct sock *sk;
-
- DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n"
- " len=%d, saddr=%X, redo=%d, protocol=%X)\n",
- skb, dev, opt, daddr, len, saddr, redo, protocol));
-
- if (skb == NULL)
- return(0);
-
- if (protocol == NULL)
- {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk = (struct sock *) protocol->data;
- if (sk == NULL)
- {
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- /* Now we need to copy this into memory. */
- skb->sk = sk;
- /*
- * Adjust to get the header back
- */
-
- skb->len += skb->ip_hdr->ihl*sizeof(long);
- skb->h.iph = skb->ip_hdr;
- skb->dev = dev;
- skb->saddr = daddr;
- skb->daddr = saddr;
-
- /* Charge it too the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk->rmem_alloc += skb->mem_len;
- skb_queue_tail(&sk->rqueue,skb);
- release_sock(sk);
- sk->data_ready(sk,skb->len);
- return(0);
+ struct sock *sk;
+
+ DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n"
+ " len=%d, saddr=%X, redo=%d, protocol=%X)\n",
+ skb, dev, opt, daddr, len, saddr, redo, protocol));
+
+ if (skb == NULL) return(0);
+ if (protocol == NULL) {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+ sk = (struct sock *) protocol->data;
+ if (sk == NULL) {
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ /* Now we need to copy this into memory. */
+ skb->sk = sk;
+ skb->len = len;
+ skb->dev = dev;
+ skb->saddr = daddr;
+ skb->daddr = saddr;
+
+ /* Charge it too the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
+ skb_queue_tail(&sk->rqueue,skb);
+ wake_up(sk->sleep);
+ release_sock(sk);
+ return(0);
}
-/*
- * Send a RAW IP packet (user level IP protocols). Root only
- * caller provides IP header.
- */
-
-static int raw_sendto(struct sock *sk, unsigned char *from, int len,
+/* This will do terrible things if len + ipheader + devheader > dev->mtu */
+static int
+raw_sendto(struct sock *sk, unsigned char *from, int len,
int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
- struct sk_buff *skb;
- struct device *dev=NULL;
- struct sockaddr_in sin;
- int tmp;
- int err;
-
- DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
- " usin=%X, addr_len = %d)\n", sk, from, len, noblock,
- flags, usin, addr_len));
-
- /* Check the flags. */
- if (flags)
- return(-EINVAL);
- if (len < 0)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ,from,len);
- if(err)
- return err;
- /* Get and verify the address. */
- if (usin)
- {
- if (addr_len < sizeof(sin))
- return(-EINVAL);
- err=verify_area (VERIFY_READ, usin, sizeof (sin));
- if(err)
- return err;
- memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EINVAL);
- }
- else
- {
- if (sk->state != TCP_ESTABLISHED)
- return(-EINVAL);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->protocol;
- sin.sin_addr.s_addr = sk->daddr;
- }
- if (sin.sin_port == 0)
- sin.sin_port = sk->protocol;
+ struct sk_buff *skb;
+ struct device *dev=NULL;
+ struct sockaddr_in sin;
+ int tmp;
+ int err;
+
+ DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
+ " usin=%X, addr_len = %d)\n", sk, from, len, noblock,
+ flags, usin, addr_len));
+
+ /* Check the flags. */
+ if (flags) return(-EINVAL);
+ if (len < 0) return(-EINVAL);
+
+ err=verify_area(VERIFY_READ,from,len);
+ if(err)
+ return err;
+ /* Get and verify the address. */
+ if (usin) {
+ if (addr_len < sizeof(sin)) return(-EINVAL);
+ err=verify_area (VERIFY_READ, usin, sizeof (sin));
+ if(err)
+ return err;
+ memcpy_fromfs(&sin, usin, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
+ } else {
+ if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = sk->protocol;
+ sin.sin_addr.s_addr = sk->daddr;
+ }
+ if (sin.sin_port == 0) sin.sin_port = sk->protocol;
- if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -EACCES;
+ if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -ENETUNREACH;
- sk->inuse = 1;
- skb = NULL;
- while (skb == NULL)
+ sk->inuse = 1;
+ skb = NULL;
+ while (skb == NULL) {
+ if(sk->err!=0)
{
- if(sk->err!=0)
- {
- err= -sk->err;
- sk->err=0;
- release_sock(sk);
- return(err);
- }
+ err= -sk->err;
+ sk->err=0;
+ release_sock(sk);
+ return(err);
+ }
- skb = (struct sk_buff *) sk->prot->wmalloc(sk,
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk,
len+sizeof(*skb) + sk->prot->max_header,
0, GFP_KERNEL);
- if (skb == NULL)
- {
- int tmp;
-
- DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
- if (noblock)
- return(-EAGAIN);
- tmp = sk->wmem_alloc;
- release_sock(sk);
- cli();
- if (tmp <= sk->wmem_alloc)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- return(-ERESTARTSYS);
- }
+ if (skb == NULL) {
+ int tmp;
+
+ DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
+ if (noblock)
+ return(-EAGAIN);
+ tmp = sk->wmem_alloc;
+ release_sock(sk);
+ cli();
+ if (tmp <= sk->wmem_alloc) {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked) {
+ sti();
+ return(-ERESTARTSYS);
}
- sk->inuse = 1;
- sti();
}
- }
- skb->sk = sk;
-
- skb->free = 1; /* these two should be unecessary. */
- skb->arp = 0;
-
- tmp = sk->prot->build_header(skb, sk->saddr,
+ sk->inuse = 1;
+ sti();
+ }
+ }
+ skb->mem_addr = skb;
+ skb->mem_len = len + sizeof(*skb) +sk->prot->max_header;
+ skb->sk = sk;
+
+ skb->free = 1; /* these two should be unecessary. */
+ skb->arp = 0;
+
+ tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev,
- sk->protocol, sk->opt, skb->mem_len,
- sk->ip_ttl,sk->ip_tos);
- if (tmp < 0)
- {
- DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
- kfree_skb(skb,FREE_WRITE);
- release_sock(sk);
- return(tmp);
- }
-
- memcpy_fromfs ((unsigned char *)(skb+1)+tmp, from, len);
-
- /* If we are using IPPROTO_RAW, we need to fill in the source address in
- the IP header */
-
- if(sk->protocol==IPPROTO_RAW)
- {
- unsigned char *buff;
- struct iphdr *iph;
-
- buff = (unsigned char *)(skb + 1);
- buff += tmp;
- iph = (struct iphdr *)buff;
- iph->saddr = sk->saddr;
- }
-
- skb->len = tmp + len;
-
- if(dev!=NULL && skb->len > 4095)
- {
- kfree_skb(skb, FREE_WRITE);
- release_sock(sk);
- return(-EMSGSIZE);
- }
+ sk->protocol, sk->opt, skb->mem_len);
+ if (tmp < 0) {
+ DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
+ kfree_skb(skb,FREE_WRITE);
+ release_sock(sk);
+ return(tmp);
+ }
+
+ /* verify_area(VERIFY_WRITE, from, len);*/
+ memcpy_fromfs ((unsigned char *)(skb+1)+tmp, from, len);
+
+ /* If we are using IPPROTO_RAW, we need to fill in the source address in
+ the IP header */
+
+ if(sk->protocol==IPPROTO_RAW) {
+ unsigned char *buff;
+ struct iphdr *iph;
+
+ buff = (unsigned char *)(skb + 1);
+ buff += tmp;
+ iph = (struct iphdr *)buff;
+ iph->saddr = sk->saddr;
+ }
+
+ skb->len = tmp + len;
- sk->prot->queue_xmit(sk, dev, skb, 1);
+ if(dev!=NULL && skb->len > 4095)
+ {
+ kfree_skb(skb, FREE_WRITE);
release_sock(sk);
- return(len);
+ return(-EMSGSIZE);
+ }
+
+ sk->prot->queue_xmit(sk, dev, skb, 1);
+ release_sock(sk);
+ return(len);
}
-static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
+static int
+raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
+ return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
-static void raw_close(struct sock *sk, int timeout)
+static void
+raw_close(struct sock *sk, int timeout)
{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
+ sk->inuse = 1;
+ sk->state = TCP_CLOSE;
- DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
- ((struct inet_protocol *)sk->pair)->protocol));
+ DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
+ ((struct inet_protocol *)sk->pair)->protocol));
- if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
+ if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n"));
- kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
- sk->pair = NULL;
- release_sock(sk);
+ kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
+ sk->pair = NULL;
+ release_sock(sk);
}
-static int raw_init(struct sock *sk)
+static int
+raw_init(struct sock *sk)
{
- struct inet_protocol *p;
-
- p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
- if (p == NULL)
- return(-ENOMEM);
-
- p->handler = raw_rcv;
- p->protocol = sk->protocol;
- p->data = (void *)sk;
- p->err_handler = raw_err;
- p->name="USER";
- p->frag_handler = NULL; /* For now */
- inet_add_protocol(p);
+ struct inet_protocol *p;
+
+ p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
+ if (p == NULL) return(-ENOMEM);
+
+ p->handler = raw_rcv;
+ p->protocol = sk->protocol;
+ p->data = (void *)sk;
+ p->err_handler = raw_err;
+ p->name="USER";
+ p->frag_handler = NULL; /* For now */
+ inet_add_protocol(p);
- /* We need to remember this somewhere. */
- sk->pair = (struct sock *)p;
+ /* We need to remember this somewhere. */
+ sk->pair = (struct sock *)p;
- DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol));
+ DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol));
- return(0);
+ return(0);
}
@@ -343,98 +307,91 @@ static int raw_init(struct sock *sk)
* This should be easy, if there is something there
* we return it, otherwise we block.
*/
-
-int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
+int
+raw_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
- int copied=0;
- struct sk_buff *skb;
- int err;
+ int copied=0;
+ struct sk_buff *skb;
+ int err;
- DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n"
- " sin=%X, addr_len=%X)\n",
+ DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n"
+ " sin=%X, addr_len=%X)\n",
sk, to, len, noblock, flags, sin, addr_len));
- if (len == 0)
- return(0);
- if (len < 0)
- return(-EINVAL);
-
- if (sk->shutdown & RCV_SHUTDOWN)
- return(0);
- if (addr_len)
- {
- err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
- if(err)
- return err;
- put_fs_long(sizeof(*sin), addr_len);
- }
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
-
- skb=skb_recv_datagram(sk,flags,noblock,&err);
- if(skb==NULL)
- return err;
-
- copied = min(len, skb->len);
+ if (len == 0) return(0);
+ if (len < 0) return(-EINVAL);
+
+ if (sk->shutdown & RCV_SHUTDOWN) return(0);
+ if (addr_len) {
+ err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(err)
+ return err;
+ put_fs_long(sizeof(*sin), addr_len);
+ }
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
+
+ copied = min(len, skb->len);
- skb_copy_datagram(skb, 0, to, copied);
+ skb_copy_datagram(skb, 0, to, copied);
- /* Copy the address. */
- if (sin)
- {
- struct sockaddr_in addr;
-
- 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));
- }
+ /* Copy the address. */
+ if (sin) {
+ struct sockaddr_in addr;
- skb_free_datagram(skb);
- release_sock(sk);
- return (copied);
+ 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));
+ }
+
+ skb_free_datagram(skb);
+ release_sock(sk);
+ return (copied);
}
-int raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,
+int
+raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
+ return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
-struct proto raw_prot =
-{
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- raw_close,
- raw_read,
- raw_write,
- raw_sendto,
- raw_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- ip_retransmit,
- NULL,
- NULL,
- raw_rcv,
- datagram_select,
- NULL,
- raw_init,
- NULL,
- ip_setsockopt,
- ip_getsockopt,
- 128,
- 0,
- {NULL,},
- "RAW"
+struct proto raw_prot = {
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ raw_close,
+ raw_read,
+ raw_write,
+ raw_sendto,
+ raw_recvfrom,
+ ip_build_header,
+ udp_connect,
+ NULL,
+ ip_queue_xmit,
+ ip_retransmit,
+ NULL,
+ NULL,
+ raw_rcv,
+ datagram_select,
+ NULL,
+ raw_init,
+ NULL,
+ 128,
+ 0,
+ {NULL,},
+ "RAW"
};
diff --git a/net/inet/route.c b/net/inet/route.c
index cd2e355..269c80d 100644
--- a/net/inet/route.c
+++ b/net/inet/route.c
@@ -47,18 +47,18 @@ static struct rtable *rt_base = NULL;
static struct rtable *rt_loopback = NULL;
/* Dump the contents of a routing table entry. */
-static void rt_print(struct rtable *rt)
+static void
+rt_print(struct rtable *rt)
{
- if (rt == NULL || inet_debug != DBG_RT)
- return;
+ if (rt == NULL || inet_debug != DBG_RT) return;
- printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
+ printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
(long) rt, (long) rt->rt_next, rt->rt_flags);
- printk(" TARGET=%s ", in_ntoa(rt->rt_dst));
- printk("GW=%s ", in_ntoa(rt->rt_gateway));
- printk(" DEV=%s USE=%ld REF=%d\n",
- (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
- rt->rt_use, rt->rt_refcnt);
+ printk(" TARGET=%s ", in_ntoa(rt->rt_dst));
+ printk("GW=%s ", in_ntoa(rt->rt_gateway));
+ printk(" DEV=%s USE=%ld REF=%d\n",
+ (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,
+ rt->rt_use, rt->rt_refcnt);
}
@@ -162,8 +162,8 @@ static inline struct device * get_gw_dev(unsigned long gw)
/*
* rewrote rt_add(), as the old one was weird. Linus
*/
-void rt_add(short flags, unsigned long dst, unsigned long mask,
- unsigned long gw, struct device *dev)
+void
+rt_add(short flags, unsigned long dst, unsigned long mask, unsigned long gw, struct device *dev)
{
struct rtable *r, *rt;
struct rtable **rp;
@@ -280,35 +280,38 @@ static int rt_new(struct rtentry *r)
}
-static int rt_kill(struct rtentry *r)
+static int
+rt_kill(struct rtentry *r)
{
- struct sockaddr_in *trg;
+ struct sockaddr_in *trg;
- trg = (struct sockaddr_in *) &r->rt_dst;
- rt_del(trg->sin_addr.s_addr);
- return 0;
+ trg = (struct sockaddr_in *) &r->rt_dst;
+ rt_del(trg->sin_addr.s_addr);
+
+ return(0);
}
/* Called from the PROCfs module. */
-int rt_get_info(char *buffer)
+int
+rt_get_info(char *buffer)
{
- struct rtable *r;
- char *pos;
+ struct rtable *r;
+ char *pos;
- pos = buffer;
+ pos = buffer;
- pos += sprintf(pos,
- "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
+ pos += sprintf(pos,
+ "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");
- /* This isn't quite right -- r->rt_dst is a struct! */
- for (r = rt_base; r != NULL; r = r->rt_next) {
- pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
- r->rt_dev->name, r->rt_dst, r->rt_gateway,
- r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
- r->rt_mask);
- }
- return pos - buffer;
+ /* This isn't quite right -- r->rt_dst is a struct! */
+ for (r = rt_base; r != NULL; r = r->rt_next) {
+ pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",
+ r->rt_dev->name, r->rt_dst, r->rt_gateway,
+ r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
+ r->rt_mask);
+ }
+ return(pos - buffer);
}
/*
@@ -337,41 +340,39 @@ no_route:
}
-int rt_ioctl(unsigned int cmd, void *arg)
+int
+rt_ioctl(unsigned int cmd, void *arg)
{
- struct device *dev;
- struct rtentry rt;
- char namebuf[32];
- int ret;
- int err;
+ struct device *dev;
+ struct rtentry rt;
+ char namebuf[32];
+ int ret;
+ int err;
- switch(cmd) {
+ switch(cmd) {
case DDIOCSDBG:
ret = dbg_ioctl(arg, DBG_RT);
break;
-
case SIOCADDRT:
case SIOCDELRT:
- if (!suser())
- return -EPERM;
- err = verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
+ if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
if(err)
return err;
memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
if (rt.rt_dev) {
- err = verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
- if(err)
- return err;
- memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
- dev = dev_get(namebuf);
- rt.rt_dev = dev;
+ err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
+ if(err)
+ return err;
+ memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
+ dev = dev_get(namebuf);
+ rt.rt_dev = dev;
}
ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
break;
-
default:
ret = -EINVAL;
- }
+ }
- return ret;
+ return(ret);
}
diff --git a/net/inet/route.h b/net/inet/route.h
index c5429c6..bba3acf 100644
--- a/net/inet/route.h
+++ b/net/inet/route.h
@@ -24,15 +24,15 @@
/* This is an entry in the IP routing table. */
struct rtable {
- struct rtable *rt_next;
- unsigned long rt_dst;
- unsigned long rt_mask;
- unsigned long rt_gateway;
- u_char rt_flags;
- u_char rt_metric;
- short rt_refcnt;
- u_long rt_use;
- struct device *rt_dev;
+ struct rtable *rt_next;
+ unsigned long rt_dst;
+ unsigned long rt_mask;
+ unsigned long rt_gateway;
+ u_char rt_flags;
+ u_char rt_metric;
+ short rt_refcnt;
+ u_long rt_use;
+ struct device *rt_dev;
};
diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c
index e69de29..1f3299d 100644
--- a/net/inet/skbuff.c
+++ b/net/inet/skbuff.c
@@ -0,0 +1,454 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * A saner implementation of the skbuff stuff scattered everywhere
+ * in the old NET2D code.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox : Tracks memory and number of buffers for kernel memory report
+ * and memory leak hunting.
+ * Alan Cox : More generic kfree handler
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+
+
+/* Socket buffer operations. Ideally much of this list swap stuff ought to be using
+ exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
+ slow C version. No doubt when Linus sees this comment he'll do horrible things
+ to this code 8-)
+*/
+
+/*
+ * 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)
+{
+ if(skb->magic_debug_cookie==SK_FREED_SKB)
+ {
+ printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
+ file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
+ }
+ if(skb->magic_debug_cookie!=SK_GOOD_SKB)
+ {
+ printk("File: %s Line %d, passed a non skb!\n", file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
+ }
+ if(skb->mem_len!=skb->truesize)
+ {
+ printk("File: %s Line %d, Dubious size setting!\n",file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
+ }
+ /* Guess it might be acceptable then */
+}
+
+/*
+ * 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);
+ 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
+ newsk->prev=newsk;
+ newsk->prev->next=newsk;
+ newsk->next->prev=newsk;
+ IS_SKB(newsk->prev);
+ IS_SKB(newsk->next);
+ *list=newsk;
+ restore_flags(flags);
+}
+
+/*
+ * 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();
+
+ newsk->list=list;
+ if(*list)
+ {
+ (*list)->prev->next=newsk;
+ newsk->prev=(*list)->prev;
+ newsk->next=*list;
+ (*list)->prev=newsk;
+ }
+ else
+ {
+ newsk->next=newsk;
+ newsk->prev=newsk;
+ *list=newsk;
+ }
+ IS_SKB(newsk->prev);
+ IS_SKB(newsk->next);
+ restore_flags(flags);
+
+}
+
+/*
+ * 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;
+ else
+ {
+ result->next->prev=result->prev;
+ result->prev->next=result->next;
+ *list=result->next;
+ }
+
+ IS_SKB(result);
+ restore_flags(flags);
+
+ if(result->list!=list)
+ printk("Dequeued packet has invalid list pointer\n");
+
+ result->list=0;
+ result->next=0;
+ result->prev=0;
+ return(result);
+}
+
+/*
+ * 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;
+ newsk->next=old;
+ 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);
+
+ if(!old->list)
+ 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;
+ newsk->prev=old;
+ newsk->next=old->next;
+ newsk->next->prev=newsk;
+ newsk->prev->next=newsk;
+
+ restore_flags(flags);
+}
+
+/*
+ * Remove an sk_buff from its list. Works even without knowing the list it
+ * is sitting on, which can be handy at times. It also means that THE LIST
+ * MUST EXIST when you unlink. Thus a list must have its contents unlinked
+ * _FIRST_.
+ */
+
+void skb_unlink(struct sk_buff *skb)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+
+ IS_SKB(skb);
+
+ if(skb->list)
+ {
+ skb->next->prev=skb->prev;
+ skb->prev->next=skb->next;
+ if(*skb->list==skb)
+ {
+ if(skb->next==skb)
+ *skb->list=NULL;
+ else
+ *skb->list=skb->next;
+ }
+ skb->next=0;
+ skb->prev=0;
+ skb->list=0;
+ }
+ restore_flags(flags);
+}
+
+/*
+ * An skbuff list has had its head reassigned. Move all the list
+ * pointers. Must be called with ints off during the whole head
+ * shifting
+ */
+
+void skb_new_list_head(struct sk_buff *volatile* list)
+{
+ struct sk_buff *skb=skb_peek(list);
+ if(skb!=NULL)
+ {
+ do
+ {
+ IS_SKB(skb);
+ skb->list=list;
+ skb=skb->next;
+ }
+ 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
+ * list and someone else may run off with it. For an interrupt
+ * type system cli() peek the buffer copy the data and sti();
+ */
+
+struct sk_buff *skb_peek(struct sk_buff *volatile* list)
+{
+ return *list;
+}
+
+/*
+ * Get a clone of an sk_buff. This is the safe way to peek at
+ * a socket queue without accidents. Its a bit long but most
+ * of it acutally ends up as tiny bits of inline assembler
+ * 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);
+ cli();
+ orig=skb_peek(list);
+ if(orig==NULL)
+ {
+ restore_flags(flags);
+ return NULL;
+ }
+ IS_SKB(orig);
+ len=orig->truesize;
+ restore_flags(flags);
+
+ newsk=alloc_skb(len,GFP_KERNEL); /* May sleep */
+
+ 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 */
+ {
+ restore_flags(flags);
+ newsk->sk=NULL;
+ newsk->free=1;
+ newsk->mem_addr=newsk;
+ newsk->mem_len=len;
+ kfree_skb(newsk, FREE_WRITE);
+ continue;
+ }
+
+ IS_SKB(orig);
+ IS_SKB(newsk);
+ memcpy(newsk,orig,len);
+ newsk->list=NULL;
+ newsk->magic=0;
+ newsk->next=NULL;
+ newsk->prev=NULL;
+ newsk->mem_addr=newsk;
+ newsk->h.raw+=((char *)newsk-(char *)orig);
+ newsk->link3=NULL;
+ newsk->sk=NULL;
+ 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.
+ */
+
+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);
+
+ }
+ else
+ {
+ /* 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);
+ }
+ }
+ 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;
+ }
+
+/*
+ * Free an skbuff by memory
+ */
+
+void kfree_skbmem(void *mem,unsigned size)
+{
+ struct sk_buff *x=mem;
+ IS_SKB(x);
+ if(x->magic_debug_cookie==SK_GOOD_SKB)
+ {
+ x->magic_debug_cookie=SK_FREED_SKB;
+ kfree_s(mem,size);
+ net_skbcount--;
+ net_memory-=size;
+ }
+}
+
diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h
index e69de29..6d5f879 100644
--- a/net/inet/skbuff.h
+++ b/net/inet/skbuff.h
@@ -0,0 +1,107 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions for the 'struct sk_buff' memory handlers.
+ *
+ * Version: @(#)skbuff.h 1.0.4 05/20/93
+ *
+ * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Corey Minyard <wf-rch!minyard@relay.EU.net>
+ *
+ * Fixes:
+ * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff)
+ * Alan Cox : Declaration for new primitives
+ * Alan Cox : Fraglist support (idea by Donald Becker)
+ * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy
+ * being used.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _SKBUFF_H
+#define _SKBUFF_H
+#include <linux/malloc.h>
+
+#ifdef CONFIG_IPX
+#include "ipx.h"
+#endif
+
+#define HAVE_ALLOC_SKB /* For the drivers to know */
+
+
+#define FREE_READ 1
+#define FREE_WRITE 0
+
+
+struct sk_buff {
+ unsigned long magic_debug_cookie;
+ struct sk_buff *volatile next;
+ struct sk_buff *volatile prev;
+ struct sk_buff *volatile link3;
+ struct sk_buff *volatile* list;
+ struct sock *sk;
+ volatile unsigned long when; /* used to compute rtt's */
+ struct device *dev;
+ void *mem_addr;
+ union {
+ struct tcphdr *th;
+ struct ethhdr *eth;
+ struct iphdr *iph;
+ struct udphdr *uh;
+ struct arphdr *arp;
+ unsigned char *raw;
+ unsigned long seq;
+#ifdef CONFIG_IPX
+ ipx_packet *ipx;
+#endif
+ } h;
+ unsigned long mem_len;
+ unsigned long len;
+ unsigned long fraglen;
+ struct sk_buff *fraglist; /* Fragment list */
+ unsigned long truesize;
+ unsigned long saddr;
+ unsigned long daddr;
+ int magic;
+ volatile char acked,
+ used,
+ free,
+ arp,
+ urg_used;
+ unsigned char tries,lock; /* Lock is now unused */
+ unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
+};
+
+#define SK_WMEM_MAX 8192
+#define SK_RMEM_MAX 32767
+
+#define SK_FREED_SKB 0x0DE2C0DE
+#define SK_GOOD_SKB 0xDEC0DED1
+
+extern void print_skb(struct sk_buff *);
+extern void kfree_skb(struct sk_buff *skb, int rw);
+extern void skb_queue_head(struct sk_buff * volatile *list,struct sk_buff *buf);
+extern void skb_queue_tail(struct sk_buff * volatile *list,struct sk_buff *buf);
+extern struct sk_buff * skb_dequeue(struct sk_buff * volatile *list);
+extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk);
+extern void skb_append(struct sk_buff *old,struct sk_buff *newsk);
+extern void skb_unlink(struct sk_buff *buf);
+extern void skb_new_list_head(struct sk_buff *volatile* list);
+extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
+extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
+extern struct sk_buff * alloc_skb(unsigned int size, int priority);
+extern void kfree_skbmem(void *mem, unsigned size);
+
+extern void skb_check(struct sk_buff *skb,int, char *);
+#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
+
+extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
+extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
+extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
+extern void skb_free_datagram(struct sk_buff *skb);
+#endif /* _SKBUFF_H */
diff --git a/net/inet/sockinet.c b/net/inet/sockinet.c
index 004d63c..e69de29 100644
--- a/net/inet/sockinet.c
+++ b/net/inet/sockinet.c
@@ -1,1636 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * SOCK - AF_INET protocol family socket handler.
- *
- * Version: @(#)sock.c 1.28 24/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Florian La Roche, <flla@stud.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : Numerous verify_area() problems
- * Alan Cox : Connecting on a connecting socket
- * now returns an error for tcp.
- * Alan Cox : sock->protocol is set correctly.
- * and is not sometimes left as 0.
- * Alan Cox : connect handles icmp errors on a
- * connect properly. Unfortunately there
- * is a restart syscall nasty there. I
- * can't match BSD without hacking the C
- * library. Ideas urgently sought!
- * Alan Cox : Disallow bind() to addresses that are
- * not ours - especially broadcast ones!!
- * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost)
- * Alan Cox : sock_wfree/sock_rfree don't destroy sockets,
- * instead they leave that for the DESTROY timer.
- * Alan Cox : Clean up error flag in accept
- * Alan Cox : TCP ack handling is buggy, the DESTROY timer
- * was buggy. Put a remove_sock() in the handler
- * for memory when we hit 0. Also altered the timer
- * code. The ACK stuff can wait and needs major
- * TCP layer surgery.
- * Alan Cox : Fixed TCP ack bug, removed remove sock
- * and fixed timer/inet_bh race.
- * Alan Cox : Added zapped flag for TCP
- * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code
- * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
- * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources
- * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing.
- * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenely occured to me how easy it was so...
- * Rick Sladkey : Relaxed UDP rules for matching packets.
- * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
- * Pauline Middelink : Pidentd support
- * Alan Cox : Fixed connect() taking signals I think.
- * Alan Cox : SO_LINGER supported
- * Alan Cox : Error reporting fixes
- * Anonymous : inet_create tidied up (sk->reuse setting)
- * Alan Cox : Tidy up for release.
- * Alan Cox : Moved this to sockinet.c and removed generic code.
- * Alan Cox : inet sockets don't set sk->type!
- *
- *
- * To Fix:
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#include "inet.h"
-#include "devinet.h"
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include "skbuff.h"
-#include "sockinet.h"
-#include "raw.h"
-#include "icmp.h"
-
-
-int inet_debug = DBG_OFF; /* INET module debug flag */
-
-
-#define min(a,b) ((a)<(b)?(a):(b))
-
-extern struct proto packet_prot;
-
-
-
-static int sk_inuse(struct proto *prot, int num)
-{
- struct sock *sk;
-
- for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )];sk != NULL;sk=sk->next)
- {
- if (sk->num == num) return(1);
- }
- return(0);
-}
-
-
-unsigned short get_new_socknum(struct proto *prot, unsigned short base)
-{
- static int start=0;
-
- /*
- * Used to cycle through the port numbers so the
- * chances of a confused connection drop.
- */
- int i, j;
- int best = 0;
- int size = 32767; /* a big num. */
- struct sock *sk;
-
- if (base == 0)
- base = PROT_SOCK+1+(start % 1024);
- if (base <= PROT_SOCK)
- {
- base += PROT_SOCK+(start % 1024);
- }
-
- /* Now look through the entire array and try to find an empty ptr. */
- for(i=0; i < SOCK_ARRAY_SIZE; i++)
- {
- j = 0;
- sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)];
- while(sk != NULL)
- {
- sk = sk->next;
- j++;
- }
- if (j == 0)
- {
- start =(i+1+start )%1024;
- DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n",
- i + base + 1, start));
- return(i+base+1);
- }
- if (j < size)
- {
- best = i;
- size = j;
- }
- }
-
- /* Now make sure the one we want is not in use. */
- while(sk_inuse(prot, base +best+1))
- {
- best += SOCK_ARRAY_SIZE;
- }
- DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n",
- best + base + 1, start));
- return(best+base+1);
-}
-
-
-void put_sock(unsigned short num, struct sock *sk)
-{
- struct sock *sk1;
- struct sock *sk2;
- int mask;
-
- DPRINTF((DBG_INET, "put_sock(num = %d, sk = %X\n", num, sk));
- sk->num = num;
- sk->next = NULL;
- num = num &(SOCK_ARRAY_SIZE -1);
-
- /* We can't have an interupt re-enter here. */
- cli();
- if (sk->prot->sock_array[num] == NULL)
- {
- sk->prot->sock_array[num] = sk;
- sti();
- return;
- }
- sti();
- for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask)
- {
- if ((mask & sk->saddr) &&
- (mask & sk->saddr) != (mask & 0xffffffff))
- {
- mask = mask << 8;
- break;
- }
- }
- DPRINTF((DBG_INET, "mask = %X\n", mask));
-
- cli();
- sk1 = sk->prot->sock_array[num];
- for(sk2 = sk1; sk2 != NULL; sk2=sk2->next)
- {
- if (!(sk2->saddr & mask))
- {
- if (sk2 == sk1)
- {
- sk->next = sk->prot->sock_array[num];
- sk->prot->sock_array[num] = sk;
- sti();
- return;
- }
- sk->next = sk2;
- sk1->next= sk;
- sti();
- return;
- }
- sk1 = sk2;
- }
-
- /* Goes at the end. */
- sk->next = NULL;
- sk1->next = sk;
- sti();
-}
-
-
-static void remove_sock(struct sock *sk1)
-{
- struct sock *sk2;
-
- DPRINTF((DBG_INET, "remove_sock(sk1=%X)\n", sk1));
-
- if (!sk1)
- {
- printk("sock.c: remove_sock: sk1 == NULL\n");
- return;
- }
-
- if (!sk1->prot)
- {
- printk("sock.c: remove_sock: sk1->prot == NULL\n");
- return;
- }
-
- /* We can't have this changing out from under us. */
- cli();
- sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)];
- if (sk2 == sk1)
- {
- sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next;
- sti();
- return;
- }
-
- while(sk2 && sk2->next != sk1)
- {
- sk2 = sk2->next;
- }
-
- if (sk2)
- {
- sk2->next = sk1->next;
- sti();
- return;
- }
-
- sti();
-
- if (sk1->num != 0)
- DPRINTF((DBG_INET, "remove_sock: sock not found.\n"));
-}
-
-
-void destroy_sock(struct sock *sk)
-{
- struct sk_buff *skb;
-
- DPRINTF((DBG_INET, "destroying socket %X\n", sk));
- sk->inuse = 1; /* just to be safe. */
-
- /* Incase it's sleeping somewhere. */
- if (!sk->dead)
- wake_up(sk->sleep);
-
- remove_sock(sk);
-
- /* Now we can no longer get new packets. */
- delete_timer(sk);
-
-
- if (sk->send_tmp != NULL)
- {
- IS_SKB(sk->send_tmp);
- kfree_skb(sk->send_tmp, FREE_WRITE);
- }
-
- /* Cleanup up the write buffer. */
- for(skb = sk->wfront; skb != NULL; )
- {
- struct sk_buff *skb2;
-
- skb2=(struct sk_buff *)skb->next;
- if (skb->magic != TCP_WRITE_QUEUE_MAGIC)
- {
- printk("sock.c:destroy_sock write queue with bad magic(%X)\n",
- skb->magic);
- break;
- }
- IS_SKB(skb);
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- }
-
- sk->wfront = NULL;
- sk->wback = NULL;
-
- if (sk->rqueue != NULL)
- {
- while((skb=skb_dequeue(&sk->rqueue))!=NULL)
- {
- /*
- * This will take care of closing sockets that were
- * listening and didn't accept everything.
- */
- if (skb->sk != NULL && skb->sk != sk)
- {
- IS_SKB(skb);
- skb->sk->dead = 1;
- skb->sk->prot->close(skb->sk, 0);
- }
- IS_SKB(skb);
- kfree_skb(skb, FREE_READ);
- }
- }
- sk->rqueue = NULL;
-
- /* Now we need to clean up the send head. */
- for(skb = sk->send_head; skb != NULL; )
- {
- struct sk_buff *skb2;
-
- /*
- * We need to remove skb from the transmit queue,
- * or maybe the arp queue.
- */
- cli();
-
- if (skb->next != NULL)
- {
- IS_SKB(skb);
- skb_unlink(skb);
- }
-
- skb->dev = NULL;
- sti();
- skb2 = (struct sk_buff *)skb->link3;
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- }
- sk->send_head = NULL;
-
- /* And now the backlog. */
- if (sk->back_log != NULL)
- {
- /* this should never happen. */
- printk("Socket Error: Socket destroyed with data backlog.\n");
- cli();
- skb = (struct sk_buff *)sk->back_log;
- do
- {
- struct sk_buff *skb2;
-
- skb2 = (struct sk_buff *)skb->next;
- kfree_skb(skb, FREE_READ);
- skb = skb2;
- }
- while(skb != sk->back_log);
- sti();
- }
- sk->back_log = NULL;
-
- /* Now if it has a half accepted/ closed socket. */
- if (sk->pair)
- {
- sk->pair->dead = 1;
- sk->pair->prot->close(sk->pair, 0);
- sk->pair = NULL;
- }
-
- /*
- * Now if everything is gone we can free the socket
- * structure, otherwise we need to keep it around until
- * everything is gone.
- */
- if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
- {
- kfree_s((void *)sk,sizeof(*sk));
- }
- else
- {
- /* this should never happen. */
- /* actually it can if an ack has just been sent. */
- DPRINTF((DBG_INET, "possible memory leak in socket = %X\n", sk));
- sk->destroy = 1;
- sk->ack_backlog = 0;
- sk->inuse = 0;
- reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
- }
- DPRINTF((DBG_INET, "leaving destroy_sock\n"));
-}
-
-
-static int inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- switch(cmd)
- {
- case F_SETOWN:
- /*
- * This is a little restrictive, but it's the only
- * way to make sure that you can't send a sigurg to
- * another process.
- */
- if (!suser() && current->pgrp != -arg && current->pid != arg)
- return(-EPERM);
- sk->proc = arg;
- return(0);
- case F_GETOWN:
- return(sk->proc);
- default:
- return(-EINVAL);
- }
-}
-
-
-/*
- * Set socket options on an inet socket.
- */
-
-static int inet_setsockopt(struct socket *sock, int level, int optname,
- char *optval, int optlen)
-{
- struct sock *sk = (struct sock *) sock->data;
- if (level == SOL_SOCKET)
- return sock_setsockopt(sk,level,optname,optval,optlen);
- if (sk->prot->setsockopt==NULL)
- return(-EOPNOTSUPP);
- else
- return sk->prot->setsockopt(sk,level,optname,optval,optlen);
-}
-
-
-
-
-static int inet_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- struct sock *sk = sock->data;
- if (level == SOL_SOCKET)
- return sock_getsockopt(sk,level,optname,optval,optlen);
- if(sk->prot->getsockopt==NULL)
- return(-EOPNOTSUPP);
- else
- return sk->prot->getsockopt(sk,level,optname,optval,optlen);
-}
-
-
-
-static int inet_listen(struct socket *sock, int backlog)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- /* No listen() on a busy socket. */
-
- if(sk->state != TCP_CLOSE)
- return -EINVAL;
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- /* Some sanity checks here are a good idea */
- if(backlog<0)
- return -EINVAL;
- /* Pick a number, any number 8-) */
- if(backlog>5)
- backlog=5;
-
- /* We might as well re use these. */
- sk->max_ack_backlog = backlog;
- if (sk->state != TCP_LISTEN)
- {
- sk->ack_backlog = 0;
- sk->state = TCP_LISTEN;
- }
- return(0);
-}
-
-/*
- * Default callbacks for user INET sockets. These just wake up
- * the user owning the socket.
- */
-
-static void def_callback1(struct sock *sk)
-{
- if(!sk->dead)
- wake_up(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk,int len)
-{
- if(!sk->dead)
- wake_up(sk->sleep);
-}
-
-
-/*
- * Create an inet socket. Note that sock=NULL is now legal, and means a kernel
- * created socket.
- */
-
-static int inet_create(struct socket *sock, int protocol)
-{
- struct sock *sk;
- struct proto *prot;
- int err;
-
- sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
-
- if (sk == NULL)
- return(-ENOMEM);
- sk->num = 0;
- sk->reuse = 0;
- switch(sock->type)
- {
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- if (protocol && protocol != IPPROTO_TCP)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- protocol = IPPROTO_TCP;
- sk->no_check = TCP_NO_CHECK;
- prot = &tcp_prot;
- break;
-
- case SOCK_DGRAM:
- if (protocol && protocol != IPPROTO_UDP)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- protocol = IPPROTO_UDP;
- sk->no_check = UDP_NO_CHECK;
- prot=&udp_prot;
- break;
-
- case SOCK_RAW:
- if (!suser())
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPERM);
- }
- if (!protocol)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- prot = &raw_prot;
- sk->reuse = 1;
- sk->no_check = 0; /*
- * Doesn't matter no checksum is
- * preformed anyway.
- */
- sk->num = protocol;
- break;
-
- case SOCK_PACKET:
- if (!suser())
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPERM);
- }
- if (!protocol)
- {
- kfree_s((void *)sk, sizeof(*sk));
- return(-EPROTONOSUPPORT);
- }
- prot = &packet_prot;
- sk->reuse = 1;
- sk->no_check = 0; /* Doesn't matter no checksum is
- * preformed anyway.
- */
- sk->num = protocol;
- break;
-
- default:
- kfree_s((void *)sk, sizeof(*sk));
- return(-ESOCKTNOSUPPORT);
- }
- sk->socket = sock;
- sk->type = sock->type;
- sk->protocol = protocol;
- sk->wmem_alloc = 0;
- sk->rmem_alloc = 0;
- sk->sndbuf = SK_WMEM_MAX;
- sk->rcvbuf = SK_RMEM_MAX;
- sk->pair = NULL;
- sk->opt = NULL;
- sk->send_seq = 0;
- sk->acked_seq = 0;
- sk->copied_seq = 0;
- sk->fin_seq = 0;
- sk->proc = 0;
- sk->rtt = TCP_WRITE_TIME;
- sk->mdev = 0;
- sk->backoff = 0;
- sk->packets_out = 0;
- sk->cong_window = 1; /* start with only sending one packet at a time. */
- sk->exp_growth = 1; /* if set cong_window grow exponentially every time
- we get an ack. */
- sk->urginline = 0;
- sk->intr = 0;
- sk->linger = 0;
- sk->destroy = 0;
-
- sk->priority = 1;
- sk->shutdown = 0;
- sk->urg = 0;
- sk->keepopen = 0;
- sk->zapped = 0;
- sk->done = 0;
- sk->ack_backlog = 0;
- sk->window = 0;
- sk->bytes_rcv = 0;
- sk->state = TCP_CLOSE;
- sk->dead = 0;
- sk->ack_timed = 0;
- sk->send_tmp = NULL;
- sk->mss = 0; /* we will try not to send any packets smaller than this. */
- sk->debug = 0;
-
- /* this is how many unacked bytes we will accept for this socket. */
- sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
-
- /* how many packets we should send before forcing an ack.
- * if this is set to zero it is the same as sk->delay_acks = 0
- */
- sk->max_ack_backlog = 0;
- sk->inuse = 0;
- sk->delay_acks = 0;
- sk->wback = NULL;
- sk->wfront = NULL;
- sk->rqueue = NULL;
- sk->mtu = 576; /* This is a reasonable typical choice. RFC791 guarantees this is acceptable */
- sk->prot = prot;
- sk->sleep = sock->wait;
- sk->daddr = 0;
- sk->saddr = my_addr();
- sk->err = 0;
- sk->next = NULL;
- sk->pair = NULL;
- sk->send_tail = NULL;
- sk->send_head = NULL;
- sk->timeout = 0;
- sk->broadcast = 0;
- sk->timer.data = (unsigned long)sk;
- sk->timer.function = &net_timer;
- sk->back_log = NULL;
- sk->blog = 0;
- sock->data =(void *) sk;
- sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
- sk->dummy_th.res1=0;
- sk->dummy_th.res2=0;
- sk->dummy_th.urg_ptr = 0;
- sk->dummy_th.fin = 0;
- sk->dummy_th.syn = 0;
- sk->dummy_th.rst = 0;
- sk->dummy_th.psh = 0;
- sk->dummy_th.ack = 0;
- sk->dummy_th.urg = 0;
- sk->dummy_th.dest = 0;
-
- sk->ip_tos=0;
- sk->ip_ttl=64;
-
- sk->state_change = def_callback1;
- sk->data_ready = def_callback2;
- sk->write_space = def_callback1;
- sk->error_report = def_callback1;
-
- if (sk->num)
- {
- /*
- * It assumes that any protocol which allows
- * the user to assign a number at socket
- * creation time automatically
- * shares.
- */
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- if (sk->prot->init)
- {
- err = sk->prot->init(sk);
- if (err != 0)
- {
- destroy_sock(sk);
- return(err);
- }
- }
- return(0);
-}
-
-
-static int inet_dup(struct socket *newsock, struct socket *oldsock)
-{
- return(inet_create(newsock,((struct sock *)(oldsock->data))->protocol));
-}
-
-
-/* The peer socket should always be NULL. */
-static int inet_release(struct socket *sock, struct socket *peer)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- return(0);
-
- DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer));
- wake_up(sk->sleep);
-
- /* Start closing the connection. This may take a while. */
- /*
- * If linger is set, we don't return until the close
- * is complete. Other wise we return immediately. The
- * actually closing is done the same either way.
- */
- if (sk->linger == 0)
- {
- sk->prot->close(sk,0);
- sk->dead = 1;
- }
- else
- {
- DPRINTF((DBG_INET, "sk->linger set.\n"));
- sk->prot->close(sk, 0);
- cli();
- if (sk->lingertime)
- current->timeout = jiffies + HZ*sk->lingertime;
- while(sk->state != TCP_CLOSE && sk->state != TCP_FIN_WAIT2 && sk->state !=TCP_TIME_WAIT && current->timeout>0)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- current->timeout=0;
- return(-ERESTARTSYS);
- }
- }
- current->timeout=0;
- sti();
- sk->dead = 1;
- }
- sk->inuse = 1;
-
- /* This will destroy it. */
- release_sock(sk);
- sock->data = NULL;
- DPRINTF((DBG_INET, "inet_release returning\n"));
- return(0);
-}
-
-
-/* this needs to be changed to dissallow
- the rebinding of sockets. What error
- should it return? */
-
-static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
- int addr_len)
-{
- struct sockaddr_in addr;
- struct sock *sk, *sk2;
- unsigned short snum;
- int err;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- /* check this error. */
- if (sk->state != TCP_CLOSE)
- return(-EIO);
- if (sk->num != 0)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, uaddr, addr_len);
- if(err)
- return err;
- memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len));
-
- snum = ntohs(addr.sin_port);
- DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum));
- sk = (struct sock *) sock->data;
- if (snum == 0)
- {
- snum = get_new_socknum(sk->prot, 0);
- }
- if (snum < PROT_SOCK && !suser())
- return(-EACCES);
-
- if (addr.sin_addr.s_addr!=0 && chk_addr(addr.sin_addr.s_addr)!=IS_MYADDR)
- return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
-
- if (chk_addr(addr.sin_addr.s_addr) || addr.sin_addr.s_addr == 0)
- sk->saddr = addr.sin_addr.s_addr;
-
- DPRINTF((DBG_INET, "sock_array[%d] = %X:\n", snum &(SOCK_ARRAY_SIZE -1),
- sk->prot->sock_array[snum &(SOCK_ARRAY_SIZE -1)]));
-
- /* Make sure we are allowed to bind here. */
- cli();
-outside_loop:
- for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];sk2 != NULL; sk2 = sk2->next)
- {
- if (sk2->num != snum)
- continue;
- if (sk2->saddr != sk->saddr)
- continue;
- if (sk2->dead && !sk2->inuse) /* Added in use check AC 24/12/93 */
- {
- destroy_sock(sk2);
- goto outside_loop;
- }
- if (!sk->reuse)
- {
- sti();
- return(-EADDRINUSE);
- }
- if (sk2->num != snum)
- continue; /* more than one */
- if (sk2->saddr != sk->saddr)
- continue; /* socket per slot ! -FB */
- if (!sk2->reuse)
- {
- sti();
- return(-EADDRINUSE);
- }
- }
- sti();
-
- remove_sock(sk);
- put_sock(snum, sk);
- sk->dummy_th.source = ntohs(sk->num);
- sk->daddr = 0;
- sk->dummy_th.dest = 0;
- return(0);
-}
-
-
-static int inet_connect(struct socket *sock, struct sockaddr * uaddr,
- int addr_len, int flags)
-{
- struct sock *sk;
- int err;
-
- sock->conn = NULL;
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
- {
- sock->state = SS_CONNECTED;
- /* Connection completing after a connect/EINPROGRESS/select/connect */
- return 0; /* Rock and roll */
- }
-
- if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
- return -EALREADY; /* Connecting is currently in progress */
-
- if (sock->state != SS_CONNECTING)
- {
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = htons(sk->num);
- }
-
- if (sk->prot->connect == NULL)
- return(-EOPNOTSUPP);
-
- err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len);
- if (err < 0)
- return(err);
-
- sock->state = SS_CONNECTING;
- }
-
- if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))
- return(-EINPROGRESS);
-
- cli(); /* avoid the race condition */
- while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- return(-ERESTARTSYS);
- }
- /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
- icmp error packets wanting to close a tcp or udp socket. */
- if(sk->err && sk->protocol == IPPROTO_TCP)
- {
- sti();
- sock->state = SS_UNCONNECTED;
- err = -sk->err;
- sk->err=0;
- return err; /* set by tcp_err() */
- }
- }
- sti();
- sock->state = SS_CONNECTED;
-
- if (sk->state != TCP_ESTABLISHED && sk->err)
- {
- sock->state = SS_UNCONNECTED;
- err=sk->err;
- sk->err=0;
- return(err);
- }
- return(0);
-}
-
-
-static int inet_socketpair(struct socket *sock1, struct socket *sock2)
-{
- return(-EOPNOTSUPP);
-}
-
-
-static int inet_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- struct sock *sk1, *sk2;
- int err;
-
- sk1 = (struct sock *) sock->data;
- if (sk1 == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- /*
- * We've been passed an extra socket.
- * We need to free it up because the tcp module creates
- * it's own when it accepts one.
- */
-
- if (newsock->data)
- kfree_s(newsock->data, sizeof(struct sock));
- newsock->data = NULL;
-
- if (sk1->prot->accept == NULL)
- return(-EOPNOTSUPP);
-
- /* Restore the state if we have been interrupted, and then returned. */
- if (sk1->pair != NULL )
- {
- sk2 = sk1->pair;
- sk1->pair = NULL;
- }
- else
- {
- sk2 = sk1->prot->accept(sk1,flags);
- if (sk2 == NULL)
- {
- if (sk1->err <= 0)
- printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n");
- err=sk1->err;
- sk1->err=0;
- return(-err);
- }
- }
- newsock->data = (void *)sk2;
- sk2->sleep = newsock->wait;
- newsock->conn = NULL;
- if (flags & O_NONBLOCK)
- return(0);
-
- cli(); /* avoid the race. */
-
- while(sk2->state == TCP_SYN_RECV)
- {
- interruptible_sleep_on(sk2->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- sk1->pair = sk2;
- sk2->sleep = NULL;
- newsock->data = NULL;
- return(-ERESTARTSYS);
- }
- }
- sti();
-
- if (sk2->state != TCP_ESTABLISHED && sk2->err > 0)
- {
-
- err = -sk2->err;
- sk2->err=0;
- destroy_sock(sk2);
- newsock->data = NULL;
- return(err);
- }
- newsock->state = SS_CONNECTED;
- return(0);
-}
-
-
-static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
-{
- struct sockaddr_in sin;
- struct sock *sk;
- int len;
- int err;
-
-
- err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long));
- if(err)
- return err;
-
- len=get_fs_long(uaddr_len);
-
- err = verify_area(VERIFY_WRITE, uaddr, len);
- if(err)
- return err;
-
- /* Check this error. */
- if (len < sizeof(sin))
- return(-EINVAL);
-
- sin.sin_family = AF_INET;
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
- if (peer)
- {
- if (!tcp_connected(sk->state))
- return(-ENOTCONN);
- sin.sin_port = sk->dummy_th.dest;
- sin.sin_addr.s_addr = sk->daddr;
- }
- else
- {
- sin.sin_port = sk->dummy_th.source;
- if (sk->saddr == 0)
- sin.sin_addr.s_addr = my_addr();
- else
- sin.sin_addr.s_addr = sk->saddr;
- }
- len = sizeof(sin);
- memcpy_tofs(uaddr, &sin, sizeof(sin));
- put_fs_long(len, uaddr_len);
- return(0);
-}
-
-
-static int inet_read(struct socket *sock, char *ubuf, int size, int noblock)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
- return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock,0));
-}
-
-
-static int inet_recv(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
- return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags));
-}
-
-
-static int inet_write(struct socket *sock, char *ubuf, int size, int noblock)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, 0));
-}
-
-
-static int inet_send(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));
-}
-
-
-static int inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sin, int addr_len)
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
-
- if (sk->prot->sendto == NULL)
- return(-EOPNOTSUPP);
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags,
- (struct sockaddr_in *)sin, addr_len));
-}
-
-
-static int inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sin, int *addr_len )
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- if (sk->prot->recvfrom == NULL)
- return(-EOPNOTSUPP);
-
- /* We may need to bind the socket. */
- if (sk->num == 0)
- {
- sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0)
- return(-EAGAIN);
- put_sock(sk->num, sk);
- sk->dummy_th.source = ntohs(sk->num);
- }
-
- return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags,
- (struct sockaddr_in*)sin, addr_len));
-}
-
-
-static int inet_shutdown(struct socket *sock, int how)
-{
- struct sock *sk;
-
- /*
- * This should really check to make sure
- * the socket is a TCP socket.
- */
- how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
- 1->2 bit 2 snds.
- 2->3 */
- if (how & ~SHUTDOWN_MASK)
- return(-EINVAL);
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
- if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
- sock->state = SS_CONNECTED;
-
- if (!tcp_connected(sk->state))
- return(-ENOTCONN);
- sk->shutdown |= how;
- if (sk->prot->shutdown)
- sk->prot->shutdown(sk, how);
- return(0);
-}
-
-
-static int inet_select(struct socket *sock, int sel_type, select_table *wait )
-{
- struct sock *sk;
-
- sk = (struct sock *) sock->data;
- if (sk == NULL)
- {
- printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
- return(0);
- }
-
- if (sk->prot->select == NULL)
- {
- DPRINTF((DBG_INET, "select on non-selectable socket.\n"));
- return(0);
- }
- return(sk->prot->select(sk, sel_type, wait));
-}
-
-
-static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct sock *sk;
- int err;
-
- DPRINTF((DBG_INET, "INET: in inet_ioctl\n"));
- sk = NULL;
- if (sock && (sk = (struct sock *) sock->data) == NULL)
- {
- printk("AF_INET: Warning: sock->data = NULL: %d\n" , __LINE__);
- return(0);
- }
-
- switch(cmd)
- {
- case FIOSETOWN:
- case SIOCSPGRP:
- err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
- if(err)
- return err;
- if (sk)
- sk->proc = get_fs_long((int *) arg);
- return(0);
- case FIOGETOWN:
- case SIOCGPGRP:
- if (sk)
- {
- err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
- if(err)
- return err;
- put_fs_long(sk->proc,(int *)arg);
- }
- return(0);
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_INET));
-
- case SIOCADDRT:
- case SIOCDELRT:
- return(rt_ioctl(cmd,(void *) arg));
-
- case SIOCDARP:
- case SIOCGARP:
- case SIOCSARP:
- return(arp_ioctl(cmd,(void *) arg));
-
- case IP_SET_DEV:
- case SIOCGIFCONF:
- case SIOCGIFFLAGS:
- case SIOCSIFFLAGS:
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- case SIOCGIFMEM:
- case SIOCSIFMEM:
- case SIOCGIFMTU:
- case SIOCSIFMTU:
- case SIOCSIFLINK:
- case SIOCGIFHWADDR:
- return(dev_ioctl(cmd,(void *) arg));
-
- default:
- if (!sk || !sk->prot->ioctl)
- return(-EINVAL);
- return(sk->prot->ioctl(sk, cmd, arg));
- }
- /*NOTREACHED*/
- return(0);
-}
-
-
-
-/*
- * This routine must find a socket given a TCP or UDP header.
- * Everyhting is assumed to be in net order.
- */
-struct sock *get_sock(struct proto *prot, unsigned short num,
- unsigned long raddr,
- unsigned short rnum, unsigned long laddr)
-{
- struct sock *s;
- unsigned short hnum;
-
- hnum = ntohs(num);
- DPRINTF((DBG_INET, "get_sock(prot=%X, num=%d, raddr=%X, rnum=%d, laddr=%X)\n",
- prot, num, raddr, rnum, laddr));
-
- /*
- * SOCK_ARRAY_SIZE must be a power of two. This will work better
- * than a prime unless 3 or more sockets end up using the same
- * array entry. This should not be a problem because most
- * well known sockets don't overlap that much, and for
- * the other ones, we can just be careful about picking our
- * socket number when we choose an arbitrary one.
- */
- for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];s != NULL; s = s->next)
- {
- if (s->num != hnum)
- continue;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(prot == &udp_prot)
- return s;
- if(ip_addr_match(s->daddr,raddr)==0)
- continue;
- if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
- continue;
- if(ip_addr_match(s->saddr,laddr) == 0)
- continue;
- return(s);
- }
- return(NULL);
-}
-
-
-void release_sock(struct sock *sk)
-{
- if (!sk)
- {
- printk("sock.c: release_sock sk == NULL\n");
- return;
- }
- /* This one _IS_ legal */
- if (!sk->prot)
- {
- return;
- }
-
- if (sk->blog)
- return;
-
- /* See if we have any packets built up. */
- cli();
- sk->inuse = 1;
- while(sk->back_log != NULL)
- {
- struct sk_buff *skb;
-
- sk->blog = 1;
- skb =(struct sk_buff *)sk->back_log;
- DPRINTF((DBG_INET, "release_sock: skb = %X:\n", skb));
- if (skb->next != skb)
- {
- sk->back_log = skb->next;
- skb->prev->next = skb->next;
- skb->next->prev = skb->prev;
- }
- else
- {
- sk->back_log = NULL;
- }
- sti();
- DPRINTF((DBG_INET, "sk->back_log = %X\n", sk->back_log));
- if (sk->prot->rcv)
- sk->prot->rcv(skb, skb->dev, sk->opt,
- skb->saddr, skb->len, skb->daddr, 1,
- /* Only used for/by raw sockets. */
- (struct inet_protocol *)sk->pair);
- cli();
- }
- sk->blog = 0;
- sk->inuse = 0;
- sti();
- if (sk->dead && sk->state == TCP_CLOSE)
- {
- /* Should be about 2 rtt's */
- reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
- }
-}
-
-
-static int inet_fioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int minor, ret;
-
- /* Extract the minor number on which we work. */
- minor = MINOR(inode->i_rdev);
- if (minor != 0)
- return(-ENODEV);
-
- /* Now dispatch on the minor device. */
- switch(minor)
- {
- case 0: /* INET */
- ret = inet_ioctl(NULL, cmd, arg);
- break;
- case 1: /* IP */
- ret = ip_ioctl(NULL, cmd, arg);
- break;
- case 2: /* ICMP */
- ret = icmp_ioctl(NULL, cmd, arg);
- break;
- case 3: /* TCP */
- ret = tcp_ioctl(NULL, cmd, arg);
- break;
- case 4: /* UDP */
- ret = udp_ioctl(NULL, cmd, arg);
- break;
- default:
- ret = -ENODEV;
- }
-
- return(ret);
-}
-
-
-static struct file_operations inet_fops =
-{
- NULL, /* LSEEK */
- NULL, /* READ */
- NULL, /* WRITE */
- NULL, /* READDIR */
- NULL, /* SELECT */
- inet_fioctl, /* IOCTL */
- NULL, /* MMAP */
- NULL, /* OPEN */
- NULL /* CLOSE */
-};
-
-
-static struct proto_ops inet_proto_ops =
-{
- AF_INET,
-
- inet_create,
- inet_dup,
- inet_release,
- inet_bind,
- inet_connect,
- inet_socketpair,
- inet_accept,
- inet_getname,
- inet_read,
- inet_write,
- inet_select,
- inet_ioctl,
- inet_listen,
- inet_send,
- inet_recv,
- inet_sendto,
- inet_recvfrom,
- inet_shutdown,
- inet_setsockopt,
- inet_getsockopt,
- inet_fcntl,
-};
-
-extern unsigned long seq_offset;
-
-/*
- * Called by ddi.c on kernel startup.
- */
-
-void inet_proto_init(struct ddi_proto *pro)
-{
- struct inet_protocol *p;
- int i;
-
- printk("Swansea University Computer Society Net2Debugged [1.28]\n");
- /* Set up our UNIX VFS major device. */
- if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0)
- {
- printk("%s: cannot register major device %d!\n",
- pro->name, AF_INET_MAJOR);
- return;
- }
-
- /* Tell SOCKET that we are alive... */
- (void) sock_register(inet_proto_ops.family, &inet_proto_ops);
-
- seq_offset = CURRENT_TIME*250;
-
- /* Add all the protocols. */
- for(i = 0; i < SOCK_ARRAY_SIZE; i++)
- {
- tcp_prot.sock_array[i] = NULL;
- udp_prot.sock_array[i] = NULL;
- raw_prot.sock_array[i] = NULL;
- }
- printk("IP Protocols: ");
- for(p = inet_protocol_base; p != NULL;)
- {
- struct inet_protocol *tmp;
-
- tmp = (struct inet_protocol *) p->next;
- inet_add_protocol(p);
- printk("%s%s",p->name,tmp?", ":"\n");
- p = tmp;
- }
-
-}
diff --git a/net/inet/sockinet.h b/net/inet/sockinet.h
index 2e25e03..e69de29 100644
--- a/net/inet/sockinet.h
+++ b/net/inet/sockinet.h
@@ -1,118 +0,0 @@
-/*
- * Definitions for the socket handler
- *
- * Version: @(#)sock.h 1.28 26/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Florian La Roche <flla@stud.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : Volatiles in skbuff pointers. See
- * skbuff comments. May be overdone,
- * better to prove they can be removed
- * than the reverse.
- * Alan Cox : Added a zapped field for tcp to note
- * a socket is reset and must stay shut up
- * Alan Cox : New fields for options
- * Pauline Middelink : identd support
- * Alan Cox : Split into sock.h and sockinet.h
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _SOCKINET_H
-#define _SOCKINET_H
-
-#ifndef _SOCK_H
-#include "socket/sock.h"
-#endif
-
-#ifndef _PROTOCOL_H_
-#include "protocol.h"
-#endif
-
-struct proto {
- void *(*wmalloc)(struct sock *sk,
- unsigned long size, int force,
- int priority);
- void *(*rmalloc)(struct sock *sk,
- unsigned long size, int force,
- int priority);
- void (*wfree)(struct sock *sk, void *mem,
- unsigned long size);
- void (*rfree)(struct sock *sk, void *mem,
- unsigned long size);
- unsigned long (*rspace)(struct sock *sk);
- unsigned long (*wspace)(struct sock *sk);
- void (*close)(struct sock *sk, int timeout);
- int (*read)(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags);
- int (*write)(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags);
- int (*sendto)(struct sock *sk,
- unsigned char *from, int len, int noblock,
- unsigned flags, struct sockaddr_in *usin,
- int addr_len);
- int (*recvfrom)(struct sock *sk,
- unsigned char *from, int len, int noblock,
- unsigned flags, struct sockaddr_in *usin,
- int *addr_len);
- int (*build_header)(struct sk_buff *skb,
- unsigned long saddr,
- unsigned long daddr,
- struct device **dev, int type,
- struct options *opt, int len,
- int ttl, int tos);
- int (*connect)(struct sock *sk,
- struct sockaddr_in *usin, int addr_len);
- struct sock *(*accept) (struct sock *sk, int flags);
- void (*queue_xmit)(struct sock *sk,
- struct device *dev, struct sk_buff *skb,
- int free);
- void (*retransmit)(struct sock *sk, int all);
- void (*write_wakeup)(struct sock *sk);
- void (*read_wakeup)(struct sock *sk);
- int (*rcv)(struct sk_buff *buff, struct device *dev,
- struct options *opt, unsigned long daddr,
- unsigned short len, unsigned long saddr,
- int redo, struct inet_protocol *protocol);
- int (*select)(struct sock *sk, int which,
- select_table *wait);
- int (*ioctl)(struct sock *sk, int cmd,
- 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];
- char name[80];
-};
-
-extern void destroy_sock(struct sock *sk);
-extern unsigned short get_new_socknum(struct proto *, unsigned short);
-extern void put_sock(unsigned short, struct sock *);
-extern void release_sock(struct sock *sk);
-extern struct sock *get_sock(struct proto *, unsigned short,
- unsigned long, unsigned short,
- unsigned long);
-
-
-/* declarations from timer.c */
-extern struct sock *timer_base;
-
-void delete_timer (struct sock *);
-void reset_timer (struct sock *, int, unsigned long);
-void net_timer (unsigned long);
-
-
-
-#endif
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 7239e09..83dfb41 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -4,9 +4,8 @@
* interface as the means of communication with the user level.
*
* Implementation of the Transmission Control Protocol(TCP).
- * This protocol is described in RFC793.
*
- * Version: @(#)tcp.c 1.28 25/12/93
+ * Version: @(#)tcp.c 1.0.16 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -15,9 +14,9 @@
* Florian La Roche, <flla@stud.uni-sb.de>
*
* Fixes:
- * Alan Cox : Numerous verify_area() calls.
- * Alan Cox : Set the ACK bit on a reset.
- * Alan Cox : Stopped it crashing if it closed while sk->inuse=1.
+ * Alan Cox : Numerous verify_area() calls
+ * Alan Cox : Set the ACK bit on a reset
+ * Alan Cox : Stopped it crashing if it closed while sk->inuse=1
* and was trying to connect (tcp_err()).
* Alan Cox : All icmp error handling was broken
* pointers passed where wrong and the
@@ -25,39 +24,29 @@
* tested any icmp error code obviously.
* Alan Cox : tcp_err() now handled properly. It wakes people
* on errors. select behaves and the icmp error race
- * has gone by moving it into sock.c.
+ * has gone by moving it into sock.c
* Alan Cox : tcp_reset() fixed to work for everything not just
* packets for unknown sockets.
* Alan Cox : tcp option processing.
- * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong].
- * Herp Rosmanith : More reset fixes.
+ * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong]
+ * Herp Rosmanith : More reset fixes
* Alan Cox : No longer acks invalid rst frames. Acking
* any kind of RST is right out.
* Alan Cox : Sets an ignore me flag on an rst receive
- * otherwise odd bits of prattle escape still.
+ * otherwise odd bits of prattle escape still
* Alan Cox : Fixed another acking RST frame bug. Should stop
* LAN workplace lockups.
- * Alan Cox : Some tidyups using the new skb list facilities.
- * Alan Cox : sk->keepopen now seems to work.
- * Alan Cox : Pulls options out correctly on accepts.
- * Alan Cox : Fixed assorted sk->rqueue->next errors.
+ * Alan Cox : Some tidyups using the new skb list facilities
+ * Alan Cox : sk->keepopen now seems to work
+ * Alan Cox : Pulls options out correctly on accepts
+ * Alan Cox : Fixed assorted sk->rqueue->next errors
* Alan Cox : PSH doesn't end a TCP read. Switched a bit to skb ops.
* Alan Cox : Tidied tcp_data to avoid a potential nasty.
- * Alan Cox : Added some beter commenting, as the tcp is hard to follow.
- * Alan Cox : Removed incorrect check for 20 * psh.
+ * Alan Cox : Added some beter commenting, as the tcp is hard to follow
+ * Alan Cox : Removed incorrect check for 20 * psh
* Michael O'Reilly : ack < copied bug fix.
* Johannes Stille : Misc tcp fixes (not all in yet).
- * Alan Cox : FIN with no memory -> CRASH.
- * Alan Cox : Tidied up ready for final release and merge of other fixes.
- * Alan Cox : Missing logic on FIN events.
- * Alan Cox : Missing SYN bit check added (was #defined out in error).
- * Alan Cox : recvfrom() semantics corrected - short recv ok, return on PSH flag.
- * Alan Cox : window no longer memory driven so doesn't shrink illegally.
- * Alan Cox : Added socket option proto entries. Also added awareness of them to accept.
- * Alan Cox : State machine error causing Linus the ACK explosion problem found
- * Unsynchronized states now send RST to bad ack frames as per RFC793 page 34.
- * Alan Cox : Added TCP options (SOL_TCP)
- * Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets.
+ * Alan Cox : FIN with no memory -> CRASH
*
*
* To Fix:
@@ -65,9 +54,12 @@
* it causes a select. Linux can - given the official select semantics I
* feel that _really_ its the BSD network programs that are bust (notably
* inetd, which hangs occasionally because of this).
+ * Proper processing of piggybacked data on connect.
+ * Add VJ Fastrecovery algorithm ?
* Protocol closedown badly messed up.
- * MSG_PEEK and read on same socket at once can cause crashes (in theory)
- * Should use the partial packet to piggy back acks.
+ * Incompatiblity with spider ports (tcp hangs on that
+ * socket occasionally).
+ * MSG_PEEK and read on same socket at once can cause crashes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -84,13 +76,13 @@
#include <linux/in.h>
#include <linux/fcntl.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "arp.h"
#include <linux/errno.h>
#include <linux/timer.h>
@@ -104,72 +96,67 @@ unsigned long seq_offset;
static __inline__ int
min(unsigned int a, unsigned int b)
{
- if (a < b)
- return(a);
- return(b);
+ if (a < b) return(a);
+ return(b);
}
-void print_th(struct tcphdr *th)
+void
+print_th(struct tcphdr *th)
{
- unsigned char *ptr;
-
- if (inet_debug != DBG_TCP)
- return;
-
- printk("TCP header:\n");
- ptr =(unsigned char *)(th + 1);
- printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
- ntohs(th->source), ntohs(th->dest),
- ntohl(th->seq), ntohl(th->ack_seq));
- printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
- th->fin, th->syn, th->rst, th->psh, th->ack,
- th->urg, th->res1, th->res2);
- printk(" window = %d, check = %d urg_ptr = %d\n",
- ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
- printk(" doff = %d\n", th->doff);
- printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
+ unsigned char *ptr;
+
+ if (inet_debug != DBG_TCP) return;
+
+ printk("TCP header:\n");
+ ptr =(unsigned char *)(th + 1);
+ printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n",
+ ntohs(th->source), ntohs(th->dest),
+ ntohl(th->seq), ntohl(th->ack_seq));
+ printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n",
+ th->fin, th->syn, th->rst, th->psh, th->ack,
+ th->urg, th->res1, th->res2);
+ printk(" window = %d, check = %d urg_ptr = %d\n",
+ ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
+ printk(" doff = %d\n", th->doff);
+ printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);
}
-/*
- * This routine grabs the first thing off of a rcv queue.
- */
-
-static struct sk_buff *get_firstr(struct sock *sk)
+/* This routine grabs the first thing off of a rcv queue. */
+static struct sk_buff *
+get_firstr(struct sock *sk)
{
- return skb_dequeue(&sk->rqueue);
+ return skb_dequeue(&sk->rqueue);
}
/*
* Difference between two values in tcp ack terms.
*/
-static long diff(unsigned long seq1, unsigned long seq2)
+static long
+diff(unsigned long seq1, unsigned long seq2)
{
- long d;
+ long d;
- d = seq1 - seq2;
- if (d > 0)
- return(d);
+ d = seq1 - seq2;
+ if (d > 0) return(d);
- /* I hope this returns what I want. */
- return(~d+1);
+ /* I hope this returns what I want. */
+ return(~d+1);
}
-/*
- * Enter the time wait state.
- */
+/* Enter the time wait state. */
static void tcp_time_wait(struct sock *sk)
{
- sk->state = TCP_TIME_WAIT;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- sk->state_change(sk);
- reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ sk->state = TCP_TIME_WAIT;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ wake_up(sk->sleep);
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
}
/*
@@ -179,20 +166,20 @@ static void tcp_time_wait(struct sock *sk)
* nothing clever here.
*/
-static void tcp_retransmit(struct sock *sk, int all)
+static void
+tcp_retransmit(struct sock *sk, int all)
{
- if (all)
- {
- ip_retransmit(sk, all);
- return;
- }
+ if (all) {
+ ip_retransmit(sk, all);
+ return;
+ }
- if (sk->cong_window > 4)
- sk->cong_window = sk->cong_window / 2;
- sk->exp_growth = 0;
+ if (sk->cong_window > 4)
+ sk->cong_window = sk->cong_window / 2;
+ sk->exp_growth = 0;
- /* Do the actuall retransmit. */
- ip_retransmit(sk, all);
+ /* Do the actuall retransmit. */
+ ip_retransmit(sk, all);
}
@@ -204,61 +191,56 @@ static void tcp_retransmit(struct sock *sk, int all)
* header points to the first 8 bytes of the tcp header. We need
* to find the appropriate port.
*/
-void tcp_err(int err, unsigned char *header, unsigned long daddr,
+void
+tcp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
- struct tcphdr *th;
- struct sock *sk;
- struct iphdr *iph=(struct iphdr *)header;
+ struct tcphdr *th;
+ struct sock *sk;
+ struct iphdr *iph=(struct iphdr *)header;
- header+=4*iph->ihl;
+ header+=4*iph->ihl;
- DPRINTF((DBG_TCP, "TCP: tcp_err(%d, hdr=%X, daddr=%X saddr=%X, protocol=%X)\n",
+ DPRINTF((DBG_TCP, "TCP: tcp_err(%d, hdr=%X, daddr=%X saddr=%X, protocol=%X)\n",
err, header, daddr, saddr, protocol));
- th =(struct tcphdr *)header;
- sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr);
- print_th(th);
+ th =(struct tcphdr *)header;
+ sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr);
+ print_th(th);
- if (sk == NULL)
- return;
+ if (sk == NULL) return;
- if(err<0)
- {
- sk->err = -err;
- sk->error_report(sk);
- return;
- }
-
- if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8))
- {
- /*
- * FIXME:
- * For now we will just trigger a linear backoff.
- * The slow start code should cause a real backoff here.
- */
- if (sk->cong_window > 4) sk->cong_window--;
- return;
- }
+ if(err<0)
+ {
+ sk->err = -err;
+ wake_up(sk->sleep);
+ return;
+ }
- DPRINTF((DBG_TCP, "TCP: icmp_err got error\n"));
- sk->err = icmp_err_convert[err & 0xff].errno;
+ if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) {
+ /*
+ * FIXME:
+ * For now we will just trigger a linear backoff.
+ * The slow start code should cause a real backoff here.
+ */
+ if (sk->cong_window > 4) sk->cong_window--;
+ return;
+ }
- /*
- * If we've already connected we will keep trying
- * until we time out, or the user gives up.
- */
+ DPRINTF((DBG_TCP, "TCP: icmp_err got error\n"));
+ sk->err = icmp_err_convert[err & 0xff].errno;
- if (icmp_err_convert[err & 0xff].fatal)
- {
- if (sk->state == TCP_SYN_SENT)
- {
- sk->state = TCP_CLOSE;
- sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */
- sk->state_change(sk);
- }
- }
- return;
+ /*
+ * If we've already connected we will keep trying
+ * until we time out, or the user gives up.
+ */
+ if (icmp_err_convert[err & 0xff].fatal) {
+ if (sk->state == TCP_SYN_SENT) {
+ sk->state = TCP_CLOSE;
+ wake_up(sk->sleep); /* Wake people up to see the error (see connect in sock.c) */
+ }
+ }
+ return;
}
@@ -267,63 +249,66 @@ void tcp_err(int err, unsigned char *header, unsigned long daddr,
* in the received data queue (ie a frame missing that needs sending to us)
*/
-static int tcp_readable(struct sock *sk)
+static int
+tcp_readable(struct sock *sk)
{
- unsigned long counted;
- unsigned long amount;
- struct sk_buff *skb;
- int count=0;
- int sum;
- unsigned long flags;
-
- DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk));
- if(sk && sk->debug)
- printk("tcp_readable: %p - ",sk);
-
- if (sk == NULL || skb_peek(&sk->rqueue) == NULL) /* Empty sockets are easy! */
- {
- if(sk && sk->debug)
- printk("empty\n");
- return(0);
- }
+ unsigned long counted;
+ unsigned long amount;
+ struct sk_buff *skb;
+ int count=0;
+ int sum;
+ unsigned long flags;
+
+ DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk));
+ if(sk && sk->debug)
+ printk("tcp_readable: %p - ",sk);
+
+ if (sk == NULL || skb_peek(&sk->rqueue) == NULL) /* Empty sockets are easy! */
+ {
+ if(sk && sk->debug)
+ printk("empty\n");
+ return(0);
+ }
- counted = sk->copied_seq+1; /* Where we are at the moment */
- amount = 0;
+ counted = sk->copied_seq+1; /* Where we are at the moment */
+ amount = 0;
- save_flags(flags); /* So nobody adds things at the wrong moment */
- cli();
- skb =(struct sk_buff *)sk->rqueue;
-
- /* Do until a push or until we are out of data. */
- do
- {
- count++;
- if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */
- break;
- sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */
- if (skb->h.th->syn)
- sum++;
- if (skb->h.th->urg)
- {
- sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */
- }
- if (sum >= 0)
- { /* Add it up, move on */
- amount += sum;
- if (skb->h.th->syn)
- amount--;
- counted += sum;
- }
-/* if (amount && skb->h.th->psh)
- break;*/
- skb =(struct sk_buff *)skb->next; /* Move along */
- }
- while(skb != sk->rqueue);
- restore_flags(flags);
- DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount));
- if(sk->debug)
- printk("got %lu bytes.\n",amount);
- return(amount);
+ save_flags(flags); /* So nobody adds things at the wrong moment */
+ cli();
+ skb =(struct sk_buff *)sk->rqueue;
+
+ /* Do until a push or until we are out of data. */
+ do {
+ count++;
+#ifdef OLD
+ /* This is wrong: It breaks Chameleon amongst other stacks */
+ if (count > 20) {
+ restore_flags(flags);
+ DPRINTF((DBG_TCP, "tcp_readable, more than 20 packets without a psh\n"));
+ printk("tcp_read: possible read_queue corruption.\n");
+ return(amount);
+ }
+#endif
+ if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */
+ break;
+ sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */
+ if (skb->h.th->syn) sum++;
+ if (skb->h.th->urg) {
+ sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */
+ }
+ if (sum >= 0) { /* Add it up, move on */
+ amount += sum;
+ if (skb->h.th->syn) amount--;
+ counted += sum;
+ }
+/* if (amount && skb->h.th->psh) break;*/
+ skb =(struct sk_buff *)skb->next; /* Move along */
+ } while(skb != sk->rqueue);
+ restore_flags(flags);
+ DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount));
+ if(sk->debug)
+ printk("got %lu bytes.\n",amount);
+ return(amount);
}
@@ -332,120 +317,112 @@ static int tcp_readable(struct sock *sk)
* listening socket has a receive queue of sockets to accept.
*/
-static int tcp_select(struct sock *sk, int sel_type, select_table *wait)
+static int
+tcp_select(struct sock *sk, int sel_type, select_table *wait)
{
- DPRINTF((DBG_TCP, "tcp_select(sk=%X, sel_type = %d, wait = %X)\n",
+ DPRINTF((DBG_TCP, "tcp_select(sk=%X, sel_type = %d, wait = %X)\n",
sk, sel_type, wait));
- sk->inuse = 1;
- switch(sel_type)
- {
- case SEL_IN:
- if(sk->debug)
- printk("select in");
- select_wait(sk->sleep, wait);
- if(sk->debug)
+ sk->inuse = 1;
+ switch(sel_type) {
+ case SEL_IN:
+ if(sk->debug)
+ printk("select in");
+ select_wait(sk->sleep, wait);
+ if(sk->debug)
printk("-select out");
- if (skb_peek(&sk->rqueue) != NULL)
- {
- if (sk->state == TCP_LISTEN || tcp_readable(sk))
- {
- release_sock(sk);
- if(sk->debug)
- printk("-select ok data\n");
- return(1);
- }
- }
- if (sk->err != 0) /* Receiver error */
- {
- release_sock(sk);
- if(sk->debug)
- printk("-select ok error");
- return(1);
- }
- if (sk->shutdown & RCV_SHUTDOWN)
- {
+ if (skb_peek(&sk->rqueue) != NULL) {
+ if (sk->state == TCP_LISTEN || tcp_readable(sk)) {
release_sock(sk);
if(sk->debug)
- printk("-select ok down\n");
+ printk("-select ok data\n");
return(1);
- }
- else
- {
- release_sock(sk);
- if(sk->debug)
- printk("-select fail\n");
- return(0);
- }
- case SEL_OUT:
- select_wait(sk->sleep, wait);
- if (sk->shutdown & SEND_SHUTDOWN)
- {
- DPRINTF((DBG_TCP,
- "write select on shutdown socket.\n"));
- /* FIXME: should this return an error? */
- release_sock(sk);
- return(0);
}
+ }
+ if (sk->err != 0) /* Receiver error */
+ {
+ release_sock(sk);
+ if(sk->debug)
+ printk("-select ok error");
+ return(1);
+ }
+ if (sk->shutdown & RCV_SHUTDOWN) {
+ release_sock(sk);
+ if(sk->debug)
+ printk("-select ok down\n");
+ return(1);
+ } else {
+ release_sock(sk);
+ if(sk->debug)
+ printk("-select fail\n");
+ return(0);
+ }
+ case SEL_OUT:
+ select_wait(sk->sleep, wait);
+ if (sk->shutdown & SEND_SHUTDOWN) {
+ DPRINTF((DBG_TCP,
+ "write select on shutdown socket.\n"));
+
+ /* FIXME: should this return an error? */
+ release_sock(sk);
+ return(0);
+ }
+
/*
* FIXME:
* Hack so it will probably be able to write
* something if it says it's ok to write.
*/
- if (sk->prot->wspace(sk) >= sk->mtu)
- {
- release_sock(sk);
- /* This should cause connect to work ok. */
- if (sk->state == TCP_SYN_RECV ||
- sk->state == TCP_SYN_SENT)
- return(0);
- return(1);
- }
- DPRINTF((DBG_TCP,
- "tcp_select: sleeping on write sk->wmem_alloc = %d, "
- "sk->packets_out = %d\n"
- "sk->wback = %X, sk->wfront = %X\n"
- "sk->send_seq = %u, sk->window_seq=%u\n",
- sk->wmem_alloc, sk->packets_out,
- sk->wback, sk->wfront,
- sk->send_seq, sk->window_seq));
-
+ if (sk->prot->wspace(sk) >= sk->mtu) {
release_sock(sk);
- return(0);
- case SEL_EX:
- select_wait(sk->sleep,wait);
- if (sk->err)
- {
- release_sock(sk);
- return(1);
- }
+ /* This should cause connect to work ok. */
+ if (sk->state == TCP_SYN_RECV ||
+ sk->state == TCP_SYN_SENT) return(0);
+ return(1);
+ }
+ DPRINTF((DBG_TCP,
+ "tcp_select: sleeping on write sk->wmem_alloc = %d, "
+ "sk->packets_out = %d\n"
+ "sk->wback = %X, sk->wfront = %X\n"
+ "sk->send_seq = %u, sk->window_seq=%u\n",
+ sk->wmem_alloc, sk->packets_out,
+ sk->wback, sk->wfront,
+ sk->send_seq, sk->window_seq));
+
+ release_sock(sk);
+ return(0);
+ case SEL_EX:
+ select_wait(sk->sleep,wait);
+ if (sk->err) {
release_sock(sk);
- return(0);
- }
+ return(1);
+ }
+ release_sock(sk);
+ return(0);
+ }
- release_sock(sk);
- return(0);
+ release_sock(sk);
+ return(0);
}
-int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+int
+tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- int err;
- DPRINTF((DBG_TCP, "tcp_ioctl(sk=%X, cmd = %d, arg=%X)\n", sk, cmd, arg));
- switch(cmd)
- {
- case DDIOCSDBG:
- return(dbg_ioctl((void *) arg, DBG_TCP));
+ int err;
+ DPRINTF((DBG_TCP, "tcp_ioctl(sk=%X, cmd = %d, arg=%X)\n", sk, cmd, arg));
+ switch(cmd) {
+ case DDIOCSDBG:
+ return(dbg_ioctl((void *) arg, DBG_TCP));
- case TIOCINQ:
+ case TIOCINQ:
#ifdef FIXME /* FIXME: */
- case FIONREAD:
+ case FIONREAD:
#endif
{
unsigned long amount;
- if (sk->state == TCP_LISTEN)
- return(-EINVAL);
+ if (sk->state == TCP_LISTEN) return(-EINVAL);
sk->inuse = 1;
amount = tcp_readable(sk);
@@ -458,7 +435,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
- case SIOCATMARK:
+ case SIOCATMARK:
{
struct sk_buff *skb;
int answ = 0;
@@ -471,7 +448,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
if ((skb=skb_peek(&sk->rqueue)) != NULL)
{
if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg)
- answ = 1;
+ answ = 1;
}
release_sock(sk);
err=verify_area(VERIFY_WRITE,(void *) arg,
@@ -481,12 +458,11 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
put_fs_long(answ,(int *) arg);
return(0);
}
- case TIOCOUTQ:
+ case TIOCOUTQ:
{
unsigned long amount;
- if (sk->state == TCP_LISTEN)
- return(-EINVAL);
+ if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = sk->prot->wspace(sk);
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
@@ -495,1288 +471,986 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
- default:
- return(-EINVAL);
- }
+ default:
+ return(-EINVAL);
+ }
}
-/*
- * This routine computes a TCP checksum.
- */
-
-unsigned short tcp_check(struct tcphdr *th, int len,
+/* This routine computes a TCP checksum. */
+unsigned short
+tcp_check(struct tcphdr *th, int len,
unsigned long saddr, unsigned long daddr)
{
- unsigned long sum;
+ unsigned long sum;
- if (saddr == 0)
- saddr = my_addr();
- print_th(th);
- __asm__("\t addl %%ecx,%%ebx\n"
- "\t adcl %%edx,%%ebx\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum)
- : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
- : "cx","bx","dx" );
+ if (saddr == 0) saddr = my_addr();
+ print_th(th);
+ __asm__("\t addl %%ecx,%%ebx\n"
+ "\t adcl %%edx,%%ebx\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum)
+ : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
+ : "cx","bx","dx" );
- if (len > 3)
- {
- __asm__("\tclc\n"
- "1:\n"
- "\t lodsl\n"
- "\t adcl %%eax, %%ebx\n"
- "\t loop 1b\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum) , "=S"(th)
- : "0"(sum), "c"(len/4) ,"1"(th)
- : "ax", "cx", "bx", "si" );
- }
+ if (len > 3) {
+ __asm__("\tclc\n"
+ "1:\n"
+ "\t lodsl\n"
+ "\t adcl %%eax, %%ebx\n"
+ "\t loop 1b\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum) , "=S"(th)
+ : "0"(sum), "c"(len/4) ,"1"(th)
+ : "ax", "cx", "bx", "si" );
+ }
- /* Convert from 32 bits to 16 bits. */
- __asm__("\t movl %%ebx, %%ecx\n"
- "\t shrl $16,%%ecx\n"
- "\t addw %%cx, %%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum)
- : "bx", "cx");
-
- /* Check for an extra word. */
- if ((len & 2) != 0)
- {
- __asm__("\t lodsw\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum), "=S"(th)
- : "0"(sum) ,"1"(th)
- : "si", "ax", "bx");
- }
+ /* Convert from 32 bits to 16 bits. */
+ __asm__("\t movl %%ebx, %%ecx\n"
+ "\t shrl $16,%%ecx\n"
+ "\t addw %%cx, %%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum)
+ : "bx", "cx");
- /* Now check for the extra byte. */
- if ((len & 1) != 0)
- {
- __asm__("\t lodsb\n"
- "\t movb $0,%%ah\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum) ,"S"(th)
- : "si", "ax", "bx");
- }
+ /* Check for an extra word. */
+ if ((len & 2) != 0) {
+ __asm__("\t lodsw\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum), "=S"(th)
+ : "0"(sum) ,"1"(th)
+ : "si", "ax", "bx");
+ }
- /* We only want the bottom 16 bits, but we never cleared the top 16. */
- return((~sum) & 0xffff);
+ /* Now check for the extra byte. */
+ if ((len & 1) != 0) {
+ __asm__("\t lodsb\n"
+ "\t movb $0,%%ah\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum) ,"S"(th)
+ : "si", "ax", "bx");
+ }
+
+ /* We only want the bottom 16 bits, but we never cleared the top 16. */
+ return((~sum) & 0xffff);
}
-void tcp_send_check(struct tcphdr *th, unsigned long saddr,
+void
+tcp_send_check(struct tcphdr *th, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
- th->check = 0;
- th->check = tcp_check(th, len, saddr, daddr);
- return;
+ th->check = 0;
+ th->check = tcp_check(th, len, saddr, daddr);
+ return;
}
-/*
- * Send current partially built frame
- */
-static void tcp_send_partial(struct sock *sk)
+static void
+tcp_send_partial(struct sock *sk)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
- if (sk == NULL || sk->send_tmp == NULL)
- return;
+ if (sk == NULL || sk->send_tmp == NULL) return;
- skb = sk->send_tmp;
+ skb = sk->send_tmp;
- /* We need to complete and send the packet. */
-
- /*
- * Fill in the checksum
- */
-
- tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
+ /* We need to complete and send the packet. */
+ tcp_send_check(skb->h.th, sk->saddr, sk->daddr,
skb->len-(unsigned long)skb->h.th +
(unsigned long)(skb+1), sk);
- /*
- * Fill in the sequence number
- */
- skb->h.seq = sk->send_seq;
-
- /*
- * Check the window and packet counts to
- * see where it goes
- */
- if (after(sk->send_seq , sk->window_seq) ||
- sk->packets_out >= sk->cong_window)
- {
- DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
- sk->cong_window, sk->packets_out));
- DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
- sk->send_seq, sk->window_seq));
- skb->next = NULL;
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (sk->wback == NULL)
- {
- sk->wfront=skb;
- }
- else
- {
- sk->wback->next = skb;
- }
- sk->wback = skb;
- }
- else
- {
- sk->prot->queue_xmit(sk, skb->dev, skb,0);
- }
- sk->send_tmp = NULL;
+ skb->h.seq = sk->send_seq;
+ if (after(sk->send_seq , sk->window_seq) ||
+ sk->packets_out >= sk->cong_window) {
+ DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
+ sk->cong_window, sk->packets_out));
+ DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
+ sk->send_seq, sk->window_seq));
+ skb->next = NULL;
+ skb->magic = TCP_WRITE_QUEUE_MAGIC;
+ if (sk->wback == NULL) {
+ sk->wfront=skb;
+ } else {
+ sk->wback->next = skb;
+ }
+ sk->wback = skb;
+ } else {
+ sk->prot->queue_xmit(sk, skb->dev, skb,0);
+ }
+ sk->send_tmp = NULL;
}
-/*
- * This routine sends an ack and also updates the window.
- */
-
-static void tcp_send_ack(unsigned long sequence, unsigned long ack,
+/* This routine sends an ack and also updates the window. */
+static void
+tcp_send_ack(unsigned long sequence, unsigned long ack,
struct sock *sk,
struct tcphdr *th, unsigned long daddr)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- struct device *dev = NULL;
- int tmp;
-
- if(sk->zapped)
- return; /* We have been reset, we may not send again */
- /*
- * We need to grab some memory, and put together an ack,
- * and then put it into the queue to be sent.
- */
- buff = (struct sk_buff *) sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- {
- /* Force it to send an ack. */
- sk->ack_backlog++;
- if (sk->timeout != TIME_WRITE && tcp_connected(sk->state))
- {
- reset_timer(sk, TIME_WRITE, 10);
- }
- if (inet_debug == DBG_SLIP)
- printk("\rtcp_ack: malloc failed\n");
- return;
- }
-
- buff->mem_addr = buff;
- buff->mem_len = MAX_ACK_SIZE;
- buff->len = sizeof(struct tcphdr);
- buff->sk = sk;
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,
- sk->ip_ttl,sk->ip_tos);
- if (tmp < 0)
- {
- buff->free=1;
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
- return;
- }
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)t1 +tmp);
-
- /* FIXME: */
- memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
-
- /* swap the send and the receive. */
- t1->dest = th->source;
- t1->source = th->dest;
- t1->seq = ntohl(sequence);
- t1->ack = 1;
- sk->window = 4096/*sk->prot->rspace(sk)*/;
- t1->window = ntohs(sk->window);
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
- t1->fin = 0;
- if (ack == sk->acked_seq)
- {
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->ack_timed = 0;
- if (sk->send_head == NULL && sk->wfront == NULL)
- {
-/* delete_timer(sk);*/
- }
- }
- t1->ack_seq = ntohl(ack);
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
- if (sk->debug)
- printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
- sk->prot->queue_xmit(sk, dev, buff, 1);
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ struct device *dev = NULL;
+ int tmp;
+
+ if(sk->zapped)
+ return; /* We have been reset, we may not send again */
+ /*
+ * We need to grab some memory, and put together an ack,
+ * and then put it into the queue to be sent.
+ */
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL) {
+ /* Force it to send an ack. */
+ sk->ack_backlog++;
+ if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) {
+ reset_timer(sk, TIME_WRITE, 10);
+ }
+if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
+ return;
+ }
+
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_ACK_SIZE;
+ buff->len = sizeof(struct tcphdr);
+ buff->sk = sk;
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+ if (tmp < 0) {
+ buff->free=1;
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
+ return;
+ }
+ buff->len += tmp;
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+
+ /* FIXME: */
+ memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */
+
+ /* swap the send and the receive. */
+ t1->dest = th->source;
+ t1->source = th->dest;
+ t1->seq = ntohl(sequence);
+ t1->ack = 1;
+ sk->window = sk->prot->rspace(sk);
+ t1->window = ntohs(sk->window);
+ t1->res1 = 0;
+ t1->res2 = 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->syn = 0;
+ t1->psh = 0;
+ t1->fin = 0;
+ if (ack == sk->acked_seq) {
+ sk->ack_backlog = 0;
+ sk->bytes_rcv = 0;
+ sk->ack_timed = 0;
+ if (sk->send_head == NULL && sk->wfront == NULL) {
+/* delete_timer(sk);*/
+ }
+ }
+ t1->ack_seq = ntohl(ack);
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk);
+ if (sk->debug)
+ printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack);
+ sk->prot->queue_xmit(sk, dev, buff, 1);
}
-/*
- * This routine builds a generic TCP header.
- */
-
-static int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
+/* This routine builds a generic TCP header. */
+static int
+tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
{
- /* FIXME: want to get rid of this. */
- memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
- th->seq = htonl(sk->send_seq);
- th->psh =(push == 0) ? 1 : 0;
- th->doff = sizeof(*th)/4;
- th->ack = 1;
- th->fin = 0;
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->ack_timed = 0;
- th->ack_seq = htonl(sk->acked_seq);
- sk->window = 4096-diff(sk->acked_seq,sk->copied_seq); /* sk->prot->rspace(sk); */
- th->window = htons(sk->window);
-
- return(sizeof(*th));
+ /* FIXME: want to get rid of this. */
+ memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
+ th->seq = htonl(sk->send_seq);
+ th->psh =(push == 0) ? 1 : 0;
+ th->doff = sizeof(*th)/4;
+ th->ack = 1;
+ th->fin = 0;
+ sk->ack_backlog = 0;
+ sk->bytes_rcv = 0;
+ sk->ack_timed = 0;
+ th->ack_seq = htonl(sk->acked_seq);
+ sk->window = sk->prot->rspace(sk);
+ th->window = htons(sk->window);
+
+ return(sizeof(*th));
}
/*
- * This routine copies from a user buffer into a socket,
- * and starts the transmit system.
+ * This routine copies from a user buffer into a socket,
+ * and starts the transmit system.
*/
-
-static int tcp_write(struct sock *sk, unsigned char *from,
- int len, int nonblock, unsigned flags)
+static int
+tcp_write(struct sock *sk, unsigned char *from,
+ int len, int nonblock, unsigned flags)
{
- int copied = 0;
- int copy;
- int tmp;
- struct sk_buff *skb;
- unsigned char *buff;
- struct proto *prot;
- struct device *dev = NULL;
-
- DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
+ int copied = 0;
+ int copy;
+ int tmp;
+ struct sk_buff *skb;
+ unsigned char *buff;
+ struct proto *prot;
+ struct device *dev = NULL;
+
+ DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, from, len, nonblock, flags));
- sk->inuse=1;
- prot = sk->prot;
-
- while(len > 0)
- {
- if (sk->err)
- { /* Stop on an error */
+ sk->inuse=1;
+ prot = sk->prot;
+ while(len > 0) {
+ if (sk->err) { /* Stop on an error */
+ release_sock(sk);
+ if (copied) return(copied);
+ tmp = -sk->err;
+ sk->err = 0;
+ return(tmp);
+ }
+
+ /* First thing we do is make sure that we are established. */
+ if (sk->shutdown & SEND_SHUTDOWN) {
+ release_sock(sk);
+ sk->err = EPIPE;
+ if (copied) return(copied);
+ sk->err = 0;
+ return(-EPIPE);
+ }
+
+
+ /* Wait for a connection to finish. */
+
+ while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) {
+ if (sk->err) {
release_sock(sk);
- if (copied)
- return(copied);
- /* FIXME: An error occuring between these two instructions _is_ remotely
- possible. This occurs throughout the old and new net code and needs
- fixing one day */
+ if (copied) return(copied);
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
- /* First thing we do is make sure that we are established. */
- if (sk->shutdown & SEND_SHUTDOWN)
- {
+ if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) {
release_sock(sk);
- sk->err = EPIPE;
- if (copied)
- return(copied);
- sk->err = 0;
- return(-EPIPE);
- }
-
+ DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
+ if (copied) return(copied);
- /* Wait for a connection to finish. */
-
- while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
- {
- if (sk->err)
- {
- release_sock(sk);
- if (copied)
- return(copied);
+ if (sk->err) {
tmp = -sk->err;
sk->err = 0;
return(tmp);
}
- if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV)
- {
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 1\n"));
- if (copied)
- return(copied);
-
- if (sk->err)
- {
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
-
- if (sk->keepopen)
- {
- send_sig(SIGPIPE, current, 0);
- }
- return(-EPIPE);
- }
-
- if (nonblock /*|| copied*/)
- {
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
- if (copied)
- return(copied);
- return(-EAGAIN);
+ if (sk->keepopen) {
+ send_sig(SIGPIPE, current, 0);
}
+ return(-EPIPE);
+ }
+ if (nonblock || copied) {
release_sock(sk);
- cli();
- if (sk->state != TCP_ESTABLISHED &&
- sk->state != TCP_CLOSE_WAIT && sk->err == 0)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
- if (copied)
- return(copied);
- return(-ERESTARTSYS);
- }
+ DPRINTF((DBG_TCP, "tcp_write: return 2\n"));
+ if (copied) return(copied);
+ return(-EAGAIN);
+ }
+
+ release_sock(sk);
+ cli();
+ if (sk->state != TCP_ESTABLISHED &&
+ sk->state != TCP_CLOSE_WAIT && sk->err == 0) {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked) {
+ sti();
+ DPRINTF((DBG_TCP, "tcp_write: return 3\n"));
+ if (copied) return(copied);
+ return(-ERESTARTSYS);
}
- sk->inuse = 1;
- sti();
}
- /*
- * When we finally arrive at this point we can consider transmission
- */
+ sk->inuse = 1;
+ sti();
+ }
- /*
- * Now we need to check if we have a half built packet. If so append to
- * it.
- */
-
- if (sk->send_tmp != NULL)
- {
- copy=0;
- /* Add more stuff to the end of skb->len */
- skb = sk->send_tmp;
- if (!(flags & MSG_OOB))
- {
- copy = min(sk->mss - skb->len + 128 +
+ /* Now we need to check if we have a half built packet. */
+ if (sk->send_tmp != NULL) {
+ /* If sk->mss has been changed this could cause problems. */
+
+ /* Add more stuff to the end of skb->len */
+ skb = sk->send_tmp;
+ if (!(flags & MSG_OOB)) {
+ copy = min(sk->mss - skb->len + 128 +
prot->max_header, len);
- /* FIXME: this is really a bug. */
- if (copy <= 0)
- {
- printk("TCP: **bug**: \"copy\" <= 0!!\n");
- copy = 0;
- }
-
- /*
- * Add data to the packet
- */
-
- memcpy_fromfs((unsigned char *)(skb+1) + skb->len, from, copy);
- skb->len += copy;
- from += copy;
- copied += copy;
- len -= copy;
- sk->send_seq += copy;
- }
+ /* FIXME: this is really a bug. */
+ if (copy <= 0) {
+ printk("TCP: **bug**: \"copy\" <= 0!!\n");
+ copy = 0;
+ }
+
+ memcpy_fromfs((unsigned char *)(skb+1) + skb->len, from, copy);
+ skb->len += copy;
+ from += copy;
+ copied += copy;
+ len -= copy;
+ sk->send_seq += copy;
+ }
- /*
- * Do we need to send it yet or can it wait for more data ?
- */
-
- if (skb->len -(unsigned long)skb->h.th + (unsigned long)(skb+1) >= sk->mss ||(flags & MSG_OOB) || copy==0)
- {
- tcp_send_partial(sk);
- }
- continue;
- }
-
- /*
- * We also need to worry about the window.
- * The smallest we will send is about 200 bytes.
- * This is a bit sad for TCP/AMPR people running
- * 196 byte windows! - FIXME
- */
-
- copy = min(sk->mtu, diff(sk->window_seq, sk->send_seq));
-
- /* FIXME: redundant check here. */
- if (copy < 200 || copy > sk->mtu) copy = sk->mtu;
- copy = min(copy, len);
-
- /*
- * We should really check the window here also.
- * [Why ?, Alan]
- */
-
- if (sk->packets_out && copy < sk->mss && !(flags & MSG_OOB))
- {
- /* We will release the socket in case we sleep here. */
- release_sock(sk);
-
- /*
- * Grab a packet to suit the mss.
- */
-
- skb = (struct sk_buff *) prot->wmalloc(sk,
- sk->mss + 128 + prot->max_header +
- sizeof(*skb), 0, GFP_KERNEL);
- sk->inuse = 1;
- sk->send_tmp = skb;
- if (skb != NULL)
- skb->mem_len = sk->mss + 128 + prot->max_header + sizeof(*skb);
- }
- else
- {
- /* We will release the socket in case we sleep here. */
- release_sock(sk);
- skb = (struct sk_buff *) prot->wmalloc(sk,
+ if (skb->len -(unsigned long)skb->h.th +
+ (unsigned long)(skb+1) >= sk->mss ||(flags & MSG_OOB)) {
+ tcp_send_partial(sk);
+ }
+ continue;
+ }
+
+ /*
+ * We also need to worry about the window.
+ * The smallest we will send is about 200 bytes.
+ * This is a bit sad for TCP/AMPR people running
+ * 196 byte windows! - FIXME
+ */
+ copy = min(sk->mtu, diff(sk->window_seq, sk->send_seq));
+
+ /* FIXME: redundent check here. */
+ if (copy < 200 || copy > sk->mtu) copy = sk->mtu;
+ copy = min(copy, len);
+
+ /* We should really check the window here also. */
+ if (sk->packets_out && copy < sk->mss && !(flags & MSG_OOB)) {
+ /* We will release the socket incase we sleep here. */
+ release_sock(sk);
+ skb = (struct sk_buff *) prot->wmalloc(sk,
+ sk->mss + 128 + prot->max_header +
+ sizeof(*skb), 0, GFP_KERNEL);
+ sk->inuse = 1;
+ sk->send_tmp = skb;
+ if (skb != NULL)
+ skb->mem_len = sk->mss + 128 + prot->max_header + sizeof(*skb);
+ } else {
+ /* We will release the socket incase we sleep here. */
+ release_sock(sk);
+ skb = (struct sk_buff *) prot->wmalloc(sk,
copy + prot->max_header +
sizeof(*skb), 0, GFP_KERNEL);
- sk->inuse = 1;
- if (skb != NULL)
- skb->mem_len = copy+prot->max_header + sizeof(*skb);
- }
-
- /* If we didn't get any memory, we need to sleep. */
- if (skb == NULL)
- {
- if (nonblock /* || copied */)
- {
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
- if (copied)
- return(copied);
- return(-EAGAIN);
- }
+ sk->inuse = 1;
+ if (skb != NULL)
+ skb->mem_len = copy+prot->max_header + sizeof(*skb);
+ }
- /* FIXME: here is another race condition. */
- tmp = sk->wmem_alloc;
+ /* If we didn't get any memory, we need to sleep. */
+ if (skb == NULL) {
+ if (nonblock /* || copied */) {
release_sock(sk);
- cli();
- /* Again we will try to avoid it. */
- if (tmp <= sk->wmem_alloc && (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT) && sk->err == 0)
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
- if (copied)
- return(copied);
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- continue;
+ DPRINTF((DBG_TCP, "tcp_write: return 4\n"));
+ if (copied) return(copied);
+ return(-EAGAIN);
}
-
- skb->mem_addr = skb;
- skb->len = 0;
- skb->sk = sk;
- skb->free = 0;
-
- buff =(unsigned char *)(skb+1);
- /*
- * FIXME: we need to optimize this.
- * Perhaps some hints here would be good.
- */
-
- /*
- * Begin putting the headers on the packet
- */
-
- tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, skb->mem_len, sk->ip_ttl,sk->ip_tos);
- if (tmp < 0 )
- {
- prot->wfree(sk, skb->mem_addr, skb->mem_len);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
- if (copied)
- return(copied);
- return(tmp);
- }
-
- skb->len += tmp;
- skb->dev = dev;
- buff += tmp;
- skb->h.th =(struct tcphdr *) buff;
-
- /*
- * Put the TCP header in
- */
-
- tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
- if (tmp < 0)
- {
- prot->wfree(sk, skb->mem_addr, skb->mem_len);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
- if (copied)
- return(copied);
- return(tmp);
+ /* FIXME: here is another race condition. */
+ tmp = sk->wmem_alloc;
+ release_sock(sk);
+ cli();
+ /* Again we will try to avoid it. */
+ if (tmp <= sk->wmem_alloc &&
+ (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
+ && sk->err == 0) {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked) {
+ sti();
+ DPRINTF((DBG_TCP, "tcp_write: return 5\n"));
+ if (copied) return(copied);
+ return(-ERESTARTSYS);
+ }
}
+ sk->inuse = 1;
+ sti();
+ continue;
+ }
- /*
- * If this was OOB data it goes at the start of a packet
- * with the urg flag and urg ptr set.
- */
-
- if (flags & MSG_OOB)
- {
- ((struct tcphdr *)buff)->urg = 1;
- ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
- }
-
- /*
- * Set the length
- */
-
- skb->len += tmp;
-
- /*
- * Insert user data
- */
-
- memcpy_fromfs(buff+tmp, from, copy);
+ skb->mem_addr = skb;
+ skb->len = 0;
+ skb->sk = sk;
+ skb->free = 0;
- from += copy;
- copied += copy;
- len -= copy;
- skb->len += copy;
- skb->free = 0;
- sk->send_seq += copy;
+ buff =(unsigned char *)(skb+1);
- if (sk->send_tmp != NULL)
- continue;
-
- /*
- * Checksum
- */
+ /*
+ * FIXME: we need to optimize this.
+ * Perhaps some hints here would be good.
+ */
+ tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt, skb->mem_len);
+ if (tmp < 0 ) {
+ prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 6\n"));
+ if (copied) return(copied);
+ return(tmp);
+ }
+ skb->len += tmp;
+ skb->dev = dev;
+ buff += tmp;
+ skb->h.th =(struct tcphdr *) buff;
+ tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy);
+ if (tmp < 0) {
+ prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 7\n"));
+ if (copied) return(copied);
+ return(tmp);
+ }
- tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr,
- copy + sizeof(struct tcphdr), sk);
+ if (flags & MSG_OOB) {
+ ((struct tcphdr *)buff)->urg = 1;
+ ((struct tcphdr *)buff)->urg_ptr = ntohs(copy);
+ }
+ skb->len += tmp;
+ memcpy_fromfs(buff+tmp, from, copy);
- /*
- * Set the sequence number
- */
+ from += copy;
+ copied += copy;
+ len -= copy;
+ skb->len += copy;
+ skb->free = 0;
+ sk->send_seq += copy;
- skb->h.seq = sk->send_seq;
-
- /*
- * Can we send (will it fit in the window and is our packet out count low
- * enough.
- */
-
- if (after(sk->send_seq , sk->window_seq) || sk->packets_out >= sk->cong_window)
- {
-
- /*
- * Nope - add it to the write queue
- */
-
- DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
- sk->cong_window, sk->packets_out));
- DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
- sk->send_seq, sk->window_seq));
- skb->next = NULL;
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (sk->wback == NULL)
- {
- sk->wfront = skb;
- }
- else
- {
- sk->wback->next = skb;
- }
- sk->wback = skb;
- }
- else
- {
- /*
- * Kick it our to IP for transmission (and maybe retransmission)
- */
-
- prot->queue_xmit(sk, dev, skb,0);
- }
- }
- sk->err = 0;
+ if (sk->send_tmp != NULL) continue;
- /* Avoid possible race on send_tmp - c/o Johannes Stille */
- if(sk->send_tmp && sk->packets_out <sk->cong_window)
- tcp_send_partial(sk);
- /* -- */
+ tcp_send_check((struct tcphdr *)buff, sk->saddr, sk->daddr,
+ copy + sizeof(struct tcphdr), sk);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
- return(copied);
+ skb->h.seq = sk->send_seq;
+ if (after(sk->send_seq , sk->window_seq) ||
+ sk->packets_out >= sk->cong_window) {
+ DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n",
+ sk->cong_window, sk->packets_out));
+ DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n",
+ sk->send_seq, sk->window_seq));
+ skb->next = NULL;
+ skb->magic = TCP_WRITE_QUEUE_MAGIC;
+ if (sk->wback == NULL) {
+ sk->wfront = skb;
+ } else {
+ sk->wback->next = skb;
+ }
+ sk->wback = skb;
+ } else {
+ prot->queue_xmit(sk, dev, skb,0);
+ }
+ }
+ sk->err = 0;
+ /* Avoid possible race on send_tmp - c/o Johannes Stille */
+ if(sk->send_tmp && !sk->packets_out)
+ tcp_send_partial(sk);
+ /* -- */
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_write: return 8\n"));
+ return(copied);
}
-static int tcp_sendto(struct sock *sk, unsigned char *from,
+static int
+tcp_sendto(struct sock *sk, unsigned char *from,
int len, int nonblock, unsigned flags,
struct sockaddr_in *addr, int addr_len)
{
- struct sockaddr_in sin;
-
- if (addr_len < sizeof(sin))
- return(-EINVAL);
-
- memcpy_fromfs(&sin, addr, sizeof(sin));
-
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EINVAL);
- if (sin.sin_port != sk->dummy_th.dest)
- return(-EINVAL);
- if (sin.sin_addr.s_addr != sk->daddr)
- return(-EINVAL);
- return(tcp_write(sk, from, len, nonblock, flags));
+ struct sockaddr_in sin;
+
+ if (addr_len < sizeof(sin)) return(-EINVAL);
+ memcpy_fromfs(&sin, addr, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
+ if (sin.sin_port != sk->dummy_th.dest) return(-EINVAL);
+ if (sin.sin_addr.s_addr != sk->daddr) return(-EINVAL);
+ return(tcp_write(sk, from, len, nonblock, flags));
}
static void
tcp_read_wakeup(struct sock *sk)
{
- int tmp;
- struct device *dev = NULL;
- struct tcphdr *t1;
- struct sk_buff *buff;
-
- DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
- if (!sk->ack_backlog)
- return;
-
- /*
- * FIXME: we need to put code here to prevent this routine from
- * being called. Being called once in a while is ok, so only check
- * if this is the second time in a row.
- */
-
- /*
- * We need to grab some memory, and put together an ack,
- * and then put it into the queue to be sent.
- *
- * The current code is rather keen to do this. It ought to first look
- * for more optimal options like kicking out the pending partial packet.
- */
-
- buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
- if (buff == NULL)
- {
- /* Try again real soon. */
- reset_timer(sk, TIME_WRITE, 10);
- return;
- }
+ int tmp;
+ struct device *dev = NULL;
+ struct tcphdr *t1;
+ struct sk_buff *buff;
- buff->mem_addr = buff;
- buff->mem_len = MAX_ACK_SIZE;
- buff->len = sizeof(struct tcphdr);
- buff->sk = sk;
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE, sk->ip_ttl,sk->ip_tos);
- if (tmp < 0)
- {
- buff->free=1;
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
-
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)(buff+1) +tmp);
+ DPRINTF((DBG_TCP, "in tcp read wakeup\n"));
+ if (!sk->ack_backlog) return;
- /*
- * Fill in the header.
- */
-
- memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
- t1->seq = ntohl(sk->send_seq);
- t1->ack = 1;
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->syn = 0;
- t1->psh = 0;
- sk->ack_backlog = 0;
- sk->bytes_rcv = 0;
- sk->window = 4096/*sk->prot->rspace(sk)*/;
- t1->window = ntohs(sk->window);
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- /*
- * These go straight out and don't retransmit
- */
-
- sk->prot->queue_xmit(sk, dev, buff, 1);
+ /*
+ * FIXME: we need to put code here to prevent this routine from
+ * being called. Being called once in a while is ok, so only check
+ * if this is the second time in a row.
+ */
+
+ /*
+ * We need to grab some memory, and put together an ack,
+ * and then put it into the queue to be sent.
+ */
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+ if (buff == NULL) {
+ /* Try again real soon. */
+ reset_timer(sk, TIME_WRITE, 10);
+ return;
+ }
+
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_ACK_SIZE;
+ buff->len = sizeof(struct tcphdr);
+ buff->sk = sk;
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+ if (tmp < 0) {
+ buff->free=1;
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ return;
+ }
+
+ buff->len += tmp;
+ t1 =(struct tcphdr *)((char *)(buff+1) +tmp);
+
+ memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq);
+ t1->ack = 1;
+ t1->res1 = 0;
+ t1->res2 = 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->syn = 0;
+ t1->psh = 0;
+ sk->ack_backlog = 0;
+ sk->bytes_rcv = 0;
+ sk->window = sk->prot->rspace(sk);
+ t1->window = ntohs(sk->window);
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+ sk->prot->queue_xmit(sk, dev, buff, 1);
}
/*
- * FIXME:
- * This routine frees used buffers.
- * It should consider sending an ACK to let the
- * other end know we now have a bigger window.
+ * FIXME:
+ * This routine frees used buffers.
+ * It should consider sending an ACK to let the
+ * other end know we now have a bigger window.
*/
-
-static void cleanup_rbuf(struct sock *sk)
+static void
+cleanup_rbuf(struct sock *sk)
{
- unsigned long flags;
- int left;
- struct sk_buff *skb;
+ unsigned long flags;
+ int left;
+ struct sk_buff *skb;
- if(sk->debug)
- printk("cleaning rbuf for sk=%p\n", sk);
+ if(sk->debug)
+ printk("cleaning rbuf for sk=%p\n", sk);
- save_flags(flags);
- cli();
+ save_flags(flags);
+ cli();
- left = sk->prot->rspace(sk);
+ left = sk->prot->rspace(sk);
- /*
- * We have to loop through all the buffer headers,
- * and try to free up all the space we can.
- */
-
- while((skb=skb_peek(&sk->rqueue)) != NULL )
- {
- if (!skb->used)
- break;
- skb_unlink(skb);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- }
+ /*
+ * We have to loop through all the buffer headers,
+ * and try to free up all the space we can.
+ */
+ while((skb=skb_peek(&sk->rqueue)) != NULL )
+ {
+ if (!skb->used)
+ break;
+ skb_unlink(skb);
+ skb->sk = sk;
+ kfree_skb(skb, FREE_READ);
+ }
- restore_flags(flags);
+ restore_flags(flags);
- /*
- * FIXME:
- * At this point we should send an ack if the difference
- * in the window, and the amount of space is bigger than
- * TCP_WINDOW_DIFF.
- */
- DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
+ /*
+ * FIXME:
+ * At this point we should send an ack if the difference
+ * in the window, and the amount of space is bigger than
+ * TCP_WINDOW_DIFF.
+ */
+ DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n",
sk->window - sk->bytes_rcv, sk->prot->rspace(sk)));
- if(sk->debug)
- printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),left);
- if (sk->prot->rspace(sk) != left)
- {
- /*
- * This area has caused the most trouble. The current strategy
- * is to simply do nothing if the other end has room to send at
- * least 3 full packets, because the ack from those will auto-
- * matically update the window. If the other end doesn't think
- * we have much space left, but we have room for atleast 1 more
- * complete packet than it thinks we do, we will send an ack
- * immediatedly. Otherwise we will wait up to .5 seconds in case
- * the user reads some more.
- *
- * Changes this to reflect real windows - Alan
- */
- sk->ack_backlog++;
- if (4096-diff(sk->acked_seq,sk->copied_seq) - sk->bytes_rcv < 3*sk->mtu)
- {
- /* Send an ack right now. */
- tcp_read_wakeup(sk);
- }
- else
- {
- /* Force it to send an ack soon. */
- int was_active = del_timer(&sk->timer);
- if (!was_active || TCP_ACK_TIME < sk->timer.expires)
- {
- reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- }
- else
- add_timer(&sk->timer);
- }
- }
+ if(sk->debug)
+ printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk),
+ left);
+ if (sk->prot->rspace(sk) != left)
+ {
+ /*
+ * This area has caused the most trouble. The current strategy
+ * is to simply do nothing if the other end has room to send at
+ * least 3 full packets, because the ack from those will auto-
+ * matically update the window. If the other end doesn't think
+ * we have much space left, but we have room for atleast 1 more
+ * complete packet than it thinks we do, we will send an ack
+ * immediatedly. Otherwise we will wait up to .5 seconds in case
+ * the user reads some more.
+ */
+ sk->ack_backlog++;
+ if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) {
+ /* Send an ack right now. */
+ tcp_read_wakeup(sk);
+ } else {
+ /* Force it to send an ack soon. */
+ int was_active = del_timer(&sk->timer);
+ if (!was_active || TCP_ACK_TIME < sk->timer.expires) {
+ reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
+ } else
+ add_timer(&sk->timer);
+ }
+ }
}
-/*
- * Handle reading urgent data.
- */
-
-static int tcp_read_urg(struct sock * sk, int nonblock,
+/* Handle reading urgent data. */
+static int
+tcp_read_urg(struct sock * sk, int nonblock,
unsigned char *to, int len, unsigned flags)
{
- int copied = 0;
- struct sk_buff *skb;
- int err;
+ int copied = 0;
+ struct sk_buff *skb;
- DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n",
+ DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n",
sk, to, len, flags));
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
-
- while(len > 0)
- {
- sk->inuse = 1;
- while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL)
- {
- if (sk->err)
- {
- int tmp;
+ while(len > 0)
+ {
+ sk->inuse = 1;
+ while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL) {
+ if (sk->err) {
+ int tmp;
- release_sock(sk);
- if (copied)
- return(copied);
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
+ release_sock(sk);
+ if (copied) return(copied);
+ tmp = -sk->err;
+ sk->err = 0;
+ return(tmp);
+ }
- if (sk->state == TCP_CLOSE || sk->done)
- {
- release_sock(sk);
- if (copied)
- return(copied);
- if (!sk->done)
- {
- sk->done = 1;
- return(0);
- }
- return(-ENOTCONN);
+ if (sk->state == TCP_CLOSE || sk->done) {
+ release_sock(sk);
+ if (copied) return(copied);
+ if (!sk->done) {
+ sk->done = 1;
+ return(0);
}
+ return(-ENOTCONN);
+ }
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- if (copied == 0)
- sk->done = 1;
- return(copied);
- }
-
- if (nonblock || copied)
- {
- release_sock(sk);
- if (copied)
- return(copied);
- return(-EAGAIN);
- }
+ if (sk->shutdown & RCV_SHUTDOWN) {
+ release_sock(sk);
+ if (copied == 0)
+ sk->done = 1;
+ return(copied);
+ }
- /* Now at this point, we may have gotten some data. */
+ if (nonblock || copied) {
release_sock(sk);
- cli();
- if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) &&
- sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN))
- {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- if (copied)
- return(copied);
- return(-ERESTARTSYS);
- }
+ if (copied) return(copied);
+ return(-EAGAIN);
+ }
+
+ /* Now at this point, we may have gotten some data. */
+ release_sock(sk);
+ cli();
+ if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) &&
+ sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) {
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked) {
+ sti();
+ if (copied) return(copied);
+ return(-ERESTARTSYS);
}
- sk->inuse = 1;
- sti();
}
+ sk->inuse = 1;
+ sti();
+ }
- skb = skb_peek(&sk->rqueue);
- do
- {
- int amt;
+ skb = skb_peek(&sk->rqueue);
+ do {
+ int amt;
- if (skb->h.th->urg && !skb->urg_used)
+ if (skb->h.th->urg && !skb->urg_used) {
+ if (skb->h.th->urg_ptr == 0) {
+ skb->h.th->urg_ptr = ntohs(skb->len);
+ }
+ amt = min(ntohs(skb->h.th->urg_ptr),len);
+ if(amt)
{
- if (skb->h.th->urg_ptr == 0)
- {
- skb->h.th->urg_ptr = ntohs(skb->len);
- }
- amt = min(ntohs(skb->h.th->urg_ptr),len);
- if(amt)
- {
- verify_area(VERIFY_WRITE, to, amt);
- memcpy_tofs(to,(unsigned char *)(skb->h.th) +
- skb->h.th->doff*4, amt);
- }
+ verify_area(VERIFY_WRITE, to, amt);
+ memcpy_tofs(to,(unsigned char *)(skb->h.th) +
+ skb->h.th->doff*4, amt);
+ }
- if (!(flags & MSG_PEEK))
- {
- skb->urg_used = 1;
- sk->urg--;
- }
- release_sock(sk);
- copied += amt;
- return(copied);
+ if (!(flags & MSG_PEEK)) {
+ skb->urg_used = 1;
+ sk->urg--;
}
- skb =(struct sk_buff *)skb->next;
- }
- while(skb != sk->rqueue);
- }
- sk->urg = 0;
- release_sock(sk);
- return(0);
+ release_sock(sk);
+ copied += amt;
+ return(copied);
+ }
+ skb =(struct sk_buff *)skb->next;
+ } while(skb != sk->rqueue);
+ }
+ sk->urg = 0;
+ release_sock(sk);
+ return(0);
}
-/*
- * This routine copies from a sock struct into the user buffer.
- */
-
-static int tcp_read_data(int type,struct sock *sk, unsigned char *to,
+/* This routine copies from a sock struct into the user buffer. */
+static int
+tcp_read(struct sock *sk, unsigned char *to,
int len, int nonblock, unsigned flags)
{
- /* Type is 0 for read, 1 for recv()/recvfrom() */
-
- int copied=0; /* will be used to say how much has been copied. */
- struct sk_buff *skb;
- unsigned long offset;
- unsigned long used;
- int err;
-
- if (len == 0)
- return(0);
- if (len < 0)
- {
- return(-EINVAL);
- }
+ int copied=0; /* will be used to say how much has been copied. */
+ struct sk_buff *skb;
+ unsigned long offset;
+ unsigned long used;
+ int err;
+
+ if (len == 0) return(0);
+ if (len < 0) {
+ return(-EINVAL);
+ }
- err=verify_area(VERIFY_WRITE,to,len);
- if(err)
- return err;
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
- /* This error should be checked. */
- if (sk->state == TCP_LISTEN)
- return(-ENOTCONN);
+ /* This error should be checked. */
+ if (sk->state == TCP_LISTEN) return(-ENOTCONN);
- /* Urgent data needs to be handled specially. */
- if ((flags & MSG_OOB))
- return(tcp_read_urg(sk, nonblock, to, len, flags));
+ /* Urgent data needs to be handled specially. */
+ if ((flags & MSG_OOB))
+ return(tcp_read_urg(sk, nonblock, to, len, flags));
- /* So no-one else will use this socket. */
- sk->inuse = 1;
+ /* So no-one else will use this socket. */
+ sk->inuse = 1;
- skb=skb_peek(&sk->rqueue);
-
- DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
+ skb=skb_peek(&sk->rqueue);
+
+ DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, to, len, nonblock, flags));
- while(len > 0)
- {
- /* skb->used just checks to see if we've gone all the way around. */
+ while(len > 0) {
+ /* 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(skb == NULL || before(sk->copied_seq+1, skb->h.th->seq) || skb->used)
+ /* While no data, or first data indicates some is missing, or data is used */
+ while(skb == NULL ||
+ before(sk->copied_seq+1, skb->h.th->seq) || skb->used) {
+ DPRINTF((DBG_TCP, "skb = %X:\n", skb));
+ cleanup_rbuf(sk);
+ if (sk->err)
{
- DPRINTF((DBG_TCP, "skb = %X:\n", skb));
-
- /*
- * Clean up anything we can
- */
- cleanup_rbuf(sk);
-
- /*
- * If an error has come in off the net report it
- */
- if (sk->err)
- {
- int tmp;
-
- release_sock(sk);
- if (copied)
- {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- tmp = -sk->err;
- sk->err = 0;
- return(tmp);
- }
+ int tmp;
- /*
- * If we have become closed
- */
- if (sk->state == TCP_CLOSE)
+ release_sock(sk);
+ if (copied)
{
- release_sock(sk);
- if (copied)
- {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
copied));
- return(copied);
- }
- if (!sk->done)
- {
- sk->done = 1;
- return(0);
- }
- return(-ENOTCONN);
+ return(copied);
}
+ tmp = -sk->err;
+ sk->err = 0;
+ return(tmp);
+ }
- /*
- * If we have been shutdown
- */
-
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- release_sock(sk);
- if (copied == 0)
- sk->done = 1;
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+ if (sk->state == TCP_CLOSE)
+ {
+ release_sock(sk);
+ if (copied) {
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ copied));
return(copied);
}
-
- /*
- * If we don't want to wait.
- */
-
- if (nonblock || copied) /* Altered AC 24/12/93 */
- {
- release_sock(sk);
- if(sk->debug)
- printk("read: EAGAIN\n");
- if (copied)
- {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- return(-EAGAIN);
+ if (!sk->done) {
+ sk->done = 1;
+ return(0);
}
-
- /*
- * Peeking doesn't wait around
- */
+ return(-ENOTCONN);
+ }
- if ((flags & MSG_PEEK) && copied != 0)
- {
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- return(copied);
- }
-
- DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
- sk->state));
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
release_sock(sk);
-
- /*
- * Now we may have some data waiting or we could
- * have changed state.
- */
- cli();
+ if (copied == 0) sk->done = 1;
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+ return(copied);
+ }
- /*
- * We just missed an event. Go round and
- * reprocess it. This happens normally because
- * release_sock will catch up on the backlog
- * queue.
- */
-
- if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0)
+ if (nonblock || copied)
+ {
+ release_sock(sk);
+ if(sk->debug)
+ printk("read: EAGAIN\n");
+ if (copied)
{
- sk->inuse = 1;
- sti();
- continue;
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ copied));
+ return(copied);
}
-
- /*
- * Anything present, if so make sure it fits at our current position
- */
+ return(-EAGAIN);
+ }
- if (skb_peek(&sk->rqueue) == NULL || before(sk->copied_seq+1, sk->rqueue->h.th->seq))
- {
- if(sk->debug)
- printk("Read wait sleep\n");
- interruptible_sleep_on(sk->sleep);
- if(sk->debug)
- printk("Read wait wakes\n");
- if (current->signal & ~current->blocked)
- {
- sti();
- if (copied)
- {
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
- copied));
- return(copied);
- }
- return(-ERESTARTSYS);
- }
- }
+ if ((flags & MSG_PEEK) && copied != 0)
+ {
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+ return(copied);
+ }
+
+ DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
+ sk->state));
+ release_sock(sk);
+
+ /*
+ * Now we may have some data waiting or we could
+ * have changed state.
+ */
+ cli();
+ if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) {
sk->inuse = 1;
sti();
- DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
-
+ continue;
+ }
- /*
- * Grab the first packet pointer
- */
+ if (skb_peek(&sk->rqueue) == NULL ||
+ before(sk->copied_seq+1, sk->rqueue->h.th->seq)) {
+ if(sk->debug)
+ printk("Read wait sleep\n");
+ interruptible_sleep_on(sk->sleep);
+ if(sk->debug)
+ printk("Read wait wakes\n");
+ if (current->signal & ~current->blocked) {
+ sti();
+ if (copied) {
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
+ copied));
+ return(copied);
+ }
+ return(-ERESTARTSYS);
+ }
+ }
+ sk->inuse = 1;
+ sti();
+ DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
- skb=skb_peek(&sk->rqueue);
- /*
- * That may have been null if we were beaten, if so we loop again
- */
- }
+ skb=skb_peek(&sk->rqueue);
+ /* That may have been null if we were beaten, if so we loop again */
+ }
+ /*
+ * Copy anything from the current block that needs
+ * to go into the user buffer.
+ */
+ offset = sk->copied_seq+1 - skb->h.th->seq;
+
+ if (skb->h.th->syn) offset--;
+ if (offset < skb->len) /* Some of the packet is useful */
+ {
/*
- * Copy anything from the current block that needs
- * to go into the user buffer.
+ * If there is urgent data we must either
+ * return or skip over it.
*/
-
- offset = sk->copied_seq+1 - skb->h.th->seq;
-
- if (skb->h.th->syn)
- offset--;
-
- if (offset < skb->len) /* Some of the packet is useful */
- {
- /*
- * If there is urgent data we must either
- * return or skip over it.
- */
- if (skb->h.th->urg)
+ if (skb->h.th->urg)
+ {
+ if (skb->urg_used)
{
- if (skb->urg_used)
+ sk->copied_seq += ntohs(skb->h.th->urg_ptr);
+ offset += ntohs(skb->h.th->urg_ptr);
+ if (offset >= skb->len)
{
- sk->copied_seq += ntohs(skb->h.th->urg_ptr);
- offset += ntohs(skb->h.th->urg_ptr);
- if (offset >= skb->len)
- {
- skb->used = 1;
- skb =(struct sk_buff *)skb->next;
- continue;
- }
- }
- else
- {
- release_sock(sk);
- if (copied)
- return(copied);
-
- /*
- * This is technically wrong. What do we do if SIGURG is
- * being ignored. EINTR as a return is certainly wrong.
- */
-
- send_sig(SIGURG, current, 0);
- return(-EINTR);
+ skb->used = 1;
+ skb =(struct sk_buff *)skb->next;
+ continue;
}
- }
-
- /*
- * Ok so how much can we use ?
- */
- used = min(skb->len - offset, len);
- /*
- * Copy it
- */
- memcpy_tofs(to,((unsigned char *)skb->h.th) +
- skb->h.th->doff*4 + offset, used);
- copied += used;
- len -= used;
- to += 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 if it doesn't contain any urgent data. And we
- * have used all the data.
- */
-
- if (!(flags & MSG_PEEK) && (!skb->h.th->urg || skb->urg_used) && (used + offset >= skb->len))
- skb->used = 1;
-
- /*
- * See if this is the end of a message or if the
- * remaining data is urgent.
- */
-
- if ((skb->h.th->psh && type) || skb->h.th->urg)
+ }
+ else
{
- break;
+ release_sock(sk);
+ if (copied)
+ return(copied);
+ send_sig(SIGURG, current, 0);
+ return(-EINTR);
}
- }
- else
- { /*
- * already used this data, must be a retransmit
- */
- skb->used = 1;
}
+ /* Ok so how much can we use ? */
+ used = min(skb->len - offset, len);
+ /* Copy it */
+ memcpy_tofs(to,((unsigned char *)skb->h.th) +
+ skb->h.th->doff*4 + offset, used);
+ copied += used;
+ len -= used;
+ to += used;
- /*
- * Move along a packet. We might reach the end if so we will wait
- * for more.
+ /* 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 if it doesn't contain any urgent data. And we
+ * have used all the data.
*/
-
- skb =(struct sk_buff *)skb->next;
- }
-
-
- /*
- * Clean up data we have read: This will do ACK frames
- */
-
- cleanup_rbuf(sk);
- release_sock(sk);
- DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
- if (copied == 0 && nonblock)
- return(-EAGAIN);
- return(copied);
+ if (!(flags & MSG_PEEK) &&
+ (!skb->h.th->urg || skb->urg_used) &&
+ (used + offset >= skb->len))
+ skb->used = 1;
+
+ /*
+ * See if this is the end of a message or if the
+ * remaining data is urgent.
+ */
+ if (/*skb->h.th->psh || */skb->h.th->urg)
+ {
+ break;
+ }
+ }
+ else
+ { /* already used this data, must be a retransmit */
+ skb->used = 1;
+ }
+ /* Move along a packet */
+ skb =(struct sk_buff *)skb->next;
+ }
+ /* Clean up data we have read: This will do ACK frames */
+ cleanup_rbuf(sk);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+ if (copied == 0 && nonblock)
+ return(-EAGAIN);
+ return(copied);
}
-/*
- * The read() user function. Read data, block and don't care
- * about PSH and no partial reads
- */
-
-static int tcp_read(struct sock *sk, unsigned char *to,
- int len, int nonblock, unsigned flags)
-{
- return(tcp_read_data(1,sk,to,len,nonblock,flags));
-}
-
/*
- * Send a FIN without closing the connection.
- * Not called at interrupt time.
+ * Send a FIN without closing the connection.
+ * Not called at interrupt time.
*/
-
-void tcp_shutdown(struct sock *sk, int how)
+void
+tcp_shutdown(struct sock *sk, int how)
{
- struct sk_buff *buff;
- struct tcphdr *t1, *th;
- struct proto *prot;
- int tmp;
- struct device *dev = NULL;
+ struct sk_buff *buff;
+ struct tcphdr *t1, *th;
+ struct proto *prot;
+ int tmp;
+ struct device *dev = NULL;
/*
* We need to grab some memory, and put together a FIN,
@@ -1786,204 +1460,179 @@ void tcp_shutdown(struct sock *sk, int how)
* Most of this is guesswork, so maybe it will work...
*/
/* If we've already sent a FIN, return. */
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2)
- return;
- if (!(how & SEND_SHUTDOWN))
- return;
- sk->inuse = 1;
-
- /* Clear out any half completed packets. */
- if (sk->send_tmp)
- tcp_send_partial(sk);
-
- prot =(struct proto *)sk->prot;
- th =(struct tcphdr *)&sk->dummy_th;
- release_sock(sk); /* incase the malloc sleeps. */
- buff = (struct sk_buff *) prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
-
- if (buff == NULL)
- return;
-
- sk->inuse = 1;
-
- DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
- buff->mem_addr = buff;
- buff->mem_len = MAX_RESET_SIZE;
- buff->sk = sk;
- buff->len = sizeof(*t1);
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr),
- sk->ip_ttl,sk->ip_tos
- );
- if (tmp < 0)
- {
- buff->free=1;
- prot->wfree(sk,buff->mem_addr, buff->mem_len);
- release_sock(sk);
- DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
- return;
- }
-
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff ->len += tmp;
- buff->dev = dev;
- memcpy(t1, th, sizeof(*t1));
- t1->seq = ntohl(sk->send_seq);
- sk->send_seq++;
- buff->h.seq = sk->send_seq;
- t1->ack = 1;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->prot->rspace(sk));
- t1->fin = 1;
- t1->rst = 0;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- /*
- * Can't just queue this up.
- * It should go at the end of the write queue.
- */
-
- if (sk->wback != NULL)
- {
- buff->free=0;
- buff->next = NULL;
- sk->wback->next = buff;
- sk->wback = buff;
- buff->magic = TCP_WRITE_QUEUE_MAGIC;
- }
- else
- {
- sk->prot->queue_xmit(sk, dev, buff, 0);
- }
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) return;
+ if (!(how & SEND_SHUTDOWN)) return;
+ sk->inuse = 1;
+
+ /* Clear out any half completed packets. */
+ if (sk->send_tmp) tcp_send_partial(sk);
+
+ prot =(struct proto *)sk->prot;
+ th =(struct tcphdr *)&sk->dummy_th;
+ release_sock(sk); /* incase the malloc sleeps. */
+ buff = (struct sk_buff *) prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL);
+ if (buff == NULL) return;
+ sk->inuse = 1;
+
+ DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_RESET_SIZE;
+ buff->sk = sk;
+ buff->len = sizeof(*t1);
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt,
+ sizeof(struct tcphdr));
+ if (tmp < 0) {
+ buff->free=1;
+ prot->wfree(sk,buff->mem_addr, buff->mem_len);
+ release_sock(sk);
+ DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
+ return;
+ }
+
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+ buff ->len += tmp;
+ buff->dev = dev;
+ memcpy(t1, th, sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq);
+ sk->send_seq++;
+ buff->h.seq = sk->send_seq;
+ t1->ack = 1;
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->window = ntohs(sk->prot->rspace(sk));
+ t1->fin = 1;
+ t1->rst = 0;
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
- if (sk->state == TCP_ESTABLISHED)
- sk->state = TCP_FIN_WAIT1;
- else
- sk->state = TCP_FIN_WAIT2;
-
- release_sock(sk);
+ /*
+ * Can't just queue this up.
+ * It should go at the end of the write queue.
+ */
+ if (sk->wback != NULL) {
+ buff->free=0;
+ buff->next = NULL;
+ sk->wback->next = buff;
+ sk->wback = buff;
+ buff->magic = TCP_WRITE_QUEUE_MAGIC;
+ } else {
+ sk->prot->queue_xmit(sk, dev, buff, 0);
+ }
+
+ if (sk->state == TCP_ESTABLISHED) sk->state = TCP_FIN_WAIT1;
+ else sk->state = TCP_FIN_WAIT2;
+
+ release_sock(sk);
}
-static int tcp_recvfrom(struct sock *sk, unsigned char *to,
+static int
+tcp_recvfrom(struct sock *sk, unsigned char *to,
int to_len, int nonblock, unsigned flags,
struct sockaddr_in *addr, int *addr_len)
{
- struct sockaddr_in sin;
- int len;
- int err;
- int result;
+ struct sockaddr_in sin;
+ int len;
+ int err;
+ int result;
- /*
- * Have to check these first unlike the old code. If
- * we check them after we lose data on an error
- * which is wrong
- */
-
- err = verify_area(VERIFY_WRITE,addr_len,sizeof(long));
- if(err)
- return err;
- len = get_fs_long(addr_len);
- if(len > sizeof(sin))
- len = sizeof(sin);
- err=verify_area(VERIFY_WRITE, addr, len);
- if(err)
- return err;
-
- result=tcp_read_data(1,sk, to, to_len, nonblock, flags);
-
- if (result < 0)
- return(result);
+ /* Have to check these first unlike the old code. If
+ we check them after we lose data on an error
+ which is wrong */
+ err = verify_area(VERIFY_WRITE,addr_len,sizeof(long));
+ if(err)
+ return err;
+ len = get_fs_long(addr_len);
+ if(len > sizeof(sin))
+ len = sizeof(sin);
+ err=verify_area(VERIFY_WRITE, addr, len);
+ if(err)
+ return err;
+
+ result=tcp_read(sk, to, to_len, nonblock, flags);
+
+ if (result < 0) return(result);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->dummy_th.dest;
- sin.sin_addr.s_addr = sk->daddr;
+ sin.sin_family = AF_INET;
+ sin.sin_port = sk->dummy_th.dest;
+ sin.sin_addr.s_addr = sk->daddr;
- memcpy_tofs(addr, &sin, len);
- put_fs_long(len, addr_len);
- return(result);
+ memcpy_tofs(addr, &sin, len);
+ put_fs_long(len, addr_len);
+ return(result);
}
-/*
- * This routine will send an RST to the other tcp.
- */
-
-static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
+/* This routine will send an RST to the other tcp. */
+static void
+tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
struct proto *prot, struct options *opt, struct device *dev)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- int tmp;
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ int tmp;
/*
* We need to grab some memory, and put together an RST,
* and then put it into the queue to be sent.
*/
- buff = (struct sk_buff *) prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- return;
-
- DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
- buff->mem_addr = buff;
- buff->mem_len = MAX_RESET_SIZE;
- buff->len = sizeof(*t1);
- buff->sk = NULL;
- buff->dev = dev;
-
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
- sizeof(struct tcphdr),255, IPTOS_RELIABILITY);
- if (tmp < 0)
- {
- buff->free = 1;
- prot->wfree(NULL, buff->mem_addr, buff->mem_len);
- return;
- }
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff->len += tmp;
- memcpy(t1, th, sizeof(*t1));
-
- /* Swap the send and the receive. */
- t1->dest = th->source;
- t1->source = th->dest;
- t1->rst = 1;
- t1->window = 0;
+ buff = (struct sk_buff *) prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL)
+ return;
+
+ DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_RESET_SIZE;
+ buff->len = sizeof(*t1);
+ buff->sk = NULL;
+ buff->dev = dev;
+
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
+ sizeof(struct tcphdr));
+ if (tmp < 0) {
+ buff->free = 1;
+ prot->wfree(NULL, buff->mem_addr, buff->mem_len);
+ return;
+ }
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+ buff->len += tmp;
+ memcpy(t1, th, sizeof(*t1));
+
+ /* Swap the send and the receive. */
+ t1->dest = th->source;
+ t1->source = th->dest;
+ t1->rst = 1;
+ t1->window = 0;
- /*
- * Fill in the ack field etc
- */
-
- if(th->ack)
- {
- t1->ack=0;
- t1->seq=th->ack_seq;
- t1->ack_seq=0;
- }
+ if(th->ack)
+ {
+ t1->ack=0;
+ t1->seq=th->ack_seq;
+ t1->ack_seq=0;
+ }
+ else
+ {
+ t1->ack=1;
+ if(!th->syn)
+ t1->ack_seq=htonl(th->seq);
else
- {
- t1->ack=1;
- if(!th->syn)
- t1->ack_seq=htonl(th->seq);
- else
- t1->ack_seq=htonl(th->seq+1);
- t1->seq=0;
- }
-
- t1->syn = 0;
- t1->urg = 0;
- t1->fin = 0;
- t1->psh = 0;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
- prot->queue_xmit(NULL, dev, buff, 1);
+ t1->ack_seq=htonl(th->seq+1);
+ t1->seq=0;
+ }
+
+ t1->syn = 0;
+ t1->urg = 0;
+ t1->fin = 0;
+ t1->psh = 0;
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL);
+ prot->queue_xmit(NULL, dev, buff, 1);
}
@@ -1991,102 +1640,96 @@ static void tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *t
* Look for tcp options. Parses everything but only knows about MSS
*/
-static void tcp_options(struct sock *sk, struct tcphdr *th)
+static void
+tcp_options(struct sock *sk, struct tcphdr *th)
{
- unsigned char *ptr;
- int length=(th->doff*4)-sizeof(struct tcphdr);
- int mtuset=0;
+ unsigned char *ptr;
+ int length=(th->doff*4)-sizeof(struct tcphdr);
+ int mtuset=0;
- ptr = (unsigned char *)(th + 1);
+ ptr = (unsigned char *)(th + 1);
- while(length>0)
- {
- int opcode=*ptr++;
- int opsize=*ptr++;
- switch(opcode)
- {
- case TCPOPT_EOL:
- return;
- case TCPOPT_NOP:
- length-=2;
- continue;
+ while(length>0)
+ {
+ int opcode=*ptr++;
+ int opsize=*ptr++;
+ switch(opcode)
+ {
+ case TCPOPT_EOL:
+ return;
+ case TCPOPT_NOP:
+ length-=2;
+ continue;
- default:
- if(opsize<=2) /* Avoid silly options looping forever */
- return;
- switch(opcode)
- {
- case TCPOPT_MSS:
- if(opsize==4)
- {
- sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
- mtuset=1;
- }
- break;
- /*
- * Add other options here as people feel the urge to implement stuff like large windows
- */
- }
- ptr+=opsize-2;
- length-=opsize;
- }
+ default:
+ if(opsize<=2) /* Avoid silly options looping forever */
+ return;
+ switch(opcode)
+ {
+ case TCPOPT_MSS:
+ if(opsize==4)
+ {
+ sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
+ mtuset=1;
+ }
+ break;
+ /* Add other options here as people feel the urge to implement stuff like large windows */
+ }
+ ptr+=opsize-2;
+ length-=opsize;
}
+ }
- if (!mtuset)
- {
- sk->mtu = min(sk->mtu, 576 - HEADER_SIZE);
- return;
- }
+ if (!mtuset)
+ {
+ sk->mtu = min(sk->mtu, 576 - HEADER_SIZE);
+ return;
+ }
}
/*
- * This routine handles a connection request.
- * It should make sure we haven't already responded.
- * Because of the way BSD works, we have to send a syn/ack now.
- * This also means it will be harder to close a socket which is
- * listening.
+ * This routine handles a connection request.
+ * It should make sure we haven't already responded.
+ * Because of the way BSD works, we have to send a syn/ack now.
+ * This also means it will be harder to close a socket which is
+ * listening.
*/
-
-static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
+static void
+tcp_conn_request(struct sock *sk, struct sk_buff *skb,
unsigned long daddr, unsigned long saddr,
struct options *opt, struct device *dev)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- unsigned char *ptr;
- struct sock *newsk;
- struct tcphdr *th;
- int tmp;
-
- DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n"
- " opt = %X, dev = %X)\n",
- sk, skb, daddr, saddr, opt, dev));
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ unsigned char *ptr;
+ struct sock *newsk;
+ struct tcphdr *th;
+ int tmp;
+
+ DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n"
+ " opt = %X, dev = %X)\n",
+ sk, skb, daddr, saddr, opt, dev));
- th = skb->h.th;
-
- /* If the socket is dead, don't accept the connection. */
- if (!sk->dead)
- {
- sk->data_ready(sk,0);
- }
- else
- {
- DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
- kfree_skb(skb, FREE_READ);
- return;
- }
+ th = skb->h.th;
+
+ /* If the socket is dead, don't accept the connection. */
+ if (!sk->dead) {
+ wake_up(sk->sleep);
+ } else {
+ DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n"));
+ tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
/*
* Make sure we can accept more. This will prevent a
* flurry of syns from eating up all our memory.
*/
-
- if (sk->ack_backlog >= sk->max_ack_backlog)
- {
- kfree_skb(skb, FREE_READ);
- return;
- }
+ if (sk->ack_backlog >= sk->max_ack_backlog) {
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
/*
* We need to build a new sock struct.
@@ -2095,360 +1738,343 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
* and if the listening socket is destroyed before this is taken
* off of the queue, this will take care of it.
*/
- newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
- if (newsk == NULL)
- {
- /* just ignore the syn. It will get retransmitted. */
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- DPRINTF((DBG_TCP, "newsk = %X\n", newsk));
- memcpy((void *)newsk,(void *)sk, sizeof(*newsk));
- newsk->wback = NULL;
- newsk->wfront = NULL;
- newsk->rqueue = NULL;
- newsk->send_head = NULL;
- newsk->send_tail = NULL;
- newsk->back_log = NULL;
- newsk->rtt = TCP_CONNECT_TIME;
- newsk->mdev = 0;
- newsk->backoff = 0;
- newsk->blog = 0;
- newsk->intr = 0;
- newsk->proc = 0;
- newsk->done = 0;
- newsk->send_tmp = NULL;
- newsk->pair = NULL;
- newsk->wmem_alloc = 0;
- newsk->rmem_alloc = 0;
-
- newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
-
- newsk->err = 0;
- newsk->shutdown = 0;
- newsk->ack_backlog = 0;
- newsk->acked_seq = skb->h.th->seq+1;
- newsk->fin_seq = skb->h.th->seq;
- newsk->copied_seq = skb->h.th->seq;
- newsk->state = TCP_SYN_RECV;
- newsk->timeout = 0;
- newsk->send_seq = jiffies * SEQ_TICK - seq_offset;
- newsk->rcv_ack_seq = newsk->send_seq;
- newsk->urg =0;
- newsk->retransmits = 0;
- newsk->destroy = 0;
- newsk->timer.data = (unsigned long)newsk;
- newsk->timer.function = &net_timer;
- newsk->dummy_th.source = skb->h.th->dest;
- newsk->dummy_th.dest = skb->h.th->source;
-
- /* Swap these two, they are from our point of view. */
- newsk->daddr = saddr;
- newsk->saddr = daddr;
-
- put_sock(newsk->num,newsk);
- newsk->dummy_th.res1 = 0;
- newsk->dummy_th.doff = 6;
- newsk->dummy_th.fin = 0;
- newsk->dummy_th.syn = 0;
- newsk->dummy_th.rst = 0;
- newsk->dummy_th.psh = 0;
- newsk->dummy_th.ack = 0;
- newsk->dummy_th.urg = 0;
- newsk->dummy_th.res2 = 0;
- newsk->acked_seq = skb->h.th->seq + 1;
- newsk->copied_seq = skb->h.th->seq;
-
- /* Grab the callers ttl and tos values and use them */
- newsk->ip_ttl=skb->ip_hdr->ttl;
- newsk->ip_tos=skb->ip_hdr->tos;
-
- tcp_options(newsk,skb->h.th);
-
- buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- {
- sk->err = -ENOMEM;
- newsk->dead = 1;
- release_sock(newsk);
- kfree_skb(skb, FREE_READ);
- return;
- }
+ newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
+ if (newsk == NULL) {
+ /* just ignore the syn. It will get retransmitted. */
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ DPRINTF((DBG_TCP, "newsk = %X\n", newsk));
+ memcpy((void *)newsk,(void *)sk, sizeof(*newsk));
+ newsk->wback = NULL;
+ newsk->wfront = NULL;
+ newsk->rqueue = NULL;
+ newsk->send_head = NULL;
+ newsk->send_tail = NULL;
+ newsk->back_log = NULL;
+ newsk->rtt = TCP_CONNECT_TIME;
+ newsk->mdev = 0;
+ newsk->backoff = 0;
+ newsk->blog = 0;
+ newsk->intr = 0;
+ newsk->proc = 0;
+ newsk->done = 0;
+ newsk->send_tmp = NULL;
+ newsk->pair = NULL;
+ newsk->wmem_alloc = 0;
+ newsk->rmem_alloc = 0;
+
+ newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF;
+
+ newsk->err = 0;
+ newsk->shutdown = 0;
+ newsk->ack_backlog = 0;
+ newsk->acked_seq = skb->h.th->seq+1;
+ newsk->fin_seq = skb->h.th->seq;
+ newsk->copied_seq = skb->h.th->seq;
+ newsk->state = TCP_SYN_RECV;
+ newsk->timeout = 0;
+ newsk->send_seq = jiffies * SEQ_TICK - seq_offset;
+ newsk->rcv_ack_seq = newsk->send_seq;
+ newsk->urg =0;
+ newsk->retransmits = 0;
+ newsk->destroy = 0;
+ newsk->timer.data = (unsigned long)newsk;
+ newsk->timer.function = &net_timer;
+ newsk->dummy_th.source = skb->h.th->dest;
+ newsk->dummy_th.dest = skb->h.th->source;
+
+ /* Swap these two, they are from our point of view. */
+ newsk->daddr = saddr;
+ newsk->saddr = daddr;
+
+ put_sock(newsk->num,newsk);
+ newsk->dummy_th.res1 = 0;
+ newsk->dummy_th.doff = 6;
+ newsk->dummy_th.fin = 0;
+ newsk->dummy_th.syn = 0;
+ newsk->dummy_th.rst = 0;
+ newsk->dummy_th.psh = 0;
+ newsk->dummy_th.ack = 0;
+ newsk->dummy_th.urg = 0;
+ newsk->dummy_th.res2 = 0;
+ newsk->acked_seq = skb->h.th->seq + 1;
+ newsk->copied_seq = skb->h.th->seq;
+
+#ifdef OLDWAY
+ if (skb->h.th->doff == 5) {
+ newsk->mtu = dev->mtu - HEADER_SIZE;
+ } else {
+ ptr =(unsigned char *)(skb->h.th + 1);
+ if (ptr[0] != 2 || ptr[1] != 4) {
+ newsk->mtu = dev->mtu - HEADER_SIZE;
+ } else {
+ newsk->mtu = min(ptr[2] * 256 + ptr[3] - HEADER_SIZE,
+ dev->mtu - HEADER_SIZE);
+ }
+ }
+#else
+ tcp_options(newsk,skb->h.th);
+#endif
+ buff = (struct sk_buff *) newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL) {
+ sk->err = -ENOMEM;
+ newsk->dead = 1;
+ release_sock(newsk);
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
- buff->mem_addr = buff;
- buff->mem_len = MAX_SYN_SIZE;
- buff->len = sizeof(struct tcphdr)+4;
- buff->sk = newsk;
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_SYN_SIZE;
+ buff->len = sizeof(struct tcphdr)+4;
+ buff->sk = newsk;
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,
- IPPROTO_TCP, NULL, MAX_SYN_SIZE,newsk->ip_ttl,newsk->ip_tos);
-
- /* Something went wrong. */
- if (tmp < 0)
- {
- sk->err = tmp;
- buff->free=1;
- kfree_skb(buff,FREE_WRITE);
- newsk->dead = 1;
- release_sock(newsk);
- skb->sk = sk;
- kfree_skb(skb, FREE_READ);
- return;
- }
-
- /*
- * Assemble a syn|ack frame in reply
- */
-
- buff->len += tmp;
- t1 =(struct tcphdr *)((char *)t1 +tmp);
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev,
+ IPPROTO_TCP, NULL, MAX_SYN_SIZE);
+
+ /* Something went wrong. */
+ if (tmp < 0) {
+ sk->err = tmp;
+ buff->free=1;
+ kfree_skb(buff,FREE_WRITE);
+ newsk->dead = 1;
+ release_sock(newsk);
+ skb->sk = sk;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ buff->len += tmp;
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
- memcpy(t1, skb->h.th, sizeof(*t1));
- buff->h.seq = newsk->send_seq;
-
- /* Swap the send and the receive. */
- t1->dest = skb->h.th->source;
- t1->source = newsk->dummy_th.source;
- t1->seq = ntohl(newsk->send_seq++);
- t1->ack = 1;
- newsk->window = 4096/*newsk->prot->rspace(newsk)*/;
- t1->window = ntohs(newsk->window);
- t1->res1 = 0;
- t1->res2 = 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->syn = 1;
- t1->ack_seq = ntohl(skb->h.th->seq+1);
- t1->doff = sizeof(*t1)/4+1;
-
- ptr =(unsigned char *)(t1+1);
- ptr[0] = 2;
- ptr[1] = 4;
- ptr[2] =((dev->mtu - HEADER_SIZE) >> 8) & 0xff;
- ptr[3] =(dev->mtu - HEADER_SIZE) & 0xff;
-
- tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
- newsk->prot->queue_xmit(newsk, dev, buff, 0);
-
- reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME);
- skb->sk = newsk;
-
- /* Charge the sock_buff to newsk. */
- sk->rmem_alloc -= skb->mem_len;
- newsk->rmem_alloc += skb->mem_len;
-
- skb_queue_tail(&sk->rqueue,skb);
- sk->ack_backlog++;
- release_sock(newsk);
+ memcpy(t1, skb->h.th, sizeof(*t1));
+ buff->h.seq = newsk->send_seq;
+
+ /* Swap the send and the receive. */
+ t1->dest = skb->h.th->source;
+ t1->source = newsk->dummy_th.source;
+ t1->seq = ntohl(newsk->send_seq++);
+ t1->ack = 1;
+ newsk->window = newsk->prot->rspace(newsk);
+ t1->window = ntohs(newsk->window);
+ t1->res1 = 0;
+ t1->res2 = 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->psh = 0;
+ t1->syn = 1;
+ t1->ack_seq = ntohl(skb->h.th->seq+1);
+ t1->doff = sizeof(*t1)/4+1;
+
+ ptr =(unsigned char *)(t1+1);
+ ptr[0] = 2;
+ ptr[1] = 4;
+ ptr[2] =((dev->mtu - HEADER_SIZE) >> 8) & 0xff;
+ ptr[3] =(dev->mtu - HEADER_SIZE) & 0xff;
+
+ tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
+ newsk->prot->queue_xmit(newsk, dev, buff, 0);
+
+ reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME);
+ skb->sk = newsk;
+
+ /* Charge the sock_buff to newsk. */
+ sk->rmem_alloc -= skb->mem_len;
+ newsk->rmem_alloc += skb->mem_len;
+
+ skb_queue_tail(&sk->rqueue,skb);
+ sk->ack_backlog++;
+ release_sock(newsk);
}
-/*
- * Close a tcp connection
- */
-static void tcp_close(struct sock *sk, int timeout)
+static void
+tcp_close(struct sock *sk, int timeout)
{
- struct sk_buff *buff;
- int need_reset = 0;
- struct tcphdr *t1, *th;
- struct proto *prot;
- struct device *dev=NULL;
- int tmp;
+ struct sk_buff *buff;
+ int need_reset = 0;
+ struct tcphdr *t1, *th;
+ struct proto *prot;
+ struct device *dev=NULL;
+ int tmp;
/*
* We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent.
*/
- DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
- sk->inuse = 1;
- sk->keepopen = 1;
- sk->shutdown = SHUTDOWN_MASK;
-
-
- /* We need to flush the recv. buffs. */
- if (skb_peek(&sk->rqueue) != NULL)
- {
- struct sk_buff *skb;
- if(sk->debug)
- printk("Clean rcv queue\n");
- while((skb=skb_dequeue(&sk->rqueue))!=NULL)
- {
- if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
- need_reset = 1;
- kfree_skb(skb, FREE_READ);
- }
- if(sk->debug)
- printk("Cleaned.\n");
+ DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout));
+ sk->inuse = 1;
+ sk->keepopen = 1;
+ sk->shutdown = SHUTDOWN_MASK;
+
+ if (!sk->dead) wake_up(sk->sleep);
+
+ /* We need to flush the recv. buffs. */
+ if (skb_peek(&sk->rqueue) != NULL)
+ {
+ struct sk_buff *skb;
+#ifdef OLD
+ struct sk_buff *skb2;
+ skb = skb_peek(&sk->rqueue);
+ do {
+ skb2 =(struct sk_buff *)skb->next;
+ /* if there is some real unread data, send a reset. */
+ if (skb->len > 0 &&
+ after(skb->h.th->seq + skb->len + 1, sk->copied_seq))
+ need_reset = 1;
+ kfree_skb(skb, FREE_WRITE);
+ skb = skb2;
+ } while(skb != sk->rqueue);
+#else
+ if(sk->debug)
+ printk("Clean rcv queue\n");
+ while((skb=skb_dequeue(&sk->rqueue))!=NULL)
+ {
+ if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq))
+ need_reset = 1;
+ kfree_skb(skb, FREE_READ);
}
- sk->rqueue = NULL;
-
- /* Get rid off any half-completed packets. */
- if (sk->send_tmp)
- {
- tcp_send_partial(sk);
- }
-
- switch(sk->state)
- {
- case TCP_FIN_WAIT1:
- case TCP_FIN_WAIT2:
- case TCP_LAST_ACK:
- /* start a timer. */
- reset_timer(sk, TIME_CLOSE, 4 * sk->rtt);
- if (timeout)
- tcp_time_wait(sk);
- release_sock(sk);
- if (!sk->dead)
- sk->state_change(sk);
- return; /* break causes a double release - messy */
- case TCP_TIME_WAIT:
- if (timeout)
- {
- sk->state = TCP_CLOSE;
- }
- release_sock(sk);
- if (!sk->dead)
- sk->state_change(sk);
- return;
- case TCP_LISTEN:
- sk->state = TCP_CLOSE;
+ if(sk->debug)
+ printk("Cleaned.\n");
+#endif
+ }
+ sk->rqueue = NULL;
+
+ /* Get rid off any half-completed packets. */
+ if (sk->send_tmp) {
+ tcp_send_partial(sk);
+ }
+
+ switch(sk->state) {
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_LAST_ACK:
+ /* start a timer. */
+ reset_timer(sk, TIME_CLOSE, 4 * sk->rtt);
+ if (timeout) tcp_time_wait(sk);
+ release_sock(sk);
+ return; /* break causes a double release - messy */
+ case TCP_TIME_WAIT:
+ if (timeout) {
+ sk->state = TCP_CLOSE;
+ }
+ release_sock(sk);
+ return;
+ case TCP_LISTEN:
+ sk->state = TCP_CLOSE;
+ release_sock(sk);
+ return;
+ case TCP_CLOSE:
+ release_sock(sk);
+ return;
+ case TCP_CLOSE_WAIT:
+ case TCP_ESTABLISHED:
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV:
+ prot =(struct proto *)sk->prot;
+ th =(struct tcphdr *)&sk->dummy_th;
+ buff = (struct sk_buff *) prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
+ if (buff == NULL) {
+ /* This will force it to try again later. */
+ /* Or it would have if someone released the socket
+ first. Anyway it might work now */
release_sock(sk);
- if (!sk->dead)
- sk->state_change(sk);
+ if (sk->state != TCP_CLOSE_WAIT)
+ sk->state = TCP_ESTABLISHED;
+ reset_timer(sk, TIME_CLOSE, 100);
return;
- case TCP_CLOSE:
+ }
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_FIN_SIZE;
+ buff->sk = sk;
+ buff->free = 1;
+ buff->len = sizeof(*t1);
+ t1 =(struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt,
+ sizeof(struct tcphdr));
+ if (tmp < 0) {
+ kfree_skb(buff,FREE_WRITE);
+ DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
release_sock(sk);
- if (!sk->dead)
- sk->state_change(sk);
return;
- case TCP_CLOSE_WAIT:
- case TCP_ESTABLISHED:
- case TCP_SYN_SENT:
- case TCP_SYN_RECV:
- prot =(struct proto *)sk->prot;
- th =(struct tcphdr *)&sk->dummy_th;
- buff = (struct sk_buff *) prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL)
- {
- /* This will force it to try again later. */
- /* Or it would have if someone released the socket
- first. Anyway it might work now */
- release_sock(sk);
- if (sk->state != TCP_CLOSE_WAIT)
- sk->state = TCP_ESTABLISHED;
- reset_timer(sk, TIME_CLOSE, 100);
- return;
- }
- buff->mem_addr = buff;
- buff->mem_len = MAX_FIN_SIZE;
- buff->sk = sk;
- buff->free = 1;
- buff->len = sizeof(*t1);
- t1 =(struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt,
- sizeof(struct tcphdr),sk->ip_ttl,sk->ip_tos);
-
- if (tmp < 0)
- {
- kfree_skb(buff,FREE_WRITE);
- DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
- release_sock(sk);
- if (!sk->dead)
- sk->state_change(sk);
- return;
- }
-
- t1 =(struct tcphdr *)((char *)t1 +tmp);
- buff ->len += tmp;
- buff->dev = dev;
- memcpy(t1, th, sizeof(*t1));
- t1->seq = ntohl(sk->send_seq);
- sk->send_seq++;
- buff->h.seq = sk->send_seq;
- t1->ack = 1;
-
- /* Ack everything immediately from now on. */
- sk->delay_acks = 0;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->prot->rspace(sk));
- t1->fin = 1;
- t1->rst = need_reset;
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- if (sk->wfront == NULL)
- {
- prot->queue_xmit(sk, dev, buff, 0);
- }
- else
- {
- buff->free=0;
- reset_timer(sk, TIME_WRITE,backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
- buff->next = NULL;
- if (sk->wback == NULL)
- {
- sk->wfront=buff;
- }
- else
- {
- sk->wback->next = buff;
- }
- sk->wback = buff;
- buff->magic = TCP_WRITE_QUEUE_MAGIC;
- }
+ }
- if (sk->state == TCP_CLOSE_WAIT)
- {
- sk->state = TCP_FIN_WAIT2;
- }
- else
- {
- sk->state = TCP_FIN_WAIT1;
- }
- break;
- }
- if (!sk->dead)
- sk->state_change(sk);
- release_sock(sk);
+ t1 =(struct tcphdr *)((char *)t1 +tmp);
+ buff ->len += tmp;
+ buff->dev = dev;
+ memcpy(t1, th, sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq);
+ sk->send_seq++;
+ buff->h.seq = sk->send_seq;
+ t1->ack = 1;
+
+ /* Ack everything immediately from now on. */
+ sk->delay_acks = 0;
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->window = ntohs(sk->prot->rspace(sk));
+ t1->fin = 1;
+ t1->rst = need_reset;
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+ if (sk->wfront == NULL) {
+ prot->queue_xmit(sk, dev, buff, 0);
+ } else {
+ reset_timer(sk, TIME_WRITE,
+ backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
+ buff->next = NULL;
+ if (sk->wback == NULL) {
+ sk->wfront=buff;
+ } else {
+ sk->wback->next = buff;
+ }
+ sk->wback = buff;
+ buff->magic = TCP_WRITE_QUEUE_MAGIC;
+ }
+
+ if (sk->state == TCP_CLOSE_WAIT) {
+ sk->state = TCP_FIN_WAIT2;
+ } else {
+ sk->state = TCP_FIN_WAIT1;
+ }
+ }
+ release_sock(sk);
}
/*
- * This routine takes stuff off of the write queue,
- * and puts it in the xmit queue.
+ * This routine takes stuff off of the write queue,
+ * and puts it in the xmit queue.
*/
-
-static void tcp_write_xmit(struct sock *sk)
+static void
+tcp_write_xmit(struct sock *sk)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
- DPRINTF((DBG_TCP, "tcp_write_xmit(sk=%X)\n", sk));
+ DPRINTF((DBG_TCP, "tcp_write_xmit(sk=%X)\n", sk));
- /* The bytes will have to remain here. In time closedown will
- empty the write queue and all will be happy */
- if(sk->zapped)
- return;
+ /* The bytes will have to remain here. In time closedown will
+ empty the write queue and all will be happy */
+ if(sk->zapped)
+ return;
- while(sk->wfront != NULL &&
- before(sk->wfront->h.seq, sk->window_seq) &&
- sk->packets_out < sk->cong_window)
- {
+ while(sk->wfront != NULL &&
+ before(sk->wfront->h.seq, sk->window_seq) &&
+ sk->packets_out < sk->cong_window) {
skb = sk->wfront;
IS_SKB(skb);
sk->wfront =(struct sk_buff *)skb->next;
- if (sk->wfront == NULL)
- sk->wback = NULL;
+ if (sk->wfront == NULL) sk->wback = NULL;
skb->next = NULL;
- if (skb->magic != TCP_WRITE_QUEUE_MAGIC)
- {
+ if (skb->magic != TCP_WRITE_QUEUE_MAGIC) {
printk("tcp.c skb with bad magic(%X) on write queue. Squashing "
"queue\n", skb->magic);
sk->wfront = NULL;
@@ -2459,15 +2085,11 @@ static void tcp_write_xmit(struct sock *sk)
DPRINTF((DBG_TCP, "Sending a packet.\n"));
/* See if we really need to send the packet. */
- if (before(skb->h.seq, sk->rcv_ack_seq +1))
- {
+ if (before(skb->h.seq, sk->rcv_ack_seq +1)) {
sk->retransmits = 0;
kfree_skb(skb, FREE_WRITE);
- if (!sk->dead)
- sk->write_space(sk);
- }
- else
- {
+ if (!sk->dead) wake_up(sk->sleep);
+ } else {
sk->prot->queue_xmit(sk, skb->dev, skb, skb->free);
}
}
@@ -2475,79 +2097,67 @@ static void tcp_write_xmit(struct sock *sk)
/*
- * This routine sorts the send list, and resets the
- * sk->send_head and sk->send_tail pointers.
+ * This routine sorts the send list, and resets the
+ * sk->send_head and sk->send_tail pointers.
*/
-
-void sort_send(struct sock *sk)
+void
+sort_send(struct sock *sk)
{
- struct sk_buff *list = NULL;
- struct sk_buff *skb,*skb2,*skb3;
-
- for (skb = sk->send_head; skb != NULL; skb = skb2)
- {
- skb2 = (struct sk_buff *)skb->link3;
- if (list == NULL || before (skb2->h.seq, list->h.seq))
- {
- skb->link3 = list;
- sk->send_tail = skb;
- list = skb;
- }
- else
- {
- for (skb3 = list; ; skb3 = (struct sk_buff *)skb3->link3)
- {
- if (skb3->link3 == NULL || before(skb->h.seq, skb3->link3->h.seq))
- {
- skb->link3 = skb3->link3;
- skb3->link3 = skb;
- if (skb->link3 == NULL)
- sk->send_tail = skb;
- break;
- }
+ struct sk_buff *list = NULL;
+ struct sk_buff *skb,*skb2,*skb3;
+
+ for (skb = sk->send_head; skb != NULL; skb = skb2) {
+ skb2 = (struct sk_buff *)skb->link3;
+ if (list == NULL || before (skb2->h.seq, list->h.seq)) {
+ skb->link3 = list;
+ sk->send_tail = skb;
+ list = skb;
+ } else {
+ for (skb3 = list; ; skb3 = (struct sk_buff *)skb3->link3) {
+ if (skb3->link3 == NULL ||
+ before(skb->h.seq, skb3->link3->h.seq)) {
+ skb->link3 = skb3->link3;
+ skb3->link3 = skb;
+ if (skb->link3 == NULL) sk->send_tail = skb;
+ break;
}
}
- }
- sk->send_head = list;
+ }
+ }
+ sk->send_head = list;
}
-/*
- * This routine deals with incoming acks, but not outgoing ones.
- */
-
-static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
+/* This routine deals with incoming acks, but not outgoing ones. */
+static int
+tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
{
- unsigned long ack;
- int flag = 0;
+ unsigned long ack;
+ int flag = 0;
- if(sk->zapped)
- return(1); /* Dead, cant ack any more so why bother */
+ if(sk->zapped)
+ return(1); /* Dead, cant ack any more so why bother */
- ack = ntohl(th->ack_seq);
- DPRINTF((DBG_TCP, "tcp_ack ack=%d, window=%d, "
- "sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
- ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq));
+ ack = ntohl(th->ack_seq);
+ DPRINTF((DBG_TCP, "tcp_ack ack=%d, window=%d, "
+ "sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
+ ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq));
- if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1))
- {
- if (after(ack, sk->send_seq) || (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT))
- {
- return(0);
- }
- if (sk->keepopen)
- {
- reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- }
- return(1);
- }
+ if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1)) {
+ if (after(ack, sk->send_seq) ||
+ (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) {
+ return(0);
+ }
+ if (sk->keepopen) {
+ reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+ }
+ return(1);
+ }
- if (len != th->doff*4)
- flag |= 1;
+ if (len != th->doff*4) flag |= 1;
- /* See if our window has been shrunk. */
- if (after(sk->window_seq, ack+ntohs(th->window)))
- {
+ /* See if our window has been shrunk. */
+ if (after(sk->window_seq, ack+ntohs(th->window))) {
/*
* We may need to move packets from the send queue
* to the write queue, if the window has been shrunk on us.
@@ -2555,312 +2165,271 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int
* like this, but if the other end does, you must be able
* to deal with it.
*/
- struct sk_buff *skb;
- struct sk_buff *skb2;
- struct sk_buff *wskb = NULL;
+ struct sk_buff *skb;
+ struct sk_buff *skb2;
+ struct sk_buff *wskb = NULL;
- skb2 = sk->send_head;
- sk->send_head = NULL;
- sk->send_tail = NULL;
+ skb2 = sk->send_head;
+ sk->send_head = NULL;
+ sk->send_tail = NULL;
- flag |= 4;
+ flag |= 4;
- sk->window_seq = ack + ntohs(th->window);
- cli();
- while (skb2 != NULL)
- {
- skb = skb2;
- skb2 = (struct sk_buff *)skb->link3;
- skb->link3 = NULL;
- if (after(skb->h.seq, sk->window_seq))
- {
- if (sk->packets_out > 0)
- sk->packets_out--;
- /*
- * We may need to remove this from the dev send list.
- */
-
- if (skb->next != NULL)
- {
- skb_unlink(skb);
+ sk->window_seq = ack + ntohs(th->window);
+ cli();
+ while (skb2 != NULL) {
+ skb = skb2;
+ skb2 = (struct sk_buff *)skb->link3;
+ skb->link3 = NULL;
+ if (after(skb->h.seq, sk->window_seq)) {
+ if (sk->packets_out > 0) sk->packets_out--;
+ /* We may need to remove this from the dev send list. */
+ if (skb->next != NULL) {
+#ifdef OLD_WAY
+ int i;
+
+ if (skb->next != skb) {
+ skb->next->prev = skb->prev;
+ skb->prev->next = skb->next;
}
- /* Now add it to the write_queue. */
- skb->magic = TCP_WRITE_QUEUE_MAGIC;
- if (wskb == NULL)
- {
- skb->next = sk->wfront;
- sk->wfront = skb;
- }
- else
- {
- skb->next = wskb->next;
- wskb->next = skb;
+
+ for(i = 0; i < DEV_NUMBUFFS; i++) {
+ if (skb->dev->buffs[i] == skb) {
+ if (skb->next == skb)
+ skb->dev->buffs[i] = NULL;
+ else
+ skb->dev->buffs[i] = skb->next;
+ break;
+ }
}
- if (sk->wback == wskb)
- sk->wback = skb;
- wskb = skb;
- }
- else
- {
- if (sk->send_head == NULL)
- {
- sk->send_head = skb;
- sk->send_tail = skb;
- }
- else
- {
- sk->send_tail->link3 = skb;
- sk->send_tail = skb;
+ if (arp_q == skb) {
+ if (skb->next == skb) arp_q = NULL;
+ else arp_q = skb->next;
}
- skb->link3 = NULL;
+#else
+ skb_unlink(skb);
+#endif
}
+ /* Now add it to the write_queue. */
+ skb->magic = TCP_WRITE_QUEUE_MAGIC;
+ if (wskb == NULL) {
+ skb->next = sk->wfront;
+ sk->wfront = skb;
+ } else {
+ skb->next = wskb->next;
+ wskb->next = skb;
+ }
+ if (sk->wback == wskb) sk->wback = skb;
+ wskb = skb;
+ } else {
+ if (sk->send_head == NULL) {
+ sk->send_head = skb;
+ sk->send_tail = skb;
+ } else {
+ sk->send_tail->link3 = skb;
+ sk->send_tail = skb;
+ }
+ skb->link3 = NULL;
}
- sti();
- }
-
- if (sk->send_tail == NULL || sk->send_head == NULL)
- {
- sk->send_head = NULL;
- sk->send_tail = NULL;
- sk->packets_out= 0;
- }
-
- sk->window_seq = ack + ntohs(th->window);
-
- /* We don't want too many packets out there. */
- if (sk->cong_window < 2048 && ack != sk->rcv_ack_seq)
- {
- if (sk->exp_growth)
- sk->cong_window *= 2;
- else
- sk->cong_window++;
- }
-
- DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n"));
- sk->rcv_ack_seq = ack;
-
- /* See if we can take anything off of the retransmit queue. */
- while(sk->send_head != NULL)
- {
- /* Check for a bug. */
- if (sk->send_head->link3 && after(sk->send_head->h.seq, sk->send_head->link3->h.seq))
- {
- printk("INET: tcp.c: *** bug send_list out of order.\n");
- sort_send(sk);
- }
+ }
+ sti();
+ }
+
+ if (sk->send_tail == NULL || sk->send_head == NULL) {
+ sk->send_head = NULL;
+ sk->send_tail = NULL;
+ sk->packets_out= 0;
+ }
+
+ sk->window_seq = ack + ntohs(th->window);
+
+ /* We don't want too many packets out there. */
+ if (sk->cong_window < 2048 && ack != sk->rcv_ack_seq) {
+ if (sk->exp_growth) sk->cong_window *= 2;
+ else sk->cong_window++;
+ }
+
+ DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n"));
+ sk->rcv_ack_seq = ack;
+
+ /* See if we can take anything off of the retransmit queue. */
+ while(sk->send_head != NULL) {
+ /* Check for a bug. */
+ if (sk->send_head->link3 &&
+ after(sk->send_head->h.seq, sk->send_head->link3->h.seq)) {
+ printk("INET: tcp.c: *** bug send_list out of order.\n");
+ sort_send(sk);
+ }
- if (before(sk->send_head->h.seq, ack+1))
- {
- struct sk_buff *oskb;
+ if (before(sk->send_head->h.seq, ack+1)) {
+ struct sk_buff *oskb;
- sk->retransmits = 0;
+ sk->retransmits = 0;
- /* We have one less packet out there. */
- if (sk->packets_out > 0)
- sk->packets_out --;
- DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n",
+ /* We have one less packet out there. */
+ if (sk->packets_out > 0) sk->packets_out --;
+ DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n",
sk->send_head, sk->send_head->h.seq, ack));
- /* Wake up the process, it can probably write more. */
- if (!sk->dead)
- sk->write_space(sk);
+ /* Wake up the process, it can probably write more. */
+ if (!sk->dead) wake_up(sk->sleep);
- oskb = sk->send_head;
+ oskb = sk->send_head;
- /* Estimate the RTT. Ignore the ones right after a retransmit. */
-
- if (sk->retransmits == 0 && !(flag&2))
- {
- long abserr, rtt = jiffies - oskb->when;
-
- if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
- /* first ack, so nothing else to average with */
- sk->rtt = rtt;
- else
- {
- abserr = (rtt > sk->rtt) ? rtt - sk->rtt : sk->rtt - rtt;
- sk->rtt = (7 * sk->rtt + rtt) >> 3;
- sk->mdev = (3 * sk->mdev + abserr) >> 2;
- }
- sk->backoff = 0;
- }
- flag |= (2|4);
- /* no point retransmitting faster than .1 sec */
- /* 2 minutes is max legal rtt for Internet */
-
- if (sk->rtt < 10)
- sk->rtt = 10;
-
- if (sk->rtt > 12000)
- sk->rtt = 12000;
-
- cli();
-
- oskb = sk->send_head;
- IS_SKB(oskb);
- sk->send_head =(struct sk_buff *)oskb->link3;
- if (sk->send_head == NULL)
- {
- sk->send_tail = NULL;
- }
+ /* Estimate the RTT. Ignore the ones right after a retransmit. */
+ if (sk->retransmits == 0 && !(flag&2)) {
+ long abserr, rtt = jiffies - oskb->when;
- /* We may need to remove this from the dev send list. */
- skb_unlink(oskb); /* Much easier! */
- sti();
- oskb->magic = 0;
- kfree_skb(oskb, FREE_WRITE); /* write. */
- if (!sk->dead)
- sk->write_space(sk);
- }
- else
- {
- break;
+ if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
+ /* first ack, so nothing else to average with */
+ sk->rtt = rtt;
+ else {
+ abserr = (rtt > sk->rtt) ? rtt - sk->rtt : sk->rtt - rtt;
+ sk->rtt = (7 * sk->rtt + rtt) >> 3;
+ sk->mdev = (3 * sk->mdev + abserr) >> 2;
+ }
+ sk->backoff = 0;
}
- }
+ flag |= (2|4);
+ /* no point retransmitting faster than .1 sec */
+ /* 2 minutes is max legal rtt for Internet */
+ if (sk->rtt < 10) sk->rtt = 10;
+ if (sk->rtt > 12000) sk->rtt = 12000;
- /*
- * Maybe we can take some stuff off of the write queue,
- * and put it onto the xmit queue.
- */
- if (sk->wfront != NULL)
- {
- if (after (sk->window_seq, sk->wfront->h.seq) && sk->packets_out < sk->cong_window)
- {
- flag |= 1;
- tcp_write_xmit(sk);
- }
- }
- else
- {
- if (sk->send_head == NULL && sk->ack_backlog == 0 && sk->state != TCP_TIME_WAIT && !sk->keepopen)
- {
- DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n"));
- if (!sk->dead)
- sk->write_space(sk);
-
- if (sk->keepopen)
- reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
- else
- delete_timer(sk);
- }
- else
- {
- if (sk->state != (unsigned char) sk->keepopen)
- {
- reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
- }
- if (sk->state == TCP_TIME_WAIT)
- {
- reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- }
+ cli();
+
+ oskb = sk->send_head;
+ IS_SKB(oskb);
+ sk->send_head =(struct sk_buff *)oskb->link3;
+ if (sk->send_head == NULL) {
+ sk->send_tail = NULL;
}
- }
- /*
- * If we have nothing left to send then send the packet we are currently assembling
- */
-
- if (sk->packets_out == 0 && sk->send_tmp != NULL && sk->wfront == NULL && sk->send_head == NULL)
- {
+ /* We may need to remove this from the dev send list. */
+ skb_unlink(oskb); /* Much easier! */
+ sti();
+ oskb->magic = 0;
+ kfree_skb(oskb, FREE_WRITE); /* write. */
+ if (!sk->dead) wake_up(sk->sleep);
+ } else {
+ break;
+ }
+ }
+
+ /*
+ * Maybe we can take some stuff off of the write queue,
+ * and put it onto the xmit queue.
+ */
+ if (sk->wfront != NULL) {
+ if (after (sk->window_seq, sk->wfront->h.seq) &&
+ sk->packets_out < sk->cong_window) {
flag |= 1;
- tcp_send_partial(sk);
- }
+ tcp_write_xmit(sk);
+ }
+ } else {
+ if (sk->send_head == NULL && sk->ack_backlog == 0 &&
+ sk->state != TCP_TIME_WAIT && !sk->keepopen) {
+ DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n"));
+ if (!sk->dead) wake_up(sk->sleep);
- /* See if we are done. */
- if (sk->state == TCP_TIME_WAIT)
- {
-
- /*
- * Our FIN has been acknowledged
- */
-
- if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq)
- {
- flag |= 1;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- sk->state_change(sk);
+ if (sk->keepopen)
+ reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+ else
+ delete_timer(sk);
+ } else {
+ if (sk->state != (unsigned char) sk->keepopen) {
+ reset_timer(sk, TIME_WRITE,
+ backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
}
- }
+ if (sk->state == TCP_TIME_WAIT) {
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ }
+ }
+ }
+
+ if (sk->packets_out == 0 && sk->send_tmp != NULL &&
+ sk->wfront == NULL && sk->send_head == NULL) {
+ flag |= 1;
+ tcp_send_partial(sk);
+ }
+
+ /* See if we are done. */
+ if (sk->state == TCP_TIME_WAIT) {
+ if (!sk->dead) wake_up(sk->sleep);
+ if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) {
+ flag |= 1;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ }
+ }
- if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2)
- {
- if (sk->rcv_ack_seq == sk->send_seq)
- {
- flag |= 1;
- if (sk->acked_seq != sk->fin_seq)
- {
- tcp_time_wait(sk);
- }
- else
- {
- DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk));
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk,
+ if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) {
+ if (!sk->dead) wake_up(sk->sleep);
+ if (sk->rcv_ack_seq == sk->send_seq) {
+ flag |= 1;
+ if (sk->acked_seq != sk->fin_seq) {
+ tcp_time_wait(sk);
+ } else {
+ DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk));
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk,
th, sk->daddr);
- sk->shutdown = SHUTDOWN_MASK;
- sk->state = TCP_CLOSE;
- }
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->state = TCP_CLOSE;
}
- if (!sk->dead)
- sk->state_change(sk);
-
- }
-
- if (((!flag) || (flag&4)) && sk->send_head != NULL && (sk->send_head->when + backoff(sk->backoff) * (2 * sk->mdev + sk->rtt) < jiffies))
- {
- sk->exp_growth = 0;
- ip_retransmit(sk, 0);
}
+ }
- DPRINTF((DBG_TCP, "leaving tcp_ack\n"));
- return(1);
+ if (((!flag) || (flag&4)) && sk->send_head != NULL &&
+ (sk->send_head->when + backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)
+ < jiffies)) {
+ sk->exp_growth = 0;
+ ip_retransmit(sk, 0);
+ }
+
+ DPRINTF((DBG_TCP, "leaving tcp_ack\n"));
+ return(1);
}
/*
- * This routine handles the data. If there is room in the buffer,
- * it will be have already been moved into it. If there is no
- * room, then we will just have to discard the packet.
+ * This routine handles the data. If there is room in the buffer,
+ * it will be have already been moved into it. If there is no
+ * room, then we will just have to discard the packet.
*/
-
-static int tcp_data(struct sk_buff *skb, struct sock *sk,
+static int
+tcp_data(struct sk_buff *skb, struct sock *sk,
unsigned long saddr, unsigned short len)
{
- struct sk_buff *skb1, *skb2;
- struct tcphdr *th;
- int dup_dumped=0;
-
- th = skb->h.th;
- print_th(th);
-
- skb->len = len -(th->doff*4);
-
- DPRINTF((DBG_TCP, "tcp_data len = %d sk = %X:\n", skb->len, sk));
-
- sk->bytes_rcv += skb->len;
- if (skb->len == 0 && !th->fin && !th->urg && !th->psh)
- {
- /* Don't want to keep passing ack's back and forth. */
- if (!th->ack)
- tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr);
- kfree_skb(skb, FREE_READ);
- return(0);
- }
-
- if (sk->shutdown & RCV_SHUTDOWN)
- {
- sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
- tcp_reset(sk->saddr, sk->daddr, skb->h.th, sk->prot, NULL, skb->dev);
- sk->state = TCP_CLOSE;
- sk->err = EPIPE;
- sk->shutdown = SHUTDOWN_MASK;
- DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk));
- kfree_skb(skb, FREE_READ);
- if (!sk->dead)
- sk->state_change(sk);
- return(0);
- }
+ struct sk_buff *skb1, *skb2;
+ struct tcphdr *th;
+ int dup_dumped=0;
+
+ th = skb->h.th;
+ print_th(th);
+ skb->len = len -(th->doff*4);
+
+ DPRINTF((DBG_TCP, "tcp_data len = %d sk = %X:\n", skb->len, sk));
+
+ sk->bytes_rcv += skb->len;
+ if (skb->len == 0 && !th->fin && !th->urg && !th->psh) {
+ /* Don't want to keep passing ack's back and forth. */
+ if (!th->ack) tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr);
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
+
+ if (sk->shutdown & RCV_SHUTDOWN) {
+ sk->acked_seq = th->seq + skb->len + th->syn + th->fin;
+ tcp_reset(sk->saddr, sk->daddr, skb->h.th,
+ sk->prot, NULL, skb->dev);
+ sk->state = TCP_CLOSE;
+ sk->err = EPIPE;
+ sk->shutdown = SHUTDOWN_MASK;
+ DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk));
+ kfree_skb(skb, FREE_READ);
+ if (!sk->dead) wake_up(sk->sleep);
+ return(0);
+ }
/*
* Now we have to walk the chain, and figure out where this one
@@ -2870,482 +2439,430 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk,
* out of order we will be able to fit things in nicely.
*/
- /*
- * This should start at the last one, and then go around forwards.
- */
-
- if (sk->rqueue == NULL)
- {
- DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb));
- skb_queue_head(&sk->rqueue,skb);
- skb1= NULL;
- }
- else
- {
- DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk));
- for(skb1=sk->rqueue->prev; ; skb1 =(struct sk_buff *)skb1->prev)
+ /* This should start at the last one, and then go around forwards. */
+ if (sk->rqueue == NULL) {
+ DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb));
+#ifdef OLDWAY
+ sk->rqueue = skb;
+ skb->next = skb;
+ skb->prev = skb;
+ skb->list = &sk->rqueue;
+#else
+ skb_queue_head(&sk->rqueue,skb);
+#endif
+ skb1= NULL;
+ } else {
+ DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk));
+ for(skb1=sk->rqueue->prev; ; skb1 =(struct sk_buff *)skb1->prev) {
+ if(sk->debug)
{
- if(sk->debug)
- {
- printk("skb1=%p :", skb1);
- printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
- printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
- printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
- sk->acked_seq);
- }
- if (th->seq==skb1->h.th->seq && skb->len>= skb1->len)
- {
- skb_append(skb1,skb);
- skb_unlink(skb1);
- kfree_skb(skb1,FREE_READ);
- dup_dumped=1;
- skb1=NULL;
- break;
- }
- if (after(th->seq+1, skb1->h.th->seq))
- {
- skb_append(skb1,skb);
- break;
- }
- if (skb1 == sk->rqueue)
- {
- skb_queue_head(&sk->rqueue, skb);
- break;
- }
+ printk("skb1=%p :", skb1);
+ printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq);
+ printk("skb->h.th->seq = %ld\n",skb->h.th->seq);
+ printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq,
+ sk->acked_seq);
+ }
+#ifdef OLD
+ if (after(th->seq+1, skb1->h.th->seq)) {
+ skb->prev = skb1;
+ skb->next = skb1->next;
+ skb->next->prev = skb;
+ skb1->next = skb;
+ if (skb1 == sk->rqueue) sk->rqueue = skb;
+ break;
+ }
+ if (skb1->prev == sk->rqueue) {
+ skb->next= skb1;
+ skb->prev = skb1->prev;
+ skb->prev->next = skb;
+ skb1->prev = skb;
+ skb1 = NULL; /* so we know we might be able
+ to ack stuff. */
+ break;
+ }
+#else
+ if (th->seq==skb1->h.th->seq && skb->len>= skb1->len)
+ {
+ skb_append(skb1,skb);
+ skb_unlink(skb1);
+ kfree_skb(skb1,FREE_READ);
+ dup_dumped=1;
+ skb1=NULL;
+ break;
+ }
+ if (after(th->seq+1, skb1->h.th->seq))
+ {
+ skb_append(skb1,skb);
+ break;
+ }
+ if (skb1 == sk->rqueue)
+ {
+ skb_queue_head(&sk->rqueue, skb);
+ break;
+ }
+#endif
+ }
+ DPRINTF((DBG_TCP, "skb = %X:\n", skb));
+ }
+
+ th->ack_seq = th->seq + skb->len;
+ if (th->syn) th->ack_seq++;
+ if (th->fin) th->ack_seq++;
+
+ if (before(sk->acked_seq, sk->copied_seq)) {
+ printk("*** tcp.c:tcp_data bug acked < copied\n");
+ sk->acked_seq = sk->copied_seq;
+ }
+
+ /* Now figure out if we can ack anything. */
+ if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) {
+ if (before(th->seq, sk->acked_seq+1)) {
+ if (after(th->ack_seq, sk->acked_seq))
+ sk->acked_seq = th->ack_seq;
+ skb->acked = 1;
+
+ /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
+ if (skb->h.th->fin) {
+ if (!sk->dead) wake_up(sk->sleep);
+ sk->shutdown |= RCV_SHUTDOWN;
}
- DPRINTF((DBG_TCP, "skb = %X:\n", skb));
- }
-
- th->ack_seq = th->seq + skb->len;
-
- if (th->syn)
- th->ack_seq++;
-
- if (th->fin)
- th->ack_seq++;
-
- if (before(sk->acked_seq, sk->copied_seq))
- {
- printk("*** tcp.c:tcp_data bug acked < copied\n");
- sk->acked_seq = sk->copied_seq;
- }
-
- /* Now figure out if we can ack anything. */
-
- if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1))
- {
- if (before(th->seq, sk->acked_seq+1))
- {
- if (after(th->ack_seq, sk->acked_seq))
- sk->acked_seq = th->ack_seq;
- skb->acked = 1;
-
- /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */
- if (skb->h.th->fin)
- {
- if (!sk->dead)
- sk->state_change(sk);
- sk->shutdown |= RCV_SHUTDOWN;
- }
- for(skb2 = (struct sk_buff *)skb->next;
- skb2 !=(struct sk_buff *) sk->rqueue;
- skb2 = (struct sk_buff *)skb2->next)
- {
- if (before(skb2->h.th->seq, sk->acked_seq+1))
- {
- if (after(skb2->h.th->ack_seq, sk->acked_seq))
- sk->acked_seq = skb2->h.th->ack_seq;
- skb2->acked = 1;
-
- /*
- * When we ack the fin, we turn on
- * the RCV_SHUTDOWN flag.
- */
- if (skb2->h.th->fin)
- {
- sk->shutdown |= RCV_SHUTDOWN;
- if (!sk->dead)
- sk->state_change(sk);
- }
+ for(skb2 = (struct sk_buff *)skb->next;
+ skb2 !=(struct sk_buff *) sk->rqueue;
+ skb2 = (struct sk_buff *)skb2->next) {
+ if (before(skb2->h.th->seq, sk->acked_seq+1)) {
+ if (after(skb2->h.th->ack_seq, sk->acked_seq))
+ sk->acked_seq = skb2->h.th->ack_seq;
+ skb2->acked = 1;
- /* Force an immediate ack. */
- sk->ack_backlog = sk->max_ack_backlog;
- }
- else
- {
- break;
+ /*
+ * When we ack the fin, we turn on
+ * the RCV_SHUTDOWN flag.
+ */
+ if (skb2->h.th->fin) {
+ sk->shutdown |= RCV_SHUTDOWN;
+ if (!sk->dead) wake_up(sk->sleep);
}
- }
- /*
- * This also takes care of updating the window.
- * This if statement needs to be simplified.
- */
- if (!sk->delay_acks || sk->ack_backlog >= sk->max_ack_backlog ||
- sk->bytes_rcv > sk->max_unacked || th->fin)
- {
-/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */
- }
- else
- {
- sk->ack_backlog++;
- if(sk->debug)
- printk("Ack queued.\n");
- reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
+ /* Force an immediate ack. */
+ sk->ack_backlog = sk->max_ack_backlog;
+ } else {
+ break;
}
}
- }
- /*
- * If we've missed a packet, send an ack.
- * Also start a timer to send another.
- */
- if (!skb->acked)
- {
/*
- * This is important. If we don't have much room left,
- * we need to throw out a few packets so we have a good
- * window.
+ * This also takes care of updating the window.
+ * This if statement needs to be simplified.
*/
- while (sk->prot->rspace(sk) < sk->mtu)
- {
- skb1 = skb_peek(&sk->rqueue);
- if (skb1 == NULL)
- {
- printk("INET: tcp.c:tcp_data memory leak detected.\n");
- break;
- }
-
- /* Don't throw out something that has been acked. */
- if (skb1->acked)
- {
- break;
- }
-
- skb_unlink(skb1);
- kfree_skb(skb1, FREE_READ);
+ if (!sk->delay_acks ||
+ sk->ack_backlog >= sk->max_ack_backlog ||
+ sk->bytes_rcv > sk->max_unacked || th->fin) {
+/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */
+ } else {
+ sk->ack_backlog++;
+ if(sk->debug)
+ printk("Ack queued.\n");
+ reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
}
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- sk->ack_backlog++;
- reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
- }
- else
- {
- /* We missed a packet. Send an ack to try to resync things. */
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- }
-
- /* Now tell the user we may have some data. */
- if (!sk->dead)
- {
- if(sk->debug)
- printk("Data wakeup.\n");
- sk->data_ready(sk,0);
- }
- else
- {
- DPRINTF((DBG_TCP, "data received on dead socket.\n"));
- }
+ }
+ }
- if (sk->state == TCP_FIN_WAIT2 && sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq)
- {
- DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk));
+ /*
+ * If we've missed a packet, send an ack.
+ * Also start a timer to send another.
+ */
+ if (!skb->acked) {
+ /*
+ * This is important. If we don't have much room left,
+ * we need to throw out a few packets so we have a good
+ * window.
+ */
+ while (sk->prot->rspace(sk) < sk->mtu) {
+ skb1 = skb_peek(&sk->rqueue);
+ if (skb1 == NULL) {
+ printk("INET: tcp.c:tcp_data memory leak detected.\n");
+ break;
+ }
-/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
- sk->shutdown = SHUTDOWN_MASK;
- sk->state = TCP_LAST_ACK;
- if (!sk->dead)
- sk->state_change(sk);
+ /* Don't throw out something that has been acked. */
+ if (skb1->acked) {
+ break;
+ }
+
+ skb_unlink(skb1);
+#ifdef OLDWAY
+ if (skb1->prev == skb1) {
+ sk->rqueue = NULL;
+ } else {
+ sk->rqueue = (struct sk_buff *)skb1->prev;
+ skb1->next->prev = skb1->prev;
+ skb1->prev->next = skb1->next;
+ }
+#endif
+ kfree_skb(skb1, FREE_READ);
}
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ sk->ack_backlog++;
+ reset_timer(sk, TIME_WRITE, TCP_ACK_TIME);
+ } else {
+ /* We missed a packet. Send an ack to try to resync things. */
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ }
+
+ /* Now tell the user we may have some data. */
+ if (!sk->dead) {
+ if(sk->debug)
+ printk("Data wakeup.\n");
+ wake_up(sk->sleep);
+ } else {
+ DPRINTF((DBG_TCP, "data received on dead socket.\n"));
+ }
+
+ if (sk->state == TCP_FIN_WAIT2 &&
+ sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq) {
+ DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk));
+
+/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->state = TCP_LAST_ACK;
+ if (!sk->dead) wake_up(sk->sleep);
+ }
- return(0);
+ return(0);
}
-static int tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
+static int
+tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr)
{
- extern int kill_pg(int pg, int sig, int priv);
- extern int kill_proc(int pid, int sig, int priv);
+ 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->dead) wake_up(sk->sleep);
- if (sk->urginline)
- {
- th->urg = 0;
- th->psh = 1;
- return(0);
- }
-
- if (!sk->urg)
- {
- /* So if we get more urgent data, we don't signal the user again. */
- if (sk->proc != 0)
- {
- if (sk->proc > 0)
- {
- kill_proc(sk->proc, SIGURG, 1);
- }
- else
- {
- kill_pg(-sk->proc, SIGURG, 1);
- }
+ if (sk->urginline) {
+ th->urg = 0;
+ th->psh = 1;
+ return(0);
+ }
+
+ if (!sk->urg) {
+ /* So if we get more urgent data, we don't signal the user again. */
+ if (sk->proc != 0) {
+ if (sk->proc > 0) {
+ kill_proc(sk->proc, SIGURG, 1);
+ } else {
+ kill_pg(-sk->proc, SIGURG, 1);
}
- }
- sk->urg++;
- return(0);
+ }
+ }
+ sk->urg++;
+ return(0);
}
-/*
- * This deals with incoming fins. [Page 75]
- */
-
-static int tcp_fin(struct sock *sk, struct tcphdr *th,
+/* This deals with incoming fins. */
+static int
+tcp_fin(struct sock *sk, struct tcphdr *th,
unsigned long saddr, struct device *dev)
{
- DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
+ DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n",
sk, th, saddr, dev));
+ if (!sk->dead) {
+ wake_up(sk->sleep);
+ }
+
+ switch(sk->state) {
+ case TCP_SYN_RECV:
+ case TCP_SYN_SENT:
+ case TCP_ESTABLISHED:
+ /* Contains the one that needs to be acked */
+ sk->fin_seq = th->seq+1;
+ sk->state = TCP_CLOSE_WAIT;
+ if (th->rst) sk->shutdown = SHUTDOWN_MASK;
+ break;
+
+ case TCP_CLOSE_WAIT:
+ case TCP_FIN_WAIT2:
+ break; /* we got a retransmit of the fin. */
+
+ case TCP_FIN_WAIT1:
+ /* Contains the one that needs to be acked */
+ sk->fin_seq = th->seq+1;
+ sk->state = TCP_FIN_WAIT2;
+ break;
+
+ default:
+ case TCP_TIME_WAIT:
+ sk->state = TCP_LAST_ACK;
- switch(sk->state)
- {
- case TCP_SYN_RECV:
- case TCP_SYN_SENT:
- case TCP_ESTABLISHED:
- /* Contains the one that needs to be acked */
- sk->fin_seq = th->seq+1;
- sk->state = TCP_CLOSE_WAIT;
- if (th->rst)
- sk->shutdown = SHUTDOWN_MASK;
- break;
-
- case TCP_CLOSE_WAIT:
- break;
-
- case TCP_FIN_WAIT2:
- tcp_time_wait(sk);
- break; /* we got a retransmit of the fin. */
-
- case TCP_FIN_WAIT1:
- /* Contains the one that needs to be acked */
- if(before(sk->send_seq,sk->rcv_ack_seq+1) && after(sk->send_seq,sk->rcv_ack_seq-1))
- tcp_time_wait(sk);
- else
- {
- sk->fin_seq = th->seq+1;
- sk->state = TCP_FIN_WAIT2;/* should be closing */
- }
- break;
-
- default:
- case TCP_TIME_WAIT:
- sk->state = TCP_LAST_ACK;
-
- /* Start the timers. */
- reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
- return(0);
- }
- sk->ack_backlog++;
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
+ /* Start the timers. */
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ return(0);
+ }
+ sk->ack_backlog++;
- return(0);
+ return(0);
}
-/*
- * This will accept the next outstanding connection.
- */
-
-static struct sock *tcp_accept(struct sock *sk, int flags)
+/* This will accept the next outstanding connection. */
+static struct sock *
+tcp_accept(struct sock *sk, int flags)
{
- struct sock *newsk;
- struct sk_buff *skb;
+ struct sock *newsk;
+ struct sk_buff *skb;
- DPRINTF((DBG_TCP, "tcp_accept(sk=%X, flags=%X, addr=%s)\n",
+ DPRINTF((DBG_TCP, "tcp_accept(sk=%X, flags=%X, addr=%s)\n",
sk, flags, in_ntoa(sk->saddr)));
- /*
- * We need to make sure that this socket is listening,
- * and that it has something pending.
- */
-
- if (sk->state != TCP_LISTEN)
- {
- sk->err = EINVAL;
- return(NULL);
- }
-
- /* avoid the race. */
-
- cli();
- sk->inuse = 1;
- while((skb = get_firstr(sk)) == NULL)
- {
- /*
- * Nobody connecting
- */
- if (flags & O_NONBLOCK)
- {
- sti();
- release_sock(sk);
- sk->err = EAGAIN;
- return(NULL);
- }
-
+ /*
+ * We need to make sure that this socket is listening,
+ * and that it has something pending.
+ */
+ if (sk->state != TCP_LISTEN) {
+ sk->err = EINVAL;
+ return(NULL);
+ }
+
+ /* avoid the race. */
+ cli();
+ sk->inuse = 1;
+ while((skb = get_firstr(sk)) == NULL) {
+ if (flags & O_NONBLOCK) {
+ sti();
release_sock(sk);
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked)
- {
- sti();
- sk->err = ERESTARTSYS;
- return(NULL);
- }
- sk->inuse = 1;
- }
- sti();
+ sk->err = EAGAIN;
+ return(NULL);
+ }
+
+ release_sock(sk);
+ interruptible_sleep_on(sk->sleep);
+ if (current->signal & ~current->blocked) {
+ sti();
+ sk->err = ERESTARTSYS;
+ return(NULL);
+ }
+ sk->inuse = 1;
+ }
+ sti();
- /* Now all we need to do is return skb->sk. */
- newsk = skb->sk;
+ /* Now all we need to do is return skb->sk. */
+ newsk = skb->sk;
- kfree_skb(skb, FREE_READ);
- sk->ack_backlog--;
- release_sock(sk);
- return(newsk);
+ kfree_skb(skb, FREE_READ);
+ sk->ack_backlog--;
+ release_sock(sk);
+ return(newsk);
}
-/*
- * This will initiate an outgoing connection.
- */
-
-static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
+/* This will initiate an outgoing connection. */
+static int
+tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{
- struct sk_buff *buff;
- struct sockaddr_in sin;
- struct device *dev=NULL;
- unsigned char *ptr;
- int tmp;
- struct tcphdr *t1;
- int err;
-
- if (sk->state != TCP_CLOSE)
- return(-EISCONN);
-
- if (addr_len < 8)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, usin, addr_len);
- if(err)
- return err;
+ struct sk_buff *buff;
+ struct sockaddr_in sin;
+ struct device *dev=NULL;
+ unsigned char *ptr;
+ int tmp;
+ struct tcphdr *t1;
+ int err;
+
+ if (sk->state != TCP_CLOSE) return(-EISCONN);
+ if (addr_len < 8) return(-EINVAL);
+
+ err=verify_area(VERIFY_READ, usin, addr_len);
+ if(err)
+ return err;
- memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
+ memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EAFNOSUPPORT);
+ if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
- DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr)));
+ DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr)));
- /*
- * Don't want a TCP connection going to a broadcast address
- */
-
- if (chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST)
- {
- DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
- return(-ENETUNREACH);
- }
-
- sk->inuse = 1;
- sk->daddr = sin.sin_addr.s_addr;
- sk->send_seq = jiffies * SEQ_TICK - seq_offset;
- sk->rcv_ack_seq = sk->send_seq -1;
- sk->err = 0;
- sk->dummy_th.dest = sin.sin_port;
- release_sock(sk);
-
- buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
- if (buff == NULL)
- {
- return(-ENOMEM);
- }
+ /* Don't want a TCP connection going to a broadcast address */
+ if (chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) {
+ DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
+ return(-ENETUNREACH);
+ }
- sk->inuse = 1;
- buff->mem_addr = buff;
- buff->mem_len = MAX_SYN_SIZE;
- buff->len = 24;
- buff->sk = sk;
- buff->free = 1;
- t1 = (struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- /* We need to build the routing stuff fromt the things saved in skb. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,IPPROTO_TCP, NULL, MAX_SYN_SIZE,
- sk->ip_ttl,sk->ip_tos);
+ sk->inuse = 1;
+ sk->daddr = sin.sin_addr.s_addr;
+ sk->send_seq = jiffies * SEQ_TICK - seq_offset;
+ sk->rcv_ack_seq = sk->send_seq -1;
+ sk->err = 0;
+ sk->dummy_th.dest = sin.sin_port;
+ release_sock(sk);
+
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL);
+ if (buff == NULL) {
+ return(-ENOMEM);
+ }
+ sk->inuse = 1;
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_SYN_SIZE;
+ buff->len = 24;
+ buff->sk = sk;
+ buff->free = 1;
+ t1 = (struct tcphdr *)(buff + 1);
+
+ /* Put in the IP header and routing stuff. */
+ /* We need to build the routing stuff fromt the things saved in skb. */
+ tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, NULL, MAX_SYN_SIZE);
+ if (tmp < 0) {
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ release_sock(sk);
+ return(-ENETUNREACH);
+ }
+ buff->len += tmp;
+ t1 = (struct tcphdr *)((char *)t1 +tmp);
+
+ memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
+ t1->seq = ntohl(sk->send_seq++);
+ buff->h.seq = sk->send_seq;
+ t1->ack = 0;
+ t1->window = 2;
+ t1->res1=0;
+ t1->res2=0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->psh = 0;
+ t1->syn = 1;
+ t1->urg_ptr = 0;
+ t1->doff = 6;
+
+ /* Put in the TCP options to say MTU. */
+ ptr = (unsigned char *)(t1+1);
+ ptr[0] = 2;
+ ptr[1] = 4;
+ ptr[2] = (dev->mtu- HEADER_SIZE) >> 8;
+ ptr[3] = (dev->mtu- HEADER_SIZE) & 0xff;
+ sk->mtu = dev->mtu - HEADER_SIZE;
+ tcp_send_check(t1, sk->saddr, sk->daddr,
+ sizeof(struct tcphdr) + 4, sk);
+
+ /* This must go first otherwise a really quick response will get reset. */
+ sk->state = TCP_SYN_SENT;
+ sk->rtt = TCP_CONNECT_TIME;
+ reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
+ sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
+
+ sk->prot->queue_xmit(sk, dev, buff, 0);
- if (tmp < 0)
- {
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- release_sock(sk);
- return(-ENETUNREACH);
- }
- buff->len += tmp;
- t1 = (struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1));
- t1->seq = ntohl(sk->send_seq++);
- buff->h.seq = sk->send_seq;
- t1->ack = 0;
- t1->window = 2;
- t1->res1=0;
- t1->res2=0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->syn = 1;
- t1->urg_ptr = 0;
- t1->doff = 6;
-
- /* Put in the TCP options to say MTU. */
- ptr = (unsigned char *)(t1+1);
- ptr[0] = 2;
- ptr[1] = 4;
- ptr[2] = (dev->mtu- HEADER_SIZE) >> 8;
- ptr[3] = (dev->mtu- HEADER_SIZE) & 0xff;
- sk->mtu = dev->mtu - HEADER_SIZE;
- tcp_send_check(t1, sk->saddr, sk->daddr,
- sizeof(struct tcphdr) + 4, sk);
-
- /*
- * This must go first otherwise a really quick response will get reset.
- */
-
- sk->state = TCP_SYN_SENT;
- sk->rtt = TCP_CONNECT_TIME;
- reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
- sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
-
- sk->prot->queue_xmit(sk, dev, buff, 0);
-
- release_sock(sk);
- return(0);
+ release_sock(sk);
+ return(0);
}
-/*
- * This functions checks to see if the tcp header is actually acceptible.
- */
-
-static int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
- struct options *opt, unsigned long saddr, struct device *dev)
+/* This functions checks to see if the tcp header is actually acceptible. */
+static int
+tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
+ struct options *opt, unsigned long saddr)
{
/*
* This isn't quite right. sk->acked_seq could be more recent
@@ -3353,711 +2870,552 @@ static int tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
* slightly more packets than we should, but it should not cause
* problems unless someone is trying to forge packets.
*/
- DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n",
- sk, th, len, opt, saddr));
-
- /* Is it within the windows */
- if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)||
- between(th->seq + len-(th->doff*4), sk->acked_seq + 1, sk->acked_seq + sk->window) ||
- (before(th->seq, sk->acked_seq) &&
- after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window)))
- {
- return(1);
- }
- DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
-
- /*
- * Send a reset if we get something not ours and we are
- * unsynchronized. Note: We don't do anything to our end. We
- * are just killing the bogus remote connection then we will
- * connect again and it will work (with luck).
- */
-
- if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV)
- {
- tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev);
- return(1);
- }
+ DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n",
+ sk, th, len, opt, saddr));
+
+ if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)||
+ between(th->seq + len-(th->doff*4), sk->acked_seq + 1,
+ sk->acked_seq + sk->window) ||
+ (before(th->seq, sk->acked_seq) &&
+ after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window))) {
+ return(1);
+ }
+ DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n"));
- /*
- * If it's too far ahead, send an ack to let the
- * other end know what we expect.
- */
-
- if (after(th->seq, sk->acked_seq + sk->window))
- {
- if(!th->rst)
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- return(0);
- }
-
- /*
- * In case it's just a late ack, let it through.
- */
-
- if (th->ack && len == (th->doff * 4) && after(th->seq, sk->acked_seq - 32767) && !th->fin && !th->syn)
- return(1);
-
- if (!th->rst)
- {
- /* Try to resync things. */
+ /*
+ * If it's too far ahead, send an ack to let the
+ * other end know what we expect.
+ */
+ if (after(th->seq, sk->acked_seq + sk->window)) {
+ if(!th->rst)
tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
- }
- return(0);
+ return(0);
+ }
+
+ /* In case it's just a late ack, let it through. */
+ if (th->ack && len == (th->doff * 4) &&
+ after(th->seq, sk->acked_seq - 32767) &&
+ !th->fin && !th->syn) return(1);
+
+ if (!th->rst) {
+ /* Try to resync things. */
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ }
+ return(0);
}
-/*
- * A TCP frame has been received by the IP layer and will now
- * be thrown to us for processing. I've dropped page numbers
- * into this. These are from the ASCII version of the RFC
- * and should help anyone following it.
- */
-int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+
+int
+tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol * protocol)
{
- struct tcphdr *th;
- struct sock *sk;
-
- if (!skb)
- {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n"));
- return(0);
- }
-
- if (!dev)
- {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n"));
- return(0);
- }
-
- th = skb->h.th;
-
- /* Find the socket. */
- sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
- DPRINTF((DBG_TCP, "<<\n"));
- DPRINTF((DBG_TCP, "len = %d, redo = %d, skb=%X\n", len, redo, skb));
-
- /* If this socket has got a reset its to all intents and purposes
- really dead */
+ struct tcphdr *th;
+ struct sock *sk;
+
+ if (!skb) {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n"));
+ return(0);
+ }
+#if 0 /* FIXME: it's ok for protocol to be NULL */
+ if (!protocol) {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv protocol = NULL\n"));
+ return(0);
+ }
+
+ if (!opt) { /* FIXME: it's ok for opt to be NULL */
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv opt = NULL\n"));
+ }
+#endif
+ if (!dev) {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n"));
+ return(0);
+ }
+ th = skb->h.th;
+
+ /* Find the socket. */
+ sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
+ DPRINTF((DBG_TCP, "<<\n"));
+ DPRINTF((DBG_TCP, "len = %d, redo = %d, skb=%X\n", len, redo, skb));
- if (sk!=NULL && sk->zapped)
- sk=NULL;
+ /* If this socket has got a reset its to all intents and purposes
+ really dead */
+ if (sk!=NULL && sk->zapped)
+ sk=NULL;
- if (sk)
- {
- DPRINTF((DBG_TCP, "sk = %X:\n", sk));
- }
+ if (sk) {
+ DPRINTF((DBG_TCP, "sk = %X:\n", sk));
+ }
- if (!redo)
- {
- if (tcp_check(th, len, saddr, daddr ))
- {
- skb->sk = NULL;
- DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n"));
- if (inet_debug == DBG_SLIP)
- printk("\rtcp_rcv: bad checksum\n");
- kfree_skb(skb,FREE_READ);
- /*
- * We don't release the socket because it was
- * never marked in use.
- */
- return(0);
- }
+ if (!redo) {
+ if (tcp_check(th, len, saddr, daddr )) {
+ skb->sk = NULL;
+ DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n"));
+if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
+ kfree_skb(skb,FREE_READ);
+ /*
+ * We don't release the socket because it was
+ * never marked in use.
+ */
+ return(0);
+ }
- /* See if we know about the socket. */
- if (sk == NULL)
- {
- /*
- * Segment to 'closed' socket [Page 65]
- */
- if (!th->rst)
- {
- th->seq = ntohl(th->seq);
- /* So reset is always called with th->seq in host order */
- tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
- }
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
+ /* See if we know about the socket. */
+ if (sk == NULL) {
+ if (!th->rst)
+ {
+ th->seq = ntohl(th->seq);
+ /* So reset is always called with th->seq in host order */
+ tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
}
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return(0);
+ }
- skb->len = len;
- skb->sk = sk;
- skb->acked = 0;
- skb->used = 0;
- skb->free = 0;
- skb->urg_used = 0;
- skb->saddr = daddr;
- skb->daddr = saddr;
-
- th->seq = ntohl(th->seq);
-
- /* We may need to add it to the backlog here. */
- cli();
- if (sk->inuse)
- {
- if (sk->back_log == NULL)
- {
- sk->back_log = skb;
- skb->next = skb;
- skb->prev = skb;
- }
- else
- {
- skb->next = sk->back_log;
- skb->prev = sk->back_log->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- }
- sti();
- return(0);
+ skb->len = len;
+ skb->sk = sk;
+ skb->acked = 0;
+ skb->used = 0;
+ skb->free = 0;
+ skb->urg_used = 0;
+ skb->saddr = daddr;
+ skb->daddr = saddr;
+
+ th->seq = ntohl(th->seq);
+
+ /* We may need to add it to the backlog here. */
+ cli();
+ if (sk->inuse) {
+ if (sk->back_log == NULL) {
+ sk->back_log = skb;
+ skb->next = skb;
+ skb->prev = skb;
+ } else {
+ skb->next = sk->back_log;
+ skb->prev = sk->back_log->prev;
+ skb->prev->next = skb;
+ skb->next->prev = skb;
}
- sk->inuse = 1;
sti();
- }
- else
- {
- if (!sk)
- {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv bug sk=NULL redo = 1\n"));
- return(0);
- }
- }
-
-
- if (!sk->prot)
- {
- DPRINTF((DBG_TCP, "tcp.c: tcp_rcv sk->prot = NULL \n"));
return(0);
- }
-
- /* Charge the memory to the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
- skb->sk = NULL;
- DPRINTF((DBG_TCP, "dropping packet due to lack of buffer space.\n"));
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
+ }
+ sk->inuse = 1;
+ sti();
+ } else {
+ if (!sk) {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv bug sk=NULL redo = 1\n"));
return(0);
- }
-
- sk->rmem_alloc += skb->mem_len;
-
- DPRINTF((DBG_TCP, "About to do switch.\n"));
-
- /* Now deal with it. */
-
- switch(sk->state)
- {
+ }
+ }
+
+ if (!sk->prot) {
+ DPRINTF((DBG_TCP, "tcp.c: tcp_rcv sk->prot = NULL \n"));
+ return(0);
+ }
+
+ /* Charge the memory to the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
+ skb->sk = NULL;
+ DPRINTF((DBG_TCP, "dropping packet due to lack of buffer space.\n"));
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
+
+ DPRINTF((DBG_TCP, "About to do switch.\n"));
+
+ /* Now deal with it. */
+ switch(sk->state) {
/*
* This should close the system down if it's waiting
* for an ack that is never going to be sent.
- *
- * [Page 68]
*/
- case TCP_LAST_ACK:
- if (th->rst)
- {
- sk->zapped=1;
- sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
+ case TCP_LAST_ACK:
+ if (th->rst) {
+ sk->zapped=1;
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead) {
+ wake_up(sk->sleep);
}
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
- case TCP_ESTABLISHED:
- case TCP_CLOSE_WAIT:
- case TCP_FIN_WAIT1:
- case TCP_FIN_WAIT2:
- case TCP_TIME_WAIT:
- if (!tcp_sequence(sk, th, len, opt, saddr,dev))
- {
- if (inet_debug == DBG_SLIP)
- printk("\rtcp_rcv: not in seq\n");
- if(!th->rst)
- tcp_send_ack(sk->send_seq, sk->acked_seq,
- sk, th, saddr);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- if (th->rst)
- {
- sk->zapped=1;
- /* This means the thing should really be closed. [Page 70] */
- sk->err = ECONNRESET;
-
- if (sk->state == TCP_CLOSE_WAIT)
- {
- sk->err = EPIPE;
- }
-
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
+ case TCP_ESTABLISHED:
+ case TCP_CLOSE_WAIT:
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_TIME_WAIT:
+ if (!tcp_sequence(sk, th, len, opt, saddr)) {
+if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
+ if(!th->rst)
+ tcp_send_ack(sk->send_seq, sk->acked_seq,
+ sk, th, saddr);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (th->rst) {
+ sk->zapped=1;
+ /* This means the thing should really be closed. */
+ sk->err = ECONNRESET;
+
+ if (sk->state == TCP_CLOSE_WAIT) {
+ sk->err = EPIPE;
}
- /* [Page 71] - security options: We just say no thanks */
- if (opt && (opt->security != 0 || opt->compartment != 0))
- {
- sk->err = ECONNRESET;
+
+ /*
+ * A reset with a fin just means that
+ * the data was not all read.
+ */
+/* The comment above appears completely bogus --clh */
+/* if (!th->fin) { */
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- if (!sk->dead)
- {
- sk->state_change(sk);
+ if (!sk->dead) {
+ wake_up(sk->sleep);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
+/* } */
+ }
+#if 0
+ if (opt && (opt->security != 0 ||
+ opt->compartment != 0 || th->syn)) {
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ if (!sk->dead) {
+ wake_up(sk->sleep);
}
- if (th->syn)
- {
- sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+#endif
+ if (th->ack) {
+ if (!tcp_ack(sk, th, saddr, len)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
-
- if (th->ack)
- {
- if (!tcp_ack(sk, th, saddr, len))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- }
- /* [Page 73] */
- if (th->urg &&(sk->state==TCP_ESTABLISHED||sk->state==TCP_FIN_WAIT1||sk->state==TCP_FIN_WAIT2))
- {
- if (tcp_urg(sk, th, saddr))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- }
-
-
- /* [Page 74] */
- if (tcp_data(skb, sk, saddr, len))
- {
+ }
+ if (th->urg) {
+ if (tcp_urg(sk, th, saddr)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
- /* Move this below the data processing [Page 74/75] */
+ }
- if (th->fin && tcp_fin(sk, th, saddr, dev))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
+ if (th->fin && tcp_fin(sk, th, saddr, dev)) {
+ kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
-
- case TCP_CLOSE:
- if (sk->dead || sk->daddr)
- {
- DPRINTF((DBG_TCP, "packet received for closed,dead socket\n"));
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- if (!th->rst)
- {
- if (!th->ack)
- th->ack_seq = 0;
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- }
+ }
+
+ if (tcp_data(skb, sk, saddr, len)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
+ }
- case TCP_LISTEN:
- if (th->rst)
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- if (th->ack)
- {
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- if (th->syn)
- {
- if (opt && (opt->security != 0 || opt->compartment != 0))
- {
- tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
- release_sock(sk);
- return(0);
- }
+ release_sock(sk);
+ return(0);
- /*
- * Now we just put the whole thing including
- * the header and saddr, and protocol pointer
- * into the buffer. We can't respond until the
- * user tells us to accept the connection.
- */
- tcp_conn_request(sk, skb, daddr, saddr, opt, dev);
+ case TCP_CLOSE:
+ if (sk->dead || sk->daddr) {
+ DPRINTF((DBG_TCP, "packet received for closed,dead socket\n"));
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (!th->rst) {
+ if (!th->ack)
+ th->ack_seq = 0;
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ }
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+
+ case TCP_LISTEN:
+ if (th->rst) {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+ if (th->ack) {
+ tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (th->syn) {
+#if 0
+ if (opt->security != 0 || opt->compartment != 0) {
+ tcp_reset(daddr, saddr, th, prot, opt,dev);
release_sock(sk);
return(0);
}
+#endif
+
+ /*
+ * Now we just put the whole thing including
+ * the header and saddr, and protocol pointer
+ * into the buffer. We can't respond until the
+ * user tells us to accept the connection.
+ */
+ tcp_conn_request(sk, skb, daddr, saddr, opt, dev);
+ release_sock(sk);
+ return(0);
+ }
+
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ default:
+ if (!tcp_sequence(sk, th, len, opt, saddr)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
+ }
- default:
- if (!tcp_sequence(sk, th, len, opt, saddr,dev))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
+ case TCP_SYN_SENT:
+ if (th->rst) {
+ sk->err = ECONNREFUSED;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ sk->zapped = 1;
+ if (!sk->dead) {
+ wake_up(sk->sleep);
}
-
- case TCP_SYN_SENT:
- if (th->rst)
- {
- sk->err = ECONNREFUSED;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- sk->zapped = 1;
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+#if 0
+ if (opt->security != 0 || opt->compartment != 0) {
+ sk->err = ECONNRESET;
+ sk->state = TCP_CLOSE;
+ sk->shutdown = SHUTDOWN_MASK;
+ tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
+ if (!sk->dead) {
+ wake_up(sk->sleep);
}
- if (opt && (opt->security != 0 || opt->compartment != 0))
- {
- sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
- sk->shutdown = SHUTDOWN_MASK;
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+#endif
+ if (!th->ack) {
+ if (th->syn) {
+ sk->state = TCP_SYN_RECV;
}
- if (!th->ack)
- {
- if (th->syn)
- {
- sk->state = TCP_SYN_RECV;
+
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ switch(sk->state) {
+ case TCP_SYN_SENT:
+ if (!tcp_ack(sk, th, saddr, len)) {
+ tcp_reset(daddr, saddr, th,
+ sk->prot, opt,dev);
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
}
-
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- switch(sk->state)
- {
- case TCP_SYN_SENT:
- /* [Page 73] */
- if (!tcp_ack(sk, th, saddr, len))
- {
- tcp_reset(daddr, saddr, th,
- sk->prot, opt,dev);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- /*
- * If the syn bit is also set, switch to
- * tcp_syn_recv, and then to established.
- */
- if (!th->syn)
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
-
- /* Ack the syn and fall through. */
- sk->acked_seq = th->seq+1;
- sk->fin_seq = th->seq;
- tcp_send_ack(sk->send_seq, th->seq+1, sk, th, sk->daddr);
-
- case TCP_SYN_RECV:
- if (!tcp_ack(sk, th, saddr, len))
- {
- tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- sk->state = TCP_ESTABLISHED;
-
- /*
- * Now we need to finish filling out
- * some of the tcp header.
- */
- /* We need to check for mtu info. */
- tcp_options(sk, th);
- sk->dummy_th.dest = th->source;
- sk->copied_seq = sk->acked_seq-1;
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
-
- /*
- * Now process the rest like we were
- * already in the established state.
- */
-
- if (th->urg)
- {
- if (tcp_urg(sk, th, saddr))
- {
- kfree_skb(skb, FREE_READ);
- release_sock(sk);
- return(0);
- }
- }
- if (tcp_data(skb, sk, saddr, len))
- kfree_skb(skb, FREE_READ);
-
- if (th->fin)
- tcp_fin(sk, th, saddr, dev);
+ /*
+ * If the syn bit is also set, switch to
+ * tcp_syn_recv, and then to established.
+ */
+ if (!th->syn) {
+ kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
- }
+ }
+
+ /* Ack the syn and fall through. */
+ sk->acked_seq = th->seq+1;
+ sk->fin_seq = th->seq;
+ tcp_send_ack(sk->send_seq, th->seq+1,
+ sk, th, sk->daddr);
- if (th->urg)
- {
- if (tcp_urg(sk, th, saddr))
- {
+ case TCP_SYN_RECV:
+ if (!tcp_ack(sk, th, saddr, len)) {
+ tcp_reset(daddr, saddr, th,
+ sk->prot, opt, dev);
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
+ sk->state = TCP_ESTABLISHED;
+
+ /*
+ * Now we need to finish filling out
+ * some of the tcp header.
+ */
+ /* We need to check for mtu info. */
+ tcp_options(sk, th);
+ sk->dummy_th.dest = th->source;
+ sk->copied_seq = sk->acked_seq-1;
+ if (!sk->dead) {
+ wake_up(sk->sleep);
+ }
+
+ /*
+ * Now process the rest like we were
+ * already in the established state.
+ */
+ if (th->urg) {
+ if (tcp_urg(sk, th, saddr)) {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
}
-
- if (tcp_data(skb, sk, saddr, len))
- {
+ if (tcp_data(skb, sk, saddr, len))
+ kfree_skb(skb, FREE_READ);
+
+ if (th->fin) tcp_fin(sk, th, saddr, dev);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (th->urg) {
+ if (tcp_urg(sk, th, saddr)) {
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
+ }
- if (!th->fin)
- {
- release_sock(sk);
- return(0);
- }
- tcp_fin(sk, th, saddr, dev);
+ if (tcp_data(skb, sk, saddr, len)) {
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
+ if (!th->fin) {
release_sock(sk);
return(0);
+ }
+ tcp_fin(sk, th, saddr, dev);
+ release_sock(sk);
+ return(0);
}
}
- /*
- * This routine sends a packet with an out of date sequence
- * number. It assumes the other end will try to ack it.
+/*
+ * This routine sends a packet with an out of date sequence
+ * number. It assumes the other end will try to ack it.
*/
-
-static void tcp_write_wakeup(struct sock *sk)
+static void
+tcp_write_wakeup(struct sock *sk)
{
- struct sk_buff *buff;
- struct tcphdr *t1;
- struct device *dev=NULL;
- int tmp;
-
- if (sk->zapped)
- return; /* Afer a valid reset we can send no more */
+ struct sk_buff *buff;
+ struct tcphdr *t1;
+ struct device *dev=NULL;
+ int tmp;
- if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)
- return;
+ if (sk->zapped)
+ return; /* Afer a valid reset we can send no more */
- buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
-
- if (buff == NULL)
- return;
-
- buff->mem_addr = buff;
- buff->mem_len = MAX_ACK_SIZE;
- buff->len = sizeof(struct tcphdr);
- buff->free = 1;
- buff->sk = sk;
- DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
- t1 = (struct tcphdr *)(buff + 1);
-
- /* Put in the IP header and routing stuff. */
- tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
- IPPROTO_TCP, sk->opt, MAX_ACK_SIZE, sk->ip_ttl,sk->ip_tos);
- if (tmp < 0)
- {
- sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
- return;
- }
+ if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) return;
- buff->len += tmp;
- t1 = (struct tcphdr *)((char *)t1 +tmp);
-
- memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
-
- /*
- * Use a previous sequence.
- * This should cause the other end to send an ack.
- */
- t1->seq = ntohl(sk->send_seq-1);
- t1->ack = 1;
- t1->res1= 0;
- t1->res2= 0;
- t1->rst = 0;
- t1->urg = 0;
- t1->psh = 0;
- t1->fin = 0;
- t1->syn = 0;
- t1->ack_seq = ntohl(sk->acked_seq);
- t1->window = ntohs(sk->prot->rspace(sk));
- t1->doff = sizeof(*t1)/4;
- tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
-
- /* Send it and free it.
- * This will prevent the timer from automatically being restarted.
- */
- sk->prot->queue_xmit(sk, dev, buff, 1);
-}
+ buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
+ if (buff == NULL) return;
-/*
- * Socket option code for TCP.
- */
-
-int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
-{
- int val,err;
+ buff->mem_addr = buff;
+ buff->mem_len = MAX_ACK_SIZE;
+ buff->len = sizeof(struct tcphdr);
+ buff->free = 1;
+ buff->sk = sk;
+ DPRINTF((DBG_TCP, "in tcp_write_wakeup\n"));
+ t1 = (struct tcphdr *)(buff + 1);
- if(level!=SOL_TCP)
- return ip_setsockopt(sk,level,optname,optval,optlen);
+ /* Put in the IP header and routing stuff. */
+ tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
+ IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
+ if (tmp < 0) {
+ sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
+ return;
+ }
- if (optval == NULL)
- return(-EINVAL);
+ buff->len += tmp;
+ t1 = (struct tcphdr *)((char *)t1 +tmp);
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_fs_long((unsigned long *)optval);
+ memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1));
- switch(optname)
- {
- case TCP_MSS:
- if(val<200||val>2048)
- return -EINVAL;
- sk->mss=val;
- return 0;
- case TCP_NODELAY:
- /* Ready for Johannes delayed ACK code */
- return 0;
- default:
- return(-ENOPROTOOPT);
- }
+ /*
+ * Use a previous sequence.
+ * This should cause the other end to send an ack.
+ */
+ t1->seq = ntohl(sk->send_seq-1);
+ t1->ack = 1;
+ t1->res1= 0;
+ t1->res2= 0;
+ t1->rst = 0;
+ t1->urg = 0;
+ t1->psh = 0;
+ t1->fin = 0;
+ t1->syn = 0;
+ t1->ack_seq = ntohl(sk->acked_seq);
+ t1->window = ntohs(sk->prot->rspace(sk));
+ t1->doff = sizeof(*t1)/4;
+ tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk);
+
+ /* Send it and free it.
+ * This will prevent the timer from automatically being restarted.
+ */
+ sk->prot->queue_xmit(sk, dev, buff, 1);
}
-int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
-{
- int val,err;
-
- if(level!=SOL_TCP)
- return ip_getsockopt(sk,level,optname,optval,optlen);
-
- switch(optname)
- {
- case TCP_MSS:
- val=sk->mss;
- break;
- case TCP_NODELAY:
- val=1; /* Until Johannes stuff is in */
- 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);
-}
-
-struct proto tcp_prot =
-{
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- tcp_close,
- tcp_read,
- tcp_write,
- tcp_sendto,
- tcp_recvfrom,
- ip_build_header,
- tcp_connect,
- tcp_accept,
- ip_queue_xmit,
- tcp_retransmit,
- tcp_write_wakeup,
- tcp_read_wakeup,
- tcp_rcv,
- tcp_select,
- tcp_ioctl,
- NULL,
- tcp_shutdown,
- tcp_setsockopt,
- tcp_getsockopt,
- 128,
- 0,
- {NULL,},
- "TCP"
+struct proto tcp_prot = {
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ tcp_close,
+ tcp_read,
+ tcp_write,
+ tcp_sendto,
+ tcp_recvfrom,
+ ip_build_header,
+ tcp_connect,
+ tcp_accept,
+ ip_queue_xmit,
+ tcp_retransmit,
+ tcp_write_wakeup,
+ tcp_read_wakeup,
+ tcp_rcv,
+ tcp_select,
+ tcp_ioctl,
+ NULL,
+ tcp_shutdown,
+ 128,
+ 0,
+ {NULL,},
+ "TCP"
};
diff --git a/net/inet/tcp.h b/net/inet/tcp.h
index 9077dbf..cb051e4 100644
--- a/net/inet/tcp.h
+++ b/net/inet/tcp.h
@@ -75,46 +75,43 @@
* normal compare so long as neither of the numbers is within
* 4K of wrapping. Otherwise we must check for the wrap.
*/
-static inline int before (unsigned long seq1, unsigned long seq2)
+static inline int
+before (unsigned long seq1, unsigned long seq2)
{
- /* this inequality is strict. */
- if (seq1 == seq2)
- return(0);
-
- if (seq1 < seq2)
- {
- if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL)
- {
- return(1);
- }
- else
- {
- return(0);
- }
- }
-
- /*
- * Now we know seq1 > seq2. So all we need to do is check
- * to see if seq1 has wrapped.
- */
- if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL))
- {
+ /* this inequality is strict. */
+ if (seq1 == seq2) return(0);
+
+ if (seq1 < seq2) {
+ if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL) {
return(1);
- }
- return(0);
+ } else {
+ return(0);
+ }
+ }
+
+ /*
+ * Now we know seq1 > seq2. So all we need to do is check
+ * to see if seq1 has wrapped.
+ */
+ if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL)) {
+ return(1);
+ }
+ return(0);
}
-static inline int after(unsigned long seq1, unsigned long seq2)
+static inline int
+after(unsigned long seq1, unsigned long seq2)
{
- return(before(seq2, seq1));
+ return(before(seq2, seq1));
}
/* is s2<=s1<=s3 ? */
-static inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
+static inline int
+between(unsigned long seq1, unsigned long seq2, unsigned long seq3)
{
- return(after(seq1+1, seq2) && before(seq1, seq3+1));
+ return(after(seq1+1, seq2) && before(seq1, seq3+1));
}
@@ -124,11 +121,12 @@ static inline int between(unsigned long seq1, unsigned long seq2, unsigned long
* convinced that this is the solution for the 'getpeername(2)'
* problem. Thanks to Stephen A. Wood <saw@cebaf.gov> -FvK
*/
-static inline const int tcp_connected(const int state)
+static inline const int
+tcp_connected(const int state)
{
- return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
- state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
- state == TCP_SYN_RECV);
+ return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
+ state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
+ state == TCP_SYN_RECV);
}
diff --git a/net/inet/timer.c b/net/inet/timer.c
index 7cd66b5..f6540a1 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -5,7 +5,7 @@
*
* TIMER - implementation of software timers.
*
- * Version: @(#)timer.c 1.28 22/12/93
+ * Version: @(#)timer.c 1.0.7 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -24,8 +24,6 @@
* of inet_bh() with this socket being handled it goes
* BOOM! Have to stop timer going off if inet_bh is
* active or the destroy causes crashes.
- * Alan Cox : Clean up for final release
- * Alan Cox : Oops - timeouts destroyed permanent arp entries!
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -43,202 +41,188 @@
#include <asm/system.h>
#include <linux/interrupt.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "arp.h"
-void delete_timer (struct sock *t)
+void
+delete_timer (struct sock *t)
{
- unsigned long flags;
+ unsigned long flags;
- save_flags (flags);
- cli();
+ save_flags (flags);
+ cli();
- t->timeout = 0;
- del_timer (&t->timer);
+ t->timeout = 0;
+ del_timer (&t->timer);
- restore_flags (flags);
+ restore_flags (flags);
}
-void reset_timer (struct sock *t, int timeout, unsigned long len)
+void
+reset_timer (struct sock *t, int timeout, unsigned long len)
{
- delete_timer (t);
+ delete_timer (t);
+
+ if (timeout != -1)
+ t->timeout = timeout;
- if (timeout != -1)
- t->timeout = timeout;
#if 1
- /* FIXME: ??? */
- if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
- len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
+ /* FIXME: ??? */
+ if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
+ len = 3; /* happen (negative values ?) - don't ask me why ! -FB */
#endif
- t->timer.expires = len;
- add_timer (&t->timer);
+ t->timer.expires = len;
+ add_timer (&t->timer);
}
/*
- * Now we will only be called whenever we need to do
- * something, but we must be sure to process all of the
- * sockets that need it.
+ * Now we will only be called whenever we need to do
+ * something, but we must be sure to process all of the
+ * sockets that need it.
*/
-
-void net_timer (unsigned long data)
+void
+net_timer (unsigned long data)
{
- struct sock *sk = (struct sock*)data;
- int why = sk->timeout;
- /* timeout is overwritten by 'delete_timer' and 'reset_timer' */
-
- if (sk->inuse || in_inet_bh())
- {
- sk->timer.expires = 10;
- add_timer(&sk->timer);
- return;
- }
- sk->inuse = 1;
-
- DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why));
- if (sk->keepopen)
- reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
-
- /* Always see if we need to send an ack. */
- if (sk->ack_backlog)
- {
- sk->prot->read_wakeup (sk);
- if (! sk->dead)
- wake_up (sk->sleep);
- }
-
- /* Now we need to figure out why the socket was on the timer. */
- switch (why)
- {
- case TIME_DONE:
- if (! sk->dead || sk->state != TCP_CLOSE)
- {
- printk ("non dead socket in time_done\n");
- release_sock (sk);
- break;
- }
- destroy_sock (sk);
- break;
- case TIME_DESTROY:
- /* We've waited for a while for all the memory associated with
- * the socket to be freed. We need to print an error message.
- */
- if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
- {
- DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk));
- sk->wmem_alloc++; /* So it DOESNT go away */
- destroy_sock (sk);
- sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */
- sk->inuse = 0; /* This will be ok, the destroy won't totally work */
- }
- if(sk->wmem_alloc==0 && sk->rmem_alloc==0)
- destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */
- break;
- case TIME_CLOSE:
- /* We've waited long enough, close the socket. */
- sk->state = TCP_CLOSE;
- delete_timer (sk);
- /* Kill the ARP entry in case the hardware has changed. */
- arp_destroy_maybe (sk->daddr);
- if (!sk->dead)
- wake_up (sk->sleep);
- sk->shutdown = SHUTDOWN_MASK;
- reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME);
- release_sock (sk);
- break;
- case TIME_WRITE: /* try to retransmit. */
- /* It could be we got here because we needed to send an ack.
- * So we need to check for that.
- */
- if (sk->send_head)
- {
- if (jiffies < (sk->send_head->when + backoff (sk->backoff)
- * (2 * sk->mdev + sk->rtt)))
- {
- reset_timer (sk, TIME_WRITE, (sk->send_head->when
- + backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
- release_sock (sk);
- break;
- }
- /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq,
- sk->retransmits, sk->packets_out, sk->cong_window); */
- DPRINTF ((DBG_TMR, "retransmitting.\n"));
- sk->prot->retransmit (sk, 0);
- 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_maybe (sk->daddr);
- ip_route_check (sk->daddr);
- }
- if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2)
- {
- DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n"));
- sk->err = ETIMEDOUT;
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2
- || sk->state == TCP_LAST_ACK)
- {
- sk->state = TCP_TIME_WAIT;
- reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
- }
- else
- {
- sk->prot->close (sk, 1);
- break;
- }
- }
- }
- release_sock (sk);
- break;
- case TIME_KEEPOPEN:
- /* Send something to keep the connection open. */
- if (sk->prot->write_wakeup)
- sk->prot->write_wakeup (sk);
- sk->retransmits++;
- if (sk->shutdown == SHUTDOWN_MASK)
- {
- sk->prot->close (sk, 1);
- sk->state = TCP_CLOSE;
- }
-
- 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_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_maybe (sk->daddr);
- sk->err = ETIMEDOUT;
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2)
- {
- sk->state = TCP_TIME_WAIT;
- if (!sk->dead)
- wake_up (sk->sleep);
- release_sock (sk);
- }
- else
- {
- sk->prot->close (sk, 1);
- }
- break;
- }
- release_sock (sk);
- break;
- default:
- printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk);
- release_sock (sk);
- break;
- }
+ struct sock *sk = (struct sock*)data;
+ int why = sk->timeout;
+ /* timeout is overwritten by 'delete_timer' and 'reset_timer' */
+
+ if (sk->inuse || in_inet_bh()) {
+ sk->timer.expires = 10;
+ add_timer(&sk->timer);
+ return;
+ }
+ sk->inuse = 1;
+
+ DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why));
+ if (sk->keepopen)
+ reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
+
+ /* Always see if we need to send an ack. */
+ if (sk->ack_backlog) {
+ sk->prot->read_wakeup (sk);
+ if (! sk->dead)
+ wake_up (sk->sleep);
+ }
+
+ /* Now we need to figure out why the socket was on the timer. */
+ switch (why) {
+ case TIME_DONE:
+ if (! sk->dead || sk->state != TCP_CLOSE) {
+ printk ("non dead socket in time_done\n");
+ release_sock (sk);
+ break;
+ }
+ destroy_sock (sk);
+ break;
+ case TIME_DESTROY:
+ /* We've waited for a while for all the memory associated with
+ * the socket to be freed. We need to print an error message.
+ */
+ if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
+ {
+ DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk));
+ sk->wmem_alloc++; /* So it DOESNT go away */
+ destroy_sock (sk);
+ sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */
+ sk->inuse = 0; /* This will be ok, the destroy won't totally work */
+ }
+ if(sk->wmem_alloc==0 && sk->rmem_alloc==0)
+ destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */
+ break;
+ case TIME_CLOSE:
+ /* We've waited long enough, close the socket. */
+ sk->state = TCP_CLOSE;
+ delete_timer (sk);
+ /* Kill the ARP entry in case the hardware has changed. */
+ arp_destroy (sk->daddr);
+ if (!sk->dead)
+ wake_up (sk->sleep);
+ sk->shutdown = SHUTDOWN_MASK;
+ reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME);
+ release_sock (sk);
+ break;
+ case TIME_WRITE: /* try to retransmit. */
+ /* It could be we got here because we needed to send an ack.
+ * So we need to check for that.
+ */
+ if (sk->send_head) {
+ if (jiffies < (sk->send_head->when + backoff (sk->backoff)
+ * (2 * sk->mdev + sk->rtt))) {
+ reset_timer (sk, TIME_WRITE, (sk->send_head->when
+ + backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
+ release_sock (sk);
+ break;
+ }
+ /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq,
+ sk->retransmits, sk->packets_out, sk->cong_window); */
+ DPRINTF ((DBG_TMR, "retransmitting.\n"));
+ sk->prot->retransmit (sk, 0);
+ 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);
+ ip_route_check (sk->daddr);
+ }
+ if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
+ DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n"));
+ sk->err = ETIMEDOUT;
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2
+ || sk->state == TCP_LAST_ACK) {
+ sk->state = TCP_TIME_WAIT;
+ reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
+ } else {
+ sk->prot->close (sk, 1);
+ break;
+ }
+ }
+ }
+ release_sock (sk);
+ break;
+ case TIME_KEEPOPEN:
+ /* Send something to keep the connection open. */
+ if (sk->prot->write_wakeup)
+ sk->prot->write_wakeup (sk);
+ sk->retransmits++;
+ if (sk->shutdown == SHUTDOWN_MASK) {
+ sk->prot->close (sk, 1);
+ sk->state = TCP_CLOSE;
+ }
+
+ 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);
+ 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);
+ sk->err = ETIMEDOUT;
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
+ sk->state = TCP_TIME_WAIT;
+ if (!sk->dead)
+ wake_up (sk->sleep);
+ release_sock (sk);
+ } else {
+ sk->prot->close (sk, 1);
+ }
+ break;
+ }
+ release_sock (sk);
+ break;
+ default:
+ printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk);
+ release_sock (sk);
+ break;
+ }
}
diff --git a/net/inet/udp.c b/net/inet/udp.c
index 33d2b38..78066c3 100644
--- a/net/inet/udp.c
+++ b/net/inet/udp.c
@@ -5,7 +5,7 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: @(#)udp.c 1.28 22/12/93
+ * Version: @(#)udp.c 1.0.13 06/02/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -30,11 +30,10 @@
* bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram
- * Alan Cox : Tidy up ready for the 'real' thing.
- * 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.
*
+ * 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
@@ -55,12 +54,12 @@
#include <linux/termios.h>
#include <linux/mm.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
-#include "sockinet.h"
+#include "sock.h"
#include "udp.h"
#include "icmp.h"
@@ -68,18 +67,17 @@
#define min(a,b) ((a)<(b)?(a):(b))
-static void print_udp(struct udphdr *uh)
+static void
+print_udp(struct udphdr *uh)
{
- if (inet_debug != DBG_UDP)
- return;
-
- if (uh == NULL)
- {
- printk("(NULL)\n");
- return;
- }
- printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest));
- printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check));
+ if (inet_debug != DBG_UDP) return;
+
+ if (uh == NULL) {
+ printk("(NULL)\n");
+ return;
+ }
+ printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest));
+ printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check));
}
@@ -93,289 +91,285 @@ static void print_udp(struct udphdr *uh)
* header points to the first 8 bytes of the udp header. We need
* to find the appropriate port.
*/
-
-void udp_err(int err, unsigned char *header, unsigned long daddr,
+void
+udp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
- struct udphdr *th;
- struct sock *sk;
- struct iphdr *ip=(struct iphdr *)header;
-
- header += 4*ip->ihl;
-
- th = (struct udphdr *)header;
-
- DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
- sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
+ struct udphdr *th;
+ struct sock *sk;
+ struct iphdr *ip=(struct iphdr *)header;
+
+ header += 4*ip->ihl;
+
+ th = (struct udphdr *)header;
+
+ DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
+sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
- sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
+ sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
- if (sk == NULL)
- return; /* No socket for error */
+ if (sk == NULL)
+ return; /* No socket for error */
- if (err < 0) /* As per the calling spec */
- {
- sk->err = -err;
- sk->error_report(sk); /* User process wakes to see error */
- return;
- }
+ if (err < 0) /* As per the calling spec */
+ {
+ sk->err = -err;
+ wake_up(sk->sleep); /* User process wakes to see error */
+ return;
+ }
- if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8))
- { /* Slow down! */
- if (sk->cong_window > 1)
- sk->cong_window = sk->cong_window/2;
- return;
- }
-
- sk->err = icmp_err_convert[err & 0xff].errno;
-
- /* It's only fatal if we have connected to them. */
- if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED)
- {
- sk->err=ECONNREFUSED;
- }
- sk->error_report(sk);
+ if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */
+ if (sk->cong_window > 1)
+ sk->cong_window = sk->cong_window/2;
+ return;
+ }
+
+ sk->err = icmp_err_convert[err & 0xff].errno;
+
+ /* It's only fatal if we have connected to them. */
+ if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
+ sk->err=ECONNREFUSED;
+ }
+ wake_up(sk->sleep);
}
-static unsigned short udp_check(struct udphdr *uh, int len,
+static unsigned short
+udp_check(struct udphdr *uh, int len,
unsigned long saddr, unsigned long daddr)
{
- unsigned long sum;
+ unsigned long sum;
- DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n",
+ DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n",
uh, len, saddr, daddr));
- print_udp(uh);
-
- __asm__("\t addl %%ecx,%%ebx\n"
- "\t adcl %%edx,%%ebx\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum)
- : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
- : "cx","bx","dx" );
-
- if (len > 3)
- {
- __asm__("\tclc\n"
- "1:\n"
- "\t lodsl\n"
- "\t adcl %%eax, %%ebx\n"
- "\t loop 1b\n"
- "\t adcl $0, %%ebx\n"
- : "=b"(sum) , "=S"(uh)
- : "0"(sum), "c"(len/4) ,"1"(uh)
- : "ax", "cx", "bx", "si" );
- }
-
- /* Convert from 32 bits to 16 bits. */
- __asm__("\t movl %%ebx, %%ecx\n"
- "\t shrl $16,%%ecx\n"
- "\t addw %%cx, %%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum)
- : "bx", "cx");
-
- /* Check for an extra word. */
- if ((len & 2) != 0)
- {
- __asm__("\t lodsw\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum), "=S"(uh)
- : "0"(sum) ,"1"(uh)
- : "si", "ax", "bx");
- }
-
- /* Now check for the extra byte. */
- if ((len & 1) != 0)
- {
- __asm__("\t lodsb\n"
- "\t movb $0,%%ah\n"
- "\t addw %%ax,%%bx\n"
- "\t adcw $0, %%bx\n"
- : "=b"(sum)
- : "0"(sum) ,"S"(uh)
- : "si", "ax", "bx");
- }
-
- /* We only want the bottom 16 bits, but we never cleared the top 16. */
- return((~sum) & 0xffff);
+ print_udp(uh);
+
+ __asm__("\t addl %%ecx,%%ebx\n"
+ "\t adcl %%edx,%%ebx\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum)
+ : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
+ : "cx","bx","dx" );
+
+ if (len > 3) {
+ __asm__("\tclc\n"
+ "1:\n"
+ "\t lodsl\n"
+ "\t adcl %%eax, %%ebx\n"
+ "\t loop 1b\n"
+ "\t adcl $0, %%ebx\n"
+ : "=b"(sum) , "=S"(uh)
+ : "0"(sum), "c"(len/4) ,"1"(uh)
+ : "ax", "cx", "bx", "si" );
+ }
+
+ /* Convert from 32 bits to 16 bits. */
+ __asm__("\t movl %%ebx, %%ecx\n"
+ "\t shrl $16,%%ecx\n"
+ "\t addw %%cx, %%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum)
+ : "bx", "cx");
+
+ /* Check for an extra word. */
+ if ((len & 2) != 0) {
+ __asm__("\t lodsw\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum), "=S"(uh)
+ : "0"(sum) ,"1"(uh)
+ : "si", "ax", "bx");
+ }
+
+ /* Now check for the extra byte. */
+ if ((len & 1) != 0) {
+ __asm__("\t lodsb\n"
+ "\t movb $0,%%ah\n"
+ "\t addw %%ax,%%bx\n"
+ "\t adcw $0, %%bx\n"
+ : "=b"(sum)
+ : "0"(sum) ,"S"(uh)
+ : "si", "ax", "bx");
+ }
+
+ /* We only want the bottom 16 bits, but we never cleared the top 16. */
+ return((~sum) & 0xffff);
}
-/*
- * Calculate the UDP checksum. Note 0 becomes FFFF because 0 means
- * 'no checksum'.
- */
-static void udp_send_check(struct udphdr *uh, unsigned long saddr,
+static void
+udp_send_check(struct udphdr *uh, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
- uh->check = 0;
- if (sk && sk->no_check)
- return;
- uh->check = udp_check(uh, len, saddr, daddr);
- if (uh->check == 0)
- uh->check = 0xffff;
+ uh->check = 0;
+ if (sk && sk->no_check)
+ return;
+ uh->check = udp_check(uh, len, saddr, daddr);
+ if (uh->check == 0) uh->check = 0xffff;
}
-static int udp_send(struct sock *sk, struct sockaddr_in *sin,
+static int
+udp_send(struct sock *sk, struct sockaddr_in *sin,
unsigned char *from, int len)
{
- struct sk_buff *skb;
- struct device *dev;
- struct udphdr *uh;
- unsigned char *buff;
- unsigned long saddr;
- int size, tmp;
- int err;
+ struct sk_buff *skb;
+ struct device *dev;
+ struct udphdr *uh;
+ unsigned char *buff;
+ unsigned long saddr;
+ int size, tmp;
+ int err;
- DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
+ DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),
from, len));
- err=verify_area(VERIFY_READ, from, len);
- if(err)
- return(err);
-
- /* Allocate a copy of the packet. */
- size = sizeof(struct sk_buff) + sk->prot->max_header + len;
- skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
- if (skb == NULL)
- return(-ENOMEM);
-
- skb->sk = NULL; /* to avoid changing sk->saddr */
- skb->free = 1;
- skb->arp = 0;
-
- /* Now build the IP and MAC header. */
- buff = (unsigned char *) (skb+1);
- saddr = 0;
- dev = NULL;
- DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
+ err=verify_area(VERIFY_READ, from, len);
+ if(err)
+ return(err);
+
+ /* Allocate a copy of the packet. */
+ size = sizeof(struct sk_buff) + sk->prot->max_header + len;
+ skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
+ if (skb == NULL) return(-ENOMEM);
+
+ skb->mem_addr = skb;
+ skb->mem_len = size;
+ skb->sk = NULL; /* to avoid changing sk->saddr */
+ skb->free = 1;
+ skb->arp = 0;
+
+ /* Now build the IP and MAC header. */
+ buff = (unsigned char *) (skb+1);
+ saddr = 0;
+ dev = NULL;
+ 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,
- sk->ip_ttl,sk->ip_tos);
- skb->sk=sk; /* So memory is freed correctly */
+ tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
+ &dev, IPPROTO_UDP, sk->opt, skb->mem_len);
+ skb->sk=sk; /* So memory is freed correctly */
- if (tmp < 0 )
- {
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(tmp);
- }
- buff += tmp;
- saddr = dev->pa_addr;
- DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp));
-
- skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
- skb->dev = dev;
- if (skb->len > 4095)
- {
- printk("UDP: send: length %d > mtu %d (ignored)\n", len, 4095);
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(-EMSGSIZE);
- }
-
- /* Fill in the UDP header. */
- uh = (struct udphdr *) buff;
- uh->len = htons(len + sizeof(struct udphdr));
- uh->source = sk->dummy_th.source;
- uh->dest = sin->sin_port;
- buff = (unsigned char *) (uh + 1);
-
- /* Copy the user data. */
- memcpy_fromfs(buff, from, len);
-
- /* Set up the UDP checksum. */
- udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
-
- /* Send the datagram to the interface. */
- sk->prot->queue_xmit(sk, dev, skb, 1);
-
- return(len);
+ if (tmp < 0 ) {
+ sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ return(tmp);
+ }
+ buff += tmp;
+ saddr = dev->pa_addr;
+ DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp));
+
+ skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
+ skb->dev = dev;
+#ifdef OLD
+ /*
+ * This code used to hack in some form of fragmentation.
+ * I removed that, since it didn't work anyway, and it made the
+ * code a bad thing to read and understand. -FvK
+ */
+ if (len > dev->mtu) {
+#else
+ if (skb->len > 4095)
+ {
+#endif
+ printk("UDP: send: length %d > mtu %d (ignored)\n", len, dev->mtu);
+ sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ return(-EMSGSIZE);
+ }
+
+ /* Fill in the UDP header. */
+ uh = (struct udphdr *) buff;
+ uh->len = htons(len + sizeof(struct udphdr));
+ uh->source = sk->dummy_th.source;
+ uh->dest = sin->sin_port;
+ buff = (unsigned char *) (uh + 1);
+
+ /* Copy the user data. */
+ memcpy_fromfs(buff, from, len);
+
+ /* Set up the UDP checksum. */
+ udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
+
+ /* Send the datagram to the interface. */
+ sk->prot->queue_xmit(sk, dev, skb, 1);
+
+ return(len);
}
-static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
+static int
+udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
- struct sockaddr_in sin;
- int tmp;
- int err;
-
- DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
-
- /* Check the flags. */
- if (flags)
- return(-EINVAL);
- if (len < 0)
- return(-EINVAL);
- if (len == 0)
- return(0);
-
- /* Get and verify the address. */
- if (usin)
- {
- if (addr_len < sizeof(sin))
- return(-EINVAL);
- err=verify_area(VERIFY_READ, usin, sizeof(sin));
- if(err)
- return err;
- memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EINVAL);
- if (sin.sin_port == 0)
- return(-EINVAL);
- }
- else
- {
- if (sk->state != TCP_ESTABLISHED)
- return(-EINVAL);
- sin.sin_family = AF_INET;
- sin.sin_port = sk->dummy_th.dest;
- sin.sin_addr.s_addr = sk->daddr;
- }
+ struct sockaddr_in sin;
+ int tmp;
+ int err;
+
+ DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
+
+ /* Check the flags. */
+ if (flags)
+ return(-EINVAL);
+ if (len < 0)
+ return(-EINVAL);
+ if (len == 0)
+ return(0);
+
+ /* Get and verify the address. */
+ if (usin) {
+ if (addr_len < sizeof(sin)) return(-EINVAL);
+ err=verify_area(VERIFY_READ, usin, sizeof(sin));
+ if(err)
+ return err;
+ memcpy_fromfs(&sin, usin, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EINVAL);
+ if (sin.sin_port == 0)
+ return(-EINVAL);
+ } else {
+ if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
+ sin.sin_family = AF_INET;
+ sin.sin_port = sk->dummy_th.dest;
+ sin.sin_addr.s_addr = sk->daddr;
+ }
- if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -EACCES; /* Must turn broadcast on first */
- sk->inuse = 1;
+ if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -ENETUNREACH; /* Must turn broadcast on first */
+ sk->inuse = 1;
- /* Send the packet. */
- tmp = udp_send(sk, &sin, from, len);
+ /* Send the packet. */
+ tmp = udp_send(sk, &sin, from, len);
- /* The datagram has been sent off. Release the socket. */
- release_sock(sk);
- return(tmp);
+ /* The datagram has been sent off. Release the socket. */
+ release_sock(sk);
+ return(tmp);
}
-static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
+static int
+udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
+ return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
-int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+int
+udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
- int err;
- switch(cmd)
- {
- case DDIOCSDBG:
+ int err;
+ switch(cmd) {
+ case DDIOCSDBG:
{
int val;
- if (!suser())
- return(-EPERM);
+ if (!suser()) return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err)
return err;
val = get_fs_long((int *)arg);
- switch(val)
- {
+ switch(val) {
case 0:
inet_debug = 0;
break;
@@ -387,14 +381,12 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
}
break;
-
- case TIOCOUTQ:
+ case TIOCOUTQ:
{
unsigned long amount;
- if (sk->state == TCP_LISTEN)
- return(-EINVAL);
- amount = sk->prot->wspace(sk);
+ if (sk->state == TCP_LISTEN) return(-EINVAL);
+ amount = sk->prot->wspace(sk)/*/2*/;
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
if(err)
@@ -403,17 +395,15 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
return(0);
}
- case TIOCINQ:
+ case TIOCINQ:
{
struct sk_buff *skb;
unsigned long amount;
- if (sk->state == TCP_LISTEN)
- return(-EINVAL);
+ if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = 0;
skb = sk->rqueue;
- if (skb != NULL)
- {
+ if (skb != NULL) {
/*
* We will only return the amount
* of this packet since that is all
@@ -429,233 +419,224 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
return(0);
}
- default:
- return(-EINVAL);
- }
- return(0);
+ default:
+ return(-EINVAL);
+ }
+ return(0);
}
/*
- * This should be easy, if there is something there we
+ * This should be easy, if there is something there we\
* return it, otherwise we block.
*/
-int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
+int
+udp_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
- int copied = 0;
- struct sk_buff *skb;
- int er;
-
-
- /*
- * This will pick up errors that occured while the program
- * was doing something else.
- */
- if (sk->err)
- {
- int err;
-
- err = -sk->err;
- sk->err = 0;
- return(err);
- }
+ int copied = 0;
+ struct sk_buff *skb;
+ int er;
+
- if (len == 0)
- return(0);
- if (len < 0)
- return(-EINVAL);
-
- if (addr_len)
- {
- er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
- if(er)
- return(er);
- put_fs_long(sizeof(*sin), addr_len);
- }
- if(sin)
- {
- er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
- if(er)
- return(er);
- }
- er=verify_area(VERIFY_WRITE,to,len);
+ /*
+ * This will pick up errors that occured while the program
+ * was doing something else.
+ */
+ if (sk->err) {
+ int err;
+
+ err = -sk->err;
+ sk->err = 0;
+ return(err);
+ }
+
+ if (len == 0)
+ return(0);
+ if (len < 0)
+ return(-EINVAL);
+
+ if (addr_len) {
+ er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(er)
+ return(er);
+ put_fs_long(sizeof(*sin), addr_len);
+ }
+ if(sin)
+ {
+ er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
if(er)
- return er;
- skb=skb_recv_datagram(sk,flags,noblock,&er);
- if(skb==NULL)
- return er;
- copied = min(len, skb->len);
-
+ return(er);
+ }
+ er=verify_area(VERIFY_WRITE,to,len);
+ if(er)
+ return er;
+ skb=skb_recv_datagram(sk,flags,noblock,&er);
+ if(skb==NULL)
+ return er;
+ copied = min(len, skb->len);
+
/* FIXME : should use udp header size info value */
- skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
+ skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
/* Copy the address. */
- if (sin)
- {
- struct sockaddr_in addr;
-
- addr.sin_family = AF_INET;
- addr.sin_port = skb->h.uh->source;
- addr.sin_addr.s_addr = skb->daddr;
- memcpy_tofs(sin, &addr, sizeof(*sin));
- }
+ if (sin) {
+ struct sockaddr_in addr;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = skb->h.uh->source;
+ addr.sin_addr.s_addr = skb->daddr;
+ memcpy_tofs(sin, &addr, sizeof(*sin));
+ }
- skb_free_datagram(skb);
- release_sock(sk);
- return(copied);
+ skb_free_datagram(skb);
+ release_sock(sk);
+ return(copied);
}
-int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
+int
+udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
unsigned flags)
{
- return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
+ return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
-int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
+int
+udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{
- struct sockaddr_in sin;
- int er;
+ struct sockaddr_in sin;
+ int er;
- if (addr_len < sizeof(sin))
- return(-EINVAL);
+ if (addr_len < sizeof(sin))
+ return(-EINVAL);
- er=verify_area(VERIFY_READ, usin, sizeof(sin));
- if(er)
- return er;
+ er=verify_area(VERIFY_READ, usin, sizeof(sin));
+ if(er)
+ return er;
- memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET)
- return(-EAFNOSUPPORT);
+ memcpy_fromfs(&sin, usin, sizeof(sin));
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EAFNOSUPPORT);
- if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
- return -EACCES; /* Must turn broadcast on first */
+ if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -ENETUNREACH; /* Must turn broadcast on first */
- sk->daddr = sin.sin_addr.s_addr;
- sk->dummy_th.dest = sin.sin_port;
- sk->state = TCP_ESTABLISHED;
- return(0);
+ sk->daddr = sin.sin_addr.s_addr;
+ sk->dummy_th.dest = sin.sin_port;
+ sk->state = TCP_ESTABLISHED;
+ return(0);
}
-static void udp_close(struct sock *sk, int timeout)
+static void
+udp_close(struct sock *sk, int timeout)
{
- sk->inuse = 1;
- sk->state = TCP_CLOSE;
- if (sk->dead)
- destroy_sock(sk);
- else
- release_sock(sk);
+ sk->inuse = 1;
+ sk->state = TCP_CLOSE;
+ if (sk->dead) destroy_sock(sk);
+ else release_sock(sk);
}
-/*
- * All we need to do is get the socket, and then do a checksum.
- */
-
-int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
+/* All we need to do is get the socket, and then do a checksum. */
+int
+udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
- struct sock *sk;
- struct udphdr *uh;
-
- uh = (struct udphdr *) skb->h.uh;
- sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
- if (sk == NULL)
- {
- if (chk_addr(daddr) == IS_MYADDR)
- {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
- }
- /*
- * Hmm. We got an UDP broadcast to a port to which we
- * don't wanna listen. The only thing we can do now is
- * to ignore the packet... -FvK
- */
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- if (uh->check && udp_check(uh, len, saddr, daddr))
- {
- DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- return(0);
- }
-
- skb->sk = sk;
- skb->dev = dev;
- skb->len = len;
-
- /* These are supposed to be switched. */
- skb->daddr = saddr;
- skb->saddr = daddr;
-
-
- /* Charge it to the socket. */
- if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
- {
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- release_sock(sk);
- return(0);
+ struct sock *sk;
+ struct udphdr *uh;
+
+ uh = (struct udphdr *) skb->h.uh;
+ sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
+ if (sk == NULL)
+ {
+ if (chk_addr(daddr) == IS_MYADDR)
+ {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
}
- sk->rmem_alloc += skb->mem_len;
+ /*
+ * Hmm. We got an UDP broadcast to a port to which we
+ * don't wanna listen. The only thing we can do now is
+ * to ignore the packet... -FvK
+ */
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+
+ if (uh->check && udp_check(uh, len, saddr, daddr)) {
+ DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ return(0);
+ }
+
+ skb->sk = sk;
+ skb->dev = dev;
+ skb->len = len;
+
+/* These are supposed to be switched. */
+ skb->daddr = saddr;
+ skb->saddr = daddr;
+
+
+ /* Charge it to the socket. */
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
+ {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_WRITE);
+ release_sock(sk);
+ return(0);
+ }
+ sk->rmem_alloc += skb->mem_len;
- /* At this point we should print the thing out. */
- DPRINTF((DBG_UDP, "<< \n"));
- print_udp(uh);
+ /* At this point we should print the thing out. */
+ DPRINTF((DBG_UDP, "<< \n"));
+ print_udp(uh);
- /* Now add it to the data chain and wake things up. */
+ /* Now add it to the data chain and wake things up. */
- skb_queue_tail(&sk->rqueue,skb);
+ skb_queue_tail(&sk->rqueue,skb);
- skb->len = len - sizeof(*uh);
+ skb->len = len - sizeof(*uh);
- release_sock(sk);
+ if (!sk->dead) wake_up(sk->sleep);
- if (!sk->dead)
- sk->data_ready(sk,skb->len);
-
- return(0);
+ release_sock(sk);
+ return(0);
}
-struct proto udp_prot =
-{
- sock_wmalloc,
- sock_rmalloc,
- sock_wfree,
- sock_rfree,
- sock_rspace,
- sock_wspace,
- udp_close,
- udp_read,
- udp_write,
- udp_sendto,
- udp_recvfrom,
- ip_build_header,
- udp_connect,
- NULL,
- ip_queue_xmit,
- ip_retransmit,
- NULL,
- NULL,
- udp_rcv,
- datagram_select,
- udp_ioctl,
- NULL,
- NULL,
- ip_setsockopt,
- ip_getsockopt,
- 128,
- 0,
- {NULL,},
- "UDP"
+struct proto udp_prot = {
+ sock_wmalloc,
+ sock_rmalloc,
+ sock_wfree,
+ sock_rfree,
+ sock_rspace,
+ sock_wspace,
+ udp_close,
+ udp_read,
+ udp_write,
+ udp_sendto,
+ udp_recvfrom,
+ ip_build_header,
+ udp_connect,
+ NULL,
+ ip_queue_xmit,
+ ip_retransmit,
+ NULL,
+ NULL,
+ udp_rcv,
+ datagram_select,
+ udp_ioctl,
+ NULL,
+ NULL,
+ 128,
+ 0,
+ {NULL,},
+ "UDP"
};
diff --git a/net/inet/utils.c b/net/inet/utils.c
index 821fbe8..f9e81e3 100644
--- a/net/inet/utils.c
+++ b/net/inet/utils.c
@@ -6,13 +6,12 @@
* Various kernel-resident INET utility functions; mainly
* for format conversion and debugging output.
*
- * Version: @(#)utils.c 1.28 20/12/93
+ * Version: @(#)utils.c 1.0.7 05/18/93
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Fixes:
* Alan Cox : verify_area check.
- * Alan Cox : Clean up to match code style
*
*
* This program is free software; you can redistribute it and/or
@@ -33,7 +32,7 @@
#include <linux/stat.h>
#include <stdarg.h>
#include "inet.h"
-#include "devinet.h"
+#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
@@ -42,118 +41,107 @@
#include "arp.h"
-/*
- * Display an IP address in readable format.
- */
-
+/* Display an IP address in readable format. */
char *in_ntoa(unsigned long in)
{
- static char buff[18];
- register char *p;
+ static char buff[18];
+ register char *p;
- p = (char *) &in;
- sprintf(buff, "%d.%d.%d.%d",
- (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
- return(buff);
+ p = (char *) &in;
+ sprintf(buff, "%d.%d.%d.%d",
+ (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
+ return(buff);
}
-/*
- * Convert an ASCII string to binary IP.
- */
-
-unsigned long in_aton(char *str)
+/* Convert an ASCII string to binary IP. */
+unsigned long
+in_aton(char *str)
{
- unsigned long l;
- unsigned int val;
- int i;
-
- l = 0;
- for (i = 0; i < 4; i++)
- {
- l <<= 8;
- if (*str != '\0')
- {
- val = 0;
- while (*str != '\0' && *str != '.')
- {
- val *= 10;
- val += *str - '0';
- str++;
- }
- l |= val;
- if (*str != '\0')
- str++;
+ unsigned long l;
+ unsigned int val;
+ int i;
+
+ l = 0;
+ for (i = 0; i < 4; i++) {
+ l <<= 8;
+ if (*str != '\0') {
+ val = 0;
+ while (*str != '\0' && *str != '.') {
+ val *= 10;
+ val += *str - '0';
+ str++;
}
- }
- return(htonl(l));
+ l |= val;
+ if (*str != '\0') str++;
+ }
+ }
+ return(htonl(l));
}
-void dprintf(int level, char *fmt, ...)
+void
+dprintf(int level, char *fmt, ...)
{
- va_list args;
- char *buff;
- extern int vsprintf(char * buf, const char * fmt, va_list args);
-
- if (level != inet_debug)
- return;
-
- buff = (char *) kmalloc(256, GFP_ATOMIC);
- if (buff != NULL)
- {
- va_start(args, fmt);
- vsprintf(buff, fmt, args);
- va_end(args);
- printk(buff);
- kfree(buff);
- }
+ va_list args;
+ char *buff;
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+ if (level != inet_debug) return;
+
+ buff = (char *) kmalloc(256, GFP_ATOMIC);
+ if (buff != NULL) {
+ va_start(args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end(args);
+ printk(buff);
+ kfree(buff);
+ }
}
-int dbg_ioctl(void *arg, int level)
+int
+dbg_ioctl(void *arg, int level)
{
- int val;
- int err;
+ int val;
+ int err;
- if (!suser())
- return(-EPERM);
- err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
- if(err)
- return err;
- val = get_fs_long((int *)arg);
- switch(val)
- {
- case 0: /* OFF */
- inet_debug = DBG_OFF;
- break;
- case 1: /* ON, INET */
- inet_debug = level;
- break;
-
- case DBG_RT: /* modules */
- case DBG_DEV:
- case DBG_ETH:
- case DBG_PROTO:
- case DBG_TMR:
- case DBG_PKT:
- case DBG_RAW:
-
- case DBG_LOOPB: /* drivers */
- case DBG_SLIP:
-
- case DBG_ARP: /* protocols */
- case DBG_IP:
- case DBG_ICMP:
- case DBG_TCP:
- case DBG_UDP:
-
- inet_debug = val;
- break;
-
- default:
- return(-EINVAL);
- }
-
- return(0);
+ if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
+ if(err)
+ return err;
+ val = get_fs_long((int *)arg);
+ switch(val) {
+ case 0: /* OFF */
+ inet_debug = DBG_OFF;
+ break;
+ case 1: /* ON, INET */
+ inet_debug = level;
+ break;
+
+ case DBG_RT: /* modules */
+ case DBG_DEV:
+ case DBG_ETH:
+ case DBG_PROTO:
+ case DBG_TMR:
+ case DBG_PKT:
+ case DBG_RAW:
+
+ case DBG_LOOPB: /* drivers */
+ case DBG_SLIP:
+
+ case DBG_ARP: /* protocols */
+ case DBG_IP:
+ case DBG_ICMP:
+ case DBG_TCP:
+ case DBG_UDP:
+
+ inet_debug = val;
+ break;
+
+ default:
+ return(-EINVAL);
+ }
+
+ return(0);
}
diff --git a/net/socket/Makefile b/net/socket/Makefile
index b3d5b42..e69de29 100644
--- a/net/socket/Makefile
+++ b/net/socket/Makefile
@@ -1,37 +0,0 @@
-#
-# Makefile for the Linux socket support layer.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
-
-CFLAGS := $(CFLAGS) -I../inet -I..
-CPP := $(CPP) -I../inet -I..
-
-.c.o:
- $(CC) $(CFLAGS) -c -o $*.o $<
-.s.o:
- $(AS) -o $*.o $<
-.c.s:
- $(CC) $(CFLAGS) -S -o $*.s $<
-
-
-OBJS = datagram.o dev.o skbuff.o sock.o
-
-socket.o: $(OBJS)
- $(LD) -r -o socket.o $(OBJS)
-
-dep:
- $(CPP) -M *.c > .depend
-
-tar:
- tar -cvf /dev/f1 .
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/net/socket/datagram.c b/net/socket/datagram.c
index b7ebe91..e69de29 100644
--- a/net/socket/datagram.c
+++ b/net/socket/datagram.c
@@ -1,213 +0,0 @@
-/*
- * 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-).
- * 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.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
- *
- * Fixes:
- * Alan Cox : NULL return from skb_peek_copy() understood
- * 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 : Tidied up ready for the big day.
- * Alan Cox : Fixed write select of no IP protocol crash.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include "inet.h"
-#include "dev.h"
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include "skbuff.h"
-#include "sock.h"
-
-
-/*
- * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
- * races. This replaces identical code in packet,raw and udp, as well as the yet to
- * be released IPX support. It also finally fixes the long standing peek and read
- * race for datagram sockets. If you alter this routine remember it must be
- * re-entrant.
- */
-
-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)
- {
- release_sock(sk);
- *err=0;
- return NULL;
- }
-
- if(sk->err)
- {
- release_sock(sk);
- *err=-sk->err;
- 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)
- {
- release_sock(sk);
- *err=-ENOTCONN;
- return NULL;
- }
-
- /* User doesn't want to wait */
- if (noblock)
- {
- release_sock(sk);
- *err=-EAGAIN;
- return NULL;
- }
- release_sock(sk);
-
- /* Interrupts off so that no packet arrives before we begin sleeping.
- Otherwise we might miss our wake up */
- cli();
- if (sk->rqueue == NULL)
- {
- interruptible_sleep_on(sk->sleep);
- /* Signals may need a restart of the syscall */
- if (current->signal & ~current->blocked)
- {
- sti();
- *err=-ERESTARTSYS;
- return(NULL);
- }
- if(sk->err != 0) /* Error while waiting for packet
- eg an icmp sent earlier by the
- peer has finaly turned up now */
- {
- *err = -sk->err;
- sti();
- sk->err=0;
- return NULL;
- }
- }
- sk->inuse = 1;
- sti();
- }
- /* Again only user level code calls this function, so nothing interrupt level
- will suddenely eat the rqueue */
- if (!(flags & MSG_PEEK))
- {
- 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;
- }
- return skb;
-}
-
-/*
- * Free a datagram buffer. This has some conditions to watch. We keep
- * a user count so the last user may free the buffer. If however the
- * buffer has a valid next pointer it was never removed and all the
- * users PEEKed at it - so don't free it yet.
- */
-
-void skb_free_datagram(struct sk_buff *skb)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- skb->users--;
- if(skb->users>0)
- {
- restore_flags(flags);
- return;
- }
- /* See if it needs destroying */
- if(skb->list == NULL) /* Been dequeued by someone - ie its read */
- kfree_skb(skb,FREE_READ);
- restore_flags(flags);
-}
-
-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
- but not this release */
- memcpy_tofs(to,skb->h.raw+offset,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)
- {
- case SEL_IN:
- if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
- {
- /* Connection closed: Wake up */
- return(1);
- }
- if (sk->rqueue != NULL || sk->err != 0)
- { /* This appears to be consistent
- with other stacks */
- return(1);
- }
- return(0);
-
- case SEL_OUT:
- if(sk->prot && 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);
-}
diff --git a/net/socket/dev.c b/net/socket/dev.c
index 20ce0f6..e69de29 100644
--- a/net/socket/dev.c
+++ b/net/socket/dev.c
@@ -1,980 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Interface (streams) handling functions.
- *
- * Version: @(#)dev.c 1.28 20/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Mark Evans, <evansmp@uhura.aston.ac.uk>
- *
- * Fixes:
- * Alan Cox: check_addr returns a value for a wrong subnet
- * ie not us but don't forward this!
- * Alan Cox: block timer if the inet_bh handler is running
- * Alan Cox: generic queue code added. A lot neater now
- * C.E.Hawkins: SIOCGIFCONF only reports 'upped' interfaces
- * C.E.Hawkins: IFF_PROMISC support
- * Alan Cox: Supports Donald Beckers new hardware
- * multicast layer, but not yet multicast lists.
- * Alan Cox: ip_addr_match problems with class A/B nets.
- * C.E.Hawkins IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT]
- * Alan Cox: Removed bogus subnet check now the subnet code
- * a) actually works for all A/B nets
- * b) doesn't forward off the same interface.
- * Alan Cox: Multiple extra protocols
- * Alan Cox: A Couple more escaped verify_area calls die
- * Alan Cox: IP_SET_DEV is gone (forever) as per Fred's comment.
- * Alan Cox: Grand tidy up ready for the big day.
- * Alan Cox: Handles dev_open errors correctly.
- * Alan Cox: IP part split from main section
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include "inet.h"
-#include "dev.h"
-#include "eth.h"
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
-#include "skbuff.h"
-#include "sock.h"
-#include "arp.h"
-#ifdef CONFIG_AX25
-#include "ax25/ax25.h"
-#endif
-#ifdef CONFIG_IPX
-#include "ipx/ipx.h"
-#endif
-
-
-#ifdef CONFIG_IPX
-
-/*
- * These describe how each lowest level protocol is processed.
- */
-
-static struct packet_type ipx_8023_type =
-{
- NET16(ETH_P_802_3),
- 0,
- ipx_rcv,
- NULL,
- NULL
-};
-
-static struct packet_type ipx_packet_type =
-{
- NET16(ETH_P_IPX), /* IPX over DIX - eg PDIPX */
- 0,
- ipx_rcv,
- NULL,
- &ipx_8023_type
-};
-
-#endif
-
-#ifdef CONFIG_AX25
-
-static struct packet_type ax25_packet_type =
-{
- NET16(ETH_P_AX25),
- 0,
- ax25_rcv,
- NULL,
-#ifdef CONFIG_IPX
- &ipx_packet_type
-#else
- NULL
-#endif
-};
-#endif
-
-
-static struct packet_type arp_packet_type =
-{
- NET16(ETH_P_ARP),
- 0, /* copy */
- arp_rcv,
- NULL,
-#ifdef CONFIG_IPX
-#ifndef CONFIG_AX25
- &ipx_packet_type
-#else
- &ax25_packet_type
-#endif
-#else
- NULL /* next */
-#endif
-};
-
-
-static struct packet_type ip_packet_type =
-{
- NET16(ETH_P_IP),
- 0, /* copy */
- ip_rcv,
- NULL,
- &arp_packet_type
-};
-
-/*
- * The list of known protocols. Note that
- * SOCK_PACKET sockets dynamically alter this.
- */
-
-#ifdef CONFIG_INET
-struct packet_type *ptype_base = &ip_packet_type;
-#else
-#ifdef CONFIG_AX25
-struct packet_type *ptype_base = &ax25_packet_type;
-#else
-struct packet_type *ptype_base = &ipx_packet_type;
-#endif
-#endif
-
-/* A queue of all the packets we have to deal with */
-static struct sk_buff *volatile backlog = NULL;
-
-
-
-/*
- * Return the lesser of the two values.
- */
-
-static unsigned long
-min(unsigned long a, unsigned long b)
-{
- if (a < b)
- return(a);
- return(b);
-}
-
-
-
-
-/*
- * Add a protocol ID to the list of known protocols
- * (see SOCK_PACKET code)
- */
-
-void dev_add_pack(struct packet_type *pt)
-{
- struct packet_type *p1;
-
- pt->next = ptype_base;
-
- /* See if we need to copy it. */
- for (p1 = ptype_base; p1 != NULL; p1 = p1->next)
- {
- if (p1->type == pt->type)
- {
- pt->copy = 1;
- break;
- }
- }
- ptype_base = pt;
-}
-
-
-/*
- * Remove a protocol ID from the list. Also used
- * for SOCK_PACKET. Maybe one day we will do loadable
- * protocol layers too.
- */
-
-void dev_remove_pack(struct packet_type *pt)
-{
- struct packet_type *lpt, *pt1;
-
- if (pt == ptype_base)
- {
- ptype_base = pt->next;
- return;
- }
-
- lpt = NULL;
- for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next)
- {
- if (pt1->next == pt )
- {
- cli();
- if (!pt->copy && lpt)
- lpt->copy = 0;
- pt1->next = pt->next;
- sti();
- return;
- }
-
- if (pt1->next -> type == pt ->type)
- {
- lpt = pt1->next;
- }
- }
-}
-
-
-/*
- * Find an interface in the list.
- */
-
-struct device *dev_get(char *name)
-{
- struct device *dev;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (strcmp(dev->name, name) == 0)
- return(dev);
- }
- return(NULL);
-}
-
-
-/*
- * Prepare an interface for use.
- */
-
-int dev_open(struct device *dev)
-{
- int ret = 0;
-
- if (dev->open)
- ret = dev->open(dev);
- if (ret == 0)
- dev->flags |= (IFF_UP | IFF_RUNNING);
-
- return(ret);
-}
-
-
-/*
- * Completely shutdown an interface.
- */
-
-int dev_close(struct device *dev)
-{
- if (dev->flags != 0)
- {
- int ct=0;
- dev->flags = 0;
- if (dev->stop)
- dev->stop(dev);
- rt_flush(dev);
- dev->pa_addr = 0;
- dev->pa_dstaddr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- /* Purge any queued packets when we down the link */
- while(ct<DEV_NUMBUFFS)
- {
- struct sk_buff *skb;
- while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL)
- if(skb->free)
- kfree_skb(skb,FREE_WRITE);
- ct++;
- }
- }
-
- return(0);
-}
-
-
-/*
- * Send (or queue for sending) a packet.
- */
-
-void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
-{
- int where = 0; /* used to say if the packet should go */
- /* at the front or the back of the */
- /* queue. */
-
- DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n",
- skb, dev, pri));
-
- if (dev == NULL)
- {
- printk("dev.c: dev_queue_xmit: dev = NULL\n");
- return;
- }
-
- IS_SKB(skb);
-
- skb->dev = dev;
- if (skb->next != NULL)
- {
- /* Make sure we haven't missed an interrupt. */
- dev->hard_start_xmit(NULL, dev);
- return;
- }
-
- if (pri < 0)
- {
- pri = -pri-1;
- where = 1;
- }
-
- if (pri >= DEV_NUMBUFFS)
- {
- printk("bad priority in dev_queue_xmit.\n");
- pri = 1;
- }
-
- if (dev->hard_start_xmit(skb, dev) == 0)
- {
- /* It went out without fuss */
- return;
- }
-
- /* The driver was busy.. */
- /* Put skb into a bidirectional circular linked list. */
- DPRINTF((DBG_DEV, "dev_queue_xmit dev->buffs[%d]=%X\n",
- pri, dev->buffs[pri]));
-
- /* Interrupts should already be cleared by hard_start_xmit. */
- cli();
- skb->magic = DEV_QUEUE_MAGIC;
- if(where)
- skb_queue_head(&dev->buffs[pri],skb);
- else
- skb_queue_tail(&dev->buffs[pri],skb);
- skb->magic = DEV_QUEUE_MAGIC;
- sti();
-}
-
-/*
- * Receive a packet from a device driver and queue it for the upper
- * (protocol) levels. It always succeeds.
- */
-
-void netif_rx(struct sk_buff *skb)
-{
- /* Set any necessary flags. */
- skb->sk = NULL;
- skb->free = 1;
-
- /* and add it to the "backlog" queue. */
- IS_SKB(skb);
- skb_queue_tail(&backlog,skb);
-
- /* If any packet arrived, mark it for processing. */
- if (backlog != NULL)
- mark_bh(INET_BH);
-
- return;
-}
-
-
-/*
- * The old interface to fetch a packet from a device driver.
- * This function is the base level entry point for all drivers that
- * want to send a packet to the upper (protocol) levels. It takes
- * care of de-multiplexing the packet to the various modules based
- * on their protocol ID.
- *
- * Return values: 1 <- exit I can't do any more
- * 0 <- feed me more (i.e. "done", "OK").
- *
- * THIS FUNCTION IS OBSOLETE: DO NOT USE IT ANY MORE!!!!
- */
-int dev_rint(unsigned char *buff, long len, int flags, struct device *dev)
-{
- static int dropping = 0;
- struct sk_buff *skb = NULL;
- unsigned char *to;
- int amount, left;
- int len2;
-
- if (dev == NULL || buff == NULL || len <= 0)
- return(1);
- if (flags & IN_SKBUFF)
- {
- skb = (struct sk_buff *) buff;
- }
- else
- {
- if (dropping)
- {
- if (backlog != NULL)
- return(1);
- printk("INET: dev_rint: no longer dropping packets.\n");
- dropping = 0;
- }
-
- skb = alloc_skb(sizeof(*skb) + len, GFP_ATOMIC);
- if (skb == NULL)
- {
- printk("dev_rint: packet dropped on %s (no memory) !\n",
- dev->name);
- dropping = 1;
- return(1);
- }
-
- /* First we copy the packet into a buffer, and save it for later. */
- to = (unsigned char *) (skb + 1);
- left = len;
- len2 = len;
- while (len2 > 0)
- {
- amount = min(len2, (unsigned long) dev->rmem_end -
- (unsigned long) buff);
- memcpy(to, buff, amount);
- len2 -= amount;
- left -= amount;
- buff += amount;
- to += amount;
- if ((unsigned long) buff == dev->rmem_end)
- buff = (unsigned char *) dev->rmem_start;
- }
- }
- skb->len = len;
- skb->dev = dev;
- skb->free = 1;
-
- netif_rx(skb);
- /* OK, all done. */
- return(0);
-}
-
-
-/*
- * This routine causes all interfaces to try to send some data.
- */
-
-void dev_transmit(void)
-{
- struct device *dev;
-
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (!dev->tbusy)
- {
- dev_tint(dev);
- }
- }
-}
-
-
-/* We need to know if we are re-entering the bottom level handler
- for the network */
-
-static volatile char in_bh = 0;
-
-int in_inet_bh() /* Used by timer.c */
-{
- return(in_bh==0?0:1);
-}
-
-/*
- * This function gets called periodically, to see if we can
- * process any data that came in from some interface.
- *
- */
-void inet_bh(void *tmp)
-{
- struct sk_buff *skb;
- struct packet_type *ptype;
- unsigned short type;
- unsigned char flag = 0;
-
-
- /* Atomically check and mark our BUSY state. */
- if (set_bit(1, (void*)&in_bh))
- return;
-
- /* Can we send anything now? */
- dev_transmit();
-
- /* Any data left to process? */
- while((skb=skb_dequeue(&backlog))!=NULL)
- {
- flag=0;
- sti();
- /*
- * Bump the pointer to the next structure.
- * This assumes that the basic 'skb' pointer points to
- * the MAC header, if any (as indicated by its "length"
- * field). Take care now!
- */
- skb->h.raw = (unsigned char *) (skb + 1) + skb->dev->hard_header_len;
- skb->len -= skb->dev->hard_header_len;
-
- /*
- * Fetch the packet protocol ID. This is also quite ugly, as
- * it depends on the protocol driver (the interface itself) to
- * know what the type is, or where to get it from. The Ethernet
- * interfaces fetch the ID from the two bytes in the Ethernet MAC
- * header (the h_proto field in struct ethhdr), but drivers like
- * SLIP and PLIP have no alternative but to force the type to be
- * IP or something like that. Sigh- FvK
- */
- type = skb->dev->type_trans(skb, skb->dev);
-
- /*
- * We got a packet ID. Now loop over the "known protocols"
- * table (which is actually a linked list, but this will
- * change soon if I get my way- FvK), and forward the packet
- * to anyone who wants it.
- */
- for (ptype = ptype_base; ptype != NULL; ptype = ptype->next)
- {
- if (ptype->type == type)
- {
- struct sk_buff *skb2;
-
- if (ptype->copy)
- { /* copy if we need to */
- skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
- if (skb2 == NULL)
- continue;
- memcpy(skb2, (const void *) skb, skb->mem_len);
- skb2->mem_addr=skb2;
- skb2->h.raw = (unsigned char *)
- (
- (unsigned long) skb2 +
- (unsigned long) skb->h.raw -
- (unsigned long) skb
- );
- skb2->free = 1;
- }
- else
- {
- skb2 = skb;
- }
-
- /* This used to be in the 'else' part, but then
- * we don't have this flag set when we get a
- * protocol that *does* require copying... -FvK
- */
- flag = 1;
-
- /* Kick the protocol handler. */
- ptype->func(skb2, skb->dev, ptype);
- }
- }
-
- /*
- * That's odd. We got an unknown packet. Who's using
- * stuff like Novell or Amoeba on this network??
- */
- if (!flag)
- {
- DPRINTF((DBG_DEV,
- "INET: unknown packet type 0x%04X (ignored)\n", type));
- skb->sk = NULL;
- kfree_skb(skb, FREE_WRITE);
- }
-
- /* Again, see if we can transmit anything now. */
- dev_transmit();
- cli();
- }
- in_bh = 0;
- sti();
- dev_transmit(); /* Try and kick anything this processing produced */
-}
-
-
-/*
- * This routine is called when an device driver (i.e. an
- * interface) is * ready to transmit a packet.
- */
-
-void dev_tint(struct device *dev)
-{
- int i;
- struct sk_buff *skb;
-
- for(i = 0;i < DEV_NUMBUFFS; i++)
- {
- while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
- {
- skb->magic = 0;
- dev->queue_xmit(skb,dev,-i - 1);
- if (dev->tbusy)
- return;
- }
- }
-}
-
-
-/*
- * Perform a SIOCGIFCONF call.
- */
-
-static int dev_ifconf(char *arg)
-{
- struct ifconf ifc;
- struct ifreq ifr;
- struct device *dev;
- char *pos;
- int len;
- int err;
-
- /* Fetch the caller's info block. */
- 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;
-
- /* Loop over the interfaces, and write an info block for each. */
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if(!(dev->flags & IFF_UP))
- continue;
- memset(&ifr, 0, sizeof(struct ifreq));
- strcpy(ifr.ifr_name, dev->name);
- (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family;
- (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
-
- /* Write this block to the caller's space. */
- memcpy_tofs(pos, &ifr, sizeof(struct ifreq));
- pos += sizeof(struct ifreq);
- len -= sizeof(struct ifreq);
- if (len < sizeof(struct ifreq)) break;
- }
-
- /* All done. Write the updated control block back to the caller. */
- ifc.ifc_len = (pos - ifc.ifc_buf);
- ifc.ifc_req = (struct ifreq *) ifc.ifc_buf;
- memcpy_tofs(arg, &ifc, sizeof(struct ifconf));
- return(pos - arg);
-}
-
-/*
- * Print device statistics.
- */
-
-char *sprintf_stats(char *buffer, struct device *dev)
-{
- char *pos = buffer;
- struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
-
- if (stats)
- pos += sprintf(pos, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n",
- dev->name,
- stats->rx_packets, stats->rx_errors,
- stats->rx_dropped + stats->rx_missed_errors,
- stats->rx_fifo_errors,
- stats->rx_length_errors + stats->rx_over_errors
- + stats->rx_crc_errors + stats->rx_frame_errors,
- stats->tx_packets, stats->tx_errors, stats->tx_dropped,
- stats->tx_fifo_errors, stats->collisions,
- stats->tx_carrier_errors + stats->tx_aborted_errors
- + stats->tx_window_errors + stats->tx_heartbeat_errors);
- else
- pos += sprintf(pos, "%6s: No statistics available.\n", dev->name);
-
- return pos;
-}
-
-/*
- * Called from the PROCfs module (/proc/net/dev).
- */
-
-int dev_get_info(char *buffer)
-{
- char *pos = buffer;
- struct device *dev;
-
- pos +=
- sprintf(pos,
- "Inter-| Receive | Transmit\n"
- " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n");
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- pos = sprintf_stats(pos, dev);
- }
- return pos - buffer;
-}
-
-/*
- * Perform the SIOCxIFxxx calls.
- */
-
-static int dev_ifsioc(void *arg, unsigned int getset)
-{
- struct ifreq ifr;
- struct device *dev;
- int ret;
- int err;
-
- /* Fetch the caller's info block. */
- 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. */
- if ((dev = dev_get(ifr.ifr_name)) == NULL)
- return(-EINVAL);
-
- switch(getset)
- {
- case SIOCGIFFLAGS:
- ifr.ifr_flags = dev->flags;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFFLAGS:
- {
- int old_flags = dev->flags;
- dev->flags = ifr.ifr_flags & (
- IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
- IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
- IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI);
-
- if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
- dev->set_multicast_list(dev,0,NULL);
- if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
- dev->set_multicast_list(dev,-1,NULL);
- 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; /* Failed to come up so go down again */
- }
- }
- break;
- case SIOCGIFADDR:
- (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr;
- (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFADDR:
- dev->pa_addr = (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_addr.s_addr;
- dev->family = ifr.ifr_addr.sa_family;
- dev->pa_mask = ip_get_mask(dev->pa_addr);
- dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
- ret = 0;
- break;
- case SIOCGIFBRDADDR:
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFBRDADDR:
- dev->pa_brdaddr = (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_addr.s_addr;
- ret = 0;
- break;
- case SIOCGIFDSTADDR:
- (*(struct sockaddr_in *)
- &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_broadaddr).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFDSTADDR:
- dev->pa_dstaddr = (*(struct sockaddr_in *)
- &ifr.ifr_dstaddr).sin_addr.s_addr;
- ret = 0;
- break;
- case SIOCGIFNETMASK:
- (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask;
- (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_family = dev->family;
- (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_port = 0;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFNETMASK:
- dev->pa_mask = (*(struct sockaddr_in *)
- &ifr.ifr_netmask).sin_addr.s_addr;
- ret = 0;
- break;
- case SIOCGIFMETRIC:
- ifr.ifr_metric = dev->metric;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFMETRIC:
- dev->metric = ifr.ifr_metric;
- ret = 0;
- break;
- case SIOCGIFMTU:
- ifr.ifr_mtu = dev->mtu;
- memcpy_tofs(arg, &ifr, sizeof(struct ifreq));
- ret = 0;
- break;
- case SIOCSIFMTU:
- dev->mtu = ifr.ifr_mtu;
- ret = 0;
- break;
- case SIOCGIFMEM:
- printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg);
- ret = -EINVAL;
- break;
- case SIOCSIFMEM:
- printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg);
- ret = -EINVAL;
- break;
- case SIOCGIFHWADDR:
- memcpy(ifr.ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN);
- memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
- ret=0;
- break;
- default:
- ret = -EINVAL;
- }
- return(ret);
-}
-
-
-/*
- * This function handles all "interface"-type I/O control requests.
- */
-
-int dev_ioctl(unsigned int cmd, void *arg)
-{
- int ret;
-
- switch(cmd)
- {
- case IP_SET_DEV:
- printk("IP_SET_DEV is obsolete. You need newer network tools.\n");
- ret= -EINVAL;
- case SIOCGIFCONF:
- (void) dev_ifconf((char *) arg);
- ret = 0;
- break;
- case SIOCGIFFLAGS:
- case SIOCSIFFLAGS:
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- case SIOCGIFMTU:
- case SIOCSIFMTU:
- case SIOCGIFMEM:
- case SIOCSIFMEM:
- case SIOCGIFHWADDR:
- if (!suser())
- return(-EPERM);
- ret = dev_ifsioc(arg, cmd);
- break;
- case SIOCSIFLINK:
- if (!suser())
- return(-EPERM);
- default:
- ret = -EINVAL;
- }
-
- return(ret);
-}
-
-/*
- * Setup an ethernet type interface
- */
-
-void eth_setup(char *str, int *ints)
-{
- struct device *d = dev_base;
-
- if (!str || !*str)
- return;
-
- /* Walk the device list */
- while (d)
- {
- if (!strcmp(str,d->name))
- {
- if (ints[0] > 0)
- d->irq=ints[1];
- if (ints[0] > 1)
- d->base_addr=ints[2];
- if (ints[0] > 2)
- d->mem_start=ints[3];
- if (ints[0] > 3)
- d->mem_end=ints[4];
- break;
- }
- d=d->next;
- }
-}
-
-
-/*
- * Initialize the DEV module.
- */
-
-void dev_init(void)
-{
- struct device *dev, *dev2;
-
- /* Add the devices.
- * If the call to dev->init fails, the dev is removed
- * from the chain disconnecting the device until the
- * next reboot.
- */
- dev2 = NULL;
- for (dev = dev_base; dev != NULL; dev=dev->next)
- {
- if (dev->init && dev->init(dev))
- {
- if (dev2 == NULL)
- dev_base = dev->next;
- else
- dev2->next = dev->next;
- }
- else
- {
- dev2 = dev;
- }
- }
-
-}
-
diff --git a/net/socket/dev.h b/net/socket/dev.h
index 4cb829b..e69de29 100644
--- a/net/socket/dev.h
+++ b/net/socket/dev.h
@@ -1,187 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the Interfaces handler.
- *
- * Version: @(#)dev.h 1.0.10 08/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Donald J. Becker, <becker@super.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _DEV_H
-#define _DEV_H
-
-#include <linux/if.h>
-#include <linux/if_ether.h>
-
-
-/* for future expansion when we will have different priorities. */
-#define DEV_NUMBUFFS 3
-#define MAX_ADDR_LEN 7
-#define MAX_HEADER 18
-
-#define IS_MYADDR 1 /* address is (one of) our own */
-#define IS_LOOPBACK 2 /* address is for LOOPBACK */
-#define IS_BROADCAST 3 /* address is a valid broadcast */
-#define IS_INVBCAST 4 /* Wrong netmask bcast not for us */
-
-/*
- * The DEVICE structure.
- * Actually, this whole structure is a big mistake. It mixes I/O
- * data with strictly "high-level" data, and it has to know about
- * almost every data structure used in the INET module. We will
- * gradually phase out this structure, and replace it with the
- * more general (but stolen :-) BSD "ifnet" structure. -FvK
- */
-struct device {
-
- /*
- * This is the first field of the "visible" part of this structure
- * (i.e. as seen by users in the "Space.c" file). It is the name
- * the interface.
- */
- char *name;
-
- /* I/O specific fields. These will be moved to DDI soon. */
- unsigned long rmem_end; /* shmem "recv" end */
- unsigned long rmem_start; /* shmem "recv" start */
- unsigned long mem_end; /* sahared mem end */
- unsigned long mem_start; /* shared mem start */
- unsigned short base_addr; /* device I/O address */
- unsigned char irq; /* device IRQ number */
-
- /* Low-level status flags. */
- volatile unsigned char start, /* start an operation */
- tbusy, /* transmitter busy */
- interrupt; /* interrupt arrived */
-
- /*
- * Another mistake.
- * This points to the next device in the "dev" chain. It will
- * be moved to the "invisible" part of the structure as soon as
- * it has been cleaned up. -FvK
- */
- struct device *next;
-
- /* The device initialization function. Called only once. */
- int (*init)(struct device *dev);
-
- /* Some hardware also needs these fields, but they are not part of the
- usual set specified in Space.c. */
- unsigned char if_port; /* Selectable AUI, TP,..*/
- unsigned char dma; /* DMA channel */
-
- struct enet_statistics* (*get_stats)(struct device *dev);
-
- /*
- * This marks the end of the "visible" part of the structure. All
- * fields hereafter are internal to the system, and may change at
- * will (read: may be cleaned up at will).
- */
-
- /* These may be needed for future network-power-down code. */
- unsigned long trans_start; /* Time (in jiffies) of last Tx */
- unsigned long last_rx; /* Time of last Rx */
-
- unsigned short flags; /* interface flags (a la BSD) */
- unsigned short family; /* address family ID (AF_INET) */
- unsigned short metric; /* routing metric (not used) */
- unsigned short mtu; /* interface MTU value */
- unsigned short type; /* interface hardware type */
- unsigned short hard_header_len; /* hardware hdr length */
- void *priv; /* pointer to private data */
-
- /* Interface address info. */
- unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
- unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */
- unsigned char addr_len; /* harfware address length */
- unsigned long pa_addr; /* protocol address */
- unsigned long pa_brdaddr; /* protocol broadcast addr */
- unsigned long pa_dstaddr; /* protocol P-P other side addr */
- unsigned long pa_mask; /* protocol netmask */
- unsigned short pa_alen; /* protocol address length */
-
- /* Pointer to the interface buffers. */
- struct sk_buff *volatile buffs[DEV_NUMBUFFS];
-
- /* Pointers to interface service routines. */
- int (*open)(struct device *dev);
- int (*stop)(struct device *dev);
- int (*hard_start_xmit) (struct sk_buff *skb,
- struct device *dev);
- int (*hard_header) (unsigned char *buff,
- struct device *dev,
- unsigned short type,
- unsigned long daddr,
- unsigned long saddr,
- unsigned len);
- void (*add_arp) (unsigned long addr,
- struct sk_buff *skb,
- struct device *dev);
- void (*queue_xmit)(struct sk_buff *skb,
- struct device *dev, int pri);
- int (*rebuild_header)(void *eth, struct device *dev);
- unsigned short (*type_trans) (struct sk_buff *skb,
- struct device *dev);
-#define HAVE_MULTICAST
- void (*set_multicast_list)(struct device *dev,
- int num_addrs, void *addrs);
-#define HAVE_SET_MAC_ADDR
- int (*set_mac_address)(struct device *dev, void *addr);
-};
-
-
-struct packet_type {
- unsigned short type; /* This is really NET16(ether_type) other
- * devices will have to translate
- * appropriately.
- */
- unsigned short copy:1;
- int (*func) (struct sk_buff *, struct device *,
- struct packet_type *);
- void *data;
- struct packet_type *next;
-};
-
-
-/* Used by dev_rint */
-#define IN_SKBUFF 1
-#define DEV_QUEUE_MAGIC 0x17432895
-
-
-extern struct device *dev_base;
-extern struct packet_type *ptype_base;
-
-
-extern unsigned long ip_get_mask(unsigned long);
-extern void dev_add_pack(struct packet_type *pt);
-extern void dev_remove_pack(struct packet_type *pt);
-extern struct device *dev_get(char *name);
-extern int dev_open(struct device *dev);
-extern int dev_close(struct device *dev);
-extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev,
- int pri);
-#define HAVE_NETIF_RX 1
-extern void netif_rx(struct sk_buff *skb);
-/* The old interface to netif_rx(). */
-extern int dev_rint(unsigned char *buff, long len, int flags,
- struct device * dev);
-extern void dev_transmit(void);
-extern int in_inet_bh(void);
-extern void inet_bh(void *tmp);
-extern void dev_tint(struct device *dev);
-extern int dev_get_info(char *buffer);
-extern int dev_ioctl(unsigned int cmd, void *);
-
-extern void dev_init(void);
-
-#endif /* _DEV_H */
diff --git a/net/socket/skbuff.c b/net/socket/skbuff.c
index 1b9ab93..e69de29 100644
--- a/net/socket/skbuff.c
+++ b/net/socket/skbuff.c
@@ -1,461 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * A saner implementation of the skbuff stuff scattered everywhere
- * in the old NET2D code.
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
- *
- * Fixes:
- * Alan Cox : Tracks memory and number of buffers for kernel memory report
- * and memory leak hunting.
- * Alan Cox : More generic kfree handler
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include "inet.h"
-#include "dev.h"
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include "skbuff.h"
-#include "sock.h"
-
-
-/* Socket buffer operations. Ideally much of this list swap stuff ought to be using
- exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
- slow C version. No doubt when Linus sees this comment he'll do horrible things
- to this code 8-)
-*/
-
-/*
- * 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)
-{
- if(skb->magic_debug_cookie==SK_FREED_SKB)
- {
- printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
- file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
- skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
- }
- if(skb->magic_debug_cookie!=SK_GOOD_SKB)
- {
- printk("File: %s Line %d, passed a non skb!\n", file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p, free=%d\n",
- skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
- }
- if(skb->mem_len!=skb->truesize)
- {
- printk("File: %s Line %d, Dubious size setting!\n",file,line);
- printk("skb=%p, real size=%ld, claimed size=%ld, magic=%d, list=%p\n",
- skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
- }
- /* Guess it might be acceptable then */
-}
-
-/*
- * 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);
- 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
- newsk->prev=newsk;
- newsk->prev->next=newsk;
- newsk->next->prev=newsk;
- IS_SKB(newsk->prev);
- IS_SKB(newsk->next);
- *list=newsk;
- restore_flags(flags);
-}
-
-/*
- * 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();
-
- newsk->list=list;
- if(*list)
- {
- (*list)->prev->next=newsk;
- newsk->prev=(*list)->prev;
- newsk->next=*list;
- (*list)->prev=newsk;
- }
- else
- {
- newsk->next=newsk;
- newsk->prev=newsk;
- *list=newsk;
- }
- IS_SKB(newsk->prev);
- IS_SKB(newsk->next);
- restore_flags(flags);
-
-}
-
-/*
- * 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;
- else
- {
- result->next->prev=result->prev;
- result->prev->next=result->next;
- *list=result->next;
- }
-
- IS_SKB(result);
- restore_flags(flags);
-
- if(result->list!=list)
- printk("Dequeued packet has invalid list pointer\n");
-
- result->list=0;
- result->next=0;
- result->prev=0;
- return(result);
-}
-
-/*
- * 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;
- newsk->next=old;
- 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);
-
- if(!old->list)
- 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;
- newsk->prev=old;
- newsk->next=old->next;
- newsk->next->prev=newsk;
- newsk->prev->next=newsk;
-
- restore_flags(flags);
-}
-
-/*
- * Remove an sk_buff from its list. Works even without knowing the list it
- * is sitting on, which can be handy at times. It also means that THE LIST
- * MUST EXIST when you unlink. Thus a list must have its contents unlinked
- * _FIRST_.
- */
-
-void skb_unlink(struct sk_buff *skb)
-{
- unsigned long flags;
- save_flags(flags);
- cli();
-
- IS_SKB(skb);
-
- if(skb->list)
- {
- skb->next->prev=skb->prev;
- skb->prev->next=skb->next;
- if(*skb->list==skb)
- {
- if(skb->next==skb)
- *skb->list=NULL;
- else
- *skb->list=skb->next;
- }
- skb->next=0;
- skb->prev=0;
- skb->list=0;
- }
- restore_flags(flags);
-}
-
-/*
- * An skbuff list has had its head reassigned. Move all the list
- * pointers. Must be called with ints off during the whole head
- * shifting
- */
-
-void skb_new_list_head(struct sk_buff *volatile* list)
-{
- struct sk_buff *skb=skb_peek(list);
- if(skb!=NULL)
- {
- do
- {
- IS_SKB(skb);
- skb->list=list;
- skb=skb->next;
- }
- 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
- * list and someone else may run off with it. For an interrupt
- * type system cli() peek the buffer copy the data and sti();
- */
-
-struct sk_buff *skb_peek(struct sk_buff *volatile* list)
-{
- return *list;
-}
-
-
-#ifdef UNUSED_NOW
-
-/*
- * Get a clone of an sk_buff. This is the safe way to peek at
- * a socket queue without accidents. Its a bit long but most
- * of it acutally ends up as tiny bits of inline assembler
- * 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);
- cli();
- orig=skb_peek(list);
- if(orig==NULL)
- {
- restore_flags(flags);
- return NULL;
- }
- IS_SKB(orig);
- len=orig->truesize;
- restore_flags(flags);
-
- newsk=alloc_skb(len,GFP_KERNEL); /* May sleep */
-
- 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 */
- {
- restore_flags(flags);
- newsk->sk=NULL;
- newsk->free=1;
- newsk->mem_addr=newsk;
- newsk->mem_len=len;
- kfree_skb(newsk, FREE_WRITE);
- continue;
- }
-
- IS_SKB(orig);
- IS_SKB(newsk);
- memcpy(newsk,orig,len);
- newsk->list=NULL;
- newsk->magic=0;
- newsk->next=NULL;
- newsk->prev=NULL;
- newsk->mem_addr=newsk;
- newsk->h.raw+=((char *)newsk-(char *)orig);
- newsk->link3=NULL;
- newsk->sk=NULL;
- newsk->free=1;
- }
- while(0);
-
- restore_flags(flags);
- return(newsk);
-}
-
-#endif
-
-/*
- * Free an sk_buff. This still knows about things it should
- * not need to like protocols and sockets.
- */
-
-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);
-
- }
- else
- {
- /* 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)
- skb->sk->write_space(skb->sk);
- 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;
- }
-
-/*
- * Free an skbuff by memory
- */
-
-void kfree_skbmem(void *mem,unsigned size)
-{
- struct sk_buff *x=mem;
- IS_SKB(x);
- if(x->magic_debug_cookie==SK_GOOD_SKB)
- {
- x->magic_debug_cookie=SK_FREED_SKB;
- kfree_s(mem,size);
- net_skbcount--;
- net_memory-=size;
- }
-}
-
diff --git a/net/socket/skbuff.h b/net/socket/skbuff.h
index ef04197..e69de29 100644
--- a/net/socket/skbuff.h
+++ b/net/socket/skbuff.h
@@ -1,111 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the 'struct sk_buff' memory handlers.
- *
- * Version: @(#)skbuff.h 1.0.4 05/20/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- *
- * Fixes:
- * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff)
- * Alan Cox : Declaration for new primitives
- * Alan Cox : Fraglist support (idea by Donald Becker)
- * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy
- * being used.
- * Alan Cox : Extra fields for RAW fixes
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _SKBUFF_H
-#define _SKBUFF_H
-#include <linux/malloc.h>
-
-#ifdef CONFIG_IPX
-#include "ipx/ipx.h"
-#endif
-
-#define HAVE_ALLOC_SKB /* For the drivers to know */
-
-
-#define FREE_READ 1
-#define FREE_WRITE 0
-
-
-struct sk_buff
-{
- unsigned long magic_debug_cookie;
- struct sk_buff *volatile next;
- struct sk_buff *volatile prev;
- struct sk_buff *volatile link3;
- struct sk_buff *volatile* list;
- struct sock *sk;
- volatile unsigned long when; /* used to compute rtt's */
- struct device *dev;
- void *mem_addr;
- union
- {
- struct tcphdr *th;
- struct ethhdr *eth;
- struct iphdr *iph;
- struct udphdr *uh;
- struct arphdr *arp;
- unsigned char *raw;
- unsigned long seq;
-#ifdef CONFIG_IPX
- ipx_packet *ipx;
-#endif
- } h;
- struct iphdr * ip_hdr;
- unsigned long mem_len;
- unsigned long len;
- unsigned long fraglen;
- struct sk_buff *fraglist; /* Fragment list */
- unsigned long truesize;
- unsigned long saddr;
- unsigned long daddr;
- int magic;
- volatile char acked,
- used,
- free,
- arp,
- urg_used;
- unsigned char tries,lock; /* Lock is now unused */
- unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */
-};
-
-#define SK_WMEM_MAX 8192
-#define SK_RMEM_MAX 32767
-
-#define SK_FREED_SKB 0x0DE2C0DE
-#define SK_GOOD_SKB 0xDEC0DED1
-
-extern void print_skb(struct sk_buff *);
-extern void kfree_skb(struct sk_buff *skb, int rw);
-extern void skb_queue_head(struct sk_buff * volatile *list,struct sk_buff *buf);
-extern void skb_queue_tail(struct sk_buff * volatile *list,struct sk_buff *buf);
-extern struct sk_buff * skb_dequeue(struct sk_buff * volatile *list);
-extern void skb_insert(struct sk_buff *old,struct sk_buff *newsk);
-extern void skb_append(struct sk_buff *old,struct sk_buff *newsk);
-extern void skb_unlink(struct sk_buff *buf);
-extern void skb_new_list_head(struct sk_buff *volatile* list);
-extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
-extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
-extern struct sk_buff * alloc_skb(unsigned int size, int priority);
-extern void kfree_skbmem(void *mem, unsigned size);
-
-extern void skb_check(struct sk_buff *skb,int, char *);
-#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
-
-extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
-extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
-extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
-extern void skb_free_datagram(struct sk_buff *skb);
-#endif /* _SKBUFF_H */
diff --git a/net/socket/sock.c b/net/socket/sock.c
index 1316be3..e69de29 100644
--- a/net/socket/sock.c
+++ b/net/socket/sock.c
@@ -1,418 +0,0 @@
-/*
- * NET2Debugged, generic socket properties.
- *
- * This module provides the generic option control and memory handling
- * for a socket of any kind.
- *
- * Version: @(#)sock.c 1.28 26/12/93
- *
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
- *
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#include "inet.h"
-#include "dev.h"
-#include "ip.h"
-#include "protocol.h"
-#include "arp.h"
-#include "route.h"
-#include "tcp.h"
-#include "udp.h"
-#include "skbuff.h"
-#include "sock.h"
-#include "raw.h"
-#include "icmp.h"
-
-static __inline__ int
-min(unsigned int a, unsigned int b)
-{
- if (a < b)
- return(a);
- return(b);
-}
-
-#ifdef SOCK_DEBUG
-
-void print_sk(struct sock *sk)
-{
- if (!sk)
- {
- printk(" print_sk(NULL)\n");
- return;
- }
- printk(" wmem_alloc = %lu\n", sk->wmem_alloc);
- printk(" rmem_alloc = %lu\n", sk->rmem_alloc);
- printk(" send_head = %p\n", sk->send_head);
- printk(" state = %d\n",sk->state);
- printk(" wback = %p, rqueue = %p\n", sk->wback, sk->rqueue);
- printk(" wfront = %p\n", sk->wfront);
- printk(" daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr);
- printk(" num = %d", sk->num);
- printk(" next = %p\n", sk->next);
- printk(" send_seq = %ld, acked_seq = %ld, copied_seq = %ld\n",
- sk->send_seq, sk->acked_seq, sk->copied_seq);
- printk(" rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n",
- sk->rcv_ack_seq, sk->window_seq, sk->fin_seq);
- printk(" prot = %p\n", sk->prot);
- printk(" pair = %p, back_log = %p\n", sk->pair,sk->back_log);
- printk(" inuse = %d , blog = %d\n", sk->inuse, sk->blog);
- printk(" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks);
- printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout);
- printk(" cong_window = %d, packets_out = %d\n", sk->cong_window,
- sk->packets_out);
- printk(" urg = %d shutdown=%d\n", sk->urg, sk->shutdown);
-}
-
-
-void print_skb(struct sk_buff *skb)
-{
- if (!skb)
- {
- printk(" print_skb(NULL)\n");
- return;
- }
- printk(" prev = %p, next = %p\n", skb->prev, skb->next);
- printk(" sk = %p link3 = %p\n", skb->sk, skb->link3);
- printk(" mem_addr = %p, mem_len = %lu\n", skb->mem_addr, skb->mem_len);
- printk(" used = %d free = %d\n", skb->used,skb->free);
-}
-
-
-#endif
-
-/*
- * This is meant for all protocols to use and covers goings on
- * at the socket level. Everything here is generic.
- */
-
-int sock_setsockopt(struct sock *sk, int level, int optname,
- char *optval, int optlen)
-{
- int val;
- int err;
- struct linger ling;
-
- if (optval == NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ, optval, sizeof(int));
- if(err)
- return err;
-
- val = get_fs_long((unsigned long *)optval);
- switch(optname)
- {
- case SO_TYPE:
- case SO_ERROR:
- return(-ENOPROTOOPT);
-
- case SO_DEBUG:
- sk->debug=val?1:0;
- case SO_DONTROUTE: /* Still to be implemented */
- return(0);
- case SO_BROADCAST:
- sk->broadcast=val?1:0;
- return 0;
- case SO_SNDBUF:
- if(val>32767)
- val=32767;
- if(val<256)
- val=256;
- sk->sndbuf=val;
- return 0;
- case SO_LINGER:
- err=verify_area(VERIFY_READ,optval,sizeof(ling));
- if(err)
- return err;
- memcpy_fromfs(&ling,optval,sizeof(ling));
- if(ling.l_onoff==0)
- sk->linger=0;
- else
- {
- sk->lingertime=ling.l_linger;
- sk->linger=1;
- }
- return 0;
- case SO_RCVBUF:
- if(val>32767)
- val=32767;
- if(val<256)
- val=256;
- sk->rcvbuf=val;
- return(0);
-
- case SO_REUSEADDR:
- if (val)
- sk->reuse = 1;
- else
- sk->reuse = 0;
- return(0);
-
- case SO_KEEPALIVE:
- if (val)
- sk->keepopen = 1;
- else
- sk->keepopen = 0;
- return(0);
-
- case SO_OOBINLINE:
- if (val)
- sk->urginline = 1;
- else
- sk->urginline = 0;
- return(0);
-
- case SO_NO_CHECK:
- if (val)
- sk->no_check = 1;
- else
- sk->no_check = 0;
- return(0);
-
- case SO_PRIORITY:
- if (val >= 0 && val < DEV_NUMBUFFS)
- {
- sk->priority = val;
- }
- else
- {
- return(-EINVAL);
- }
- return(0);
-
- default:
- return(-ENOPROTOOPT);
- }
-}
-
-
-int sock_getsockopt(struct sock *sk, int level, int optname,
- char *optval, int *optlen)
-{
- int val;
- int err;
- struct linger ling;
-
- switch(optname)
- {
- case SO_DEBUG:
- val = sk->debug;
- break;
-
- case SO_DONTROUTE: /* One last option to implement */
- val = 0;
- break;
-
- case SO_BROADCAST:
- val= sk->broadcast;
- break;
-
- case SO_LINGER:
- err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
- if(err)
- return err;
- err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(ling),(unsigned long *)optlen);
- ling.l_onoff=sk->linger;
- ling.l_linger=sk->lingertime;
- memcpy_tofs(optval,&ling,sizeof(ling));
- return 0;
-
- case SO_SNDBUF:
- val=sk->sndbuf;
- break;
-
- case SO_RCVBUF:
- val =sk->rcvbuf;
- break;
-
- case SO_REUSEADDR:
- val = sk->reuse;
- break;
-
- case SO_KEEPALIVE:
- val = sk->keepopen;
- break;
-
- case SO_TYPE:
- if (sk->prot == &tcp_prot)
- val = SOCK_STREAM;
- else
- val = SOCK_DGRAM;
- break;
-
- case SO_ERROR:
- val = sk->err;
- sk->err = 0;
- break;
-
- case SO_OOBINLINE:
- val = sk->urginline;
- break;
-
- case SO_NO_CHECK:
- val = sk->no_check;
- break;
-
- case SO_PRIORITY:
- val = sk->priority;
- 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);
-}
-
-
-void *sock_wmalloc(struct sock *sk, unsigned long size, int force,
- int priority)
-{
- if (sk)
- {
- if (sk->wmem_alloc + size < sk->sndbuf || force)
- {
- cli();
- sk->wmem_alloc+= size;
- sti();
- return(alloc_skb(size, priority));
- }
- DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n",
- sk, size, force, priority));
- return(NULL);
- }
- return(alloc_skb(size, priority));
-}
-
-
-void *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
-{
- if (sk)
- {
- if (sk->rmem_alloc + size < sk->rcvbuf || force)
- {
- void *c = alloc_skb(size, priority);
- cli();
- if (c)
- sk->rmem_alloc += size;
- sti();
- return(c);
- }
- DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n",
- sk,size,force, priority));
- return(NULL);
- }
- return(alloc_skb(size, priority));
-}
-
-
-unsigned long sock_rspace(struct sock *sk)
-{
- int amt;
-
- if (sk != NULL)
- {
- if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW)
- return(0);
- amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
- if (amt < 0)
- return(0);
- return(amt);
- }
- return(0);
-}
-
-
-unsigned long sock_wspace(struct sock *sk)
-{
- if (sk != NULL)
- {
- if (sk->shutdown & SEND_SHUTDOWN)
- return(0);
- if (sk->wmem_alloc >= sk->sndbuf)
- return(0);
- return(sk->sndbuf-sk->wmem_alloc );
- }
- return(0);
-}
-
-
-void sock_wfree(struct sock *sk, void *mem, unsigned long size)
-{
- struct sk_buff *skb;
- DPRINTF((DBG_INET, "sock_wfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
-
- IS_SKB(mem);
-
- skb=mem;
-
- kfree_skbmem(mem, size);
- if (sk)
- {
- sk->wmem_alloc -= size;
-
- /* In case it might be waiting for more memory. */
- if (!sk->dead)
- sk->write_space(sk);
- if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0)
- {
- DPRINTF((DBG_INET,
- "recovered lost memory, sock = %X\n", sk));
- }
- return;
- }
-}
-
-
-void sock_rfree(struct sock *sk, void *mem, unsigned long size)
-{
- struct sk_buff *skb;
-
- DPRINTF((DBG_INET, "sock_rfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
-
- IS_SKB(mem);
- skb=mem;
-
- kfree_skbmem(mem, size);
-
- if (sk)
- {
- sk->rmem_alloc -= size;
- if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0)
- {
- DPRINTF((DBG_INET,"recovered lot memory, sock = %X\n", sk));
- }
- }
-}
-
diff --git a/net/socket/sock.h b/net/socket/sock.h
index 6f0b1d8..e69de29 100644
--- a/net/socket/sock.h
+++ b/net/socket/sock.h
@@ -1,191 +0,0 @@
-/*
- * Definitions for the socket handler
- *
- * Version: @(#)sock.h 1.28 26/12/93
- *
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Corey Minyard <wf-rch!minyard@relay.EU.net>
- * Florian La Roche <flla@stud.uni-sb.de>
- *
- * Fixes:
- * Alan Cox : Volatiles in skbuff pointers. See
- * skbuff comments. May be overdone,
- * better to prove they can be removed
- * than the reverse.
- * Alan Cox : Added a zapped field for tcp to note
- * a socket is reset and must stay shut up
- * Alan Cox : New fields for options
- * Pauline Middelink : identd support
- * Alan Cox : Split into sock.h and sockinet.h
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _SOCK_H
-#define _SOCK_H
-
-#include <linux/timer.h>
-#include <linux/ip.h> /* struct options */
-#include <linux/tcp.h> /* struct tcphdr */
-
-#include "skbuff.h" /* struct sk_buff */
-#ifdef CONFIG_AX25
-#include "ax25/ax25.h"
-#endif
-#ifdef CONFIG_IPX
-#include "ipx/ipx.h"
-#endif
-
-#define SOCK_ARRAY_SIZE 64
-
-
-/*
- * This structure really needs to be cleaned up.
- * Most of it is for TCP, and not used by any of
- * the other protocols.
- */
-struct sock {
- struct options *opt;
- struct options *rcv_opt;
- volatile unsigned long wmem_alloc;
- volatile unsigned long rmem_alloc;
- unsigned long send_seq;
- unsigned long acked_seq;
- unsigned long copied_seq;
- unsigned long rcv_ack_seq;
- unsigned long window_seq;
- unsigned long fin_seq;
-
- /*
- * Not all are volatile, but some are, so we
- * might as well say they all are.
- */
- volatile char inuse,
- dead,
- urginline,
- intr,
- blog,
- done,
- reuse,
- keepopen,
- linger,
- delay_acks,
- destroy,
- ack_timed,
- no_check,
- exp_growth,
- zapped, /* In ax25 & ipx means not linked */
- broadcast;
- unsigned long lingertime;
- int proc;
- struct sock *next;
- struct sock *pair;
- struct sk_buff *volatile send_tail;
- struct sk_buff *volatile send_head;
- struct sk_buff *volatile back_log;
- struct sk_buff *send_tmp;
- long retransmits;
- struct sk_buff *volatile wback,
- *volatile wfront,
- *volatile rqueue;
- struct proto *prot;
- struct wait_queue **sleep;
- unsigned long daddr;
- unsigned long saddr;
- unsigned short max_unacked;
- unsigned short window;
- unsigned short bytes_rcv;
- unsigned short mtu;
- unsigned short num;
- volatile unsigned short cong_window;
- volatile unsigned short packets_out;
- volatile unsigned short urg;
- volatile unsigned short shutdown;
- unsigned short mss;
- volatile unsigned long rtt;
- volatile unsigned long mdev;
- volatile unsigned short backoff;
- volatile short err;
- unsigned char protocol;
- volatile unsigned char state;
- volatile unsigned char ack_backlog;
- unsigned char max_ack_backlog;
- unsigned char priority;
- unsigned char debug;
- unsigned short rcvbuf;
- unsigned short sndbuf;
- unsigned short type;
-#ifdef CONFIG_IPX
- ipx_address ipx_source_addr,ipx_dest_addr;
- unsigned short ipx_type;
-#endif
-#ifdef CONFIG_AX25
-/* Really we want to add a per protocol private area */
- ax25_address ax25_source_addr,ax25_dest_addr;
- struct sk_buff *volatile ax25_retxq[8];
- char ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr;
- char ax25_condition;
- char ax25_retxcnt;
- char ax25_xx;
- char ax25_retxqi;
- char ax25_rrtimer;
- char ax25_timer;
-#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). */
- int timeout; /* What are we waiting for? */
- struct timer_list timer;
-
- /* identd */
- struct socket *socket;
-
- /* Event 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);
-};
-
-
-#define TIME_WRITE 1
-#define TIME_CLOSE 2
-#define TIME_KEEPOPEN 3
-#define TIME_DESTROY 4
-#define TIME_DONE 5 /* used to absorb those last few packets */
-#define SOCK_DESTROY_TIME 1000 /* about 10 seconds */
-
-#define PROT_SOCK 1024 /* Sockets 0-1023 can't be bound too unless you are superuser */
-
-#define SHUTDOWN_MASK 3
-#define RCV_SHUTDOWN 1
-#define SEND_SHUTDOWN 2
-
-extern void print_sk(struct sock *);
-extern void *sock_wmalloc(struct sock *sk,
- unsigned long size, int force,
- int priority);
-extern void *sock_rmalloc(struct sock *sk,
- unsigned long size, int force,
- int priority);
-extern void sock_wfree(struct sock *sk, void *mem,
- unsigned long size);
-extern void sock_rfree(struct sock *sk, void *mem,
- unsigned long size);
-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 optname, char *optval,
- int optlen);
-extern int sock_getsockopt(struct sock *sk, int level, int optname, char *optval,
- int *optlen);
-
-#endif /* _SOCK_H */
diff --git a/net/unix/proc.c b/net/unix/proc.c
index 4e23976..8a80ad5 100644
--- a/net/unix/proc.c
+++ b/net/unix/proc.c
@@ -8,7 +8,7 @@
* the PROC file system and the "unix" family of networking
* protocols. It is mainly used for debugging and statistics.
*
- * Version: @(#)proc.c 1.28 25/12/93
+ * Version: @(#)proc.c 1.0.4 05/23/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -16,14 +16,12 @@
* Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
*
* Fixes:
- * Anonymous : Comment errors
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
#include <linux/autoconf.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -35,55 +33,45 @@
#include "unix.h"
-/*
- * Called from PROCfs.
- */
-
+/* Called from PROCfs. */
int unix_get_info(char *buffer)
{
- char *pos;
- int i;
+ char *pos;
+ int i;
- pos = buffer;
- pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
+ pos = buffer;
+ pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
- for(i = 0; i < NSOCKETS; i++)
- {
- if (unix_datas[i].refcnt)
- {
- pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
- unix_datas[i].refcnt,
- unix_datas[i].protocol,
- unix_datas[i].socket->flags,
- unix_datas[i].socket->type,
- unix_datas[i].socket->state
- );
-
- /* If socket is bound to a filename, we'll print it. */
- if(unix_datas[i].sockaddr_len>0)
- {
- pos += sprintf(pos, " %s\n",
- unix_datas[i].sockaddr_un.sun_path);
- }
- else
- { /* just add a newline */
- *pos='\n';
- pos++;
- *pos='\0';
- }
+ for(i = 0; i < NSOCKETS; i++) {
+ if (unix_datas[i].refcnt) {
+ pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
+ unix_datas[i].refcnt,
+ unix_datas[i].protocol,
+ unix_datas[i].socket->flags,
+ unix_datas[i].socket->type,
+ unix_datas[i].socket->state
+ );
+
+ /* If socket is bound to a filename, we'll print it. */
+ if(unix_datas[i].sockaddr_len>0) {
+ pos += sprintf(pos, " %s\n",
+ unix_datas[i].sockaddr_un.sun_path);
+ } else { /* just add a newline */
+ *pos='\n';
+ pos++;
+ *pos='\0';
+ }
- /*
- * Check whether buffer _may_ overflow in the next loop.
- * Since sockets may have very very long paths, we make
- * PATH_MAX+80 the minimum space left for a new line.
- */
-
- if (pos > buffer+PAGE_SIZE-80-PATH_MAX)
- {
- printk("UNIX: netinfo: oops, too many sockets.\n");
- return(pos - buffer);
- }
+ /*
+ * Check whether buffer _may_ overflow in the next loop.
+ * Since sockets may have very very long paths, we make
+ * PATH_MAX+80 the minimum space left for a new line.
+ */
+ if (pos > buffer+PAGE_SIZE-80-PATH_MAX) {
+ printk("UNIX: netinfo: oops, too many sockets.\n");
+ return(pos - buffer);
}
- }
- return(pos - buffer);
+ }
+ }
+ return(pos - buffer);
}
diff --git a/net/unix/sock.c b/net/unix/sock.c
index 7e68b24..f4de8a8 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -4,7 +4,7 @@
* BSD Socket interface as the means of communication with
* the user level.
*
- * Version: @(#)sock.c 1.28 25/12/93
+ * Version: @(#)sock.c 1.0.5 05/25/93
*
* Authors: Orest Zborowski, <obz@Kodak.COM>
* Ross Biro, <bir7@leland.Stanford.Edu>
@@ -12,7 +12,6 @@
*
* Fixes:
* Alan Cox : Verify Area
- * Alan Cox : Tidy up ready for release
*
* BUGS
* Page faults on read while another process reads could lose data.
@@ -94,268 +93,252 @@ static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen);
-static void dprintf(int level, char *fmt, ...)
+static void
+dprintf(int level, char *fmt, ...)
{
- va_list args;
- char *buff;
- extern int vsprintf(char * buf, const char * fmt, va_list args);
-
- if (level != unix_debug)
- return;
-
- buff = (char *) kmalloc(256, GFP_KERNEL);
- if (buff != NULL)
- {
- va_start(args, fmt);
- vsprintf(buff, fmt, args);
- va_end(args);
- printk(buff);
- kfree(buff);
- }
+ va_list args;
+ char *buff;
+ extern int vsprintf(char * buf, const char * fmt, va_list args);
+
+ if (level != unix_debug) return;
+
+ buff = (char *) kmalloc(256, GFP_KERNEL);
+ if (buff != NULL) {
+ va_start(args, fmt);
+ vsprintf(buff, fmt, args);
+ va_end(args);
+ printk(buff);
+ kfree(buff);
+ }
}
-static inline int min(int a, int b)
+static inline int
+min(int a, int b)
{
- if (a < b)
- return(a);
- return(b);
+ if (a < b) return(a);
+ return(b);
}
-void sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
+void
+sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
{
- char buf[sizeof(sockun->sun_path) + 1];
-
- if (unix_debug == 0)
- return;
-
- sockaddr_len -= UN_PATH_OFFSET;
- if (sockun->sun_family != AF_UNIX)
- printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
- else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
- printk("UNIX: Bad addr len %d>\n", sockaddr_len);
- else
- {
- memcpy(buf, sockun->sun_path, sockaddr_len);
- buf[sockaddr_len] = '\0';
- printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET);
- }
+ char buf[sizeof(sockun->sun_path) + 1];
+
+ if (unix_debug == 0) return;
+
+ sockaddr_len -= UN_PATH_OFFSET;
+ if (sockun->sun_family != AF_UNIX)
+ printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
+ else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
+ printk("UNIX: Bad addr len %d>\n", sockaddr_len);
+ else {
+ memcpy(buf, sockun->sun_path, sockaddr_len);
+ buf[sockaddr_len] = '\0';
+ printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET);
+ }
}
-/*
- * Don't have to do anything.
- */
-
-static int unix_proto_listen(struct socket *sock, int backlog)
+/* don't have to do anything. */
+static int
+unix_proto_listen(struct socket *sock, int backlog)
{
- return(0);
+ return(0);
}
-static int unix_proto_setsockopt(struct socket *sock, int level, int optname,
+static int
+unix_proto_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
+static int
+unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
+static int
+unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int addr_len)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
+static int
+unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int *addr_len)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-static int unix_proto_shutdown(struct socket *sock, int how)
+static int
+unix_proto_shutdown(struct socket *sock, int how)
{
- return(-EOPNOTSUPP);
+ return(-EOPNOTSUPP);
}
-/*
- * This error needs to be checked.
- */
-
-static int unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
+/* This error needs to be checked. */
+static int
+unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
- if (flags != 0)
- return(-EINVAL);
- return(unix_proto_write(sock, (char *) buff, len, nonblock));
+ if (flags != 0) return(-EINVAL);
+ return(unix_proto_write(sock, (char *) buff, len, nonblock));
}
-/*
- * This error needs to be checked.
- */
-
-static int unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
+/* This error needs to be checked. */
+static int
+unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
- if (flags != 0)
- return(-EINVAL);
- return(unix_proto_read(sock, (char *) buff, len, nonblock));
+ if (flags != 0) return(-EINVAL);
+ return(unix_proto_read(sock, (char *) buff, len, nonblock));
}
-static struct unix_proto_data * unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
+static struct unix_proto_data *
+unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
struct inode *inode)
{
- struct unix_proto_data *upd;
-
- for(upd = unix_datas; upd <= last_unix_data; ++upd)
- {
- if (upd->refcnt && upd->socket &&
- upd->socket->state == SS_UNCONNECTED &&
- upd->sockaddr_un.sun_family == sockun->sun_family &&
- upd->inode == inode)
- {
- return(upd);
- }
- }
- return(NULL);
+ struct unix_proto_data *upd;
+
+ for(upd = unix_datas; upd <= last_unix_data; ++upd) {
+ if (upd->refcnt && upd->socket &&
+ upd->socket->state == SS_UNCONNECTED &&
+ upd->sockaddr_un.sun_family == sockun->sun_family &&
+ upd->inode == inode) return(upd);
+ }
+ return(NULL);
}
-static struct unix_proto_data *unix_data_alloc(void)
+static struct unix_proto_data *
+unix_data_alloc(void)
{
- struct unix_proto_data *upd;
-
- cli();
- for(upd = unix_datas; upd <= last_unix_data; ++upd)
- {
- if (!upd->refcnt)
- {
- upd->refcnt = 1;
- sti();
- upd->socket = NULL;
- upd->sockaddr_len = 0;
- upd->sockaddr_un.sun_family = 0;
- upd->buf = NULL;
- upd->bp_head = upd->bp_tail = 0;
- upd->inode = NULL;
- upd->peerupd = NULL;
- return(upd);
- }
- }
- sti();
- return(NULL);
+ struct unix_proto_data *upd;
+
+ cli();
+ for(upd = unix_datas; upd <= last_unix_data; ++upd) {
+ if (!upd->refcnt) {
+ upd->refcnt = 1;
+ sti();
+ upd->socket = NULL;
+ upd->sockaddr_len = 0;
+ upd->sockaddr_un.sun_family = 0;
+ upd->buf = NULL;
+ upd->bp_head = upd->bp_tail = 0;
+ upd->inode = NULL;
+ upd->peerupd = NULL;
+ return(upd);
+ }
+ }
+ sti();
+ return(NULL);
}
-static inline void unix_data_ref(struct unix_proto_data *upd)
+static inline void
+unix_data_ref(struct unix_proto_data *upd)
{
- if (!upd)
- {
- dprintf(1, "UNIX: data_ref: upd = NULL\n");
- return;
- }
- ++upd->refcnt;
- dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt);
+ if (!upd) {
+ dprintf(1, "UNIX: data_ref: upd = NULL\n");
+ return;
+ }
+ ++upd->refcnt;
+ dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt);
}
-static void unix_data_deref(struct unix_proto_data *upd)
+static void
+unix_data_deref(struct unix_proto_data *upd)
{
- if (!upd)
- {
- dprintf(1, "UNIX: data_deref: upd = NULL\n");
- return;
- }
- if (upd->refcnt == 1)
- {
- dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
- if (upd->buf)
- {
- free_page((unsigned long)upd->buf);
- upd->buf = NULL;
- upd->bp_head = upd->bp_tail = 0;
- }
- }
- --upd->refcnt;
+ if (!upd) {
+ dprintf(1, "UNIX: data_deref: upd = NULL\n");
+ return;
+ }
+ if (upd->refcnt == 1) {
+ dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
+ if (upd->buf) {
+ free_page((unsigned long)upd->buf);
+ upd->buf = NULL;
+ upd->bp_head = upd->bp_tail = 0;
+ }
+ }
+ --upd->refcnt;
}
/*
- * Upon a create, we allocate an empty protocol data,
- * and grab a page to buffer writes.
+ * Upon a create, we allocate an empty protocol data,
+ * and grab a page to buffer writes.
*/
-
-static int unix_proto_create(struct socket *sock, int protocol)
-{
- struct unix_proto_data *upd;
-
- dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
- if (protocol != 0)
- {
- dprintf(1, "UNIX: create: protocol != 0\n");
- return(-EINVAL);
- }
- if (!(upd = unix_data_alloc()))
- {
- printk("UNIX: create: can't allocate buffer\n");
- return(-ENOMEM);
- }
- if (!(upd->buf = (char*) get_free_page(GFP_USER)))
- {
- printk("UNIX: create: can't get page!\n");
- unix_data_deref(upd);
- return(-ENOMEM);
- }
- upd->protocol = protocol;
- upd->socket = sock;
- UN_DATA(sock) = upd;
- dprintf(1, "UNIX: create: allocated data 0x%x\n", upd);
- return(0);
+static int
+unix_proto_create(struct socket *sock, int protocol)
+{
+ struct unix_proto_data *upd;
+
+ dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
+ if (protocol != 0) {
+ dprintf(1, "UNIX: create: protocol != 0\n");
+ return(-EINVAL);
+ }
+ if (!(upd = unix_data_alloc())) {
+ printk("UNIX: create: can't allocate buffer\n");
+ return(-ENOMEM);
+ }
+ if (!(upd->buf = (char*) get_free_page(GFP_USER))) {
+ printk("UNIX: create: can't get page!\n");
+ unix_data_deref(upd);
+ return(-ENOMEM);
+ }
+ upd->protocol = protocol;
+ upd->socket = sock;
+ UN_DATA(sock) = upd;
+ dprintf(1, "UNIX: create: allocated data 0x%x\n", upd);
+ return(0);
}
-static int unix_proto_dup(struct socket *newsock, struct socket *oldsock)
+static int
+unix_proto_dup(struct socket *newsock, struct socket *oldsock)
{
- struct unix_proto_data *upd = UN_DATA(oldsock);
+ struct unix_proto_data *upd = UN_DATA(oldsock);
- return(unix_proto_create(newsock, upd->protocol));
+ return(unix_proto_create(newsock, upd->protocol));
}
-static int unix_proto_release(struct socket *sock, struct socket *peer)
-{
- struct unix_proto_data *upd = UN_DATA(sock);
-
- dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
- if (!upd)
- return(0);
- if (upd->socket != sock)
- {
- printk("UNIX: release: socket link mismatch!\n");
- return(-EINVAL);
- }
- if (upd->inode)
- {
- dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
- iput(upd->inode);
- upd->inode = NULL;
- }
- UN_DATA(sock) = NULL;
- upd->socket = NULL;
- if (upd->peerupd)
- unix_data_deref(upd->peerupd);
- unix_data_deref(upd);
- return(0);
+static int
+unix_proto_release(struct socket *sock, struct socket *peer)
+{
+ struct unix_proto_data *upd = UN_DATA(sock);
+
+ dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
+ if (!upd) return(0);
+ if (upd->socket != sock) {
+ printk("UNIX: release: socket link mismatch!\n");
+ return(-EINVAL);
+ }
+ if (upd->inode) {
+ dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
+ iput(upd->inode);
+ upd->inode = NULL;
+ }
+ UN_DATA(sock) = NULL;
+ upd->socket = NULL;
+ if (upd->peerupd) unix_data_deref(upd->peerupd);
+ unix_data_deref(upd);
+ return(0);
}
@@ -368,57 +351,54 @@ static int unix_proto_release(struct socket *sock, struct socket *peer)
* Here we return EINVAL, but it may be necessary to re-bind.
* I think thats what BSD does in the case of datagram sockets...
*/
-static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
+static int
+unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
int sockaddr_len)
{
- char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
- struct unix_proto_data *upd = UN_DATA(sock);
- unsigned long old_fs;
- int i;
- int er;
-
- dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len);
- if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un))
- {
- dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
- return(-EINVAL);
- }
- if (upd->sockaddr_len || upd->inode)
- {
- printk("UNIX: bind: already bound!\n");
- return(-EINVAL);
- }
- er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len);
- if(er)
- return er;
- memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
- upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
- if (upd->sockaddr_un.sun_family != AF_UNIX)
- {
- dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
- upd->sockaddr_un.sun_family, AF_UNIX);
- return(-EINVAL);
- }
-
- memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
- fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
- old_fs = get_fs();
- set_fs(get_ds());
- i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
- if (i == 0)
- i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
- set_fs(old_fs);
- if (i < 0)
- {
- printk("UNIX: bind: can't open socket %s\n", fname);
- return(i);
- }
- upd->sockaddr_len = sockaddr_len; /* now its legal */
-
- dprintf(1, "UNIX: bind: bound socket address: ");
- sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
- dprintf(1, "to inode 0x%x\n", upd->inode);
- return(0);
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
+ struct unix_proto_data *upd = UN_DATA(sock);
+ unsigned long old_fs;
+ int i;
+ int er;
+
+ dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len);
+ if (sockaddr_len <= UN_PATH_OFFSET ||
+ sockaddr_len > sizeof(struct sockaddr_un)) {
+ dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
+ return(-EINVAL);
+ }
+ if (upd->sockaddr_len || upd->inode) {
+ printk("UNIX: bind: already bound!\n");
+ return(-EINVAL);
+ }
+ er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len);
+ if(er)
+ return er;
+ memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
+ upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ if (upd->sockaddr_un.sun_family != AF_UNIX) {
+ dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
+ upd->sockaddr_un.sun_family, AF_UNIX);
+ return(-EINVAL);
+ }
+
+ memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET);
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ old_fs = get_fs();
+ set_fs(get_ds());
+ i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
+ if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
+ set_fs(old_fs);
+ if (i < 0) {
+ printk("UNIX: bind: can't open socket %s\n", fname);
+ return(i);
+ }
+ upd->sockaddr_len = sockaddr_len; /* now its legal */
+
+ dprintf(1, "UNIX: bind: bound socket address: ");
+ sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len);
+ dprintf(1, "to inode 0x%x\n", upd->inode);
+ return(0);
}
@@ -427,79 +407,71 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
* (I can't for the life of me find an application where that
* wouldn't be the case!)
*/
-
-static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags)
-{
- char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
- struct sockaddr_un sockun;
- struct unix_proto_data *serv_upd;
- struct inode *inode;
- unsigned long old_fs;
- int i;
- int er;
-
- dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len);
-
- if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un))
- {
- dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len);
- return(-EINVAL);
- }
- if (sock->state == SS_CONNECTING)
- return(-EINPROGRESS);
- if (sock->state == SS_CONNECTED)
- return(-EISCONN);
-
- er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
- if(er)
- return er;
- memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
- sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
- if (sockun.sun_family != AF_UNIX)
- {
- dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
- sockun.sun_family, AF_UNIX);
- return(-EINVAL);
- }
-
- /*
- * Try to open the name in the filesystem - this is how we
- * identify ourselves and our server. Note that we don't
- * hold onto the inode that long, just enough to find our
- * server. When we're connected, we mooch off the server.
- */
-
- memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
- fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
- old_fs = get_fs();
- set_fs(get_ds());
- i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
- set_fs(old_fs);
- if (i < 0)
- {
- dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
- return(i);
- }
- serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
- iput(inode);
- if (!serv_upd)
- {
- dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
- fname, inode);
- return(-EINVAL);
- }
- if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0)
- {
- dprintf(1, "UNIX: connect: can't await connection\n");
- return(i);
- }
- if (sock->conn)
- {
- unix_data_ref(UN_DATA(sock->conn));
- UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
- }
- return(0);
+static int
+unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len, int flags)
+{
+ char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
+ struct sockaddr_un sockun;
+ struct unix_proto_data *serv_upd;
+ struct inode *inode;
+ unsigned long old_fs;
+ int i;
+ int er;
+
+ dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len);
+
+ if (sockaddr_len <= UN_PATH_OFFSET ||
+ sockaddr_len > sizeof(struct sockaddr_un)) {
+ dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len);
+ return(-EINVAL);
+ }
+ if (sock->state == SS_CONNECTING) return(-EINPROGRESS);
+ if (sock->state == SS_CONNECTED) return(-EISCONN);
+
+ er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
+ if(er)
+ return er;
+ memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
+ sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ if (sockun.sun_family != AF_UNIX) {
+ dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
+ sockun.sun_family, AF_UNIX);
+ return(-EINVAL);
+ }
+
+ /*
+ * Try to open the name in the filesystem - this is how we
+ * identify ourselves and our server. Note that we don't
+ * hold onto the inode that long, just enough to find our
+ * server. When we're connected, we mooch off the server.
+ */
+ memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
+ fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
+ old_fs = get_fs();
+ set_fs(get_ds());
+ i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
+ set_fs(old_fs);
+ if (i < 0) {
+ dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
+ return(i);
+ }
+ serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
+ iput(inode);
+ if (!serv_upd) {
+ dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
+ fname, inode);
+ return(-EINVAL);
+ }
+ if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
+ dprintf(1, "UNIX: connect: can't await connection\n");
+ return(i);
+ }
+ if (sock->conn) {
+ unix_data_ref(UN_DATA(sock->conn));
+ UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
+ }
+ return(0);
}
@@ -509,173 +481,146 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
* for a wait area, and deadlock prevention in the case of a process
* writing to itself is, ignored, in true unix fashion!
*/
-
-static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
+static int
+unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
{
- struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
+ struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
- unix_data_ref(upd1);
- unix_data_ref(upd2);
- upd1->peerupd = upd2;
- upd2->peerupd = upd1;
- return(0);
+ unix_data_ref(upd1);
+ unix_data_ref(upd2);
+ upd1->peerupd = upd2;
+ upd2->peerupd = upd1;
+ return(0);
}
/* On accept, we ref the peer's data for safe writes. */
-
-static int unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- struct socket *clientsock;
-
- dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n",
- sock, newsock);
-
- /*
- * If there aren't any sockets awaiting connection,
- * then wait for one, unless nonblocking.
- */
- while(!(clientsock = sock->iconn))
- {
- if (flags & O_NONBLOCK)
- return(-EAGAIN);
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked)
- {
- dprintf(1, "UNIX: accept: sleep was interrupted\n");
- return(-ERESTARTSYS);
- }
- }
-
- /*
- * Great. Finish the connection relative to server and client,
- * wake up the client and return the new fd to the server.
- */
- sock->iconn = clientsock->next;
- clientsock->next = NULL;
- newsock->conn = clientsock;
- clientsock->conn = newsock;
- clientsock->state = SS_CONNECTED;
- newsock->state = SS_CONNECTED;
- unix_data_ref(UN_DATA(clientsock));
- UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
- UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
- UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
- wake_up(clientsock->wait);
- return(0);
+static int
+unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+ struct socket *clientsock;
+
+ dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n",
+ sock, newsock);
+
+ /*
+ * If there aren't any sockets awaiting connection,
+ * then wait for one, unless nonblocking.
+ */
+ while(!(clientsock = sock->iconn)) {
+ if (flags & O_NONBLOCK) return(-EAGAIN);
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ dprintf(1, "UNIX: accept: sleep was interrupted\n");
+ return(-ERESTARTSYS);
+ }
+ }
+
+ /*
+ * Great. Finish the connection relative to server and client,
+ * wake up the client and return the new fd to the server.
+ */
+ sock->iconn = clientsock->next;
+ clientsock->next = NULL;
+ newsock->conn = clientsock;
+ clientsock->conn = newsock;
+ clientsock->state = SS_CONNECTED;
+ newsock->state = SS_CONNECTED;
+ unix_data_ref(UN_DATA(clientsock));
+ UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
+ UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
+ UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
+ wake_up(clientsock->wait);
+ return(0);
}
-/*
- * Gets the current name or the name of the connected socket.
- */
-
-static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
- int *usockaddr_len, int peer)
+/* Gets the current name or the name of the connected socket. */
+static int
+unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
+ int *usockaddr_len, int peer)
{
- struct unix_proto_data *upd;
- int len;
- int er;
-
- dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
- if (peer)
- {
- if (sock->state != SS_CONNECTED)
- {
- dprintf(1, "UNIX: getname: socket not connected\n");
- return(-EINVAL);
- }
- upd = UN_DATA(sock->conn);
- }
- else
- upd = UN_DATA(sock);
-
- er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
- if(er)
- return er;
- if ((len = get_fs_long(usockaddr_len)) <= 0)
- return(-EINVAL);
- if (len > upd->sockaddr_len)
- len = upd->sockaddr_len;
- if (len)
- {
- er=verify_area(VERIFY_WRITE, usockaddr, len);
- if(er)
- return er;
- memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
- }
- put_fs_long(len, usockaddr_len);
- return(0);
+ struct unix_proto_data *upd;
+ int len;
+ int er;
+
+ dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
+ if (peer) {
+ if (sock->state != SS_CONNECTED) {
+ dprintf(1, "UNIX: getname: socket not connected\n");
+ return(-EINVAL);
+ }
+ upd = UN_DATA(sock->conn);
+ } else
+ upd = UN_DATA(sock);
+
+ er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
+ if(er)
+ return er;
+ if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL);
+ if (len > upd->sockaddr_len) len = upd->sockaddr_len;
+ if (len) {
+ er=verify_area(VERIFY_WRITE, usockaddr, len);
+ if(er)
+ return er;
+ memcpy_tofs(usockaddr, &upd->sockaddr_un, len);
+ }
+ put_fs_long(len, usockaddr_len);
+ return(0);
}
/* We read from our own buf. */
+static int
+unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+ struct unix_proto_data *upd;
+ int todo, avail;
+ int er;
+
+ if ((todo = size) <= 0) return(0);
+ upd = UN_DATA(sock);
+ while(!(avail = UN_BUF_AVAIL(upd))) {
+ if (sock->state != SS_CONNECTED) {
+ dprintf(1, "UNIX: read: socket not connected\n");
+ return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
+ }
+ dprintf(1, "UNIX: read: no data available...\n");
+ if (nonblock) return(-EAGAIN);
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ dprintf(1, "UNIX: read: interrupted\n");
+ return(-ERESTARTSYS);
+ }
+ }
+
+ /*
+ * Copy from the read buffer into the user's buffer,
+ * watching for wraparound. Then we wake up the writer.
+ */
+ do {
+ int part, cando;
+
+ if (avail <= 0) {
+ printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
+ send_sig(SIGKILL, current, 1);
+ return(-EPIPE);
+ }
-static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
-{
- struct unix_proto_data *upd;
- int todo, avail;
- int er;
-
- if ((todo = size) <= 0)
- return(0);
- upd = UN_DATA(sock);
- while(!(avail = UN_BUF_AVAIL(upd)))
- {
- if (sock->state != SS_CONNECTED)
- {
- dprintf(1, "UNIX: read: socket not connected\n");
- return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
- }
- dprintf(1, "UNIX: read: no data available...\n");
- if (nonblock)
- return(-EAGAIN);
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked)
- {
- dprintf(1, "UNIX: read: interrupted\n");
- return(-ERESTARTSYS);
- }
- }
-
- /*
- * Copy from the read buffer into the user's buffer,
- * watching for wraparound. Then we wake up the writer.
- */
-
- do
- {
- int part, cando;
-
- if (avail <= 0)
- {
- printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
- send_sig(SIGKILL, current, 1);
- return(-EPIPE);
- }
-
- if ((cando = todo) > avail)
- cando = avail;
- if (cando >(part = BUF_SIZE - upd->bp_tail))
- cando = part;
-
- dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
- avail, todo, cando);
-
- if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
- return er;
-
- memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
- upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
- ubuf += cando;
- todo -= cando;
-
- if (sock->state == SS_CONNECTED)
- wake_up(sock->conn->wait);
- avail = UN_BUF_AVAIL(upd);
- }
- while(todo && avail);
- return(size - todo);
+ if ((cando = todo) > avail) cando = avail;
+ if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part;
+ dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
+ avail, todo, cando);
+ if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
+ return er;
+ memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
+ upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
+ ubuf += cando;
+ todo -= cando;
+ if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
+ avail = UN_BUF_AVAIL(upd);
+ } while(todo && avail);
+ return(size - todo);
}
@@ -684,308 +629,274 @@ static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblo
* peer so we are safe that the buffer remains, even after the
* peer has disconnected, which we check other ways.
*/
-static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
-{
- struct unix_proto_data *pupd;
- int todo, space;
- int er;
-
- if ((todo = size) <= 0)
- return(0);
- if (sock->state != SS_CONNECTED)
- {
- dprintf(1, "UNIX: write: socket not connected\n");
- if (sock->state == SS_DISCONNECTING)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- return(-EINVAL);
- }
- pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
-
- while(!(space = UN_BUF_SPACE(pupd)))
- {
- dprintf(1, "UNIX: write: no space left...\n");
- if (nonblock)
- return(-EAGAIN);
- interruptible_sleep_on(sock->wait);
- if (current->signal & ~current->blocked)
- {
- dprintf(1, "UNIX: write: interrupted\n");
- return(-ERESTARTSYS);
- }
- if (sock->state == SS_DISCONNECTING)
- {
- dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- }
-
- /*
- * Copy from the user's buffer to the write buffer,
- * watching for wraparound. Then we wake up the reader.
- */
-
- do
- {
- int part, cando;
-
- if (space <= 0)
- {
- printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
- send_sig(SIGKILL, current, 1);
- return(-EPIPE);
- }
+static int
+unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
+{
+ struct unix_proto_data *pupd;
+ int todo, space;
+ int er;
+
+ if ((todo = size) <= 0) return(0);
+ if (sock->state != SS_CONNECTED) {
+ dprintf(1, "UNIX: write: socket not connected\n");
+ if (sock->state == SS_DISCONNECTING) {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ return(-EINVAL);
+ }
+ pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
+
+ while(!(space = UN_BUF_SPACE(pupd))) {
+ dprintf(1, "UNIX: write: no space left...\n");
+ if (nonblock) return(-EAGAIN);
+ interruptible_sleep_on(sock->wait);
+ if (current->signal & ~current->blocked) {
+ dprintf(1, "UNIX: write: interrupted\n");
+ return(-ERESTARTSYS);
+ }
+ if (sock->state == SS_DISCONNECTING) {
+ dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ }
+
+ /*
+ * Copy from the user's buffer to the write buffer,
+ * watching for wraparound. Then we wake up the reader.
+ */
+ do {
+ int part, cando;
+
+ if (space <= 0) {
+ printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
+ send_sig(SIGKILL, current, 1);
+ return(-EPIPE);
+ }
- /*
- * We may become disconnected inside this loop, so watch
- * for it (peerupd is safe until we close).
- */
-
- if (sock->state == SS_DISCONNECTING)
- {
- send_sig(SIGPIPE, current, 1);
- return(-EPIPE);
- }
- if ((cando = todo) > space)
- cando = space;
-
- if (cando >(part = BUF_SIZE - pupd->bp_head))
- cando = part;
-
- dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
- space, todo, cando);
-
- er=verify_area(VERIFY_READ, ubuf, cando);
- if(er)
- return er;
- memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
- pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
-
- ubuf += cando;
- todo -= cando;
-
- if (sock->state == SS_CONNECTED)
- wake_up(sock->conn->wait);
- space = UN_BUF_SPACE(pupd);
- }
- while(todo && space);
- return(size - todo);
+ /*
+ * We may become disconnected inside this loop, so watch
+ * for it (peerupd is safe until we close).
+ */
+ if (sock->state == SS_DISCONNECTING) {
+ send_sig(SIGPIPE, current, 1);
+ return(-EPIPE);
+ }
+ if ((cando = todo) > space) cando = space;
+ if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;
+ dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
+ space, todo, cando);
+ er=verify_area(VERIFY_READ, ubuf, cando);
+ if(er)
+ return er;
+ memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
+ pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
+ ubuf += cando;
+ todo -= cando;
+ if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
+ space = UN_BUF_SPACE(pupd);
+ } while(todo && space);
+ return(size - todo);
}
-static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
+static int
+unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
{
- struct unix_proto_data *upd, *peerupd;
-
- /* Handle server sockets specially. */
- if (sock->flags & SO_ACCEPTCON)
- {
- if (sel_type == SEL_IN)
- {
- dprintf(1, "UNIX: select: %sconnections pending\n",
- sock->iconn ? "" : "no ");
- if (sock->iconn)
- return(1);
- select_wait(sock->wait, wait);
- return(sock->iconn ? 1 : 0);
- }
- dprintf(1, "UNIX: select: nothing else for server socket\n");
+ struct unix_proto_data *upd, *peerupd;
+
+ /* Handle server sockets specially. */
+ if (sock->flags & SO_ACCEPTCON) {
+ if (sel_type == SEL_IN) {
+ dprintf(1, "UNIX: select: %sconnections pending\n",
+ sock->iconn ? "" : "no ");
+ if (sock->iconn) return(1);
select_wait(sock->wait, wait);
- return(0);
- }
-
- if (sel_type == SEL_IN)
- {
- upd = UN_DATA(sock);
- dprintf(1, "UNIX: select: there is%s data available\n",
- UN_BUF_AVAIL(upd) ? "" : " no");
- if (UN_BUF_AVAIL(upd)) /* even if disconnected */
- return(1);
- else if (sock->state != SS_CONNECTED)
- {
- dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
- return(1);
- }
- select_wait(sock->wait,wait);
- return(0);
- }
- if (sel_type == SEL_OUT)
- {
- if (sock->state != SS_CONNECTED)
- {
- dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
- return(1);
- }
- peerupd = UN_DATA(sock->conn);
- dprintf(1, "UNIX: select: there is%s space available\n",
- UN_BUF_SPACE(peerupd) ? "" : " no");
- if (UN_BUF_SPACE(peerupd) > 0)
+ return(sock->iconn ? 1 : 0);
+ }
+ dprintf(1, "UNIX: select: nothing else for server socket\n");
+ select_wait(sock->wait, wait);
+ return(0);
+ }
+
+ if (sel_type == SEL_IN) {
+ upd = UN_DATA(sock);
+ dprintf(1, "UNIX: select: there is%s data available\n",
+ UN_BUF_AVAIL(upd) ? "" : " no");
+ if (UN_BUF_AVAIL(upd)) /* even if disconnected */
return(1);
- select_wait(sock->wait,wait);
- return(0);
- }
-
- /* SEL_EX */
- dprintf(1, "UNIX: select: there are no exceptions here?!\n");
- return(0);
+ else if (sock->state != SS_CONNECTED) {
+ dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
+ return(1);
+ }
+ select_wait(sock->wait,wait);
+ return(0);
+ }
+ if (sel_type == SEL_OUT) {
+ if (sock->state != SS_CONNECTED) {
+ dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
+ return(1);
+ }
+ peerupd = UN_DATA(sock->conn);
+ dprintf(1, "UNIX: select: there is%s space available\n",
+ UN_BUF_SPACE(peerupd) ? "" : " no");
+ if (UN_BUF_SPACE(peerupd) > 0) return(1);
+ select_wait(sock->wait,wait);
+ return(0);
+ }
+
+ /* SEL_EX */
+ dprintf(1, "UNIX: select: there are no exceptions here?!\n");
+ return(0);
}
-static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+static int
+unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
- struct unix_proto_data *upd, *peerupd;
- int er;
-
- upd = UN_DATA(sock);
- peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
-
- switch(cmd)
- {
- case TIOCINQ:
- if (sock->flags & SO_ACCEPTCON)
- return(-EINVAL);
- er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
- if(er)
- return er;
- if (UN_BUF_AVAIL(upd) || peerupd)
- put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
- else
- put_fs_long(0,(unsigned long *)arg);
- break;
- case TIOCOUTQ:
- if (sock->flags & SO_ACCEPTCON)
- return(-EINVAL);
- er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
- if(er)
- return er;
- if (peerupd)
- put_fs_long(UN_BUF_SPACE(peerupd), (unsigned long *)arg);
- else
- put_fs_long(0,(unsigned long *)arg);
- break;
- default:
- return(-EINVAL);
- }
- return(0);
+ struct unix_proto_data *upd, *peerupd;
+ int er;
+
+ upd = UN_DATA(sock);
+ peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
+
+ switch(cmd) {
+ case TIOCINQ:
+ if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
+ er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
+ if(er)
+ return er;
+ if (UN_BUF_AVAIL(upd) || peerupd)
+ put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg);
+ else
+ put_fs_long(0,(unsigned long *)arg);
+ break;
+ case TIOCOUTQ:
+ if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
+ er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
+ if(er)
+ return er;
+ if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd),
+ (unsigned long *)arg);
+ else
+ put_fs_long(0,(unsigned long *)arg);
+ break;
+ default:
+ return(-EINVAL);
+ }
+ return(0);
}
-static int unix_open(struct inode * inode, struct file * file)
+static int
+unix_open(struct inode * inode, struct file * file)
{
- int minor;
+ int minor;
- dprintf(1, "UNIX: open\n");
- minor = MINOR(inode->i_rdev);
-
- if (minor != 0)
- return(-ENODEV);
+ dprintf(1, "UNIX: open\n");
+ minor = MINOR(inode->i_rdev);
+ if (minor != 0) return(-ENODEV);
- return(0);
+ return(0);
}
-static void unix_close(struct inode * inode, struct file * file)
+static void
+unix_close(struct inode * inode, struct file * file)
{
- dprintf(1, "UNIX: close\n");
+ dprintf(1, "UNIX: close\n");
}
-static int unix_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int
+unix_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- int minor, ret;
- int er;
-
- dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);
- minor = MINOR(inode->i_rdev);
-
- if (minor != 0)
- return(-ENODEV);
-
- ret = -EINVAL;
- switch(cmd)
- {
- case DDIOCSDBG:
- er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
- if(er)
- return er;
- unix_debug = get_fs_long((int *)arg);
- if (unix_debug != 0 && unix_debug != 1)
- {
- unix_debug = 0;
- return(-EINVAL);
- }
- return(0);
- case SIOCSIFLINK:
- printk("UNIX: cannot link streams!\n");
- break;
- default:
- break;
- }
- return(ret);
+ int minor, ret;
+ int er;
+
+ dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);
+ minor = MINOR(inode->i_rdev);
+ if (minor != 0) return(-ENODEV);
+
+ ret = -EINVAL;
+ switch(cmd) {
+ case DDIOCSDBG:
+ er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
+ if(er)
+ return er;
+ unix_debug = get_fs_long((int *)arg);
+ if (unix_debug != 0 && unix_debug != 1) {
+ unix_debug = 0;
+ return(-EINVAL);
+ }
+ return(0);
+ case SIOCSIFLINK:
+ printk("UNIX: cannot link streams!\n");
+ break;
+ default:
+ break;
+ }
+ return(ret);
}
-static struct file_operations unix_fops =
-{
- NULL, /* LSEEK */
- NULL, /* READ */
- NULL, /* WRITE */
- NULL, /* READDIR */
- NULL, /* SELECT */
- unix_ioctl, /* IOCTL */
- NULL, /* MMAP */
- unix_open, /* OPEN */
- unix_close /* CLOSE */
+static struct file_operations unix_fops = {
+ NULL, /* LSEEK */
+ NULL, /* READ */
+ NULL, /* WRITE */
+ NULL, /* READDIR */
+ NULL, /* SELECT */
+ unix_ioctl, /* IOCTL */
+ NULL, /* MMAP */
+ unix_open, /* OPEN */
+ unix_close /* CLOSE */
};
static struct proto_ops unix_proto_ops = {
- AF_UNIX,
- unix_proto_create,
- unix_proto_dup,
- unix_proto_release,
- unix_proto_bind,
- unix_proto_connect,
- unix_proto_socketpair,
- unix_proto_accept,
- unix_proto_getname,
- unix_proto_read,
- unix_proto_write,
- unix_proto_select,
- unix_proto_ioctl,
- unix_proto_listen,
- unix_proto_send,
- unix_proto_recv,
- unix_proto_sendto,
- unix_proto_recvfrom,
- unix_proto_shutdown,
- unix_proto_setsockopt,
- unix_proto_getsockopt,
- NULL /* unix_proto_fcntl */
+ AF_UNIX,
+ unix_proto_create,
+ unix_proto_dup,
+ unix_proto_release,
+ unix_proto_bind,
+ unix_proto_connect,
+ unix_proto_socketpair,
+ unix_proto_accept,
+ unix_proto_getname,
+ unix_proto_read,
+ unix_proto_write,
+ unix_proto_select,
+ unix_proto_ioctl,
+ unix_proto_listen,
+ unix_proto_send,
+ unix_proto_recv,
+ unix_proto_sendto,
+ unix_proto_recvfrom,
+ unix_proto_shutdown,
+ unix_proto_setsockopt,
+ unix_proto_getsockopt,
+ NULL /* unix_proto_fcntl */
};
-void unix_proto_init(struct ddi_proto *pro)
+void
+unix_proto_init(struct ddi_proto *pro)
{
- struct unix_proto_data *upd;
-
- dprintf(1, "%s: init: initializing...\n", pro->name);
- if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0)
- {
- printk("%s: cannot register major device %d!\n",
- pro->name, AF_UNIX_MAJOR);
- return;
- }
-
- /* Tell SOCKET that we are alive... */
- (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
-
- for(upd = unix_datas; upd <= last_unix_data; ++upd)
- {
- upd->refcnt = 0;
- }
+ struct unix_proto_data *upd;
+
+ dprintf(1, "%s: init: initializing...\n", pro->name);
+ if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) {
+ printk("%s: cannot register major device %d!\n",
+ pro->name, AF_UNIX_MAJOR);
+ return;
+ }
+
+ /* Tell SOCKET that we are alive... */
+ (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
+
+ for(upd = unix_datas; upd <= last_unix_data; ++upd) {
+ upd->refcnt = 0;
+ }
}