Commit ddd9ed00 authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14o

parent 28067f4d
VERSION = 0.99 VERSION = 0.99
PATCHLEVEL = 14 PATCHLEVEL = 14
ALPHA = n ALPHA = o
all: Version zImage all: Version zImage
...@@ -50,7 +50,7 @@ SVGA_MODE= -DSVGA_MODE=NORMAL_VGA ...@@ -50,7 +50,7 @@ SVGA_MODE= -DSVGA_MODE=NORMAL_VGA
# standard CFLAGS # standard CFLAGS
# #
CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -pipe CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe
ifdef CONFIG_CPP ifdef CONFIG_CPP
CFLAGS := $(CFLAGS) -x c++ CFLAGS := $(CFLAGS) -x c++
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
include CONFIG include CONFIG
NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o) 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 CFLAGS := $(CFLAGS) -I../../net/inet
CPP := $(CPP) -I../../net/inet -I../../net/socket -I../../net CPP := $(CPP) -I../../net/inet
# The point of the makefile... # The point of the makefile...
all: net.a all: net.a
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
#include "ax25/ax25.h" #include "ax25.h"
#endif #endif
#include "eth.h" #include "eth.h"
#include "ip.h" #include "ip.h"
......
...@@ -53,19 +53,27 @@ ...@@ -53,19 +53,27 @@
#define MAYBE_CONTINUE(LABEL,DEV) \ #define MAYBE_CONTINUE(LABEL,DEV) \
{if (buffer) kfree(buffer); \ {if (buffer) kfree(buffer); \
if (cont_extent){ \ if (cont_extent){ \
int block, offset; \ int block, offset, offset1; \
struct buffer_head * bh; \ struct buffer_head * bh; \
buffer = kmalloc(cont_size,GFP_KERNEL); \ buffer = kmalloc(cont_size,GFP_KERNEL); \
block = cont_extent; \ block = cont_extent; \
offset = cont_offset; \ offset = cont_offset; \
offset1 = 0; \
if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \ if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \
block <<= 1; \ block <<= 1; \
if (offset >= 1024) block++; \ if (offset >= 1024) block++; \
offset &= 1023; \ 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)); \ bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \ if(bh){ \
memcpy(buffer, bh->b_data, cont_size); \ memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
brelse(bh); \ brelse(bh); \
chr = (unsigned char *) buffer; \ chr = (unsigned char *) buffer; \
len = cont_size; \ len = cont_size; \
...@@ -291,10 +299,17 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, ...@@ -291,10 +299,17 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
}; };
break; break;
case SIG('T','F'): 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 */ 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_CREATE)
if(rr->u.TF.flags & TF_MODIFY) inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0); inode->i_ctime = 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_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; break;
case SIG('S','L'): case SIG('S','L'):
{int slen; {int slen;
......
...@@ -59,8 +59,6 @@ struct options { ...@@ -59,8 +59,6 @@ struct options {
unsigned short handling; unsigned short handling;
unsigned short stream; unsigned short stream;
unsigned tcc; unsigned tcc;
int option_length;
void *option_data;
}; };
......
...@@ -30,14 +30,10 @@ struct linger { ...@@ -30,14 +30,10 @@ struct linger {
#define AF_UNSPEC 0 #define AF_UNSPEC 0
#define AF_UNIX 1 #define AF_UNIX 1
#define AF_INET 2 #define AF_INET 2
#define AF_AX25 3
#define AF_IPX 4
/* Protocol families, same as address families. */ /* Protocol families, same as address families. */
#define PF_UNIX AF_UNIX #define PF_UNIX AF_UNIX
#define PF_INET AF_INET #define PF_INET AF_INET
#define PF_AX25 AF_AX25
#define PF_IPX AF_IPX
/* Flags we can use with send/ and recv. */ /* Flags we can use with send/ and recv. */
#define MSG_OOB 1 #define MSG_OOB 1
...@@ -45,10 +41,6 @@ struct linger { ...@@ -45,10 +41,6 @@ struct linger {
/* Setsockoptions(2) level. */ /* Setsockoptions(2) level. */
#define SOL_SOCKET 1 #define SOL_SOCKET 1
#define SOL_IP 2
#define SOL_IPX 3
#define SOL_AX25 4
#define SOL_TCP 5
/* For setsockoptions(2) */ /* For setsockoptions(2) */
#define SO_DEBUG 1 #define SO_DEBUG 1
...@@ -64,19 +56,6 @@ struct linger { ...@@ -64,19 +56,6 @@ struct linger {
#define SO_NO_CHECK 11 #define SO_NO_CHECK 11
#define SO_PRIORITY 12 #define SO_PRIORITY 12
#define SO_LINGER 13 #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. */ /* The various priorities. */
#define SOPRI_INTERACTIVE 0 #define SOPRI_INTERACTIVE 0
......
...@@ -7,17 +7,10 @@ ...@@ -7,17 +7,10 @@
# #
# Note 2! The CFLAGS definition is now in the main makefile... # 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 := unix inet
SUBDIRS := $(SUBDIRS) inet
endif
ifdef CONFIG_IPX
SUBDIRS := $(SUBDIRS) ipx
endif
ifdef CONFIG_AX25
SUBDIRS := $(SUBDIRS) ax25
endif
SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o) SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o)
......
...@@ -30,10 +30,10 @@ ...@@ -30,10 +30,10 @@
# include "inet/inet.h" # include "inet/inet.h"
#endif #endif
#ifdef CONFIG_IPX #ifdef CONFIG_IPX
#include "ipx/ipxcall.h" #include "inet/ipxcall.h"
#endif #endif
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
#include "ax25/ax25call.h" #include "inet/ax25call.h"
#endif #endif
struct ddi_proto protocols[] = { struct ddi_proto protocols[] = {
...@@ -53,3 +53,43 @@ 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 @@ ...@@ -4,11 +4,9 @@
* but it eventually might move to an upper directory of * but it eventually might move to an upper directory of
* the system. * 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> * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
* Unused pieces nobbled.
*/ */
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -20,9 +18,6 @@ ...@@ -20,9 +18,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/ddi.h> #include <linux/ddi.h>
#include <linux/interrupt.h>
#include "socket/dev.h"
#undef DDI_DEBUG #undef DDI_DEBUG
...@@ -33,32 +28,64 @@ ...@@ -33,32 +28,64 @@
#endif #endif
extern struct ddi_device devices[]; /* device driver map */
extern struct ddi_proto protocols[]; /* network protocols */ 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 * This is the function that is called by a kernel routine during
* system startup. Its purpose is to walk trough the "devices" * system startup. Its purpose is to walk trough the "devices"
* table (defined above), and to call all moduled defined in it. * table (defined above), and to call all moduled defined in it.
*/ */
void
void ddi_init(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. */ /* First off, kick all configured protocols. */
pro = protocols; pro = protocols;
while (pro->name != NULL) while (pro->name != NULL) {
{
(*pro->init)(pro); (*pro->init)(pro);
pro++; pro++;
} }
dev_init(); /* Done. Now kick all configured device drivers. */
/* Initialize the "Buffer Head" pointers. */ dev = devices;
bh_base[INET_BH].routine = inet_bh; while (dev->title != NULL) {
(*dev->init)(dev);
dev++;
}
/* We're all done... */ /* We're all done... */
} }
...@@ -7,9 +7,6 @@ ...@@ -7,9 +7,6 @@
# #
# Note 2! The CFLAGS definition is now in the main makefile... # Note 2! The CFLAGS definition is now in the main makefile...
CFLAGS := $(CFLAGS) -I../socket -I..
CPP := $(CPP) -I../socket -I..
.c.o: .c.o:
$(CC) $(CFLAGS) -c -o $*.o $< $(CC) $(CFLAGS) -c -o $*.o $<
.s.o: .s.o:
...@@ -18,8 +15,10 @@ CPP := $(CPP) -I../socket -I.. ...@@ -18,8 +15,10 @@ CPP := $(CPP) -I../socket -I..
$(CC) $(CFLAGS) -S -o $*.s $< $(CC) $(CFLAGS) -S -o $*.s $<
OBJS = sockinet.o utils.o route.o proc.o timer.o protocol.o loopback.o \ OBJS = sock.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 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 ifdef CONFIG_INET
......
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: NOTE:
Drivers for this stack set must be using alloc_skb() not just Drivers for this stack set must be using alloc_skb() not just
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* resolver, like it should be. It will be put in a separate * resolver, like it should be. It will be put in a separate
* directory under 'net', being a protocol of its own. -FvK * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -36,11 +36,6 @@ ...@@ -36,11 +36,6 @@
* Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet. * 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 * Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet
* one. * 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: * To Fix:
* : arp response allocates an skbuff to send. However there is a perfectly * : arp response allocates an skbuff to send. However there is a perfectly
...@@ -69,26 +64,51 @@ ...@@ -69,26 +64,51 @@
#include <asm/segment.h> #include <asm/segment.h>
#include <stdarg.h> #include <stdarg.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "eth.h" #include "eth.h"
#include "ip.h" #include "ip.h"
#include "route.h" #include "route.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "arp.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 #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] = { struct arp_table *arp_tables[ARP_TABLE_SIZE] = {
NULL, NULL,
...@@ -98,25 +118,84 @@ static int arp_proxies=0; /* So we can avoid the proxy arp ...@@ -98,25 +118,84 @@ static int arp_proxies=0; /* So we can avoid the proxy arp
overhead with the usual case of overhead with the usual case of
no proxy arps */ 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; struct sk_buff * volatile arp_q = NULL;
static struct arp_table *arp_lookup(unsigned long addr); static struct arp_table *arp_lookup(unsigned long addr);
static struct arp_table *arp_lookup_proxy(unsigned long addr); static struct arp_table *arp_lookup_proxy(unsigned long addr);
/* /* Dump the ADDRESS bytes of an unknown hardware type. */
* We grab the arp queue, empty it and walk down it adding anything we can't static char *
* resolve back onto the queue. We MUST do things this way as other entries unk_print(unsigned char *ptr, int len)
* may (will) get added as we walk the old list. {
static char buff[32];
char *bufp = buff;
int i;
for (i = 0; i < len; i++)
bufp += sprintf(bufp, "%02X ", (*ptr++ & 0377));
return(buff);
}
/* Dump the ADDRESS bytes of an Ethernet hardware type. */
static char *
eth_aprint(unsigned char *ptr, int len)
{
if (len != ETH_ALEN) return("");
return(eth_print(ptr));
}
/* 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));
}
static void arp_send_q(void) /* This will try to retransmit everything on the queue. */
static void
arp_send_q(void)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct sk_buff *volatile work_q; struct sk_buff *volatile work_q;
...@@ -128,13 +207,14 @@ static void arp_send_q(void) ...@@ -128,13 +207,14 @@ static void arp_send_q(void)
while((skb=skb_dequeue(&work_q))!=NULL) while((skb=skb_dequeue(&work_q))!=NULL)
{ {
IS_SKB(skb); IS_SKB(skb);
skb->magic = 0; /* So everyone knows this is _NOT_ on the arp queue */ skb->magic = 0;
skb->next = NULL;
skb->prev = NULL;
/* Decrement the 'tries' counter. */ /* Decrement the 'tries' counter. */
cli(); cli();
skb->tries--; skb->tries--;
if (skb->tries == 0) if (skb->tries == 0) {
{
/* /*
* Grmpf. * Grmpf.
* We have tried ARP_MAX_TRIES to resolve the IP address * We have tried ARP_MAX_TRIES to resolve the IP address
...@@ -155,13 +235,10 @@ static void arp_send_q(void) ...@@ -155,13 +235,10 @@ static void arp_send_q(void)
/* Can we now complete this packet? */ /* Can we now complete this packet? */
sti(); sti();
if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev)) if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev)) {
{
skb->arp = 1; skb->arp = 1;
skb->dev->queue_xmit(skb, skb->dev, 0); skb->dev->queue_xmit(skb, skb->dev, 0);
} } else {
else
{
/* Alas. Re-queue it... */ /* Alas. Re-queue it... */
skb->magic = ARP_QUEUE_MAGIC; skb->magic = ARP_QUEUE_MAGIC;
skb_queue_head(&arp_q,skb); skb_queue_head(&arp_q,skb);
...@@ -170,11 +247,9 @@ static void arp_send_q(void) ...@@ -170,11 +247,9 @@ static void arp_send_q(void)
} }
/* /* Create and send our response to an ARP request. */
* Create and send our response to an ARP request. static int
*/ arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
{ {
struct arphdr *arp2; struct arphdr *arp2;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -200,19 +275,18 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype) ...@@ -200,19 +275,18 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
sizeof(struct arphdr) + sizeof(struct arphdr) +
(2 * arp1->ar_hln) + (2 * arp1->ar_pln) + (2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
dev->hard_header_len, GFP_ATOMIC); dev->hard_header_len, GFP_ATOMIC);
if (skb == NULL) {
if (skb == NULL)
{
printk("ARP: no memory available for ARP REPLY!\n"); printk("ARP: no memory available for ARP REPLY!\n");
return(1); return(1);
} }
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) + skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
(2 * arp1->ar_pln) + dev->hard_header_len; (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, hlen = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, src, dst, skb->len); ETH_P_ARP, src, dst, skb->len);
if (hlen < 0) if (hlen < 0) {
{
printk("ARP: cannot create HW frame header for REPLY !\n"); printk("ARP: cannot create HW frame header for REPLY !\n");
kfree_skb(skb, FREE_WRITE); kfree_skb(skb, FREE_WRITE);
return(1); return(1);
...@@ -230,12 +304,10 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype) ...@@ -230,12 +304,10 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
arp2->ar_hln = arp1->ar_hln; arp2->ar_hln = arp1->ar_hln;
arp2->ar_pln = arp1->ar_pln; arp2->ar_pln = arp1->ar_pln;
arp2->ar_op = htons(ARPOP_REPLY); arp2->ar_op = htons(ARPOP_REPLY);
if(addrtype==IS_MYADDR) if(addrtype==IS_MYADDR)
memcpy(ptr2, dev->dev_addr, arp2->ar_hln); memcpy(ptr2, dev->dev_addr, arp2->ar_hln);
else /* Proxy arp, so pull from the table */ else /* Proxy arp, so pull from the table */
memcpy(ptr2, apt->ha, arp2->ar_hln); memcpy(ptr2, apt->ha, arp2->ar_hln);
ptr2 += arp2->ar_hln; ptr2 += arp2->ar_hln;
memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln); memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);
ptr2 += arp2->ar_pln; ptr2 += arp2->ar_pln;
...@@ -248,17 +320,18 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype) ...@@ -248,17 +320,18 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
skb->sk = NULL; skb->sk = NULL;
skb->next = NULL; skb->next = NULL;
DPRINTF((DBG_ARP, ">>"));
arp_print(arp2);
/* Queue the packet for transmission. */ /* Queue the packet for transmission. */
dev->queue_xmit(skb, dev, 0); dev->queue_xmit(skb, dev, 0);
return(0); return(0);
} }
/* /* This will find an entry in the ARP table by looking at the IP address. */
* This will find an entry in the ARP table by looking at the IP address. static struct arp_table *
*/ arp_lookup(unsigned long paddr)
static struct arp_table *arp_lookup(unsigned long paddr)
{ {
struct arp_table *apt; struct arp_table *apt;
unsigned long hash; unsigned long hash;
...@@ -266,8 +339,7 @@ static struct arp_table *arp_lookup(unsigned long paddr) ...@@ -266,8 +339,7 @@ static struct arp_table *arp_lookup(unsigned long paddr)
DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr))); DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));
/* We don't want to ARP ourselves. */ /* We don't want to ARP ourselves. */
if (chk_addr(paddr) == IS_MYADDR) if (chk_addr(paddr) == IS_MYADDR) {
{
printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr)); printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr));
return(NULL); return(NULL);
} }
...@@ -276,10 +348,8 @@ static struct arp_table *arp_lookup(unsigned long paddr) ...@@ -276,10 +348,8 @@ static struct arp_table *arp_lookup(unsigned long paddr)
hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
cli(); cli();
apt = arp_tables[hash]; apt = arp_tables[hash];
while(apt != NULL) while(apt != NULL) {
{ if (apt->ip == paddr) {
if (apt->ip == paddr)
{
sti(); sti();
return(apt); return(apt);
} }
...@@ -290,10 +360,7 @@ static struct arp_table *arp_lookup(unsigned long paddr) ...@@ -290,10 +360,7 @@ static struct arp_table *arp_lookup(unsigned long paddr)
} }
/* /* 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) static struct arp_table *arp_lookup_proxy(unsigned long paddr)
{ {
struct arp_table *apt; struct arp_table *apt;
...@@ -305,10 +372,8 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr) ...@@ -305,10 +372,8 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
cli(); cli();
apt = arp_tables[hash]; apt = arp_tables[hash];
while(apt != NULL) while(apt != NULL) {
{ if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) {
if (apt->ip == paddr && (apt->flags & ATF_PUBL) )
{
sti(); sti();
return(apt); return(apt);
} }
...@@ -319,11 +384,9 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr) ...@@ -319,11 +384,9 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
} }
/* /* Delete an ARP mapping entry in the cache. */
* Delete an ARP mapping entry in the cache. void
*/ arp_destroy(unsigned long paddr)
static void arp_destructor(unsigned long paddr, int force)
{ {
struct arp_table *apt; struct arp_table *apt;
struct arp_table **lapt; struct arp_table **lapt;
...@@ -332,8 +395,7 @@ static void arp_destructor(unsigned long paddr, int force) ...@@ -332,8 +395,7 @@ static void arp_destructor(unsigned long paddr, int force)
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. */ /* We cannot destroy our own ARP entry. */
if (chk_addr(paddr) == IS_MYADDR) if (chk_addr(paddr) == IS_MYADDR) {
{
DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n", DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n",
in_ntoa(paddr))); in_ntoa(paddr)));
return; return;
...@@ -342,12 +404,8 @@ static void arp_destructor(unsigned long paddr, int force) ...@@ -342,12 +404,8 @@ static void arp_destructor(unsigned long paddr, int force)
cli(); cli();
lapt = &arp_tables[hash]; lapt = &arp_tables[hash];
while ((apt = *lapt) != NULL) while ((apt = *lapt) != NULL) {
{ if (apt->ip == paddr) {
if (apt->ip == paddr)
{
if((apt->flags&ATF_PERM) && !force)
return;
*lapt = apt->next; *lapt = apt->next;
if(apt->flags&ATF_PUBL) if(apt->flags&ATF_PUBL)
arp_proxies--; arp_proxies--;
...@@ -360,37 +418,20 @@ static void arp_destructor(unsigned long paddr, int force) ...@@ -360,37 +418,20 @@ static void arp_destructor(unsigned long paddr, int force)
sti(); sti();
} }
/*
* Kill an entry - eg for ioctl()
*/
void arp_destroy(unsigned long paddr) /* Create an ARP entry. The caller should check for duplicates! */
{ static struct arp_table *
arp_destructor(paddr,1); arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
}
/*
* Delete a possibly invalid entry (see timer.c)
*/
void arp_destroy_maybe(unsigned long paddr)
{
arp_destructor(paddr,0);
}
/*
* Create an ARP entry. The caller should check for duplicates!
*/
static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
{ {
struct arp_table *apt; struct arp_table *apt;
unsigned long hash; 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); apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
if (apt == NULL) if (apt == NULL) {
{
printk("ARP: no memory available for new ARP entry!\n"); printk("ARP: no memory available for new ARP entry!\n");
return(NULL); return(NULL);
} }
...@@ -420,7 +461,8 @@ static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, in ...@@ -420,7 +461,8 @@ 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 * one of our own IP addresses), we set up and send out an ARP REPLY
* packet to the sender. * 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 arphdr *arp;
struct arp_table *tbl; struct arp_table *tbl;
...@@ -429,7 +471,9 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -429,7 +471,9 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
int ret; int ret;
int addr_hint; int addr_hint;
DPRINTF((DBG_ARP, "<<\n"));
arp = skb->h.arp; arp = skb->h.arp;
arp_print(arp);
/* If this test doesn't pass, its not IP. Might be DECNET or friends */ /* 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)) if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
...@@ -456,27 +500,20 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -456,27 +500,20 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short);
memcpy(&src, ptr + arp->ar_hln, arp->ar_pln); memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);
tbl = arp_lookup(src); tbl = arp_lookup(src);
if (tbl != NULL) if (tbl != NULL) {
{
DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src))); DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));
memcpy(tbl->ha, ptr, arp->ar_hln); memcpy(tbl->ha, ptr, arp->ar_hln);
tbl->hlen = arp->ar_hln; tbl->hlen = arp->ar_hln;
tbl->flags |= ATF_COM; tbl->flags |= ATF_COM;
tbl->last_used = jiffies; tbl->last_used = jiffies;
} } else {
else
{
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if (chk_addr(dst) != IS_MYADDR) if (chk_addr(dst) != IS_MYADDR) {
{
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} } else {
else
{
tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd); tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);
if (tbl == NULL) if (tbl == NULL) {
{
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} }
...@@ -494,8 +531,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -494,8 +531,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* OK, we used that part of the info. Now check if the * OK, we used that part of the info. Now check if the
* request was an ARP REQUEST for one of our own addresses.. * request was an ARP REQUEST for one of our own addresses..
*/ */
if (arp->ar_op != NET16(ARPOP_REQUEST)) if (arp->ar_op != NET16(ARPOP_REQUEST)) {
{
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} }
...@@ -504,15 +540,14 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -504,15 +540,14 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* A broadcast arp, ignore it * A broadcast arp, ignore it
*/ */
if(chk_addr(dst)==IS_BROADCAST) if((dst&0xFF)==0xFF)
{ {
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return 0; return 0;
} }
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
{
DPRINTF((DBG_ARP, "ARP: request was not for me!\n")); DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
...@@ -528,11 +563,9 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -528,11 +563,9 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
} }
/* /* Create and send an ARP REQUEST packet. */
* Create and send an ARP REQUEST packet. void
*/ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct arphdr *arp; struct arphdr *arp;
...@@ -547,24 +580,24 @@ void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr) ...@@ -547,24 +580,24 @@ void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
sizeof(struct arphdr) + (2 * dev->addr_len) + sizeof(struct arphdr) + (2 * dev->addr_len) +
dev->hard_header_len + dev->hard_header_len +
(2 * 4 /* arp->plen */), GFP_ATOMIC); (2 * 4 /* arp->plen */), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL) {
{
printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr)); printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
return; return;
} }
/* Fill in the request. */ /* Fill in the request. */
skb->sk = NULL; skb->sk = NULL;
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) + skb->len = sizeof(struct arphdr) +
dev->hard_header_len + (2 * dev->addr_len) + 8; dev->hard_header_len + (2 * dev->addr_len) + 8;
skb->mem_len = sizeof(struct sk_buff) + skb->len;
skb->arp = 1; skb->arp = 1;
skb->dev = dev; skb->dev = dev;
skb->next = NULL; skb->next = NULL;
skb->free = 1; skb->free = 1;
tmp = dev->hard_header((unsigned char *)(skb+1), dev, tmp = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, 0, saddr, skb->len); ETH_P_ARP, 0, saddr, skb->len);
if (tmp < 0) if (tmp < 0) {
{
kfree_skb(skb,FREE_WRITE); kfree_skb(skb,FREE_WRITE);
return; return;
} }
...@@ -588,21 +621,24 @@ void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr) ...@@ -588,21 +621,24 @@ void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
ptr += arp->ar_hln; ptr += arp->ar_hln;
memcpy(ptr, &paddr, arp->ar_pln); memcpy(ptr, &paddr, arp->ar_pln);
DPRINTF((DBG_ARP, ">>\n"));
arp_print(arp);
dev->queue_xmit(skb, dev, 0); dev->queue_xmit(skb, dev, 0);
} }
/* /* Find an ARP mapping in the cache. If not found, post a REQUEST. */
* 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,
int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
unsigned long saddr) unsigned long saddr)
{ {
struct arp_table *apt; struct arp_table *apt;
switch(chk_addr(paddr)) 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: case IS_MYADDR:
memcpy(haddr, dev->dev_addr, dev->addr_len); memcpy(haddr, dev->dev_addr, dev->addr_len);
return(0); return(0);
...@@ -612,22 +648,18 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -612,22 +648,18 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
} }
apt = arp_lookup(paddr); apt = arp_lookup(paddr);
if (apt != NULL) if (apt != NULL) {
{
/* /*
* Make sure it's not too old. If it is too old, we will * 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 * just pretend we did not find it, and then arp_send will
* verify the address for us. * verify the address for us.
*/ */
if ((apt->flags & ATF_PERM) || if ((!(apt->flags & ATF_PERM)) ||
(apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) (!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
{
apt->last_used = jiffies; apt->last_used = jiffies;
memcpy(haddr, apt->ha, dev->addr_len); memcpy(haddr, apt->ha, dev->addr_len);
return(0); return(0);
} } else {
else
{
DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n", DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",
in_ntoa(apt->ip))); in_ntoa(apt->ip)));
} }
...@@ -636,8 +668,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -636,8 +668,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
/* /*
* This assume haddr are at least 4 bytes. * This assume haddr are at least 4 bytes.
* If this isn't true we can use a lookup table, one for every dev. * 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. */ /* If we didn't find an entry, we will try to send an ARP packet. */
...@@ -647,25 +679,25 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -647,25 +679,25 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
} }
/* /* Add an entry to the ARP cache. Check for dupes! */
* Add an entry to the ARP cache. Check for dupes! void
*/ arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
void arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
{ {
struct arp_table *apt; 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... */ /* This is probably a good check... */
if (addr == 0) if (addr == 0) {
{
printk("ARP: add: will not add entry for 0.0.0.0 !\n"); printk("ARP: add: will not add entry for 0.0.0.0 !\n");
return; return;
} }
/* First see if the address is already in the table. */ /* First see if the address is already in the table. */
apt = arp_lookup(addr); apt = arp_lookup(addr);
if (apt != NULL) if (apt != NULL) {
{
DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr))); DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));
apt->last_used = jiffies; apt->last_used = jiffies;
memcpy(apt->ha, haddr , dev->addr_len); memcpy(apt->ha, haddr , dev->addr_len);
...@@ -675,40 +707,35 @@ void arp_add(unsigned long addr, unsigned char *haddr, struct device *dev) ...@@ -675,40 +707,35 @@ void arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
} }
/* /* Create an ARP entry for a device's broadcast address. */
* Create an ARP entry for a device's broadcast address. void
*/ arp_add_broad(unsigned long addr, struct device *dev)
void arp_add_broad(unsigned long addr, struct device *dev)
{ {
struct arp_table *apt; struct arp_table *apt;
arp_add(addr, dev->broadcast, dev); arp_add(addr, dev->broadcast, dev);
apt = arp_lookup(addr); apt = arp_lookup(addr);
if (apt != NULL) if (apt != NULL) {
{
apt->flags |= ATF_PERM; apt->flags |= ATF_PERM;
} }
} }
/* Queue an IP packet, while waiting for the ARP reply packet. */ /* 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(); cli();
skb->tries = ARP_MAX_TRIES; skb->tries = ARP_MAX_TRIES;
if (skb->next != NULL) if (skb->next != NULL) {
{
sti(); sti();
printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic); printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
return; return;
} }
skb_queue_tail(&arp_q,skb); skb_queue_tail(&arp_q,skb);
skb->magic = ARP_QUEUE_MAGIC; skb->magic = ARP_QUEUE_MAGIC;
restore_flags(flags); sti();
} }
...@@ -727,8 +754,8 @@ void arp_queue(struct sk_buff *skb) ...@@ -727,8 +754,8 @@ void arp_queue(struct sk_buff *skb)
* *
* Perhaps we should redo PROCfs to handle larger buffers? Michael? * Perhaps we should redo PROCfs to handle larger buffers? Michael?
*/ */
int
int arp_get_info(char *buffer) arp_get_info(char *buffer)
{ {
struct arpreq *req; struct arpreq *req;
struct arp_table *apt; struct arp_table *apt;
...@@ -738,15 +765,12 @@ int arp_get_info(char *buffer) ...@@ -738,15 +765,12 @@ int arp_get_info(char *buffer)
/* Loop over the ARP table and copy structures to the buffer. */ /* Loop over the ARP table and copy structures to the buffer. */
pos = buffer; pos = buffer;
i = 0; i = 0;
for (i = 0; i < ARP_TABLE_SIZE; i++) for (i = 0; i < ARP_TABLE_SIZE; i++) {
{
cli(); cli();
apt = arp_tables[i]; apt = arp_tables[i];
sti(); sti();
while (apt != NULL) while (apt != NULL) {
{ if (pos < (buffer + 4000)) {
if (pos < (buffer + 4000))
{
req = (struct arpreq *) pos; req = (struct arpreq *) pos;
memset((char *) req, 0, sizeof(struct arpreq)); memset((char *) req, 0, sizeof(struct arpreq));
req->arp_pa.sa_family = AF_INET; req->arp_pa.sa_family = AF_INET;
...@@ -765,11 +789,9 @@ int arp_get_info(char *buffer) ...@@ -765,11 +789,9 @@ int arp_get_info(char *buffer)
} }
/* /* Set (create) an ARP cache entry. */
* Set (create) an ARP cache entry. static int
*/ arp_req_set(struct arpreq *req)
static int arp_req_set(struct arpreq *req)
{ {
struct arpreq r; struct arpreq r;
struct arp_table *apt; struct arp_table *apt;
...@@ -778,8 +800,7 @@ static int arp_req_set(struct arpreq *req) ...@@ -778,8 +800,7 @@ static int arp_req_set(struct arpreq *req)
/* We only understand about IP addresses... */ /* We only understand about IP addresses... */
memcpy_fromfs(&r, req, sizeof(r)); memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET) if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
return(-EPFNOSUPPORT);
/* /*
* Find out about the hardware type. * Find out about the hardware type.
...@@ -787,35 +808,26 @@ static int arp_req_set(struct arpreq *req) ...@@ -787,35 +808,26 @@ static int arp_req_set(struct arpreq *req)
* assume that a "not set" value (i.e. 0) means Ethernet. * assume that a "not set" value (i.e. 0) means Ethernet.
*/ */
si = (struct sockaddr_in *) &r.arp_pa; si = (struct sockaddr_in *) &r.arp_pa;
switch(r.arp_ha.sa_family) switch(r.arp_ha.sa_family) {
{
case 0: case 0:
case ARPHRD_ETHER: case ARPHRD_ETHER:
htype = ARPHRD_ETHER; htype = ARPHRD_ETHER;
hlen = ETH_ALEN; hlen = ETH_ALEN;
break; break;
case ARPHRD_AX25:
htype = ARPHRD_AX25;
hlen = 7;
break;
default: default:
return(-EPFNOSUPPORT); return(-EPFNOSUPPORT);
} }
/* Is there an existing entry for this address? */ /* Is there an existing entry for this address? */
if (si->sin_addr.s_addr == 0) if (si->sin_addr.s_addr == 0) {
{
printk("ARP: SETARP: requested PA is 0.0.0.0 !\n"); printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
return(-EINVAL); return(-EINVAL);
} }
apt = arp_lookup(si->sin_addr.s_addr); apt = arp_lookup(si->sin_addr.s_addr);
if (apt == NULL) if (apt == NULL) {
{
apt = arp_create(si->sin_addr.s_addr, apt = arp_create(si->sin_addr.s_addr,
(unsigned char *) r.arp_ha.sa_data, hlen, htype); (unsigned char *) r.arp_ha.sa_data, hlen, htype);
if (apt == NULL) if (apt == NULL) return(-ENOMEM);
return(-ENOMEM);
} }
/* We now have a pointer to an ARP entry. Update it! */ /* We now have a pointer to an ARP entry. Update it! */
...@@ -829,11 +841,9 @@ static int arp_req_set(struct arpreq *req) ...@@ -829,11 +841,9 @@ static int arp_req_set(struct arpreq *req)
} }
/* /* Get an ARP cache entry. */
* Get an ARP cache entry. static int
*/ arp_req_get(struct arpreq *req)
static int arp_req_get(struct arpreq *req)
{ {
struct arpreq r; struct arpreq r;
struct arp_table *apt; struct arp_table *apt;
...@@ -841,14 +851,12 @@ static int arp_req_get(struct arpreq *req) ...@@ -841,14 +851,12 @@ static int arp_req_get(struct arpreq *req)
/* We only understand about IP addresses... */ /* We only understand about IP addresses... */
memcpy_fromfs(&r, req, sizeof(r)); memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET) if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
return(-EPFNOSUPPORT);
/* Is there an existing entry for this address? */ /* Is there an existing entry for this address? */
si = (struct sockaddr_in *) &r.arp_pa; si = (struct sockaddr_in *) &r.arp_pa;
apt = arp_lookup(si->sin_addr.s_addr); apt = arp_lookup(si->sin_addr.s_addr);
if (apt == NULL) if (apt == NULL) return(-ENXIO);
return(-ENXIO);
/* We found it; copy into structure. */ /* We found it; copy into structure. */
memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen); memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);
...@@ -860,19 +868,17 @@ static int arp_req_get(struct arpreq *req) ...@@ -860,19 +868,17 @@ static int arp_req_get(struct arpreq *req)
} }
/* /* Delete an ARP cache entry. */
* Delete an ARP cache entry. static int
*/ arp_req_del(struct arpreq *req)
static int arp_req_del(struct arpreq *req)
{ {
struct arpreq r; struct arpreq r;
struct sockaddr_in *si; struct sockaddr_in *si;
/* We only understand about IP addresses... */ /* We only understand about IP addresses... */
memcpy_fromfs(&r, req, sizeof(r)); memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET) if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
return(-EPFNOSUPPORT);
si = (struct sockaddr_in *) &r.arp_pa; si = (struct sockaddr_in *) &r.arp_pa;
/* The system cope with this but splats up a nasty kernel message /* The system cope with this but splats up a nasty kernel message
...@@ -886,15 +892,12 @@ static int arp_req_del(struct arpreq *req) ...@@ -886,15 +892,12 @@ static int arp_req_del(struct arpreq *req)
} }
/* /* Handle an ARP layer I/O control request. */
* Handle an ARP layer I/O control request. int
*/ arp_ioctl(unsigned int cmd, void *arg)
int arp_ioctl(unsigned int cmd, void *arg)
{ {
int err; int err;
switch(cmd) switch(cmd) {
{
case DDIOCSDBG: case DDIOCSDBG:
return(dbg_ioctl(arg, DBG_ARP)); return(dbg_ioctl(arg, DBG_ARP));
case SIOCDARP: case SIOCDARP:
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Definitions for the ARP protocol module. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -26,31 +26,29 @@ ...@@ -26,31 +26,29 @@
#define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */ #define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */
/* /* This structure defines the ARP mapping cache. */
* This structure defines the ARP mapping cache. struct arp_table {
*/
struct arp_table
{
struct arp_table *next; struct arp_table *next;
volatile unsigned long last_used; volatile unsigned long last_used;
unsigned int flags; unsigned int flags;
#if 1
unsigned long ip; 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 ha[MAX_ADDR_LEN];
unsigned char hlen; unsigned char hlen;
unsigned char htype; 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 struct sk_buff *arp_q;
extern void arp_destroy(unsigned long paddr); 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, extern int arp_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt); struct packet_type *pt);
extern int arp_find(unsigned char *haddr, unsigned long paddr, extern int arp_find(unsigned char *haddr, unsigned long paddr,
......
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
* Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff. * 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 * 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. * 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/config.h>
...@@ -138,13 +136,6 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, ...@@ -138,13 +136,6 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
return skb; 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) void skb_free_datagram(struct sk_buff *skb)
{ {
unsigned long flags; unsigned long flags;
...@@ -194,11 +185,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait) ...@@ -194,11 +185,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return(0); return(0);
case SEL_OUT: case SEL_OUT:
if(sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE) if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
return(1);
}
if(sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
{ {
return(1); return(1);
} }
......
...@@ -790,6 +790,7 @@ static inline int bad_mask(unsigned long mask, unsigned long addr) ...@@ -790,6 +790,7 @@ static inline int bad_mask(unsigned long mask, unsigned long addr)
return 0; return 0;
} }
/* Perform the SIOCxIFxxx calls. */ /* Perform the SIOCxIFxxx calls. */
static int static int
dev_ifsioc(void *arg, unsigned int getset) dev_ifsioc(void *arg, unsigned int getset)
......
/*
* 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;
}
/*
* 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 */
...@@ -5,27 +5,24 @@ ...@@ -5,27 +5,24 @@
* *
* Ethernet-type device handling. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk> * Mark Evans, <evansmp@uhura.aston.ac.uk>
* *
* Fixes: * Fixes:
* Mr Linux : Arp problems. * Mr Linux : Arp problems
* Alan Cox : Generic queue tidyup (very tiny here). * Alan Cox : Generic queue tidyup (very tiny here)
* Alan Cox : eth_header ntohs should be htons. * Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and * Alan Cox : eth_rebuild_header missing an htons and
* minor other things. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -36,19 +33,18 @@ ...@@ -36,19 +33,18 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "eth.h" #include "eth.h"
#include "ip.h" #include "ip.h"
#include "route.h" #include "route.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include <linux/errno.h> #include <linux/errno.h>
#include "arp.h" #include "arp.h"
#ifdef ETH_DEBUG
/* Display an Ethernet address in readable format. */ /* Display an Ethernet address in readable format. */
char *eth_print(unsigned char *ptr) char *eth_print(unsigned char *ptr)
{ {
...@@ -61,16 +57,32 @@ char *eth_print(unsigned char *ptr) ...@@ -61,16 +57,32 @@ char *eth_print(unsigned char *ptr)
); );
return(buff); return(buff);
} }
#endif
#ifdef ETH_DEBUG void eth_setup(char *str, int *ints)
{
/* struct device *d = dev_base;
* Display the contents of the Ethernet MAC header.
*/ 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; if (inet_debug != DBG_ETH) return;
...@@ -79,17 +91,10 @@ void eth_dump(struct ethhdr *eth) ...@@ -79,17 +91,10 @@ void eth_dump(struct ethhdr *eth)
printk("TYPE = %04X\n", ntohs(eth->h_proto)); 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) unsigned long daddr, unsigned long saddr, unsigned len)
{ {
struct ethhdr *eth; struct ethhdr *eth;
...@@ -102,8 +107,7 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type, ...@@ -102,8 +107,7 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
eth->h_proto = htons(type); eth->h_proto = htons(type);
/* We don't ARP for the LOOPBACK device... */ /* We don't ARP for the LOOPBACK device... */
if (dev->flags & IFF_LOOPBACK) if (dev->flags & IFF_LOOPBACK) {
{
DPRINTF((DBG_DEV, "ETH: No header for loopback\n")); DPRINTF((DBG_DEV, "ETH: No header for loopback\n"));
memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
memset(eth->h_dest, 0, dev->addr_len); memset(eth->h_dest, 0, dev->addr_len);
...@@ -111,21 +115,16 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type, ...@@ -111,21 +115,16 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
} }
/* Check if we can use the MAC BROADCAST address. */ /* Check if we can use the MAC BROADCAST address. */
if (chk_addr(daddr) == IS_BROADCAST) if (chk_addr(daddr) == IS_BROADCAST) {
{
DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n")); DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
memcpy(eth->h_dest, dev->broadcast, dev->addr_len); memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
return(dev->hard_header_len); return(dev->hard_header_len);
} }
/*
* We disable interrupts here to avoid a race if the ARP
* reply is too quick.
*/
cli(); cli();
memcpy(eth->h_source, &saddr, 4); memcpy(eth->h_source, &saddr, 4);
/* No. Ask ARP to resolve the Ethernet address. */ /* No. Ask ARP to resolve the Ethernet address. */
if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr/* saddr */)) if (arp_find(eth->h_dest, daddr, dev, saddr))
{ {
sti(); sti();
if(type!=ETH_P_IP) if(type!=ETH_P_IP)
...@@ -142,14 +141,9 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type, ...@@ -142,14 +141,9 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
} }
/* /* Rebuild the Ethernet MAC header. */
* Rebuild the Ethernet MAC header. int
* eth_rebuild_header(void *buff, struct device *dev)
* 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)
{ {
struct ethhdr *eth; struct ethhdr *eth;
unsigned long src, dst; unsigned long src, dst;
...@@ -161,19 +155,15 @@ int eth_rebuild_header(void *buff, struct device *dev) ...@@ -161,19 +155,15 @@ int eth_rebuild_header(void *buff, struct device *dev)
DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src))); DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst))); 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(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 */)) if (arp_find(eth->h_dest, dst, dev, src)) return(1);
/* Still not known */
return(1);
memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return(0); return(0);
} }
/* /* Add an ARP entry for a host on this interface. */
* Add an ARP entry for a host on this interface. void
*/ eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
{ {
struct ethhdr *eth; struct ethhdr *eth;
...@@ -182,19 +172,9 @@ void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev) ...@@ -182,19 +172,9 @@ void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
} }
/* /* Determine the packet's protocol ID. */
* Determine the packet's protocol ID. unsigned short
* eth_type_trans(struct sk_buff *skb, struct device *dev)
* 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)
{ {
struct ethhdr *eth; struct ethhdr *eth;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Internet Control Message Protocol (ICMP) * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
* Fixes: * Fixes:
* Alan Cox : Generic queue usage. * Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected * Gerhard Koerting: ICMP addressing corrected
* Tegge : Subnet problems
* *
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -22,7 +21,6 @@ ...@@ -22,7 +21,6 @@
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -30,14 +28,14 @@ ...@@ -30,14 +28,14 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "route.h" #include "route.h"
#include "protocol.h" #include "protocol.h"
#include "icmp.h" #include "icmp.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -65,30 +63,21 @@ struct icmp_err icmp_err_convert[] = { ...@@ -65,30 +63,21 @@ struct icmp_err icmp_err_convert[] = {
}; };
#ifdef ICMP_DEBUG
/* Display the contents of an ICMP header. */ /* Display the contents of an ICMP header. */
static void static void
print_icmp(struct icmphdr *icmph) print_icmp(struct icmphdr *icmph)
{ {
if (inet_debug != DBG_ICMP) if (inet_debug != DBG_ICMP) return;
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); 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. */
* Send an ICMP message. void
* icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
* 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)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct iphdr *iph; struct iphdr *iph;
...@@ -105,13 +94,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) ...@@ -105,13 +94,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
sizeof(struct iphdr) + 8; /* amount of header to return */ sizeof(struct iphdr) + 8; /* amount of header to return */
skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC); 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) if (skb == NULL)
return; return;
skb->sk = NULL; skb->sk = NULL;
skb->mem_addr = skb;
skb->mem_len = len;
len -= sizeof(struct sk_buff); len -= sizeof(struct sk_buff);
/* Find the IP header. */ /* Find the IP header. */
...@@ -120,9 +108,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) ...@@ -120,9 +108,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
/* Build Layer 2-3 headers for message back to source. */ /* Build Layer 2-3 headers for message back to source. */
offset = ip_build_header(skb, dev->pa_addr, iph->saddr, offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
&dev, IPPROTO_ICMP, NULL, len, 25, IPTOS_RELIABILITY); &dev, IPPROTO_ICMP, NULL, len);
if (offset < 0) if (offset < 0) {
{
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return; return;
...@@ -140,20 +127,17 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) ...@@ -140,20 +127,17 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
icmph->checksum = ip_compute_csum((unsigned char *)icmph, icmph->checksum = ip_compute_csum((unsigned char *)icmph,
sizeof(struct icmphdr) + sizeof(struct iphdr) + 8); sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
#ifdef ICMP_DEBUG
DPRINTF((DBG_ICMP, ">>\n")); DPRINTF((DBG_ICMP, ">>\n"));
print_icmp(icmph); print_icmp(icmph);
#endif
/* Send it and free it. */ /* Send it and free it. */
ip_queue_xmit(NULL, dev, skb, 1); ip_queue_xmit(NULL, dev, skb, 1);
} }
/* /* Handle ICMP_UNREACH and ICMP_QUENCH. */
* Handle ICMP_UNREACH and ICMP_QUENCH. static void
*/ icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
{ {
struct inet_protocol *ipprot; struct inet_protocol *ipprot;
struct iphdr *iph; struct iphdr *iph;
...@@ -162,8 +146,7 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) ...@@ -162,8 +146,7 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
err = (icmph->type << 8) | icmph->code; err = (icmph->type << 8) | icmph->code;
iph = (struct iphdr *) (icmph + 1); iph = (struct iphdr *) (icmph + 1);
switch(icmph->code & 7) switch(icmph->code & 7) {
{
case ICMP_NET_UNREACH: case ICMP_NET_UNREACH:
DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n", DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
in_ntoa(iph->daddr))); in_ntoa(iph->daddr)));
...@@ -198,15 +181,13 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) ...@@ -198,15 +181,13 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
/* This can change while we are doing it. */ /* This can change while we are doing it. */
ipprot = (struct inet_protocol *) inet_protos[hash]; ipprot = (struct inet_protocol *) inet_protos[hash];
while(ipprot != NULL) while(ipprot != NULL) {
{
struct inet_protocol *nextip; struct inet_protocol *nextip;
nextip = (struct inet_protocol *) ipprot->next; nextip = (struct inet_protocol *) ipprot->next;
/* Pass it off to everyone who wants it. */ /* Pass it off to everyone who wants it. */
if (iph->protocol == ipprot->protocol && ipprot->err_handler) if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
{
ipprot->err_handler(err, (unsigned char *)(icmph + 1), ipprot->err_handler(err, (unsigned char *)(icmph + 1),
iph->daddr, iph->saddr, ipprot); iph->daddr, iph->saddr, ipprot);
} }
...@@ -218,19 +199,16 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) ...@@ -218,19 +199,16 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
} }
/* /* Handle ICMP_REDIRECT. */
* Handle ICMP_REDIRECT. static void
*/ icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
{ {
struct iphdr *iph; struct iphdr *iph;
unsigned long ip; unsigned long ip;
iph = (struct iphdr *) (icmph + 1); iph = (struct iphdr *) (icmph + 1);
ip = iph->daddr; ip = iph->daddr;
switch(icmph->code & 7) switch(icmph->code & 7) {
{
case ICMP_REDIR_NET: case ICMP_REDIR_NET:
rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
ip, 0, icmph->un.gateway, dev); ip, 0, icmph->un.gateway, dev);
...@@ -254,7 +232,8 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev ...@@ -254,7 +232,8 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
/* Handle ICMP_ECHO ("ping") requests. */ /* 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, unsigned long saddr, unsigned long daddr, int len,
struct options *opt) struct options *opt)
{ {
...@@ -264,20 +243,20 @@ static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device ...@@ -264,20 +243,20 @@ static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device
size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
skb2 = alloc_skb(size, GFP_ATOMIC); skb2 = alloc_skb(size, GFP_ATOMIC);
if (skb2 == NULL) if (skb2 == NULL) {
{
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return; return;
} }
skb2->sk = NULL; skb2->sk = NULL;
skb2->mem_addr = skb2;
skb2->mem_len = size;
skb2->free = 1; skb2->free = 1;
/* Build Layer 2-3 headers for message back to source */ /* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev, offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY); IPPROTO_ICMP, opt, len);
if (offset < 0) if (offset < 0) {
{
printk("ICMP: Could not build IP Header for ICMP ECHO Response\n"); printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
kfree_skb(skb2,FREE_WRITE); kfree_skb(skb2,FREE_WRITE);
skb->sk = NULL; skb->sk = NULL;
...@@ -304,11 +283,9 @@ static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device ...@@ -304,11 +283,9 @@ static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device
} }
/* /* Handle the ICMP INFORMATION REQUEST. */
* Handle the ICMP INFORMATION REQUEST. static void
*/ icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len, unsigned long saddr, unsigned long daddr, int len,
struct options *opt) struct options *opt)
{ {
...@@ -318,11 +295,9 @@ static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device ...@@ -318,11 +295,9 @@ static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device
} }
/* /* Handle ICMP_ADRESS_MASK requests. */
* Handle ICMP_ADRESS_MASK requests. static void
*/ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len, unsigned long saddr, unsigned long daddr, int len,
struct options *opt) struct options *opt)
{ {
...@@ -332,20 +307,20 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi ...@@ -332,20 +307,20 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi
size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
skb2 = alloc_skb(size, GFP_ATOMIC); skb2 = alloc_skb(size, GFP_ATOMIC);
if (skb2 == NULL) if (skb2 == NULL) {
{
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return; return;
} }
skb2->sk = NULL; skb2->sk = NULL;
skb2->mem_addr = skb2;
skb2->mem_len = size;
skb2->free = 1; skb2->free = 1;
/* Build Layer 2-3 headers for message back to source */ /* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev, offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY); IPPROTO_ICMP, opt, len);
if (offset < 0) if (offset < 0) {
{
printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n"); printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
kfree_skb(skb2,FREE_WRITE); kfree_skb(skb2,FREE_WRITE);
skb->sk = NULL; skb->sk = NULL;
...@@ -375,11 +350,9 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi ...@@ -375,11 +350,9 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi
} }
/* /* Deal with incoming ICMP packets. */
* Deal with incoming ICMP packets. int
*/ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol) unsigned long saddr, int redo, struct inet_protocol *protocol)
{ {
...@@ -387,8 +360,7 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, ...@@ -387,8 +360,7 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned char *buff; unsigned char *buff;
/* Drop broadcast packets. */ /* Drop broadcast packets. */
if (chk_addr(daddr) == IS_BROADCAST) if (chk_addr(daddr) == IS_BROADCAST) {
{
DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n", DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
in_ntoa(saddr))); in_ntoa(saddr)));
skb1->sk = NULL; skb1->sk = NULL;
...@@ -400,20 +372,17 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, ...@@ -400,20 +372,17 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
icmph = (struct icmphdr *) buff; icmph = (struct icmphdr *) buff;
/* Validate the packet first */ /* Validate the packet first */
if (ip_compute_csum((unsigned char *) icmph, len)) if (ip_compute_csum((unsigned char *) icmph, len)) {
{
/* Failed checksum! */ /* Failed checksum! */
printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr)); printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
skb1->sk = NULL; skb1->sk = NULL;
kfree_skb(skb1, FREE_READ); kfree_skb(skb1, FREE_READ);
return(0); return(0);
} }
#ifdef ICMP_DEBUG
print_icmp(icmph); print_icmp(icmph);
#endif
/* Parse the ICMP message */ /* Parse the ICMP message */
switch(icmph->type) switch(icmph->type) {
{
case ICMP_TIME_EXCEEDED: case ICMP_TIME_EXCEEDED:
case ICMP_DEST_UNREACH: case ICMP_DEST_UNREACH:
case ICMP_SOURCE_QUENCH: case ICMP_SOURCE_QUENCH:
...@@ -458,16 +427,11 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, ...@@ -458,16 +427,11 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
} }
/* /* Perform any ICMP-related I/O control requests. */
* Perform any ICMP-related I/O control requests. int
* icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
* 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)
{ {
switch(cmd) switch(cmd) {
{
case DDIOCSDBG: case DDIOCSDBG:
return(dbg_ioctl((void *) arg, DBG_ICMP)); return(dbg_ioctl((void *) arg, DBG_ICMP));
default: default:
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* The Internet Protocol (IP) module. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -31,14 +31,10 @@ ...@@ -31,14 +31,10 @@
* Gerhard Koerting: IP interface addressing fix. * Gerhard Koerting: IP interface addressing fix.
* Linus Torvalds : More robustness checks * Linus Torvalds : More robustness checks
* Alan Cox : Even more checks: Still not as robust as it ought to be * 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: * To Fix:
* RFC791 states that options are a 'required' feature of an * IP option processing is mostly not needed. ip_forward needs to know about routing rules
* IP implementation. We don't do options at all. * and time stamp but that's about all.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -56,40 +52,31 @@ ...@@ -56,40 +52,31 @@
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "eth.h" #include "eth.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "route.h" #include "route.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "arp.h" #include "arp.h"
#include "icmp.h" #include "icmp.h"
/* #define CONFIG_IP_FORWARD
* These two can normally be left. In olden times the numerous bugs used to #define CONFIG_IP_DEFRAG
* make forwarding go crazy on some nets and fragmentation fragment your
* computer 8-)
*/
#define CONFIG_IP_FORWARD /* Forwarding ? */
#define CONFIG_IP_DEFRAG /* Fragmentation ? */
extern int last_retran; extern int last_retran;
extern void sort_send(struct sock *sk); 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 buff[32];
unsigned char *ptr; unsigned char *ptr;
int addr, len, i; int addr, len, i;
if (inet_debug != DBG_IP) if (inet_debug != DBG_IP) return;
return;
/* Dump the IP header. */ /* Dump the IP header. */
printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n", printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
...@@ -105,19 +92,14 @@ void ip_print(struct iphdr *ip) ...@@ -105,19 +92,14 @@ void ip_print(struct iphdr *ip)
ptr = (unsigned char *)(ip + 1); ptr = (unsigned char *)(ip + 1);
addr = 0; addr = 0;
len = ntohs(ip->tot_len) - (4 * ip->ihl); len = ntohs(ip->tot_len) - (4 * ip->ihl);
while (len > 0) while (len > 0) {
{
printk(" %04X: ", addr); printk(" %04X: ", addr);
for(i = 0; i < 16; i++) for(i = 0; i < 16; i++) {
{ if (len > 0) {
if (len > 0)
{
printk("%02X ", (*ptr & 0xFF)); printk("%02X ", (*ptr & 0xFF));
buff[i] = *ptr++; buff[i] = *ptr++;
if (buff[i] < 32 || buff[i] > 126) buff[i] = '.'; if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
} } else {
else
{
printk(" "); printk(" ");
buff[i] = ' '; buff[i] = ' ';
} }
...@@ -130,17 +112,11 @@ void ip_print(struct iphdr *ip) ...@@ -130,17 +112,11 @@ void ip_print(struct iphdr *ip)
printk(" ----\n\n"); printk(" ----\n\n");
} }
#endif
/* int
* Low level user requests to the IP device. NOT that same as IP layer ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
* socket requests (which also do nothing useful at the moment)
*/
int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
{ {
switch(cmd) switch(cmd) {
{
case DDIOCSDBG: case DDIOCSDBG:
return(dbg_ioctl((void *) arg, DBG_IP)); return(dbg_ioctl((void *) arg, DBG_IP));
default: default:
...@@ -149,64 +125,51 @@ int ip_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -149,64 +125,51 @@ int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
} }
/* /* these two routines will do routining. */
* These two routines will do routing when we have ip options support static void
* (RFC 791 page 18,19) strict_route(struct iphdr *iph, struct options *opt)
*/
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", DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
ipprot->handler, ipprot->protocol, ipprot->copy)); ipprot->handler, ipprot->protocol, ipprot->copy));
} }
/* /* This routine will check to see if we have lost a gateway. */
* This routine will check to see if we have lost a gateway. void
*/ ip_route_check(unsigned long daddr)
void ip_route_check(unsigned long daddr)
{ {
} }
/* #if 0
* This routine puts the options at the end of an ip header. /* this routine puts the options at the end of an ip header. */
*/ static int
build_options(struct iphdr *iph, struct options *opt)
static int build_options(struct iphdr *iph, struct options *opt)
{ {
unsigned char *ptr; unsigned char *ptr;
ptr = (unsigned char *)(iph+1);
/* currently we don't support any options. */ /* currently we don't support any options. */
if(opt==NULL) ptr = (unsigned char *)(iph+1);
{
*ptr = 0; *ptr = 0;
return (1); return (4);
}
else
{
memcpy(ptr,opt->option_data,opt->option_length);
return((opt->option_length+3)/4);
}
} }
#endif
/* /* Take an skb, and fill in the MAC header. */
* 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,
static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
unsigned long saddr) unsigned long saddr)
{ {
unsigned char *ptr; unsigned char *ptr;
...@@ -215,12 +178,10 @@ static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct dev ...@@ -215,12 +178,10 @@ static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct dev
ptr = (unsigned char *)(skb + 1); ptr = (unsigned char *)(skb + 1);
mac = 0; mac = 0;
skb->arp = 1; skb->arp = 1;
if (dev->hard_header) if (dev->hard_header) {
{
mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len); mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
} }
if (mac < 0) if (mac < 0) {
{
mac = -mac; mac = -mac;
skb->arp = 0; skb->arp = 0;
} }
...@@ -235,8 +196,9 @@ static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct dev ...@@ -235,8 +196,9 @@ 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 * protocol knows what it's doing, otherwise it uses the
* routing/ARP tables to select a device struct. * routing/ARP tables to select a device struct.
*/ */
int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, int
struct device **dev, int type, struct options *opt, int len, int ttl,int tos) 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; static struct options optmem;
struct iphdr *iph; struct iphdr *iph;
...@@ -245,7 +207,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -245,7 +207,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
unsigned long raddr; unsigned long raddr;
static int count = 0; static int count = 0;
int tmp; int tmp;
int optlen;
if (saddr == 0) if (saddr == 0)
saddr = my_addr(); saddr = my_addr();
...@@ -257,8 +218,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -257,8 +218,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
buff = (unsigned char *)(skb + 1); buff = (unsigned char *)(skb + 1);
/* See if we need to look up the device. */ /* See if we need to look up the device. */
if (*dev == NULL) if (*dev == NULL) {
{
rt = rt_route(daddr, &optmem); rt = rt_route(daddr, &optmem);
if (rt == NULL) if (rt == NULL)
return(-ENETUNREACH); return(-ENETUNREACH);
...@@ -270,9 +230,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -270,9 +230,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr))); DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
opt = &optmem; opt = &optmem;
} } else {
else
{
/* We still need the address of the first hop. */ /* We still need the address of the first hop. */
rt = rt_route(daddr, &optmem); rt = rt_route(daddr, &optmem);
raddr = (rt == NULL) ? 0 : rt->rt_gateway; raddr = (rt == NULL) ? 0 : rt->rt_gateway;
...@@ -287,70 +245,41 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -287,70 +245,41 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
skb->dev = *dev; skb->dev = *dev;
skb->saddr = saddr; skb->saddr = saddr;
if (skb->sk) if (skb->sk) skb->sk->saddr = saddr;
skb->sk->saddr = saddr;
/* Now build the IP header. */ /* Now build the IP header. */
/* If we are using IPPROTO_RAW, then we don't need an IP header, since /* If we are using IPPROTO_RAW, then we don't need an IP header, since
one is being supplied to us by the user */ one is being supplied to us by the user */
if(type == IPPROTO_RAW) if(type == IPPROTO_RAW) return (tmp);
return (tmp);
iph = (struct iphdr *)buff; iph = (struct iphdr *)buff;
iph->version = 4; iph->version = 4;
iph->tos = tos; iph->tos = 0;
iph->frag_off = 0; iph->frag_off = 0;
iph->ttl = ttl; iph->ttl = 32;
iph->daddr = daddr; iph->daddr = daddr;
iph->saddr = saddr; iph->saddr = saddr;
iph->protocol = type; iph->protocol = type;
iph->ihl = 5; iph->ihl = 5;
iph->id = htons(count++); iph->id = htons(count++);
/* Setup the IP options. Length is in longs.*/ /* Setup the IP options. */
#ifdef Not_Yet_Avail
optlen=build_options(iph, opt); build_options(iph, opt);
iph->ihl+=optlen; #endif
return(20 + tmp + 4*optlen); /* IP header plus MAC header size */ return(20 + tmp); /* IP header plus MAC header size */
} }
/* static int
* Interpret the incoming options do_options(struct iphdr *iph, struct options *opt)
*/
static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device *dev)
{ {
unsigned char *buff; unsigned char *buff;
int done = 0; int done = 0;
int i, len = sizeof(struct iphdr); 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. */ /* Zero out the options. */
opt->record_route.route_size = 0; opt->record_route.route_size = 0;
...@@ -362,17 +291,13 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device ...@@ -362,17 +291,13 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
opt->handling = 0; opt->handling = 0;
opt->stream = 0; opt->stream = 0;
opt->tcc = 0; opt->tcc = 0;
return(0);
/* Advance the pointer to start at the options. */ /* Advance the pointer to start at the options. */
buff = (unsigned char *)(iph + 1); buff = (unsigned char *)(iph + 1);
/* Copy the data */
memcpy(outbuf,buff,opt->option_length);
buff = outbuf;
/* Now start the processing. */ /* Now start the processing. */
while (!done && len < iph->ihl*4) switch(*buff) while (!done && len < iph->ihl*4) switch(*buff) {
{
case IPOPT_END: case IPOPT_END:
done = 1; done = 1;
break; break;
...@@ -382,8 +307,7 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device ...@@ -382,8 +307,7 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
break; break;
case IPOPT_SEC: case IPOPT_SEC:
buff++; buff++;
if (*buff != 11) if (*buff != 11) return(1);
return(1);
buff++; buff++;
opt->security = ntohs(*(unsigned short *)buff); opt->security = ntohs(*(unsigned short *)buff);
buff += 2; buff += 2;
...@@ -397,78 +321,51 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device ...@@ -397,78 +321,51 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
break; break;
case IPOPT_LSRR: case IPOPT_LSRR:
buff++; buff++;
if ((*buff - 3)% 4 != 0) if ((*buff - 3)% 4 != 0) return(1);
return(1); len += *buff;
if(*buff<2)
return(1);
len += (optsiz= *buff);
opt->loose_route.route_size = (*buff -3)/4; opt->loose_route.route_size = (*buff -3)/4;
buff++; buff++;
if (*buff % 4 != 0) if (*buff % 4 != 0) return(1);
return(1);
opt->loose_route.pointer = *buff/4 - 1; opt->loose_route.pointer = *buff/4 - 1;
if(*buff<=optsiz)
*buff+=4; /* Move on a route */
buff++; buff++;
buff++; buff++;
for (i = 0; i < opt->loose_route.route_size; i++) for (i = 0; i < opt->loose_route.route_size; i++) {
{
if(i>=MAX_ROUTE) if(i>=MAX_ROUTE)
return(1); return(1);
if(i==opt->strict_route.pointer)
*(unsigned long *)buff=dev->pa_addr;
opt->loose_route.route[i] = *(unsigned long *)buff; opt->loose_route.route[i] = *(unsigned long *)buff;
buff += 4; buff += 4;
} }
break; break;
case IPOPT_SSRR: case IPOPT_SSRR:
buff++; buff++;
if ((*buff - 3)% 4 != 0) if ((*buff - 3)% 4 != 0) return(1);
return(1); len += *buff;
if(*buff<2)
return(1);
len += (optsiz= *buff);
opt->strict_route.route_size = (*buff -3)/4; opt->strict_route.route_size = (*buff -3)/4;
buff++; buff++;
if (*buff % 4 != 0) if (*buff % 4 != 0) return(1);
return(1);
opt->strict_route.pointer = *buff/4 - 1; opt->strict_route.pointer = *buff/4 - 1;
if(*buff<=optsiz)
*buff+=4;
buff++; buff++;
buff++; buff++;
for (i = 0; i < opt->strict_route.route_size; i++) for (i = 0; i < opt->strict_route.route_size; i++) {
{
if(i>=MAX_ROUTE) if(i>=MAX_ROUTE)
return(1); return(1);
if(i==opt->strict_route.pointer)
*(unsigned long *)buff=dev->pa_addr;
opt->strict_route.route[i] = *(unsigned long *)buff; opt->strict_route.route[i] = *(unsigned long *)buff;
buff += 4; buff += 4;
} }
break; break;
case IPOPT_RR: case IPOPT_RR:
buff++; buff++;
if ((*buff - 3)% 4 != 0) if ((*buff - 3)% 4 != 0) return(1);
return(1); len += *buff;
if(*buff<2)
return(1);
len += (optsiz= *buff);
opt->record_route.route_size = (*buff -3)/4; opt->record_route.route_size = (*buff -3)/4;
buff++; buff++;
if (*buff % 4 != 0) if (*buff % 4 != 0) return(1);
return(1);
opt->record_route.pointer = *buff/4 - 1; opt->record_route.pointer = *buff/4 - 1;
if(*buff+4<=optsiz)
*buff+=4;
buff++; buff++;
buff++; buff++;
for (i = 0; i < opt->record_route.route_size; i++) for (i = 0; i < opt->record_route.route_size; i++) {
{
if(i>=MAX_ROUTE) if(i>=MAX_ROUTE)
return 1; return 1;
if(i==opt->record_route.pointer)
*(unsigned long *)buff=dev->pa_addr;
opt->record_route.route[i] = *(unsigned long *)buff; opt->record_route.route[i] = *(unsigned long *)buff;
buff += 4; buff += 4;
} }
...@@ -480,23 +377,17 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device ...@@ -480,23 +377,17 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
buff += 2; buff += 2;
break; break;
case IPOPT_TIMESTAMP: case IPOPT_TIMESTAMP:
/* FIXME: This one isn't altered correctly yet */
buff++; buff++;
if(*buff<2)
return 1;
len += *buff; len += *buff;
if (*buff % 4 != 0) if (*buff % 4 != 0) return(1);
return(1);
opt->tstamp.len = *buff / 4 - 1; opt->tstamp.len = *buff / 4 - 1;
buff++; buff++;
if ((*buff - 1) % 4 != 0) if ((*buff - 1) % 4 != 0) return(1);
return(1);
opt->tstamp.ptr = (*buff-1)/4; opt->tstamp.ptr = (*buff-1)/4;
buff++; buff++;
opt->tstamp.x.full_char = *buff; opt->tstamp.x.full_char = *buff;
buff++; buff++;
for (i = 0; i < opt->tstamp.len; i++) for (i = 0; i < opt->tstamp.len; i++) {
{
opt->tstamp.data[i] = *(unsigned long *)buff; opt->tstamp.data[i] = *(unsigned long *)buff;
buff += 4; buff += 4;
} }
...@@ -505,30 +396,24 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device ...@@ -505,30 +396,24 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
return(1); return(1);
} }
if (opt->record_route.route_size == 0) if (opt->record_route.route_size == 0) {
{ if (opt->strict_route.route_size != 0) {
if (opt->strict_route.route_size != 0)
{
memcpy(&(opt->record_route), &(opt->strict_route), memcpy(&(opt->record_route), &(opt->strict_route),
sizeof(opt->record_route)); sizeof(opt->record_route));
} } else if (opt->loose_route.route_size != 0) {
else if (opt->loose_route.route_size != 0)
{
memcpy(&(opt->record_route), &(opt->loose_route), memcpy(&(opt->record_route), &(opt->loose_route),
sizeof(opt->record_route)); sizeof(opt->record_route));
} }
} }
if (opt->strict_route.route_size != 0 && if (opt->strict_route.route_size != 0 &&
opt->strict_route.route_size != opt->strict_route.pointer) opt->strict_route.route_size != opt->strict_route.pointer) {
{
strict_route(iph, opt); strict_route(iph, opt);
return(0); return(0);
} }
if (opt->loose_route.route_size != 0 && if (opt->loose_route.route_size != 0 &&
opt->loose_route.route_size != opt->loose_route.pointer) opt->loose_route.route_size != opt->loose_route.pointer) {
{
loose_route(iph, opt); loose_route(iph, opt);
return(0); return(0);
} }
...@@ -536,12 +421,10 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device ...@@ -536,12 +421,10 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
return(0); return(0);
} }
/* /* This is a version of ip_compute_csum() optimized for IP headers, which
* This is a version of ip_compute_csum() optimized for IP headers, which always checksum on 4 octet boundaries. */
* always checksum on 4 octet boundaries. static inline unsigned short
*/ ip_fast_csum(unsigned char * buff, int wlen)
static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
{ {
unsigned long sum = 0; unsigned long sum = 0;
...@@ -568,8 +451,8 @@ static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen) ...@@ -568,8 +451,8 @@ static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
* This routine does all the checksum computations that don't * This routine does all the checksum computations that don't
* require anything special (like copying or special headers). * require anything special (like copying or special headers).
*/ */
unsigned short
unsigned short ip_compute_csum(unsigned char * buff, int len) ip_compute_csum(unsigned char * buff, int len)
{ {
unsigned long sum = 0; unsigned long sum = 0;
...@@ -610,20 +493,16 @@ unsigned short ip_compute_csum(unsigned char * buff, int len) ...@@ -610,20 +493,16 @@ unsigned short ip_compute_csum(unsigned char * buff, int len)
return(sum & 0xffff); return(sum & 0xffff);
} }
/* /* Check the header of an incoming IP datagram. This version is still used in slhc.c. */
* Check the header of an incoming IP datagram. This version is still used in slhc.c. int
*/ ip_csum(struct iphdr *iph)
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. */
* Generate a checksym for an outgoing IP datagram. (RFC791, Page 14) static void
*/ ip_send_check(struct iphdr *iph)
static void ip_send_check(struct iphdr *iph)
{ {
iph->check = 0; iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
...@@ -632,11 +511,7 @@ static void ip_send_check(struct iphdr *iph) ...@@ -632,11 +511,7 @@ static void ip_send_check(struct iphdr *iph)
/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/ /************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/
static struct ipq *ipqueue = NULL; /* IP fragment queue */ 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) static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
{ {
struct ipfrag *fp; struct ipfrag *fp;
...@@ -664,7 +539,6 @@ static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, u ...@@ -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 * Find the correct entry in the "incomplete datagrams" queue for
* this IP datagram, and return the queue entry address if found. * this IP datagram, and return the queue entry address if found.
*/ */
static struct ipq *ip_find(struct iphdr *iph) static struct ipq *ip_find(struct iphdr *iph)
{ {
struct ipq *qp; struct ipq *qp;
...@@ -744,9 +618,7 @@ static void ip_free(struct ipq *qp) ...@@ -744,9 +618,7 @@ static void ip_free(struct ipq *qp)
} }
/* /* 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) static void ip_expire(unsigned long arg)
{ {
...@@ -839,10 +711,7 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct devi ...@@ -839,10 +711,7 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct devi
} }
/* /* See if a fragment queue is complete. */
* See if a fragment queue is complete.
*/
static int ip_done(struct ipq *qp) static int ip_done(struct ipq *qp)
{ {
struct ipfrag *fp; struct ipfrag *fp;
...@@ -868,10 +737,7 @@ static int ip_done(struct ipq *qp) ...@@ -868,10 +737,7 @@ static int ip_done(struct ipq *qp)
} }
/* /* 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) static struct sk_buff *ip_glue(struct ipq *qp)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -914,7 +780,6 @@ static struct sk_buff *ip_glue(struct ipq *qp) ...@@ -914,7 +780,6 @@ static struct sk_buff *ip_glue(struct ipq *qp)
{ {
if(count+fp->len>skb->len) if(count+fp->len>skb->len)
{ {
/* In case some fool sends us a silly fragment. */
printk("Invalid fragment list: Fragment over size.\n"); printk("Invalid fragment list: Fragment over size.\n");
kfree_skb(skb,FREE_WRITE); kfree_skb(skb,FREE_WRITE);
return NULL; return NULL;
...@@ -936,10 +801,7 @@ static struct sk_buff *ip_glue(struct ipq *qp) ...@@ -936,10 +801,7 @@ static struct sk_buff *ip_glue(struct ipq *qp)
} }
/* /* 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) static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev)
{ {
struct ipfrag *prev, *next; struct ipfrag *prev, *next;
...@@ -1091,7 +953,6 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct ...@@ -1091,7 +953,6 @@ 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 * ip_queue_xmit(). Note that this is recursion, and bad things will happen
* if this function causes a loop... * if this function causes a loop...
*/ */
void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag) void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag)
{ {
struct iphdr *iph; struct iphdr *iph;
...@@ -1134,16 +995,6 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct ...@@ -1134,16 +995,6 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
return; 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. */ /* Fragment the datagram. */
if (is_frag & 2) if (is_frag & 2)
offset = (ntohs(iph->frag_off) & 0x1fff) << 3; offset = (ntohs(iph->frag_off) & 0x1fff) << 3;
...@@ -1205,11 +1056,9 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct ...@@ -1205,11 +1056,9 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
#ifdef CONFIG_IP_FORWARD #ifdef CONFIG_IP_FORWARD
/* /* Forward an IP datagram to its next destination. */
* Forward an IP datagram to its next destination. static void
*/ ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
{ {
struct device *dev2; struct device *dev2;
struct iphdr *iph; struct iphdr *iph;
...@@ -1232,12 +1081,11 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1232,12 +1081,11 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
/* /*
* According to the RFC, we must first decrease the TTL field. If * According to the RFC, we must first decrease the TTL field. If
* that reaches zero, we must reply an ICMP control message telling * that reaches zero, we must reply an ICMP control message telling
* that the packet's lifetime expired. RFC791 page 30. * that the packet's lifetime expired.
*/ */
iph = skb->h.iph; iph = skb->h.iph;
iph->ttl--; iph->ttl--;
if (iph->ttl <= 0) if (iph->ttl <= 0) {
{
DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n")); DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));
DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
...@@ -1255,8 +1103,7 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1255,8 +1103,7 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
* and give it to the IP sender for further processing. * and give it to the IP sender for further processing.
*/ */
rt = rt_route(iph->daddr, NULL); rt = rt_route(iph->daddr, NULL);
if (rt == NULL) if (rt == NULL) {
{
DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n")); DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));
/* Tell the sender its packet cannot be delivered... */ /* Tell the sender its packet cannot be delivered... */
...@@ -1273,28 +1120,20 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1273,28 +1120,20 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
* IP address itself- we seem to be connected directly... * IP address itself- we seem to be connected directly...
*/ */
raddr = rt->rt_gateway; raddr = rt->rt_gateway;
if (raddr != 0) if (raddr != 0) {
{
rt = rt_route(raddr, NULL); rt = rt_route(raddr, NULL);
if (rt == NULL) if (rt == NULL) {
{
DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n")); DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));
/* Tell the sender its packet cannot be delivered... */ /* Tell the sender its packet cannot be delivered... */
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);
return; return;
} }
if (rt->rt_gateway != 0) if (rt->rt_gateway != 0) raddr = rt->rt_gateway;
raddr = rt->rt_gateway; } else raddr = iph->daddr;
}
else
raddr = iph->daddr;
dev2 = rt->rt_dev; dev2 = rt->rt_dev;
/*
* Never forward out on the same interface, its not allowed, its often not pretty either (except for on
* source routing)
*/
if (dev == dev2) if (dev == dev2)
return; return;
/* /*
...@@ -1305,12 +1144,10 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1305,12 +1144,10 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n", DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n",
in_ntoa(raddr), dev2->name, skb->len)); in_ntoa(raddr), dev2->name, skb->len));
if (dev2->flags & IFF_UP) if (dev2->flags & IFF_UP) {
{
skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) + skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +
dev2->hard_header_len + skb->len, GFP_ATOMIC); dev2->hard_header_len + skb->len, GFP_ATOMIC);
if (skb2 == NULL) if (skb2 == NULL) {
{
printk("\nIP: No memory available for IP forward\n"); printk("\nIP: No memory available for IP forward\n");
return; return;
} }
...@@ -1318,6 +1155,8 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1318,6 +1155,8 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
skb2->sk = NULL; skb2->sk = NULL;
skb2->free = 1; skb2->free = 1;
skb2->len = skb->len + dev2->hard_header_len; 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->next = NULL;
skb2->h.raw = ptr; skb2->h.raw = ptr;
...@@ -1340,28 +1179,24 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) ...@@ -1340,28 +1179,24 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
#endif #endif
/* This function receives all incoming IP datagrams. */
/* int
* This function receives all incoming IP datagrams. ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
*/
int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{ {
struct iphdr *iph = skb->h.iph; struct iphdr *iph = skb->h.iph;
unsigned char hash; unsigned char hash;
unsigned char flag = 0; unsigned char flag = 0;
unsigned char opts_p = 0; /* Set iff the packet has options. */ unsigned char opts_p = 0; /* Set iff the packet has options. */
struct inet_protocol *ipprot; struct inet_protocol *ipprot;
struct options *opt=NULL; static struct options opt; /* since we don't use these yet, and they
take up stack space. */
int brd; int brd;
int is_frag=0; int is_frag=0;
DPRINTF((DBG_IP, "<<\n")); DPRINTF((DBG_IP, "<<\n"));
/* Is the datagram acceptable? */ /* 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) 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, "\nIP: *** datagram error ***\n"));
DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
...@@ -1370,21 +1205,12 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1370,21 +1205,12 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0); return(0);
} }
if (iph->ihl != 5) if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */
{ /* Fast path for the typical optionless IP packet. */
#ifdef IP_DEBUG
ip_print(iph); /* Bogus, only for debugging. */ ip_print(iph); /* Bogus, only for debugging. */
#endif memset((char *) &opt, 0, sizeof(opt));
if (do_options(iph, &opt,dev) != 0) if (do_options(iph, &opt) != 0)
{
if(opt)
kfree(opt);
return 0; return 0;
} opts_p = 1;
/* skb->ip_options=opt_ptr;*/
kfree(opt);
opt = NULL;
opts_p = 0/*1*/;
} }
if (iph->frag_off & 0x0020) if (iph->frag_off & 0x0020)
...@@ -1393,8 +1219,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1393,8 +1219,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
is_frag|=2; is_frag|=2;
/* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */ /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */
if ((brd = chk_addr(iph->daddr)) == 0) if ((brd = chk_addr(iph->daddr)) == 0) {
{
#ifdef CONFIG_IP_FORWARD #ifdef CONFIG_IP_FORWARD
ip_forward(skb, dev, is_frag); ip_forward(skb, dev, is_frag);
#else #else
...@@ -1431,21 +1256,26 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1431,21 +1256,26 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
} }
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. */ /* Point into the IP datagram, just past the header. */
skb->ip_hdr = iph;
skb->h.raw += iph->ihl*4; skb->h.raw += iph->ihl*4;
hash = iph->protocol & (MAX_INET_PROTOS -1); hash = iph->protocol & (MAX_INET_PROTOS -1);
/* Find someone to deliver it too */
for (ipprot = (struct inet_protocol *)inet_protos[hash]; for (ipprot = (struct inet_protocol *)inet_protos[hash];
ipprot != NULL; ipprot != NULL;
ipprot=(struct inet_protocol *)ipprot->next) ipprot=(struct inet_protocol *)ipprot->next)
{ {
struct sk_buff *skb2; struct sk_buff *skb2;
if (ipprot->protocol != iph->protocol) if (ipprot->protocol != iph->protocol) continue;
continue;
DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot)); DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot));
print_ipprot(ipprot); print_ipprot(ipprot);
...@@ -1454,8 +1284,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1454,8 +1284,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* only be set if more than one protocol wants it. * only be set if more than one protocol wants it.
* and then not for the last one. * and then not for the last one.
*/ */
if (ipprot->copy) if (ipprot->copy) {
{
skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
if (skb2 == NULL) if (skb2 == NULL)
continue; continue;
...@@ -1466,9 +1295,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1466,9 +1295,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
(unsigned long) skb->h.raw - (unsigned long) skb->h.raw -
(unsigned long)skb); (unsigned long)skb);
skb2->free=1; skb2->free=1;
} } else {
else
{
skb2 = skb; skb2 = skb;
} }
flag = 1; flag = 1;
...@@ -1478,7 +1305,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1478,7 +1305,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* based on the datagram protocol. We should really * based on the datagram protocol. We should really
* check the protocol handler's return values here... * check the protocol handler's return values here...
*/ */
ipprot->handler(skb2, dev, opts_p ? opt : 0, iph->daddr, ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr,
(ntohs(iph->tot_len) - (iph->ihl * 4)), (ntohs(iph->tot_len) - (iph->ihl * 4)),
iph->saddr, 0, ipprot); iph->saddr, 0, ipprot);
...@@ -1490,8 +1317,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1490,8 +1317,7 @@ 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 * causes (proven, grin) ARP storms and a leakage of memory (i.e. all
* ICMP reply messages get queued up for transmission...) * ICMP reply messages get queued up for transmission...)
*/ */
if (!flag) if (!flag) {
{
if (brd != IS_BROADCAST) if (brd != IS_BROADCAST)
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
skb->sk = NULL; skb->sk = NULL;
...@@ -1509,16 +1335,15 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1509,16 +1335,15 @@ 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 * This routine also needs to put in the total length, and
* compute the checksum. * 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 sk_buff *skb, int free)
{ {
struct iphdr *iph; struct iphdr *iph;
unsigned char *ptr; unsigned char *ptr;
if (sk == NULL) if (sk == NULL) free = 1;
free = 1; if (dev == NULL) {
if (dev == NULL)
{
printk("IP: ip_queue_xmit dev = NULL\n"); printk("IP: ip_queue_xmit dev = NULL\n");
return; return;
} }
...@@ -1543,33 +1368,24 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, ...@@ -1543,33 +1368,24 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
} }
ip_send_check(iph); ip_send_check(iph);
#ifdef IP_DEBUG
ip_print(iph); ip_print(iph);
#endif
skb->next = NULL; skb->next = NULL;
/* See if this is the one trashing our queue. Ross? */ /* See if this is the one trashing our queue. Ross? */
skb->magic = 1; skb->magic = 1;
if (!free) if (!free) {
{
skb->link3 = NULL; skb->link3 = NULL;
sk->packets_out++; sk->packets_out++;
cli(); cli();
if (sk->send_head == NULL) if (sk->send_head == NULL) {
{
sk->send_tail = skb; sk->send_tail = skb;
sk->send_head = skb; sk->send_head = skb;
} } else {
else
{
/* See if we've got a problem. */ /* See if we've got a problem. */
if (sk->send_tail == NULL) if (sk->send_tail == NULL) {
{
printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n"); printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n");
sort_send(sk); sort_send(sk);
} } else {
else
{
sk->send_tail->link3 = skb; sk->send_tail->link3 = skb;
sk->send_tail = skb; sk->send_tail = skb;
} }
...@@ -1577,32 +1393,26 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, ...@@ -1577,32 +1393,26 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
sti(); sti();
reset_timer(sk, TIME_WRITE, reset_timer(sk, TIME_WRITE,
backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)); backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
} } else {
else
{
skb->sk = sk; skb->sk = sk;
} }
/* If the indicated interface is up and running, kick it. */ /* If the indicated interface is up and running, kick it. */
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP) {
{ if (sk != NULL) {
if (sk != NULL)
{
dev->queue_xmit(skb, dev, sk->priority); dev->queue_xmit(skb, dev, sk->priority);
} }
else else {
{
dev->queue_xmit(skb, dev, SOPRI_NORMAL); dev->queue_xmit(skb, dev, SOPRI_NORMAL);
} }
} } else {
else
{
if (free) kfree_skb(skb, FREE_WRITE); 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 sk_buff * skb;
struct proto *prot; struct proto *prot;
...@@ -1610,8 +1420,7 @@ void ip_retransmit(struct sock *sk, int all) ...@@ -1610,8 +1420,7 @@ void ip_retransmit(struct sock *sk, int all)
prot = sk->prot; prot = sk->prot;
skb = sk->send_head; skb = sk->send_head;
while (skb != NULL) while (skb != NULL) {
{
dev = skb->dev; dev = skb->dev;
/* I know this can't happen but as it does.. */ /* I know this can't happen but as it does.. */
if(dev==NULL) if(dev==NULL)
...@@ -1630,13 +1439,10 @@ void ip_retransmit(struct sock *sk, int all) ...@@ -1630,13 +1439,10 @@ void ip_retransmit(struct sock *sk, int all)
cli(); /* We might get interrupted by an arp reply here and fill cli(); /* We might get interrupted by an arp reply here and fill
the frame in twice. Because of the technique used this the frame in twice. Because of the technique used this
would be a little sad */ would be a little sad */
if (!skb->arp) if (!skb->arp) {
{ if (dev->rebuild_header(skb+1, dev)) {
if (dev->rebuild_header(skb+1, dev))
{
sti(); /* Failed to rebuild - next */ sti(); /* Failed to rebuild - next */
if (!all) if (!all) break;
break;
skb = (struct sk_buff *)skb->link3; skb = (struct sk_buff *)skb->link3;
continue; continue;
} }
...@@ -1646,20 +1452,17 @@ void ip_retransmit(struct sock *sk, int all) ...@@ -1646,20 +1452,17 @@ void ip_retransmit(struct sock *sk, int all)
skb->when = jiffies; skb->when = jiffies;
/* If the interface is (still) up and running, kick it. */ /* If the interface is (still) up and running, kick it. */
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP) {
{ if (sk) dev->queue_xmit(skb, dev, sk->priority);
if (sk) /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
dev->queue_xmit(skb, dev, sk->priority);
} }
oops: sk->retransmits++; oops: sk->retransmits++;
sk->prot->retransmits ++; sk->prot->retransmits ++;
if (!all) if (!all) break;
break;
/* This should cut it off before we send too many packets. */ /* This should cut it off before we send too many packets. */
if (sk->retransmits > sk->cong_window) if (sk->retransmits > sk->cong_window) break;
break;
skb = (struct sk_buff *)skb->link3; skb = (struct sk_buff *)skb->link3;
} }
...@@ -1673,10 +1476,7 @@ oops: sk->retransmits++; ...@@ -1673,10 +1476,7 @@ oops: sk->retransmits++;
reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt)); reset_timer(sk, TIME_WRITE, backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
} }
/* /* Backoff function - the subject of much research */
* Backoff function - the subject of much research
*/
int backoff(int n) int backoff(int n)
{ {
/* Use binary exponential up to retry #4, and quadratic after that /* Use binary exponential up to retry #4, and quadratic after that
...@@ -1704,73 +1504,3 @@ int backoff(int n) ...@@ -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);
}
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
#include <linux/ip.h> #include <linux/ip.h>
#include "sockinet.h"
#include "sock.h" /* struct sock */
/* IP flags. */ /* IP flags. */
#define IP_CE 0x8000 /* Flag: "Congestion" */ #define IP_CE 0x8000 /* Flag: "Congestion" */
...@@ -69,8 +69,7 @@ extern int ip_build_header(struct sk_buff *skb, ...@@ -69,8 +69,7 @@ extern int ip_build_header(struct sk_buff *skb,
unsigned long saddr, unsigned long saddr,
unsigned long daddr, unsigned long daddr,
struct device **dev, int type, struct device **dev, int type,
struct options *opt, int len, struct options *opt, int len);
int tos,int ttl);
extern unsigned short ip_compute_csum(unsigned char * buff, int len); extern unsigned short ip_compute_csum(unsigned char * buff, int len);
extern int ip_rcv(struct sk_buff *skb, struct device *dev, extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt); struct packet_type *pt);
...@@ -78,6 +77,5 @@ extern void ip_queue_xmit(struct sock *sk, ...@@ -78,6 +77,5 @@ extern void ip_queue_xmit(struct sock *sk,
struct device *dev, struct sk_buff *skb, struct device *dev, struct sk_buff *skb,
int free); int free);
extern void ip_retransmit(struct sock *sk, int all); 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 */ #endif /* _IP_H */
...@@ -5,59 +5,55 @@ ...@@ -5,59 +5,55 @@
* *
* Pseudo-driver for the loopback interface. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later 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/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/if_ether.h> /* For the statistics structure. */ #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 "inet.h"
#include "devinet.h" #include "dev.h"
#include "eth.h" #include "eth.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "arp.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; struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
int done; int done;
DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb)); DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
if (skb == NULL || dev == NULL) if (skb == NULL || dev == NULL) return(0);
return(0);
cli(); cli();
if (dev->tbusy != 0) if (dev->tbusy != 0) {
{
sti(); sti();
stats->tx_errors++; stats->tx_errors++;
return(1); return(1);
...@@ -66,11 +62,9 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev) ...@@ -66,11 +62,9 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
sti(); sti();
done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev); done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev);
if (skb->free) if (skb->free) kfree_skb(skb, FREE_WRITE);
kfree_skb(skb, FREE_WRITE);
while (done != 1) while (done != 1) {
{
done = dev_rint(NULL, 0, 0, dev); done = dev_rint(NULL, 0, 0, dev);
} }
stats->tx_packets++; stats->tx_packets++;
...@@ -95,13 +89,15 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev) ...@@ -95,13 +89,15 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
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; return (struct enet_statistics *)dev->priv;
} }
/* Initialize the rest of the LOOPBACK device. */ /* Initialize the rest of the LOOPBACK device. */
int loopback_init(struct device *dev) int
loopback_init(struct device *dev)
{ {
dev->mtu = 2000; /* MTU */ dev->mtu = 2000; /* MTU */
dev->tbusy = 0; dev->tbusy = 0;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* PACKET - implements raw packet sockets. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
* added. Also fixed the peek/read crash * added. Also fixed the peek/read crash
* from all old Linux datagram code. * from all old Linux datagram code.
* Alan Cox : Uses the improved 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 * This program is free software; you can redistribute it and/or
...@@ -32,12 +31,12 @@ ...@@ -32,12 +31,12 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -45,23 +44,18 @@ ...@@ -45,23 +44,18 @@
#include "udp.h" #include "udp.h"
#include "raw.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) if (a < b) return(a);
return(a);
return(b); return(b);
} }
/* /* This should be the easiest of all, all we do is copy it into a buffer. */
* 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)
int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{ {
struct sock *sk; struct sock *sk;
...@@ -72,26 +66,22 @@ int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -72,26 +66,22 @@ int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
skb->sk = sk; skb->sk = sk;
/* Charge it too the socket. */ /* Charge it too the socket. */
if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
{
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} }
sk->rmem_alloc += skb->mem_len; sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb); skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
release_sock(sk); release_sock(sk);
sk->data_ready(sk,skb->len);
return(0); return(0);
} }
/* /* This will do terrible things if len + ipheader + devheader > dev->mtu */
* This will do terrible things if len + ipheader + devheader > dev->mtu static int
* Since only root can use these thats okish... packet_sendto(struct sock *sk, unsigned char *from, int len,
*/
static int packet_sendto(struct sock *sk, unsigned char *from, int len,
int noblock, unsigned flags, struct sockaddr_in *usin, int noblock, unsigned flags, struct sockaddr_in *usin,
int addr_len) int addr_len)
{ {
...@@ -101,69 +91,64 @@ static int packet_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -101,69 +91,64 @@ static int packet_sendto(struct sock *sk, unsigned char *from, int len,
int err; int err;
/* Check the flags. */ /* Check the flags. */
if (flags) if (flags) return(-EINVAL);
return(-EINVAL); if (len < 0) return(-EINVAL);
if (len < 0)
return(-EINVAL);
/* Get and verify the address. */ /* Get and verify the address. */
if (usin) if (usin) {
{ if (addr_len < sizeof(saddr)) return(-EINVAL);
if (addr_len < sizeof(saddr))
return(-EINVAL);
err=verify_area(VERIFY_READ, usin, sizeof(saddr)); err=verify_area(VERIFY_READ, usin, sizeof(saddr));
if(err) if(err)
return err; return err;
memcpy_fromfs(&saddr, usin, sizeof(saddr)); memcpy_fromfs(&saddr, usin, sizeof(saddr));
} } else
else
return(-EINVAL); return(-EINVAL);
err=verify_area(VERIFY_READ,from,len); err=verify_area(VERIFY_READ,from,len);
if(err) if(err)
return(err); return(err);
/* Find the device first to size check it */ /* Find the device first to size check it */
saddr.sa_data[13] = 0; saddr.sa_data[13] = 0;
dev = dev_get(saddr.sa_data); dev = dev_get(saddr.sa_data);
if (dev == NULL) if (dev == NULL) {
{
return(-ENXIO); return(-ENXIO);
} }
if(len>dev->mtu) if(len>dev->mtu)
return -EMSGSIZE; return -EMSGSIZE;
/* Now allocate the buffer, knowing 4K pagelimits wont break this line */ /* 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); skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
/* This shouldn't happen, but it could. */ /* This shouldn't happen, but it could. */
if (skb == NULL) if (skb == NULL) {
{
DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n")); DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
return(-ENOMEM); return(-ENOMEM);
} }
/* Fill it in */ /* Fill it in */
skb->mem_addr = skb;
skb->mem_len = len + sizeof(*skb);
skb->sk = sk; skb->sk = sk;
skb->free = 1; skb->free = 1;
memcpy_fromfs (skb+1, from, len); memcpy_fromfs (skb+1, from, len);
skb->len = len; skb->len = len;
skb->next = NULL; skb->next = NULL;
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority);
dev->queue_xmit(skb, dev, sk->priority); else kfree_skb(skb, FREE_WRITE);
else
kfree_skb(skb, FREE_WRITE);
return(len); 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) 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->inuse = 1;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
...@@ -174,13 +159,13 @@ static void packet_close(struct sock *sk, int timeout) ...@@ -174,13 +159,13 @@ static void packet_close(struct sock *sk, int timeout)
} }
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); p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL) if (p == NULL) return(-ENOMEM);
return(-ENOMEM);
p->func = packet_rcv; p->func = packet_rcv;
p->type = sk->num; p->type = sk->num;
...@@ -198,7 +183,8 @@ static int packet_init(struct sock *sk) ...@@ -198,7 +183,8 @@ static int packet_init(struct sock *sk)
* This should be easy, if there is something there * This should be easy, if there is something there
* we return it, otherwise we block. * 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 noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len) int *addr_len)
{ {
...@@ -208,15 +194,11 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -208,15 +194,11 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int err; int err;
saddr = (struct sockaddr *)sin; saddr = (struct sockaddr *)sin;
if (len == 0) if (len == 0) return(0);
return(0); if (len < 0) return(-EINVAL);
if (len < 0)
return(-EINVAL);
if (sk->shutdown & RCV_SHUTDOWN) if (sk->shutdown & RCV_SHUTDOWN) return(0);
return(0); if (addr_len) {
if (addr_len)
{
err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(err) if(err)
return err; return err;
...@@ -234,8 +216,7 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -234,8 +216,7 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
memcpy_tofs(to, skb+1, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */ memcpy_tofs(to, skb+1, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */
/* Copy the address. */ /* Copy the address. */
if (saddr) if (saddr) {
{
struct sockaddr addr; struct sockaddr addr;
addr.sa_family = skb->dev->type; addr.sa_family = skb->dev->type;
...@@ -251,15 +232,15 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -251,15 +232,15 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
} }
int packet_read(struct sock *sk, unsigned char *buff, int
packet_read(struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags) 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 = struct proto packet_prot = {
{
sock_wmalloc, sock_wmalloc,
sock_rmalloc, sock_rmalloc,
sock_wfree, sock_wfree,
...@@ -283,8 +264,6 @@ struct proto packet_prot = ...@@ -283,8 +264,6 @@ struct proto packet_prot =
NULL, NULL,
packet_init, packet_init,
NULL, NULL,
NULL, /* No set/get socket options */
NULL,
128, 128,
0, 0,
{NULL,}, {NULL,},
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* PROC file system. It is mainly used for debugging and * PROC file system. It is mainly used for debugging and
* statistics. * 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> * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de> * Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
...@@ -18,7 +18,10 @@ ...@@ -18,7 +18,10 @@
* using hint flag for the netinfo. * using hint flag for the netinfo.
* Pauline Middelink : Pidentd support * Pauline Middelink : Pidentd support
* Alan Cox : Make /proc safer. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -34,13 +37,13 @@ ...@@ -34,13 +37,13 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/param.h> #include <linux/param.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "udp.h" #include "udp.h"
#include "socket/skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "raw.h" #include "raw.h"
/* /*
...@@ -50,7 +53,8 @@ ...@@ -50,7 +53,8 @@
* As in get_unix_netinfo, the buffer might be too small. If this * As in get_unix_netinfo, the buffer might be too small. If this
* happens, get__netinfo returns only part of the available infos. * 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 **s_array;
struct sock *sp; struct sock *sp;
...@@ -67,12 +71,10 @@ static int get__netinfo(struct proto *pro, char *buffer, int format) ...@@ -67,12 +71,10 @@ static int get__netinfo(struct proto *pro, char *buffer, int format)
* (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing * (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing
* with timers we just concede defeat and cli(). * with timers we just concede defeat and cli().
*/ */
for(i = 0; i < SOCK_ARRAY_SIZE; i++) for(i = 0; i < SOCK_ARRAY_SIZE; i++) {
{
cli(); cli();
sp = s_array[i]; sp = s_array[i];
while(sp != NULL) while(sp != NULL) {
{
dest = sp->daddr; dest = sp->daddr;
src = sp->saddr; src = sp->saddr;
destp = sp->dummy_th.dest; destp = sp->dummy_th.dest;
...@@ -93,8 +95,7 @@ static int get__netinfo(struct proto *pro, char *buffer, int format) ...@@ -93,8 +95,7 @@ static int get__netinfo(struct proto *pro, char *buffer, int format)
if (timer_active) if (timer_active)
add_timer(&sp->timer); add_timer(&sp->timer);
/* Is place in buffer too rare? then abort. */ /* Is place in buffer too rare? then abort. */
if (pos > buffer+PAGE_SIZE-80) if (pos > buffer+PAGE_SIZE-80) {
{
printk("oops, too many %s sockets for netinfo.\n", printk("oops, too many %s sockets for netinfo.\n",
pro->name); pro->name);
return(strlen(buffer)); return(strlen(buffer));
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* INET protocol dispatch tables. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -14,8 +14,7 @@ ...@@ -14,8 +14,7 @@
* Alan Cox : Ahah! udp icmp errors don't work because * Alan Cox : Ahah! udp icmp errors don't work because
* udp_err is never called! * udp_err is never called!
* Alan Cox : Added new fields for init and ready for * Alan Cox : Added new fields for init and ready for
* proper fragmentation (_NO_ 4K limits!). * proper fragmentation (_NO_ 4K limits!)
* Alan Cox : Final clean up.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -31,18 +30,17 @@ ...@@ -31,18 +30,17 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "socket/skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "icmp.h" #include "icmp.h"
#include "udp.h" #include "udp.h"
static struct inet_protocol tcp_protocol = static struct inet_protocol tcp_protocol = {
{
tcp_rcv, /* TCP handler */ tcp_rcv, /* TCP handler */
NULL, /* No fragment handler (and won't be for a long time) */ NULL, /* No fragment handler (and won't be for a long time) */
tcp_err, /* TCP error control */ tcp_err, /* TCP error control */
...@@ -54,8 +52,7 @@ static struct inet_protocol tcp_protocol = ...@@ -54,8 +52,7 @@ static struct inet_protocol tcp_protocol =
}; };
static struct inet_protocol udp_protocol = static struct inet_protocol udp_protocol = {
{
udp_rcv, /* UDP handler */ udp_rcv, /* UDP handler */
NULL, /* Will be UDP fraglist handler */ NULL, /* Will be UDP fraglist handler */
udp_err, /* UDP error control */ udp_err, /* UDP error control */
...@@ -67,8 +64,7 @@ static struct inet_protocol udp_protocol = ...@@ -67,8 +64,7 @@ static struct inet_protocol udp_protocol =
}; };
static struct inet_protocol icmp_protocol = static struct inet_protocol icmp_protocol = {
{
icmp_rcv, /* ICMP handler */ icmp_rcv, /* ICMP handler */
NULL, /* ICMP never fragments anyway */ NULL, /* ICMP never fragments anyway */
NULL, /* ICMP error control */ NULL, /* ICMP error control */
...@@ -81,31 +77,29 @@ static struct inet_protocol icmp_protocol = ...@@ -81,31 +77,29 @@ static struct inet_protocol icmp_protocol =
struct inet_protocol *inet_protocol_base = &icmp_protocol; struct inet_protocol *inet_protocol_base = &icmp_protocol;
struct inet_protocol *inet_protos[MAX_INET_PROTOS] = {
struct inet_protocol *inet_protos[MAX_INET_PROTOS] =
{
NULL NULL
}; };
struct inet_protocol *inet_get_protocol(unsigned char prot) struct inet_protocol *
inet_get_protocol(unsigned char prot)
{ {
unsigned char hash; unsigned char hash;
struct inet_protocol *p; struct inet_protocol *p;
DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot)); DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
hash = prot & (MAX_INET_PROTOS - 1); hash = prot & (MAX_INET_PROTOS - 1);
for (p = inet_protos[hash] ; p != NULL; p=p->next) for (p = inet_protos[hash] ; p != NULL; p=p->next) {
{
DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol)); DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
if (p->protocol == prot) if (p->protocol == prot) return((struct inet_protocol *) p);
return((struct inet_protocol *) p);
} }
return(NULL); return(NULL);
} }
void inet_add_protocol(struct inet_protocol *prot) void
inet_add_protocol(struct inet_protocol *prot)
{ {
unsigned char hash; unsigned char hash;
struct inet_protocol *p2; struct inet_protocol *p2;
...@@ -117,10 +111,8 @@ void inet_add_protocol(struct inet_protocol *prot) ...@@ -117,10 +111,8 @@ void inet_add_protocol(struct inet_protocol *prot)
/* Set the copy bit if we need to. */ /* Set the copy bit if we need to. */
p2 = (struct inet_protocol *) prot->next; p2 = (struct inet_protocol *) prot->next;
while(p2 != NULL) while(p2 != NULL) {
{ if (p2->protocol == prot->protocol) {
if (p2->protocol == prot->protocol)
{
prot->copy = 1; prot->copy = 1;
break; break;
} }
...@@ -129,41 +121,37 @@ void inet_add_protocol(struct inet_protocol *prot) ...@@ -129,41 +121,37 @@ void inet_add_protocol(struct inet_protocol *prot)
} }
int inet_del_protocol(struct inet_protocol *prot) int
inet_del_protocol(struct inet_protocol *prot)
{ {
struct inet_protocol *p; struct inet_protocol *p;
struct inet_protocol *lp = NULL; struct inet_protocol *lp = NULL;
unsigned char hash; unsigned char hash;
hash = prot->protocol & (MAX_INET_PROTOS - 1); hash = prot->protocol & (MAX_INET_PROTOS - 1);
if (prot == inet_protos[hash]) if (prot == inet_protos[hash]) {
{
inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next; inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
return(0); return(0);
} }
p = (struct inet_protocol *) inet_protos[hash]; p = (struct inet_protocol *) inet_protos[hash];
while(p != NULL) while(p != NULL) {
{
/* /*
* We have to worry if the protocol being deleted is * We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset * the last one on the list, then we may need to reset
* someones copied bit. * someones copied bit.
*/ */
if (p->next != NULL && p->next == prot) if (p->next != NULL && p->next == prot) {
{
/* /*
* if we are the last one with this protocol and * if we are the last one with this protocol and
* there is a previous one, reset its copy bit. * there is a previous one, reset its copy bit.
*/ */
if (p->copy == 0 && lp != NULL) if (p->copy == 0 && lp != NULL) lp->copy = 0;
lp->copy = 0;
p->next = prot->next; p->next = prot->next;
return(0); return(0);
} }
if (p->next != NULL && p->next->protocol == prot->protocol) if (p->next != NULL && p->next->protocol == prot->protocol) {
{
lp = p; lp = p;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* RAW - implementation of IP "raw" sockets. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -19,16 +19,12 @@ ...@@ -19,16 +19,12 @@
* Alan Cox : Checks sk->broadcast. * Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram * Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#include <asm/system.h> #include <asm/system.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -41,29 +37,27 @@ ...@@ -41,29 +37,27 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/in.h> #include <linux/in.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "icmp.h" #include "icmp.h"
#include "udp.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) if (a < b) return(a);
return(a);
return(b); return(b);
} }
/* /* raw_err gets called by the icmp module. */
* raw_err gets called by the icmp module. void
*/ raw_err (int err, unsigned char *header, unsigned long daddr,
void raw_err (int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol) unsigned long saddr, struct inet_protocol *protocol)
{ {
struct sock *sk; struct sock *sk;
...@@ -71,35 +65,29 @@ void raw_err (int err, unsigned char *header, unsigned long daddr, ...@@ -71,35 +65,29 @@ void raw_err (int err, unsigned char *header, unsigned long daddr,
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)); err, header, daddr, saddr, protocol));
if (protocol == NULL) if (protocol == NULL) return;
return;
sk = (struct sock *) protocol->data; sk = (struct sock *) protocol->data;
if (sk == NULL) if (sk == NULL) return;
return;
/* This is meaningless in raw sockets. */ /* This is meaningless in raw sockets. */
if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) {
if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
{
if (sk->cong_window > 1)
sk->cong_window = sk->cong_window/2;
return; return;
} }
sk->err = icmp_err_convert[err & 0xff].errno; sk->err = icmp_err_convert[err & 0xff].errno;
sk->error_report(sk); wake_up(sk->sleep);
return; return;
} }
/* /*
* This should be the easiest of all, all we do is\ * This should be the easiest of all, all we do is\
* copy it into a buffer. We do have to diddle the pointer * copy it into a buffer.
* to get the ip header too.
*/ */
int
int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long saddr, unsigned long daddr, unsigned short len, unsigned long saddr,
int redo, struct inet_protocol *protocol) int redo, struct inet_protocol *protocol)
{ {
...@@ -109,54 +97,41 @@ int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -109,54 +97,41 @@ int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
" len=%d, saddr=%X, redo=%d, protocol=%X)\n", " len=%d, saddr=%X, redo=%d, protocol=%X)\n",
skb, dev, opt, daddr, len, saddr, redo, protocol)); skb, dev, opt, daddr, len, saddr, redo, protocol));
if (skb == NULL) if (skb == NULL) return(0);
return(0); if (protocol == NULL) {
if (protocol == NULL)
{
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} }
sk = (struct sock *) protocol->data; sk = (struct sock *) protocol->data;
if (sk == NULL) if (sk == NULL) {
{
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} }
/* Now we need to copy this into memory. */ /* Now we need to copy this into memory. */
skb->sk = sk; skb->sk = sk;
/* skb->len = len;
* Adjust to get the header back
*/
skb->len += skb->ip_hdr->ihl*sizeof(long);
skb->h.iph = skb->ip_hdr;
skb->dev = dev; skb->dev = dev;
skb->saddr = daddr; skb->saddr = daddr;
skb->daddr = saddr; skb->daddr = saddr;
/* Charge it too the socket. */ /* Charge it too the socket. */
if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
{
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_READ); kfree_skb(skb, FREE_READ);
return(0); return(0);
} }
sk->rmem_alloc += skb->mem_len; sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb); skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
release_sock(sk); release_sock(sk);
sk->data_ready(sk,skb->len);
return(0); return(0);
} }
/* /* This will do terrible things if len + ipheader + devheader > dev->mtu */
* Send a RAW IP packet (user level IP protocols). Root only static int
* caller provides IP header. raw_sendto(struct sock *sk, unsigned char *from, int len,
*/
static int raw_sendto(struct sock *sk, unsigned char *from, int len,
int noblock, int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len) unsigned flags, struct sockaddr_in *usin, int addr_len)
{ {
...@@ -171,44 +146,34 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -171,44 +146,34 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
flags, usin, addr_len)); flags, usin, addr_len));
/* Check the flags. */ /* Check the flags. */
if (flags) if (flags) return(-EINVAL);
return(-EINVAL); if (len < 0) return(-EINVAL);
if (len < 0)
return(-EINVAL);
err=verify_area(VERIFY_READ,from,len); err=verify_area(VERIFY_READ,from,len);
if(err) if(err)
return err; return err;
/* Get and verify the address. */ /* Get and verify the address. */
if (usin) if (usin) {
{ if (addr_len < sizeof(sin)) return(-EINVAL);
if (addr_len < sizeof(sin))
return(-EINVAL);
err=verify_area (VERIFY_READ, usin, sizeof (sin)); err=verify_area (VERIFY_READ, usin, sizeof (sin));
if(err) if(err)
return err; return err;
memcpy_fromfs(&sin, usin, sizeof(sin)); memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET) if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
return(-EINVAL); } else {
} if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
else
{
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_port = sk->protocol; sin.sin_port = sk->protocol;
sin.sin_addr.s_addr = sk->daddr; sin.sin_addr.s_addr = sk->daddr;
} }
if (sin.sin_port == 0) if (sin.sin_port == 0) sin.sin_port = sk->protocol;
sin.sin_port = sk->protocol;
if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; return -ENETUNREACH;
sk->inuse = 1; sk->inuse = 1;
skb = NULL; skb = NULL;
while (skb == NULL) while (skb == NULL) {
{
if(sk->err!=0) if(sk->err!=0)
{ {
err= -sk->err; err= -sk->err;
...@@ -220,8 +185,7 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -220,8 +185,7 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
skb = (struct sk_buff *) sk->prot->wmalloc(sk, skb = (struct sk_buff *) sk->prot->wmalloc(sk,
len+sizeof(*skb) + sk->prot->max_header, len+sizeof(*skb) + sk->prot->max_header,
0, GFP_KERNEL); 0, GFP_KERNEL);
if (skb == NULL) if (skb == NULL) {
{
int tmp; int tmp;
DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n")); DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
...@@ -230,11 +194,9 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -230,11 +194,9 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp = sk->wmem_alloc; tmp = sk->wmem_alloc;
release_sock(sk); release_sock(sk);
cli(); cli();
if (tmp <= sk->wmem_alloc) if (tmp <= sk->wmem_alloc) {
{
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked) {
{
sti(); sti();
return(-ERESTARTSYS); return(-ERESTARTSYS);
} }
...@@ -243,6 +205,8 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -243,6 +205,8 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
sti(); sti();
} }
} }
skb->mem_addr = skb;
skb->mem_len = len + sizeof(*skb) +sk->prot->max_header;
skb->sk = sk; skb->sk = sk;
skb->free = 1; /* these two should be unecessary. */ skb->free = 1; /* these two should be unecessary. */
...@@ -250,23 +214,21 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -250,23 +214,21 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp = sk->prot->build_header(skb, sk->saddr, tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev, sin.sin_addr.s_addr, &dev,
sk->protocol, sk->opt, skb->mem_len, sk->protocol, sk->opt, skb->mem_len);
sk->ip_ttl,sk->ip_tos); if (tmp < 0) {
if (tmp < 0)
{
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
kfree_skb(skb,FREE_WRITE); kfree_skb(skb,FREE_WRITE);
release_sock(sk); release_sock(sk);
return(tmp); return(tmp);
} }
/* verify_area(VERIFY_WRITE, from, len);*/
memcpy_fromfs ((unsigned char *)(skb+1)+tmp, 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 /* If we are using IPPROTO_RAW, we need to fill in the source address in
the IP header */ the IP header */
if(sk->protocol==IPPROTO_RAW) if(sk->protocol==IPPROTO_RAW) {
{
unsigned char *buff; unsigned char *buff;
struct iphdr *iph; struct iphdr *iph;
...@@ -291,14 +253,16 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len, ...@@ -291,14 +253,16 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int 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) 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->inuse = 1;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
...@@ -314,13 +278,13 @@ static void raw_close(struct sock *sk, int timeout) ...@@ -314,13 +278,13 @@ static void raw_close(struct sock *sk, int timeout)
} }
static int raw_init(struct sock *sk) static int
raw_init(struct sock *sk)
{ {
struct inet_protocol *p; struct inet_protocol *p;
p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL); p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
if (p == NULL) if (p == NULL) return(-ENOMEM);
return(-ENOMEM);
p->handler = raw_rcv; p->handler = raw_rcv;
p->protocol = sk->protocol; p->protocol = sk->protocol;
...@@ -343,8 +307,8 @@ static int raw_init(struct sock *sk) ...@@ -343,8 +307,8 @@ static int raw_init(struct sock *sk)
* This should be easy, if there is something there * This should be easy, if there is something there
* we return it, otherwise we block. * we return it, otherwise we block.
*/ */
int
int raw_recvfrom(struct sock *sk, unsigned char *to, int len, raw_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin, int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len) int *addr_len)
{ {
...@@ -356,15 +320,11 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -356,15 +320,11 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
" sin=%X, addr_len=%X)\n", " sin=%X, addr_len=%X)\n",
sk, to, len, noblock, flags, sin, addr_len)); sk, to, len, noblock, flags, sin, addr_len));
if (len == 0) if (len == 0) return(0);
return(0); if (len < 0) return(-EINVAL);
if (len < 0)
return(-EINVAL);
if (sk->shutdown & RCV_SHUTDOWN) if (sk->shutdown & RCV_SHUTDOWN) return(0);
return(0); if (addr_len) {
if (addr_len)
{
err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(err) if(err)
return err; return err;
...@@ -383,8 +343,7 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -383,8 +343,7 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
skb_copy_datagram(skb, 0, to, copied); skb_copy_datagram(skb, 0, to, copied);
/* Copy the address. */ /* Copy the address. */
if (sin) if (sin) {
{
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
...@@ -399,15 +358,15 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -399,15 +358,15 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
} }
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) 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 = struct proto raw_prot = {
{
sock_wmalloc, sock_wmalloc,
sock_rmalloc, sock_rmalloc,
sock_wfree, sock_wfree,
...@@ -431,8 +390,6 @@ struct proto raw_prot = ...@@ -431,8 +390,6 @@ struct proto raw_prot =
NULL, NULL,
raw_init, raw_init,
NULL, NULL,
ip_setsockopt,
ip_getsockopt,
128, 128,
0, 0,
{NULL,}, {NULL,},
......
...@@ -47,10 +47,10 @@ static struct rtable *rt_base = NULL; ...@@ -47,10 +47,10 @@ static struct rtable *rt_base = NULL;
static struct rtable *rt_loopback = NULL; static struct rtable *rt_loopback = NULL;
/* Dump the contents of a routing table entry. */ /* 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) if (rt == NULL || inet_debug != DBG_RT) return;
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); (long) rt, (long) rt->rt_next, rt->rt_flags);
...@@ -162,8 +162,8 @@ static inline struct device * get_gw_dev(unsigned long gw) ...@@ -162,8 +162,8 @@ static inline struct device * get_gw_dev(unsigned long gw)
/* /*
* rewrote rt_add(), as the old one was weird. Linus * rewrote rt_add(), as the old one was weird. Linus
*/ */
void rt_add(short flags, unsigned long dst, unsigned long mask, void
unsigned long gw, struct device *dev) rt_add(short flags, unsigned long dst, unsigned long mask, unsigned long gw, struct device *dev)
{ {
struct rtable *r, *rt; struct rtable *r, *rt;
struct rtable **rp; struct rtable **rp;
...@@ -280,18 +280,21 @@ static int rt_new(struct rtentry *r) ...@@ -280,18 +280,21 @@ 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; trg = (struct sockaddr_in *) &r->rt_dst;
rt_del(trg->sin_addr.s_addr); rt_del(trg->sin_addr.s_addr);
return 0;
return(0);
} }
/* Called from the PROCfs module. */ /* Called from the PROCfs module. */
int rt_get_info(char *buffer) int
rt_get_info(char *buffer)
{ {
struct rtable *r; struct rtable *r;
char *pos; char *pos;
...@@ -308,7 +311,7 @@ int rt_get_info(char *buffer) ...@@ -308,7 +311,7 @@ int rt_get_info(char *buffer)
r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
r->rt_mask); r->rt_mask);
} }
return pos - buffer; return(pos - buffer);
} }
/* /*
...@@ -337,7 +340,8 @@ struct rtable * rt_route(unsigned long daddr, struct options *opt) ...@@ -337,7 +340,8 @@ struct rtable * rt_route(unsigned long daddr, struct options *opt)
} }
int rt_ioctl(unsigned int cmd, void *arg) int
rt_ioctl(unsigned int cmd, void *arg)
{ {
struct device *dev; struct device *dev;
struct rtentry rt; struct rtentry rt;
...@@ -349,17 +353,15 @@ int rt_ioctl(unsigned int cmd, void *arg) ...@@ -349,17 +353,15 @@ int rt_ioctl(unsigned int cmd, void *arg)
case DDIOCSDBG: case DDIOCSDBG:
ret = dbg_ioctl(arg, DBG_RT); ret = dbg_ioctl(arg, DBG_RT);
break; break;
case SIOCADDRT: case SIOCADDRT:
case SIOCDELRT: case SIOCDELRT:
if (!suser()) if (!suser()) return(-EPERM);
return -EPERM; err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
err = verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
if(err) if(err)
return err; return err;
memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
if (rt.rt_dev) { if (rt.rt_dev) {
err = verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf); err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
if(err) if(err)
return err; return err;
memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf); memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
...@@ -368,10 +370,9 @@ int rt_ioctl(unsigned int cmd, void *arg) ...@@ -368,10 +370,9 @@ int rt_ioctl(unsigned int cmd, void *arg)
} }
ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
return ret; return(ret);
} }
...@@ -303,9 +303,6 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list) ...@@ -303,9 +303,6 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list)
return *list; return *list;
} }
#ifdef UNUSED_NOW
/* /*
* Get a clone of an sk_buff. This is the safe way to peek at * 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 * a socket queue without accidents. Its a bit long but most
...@@ -372,8 +369,6 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list) ...@@ -372,8 +369,6 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
return(newsk); return(newsk);
} }
#endif
/* /*
* Free an sk_buff. This still knows about things it should * Free an sk_buff. This still knows about things it should
* not need to like protocols and sockets. * not need to like protocols and sockets.
...@@ -409,14 +404,12 @@ void kfree_skb(struct sk_buff *skb, int rw) ...@@ -409,14 +404,12 @@ void kfree_skb(struct sk_buff *skb, int rw)
else else
skb->sk->wmem_alloc-=skb->mem_len; skb->sk->wmem_alloc-=skb->mem_len;
if(!skb->sk->dead) if(!skb->sk->dead)
skb->sk->write_space(skb->sk); wake_up(skb->sk->sleep);
kfree_skbmem(skb->mem_addr,skb->mem_len); kfree_skbmem(skb->mem_addr,skb->mem_len);
} }
} }
else else
{
kfree_skbmem(skb->mem_addr, skb->mem_len); kfree_skbmem(skb->mem_addr, skb->mem_len);
}
} }
/* /*
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
* Alan Cox : Fraglist support (idea by Donald Becker) * Alan Cox : Fraglist support (idea by Donald Becker)
* Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy
* being used. * being used.
* Alan Cox : Extra fields for RAW fixes
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -29,7 +28,7 @@ ...@@ -29,7 +28,7 @@
#include <linux/malloc.h> #include <linux/malloc.h>
#ifdef CONFIG_IPX #ifdef CONFIG_IPX
#include "ipx/ipx.h" #include "ipx.h"
#endif #endif
#define HAVE_ALLOC_SKB /* For the drivers to know */ #define HAVE_ALLOC_SKB /* For the drivers to know */
...@@ -39,8 +38,7 @@ ...@@ -39,8 +38,7 @@
#define FREE_WRITE 0 #define FREE_WRITE 0
struct sk_buff struct sk_buff {
{
unsigned long magic_debug_cookie; unsigned long magic_debug_cookie;
struct sk_buff *volatile next; struct sk_buff *volatile next;
struct sk_buff *volatile prev; struct sk_buff *volatile prev;
...@@ -50,8 +48,7 @@ struct sk_buff ...@@ -50,8 +48,7 @@ struct sk_buff
volatile unsigned long when; /* used to compute rtt's */ volatile unsigned long when; /* used to compute rtt's */
struct device *dev; struct device *dev;
void *mem_addr; void *mem_addr;
union union {
{
struct tcphdr *th; struct tcphdr *th;
struct ethhdr *eth; struct ethhdr *eth;
struct iphdr *iph; struct iphdr *iph;
...@@ -63,7 +60,6 @@ struct sk_buff ...@@ -63,7 +60,6 @@ struct sk_buff
ipx_packet *ipx; ipx_packet *ipx;
#endif #endif
} h; } h;
struct iphdr * ip_hdr;
unsigned long mem_len; unsigned long mem_len;
unsigned long len; unsigned long len;
unsigned long fraglen; unsigned long fraglen;
......
/*
* 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;
}
}
/*
* 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
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -75,20 +75,16 @@ ...@@ -75,20 +75,16 @@
* normal compare so long as neither of the numbers is within * normal compare so long as neither of the numbers is within
* 4K of wrapping. Otherwise we must check for the wrap. * 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. */ /* this inequality is strict. */
if (seq1 == seq2) if (seq1 == seq2) return(0);
return(0);
if (seq1 < seq2) if (seq1 < seq2) {
{ if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL) {
if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL)
{
return(1); return(1);
} } else {
else
{
return(0); return(0);
} }
} }
...@@ -97,22 +93,23 @@ static inline int before (unsigned long seq1, unsigned long seq2) ...@@ -97,22 +93,23 @@ static inline int before (unsigned long seq1, unsigned long seq2)
* Now we know seq1 > seq2. So all we need to do is check * Now we know seq1 > seq2. So all we need to do is check
* to see if seq1 has wrapped. * to see if seq1 has wrapped.
*/ */
if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL)) if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL)) {
{
return(1); return(1);
} }
return(0); 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 ? */ /* 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,7 +121,8 @@ static inline int between(unsigned long seq1, unsigned long seq2, unsigned long ...@@ -124,7 +121,8 @@ static inline int between(unsigned long seq1, unsigned long seq2, unsigned long
* convinced that this is the solution for the 'getpeername(2)' * convinced that this is the solution for the 'getpeername(2)'
* problem. Thanks to Stephen A. Wood <saw@cebaf.gov> -FvK * 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 || return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 || state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* TIMER - implementation of software timers. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
* of inet_bh() with this socket being handled it goes * of inet_bh() with this socket being handled it goes
* BOOM! Have to stop timer going off if inet_bh is * BOOM! Have to stop timer going off if inet_bh is
* active or the destroy causes crashes. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -43,15 +41,16 @@ ...@@ -43,15 +41,16 @@
#include <asm/system.h> #include <asm/system.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "arp.h" #include "arp.h"
void delete_timer (struct sock *t) void
delete_timer (struct sock *t)
{ {
unsigned long flags; unsigned long flags;
...@@ -64,12 +63,14 @@ void delete_timer (struct sock *t) ...@@ -64,12 +63,14 @@ void delete_timer (struct sock *t)
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) if (timeout != -1)
t->timeout = timeout; t->timeout = timeout;
#if 1 #if 1
/* FIXME: ??? */ /* FIXME: ??? */
if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */
...@@ -85,15 +86,14 @@ void reset_timer (struct sock *t, int timeout, unsigned long len) ...@@ -85,15 +86,14 @@ void reset_timer (struct sock *t, int timeout, unsigned long len)
* something, but we must be sure to process all of the * something, but we must be sure to process all of the
* sockets that need it. * sockets that need it.
*/ */
void
void net_timer (unsigned long data) net_timer (unsigned long data)
{ {
struct sock *sk = (struct sock*)data; struct sock *sk = (struct sock*)data;
int why = sk->timeout; int why = sk->timeout;
/* timeout is overwritten by 'delete_timer' and 'reset_timer' */ /* timeout is overwritten by 'delete_timer' and 'reset_timer' */
if (sk->inuse || in_inet_bh()) if (sk->inuse || in_inet_bh()) {
{
sk->timer.expires = 10; sk->timer.expires = 10;
add_timer(&sk->timer); add_timer(&sk->timer);
return; return;
...@@ -105,19 +105,16 @@ void net_timer (unsigned long data) ...@@ -105,19 +105,16 @@ void net_timer (unsigned long data)
reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
/* Always see if we need to send an ack. */ /* Always see if we need to send an ack. */
if (sk->ack_backlog) if (sk->ack_backlog) {
{
sk->prot->read_wakeup (sk); sk->prot->read_wakeup (sk);
if (! sk->dead) if (! sk->dead)
wake_up (sk->sleep); wake_up (sk->sleep);
} }
/* Now we need to figure out why the socket was on the timer. */ /* Now we need to figure out why the socket was on the timer. */
switch (why) switch (why) {
{
case TIME_DONE: case TIME_DONE:
if (! sk->dead || sk->state != TCP_CLOSE) if (! sk->dead || sk->state != TCP_CLOSE) {
{
printk ("non dead socket in time_done\n"); printk ("non dead socket in time_done\n");
release_sock (sk); release_sock (sk);
break; break;
...@@ -144,7 +141,7 @@ void net_timer (unsigned long data) ...@@ -144,7 +141,7 @@ void net_timer (unsigned long data)
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
delete_timer (sk); delete_timer (sk);
/* Kill the ARP entry in case the hardware has changed. */ /* Kill the ARP entry in case the hardware has changed. */
arp_destroy_maybe (sk->daddr); arp_destroy (sk->daddr);
if (!sk->dead) if (!sk->dead)
wake_up (sk->sleep); wake_up (sk->sleep);
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
...@@ -155,11 +152,9 @@ void net_timer (unsigned long data) ...@@ -155,11 +152,9 @@ void net_timer (unsigned long data)
/* It could be we got here because we needed to send an ack. /* It could be we got here because we needed to send an ack.
* So we need to check for that. * So we need to check for that.
*/ */
if (sk->send_head) if (sk->send_head) {
{
if (jiffies < (sk->send_head->when + backoff (sk->backoff) if (jiffies < (sk->send_head->when + backoff (sk->backoff)
* (2 * sk->mdev + sk->rtt))) * (2 * sk->mdev + sk->rtt))) {
{
reset_timer (sk, TIME_WRITE, (sk->send_head->when reset_timer (sk, TIME_WRITE, (sk->send_head->when
+ backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies); + backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
release_sock (sk); release_sock (sk);
...@@ -170,24 +165,19 @@ void net_timer (unsigned long data) ...@@ -170,24 +165,19 @@ void net_timer (unsigned long data)
DPRINTF ((DBG_TMR, "retransmitting.\n")); DPRINTF ((DBG_TMR, "retransmitting.\n"));
sk->prot->retransmit (sk, 0); sk->prot->retransmit (sk, 0);
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
{
DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n"));
arp_destroy_maybe (sk->daddr); arp_destroy (sk->daddr);
ip_route_check (sk->daddr); ip_route_check (sk->daddr);
} }
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
{
DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n")); DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n"));
sk->err = ETIMEDOUT; sk->err = ETIMEDOUT;
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2
|| sk->state == TCP_LAST_ACK) || sk->state == TCP_LAST_ACK) {
{
sk->state = TCP_TIME_WAIT; sk->state = TCP_TIME_WAIT;
reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
} } else {
else
{
sk->prot->close (sk, 1); sk->prot->close (sk, 1);
break; break;
} }
...@@ -200,35 +190,29 @@ void net_timer (unsigned long data) ...@@ -200,35 +190,29 @@ void net_timer (unsigned long data)
if (sk->prot->write_wakeup) if (sk->prot->write_wakeup)
sk->prot->write_wakeup (sk); sk->prot->write_wakeup (sk);
sk->retransmits++; sk->retransmits++;
if (sk->shutdown == SHUTDOWN_MASK) if (sk->shutdown == SHUTDOWN_MASK) {
{
sk->prot->close (sk, 1); sk->prot->close (sk, 1);
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
} }
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
{
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n"));
arp_destroy_maybe (sk->daddr); arp_destroy (sk->daddr);
ip_route_check (sk->daddr); ip_route_check (sk->daddr);
release_sock (sk); release_sock (sk);
break; break;
} }
if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) {
{
DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n"));
arp_destroy_maybe (sk->daddr); arp_destroy (sk->daddr);
sk->err = ETIMEDOUT; sk->err = ETIMEDOUT;
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
{
sk->state = TCP_TIME_WAIT; sk->state = TCP_TIME_WAIT;
if (!sk->dead) if (!sk->dead)
wake_up (sk->sleep); wake_up (sk->sleep);
release_sock (sk); release_sock (sk);
} } else {
else
{
sk->prot->close (sk, 1); sk->prot->close (sk, 1);
} }
break; break;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* The User Datagram Protocol (UDP). * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -30,11 +30,10 @@ ...@@ -30,11 +30,10 @@
* bug no longer crashes it. * bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast. * Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -55,12 +54,12 @@ ...@@ -55,12 +54,12 @@
#include <linux/termios.h> #include <linux/termios.h>
#include <linux/mm.h> #include <linux/mm.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
#include "tcp.h" #include "tcp.h"
#include "skbuff.h" #include "skbuff.h"
#include "sockinet.h" #include "sock.h"
#include "udp.h" #include "udp.h"
#include "icmp.h" #include "icmp.h"
...@@ -68,13 +67,12 @@ ...@@ -68,13 +67,12 @@
#define min(a,b) ((a)<(b)?(a):(b)) #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) if (inet_debug != DBG_UDP) return;
return;
if (uh == NULL) if (uh == NULL) {
{
printk("(NULL)\n"); printk("(NULL)\n");
return; return;
} }
...@@ -93,8 +91,8 @@ static void print_udp(struct udphdr *uh) ...@@ -93,8 +91,8 @@ static void print_udp(struct udphdr *uh)
* header points to the first 8 bytes of the udp header. We need * header points to the first 8 bytes of the udp header. We need
* to find the appropriate port. * to find the appropriate port.
*/ */
void
void udp_err(int err, unsigned char *header, unsigned long daddr, udp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol) unsigned long saddr, struct inet_protocol *protocol)
{ {
struct udphdr *th; struct udphdr *th;
...@@ -106,7 +104,7 @@ void udp_err(int err, unsigned char *header, unsigned long daddr, ...@@ -106,7 +104,7 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
th = (struct udphdr *)header; th = (struct udphdr *)header;
DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\ 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)); 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);
...@@ -116,12 +114,11 @@ void udp_err(int err, unsigned char *header, unsigned long daddr, ...@@ -116,12 +114,11 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
if (err < 0) /* As per the calling spec */ if (err < 0) /* As per the calling spec */
{ {
sk->err = -err; sk->err = -err;
sk->error_report(sk); /* User process wakes to see error */ wake_up(sk->sleep); /* User process wakes to see error */
return; return;
} }
if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */
{ /* Slow down! */
if (sk->cong_window > 1) if (sk->cong_window > 1)
sk->cong_window = sk->cong_window/2; sk->cong_window = sk->cong_window/2;
return; return;
...@@ -130,15 +127,15 @@ void udp_err(int err, unsigned char *header, unsigned long daddr, ...@@ -130,15 +127,15 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
sk->err = icmp_err_convert[err & 0xff].errno; sk->err = icmp_err_convert[err & 0xff].errno;
/* It's only fatal if we have connected to them. */ /* It's only fatal if we have connected to them. */
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
{
sk->err=ECONNREFUSED; sk->err=ECONNREFUSED;
} }
sk->error_report(sk); 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 saddr, unsigned long daddr)
{ {
unsigned long sum; unsigned long sum;
...@@ -155,8 +152,7 @@ static unsigned short udp_check(struct udphdr *uh, int len, ...@@ -155,8 +152,7 @@ static unsigned short udp_check(struct udphdr *uh, int len,
: "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256) : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
: "cx","bx","dx" ); : "cx","bx","dx" );
if (len > 3) if (len > 3) {
{
__asm__("\tclc\n" __asm__("\tclc\n"
"1:\n" "1:\n"
"\t lodsl\n" "\t lodsl\n"
...@@ -178,8 +174,7 @@ static unsigned short udp_check(struct udphdr *uh, int len, ...@@ -178,8 +174,7 @@ static unsigned short udp_check(struct udphdr *uh, int len,
: "bx", "cx"); : "bx", "cx");
/* Check for an extra word. */ /* Check for an extra word. */
if ((len & 2) != 0) if ((len & 2) != 0) {
{
__asm__("\t lodsw\n" __asm__("\t lodsw\n"
"\t addw %%ax,%%bx\n" "\t addw %%ax,%%bx\n"
"\t adcw $0, %%bx\n" "\t adcw $0, %%bx\n"
...@@ -189,8 +184,7 @@ static unsigned short udp_check(struct udphdr *uh, int len, ...@@ -189,8 +184,7 @@ static unsigned short udp_check(struct udphdr *uh, int len,
} }
/* Now check for the extra byte. */ /* Now check for the extra byte. */
if ((len & 1) != 0) if ((len & 1) != 0) {
{
__asm__("\t lodsb\n" __asm__("\t lodsb\n"
"\t movb $0,%%ah\n" "\t movb $0,%%ah\n"
"\t addw %%ax,%%bx\n" "\t addw %%ax,%%bx\n"
...@@ -204,24 +198,21 @@ static unsigned short udp_check(struct udphdr *uh, int len, ...@@ -204,24 +198,21 @@ static unsigned short udp_check(struct udphdr *uh, int len,
return((~sum) & 0xffff); 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) unsigned long daddr, int len, struct sock *sk)
{ {
uh->check = 0; uh->check = 0;
if (sk && sk->no_check) if (sk && sk->no_check)
return; return;
uh->check = udp_check(uh, len, saddr, daddr); uh->check = udp_check(uh, len, saddr, daddr);
if (uh->check == 0) if (uh->check == 0) uh->check = 0xffff;
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) unsigned char *from, int len)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -243,9 +234,10 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin, ...@@ -243,9 +234,10 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
/* Allocate a copy of the packet. */ /* Allocate a copy of the packet. */
size = sizeof(struct sk_buff) + sk->prot->max_header + len; size = sizeof(struct sk_buff) + sk->prot->max_header + len;
skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL); skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
if (skb == NULL) if (skb == NULL) return(-ENOMEM);
return(-ENOMEM);
skb->mem_addr = skb;
skb->mem_len = size;
skb->sk = NULL; /* to avoid changing sk->saddr */ skb->sk = NULL; /* to avoid changing sk->saddr */
skb->free = 1; skb->free = 1;
skb->arp = 0; skb->arp = 0;
...@@ -257,12 +249,10 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin, ...@@ -257,12 +249,10 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n", 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)); saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr, tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
&dev, IPPROTO_UDP, sk->opt, skb->mem_len, &dev, IPPROTO_UDP, sk->opt, skb->mem_len);
sk->ip_ttl,sk->ip_tos);
skb->sk=sk; /* So memory is freed correctly */ skb->sk=sk; /* So memory is freed correctly */
if (tmp < 0 ) if (tmp < 0 ) {
{
sk->prot->wfree(sk, skb->mem_addr, skb->mem_len); sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
return(tmp); return(tmp);
} }
...@@ -272,9 +262,18 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin, ...@@ -272,9 +262,18 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */ skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
skb->dev = dev; 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) if (skb->len > 4095)
{ {
printk("UDP: send: length %d > mtu %d (ignored)\n", 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); sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
return(-EMSGSIZE); return(-EMSGSIZE);
} }
...@@ -299,7 +298,8 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin, ...@@ -299,7 +298,8 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
} }
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) unsigned flags, struct sockaddr_in *usin, int addr_len)
{ {
struct sockaddr_in sin; struct sockaddr_in sin;
...@@ -317,10 +317,8 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock ...@@ -317,10 +317,8 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
return(0); return(0);
/* Get and verify the address. */ /* Get and verify the address. */
if (usin) if (usin) {
{ if (addr_len < sizeof(sin)) return(-EINVAL);
if (addr_len < sizeof(sin))
return(-EINVAL);
err=verify_area(VERIFY_READ, usin, sizeof(sin)); err=verify_area(VERIFY_READ, usin, sizeof(sin));
if(err) if(err)
return err; return err;
...@@ -329,18 +327,15 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock ...@@ -329,18 +327,15 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
return(-EINVAL); return(-EINVAL);
if (sin.sin_port == 0) if (sin.sin_port == 0)
return(-EINVAL); return(-EINVAL);
} } else {
else if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
{
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_port = sk->dummy_th.dest; sin.sin_port = sk->dummy_th.dest;
sin.sin_addr.s_addr = sk->daddr; sin.sin_addr.s_addr = sk->daddr;
} }
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */ return -ENETUNREACH; /* Must turn broadcast on first */
sk->inuse = 1; sk->inuse = 1;
/* Send the packet. */ /* Send the packet. */
...@@ -352,30 +347,29 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock ...@@ -352,30 +347,29 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
} }
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) 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; int err;
switch(cmd) switch(cmd) {
{
case DDIOCSDBG: case DDIOCSDBG:
{ {
int val; int val;
if (!suser()) if (!suser()) return(-EPERM);
return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err) if(err)
return err; return err;
val = get_fs_long((int *)arg); val = get_fs_long((int *)arg);
switch(val) switch(val) {
{
case 0: case 0:
inet_debug = 0; inet_debug = 0;
break; break;
...@@ -387,14 +381,12 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -387,14 +381,12 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
} }
} }
break; break;
case TIOCOUTQ: case TIOCOUTQ:
{ {
unsigned long amount; unsigned long amount;
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN) return(-EINVAL);
return(-EINVAL); amount = sk->prot->wspace(sk)/*/2*/;
amount = sk->prot->wspace(sk);
err=verify_area(VERIFY_WRITE,(void *)arg, err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long)); sizeof(unsigned long));
if(err) if(err)
...@@ -408,12 +400,10 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -408,12 +400,10 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
struct sk_buff *skb; struct sk_buff *skb;
unsigned long amount; unsigned long amount;
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN) return(-EINVAL);
return(-EINVAL);
amount = 0; amount = 0;
skb = sk->rqueue; skb = sk->rqueue;
if (skb != NULL) if (skb != NULL) {
{
/* /*
* We will only return the amount * We will only return the amount
* of this packet since that is all * of this packet since that is all
...@@ -437,10 +427,11 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -437,10 +427,11 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
/* /*
* 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. * 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 noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len) int *addr_len)
{ {
...@@ -453,8 +444,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -453,8 +444,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
* This will pick up errors that occured while the program * This will pick up errors that occured while the program
* was doing something else. * was doing something else.
*/ */
if (sk->err) if (sk->err) {
{
int err; int err;
err = -sk->err; err = -sk->err;
...@@ -467,8 +457,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -467,8 +457,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
if (len < 0) if (len < 0)
return(-EINVAL); return(-EINVAL);
if (addr_len) if (addr_len) {
{
er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(er) if(er)
return(er); return(er);
...@@ -492,8 +481,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -492,8 +481,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
skb_copy_datagram(skb,sizeof(struct udphdr),to,copied); skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
/* Copy the address. */ /* Copy the address. */
if (sin) if (sin) {
{
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
...@@ -508,14 +496,16 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len, ...@@ -508,14 +496,16 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
} }
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) 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; struct sockaddr_in sin;
int er; int er;
...@@ -532,7 +522,7 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) ...@@ -532,7 +522,7 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return(-EAFNOSUPPORT); return(-EAFNOSUPPORT);
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */ return -ENETUNREACH; /* Must turn broadcast on first */
sk->daddr = sin.sin_addr.s_addr; sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port; sk->dummy_th.dest = sin.sin_port;
...@@ -541,22 +531,19 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) ...@@ -541,22 +531,19 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
} }
static void udp_close(struct sock *sk, int timeout) static void
udp_close(struct sock *sk, int timeout)
{ {
sk->inuse = 1; sk->inuse = 1;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
if (sk->dead) if (sk->dead) destroy_sock(sk);
destroy_sock(sk); else release_sock(sk);
else
release_sock(sk);
} }
/* /* All we need to do is get the socket, and then do a checksum. */
* 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,
int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol) unsigned long saddr, int redo, struct inet_protocol *protocol)
{ {
...@@ -581,8 +568,7 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -581,8 +568,7 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return(0); return(0);
} }
if (uh->check && udp_check(uh, len, saddr, daddr)) if (uh->check && udp_check(uh, len, saddr, daddr)) {
{
DPRINTF((DBG_UDP, "UDP: bad checksum\n")); DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb, FREE_WRITE); kfree_skb(skb, FREE_WRITE);
...@@ -593,7 +579,7 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -593,7 +579,7 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->dev = dev; skb->dev = dev;
skb->len = len; skb->len = len;
/* These are supposed to be switched. */ /* These are supposed to be switched. */
skb->daddr = saddr; skb->daddr = saddr;
skb->saddr = daddr; skb->saddr = daddr;
...@@ -618,17 +604,14 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, ...@@ -618,17 +604,14 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
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);
release_sock(sk);
return(0); return(0);
} }
struct proto udp_prot = struct proto udp_prot = {
{
sock_wmalloc, sock_wmalloc,
sock_rmalloc, sock_rmalloc,
sock_wfree, sock_wfree,
...@@ -652,8 +635,6 @@ struct proto udp_prot = ...@@ -652,8 +635,6 @@ struct proto udp_prot =
udp_ioctl, udp_ioctl,
NULL, NULL,
NULL, NULL,
ip_setsockopt,
ip_getsockopt,
128, 128,
0, 0,
{NULL,}, {NULL,},
......
...@@ -6,13 +6,12 @@ ...@@ -6,13 +6,12 @@
* Various kernel-resident INET utility functions; mainly * Various kernel-resident INET utility functions; mainly
* for format conversion and debugging output. * 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> * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* *
* Fixes: * Fixes:
* Alan Cox : verify_area check. * Alan Cox : verify_area check.
* Alan Cox : Clean up to match code style
* *
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -33,7 +32,7 @@ ...@@ -33,7 +32,7 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <stdarg.h> #include <stdarg.h>
#include "inet.h" #include "inet.h"
#include "devinet.h" #include "dev.h"
#include "eth.h" #include "eth.h"
#include "ip.h" #include "ip.h"
#include "protocol.h" #include "protocol.h"
...@@ -42,10 +41,7 @@ ...@@ -42,10 +41,7 @@
#include "arp.h" #include "arp.h"
/* /* Display an IP address in readable format. */
* Display an IP address in readable format.
*/
char *in_ntoa(unsigned long in) char *in_ntoa(unsigned long in)
{ {
static char buff[18]; static char buff[18];
...@@ -58,50 +54,43 @@ char *in_ntoa(unsigned long in) ...@@ -58,50 +54,43 @@ char *in_ntoa(unsigned long in)
} }
/* /* Convert an ASCII string to binary IP. */
* Convert an ASCII string to binary IP. unsigned long
*/ in_aton(char *str)
unsigned long in_aton(char *str)
{ {
unsigned long l; unsigned long l;
unsigned int val; unsigned int val;
int i; int i;
l = 0; l = 0;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++) {
{
l <<= 8; l <<= 8;
if (*str != '\0') if (*str != '\0') {
{
val = 0; val = 0;
while (*str != '\0' && *str != '.') while (*str != '\0' && *str != '.') {
{
val *= 10; val *= 10;
val += *str - '0'; val += *str - '0';
str++; str++;
} }
l |= val; l |= val;
if (*str != '\0') if (*str != '\0') str++;
str++;
} }
} }
return(htonl(l)); return(htonl(l));
} }
void dprintf(int level, char *fmt, ...) void
dprintf(int level, char *fmt, ...)
{ {
va_list args; va_list args;
char *buff; char *buff;
extern int vsprintf(char * buf, const char * fmt, va_list args); extern int vsprintf(char * buf, const char * fmt, va_list args);
if (level != inet_debug) if (level != inet_debug) return;
return;
buff = (char *) kmalloc(256, GFP_ATOMIC); buff = (char *) kmalloc(256, GFP_ATOMIC);
if (buff != NULL) if (buff != NULL) {
{
va_start(args, fmt); va_start(args, fmt);
vsprintf(buff, fmt, args); vsprintf(buff, fmt, args);
va_end(args); va_end(args);
...@@ -111,19 +100,18 @@ void dprintf(int level, char *fmt, ...) ...@@ -111,19 +100,18 @@ void dprintf(int level, char *fmt, ...)
} }
int dbg_ioctl(void *arg, int level) int
dbg_ioctl(void *arg, int level)
{ {
int val; int val;
int err; int err;
if (!suser()) if (!suser()) return(-EPERM);
return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err) if(err)
return err; return err;
val = get_fs_long((int *)arg); val = get_fs_long((int *)arg);
switch(val) switch(val) {
{
case 0: /* OFF */ case 0: /* OFF */
inet_debug = DBG_OFF; inet_debug = DBG_OFF;
break; break;
......
#
# 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
/*
* 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;
}
}
}
/*
* 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 */
/*
* 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));
}
}
}
/*
* 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 */
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* the PROC file system and the "unix" family of networking * the PROC file system and the "unix" family of networking
* protocols. It is mainly used for debugging and statistics. * 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> * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
...@@ -16,14 +16,12 @@ ...@@ -16,14 +16,12 @@
* Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de> * Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
* *
* Fixes: * Fixes:
* Anonymous : Comment errors
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#include <linux/autoconf.h> #include <linux/autoconf.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -35,10 +33,7 @@ ...@@ -35,10 +33,7 @@
#include "unix.h" #include "unix.h"
/* /* Called from PROCfs. */
* Called from PROCfs.
*/
int unix_get_info(char *buffer) int unix_get_info(char *buffer)
{ {
char *pos; char *pos;
...@@ -47,10 +42,8 @@ int unix_get_info(char *buffer) ...@@ -47,10 +42,8 @@ int unix_get_info(char *buffer)
pos = buffer; pos = buffer;
pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n"); pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
for(i = 0; i < NSOCKETS; i++) for(i = 0; i < NSOCKETS; i++) {
{ if (unix_datas[i].refcnt) {
if (unix_datas[i].refcnt)
{
pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i, pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
unix_datas[i].refcnt, unix_datas[i].refcnt,
unix_datas[i].protocol, unix_datas[i].protocol,
...@@ -60,13 +53,10 @@ int unix_get_info(char *buffer) ...@@ -60,13 +53,10 @@ int unix_get_info(char *buffer)
); );
/* If socket is bound to a filename, we'll print it. */ /* If socket is bound to a filename, we'll print it. */
if(unix_datas[i].sockaddr_len>0) if(unix_datas[i].sockaddr_len>0) {
{
pos += sprintf(pos, " %s\n", pos += sprintf(pos, " %s\n",
unix_datas[i].sockaddr_un.sun_path); unix_datas[i].sockaddr_un.sun_path);
} } else { /* just add a newline */
else
{ /* just add a newline */
*pos='\n'; *pos='\n';
pos++; pos++;
*pos='\0'; *pos='\0';
...@@ -77,9 +67,7 @@ int unix_get_info(char *buffer) ...@@ -77,9 +67,7 @@ int unix_get_info(char *buffer)
* Since sockets may have very very long paths, we make * Since sockets may have very very long paths, we make
* PATH_MAX+80 the minimum space left for a new line. * PATH_MAX+80 the minimum space left for a new line.
*/ */
if (pos > buffer+PAGE_SIZE-80-PATH_MAX) {
if (pos > buffer+PAGE_SIZE-80-PATH_MAX)
{
printk("UNIX: netinfo: oops, too many sockets.\n"); printk("UNIX: netinfo: oops, too many sockets.\n");
return(pos - buffer); return(pos - buffer);
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* BSD Socket interface as the means of communication with * BSD Socket interface as the means of communication with
* the user level. * 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> * Authors: Orest Zborowski, <obz@Kodak.COM>
* Ross Biro, <bir7@leland.Stanford.Edu> * Ross Biro, <bir7@leland.Stanford.Edu>
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
* *
* Fixes: * Fixes:
* Alan Cox : Verify Area * Alan Cox : Verify Area
* Alan Cox : Tidy up ready for release
* *
* BUGS * BUGS
* Page faults on read while another process reads could lose data. * Page faults on read while another process reads could lose data.
...@@ -94,18 +93,17 @@ static int unix_proto_getsockopt(struct socket *sock, int level, int optname, ...@@ -94,18 +93,17 @@ static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen); char *optval, int *optlen);
static void dprintf(int level, char *fmt, ...) static void
dprintf(int level, char *fmt, ...)
{ {
va_list args; va_list args;
char *buff; char *buff;
extern int vsprintf(char * buf, const char * fmt, va_list args); extern int vsprintf(char * buf, const char * fmt, va_list args);
if (level != unix_debug) if (level != unix_debug) return;
return;
buff = (char *) kmalloc(256, GFP_KERNEL); buff = (char *) kmalloc(256, GFP_KERNEL);
if (buff != NULL) if (buff != NULL) {
{
va_start(args, fmt); va_start(args, fmt);
vsprintf(buff, fmt, args); vsprintf(buff, fmt, args);
va_end(args); va_end(args);
...@@ -115,28 +113,27 @@ static void dprintf(int level, char *fmt, ...) ...@@ -115,28 +113,27 @@ static void dprintf(int level, char *fmt, ...)
} }
static inline int min(int a, int b) static inline int
min(int a, int b)
{ {
if (a < b) if (a < b) return(a);
return(a);
return(b); 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]; char buf[sizeof(sockun->sun_path) + 1];
if (unix_debug == 0) if (unix_debug == 0) return;
return;
sockaddr_len -= UN_PATH_OFFSET; sockaddr_len -= UN_PATH_OFFSET;
if (sockun->sun_family != AF_UNIX) if (sockun->sun_family != AF_UNIX)
printk("UNIX: Badd addr family %d>\n", sockun->sun_family); printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf)) else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
printk("UNIX: Bad addr len %d>\n", sockaddr_len); printk("UNIX: Bad addr len %d>\n", sockaddr_len);
else else {
{
memcpy(buf, sockun->sun_path, sockaddr_len); memcpy(buf, sockun->sun_path, sockaddr_len);
buf[sockaddr_len] = '\0'; buf[sockaddr_len] = '\0';
printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET); printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET);
...@@ -144,102 +141,95 @@ void sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len) ...@@ -144,102 +141,95 @@ void sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
} }
/* /* don't have to do anything. */
* Don't have to do anything. static int
*/ unix_proto_listen(struct socket *sock, int backlog)
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) 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) 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) 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) 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. */
* This error needs to be checked. static int
*/ unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
static int unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags) unsigned flags)
{ {
if (flags != 0) if (flags != 0) return(-EINVAL);
return(-EINVAL);
return(unix_proto_write(sock, (char *) buff, len, nonblock)); return(unix_proto_write(sock, (char *) buff, len, nonblock));
} }
/* /* This error needs to be checked. */
* This error needs to be checked. static int
*/ unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
static int unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags) unsigned flags)
{ {
if (flags != 0) if (flags != 0) return(-EINVAL);
return(-EINVAL);
return(unix_proto_read(sock, (char *) buff, len, nonblock)); 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 inode *inode)
{ {
struct unix_proto_data *upd; struct unix_proto_data *upd;
for(upd = unix_datas; upd <= last_unix_data; ++upd) for(upd = unix_datas; upd <= last_unix_data; ++upd) {
{
if (upd->refcnt && upd->socket && if (upd->refcnt && upd->socket &&
upd->socket->state == SS_UNCONNECTED && upd->socket->state == SS_UNCONNECTED &&
upd->sockaddr_un.sun_family == sockun->sun_family && upd->sockaddr_un.sun_family == sockun->sun_family &&
upd->inode == inode) upd->inode == inode) return(upd);
{
return(upd);
}
} }
return(NULL); 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; struct unix_proto_data *upd;
cli(); cli();
for(upd = unix_datas; upd <= last_unix_data; ++upd) for(upd = unix_datas; upd <= last_unix_data; ++upd) {
{ if (!upd->refcnt) {
if (!upd->refcnt)
{
upd->refcnt = 1; upd->refcnt = 1;
sti(); sti();
upd->socket = NULL; upd->socket = NULL;
...@@ -257,10 +247,10 @@ static struct unix_proto_data *unix_data_alloc(void) ...@@ -257,10 +247,10 @@ static struct unix_proto_data *unix_data_alloc(void)
} }
static inline void unix_data_ref(struct unix_proto_data *upd) static inline void
unix_data_ref(struct unix_proto_data *upd)
{ {
if (!upd) if (!upd) {
{
dprintf(1, "UNIX: data_ref: upd = NULL\n"); dprintf(1, "UNIX: data_ref: upd = NULL\n");
return; return;
} }
...@@ -269,18 +259,16 @@ static inline void unix_data_ref(struct unix_proto_data *upd) ...@@ -269,18 +259,16 @@ static inline void unix_data_ref(struct unix_proto_data *upd)
} }
static void unix_data_deref(struct unix_proto_data *upd) static void
unix_data_deref(struct unix_proto_data *upd)
{ {
if (!upd) if (!upd) {
{
dprintf(1, "UNIX: data_deref: upd = NULL\n"); dprintf(1, "UNIX: data_deref: upd = NULL\n");
return; return;
} }
if (upd->refcnt == 1) if (upd->refcnt == 1) {
{
dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd); dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
if (upd->buf) if (upd->buf) {
{
free_page((unsigned long)upd->buf); free_page((unsigned long)upd->buf);
upd->buf = NULL; upd->buf = NULL;
upd->bp_head = upd->bp_tail = 0; upd->bp_head = upd->bp_tail = 0;
...@@ -294,24 +282,21 @@ static void unix_data_deref(struct unix_proto_data *upd) ...@@ -294,24 +282,21 @@ static void unix_data_deref(struct unix_proto_data *upd)
* Upon a create, we allocate an empty protocol data, * Upon a create, we allocate an empty protocol data,
* and grab a page to buffer writes. * and grab a page to buffer writes.
*/ */
static int
static int unix_proto_create(struct socket *sock, int protocol) unix_proto_create(struct socket *sock, int protocol)
{ {
struct unix_proto_data *upd; struct unix_proto_data *upd;
dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol); dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
if (protocol != 0) if (protocol != 0) {
{
dprintf(1, "UNIX: create: protocol != 0\n"); dprintf(1, "UNIX: create: protocol != 0\n");
return(-EINVAL); return(-EINVAL);
} }
if (!(upd = unix_data_alloc())) if (!(upd = unix_data_alloc())) {
{
printk("UNIX: create: can't allocate buffer\n"); printk("UNIX: create: can't allocate buffer\n");
return(-ENOMEM); return(-ENOMEM);
} }
if (!(upd->buf = (char*) get_free_page(GFP_USER))) if (!(upd->buf = (char*) get_free_page(GFP_USER))) {
{
printk("UNIX: create: can't get page!\n"); printk("UNIX: create: can't get page!\n");
unix_data_deref(upd); unix_data_deref(upd);
return(-ENOMEM); return(-ENOMEM);
...@@ -324,7 +309,8 @@ static int unix_proto_create(struct socket *sock, int protocol) ...@@ -324,7 +309,8 @@ static int unix_proto_create(struct socket *sock, int protocol)
} }
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);
...@@ -332,28 +318,25 @@ static int unix_proto_dup(struct socket *newsock, struct socket *oldsock) ...@@ -332,28 +318,25 @@ static int unix_proto_dup(struct socket *newsock, struct socket *oldsock)
} }
static int unix_proto_release(struct socket *sock, struct socket *peer) static int
unix_proto_release(struct socket *sock, struct socket *peer)
{ {
struct unix_proto_data *upd = UN_DATA(sock); struct unix_proto_data *upd = UN_DATA(sock);
dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd); dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
if (!upd) if (!upd) return(0);
return(0); if (upd->socket != sock) {
if (upd->socket != sock)
{
printk("UNIX: release: socket link mismatch!\n"); printk("UNIX: release: socket link mismatch!\n");
return(-EINVAL); return(-EINVAL);
} }
if (upd->inode) if (upd->inode) {
{
dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode); dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
iput(upd->inode); iput(upd->inode);
upd->inode = NULL; upd->inode = NULL;
} }
UN_DATA(sock) = NULL; UN_DATA(sock) = NULL;
upd->socket = NULL; upd->socket = NULL;
if (upd->peerupd) if (upd->peerupd) unix_data_deref(upd->peerupd);
unix_data_deref(upd->peerupd);
unix_data_deref(upd); unix_data_deref(upd);
return(0); return(0);
} }
...@@ -368,7 +351,8 @@ static int unix_proto_release(struct socket *sock, struct socket *peer) ...@@ -368,7 +351,8 @@ static int unix_proto_release(struct socket *sock, struct socket *peer)
* Here we return EINVAL, but it may be necessary to re-bind. * Here we return EINVAL, but it may be necessary to re-bind.
* I think thats what BSD does in the case of datagram sockets... * 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) int sockaddr_len)
{ {
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
...@@ -378,13 +362,12 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, ...@@ -378,13 +362,12 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
int er; int er;
dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len); 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)) if (sockaddr_len <= UN_PATH_OFFSET ||
{ sockaddr_len > sizeof(struct sockaddr_un)) {
dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len); dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
return(-EINVAL); return(-EINVAL);
} }
if (upd->sockaddr_len || upd->inode) if (upd->sockaddr_len || upd->inode) {
{
printk("UNIX: bind: already bound!\n"); printk("UNIX: bind: already bound!\n");
return(-EINVAL); return(-EINVAL);
} }
...@@ -393,8 +376,7 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, ...@@ -393,8 +376,7 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
return er; return er;
memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len); memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
if (upd->sockaddr_un.sun_family != AF_UNIX) if (upd->sockaddr_un.sun_family != AF_UNIX) {
{
dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n", dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
upd->sockaddr_un.sun_family, AF_UNIX); upd->sockaddr_un.sun_family, AF_UNIX);
return(-EINVAL); return(-EINVAL);
...@@ -405,11 +387,9 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, ...@@ -405,11 +387,9 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
old_fs = get_fs(); old_fs = get_fs();
set_fs(get_ds()); set_fs(get_ds());
i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0); i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
if (i == 0) if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
set_fs(old_fs); set_fs(old_fs);
if (i < 0) if (i < 0) {
{
printk("UNIX: bind: can't open socket %s\n", fname); printk("UNIX: bind: can't open socket %s\n", fname);
return(i); return(i);
} }
...@@ -427,8 +407,8 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, ...@@ -427,8 +407,8 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
* (I can't for the life of me find an application where that * (I can't for the life of me find an application where that
* wouldn't be the case!) * wouldn't be the case!)
*/ */
static int
static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len, int flags) int sockaddr_len, int flags)
{ {
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
...@@ -441,23 +421,20 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -441,23 +421,20 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len); 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)) if (sockaddr_len <= UN_PATH_OFFSET ||
{ sockaddr_len > sizeof(struct sockaddr_un)) {
dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len); dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len);
return(-EINVAL); return(-EINVAL);
} }
if (sock->state == SS_CONNECTING) if (sock->state == SS_CONNECTING) return(-EINPROGRESS);
return(-EINPROGRESS); if (sock->state == SS_CONNECTED) return(-EISCONN);
if (sock->state == SS_CONNECTED)
return(-EISCONN);
er=verify_area(VERIFY_READ, uservaddr, sockaddr_len); er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
if(er) if(er)
return er; return er;
memcpy_fromfs(&sockun, uservaddr, sockaddr_len); memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
if (sockun.sun_family != AF_UNIX) if (sockun.sun_family != AF_UNIX) {
{
dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n", dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
sockun.sun_family, AF_UNIX); sockun.sun_family, AF_UNIX);
return(-EINVAL); return(-EINVAL);
...@@ -469,33 +446,28 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -469,33 +446,28 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
* hold onto the inode that long, just enough to find our * hold onto the inode that long, just enough to find our
* server. When we're connected, we mooch off the server. * server. When we're connected, we mooch off the server.
*/ */
memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET); memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
fname[sockaddr_len-UN_PATH_OFFSET] = '\0'; fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
old_fs = get_fs(); old_fs = get_fs();
set_fs(get_ds()); set_fs(get_ds());
i = open_namei(fname, 0, S_IFSOCK, &inode, NULL); i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
set_fs(old_fs); set_fs(old_fs);
if (i < 0) if (i < 0) {
{
dprintf(1, "UNIX: connect: can't open socket %s\n", fname); dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
return(i); return(i);
} }
serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode); serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
iput(inode); iput(inode);
if (!serv_upd) if (!serv_upd) {
{
dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n", dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
fname, inode); fname, inode);
return(-EINVAL); return(-EINVAL);
} }
if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
{
dprintf(1, "UNIX: connect: can't await connection\n"); dprintf(1, "UNIX: connect: can't await connection\n");
return(i); return(i);
} }
if (sock->conn) if (sock->conn) {
{
unix_data_ref(UN_DATA(sock->conn)); unix_data_ref(UN_DATA(sock->conn));
UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */ UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */
} }
...@@ -509,8 +481,8 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, ...@@ -509,8 +481,8 @@ static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
* for a wait area, and deadlock prevention in the case of a process * for a wait area, and deadlock prevention in the case of a process
* writing to itself is, ignored, in true unix fashion! * writing to itself is, ignored, in true unix fashion!
*/ */
static int
static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2) 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);
...@@ -523,8 +495,8 @@ static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2) ...@@ -523,8 +495,8 @@ static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
/* On accept, we ref the peer's data for safe writes. */ /* On accept, we ref the peer's data for safe writes. */
static int
static int unix_proto_accept(struct socket *sock, struct socket *newsock, int flags) unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
struct socket *clientsock; struct socket *clientsock;
...@@ -535,13 +507,10 @@ static int unix_proto_accept(struct socket *sock, struct socket *newsock, int fl ...@@ -535,13 +507,10 @@ static int unix_proto_accept(struct socket *sock, struct socket *newsock, int fl
* If there aren't any sockets awaiting connection, * If there aren't any sockets awaiting connection,
* then wait for one, unless nonblocking. * then wait for one, unless nonblocking.
*/ */
while(!(clientsock = sock->iconn)) while(!(clientsock = sock->iconn)) {
{ if (flags & O_NONBLOCK) return(-EAGAIN);
if (flags & O_NONBLOCK)
return(-EAGAIN);
interruptible_sleep_on(sock->wait); interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked) {
{
dprintf(1, "UNIX: accept: sleep was interrupted\n"); dprintf(1, "UNIX: accept: sleep was interrupted\n");
return(-ERESTARTSYS); return(-ERESTARTSYS);
} }
...@@ -566,11 +535,9 @@ static int unix_proto_accept(struct socket *sock, struct socket *newsock, int fl ...@@ -566,11 +535,9 @@ static int unix_proto_accept(struct socket *sock, struct socket *newsock, int fl
} }
/* /* Gets the current name or the name of the connected socket. */
* Gets the current name or the name of the connected socket. static int
*/ unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
int *usockaddr_len, int peer) int *usockaddr_len, int peer)
{ {
struct unix_proto_data *upd; struct unix_proto_data *upd;
...@@ -578,27 +545,21 @@ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, ...@@ -578,27 +545,21 @@ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
int er; int er;
dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self"); dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
if (peer) if (peer) {
{ if (sock->state != SS_CONNECTED) {
if (sock->state != SS_CONNECTED)
{
dprintf(1, "UNIX: getname: socket not connected\n"); dprintf(1, "UNIX: getname: socket not connected\n");
return(-EINVAL); return(-EINVAL);
} }
upd = UN_DATA(sock->conn); upd = UN_DATA(sock->conn);
} } else
else
upd = UN_DATA(sock); upd = UN_DATA(sock);
er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len)); er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
if(er) if(er)
return er; return er;
if ((len = get_fs_long(usockaddr_len)) <= 0) if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL);
return(-EINVAL); if (len > upd->sockaddr_len) len = upd->sockaddr_len;
if (len > upd->sockaddr_len) if (len) {
len = upd->sockaddr_len;
if (len)
{
er=verify_area(VERIFY_WRITE, usockaddr, len); er=verify_area(VERIFY_WRITE, usockaddr, len);
if(er) if(er)
return er; return er;
...@@ -610,29 +571,24 @@ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, ...@@ -610,29 +571,24 @@ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
/* We read from our own buf. */ /* We read from our own buf. */
static int
static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
{ {
struct unix_proto_data *upd; struct unix_proto_data *upd;
int todo, avail; int todo, avail;
int er; int er;
if ((todo = size) <= 0) if ((todo = size) <= 0) return(0);
return(0);
upd = UN_DATA(sock); upd = UN_DATA(sock);
while(!(avail = UN_BUF_AVAIL(upd))) while(!(avail = UN_BUF_AVAIL(upd))) {
{ if (sock->state != SS_CONNECTED) {
if (sock->state != SS_CONNECTED)
{
dprintf(1, "UNIX: read: socket not connected\n"); dprintf(1, "UNIX: read: socket not connected\n");
return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL); return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
} }
dprintf(1, "UNIX: read: no data available...\n"); dprintf(1, "UNIX: read: no data available...\n");
if (nonblock) if (nonblock) return(-EAGAIN);
return(-EAGAIN);
interruptible_sleep_on(sock->wait); interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked) {
{
dprintf(1, "UNIX: read: interrupted\n"); dprintf(1, "UNIX: read: interrupted\n");
return(-ERESTARTSYS); return(-ERESTARTSYS);
} }
...@@ -642,39 +598,28 @@ static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblo ...@@ -642,39 +598,28 @@ static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblo
* Copy from the read buffer into the user's buffer, * Copy from the read buffer into the user's buffer,
* watching for wraparound. Then we wake up the writer. * watching for wraparound. Then we wake up the writer.
*/ */
do {
do
{
int part, cando; int part, cando;
if (avail <= 0) if (avail <= 0) {
{
printk("UNIX: read: AVAIL IS NEGATIVE!!!\n"); printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
send_sig(SIGKILL, current, 1); send_sig(SIGKILL, current, 1);
return(-EPIPE); return(-EPIPE);
} }
if ((cando = todo) > avail) if ((cando = todo) > avail) cando = avail;
cando = avail; if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part;
if (cando >(part = BUF_SIZE - upd->bp_tail))
cando = part;
dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n", dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
avail, todo, cando); avail, todo, cando);
if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0) if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
return er; return er;
memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando); memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1); upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
ubuf += cando; ubuf += cando;
todo -= cando; todo -= cando;
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
if (sock->state == SS_CONNECTED)
wake_up(sock->conn->wait);
avail = UN_BUF_AVAIL(upd); avail = UN_BUF_AVAIL(upd);
} } while(todo && avail);
while(todo && avail);
return(size - todo); return(size - todo);
} }
...@@ -684,19 +629,17 @@ static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblo ...@@ -684,19 +629,17 @@ 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 so we are safe that the buffer remains, even after the
* peer has disconnected, which we check other ways. * peer has disconnected, which we check other ways.
*/ */
static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) static int
unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
{ {
struct unix_proto_data *pupd; struct unix_proto_data *pupd;
int todo, space; int todo, space;
int er; int er;
if ((todo = size) <= 0) if ((todo = size) <= 0) return(0);
return(0); if (sock->state != SS_CONNECTED) {
if (sock->state != SS_CONNECTED)
{
dprintf(1, "UNIX: write: socket not connected\n"); dprintf(1, "UNIX: write: socket not connected\n");
if (sock->state == SS_DISCONNECTING) if (sock->state == SS_DISCONNECTING) {
{
send_sig(SIGPIPE, current, 1); send_sig(SIGPIPE, current, 1);
return(-EPIPE); return(-EPIPE);
} }
...@@ -704,19 +647,15 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonbl ...@@ -704,19 +647,15 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonbl
} }
pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */
while(!(space = UN_BUF_SPACE(pupd))) while(!(space = UN_BUF_SPACE(pupd))) {
{
dprintf(1, "UNIX: write: no space left...\n"); dprintf(1, "UNIX: write: no space left...\n");
if (nonblock) if (nonblock) return(-EAGAIN);
return(-EAGAIN);
interruptible_sleep_on(sock->wait); interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked) if (current->signal & ~current->blocked) {
{
dprintf(1, "UNIX: write: interrupted\n"); dprintf(1, "UNIX: write: interrupted\n");
return(-ERESTARTSYS); return(-ERESTARTSYS);
} }
if (sock->state == SS_DISCONNECTING) if (sock->state == SS_DISCONNECTING) {
{
dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n"); dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
send_sig(SIGPIPE, current, 1); send_sig(SIGPIPE, current, 1);
return(-EPIPE); return(-EPIPE);
...@@ -727,13 +666,10 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonbl ...@@ -727,13 +666,10 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonbl
* Copy from the user's buffer to the write buffer, * Copy from the user's buffer to the write buffer,
* watching for wraparound. Then we wake up the reader. * watching for wraparound. Then we wake up the reader.
*/ */
do {
do
{
int part, cando; int part, cando;
if (space <= 0) if (space <= 0) {
{
printk("UNIX: write: SPACE IS NEGATIVE!!!\n"); printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
send_sig(SIGKILL, current, 1); send_sig(SIGKILL, current, 1);
return(-EPIPE); return(-EPIPE);
...@@ -743,52 +679,39 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonbl ...@@ -743,52 +679,39 @@ static int unix_proto_write(struct socket *sock, char *ubuf, int size, int nonbl
* We may become disconnected inside this loop, so watch * We may become disconnected inside this loop, so watch
* for it (peerupd is safe until we close). * for it (peerupd is safe until we close).
*/ */
if (sock->state == SS_DISCONNECTING) {
if (sock->state == SS_DISCONNECTING)
{
send_sig(SIGPIPE, current, 1); send_sig(SIGPIPE, current, 1);
return(-EPIPE); return(-EPIPE);
} }
if ((cando = todo) > space) if ((cando = todo) > space) cando = space;
cando = space; if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;
if (cando >(part = BUF_SIZE - pupd->bp_head))
cando = part;
dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n", dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
space, todo, cando); space, todo, cando);
er=verify_area(VERIFY_READ, ubuf, cando); er=verify_area(VERIFY_READ, ubuf, cando);
if(er) if(er)
return er; return er;
memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1); pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
ubuf += cando; ubuf += cando;
todo -= cando; todo -= cando;
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
if (sock->state == SS_CONNECTED)
wake_up(sock->conn->wait);
space = UN_BUF_SPACE(pupd); space = UN_BUF_SPACE(pupd);
} } while(todo && space);
while(todo && space);
return(size - todo); 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; struct unix_proto_data *upd, *peerupd;
/* Handle server sockets specially. */ /* Handle server sockets specially. */
if (sock->flags & SO_ACCEPTCON) if (sock->flags & SO_ACCEPTCON) {
{ if (sel_type == SEL_IN) {
if (sel_type == SEL_IN)
{
dprintf(1, "UNIX: select: %sconnections pending\n", dprintf(1, "UNIX: select: %sconnections pending\n",
sock->iconn ? "" : "no "); sock->iconn ? "" : "no ");
if (sock->iconn) if (sock->iconn) return(1);
return(1);
select_wait(sock->wait, wait); select_wait(sock->wait, wait);
return(sock->iconn ? 1 : 0); return(sock->iconn ? 1 : 0);
} }
...@@ -797,33 +720,28 @@ static int unix_proto_select(struct socket *sock, int sel_type, select_table * w ...@@ -797,33 +720,28 @@ static int unix_proto_select(struct socket *sock, int sel_type, select_table * w
return(0); return(0);
} }
if (sel_type == SEL_IN) if (sel_type == SEL_IN) {
{
upd = UN_DATA(sock); upd = UN_DATA(sock);
dprintf(1, "UNIX: select: there is%s data available\n", dprintf(1, "UNIX: select: there is%s data available\n",
UN_BUF_AVAIL(upd) ? "" : " no"); UN_BUF_AVAIL(upd) ? "" : " no");
if (UN_BUF_AVAIL(upd)) /* even if disconnected */ if (UN_BUF_AVAIL(upd)) /* even if disconnected */
return(1); return(1);
else if (sock->state != SS_CONNECTED) else if (sock->state != SS_CONNECTED) {
{
dprintf(1, "UNIX: select: socket not connected(read EOF)\n"); dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
return(1); return(1);
} }
select_wait(sock->wait,wait); select_wait(sock->wait,wait);
return(0); return(0);
} }
if (sel_type == SEL_OUT) if (sel_type == SEL_OUT) {
{ if (sock->state != SS_CONNECTED) {
if (sock->state != SS_CONNECTED)
{
dprintf(1, "UNIX: select: socket not connected(write EOF)\n"); dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
return(1); return(1);
} }
peerupd = UN_DATA(sock->conn); peerupd = UN_DATA(sock->conn);
dprintf(1, "UNIX: select: there is%s space available\n", dprintf(1, "UNIX: select: there is%s space available\n",
UN_BUF_SPACE(peerupd) ? "" : " no"); UN_BUF_SPACE(peerupd) ? "" : " no");
if (UN_BUF_SPACE(peerupd) > 0) if (UN_BUF_SPACE(peerupd) > 0) return(1);
return(1);
select_wait(sock->wait,wait); select_wait(sock->wait,wait);
return(0); return(0);
} }
...@@ -834,7 +752,8 @@ static int unix_proto_select(struct socket *sock, int sel_type, select_table * w ...@@ -834,7 +752,8 @@ static int unix_proto_select(struct socket *sock, int sel_type, select_table * w
} }
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; struct unix_proto_data *upd, *peerupd;
int er; int er;
...@@ -842,11 +761,9 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -842,11 +761,9 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long
upd = UN_DATA(sock); upd = UN_DATA(sock);
peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL; peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
switch(cmd) switch(cmd) {
{
case TIOCINQ: case TIOCINQ:
if (sock->flags & SO_ACCEPTCON) if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
return(-EINVAL);
er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
if(er) if(er)
return er; return er;
...@@ -856,13 +773,12 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -856,13 +773,12 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long
put_fs_long(0,(unsigned long *)arg); put_fs_long(0,(unsigned long *)arg);
break; break;
case TIOCOUTQ: case TIOCOUTQ:
if (sock->flags & SO_ACCEPTCON) if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
return(-EINVAL);
er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
if(er) if(er)
return er; return er;
if (peerupd) if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd),
put_fs_long(UN_BUF_SPACE(peerupd), (unsigned long *)arg); (unsigned long *)arg);
else else
put_fs_long(0,(unsigned long *)arg); put_fs_long(0,(unsigned long *)arg);
break; break;
...@@ -873,27 +789,28 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long ...@@ -873,27 +789,28 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long
} }
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"); dprintf(1, "UNIX: open\n");
minor = MINOR(inode->i_rdev); minor = MINOR(inode->i_rdev);
if (minor != 0) return(-ENODEV);
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, static int
unix_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int minor, ret; int minor, ret;
...@@ -901,20 +818,16 @@ static int unix_ioctl(struct inode *inode, struct file *file, ...@@ -901,20 +818,16 @@ static int unix_ioctl(struct inode *inode, struct file *file,
dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg); dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg);
minor = MINOR(inode->i_rdev); minor = MINOR(inode->i_rdev);
if (minor != 0) return(-ENODEV);
if (minor != 0)
return(-ENODEV);
ret = -EINVAL; ret = -EINVAL;
switch(cmd) switch(cmd) {
{
case DDIOCSDBG: case DDIOCSDBG:
er=verify_area(VERIFY_READ,(void *)arg, sizeof(int)); er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
if(er) if(er)
return er; return er;
unix_debug = get_fs_long((int *)arg); unix_debug = get_fs_long((int *)arg);
if (unix_debug != 0 && unix_debug != 1) if (unix_debug != 0 && unix_debug != 1) {
{
unix_debug = 0; unix_debug = 0;
return(-EINVAL); return(-EINVAL);
} }
...@@ -929,8 +842,7 @@ static int unix_ioctl(struct inode *inode, struct file *file, ...@@ -929,8 +842,7 @@ static int unix_ioctl(struct inode *inode, struct file *file,
} }
static struct file_operations unix_fops = static struct file_operations unix_fops = {
{
NULL, /* LSEEK */ NULL, /* LSEEK */
NULL, /* READ */ NULL, /* READ */
NULL, /* WRITE */ NULL, /* WRITE */
...@@ -969,13 +881,13 @@ static struct proto_ops unix_proto_ops = { ...@@ -969,13 +881,13 @@ static struct proto_ops unix_proto_ops = {
}; };
void unix_proto_init(struct ddi_proto *pro) void
unix_proto_init(struct ddi_proto *pro)
{ {
struct unix_proto_data *upd; struct unix_proto_data *upd;
dprintf(1, "%s: init: initializing...\n", pro->name); dprintf(1, "%s: init: initializing...\n", pro->name);
if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) {
{
printk("%s: cannot register major device %d!\n", printk("%s: cannot register major device %d!\n",
pro->name, AF_UNIX_MAJOR); pro->name, AF_UNIX_MAJOR);
return; return;
...@@ -984,8 +896,7 @@ void unix_proto_init(struct ddi_proto *pro) ...@@ -984,8 +896,7 @@ void unix_proto_init(struct ddi_proto *pro)
/* Tell SOCKET that we are alive... */ /* Tell SOCKET that we are alive... */
(void) sock_register(unix_proto_ops.family, &unix_proto_ops); (void) sock_register(unix_proto_ops.family, &unix_proto_ops);
for(upd = unix_datas; upd <= last_unix_data; ++upd) for(upd = unix_datas; upd <= last_unix_data; ++upd) {
{
upd->refcnt = 0; upd->refcnt = 0;
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment