Commit ddd9ed00 authored by Linus Torvalds's avatar Linus Torvalds

Import 0.99.14o

parent 28067f4d
VERSION = 0.99
PATCHLEVEL = 14
ALPHA = n
ALPHA = o
all: Version zImage
......@@ -50,7 +50,7 @@ SVGA_MODE= -DSVGA_MODE=NORMAL_VGA
# standard CFLAGS
#
CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -pipe
CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe
ifdef CONFIG_CPP
CFLAGS := $(CFLAGS) -x c++
......
......@@ -8,8 +8,8 @@
include CONFIG
NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o)
CFLAGS := $(CFLAGS) -I../../net/inet -I../../net/socket -I../../net
CPP := $(CPP) -I../../net/inet -I../../net/socket -I../../net
CFLAGS := $(CFLAGS) -I../../net/inet
CPP := $(CPP) -I../../net/inet
# The point of the makefile...
all: net.a
......
......@@ -40,9 +40,9 @@
#include <linux/tty.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#ifdef CONFIG_AX25
#include "ax25/ax25.h"
#include "ax25.h"
#endif
#include "eth.h"
#include "ip.h"
......
......@@ -53,19 +53,27 @@
#define MAYBE_CONTINUE(LABEL,DEV) \
{if (buffer) kfree(buffer); \
if (cont_extent){ \
int block, offset; \
int block, offset, offset1; \
struct buffer_head * bh; \
buffer = kmalloc(cont_size,GFP_KERNEL); \
block = cont_extent; \
offset = cont_offset; \
offset1 = 0; \
if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \
block <<= 1; \
if (offset >= 1024) block++; \
offset &= 1023; \
if(offset + cont_size >= 1024) { \
bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \
memcpy(buffer, bh->b_data + offset, 1024 - offset); \
brelse(bh); \
offset1 = 1024 - offset; \
offset = 0; \
} \
}; \
bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \
if(bh){ \
memcpy(buffer, bh->b_data, cont_size); \
memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \
brelse(bh); \
chr = (unsigned char *) buffer; \
len = cont_size; \
......@@ -291,10 +299,17 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
};
break;
case SIG('T','F'):
/* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
Try and handle this correctly for either case. */
cnt = 0; /* Rock ridge never appears on a High Sierra disk */
if(rr->u.TF.flags & TF_CREATE) inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
if(rr->u.TF.flags & TF_MODIFY) inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
if(rr->u.TF.flags & TF_ACCESS) inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0);
if(rr->u.TF.flags & TF_CREATE)
inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
if(rr->u.TF.flags & TF_MODIFY)
inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0);
if(rr->u.TF.flags & TF_ACCESS)
inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0);
if(rr->u.TF.flags & TF_ATTRIBUTES)
inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
break;
case SIG('S','L'):
{int slen;
......
......@@ -59,8 +59,6 @@ struct options {
unsigned short handling;
unsigned short stream;
unsigned tcc;
int option_length;
void *option_data;
};
......
......@@ -30,14 +30,10 @@ struct linger {
#define AF_UNSPEC 0
#define AF_UNIX 1
#define AF_INET 2
#define AF_AX25 3
#define AF_IPX 4
/* Protocol families, same as address families. */
#define PF_UNIX AF_UNIX
#define PF_INET AF_INET
#define PF_AX25 AF_AX25
#define PF_IPX AF_IPX
/* Flags we can use with send/ and recv. */
#define MSG_OOB 1
......@@ -45,10 +41,6 @@ struct linger {
/* Setsockoptions(2) level. */
#define SOL_SOCKET 1
#define SOL_IP 2
#define SOL_IPX 3
#define SOL_AX25 4
#define SOL_TCP 5
/* For setsockoptions(2) */
#define SO_DEBUG 1
......@@ -64,19 +56,6 @@ struct linger {
#define SO_NO_CHECK 11
#define SO_PRIORITY 12
#define SO_LINGER 13
/* IP options */
#define IP_TOS 1
#define IPTOS_LOWDELAY 0x10
#define IPTOS_THROUGHPUT 0x08
#define IPTOS_RELIABILITY 0x04
#define IP_TTL 2
/* IPX options */
#define IPX_TYPE 1
/* AX.25 options */
#define AX25_WINDOW 1
/* TCP options */
#define TCP_MSS 1
#define TCP_NODELAY 2
/* The various priorities. */
#define SOPRI_INTERACTIVE 0
......
......@@ -7,17 +7,10 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
SUBDIRS := unix socket
# only these two lines should need to be changed to remove inet sockets.
# (and the inet/tcpip.o in net.o)
ifdef CONFIG_INET
SUBDIRS := $(SUBDIRS) inet
endif
ifdef CONFIG_IPX
SUBDIRS := $(SUBDIRS) ipx
endif
ifdef CONFIG_AX25
SUBDIRS := $(SUBDIRS) ax25
endif
SUBDIRS := unix inet
SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o)
......
......@@ -30,10 +30,10 @@
# include "inet/inet.h"
#endif
#ifdef CONFIG_IPX
#include "ipx/ipxcall.h"
#include "inet/ipxcall.h"
#endif
#ifdef CONFIG_AX25
#include "ax25/ax25call.h"
#include "inet/ax25call.h"
#endif
struct ddi_proto protocols[] = {
......@@ -53,3 +53,43 @@ struct ddi_proto protocols[] = {
};
/*
* Section B: Device Driver Modules.
* This section defines which network device drivers
* get linked into the Linux kernel. It is currently
* only used by the INET protocol. Any takers for the
* other protocols like XNS or Novell?
*
* WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!!
*/
/*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */
/*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */
/*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */
struct ddi_device devices[] = {
#if CONF_WE8003
{ "WD80x3[EBT]",
"", 0, 1, we8003_init, NULL,
19, 0, DDI_FCHRDEV,
{ 0x280, 0, 15, 0, 32768, 0xD0000 } },
#endif
#if CONF_DP8390
{ "DP8390/WD80x3",
"", 0, 1, dpwd8003_init, NULL,
20, 0, DDI_FCHRDEV,
{ 0, 0, 0, 0, 0, 0, } },
{ "DP8390/NE-x000",
"", 0, 1, dpne2000_init, NULL,
20, 8, DDI_FCHRDEV,
{ 0, 0, 0, 0, 0, 0, } },
{ "DP8390/3C50x",
"", 0, 1, dpec503_init, NULL,
20, 16, DDI_FCHRDEV,
{ 0, 0, 0, 0, 0, 0, } },
#endif
{ NULL,
"", 0, 0, NULL, NULL,
0, 0, 0,
{ 0, 0, 0, 0, 0, 0 } }
};
......@@ -4,11 +4,9 @@
* but it eventually might move to an upper directory of
* the system.
*
* Version: @(#)ddi.c 1.28 27/12/93
* Version: @(#)ddi.c 1.0.5 04/22/93
*
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
* Unused pieces nobbled.
*/
#include <asm/segment.h>
#include <asm/system.h>
......@@ -20,9 +18,6 @@
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/ddi.h>
#include <linux/interrupt.h>
#include "socket/dev.h"
#undef DDI_DEBUG
......@@ -33,32 +28,64 @@
#endif
extern struct ddi_device devices[]; /* device driver map */
extern struct ddi_proto protocols[]; /* network protocols */
/*
* This function gets called with an ASCII string representing the
* ID of some DDI driver. We loop through the DDI Devices table
* and return the address of the control block that has a matching
* "name" field. It is used by upper-level layers that want to
* dynamically bind some UNIX-domain "/dev/XXXX" file name to a
* DDI device driver. The "iflink(8)" program is an example of
* this behaviour.
*/
struct ddi_device *
ddi_map(const char *id)
{
register struct ddi_device *dev;
PRINTK (("DDI: MAP: looking for \"%s\": ", id));
dev = devices;
while (dev->title != NULL) {
if (strncmp(dev->name, id, DDI_MAXNAME) == 0) {
PRINTK (("OK at 0x%X\n", dev));
return(dev);
}
dev++;
}
PRINTK (("NOT FOUND\n"));
return(NULL);
}
/*
* This is the function that is called by a kernel routine during
* system startup. Its purpose is to walk trough the "devices"
* table (defined above), and to call all moduled defined in it.
*/
void ddi_init(void)
void
ddi_init(void)
{
struct ddi_proto *pro;
struct ddi_device *dev;
PRINTK (("DDI: Starting up!\n"));
/* First off, kick all configured protocols. */
pro = protocols;
while (pro->name != NULL)
{
while (pro->name != NULL) {
(*pro->init)(pro);
pro++;
}
dev_init();
/* Initialize the "Buffer Head" pointers. */
bh_base[INET_BH].routine = inet_bh;
/* Done. Now kick all configured device drivers. */
dev = devices;
while (dev->title != NULL) {
(*dev->init)(dev);
dev++;
}
/* We're all done... */
}
......@@ -7,9 +7,6 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
CFLAGS := $(CFLAGS) -I../socket -I..
CPP := $(CPP) -I../socket -I..
.c.o:
$(CC) $(CFLAGS) -c -o $*.o $<
.s.o:
......@@ -18,8 +15,10 @@ CPP := $(CPP) -I../socket -I..
$(CC) $(CFLAGS) -S -o $*.s $<
OBJS = sockinet.o utils.o route.o proc.o timer.o protocol.o loopback.o \
eth.o packet.o arp.o devinet.o ip.o raw.o icmp.o tcp.o udp.o
OBJS = sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \
eth.o packet.o arp.o dev.o ip.o raw.o icmp.o tcp.o udp.o \
datagram.o skbuff.o
# ipx.o ax25.o ax25_in.o ax25_out.o ax25_subr.o ax25_timer.o
ifdef CONFIG_INET
......
NET2Debugged 1.28 README
NET2Debugged 1.24 README
------------------------
Major Changes
o PLIP driver sort of works
o UDP and RAW have been partially rewritten for speed
o Internals heavily cleaned up, and memory monitoring of network
memory is now done. (On shift-scroll-lock)
o ARP should now not generate garbage
o Using MSG_PEEK can't cause race conditions and crashes
o Support for bootp clients.
o Supports RFC931 TAP authd
o NFS problems with certain types of network configuration are
fixed.
o Doesn't forward packets for other subnet (can cause packet storms)
o TCP won't ack rst frames causing packet storms (especially with
Lan workplace for DOS).
o Numerous fixes for solidity
o Verify_area used properly.
o MSG_PEEK is faster again
o Minor TCP fixes. Hopefully no more TCP lockups (ha!)
o Donald's promiscuous mode. Go forth and write protocol analysers...
-------------------------------------------------------------------------
NOTE:
Drivers for this stack set must be using alloc_skb() not just
......
......@@ -13,7 +13,7 @@
* resolver, like it should be. It will be put in a separate
* directory under 'net', being a protocol of its own. -FvK
*
* Version: @(#)arp.c 1.28 20/12/93
* Version: @(#)arp.c 1.0.15 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -36,11 +36,6 @@
* Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet.
* Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet
* one.
* Dominik Kubla : Better checking
* Tegge : Assorted corrections on cross port stuff
* Alan Cox : Heavily reformatted & recommented ready for the big day
* Alan Cox : ATF_PERM was backwards! - might be useful now (sigh)
*
*
* To Fix:
* : arp response allocates an skbuff to send. However there is a perfectly
......@@ -69,26 +64,51 @@
#include <asm/segment.h>
#include <stdarg.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include "arp.h"
/*
* We will try an ARP the recommended three times before we abandon it. If we
* do abandon it all is not lost as the next frame will also try.
*/
#define ARP_MAX_TRIES 3
/*
* The ARP table itself
*/
static char *unk_print(unsigned char *, int);
static char *eth_aprint(unsigned char *, int);
static char *arp_cmds[] = {
"0x%04X",
"REQUEST",
"REPLY",
"REVERSE REQUEST",
"REVERSE REPLY",
NULL
};
#define ARP_MAX_CMDS (sizeof(arp_cmds) / sizeof(arp_cmds[0]))
static struct {
char *name;
char *(*print)(unsigned char *ptr, int len);
} arp_types[] = {
{ "0x%04X", unk_print },
{ "10 Mbps Ethernet", eth_aprint },
{ "3 Mbps Ethernet", eth_aprint },
{ "AX.25", unk_print },
{ "Pronet", unk_print },
{ "Chaos", unk_print },
{ "IEEE 802.2 Ethernet (?)", eth_aprint },
{ "Arcnet", unk_print },
{ "AppleTalk", unk_print },
{ NULL, NULL }
};
#define ARP_MAX_TYPE (sizeof(arp_types) / sizeof(arp_types[0]))
struct arp_table *arp_tables[ARP_TABLE_SIZE] = {
NULL,
......@@ -98,25 +118,84 @@ static int arp_proxies=0; /* So we can avoid the proxy arp
overhead with the usual case of
no proxy arps */
/*
* Every packet awaiting an ARP resolution is stuffed on this
* queue until resolved or deleted. Note items in this queue
* may be on other (tcp retransmit) queues and we must not
* be the one to delete them.
*/
struct sk_buff * volatile arp_q = NULL;
static struct arp_table *arp_lookup(unsigned long addr);
static struct arp_table *arp_lookup_proxy(unsigned long addr);
/*
* We grab the arp queue, empty it and walk down it adding anything we can't
* resolve back onto the queue. We MUST do things this way as other entries
* may (will) get added as we walk the old list.
/* Dump the ADDRESS bytes of an unknown hardware type. */
static char *
unk_print(unsigned char *ptr, int len)
{
static char buff[32];
char *bufp = buff;
int i;
for (i = 0; i < len; i++)
bufp += sprintf(bufp, "%02X ", (*ptr++ & 0377));
return(buff);
}
/* 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 *volatile work_q;
......@@ -128,13 +207,14 @@ static void arp_send_q(void)
while((skb=skb_dequeue(&work_q))!=NULL)
{
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. */
cli();
skb->tries--;
if (skb->tries == 0)
{
if (skb->tries == 0) {
/*
* Grmpf.
* We have tried ARP_MAX_TRIES to resolve the IP address
......@@ -155,13 +235,10 @@ static void arp_send_q(void)
/* Can we now complete this packet? */
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->dev->queue_xmit(skb, skb->dev, 0);
}
else
{
} else {
/* Alas. Re-queue it... */
skb->magic = ARP_QUEUE_MAGIC;
skb_queue_head(&arp_q,skb);
......@@ -170,11 +247,9 @@ static void arp_send_q(void)
}
/*
* Create and send our response to an ARP request.
*/
static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
/* Create and send our response to an ARP request. */
static int
arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
{
struct arphdr *arp2;
struct sk_buff *skb;
......@@ -200,19 +275,18 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
sizeof(struct arphdr) +
(2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
dev->hard_header_len, GFP_ATOMIC);
if (skb == NULL)
{
if (skb == NULL) {
printk("ARP: no memory available for ARP REPLY!\n");
return(1);
}
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
(2 * arp1->ar_pln) + dev->hard_header_len;
skb->mem_len = sizeof(struct sk_buff) + skb->len;
hlen = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, src, dst, skb->len);
if (hlen < 0)
{
if (hlen < 0) {
printk("ARP: cannot create HW frame header for REPLY !\n");
kfree_skb(skb, FREE_WRITE);
return(1);
......@@ -230,12 +304,10 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
arp2->ar_hln = arp1->ar_hln;
arp2->ar_pln = arp1->ar_pln;
arp2->ar_op = htons(ARPOP_REPLY);
if(addrtype==IS_MYADDR)
memcpy(ptr2, dev->dev_addr, arp2->ar_hln);
else /* Proxy arp, so pull from the table */
memcpy(ptr2, apt->ha, arp2->ar_hln);
ptr2 += arp2->ar_hln;
memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln);
ptr2 += arp2->ar_pln;
......@@ -248,17 +320,18 @@ static int arp_response(struct arphdr *arp1, struct device *dev, int addrtype)
skb->sk = NULL;
skb->next = NULL;
DPRINTF((DBG_ARP, ">>"));
arp_print(arp2);
/* Queue the packet for transmission. */
dev->queue_xmit(skb, dev, 0);
return(0);
}
/*
* This will find an entry in the ARP table by looking at the IP address.
*/
static struct arp_table *arp_lookup(unsigned long paddr)
/* This will find an entry in the ARP table by looking at the IP address. */
static struct arp_table *
arp_lookup(unsigned long paddr)
{
struct arp_table *apt;
unsigned long hash;
......@@ -266,8 +339,7 @@ static struct arp_table *arp_lookup(unsigned long paddr)
DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr)));
/* 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));
return(NULL);
}
......@@ -276,10 +348,8 @@ static struct arp_table *arp_lookup(unsigned long paddr)
hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
cli();
apt = arp_tables[hash];
while(apt != NULL)
{
if (apt->ip == paddr)
{
while(apt != NULL) {
if (apt->ip == paddr) {
sti();
return(apt);
}
......@@ -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)
{
struct arp_table *apt;
......@@ -305,10 +372,8 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
hash = htonl(paddr) & (ARP_TABLE_SIZE - 1);
cli();
apt = arp_tables[hash];
while(apt != NULL)
{
if (apt->ip == paddr && (apt->flags & ATF_PUBL) )
{
while(apt != NULL) {
if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) {
sti();
return(apt);
}
......@@ -319,11 +384,9 @@ static struct arp_table *arp_lookup_proxy(unsigned long paddr)
}
/*
* Delete an ARP mapping entry in the cache.
*/
static void arp_destructor(unsigned long paddr, int force)
/* Delete an ARP mapping entry in the cache. */
void
arp_destroy(unsigned long paddr)
{
struct arp_table *apt;
struct arp_table **lapt;
......@@ -332,8 +395,7 @@ static void arp_destructor(unsigned long paddr, int force)
DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr)));
/* 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",
in_ntoa(paddr)));
return;
......@@ -342,12 +404,8 @@ static void arp_destructor(unsigned long paddr, int force)
cli();
lapt = &arp_tables[hash];
while ((apt = *lapt) != NULL)
{
if (apt->ip == paddr)
{
if((apt->flags&ATF_PERM) && !force)
return;
while ((apt = *lapt) != NULL) {
if (apt->ip == paddr) {
*lapt = apt->next;
if(apt->flags&ATF_PUBL)
arp_proxies--;
......@@ -360,37 +418,20 @@ static void arp_destructor(unsigned long paddr, int force)
sti();
}
/*
* Kill an entry - eg for ioctl()
*/
void arp_destroy(unsigned long paddr)
{
arp_destructor(paddr,1);
}
/*
* Delete a possibly invalid entry (see timer.c)
*/
void arp_destroy_maybe(unsigned long paddr)
{
arp_destructor(paddr,0);
}
/*
* Create an ARP entry. The caller should check for duplicates!
*/
static struct arp_table *arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
/* Create an ARP entry. The caller should check for duplicates! */
static struct arp_table *
arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype)
{
struct arp_table *apt;
unsigned long hash;
DPRINTF((DBG_ARP, "ARP: create(%s, ", in_ntoa(paddr)));
DPRINTF((DBG_ARP, "%s, ", eth_print(addr)));
DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype));
apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC);
if (apt == NULL)
{
if (apt == NULL) {
printk("ARP: no memory available for new ARP entry!\n");
return(NULL);
}
......@@ -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
* packet to the sender.
*/
int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
int
arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct arphdr *arp;
struct arp_table *tbl;
......@@ -429,7 +471,9 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
int ret;
int addr_hint;
DPRINTF((DBG_ARP, "<<\n"));
arp = skb->h.arp;
arp_print(arp);
/* If this test doesn't pass, its not IP. Might be DECNET or friends */
if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
......@@ -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);
memcpy(&src, ptr + arp->ar_hln, arp->ar_pln);
tbl = arp_lookup(src);
if (tbl != NULL)
{
if (tbl != NULL) {
DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src)));
memcpy(tbl->ha, ptr, arp->ar_hln);
tbl->hlen = arp->ar_hln;
tbl->flags |= ATF_COM;
tbl->last_used = jiffies;
}
else
{
} else {
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);
return(0);
}
else
{
} else {
tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd);
if (tbl == NULL)
{
if (tbl == NULL) {
kfree_skb(skb, FREE_READ);
return(0);
}
......@@ -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
* 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);
return(0);
}
......@@ -504,15 +540,14 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* A broadcast arp, ignore it
*/
if(chk_addr(dst)==IS_BROADCAST)
if((dst&0xFF)==0xFF)
{
kfree_skb(skb, FREE_READ);
return 0;
}
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0)
{
if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) {
DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
kfree_skb(skb, FREE_READ);
return(0);
......@@ -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.
*/
void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
/* Create and send an ARP REQUEST packet. */
void
arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
{
struct sk_buff *skb;
struct arphdr *arp;
......@@ -547,24 +580,24 @@ void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
sizeof(struct arphdr) + (2 * dev->addr_len) +
dev->hard_header_len +
(2 * 4 /* arp->plen */), GFP_ATOMIC);
if (skb == NULL)
{
if (skb == NULL) {
printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr));
return;
}
/* Fill in the request. */
skb->sk = NULL;
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) +
dev->hard_header_len + (2 * dev->addr_len) + 8;
skb->mem_len = sizeof(struct sk_buff) + skb->len;
skb->arp = 1;
skb->dev = dev;
skb->next = NULL;
skb->free = 1;
tmp = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, 0, saddr, skb->len);
if (tmp < 0)
{
if (tmp < 0) {
kfree_skb(skb,FREE_WRITE);
return;
}
......@@ -588,21 +621,24 @@ void arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
ptr += arp->ar_hln;
memcpy(ptr, &paddr, arp->ar_pln);
DPRINTF((DBG_ARP, ">>\n"));
arp_print(arp);
dev->queue_xmit(skb, dev, 0);
}
/*
* Find an ARP mapping in the cache. If not found, post a REQUEST.
*/
int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
/* Find an ARP mapping in the cache. If not found, post a REQUEST. */
int
arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
unsigned long saddr)
{
struct arp_table *apt;
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:
memcpy(haddr, dev->dev_addr, dev->addr_len);
return(0);
......@@ -612,22 +648,18 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
}
apt = arp_lookup(paddr);
if (apt != NULL)
{
if (apt != NULL) {
/*
* Make sure it's not too old. If it is too old, we will
* just pretend we did not find it, and then arp_send will
* verify the address for us.
*/
if ((apt->flags & ATF_PERM) ||
(apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0))
{
if ((!(apt->flags & ATF_PERM)) ||
(!before(apt->last_used, jiffies+ARP_TIMEOUT) && apt->hlen != 0)) {
apt->last_used = jiffies;
memcpy(haddr, apt->ha, dev->addr_len);
return(0);
}
else
{
} else {
DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n",
in_ntoa(apt->ip)));
}
......@@ -636,8 +668,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
/*
* This assume haddr are at least 4 bytes.
* If this isn't true we can use a lookup table, one for every dev.
* NOTE: this bit of code still looks fishy to me- FvK
*/
*(unsigned long *)haddr = paddr;
/* 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,
}
/*
* Add an entry to the ARP cache. Check for dupes!
*/
void arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
/* Add an entry to the ARP cache. Check for dupes! */
void
arp_add(unsigned long addr, unsigned char *haddr, struct device *dev)
{
struct arp_table *apt;
DPRINTF((DBG_ARP, "ARP: add(%s, ", in_ntoa(addr)));
DPRINTF((DBG_ARP, "%s, ", eth_print(haddr)));
DPRINTF((DBG_ARP, "%d, %d)\n", dev->hard_header_len, dev->type));
/* This is probably a good check... */
if (addr == 0)
{
if (addr == 0) {
printk("ARP: add: will not add entry for 0.0.0.0 !\n");
return;
}
/* First see if the address is already in the table. */
apt = arp_lookup(addr);
if (apt != NULL)
{
if (apt != NULL) {
DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr)));
apt->last_used = jiffies;
memcpy(apt->ha, haddr , dev->addr_len);
......@@ -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.
*/
void arp_add_broad(unsigned long addr, struct device *dev)
/* Create an ARP entry for a device's broadcast address. */
void
arp_add_broad(unsigned long addr, struct device *dev)
{
struct arp_table *apt;
arp_add(addr, dev->broadcast, dev);
apt = arp_lookup(addr);
if (apt != NULL)
{
if (apt != NULL) {
apt->flags |= ATF_PERM;
}
}
/* Queue an IP packet, while waiting for the ARP reply packet. */
void arp_queue(struct sk_buff *skb)
void
arp_queue(struct sk_buff *skb)
{
unsigned long flags;
save_flags(flags);
cli();
skb->tries = ARP_MAX_TRIES;
if (skb->next != NULL)
{
if (skb->next != NULL) {
sti();
printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
return;
}
skb_queue_tail(&arp_q,skb);
skb->magic = ARP_QUEUE_MAGIC;
restore_flags(flags);
sti();
}
......@@ -727,8 +754,8 @@ void arp_queue(struct sk_buff *skb)
*
* Perhaps we should redo PROCfs to handle larger buffers? Michael?
*/
int arp_get_info(char *buffer)
int
arp_get_info(char *buffer)
{
struct arpreq *req;
struct arp_table *apt;
......@@ -738,15 +765,12 @@ int arp_get_info(char *buffer)
/* Loop over the ARP table and copy structures to the buffer. */
pos = buffer;
i = 0;
for (i = 0; i < ARP_TABLE_SIZE; i++)
{
for (i = 0; i < ARP_TABLE_SIZE; i++) {
cli();
apt = arp_tables[i];
sti();
while (apt != NULL)
{
if (pos < (buffer + 4000))
{
while (apt != NULL) {
if (pos < (buffer + 4000)) {
req = (struct arpreq *) pos;
memset((char *) req, 0, sizeof(struct arpreq));
req->arp_pa.sa_family = AF_INET;
......@@ -765,11 +789,9 @@ int arp_get_info(char *buffer)
}
/*
* Set (create) an ARP cache entry.
*/
static int arp_req_set(struct arpreq *req)
/* Set (create) an ARP cache entry. */
static int
arp_req_set(struct arpreq *req)
{
struct arpreq r;
struct arp_table *apt;
......@@ -778,8 +800,7 @@ static int arp_req_set(struct arpreq *req)
/* We only understand about IP addresses... */
memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET)
return(-EPFNOSUPPORT);
if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
/*
* Find out about the hardware type.
......@@ -787,35 +808,26 @@ static int arp_req_set(struct arpreq *req)
* assume that a "not set" value (i.e. 0) means Ethernet.
*/
si = (struct sockaddr_in *) &r.arp_pa;
switch(r.arp_ha.sa_family)
{
switch(r.arp_ha.sa_family) {
case 0:
case ARPHRD_ETHER:
htype = ARPHRD_ETHER;
hlen = ETH_ALEN;
break;
case ARPHRD_AX25:
htype = ARPHRD_AX25;
hlen = 7;
break;
default:
return(-EPFNOSUPPORT);
}
/* Is there an existing entry for this address? */
if (si->sin_addr.s_addr == 0)
{
if (si->sin_addr.s_addr == 0) {
printk("ARP: SETARP: requested PA is 0.0.0.0 !\n");
return(-EINVAL);
}
apt = arp_lookup(si->sin_addr.s_addr);
if (apt == NULL)
{
if (apt == NULL) {
apt = arp_create(si->sin_addr.s_addr,
(unsigned char *) r.arp_ha.sa_data, hlen, htype);
if (apt == NULL)
return(-ENOMEM);
if (apt == NULL) return(-ENOMEM);
}
/* We now have a pointer to an ARP entry. Update it! */
......@@ -829,11 +841,9 @@ static int arp_req_set(struct arpreq *req)
}
/*
* Get an ARP cache entry.
*/
static int arp_req_get(struct arpreq *req)
/* Get an ARP cache entry. */
static int
arp_req_get(struct arpreq *req)
{
struct arpreq r;
struct arp_table *apt;
......@@ -841,14 +851,12 @@ static int arp_req_get(struct arpreq *req)
/* We only understand about IP addresses... */
memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET)
return(-EPFNOSUPPORT);
if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
/* Is there an existing entry for this address? */
si = (struct sockaddr_in *) &r.arp_pa;
apt = arp_lookup(si->sin_addr.s_addr);
if (apt == NULL)
return(-ENXIO);
if (apt == NULL) return(-ENXIO);
/* We found it; copy into structure. */
memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen);
......@@ -860,19 +868,17 @@ static int arp_req_get(struct arpreq *req)
}
/*
* Delete an ARP cache entry.
*/
static int arp_req_del(struct arpreq *req)
/* Delete an ARP cache entry. */
static int
arp_req_del(struct arpreq *req)
{
struct arpreq r;
struct sockaddr_in *si;
/* We only understand about IP addresses... */
memcpy_fromfs(&r, req, sizeof(r));
if (r.arp_pa.sa_family != AF_INET)
return(-EPFNOSUPPORT);
if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
si = (struct sockaddr_in *) &r.arp_pa;
/* The system cope with this but splats up a nasty kernel message
......@@ -886,15 +892,12 @@ static int arp_req_del(struct arpreq *req)
}
/*
* Handle an ARP layer I/O control request.
*/
int arp_ioctl(unsigned int cmd, void *arg)
/* Handle an ARP layer I/O control request. */
int
arp_ioctl(unsigned int cmd, void *arg)
{
int err;
switch(cmd)
{
switch(cmd) {
case DDIOCSDBG:
return(dbg_ioctl(arg, DBG_ARP));
case SIOCDARP:
......
......@@ -5,7 +5,7 @@
*
* Definitions for the ARP protocol module.
*
* Version: @(#)arp.h 1.28 24/12/93
* Version: @(#)arp.h 1.0.6 05/21/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -26,31 +26,29 @@
#define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */
/*
* This structure defines the ARP mapping cache.
*/
struct arp_table
{
/* This structure defines the ARP mapping cache. */
struct arp_table {
struct arp_table *next;
volatile unsigned long last_used;
unsigned int flags;
#if 1
unsigned long ip;
#else
unsigned char pa[MAX_ADDR_LEN];
unsigned char plen;
unsigned char ptype;
#endif
unsigned char ha[MAX_ADDR_LEN];
unsigned char hlen;
unsigned char htype;
};
/*
* This is also used in "sock.c" and "tcp.c" - YUCK! - FvK
*/
/* This is also used in "sock.c" and "tcp.c" - YUCK! - FvK */
extern struct sk_buff *arp_q;
extern void arp_destroy(unsigned long paddr);
extern void arp_destroy_maybe(unsigned long paddr);
extern int arp_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
extern int arp_find(unsigned char *haddr, unsigned long paddr,
......
......@@ -13,8 +13,6 @@
* Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
* Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
* AX.25 now works right, and SPX is feasible.
* Alan Cox : Tidied up ready for the big day.
* Alan Cox : Fixed write select of no IP protocol crash.
*/
#include <linux/config.h>
......@@ -138,13 +136,6 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
return skb;
}
/*
* Free a datagram buffer. This has some conditions to watch. We keep
* a user count so the last user may free the buffer. If however the
* buffer has a valid next pointer it was never removed and all the
* users PEEKed at it - so don't free it yet.
*/
void skb_free_datagram(struct sk_buff *skb)
{
unsigned long flags;
......@@ -194,11 +185,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
return(0);
case SEL_OUT:
if(sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
return(1);
}
if(sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
{
return(1);
}
......
......@@ -790,6 +790,7 @@ static inline int bad_mask(unsigned long mask, unsigned long addr)
return 0;
}
/* Perform the SIOCxIFxxx calls. */
static int
dev_ifsioc(void *arg, unsigned int getset)
......
/*
* 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 @@
*
* Ethernet-type device handling.
*
* Version: @(#)eth.c 1.28 20/12/93
* Version: @(#)eth.c 1.0.7 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
*
* Fixes:
* Mr Linux : Arp problems.
* Alan Cox : Generic queue tidyup (very tiny here).
* Alan Cox : eth_header ntohs should be htons.
* Mr Linux : Arp problems
* Alan Cox : Generic queue tidyup (very tiny here)
* Alan Cox : eth_header ntohs should be htons
* Alan Cox : eth_rebuild_header missing an htons and
* minor other things.
* Tegge : Arp bug fixes.
* Alan Cox : Tidy up ready for the big day.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/types.h>
......@@ -36,19 +33,18 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include <linux/errno.h>
#include "arp.h"
#ifdef ETH_DEBUG
/* Display an Ethernet address in readable format. */
char *eth_print(unsigned char *ptr)
{
......@@ -61,16 +57,32 @@ char *eth_print(unsigned char *ptr)
);
return(buff);
}
#endif
#ifdef ETH_DEBUG
/*
* Display the contents of the Ethernet MAC header.
*/
void eth_setup(char *str, int *ints)
{
struct device *d = dev_base;
if (!str || !*str)
return;
while (d) {
if (!strcmp(str,d->name)) {
if (ints[0] > 0)
d->irq=ints[1];
if (ints[0] > 1)
d->base_addr=ints[2];
if (ints[0] > 2)
d->mem_start=ints[3];
if (ints[0] > 3)
d->mem_end=ints[4];
break;
}
d=d->next;
}
}
void eth_dump(struct ethhdr *eth)
/* Display the contents of the Ethernet MAC header. */
void
eth_dump(struct ethhdr *eth)
{
if (inet_debug != DBG_ETH) return;
......@@ -79,17 +91,10 @@ void eth_dump(struct ethhdr *eth)
printk("TYPE = %04X\n", ntohs(eth->h_proto));
}
#endif
/*
* Create the Ethernet MAC header.
*
* ARP might prevent this from working all in one go. See also
* the rebuild header function.
*/
int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
/* Create the Ethernet MAC header. */
int
eth_header(unsigned char *buff, struct device *dev, unsigned short type,
unsigned long daddr, unsigned long saddr, unsigned len)
{
struct ethhdr *eth;
......@@ -102,8 +107,7 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
eth->h_proto = htons(type);
/* 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"));
memcpy(eth->h_source, dev->dev_addr, 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,
}
/* 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"));
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
return(dev->hard_header_len);
}
/*
* We disable interrupts here to avoid a race if the ARP
* reply is too quick.
*/
cli();
memcpy(eth->h_source, &saddr, 4);
/* No. Ask ARP to resolve the Ethernet address. */
if (arp_find(eth->h_dest, daddr, dev, dev->pa_addr/* saddr */))
if (arp_find(eth->h_dest, daddr, dev, saddr))
{
sti();
if(type!=ETH_P_IP)
......@@ -142,14 +141,9 @@ int eth_header(unsigned char *buff, struct device *dev, unsigned short type,
}
/*
* Rebuild the Ethernet MAC header.
*
* We've got a 'stuck' packet that failed to go out before. See if
* the arp is resolved and we can finally shift it.
*/
int eth_rebuild_header(void *buff, struct device *dev)
/* Rebuild the Ethernet MAC header. */
int
eth_rebuild_header(void *buff, struct device *dev)
{
struct ethhdr *eth;
unsigned long src, dst;
......@@ -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, "DST=%s\n", in_ntoa(dst)));
if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */
if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */))
/* Still not known */
return(1);
if (arp_find(eth->h_dest, dst, dev, src)) return(1);
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return(0);
}
/*
* Add an ARP entry for a host on this interface.
*/
void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
/* Add an ARP entry for a host on this interface. */
void
eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
{
struct ethhdr *eth;
......@@ -182,19 +172,9 @@ void eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev)
}
/*
* Determine the packet's protocol ID.
*
* Ethernet comes in two 'species' DIX (Digitial Intel Xerox) and IEE802.3
* needless to say they are different. Fortunately there is a way of telling
* them apart. All 'normal' modern DIX service ID's are >1536.
* All IEE802.3 frames have a length at this position and that cannot be
* >=1536. Note IEE802.3 frames have a second 802.2 header normally. We don't
* deal with this bit in the current kernel, but a user using SOCK_PACKET
* for 802.3 frames can do so.
*/
unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
/* Determine the packet's protocol ID. */
unsigned short
eth_type_trans(struct sk_buff *skb, struct device *dev)
{
struct ethhdr *eth;
......
......@@ -5,7 +5,7 @@
*
* Internet Control Message Protocol (ICMP)
*
* Version: @(#)icmp.c 1.28 20/12/93
* Version: @(#)icmp.c 1.0.11 06/02/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -14,7 +14,6 @@
* Fixes:
* Alan Cox : Generic queue usage.
* Gerhard Koerting: ICMP addressing corrected
* Tegge : Subnet problems
*
*
* This program is free software; you can redistribute it and/or
......@@ -22,7 +21,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......@@ -30,14 +28,14 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "icmp.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
......@@ -65,30 +63,21 @@ struct icmp_err icmp_err_convert[] = {
};
#ifdef ICMP_DEBUG
/* Display the contents of an ICMP header. */
static void
print_icmp(struct icmphdr *icmph)
{
if (inet_debug != DBG_ICMP)
return;
if (inet_debug != DBG_ICMP) return;
printk("ICMP: type = %d, code = %d, checksum = %X\n",
icmph->type, icmph->code, icmph->checksum);
printk(" gateway = %s\n", in_ntoa(icmph->un.gateway));
}
#endif
/*
* Send an ICMP message.
*
* ICMP is the control message protocol for error reporting in IP.
* A good document to start with for this stuff is RFC 791.
*/
void icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
/* Send an ICMP message. */
void
icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
{
struct sk_buff *skb;
struct iphdr *iph;
......@@ -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 */
skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
/* We just forget about failed ICMP messages. ICMP is unreliable anyway and
things will sort out in time */
if (skb == NULL)
return;
skb->sk = NULL;
skb->mem_addr = skb;
skb->mem_len = len;
len -= sizeof(struct sk_buff);
/* Find the IP header. */
......@@ -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. */
offset = ip_build_header(skb, dev->pa_addr, iph->saddr,
&dev, IPPROTO_ICMP, NULL, len, 25, IPTOS_RELIABILITY);
if (offset < 0)
{
&dev, IPPROTO_ICMP, NULL, len);
if (offset < 0) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
......@@ -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,
sizeof(struct icmphdr) + sizeof(struct iphdr) + 8);
#ifdef ICMP_DEBUG
DPRINTF((DBG_ICMP, ">>\n"));
print_icmp(icmph);
#endif
/* Send it and free it. */
ip_queue_xmit(NULL, dev, skb, 1);
}
/*
* Handle ICMP_UNREACH and ICMP_QUENCH.
*/
static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
/* Handle ICMP_UNREACH and ICMP_QUENCH. */
static void
icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
{
struct inet_protocol *ipprot;
struct iphdr *iph;
......@@ -162,8 +146,7 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
err = (icmph->type << 8) | icmph->code;
iph = (struct iphdr *) (icmph + 1);
switch(icmph->code & 7)
{
switch(icmph->code & 7) {
case ICMP_NET_UNREACH:
DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n",
in_ntoa(iph->daddr)));
......@@ -198,15 +181,13 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
/* This can change while we are doing it. */
ipprot = (struct inet_protocol *) inet_protos[hash];
while(ipprot != NULL)
{
while(ipprot != NULL) {
struct inet_protocol *nextip;
nextip = (struct inet_protocol *) ipprot->next;
/* Pass it off to everyone who wants it. */
if (iph->protocol == ipprot->protocol && ipprot->err_handler)
{
if (iph->protocol == ipprot->protocol && ipprot->err_handler) {
ipprot->err_handler(err, (unsigned char *)(icmph + 1),
iph->daddr, iph->saddr, ipprot);
}
......@@ -218,19 +199,16 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb)
}
/*
* Handle ICMP_REDIRECT.
*/
static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
/* Handle ICMP_REDIRECT. */
static void
icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev)
{
struct iphdr *iph;
unsigned long ip;
iph = (struct iphdr *) (icmph + 1);
ip = iph->daddr;
switch(icmph->code & 7)
{
switch(icmph->code & 7) {
case ICMP_REDIR_NET:
rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY),
ip, 0, icmph->un.gateway, dev);
......@@ -254,7 +232,8 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev
/* Handle ICMP_ECHO ("ping") requests. */
static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
static void
icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
......@@ -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;
skb2 = alloc_skb(size, GFP_ATOMIC);
if (skb2 == NULL)
{
if (skb2 == NULL) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
}
skb2->sk = NULL;
skb2->mem_addr = skb2;
skb2->mem_len = size;
skb2->free = 1;
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
if (offset < 0)
{
IPPROTO_ICMP, opt, len);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
kfree_skb(skb2,FREE_WRITE);
skb->sk = NULL;
......@@ -304,11 +283,9 @@ static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device
}
/*
* Handle the ICMP INFORMATION REQUEST.
*/
static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Handle the ICMP INFORMATION REQUEST. */
static void
icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
......@@ -318,11 +295,9 @@ static void icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device
}
/*
* Handle ICMP_ADRESS_MASK requests.
*/
static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
/* Handle ICMP_ADRESS_MASK requests. */
static void
icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
unsigned long saddr, unsigned long daddr, int len,
struct options *opt)
{
......@@ -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;
skb2 = alloc_skb(size, GFP_ATOMIC);
if (skb2 == NULL)
{
if (skb2 == NULL) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
}
skb2->sk = NULL;
skb2->mem_addr = skb2;
skb2->mem_len = size;
skb2->free = 1;
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len, 255, IPTOS_RELIABILITY);
if (offset < 0)
{
IPPROTO_ICMP, opt, len);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
kfree_skb(skb2,FREE_WRITE);
skb->sk = NULL;
......@@ -375,11 +350,9 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi
}
/*
* Deal with incoming ICMP packets.
*/
int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
/* Deal with incoming ICMP packets. */
int
icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
......@@ -387,8 +360,7 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned char *buff;
/* Drop broadcast packets. */
if (chk_addr(daddr) == IS_BROADCAST)
{
if (chk_addr(daddr) == IS_BROADCAST) {
DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
in_ntoa(saddr)));
skb1->sk = NULL;
......@@ -400,20 +372,17 @@ int icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
icmph = (struct icmphdr *) buff;
/* Validate the packet first */
if (ip_compute_csum((unsigned char *) icmph, len))
{
if (ip_compute_csum((unsigned char *) icmph, len)) {
/* Failed checksum! */
printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
}
#ifdef ICMP_DEBUG
print_icmp(icmph);
#endif
/* Parse the ICMP message */
switch(icmph->type)
{
switch(icmph->type) {
case ICMP_TIME_EXCEEDED:
case ICMP_DEST_UNREACH:
case ICMP_SOURCE_QUENCH:
......@@ -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.
*
* In the case of ICMP all the user can do is play with the debygging
*/
int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
/* Perform any ICMP-related I/O control requests. */
int
icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
switch(cmd)
{
switch(cmd) {
case DDIOCSDBG:
return(dbg_ioctl((void *) arg, DBG_ICMP));
default:
......
......@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) module.
*
* Version: @(#)ip.c 1.28 20/12/93
* Version: @(#)ip.c 1.0.16b 9/1/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -31,14 +31,10 @@
* Gerhard Koerting: IP interface addressing fix.
* Linus Torvalds : More robustness checks
* Alan Cox : Even more checks: Still not as robust as it ought to be
* Alan Cox : Reformatted for neatness and final release.
* Alan Cox : Tags ip header for RAW sockets, and for accept(). Old
* method wasn't suitable for AX.25
* Alan Cox : Most of the ip_options processing logic added.
*
* To Fix:
* RFC791 states that options are a 'required' feature of an
* IP implementation. We don't do options at all.
* IP option processing is mostly not needed. ip_forward needs to know about routing rules
* and time stamp but that's about all.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -56,40 +52,31 @@
#include <linux/sockios.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "route.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include "arp.h"
#include "icmp.h"
/*
* These two can normally be left. In olden times the numerous bugs used to
* make forwarding go crazy on some nets and fragmentation fragment your
* computer 8-)
*/
#define CONFIG_IP_FORWARD /* Forwarding ? */
#define CONFIG_IP_DEFRAG /* Fragmentation ? */
#define CONFIG_IP_FORWARD
#define CONFIG_IP_DEFRAG
extern int last_retran;
extern void sort_send(struct sock *sk);
#ifdef IP_DEBUG
void ip_print(struct iphdr *ip)
void
ip_print(struct iphdr *ip)
{
unsigned char buff[32];
unsigned char *ptr;
int addr, len, i;
if (inet_debug != DBG_IP)
return;
if (inet_debug != DBG_IP) return;
/* Dump the IP header. */
printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n",
......@@ -105,19 +92,14 @@ void ip_print(struct iphdr *ip)
ptr = (unsigned char *)(ip + 1);
addr = 0;
len = ntohs(ip->tot_len) - (4 * ip->ihl);
while (len > 0)
{
while (len > 0) {
printk(" %04X: ", addr);
for(i = 0; i < 16; i++)
{
if (len > 0)
{
for(i = 0; i < 16; i++) {
if (len > 0) {
printk("%02X ", (*ptr & 0xFF));
buff[i] = *ptr++;
if (buff[i] < 32 || buff[i] > 126) buff[i] = '.';
}
else
{
} else {
printk(" ");
buff[i] = ' ';
}
......@@ -130,17 +112,11 @@ void ip_print(struct iphdr *ip)
printk(" ----\n\n");
}
#endif
/*
* Low level user requests to the IP device. NOT that same as IP layer
* socket requests (which also do nothing useful at the moment)
*/
int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
int
ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
switch(cmd)
{
switch(cmd) {
case DDIOCSDBG:
return(dbg_ioctl((void *) arg, DBG_IP));
default:
......@@ -149,64 +125,51 @@ int ip_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
/*
* These two routines will do routing when we have ip options support
* (RFC 791 page 18,19)
*/
static void strict_route(struct iphdr *iph, struct options *opt)
/* these two routines will do routining. */
static void
strict_route(struct iphdr *iph, struct options *opt)
{
}
static void loose_route(struct iphdr *iph, struct options *opt)
static void
loose_route(struct iphdr *iph, struct options *opt)
{
}
static void print_ipprot(struct inet_protocol *ipprot)
static void
print_ipprot(struct inet_protocol *ipprot)
{
DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n",
ipprot->handler, ipprot->protocol, ipprot->copy));
}
/*
* This routine will check to see if we have lost a gateway.
*/
void ip_route_check(unsigned long daddr)
/* This routine will check to see if we have lost a gateway. */
void
ip_route_check(unsigned long daddr)
{
}
/*
* This routine puts the options at the end of an ip header.
*/
static int build_options(struct iphdr *iph, struct options *opt)
#if 0
/* this routine puts the options at the end of an ip header. */
static int
build_options(struct iphdr *iph, struct options *opt)
{
unsigned char *ptr;
ptr = (unsigned char *)(iph+1);
/* currently we don't support any options. */
if(opt==NULL)
{
ptr = (unsigned char *)(iph+1);
*ptr = 0;
return (1);
}
else
{
memcpy(ptr,opt->option_data,opt->option_length);
return((opt->option_length+3)/4);
}
return (4);
}
#endif
/*
* Take an skb, and fill in the MAC header.
*/
static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
/* Take an skb, and fill in the MAC header. */
static int
ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev,
unsigned long saddr)
{
unsigned char *ptr;
......@@ -215,12 +178,10 @@ static int ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct dev
ptr = (unsigned char *)(skb + 1);
mac = 0;
skb->arp = 1;
if (dev->hard_header)
{
if (dev->hard_header) {
mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len);
}
if (mac < 0)
{
if (mac < 0) {
mac = -mac;
skb->arp = 0;
}
......@@ -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
* routing/ARP tables to select a device struct.
*/
int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
struct device **dev, int type, struct options *opt, int len, int ttl,int tos)
int
ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
struct device **dev, int type, struct options *opt, int len)
{
static struct options optmem;
struct iphdr *iph;
......@@ -245,7 +207,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
unsigned long raddr;
static int count = 0;
int tmp;
int optlen;
if (saddr == 0)
saddr = my_addr();
......@@ -257,8 +218,7 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
buff = (unsigned char *)(skb + 1);
/* See if we need to look up the device. */
if (*dev == NULL)
{
if (*dev == NULL) {
rt = rt_route(daddr, &optmem);
if (rt == NULL)
return(-ENETUNREACH);
......@@ -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)));
opt = &optmem;
}
else
{
} else {
/* We still need the address of the first hop. */
rt = rt_route(daddr, &optmem);
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
skb->dev = *dev;
skb->saddr = saddr;
if (skb->sk)
skb->sk->saddr = saddr;
if (skb->sk) skb->sk->saddr = saddr;
/* Now build the IP header. */
/* If we are using IPPROTO_RAW, then we don't need an IP header, since
one is being supplied to us by the user */
if(type == IPPROTO_RAW)
return (tmp);
if(type == IPPROTO_RAW) return (tmp);
iph = (struct iphdr *)buff;
iph->version = 4;
iph->tos = tos;
iph->tos = 0;
iph->frag_off = 0;
iph->ttl = ttl;
iph->ttl = 32;
iph->daddr = daddr;
iph->saddr = saddr;
iph->protocol = type;
iph->ihl = 5;
iph->id = htons(count++);
/* Setup the IP options. Length is in longs.*/
optlen=build_options(iph, opt);
iph->ihl+=optlen;
/* Setup the IP options. */
#ifdef Not_Yet_Avail
build_options(iph, opt);
#endif
return(20 + tmp + 4*optlen); /* IP header plus MAC header size */
return(20 + tmp); /* IP header plus MAC header size */
}
/*
* Interpret the incoming options
*/
static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device *dev)
static int
do_options(struct iphdr *iph, struct options *opt)
{
unsigned char *buff;
int done = 0;
int i, len = sizeof(struct iphdr);
unsigned char *outbuf;
struct options *opt;
int ol;
int optsiz;
if(iph->ihl==5)
{
*opt_ptr=NULL;
return(0);
}
/* Allocate a buffer to stuff the options (decoded) and the raw option data into */
ol=(iph->ihl*4)-sizeof(struct iphdr);
opt=(struct options *)kmalloc(ol+sizeof(*opt),GFP_ATOMIC);
*opt_ptr=opt;
if(opt==NULL)
return(1);
opt->option_length=ol;
outbuf=(unsigned char *)(opt+1);
opt->option_data=outbuf;
/* Zero out the options. */
opt->record_route.route_size = 0;
......@@ -362,17 +291,13 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
opt->handling = 0;
opt->stream = 0;
opt->tcc = 0;
return(0);
/* Advance the pointer to start at the options. */
buff = (unsigned char *)(iph + 1);
/* Copy the data */
memcpy(outbuf,buff,opt->option_length);
buff = outbuf;
/* Now start the processing. */
while (!done && len < iph->ihl*4) switch(*buff)
{
while (!done && len < iph->ihl*4) switch(*buff) {
case IPOPT_END:
done = 1;
break;
......@@ -382,8 +307,7 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
break;
case IPOPT_SEC:
buff++;
if (*buff != 11)
return(1);
if (*buff != 11) return(1);
buff++;
opt->security = ntohs(*(unsigned short *)buff);
buff += 2;
......@@ -397,78 +321,51 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
break;
case IPOPT_LSRR:
buff++;
if ((*buff - 3)% 4 != 0)
return(1);
if(*buff<2)
return(1);
len += (optsiz= *buff);
if ((*buff - 3)% 4 != 0) return(1);
len += *buff;
opt->loose_route.route_size = (*buff -3)/4;
buff++;
if (*buff % 4 != 0)
return(1);
if (*buff % 4 != 0) return(1);
opt->loose_route.pointer = *buff/4 - 1;
if(*buff<=optsiz)
*buff+=4; /* Move on a route */
buff++;
buff++;
for (i = 0; i < opt->loose_route.route_size; i++)
{
for (i = 0; i < opt->loose_route.route_size; i++) {
if(i>=MAX_ROUTE)
return(1);
if(i==opt->strict_route.pointer)
*(unsigned long *)buff=dev->pa_addr;
opt->loose_route.route[i] = *(unsigned long *)buff;
buff += 4;
}
break;
case IPOPT_SSRR:
buff++;
if ((*buff - 3)% 4 != 0)
return(1);
if(*buff<2)
return(1);
len += (optsiz= *buff);
if ((*buff - 3)% 4 != 0) return(1);
len += *buff;
opt->strict_route.route_size = (*buff -3)/4;
buff++;
if (*buff % 4 != 0)
return(1);
if (*buff % 4 != 0) return(1);
opt->strict_route.pointer = *buff/4 - 1;
if(*buff<=optsiz)
*buff+=4;
buff++;
buff++;
for (i = 0; i < opt->strict_route.route_size; i++)
{
for (i = 0; i < opt->strict_route.route_size; i++) {
if(i>=MAX_ROUTE)
return(1);
if(i==opt->strict_route.pointer)
*(unsigned long *)buff=dev->pa_addr;
opt->strict_route.route[i] = *(unsigned long *)buff;
buff += 4;
}
break;
case IPOPT_RR:
buff++;
if ((*buff - 3)% 4 != 0)
return(1);
if(*buff<2)
return(1);
len += (optsiz= *buff);
if ((*buff - 3)% 4 != 0) return(1);
len += *buff;
opt->record_route.route_size = (*buff -3)/4;
buff++;
if (*buff % 4 != 0)
return(1);
if (*buff % 4 != 0) return(1);
opt->record_route.pointer = *buff/4 - 1;
if(*buff+4<=optsiz)
*buff+=4;
buff++;
buff++;
for (i = 0; i < opt->record_route.route_size; i++)
{
for (i = 0; i < opt->record_route.route_size; i++) {
if(i>=MAX_ROUTE)
return 1;
if(i==opt->record_route.pointer)
*(unsigned long *)buff=dev->pa_addr;
opt->record_route.route[i] = *(unsigned long *)buff;
buff += 4;
}
......@@ -480,23 +377,17 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
buff += 2;
break;
case IPOPT_TIMESTAMP:
/* FIXME: This one isn't altered correctly yet */
buff++;
if(*buff<2)
return 1;
len += *buff;
if (*buff % 4 != 0)
return(1);
if (*buff % 4 != 0) return(1);
opt->tstamp.len = *buff / 4 - 1;
buff++;
if ((*buff - 1) % 4 != 0)
return(1);
if ((*buff - 1) % 4 != 0) return(1);
opt->tstamp.ptr = (*buff-1)/4;
buff++;
opt->tstamp.x.full_char = *buff;
buff++;
for (i = 0; i < opt->tstamp.len; i++)
{
for (i = 0; i < opt->tstamp.len; i++) {
opt->tstamp.data[i] = *(unsigned long *)buff;
buff += 4;
}
......@@ -505,30 +396,24 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
return(1);
}
if (opt->record_route.route_size == 0)
{
if (opt->strict_route.route_size != 0)
{
if (opt->record_route.route_size == 0) {
if (opt->strict_route.route_size != 0) {
memcpy(&(opt->record_route), &(opt->strict_route),
sizeof(opt->record_route));
}
else if (opt->loose_route.route_size != 0)
{
} else if (opt->loose_route.route_size != 0) {
memcpy(&(opt->record_route), &(opt->loose_route),
sizeof(opt->record_route));
}
}
if (opt->strict_route.route_size != 0 &&
opt->strict_route.route_size != opt->strict_route.pointer)
{
opt->strict_route.route_size != opt->strict_route.pointer) {
strict_route(iph, opt);
return(0);
}
if (opt->loose_route.route_size != 0 &&
opt->loose_route.route_size != opt->loose_route.pointer)
{
opt->loose_route.route_size != opt->loose_route.pointer) {
loose_route(iph, opt);
return(0);
}
......@@ -536,12 +421,10 @@ static int do_options(struct iphdr *iph, struct options **opt_ptr, struct device
return(0);
}
/*
* This is a version of ip_compute_csum() optimized for IP headers, which
* always checksum on 4 octet boundaries.
*/
static inline unsigned short ip_fast_csum(unsigned char * buff, int wlen)
/* This is a version of ip_compute_csum() optimized for IP headers, which
always checksum on 4 octet boundaries. */
static inline unsigned short
ip_fast_csum(unsigned char * buff, int wlen)
{
unsigned long sum = 0;
......@@ -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
* require anything special (like copying or special headers).
*/
unsigned short ip_compute_csum(unsigned char * buff, int len)
unsigned short
ip_compute_csum(unsigned char * buff, int len)
{
unsigned long sum = 0;
......@@ -610,20 +493,16 @@ unsigned short ip_compute_csum(unsigned char * buff, int len)
return(sum & 0xffff);
}
/*
* Check the header of an incoming IP datagram. This version is still used in slhc.c.
*/
int ip_csum(struct iphdr *iph)
/* Check the header of an incoming IP datagram. This version is still used in slhc.c. */
int
ip_csum(struct iphdr *iph)
{
return ip_fast_csum((unsigned char *)iph, iph->ihl);
}
/*
* Generate a checksym for an outgoing IP datagram. (RFC791, Page 14)
*/
static void ip_send_check(struct iphdr *iph)
/* Generate a checksym for an outgoing IP datagram. */
static void
ip_send_check(struct iphdr *iph)
{
iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
......@@ -632,11 +511,7 @@ static void ip_send_check(struct iphdr *iph)
/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/
static struct ipq *ipqueue = NULL; /* IP fragment queue */
/*
* Create a new fragment entry.
*/
/* Create a new fragment entry. */
static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr)
{
struct ipfrag *fp;
......@@ -664,7 +539,6 @@ static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, u
* Find the correct entry in the "incomplete datagrams" queue for
* this IP datagram, and return the queue entry address if found.
*/
static struct ipq *ip_find(struct iphdr *iph)
{
struct ipq *qp;
......@@ -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)
{
......@@ -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)
{
struct ipfrag *fp;
......@@ -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)
{
struct sk_buff *skb;
......@@ -914,7 +780,6 @@ static struct sk_buff *ip_glue(struct ipq *qp)
{
if(count+fp->len>skb->len)
{
/* In case some fool sends us a silly fragment. */
printk("Invalid fragment list: Fragment over size.\n");
kfree_skb(skb,FREE_WRITE);
return NULL;
......@@ -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)
{
struct ipfrag *prev, *next;
......@@ -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
* if this function causes a loop...
*/
void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag)
{
struct iphdr *iph;
......@@ -1134,16 +995,6 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
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. */
if (is_frag & 2)
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
#ifdef CONFIG_IP_FORWARD
/*
* Forward an IP datagram to its next destination.
*/
static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
/* Forward an IP datagram to its next destination. */
static void
ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
{
struct device *dev2;
struct iphdr *iph;
......@@ -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
* 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->ttl--;
if (iph->ttl <= 0)
{
if (iph->ttl <= 0) {
DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n"));
DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
......@@ -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.
*/
rt = rt_route(iph->daddr, NULL);
if (rt == NULL)
{
if (rt == NULL) {
DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n"));
/* 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)
* IP address itself- we seem to be connected directly...
*/
raddr = rt->rt_gateway;
if (raddr != 0)
{
if (raddr != 0) {
rt = rt_route(raddr, NULL);
if (rt == NULL)
{
if (rt == NULL) {
DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n"));
/* Tell the sender its packet cannot be delivered... */
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev);
return;
}
if (rt->rt_gateway != 0)
raddr = rt->rt_gateway;
}
else
raddr = iph->daddr;
if (rt->rt_gateway != 0) raddr = rt->rt_gateway;
} else raddr = iph->daddr;
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)
return;
/*
......@@ -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",
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) +
dev2->hard_header_len + skb->len, GFP_ATOMIC);
if (skb2 == NULL)
{
if (skb2 == NULL) {
printk("\nIP: No memory available for IP forward\n");
return;
}
......@@ -1318,6 +1155,8 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
skb2->sk = NULL;
skb2->free = 1;
skb2->len = skb->len + dev2->hard_header_len;
skb2->mem_addr = skb2;
skb2->mem_len = sizeof(struct sk_buff) + skb2->len;
skb2->next = NULL;
skb2->h.raw = ptr;
......@@ -1340,28 +1179,24 @@ static void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag)
#endif
/*
* This function receives all incoming IP datagrams.
*/
int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/* This function receives all incoming IP datagrams. */
int
ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct iphdr *iph = skb->h.iph;
unsigned char hash;
unsigned char flag = 0;
unsigned char opts_p = 0; /* Set iff the packet has options. */
struct inet_protocol *ipprot;
struct options *opt=NULL;
static struct options opt; /* since we don't use these yet, and they
take up stack space. */
int brd;
int is_frag=0;
DPRINTF((DBG_IP, "<<\n"));
/* Is the datagram acceptable? */
if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)
{
if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) {
DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
......@@ -1370,21 +1205,12 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0);
}
if (iph->ihl != 5)
{ /* Fast path for the typical optionless IP packet. */
#ifdef IP_DEBUG
if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */
ip_print(iph); /* Bogus, only for debugging. */
#endif
if (do_options(iph, &opt,dev) != 0)
{
if(opt)
kfree(opt);
memset((char *) &opt, 0, sizeof(opt));
if (do_options(iph, &opt) != 0)
return 0;
}
/* skb->ip_options=opt_ptr;*/
kfree(opt);
opt = NULL;
opts_p = 0/*1*/;
opts_p = 1;
}
if (iph->frag_off & 0x0020)
......@@ -1393,8 +1219,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
is_frag|=2;
/* 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
ip_forward(skb, dev, is_frag);
#else
......@@ -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. */
skb->ip_hdr = iph;
skb->h.raw += iph->ihl*4;
hash = iph->protocol & (MAX_INET_PROTOS -1);
/* Find someone to deliver it too */
for (ipprot = (struct inet_protocol *)inet_protos[hash];
ipprot != NULL;
ipprot=(struct inet_protocol *)ipprot->next)
{
struct sk_buff *skb2;
if (ipprot->protocol != iph->protocol)
continue;
if (ipprot->protocol != iph->protocol) continue;
DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot));
print_ipprot(ipprot);
......@@ -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.
* and then not for the last one.
*/
if (ipprot->copy)
{
if (ipprot->copy) {
skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
if (skb2 == NULL)
continue;
......@@ -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);
skb2->free=1;
}
else
{
} else {
skb2 = skb;
}
flag = 1;
......@@ -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
* 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)),
iph->saddr, 0, ipprot);
......@@ -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
* ICMP reply messages get queued up for transmission...)
*/
if (!flag)
{
if (!flag) {
if (brd != IS_BROADCAST)
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
skb->sk = NULL;
......@@ -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
* compute the checksum.
*/
void ip_queue_xmit(struct sock *sk, struct device *dev,
void
ip_queue_xmit(struct sock *sk, struct device *dev,
struct sk_buff *skb, int free)
{
struct iphdr *iph;
unsigned char *ptr;
if (sk == NULL)
free = 1;
if (dev == NULL)
{
if (sk == NULL) free = 1;
if (dev == NULL) {
printk("IP: ip_queue_xmit dev = NULL\n");
return;
}
......@@ -1543,33 +1368,24 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
}
ip_send_check(iph);
#ifdef IP_DEBUG
ip_print(iph);
#endif
skb->next = NULL;
/* See if this is the one trashing our queue. Ross? */
skb->magic = 1;
if (!free)
{
if (!free) {
skb->link3 = NULL;
sk->packets_out++;
cli();
if (sk->send_head == NULL)
{
if (sk->send_head == NULL) {
sk->send_tail = skb;
sk->send_head = skb;
}
else
{
} else {
/* 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");
sort_send(sk);
}
else
{
} else {
sk->send_tail->link3 = skb;
sk->send_tail = skb;
}
......@@ -1577,32 +1393,26 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
sti();
reset_timer(sk, TIME_WRITE,
backoff(sk->backoff) * (2 * sk->mdev + sk->rtt));
}
else
{
} else {
skb->sk = sk;
}
/* If the indicated interface is up and running, kick it. */
if (dev->flags & IFF_UP)
{
if (sk != NULL)
{
if (dev->flags & IFF_UP) {
if (sk != NULL) {
dev->queue_xmit(skb, dev, sk->priority);
}
else
{
else {
dev->queue_xmit(skb, dev, SOPRI_NORMAL);
}
}
else
{
} else {
if (free) kfree_skb(skb, FREE_WRITE);
}
}
void ip_retransmit(struct sock *sk, int all)
void
ip_retransmit(struct sock *sk, int all)
{
struct sk_buff * skb;
struct proto *prot;
......@@ -1610,8 +1420,7 @@ void ip_retransmit(struct sock *sk, int all)
prot = sk->prot;
skb = sk->send_head;
while (skb != NULL)
{
while (skb != NULL) {
dev = skb->dev;
/* I know this can't happen but as it does.. */
if(dev==NULL)
......@@ -1630,13 +1439,10 @@ void ip_retransmit(struct sock *sk, int all)
cli(); /* We might get interrupted by an arp reply here and fill
the frame in twice. Because of the technique used this
would be a little sad */
if (!skb->arp)
{
if (dev->rebuild_header(skb+1, dev))
{
if (!skb->arp) {
if (dev->rebuild_header(skb+1, dev)) {
sti(); /* Failed to rebuild - next */
if (!all)
break;
if (!all) break;
skb = (struct sk_buff *)skb->link3;
continue;
}
......@@ -1646,20 +1452,17 @@ void ip_retransmit(struct sock *sk, int all)
skb->when = jiffies;
/* If the interface is (still) up and running, kick it. */
if (dev->flags & IFF_UP)
{
if (sk)
dev->queue_xmit(skb, dev, sk->priority);
if (dev->flags & IFF_UP) {
if (sk) dev->queue_xmit(skb, dev, sk->priority);
/* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
oops: sk->retransmits++;
sk->prot->retransmits ++;
if (!all)
break;
if (!all) break;
/* This should cut it off before we send too many packets. */
if (sk->retransmits > sk->cong_window)
break;
if (sk->retransmits > sk->cong_window) break;
skb = (struct sk_buff *)skb->link3;
}
......@@ -1673,10 +1476,7 @@ oops: sk->retransmits++;
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)
{
/* Use binary exponential up to retry #4, and quadratic after that
......@@ -1704,73 +1504,3 @@ int backoff(int n)
}
}
/*
* Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
* an IP socket.
*/
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
int val,err;
if (optval == NULL)
return(-EINVAL);
err=verify_area(VERIFY_READ, optval, sizeof(int));
if(err)
return err;
val = get_fs_long((unsigned long *)optval);
if(level!=SOL_IP)
return -EOPNOTSUPP;
switch(optname)
{
case IP_TOS:
if(val<0||val>255)
return -EINVAL;
sk->ip_tos=val;
return 0;
case IP_TTL:
if(val<1||val<255)
return -EINVAL;
sk->ip_ttl=val;
return 0;
/* IP_OPTIONS and friends go here eventually */
default:
return(-ENOPROTOOPT);
}
}
int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
{
int val,err;
if(level!=SOL_IP)
return -EOPNOTSUPP;
switch(optname)
{
case IP_TOS:
val=sk->ip_tos;
break;
case IP_TTL:
val=sk->ip_ttl;
break;
default:
return(-ENOPROTOOPT);
}
err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
if(err)
return err;
put_fs_long(sizeof(int),(unsigned long *) optlen);
err=verify_area(VERIFY_WRITE, optval, sizeof(int));
if(err)
return err;
put_fs_long(val,(unsigned long *)optval);
return(0);
}
......@@ -21,8 +21,8 @@
#include <linux/ip.h>
#include "sockinet.h"
#include "sock.h" /* struct sock */
/* IP flags. */
#define IP_CE 0x8000 /* Flag: "Congestion" */
......@@ -69,8 +69,7 @@ extern int ip_build_header(struct sk_buff *skb,
unsigned long saddr,
unsigned long daddr,
struct device **dev, int type,
struct options *opt, int len,
int tos,int ttl);
struct options *opt, int len);
extern unsigned short ip_compute_csum(unsigned char * buff, int len);
extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
......@@ -78,6 +77,5 @@ extern void ip_queue_xmit(struct sock *sk,
struct device *dev, struct sk_buff *skb,
int free);
extern void ip_retransmit(struct sock *sk, int all);
extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen);
extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
#endif /* _IP_H */
......@@ -5,59 +5,55 @@
*
* Pseudo-driver for the loopback interface.
*
* Version: @(#)loopback.c 1.28 20/12/93
* Version: @(#)loopback.c 1.0.4b 08/16/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
*
* This file should be in drivers/net, but our glorious leader
* has put it here, and who are we to argue with the Linus 8-)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>
#include <linux/if_ether.h> /* For the statistics structure. */
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include "arp.h"
static int loopback_xmit(struct sk_buff *skb, struct device *dev)
static int
loopback_xmit(struct sk_buff *skb, struct device *dev)
{
struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
int done;
DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb));
if (skb == NULL || dev == NULL)
return(0);
if (skb == NULL || dev == NULL) return(0);
cli();
if (dev->tbusy != 0)
{
if (dev->tbusy != 0) {
sti();
stats->tx_errors++;
return(1);
......@@ -66,11 +62,9 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
sti();
done = dev_rint((unsigned char *)(skb+1), skb->len, 0, dev);
if (skb->free)
kfree_skb(skb, FREE_WRITE);
if (skb->free) kfree_skb(skb, FREE_WRITE);
while (done != 1)
{
while (done != 1) {
done = dev_rint(NULL, 0, 0, dev);
}
stats->tx_packets++;
......@@ -95,13 +89,15 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev)
return(0);
}
static struct enet_statistics *get_stats(struct device *dev)
static struct enet_statistics *
get_stats(struct device *dev)
{
return (struct enet_statistics *)dev->priv;
}
/* Initialize the rest of the LOOPBACK device. */
int loopback_init(struct device *dev)
int
loopback_init(struct device *dev)
{
dev->mtu = 2000; /* MTU */
dev->tbusy = 0;
......
......@@ -5,7 +5,7 @@
*
* PACKET - implements raw packet sockets.
*
* Version: @(#)packet.c 1.28 20/12/93
* Version: @(#)packet.c 1.0.6 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -18,7 +18,6 @@
* added. Also fixed the peek/read crash
* from all old Linux datagram code.
* Alan Cox : Uses the improved datagram code.
* Alan Cox : Clean up for final release.
*
*
* This program is free software; you can redistribute it and/or
......@@ -32,12 +31,12 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include <linux/errno.h>
#include <linux/timer.h>
#include <asm/system.h>
......@@ -45,23 +44,18 @@
#include "udp.h"
#include "raw.h"
/*
* I'm sure there should be one of these, not one every file.
*/
static unsigned long min(unsigned long a, unsigned long b)
static unsigned long
min(unsigned long a, unsigned long b)
{
if (a < b)
return(a);
if (a < b) return(a);
return(b);
}
/*
* This should be the easiest of all, all we do is copy it into a buffer.
*/
int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/* This should be the easiest of all, all we do is copy it into a buffer. */
int
packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct sock *sk;
......@@ -72,26 +66,22 @@ int packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
skb->sk = sk;
/* 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;
kfree_skb(skb, FREE_READ);
return(0);
}
sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
release_sock(sk);
sk->data_ready(sk,skb->len);
return(0);
}
/*
* This will do terrible things if len + ipheader + devheader > dev->mtu
* Since only root can use these thats okish...
*/
static int packet_sendto(struct sock *sk, unsigned char *from, int len,
/* This will do terrible things if len + ipheader + devheader > dev->mtu */
static int
packet_sendto(struct sock *sk, unsigned char *from, int len,
int noblock, unsigned flags, struct sockaddr_in *usin,
int addr_len)
{
......@@ -101,69 +91,64 @@ static int packet_sendto(struct sock *sk, unsigned char *from, int len,
int err;
/* Check the flags. */
if (flags)
return(-EINVAL);
if (len < 0)
return(-EINVAL);
if (flags) return(-EINVAL);
if (len < 0) return(-EINVAL);
/* Get and verify the address. */
if (usin)
{
if (addr_len < sizeof(saddr))
return(-EINVAL);
if (usin) {
if (addr_len < sizeof(saddr)) return(-EINVAL);
err=verify_area(VERIFY_READ, usin, sizeof(saddr));
if(err)
return err;
memcpy_fromfs(&saddr, usin, sizeof(saddr));
}
else
} else
return(-EINVAL);
err=verify_area(VERIFY_READ,from,len);
if(err)
return(err);
/* Find the device first to size check it */
/* Find the device first to size check it */
saddr.sa_data[13] = 0;
dev = dev_get(saddr.sa_data);
if (dev == NULL)
{
if (dev == NULL) {
return(-ENXIO);
}
if(len>dev->mtu)
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);
/* This shouldn't happen, but it could. */
if (skb == NULL)
{
if (skb == NULL) {
DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
return(-ENOMEM);
}
/* Fill it in */
skb->mem_addr = skb;
skb->mem_len = len + sizeof(*skb);
skb->sk = sk;
skb->free = 1;
memcpy_fromfs (skb+1, from, len);
skb->len = len;
skb->next = NULL;
if (dev->flags & IFF_UP)
dev->queue_xmit(skb, dev, sk->priority);
else
kfree_skb(skb, FREE_WRITE);
if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority);
else kfree_skb(skb, FREE_WRITE);
return(len);
}
static int packet_write(struct sock *sk, unsigned char *buff,
static int
packet_write(struct sock *sk, unsigned char *buff,
int len, int noblock, unsigned flags)
{
return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
static void packet_close(struct sock *sk, int timeout)
static void
packet_close(struct sock *sk, int timeout)
{
sk->inuse = 1;
sk->state = TCP_CLOSE;
......@@ -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;
p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL)
return(-ENOMEM);
if (p == NULL) return(-ENOMEM);
p->func = packet_rcv;
p->type = sk->num;
......@@ -198,7 +183,8 @@ static int packet_init(struct sock *sk)
* This should be easy, if there is something there
* we return it, otherwise we block.
*/
int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int
packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
......@@ -208,15 +194,11 @@ int packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int err;
saddr = (struct sockaddr *)sin;
if (len == 0)
return(0);
if (len < 0)
return(-EINVAL);
if (len == 0) return(0);
if (len < 0) return(-EINVAL);
if (sk->shutdown & RCV_SHUTDOWN)
return(0);
if (addr_len)
{
if (sk->shutdown & RCV_SHUTDOWN) return(0);
if (addr_len) {
err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(err)
return err;
......@@ -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 */
/* Copy the address. */
if (saddr)
{
if (saddr) {
struct sockaddr addr;
addr.sa_family = skb->dev->type;
......@@ -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)
{
return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
struct proto packet_prot =
{
struct proto packet_prot = {
sock_wmalloc,
sock_rmalloc,
sock_wfree,
......@@ -283,8 +264,6 @@ struct proto packet_prot =
NULL,
packet_init,
NULL,
NULL, /* No set/get socket options */
NULL,
128,
0,
{NULL,},
......
......@@ -7,7 +7,7 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
* Version: @(#)proc.c 1.28 20/12/93
* Version: @(#)proc.c 1.0.5 05/27/93
*
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
......@@ -18,7 +18,10 @@
* using hint flag for the netinfo.
* Pauline Middelink : Pidentd support
* Alan Cox : Make /proc safer.
* Alan Cox : Final clean up.
*
* To Do:
* Put the creating userid in the proc/net/... files. This will
* allow us to write an RFC931 daemon for Linux
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -34,13 +37,13 @@
#include <linux/in.h>
#include <linux/param.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "udp.h"
#include "socket/skbuff.h"
#include "sockinet.h"
#include "skbuff.h"
#include "sock.h"
#include "raw.h"
/*
......@@ -50,7 +53,8 @@
* As in get_unix_netinfo, the buffer might be too small. If this
* happens, get__netinfo returns only part of the available infos.
*/
static int get__netinfo(struct proto *pro, char *buffer, int format)
static int
get__netinfo(struct proto *pro, char *buffer, int format)
{
struct sock **s_array;
struct sock *sp;
......@@ -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
* 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();
sp = s_array[i];
while(sp != NULL)
{
while(sp != NULL) {
dest = sp->daddr;
src = sp->saddr;
destp = sp->dummy_th.dest;
......@@ -93,8 +95,7 @@ static int get__netinfo(struct proto *pro, char *buffer, int format)
if (timer_active)
add_timer(&sp->timer);
/* 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",
pro->name);
return(strlen(buffer));
......
......@@ -5,7 +5,7 @@
*
* INET protocol dispatch tables.
*
* Version: @(#)protocol.c 1.28 20/12/93
* Version: @(#)protocol.c 1.0.5 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -14,8 +14,7 @@
* Alan Cox : Ahah! udp icmp errors don't work because
* udp_err is never called!
* Alan Cox : Added new fields for init and ready for
* proper fragmentation (_NO_ 4K limits!).
* Alan Cox : Final clean up.
* proper fragmentation (_NO_ 4K limits!)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -31,18 +30,17 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "socket/skbuff.h"
#include "sockinet.h"
#include "skbuff.h"
#include "sock.h"
#include "icmp.h"
#include "udp.h"
static struct inet_protocol tcp_protocol =
{
static struct inet_protocol tcp_protocol = {
tcp_rcv, /* TCP handler */
NULL, /* No fragment handler (and won't be for a long time) */
tcp_err, /* TCP error control */
......@@ -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 */
NULL, /* Will be UDP fraglist handler */
udp_err, /* UDP error control */
......@@ -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 */
NULL, /* ICMP never fragments anyway */
NULL, /* ICMP error control */
......@@ -81,31 +77,29 @@ static struct inet_protocol 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
};
struct inet_protocol *inet_get_protocol(unsigned char prot)
struct inet_protocol *
inet_get_protocol(unsigned char prot)
{
unsigned char hash;
struct inet_protocol *p;
DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot));
hash = prot & (MAX_INET_PROTOS - 1);
for (p = inet_protos[hash] ; p != NULL; p=p->next)
{
for (p = inet_protos[hash] ; p != NULL; p=p->next) {
DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol));
if (p->protocol == prot)
return((struct inet_protocol *) p);
if (p->protocol == prot) return((struct inet_protocol *) p);
}
return(NULL);
}
void inet_add_protocol(struct inet_protocol *prot)
void
inet_add_protocol(struct inet_protocol *prot)
{
unsigned char hash;
struct inet_protocol *p2;
......@@ -117,10 +111,8 @@ void inet_add_protocol(struct inet_protocol *prot)
/* Set the copy bit if we need to. */
p2 = (struct inet_protocol *) prot->next;
while(p2 != NULL)
{
if (p2->protocol == prot->protocol)
{
while(p2 != NULL) {
if (p2->protocol == prot->protocol) {
prot->copy = 1;
break;
}
......@@ -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 *lp = NULL;
unsigned char hash;
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;
return(0);
}
p = (struct inet_protocol *) inet_protos[hash];
while(p != NULL)
{
while(p != NULL) {
/*
* We have to worry if the protocol being deleted is
* the last one on the list, then we may need to reset
* someones copied bit.
*/
if (p->next != NULL && p->next == prot)
{
if (p->next != NULL && p->next == prot) {
/*
* if we are the last one with this protocol and
* there is a previous one, reset its copy bit.
*/
if (p->copy == 0 && lp != NULL)
lp->copy = 0;
if (p->copy == 0 && lp != NULL) lp->copy = 0;
p->next = prot->next;
return(0);
}
if (p->next != NULL && p->next->protocol == prot->protocol)
{
if (p->next != NULL && p->next->protocol == prot->protocol) {
lp = p;
}
......
......@@ -5,7 +5,7 @@
*
* RAW - implementation of IP "raw" sockets.
*
* Version: @(#)raw.c 1.28 20/12/93
* Version: @(#)raw.c 1.0.4 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -19,16 +19,12 @@
* Alan Cox : Checks sk->broadcast.
* Alan Cox : Uses skb_free_datagram/skb_copy_datagram
* Alan Cox : Raw passes ip options too
* Alan Cox : Cleaned up and reformatted for final release
* Alan Cox : Added socket option call to proto
* Alan Cox : Corrected broadcast check error to EACCES
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/types.h>
......@@ -41,29 +37,27 @@
#include <linux/socket.h>
#include <linux/in.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include "icmp.h"
#include "udp.h"
static unsigned long min(unsigned long a, unsigned long b)
static unsigned long
min(unsigned long a, unsigned long b)
{
if (a < b)
return(a);
if (a < b) return(a);
return(b);
}
/*
* raw_err gets called by the icmp module.
*/
void raw_err (int err, unsigned char *header, unsigned long daddr,
/* raw_err gets called by the icmp module. */
void
raw_err (int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
struct sock *sk;
......@@ -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",
err, header, daddr, saddr, protocol));
if (protocol == NULL)
return;
if (protocol == NULL) return;
sk = (struct sock *) protocol->data;
if (sk == NULL)
return;
if (sk == NULL) return;
/* This is meaningless in raw sockets. */
if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8))
{
if (sk->cong_window > 1)
sk->cong_window = sk->cong_window/2;
if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) {
if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
return;
}
sk->err = icmp_err_convert[err & 0xff].errno;
sk->error_report(sk);
wake_up(sk->sleep);
return;
}
/*
* This should be the easiest of all, all we do is\
* copy it into a buffer. We do have to diddle the pointer
* to get the ip header too.
* copy it into a buffer.
*/
int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
int
raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len, unsigned long saddr,
int redo, struct inet_protocol *protocol)
{
......@@ -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",
skb, dev, opt, daddr, len, saddr, redo, protocol));
if (skb == NULL)
return(0);
if (protocol == NULL)
{
if (skb == NULL) return(0);
if (protocol == NULL) {
kfree_skb(skb, FREE_READ);
return(0);
}
sk = (struct sock *) protocol->data;
if (sk == NULL)
{
if (sk == NULL) {
kfree_skb(skb, FREE_READ);
return(0);
}
/* Now we need to copy this into memory. */
skb->sk = sk;
/*
* Adjust to get the header back
*/
skb->len += skb->ip_hdr->ihl*sizeof(long);
skb->h.iph = skb->ip_hdr;
skb->len = len;
skb->dev = dev;
skb->saddr = daddr;
skb->daddr = saddr;
/* Charge it too the socket. */
if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf)
{
if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return(0);
}
sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
release_sock(sk);
sk->data_ready(sk,skb->len);
return(0);
}
/*
* Send a RAW IP packet (user level IP protocols). Root only
* caller provides IP header.
*/
static int raw_sendto(struct sock *sk, unsigned char *from, int len,
/* This will do terrible things if len + ipheader + devheader > dev->mtu */
static int
raw_sendto(struct sock *sk, unsigned char *from, int len,
int noblock,
unsigned flags, struct sockaddr_in *usin, int addr_len)
{
......@@ -171,44 +146,34 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
flags, usin, addr_len));
/* Check the flags. */
if (flags)
return(-EINVAL);
if (len < 0)
return(-EINVAL);
if (flags) return(-EINVAL);
if (len < 0) return(-EINVAL);
err=verify_area(VERIFY_READ,from,len);
if(err)
return err;
/* Get and verify the address. */
if (usin)
{
if (addr_len < sizeof(sin))
return(-EINVAL);
if (usin) {
if (addr_len < sizeof(sin)) return(-EINVAL);
err=verify_area (VERIFY_READ, usin, sizeof (sin));
if(err)
return err;
memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET)
return(-EINVAL);
}
else
{
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);
if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
} else {
if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
sin.sin_family = AF_INET;
sin.sin_port = sk->protocol;
sin.sin_addr.s_addr = sk->daddr;
}
if (sin.sin_port == 0)
sin.sin_port = sk->protocol;
if (sin.sin_port == 0) sin.sin_port = sk->protocol;
if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES;
return -ENETUNREACH;
sk->inuse = 1;
skb = NULL;
while (skb == NULL)
{
while (skb == NULL) {
if(sk->err!=0)
{
err= -sk->err;
......@@ -220,8 +185,7 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
skb = (struct sk_buff *) sk->prot->wmalloc(sk,
len+sizeof(*skb) + sk->prot->max_header,
0, GFP_KERNEL);
if (skb == NULL)
{
if (skb == NULL) {
int tmp;
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,
tmp = sk->wmem_alloc;
release_sock(sk);
cli();
if (tmp <= sk->wmem_alloc)
{
if (tmp <= sk->wmem_alloc) {
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked)
{
if (current->signal & ~current->blocked) {
sti();
return(-ERESTARTSYS);
}
......@@ -243,6 +205,8 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
sti();
}
}
skb->mem_addr = skb;
skb->mem_len = len + sizeof(*skb) +sk->prot->max_header;
skb->sk = sk;
skb->free = 1; /* these two should be unecessary. */
......@@ -250,23 +214,21 @@ static int raw_sendto(struct sock *sk, unsigned char *from, int len,
tmp = sk->prot->build_header(skb, sk->saddr,
sin.sin_addr.s_addr, &dev,
sk->protocol, sk->opt, skb->mem_len,
sk->ip_ttl,sk->ip_tos);
if (tmp < 0)
{
sk->protocol, sk->opt, skb->mem_len);
if (tmp < 0) {
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
kfree_skb(skb,FREE_WRITE);
release_sock(sk);
return(tmp);
}
/* verify_area(VERIFY_WRITE, from, len);*/
memcpy_fromfs ((unsigned char *)(skb+1)+tmp, from, len);
/* If we are using IPPROTO_RAW, we need to fill in the source address in
the IP header */
if(sk->protocol==IPPROTO_RAW)
{
if(sk->protocol==IPPROTO_RAW) {
unsigned char *buff;
struct iphdr *iph;
......@@ -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)
{
return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
static void raw_close(struct sock *sk, int timeout)
static void
raw_close(struct sock *sk, int timeout)
{
sk->inuse = 1;
sk->state = TCP_CLOSE;
......@@ -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;
p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
if (p == NULL)
return(-ENOMEM);
if (p == NULL) return(-ENOMEM);
p->handler = raw_rcv;
p->protocol = sk->protocol;
......@@ -343,8 +307,8 @@ static int raw_init(struct sock *sk)
* This should be easy, if there is something there
* we return it, otherwise we block.
*/
int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
int
raw_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
......@@ -356,15 +320,11 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
" sin=%X, addr_len=%X)\n",
sk, to, len, noblock, flags, sin, addr_len));
if (len == 0)
return(0);
if (len < 0)
return(-EINVAL);
if (len == 0) return(0);
if (len < 0) return(-EINVAL);
if (sk->shutdown & RCV_SHUTDOWN)
return(0);
if (addr_len)
{
if (sk->shutdown & RCV_SHUTDOWN) return(0);
if (addr_len) {
err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(err)
return err;
......@@ -383,8 +343,7 @@ int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
skb_copy_datagram(skb, 0, to, copied);
/* Copy the address. */
if (sin)
{
if (sin) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
......@@ -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)
{
return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
struct proto raw_prot =
{
struct proto raw_prot = {
sock_wmalloc,
sock_rmalloc,
sock_wfree,
......@@ -431,8 +390,6 @@ struct proto raw_prot =
NULL,
raw_init,
NULL,
ip_setsockopt,
ip_getsockopt,
128,
0,
{NULL,},
......
......@@ -47,10 +47,10 @@ static struct rtable *rt_base = NULL;
static struct rtable *rt_loopback = NULL;
/* Dump the contents of a routing table entry. */
static void rt_print(struct rtable *rt)
static void
rt_print(struct rtable *rt)
{
if (rt == NULL || inet_debug != DBG_RT)
return;
if (rt == NULL || inet_debug != DBG_RT) return;
printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",
(long) rt, (long) rt->rt_next, rt->rt_flags);
......@@ -162,8 +162,8 @@ static inline struct device * get_gw_dev(unsigned long gw)
/*
* rewrote rt_add(), as the old one was weird. Linus
*/
void rt_add(short flags, unsigned long dst, unsigned long mask,
unsigned long gw, struct device *dev)
void
rt_add(short flags, unsigned long dst, unsigned long mask, unsigned long gw, struct device *dev)
{
struct rtable *r, *rt;
struct rtable **rp;
......@@ -280,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;
trg = (struct sockaddr_in *) &r->rt_dst;
rt_del(trg->sin_addr.s_addr);
return 0;
return(0);
}
/* Called from the PROCfs module. */
int rt_get_info(char *buffer)
int
rt_get_info(char *buffer)
{
struct rtable *r;
char *pos;
......@@ -308,7 +311,7 @@ int rt_get_info(char *buffer)
r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,
r->rt_mask);
}
return pos - buffer;
return(pos - buffer);
}
/*
......@@ -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 rtentry rt;
......@@ -349,17 +353,15 @@ int rt_ioctl(unsigned int cmd, void *arg)
case DDIOCSDBG:
ret = dbg_ioctl(arg, DBG_RT);
break;
case SIOCADDRT:
case SIOCDELRT:
if (!suser())
return -EPERM;
err = verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
if (!suser()) return(-EPERM);
err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
if(err)
return err;
memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
if (rt.rt_dev) {
err = verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
if(err)
return err;
memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
......@@ -368,10 +370,9 @@ int rt_ioctl(unsigned int cmd, void *arg)
}
ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);
break;
default:
ret = -EINVAL;
}
return ret;
return(ret);
}
......@@ -303,9 +303,6 @@ struct sk_buff *skb_peek(struct sk_buff *volatile* list)
return *list;
}
#ifdef UNUSED_NOW
/*
* Get a clone of an sk_buff. This is the safe way to peek at
* a socket queue without accidents. Its a bit long but most
......@@ -372,8 +369,6 @@ struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
return(newsk);
}
#endif
/*
* Free an sk_buff. This still knows about things it should
* not need to like protocols and sockets.
......@@ -409,14 +404,12 @@ void kfree_skb(struct sk_buff *skb, int rw)
else
skb->sk->wmem_alloc-=skb->mem_len;
if(!skb->sk->dead)
skb->sk->write_space(skb->sk);
wake_up(skb->sk->sleep);
kfree_skbmem(skb->mem_addr,skb->mem_len);
}
}
else
{
kfree_skbmem(skb->mem_addr, skb->mem_len);
}
}
/*
......
......@@ -17,7 +17,6 @@
* Alan Cox : Fraglist support (idea by Donald Becker)
* Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy
* being used.
* Alan Cox : Extra fields for RAW fixes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -29,7 +28,7 @@
#include <linux/malloc.h>
#ifdef CONFIG_IPX
#include "ipx/ipx.h"
#include "ipx.h"
#endif
#define HAVE_ALLOC_SKB /* For the drivers to know */
......@@ -39,8 +38,7 @@
#define FREE_WRITE 0
struct sk_buff
{
struct sk_buff {
unsigned long magic_debug_cookie;
struct sk_buff *volatile next;
struct sk_buff *volatile prev;
......@@ -50,8 +48,7 @@ struct sk_buff
volatile unsigned long when; /* used to compute rtt's */
struct device *dev;
void *mem_addr;
union
{
union {
struct tcphdr *th;
struct ethhdr *eth;
struct iphdr *iph;
......@@ -63,7 +60,6 @@ struct sk_buff
ipx_packet *ipx;
#endif
} h;
struct iphdr * ip_hdr;
unsigned long mem_len;
unsigned long len;
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 @@
* normal compare so long as neither of the numbers is within
* 4K of wrapping. Otherwise we must check for the wrap.
*/
static inline int before (unsigned long seq1, unsigned long seq2)
static inline int
before (unsigned long seq1, unsigned long seq2)
{
/* this inequality is strict. */
if (seq1 == seq2)
return(0);
if (seq1 == seq2) return(0);
if (seq1 < seq2)
{
if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL)
{
if (seq1 < seq2) {
if ((unsigned long)seq2-(unsigned long)seq1 < 65536UL) {
return(1);
}
else
{
} else {
return(0);
}
}
......@@ -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
* to see if seq1 has wrapped.
*/
if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL))
{
if (seq2 < 8192UL && seq1 > (0xffffffffUL - 8192UL)) {
return(1);
}
return(0);
}
static inline int after(unsigned long seq1, unsigned long seq2)
static inline int
after(unsigned long seq1, unsigned long seq2)
{
return(before(seq2, seq1));
}
/* 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));
}
......@@ -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)'
* problem. Thanks to Stephen A. Wood <saw@cebaf.gov> -FvK
*/
static inline const int tcp_connected(const int state)
static inline const int
tcp_connected(const int state)
{
return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT ||
state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 ||
......
......@@ -5,7 +5,7 @@
*
* TIMER - implementation of software timers.
*
* Version: @(#)timer.c 1.28 22/12/93
* Version: @(#)timer.c 1.0.7 05/25/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -24,8 +24,6 @@
* of inet_bh() with this socket being handled it goes
* BOOM! Have to stop timer going off if inet_bh is
* active or the destroy causes crashes.
* Alan Cox : Clean up for final release
* Alan Cox : Oops - timeouts destroyed permanent arp entries!
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -43,15 +41,16 @@
#include <asm/system.h>
#include <linux/interrupt.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include "arp.h"
void delete_timer (struct sock *t)
void
delete_timer (struct sock *t)
{
unsigned long flags;
......@@ -64,12 +63,14 @@ void delete_timer (struct sock *t)
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);
if (timeout != -1)
t->timeout = timeout;
#if 1
/* FIXME: ??? */
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)
* something, but we must be sure to process all of the
* sockets that need it.
*/
void net_timer (unsigned long data)
void
net_timer (unsigned long data)
{
struct sock *sk = (struct sock*)data;
int why = sk->timeout;
/* timeout is overwritten by 'delete_timer' and 'reset_timer' */
if (sk->inuse || in_inet_bh())
{
if (sk->inuse || in_inet_bh()) {
sk->timer.expires = 10;
add_timer(&sk->timer);
return;
......@@ -105,19 +105,16 @@ void net_timer (unsigned long data)
reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
/* Always see if we need to send an ack. */
if (sk->ack_backlog)
{
if (sk->ack_backlog) {
sk->prot->read_wakeup (sk);
if (! sk->dead)
wake_up (sk->sleep);
}
/* Now we need to figure out why the socket was on the timer. */
switch (why)
{
switch (why) {
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");
release_sock (sk);
break;
......@@ -144,7 +141,7 @@ void net_timer (unsigned long data)
sk->state = TCP_CLOSE;
delete_timer (sk);
/* Kill the ARP entry in case the hardware has changed. */
arp_destroy_maybe (sk->daddr);
arp_destroy (sk->daddr);
if (!sk->dead)
wake_up (sk->sleep);
sk->shutdown = SHUTDOWN_MASK;
......@@ -155,11 +152,9 @@ void net_timer (unsigned long data)
/* It could be we got here because we needed to send an ack.
* So we need to check for that.
*/
if (sk->send_head)
{
if (sk->send_head) {
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
+ backoff (sk->backoff) * (2 * sk->mdev + sk->rtt)) - jiffies);
release_sock (sk);
......@@ -170,24 +165,19 @@ void net_timer (unsigned long data)
DPRINTF ((DBG_TMR, "retransmitting.\n"));
sk->prot->retransmit (sk, 0);
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
{
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
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);
}
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"));
sk->err = ETIMEDOUT;
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;
reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
}
else
{
} else {
sk->prot->close (sk, 1);
break;
}
......@@ -200,35 +190,29 @@ void net_timer (unsigned long data)
if (sk->prot->write_wakeup)
sk->prot->write_wakeup (sk);
sk->retransmits++;
if (sk->shutdown == SHUTDOWN_MASK)
{
if (sk->shutdown == SHUTDOWN_MASK) {
sk->prot->close (sk, 1);
sk->state = TCP_CLOSE;
}
if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7))
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1))
{
|| (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) {
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);
release_sock (sk);
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"));
arp_destroy_maybe (sk->daddr);
arp_destroy (sk->daddr);
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;
if (!sk->dead)
wake_up (sk->sleep);
release_sock (sk);
}
else
{
} else {
sk->prot->close (sk, 1);
}
break;
......
......@@ -5,7 +5,7 @@
*
* The User Datagram Protocol (UDP).
*
* Version: @(#)udp.c 1.28 22/12/93
* Version: @(#)udp.c 1.0.13 06/02/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -30,11 +30,10 @@
* bug no longer crashes it.
* Fred Van Kempen : Net2e support for sk->broadcast.
* Alan Cox : Uses skb_free_datagram
* Alan Cox : Tidy up ready for the 'real' thing.
* Alan Cox : Added get/set sockopt support.
* Alan Cox : Broadcasting without option set returns EACCES.
* Alan Cox : No wakeup calls. Instead we now use the callbacks.
*
* To Do:
* Verify all the error codes from UDP operations match the
* BSD behaviour, since thats effectively the formal spec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -55,12 +54,12 @@
#include <linux/termios.h>
#include <linux/mm.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "ip.h"
#include "protocol.h"
#include "tcp.h"
#include "skbuff.h"
#include "sockinet.h"
#include "sock.h"
#include "udp.h"
#include "icmp.h"
......@@ -68,13 +67,12 @@
#define min(a,b) ((a)<(b)?(a):(b))
static void print_udp(struct udphdr *uh)
static void
print_udp(struct udphdr *uh)
{
if (inet_debug != DBG_UDP)
return;
if (inet_debug != DBG_UDP) return;
if (uh == NULL)
{
if (uh == NULL) {
printk("(NULL)\n");
return;
}
......@@ -93,8 +91,8 @@ static void print_udp(struct udphdr *uh)
* header points to the first 8 bytes of the udp header. We need
* to find the appropriate port.
*/
void udp_err(int err, unsigned char *header, unsigned long daddr,
void
udp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol)
{
struct udphdr *th;
......@@ -106,7 +104,7 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
th = (struct udphdr *)header;
DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
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);
......@@ -116,12 +114,11 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
if (err < 0) /* As per the calling spec */
{
sk->err = -err;
sk->error_report(sk); /* User process wakes to see error */
wake_up(sk->sleep); /* User process wakes to see error */
return;
}
if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8))
{ /* Slow down! */
if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */
if (sk->cong_window > 1)
sk->cong_window = sk->cong_window/2;
return;
......@@ -130,15 +127,15 @@ void udp_err(int err, unsigned char *header, unsigned long daddr,
sk->err = icmp_err_convert[err & 0xff].errno;
/* It's only fatal if we have connected to them. */
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED)
{
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
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 sum;
......@@ -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)
: "cx","bx","dx" );
if (len > 3)
{
if (len > 3) {
__asm__("\tclc\n"
"1:\n"
"\t lodsl\n"
......@@ -178,8 +174,7 @@ static unsigned short udp_check(struct udphdr *uh, int len,
: "bx", "cx");
/* Check for an extra word. */
if ((len & 2) != 0)
{
if ((len & 2) != 0) {
__asm__("\t lodsw\n"
"\t addw %%ax,%%bx\n"
"\t adcw $0, %%bx\n"
......@@ -189,8 +184,7 @@ static unsigned short udp_check(struct udphdr *uh, int len,
}
/* Now check for the extra byte. */
if ((len & 1) != 0)
{
if ((len & 1) != 0) {
__asm__("\t lodsb\n"
"\t movb $0,%%ah\n"
"\t addw %%ax,%%bx\n"
......@@ -204,24 +198,21 @@ static unsigned short udp_check(struct udphdr *uh, int len,
return((~sum) & 0xffff);
}
/*
* Calculate the UDP checksum. Note 0 becomes FFFF because 0 means
* 'no checksum'.
*/
static void udp_send_check(struct udphdr *uh, unsigned long saddr,
static void
udp_send_check(struct udphdr *uh, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
uh->check = 0;
if (sk && sk->no_check)
return;
uh->check = udp_check(uh, len, saddr, daddr);
if (uh->check == 0)
uh->check = 0xffff;
if (uh->check == 0) uh->check = 0xffff;
}
static int udp_send(struct sock *sk, struct sockaddr_in *sin,
static int
udp_send(struct sock *sk, struct sockaddr_in *sin,
unsigned char *from, int len)
{
struct sk_buff *skb;
......@@ -243,9 +234,10 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
/* Allocate a copy of the packet. */
size = sizeof(struct sk_buff) + sk->prot->max_header + len;
skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
if (skb == NULL)
return(-ENOMEM);
if (skb == NULL) return(-ENOMEM);
skb->mem_addr = skb;
skb->mem_len = size;
skb->sk = NULL; /* to avoid changing sk->saddr */
skb->free = 1;
skb->arp = 0;
......@@ -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",
saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
&dev, IPPROTO_UDP, sk->opt, skb->mem_len,
sk->ip_ttl,sk->ip_tos);
&dev, IPPROTO_UDP, sk->opt, skb->mem_len);
skb->sk=sk; /* So memory is freed correctly */
if (tmp < 0 )
{
if (tmp < 0 ) {
sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
return(tmp);
}
......@@ -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->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)
{
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);
return(-EMSGSIZE);
}
......@@ -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)
{
struct sockaddr_in sin;
......@@ -317,10 +317,8 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
return(0);
/* Get and verify the address. */
if (usin)
{
if (addr_len < sizeof(sin))
return(-EINVAL);
if (usin) {
if (addr_len < sizeof(sin)) return(-EINVAL);
err=verify_area(VERIFY_READ, usin, sizeof(sin));
if(err)
return err;
......@@ -329,18 +327,15 @@ static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock
return(-EINVAL);
if (sin.sin_port == 0)
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_port = sk->dummy_th.dest;
sin.sin_addr.s_addr = sk->daddr;
}
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */
return -ENETUNREACH; /* Must turn broadcast on first */
sk->inuse = 1;
/* Send the packet. */
......@@ -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)
{
return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
}
int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
int
udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
int err;
switch(cmd)
{
switch(cmd) {
case DDIOCSDBG:
{
int val;
if (!suser())
return(-EPERM);
if (!suser()) return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err)
return err;
val = get_fs_long((int *)arg);
switch(val)
{
switch(val) {
case 0:
inet_debug = 0;
break;
......@@ -387,14 +381,12 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
}
break;
case TIOCOUTQ:
{
unsigned long amount;
if (sk->state == TCP_LISTEN)
return(-EINVAL);
amount = sk->prot->wspace(sk);
if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = sk->prot->wspace(sk)/*/2*/;
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
if(err)
......@@ -408,12 +400,10 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
struct sk_buff *skb;
unsigned long amount;
if (sk->state == TCP_LISTEN)
return(-EINVAL);
if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = 0;
skb = sk->rqueue;
if (skb != NULL)
{
if (skb != NULL) {
/*
* We will only return the amount
* of this packet since that is all
......@@ -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.
*/
int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
int
udp_recvfrom(struct sock *sk, unsigned char *to, int len,
int noblock, unsigned flags, struct sockaddr_in *sin,
int *addr_len)
{
......@@ -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
* was doing something else.
*/
if (sk->err)
{
if (sk->err) {
int err;
err = -sk->err;
......@@ -467,8 +457,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
if (len < 0)
return(-EINVAL);
if (addr_len)
{
if (addr_len) {
er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(er)
return(er);
......@@ -492,8 +481,7 @@ int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
/* Copy the address. */
if (sin)
{
if (sin) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
......@@ -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)
{
return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
}
int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
int
udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
{
struct sockaddr_in sin;
int er;
......@@ -532,7 +522,7 @@ int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return(-EAFNOSUPPORT);
if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
return -EACCES; /* Must turn broadcast on first */
return -ENETUNREACH; /* Must turn broadcast on first */
sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port;
......@@ -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->state = TCP_CLOSE;
if (sk->dead)
destroy_sock(sk);
else
release_sock(sk);
if (sk->dead) destroy_sock(sk);
else release_sock(sk);
}
/*
* All we need to do is get the socket, and then do a checksum.
*/
int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
/* All we need to do is get the socket, and then do a checksum. */
int
udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
......@@ -581,8 +568,7 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
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"));
skb->sk = NULL;
kfree_skb(skb, FREE_WRITE);
......@@ -593,7 +579,7 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->dev = dev;
skb->len = len;
/* These are supposed to be switched. */
/* These are supposed to be switched. */
skb->daddr = saddr;
skb->saddr = daddr;
......@@ -618,17 +604,14 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->len = len - sizeof(*uh);
release_sock(sk);
if (!sk->dead)
sk->data_ready(sk,skb->len);
if (!sk->dead) wake_up(sk->sleep);
release_sock(sk);
return(0);
}
struct proto udp_prot =
{
struct proto udp_prot = {
sock_wmalloc,
sock_rmalloc,
sock_wfree,
......@@ -652,8 +635,6 @@ struct proto udp_prot =
udp_ioctl,
NULL,
NULL,
ip_setsockopt,
ip_getsockopt,
128,
0,
{NULL,},
......
......@@ -6,13 +6,12 @@
* Various kernel-resident INET utility functions; mainly
* for format conversion and debugging output.
*
* Version: @(#)utils.c 1.28 20/12/93
* Version: @(#)utils.c 1.0.7 05/18/93
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Fixes:
* Alan Cox : verify_area check.
* Alan Cox : Clean up to match code style
*
*
* This program is free software; you can redistribute it and/or
......@@ -33,7 +32,7 @@
#include <linux/stat.h>
#include <stdarg.h>
#include "inet.h"
#include "devinet.h"
#include "dev.h"
#include "eth.h"
#include "ip.h"
#include "protocol.h"
......@@ -42,10 +41,7 @@
#include "arp.h"
/*
* Display an IP address in readable format.
*/
/* Display an IP address in readable format. */
char *in_ntoa(unsigned long in)
{
static char buff[18];
......@@ -58,50 +54,43 @@ char *in_ntoa(unsigned long in)
}
/*
* Convert an ASCII string to binary IP.
*/
unsigned long in_aton(char *str)
/* Convert an ASCII string to binary IP. */
unsigned long
in_aton(char *str)
{
unsigned long l;
unsigned int val;
int i;
l = 0;
for (i = 0; i < 4; i++)
{
for (i = 0; i < 4; i++) {
l <<= 8;
if (*str != '\0')
{
if (*str != '\0') {
val = 0;
while (*str != '\0' && *str != '.')
{
while (*str != '\0' && *str != '.') {
val *= 10;
val += *str - '0';
str++;
}
l |= val;
if (*str != '\0')
str++;
if (*str != '\0') str++;
}
}
return(htonl(l));
}
void dprintf(int level, char *fmt, ...)
void
dprintf(int level, char *fmt, ...)
{
va_list args;
char *buff;
extern int vsprintf(char * buf, const char * fmt, va_list args);
if (level != inet_debug)
return;
if (level != inet_debug) return;
buff = (char *) kmalloc(256, GFP_ATOMIC);
if (buff != NULL)
{
if (buff != NULL) {
va_start(args, fmt);
vsprintf(buff, fmt, args);
va_end(args);
......@@ -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 err;
if (!suser())
return(-EPERM);
if (!suser()) return(-EPERM);
err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
if(err)
return err;
val = get_fs_long((int *)arg);
switch(val)
{
switch(val) {
case 0: /* OFF */
inet_debug = DBG_OFF;
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 @@
* the PROC file system and the "unix" family of networking
* protocols. It is mainly used for debugging and statistics.
*
* Version: @(#)proc.c 1.28 25/12/93
* Version: @(#)proc.c 1.0.4 05/23/93
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
......@@ -16,14 +16,12 @@
* Fred Baumgarten, <dc6iq@insu1.etec.uni-kalrsruhe.de>
*
* Fixes:
* Anonymous : Comment errors
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/autoconf.h>
#include <linux/sched.h>
#include <linux/string.h>
......@@ -35,10 +33,7 @@
#include "unix.h"
/*
* Called from PROCfs.
*/
/* Called from PROCfs. */
int unix_get_info(char *buffer)
{
char *pos;
......@@ -47,10 +42,8 @@ int unix_get_info(char *buffer)
pos = buffer;
pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n");
for(i = 0; i < NSOCKETS; i++)
{
if (unix_datas[i].refcnt)
{
for(i = 0; i < NSOCKETS; i++) {
if (unix_datas[i].refcnt) {
pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i,
unix_datas[i].refcnt,
unix_datas[i].protocol,
......@@ -60,13 +53,10 @@ int unix_get_info(char *buffer)
);
/* 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",
unix_datas[i].sockaddr_un.sun_path);
}
else
{ /* just add a newline */
} else { /* just add a newline */
*pos='\n';
pos++;
*pos='\0';
......@@ -77,9 +67,7 @@ int unix_get_info(char *buffer)
* Since sockets may have very very long paths, we make
* PATH_MAX+80 the minimum space left for a new line.
*/
if (pos > buffer+PAGE_SIZE-80-PATH_MAX)
{
if (pos > buffer+PAGE_SIZE-80-PATH_MAX) {
printk("UNIX: netinfo: oops, too many sockets.\n");
return(pos - buffer);
}
......
......@@ -4,7 +4,7 @@
* BSD Socket interface as the means of communication with
* the user level.
*
* Version: @(#)sock.c 1.28 25/12/93
* Version: @(#)sock.c 1.0.5 05/25/93
*
* Authors: Orest Zborowski, <obz@Kodak.COM>
* Ross Biro, <bir7@leland.Stanford.Edu>
......@@ -12,7 +12,6 @@
*
* Fixes:
* Alan Cox : Verify Area
* Alan Cox : Tidy up ready for release
*
* BUGS
* Page faults on read while another process reads could lose data.
......@@ -94,18 +93,17 @@ static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen);
static void dprintf(int level, char *fmt, ...)
static void
dprintf(int level, char *fmt, ...)
{
va_list args;
char *buff;
extern int vsprintf(char * buf, const char * fmt, va_list args);
if (level != unix_debug)
return;
if (level != unix_debug) return;
buff = (char *) kmalloc(256, GFP_KERNEL);
if (buff != NULL)
{
if (buff != NULL) {
va_start(args, fmt);
vsprintf(buff, fmt, args);
va_end(args);
......@@ -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)
return(a);
if (a < b) return(a);
return(b);
}
void sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
void
sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len)
{
char buf[sizeof(sockun->sun_path) + 1];
if (unix_debug == 0)
return;
if (unix_debug == 0) return;
sockaddr_len -= UN_PATH_OFFSET;
if (sockun->sun_family != AF_UNIX)
printk("UNIX: Badd addr family %d>\n", sockun->sun_family);
else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf))
printk("UNIX: Bad addr len %d>\n", sockaddr_len);
else
{
else {
memcpy(buf, sockun->sun_path, sockaddr_len);
buf[sockaddr_len] = '\0';
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)
}
/*
* Don't have to do anything.
*/
static int unix_proto_listen(struct socket *sock, int backlog)
/* don't have to do anything. */
static int
unix_proto_listen(struct socket *sock, int backlog)
{
return(0);
}
static int unix_proto_setsockopt(struct socket *sock, int level, int optname,
static int
unix_proto_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen)
{
return(-EOPNOTSUPP);
}
static int unix_proto_getsockopt(struct socket *sock, int level, int optname,
static int
unix_proto_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
{
return(-EOPNOTSUPP);
}
static int unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
static int
unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int addr_len)
{
return(-EOPNOTSUPP);
}
static int unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
static int
unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags, struct sockaddr *addr, int *addr_len)
{
return(-EOPNOTSUPP);
}
static int unix_proto_shutdown(struct socket *sock, int how)
static int
unix_proto_shutdown(struct socket *sock, int how)
{
return(-EOPNOTSUPP);
}
/*
* This error needs to be checked.
*/
static int unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
/* This error needs to be checked. */
static int
unix_proto_send(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
if (flags != 0)
return(-EINVAL);
if (flags != 0) return(-EINVAL);
return(unix_proto_write(sock, (char *) buff, len, nonblock));
}
/*
* This error needs to be checked.
*/
static int unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
/* This error needs to be checked. */
static int
unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock,
unsigned flags)
{
if (flags != 0)
return(-EINVAL);
if (flags != 0) return(-EINVAL);
return(unix_proto_read(sock, (char *) buff, len, nonblock));
}
static struct unix_proto_data * unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
static struct unix_proto_data *
unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len,
struct inode *inode)
{
struct unix_proto_data *upd;
for(upd = unix_datas; upd <= last_unix_data; ++upd)
{
for(upd = unix_datas; upd <= last_unix_data; ++upd) {
if (upd->refcnt && upd->socket &&
upd->socket->state == SS_UNCONNECTED &&
upd->sockaddr_un.sun_family == sockun->sun_family &&
upd->inode == inode)
{
return(upd);
}
upd->inode == inode) return(upd);
}
return(NULL);
}
static struct unix_proto_data *unix_data_alloc(void)
static struct unix_proto_data *
unix_data_alloc(void)
{
struct unix_proto_data *upd;
cli();
for(upd = unix_datas; upd <= last_unix_data; ++upd)
{
if (!upd->refcnt)
{
for(upd = unix_datas; upd <= last_unix_data; ++upd) {
if (!upd->refcnt) {
upd->refcnt = 1;
sti();
upd->socket = NULL;
......@@ -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");
return;
}
......@@ -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");
return;
}
if (upd->refcnt == 1)
{
if (upd->refcnt == 1) {
dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd);
if (upd->buf)
{
if (upd->buf) {
free_page((unsigned long)upd->buf);
upd->buf = NULL;
upd->bp_head = upd->bp_tail = 0;
......@@ -294,24 +282,21 @@ static void unix_data_deref(struct unix_proto_data *upd)
* Upon a create, we allocate an empty protocol data,
* and grab a page to buffer writes.
*/
static int unix_proto_create(struct socket *sock, int protocol)
static int
unix_proto_create(struct socket *sock, int protocol)
{
struct unix_proto_data *upd;
dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol);
if (protocol != 0)
{
if (protocol != 0) {
dprintf(1, "UNIX: create: protocol != 0\n");
return(-EINVAL);
}
if (!(upd = unix_data_alloc()))
{
if (!(upd = unix_data_alloc())) {
printk("UNIX: create: can't allocate buffer\n");
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");
unix_data_deref(upd);
return(-ENOMEM);
......@@ -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);
......@@ -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);
dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd);
if (!upd)
return(0);
if (upd->socket != sock)
{
if (!upd) return(0);
if (upd->socket != sock) {
printk("UNIX: release: socket link mismatch!\n");
return(-EINVAL);
}
if (upd->inode)
{
if (upd->inode) {
dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode);
iput(upd->inode);
upd->inode = NULL;
}
UN_DATA(sock) = NULL;
upd->socket = NULL;
if (upd->peerupd)
unix_data_deref(upd->peerupd);
if (upd->peerupd) unix_data_deref(upd->peerupd);
unix_data_deref(upd);
return(0);
}
......@@ -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.
* I think thats what BSD does in the case of datagram sockets...
*/
static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
static int
unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
int sockaddr_len)
{
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
......@@ -378,13 +362,12 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
int er;
dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len);
if (sockaddr_len <= UN_PATH_OFFSET || sockaddr_len > sizeof(struct sockaddr_un))
{
if (sockaddr_len <= UN_PATH_OFFSET ||
sockaddr_len > sizeof(struct sockaddr_un)) {
dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len);
return(-EINVAL);
}
if (upd->sockaddr_len || upd->inode)
{
if (upd->sockaddr_len || upd->inode) {
printk("UNIX: bind: already bound!\n");
return(-EINVAL);
}
......@@ -393,8 +376,7 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
return er;
memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len);
upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
if (upd->sockaddr_un.sun_family != AF_UNIX)
{
if (upd->sockaddr_un.sun_family != AF_UNIX) {
dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n",
upd->sockaddr_un.sun_family, AF_UNIX);
return(-EINVAL);
......@@ -405,11 +387,9 @@ static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr,
old_fs = get_fs();
set_fs(get_ds());
i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0);
if (i == 0)
i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL);
set_fs(old_fs);
if (i < 0)
{
if (i < 0) {
printk("UNIX: bind: can't open socket %s\n", fname);
return(i);
}
......@@ -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
* wouldn't be the case!)
*/
static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
static int
unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr,
int sockaddr_len, int flags)
{
char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1];
......@@ -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);
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);
return(-EINVAL);
}
if (sock->state == SS_CONNECTING)
return(-EINPROGRESS);
if (sock->state == SS_CONNECTED)
return(-EISCONN);
if (sock->state == SS_CONNECTING) return(-EINPROGRESS);
if (sock->state == SS_CONNECTED) return(-EISCONN);
er=verify_area(VERIFY_READ, uservaddr, sockaddr_len);
if(er)
return er;
memcpy_fromfs(&sockun, uservaddr, sockaddr_len);
sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0';
if (sockun.sun_family != AF_UNIX)
{
if (sockun.sun_family != AF_UNIX) {
dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n",
sockun.sun_family, AF_UNIX);
return(-EINVAL);
......@@ -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
* server. When we're connected, we mooch off the server.
*/
memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET);
fname[sockaddr_len-UN_PATH_OFFSET] = '\0';
old_fs = get_fs();
set_fs(get_ds());
i = open_namei(fname, 0, S_IFSOCK, &inode, NULL);
set_fs(old_fs);
if (i < 0)
{
if (i < 0) {
dprintf(1, "UNIX: connect: can't open socket %s\n", fname);
return(i);
}
serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode);
iput(inode);
if (!serv_upd)
{
if (!serv_upd) {
dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n",
fname, inode);
return(-EINVAL);
}
if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0)
{
if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) {
dprintf(1, "UNIX: connect: can't await connection\n");
return(i);
}
if (sock->conn)
{
if (sock->conn) {
unix_data_ref(UN_DATA(sock->conn));
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,
* for a wait area, and deadlock prevention in the case of a process
* writing to itself is, ignored, in true unix fashion!
*/
static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
static int
unix_proto_socketpair(struct socket *sock1, struct socket *sock2)
{
struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2);
......@@ -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. */
static int unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
static int
unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct socket *clientsock;
......@@ -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,
* then wait for one, unless nonblocking.
*/
while(!(clientsock = sock->iconn))
{
if (flags & O_NONBLOCK)
return(-EAGAIN);
while(!(clientsock = sock->iconn)) {
if (flags & O_NONBLOCK) return(-EAGAIN);
interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked)
{
if (current->signal & ~current->blocked) {
dprintf(1, "UNIX: accept: sleep was interrupted\n");
return(-ERESTARTSYS);
}
......@@ -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.
*/
static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
/* Gets the current name or the name of the connected socket. */
static int
unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
int *usockaddr_len, int peer)
{
struct unix_proto_data *upd;
......@@ -578,27 +545,21 @@ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
int er;
dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self");
if (peer)
{
if (sock->state != SS_CONNECTED)
{
if (peer) {
if (sock->state != SS_CONNECTED) {
dprintf(1, "UNIX: getname: socket not connected\n");
return(-EINVAL);
}
upd = UN_DATA(sock->conn);
}
else
} else
upd = UN_DATA(sock);
er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len));
if(er)
return er;
if ((len = get_fs_long(usockaddr_len)) <= 0)
return(-EINVAL);
if (len > upd->sockaddr_len)
len = upd->sockaddr_len;
if (len)
{
if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL);
if (len > upd->sockaddr_len) len = upd->sockaddr_len;
if (len) {
er=verify_area(VERIFY_WRITE, usockaddr, len);
if(er)
return er;
......@@ -610,29 +571,24 @@ static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr,
/* We read from our own buf. */
static int unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
static int
unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
{
struct unix_proto_data *upd;
int todo, avail;
int er;
if ((todo = size) <= 0)
return(0);
if ((todo = size) <= 0) return(0);
upd = UN_DATA(sock);
while(!(avail = UN_BUF_AVAIL(upd)))
{
if (sock->state != SS_CONNECTED)
{
while(!(avail = UN_BUF_AVAIL(upd))) {
if (sock->state != SS_CONNECTED) {
dprintf(1, "UNIX: read: socket not connected\n");
return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL);
}
dprintf(1, "UNIX: read: no data available...\n");
if (nonblock)
return(-EAGAIN);
if (nonblock) return(-EAGAIN);
interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked)
{
if (current->signal & ~current->blocked) {
dprintf(1, "UNIX: read: interrupted\n");
return(-ERESTARTSYS);
}
......@@ -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,
* watching for wraparound. Then we wake up the writer.
*/
do
{
do {
int part, cando;
if (avail <= 0)
{
if (avail <= 0) {
printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
send_sig(SIGKILL, current, 1);
return(-EPIPE);
}
if ((cando = todo) > avail)
cando = avail;
if (cando >(part = BUF_SIZE - upd->bp_tail))
cando = part;
if ((cando = todo) > avail) cando = avail;
if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part;
dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n",
avail, todo, cando);
if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0)
return er;
memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando);
upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
ubuf += cando;
todo -= cando;
if (sock->state == SS_CONNECTED)
wake_up(sock->conn->wait);
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
avail = UN_BUF_AVAIL(upd);
}
while(todo && avail);
} while(todo && avail);
return(size - todo);
}
......@@ -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 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;
int todo, space;
int er;
if ((todo = size) <= 0)
return(0);
if (sock->state != SS_CONNECTED)
{
if ((todo = size) <= 0) return(0);
if (sock->state != SS_CONNECTED) {
dprintf(1, "UNIX: write: socket not connected\n");
if (sock->state == SS_DISCONNECTING)
{
if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1);
return(-EPIPE);
}
......@@ -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 */
while(!(space = UN_BUF_SPACE(pupd)))
{
while(!(space = UN_BUF_SPACE(pupd))) {
dprintf(1, "UNIX: write: no space left...\n");
if (nonblock)
return(-EAGAIN);
if (nonblock) return(-EAGAIN);
interruptible_sleep_on(sock->wait);
if (current->signal & ~current->blocked)
{
if (current->signal & ~current->blocked) {
dprintf(1, "UNIX: write: interrupted\n");
return(-ERESTARTSYS);
}
if (sock->state == SS_DISCONNECTING)
{
if (sock->state == SS_DISCONNECTING) {
dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
send_sig(SIGPIPE, current, 1);
return(-EPIPE);
......@@ -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,
* watching for wraparound. Then we wake up the reader.
*/
do
{
do {
int part, cando;
if (space <= 0)
{
if (space <= 0) {
printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
send_sig(SIGKILL, current, 1);
return(-EPIPE);
......@@ -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
* for it (peerupd is safe until we close).
*/
if (sock->state == SS_DISCONNECTING)
{
if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1);
return(-EPIPE);
}
if ((cando = todo) > space)
cando = space;
if (cando >(part = BUF_SIZE - pupd->bp_head))
cando = part;
if ((cando = todo) > space) cando = space;
if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;
dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n",
space, todo, cando);
er=verify_area(VERIFY_READ, ubuf, cando);
if(er)
return er;
memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando);
pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
ubuf += cando;
todo -= cando;
if (sock->state == SS_CONNECTED)
wake_up(sock->conn->wait);
if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
space = UN_BUF_SPACE(pupd);
}
while(todo && space);
} while(todo && space);
return(size - todo);
}
static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
static int
unix_proto_select(struct socket *sock, int sel_type, select_table * wait)
{
struct unix_proto_data *upd, *peerupd;
/* Handle server sockets specially. */
if (sock->flags & SO_ACCEPTCON)
{
if (sel_type == SEL_IN)
{
if (sock->flags & SO_ACCEPTCON) {
if (sel_type == SEL_IN) {
dprintf(1, "UNIX: select: %sconnections pending\n",
sock->iconn ? "" : "no ");
if (sock->iconn)
return(1);
if (sock->iconn) return(1);
select_wait(sock->wait, wait);
return(sock->iconn ? 1 : 0);
}
......@@ -797,33 +720,28 @@ static int unix_proto_select(struct socket *sock, int sel_type, select_table * w
return(0);
}
if (sel_type == SEL_IN)
{
if (sel_type == SEL_IN) {
upd = UN_DATA(sock);
dprintf(1, "UNIX: select: there is%s data available\n",
UN_BUF_AVAIL(upd) ? "" : " no");
if (UN_BUF_AVAIL(upd)) /* even if disconnected */
return(1);
else if (sock->state != SS_CONNECTED)
{
else if (sock->state != SS_CONNECTED) {
dprintf(1, "UNIX: select: socket not connected(read EOF)\n");
return(1);
}
select_wait(sock->wait,wait);
return(0);
}
if (sel_type == SEL_OUT)
{
if (sock->state != SS_CONNECTED)
{
if (sel_type == SEL_OUT) {
if (sock->state != SS_CONNECTED) {
dprintf(1, "UNIX: select: socket not connected(write EOF)\n");
return(1);
}
peerupd = UN_DATA(sock->conn);
dprintf(1, "UNIX: select: there is%s space available\n",
UN_BUF_SPACE(peerupd) ? "" : " no");
if (UN_BUF_SPACE(peerupd) > 0)
return(1);
if (UN_BUF_SPACE(peerupd) > 0) return(1);
select_wait(sock->wait,wait);
return(0);
}
......@@ -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;
int er;
......@@ -842,11 +761,9 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long
upd = UN_DATA(sock);
peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL;
switch(cmd)
{
switch(cmd) {
case TIOCINQ:
if (sock->flags & SO_ACCEPTCON)
return(-EINVAL);
if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
if(er)
return er;
......@@ -856,13 +773,12 @@ static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long
put_fs_long(0,(unsigned long *)arg);
break;
case TIOCOUTQ:
if (sock->flags & SO_ACCEPTCON)
return(-EINVAL);
if (sock->flags & SO_ACCEPTCON) return(-EINVAL);
er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long));
if(er)
return er;
if (peerupd)
put_fs_long(UN_BUF_SPACE(peerupd), (unsigned long *)arg);
if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd),
(unsigned long *)arg);
else
put_fs_long(0,(unsigned long *)arg);
break;
......@@ -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;
dprintf(1, "UNIX: open\n");
minor = MINOR(inode->i_rdev);
if (minor != 0)
return(-ENODEV);
if (minor != 0) return(-ENODEV);
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");
}
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)
{
int minor, ret;
......@@ -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);
minor = MINOR(inode->i_rdev);
if (minor != 0)
return(-ENODEV);
if (minor != 0) return(-ENODEV);
ret = -EINVAL;
switch(cmd)
{
switch(cmd) {
case DDIOCSDBG:
er=verify_area(VERIFY_READ,(void *)arg, sizeof(int));
if(er)
return er;
unix_debug = get_fs_long((int *)arg);
if (unix_debug != 0 && unix_debug != 1)
{
if (unix_debug != 0 && unix_debug != 1) {
unix_debug = 0;
return(-EINVAL);
}
......@@ -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, /* READ */
NULL, /* WRITE */
......@@ -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;
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",
pro->name, AF_UNIX_MAJOR);
return;
......@@ -984,8 +896,7 @@ void unix_proto_init(struct ddi_proto *pro)
/* Tell SOCKET that we are alive... */
(void) sock_register(unix_proto_ops.family, &unix_proto_ops);
for(upd = unix_datas; upd <= last_unix_data; ++upd)
{
for(upd = unix_datas; upd <= last_unix_data; ++upd) {
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