diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1994-01-08 13:13:10 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:26 -0400 |
commit | 9ee059ad6f92a777f874ddf472cd36aa9a901c16 (patch) | |
tree | b89bcf7ec57269238ee371f67b6a3e1344c89dba | |
parent | a9cc257a8016df80d8bbfdc3ffc6dd2193280c0a (diff) | |
download | archive-9ee059ad6f92a777f874ddf472cd36aa9a901c16.tar.gz |
ALPHA-pl14o
48 files changed, 7875 insertions, 12880 deletions
@@ -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 } } +}; @@ -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 *) ∈ - sprintf(buff, "%d.%d.%d.%d", - (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); - return(buff); + p = (char *) ∈ + 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; + } } |